@drzl/cli 4.21.0 → 4.23.0

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.
@@ -0,0 +1,350 @@
1
+ import {
2
+ tableSchemas
3
+ } from "./chunk-KKPDOZOD.js";
4
+
5
+ // ../generator-fastify/dist/index.js
6
+ import { fileWriter } from "@drzl/validation-core";
7
+ import { formatCode, importSpecifier, selectColumns } from "@drzl/validation-core";
8
+ var APP_MODULE = "index";
9
+ var lit = (v) => /['\\]/.test(v) ? JSON.stringify(v) : `'${v}'`;
10
+ var NUMERIC_SEGMENT_PATTERN = "^-?\\d+(\\.\\d+)?$";
11
+ var BIGINT_SEGMENT_PATTERN = "^-?\\d+$";
12
+ var NOT_FOUND_SCHEMA = "{ type: 'object', properties: { message: { type: 'string' } }, required: ['message'], additionalProperties: false }";
13
+ var cap = (s) => s.charAt(0).toUpperCase() + s.slice(1);
14
+ var isIdent = (s) => /^[A-Za-z_$][A-Za-z0-9_$]*$/.test(s);
15
+ function keyColumns(table) {
16
+ const names = table.primaryKey?.columns ?? [];
17
+ if (!names.length) return null;
18
+ const cols = names.map((n) => table.columns.find((c) => c.name === n));
19
+ if (cols.some((c) => !c)) return null;
20
+ return cols;
21
+ }
22
+ function segmentSchema(column) {
23
+ if (column.enumValues && column.enumValues.length) return { enum: [...column.enumValues] };
24
+ switch (column.tsType) {
25
+ case "number":
26
+ return { type: "string", pattern: NUMERIC_SEGMENT_PATTERN };
27
+ case "bigint":
28
+ return { type: "string", pattern: BIGINT_SEGMENT_PATTERN };
29
+ case "Date":
30
+ return { type: "string", format: "date-time" };
31
+ default:
32
+ return { type: "string" };
33
+ }
34
+ }
35
+ function paramsSchema(cols) {
36
+ return {
37
+ type: "object",
38
+ properties: Object.fromEntries(cols.map((c) => [c.name, segmentSchema(c)])),
39
+ required: cols.map((c) => c.name),
40
+ additionalProperties: false
41
+ };
42
+ }
43
+ function adaptForFastify(schema) {
44
+ const { $schema: _dialect, $id: _id, ...rest } = walk(schema);
45
+ return rest;
46
+ }
47
+ function walk(value) {
48
+ if (Array.isArray(value)) return value.map(walk);
49
+ if (value && typeof value === "object") {
50
+ const out = {};
51
+ for (const [k, v] of Object.entries(value)) {
52
+ if (k === "prefixItems") continue;
53
+ out[k] = walk(v);
54
+ }
55
+ const prefix = value.prefixItems;
56
+ if (Array.isArray(prefix) && prefix.length) out.items = walk(prefix[0]);
57
+ return out;
58
+ }
59
+ return value;
60
+ }
61
+ function rowFieldType(column) {
62
+ if (column.enumValues && column.enumValues.length) {
63
+ return column.enumValues.map((v) => `'${v.replace(/'/g, "\\'")}'`).join(" | ");
64
+ }
65
+ const s = column.shape;
66
+ if (s) {
67
+ switch (s.kind) {
68
+ case "tuple":
69
+ return `[${Array.from({ length: s.length }, () => "number").join(", ")}]`;
70
+ case "numberObject":
71
+ return `{ ${s.fields.map((f) => `${f}: number`).join("; ")} }`;
72
+ case "numberVector":
73
+ return "number[]";
74
+ default:
75
+ return "unknown";
76
+ }
77
+ }
78
+ switch (column.tsType) {
79
+ case "number":
80
+ return "number";
81
+ case "string":
82
+ return "string";
83
+ case "boolean":
84
+ return "boolean";
85
+ case "Date":
86
+ return "Date";
87
+ case "bigint":
88
+ return "bigint";
89
+ default:
90
+ return "unknown";
91
+ }
92
+ }
93
+ function objectKey(name) {
94
+ return isIdent(name) ? name : JSON.stringify(name);
95
+ }
96
+ function toCase(s, c) {
97
+ if (!c) return s;
98
+ const parts = s.replace(/([a-z0-9])([A-Z])/g, "$1 $2").replace(/[_-]/g, " ").split(/\s+/);
99
+ if (c === "camel") {
100
+ return parts.map(
101
+ (p, i) => i === 0 ? p.toLowerCase() : p.charAt(0).toUpperCase() + p.slice(1).toLowerCase()
102
+ ).join("");
103
+ }
104
+ if (c === "kebab") return parts.map((p) => p.toLowerCase()).join("-");
105
+ if (c === "snake") return parts.map((p) => p.toLowerCase()).join("_");
106
+ return s;
107
+ }
108
+ function routesExportName(table, naming) {
109
+ const base = `${table.tsName}${naming?.routerSuffix ?? "Routes"}`;
110
+ const c = naming?.procedureCase;
111
+ return toCase(base, c === "kebab" ? "camel" : c);
112
+ }
113
+ function mountPath(table, naming) {
114
+ return `/${toCase(table.tsName, naming?.procedureCase)}`;
115
+ }
116
+ var FastifyGenerator = class {
117
+ constructor(analysis) {
118
+ this.analysis = analysis;
119
+ }
120
+ async generate(opts) {
121
+ const fs = fileWriter(opts.fileSink);
122
+ const path = await import("path");
123
+ const out = path.resolve(process.cwd(), opts.outputDir);
124
+ const ctx = { out };
125
+ await fs.mkdir(out, { recursive: true });
126
+ const files = [];
127
+ const write = async (filePath, content) => {
128
+ const formatted = await formatCode(
129
+ buildHeader(opts.outputHeader) + content,
130
+ filePath,
131
+ opts.format
132
+ );
133
+ await fs.writeFile(filePath, formatted, "utf8");
134
+ files.push(filePath);
135
+ };
136
+ const barrelPath = path.join(out, `${APP_MODULE}.ts`);
137
+ const modules = [];
138
+ const total = this.analysis.tables.length;
139
+ let index = 0;
140
+ for (const table of this.analysis.tables) {
141
+ const base = `${table.tsName}${opts.naming?.routerSuffix ?? ""}`;
142
+ const filePath = path.join(out, `${toCase(base, opts.naming?.procedureCase)}.ts`);
143
+ if (filePath === barrelPath) {
144
+ throw new Error(
145
+ `@drzl/generator-fastify: the routes for table "${table.name}" would be written to ${filePath}, which is the barrel this generator also writes. Set naming.routerSuffix to move it out of the way.`
146
+ );
147
+ }
148
+ await write(filePath, renderRoutes(table, opts));
149
+ modules.push({ table, filePath, exportName: routesExportName(table, opts.naming) });
150
+ index++;
151
+ opts.onProgress?.({ index, total, table: table.name, filePath });
152
+ }
153
+ await write(barrelPath, renderBarrel(modules, ctx, path, opts));
154
+ return { files };
155
+ }
156
+ };
157
+ var index_default = FastifyGenerator;
158
+ function buildHeader(h) {
159
+ if (h && h.enabled === false) return "";
160
+ const text = h?.text?.trim();
161
+ const lines = text ? text.split(/\r?\n/).map((l) => `// ${l}`) : [
162
+ "// Generated by DRZL (@drzl/*)",
163
+ "// Generated output is granted to you under your project's license.",
164
+ "// You may use, copy, modify, and distribute without attribution."
165
+ ];
166
+ return lines.join("\n") + "\n\n";
167
+ }
168
+ function renderRoutes(table, opts) {
169
+ const insertName = `Insert${table.tsName}Schema`;
170
+ const updateName = `Update${table.tsName}Schema`;
171
+ const selectName = `Select${table.tsName}Schema`;
172
+ const paramsName = `${cap(table.tsName)}ParamsSchema`;
173
+ const rowType = `Select${table.tsName}Row`;
174
+ const writable = !table.readOnly;
175
+ const key = keyColumns(table);
176
+ const routes = [];
177
+ const notImplemented = (what) => `throw new Error('Not implemented: ${what} ${table.tsName}.');`;
178
+ const paramHint = `// Fastify has already validated req.params against ${paramsName}; numeric key segments stay strings here.`;
179
+ routes.push({
180
+ name: "list",
181
+ method: "get",
182
+ path: "/",
183
+ schema: [`response: { 200: { type: 'array', items: ${selectName} } }`],
184
+ replyType: `${rowType}[]`,
185
+ // The stub states its contract twice over: the annotated local is what a reader sees, and the
186
+ // Reply generic is what Fastify's own types hold the handler to. The response schema is what
187
+ // the serializer runs; nothing infers a client from any of them, which the docs say plainly.
188
+ body: [`const rows: ${rowType}[] = [];`, "return rows;"]
189
+ });
190
+ if (key) {
191
+ const keyPath = "/" + key.map((c) => `:${c.name}`).join("/");
192
+ routes.push({
193
+ name: "byId",
194
+ method: "get",
195
+ path: keyPath,
196
+ schema: [
197
+ `params: ${paramsName}`,
198
+ `response: { 200: ${selectName}, 404: ${NOT_FOUND_SCHEMA} }`
199
+ ],
200
+ replyType: `${rowType} | { message: string }`,
201
+ body: [
202
+ paramHint,
203
+ `const row: ${rowType} | null = null;`,
204
+ "if (row !== null) return row;",
205
+ `return reply.code(404).send({ message: ${lit(`${table.tsName} row not found`)} });`
206
+ ]
207
+ });
208
+ if (writable) {
209
+ routes.push({
210
+ name: "update",
211
+ method: "patch",
212
+ path: keyPath,
213
+ schema: [
214
+ `params: ${paramsName}`,
215
+ `body: ${updateName}`,
216
+ `response: { 200: ${selectName} }`
217
+ ],
218
+ replyType: rowType,
219
+ body: [notImplemented("update")]
220
+ });
221
+ routes.push({
222
+ name: "delete",
223
+ method: "delete",
224
+ path: keyPath,
225
+ schema: [`params: ${paramsName}`, `response: { 200: { type: 'boolean' } }`],
226
+ replyType: "boolean",
227
+ body: [paramHint, "return true;"]
228
+ });
229
+ }
230
+ }
231
+ if (writable) {
232
+ routes.push({
233
+ name: "create",
234
+ method: "post",
235
+ path: "/",
236
+ schema: [`body: ${insertName}`, `response: { 200: ${selectName} }`],
237
+ replyType: rowType,
238
+ body: [notImplemented("create")]
239
+ });
240
+ }
241
+ if (opts.includeRelations) {
242
+ routes.push(...relationRoutes(table, rowType, selectName, opts));
243
+ }
244
+ const order = ["list", "byId", "create", "update", "delete"];
245
+ const rank = (n) => order.indexOf(n) === -1 ? order.length : order.indexOf(n);
246
+ routes.sort((a, b) => rank(a.name) - rank(b.name));
247
+ const exportName = routesExportName(table, opts.naming);
248
+ const statements = routes.map((r) => {
249
+ const reads = (what) => r.body.some((line) => !line.startsWith("//") && what.test(line));
250
+ const params = reads(/\breply\./) ? reads(/\breq\./) ? "(req, reply)" : "(_req, reply)" : reads(/\breq\./) ? "(req)" : "()";
251
+ return [
252
+ ` app.${r.method}<{ Reply: ${r.replyType} }>(${lit(r.path)}, {`,
253
+ ` schema: { ${r.schema.join(", ")} },`,
254
+ ` }, async ${params} => {`,
255
+ ...r.body.map((line) => ` ${line}`),
256
+ ` });`
257
+ ].join("\n");
258
+ }).join("\n\n");
259
+ const plugin = `export const ${exportName}: FastifyPluginAsync = async (app) => {
260
+ ${statements}
261
+ };
262
+ `;
263
+ const schemas = tableSchemas(table);
264
+ const declared = [];
265
+ const emit = (name, schema) => `export const ${name} = ${JSON.stringify(adaptForFastify(schema), null, 2)} as const;`;
266
+ if (writable) {
267
+ declared.push(emit(insertName, schemas.insert));
268
+ declared.push(emit(updateName, schemas.update));
269
+ }
270
+ declared.push(emit(selectName, schemas.select));
271
+ if (key) {
272
+ declared.push(emit(paramsName, paramsSchema(key)));
273
+ }
274
+ const rowFields = selectColumns(table).map((c) => ` ${objectKey(c.name)}: ${rowFieldType(c)}${c.nullable ? " | null" : ""};`).join("\n");
275
+ declared.push(`export interface ${rowType} {
276
+ ${rowFields}
277
+ }`);
278
+ const wide = selectColumns(table).filter((c) => rowFieldType(c) === "unknown").map((c) => c.name);
279
+ const wideNote = wide.length ? `// No precise type for ${wide.length === 1 ? "this column" : "these columns"}: ${wide.join(", ")}.
280
+ // DRZL could not derive one from the schema, so these routes carry it as unknown and its
281
+ // schema constrains only what the builder could state.
282
+ ` : "";
283
+ return `// Generated by @drzl/generator-fastify
284
+ // Routes for table: ${table.name}
285
+ ${wideNote}import type { FastifyPluginAsync } from 'fastify';
286
+
287
+ ${declared.join("\n\n")}
288
+
289
+ ${plugin}`;
290
+ }
291
+ function relationRoutes(table, rowType, selectName, opts) {
292
+ const out = [];
293
+ const taken = /* @__PURE__ */ new Set();
294
+ for (const fk of table.foreignKeys ?? []) {
295
+ if (fk.columns.length !== 1) continue;
296
+ const colName = fk.columns[0];
297
+ const column = table.columns.find((c) => c.name === colName);
298
+ if (!column) continue;
299
+ const segment = toCase(`by-${colName}`, opts.naming?.procedureCase ?? "kebab");
300
+ if (taken.has(segment)) continue;
301
+ taken.add(segment);
302
+ const params = JSON.stringify(paramsSchema([column]));
303
+ out.push({
304
+ name: `listBy${cap(colName)}`,
305
+ method: "get",
306
+ path: `/${segment}/:${colName}`,
307
+ schema: [`params: ${params}`, `response: { 200: { type: 'array', items: ${selectName} } }`],
308
+ replyType: `${rowType}[]`,
309
+ body: [`const rows: ${rowType}[] = [];`, "return rows;"]
310
+ });
311
+ }
312
+ return out;
313
+ }
314
+ function renderBarrel(modules, ctx, path, opts) {
315
+ if (!modules.length) {
316
+ return `// Generated by @drzl/generator-fastify
317
+ // No tables detected in analysis. Add tables to your schema and regenerate.
318
+ import type { FastifyPluginAsync } from 'fastify';
319
+
320
+ export const routes: FastifyPluginAsync = async () => {};
321
+ `;
322
+ }
323
+ const entries = modules.map(({ filePath, exportName, table }) => ({
324
+ rel: importSpecifier(
325
+ "./" + path.relative(ctx.out, filePath).replace(/\\/g, "/"),
326
+ opts.importExtension
327
+ ),
328
+ exportName,
329
+ mount: mountPath(table, opts.naming)
330
+ }));
331
+ const imports = entries.map((e) => `import { ${e.exportName} } from '${e.rel}';`).join("\n");
332
+ const registrations = entries.map((e) => ` app.register(${e.exportName}, { prefix: ${lit(e.mount)} });`).join("\n");
333
+ const reExports = entries.map((e) => `export * from '${e.rel}';`).join("\n");
334
+ return `// Generated by @drzl/generator-fastify
335
+ import type { FastifyPluginAsync } from 'fastify';
336
+ ${imports}
337
+
338
+ export const routes: FastifyPluginAsync = async (app) => {
339
+ ${registrations}
340
+ };
341
+
342
+ ${reExports}
343
+ `;
344
+ }
345
+ export {
346
+ APP_MODULE,
347
+ FastifyGenerator,
348
+ index_default as default
349
+ };
350
+ //# sourceMappingURL=dist-KQMPKOFK.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../generator-fastify/dist/index.js"],"sourcesContent":["// src/index.ts\nimport { fileWriter } from \"@drzl/validation-core\";\nimport { tableSchemas } from \"@drzl/generator-json-schema\";\nimport { formatCode, importSpecifier, selectColumns } from \"@drzl/validation-core\";\nvar APP_MODULE = \"index\";\nvar lit = (v) => /['\\\\]/.test(v) ? JSON.stringify(v) : `'${v}'`;\nvar NUMERIC_SEGMENT_PATTERN = \"^-?\\\\d+(\\\\.\\\\d+)?$\";\nvar BIGINT_SEGMENT_PATTERN = \"^-?\\\\d+$\";\nvar NOT_FOUND_SCHEMA = \"{ type: 'object', properties: { message: { type: 'string' } }, required: ['message'], additionalProperties: false }\";\nvar cap = (s) => s.charAt(0).toUpperCase() + s.slice(1);\nvar isIdent = (s) => /^[A-Za-z_$][A-Za-z0-9_$]*$/.test(s);\nfunction keyColumns(table) {\n const names = table.primaryKey?.columns ?? [];\n if (!names.length) return null;\n const cols = names.map((n) => table.columns.find((c) => c.name === n));\n if (cols.some((c) => !c)) return null;\n return cols;\n}\nfunction segmentSchema(column) {\n if (column.enumValues && column.enumValues.length) return { enum: [...column.enumValues] };\n switch (column.tsType) {\n case \"number\":\n return { type: \"string\", pattern: NUMERIC_SEGMENT_PATTERN };\n case \"bigint\":\n return { type: \"string\", pattern: BIGINT_SEGMENT_PATTERN };\n case \"Date\":\n return { type: \"string\", format: \"date-time\" };\n default:\n return { type: \"string\" };\n }\n}\nfunction paramsSchema(cols) {\n return {\n type: \"object\",\n properties: Object.fromEntries(cols.map((c) => [c.name, segmentSchema(c)])),\n required: cols.map((c) => c.name),\n additionalProperties: false\n };\n}\nfunction adaptForFastify(schema) {\n const { $schema: _dialect, $id: _id, ...rest } = walk(schema);\n return rest;\n}\nfunction walk(value) {\n if (Array.isArray(value)) return value.map(walk);\n if (value && typeof value === \"object\") {\n const out = {};\n for (const [k, v] of Object.entries(value)) {\n if (k === \"prefixItems\") continue;\n out[k] = walk(v);\n }\n const prefix = value.prefixItems;\n if (Array.isArray(prefix) && prefix.length) out.items = walk(prefix[0]);\n return out;\n }\n return value;\n}\nfunction rowFieldType(column) {\n if (column.enumValues && column.enumValues.length) {\n return column.enumValues.map((v) => `'${v.replace(/'/g, \"\\\\'\")}'`).join(\" | \");\n }\n const s = column.shape;\n if (s) {\n switch (s.kind) {\n case \"tuple\":\n return `[${Array.from({ length: s.length }, () => \"number\").join(\", \")}]`;\n case \"numberObject\":\n return `{ ${s.fields.map((f) => `${f}: number`).join(\"; \")} }`;\n case \"numberVector\":\n return \"number[]\";\n default:\n return \"unknown\";\n }\n }\n switch (column.tsType) {\n case \"number\":\n return \"number\";\n case \"string\":\n return \"string\";\n case \"boolean\":\n return \"boolean\";\n case \"Date\":\n return \"Date\";\n case \"bigint\":\n return \"bigint\";\n default:\n return \"unknown\";\n }\n}\nfunction objectKey(name) {\n return isIdent(name) ? name : JSON.stringify(name);\n}\nfunction toCase(s, c) {\n if (!c) return s;\n const parts = s.replace(/([a-z0-9])([A-Z])/g, \"$1 $2\").replace(/[_-]/g, \" \").split(/\\s+/);\n if (c === \"camel\") {\n return parts.map(\n (p, i) => i === 0 ? p.toLowerCase() : p.charAt(0).toUpperCase() + p.slice(1).toLowerCase()\n ).join(\"\");\n }\n if (c === \"kebab\") return parts.map((p) => p.toLowerCase()).join(\"-\");\n if (c === \"snake\") return parts.map((p) => p.toLowerCase()).join(\"_\");\n return s;\n}\nfunction routesExportName(table, naming) {\n const base = `${table.tsName}${naming?.routerSuffix ?? \"Routes\"}`;\n const c = naming?.procedureCase;\n return toCase(base, c === \"kebab\" ? \"camel\" : c);\n}\nfunction mountPath(table, naming) {\n return `/${toCase(table.tsName, naming?.procedureCase)}`;\n}\nvar FastifyGenerator = class {\n constructor(analysis) {\n this.analysis = analysis;\n }\n async generate(opts) {\n const fs = fileWriter(opts.fileSink);\n const path = await import(\"path\");\n const out = path.resolve(process.cwd(), opts.outputDir);\n const ctx = { out };\n await fs.mkdir(out, { recursive: true });\n const files = [];\n const write = async (filePath, content) => {\n const formatted = await formatCode(\n buildHeader(opts.outputHeader) + content,\n filePath,\n opts.format\n );\n await fs.writeFile(filePath, formatted, \"utf8\");\n files.push(filePath);\n };\n const barrelPath = path.join(out, `${APP_MODULE}.ts`);\n const modules = [];\n const total = this.analysis.tables.length;\n let index = 0;\n for (const table of this.analysis.tables) {\n const base = `${table.tsName}${opts.naming?.routerSuffix ?? \"\"}`;\n const filePath = path.join(out, `${toCase(base, opts.naming?.procedureCase)}.ts`);\n if (filePath === barrelPath) {\n throw new Error(\n `@drzl/generator-fastify: the routes for table \"${table.name}\" would be written to ${filePath}, which is the barrel this generator also writes. Set naming.routerSuffix to move it out of the way.`\n );\n }\n await write(filePath, renderRoutes(table, opts));\n modules.push({ table, filePath, exportName: routesExportName(table, opts.naming) });\n index++;\n opts.onProgress?.({ index, total, table: table.name, filePath });\n }\n await write(barrelPath, renderBarrel(modules, ctx, path, opts));\n return { files };\n }\n};\nvar index_default = FastifyGenerator;\nfunction buildHeader(h) {\n if (h && h.enabled === false) return \"\";\n const text = h?.text?.trim();\n const lines = text ? text.split(/\\r?\\n/).map((l) => `// ${l}`) : [\n \"// Generated by DRZL (@drzl/*)\",\n \"// Generated output is granted to you under your project's license.\",\n \"// You may use, copy, modify, and distribute without attribution.\"\n ];\n return lines.join(\"\\n\") + \"\\n\\n\";\n}\nfunction renderRoutes(table, opts) {\n const insertName = `Insert${table.tsName}Schema`;\n const updateName = `Update${table.tsName}Schema`;\n const selectName = `Select${table.tsName}Schema`;\n const paramsName = `${cap(table.tsName)}ParamsSchema`;\n const rowType = `Select${table.tsName}Row`;\n const writable = !table.readOnly;\n const key = keyColumns(table);\n const routes = [];\n const notImplemented = (what) => `throw new Error('Not implemented: ${what} ${table.tsName}.');`;\n const paramHint = `// Fastify has already validated req.params against ${paramsName}; numeric key segments stay strings here.`;\n routes.push({\n name: \"list\",\n method: \"get\",\n path: \"/\",\n schema: [`response: { 200: { type: 'array', items: ${selectName} } }`],\n replyType: `${rowType}[]`,\n // The stub states its contract twice over: the annotated local is what a reader sees, and the\n // Reply generic is what Fastify's own types hold the handler to. The response schema is what\n // the serializer runs; nothing infers a client from any of them, which the docs say plainly.\n body: [`const rows: ${rowType}[] = [];`, \"return rows;\"]\n });\n if (key) {\n const keyPath = \"/\" + key.map((c) => `:${c.name}`).join(\"/\");\n routes.push({\n name: \"byId\",\n method: \"get\",\n path: keyPath,\n schema: [\n `params: ${paramsName}`,\n `response: { 200: ${selectName}, 404: ${NOT_FOUND_SCHEMA} }`\n ],\n replyType: `${rowType} | { message: string }`,\n body: [\n paramHint,\n `const row: ${rowType} | null = null;`,\n \"if (row !== null) return row;\",\n `return reply.code(404).send({ message: ${lit(`${table.tsName} row not found`)} });`\n ]\n });\n if (writable) {\n routes.push({\n name: \"update\",\n method: \"patch\",\n path: keyPath,\n schema: [\n `params: ${paramsName}`,\n `body: ${updateName}`,\n `response: { 200: ${selectName} }`\n ],\n replyType: rowType,\n body: [notImplemented(\"update\")]\n });\n routes.push({\n name: \"delete\",\n method: \"delete\",\n path: keyPath,\n schema: [`params: ${paramsName}`, `response: { 200: { type: 'boolean' } }`],\n replyType: \"boolean\",\n body: [paramHint, \"return true;\"]\n });\n }\n }\n if (writable) {\n routes.push({\n name: \"create\",\n method: \"post\",\n path: \"/\",\n schema: [`body: ${insertName}`, `response: { 200: ${selectName} }`],\n replyType: rowType,\n body: [notImplemented(\"create\")]\n });\n }\n if (opts.includeRelations) {\n routes.push(...relationRoutes(table, rowType, selectName, opts));\n }\n const order = [\"list\", \"byId\", \"create\", \"update\", \"delete\"];\n const rank = (n) => order.indexOf(n) === -1 ? order.length : order.indexOf(n);\n routes.sort((a, b) => rank(a.name) - rank(b.name));\n const exportName = routesExportName(table, opts.naming);\n const statements = routes.map((r) => {\n const reads = (what) => r.body.some((line) => !line.startsWith(\"//\") && what.test(line));\n const params = reads(/\\breply\\./) ? reads(/\\breq\\./) ? \"(req, reply)\" : \"(_req, reply)\" : reads(/\\breq\\./) ? \"(req)\" : \"()\";\n return [\n ` app.${r.method}<{ Reply: ${r.replyType} }>(${lit(r.path)}, {`,\n ` schema: { ${r.schema.join(\", \")} },`,\n ` }, async ${params} => {`,\n ...r.body.map((line) => ` ${line}`),\n ` });`\n ].join(\"\\n\");\n }).join(\"\\n\\n\");\n const plugin = `export const ${exportName}: FastifyPluginAsync = async (app) => {\n${statements}\n};\n`;\n const schemas = tableSchemas(table);\n const declared = [];\n const emit = (name, schema) => `export const ${name} = ${JSON.stringify(adaptForFastify(schema), null, 2)} as const;`;\n if (writable) {\n declared.push(emit(insertName, schemas.insert));\n declared.push(emit(updateName, schemas.update));\n }\n declared.push(emit(selectName, schemas.select));\n if (key) {\n declared.push(emit(paramsName, paramsSchema(key)));\n }\n const rowFields = selectColumns(table).map((c) => ` ${objectKey(c.name)}: ${rowFieldType(c)}${c.nullable ? \" | null\" : \"\"};`).join(\"\\n\");\n declared.push(`export interface ${rowType} {\n${rowFields}\n}`);\n const wide = selectColumns(table).filter((c) => rowFieldType(c) === \"unknown\").map((c) => c.name);\n const wideNote = wide.length ? `// No precise type for ${wide.length === 1 ? \"this column\" : \"these columns\"}: ${wide.join(\", \")}.\n// DRZL could not derive one from the schema, so these routes carry it as unknown and its\n// schema constrains only what the builder could state.\n` : \"\";\n return `// Generated by @drzl/generator-fastify\n// Routes for table: ${table.name}\n${wideNote}import type { FastifyPluginAsync } from 'fastify';\n\n${declared.join(\"\\n\\n\")}\n\n${plugin}`;\n}\nfunction relationRoutes(table, rowType, selectName, opts) {\n const out = [];\n const taken = /* @__PURE__ */ new Set();\n for (const fk of table.foreignKeys ?? []) {\n if (fk.columns.length !== 1) continue;\n const colName = fk.columns[0];\n const column = table.columns.find((c) => c.name === colName);\n if (!column) continue;\n const segment = toCase(`by-${colName}`, opts.naming?.procedureCase ?? \"kebab\");\n if (taken.has(segment)) continue;\n taken.add(segment);\n const params = JSON.stringify(paramsSchema([column]));\n out.push({\n name: `listBy${cap(colName)}`,\n method: \"get\",\n path: `/${segment}/:${colName}`,\n schema: [`params: ${params}`, `response: { 200: { type: 'array', items: ${selectName} } }`],\n replyType: `${rowType}[]`,\n body: [`const rows: ${rowType}[] = [];`, \"return rows;\"]\n });\n }\n return out;\n}\nfunction renderBarrel(modules, ctx, path, opts) {\n if (!modules.length) {\n return `// Generated by @drzl/generator-fastify\n// No tables detected in analysis. Add tables to your schema and regenerate.\nimport type { FastifyPluginAsync } from 'fastify';\n\nexport const routes: FastifyPluginAsync = async () => {};\n`;\n }\n const entries = modules.map(({ filePath, exportName, table }) => ({\n rel: importSpecifier(\n \"./\" + path.relative(ctx.out, filePath).replace(/\\\\/g, \"/\"),\n opts.importExtension\n ),\n exportName,\n mount: mountPath(table, opts.naming)\n }));\n const imports = entries.map((e) => `import { ${e.exportName} } from '${e.rel}';`).join(\"\\n\");\n const registrations = entries.map((e) => ` app.register(${e.exportName}, { prefix: ${lit(e.mount)} });`).join(\"\\n\");\n const reExports = entries.map((e) => `export * from '${e.rel}';`).join(\"\\n\");\n return `// Generated by @drzl/generator-fastify\nimport type { FastifyPluginAsync } from 'fastify';\n${imports}\n\nexport const routes: FastifyPluginAsync = async (app) => {\n${registrations}\n};\n\n${reExports}\n`;\n}\nexport {\n APP_MODULE,\n FastifyGenerator,\n index_default as default\n};\n"],"mappings":"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","names":[]}
@@ -1,4 +1,5 @@
1
1
  // ../generator-effect/dist/index.js
2
+ import { fileWriter } from "@drzl/validation-core";
2
3
  import {
3
4
  buildBrandPlan,
4
5
  buildNestedPlan,
@@ -8,11 +9,22 @@ import {
8
9
  nestedSchemaName,
9
10
  nestedTypeName,
10
11
  resolveNestedDepth,
12
+ applyWirePolicy,
13
+ canonicalMembers,
14
+ canonicalNumericText,
15
+ comparisonWire,
16
+ describeSet,
17
+ needsNumericCanon,
11
18
  CODEPOINT_LENGTH,
12
19
  COERCIBLE_DATE_STRING,
13
20
  COLUMN_FORMATS,
21
+ NUMERIC_CANON_NAME,
22
+ NUMERIC_CANON_SOURCE,
14
23
  insertColumns,
15
24
  isIntegerColumn,
25
+ lengthCheckLabel,
26
+ lengthMeasure,
27
+ measureExpression,
16
28
  moduleFileName,
17
29
  moduleSpecifier,
18
30
  nonFiniteAccepted,
@@ -24,7 +36,8 @@ import {
24
36
  schemaName,
25
37
  selectColumns,
26
38
  typeName,
27
- updateColumns
39
+ updateColumns,
40
+ wireNumberLiteral
28
41
  } from "@drzl/validation-core";
29
42
  var DEFAULT_FILE_SUFFIX = ".effect.ts";
30
43
  var STANDARD_PREFIX = "Standard";
@@ -149,13 +162,16 @@ function capSteps(c, mode) {
149
162
  return steps;
150
163
  }
151
164
  function lengthSteps(c, lengths) {
152
- if (c.arrayDimensions || c.shape) return [];
153
- return lengths.filter((k) => k.column === c.name).map(
154
- (k) => filter(
155
- `${CODEPOINT_LENGTH} ${OPS[k.operator]} ${k.value}`,
156
- `${k.name ? `${k.name}: ` : ""}length(${c.name}) ${k.operator} ${k.value}`
157
- )
158
- );
165
+ return lengths.filter((k) => k.column === c.name).flatMap((k) => {
166
+ const measure = lengthMeasure(c, k);
167
+ if (!measure) return [];
168
+ return [
169
+ filter(
170
+ `${measureExpression(measure, "v")} ${OPS[k.operator]} ${k.value}`,
171
+ lengthCheckLabel(k)
172
+ )
173
+ ];
174
+ });
159
175
  }
160
176
  function cardinalitySteps(c, cardinalities) {
161
177
  if (!c.arrayDimensions) return [];
@@ -169,12 +185,19 @@ function cardinalitySteps(c, cardinalities) {
169
185
  function checkSteps(c, checks) {
170
186
  if (c.arrayDimensions || c.shape) return [];
171
187
  const folded = foldedIntoBounds(c, checks);
188
+ const numericWire = comparisonWire(c) === "numeric-string";
172
189
  return checks.filter((k) => k.column === c.name && !folded.has(k)).map((k) => {
173
- const literal = k.kind === "string" ? JSON.stringify(k.value) : k.value;
174
- return filter(
175
- `v ${OPS[k.operator]} ${literal}`,
176
- `${k.name ? `${k.name}: ` : ""}${c.name} ${k.operator} ${k.value}`
177
- );
190
+ const label = `${k.name ? `${k.name}: ` : ""}${c.name} ${k.operator} ${k.value}`;
191
+ if (numericWire) {
192
+ if (k.operator === "=" || k.operator === "<>") {
193
+ const canon = JSON.stringify(canonicalNumericText(k.value));
194
+ const op = k.operator === "=" ? "===" : "!==";
195
+ return filter(`${NUMERIC_CANON_NAME}(v) ${op} ${canon}`, label);
196
+ }
197
+ return filter(`Number(v) ${OPS[k.operator]} ${k.value}`, label);
198
+ }
199
+ const literal = k.kind === "string" ? JSON.stringify(k.value) : wireNumberLiteral(c, k.value);
200
+ return filter(`v ${OPS[k.operator]} ${literal}`, label);
178
201
  });
179
202
  }
180
203
  function hasNoRuntimeType(c) {
@@ -212,10 +235,19 @@ function shapeExpr(c, mode, replaced = false) {
212
235
  }
213
236
  function exprForColumn(c, mode, coerceDates, checks, sets, lengths, replaced) {
214
237
  const shaped = shapeExpr(c, mode, replaced);
215
- if (shaped) return shaped;
238
+ if (shaped) return piped(shaped, lengthSteps(c, lengths));
216
239
  const set = sets.find((x) => x.column === c.name);
217
240
  if (set) {
218
- const values = set.values.map((v) => set.kind === "string" ? JSON.stringify(v) : v);
241
+ if (comparisonWire(c) === "numeric-string") {
242
+ const members = canonicalMembers(set.values);
243
+ const test = members.map((m) => `canon === ${JSON.stringify(m)}`).join(" || ");
244
+ return piped(`${NS}.String`, [
245
+ filter(`((canon) => ${test})(${NUMERIC_CANON_NAME}(v))`, describeSet(set))
246
+ ]);
247
+ }
248
+ const values = set.values.map(
249
+ (v) => set.kind === "string" ? JSON.stringify(v) : wireNumberLiteral(c, v)
250
+ );
219
251
  return `${NS}.Literal(${values.join(", ")})`;
220
252
  }
221
253
  if (c.arrayDimensions) checks = [];
@@ -223,8 +255,8 @@ function exprForColumn(c, mode, coerceDates, checks, sets, lengths, replaced) {
223
255
  return `${NS}.Literal(${c.enumValues.map((v) => JSON.stringify(v)).join(", ")})`;
224
256
  }
225
257
  const eq = checks.find((k) => k.column === c.name && k.operator === "=");
226
- if (eq && !c.shape) {
227
- return `${NS}.Literal(${eq.kind === "string" ? JSON.stringify(eq.value) : eq.value})`;
258
+ if (eq && !c.shape && comparisonWire(c) !== "numeric-string") {
259
+ return `${NS}.Literal(${eq.kind === "string" ? JSON.stringify(eq.value) : wireNumberLiteral(c, eq.value)})`;
228
260
  }
229
261
  const rest = [...checkSteps(c, checks), ...lengthSteps(c, lengths)];
230
262
  switch (c.tsType) {
@@ -316,9 +348,14 @@ function indentBlock(code, by = " ") {
316
348
  }
317
349
  function parsedChecksFor(table) {
318
350
  const parsed = (table.checks ?? []).map((k) => parseCheck(k.expression, k.name));
351
+ const { checks, sets } = applyWirePolicy(
352
+ table.columns,
353
+ parsed.flatMap((p) => p.ok ? p.checks : []),
354
+ parsed.flatMap((p) => p.ok ? p.sets ?? [] : [])
355
+ );
319
356
  return {
320
- checks: parsed.flatMap((p) => p.ok ? p.checks : []),
321
- sets: parsed.flatMap((p) => p.ok ? p.sets ?? [] : []),
357
+ checks,
358
+ sets,
322
359
  rows: parsed.flatMap((p) => p.ok ? p.rows ?? [] : []),
323
360
  lengths: parsed.flatMap((p) => p.ok ? p.lengths ?? [] : []),
324
361
  cardinalities: parsed.flatMap((p) => p.ok ? p.cardinalities ?? [] : [])
@@ -480,9 +517,21 @@ export type ${a.alias} = ${NS}.Schema.Type<typeof ${selectName}>[${JSON.stringif
480
517
  const brandCode = brandAliases ? `
481
518
  ${brandAliases}
482
519
  ` : "";
520
+ const involved = [
521
+ table,
522
+ ...["insert", "select"].flatMap((m) => {
523
+ const plan = nested[m];
524
+ return plan ? nestedNodes(plan).map((n) => n.table) : [];
525
+ })
526
+ ];
527
+ const canonPreamble = involved.some((t) => {
528
+ const own = parsedChecksFor(t);
529
+ return needsNumericCanon(t.columns, own.checks, own.sets);
530
+ }) ? `
531
+ ${NUMERIC_CANON_SOURCE}` : "";
483
532
  return `import * as ${NS} from 'effect/Schema';
484
533
  ${schemaImport}${needsJson ? `
485
- ${JSON_PREAMBLE}` : ""}
534
+ ${JSON_PREAMBLE}` : ""}${canonPreamble}
486
535
  ${blocks.join("\n\n")}
487
536
  ${brandCode}${nestedCode}${duplicates}`;
488
537
  }
@@ -492,7 +541,7 @@ var EffectGenerator = class {
492
541
  this.library = "effect";
493
542
  }
494
543
  async generate(opts) {
495
- const fs = await import("fs/promises");
544
+ const fs = fileWriter(opts.fileSink);
496
545
  const path = await import("path");
497
546
  const out = path.resolve(process.cwd(), opts.outDir);
498
547
  const files = [];
@@ -582,4 +631,4 @@ export {
582
631
  EffectGenerator,
583
632
  index_default as default
584
633
  };
585
- //# sourceMappingURL=dist-WHAW3AMQ.js.map
634
+ //# sourceMappingURL=dist-KX62ETKK.js.map