/** * real-output.ts — the REAL scaffold-component output as a test fixture. * * Runs `validate()` + `generate()` IN-PROCESS on a documented-shape spec and * writes every emitted file (pages + the 4 i18n catalogues) under a fixture * root, plus the hooks / service / types the sibling scaffold-api-client * emits for the same entity — so an audit pack's SILENT case is green on what * the scaffolder really renders today, and goes red the day a rendering * change in `render/*.ts` starts tripping a rule. * * QC 2026-09-24: the SILENT fixtures of ui-polish and audit-dev-frontend were * hand-typed transcriptions of `render/list.ts` — a rendering change could * never turn them red. This helper is the shared replacement; the transcribed * fixtures stay for their FIRES surgery. * * Never a test file: no `describe` lives here. Importable from any pack * (validate-page and audit-dev-external-api already import a sibling * scaffolder's `generate.js` the same way). */ import { mkdirSync, writeFileSync } from 'node:fs' import { dirname, join } from 'node:path' import { validate } from '../validate.js' import { generate } from '../generate.js' import type { GenerateContext, ScaffoldComponentInput } from '../types.js' import { validate as validateApiClient } from '../../../../api-client/cli/scaffold-api-client/validate.js' import { generate as generateApiClient } from '../../../../api-client/cli/scaffold-api-client/generate.js' /** The views this helper materialises as page files (kanban/cards fold into the list). */ export type RealPageView = 'list' | 'detail' | 'form' | 'dashboard' | 'reconduction' | 'app-home' | 'module-home' | 'section-home' export interface RealPagesOptions { /** PascalCase entity — use a non-trivial plural (`JourFerie` → `JourFeries`). */ entity: string /** Module code (kebab), also the i18n namespace. */ module: string /** Application code (any case; the page directory lowercases it). */ app: string /** Section code (kebab) — the page directory + the app-less permission root. */ section: string /** Default: list + detail + form. */ views?: RealPageView[] /** Default: `REAL_FIELDS` (6 fields — required string, optional string, 2 dates, a boolean, a decimal). */ fields?: Array & { name: string; type: string }> /** Explicit plural when `pluralize()` would get it wrong. */ pluralName?: string /** * Extra invocation keys spliced VERBATIM over the base spec (`pageSpec`, * `formLayout`, `entityViews`, `codedEntity`…) — the shape ba-develop Phase * 3a passes. Never overrides `projectPath`. */ extra?: Partial> & Record /** Optional generation context (routesFamilies / existingI18n). */ ctx?: GenerateContext /** Also write the hooks / service / types of scaffold-api-client (default true). */ withApiClient?: boolean } export interface RealPages { /** The fixture root the files were written under. */ root: string /** Project-relative POSIX paths of the page files, in emission order. */ pages: string[] /** Project-relative POSIX paths of EVERY file written (pages, i18n, api-client). */ files: string[] /** Project-relative POSIX path of the list / detail / form page when emitted. */ list?: string detail?: string form?: string /** The Zod-parsed spec generate() rendered from. */ spec: ScaffoldComponentInput /** validate() + generate() notices (never errors — an invalid spec throws). */ warnings: string[] } /** * The documented six-field shape: a required string, an optional string, two * dates, a boolean and a decimal — every widget family the form renders * (``, `