105 lines
3.1 KiB
TypeScript
105 lines
3.1 KiB
TypeScript
import fs from "node:fs/promises";
|
|
import path from "node:path";
|
|
import { pathToFileURL } from "node:url";
|
|
|
|
/**
|
|
* This just convers the <template>.ts file to a <template>.json file.
|
|
* Im fairly sure there is a util in the engine or engine-packages for this, but I decided to just keep it as simple as possible because I didn't feel like digging around for it.
|
|
*
|
|
* Usage:
|
|
* tsx scripts/template-to-json.ts ../templates/source/p2pkh.ts ./p2pkh.json p2pkhTemplate
|
|
*/
|
|
|
|
/**
|
|
* Prints usage to stderr and exits with a non-zero code.
|
|
*/
|
|
function printUsageAndExit(): never {
|
|
console.error(
|
|
[
|
|
"Usage: tsx scripts/template-to-json.ts <input.ts> <output.json> [exportName]",
|
|
"",
|
|
"Loads a TypeScript module, picks one exported value, and writes JSON.stringify to the output path.",
|
|
"If exportName is omitted: uses default export, or the only non-function export if there is exactly one.",
|
|
"",
|
|
"Example:",
|
|
" tsx scripts/template-to-json.ts ../templates/source/p2pkh.ts ./p2pkh.json p2pkhTemplate",
|
|
].join("\n"),
|
|
);
|
|
process.exit(1);
|
|
}
|
|
|
|
/**
|
|
* Collects runtime export keys whose values are not functions (typical for data/template objects).
|
|
*/
|
|
function listDataExportKeys(mod: Record<string, unknown>): string[] {
|
|
return Object.keys(mod).filter((key) => {
|
|
if (key === "__esModule") {
|
|
return false;
|
|
}
|
|
const value = mod[key];
|
|
return typeof value !== "function";
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Resolves which export to serialize: explicit name, default, or a single unambiguous data export.
|
|
*/
|
|
function resolveExportedValue(
|
|
mod: Record<string, unknown>,
|
|
exportName: string | undefined,
|
|
): unknown {
|
|
if (exportName !== undefined) {
|
|
if (!(exportName in mod)) {
|
|
const keys = listDataExportKeys(mod);
|
|
console.error(
|
|
`Export "${exportName}" not found. Available data exports: ${keys.length ? keys.join(", ") : "(none)"}`,
|
|
);
|
|
process.exit(1);
|
|
}
|
|
return mod[exportName];
|
|
}
|
|
|
|
if ("default" in mod && mod.default !== undefined) {
|
|
return mod.default;
|
|
}
|
|
|
|
const keys = listDataExportKeys(mod);
|
|
if (keys.length === 1) {
|
|
return mod[keys[0]!];
|
|
}
|
|
|
|
if (keys.length === 0) {
|
|
console.error(
|
|
"No suitable exports found (need default or a non-function export).",
|
|
);
|
|
} else {
|
|
console.error(
|
|
`Multiple data exports found; pass exportName. Candidates: ${keys.join(", ")}`,
|
|
);
|
|
}
|
|
process.exit(1);
|
|
}
|
|
|
|
async function main(): Promise<void> {
|
|
const args = process.argv.slice(2);
|
|
if (args.length < 2) {
|
|
printUsageAndExit();
|
|
}
|
|
|
|
const [inputRel, outputRel, exportName] = args;
|
|
const inputPath = path.resolve(process.cwd(), inputRel!);
|
|
const outputPath = path.resolve(process.cwd(), outputRel!);
|
|
|
|
/** Dynamic import needs a file URL so Windows paths and ESM resolution behave. */
|
|
const fileUrl = pathToFileURL(inputPath).href;
|
|
const mod = (await import(fileUrl)) as Record<string, unknown>;
|
|
const value = resolveExportedValue(mod, exportName);
|
|
|
|
const json = `${JSON.stringify(value, null, 2)}\n`;
|
|
await fs.mkdir(path.dirname(outputPath), { recursive: true });
|
|
await fs.writeFile(outputPath, json, "utf8");
|
|
console.log(`Wrote ${outputPath}`);
|
|
}
|
|
|
|
await main();
|