diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 1342da3..34809a5 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -28,8 +28,11 @@ jobs: node-version: "24" cache: npm - - name: Install Node dependencies - run: npm ci + - name: Install dependencies + run: | + npm ci + npm --prefix variants/beta ci + npm --prefix variants/stable ci - name: Test run: npm test diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 7c13b08..8484de0 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -26,9 +26,13 @@ jobs: with: node-version: "24" cache: npm + registry-url: "https://registry.npmjs.org" - name: Install dependencies - run: npm ci + run: | + npm ci + npm --prefix variants/beta ci + npm --prefix variants/stable ci - name: Test run: npm test @@ -42,3 +46,26 @@ jobs: files: "*.tgz" env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + + # 双渠道发布:beta 版本发 beta 标签;stable 版本发 stable 标签(均不挂 latest)。 + # 需在仓库 Secrets 配置 NPM_TOKEN(有发布权限);未配置则跳过。 + # secrets 上下文不能用于 step 级 if(报 Unrecognized named-value),先经 env 读出是否配置, + # 再用 steps..outputs 作为发布步骤的闸门 + - name: Check NPM_TOKEN configured + id: npm_token + env: + NPM_TOKEN: ${{ secrets.NPM_TOKEN }} + run: | + if [ -n "$NPM_TOKEN" ]; then echo "configured=true" >> "$GITHUB_OUTPUT"; else echo "configured=false" >> "$GITHUB_OUTPUT"; fi + + - name: Publish to npm (beta -> beta tag) + if: ${{ steps.npm_token.outputs.configured == 'true' }} + run: npm publish ./variants/beta --tag beta + env: + NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} + + - name: Publish to npm (stable -> stable tag) + if: ${{ steps.npm_token.outputs.configured == 'true' }} + run: npm publish ./variants/stable --tag stable + env: + NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} diff --git a/.gitignore b/.gitignore index 738ab9d..c61efd8 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ build node_modules scripts -*.tgz \ No newline at end of file +*.tgz +variants/*/dist diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 0000000..33bbe32 --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1,81 @@ +# CLAUDE.md + +This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. + +## 项目简介 + +sapi-pro 是 Minecraft Bedrock ScriptAPI(SAPI)库,提供命令系统、表单导航、数据存储、多包通信、国际化。安装/使用见 README.md,API 文档在 docs/,教程在 tutorial/。**同一个 npm 包发布双渠道**:`latest` 标签 → stable 版,`beta` 标签 → beta 版;不维护两个分支,用 monorepo 共享源码。开发时加载 `sapi-pro-dev` skill。 + +## 目录结构 + +- `packages/core/`:共享源码(`src/`)与共享测试(`test/`),**不发布**。 +- `variants/beta/`:beta 渠道构建与发布(使用最新 beta 版 `@minecraft/*`,全功能)。 +- `variants/stable/`:stable 渠道构建与发布(使用最新 stable 版 `@minecraft/*`,**无模拟命令、无 chatBus**)。 +- `tools/`:版本注入、fflate 打包等构建脚本。 +- 根 `package.json` 是编排层(`private: true`),不包含库源码,只做脚本编排与测试依赖。 + +## 常用命令 + +| 命令 | 作用 | +|---|---| +| `npm install` | 安装根目录工具链 + 测试用 beta `@minecraft/*` | +| `npm run install:variants` | 分别安装 `variants/beta` 与 `variants/stable` 各自的 `@minecraft/*` 依赖 | +| `npm test` | vitest 全部测试(`packages/core/test`,打桩 `@minecraft/server`) | +| `npm run typecheck` | 双渠道 typecheck(beta + stable,各用各的 `@minecraft/*` 类型) | +| `npm run typecheck:beta` | `tsc -p tsconfig.beta.json --noEmit` | +| `npm run typecheck:stable` | `tsc -p tsconfig.stable.json --noEmit` | +| `npm run compile:beta` | rolldown 编译 beta → `variants/beta/dist/`(含 .d.ts) | +| `npm run compile:stable` | rolldown 编译 stable → `variants/stable/dist/` | +| `npm run dev:beta` / `dev:stable` | rolldown 监听模式 | +| `npm run build` | 完整构建:clean → 双渠道 typecheck → 双渠道 rolldown → fflate 打包 zip | +| `npm run pack` | 完整构建 + `pack:beta` + `pack:stable`,产出 `build/*.zip` 与两个 `.tgz`(CI 用) | +| `npm run build:beta` / `build:stable` | 单渠道 typecheck + 编译 | +| `npm run pack:beta` | `npm pack ./variants/beta` 生成 `sapi-pro-.tgz` | +| `npm run pack:stable` | 生成 `sapi-pro-.tgz` | +| `npm run publish:beta` | `npm publish ./variants/beta --tag beta` | +| `npm run publish:stable` | `npm publish ./variants/stable --tag stable` | + +构建产物 `build/`、`variants/*/dist`、`variants/*/node_modules`、`*.tgz` 均被 gitignore。测试在 `packages/core/test/` 下,直接从 `../../src/...` 相对导入并用 `vi.mock("@minecraft/server")` 打桩,不走别名。 + +## 架构 + +- 共享实现 `packages/core/src/main.ts`:`initSAPIPro()` 初始化库并 re-export 各模块。每个 variant 的 `package.json` 的 `exports` 暴露 10 个子路径:`.`、`./Command`、`./DataBase`、`./Deferred`、`./Form`、`./Translate`、`./Event`、`./func`、`./constants`、`./utils`,指向各自 `dist/`。其中 `.` 与 `./Event` 指向**每渠道入口 barrel**(`entry.beta.ts` / `entry.stable.ts`、`Event.entry.beta.ts` / `Event.entry.stable.ts`),其余指向共享模块根文件。 +- `packages/core/src/Config.ts`:`LibConfig` 单例。`version`(数字,多包主机选举权重)+ `versionString`(显示字符串),均由构建时从**各自 variant 的 package.json** 注入;`isBeta = __BETA__`(构建期常量)。 +- `packages/core/src/System/`:`ScriptCom.ts` 初始化命令注册与多包主机选举(各包 `packComInfo.version` 做数字比较,最大者当主模块;**stable 版不参与选举**);`sysinfo.ts` 信息命令/表单。 +- `packages/core/src/Command/`:命令系统。**`.` 前缀模拟命令(`Command/parser/parser.ts`)、自定义 help(`Command/help.ts`,专门为 `.help` 准备的)与 chatBus 仅 beta 渠道存在**;stable 渠道这三个模块不进产物、`CommandManager.parser` 与 `help` 均为 `undefined`(通过 `SimulatedParserLike` / `HelpLike` 结构接口解耦)。**stable 只允许 `registerNative` 注册游戏原生命令**(customCommandRegistry + `NativeCommandParser`),`registerCommand`(模拟命令)在 stable 无效、不自动转原生,自定义 help 由游戏自带 `/help` 覆盖。 +- `packages/core/src/Form/`:表单导航,`formManager` 全局管理,支持跨包 `openExternal` 打开别的行为包的表单。 +- `packages/core/src/DataBase/`:`DPDataBase` / `ScoreBoardJSONDataBase` / `ScoreBoardDataBase`,超大文本分割存储。 +- `packages/core/src/Deferred/`:世界加载后才求值的延迟对象,`gameDeferredRegistry` 统一绑定。 +- `packages/core/src/Event.ts`:事件总线(聊天/间隔等);`Translate/`:i18n,`translator`;`utils/`:random / vector / chunk / logger / vanilla-data 封装。 + +## 双渠道构建(改构建相关代码时必看) + +- 两个 variant 各自有 `rolldown.config.ts` + `tsconfig.json` + `package.json`,**同一份 `packages/core/src` 构建成不同 dist**。编译是 **rolldown + rolldown-plugin-dts**,`preserveModules` 逐模块镜像 `packages/core/src` → `variants//dist`;tsc 只做 typecheck。 +- 每个 variant 的 rolldown `input` 必须列出 `exports` 的**全部 10 个子路径根文件**。其中 `.` 与 `./Event` 是本渠道入口 barrel(`entry..ts`、`Event.entry..ts`),其余 8 个是共享模块根文件(如 `Event.ts`、`Command/main.ts`)。纯 re-export barrel(如 `Deferred/index.ts`)会被 rolldown 提升折叠掉,导致子路径失效。新增公开子路径时,要同步改两个 variant 的 `exports` map、`rolldown.config.ts` 的 input。 +- **dts 插件 `entry` 必须用相对 `process.cwd()` 的 glob**(`${CORE_REL}/**/*.ts`)。插件按 `path.relative(cwd, id)` 匹配,绝对路径 glob 会一个 `.d.ts` 都出不来。 +- **同一份源码对不同版本类型检查**:每渠道一个 tsconfig 在**仓库根**(`tsconfig.beta.json` / `tsconfig.stable.json`),用 `paths` 把 `@minecraft/server`、`@minecraft/server-ui` 重定向到各自 `node_modules` 里的类型。**TS7 已移除 `baseUrl`**,`paths` 相对各自 tsconfig 所在目录解析。 +- **dts 输出路径必须与 .js 对齐**:rolldown dts 插件以 `dirname(tsconfig)` 为 rootDir(即仓库根)。全部源码都在 `packages/core/src`(**没有渠道源码**),因此 `output.preserveModulesRoot = CORE`,同时 dts 插件显式传 `compilerOptions.rootDir = CORE`——两者一致,dist 干净镜像成 `dist/main.js`、`dist/Event.js`、`dist/entry.beta.js` 等。曾把渠道源码(chatBus/commandWiring)放 `variants/` 目录,导致 preserveModulesRoot 必须为仓库根、dist 带 `packages/core/src/` 与 `variants//` 前缀,且依赖 `@sapi/*` 别名,已废弃。 +- **构建期条件编译**:`__BETA__` 在 beta 的 rolldown 里注入 `true`、stable 注入 `false`,实现 dead code elimination。stable 因此没有模拟命令的聊天接线(`Command/main.ts` 里 `if (__BETA__)` 整段消除),且 `Event/chatBus.ts` 经 `treeshake.moduleSideEffects` 声明为无副作用后整个模块不进产物。 +- **chatBus 按入口隔离(唯一渠道差异点,stable 不导出)**:聊天相关类型与 `chatBusClass` 在共享的 `Event/chatBusClass.ts`(stable 也在用,`ChatSendBeforeEventLike` 结构类型兜底),**chatBus 实例**在共享的 `Event/chatBus.ts`(`export const chatBus = new chatBusClass()`)。`Event.ts` 只 re-export `chatBusClass`,不导出实例。**每渠道入口 barrel 决定是否暴露实例**:`entry.beta.ts` / `Event.entry.beta.ts` = 共享入口 + `export * from "./Event/chatBus"`;`entry.stable.ts` / `Event.entry.stable.ts` 不含 chatBus → stable 的 `.` 与 `./Event` 的 d.ts 都没有 chatBus,消费方 `import { chatBus }` 报 TS2305,beta 免空检查。运行时接线在共享 `Command/main.ts`:`if (__BETA__) chatBus.subscribe(pcommand.runCommand.bind(pcommand))`。**stable 产物不含 `Event/chatBus.js`/`.d.ts`**:靠 stable 的 `treeshake.moduleSideEffects`(`Event/chatBus.ts` 无副作用)+ dts entry glob 排除。曾尝试 `typeof __BETA__` 条件类型、独立类型文件 + tsconfig paths、per-channel 源码 + `@sapi/*` 别名等方案,均因 dts 插件局限或过度复杂失败/废弃。 +- **`ChatSendBeforeEvent` 仅 beta 有**(stable `@minecraft/server@2.8.0` 已移除)。共享源码里用结构类型 `ChatSendBeforeEventLike`(`Event.ts` 导出)替代,`world.beforeEvents.chatSend` 用断言访问,保证 stable 类型下也能通过。新增代码不要直接 import `ChatSendBeforeEvent`。 +- **stable 剔除模拟命令子系统**:`CommandManager`/`CommandHelp` 通过结构接口 `SimulatedParserLike`、`HelpLike`(定义在 `Command/manager.ts`)解耦,不直接引用 `CommandParser`/`CommandHelp` 类型;`Command/main.ts` 里 `const parser = __BETA__ ? new CommandParser() : undefined`、`const help = __BETA__ ? new CommandHelp(...) : undefined`。stable 的 rolldown 配置额外用 `treeshake.moduleSideEffects` 把 `Command/parser/parser.ts`、`Command/parser/func.ts`、`Command/help.ts` 声明为**无副作用**(`main.ts` 对它们的 import 在 `__BETA__=false` 下成为未使用 import,整体丢弃),并在 dts entry glob 里排除这三个文件;因此 **stable 产物完全没有 `parser.js`、`parser/func.js`、`help.js` 及对应 `.d.ts`**。beta 配置不做这些,全量保留。新增模拟命令相关代码注意别让 stable 重新引用这三个模块。 +- **版本注入**:`tools/libVersion.ts` 的 `getLibVersion(packageJsonPath)` 读**指定 variant 的 package.json** 版本(去预发布后缀),在各自 `rolldown.config.ts` 的 `transform.define` 注入 `__SAPI_PRO_VERSION__`(显示字符串 major.minor.patch)与 `__SAPI_PRO_VERSION_NUM__`(选举数字 (major×100+minor×10+patch)/100)。`vitest.config.ts` 的 `define` 与 **beta** variant 保持一致。`packages/core/src/global.d.ts` 声明这三个常量。 +- **`@minecraft/*` 版本钉死精确值,不要放宽成 `^`**:beta 用 `2.10.0-beta.1.26.40-stable` / `2.2.0-beta.1.26.40-stable`,stable 用 `2.8.0` / `2.1.0`(以 npm `dist-tags` 为准)。会漂到 rc 版本并破坏 API。 +- **每渠道类型单独安装**:`variants/beta` 与 `variants/stable` 各自的 `devDependencies` 钉各自的 `@minecraft/*`,需 `npm run install:variants`(两个目录各有 package-lock.json)。**根目录不安装 `@minecraft/*`**:构建链路各自用 `tsconfig.beta/stable.json` 的 paths 重定向到渠道 node_modules;编辑器/测试类型经根 `tsconfig.json` 的 paths 指向 `variants/beta` 安装的 beta 类型(vitest 用工厂 mock 不加载真实模块)。三者不得混用。 +- `.npmrc` 的 `legacy-peer-deps=true` 是必须的(typescript@7 与 typedoc 的 peer 冲突),删掉则 `npm ci` 报 ERESOLVE。 +- **typescript@7 无编译器 API**(`require("typescript")` 只返回 version);rolldown-plugin-dts 用其实验性 tsgo 生成器兼容 TS7。 +- 纯类型 re-export 必须写 `export type { X }`(rolldown 比 tsc 严格,漏了报 MISSING_EXPORT)。 + +## 发版 + +- **版本规则**:两渠道共享同一 base 版本,beta 不带后缀、stable 带 `-stable` 后缀。如 base `0.4.2`:beta 版 `0.4.2`,stable 版 `0.4.2-stable`。`libVersionString` 两边都解析为 `0.4.2`,游戏内显示 `0.4.2-beta` / `0.4.2-stable`。 +- beta 渠道:改 `variants/beta/package.json` 的 `version`(如 `0.4.2`)→ `npm run pack:beta` → `npm run publish:beta`(`--tag beta`)。 +- stable 渠道:改 `variants/stable/package.json` 的 `version`(如 `0.4.2-stable`)→ `npm run pack:stable` → `npm run publish:stable`(`--tag stable`)。**两渠道都不挂 `latest` 标签**,安装时用 `sapi-pro@beta` / `sapi-pro@stable` 显式指定。 +- 下游行为包通过 `file:` 按文件名依赖 `sapi-pro-.tgz`,版本不同文件名不同,直接换引用即可。 + +## 开发规则 + +- 调用/修改 sapi-pro 与 `@minecraft/*` API 时,以各渠道 `node_modules` 里实际安装的类型定义为准,不要凭记忆写。 +- 游戏内玩家可见文本不要用 Emoji(✅ 🎉 等),用 Unicode 符号(✔ ✘ ▸ 等);颜色用 `§` 代码。按钮文字用深色系,表单 body/聊天用浅色系。 +- 新增功能若依赖 beta-only API(如 chatSend before 事件),必须用 `__BETA__` 或结构类型隔离,保证 stable 渠道 typecheck 通过;stable 不提供该功能。 +- 数据存储优先复用 `DataBase` 封装、命令用 `Command` 系统,不要重新实现已有功能。 diff --git a/package-lock.json b/package-lock.json index 5d89e52..79cd84a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,18 +1,13 @@ { - "name": "sapi-pro", - "version": "0.4.1", + "name": "sapi-pro-monorepo", + "version": "0.0.0", "lockfileVersion": 3, "requires": true, "packages": { "": { - "name": "sapi-pro", - "version": "0.4.1", - "license": "MIT", + "name": "sapi-pro-monorepo", + "version": "0.0.0", "devDependencies": { - "@minecraft/common": "1.2.0", - "@minecraft/server": "2.9.0-beta.1.26.30-stable", - "@minecraft/server-ui": "2.2.0-beta.1.26.30-stable", - "@minecraft/vanilla-data": "1.26.10", "@types/node": "^26.1.2", "fflate": "^0.8.3", "rimraf": "^6.1.3", @@ -22,11 +17,6 @@ "typedoc-plugin-markdown": "^4.4.2", "typescript": "^7.0.2", "vitest": "^4.1.8" - }, - "peerDependencies": { - "@minecraft/server": "^2.9.0-beta.1.26.30-stable", - "@minecraft/server-ui": "^2.2.0-beta.1.26.30-stable", - "@minecraft/vanilla-data": ">=1.26.0" } }, "node_modules/@emnapi/core": { @@ -84,42 +74,6 @@ "dev": true, "license": "MIT" }, - "node_modules/@minecraft/common": { - "version": "1.2.0", - "resolved": "https://registry.npmmirror.com/@minecraft/common/-/common-1.2.0.tgz", - "integrity": "sha512-JdmEq4P3Z/FtoBzhLijFgMSVFnFRrUoLwY8DHHrgtFo0mfLTOLTB1RErYjLMsA6b7BGVNxkX/pfFRiH7QZ0XwQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/@minecraft/server": { - "version": "2.9.0-beta.1.26.30-stable", - "resolved": "https://registry.npmmirror.com/@minecraft/server/-/server-2.9.0-beta.1.26.30-stable.tgz", - "integrity": "sha512-KhYSda6eAyFCVC5mcnVE6F0lyXmZJQGpF1D07t7b0rNztFVp7Eh0/nvPRfBNUs90G4O1reAS7jZBHl9Kp9+cZA==", - "dev": true, - "license": "MIT", - "peerDependencies": { - "@minecraft/common": "^1.2.0", - "@minecraft/vanilla-data": ">=1.20.70" - } - }, - "node_modules/@minecraft/server-ui": { - "version": "2.2.0-beta.1.26.30-stable", - "resolved": "https://registry.npmmirror.com/@minecraft/server-ui/-/server-ui-2.2.0-beta.1.26.30-stable.tgz", - "integrity": "sha512-OMkGdrU5w/g/oIHR6ltpxbTNzEDYcDoHI56jW5FOBK+U6UwBO5wQteAPVvKKcBqD8KsY0R72xw1cKNfVwwJFIg==", - "dev": true, - "license": "MIT", - "peerDependencies": { - "@minecraft/common": "^1.0.0", - "@minecraft/server": "^2.0.0 || ^2.9.0-beta.1.26.30-stable" - } - }, - "node_modules/@minecraft/vanilla-data": { - "version": "1.26.10", - "resolved": "https://registry.npmmirror.com/@minecraft/vanilla-data/-/vanilla-data-1.26.10.tgz", - "integrity": "sha512-MViGntJ2xc+1eVDEBNBTFpIZ2kg2ygnOUR2aBqn7WzxuBYKda4eBEruDCGLuctgdqleebzqAdBPSndQ/z27cJA==", - "dev": true, - "license": "MIT" - }, "node_modules/@napi-rs/wasm-runtime": { "version": "1.2.2", "resolved": "https://registry.npmmirror.com/@napi-rs/wasm-runtime/-/wasm-runtime-1.2.2.tgz", diff --git a/package.json b/package.json index 6ea2b4a..a1b7ce0 100644 --- a/package.json +++ b/package.json @@ -1,29 +1,32 @@ { - "name": "sapi-pro", - "version": "0.4.1", - "description": "A practical library for MCBE ScriptAPI", - "main": "scripts/main.js", - "types": "scripts/main.d.ts", + "name": "sapi-pro-monorepo", + "version": "0.0.0", + "private": true, + "description": "sapi-pro monorepo:packages/core 共享源码,variants/beta 与 variants/stable 双渠道构建发布", "type": "module", - "author": { - "name": "XiaoYangx666", - "email": "2408807389@qq.com" - }, - "license": "MIT", - "repository": { - "type": "git", - "url": "https://github.com/XiaoYangx666/SAPI-Pro.git" - }, - "peerDependencies": { - "@minecraft/server": "^2.9.0-beta.1.26.30-stable", - "@minecraft/server-ui": "^2.2.0-beta.1.26.30-stable", - "@minecraft/vanilla-data": ">=1.26.0" + "scripts": { + "clean": "rimraf build variants/beta/dist variants/stable/dist", + "install:variants": "npm --prefix variants/beta install && npm --prefix variants/stable install", + "test": "vitest run", + "typecheck": "npm run typecheck:beta && npm run typecheck:stable", + "typecheck:beta": "tsc -p tsconfig.beta.json --noEmit", + "typecheck:stable": "tsc -p tsconfig.stable.json --noEmit", + "compile:beta": "rolldown -c variants/beta/rolldown.config.ts", + "compile:stable": "rolldown -c variants/stable/rolldown.config.ts", + "dev:beta": "rolldown -c variants/beta/rolldown.config.ts -w", + "dev:stable": "rolldown -c variants/stable/rolldown.config.ts -w", + "build": "npm run clean && npm run typecheck && npm run compile:beta && npm run compile:stable && npm run package", + "build:beta": "npm run typecheck:beta && npm run compile:beta", + "build:stable": "npm run typecheck:stable && npm run compile:stable", + "package": "node tools/build.ts", + "pack": "npm run build && npm run pack:beta && npm run pack:stable", + "pack:beta": "npm pack ./variants/beta", + "pack:stable": "npm pack ./variants/stable", + "publish:beta": "npm publish ./variants/beta --tag beta", + "publish:stable": "npm publish ./variants/stable --tag stable", + "skills": "node tools/cp_skill.ts" }, "devDependencies": { - "@minecraft/common": "1.2.0", - "@minecraft/server": "2.9.0-beta.1.26.30-stable", - "@minecraft/server-ui": "2.2.0-beta.1.26.30-stable", - "@minecraft/vanilla-data": "1.26.10", "@types/node": "^26.1.2", "fflate": "^0.8.3", "rimraf": "^6.1.3", @@ -33,40 +36,5 @@ "typedoc-plugin-markdown": "^4.4.2", "typescript": "^7.0.2", "vitest": "^4.1.8" - }, - "scripts": { - "clean": "rimraf build scripts", - "dev": "rolldown -c rolldown.config.ts -w", - "typecheck": "tsc --noEmit", - "compile": "rolldown -c rolldown.config.ts", - "test": "vitest run", - "package": "node tools/build.ts", - "build": "npm run clean && npm run typecheck && npm run compile && npm run package", - "pack": "npm run typecheck && npm run compile && npm pack", - "doc": "npx typedoc --plugin typedoc-plugin-markdown ./src/main.ts --disableSources", - "skills": "node tools/cp_skill.ts" - }, - "files": [ - "scripts" - ], - "exports": { - ".": "./scripts/main.js", - "./Deferred": "./scripts/Deferred/index.js", - "./Form": "./scripts/Form/main.js", - "./Translate": "./scripts/Translate/index.js", - "./Event": "./scripts/Event.js", - "./func": "./scripts/func.js", - "./constants": "./scripts/constants.js", - "./utils": "./scripts/utils/main.js", - "./Command": "./scripts/Command/main.js", - "./DataBase": "./scripts/DataBase/index.js" - }, - "keywords": [ - "minecraft", - "bedrock", - "bedrock-edition", - "ScriptApi", - "library" - ], - "sideEffects": false + } } diff --git a/packages/core/package.json b/packages/core/package.json new file mode 100644 index 0000000..0ee0a10 --- /dev/null +++ b/packages/core/package.json @@ -0,0 +1,7 @@ +{ + "name": "@sapi-pro/core", + "version": "0.0.0", + "private": true, + "description": "sapi-pro 共享源码(beta/stable 双渠道共用,不发布)", + "type": "module" +} diff --git a/src/Command/commandClass.ts b/packages/core/src/Command/commandClass.ts similarity index 97% rename from src/Command/commandClass.ts rename to packages/core/src/Command/commandClass.ts index ef1776a..dbcceb4 100644 --- a/src/Command/commandClass.ts +++ b/packages/core/src/Command/commandClass.ts @@ -1,9 +1,4 @@ -import { - CommandPermissionLevel, - CustomCommand, - CustomCommandParameter, - CustomCommandParamType, -} from "@minecraft/server"; +import { CommandPermissionLevel, CustomCommandParameter } from "@minecraft/server"; import { commandHandler, CommandObject, @@ -12,7 +7,6 @@ import { ParamDefinition, } from "./interface"; import { NativeTypeMapping, paramTypes } from "./parser/ParamTypes"; -import { LibConfig } from "@/Config"; export class Command { name: string; diff --git a/src/Command/help.ts b/packages/core/src/Command/help.ts similarity index 92% rename from src/Command/help.ts rename to packages/core/src/Command/help.ts index 3147b42..d7ca653 100644 --- a/src/Command/help.ts +++ b/packages/core/src/Command/help.ts @@ -3,8 +3,7 @@ import { isAdmin } from "../func"; import { Command } from "./commandClass"; import { enterNodeFunc, PreOrdertraverse } from "./parser/func"; import { ParamDefinition } from "./interface"; -import { CommandParser } from "./parser/parser"; -import { CommandManager } from "./manager"; +import { CommandManager, SimulatedParserLike } from "./manager"; interface helpCommandParam { page?: number; @@ -14,7 +13,7 @@ export class CommandHelp { private readonly helpCommand: Command; constructor( private readonly pcommand: CommandManager, - private readonly parser: CommandParser + private readonly parser: SimulatedParserLike | undefined ) { this.helpCommand = new Command( "help", @@ -40,7 +39,12 @@ export class CommandHelp { commandHelp(player: Player, args: helpCommandParam) { if (args.commandName) { const commandObj = this.pcommand.getCommandInfo(args.commandName); - if (commandObj == undefined) + if (commandObj == undefined) { + // stable 渠道无模拟命令解析器,直接发送错误文本 + if (!this.parser) { + player.sendMessage({ rawtext: [{ text: "§c命令不存在" }] }); + return; + } return this.parser.dispatchError( player, true, @@ -52,6 +56,7 @@ export class CommandHelp { "命令不存在" ) ); + } this.handleCommandHelp(player, commandObj); } if (args.page != undefined) this.handlePageHelp(player, args.page - 1); diff --git a/src/Command/interface.ts b/packages/core/src/Command/interface.ts similarity index 100% rename from src/Command/interface.ts rename to packages/core/src/Command/interface.ts diff --git a/packages/core/src/Command/main.ts b/packages/core/src/Command/main.ts new file mode 100644 index 0000000..d8d95e7 --- /dev/null +++ b/packages/core/src/Command/main.ts @@ -0,0 +1,26 @@ +import { CommandHelp } from "./help"; +import { CommandManager } from "./manager"; +import { NativeCommandParser } from "./parser/nativeParser"; +import { CommandParser } from "./parser/parser"; +import { chatBus } from "../Event/chatBus"; + +//初始化 +function initCommandSystem() { + // 模拟命令解析器与自定义 help(.help)仅 beta 渠道存在;stable 渠道 __BETA__=false 时整段死代码消除, + // parser.ts / help.ts 不进入产物。stable 只注册游戏原生命令,自定义 help 由游戏自带 /help 覆盖 + const parser = __BETA__ ? new CommandParser() : undefined; + const nativeParser = new NativeCommandParser(); + const pcommand = new CommandManager(parser, nativeParser); + const help = __BETA__ ? new CommandHelp(pcommand, parser) : undefined; + parser?.init(pcommand); + pcommand.init(help); + // 聊天触发的模拟命令接线:仅 beta 渠道订阅 chatBus(__BETA__=false 时整段死代码消除, + // 且 chatBus 模块被 stable 的 treeshake.moduleSideEffects 声明为无副作用,整个实例不进 stable 产物) + if (__BETA__) chatBus.subscribe(pcommand.runCommand.bind(pcommand)); + return pcommand; +} + +export const pcommand = initCommandSystem(); +export { CommandManager } from "./manager"; +export * from "./commandClass"; +export * from "./interface"; diff --git a/src/Command/manager.ts b/packages/core/src/Command/manager.ts similarity index 64% rename from src/Command/manager.ts rename to packages/core/src/Command/manager.ts index 814cd1a..b03d034 100644 --- a/src/Command/manager.ts +++ b/packages/core/src/Command/manager.ts @@ -1,39 +1,69 @@ import { - ChatSendBeforeEvent, CustomCommandOrigin, CustomCommandResult, CustomCommandSource, CustomCommandStatus, Player, + RawMessage, StartupEvent, system, } from "@minecraft/server"; import { LibConfig } from "../Config"; import { exchangedb } from "../DataBase/DataBase"; -import { chatBus } from "../Event"; +import { chatOpe, ChatSendBeforeEventLike } from "../Event"; import { Command } from "./commandClass"; -import { CommandHelp } from "./help"; -import { CommandParser } from "./parser/parser"; import { NativeCommandParser } from "./parser/nativeParser"; +/** + * 模拟命令解析器(聊天触发的 `.命令`)的最小接口。 + * + * 仅 beta 渠道存在实现(`CommandParser`);stable 渠道 `__BETA__` 为 false, + * 该解析器整段死代码消除、不进入产物,`CommandManager` 的 parser 为 undefined。 + * 用结构接口而非直接引用 `CommandParser`,保证 stable 的 .d.ts 不依赖 `./parser/parser` 模块。 + */ +export interface SimulatedParserLike { + parseCommand(input: string, player: Player): void | chatOpe; + dispatchError( + player: Player, + showError: boolean, + errorMsg: RawMessage | string + ): void | RawMessage; + buildSyntaxError( + command: Command, + value: string | undefined, + params: string[], + current: number, + tip?: string | RawMessage + ): RawMessage; +} + +/** + * 自定义 help 命令的最小接口。 + * + * 仅 beta 渠道存在实现(`CommandHelp`,模拟命令 `.help`);stable 渠道游戏自带 `/help`, + * 不需要自定义 help,`CommandManager.help` 恒为 undefined。用结构接口避免 .d.ts 依赖 `./help` 模块。 + */ +export interface HelpLike { + handleCommandHelp(player: Player, command: Command): void; +} + //命令管理类 export class CommandManager { readonly commands: Map; readonly nativeCommands: Command[] = []; testMode = false; - help?: CommandHelp; + help?: HelpLike; constructor( - private readonly parser: CommandParser, + private readonly parser: SimulatedParserLike | undefined, private readonly nativeParser: NativeCommandParser ) { this.commands = new Map(); - chatBus.subscribe(this.runCommand.bind(this)); //注册原生指令 system.beforeEvents.startup.subscribe(this.registerNativeCommands.bind(this)); } - init(help: CommandHelp) { + init(help: HelpLike | undefined) { this.help = help; } @@ -55,7 +85,7 @@ export class CommandManager { }); } - /** 注册命令 */ + /** 注册模拟命令(仅 beta 渠道的聊天触发 `.命令`);stable 渠道只允许 registerNative 注册原生命令 */ registerCommand(command: Command) { // prettier-ignore if (command.name != "help"&&this.help!=undefined) { @@ -100,15 +130,16 @@ export class CommandManager { } } - /** 运行命令注册回调*/ - runCommand(t: ChatSendBeforeEvent) { + /** 运行命令注册回调(仅 beta 渠道被 chatBus 订阅) */ + runCommand(t: ChatSendBeforeEventLike) { if (!(t.message.length > 0 && t.message[0] === ".")) return; let msg = t.message.slice(1); - return this.parser.parseCommand(msg, t.sender); + return this.parser?.parseCommand(msg, t.sender); } + /** 编程式解析一条模拟命令;stable 渠道无解析器,调用为无操作 */ parseCommand(input: string, player: Player) { - this.parser.parseCommand(input, player); + this.parser?.parseCommand(input, player); } private runNativeCommand( @@ -129,14 +160,17 @@ export class CommandManager { } getCommandInfo(command: string) { - return this.commands.get(command); + return this.commands.get(command) ?? this.nativeCommands.find((t) => t.name === command); } getCommandsList(admin: boolean) { + const all = [ + ...new Set([...this.commands.keys(), ...this.nativeCommands.map((t) => t.name)]), + ]; if (admin) { - return [...this.commands.keys()]; + return all; } else { - return [...this.commands.keys()].filter((t) => !this.getCommandInfo(t)?.isAdmin); + return all.filter((t) => !this.getCommandInfo(t)?.isAdmin); } } } diff --git a/src/Command/parser/ParamTypes.ts b/packages/core/src/Command/parser/ParamTypes.ts similarity index 100% rename from src/Command/parser/ParamTypes.ts rename to packages/core/src/Command/parser/ParamTypes.ts diff --git a/src/Command/parser/func.ts b/packages/core/src/Command/parser/func.ts similarity index 100% rename from src/Command/parser/func.ts rename to packages/core/src/Command/parser/func.ts diff --git a/src/Command/parser/nativeParser.ts b/packages/core/src/Command/parser/nativeParser.ts similarity index 100% rename from src/Command/parser/nativeParser.ts rename to packages/core/src/Command/parser/nativeParser.ts diff --git a/src/Command/parser/parser.ts b/packages/core/src/Command/parser/parser.ts similarity index 100% rename from src/Command/parser/parser.ts rename to packages/core/src/Command/parser/parser.ts diff --git a/src/Config.ts b/packages/core/src/Config.ts similarity index 86% rename from src/Config.ts rename to packages/core/src/Config.ts index 72258a1..be85b8b 100644 --- a/src/Config.ts +++ b/packages/core/src/Config.ts @@ -15,8 +15,8 @@ class LibConfigClass { version = __SAPI_PRO_VERSION_NUM__; /**库显示版本 */ versionString = __SAPI_PRO_VERSION__; - /**是否是beta版库 */ - isBeta = true; + /**是否是beta版库(构建期由 __BETA__ 注入,决定是否参与主机选举);显式 boolean 避免按渠道收窄成字面量 */ + isBeta: boolean = __BETA__; /**是否是主行为包 */ isHost = false; packInfo: PackInfo; diff --git a/src/DataBase/DataBase.ts b/packages/core/src/DataBase/DataBase.ts similarity index 100% rename from src/DataBase/DataBase.ts rename to packages/core/src/DataBase/DataBase.ts diff --git a/src/DataBase/NameDB.ts b/packages/core/src/DataBase/NameDB.ts similarity index 100% rename from src/DataBase/NameDB.ts rename to packages/core/src/DataBase/NameDB.ts diff --git a/src/DataBase/index.ts b/packages/core/src/DataBase/index.ts similarity index 100% rename from src/DataBase/index.ts rename to packages/core/src/DataBase/index.ts diff --git a/src/Deferred/DeferredRegistry.ts b/packages/core/src/Deferred/DeferredRegistry.ts similarity index 100% rename from src/Deferred/DeferredRegistry.ts rename to packages/core/src/Deferred/DeferredRegistry.ts diff --git a/src/Deferred/createDeferredObject.ts b/packages/core/src/Deferred/createDeferredObject.ts similarity index 100% rename from src/Deferred/createDeferredObject.ts rename to packages/core/src/Deferred/createDeferredObject.ts diff --git a/src/Deferred/index.ts b/packages/core/src/Deferred/index.ts similarity index 100% rename from src/Deferred/index.ts rename to packages/core/src/Deferred/index.ts diff --git a/packages/core/src/Event.entry.beta.ts b/packages/core/src/Event.entry.beta.ts new file mode 100644 index 0000000..fa9746a --- /dev/null +++ b/packages/core/src/Event.entry.beta.ts @@ -0,0 +1,3 @@ +// beta 渠道 `./Event` 子路径入口:共享 Event + chatBus 实例 +export * from "./Event"; +export * from "./Event/chatBus"; diff --git a/packages/core/src/Event.entry.stable.ts b/packages/core/src/Event.entry.stable.ts new file mode 100644 index 0000000..c1ab900 --- /dev/null +++ b/packages/core/src/Event.entry.stable.ts @@ -0,0 +1,2 @@ +// stable 渠道 `./Event` 子路径入口:仅共享 Event,不导出 chatBus +export * from "./Event"; diff --git a/src/Event.ts b/packages/core/src/Event.ts similarity index 66% rename from src/Event.ts rename to packages/core/src/Event.ts index 571118c..9740d6d 100644 --- a/src/Event.ts +++ b/packages/core/src/Event.ts @@ -1,5 +1,4 @@ import { - ChatSendBeforeEvent, ItemUseAfterEvent, Player, ScriptEventCommandMessageAfterEvent, @@ -9,70 +8,9 @@ import { import { LibErrorMes } from "./func"; import { RandomUtils } from "./utils/main"; -//先不搞优先队列了,能用就行,反正只有注册的时候排序 -export type chatFunc = (t: ChatSendBeforeEvent) => void | chatOpe; -export interface chatEvents { - priority: number; - callback: (t: ChatSendBeforeEvent) => void | chatOpe; -} -/** - * 聊天订阅 - */ -export class chatBusClass { - private eventList: chatEvents[]; - private send: (t: ChatSendBeforeEvent) => boolean; - constructor() { - this.eventList = []; - this.send = (t) => { - return false; - }; - world.beforeEvents.chatSend.subscribe((t) => { - t.cancel = chatBus.publish(t); - }); - } - /** - * 订阅聊天事件 - * - * 返回值:是否取消原版聊天发送 - */ - subscribe(callback: chatFunc, priority: number = 0) { - this.eventList.push({ callback: callback, priority: priority }); - this.eventList.sort((a, b) => b.priority - a.priority); - } - /** - * 发布聊天事件 - * @param {ChatSendBeforeEvent} t 聊天事件 - */ - private publish(t: ChatSendBeforeEvent) { - let Ope = undefined; - if (this.eventList) { - for (let event of this.eventList) { - Ope = event.callback(t); - if (Ope != undefined) break; - } - } - if (Ope === chatOpe.cancel) return true; - if (Ope === chatOpe.skipsend) return false; - return this.send(t); - } - /** - * 设置聊天处理函数(唯一) - * - * 当聊天没有被任一函数取消时,将会调用此函数发送聊天 - * - * 返回值:是否取消原版聊天发送 - */ - regsend(callback: (t: ChatSendBeforeEvent) => boolean) { - this.send = callback; - } -} - -export enum chatOpe { - /**捕获消息取消发送 */ - cancel, - /**捕获消息并原版发送 */ - skipsend, -} +// 聊天相关类型与 chatBusClass(含 chatOpe / chatFunc / chatEvents / ChatSendBeforeEventLike)。 +// chatBus 实例不在此导出——它是唯一的 beta-only 导出,由渠道入口(Event.entry.beta.ts)决定是否暴露 +export * from "./Event/chatBusClass"; /** * 订阅周期事件 @@ -190,6 +128,5 @@ export class ScriptEventBusClass { } export const intervalBus = new intervalBusClass(); -export const chatBus = new chatBusClass(); export const itemBus = new itemBase(); export const ScriptEventBus = new ScriptEventBusClass(); diff --git a/packages/core/src/Event/chatBus.ts b/packages/core/src/Event/chatBus.ts new file mode 100644 index 0000000..976da8b --- /dev/null +++ b/packages/core/src/Event/chatBus.ts @@ -0,0 +1,10 @@ +import { chatBusClass } from "./chatBusClass"; + +/** + * chatBus 实例:唯一的 beta-only 导出。 + * + * 实例本身是共享源码,但只有 beta 渠道的入口(entry.beta.ts / Event.entry.beta.ts)re-export 它, + * stable 渠道的入口不引用本模块 → stable 的 d.ts 没有 chatBus 导出。 + * 运行时 stable 的产物里本模块经 treeshake.moduleSideEffects 剔除(实例无需创建)。 + */ +export const chatBus = new chatBusClass(); diff --git a/packages/core/src/Event/chatBusClass.ts b/packages/core/src/Event/chatBusClass.ts new file mode 100644 index 0000000..27ff97e --- /dev/null +++ b/packages/core/src/Event/chatBusClass.ts @@ -0,0 +1,85 @@ +import { Player, world } from "@minecraft/server"; + +/** + * 聊天发送前事件的轻量结构类型。 + * + * `ChatSendBeforeEvent` 只存在于 beta 版 `@minecraft/server`,stable 版没有该事件, + * 因此这里用结构类型代替,避免在 stable 渠道下 import 不存在的命名导出导致类型检查失败。 + */ +export interface ChatSendBeforeEventLike { + cancel: boolean; + message: string; + sender: Player; +} + +//先不搞优先队列了,能用就行,反正只有注册的时候排序 +export type chatFunc = (t: ChatSendBeforeEventLike) => void | chatOpe; +export interface chatEvents { + priority: number; + callback: (t: ChatSendBeforeEventLike) => void | chatOpe; +} +/** + * 聊天订阅 + */ +export class chatBusClass { + private eventList: chatEvents[]; + private send: (t: ChatSendBeforeEventLike) => boolean; + constructor() { + this.eventList = []; + this.send = (t) => { + return false; + }; + // 仅 beta 版 @minecraft/server 提供 beforeEvents.chatSend(stable 类型里不存在该属性,故断言), + // 整段包在 __BETA__ 里,stable 构建连类定义都会死代码消除,产物里不含任何 chatSend 引用 + if (__BETA__) { + const beforeEvents = world.beforeEvents as unknown as { + chatSend: { subscribe(cb: (t: ChatSendBeforeEventLike) => void): void }; + }; + beforeEvents.chatSend.subscribe((t) => { + t.cancel = this.publish(t); + }); + } + } + /** + * 订阅聊天事件 + * + * 返回值:是否取消原版聊天发送 + */ + subscribe(callback: chatFunc, priority: number = 0) { + this.eventList.push({ callback: callback, priority: priority }); + this.eventList.sort((a, b) => b.priority - a.priority); + } + /** + * 发布聊天事件 + * @param {ChatSendBeforeEvent} t 聊天事件 + */ + private publish(t: ChatSendBeforeEventLike) { + let Ope = undefined; + if (this.eventList) { + for (let event of this.eventList) { + Ope = event.callback(t); + if (Ope != undefined) break; + } + } + if (Ope === chatOpe.cancel) return true; + if (Ope === chatOpe.skipsend) return false; + return this.send(t); + } + /** + * 设置聊天处理函数(唯一) + * + * 当聊天没有被任一函数取消时,将会调用此函数发送聊天 + * + * 返回值:是否取消原版聊天发送 + */ + regsend(callback: (t: ChatSendBeforeEventLike) => boolean) { + this.send = callback; + } +} + +export enum chatOpe { + /**捕获消息取消发送 */ + cancel, + /**捕获消息并原版发送 */ + skipsend, +} diff --git a/src/Form/commonForm/BodyInfoForm.ts b/packages/core/src/Form/commonForm/BodyInfoForm.ts similarity index 100% rename from src/Form/commonForm/BodyInfoForm.ts rename to packages/core/src/Form/commonForm/BodyInfoForm.ts diff --git a/src/Form/commonForm/ButtonForm.ts b/packages/core/src/Form/commonForm/ButtonForm.ts similarity index 100% rename from src/Form/commonForm/ButtonForm.ts rename to packages/core/src/Form/commonForm/ButtonForm.ts diff --git a/src/Form/commonForm/ConfigForm.ts b/packages/core/src/Form/commonForm/ConfigForm.ts similarity index 100% rename from src/Form/commonForm/ConfigForm.ts rename to packages/core/src/Form/commonForm/ConfigForm.ts diff --git a/src/Form/commonForm/InputForm.ts b/packages/core/src/Form/commonForm/InputForm.ts similarity index 100% rename from src/Form/commonForm/InputForm.ts rename to packages/core/src/Form/commonForm/InputForm.ts diff --git a/src/Form/commonForm/InputFormFields.ts b/packages/core/src/Form/commonForm/InputFormFields.ts similarity index 100% rename from src/Form/commonForm/InputFormFields.ts rename to packages/core/src/Form/commonForm/InputFormFields.ts diff --git a/src/Form/commonForm/MessageForm.ts b/packages/core/src/Form/commonForm/MessageForm.ts similarity index 100% rename from src/Form/commonForm/MessageForm.ts rename to packages/core/src/Form/commonForm/MessageForm.ts diff --git a/src/Form/commonForm/commonFormInterface.ts b/packages/core/src/Form/commonForm/commonFormInterface.ts similarity index 100% rename from src/Form/commonForm/commonFormInterface.ts rename to packages/core/src/Form/commonForm/commonFormInterface.ts diff --git a/src/Form/commonForm/main.ts b/packages/core/src/Form/commonForm/main.ts similarity index 100% rename from src/Form/commonForm/main.ts rename to packages/core/src/Form/commonForm/main.ts diff --git a/src/Form/commonForm/validators.ts b/packages/core/src/Form/commonForm/validators.ts similarity index 100% rename from src/Form/commonForm/validators.ts rename to packages/core/src/Form/commonForm/validators.ts diff --git a/src/Form/form.ts b/packages/core/src/Form/form.ts similarity index 100% rename from src/Form/form.ts rename to packages/core/src/Form/form.ts diff --git a/src/Form/formManager.ts b/packages/core/src/Form/formManager.ts similarity index 100% rename from src/Form/formManager.ts rename to packages/core/src/Form/formManager.ts diff --git a/src/Form/interface.ts b/packages/core/src/Form/interface.ts similarity index 100% rename from src/Form/interface.ts rename to packages/core/src/Form/interface.ts diff --git a/src/Form/lang.ts b/packages/core/src/Form/lang.ts similarity index 100% rename from src/Form/lang.ts rename to packages/core/src/Form/lang.ts diff --git a/src/Form/main.ts b/packages/core/src/Form/main.ts similarity index 100% rename from src/Form/main.ts rename to packages/core/src/Form/main.ts diff --git a/src/Form/stackManager.ts b/packages/core/src/Form/stackManager.ts similarity index 100% rename from src/Form/stackManager.ts rename to packages/core/src/Form/stackManager.ts diff --git a/src/System/ScriptCom.ts b/packages/core/src/System/ScriptCom.ts similarity index 100% rename from src/System/ScriptCom.ts rename to packages/core/src/System/ScriptCom.ts diff --git a/src/System/lang.ts b/packages/core/src/System/lang.ts similarity index 100% rename from src/System/lang.ts rename to packages/core/src/System/lang.ts diff --git a/src/System/sysinfo.ts b/packages/core/src/System/sysinfo.ts similarity index 100% rename from src/System/sysinfo.ts rename to packages/core/src/System/sysinfo.ts diff --git a/src/Translate/index.ts b/packages/core/src/Translate/index.ts similarity index 100% rename from src/Translate/index.ts rename to packages/core/src/Translate/index.ts diff --git a/src/Translate/interface.ts b/packages/core/src/Translate/interface.ts similarity index 100% rename from src/Translate/interface.ts rename to packages/core/src/Translate/interface.ts diff --git a/src/Translate/langCmd.ts b/packages/core/src/Translate/langCmd.ts similarity index 100% rename from src/Translate/langCmd.ts rename to packages/core/src/Translate/langCmd.ts diff --git a/src/Translate/languages.ts b/packages/core/src/Translate/languages.ts similarity index 100% rename from src/Translate/languages.ts rename to packages/core/src/Translate/languages.ts diff --git a/src/Translate/translator.ts b/packages/core/src/Translate/translator.ts similarity index 100% rename from src/Translate/translator.ts rename to packages/core/src/Translate/translator.ts diff --git a/src/Translate/ui.ts b/packages/core/src/Translate/ui.ts similarity index 100% rename from src/Translate/ui.ts rename to packages/core/src/Translate/ui.ts diff --git a/src/Translate/ui_lang.ts b/packages/core/src/Translate/ui_lang.ts similarity index 100% rename from src/Translate/ui_lang.ts rename to packages/core/src/Translate/ui_lang.ts diff --git a/src/constants.ts b/packages/core/src/constants.ts similarity index 100% rename from src/constants.ts rename to packages/core/src/constants.ts diff --git a/packages/core/src/entry.beta.ts b/packages/core/src/entry.beta.ts new file mode 100644 index 0000000..6539554 --- /dev/null +++ b/packages/core/src/entry.beta.ts @@ -0,0 +1,3 @@ +// beta 渠道主入口(`.`):共享 API + chatBus 实例 +export * from "./main"; +export * from "./Event/chatBus"; diff --git a/packages/core/src/entry.stable.ts b/packages/core/src/entry.stable.ts new file mode 100644 index 0000000..b9eae7e --- /dev/null +++ b/packages/core/src/entry.stable.ts @@ -0,0 +1,2 @@ +// stable 渠道主入口(`.`):仅共享 API,不导出 chatBus +export * from "./main"; diff --git a/src/func.ts b/packages/core/src/func.ts similarity index 100% rename from src/func.ts rename to packages/core/src/func.ts diff --git a/src/global.d.ts b/packages/core/src/global.d.ts similarity index 86% rename from src/global.d.ts rename to packages/core/src/global.d.ts index 478f08a..d60ba18 100644 --- a/src/global.d.ts +++ b/packages/core/src/global.d.ts @@ -1,3 +1,4 @@ // 构建时由 rolldown / vitest 通过 define 替换注入,这里仅声明类型供 tsc 与声明生成使用 +declare const __BETA__: boolean; declare const __SAPI_PRO_VERSION__: string; declare const __SAPI_PRO_VERSION_NUM__: number; diff --git a/src/main.ts b/packages/core/src/main.ts similarity index 100% rename from src/main.ts rename to packages/core/src/main.ts diff --git a/src/utils/chunkUtils.ts b/packages/core/src/utils/chunkUtils.ts similarity index 100% rename from src/utils/chunkUtils.ts rename to packages/core/src/utils/chunkUtils.ts diff --git a/src/utils/logger.ts b/packages/core/src/utils/logger.ts similarity index 100% rename from src/utils/logger.ts rename to packages/core/src/utils/logger.ts diff --git a/src/utils/main.ts b/packages/core/src/utils/main.ts similarity index 100% rename from src/utils/main.ts rename to packages/core/src/utils/main.ts diff --git a/src/utils/random.ts b/packages/core/src/utils/random.ts similarity index 100% rename from src/utils/random.ts rename to packages/core/src/utils/random.ts diff --git a/src/utils/vanila-data.ts b/packages/core/src/utils/vanila-data.ts similarity index 100% rename from src/utils/vanila-data.ts rename to packages/core/src/utils/vanila-data.ts diff --git a/src/utils/vector.ts b/packages/core/src/utils/vector.ts similarity index 100% rename from src/utils/vector.ts rename to packages/core/src/utils/vector.ts diff --git a/test/command/parser.test.ts b/packages/core/test/command/parser.test.ts similarity index 100% rename from test/command/parser.test.ts rename to packages/core/test/command/parser.test.ts diff --git a/test/form/inputForm.test.ts b/packages/core/test/form/inputForm.test.ts similarity index 100% rename from test/form/inputForm.test.ts rename to packages/core/test/form/inputForm.test.ts diff --git a/rolldown.config.ts b/rolldown.config.ts deleted file mode 100644 index 6cf7e07..0000000 --- a/rolldown.config.ts +++ /dev/null @@ -1,41 +0,0 @@ -import { defineConfig } from "rolldown"; -import { dts } from "rolldown-plugin-dts"; -import { libVersionNum, libVersionString } from "./tools/libVersion"; - -// package.json 的 exports 子路径根文件,作为显式入口防止 barrel 提升折叠 -const entryPoints = [ - "src/main.ts", - "src/Deferred/index.ts", - "src/Form/main.ts", - "src/Translate/index.ts", - "src/Event.ts", - "src/func.ts", - "src/constants.ts", - "src/utils/main.ts", - "src/Command/main.ts", - "src/DataBase/index.ts", -]; - -export default defineConfig({ - input: entryPoints, - output: { - dir: "scripts", - format: "esm", - preserveModules: true, - preserveModulesRoot: "src", - }, - external: (id) => id.startsWith("@minecraft/"), - // 构建时替换注入版本常量(来自 package.json,见 tools/libVersion.ts) - transform: { - define: { - __SAPI_PRO_VERSION__: JSON.stringify(libVersionString), - __SAPI_PRO_VERSION_NUM__: String(libVersionNum), - }, - }, - plugins: [ - dts({ - // 所有 src 模块都生成声明,保证子路径 exports 的 .d.ts 完整 - entry: ["src/**/*.ts", "!src/global.d.ts"], - }), - ], -}); diff --git a/src/Command/main.ts b/src/Command/main.ts deleted file mode 100644 index e28611f..0000000 --- a/src/Command/main.ts +++ /dev/null @@ -1,20 +0,0 @@ -import { CommandHelp } from "./help"; -import { CommandManager } from "./manager"; -import { NativeCommandParser } from "./parser/nativeParser"; -import { CommandParser } from "./parser/parser"; - -//初始化 -function initCommandSystem() { - const parser = new CommandParser(); - const nativeParser = new NativeCommandParser(); - const pcommand = new CommandManager(parser, nativeParser); - const help = new CommandHelp(pcommand, parser); - parser.init(pcommand); - pcommand.init(help); - return pcommand; -} - -export const pcommand = initCommandSystem(); -export { CommandManager } from "./manager"; -export * from "./commandClass"; -export * from "./interface"; diff --git a/tools/build.ts b/tools/build.ts index be45503..6652c72 100644 --- a/tools/build.ts +++ b/tools/build.ts @@ -58,8 +58,8 @@ async function main() { await recreateDir(buildDir); const zipTasks: Array<[string, string]> = [ - ["src", "SAPI-Pro_ts.zip"], - ["scripts", "SAPI-Pro_js.zip"], + ["packages/core/src", "SAPI-Pro_ts.zip"], + ["variants/beta/dist", "SAPI-Pro_js.zip"], ]; for (const [sourceDir, zipName] of zipTasks) { diff --git a/tools/libVersion.ts b/tools/libVersion.ts index 717ca86..aefb84c 100644 --- a/tools/libVersion.ts +++ b/tools/libVersion.ts @@ -1,17 +1,29 @@ import { readFileSync } from "node:fs"; -import { join } from "node:path"; -// 从 package.json 读取版本,供 rolldown 构建与 vitest 测试通过 define 注入 -const { version } = JSON.parse( - readFileSync(join(process.cwd(), "package.json"), "utf8") -) as { version: string }; +export interface LibVersion { + /** 显示版本:仅 major.minor.patch(beta/stable 由 isBeta/渠道决定) */ + libVersionString: string; + /** 数字版本:用于主机选举,编码与旧版一致(major + minor/10 + patch/100) */ + libVersionNum: number; +} -// 去掉预发布后缀(如 -beta.1),取 major.minor.patch -const [core] = version.split("-"); -const [major = 0, minor = 0, patch = 0] = core.split(".").map(Number); +/** + * 从指定 package.json 读取版本,供 rolldown / vitest 通过 define 注入。 + * + * beta/stable 两个 variant 各自有自己的 package.json 与版本号, + * 各自构建时把本 variant 的版本注入为编译常量。 + */ +export function getLibVersion(packageJsonPath: string): LibVersion { + const { version } = JSON.parse(readFileSync(packageJsonPath, "utf8")) as { + version: string; + }; -/** 显示版本:仅 major.minor.patch(beta/stable 由 isBeta 拼接后缀) */ -export const libVersionString = `${major}.${minor}.${patch}`; + // 去掉预发布后缀(如 -beta.1),取 major.minor.patch + const [core] = version.split("-"); + const [major = 0, minor = 0, patch = 0] = core.split(".").map(Number); -/** 数字版本:用于主机选举,编码与旧版一致(major + minor/10 + patch/100) */ -export const libVersionNum = (major * 100 + minor * 10 + patch) / 100; + return { + libVersionString: `${major}.${minor}.${patch}`, + libVersionNum: (major * 100 + minor * 10 + patch) / 100, + }; +} diff --git a/tsconfig.base.json b/tsconfig.base.json new file mode 100644 index 0000000..98e446a --- /dev/null +++ b/tsconfig.base.json @@ -0,0 +1,14 @@ +{ + "compilerOptions": { + "target": "es2023", + "moduleResolution": "bundler", + "module": "esnext", + "types": ["node"], + "noEmit": true, + "forceConsistentCasingInFileNames": true, + "preserveConstEnums": true, + "strict": true, + "noImplicitAny": true, + "allowJs": true + } +} diff --git a/tsconfig.beta.json b/tsconfig.beta.json new file mode 100644 index 0000000..a0b8adf --- /dev/null +++ b/tsconfig.beta.json @@ -0,0 +1,17 @@ +{ + "extends": "./tsconfig.base.json", + "compilerOptions": { + // 本文件在仓库根,paths 相对本文件解析;@minecraft/* 重定向到本渠道安装的类型。 + // dts 插件的输出 rootDir 在各自 rolldown.config.ts 里通过 compilerOptions.rootDir 显式指定(对齐 preserveModulesRoot) + "paths": { + "@/*": ["./packages/core/src/*"], + "@minecraft/server": [ + "./variants/beta/node_modules/@minecraft/server/index.d.ts" + ], + "@minecraft/server-ui": [ + "./variants/beta/node_modules/@minecraft/server-ui/index.d.ts" + ] + } + }, + "include": ["./packages/core/src"] +} diff --git a/tsconfig.json b/tsconfig.json index c94715a..012b387 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,19 +1,14 @@ { + "extends": "./tsconfig.base.json", "compilerOptions": { - "target": "es2023", - "moduleResolution": "bundler", - "module": "esnext", - "types": ["node"], - "noEmit": true, - "forceConsistentCasingInFileNames": true, - "preserveConstEnums": true, - "strict": true, - "noImplicitAny": true, - "allowJs": true, + // TS7 已移除 baseUrl,paths 相对本 tsconfig 所在目录解析 + // 根目录不再装 @minecraft/*:编辑器/测试类型走 variants/beta 安装的 beta 版类型(与 __BETA__=true 一致) "paths": { - "@/*": ["./src/*"], - "@test/*": ["./test/*"] + "@/*": ["./packages/core/src/*"], + "@test/*": ["./packages/core/test/*"], + "@minecraft/server": ["./variants/beta/node_modules/@minecraft/server/index.d.ts"], + "@minecraft/server-ui": ["./variants/beta/node_modules/@minecraft/server-ui/index.d.ts"] } }, - "include": ["./src", "./test"] + "include": ["./packages/core/src", "./packages/core/test"] } diff --git a/tsconfig.stable.json b/tsconfig.stable.json new file mode 100644 index 0000000..6f5ff50 --- /dev/null +++ b/tsconfig.stable.json @@ -0,0 +1,17 @@ +{ + "extends": "./tsconfig.base.json", + "compilerOptions": { + // 本文件在仓库根,paths 相对本文件解析;@minecraft/* 重定向到本渠道安装的类型。 + // dts 插件的输出 rootDir 在各自 rolldown.config.ts 里通过 compilerOptions.rootDir 显式指定(对齐 preserveModulesRoot) + "paths": { + "@/*": ["./packages/core/src/*"], + "@minecraft/server": [ + "./variants/stable/node_modules/@minecraft/server/index.d.ts" + ], + "@minecraft/server-ui": [ + "./variants/stable/node_modules/@minecraft/server-ui/index.d.ts" + ] + } + }, + "include": ["./packages/core/src"] +} diff --git a/variants/beta/package-lock.json b/variants/beta/package-lock.json new file mode 100644 index 0000000..f01baaf --- /dev/null +++ b/variants/beta/package-lock.json @@ -0,0 +1,59 @@ +{ + "name": "sapi-pro", + "version": "0.5.0-beta.1", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "sapi-pro", + "version": "0.5.0-beta.1", + "license": "MIT", + "devDependencies": { + "@minecraft/common": "1.2.0", + "@minecraft/server": "2.10.0-beta.1.26.40-stable", + "@minecraft/server-ui": "2.2.0-beta.1.26.40-stable" + }, + "peerDependencies": { + "@minecraft/server": "^2.10.0-beta.1.26.40-stable", + "@minecraft/server-ui": "^2.2.0-beta.1.26.40-stable", + "@minecraft/vanilla-data": ">=1.26.0" + } + }, + "node_modules/@minecraft/common": { + "version": "1.2.0", + "resolved": "https://registry.npmmirror.com/@minecraft/common/-/common-1.2.0.tgz", + "integrity": "sha512-JdmEq4P3Z/FtoBzhLijFgMSVFnFRrUoLwY8DHHrgtFo0mfLTOLTB1RErYjLMsA6b7BGVNxkX/pfFRiH7QZ0XwQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@minecraft/server": { + "version": "2.10.0-beta.1.26.40-stable", + "resolved": "https://registry.npmmirror.com/@minecraft/server/-/server-2.10.0-beta.1.26.40-stable.tgz", + "integrity": "sha512-PygRGiom/LRXV/fxcZ0ygCzCzF8pRp+PoqnVX+saazdOMXUvu940fZZjXCaTdjvasLp8tN4i3EgJV1aTxidKAQ==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "@minecraft/common": "^1.2.0", + "@minecraft/vanilla-data": ">=1.20.70" + } + }, + "node_modules/@minecraft/server-ui": { + "version": "2.2.0-beta.1.26.40-stable", + "resolved": "https://registry.npmmirror.com/@minecraft/server-ui/-/server-ui-2.2.0-beta.1.26.40-stable.tgz", + "integrity": "sha512-Ab/k5lYMktAjVttv3u//SCCc/AUmKnzJYA+ZvvAoKxQ1hEDwLC2OhGF+YF/S/mkSX6oPK8hD6I8bJBEq2CyCOw==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "@minecraft/common": "^1.0.0", + "@minecraft/server": "^2.0.0 || ^2.10.0-beta.1.26.40-stable" + } + }, + "node_modules/@minecraft/vanilla-data": { + "version": "1.26.40", + "resolved": "https://registry.npmmirror.com/@minecraft/vanilla-data/-/vanilla-data-1.26.40.tgz", + "integrity": "sha512-6CKqzKXmTaQOKofuTPiJVE5SqFXs8nRTHDujvL77rT/9cRArsdzagRcPFBcbhL8MnGjsINXxkdqFnjUqhZjxsA==", + "license": "MIT", + "peer": true + } + } +} diff --git a/variants/beta/package.json b/variants/beta/package.json new file mode 100644 index 0000000..00b214a --- /dev/null +++ b/variants/beta/package.json @@ -0,0 +1,55 @@ +{ + "name": "sapi-pro", + "version": "0.4.2", + "description": "A practical library for MCBE ScriptAPI (beta channel, requires ScriptAPI beta)", + "main": "dist/entry.beta.js", + "types": "dist/entry.beta.d.ts", + "type": "module", + "author": { + "name": "XiaoYangx666", + "email": "2408807389@qq.com" + }, + "license": "MIT", + "repository": { + "type": "git", + "url": "https://github.com/XiaoYangx666/SAPI-Pro.git" + }, + "peerDependencies": { + "@minecraft/server": "^2.10.0-beta.1.26.40-stable", + "@minecraft/server-ui": "^2.2.0-beta.1.26.40-stable", + "@minecraft/vanilla-data": ">=1.26.0" + }, + "devDependencies": { + "@minecraft/common": "1.2.0", + "@minecraft/server": "2.10.0-beta.1.26.40-stable", + "@minecraft/server-ui": "2.2.0-beta.1.26.40-stable" + }, + "scripts": { + "build": "rolldown -c rolldown.config.ts", + "typecheck": "tsc -p ../tsconfig.beta.json --noEmit", + "pack": "npm run typecheck && npm run build && npm pack" + }, + "files": [ + "dist" + ], + "exports": { + ".": "./dist/entry.beta.js", + "./Deferred": "./dist/Deferred/index.js", + "./Form": "./dist/Form/main.js", + "./Translate": "./dist/Translate/index.js", + "./Event": "./dist/Event.entry.beta.js", + "./func": "./dist/func.js", + "./constants": "./dist/constants.js", + "./utils": "./dist/utils/main.js", + "./Command": "./dist/Command/main.js", + "./DataBase": "./dist/DataBase/index.js" + }, + "keywords": [ + "minecraft", + "bedrock", + "bedrock-edition", + "ScriptApi", + "library" + ], + "sideEffects": false +} diff --git a/variants/beta/rolldown.config.ts b/variants/beta/rolldown.config.ts new file mode 100644 index 0000000..f3e76b7 --- /dev/null +++ b/variants/beta/rolldown.config.ts @@ -0,0 +1,68 @@ +import { defineConfig } from "rolldown"; +import { dts } from "rolldown-plugin-dts"; +import { fileURLToPath } from "node:url"; +import path from "node:path"; +import { getLibVersion } from "../../tools/libVersion"; + +const VARIANT = path.dirname(fileURLToPath(import.meta.url)); +const ROOT = path.resolve(VARIANT, "../.."); +const CORE = path.join(ROOT, "packages/core/src"); +// dts 插件按 process.cwd() 相对路径匹配 entry glob,需与调用时的 cwd 对齐 +const CORE_REL = path.relative(process.cwd(), CORE); +const { libVersionString, libVersionNum } = getLibVersion(path.join(VARIANT, "package.json")); + +// 与 package.json exports 的 10 个子路径根文件一一对应(显式入口防止 barrel 提升折叠)。 +// `.` 与 `./Event` 指向本渠道入口(entry.beta.ts / Event.entry.beta.ts),其余指向共享模块 +const entryPoints = [ + "entry.beta.ts", + "Deferred/index.ts", + "Form/main.ts", + "Translate/index.ts", + "Event.entry.beta.ts", + "func.ts", + "constants.ts", + "utils/main.ts", + "Command/main.ts", + "DataBase/index.ts", +].map((f) => path.join(CORE, f)); + +export default defineConfig({ + input: entryPoints, + output: { + dir: path.join(VARIANT, "dist"), + format: "esm", + preserveModules: true, + // 全部源码(含渠道入口)都在 packages/core/src,dist 直接镜像成 dist/main.js、dist/Event.js 等 + preserveModulesRoot: CORE, + }, + external: (id) => id.startsWith("@minecraft/"), + resolve: { + alias: { + "@": CORE, + }, + }, + tsconfig: path.join(ROOT, "tsconfig.beta.json"), + // 构建期条件编译:__BETA__ 注入为字面量 true,死代码消除保留全功能 + transform: { + define: { + __BETA__: "true", + __SAPI_PRO_VERSION__: JSON.stringify(libVersionString), + __SAPI_PRO_VERSION_NUM__: String(libVersionNum), + }, + }, + plugins: [ + dts({ + // 用本渠道 tsconfig 解析 @minecraft 版本与别名 + tsconfig: path.join(ROOT, "tsconfig.beta.json"), + // rootDir 对齐 output.preserveModulesRoot,保证 .d.ts 与 .js 输出路径一致(dist/main.d.ts 等) + compilerOptions: { rootDir: CORE }, + // 共享源码 + 本渠道入口生成声明;排除 stable 渠道入口(不在 beta 图内) + entry: [ + `${CORE_REL}/**/*.ts`, + `!${CORE_REL}/global.d.ts`, + `!${CORE_REL}/entry.stable.ts`, + `!${CORE_REL}/Event.entry.stable.ts`, + ], + }), + ], +}); diff --git a/variants/stable/package-lock.json b/variants/stable/package-lock.json new file mode 100644 index 0000000..8e785b4 --- /dev/null +++ b/variants/stable/package-lock.json @@ -0,0 +1,59 @@ +{ + "name": "sapi-pro", + "version": "0.4.3", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "sapi-pro", + "version": "0.4.3", + "license": "MIT", + "devDependencies": { + "@minecraft/common": "1.2.0", + "@minecraft/server": "2.8.0", + "@minecraft/server-ui": "2.1.0" + }, + "peerDependencies": { + "@minecraft/server": "^2.8.0", + "@minecraft/server-ui": "^2.1.0", + "@minecraft/vanilla-data": ">=1.26.0" + } + }, + "node_modules/@minecraft/common": { + "version": "1.2.0", + "resolved": "https://registry.npmmirror.com/@minecraft/common/-/common-1.2.0.tgz", + "integrity": "sha512-JdmEq4P3Z/FtoBzhLijFgMSVFnFRrUoLwY8DHHrgtFo0mfLTOLTB1RErYjLMsA6b7BGVNxkX/pfFRiH7QZ0XwQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@minecraft/server": { + "version": "2.8.0", + "resolved": "https://registry.npmmirror.com/@minecraft/server/-/server-2.8.0.tgz", + "integrity": "sha512-5VPlToP3IihUWrLHQJdNPSq++vPYnB+IZUVdO6kJ/VWVE29pN230f9SiCD28XU+Ujfh/EdjU3anktXG77pjWLA==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "@minecraft/common": "^1.2.0", + "@minecraft/vanilla-data": ">=1.20.70" + } + }, + "node_modules/@minecraft/server-ui": { + "version": "2.1.0", + "resolved": "https://registry.npmmirror.com/@minecraft/server-ui/-/server-ui-2.1.0.tgz", + "integrity": "sha512-7zXyqK6HI62aH0RlfObLitBc7EldpoAH3AeC8JWOaI6CCNoCi2DG2U78ELdq+NrUIjvCE87Bix/I+hgXsQ5AdA==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "@minecraft/common": "^1.0.0", + "@minecraft/server": "^2.0.0" + } + }, + "node_modules/@minecraft/vanilla-data": { + "version": "1.26.40", + "resolved": "https://registry.npmmirror.com/@minecraft/vanilla-data/-/vanilla-data-1.26.40.tgz", + "integrity": "sha512-6CKqzKXmTaQOKofuTPiJVE5SqFXs8nRTHDujvL77rT/9cRArsdzagRcPFBcbhL8MnGjsINXxkdqFnjUqhZjxsA==", + "license": "MIT", + "peer": true + } + } +} diff --git a/variants/stable/package.json b/variants/stable/package.json new file mode 100644 index 0000000..09ec715 --- /dev/null +++ b/variants/stable/package.json @@ -0,0 +1,55 @@ +{ + "name": "sapi-pro", + "version": "0.4.2-stable", + "description": "A practical library for MCBE ScriptAPI (stable channel, uses stable ScriptAPI)", + "main": "dist/entry.stable.js", + "types": "dist/entry.stable.d.ts", + "type": "module", + "author": { + "name": "XiaoYangx666", + "email": "2408807389@qq.com" + }, + "license": "MIT", + "repository": { + "type": "git", + "url": "https://github.com/XiaoYangx666/SAPI-Pro.git" + }, + "peerDependencies": { + "@minecraft/server": "^2.8.0", + "@minecraft/server-ui": "^2.1.0", + "@minecraft/vanilla-data": ">=1.26.0" + }, + "devDependencies": { + "@minecraft/common": "1.2.0", + "@minecraft/server": "2.8.0", + "@minecraft/server-ui": "2.1.0" + }, + "scripts": { + "build": "rolldown -c rolldown.config.ts", + "typecheck": "tsc -p ../tsconfig.stable.json --noEmit", + "pack": "npm run typecheck && npm run build && npm pack" + }, + "files": [ + "dist" + ], + "exports": { + ".": "./dist/entry.stable.js", + "./Deferred": "./dist/Deferred/index.js", + "./Form": "./dist/Form/main.js", + "./Translate": "./dist/Translate/index.js", + "./Event": "./dist/Event.entry.stable.js", + "./func": "./dist/func.js", + "./constants": "./dist/constants.js", + "./utils": "./dist/utils/main.js", + "./Command": "./dist/Command/main.js", + "./DataBase": "./dist/DataBase/index.js" + }, + "keywords": [ + "minecraft", + "bedrock", + "bedrock-edition", + "ScriptApi", + "library" + ], + "sideEffects": false +} diff --git a/variants/stable/rolldown.config.ts b/variants/stable/rolldown.config.ts new file mode 100644 index 0000000..230b3cd --- /dev/null +++ b/variants/stable/rolldown.config.ts @@ -0,0 +1,82 @@ +import { defineConfig } from "rolldown"; +import { dts } from "rolldown-plugin-dts"; +import { fileURLToPath } from "node:url"; +import path from "node:path"; +import { getLibVersion } from "../../tools/libVersion"; + +const VARIANT = path.dirname(fileURLToPath(import.meta.url)); +const ROOT = path.resolve(VARIANT, "../.."); +const CORE = path.join(ROOT, "packages/core/src"); +// dts 插件按 process.cwd() 相对路径匹配 entry glob,需与调用时的 cwd 对齐 +const CORE_REL = path.relative(process.cwd(), CORE); +const { libVersionString, libVersionNum } = getLibVersion(path.join(VARIANT, "package.json")); + +// 与 package.json exports 的 10 个子路径根文件一一对应(显式入口防止 barrel 提升折叠)。 +// `.` 与 `./Event` 指向本渠道入口(entry.stable.ts / Event.entry.stable.ts),其余指向共享模块 +const entryPoints = [ + "entry.stable.ts", + "Deferred/index.ts", + "Form/main.ts", + "Translate/index.ts", + "Event.entry.stable.ts", + "func.ts", + "constants.ts", + "utils/main.ts", + "Command/main.ts", + "DataBase/index.ts", +].map((f) => path.join(CORE, f)); + +export default defineConfig({ + input: entryPoints, + output: { + dir: path.join(VARIANT, "dist"), + format: "esm", + preserveModules: true, + // 全部源码(含渠道入口)都在 packages/core/src,dist 直接镜像成 dist/main.js、dist/Event.js 等 + preserveModulesRoot: CORE, + }, + external: (id) => id.startsWith("@minecraft/"), + resolve: { + alias: { + "@": CORE, + }, + }, + tsconfig: path.join(ROOT, "tsconfig.stable.json"), + // 构建期条件编译:__BETA__ 注入为字面量 false,chatBus/模拟命令等 beta 专属代码被死代码消除 + transform: { + define: { + __BETA__: "false", + __SAPI_PRO_VERSION__: JSON.stringify(libVersionString), + __SAPI_PRO_VERSION_NUM__: String(libVersionNum), + }, + }, + // stable 渠道把模拟命令子系统与 chatBus 实例视为无副作用模块: + // main.ts 里对它们的 import 在 __BETA__=false 下成为未使用 import,整体丢弃,相关文件不进产物 + treeshake: { + moduleSideEffects: [ + { test: /Event[\/\\]chatBus\.ts$/, sideEffects: false }, + { test: /Command[\/\\]parser[\/\\]parser\.ts$/, sideEffects: false }, + { test: /Command[\/\\]parser[\/\\]func\.ts$/, sideEffects: false }, + { test: /Command[\/\\]help\.ts$/, sideEffects: false }, + ], + }, + plugins: [ + dts({ + // 用本渠道 tsconfig 解析 @minecraft 版本与别名 + tsconfig: path.join(ROOT, "tsconfig.stable.json"), + // rootDir 对齐 output.preserveModulesRoot,保证 .d.ts 与 .js 输出路径一致(dist/main.d.ts 等) + compilerOptions: { rootDir: CORE }, + // 共享源码 + 本渠道入口生成声明;排除 beta 渠道入口与 stable 剔除的模块 + entry: [ + `${CORE_REL}/**/*.ts`, + `!${CORE_REL}/global.d.ts`, + `!${CORE_REL}/entry.beta.ts`, + `!${CORE_REL}/Event.entry.beta.ts`, + `!${CORE_REL}/Event/chatBus.ts`, + `!${CORE_REL}/Command/parser/parser.ts`, + `!${CORE_REL}/Command/parser/func.ts`, + `!${CORE_REL}/Command/help.ts`, + ], + }), + ], +}); diff --git a/vitest.config.ts b/vitest.config.ts index bf75359..a120cd6 100644 --- a/vitest.config.ts +++ b/vitest.config.ts @@ -1,21 +1,26 @@ import { defineConfig } from "vitest/config"; -import path from "path"; -import { libVersionNum, libVersionString } from "./tools/libVersion"; +import path from "node:path"; +import { getLibVersion } from "./tools/libVersion"; + +// 测试针对完整的 beta 版源码(chatBus/模拟命令等全功能),版本常量与 beta variant 保持一致 +const { libVersionString, libVersionNum } = getLibVersion( + path.resolve(__dirname, "variants/beta/package.json") +); export default defineConfig({ - // 与 rolldown.config.ts 相同的版本注入,保证测试环境可解析 + // 与 rolldown 各 variant 的 transform.define 保持一致的版本注入,保证测试环境可解析 define: { + __BETA__: "true", __SAPI_PRO_VERSION__: JSON.stringify(libVersionString), __SAPI_PRO_VERSION_NUM__: String(libVersionNum), }, resolve: { alias: { - "@": path.resolve(__dirname, "src"), - "@test": path.resolve(__dirname, "test"), + "@": path.resolve(__dirname, "packages/core/src"), + "@test": path.resolve(__dirname, "packages/core/test"), }, }, test: { - include: ["test/**/*.test.ts"], - setupFiles: [], + include: ["packages/core/test/**/*.test.ts"], }, });