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();
|