diff --git a/bds-tools/package.json b/bds-tools/package.json index 11470410..9ea3ea45 100644 --- a/bds-tools/package.json +++ b/bds-tools/package.json @@ -43,7 +43,7 @@ "scripts": { "build": "node ../scripts/esbuild-transpile.mjs --dts", "dev": "tsx src/bds-manager.ts", - "typecheck": "node ../tools/tsc7.mjs --noEmit", + "typecheck": "tsc7 --noEmit", "clean": "node -e \"require('node:fs').rmSync('dist',{recursive:true,force:true})\"", "test": "node --test is-main.test.mjs pack-manager-lifecycle.test.mjs server-properties.test.mjs world-packs.test.mjs zipx.test.mjs", "update": "node dist/check-update.js", diff --git a/db-server/package.json b/db-server/package.json index 914c0527..c4a1d227 100644 --- a/db-server/package.json +++ b/db-server/package.json @@ -31,7 +31,7 @@ "start": "node dist/index.js", "dev": "tsx src/index.ts", "build": "node ../scripts/esbuild-transpile.mjs --dts", - "typecheck": "node ../tools/tsc7.mjs --noEmit", + "typecheck": "tsc7 --noEmit", "clean": "node -e \"require('node:fs').rmSync('dist',{recursive:true,force:true})\"", "test": "npm run build && node --test dist/*.test.js", "format": "prettier --write \"src/**/*.{ts,tsx,js,json}\"", diff --git a/modules/packages/afk/package.json b/modules/packages/afk/package.json index f6fcb900..664f931e 100644 --- a/modules/packages/afk/package.json +++ b/modules/packages/afk/package.json @@ -6,7 +6,7 @@ "description": "SAPI module: AFK - 玩家挂机检测与状态管理。", "main": "sapi/src/index.ts", "scripts": { - "typecheck": "node ../../../tools/tsc7.mjs --noEmit -p sapi/tsconfig.json" + "typecheck": "tsc7 --noEmit -p sapi/tsconfig.json" }, "dependencies": { "@sfmc-bds/sdk": "*" diff --git a/modules/sdk/@sfmc-eslint-plugin/package.json b/modules/sdk/@sfmc-eslint-plugin/package.json index 20ed629b..9cead542 100644 --- a/modules/sdk/@sfmc-eslint-plugin/package.json +++ b/modules/sdk/@sfmc-eslint-plugin/package.json @@ -19,8 +19,8 @@ "README.md" ], "scripts": { - "build": "node ../../../tools/tsc7.mjs -p tsconfig.json", - "typecheck": "node ../../../tools/tsc7.mjs --noEmit -p tsconfig.json", + "build": "tsc7 -p tsconfig.json", + "typecheck": "tsc7 --noEmit -p tsconfig.json", "test": "npm run build && node --test dist/**/*.test.js", "prepublishOnly": "npm run build" }, diff --git a/modules/sdk/@sfmc-sdk/build.mjs b/modules/sdk/@sfmc-sdk/build.mjs index 48314fea..26ab274b 100644 --- a/modules/sdk/@sfmc-sdk/build.mjs +++ b/modules/sdk/@sfmc-sdk/build.mjs @@ -23,9 +23,9 @@ * 2) tsc 发 .d.ts → dist/types//index.d.ts */ import { build } from "esbuild"; -import { execSync } from "node:child_process"; import fs from "node:fs"; import path from "node:path"; +import { runTsc7 } from "../../../tools/tsc7.mjs"; const SUBPATHS = [ { sub: "contracts", platform: "neutral" }, @@ -74,9 +74,10 @@ for (const { sub, platform } of SUBPATHS) { }); } -// 2) .d.ts — tsc --emitDeclarationOnly 产 dist/types -console.log("[sdk] emitting .d.ts via tsc..."); -execSync("npx tsc -p tsconfig.types.json", { stdio: "inherit" }); +// 2) .d.ts — 经 tsc7(TS7 native)产 dist/types +console.log("[sdk] emitting .d.ts via tsc7..."); +const dtsCode = runTsc7(["-p", "tsconfig.types.json"]); +if (dtsCode !== 0) process.exit(dtsCode); console.log("@sfmc-bds/sdk build done:", SUBPATHS.length, "subpaths"); diff --git a/modules/sdk/@sfmc-sdk/package.json b/modules/sdk/@sfmc-sdk/package.json index ab318470..c47dfd9f 100644 --- a/modules/sdk/@sfmc-sdk/package.json +++ b/modules/sdk/@sfmc-sdk/package.json @@ -99,8 +99,8 @@ "scripts": { "build": "node build.mjs", "build:js": "node build.mjs", - "build:types": "node ../../../tools/tsc7.mjs -p tsconfig.types.json", - "typecheck": "node ../../../tools/tsc7.mjs --noEmit -p tsconfig.types.json", + "build:types": "tsc7 -p tsconfig.types.json", + "typecheck": "tsc7 --noEmit -p tsconfig.types.json", "clean": "node -e \"require('node:fs').rmSync('dist',{recursive:true,force:true})\"", "prepublishOnly": "npm run clean && npm run build:types && node build.mjs" }, diff --git a/package.json b/package.json index 2760442d..cbfcf570 100644 --- a/package.json +++ b/package.json @@ -50,7 +50,7 @@ "check-ootb": "node tools/check-ootb.mjs", "check-minecraft-versions": "node tools/check-minecraft-versions.mjs", "smoke-modules": "node tools/smoke-modules.mjs", - "typecheck": "node ./tools/tsc7.mjs --noEmit -p sfmc/tsconfig.json && node ./tools/tsc7.mjs --noEmit -p db-server/tsconfig.json && node ./tools/tsc7.mjs --noEmit -p bds-tools/tsconfig.json && node ./tools/tsc7.mjs --noEmit -p qq-bridge/tsconfig.json && node ./tools/tsc7.mjs --noEmit -p modules/sdk/@sfmc-sdk/tsconfig.types.json && node ./tools/tsc7.mjs --noEmit -p modules/sdk/@sfmc-eslint-plugin/tsconfig.json && node ./tools/tsc7.mjs --noEmit -p remote-controller/tsconfig.json", + "typecheck": "npm run typecheck --workspaces --if-present", "lint": "npm run eslint-plugin:build && eslint .", "bundle": "node build-sea.mjs", "sea": "node --build-sea sea-config.json" diff --git a/qq-bridge/package.json b/qq-bridge/package.json index 58f732f9..a462ae4e 100644 --- a/qq-bridge/package.json +++ b/qq-bridge/package.json @@ -31,7 +31,7 @@ "start": "node dist/index.js", "dev": "tsx src/index.ts", "build": "node ../scripts/esbuild-transpile.mjs", - "typecheck": "node ../tools/tsc7.mjs --noEmit", + "typecheck": "tsc7 --noEmit", "clean": "node -e \"require('node:fs').rmSync('dist',{recursive:true,force:true})\"", "format": "prettier --write \"src/**/*.{ts,tsx,js,json}\"", "prepublishOnly": "npm run build" diff --git a/remote-controller/package.json b/remote-controller/package.json index 33932ee8..45d350cb 100644 --- a/remote-controller/package.json +++ b/remote-controller/package.json @@ -5,7 +5,7 @@ "type": "module", "scripts": { "build": "node ../scripts/esbuild-transpile.mjs", - "typecheck": "node ../tools/tsc7.mjs --noEmit", + "typecheck": "tsc7 --noEmit", "start": "node dist/index.js" }, "dependencies": { diff --git a/scripts/esbuild-transpile.mjs b/scripts/esbuild-transpile.mjs index 26dd910e..4c87d254 100644 --- a/scripts/esbuild-transpile.mjs +++ b/scripts/esbuild-transpile.mjs @@ -10,9 +10,9 @@ */ import { build } from "esbuild"; -import { execSync } from "node:child_process"; import fs from "node:fs"; import path from "node:path"; +import { runTsc7 } from "../tools/tsc7.mjs"; const emitDts = process.argv.includes("--dts"); const srcDir = path.resolve("src"); @@ -60,8 +60,13 @@ await build({ console.log(`[esbuild-transpile] emitted ${entryPoints.length} files → dist/`); if (emitDts) { - console.log("[esbuild-transpile] emitting .d.ts via tsc --emitDeclarationOnly..."); - execSync("npx tsc -p tsconfig.json --emitDeclarationOnly --declaration --declarationMap", { - stdio: "inherit", - }); + console.log("[esbuild-transpile] emitting .d.ts via tsc7 --emitDeclarationOnly..."); + const code = runTsc7([ + "-p", + "tsconfig.json", + "--emitDeclarationOnly", + "--declaration", + "--declarationMap", + ]); + if (code !== 0) process.exit(code); } diff --git a/sfmc/package.json b/sfmc/package.json index 424e650a..dca8621b 100644 --- a/sfmc/package.json +++ b/sfmc/package.json @@ -44,7 +44,7 @@ "scripts": { "start": "node ./dist/main.js", "build": "node ../scripts/esbuild-transpile.mjs --dts", - "typecheck": "node ../tools/tsc7.mjs --noEmit -p tsconfig.json", + "typecheck": "tsc7 --noEmit -p tsconfig.json", "dev": "tsx src/main.ts", "prepublishOnly": "npm run build" }, diff --git a/tools/new-module.mjs b/tools/new-module.mjs old mode 100644 new mode 100755 index 61ce0026..ad6963d3 --- a/tools/new-module.mjs +++ b/tools/new-module.mjs @@ -66,7 +66,7 @@ function buildPackageJson(folderId) { description: `SAPI module: ${folderId}`, main: "sapi/src/index.ts", scripts: { - typecheck: "tsc --noEmit -p sapi/tsconfig.json", + typecheck: "tsc7 --noEmit -p sapi/tsconfig.json", }, dependencies: { "@sfmc-bds/sdk": "^0.1.0", diff --git a/tools/package.json b/tools/package.json index 68d50230..b69c1eba 100644 --- a/tools/package.json +++ b/tools/package.json @@ -28,7 +28,8 @@ "sfmc-fetch-module": "./fetch-module.mjs", "sfmc-new-module": "./new-module.mjs", "sfmc-smoke-modules": "./smoke-modules.mjs", - "sfmc-sim-new-user": "./sim-new-user.mjs" + "sfmc-sim-new-user": "./sim-new-user.mjs", + "tsc7": "./tsc7.mjs" }, "files": [ "*.mjs", diff --git a/tools/smoke-remote-controller.mjs b/tools/smoke-remote-controller.mjs index 14921ecc..6690c0c8 100644 --- a/tools/smoke-remote-controller.mjs +++ b/tools/smoke-remote-controller.mjs @@ -19,7 +19,7 @@ const DIST = path.join(ROOT, "remote-controller", "dist", "index.js"); const ENTRY = path.join(ROOT, "tools", "smoke-remote-controller-agent.mjs"); if (!fs.existsSync(DIST)) { - console.error(`FAIL: missing build artifact ${DIST} (run: cd remote-controller && npx tsc)`); + console.error(`FAIL: missing build artifact ${DIST} (run: npm run build -w remote-controller)`); process.exit(1); } diff --git a/tools/tsc7.mjs b/tools/tsc7.mjs old mode 100644 new mode 100755 index 9cd19589..e55fb798 --- a/tools/tsc7.mjs +++ b/tools/tsc7.mjs @@ -1,17 +1,64 @@ #!/usr/bin/env node /** - * 调用 TypeScript 7 原生 tsc。 - * 双轨安装下 `typescript` 解析为 @typescript/typescript6(ESLint API), - * 其依赖 @typescript/old 会占用 node_modules/.bin/tsc,故 typecheck/emit 需显式走本入口。 + * 调用 TypeScript 7 原生 tsc(权威入口)。 + * + * 双轨安装: + * - `typescript` → `@typescript/typescript6`(供 ESLint / typescript-eslint API,bin 为 tsc6) + * - `@typescript/native` → `typescript@7`(类型检查 / emit) + * + * 各包 typecheck、.d.ts emit 应走本入口(或 bin `tsc7`),不要依赖 `.bin/tsc` 的链接胜出方。 */ import { spawnSync } from "node:child_process"; +import fs from "node:fs"; import { createRequire } from "node:module"; import path from "node:path"; +import { fileURLToPath } from "node:url"; const require = createRequire(import.meta.url); -const pkgDir = path.dirname(require.resolve("@typescript/native/package.json")); -const tscPath = path.join(pkgDir, "bin", "tsc"); -const result = spawnSync(process.execPath, [tscPath, ...process.argv.slice(2)], { - stdio: "inherit", -}); -process.exit(result.status === null ? 1 : result.status); + +function tryRealpath(filePath) { + try { + return fs.realpathSync.native(filePath); + } catch { + return filePath; + } +} + +/** 解析 @typescript/native 包内 tsc 脚本路径 */ +export function resolveNativeTsc() { + let pkgJson; + try { + pkgJson = require.resolve("@typescript/native/package.json"); + } catch { + throw new Error("未找到 @typescript/native(TypeScript 7)。请在仓库根目录执行 npm install。"); + } + return path.join(path.dirname(pkgJson), "bin", "tsc"); +} + +/** + * 以当前 Node 进程调用 TS7 tsc。 + * @param {string[]} args tsc CLI 参数 + * @param {{ stdio?: import("node:child_process").StdioOptions }} [opts] + * @returns {number} 进程退出码 + */ +export function runTsc7(args, opts = {}) { + const tscPath = resolveNativeTsc(); + const result = spawnSync(process.execPath, [tscPath, ...args], { + stdio: opts.stdio ?? "inherit", + }); + if (result.error) throw result.error; + return result.status === null ? 1 : result.status; +} + +/** 经 node_modules/.bin/tsc7 符号链接调用时也须识别为主入口 */ +function isMainModule() { + const entry = process.argv[1]; + if (!entry) return false; + const entryReal = tryRealpath(path.resolve(entry)); + const selfReal = tryRealpath(fileURLToPath(import.meta.url)); + return entryReal === selfReal; +} + +if (isMainModule()) { + process.exit(runTsc7(process.argv.slice(2))); +}