import { execFileSync } from 'node:child_process'; import fs from 'node:fs'; import { createRequire } from 'node:module'; import path from 'node:path'; import process from 'node:process'; import { fileURLToPath } from 'node:url'; const __filename = fileURLToPath(import.meta.url); const __dirname = path.dirname(__filename); const appRoot = path.resolve(__dirname, '..'); const repoRoot = path.resolve(appRoot, '../..'); const requireFromApp = createRequire(path.join(appRoot, 'package.json')); const monacoDtsDir = path.join(appRoot, 'monaco.dts'); const cacheDir = path.join(monacoDtsDir, '.cache'); const legacyOutputFile = path.join(monacoDtsDir, 'index.d.ts'); const outputFile = path.join( repoRoot, 'packages/form-designer/src/utils/user-script/context/monaco/index.d.ts', ); const globalLsBlock = [ 'declare global {', ' const ls: MonacoLsTypes.LsGlobal;', '}', ].join('\n'); const banner = [ '// Auto-generated by `pnpm run monaco:dts:build`.', '// Do not edit this file directly.', '', ].join('\n'); function readJsonFile(filePath) { return JSON.parse(fs.readFileSync(filePath, 'utf8')); } function findPackageRoot(packageName) { let entryPath; try { entryPath = requireFromApp.resolve(packageName); } catch (error) { throw new Error( `[monaco:dts:build] 无法解析依赖 ${packageName}。请先在仓库根目录执行 pnpm install,` + `并确认 apps/lcdp/package.json 已声明该依赖。原始错误:${error.message}`, ); } let currentDir = path.dirname(entryPath); while (currentDir !== path.dirname(currentDir)) { const packageJsonPath = path.join(currentDir, 'package.json'); if (fs.existsSync(packageJsonPath)) { const packageJson = readJsonFile(packageJsonPath); if (packageJson.name === packageName) { return { root: currentDir, packageJson }; } } currentDir = path.dirname(currentDir); } throw new Error(`[monaco:dts:build] 已解析 ${packageName},但无法找到对应 package.json。`); } function resolvePackageBin(packageName, binName) { const { root, packageJson } = findPackageRoot(packageName); const binConfig = packageJson.bin; const binPath = typeof binConfig === 'string' ? binConfig : binConfig?.[binName]; if (!binPath) { throw new Error(`[monaco:dts:build] ${packageName} 未声明 bin.${binName}。`); } const resolvedBinPath = path.resolve(root, binPath); if (!fs.existsSync(resolvedBinPath)) { throw new Error(`[monaco:dts:build] ${packageName} 的 bin.${binName} 不存在:${resolvedBinPath}`); } return resolvedBinPath; } // 通过 package.json 的 bin 字段定位 CLI,避免写死深层子路径或依赖 Windows/macOS 不一致的 .bin shim。 const tscBin = resolvePackageBin('typescript', 'tsc'); const apiExtractorBin = resolvePackageBin('@microsoft/api-extractor', 'api-extractor'); function runNodeScript(scriptPath, args) { execFileSync(process.execPath, [scriptPath, ...args], { cwd: appRoot, stdio: 'inherit', env: { ...process.env, }, }); } function validateOutput() { const content = fs.readFileSync(outputFile, 'utf8'); const hasImportLikeLine = content.split('\n').some((line) => { const trimmed = line.trim(); return trimmed.startsWith('import ') || (trimmed.startsWith('export ') && trimmed.includes(' from ')); }); if (hasImportLikeLine) { throw new Error('Generated Monaco d.ts still contains import/export-from statements.'); } if (/\b(?:typeof\s+)?import\((['"]).+?\1\)/.test(content)) { throw new Error('Generated Monaco d.ts still contains external import type references.'); } if (!content.includes('const ls: MonacoLsTypes.LsGlobal;')) { throw new Error('Generated Monaco d.ts is missing the global ls declaration.'); } } function ensureGlobalLs() { const content = fs.readFileSync(outputFile, 'utf8'); if (!content.includes('declare global {')) { const footer = 'export { }'; const body = content.trimEnd().endsWith(footer) ? content.trimEnd().slice(0, -footer.length).trimEnd() : content.trimEnd(); fs.writeFileSync(outputFile, `${body}\n\n${globalLsBlock}\n\nexport { }\n`); } } function addBanner() { const content = fs.readFileSync(outputFile, 'utf8'); if (!content.startsWith('// Auto-generated')) { fs.writeFileSync(outputFile, `${banner}${content}`); } } function main() { fs.rmSync(cacheDir, { recursive: true, force: true }); fs.rmSync(legacyOutputFile, { force: true }); fs.rmSync(outputFile, { force: true }); runNodeScript(tscBin, ['-p', 'monaco-types/tsconfig.json']); runNodeScript(apiExtractorBin, ['run', '--local', '--config', 'api-extractor.monaco.json']); ensureGlobalLs(); validateOutput(); addBanner(); fs.rmSync(cacheDir, { recursive: true, force: true }); } main();