#!/usr/bin/env node /** * Capabilities Codegen * * Projects `packages/capabilities/index.js` (ESM, the source of truth) into * a checked-in CommonJS module at `apps/server/capabilities.js`. * * apps/server/ is subtree-split and deployed standalone, so it can't import * packages/ at runtime (see the comment atop apps/server/db.js) — same * constraint `packages/schema/codegen.js` works around by generating * apps/server/schema.json from packages/schema/v1.json. That precedent * projects *data*; this one projects *logic*, because resolveCapabilities() * and validateTileManifest() are code the server needs to run, not read. * The projection is a mechanical ESM→CommonJS syntax rewrite — index.js has * no imports and no capability is added, widened, narrowed or removed by it. * * Usage: * node packages/capabilities/codegen.js * yarn capabilities:codegen */ import { readFileSync, writeFileSync } from 'fs'; import { dirname, join } from 'path'; import { fileURLToPath } from 'url'; const __filename = fileURLToPath(import.meta.url); const __dirname = dirname(__filename); /** * Rewrite `index.js`'s ESM export syntax to CommonJS and collect the * exported names, so the projection can end with a single `module.exports` * rather than one `exports.x =` per declaration (keeps the body a literal * copy of the source instead of another place per-export logic could * drift). */ export function generateServerCapabilities(sourceJs) { const exportedNames = []; const body = sourceJs .replace(/^export function (\w+)/gm, (_match, name) => { exportedNames.push(name); return `function ${name}`; }) .replace(/^export const (\w+)/gm, (_match, name) => { exportedNames.push(name); return `const ${name}`; }); const banner = [ '/**', ' * Generated by packages/capabilities/codegen.js from packages/capabilities/index.js.', ' * DO NOT EDIT - regenerate with: yarn capabilities:codegen', ' *', ' * apps/server/ is subtree-split and deployed standalone, so it can\'t import', ' * packages/ at runtime and carries its own copy instead (see the comment atop', ' * apps/server/db.js). This file is a straight ESM->CommonJS syntax rewrite of', ' * packages/capabilities/index.js — no capability is added, widened, narrowed', ' * or removed by the projection.', ' */', '', '\'use strict\';', '', ].join('\n'); const footer = `\nmodule.exports = { ${exportedNames.join(', ')} };\n`; return banner + body + footer; } function main() { console.log('[capabilities-codegen] Reading packages/capabilities/index.js...'); const sourcePath = join(__dirname, 'index.js'); const sourceJs = readFileSync(sourcePath, 'utf-8'); const generated = generateServerCapabilities(sourceJs); const serverPath = join(__dirname, '..', '..', 'apps', 'server', 'capabilities.js'); writeFileSync(serverPath, generated); console.log('[capabilities-codegen] Wrote apps/server/capabilities.js'); } // Only run when invoked directly (node packages/capabilities/codegen.js), // not when imported by check-freshness.js to reuse generateServerCapabilities. const isMain = process.argv[1] === __filename; if (isMain) { main(); }