w-funnel/scripts/bake-funnels.mjs
2025-09-26 02:46:48 +02:00

80 lines
2.5 KiB
JavaScript

#!/usr/bin/env node
import { promises as fs } from "fs";
import path from "path";
import { fileURLToPath } from "url";
const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);
const projectRoot = path.resolve(__dirname, "..");
const funnelsDir = path.join(projectRoot, "public", "funnels");
const outputFile = path.join(projectRoot, "src", "lib", "funnel", "bakedFunnels.ts");
function formatFunnelRecord(funnels) {
const entries = Object.entries(funnels)
.map(([funnelId, definition]) => {
const serialized = JSON.stringify(definition, null, 2);
const indented = serialized
.split("\n")
.map((line, index) => (index === 0 ? line : ` ${line}`))
.join("\n");
return ` "${funnelId}": ${indented}`;
})
.join(",\n\n");
return `{
${entries}\n}`;
}
async function bakeFunnels() {
const dirExists = await fs
.access(funnelsDir)
.then(() => true)
.catch(() => false);
if (!dirExists) {
throw new Error(`Funnels directory not found: ${funnelsDir}`);
}
const files = (await fs.readdir(funnelsDir)).sort((a, b) => a.localeCompare(b));
const funnels = {};
for (const file of files) {
if (!file.endsWith(".json")) continue;
const filePath = path.join(funnelsDir, file);
const raw = await fs.readFile(filePath, "utf8");
let parsed;
try {
parsed = JSON.parse(raw);
} catch (error) {
throw new Error(`Failed to parse ${file}: ${error.message}`);
}
const funnelId = parsed?.meta?.id ?? parsed?.id ?? file.replace(/\.json$/, "");
if (!funnelId || typeof funnelId !== "string") {
throw new Error(
`Unable to determine funnel id for '${file}'. Ensure the file contains an 'id' or 'meta.id' field.`
);
}
funnels[funnelId] = parsed;
}
const headerComment = `/**\n * This file is auto-generated by scripts/bake-funnels.mjs.\n * Do not edit this file manually; update the source JSON files instead.\n */`;
const recordLiteral = formatFunnelRecord(funnels);
const contents = `${headerComment}\n\nimport type { FunnelDefinition } from "./types";\n\nexport const BAKED_FUNNELS: Record<string, FunnelDefinition> = ${recordLiteral};\n`;
await fs.mkdir(path.dirname(outputFile), { recursive: true });
await fs.writeFile(outputFile, contents, "utf8");
console.log(`Baked ${Object.keys(funnels).length} funnel(s) into ${path.relative(projectRoot, outputFile)}`);
}
bakeFunnels().catch((error) => {
console.error(error);
process.exit(1);
});