@ogygie/generate 0.33.0 → 0.34.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -3182,10 +3182,6 @@ function orderPlanOf(operation, schemas, resourceFields) {
3182
3182
  const tuples = typeof operation.orderBy[0] === "string" ? [operation.orderBy] : operation.orderBy;
3183
3183
  return { enumOrder: null, tuples: tuples.map(([field, direction]) => ({ field, direction })) };
3184
3184
  }
3185
- function tenantOf(plan) {
3186
- if (plan.tenant === null) throw new Error("generation plan: this emitter needs a tenant column (target.tenancy column) \u2014 a target without tenant is emitted by the mssql emitters");
3187
- return plan.tenant;
3188
- }
3189
3185
  function schemaNameOfModel(model, schemas, except) {
3190
3186
  const wanted = JSON.stringify({ ...model, optional: false, nullable: model.nullable, examples: [] });
3191
3187
  for (const [name, entry] of Object.entries(schemas)) {
@@ -4051,7 +4047,7 @@ function drizzleTableLines(table, builders, tablesByName) {
4051
4047
  function drizzleViewLines(view, builders) {
4052
4048
  for (const column of view.columns) builders.add(builderOf(column));
4053
4049
  return [
4054
- `/** READ-ONLY mapping of the view ${view.name} (hole ${view.id}, D32): the SQL lives in the migration, this table shape is what tenantDb reads; nothing is ever written through it. */`,
4050
+ `/** READ-ONLY mapping of the view ${view.name} (hole ${view.id}, D32): the SQL lives in the migration, this table shape is what the repository's facade reads; nothing is ever written through it. */`,
4055
4051
  `export const ${view.tsName} = pgTable(${quote(view.name)}, {`,
4056
4052
  ...view.columns.map((column) => ` ${column.key}: ${column.drizzle},`),
4057
4053
  "});",
@@ -4061,7 +4057,7 @@ function drizzleViewLines(view, builders) {
4061
4057
  function drizzleSharedLines(table, builders) {
4062
4058
  for (const column of table.columns) builders.add(builderOf(column));
4063
4059
  return [
4064
- `/** READ-ONLY mapping of the shared table ${table.sqlName} (D60): a table of the product outside this feature, read by its aggregate holes through tenantDb; never created nor written here. */`,
4060
+ `/** READ-ONLY mapping of the shared table ${table.sqlName} (D60): a table of the product outside this feature, read by its aggregate holes through the repository's facade; never created nor written here. */`,
4065
4061
  `export const ${table.tsName} = pgTable(${quote(table.sqlName)}, {`,
4066
4062
  ...table.columns.map((column) => ` ${column.key}: ${column.drizzle},`),
4067
4063
  "});",
@@ -4114,7 +4110,7 @@ function emitDbSchema(plan) {
4114
4110
  for (const table of plan.sharedTables) sections.push("", ...drizzleSharedLines(table, builders));
4115
4111
  const needsSql = tables.some((table) => table.uniques.some((unique) => unique.where !== null));
4116
4112
  const intent = wrap(
4117
- `Drizzle tables owned by the ${plan.featureId} feature, derived from ${plan.resource.schemaName} (${plan.specPath}, section G\xE9n\xE9ration): tenant-scoped by ${tenantOf(plan).column} (TS key \`${tenantOf(plan).columnKey}\`, the column tenantDb injects and filters).${plan.key === null ? "" : ` The business key ${plan.key.field} is unique per tenant (${plan.key.uniqueName}), the target of every slot and reference foreign key.`}${plan.slots.length === 0 ? "" : ` Slot tables: ${plan.slots.map((slot) => slot.table.sqlName).join(", ")} (cascade with the resource row).`}${plan.references.some((reference) => reference.table !== null) ? ` Reference tables: ${plan.references.flatMap((reference) => reference.table === null ? [] : [reference.table.sqlName]).join(", ")} (a referenced row cannot be deleted).` : ""}${views.length === 0 ? "" : ` Views ${views.map((view) => view.name).join(", ")} are read-only mappings: their SQL is in the migration.`}${plan.appendOnly === null ? "" : ` The append-only key (${plan.appendOnly.key.join(", ")}) is unique among CURRENT rows (superseded_by is null).`} SQL migration: ${plan.migrationPath}.`
4113
+ `Drizzle tables owned by the ${plan.featureId} feature, derived from ${plan.resource.schemaName} (${plan.specPath}, section G\xE9n\xE9ration): ${plan.tenant === null ? "without tenant column (target.tenancy none, D33: the product is single-tenant, the repository reads whole tables through plainDb)" : `tenant-scoped by ${plan.tenant.column} (TS key \`${plan.tenant.columnKey}\`, the column tenantDb injects and filters)`}.${plan.key === null ? "" : ` The business key ${plan.key.field} is unique per tenant (${plan.key.uniqueName}), the target of every slot and reference foreign key.`}${plan.slots.length === 0 ? "" : ` Slot tables: ${plan.slots.map((slot) => slot.table.sqlName).join(", ")} (cascade with the resource row).`}${plan.references.some((reference) => reference.table !== null) ? ` Reference tables: ${plan.references.flatMap((reference) => reference.table === null ? [] : [reference.table.sqlName]).join(", ")} (a referenced row cannot be deleted).` : ""}${views.length === 0 ? "" : ` Views ${views.map((view) => view.name).join(", ")} are read-only mappings: their SQL is in the migration.`}${plan.appendOnly === null ? "" : ` The append-only key (${plan.appendOnly.key.join(", ")}) is unique among CURRENT rows (superseded_by is null).`} SQL migration: ${plan.migrationPath}.`
4118
4114
  );
4119
4115
  return fileOf(
4120
4116
  tsGeneratedHeader(plan.generatorVersion),
@@ -4142,6 +4138,8 @@ function createTableStatements(table) {
4142
4138
  for (const unique of table.uniques.filter((candidate) => candidate.where !== null)) {
4143
4139
  statements.push(`create unique index ${quote(unique.name)} on ${quote(table.sqlName)} (${unique.columns.map(quote).join(", ")}) where ${unique.where ?? ""};`);
4144
4140
  }
4141
+ const tenantColumn = table.columns.find((column) => column.model === null && column.key !== "id");
4142
+ if (tenantColumn === void 0) return statements;
4145
4143
  statements.push(
4146
4144
  "",
4147
4145
  `alter table ${quote(table.sqlName)} enable row level security;`,
@@ -4160,7 +4158,7 @@ function emitMigration(plan, existingMigration = null) {
4160
4158
  const bodies = viewBodiesOf(existingMigration);
4161
4159
  const adopted = tablesOf(plan).filter((candidate) => candidate.mode === "adopted");
4162
4160
  const intent = wrap(
4163
- `${plan.featureId} feature: the ${plan.table.sqlName} table${tables.length > 1 ? ` and ${tables.slice(1).map((table) => table.sqlName).join(", ")}` : ""}, tenant-scoped by ${tenantOf(plan).column} (derived from ${plan.resource.schemaName}, ${plan.specPath}).${adopted.length === 0 ? "" : ` ${adopted.map((table) => table.sqlName).join(", ")} ${adopted.length > 1 ? "are ADOPTED tables" : "is an ADOPTED table"} (D36): declared in the block, created by the product, altered here within the closed list only.`} Same rails as the socle: foreign key to ${tenantOf(plan).table}, Row-Level Security on every table (AGENTS.md \xA7Multi-tenant 3 \u2014 second rampart, tenantDb remains the first)${plan.appendOnly === null ? "" : ", plus the append-only motif: a partial unique index on the current rows and a DEFERRABLE superseded_by foreign key, so the old row is marked before the new one is inserted"}${views.length === 0 ? "." : `. The views ${views.map((view) => view.name).join(", ")} are HOLES (D32): their SQL stands between the @hole markers below, written by a human, kept at every regeneration; everything else in this file is generated.`}`
4161
+ `${plan.featureId} feature: the ${plan.table.sqlName} table${tables.length > 1 ? ` and ${tables.slice(1).map((table) => table.sqlName).join(", ")}` : ""}, ${plan.tenant === null ? "without tenant column (target.tenancy none, D33)" : `tenant-scoped by ${plan.tenant.column}`} (derived from ${plan.resource.schemaName}, ${plan.specPath}).${adopted.length === 0 ? "" : ` ${adopted.map((table) => table.sqlName).join(", ")} ${adopted.length > 1 ? "are ADOPTED tables" : "is an ADOPTED table"} (D36): declared in the block, created by the product, altered here within the closed list only.`} ${plan.tenant === null ? "No tenant column, no row-level security: the product is single-tenant (D33)" : `Same rails as the socle: foreign key to ${plan.tenant.table}, Row-Level Security on every table (AGENTS.md \xA7Multi-tenant 3 \u2014 second rampart, tenantDb remains the first)`}${plan.appendOnly === null ? "" : ", plus the append-only motif: a partial unique index on the current rows and a DEFERRABLE superseded_by foreign key, so the old row is marked before the new one is inserted"}${views.length === 0 ? "." : `. The views ${views.map((view) => view.name).join(", ")} are HOLES (D32): their SQL stands between the @hole markers below, written by a human, kept at every regeneration; everything else in this file is generated.`}`
4164
4162
  ).map((line, index) => `-- ${index === 0 ? "@intent " : ""}${line}`);
4165
4163
  const statements = [];
4166
4164
  for (const table of tables) statements.push(...statements.length === 0 ? [] : [""], ...createTableStatements(table));
@@ -6898,6 +6896,9 @@ function emitBehaviorTests(plan) {
6898
6896
  }
6899
6897
 
6900
6898
  // src/emit/repository.ts
6899
+ function writtenTypeOf(plan, newType) {
6900
+ return plan.tenant === null ? newType : `Omit<${newType}, ${quote(plan.tenant.columnKey)}>`;
6901
+ }
6901
6902
  function comparatorLines(plan, operation) {
6902
6903
  const order = operation.order;
6903
6904
  if (order === null) return [" return 0;"];
@@ -7036,7 +7037,7 @@ function insertFunctionLines2(plan, operation) {
7036
7037
  const signature = signatureParts(plan);
7037
7038
  const derivedParameter = derived.length === 0 ? "" : `, derived: Pick<${plan.resource.typeName}, ${derived.map(quote).join(" | ")}>`;
7038
7039
  const valuesLines = [
7039
- ` const values: Omit<${plan.table.newType}, ${quote(tenantOf(plan).columnKey)}> = {`,
7040
+ ` const values: ${writtenTypeOf(plan, plan.table.newType)} = {`,
7040
7041
  " id,",
7041
7042
  ...inputFieldsPresent.map((field) => ` ${field}: input.${field},`),
7042
7043
  ...derived.map((field) => ` ${field}: derived.${field},`),
@@ -7146,7 +7147,7 @@ function insertFunctionLines2(plan, operation) {
7146
7147
  " 409,",
7147
7148
  " );",
7148
7149
  " }",
7149
- ` const marking: Partial<Omit<${plan.table.newType}, ${quote(tenantOf(plan).columnKey)}>> = { supersededBy: id };`,
7150
+ ` const marking: Partial<${writtenTypeOf(plan, plan.table.newType)}> = { supersededBy: id };`,
7150
7151
  ` await db.update(${table}).set(marking).where(eq(${table}.id, old.id));`,
7151
7152
  " } else {",
7152
7153
  ` const [existing] = await db`,
@@ -7238,7 +7239,7 @@ function importFunctionLines(plan, operation) {
7238
7239
  }
7239
7240
  lines.push(
7240
7241
  " for (const { row } of rows) {",
7241
- ` const values: Omit<${plan.table.newType}, ${quote(tenantOf(plan).columnKey)}> = {`,
7242
+ ` const values: ${writtenTypeOf(plan, plan.table.newType)} = {`,
7242
7243
  " id: crypto.randomUUID(),",
7243
7244
  ...valueFields.map((field) => ` ${field}: row.${field},`),
7244
7245
  ...appendOnly === null ? [] : [" supersedes: null,", " supersededBy: null,"],
@@ -7275,7 +7276,7 @@ function updateFunctionLines2(plan, operation) {
7275
7276
  `/** ${operation.id} \u2014 update by key (D28): the fields sent are written, the key never changes${plan.signed === null ? "" : ", the signature is renewed (D31)"}. */`,
7276
7277
  `export async function update${plan.resource.typeName}ByKey(ctx: ${plan.context.typeName}, key: ${plan.resource.typeName}[${quote(plan.key.field)}], input: ${operation.inputType}${signature.parameter}): Promise<${plan.table.rowType}> {`,
7277
7278
  ` const row = await load${plan.resource.typeName}ByKey(ctx, key, ${quote(operation.notFound ?? "")});`,
7278
- ` const patch: Partial<Omit<${plan.table.newType}, ${quote(tenantOf(plan).columnKey)}>> = {`,
7279
+ ` const patch: Partial<${writtenTypeOf(plan, plan.table.newType)}> = {`,
7279
7280
  ...fields.map((field) => ` ...(input.${field} === undefined ? {} : { ${field}: input.${field} }),`),
7280
7281
  ...signature.values,
7281
7282
  " };",
@@ -7312,11 +7313,11 @@ function setOrClearFunctionLines2(plan, operation) {
7312
7313
  " }",
7313
7314
  ...idempotent ? [` if (existing !== undefined && existing.${slot.value} === value) return "unchanged";`] : [],
7314
7315
  " if (existing !== undefined) {",
7315
- ` const patch: Partial<Omit<${slot.table.newType}, ${quote(tenantOf(plan).columnKey)}>> = { ${slot.value}: value${signature.values.length === 0 ? "" : `, ${plan.signed?.by ?? ""}: signature.by, ${plan.signed?.at ?? ""}: signature.at`} };`,
7316
+ ` const patch: Partial<${writtenTypeOf(plan, slot.table.newType)}> = { ${slot.value}: value${signature.values.length === 0 ? "" : `, ${plan.signed?.by ?? ""}: signature.by, ${plan.signed?.at ?? ""}: signature.at`} };`,
7316
7317
  ` await db.update(${table}).set(patch).where(${whereExisting});`,
7317
7318
  ` return "set";`,
7318
7319
  " }",
7319
- ` const values: Omit<${slot.table.newType}, ${quote(tenantOf(plan).columnKey)}> = {`,
7320
+ ` const values: ${writtenTypeOf(plan, slot.table.newType)} = {`,
7320
7321
  ...slot.table.hasId ? [" id: crypto.randomUUID(),"] : [],
7321
7322
  ` ${slot.parentKey}: parent.${plan.key.field},`,
7322
7323
  ` ${slot.key}: slotKey,`,
@@ -7383,7 +7384,7 @@ function referenceLines2(plan, reference) {
7383
7384
  "",
7384
7385
  `/** One ${reference.name} row pointing at a resource key \u2014 what a test arranges to prove \xAB ligne r\xE9f\xE9renc\xE9e \xBB. */`,
7385
7386
  `export async function insert${typeName}(ctx: ${plan.context.typeName}, values: Pick<${reference.table.newType}, ${writtenColumns2.map(quote).join(" | ")}>): Promise<${reference.table.rowType}> {`,
7386
- ` const inserted: Omit<${reference.table.newType}, ${quote(tenantOf(plan).columnKey)}> = { ...values };`,
7387
+ ` const inserted: ${writtenTypeOf(plan, reference.table.newType)} = { ...values };`,
7387
7388
  ` const [row] = await tenantDb(ctx).insert(${reference.table.tsName}).values(inserted).returning();`,
7388
7389
  " if (row === undefined) throwOgygieError(insertReturnedNothing());",
7389
7390
  " return row;",
@@ -7411,7 +7412,7 @@ function arrangeLines2(plan, target) {
7411
7412
  `export async function arrange${target.typeName}Rows(ctx: ${plan.context.typeName}, rows: readonly ${target.withId ? `Omit<${target.typeName}, "id">` : target.typeName}[]): Promise<${target.rowType}[]> {`,
7412
7413
  ` const inserted: ${target.rowType}[] = [];`,
7413
7414
  " for (const row of rows) {",
7414
- ` const values: Omit<${valuesType}, ${quote(tenantOf(plan).columnKey)}> = {`,
7415
+ ` const values: ${writtenTypeOf(plan, valuesType)} = {`,
7415
7416
  ...target.withId ? [" id: crypto.randomUUID(),"] : [],
7416
7417
  ...target.fields.filter((field) => !(target.withId && field.name === "id")).map((field) => ` ${field.name}: ${insertExpressionOf(field)},`),
7417
7418
  " };",
@@ -7476,18 +7477,21 @@ function emitRepository(plan) {
7476
7477
  if (setOrClear !== void 0) sections.push("", ...setOrClearFunctionLines2(plan, setOrClear));
7477
7478
  if (deleteOperation !== void 0) sections.push("", ...deleteFunctionLines2(plan, deleteOperation));
7478
7479
  if (importOperation !== void 0) sections.push("", ...importFunctionLines(plan, importOperation));
7480
+ const noTenant = plan.tenant === null;
7481
+ const handleType = noTenant ? plan.databasePort?.typeName ?? "Database" : plan.context.typeName;
7482
+ const finalSections = noTenant ? sections.map((line) => line.replace(/\btenantDb\(ctx\)/gu, "plainDb(db)").replace(/\bctx\b/gu, "db").replaceAll(`db: ${plan.context.typeName}`, `db: ${handleType}`)) : sections;
7479
7483
  return fileOf(
7480
7484
  tsGeneratedHeader(plan.generatorVersion),
7481
7485
  intentBlock(
7482
7486
  wrap(
7483
- `Persistence of the ${plan.featureId} feature \u2014 the only file of the feature allowed to touch the database, always through tenantDb: the tenant column is injected on insert and filtered on every read, never written by hand (AGENTS.md \xA7Multi-tenant).${plan.appendOnly === null ? "" : ` The append-only motif appendOnlySupersedes on (${plan.appendOnly.key.join(", ")}): current rows per key, supersede by marking the old row BEFORE inserting the new one.`}${plan.importMotif === null ? "" : " The all-or-nothing import: one transaction or nothing."}${plan.key === null ? "" : ` The keyed writes of D28 address a row by ${plan.key.field} and answer the operation's 404 otherwise.`}${plan.unique === null ? "" : ` uniqueKey: 409 ${plan.unique.error} on a taken key.`}${plan.referenced === null ? "" : ` refuseWhenReferenced: 409 ${plan.referenced.error} while a ${plan.referenced.reference.name} row points at the row.`}${plan.signed === null ? "" : ` signedWrite: ${plan.signed.by} and ${plan.signed.at} on every write.`}${views.length === 0 ? "" : ` The views ${views.map((view) => view.name).join(", ")} are read through their read-only mappings (D32).`} Derived from ${plan.specPath}.`
7487
+ `Persistence of the ${plan.featureId} feature \u2014 the only file of the feature allowed to touch the database, ${noTenant ? "always through plainDb: the product is single-tenant (target.tenancy none, D33), the whole table is read and written through the one facade, never a raw query builder" : "always through tenantDb: the tenant column is injected on insert and filtered on every read, never written by hand (AGENTS.md \xA7Multi-tenant)"}.${plan.appendOnly === null ? "" : ` The append-only motif appendOnlySupersedes on (${plan.appendOnly.key.join(", ")}): current rows per key, supersede by marking the old row BEFORE inserting the new one.`}${plan.importMotif === null ? "" : " The all-or-nothing import: one transaction or nothing."}${plan.key === null ? "" : ` The keyed writes of D28 address a row by ${plan.key.field} and answer the operation's 404 otherwise.`}${plan.unique === null ? "" : ` uniqueKey: 409 ${plan.unique.error} on a taken key.`}${plan.referenced === null ? "" : ` refuseWhenReferenced: 409 ${plan.referenced.error} while a ${plan.referenced.reference.name} row points at the row.`}${plan.signed === null ? "" : ` signedWrite: ${plan.signed.by} and ${plan.signed.at} on every write.`}${views.length === 0 ? "" : ` The views ${views.map((view) => view.name).join(", ")} are read through their read-only mappings (D32).`} Derived from ${plan.specPath}.`
7484
7488
  )
7485
7489
  ),
7486
7490
  drizzleImports.size === 0 ? null : `import { ${[...drizzleImports].sort().join(", ")} } from "drizzle-orm";`,
7487
7491
  'import type { Clock } from "@ogygie/core/clock";',
7488
7492
  'import { throwOgygieError } from "@ogygie/core/errors";',
7489
- 'import { tenantDb } from "@ogygie/core/tenant";',
7490
- `import type { ${plan.context.typeName} } from ${quote(plan.context.importPath)};`,
7493
+ noTenant ? 'import { plainDb } from "@ogygie/core/tenant";' : 'import { tenantDb } from "@ogygie/core/tenant";',
7494
+ noTenant ? `import type { ${handleType} } from ${quote(plan.databasePort?.importPath ?? "../../db.js")};` : `import type { ${plan.context.typeName} } from ${quote(plan.context.importPath)};`,
7491
7495
  "import {",
7492
7496
  ...tableImports.map((line) => ` ${line},`),
7493
7497
  '} from "./db.schema.gen.js";',
@@ -7522,7 +7526,7 @@ function emitRepository(plan) {
7522
7526
  ` suggestedFix: "Check the migration ${plan.migrationFileName} was applied to this database.",`,
7523
7527
  " };",
7524
7528
  "}",
7525
- ...sections
7529
+ ...finalSections
7526
7530
  );
7527
7531
  }
7528
7532
 
@@ -11847,9 +11851,23 @@ async function fillLogicHoles(project, featureId, argv, out, deps) {
11847
11851
  }
11848
11852
  });
11849
11853
  const summary = await fillFeature(inputs, fillDeps, wiring.options);
11854
+ for (const path of refreshHoleDocs(project.root, folder, plan, loadHolesLibrary(wiring.libraryDir))) out.log(` r\xE9\xE9crite ${path}`);
11850
11855
  report(wiring, summary, { unit: "trou", human: "HUMAIN (todo)" });
11851
11856
  return summary.unfilled === 0 ? 0 : 1;
11852
11857
  }
11858
+ function refreshHoleDocs(projectRoot, folder, plan, library) {
11859
+ const changed = [];
11860
+ for (const hole of plan.holes) {
11861
+ const relativePath = `${folder}/holes/${hole.id}.gen.md`;
11862
+ const path = join6(projectRoot, relativePath);
11863
+ const content = emitHoleDoc(plan, hole, library);
11864
+ if (existsSync5(path) && readFileSync6(path, "utf8") === content) continue;
11865
+ mkdirSync3(join6(projectRoot, folder, "holes"), { recursive: true });
11866
+ writeFileSync3(path, content, "utf8");
11867
+ changed.push(relativePath);
11868
+ }
11869
+ return changed;
11870
+ }
11853
11871
  function viewContextOf(projectRoot, plan, view) {
11854
11872
  const docPath = join6(projectRoot, plan.folder, "holes", `${view.hole.id}.gen.md`);
11855
11873
  const doc = existsSync5(docPath) ? readFileSync6(docPath, "utf8") : `# ${view.hole.id}`;
@@ -1,3 +1,4 @@
1
+ import { type FeaturePlan } from "../emit/plan.js";
1
2
  import type { CustomViewPlan, ScreenPlan } from "../emit/screen-plan.js";
2
3
  import { type HoleLibraryEntry } from "../hole-shape.js";
3
4
  import { type FillOptions } from "../fill/fill.js";
@@ -46,6 +47,8 @@ export interface FillCommandDeps {
46
47
  }
47
48
  /** An entry recorded in the library: a new file, or the provenance of an existing one extended. */
48
49
  export declare function recordLibraryEntry(libraryDir: string, entry: HoleLibraryEntry): "created" | "extended" | "unchanged";
50
+ /** Re-emits the `holes/<id>.gen.md` of a feature against the library as it stands; answers the repo-relative paths it changed. */
51
+ export declare function refreshHoleDocs(projectRoot: string, folder: string, plan: FeaturePlan, library: readonly HoleLibraryEntry[]): string[];
49
52
  /** The context a view candidate is drawn on: the view's hole doc, then the product's pattern catalogue when the repo keeps one (D53). */
50
53
  export declare function viewContextOf(projectRoot: string, plan: ScreenPlan, view: CustomViewPlan): string;
51
54
  export declare function runFillCommand(project: GenerateProject, featureId: string | undefined, argv: readonly string[], out: CommandOutput, deps?: FillCommandDeps): Promise<number>;
package/dist/cli/run.js CHANGED
@@ -37,7 +37,7 @@ import {
37
37
  throwOgygieError,
38
38
  verifyGeneration,
39
39
  writeExtensionRegistries
40
- } from "../chunk-MI725PT3.js";
40
+ } from "../chunk-VPJEACPK.js";
41
41
 
42
42
  // src/cli/check-command.ts
43
43
  import { existsSync, readFileSync, readdirSync } from "node:fs";
package/dist/index.js CHANGED
@@ -193,7 +193,7 @@ import {
193
193
  viewCandidateTextOf,
194
194
  viewExampleTestName,
195
195
  vocabularyOf
196
- } from "./chunk-MI725PT3.js";
196
+ } from "./chunk-VPJEACPK.js";
197
197
 
198
198
  // src/prompt-card.ts
199
199
  var phrase = (caseKey) => caseKey.replace(/^with:/u, "avec ").replace(/^without:/u, "sans ");
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ogygie/generate",
3
- "version": "0.33.0",
3
+ "version": "0.34.1",
4
4
  "description": "Ogygie generator: reads the `# Génération` block of a spec and its schemas.ts, derives everything deterministic without a model (routes, pipeline, database, factories, tests, screens, previews), fills the typed holes of logic.ts by library, draw and escalation, and draws the first schemas.ts of a new feature — judged by the gates. Sixth package of the lockstep (D55).",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -29,7 +29,7 @@
29
29
  }
30
30
  },
31
31
  "dependencies": {
32
- "@ogygie/core": "0.33.0",
32
+ "@ogygie/core": "0.34.1",
33
33
  "tsx": "^4.20.0",
34
34
  "yaml": "^2.9.0",
35
35
  "zod": "^4.0.0"
@@ -38,7 +38,7 @@
38
38
  "@lingui/babel-plugin-lingui-macro": "^5.9.5",
39
39
  "@lingui/core": "^5.9.5",
40
40
  "@lingui/react": "^5.9.5",
41
- "@ogygie/ui": "0.33.0",
41
+ "@ogygie/ui": "0.34.1",
42
42
  "@starter/api": "0.1.0",
43
43
  "@tanstack/react-query": "^5.102.2",
44
44
  "@tanstack/react-router": "^1.170.32",