#!/usr/bin/env bun // Writes cli/lib/embedded.ts: the text files the CLI ships inside its code, so they work on every runtime and in every // build without a files folder next to it: the Node bundle (dist/storebound.mjs), the compiled desktop sidecar // (`bun build --compile`) and the sources. Bun's `import ... with { type: 'text' }` did this before, but Node cannot // run that. Embedded: every file under templates/ (storebound init, web init), the shots pages (cli/shots/*.html, // served by shots render / video) and Play's Data safety form export (cli/data/play-data-safety-form.csv). // bun tools/gen-embedded.ts write cli/lib/embedded.ts // bun tools/gen-embedded.ts --check exit 1 when the file is stale (bun run ci) import { readdirSync, readFileSync, writeFileSync } from 'node:fs'; import { join, relative, resolve } from 'node:path'; const ROOT = resolve(import.meta.dir, '..'); export const OUT = join(ROOT, 'cli/lib/embedded.ts'); function walk(dir: string): string[] { return readdirSync(dir, { withFileTypes: true }).flatMap(e => { if (e.name === '.DS_Store') return []; const p = join(dir, e.name); return e.isDirectory() ? walk(p) : [p]; }).sort(); } const rel = (base: string, p: string) => relative(base, p).split('\\').join('/'); const table = (entries: [string, string][]): string => entries.map(([k, v]) => ` ${JSON.stringify(k)}: ${JSON.stringify(v)},`).join('\n'); export function generate(root = ROOT): string { const templates = walk(join(root, 'templates')).map(p => [rel(join(root, 'templates'), p), readFileSync(p, 'utf8')] as [string, string]); const shots = readdirSync(join(root, 'cli/shots')).filter(f => f.endsWith('.html')).sort().map(f => [f, readFileSync(join(root, 'cli/shots', f), 'utf8')] as [string, string]); const form = readFileSync(join(root, 'cli/data/play-data-safety-form.csv'), 'utf8'); return [ '// GENERATED by tools/gen-embedded.ts from templates/, cli/shots/*.html and cli/data/play-data-safety-form.csv.', '// Do not edit: change those files and run `bun tools/gen-embedded.ts` (bun run ci checks it is fresh).', '/* eslint-disable */', '', '/** Every file under templates/, by its path there (forward slashes). */', 'export const TEMPLATE_TEXT: Record = {', table(templates), '};', '', '/** The pages shots render / video load (cli/shots/*.html), by file name. */', 'export const SHOTS_PAGES: Record = {', table(shots), '};', '', "/** Play Console's Data safety form export (cli/data/play-data-safety-form.csv). */", `export const PLAY_DATA_SAFETY_FORM = ${JSON.stringify(form)};`, '', ].join('\n'); } if (import.meta.main) { const want = generate(); let have = ''; try { have = readFileSync(OUT, 'utf8'); } catch { /* missing */ } if (process.argv.includes('--check')) { if (have !== want) { console.error(`stale: ${rel(ROOT, OUT)} (run bun tools/gen-embedded.ts)`); process.exit(1); } console.log(`${rel(ROOT, OUT)}: fresh`); } else if (have !== want) { writeFileSync(OUT, want); console.log(`wrote ${rel(ROOT, OUT)}`); } else console.log(`${rel(ROOT, OUT)}: unchanged`); }