Files
Endoleap/scripts/build-headless.mjs

42 lines
3.0 KiB
JavaScript

/**
* 独立headless SDK的产物生成脚本。先清理.headless-dist,再用tsconfig.headless.json编译四个库目录,修正声明与Worker引用。
* 最后复制包清单、无UI宿主示例和验收文档;失败立即抛出,不把半成品报告成可用包。执行会删除并重建该产物目录。
*/
import { execFileSync } from 'node:child_process';
import { cp, readdir, readFile, rm, writeFile } from 'node:fs/promises';
import { fileURLToPath } from 'node:url';
import { join, resolve } from 'node:path';
// 路径基于脚本URL而非当前终端目录;tsc仍显式以仓库根作为cwd解析项目依赖。
const root=resolve(fileURLToPath(new URL('..',import.meta.url))),output=join(root,'.headless-dist');
await rm(output,{recursive:true,force:true});
// 同步等待TypeScript生成ESM及声明;继承终端输出,编译失败直接中止后续处理。
execFileSync(process.execPath,[join(root,'node_modules/typescript/bin/tsc'),'-p',join(root,'tsconfig.headless.json')],{cwd:root,stdio:'inherit'});
/** 递归只处理.d.ts的相对模块说明符,将源.ts后缀改为.js;普通schema/data字符串不做全局替换。
* 这是针对当前输出格式的正则修补,不是任意TypeScript语法的完整重写器。 */
async function declarations(directory){
for(const entry of await readdir(directory,{withFileTypes:true})){
const path=join(directory,entry.name);
if(entry.isDirectory())await declarations(path);
else if(entry.name.endsWith('.d.ts')){
const source=await readFile(path,'utf8');
// Native TS rewrites runtime imports, but leaves source suffixes in declarations.
// Only module specifiers change; data/schema string literals remain intact.
const next=source.replace(/((?:from\s+|import\s*\()\s*['"])(\.\.?\/[^'"]+)\.ts(['"])/g,'$1$2.js$3');
await writeFile(path,next);
}
}
}
// 原生编译器处理运行时import后缀,声明文件仍需此补充;完成后再修URL字面量里的Worker源后缀。
await declarations(join(output,'modules'));
// 两个浏览器适配器各应含一个预期Worker URL;要求目标.js文件存在并且源字符串只出现一次才改写。
for(const [module,worker]of [['browser-digests','digest.worker'],['browser-images','image.worker']]){
const path=join(output,'modules/canvas-runtime',`${module}.js`),source=await readFile(path,'utf8'),before=`./${worker}.ts`;
if(source.split(before).length!==2)throw Error(`Unexpected Worker URL in ${module}`);
await readFile(join(output,'modules/canvas-runtime',`${worker}.js`));
await writeFile(path,source.replace(before,`./${worker}.js`));
}
// 产物保留与headless/package.json的exports/files配套的模块布局;这里复制清单,不执行npm发布或包验收测试。
for(const name of ['package.json','consumer.mjs','README.md','STEP4_ACCEPTANCE.md','SERVICE_ACCEPTANCE.md','FINAL_ACCEPTANCE.md'])await cp(join(root,'headless',name),join(output,name));
console.log('Built .headless-dist: ESM, declarations, browser adapters and Worker modules');