143 lines
4.7 KiB
JavaScript
143 lines
4.7 KiB
JavaScript
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();
|