/**
* cli:scaffold-component — generate.ts
*
* Emits:
* - React pages (list, detail, form) under src/features/{module}/{entity}/pages
* conforming to the SmartStack customisation-ui baseline
* (`@/components/ui/PageTemplate` + `@/components/ui/ResponsiveDataTable` +
* token-based Tailwind, lucide-react icons, PermissionGuard + Slot/Fill).
* - Locale JSON files under src/i18n/locales/{fr,en,it,de}/{module}.json
* (relative to the web root, the SAME base as the pages — projectPath IS the
* web root, enforced by assertWebProjectRoot)
* — one file per MODULE (the entities of a module share it). The CLI writer
* (index.ts) deep-merges into the existing file, so generating one entity never
* wipes a sibling entity's keys. Concurrent generation of two entities in the
* SAME module is therefore unsafe (read-modify-write race) — serialize within a
* module (see ba-develop/SKILL.md § Phase 3a).
*
* Baseline anatomy (derived verbatim from D:\01 - projets\SmartStack.app\features\customisation-ui
* pages administration/uiConfiguration/{ThemesListPage, PresetsListPage},
* administration/tenants/OrganisationCreatePage, administration/tenants/TenantDetailPage):
*
* - Every page is wrapped in `} actions={...}>`.
* - List views use ``
* (wraps the local : columns carry `minBreakpoint` so the default
* code/label/actions stay visible and extra columns appear as the screen
* widens, plus `truncate` for ellipsis + tooltip on overflowing cells).
* - Detail views use card sections with `rounded-[var(--radius-card)] border
* border-[var(--border-color)] bg-[var(--bg-card)]`.
* - Form views use `.input` class for fields, primary CTA with the
* `.btn .btn-primary` helper class (the theme owns the accent fill + hover +
* radius + padding — never re-assemble it inline; ui-polish R21 enforces this).
* - All colors through CSS vars — no Tailwind color palette (`bg-red-500` etc.).
* - Icons from lucide-react only.
* - i18n namespace = {module}, keys nested under entity key (lowercased).
* - PermissionGuard keys: `{module}.{section}.{action}` — no appCode prefix.
* - Slot/Fill points: {entity}.header.actions, {entity}.table.columns.before/after,
* {entity}.form.fields.before/after, {entity}.detail.header/sidebar.
*
* No legacy patterns from the prior generate.ts are carried forward.
*/
import type { ScaffoldComponentInput, GeneratedFile, GenerateContext } from './types.js'
import { buildRenderContext } from './render/context.js'
import { renderList } from './render/list.js'
import { renderDetail } from './render/detail.js'
import { renderForm } from './render/form.js'
import { renderDashboard } from './render/dashboard.js'
import { renderReconduction } from './render/reconduction.js'
import { renderHomes } from './render/home.js'
import { renderI18nFiles } from './render/i18n-files.js'
export function generate(spec: ScaffoldComponentInput, ctx: GenerateContext = {}): GeneratedFile[] {
if (spec.fields.length === 0) {
throw new Error(`scaffold-component: entity '${spec.entity}' has no fields — scaffolding would produce an empty UI`)
}
const files: GeneratedFile[] = []
const rc = buildRenderContext(spec, ctx)
// View order is part of the contract (files[] order → writer order).
files.push(...renderList(rc))
files.push(...renderDetail(rc))
files.push(...renderForm(rc))
files.push(...renderDashboard(rc))
// The kanban board is rendered by renderList (the `kanban` viewMode of the
// list page) — the standalone renderKanban page is retired.
files.push(...renderReconduction(rc))
files.push(...renderHomes(rc))
files.push(...renderI18nFiles(rc))
// (the status/boolean pill primitive) is emitted by shared render
// helpers that list, detail AND form compose — inject its import wherever a
// page actually renders one. Central so no template forgets it, conditional
// so a pill-less page never ships an unused import (type-check gate).
const BADGE_IMPORT = `import { Badge } from '@/components/ui/Badge'`
const PAGE_TEMPLATE_IMPORT = `import { PageTemplate } from '@/components/ui/PageTemplate'`
for (const f of files) {
if (f.path.endsWith('.tsx') && f.content.includes('