- gen-seed.mts: deterministischer Generator aus catalog.ts (Single Source); emittiert BEIDE Artefakte: generated.json (Klammer-Notation, Display) + backend.json (frozen ef/cchm/ch, für Pam EF-Migrationen). Kein magisches Artefakt mehr. - package.json: npm run gen:catalog (npx tsx gen-seed.mts) - catalog-drift.test.ts: Drift-Guard — liest generated.json von Disk via import.meta.url + readFileSync, vergleicht mit live CATALOG; Fail-Meldung zeigt 'npm run gen:catalog'. 5 Test-Files, 93 Tests grün. - colorVarietySeed.backend.json: 66 Zeilen frozen symbols (ef/cchm/ch), kein sofortiger Backend-Eingriff (AR-5 Guardrail; Pam konsumiert bei nächster Reseed-Migration). - README.md: Katalog-Generator-Doku (wann laufen, was erzeugt wird). Gate: build ✓ eslint ✓ vitest 93/93 ✓
50 lines
2.5 KiB
TypeScript
50 lines
2.5 KiB
TypeScript
/**
|
|
* Katalog-Generator — AR-5
|
|
*
|
|
* Erzeugt zwei Artefakte aus catalog.ts (Single Source of Truth):
|
|
*
|
|
* colorVarietySeed.generated.json — Display-Notation (Klammer: e[f]/c[chm]/c[h])
|
|
* → Quelle für UI-Dropdowns, Frontend-Suche.
|
|
*
|
|
* colorVarietySeed.backend.json — Frozen internal symbols (ef/cchm/ch)
|
|
* → Quelle für künftige EF-Seed-Migrationen (Pam).
|
|
* NICHT in Bracket-Notation ändern — Backend-Parser
|
|
* erwartet frozen symbols (CR-11-Matcher-Guardrail).
|
|
*
|
|
* Ausführen nach jeder Änderung an catalog.ts:
|
|
* npm run gen:catalog
|
|
*
|
|
* Der vitest-Drift-Guard (catalog-drift.test.ts) schlägt fehl, wenn
|
|
* generated.json veraltet ist — Fehler macht den fehlenden Generator-Lauf sichtbar.
|
|
*/
|
|
import { BASE_COLORS, CATALOG, representativeGenotype } from './src/genetics/catalog.ts'
|
|
import { LOCUS_ORDER } from './src/genetics/loci.ts'
|
|
import type { Genotype } from './src/genetics/genotype.ts'
|
|
import { writeFileSync } from 'fs'
|
|
|
|
/** Internal (frozen) display string — concatenates canonical allele symbols without bracket mapping. */
|
|
function toInternalString(g: Genotype): string {
|
|
return LOCUS_ORDER.filter(
|
|
(locus) => locus !== 'Sls' || !(g.Sls[0] === 'sl' && g.Sls[1] === 'sl'),
|
|
)
|
|
.map((locus) => (g[locus][0] + g[locus][1]).replace(/\?/g, '-'))
|
|
.join(' ')
|
|
}
|
|
|
|
// ── Display artefact (bracket notation) ─────────────────────────────────────
|
|
const displayPath = './src/genetics/colorVarietySeed.generated.json'
|
|
writeFileSync(displayPath, JSON.stringify(CATALOG, null, 2) + '\n')
|
|
console.log(`[gen:catalog] display → ${displayPath} (${CATALOG.length} rows)`)
|
|
|
|
// ── Backend artefact (frozen internal symbols) ───────────────────────────────
|
|
const backendSeed = BASE_COLORS.map((entry, i) => ({
|
|
name: entry.name,
|
|
...(entry.english !== undefined ? { english: entry.english } : {}),
|
|
canonicalGenotype: toInternalString(representativeGenotype(entry)),
|
|
sortOrder: i,
|
|
...(entry.image !== undefined ? { image: entry.image } : {}),
|
|
}))
|
|
const backendPath = './src/genetics/colorVarietySeed.backend.json'
|
|
writeFileSync(backendPath, JSON.stringify(backendSeed, null, 2) + '\n')
|
|
console.log(`[gen:catalog] backend → ${backendPath} (${backendSeed.length} rows)`)
|