Files
xread/scripts/transpile.cjs
T

149 lines
3.7 KiB
JavaScript

#!/usr/bin/env node
const fs = require("node:fs");
const path = require("node:path");
const childProcess = require("node:child_process");
const projectRoot = path.resolve(__dirname, "..");
const tsconfigPath = path.join(projectRoot, "tsconfig.json");
const bootstrapPrefix = path.join(projectRoot, ".codex-cache", "ts-compiler");
function resolveTypeScript() {
const candidatePaths = [
path.join(projectRoot, "node_modules", "typescript"),
path.join(bootstrapPrefix, "node_modules", "typescript"),
];
for (const candidate of candidatePaths) {
if (fs.existsSync(candidate)) {
return require(candidate);
}
}
ensureDir(bootstrapPrefix);
const install = childProcess.spawnSync(
"npm",
[
"install",
"--prefix",
bootstrapPrefix,
"--no-save",
"--ignore-scripts",
"--no-package-lock",
"typescript@5.5.4",
],
{
cwd: projectRoot,
stdio: "inherit",
shell: true,
},
);
if (install.status !== 0) {
throw new Error(
`Unable to bootstrap TypeScript compiler (exit ${install.status ?? "unknown"})`,
);
}
return require(path.join(bootstrapPrefix, "node_modules", "typescript"));
}
const ts = resolveTypeScript();
function ensureDir(dirPath) {
fs.mkdirSync(dirPath, { recursive: true });
}
function cleanDir(dirPath) {
if (fs.existsSync(dirPath)) {
fs.rmSync(dirPath, { recursive: true, force: true });
}
ensureDir(dirPath);
}
function loadConfig() {
const rawConfig = ts.readConfigFile(tsconfigPath, ts.sys.readFile);
if (rawConfig.error) {
throw new Error(
ts.flattenDiagnosticMessageText(rawConfig.error.messageText, "\n"),
);
}
const parsed = ts.parseJsonConfigFileContent(
rawConfig.config,
ts.sys,
projectRoot,
undefined,
tsconfigPath,
);
return {
compilerOptions: {
...parsed.options,
noEmitOnError: false,
},
fileNames: parsed.fileNames.filter((fileName) => {
const normalized = path.resolve(fileName);
if (!normalized.startsWith(path.join(projectRoot, "src"))) {
return false;
}
return !normalized.endsWith(".d.ts");
}),
outDir: path.resolve(projectRoot, parsed.options.outDir || "build"),
};
}
function outputPathFor(fileName, outDir) {
const relative = path.relative(path.join(projectRoot, "src"), fileName);
const ext = path.extname(relative);
const base = relative.slice(0, relative.length - ext.length);
return path.join(outDir, `${base}.js`);
}
function transpileFile(fileName, compilerOptions, outDir) {
const sourceText = fs.readFileSync(fileName, "utf8");
const transpiled = ts.transpileModule(sourceText, {
compilerOptions,
fileName,
reportDiagnostics: true,
});
const outputFile = outputPathFor(fileName, outDir);
ensureDir(path.dirname(outputFile));
fs.writeFileSync(outputFile, transpiled.outputText, "utf8");
if (transpiled.sourceMapText) {
fs.writeFileSync(`${outputFile}.map`, transpiled.sourceMapText, "utf8");
}
if (transpiled.diagnostics?.length) {
for (const diagnostic of transpiled.diagnostics) {
const message = ts.flattenDiagnosticMessageText(
diagnostic.messageText,
"\n",
);
process.stderr.write(`[transpile warning] ${fileName}: ${message}\n`);
}
}
}
function main() {
const { compilerOptions, fileNames, outDir } = loadConfig();
cleanDir(outDir);
for (const fileName of fileNames) {
transpileFile(fileName, compilerOptions, outDir);
}
process.stdout.write(
`Transpiled ${fileNames.length} source files to ${outDir}\n`,
);
}
try {
main();
} catch (error) {
process.stderr.write(`${error.stack || error}\n`);
process.exit(1);
}