/** * cli:scaffold-extension-config — generate.ts * * Emits an ExtensionConfig for a module, listing every slot that the scaffolded * components publish via ``. Clients (or other extensions) * fill these slots with ``. * * ExtensionConfig type comes from `@atlashub/smartstack` (npm). * * The slot catalog is the SSOT `lib/slot-names.ts` — the exact `` * calls scaffold-component renders (drift-tested against the real renderer). * Until 2026-09-24 this file published `${module}.${entity}.list.before…` while * the pages rendered `${entity}.header.actions`… — zero names in common, every * dead (audit B-CRIT-05). Slot names carry NO module prefix. */ import type { ScaffoldExtensionConfigInput, GeneratedFile } from './types.js' import { DEFAULT_SLOT_VIEWS, SLOT_SUFFIXES_BY_VIEW, slotCatalogue } from '../../../../../lib/slot-names.js' import { toCamelCase } from '../../../../../lib/string-utils.js' const OPTIONAL_VIEWS = (Object.keys(SLOT_SUFFIXES_BY_VIEW) as Array).filter( (v) => !DEFAULT_SLOT_VIEWS.includes(v), ) export function generate(spec: ScaffoldExtensionConfigInput): GeneratedFile[] { const allSlots = spec.entities.flatMap((e) => slotCatalogue(e)) const jsDocLines = allSlots .map((s) => ` * - '${s.name}' (${s.view} page): ${s.description}`) .join('\n') const optionalLines = OPTIONAL_VIEWS .map((v) => ` * - ${v} page (when generated): ${SLOT_SUFFIXES_BY_VIEW[v].map((sfx) => `'{entity}.${sfx}'`).join(', ')}`) .join('\n') const slotEntries = allSlots.map((s) => ` '${s.name}': null,`).join('\n') // A hyphenated module (`time-entry`) is not a valid identifier (audit B-WARN-17). const configName = `${toCamelCase(spec.module)}Config` const content = `import type { ExtensionConfig } from '@atlashub/smartstack'; /** * Extension configuration for the ${spec.module} module. * * Slot catalog — the exact calls the generated pages render * (SSOT: skills/lib/slot-names.ts, no module prefix): ${jsDocLines} * * Also rendered by the optional views: ${optionalLines} * * Add Fill components in your app entrypoint to inject content into any slot: * {yourJsx} */ export const ${configName}: ExtensionConfig = { slots: { ${slotEntries} }, tableColumns: {}, formFields: {}, hooks: {}, }; ` return [{ path: `src/extensions/${spec.module}Extensions.ts`, content }] }