@drzl/cli 4.17.0 → 4.19.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.
package/dist/cli.cjs CHANGED
@@ -261,7 +261,7 @@ ${entries}
261
261
  const decided = [...declared, body].join("\n\n");
262
262
  const imports = [];
263
263
  if (useShared) {
264
- const sharedAffix = (0, import_validation_core2.resolveAffix)({
264
+ const sharedAffix = (0, import_validation_core3.resolveAffix)({
265
265
  affix: opts.validation?.affix,
266
266
  schemaSuffix: opts.validation?.schemaSuffix
267
267
  });
@@ -271,21 +271,21 @@ ${entries}
271
271
  ["select", selectName]
272
272
  ].filter(([, local]) => decided.includes(local));
273
273
  if (wanted.length) {
274
- const spec = (0, import_validation_core2.resolveConfiguredImport)(
274
+ const spec = (0, import_validation_core3.resolveConfiguredImport)(
275
275
  opts.validation.importPath,
276
276
  ctx.out,
277
277
  process.cwd(),
278
278
  opts.importExtension
279
279
  );
280
280
  const names = wanted.map(([mode, local]) => {
281
- const exported = (0, import_validation_core2.schemaName)(mode, table.tsName, sharedAffix);
281
+ const exported = (0, import_validation_core3.schemaName)(mode, table.tsName, sharedAffix);
282
282
  return exported === local ? local : `${exported} as ${local}`;
283
283
  }).join(", ");
284
284
  imports.push(`import { ${names} } from '${spec}';`);
285
285
  }
286
286
  }
287
287
  imports.push(
288
- `import { ${[builder, "router"].sort().join(", ")} } from '${(0, import_validation_core2.importSpecifier)(
288
+ `import { ${[builder, "router"].sort().join(", ")} } from '${(0, import_validation_core3.importSpecifier)(
289
289
  `./${BASE_MODULE}.ts`,
290
290
  opts.importExtension
291
291
  )}';`
@@ -334,7 +334,7 @@ function relationProcedures(table, lib, selectSchemaName, taken, service) {
334
334
  return out;
335
335
  }
336
336
  function renderBarrel(routers, ctx, path6, opts) {
337
- const baseSpec = (0, import_validation_core2.importSpecifier)(`./${BASE_MODULE}.ts`, opts.importExtension);
337
+ const baseSpec = (0, import_validation_core3.importSpecifier)(`./${BASE_MODULE}.ts`, opts.importExtension);
338
338
  const reExports = `export { createCallerFactory, publicProcedure, router } from '${baseSpec}';
339
339
  ` + (opts.databaseInjection?.enabled === true ? `export { dbProcedure } from '${baseSpec}';
340
340
  ` : "") + `export type { Context } from '${baseSpec}';
@@ -352,7 +352,7 @@ export type AppRouter = typeof appRouter;
352
352
  ${reExports}`;
353
353
  }
354
354
  const entries = routers.map(({ filePath, exportName, table }) => ({
355
- rel: (0, import_validation_core2.importSpecifier)(
355
+ rel: (0, import_validation_core3.importSpecifier)(
356
356
  "./" + path6.relative(ctx.out, filePath).replace(/\\/g, "/"),
357
357
  opts.importExtension
358
358
  ),
@@ -393,7 +393,7 @@ function routerExportName(table, naming) {
393
393
  function serviceImportSpecifier(table, ctx, opts) {
394
394
  const rel = relativePosix(ctx.out, ctx.services);
395
395
  const dir = !rel ? "." : rel.startsWith(".") ? rel : `./${rel}`;
396
- return (0, import_validation_core2.importSpecifier)(`${dir}/${singularize(table.tsName)}Service.ts`, opts.importExtension);
396
+ return (0, import_validation_core3.importSpecifier)(`${dir}/${singularize(table.tsName)}Service.ts`, opts.importExtension);
397
397
  }
398
398
  function relativePosix(from, to) {
399
399
  const norm = (p) => p.replace(/\\/g, "/").replace(/\/+$/, "");
@@ -413,11 +413,11 @@ function buildHeader(h) {
413
413
  ];
414
414
  return lines.join("\n") + "\n\n";
415
415
  }
416
- var import_validation_core2, TRPC_MAJOR, q, LIB_IMPORTS, LIB_USAGE, LIBS, cap, singularize, isIdent, BASE_MODULE, TRPCGenerator, index_default;
416
+ var import_validation_core3, TRPC_MAJOR, q, LIB_IMPORTS, LIB_USAGE, LIBS, cap, singularize, isIdent, BASE_MODULE, TRPCGenerator, index_default;
417
417
  var init_dist = __esm({
418
418
  "../generator-trpc/dist/index.js"() {
419
419
  "use strict";
420
- import_validation_core2 = require("@drzl/validation-core");
420
+ import_validation_core3 = require("@drzl/validation-core");
421
421
  TRPC_MAJOR = 11;
422
422
  q = (v) => JSON.stringify(v);
423
423
  LIB_IMPORTS = {
@@ -510,7 +510,7 @@ ${body}
510
510
  await fs3.mkdir(out, { recursive: true });
511
511
  const files = [];
512
512
  const write = async (filePath, content) => {
513
- const formatted = await (0, import_validation_core2.formatCode)(
513
+ const formatted = await (0, import_validation_core3.formatCode)(
514
514
  buildHeader(opts.outputHeader) + content,
515
515
  filePath,
516
516
  opts.format
@@ -606,14 +606,14 @@ function baseSchema(c, mode, target, checks, sets, lengths) {
606
606
  case "string": {
607
607
  const out = { type: "string" };
608
608
  if (c.format === "uuid") out.format = UUID_FORMAT;
609
- else if (c.format && import_validation_core4.COLUMN_FORMATS[c.format]) out.pattern = import_validation_core4.COLUMN_FORMATS[c.format];
609
+ else if (c.format && import_validation_core5.COLUMN_FORMATS[c.format]) out.pattern = import_validation_core5.COLUMN_FORMATS[c.format];
610
610
  if (c.maxLength !== void 0) out.maxLength = c.maxLength;
611
611
  applyByteCap(out, c);
612
612
  applyLengths(out, c, lengths);
613
613
  return out;
614
614
  }
615
615
  case "number": {
616
- const out = { type: (0, import_validation_core4.isIntegerColumn)(c) ? "integer" : "number" };
616
+ const out = { type: (0, import_validation_core5.isIntegerColumn)(c) ? "integer" : "number" };
617
617
  if (!c.arrayDimensions) applyNumericBounds(out, c, checks, target);
618
618
  return out;
619
619
  }
@@ -750,7 +750,7 @@ function tableSchema(table, cols, mode, target, applyDefaults, parsed) {
750
750
  };
751
751
  }
752
752
  function collect(table) {
753
- const parsed = (table.checks ?? []).map((k) => (0, import_validation_core4.parseCheck)(k.expression, k.name));
753
+ const parsed = (table.checks ?? []).map((k) => (0, import_validation_core5.parseCheck)(k.expression, k.name));
754
754
  return {
755
755
  checks: parsed.flatMap((p) => p.ok ? p.checks : []),
756
756
  sets: parsed.flatMap((p) => p.ok ? p.sets ?? [] : []),
@@ -764,9 +764,9 @@ function tableSchemas(table, opts = {}) {
764
764
  const parsed = collect(table);
765
765
  const build2 = (cols, mode) => tableSchema(table, cols, mode, target, !!opts.applyDefaults, parsed);
766
766
  return {
767
- insert: build2((0, import_validation_core4.insertColumns)(table), "insert"),
768
- update: build2((0, import_validation_core4.updateColumns)(table), "update"),
769
- select: build2((0, import_validation_core4.selectColumns)(table), "select")
767
+ insert: build2((0, import_validation_core5.insertColumns)(table), "insert"),
768
+ update: build2((0, import_validation_core5.updateColumns)(table), "update"),
769
+ select: build2((0, import_validation_core5.selectColumns)(table), "select")
770
770
  };
771
771
  }
772
772
  function componentsDocument(tables, opts = {}) {
@@ -995,9 +995,9 @@ function openApiDocument(tables, opts = {}) {
995
995
  function renderTableModule(table, affix, target, applyDefaults) {
996
996
  const T = table.tsName;
997
997
  const schemas = tableSchemas(table, { target, applyDefaults });
998
- const decl = (mode) => `export const ${(0, import_validation_core3.schemaName)(mode, T, affix)} = ${JSON.stringify(schemas[mode], null, 2)} as const;
998
+ const decl = (mode) => `export const ${(0, import_validation_core4.schemaName)(mode, T, affix)} = ${JSON.stringify(schemas[mode], null, 2)} as const;
999
999
 
1000
- export type ${(0, import_validation_core3.typeName)(mode, T, affix)} = typeof ${(0, import_validation_core3.schemaName)(mode, T, affix)};`;
1000
+ export type ${(0, import_validation_core4.typeName)(mode, T, affix)} = typeof ${(0, import_validation_core4.schemaName)(mode, T, affix)};`;
1001
1001
  return [decl("insert"), decl("update"), decl("select")].join("\n\n") + "\n";
1002
1002
  }
1003
1003
  function resolveDocument(opt) {
@@ -1013,12 +1013,12 @@ function buildHeader2(h) {
1013
1013
 
1014
1014
  `;
1015
1015
  }
1016
- var import_validation_core3, import_validation_core4, DRAFT, UUID_FORMAT, base64, ERROR_SCHEMA, componentName, ref, pascal, modesFor, resourceSegment, jsonBody, errorSchema, DEFAULT_FILE_SUFFIX, JsonSchemaGenerator, index_default2;
1016
+ var import_validation_core4, import_validation_core5, DRAFT, UUID_FORMAT, base64, ERROR_SCHEMA, componentName, ref, pascal, modesFor, resourceSegment, jsonBody, errorSchema, DEFAULT_FILE_SUFFIX, JsonSchemaGenerator, index_default2;
1017
1017
  var init_dist2 = __esm({
1018
1018
  "../generator-json-schema/dist/index.js"() {
1019
1019
  "use strict";
1020
- import_validation_core3 = require("@drzl/validation-core");
1021
1020
  import_validation_core4 = require("@drzl/validation-core");
1021
+ import_validation_core5 = require("@drzl/validation-core");
1022
1022
  DRAFT = "https://json-schema.org/draft/2020-12/schema";
1023
1023
  UUID_FORMAT = "uuid";
1024
1024
  base64 = (target) => target === "openapi-3.0" ? { type: "string", format: "byte" } : { type: "string", contentEncoding: "base64" };
@@ -1056,14 +1056,14 @@ var init_dist2 = __esm({
1056
1056
  const out = path6.resolve(process.cwd(), opts.outDir);
1057
1057
  const files = [];
1058
1058
  await fs3.mkdir(out, { recursive: true });
1059
- const affix = (0, import_validation_core3.resolveAffix)(opts);
1059
+ const affix = (0, import_validation_core4.resolveAffix)(opts);
1060
1060
  const fileSuffix = opts.fileSuffix ?? DEFAULT_FILE_SUFFIX;
1061
1061
  const target = opts.target ?? "draft-2020-12";
1062
1062
  const document = resolveDocument(opts.document);
1063
1063
  for (const table of this.analysis.tables) {
1064
- const filePath = path6.join(out, (0, import_validation_core3.moduleFileName)(table.tsName, fileSuffix));
1064
+ const filePath = path6.join(out, (0, import_validation_core4.moduleFileName)(table.tsName, fileSuffix));
1065
1065
  const code = renderTableModule(table, affix, target, !!opts.applyDefaults);
1066
- const formatted = await (0, import_validation_core3.formatCode)(
1066
+ const formatted = await (0, import_validation_core4.formatCode)(
1067
1067
  buildHeader2(opts.outputHeader) + code,
1068
1068
  filePath,
1069
1069
  opts.format
@@ -1081,7 +1081,7 @@ var init_dist2 = __esm({
1081
1081
  `;
1082
1082
  await fs3.writeFile(
1083
1083
  componentsPath,
1084
- await (0, import_validation_core3.formatCode)(buildHeader2(opts.outputHeader) + code, componentsPath, opts.format),
1084
+ await (0, import_validation_core4.formatCode)(buildHeader2(opts.outputHeader) + code, componentsPath, opts.format),
1085
1085
  "utf8"
1086
1086
  );
1087
1087
  files.push(componentsPath);
@@ -1102,7 +1102,7 @@ var init_dist2 = __esm({
1102
1102
  `;
1103
1103
  await fs3.writeFile(
1104
1104
  tsPath,
1105
- await (0, import_validation_core3.formatCode)(buildHeader2(opts.outputHeader) + code, tsPath, opts.format),
1105
+ await (0, import_validation_core4.formatCode)(buildHeader2(opts.outputHeader) + code, tsPath, opts.format),
1106
1106
  "utf8"
1107
1107
  );
1108
1108
  files.push(tsPath);
@@ -1116,9 +1116,9 @@ var init_dist2 = __esm({
1116
1116
  const ext = opts.importExtension === "none" ? "" : ".js";
1117
1117
  const indexPath = path6.join(out, "index.ts");
1118
1118
  const index = this.analysis.tables.map(
1119
- (t) => `export * from '${(0, import_validation_core3.moduleSpecifier)(t.tsName, fileSuffix, opts.importExtension)}';`
1119
+ (t) => `export * from '${(0, import_validation_core4.moduleSpecifier)(t.tsName, fileSuffix, opts.importExtension)}';`
1120
1120
  ).concat(opts.components ? [`export * from './components${ext}';`] : []).concat(document && document.format !== "json" ? [`export * from './openapi${ext}';`] : []).join("\n") + "\n";
1121
- const indexFormatted = await (0, import_validation_core3.formatCode)(
1121
+ const indexFormatted = await (0, import_validation_core4.formatCode)(
1122
1122
  buildHeader2(opts.outputHeader) + index,
1123
1123
  indexPath,
1124
1124
  opts.format
@@ -1130,7 +1130,7 @@ var init_dist2 = __esm({
1130
1130
  renderTable(table, opts) {
1131
1131
  return renderTableModule(
1132
1132
  table,
1133
- (0, import_validation_core3.resolveAffix)(opts),
1133
+ (0, import_validation_core4.resolveAffix)(opts),
1134
1134
  opts?.target ?? "draft-2020-12",
1135
1135
  !!opts?.applyDefaults
1136
1136
  );
@@ -1140,10 +1140,551 @@ var init_dist2 = __esm({
1140
1140
  }
1141
1141
  });
1142
1142
 
1143
+ // ../generator-effect/dist/index.js
1144
+ var dist_exports3 = {};
1145
+ __export(dist_exports3, {
1146
+ EffectGenerator: () => EffectGenerator,
1147
+ default: () => index_default3
1148
+ });
1149
+ function filter(expr, description) {
1150
+ return `${NS}.filter((v) => ${expr}, { description: ${JSON.stringify(description)} })`;
1151
+ }
1152
+ function piped(base, steps) {
1153
+ return steps.length ? `${base}.pipe(${steps.join(", ")})` : base;
1154
+ }
1155
+ function isUnknownExpr(expr) {
1156
+ return expr === UNKNOWN_EXPR;
1157
+ }
1158
+ function withNarrowedType(expr, ref2) {
1159
+ return `${expr} as unknown as ${NS}.Schema<${ref2}>`;
1160
+ }
1161
+ function numericBounds(c, checks) {
1162
+ let lo = c.min !== void 0 ? { fn: "greaterThanOrEqualTo", value: c.min } : void 0;
1163
+ let hi = c.max !== void 0 ? { fn: "lessThanOrEqualTo", value: c.max } : void 0;
1164
+ for (const k of checks.filter((x) => x.column === c.name && x.kind === "number")) {
1165
+ if (k.operator === ">=") lo = { fn: "greaterThanOrEqualTo", value: k.value };
1166
+ else if (k.operator === ">") lo = { fn: "greaterThan", value: k.value };
1167
+ else if (k.operator === "<=") hi = { fn: "lessThanOrEqualTo", value: k.value };
1168
+ else if (k.operator === "<") hi = { fn: "lessThan", value: k.value };
1169
+ }
1170
+ return [lo, hi].filter(Boolean).map((x) => `${NS}.${x.fn}(${x.value})`);
1171
+ }
1172
+ function foldedIntoBounds(c, checks) {
1173
+ if (c.arrayDimensions || c.shape) return /* @__PURE__ */ new Set();
1174
+ if (c.tsType !== "number" && c.tsType !== "bigint") return /* @__PURE__ */ new Set();
1175
+ return new Set(
1176
+ checks.filter(
1177
+ (k) => k.column === c.name && k.kind === "number" && k.operator !== "=" && k.operator !== "<>"
1178
+ )
1179
+ );
1180
+ }
1181
+ function nonFiniteBranches(c) {
1182
+ const { nan, infinity } = (0, import_validation_core6.nonFiniteAccepted)(c);
1183
+ return [
1184
+ ...nan ? [`${NS}.Number.pipe(${filter("Number.isNaN(v)", "NaN, which this column stores")})`] : [],
1185
+ ...infinity ? [`${NS}.Literal(Infinity, -Infinity)`] : []
1186
+ ];
1187
+ }
1188
+ function withNonFinite(c, base) {
1189
+ const branches = nonFiniteBranches(c);
1190
+ return branches.length ? `${NS}.Union(${base}, ${branches.join(", ")})` : base;
1191
+ }
1192
+ function dateExpr(mode, coerceDates) {
1193
+ const plain = `${NS}.ValidDateFromSelf`;
1194
+ if (coerceDates === "none") return plain;
1195
+ const fromString = piped(`${NS}.String`, [
1196
+ `${NS}.pattern(new RegExp(${JSON.stringify(import_validation_core6.COERCIBLE_DATE_STRING)}))`,
1197
+ filter((0, import_validation_core6.parsesToADate)("new Date(v)"), "a date the runtime can parse")
1198
+ ]);
1199
+ const fromNumber = piped(`${NS}.Number`, [
1200
+ filter((0, import_validation_core6.parsesToADate)("new Date(v)"), "a date the runtime can parse")
1201
+ ]);
1202
+ const union = `${NS}.Union(${plain}, ${fromString}, ${fromNumber})`;
1203
+ if (coerceDates === "all") return union;
1204
+ return mode === "select" ? plain : union;
1205
+ }
1206
+ function capSteps(c, mode) {
1207
+ const steps = [];
1208
+ if (c.shape?.kind === "byteString") {
1209
+ const n = c.shape.length;
1210
+ if (!n) return steps;
1211
+ return mode === "select" ? [filter(`${import_validation_core6.CODEPOINT_LENGTH} <= ${n}`, `at most ${n} characters`)] : [filter(`new TextEncoder().encode(v).length <= ${n}`, `at most ${n} bytes`)];
1212
+ }
1213
+ if (c.maxLength) {
1214
+ steps.push(
1215
+ filter(`${import_validation_core6.CODEPOINT_LENGTH} <= ${c.maxLength}`, `at most ${c.maxLength} characters`)
1216
+ );
1217
+ }
1218
+ if (c.maxBytes) {
1219
+ steps.push(
1220
+ filter(`new TextEncoder().encode(v).length <= ${c.maxBytes}`, `at most ${c.maxBytes} bytes`)
1221
+ );
1222
+ }
1223
+ return steps;
1224
+ }
1225
+ function lengthSteps(c, lengths) {
1226
+ if (c.arrayDimensions || c.shape) return [];
1227
+ return lengths.filter((k) => k.column === c.name).map(
1228
+ (k) => filter(
1229
+ `${import_validation_core6.CODEPOINT_LENGTH} ${OPS[k.operator]} ${k.value}`,
1230
+ `${k.name ? `${k.name}: ` : ""}length(${c.name}) ${k.operator} ${k.value}`
1231
+ )
1232
+ );
1233
+ }
1234
+ function cardinalitySteps(c, cardinalities) {
1235
+ if (!c.arrayDimensions) return [];
1236
+ return cardinalities.filter((k) => k.column === c.name).map(
1237
+ (k) => filter(
1238
+ `v.length ${OPS[k.operator]} ${k.value}`,
1239
+ `${k.name ? `${k.name}: ` : ""}cardinality(${c.name}) ${k.operator} ${k.value}`
1240
+ )
1241
+ );
1242
+ }
1243
+ function checkSteps(c, checks) {
1244
+ if (c.arrayDimensions || c.shape) return [];
1245
+ const folded = foldedIntoBounds(c, checks);
1246
+ return checks.filter((k) => k.column === c.name && !folded.has(k)).map((k) => {
1247
+ const literal = k.kind === "string" ? JSON.stringify(k.value) : k.value;
1248
+ return filter(
1249
+ `v ${OPS[k.operator]} ${literal}`,
1250
+ `${k.name ? `${k.name}: ` : ""}${c.name} ${k.operator} ${k.value}`
1251
+ );
1252
+ });
1253
+ }
1254
+ function hasNoRuntimeType(c) {
1255
+ return c.tsType === "any" || c.shape?.kind === "custom" || c.shape?.kind === "json";
1256
+ }
1257
+ function shapeExpr(c, mode, replaced = false) {
1258
+ const s = c.shape;
1259
+ if (!s) return void 0;
1260
+ switch (s.kind) {
1261
+ case "json":
1262
+ return replaced ? UNKNOWN_EXPR : JSON_CONST;
1263
+ case "custom":
1264
+ return UNKNOWN_EXPR;
1265
+ case "buffer":
1266
+ return `${NS}.Uint8ArrayFromSelf`;
1267
+ case "tuple":
1268
+ return `${NS}.Tuple(${Array.from({ length: s.length }, () => `${NS}.Number`).join(", ")})`;
1269
+ case "numberObject":
1270
+ return `${NS}.Struct({ ${s.fields.map((f) => `${f}: ${NS}.Number`).join(", ")} })`;
1271
+ case "numberVector":
1272
+ return piped(
1273
+ `${NS}.Array(${NS}.Number)`,
1274
+ s.length ? [filter(`v.length === ${s.length}`, `exactly ${s.length} elements`)] : []
1275
+ );
1276
+ case "bitstring":
1277
+ return piped(`${NS}.String`, [
1278
+ `${NS}.pattern(/^[01]*$/)`,
1279
+ ...s.length ? [
1280
+ s.exact ? filter(`v.length === ${s.length}`, `exactly ${s.length} binary digits`) : filter(`v.length <= ${s.length}`, `at most ${s.length} binary digits`)
1281
+ ] : []
1282
+ ]);
1283
+ case "byteString":
1284
+ return piped(`${NS}.String`, capSteps(c, mode));
1285
+ }
1286
+ }
1287
+ function exprForColumn(c, mode, coerceDates, checks, sets, lengths, replaced) {
1288
+ const shaped = shapeExpr(c, mode, replaced);
1289
+ if (shaped) return shaped;
1290
+ const set = sets.find((x) => x.column === c.name);
1291
+ if (set) {
1292
+ const values = set.values.map((v) => set.kind === "string" ? JSON.stringify(v) : v);
1293
+ return `${NS}.Literal(${values.join(", ")})`;
1294
+ }
1295
+ if (c.arrayDimensions) checks = [];
1296
+ if (c.enumValues && c.enumValues.length) {
1297
+ return `${NS}.Literal(${c.enumValues.map((v) => JSON.stringify(v)).join(", ")})`;
1298
+ }
1299
+ const eq = checks.find((k) => k.column === c.name && k.operator === "=");
1300
+ if (eq && !c.shape) {
1301
+ return `${NS}.Literal(${eq.kind === "string" ? JSON.stringify(eq.value) : eq.value})`;
1302
+ }
1303
+ const rest = [...checkSteps(c, checks), ...lengthSteps(c, lengths)];
1304
+ switch (c.tsType) {
1305
+ case "string": {
1306
+ const base = c.format === "uuid" ? `${NS}.UUID` : `${NS}.String`;
1307
+ const pattern = c.format && c.format !== "uuid" && import_validation_core6.COLUMN_FORMATS[c.format] ? [`${NS}.pattern(new RegExp(${JSON.stringify(import_validation_core6.COLUMN_FORMATS[c.format])}))`] : [];
1308
+ return piped(base, [...pattern, ...capSteps(c, mode), ...rest]);
1309
+ }
1310
+ case "number": {
1311
+ const base = (0, import_validation_core6.isIntegerColumn)(c) ? `${NS}.Int` : `${NS}.Finite`;
1312
+ return withNonFinite(c, piped(base, [...numericBounds(c, checks), ...rest]));
1313
+ }
1314
+ case "bigint":
1315
+ return piped(`${NS}.BigIntFromSelf`, [
1316
+ ...c.min !== void 0 ? [`${NS}.greaterThanOrEqualToBigInt(${c.min}n)`] : [],
1317
+ ...c.max !== void 0 ? [`${NS}.lessThanOrEqualToBigInt(${c.max}n)`] : [],
1318
+ ...rest
1319
+ ]);
1320
+ case "boolean":
1321
+ return `${NS}.Boolean`;
1322
+ case "Date":
1323
+ return dateExpr(mode, coerceDates);
1324
+ case "Uint8Array":
1325
+ return `${NS}.Uint8ArrayFromSelf`;
1326
+ case "any":
1327
+ return UNKNOWN_EXPR;
1328
+ default:
1329
+ return UNKNOWN_EXPR;
1330
+ }
1331
+ }
1332
+ function renderField(c, mode, coerceDates, checks, sets, lengths, cardinalities, applyDefault, narrowRef) {
1333
+ let expr = exprForColumn(
1334
+ c,
1335
+ mode,
1336
+ coerceDates,
1337
+ checks,
1338
+ sets,
1339
+ lengths,
1340
+ !!narrowRef && hasNoRuntimeType(c)
1341
+ );
1342
+ const dims = c.arrayDimensions ?? 0;
1343
+ for (let i = 0; i < dims; i++) {
1344
+ expr = `${NS}.Array(${expr})`;
1345
+ if (i === dims - 1) expr = piped(expr, cardinalitySteps(c, cardinalities));
1346
+ }
1347
+ if (c.nullable && !isUnknownExpr(expr)) expr = `${NS}.NullOr(${expr})`;
1348
+ if (narrowRef) expr = withNarrowedType(expr, narrowRef);
1349
+ if (mode === "select") return expr;
1350
+ const wantsDefault = mode === "insert" && applyDefault && c.defaultValue !== void 0;
1351
+ if (wantsDefault) {
1352
+ return `${NS}.optionalWith(${expr}, { default: () => ${JSON.stringify(c.defaultValue)} })`;
1353
+ }
1354
+ if (mode === "update" || c.nullable || c.hasDefault) return `${NS}.optional(${expr})`;
1355
+ return expr;
1356
+ }
1357
+ function wantsRef(c, allColumns) {
1358
+ return allColumns || hasNoRuntimeType(c);
1359
+ }
1360
+ function renderObjectShape(cols, mode, coerceDates, checks, sets, lengths, cardinalities, typedJson, applyDefaults) {
1361
+ return cols.map((c) => {
1362
+ const ref2 = typedJson && wantsRef(c, !!typedJson.allColumns) ? `(typeof ${typedJson.table}.$infer${typedJson.mode === "insert" ? "Insert" : "Select"})[${JSON.stringify(c.name)}]` : void 0;
1363
+ const field2 = renderField(
1364
+ c,
1365
+ mode,
1366
+ coerceDates,
1367
+ checks,
1368
+ sets,
1369
+ lengths,
1370
+ cardinalities,
1371
+ applyDefaults,
1372
+ ref2
1373
+ );
1374
+ return ` ${JSON.stringify(c.name)}: ${field2},`;
1375
+ }).join("\n");
1376
+ }
1377
+ function rowSteps(rows, cols) {
1378
+ const present = new Set(cols.map((c) => c.name));
1379
+ return rows.filter((r) => present.has(r.left) && present.has(r.right)).map((r) => {
1380
+ const l = `o[${JSON.stringify(r.left)}]`;
1381
+ const rt = `o[${JSON.stringify(r.right)}]`;
1382
+ const msg = `${r.name ? `${r.name}: ` : ""}${r.left} ${r.operator} ${r.right}`;
1383
+ return `${NS}.filter((o) => ${l} == null || ${rt} == null || ${l} ${OPS[r.operator]} ${rt}, { description: ${JSON.stringify(msg)} })`;
1384
+ });
1385
+ }
1386
+ function indentBlock(code, by = " ") {
1387
+ return code.split("\n").map((line) => line ? by + line : line).join("\n");
1388
+ }
1389
+ function parsedChecksFor(table) {
1390
+ const parsed = (table.checks ?? []).map((k) => (0, import_validation_core6.parseCheck)(k.expression, k.name));
1391
+ return {
1392
+ checks: parsed.flatMap((p) => p.ok ? p.checks : []),
1393
+ sets: parsed.flatMap((p) => p.ok ? p.sets ?? [] : []),
1394
+ rows: parsed.flatMap((p) => p.ok ? p.rows ?? [] : []),
1395
+ lengths: parsed.flatMap((p) => p.ok ? p.lengths ?? [] : []),
1396
+ cardinalities: parsed.flatMap((p) => p.ok ? p.cardinalities ?? [] : [])
1397
+ };
1398
+ }
1399
+ function nestedNodeCols(node, mode) {
1400
+ const all = mode === "insert" ? (0, import_validation_core6.insertColumns)(node.table) : (0, import_validation_core6.selectColumns)(node.table);
1401
+ return (0, import_validation_core6.nestedNodeColumns)(all, node);
1402
+ }
1403
+ function nestedNodes(node, into = []) {
1404
+ into.push(node);
1405
+ for (const arm of node.arms) nestedNodes(arm.child, into);
1406
+ return into;
1407
+ }
1408
+ function renderNestedObject(node, mode, coerceDates, typedJson, applyDefaults) {
1409
+ const cols = nestedNodeCols(node, mode);
1410
+ const { checks, sets, rows, lengths, cardinalities } = parsedChecksFor(node.table);
1411
+ const tj = typedJson ? { table: node.table.tsName, mode, allColumns: typedJson.allColumns } : void 0;
1412
+ const fields = renderObjectShape(
1413
+ cols,
1414
+ mode,
1415
+ coerceDates,
1416
+ checks,
1417
+ sets,
1418
+ lengths,
1419
+ cardinalities,
1420
+ tj,
1421
+ applyDefaults
1422
+ );
1423
+ const arms = node.arms.map((arm) => {
1424
+ const notes = (0, import_validation_core6.nestedArmNotes)(arm).map((n) => ` // ${n}
1425
+ `).join("");
1426
+ const child = renderNestedObject(arm.child, mode, coerceDates, typedJson, applyDefaults);
1427
+ const inner = arm.single ? `${NS}.NullOr(
1428
+ ${indentBlock(indentBlock(child))}
1429
+ )` : `${NS}.Array(
1430
+ ${indentBlock(indentBlock(child))}
1431
+ )`;
1432
+ return `${notes} ${JSON.stringify(arm.key)}: ${NS}.optional(${inner}),`;
1433
+ });
1434
+ const body = [fields, ...arms].filter(Boolean).join("\n");
1435
+ return piped(`${NS}.Struct({
1436
+ ${body}
1437
+ })`, rowSteps(rows, cols));
1438
+ }
1439
+ function renderNestedSchemas(table, affix, coerceDates, typedJson, applyDefaults, plans) {
1440
+ const out = [];
1441
+ for (const mode of ["insert", "select"]) {
1442
+ const plan = plans[mode];
1443
+ if (!plan) continue;
1444
+ const name = (0, import_validation_core6.nestedSchemaName)(mode, table.tsName, affix);
1445
+ const tname = (0, import_validation_core6.nestedTypeName)(mode, table.tsName, affix);
1446
+ const expr = renderNestedObject(plan, mode, coerceDates, typedJson, applyDefaults);
1447
+ out.push(
1448
+ `export const ${name} = ${expr};
1449
+
1450
+ export type ${tname} = ${NS}.Schema.Type<typeof ${name}>;
1451
+
1452
+ export const ${STANDARD_PREFIX}${name} = ${NS}.standardSchemaV1(${name});`
1453
+ );
1454
+ }
1455
+ return out.length ? `
1456
+ ${out.join("\n\n")}
1457
+ ` : "";
1458
+ }
1459
+ function nestedPlansFor(table, analysis, depth) {
1460
+ const out = {};
1461
+ for (const mode of ["insert", "select"]) {
1462
+ if (mode === "insert" && table.readOnly) continue;
1463
+ const plan = (0, import_validation_core6.buildNestedPlan)(table, analysis.tables, analysis.relations ?? [], mode, depth);
1464
+ if (plan) out[mode] = plan;
1465
+ }
1466
+ return out;
1467
+ }
1468
+ function renderTableSchemas(table, affix, coerceDates, typedJson, applyDefaults = false, wantsDuplicateFinder = false, nested = {}) {
1469
+ const T = table.tsName;
1470
+ const insertCols = (0, import_validation_core6.insertColumns)(table);
1471
+ const updateCols = (0, import_validation_core6.updateColumns)(table);
1472
+ const selectCols = (0, import_validation_core6.selectColumns)(table);
1473
+ const { checks, sets, rows, lengths, cardinalities } = parsedChecksFor(table);
1474
+ const tj = typedJson ? { table: T, allColumns: typedJson.allColumns } : void 0;
1475
+ const modes = [
1476
+ ["insert", insertCols],
1477
+ ["update", updateCols],
1478
+ ["select", selectCols]
1479
+ ];
1480
+ const blocks = modes.map(([mode, cols]) => {
1481
+ const name = (0, import_validation_core6.schemaName)(mode, T, affix);
1482
+ const tname = (0, import_validation_core6.typeName)(mode, T, affix);
1483
+ const body = renderObjectShape(
1484
+ cols,
1485
+ mode,
1486
+ coerceDates,
1487
+ checks,
1488
+ sets,
1489
+ lengths,
1490
+ cardinalities,
1491
+ // The update schema references the insert-side inferred types: both describe a value going
1492
+ // in, and `$inferSelect` would name the post-default type for a column a write may omit.
1493
+ tj ? { ...tj, mode: mode === "select" ? "select" : "insert" } : void 0,
1494
+ applyDefaults
1495
+ );
1496
+ const expr = piped(`${NS}.Struct({
1497
+ ${body}
1498
+ })`, rowSteps(rows, cols));
1499
+ return `export const ${name} = ${expr};
1500
+
1501
+ export type ${tname} = ${NS}.Schema.Type<typeof ${name}>;
1502
+
1503
+ export const ${STANDARD_PREFIX}${name} = ${NS}.standardSchemaV1(${name});`;
1504
+ });
1505
+ const nestedByTable = ["insert", "select"].flatMap((m) => {
1506
+ const plan = nested[m];
1507
+ return plan ? nestedNodes(plan).map((n) => [n.table.tsName, nestedNodeCols(n, m)]) : [];
1508
+ });
1509
+ const nestedCols = nestedByTable.flatMap(([, cs]) => cs);
1510
+ const referenced = /* @__PURE__ */ new Set();
1511
+ if (typedJson) {
1512
+ const all = !!typedJson.allColumns;
1513
+ if ([...insertCols, ...updateCols, ...selectCols].some((c) => wantsRef(c, all))) {
1514
+ referenced.add(T);
1515
+ }
1516
+ for (const [name, cs] of nestedByTable) {
1517
+ if (cs.some((c) => wantsRef(c, all))) referenced.add(name);
1518
+ }
1519
+ }
1520
+ const schemaImport = referenced.size ? `import type { ${[...referenced].join(", ")} } from '${typedJson.schemaSpecifier}';
1521
+ ` : "";
1522
+ const needsJson = !typedJson && [...insertCols, ...updateCols, ...selectCols, ...nestedCols].some(
1523
+ (c) => c.shape?.kind === "json"
1524
+ );
1525
+ const finder = wantsDuplicateFinder ? (0, import_validation_core6.renderDuplicateFinder)(table, `findDuplicate${T}`, (0, import_validation_core6.typeName)("insert", T, affix)) : void 0;
1526
+ const duplicates = finder ? `
1527
+ ${finder}
1528
+ ` : "";
1529
+ const nestedCode = renderNestedSchemas(
1530
+ table,
1531
+ affix,
1532
+ coerceDates,
1533
+ typedJson,
1534
+ applyDefaults,
1535
+ nested
1536
+ );
1537
+ return `import * as ${NS} from 'effect/Schema';
1538
+ ${schemaImport}${needsJson ? `
1539
+ ${JSON_PREAMBLE}` : ""}
1540
+ ${blocks.join("\n\n")}
1541
+ ${nestedCode}${duplicates}`;
1542
+ }
1543
+ function buildHeader3(h) {
1544
+ if (h && h.enabled === false) return "";
1545
+ const text = h?.text?.trim();
1546
+ const lines = text ? text.split(/\r?\n/).map((l) => `// ${l}`) : [
1547
+ "// Generated by DRZL (@drzl/*)",
1548
+ "// Generated output is granted to you under your project's license.",
1549
+ "// You may use, copy, modify, and distribute without attribution."
1550
+ ];
1551
+ return lines.join("\n") + "\n\n";
1552
+ }
1553
+ var import_validation_core6, DEFAULT_FILE_SUFFIX2, STANDARD_PREFIX, NS, OPS, JSON_CONST, JSON_PREAMBLE, UNKNOWN_EXPR, EffectGenerator, index_default3;
1554
+ var init_dist3 = __esm({
1555
+ "../generator-effect/dist/index.js"() {
1556
+ "use strict";
1557
+ import_validation_core6 = require("@drzl/validation-core");
1558
+ DEFAULT_FILE_SUFFIX2 = ".effect.ts";
1559
+ STANDARD_PREFIX = "Standard";
1560
+ NS = "Schema";
1561
+ OPS = {
1562
+ ">=": ">=",
1563
+ ">": ">",
1564
+ "<=": "<=",
1565
+ "<": "<",
1566
+ "=": "===",
1567
+ "<>": "!=="
1568
+ };
1569
+ JSON_CONST = "DrzlJsonValue";
1570
+ JSON_PREAMBLE = `type ${JSON_CONST}Type =
1571
+ | string
1572
+ | number
1573
+ | boolean
1574
+ | null
1575
+ | readonly ${JSON_CONST}Type[]
1576
+ | { readonly [key: string]: ${JSON_CONST}Type };
1577
+
1578
+ const ${JSON_CONST}: ${NS}.Schema<${JSON_CONST}Type, unknown> = ${NS}.suspend(() =>
1579
+ ${NS}.Union(
1580
+ ${NS}.String,
1581
+ ${NS}.Finite,
1582
+ ${NS}.Boolean,
1583
+ ${NS}.Null,
1584
+ ${NS}.Array(${JSON_CONST}),
1585
+ // The plain-object test comes before the record, not after it. \`Schema.Record\` rebuilds its
1586
+ // output, so a check placed after it inspects that new object and reports every input as
1587
+ // plain. A Date sailed through: it has no own enumerable keys, so the record accepted it and
1588
+ // rebuilt it as \`{}\`.
1589
+ ${NS}.Unknown.pipe(
1590
+ ${NS}.filter(
1591
+ (o) => {
1592
+ if (typeof o !== 'object' || o === null || Array.isArray(o)) return false;
1593
+ const p = Object.getPrototypeOf(o);
1594
+ return p === Object.prototype || p === null;
1595
+ },
1596
+ { description: 'a plain object' }
1597
+ ),
1598
+ ${NS}.compose(${NS}.Record({ key: ${NS}.String, value: ${JSON_CONST} }), { strict: false })
1599
+ )
1600
+ )
1601
+ );
1602
+ `;
1603
+ UNKNOWN_EXPR = `${NS}.Unknown`;
1604
+ EffectGenerator = class {
1605
+ constructor(analysis) {
1606
+ this.analysis = analysis;
1607
+ this.library = "effect";
1608
+ }
1609
+ async generate(opts) {
1610
+ const fs3 = await import("fs/promises");
1611
+ const path6 = await import("path");
1612
+ const out = path6.resolve(process.cwd(), opts.outDir);
1613
+ const files = [];
1614
+ await fs3.mkdir(out, { recursive: true });
1615
+ const affix = (0, import_validation_core6.resolveAffix)(opts);
1616
+ const coerceDates = opts.coerceDates ?? "input";
1617
+ const fileSuffix = opts.fileSuffix ?? DEFAULT_FILE_SUFFIX2;
1618
+ const wantsTypes = opts.typedJson || opts.typedColumns;
1619
+ const typedJson = wantsTypes && opts.schemaPath ? {
1620
+ schemaSpecifier: (0, import_validation_core6.resolveConfiguredImport)(
1621
+ opts.schemaPath,
1622
+ out,
1623
+ process.cwd(),
1624
+ opts.importExtension
1625
+ ),
1626
+ allColumns: !!opts.typedColumns
1627
+ } : void 0;
1628
+ if (wantsTypes && !opts.schemaPath) {
1629
+ console.warn(
1630
+ "[drzl] typedJson was requested but the schema path is unknown, so json columns keep their wide type."
1631
+ );
1632
+ }
1633
+ const nestedDepth = opts.nestedSchemas ? (0, import_validation_core6.resolveNestedDepth)(opts.nestedDepth, (m) => console.warn(m)) : 0;
1634
+ for (const table of this.analysis.tables) {
1635
+ const filePath = path6.join(out, (0, import_validation_core6.moduleFileName)(table.tsName, fileSuffix));
1636
+ const code = renderTableSchemas(
1637
+ table,
1638
+ affix,
1639
+ coerceDates,
1640
+ typedJson,
1641
+ !!opts.applyDefaults,
1642
+ !!opts?.duplicateFinder,
1643
+ opts.nestedSchemas ? nestedPlansFor(table, this.analysis, nestedDepth) : {}
1644
+ );
1645
+ const formatted = await (0, import_validation_core6.formatCode)(
1646
+ buildHeader3(opts.outputHeader) + code,
1647
+ filePath,
1648
+ opts.format
1649
+ );
1650
+ await fs3.writeFile(filePath, formatted, "utf8");
1651
+ files.push(filePath);
1652
+ }
1653
+ const indexPath = path6.join(out, "index.ts");
1654
+ const indexFormatted = await (0, import_validation_core6.formatCode)(
1655
+ buildHeader3(opts.outputHeader) + this.defaultIndex(this.analysis, opts),
1656
+ indexPath,
1657
+ opts.format
1658
+ );
1659
+ await fs3.writeFile(indexPath, indexFormatted, "utf8");
1660
+ files.push(indexPath);
1661
+ return files;
1662
+ }
1663
+ renderTable(table, opts) {
1664
+ return renderTableSchemas(
1665
+ table,
1666
+ (0, import_validation_core6.resolveAffix)(opts),
1667
+ opts?.coerceDates ?? "input",
1668
+ void 0,
1669
+ !!opts?.applyDefaults,
1670
+ !!opts?.duplicateFinder
1671
+ );
1672
+ }
1673
+ defaultIndex(analysis, opts) {
1674
+ const fileSuffix = opts.fileSuffix ?? DEFAULT_FILE_SUFFIX2;
1675
+ return analysis.tables.map(
1676
+ (t) => `export * from '${(0, import_validation_core6.moduleSpecifier)(t.tsName, fileSuffix, opts.importExtension)}';`
1677
+ ).join("\n") + "\n";
1678
+ }
1679
+ };
1680
+ index_default3 = EffectGenerator;
1681
+ }
1682
+ });
1683
+
1143
1684
  // src/cli.ts
1144
1685
  var import_analyzer = require("@drzl/analyzer");
1145
1686
  var import_generator_orpc = require("@drzl/generator-orpc");
1146
- var import_chalk2 = __toESM(require("chalk"), 1);
1687
+ var import_chalk3 = __toESM(require("chalk"), 1);
1147
1688
  var import_chokidar = __toESM(require("chokidar"), 1);
1148
1689
  var import_cli_progress = __toESM(require("cli-progress"), 1);
1149
1690
  var import_commander = require("commander");
@@ -1229,7 +1770,17 @@ var AffixSchema = import_zod.z.object({
1229
1770
  }).strict();
1230
1771
  var ImportExtensionSchema = import_zod.z.enum(import_validation_core.IMPORT_EXTENSIONS);
1231
1772
  var GeneratorSchema = import_zod.z.object({
1232
- kind: import_zod.z.enum(["orpc", "trpc", "service", "zod", "valibot", "arktype", "typebox", "json-schema"]),
1773
+ kind: import_zod.z.enum([
1774
+ "orpc",
1775
+ "trpc",
1776
+ "service",
1777
+ "zod",
1778
+ "valibot",
1779
+ "arktype",
1780
+ "typebox",
1781
+ "effect",
1782
+ "json-schema"
1783
+ ]),
1233
1784
  /**
1234
1785
  * Overrides the top-level `importExtension` for this generator alone, for a project whose
1235
1786
  * generated directories are compiled by different tsconfigs.
@@ -1563,6 +2114,7 @@ function computeGeneratorOutputDirs(cfg, cwd = process.cwd()) {
1563
2114
  if (g.kind === "valibot") dirs.add(abs(g.path ?? "src/validators/valibot"));
1564
2115
  if (g.kind === "arktype") dirs.add(abs(g.path ?? "src/validators/arktype"));
1565
2116
  if (g.kind === "typebox") dirs.add(abs(g.path ?? "src/validators/typebox"));
2117
+ if (g.kind === "effect") dirs.add(abs(g.path ?? "src/validators/effect"));
1566
2118
  if (g.kind === "json-schema") dirs.add(abs(g.path ?? "src/validators/json-schema"));
1567
2119
  }
1568
2120
  return [...dirs];
@@ -1635,6 +2187,264 @@ function trpcOptions(g, cfg, servicesDir) {
1635
2187
  };
1636
2188
  }
1637
2189
 
2190
+ // src/doctor.ts
2191
+ var import_validation_core2 = require("@drzl/validation-core");
2192
+ var import_chalk = __toESM(require("chalk"), 1);
2193
+ var HANDLED_CODES = /* @__PURE__ */ new Set(["DRZL_ANL_UNKNOWN_COLUMN"]);
2194
+ function splitPath(path6) {
2195
+ if (!path6) return {};
2196
+ const dot = path6.lastIndexOf(".");
2197
+ if (dot <= 0) return { table: path6 };
2198
+ return { table: path6.slice(0, dot), column: path6.slice(dot + 1) };
2199
+ }
2200
+ function namedColumns(parsed) {
2201
+ const out = [];
2202
+ for (const c of parsed.checks) out.push({ column: c.column, scalar: true });
2203
+ for (const s of parsed.sets ?? []) out.push({ column: s.column, scalar: true });
2204
+ for (const l of parsed.lengths ?? []) out.push({ column: l.column, scalar: false });
2205
+ for (const c of parsed.cardinalities ?? []) out.push({ column: c.column, scalar: false });
2206
+ for (const r of parsed.rows ?? []) {
2207
+ out.push({ column: r.left, scalar: false });
2208
+ out.push({ column: r.right, scalar: false });
2209
+ }
2210
+ return out;
2211
+ }
2212
+ function describeShape(c) {
2213
+ if (c.arrayDimensions) return "an array";
2214
+ switch (c.shape?.kind) {
2215
+ case "json":
2216
+ return "a JSON";
2217
+ case "buffer":
2218
+ return "a binary";
2219
+ case "tuple":
2220
+ case "numberObject":
2221
+ return "a structured";
2222
+ case "numberVector":
2223
+ return "a vector";
2224
+ case "bitstring":
2225
+ return "a bit-string";
2226
+ case "byteString":
2227
+ return "a byte-string";
2228
+ case "custom":
2229
+ return "a customType";
2230
+ default:
2231
+ return "a structured";
2232
+ }
2233
+ }
2234
+ function checkFindings(table) {
2235
+ const out = [];
2236
+ const byName = new Map(table.columns.map((c) => [c.name, c]));
2237
+ for (const k of table.checks ?? []) {
2238
+ const label = k.name ? `"${k.name}"` : "an unnamed constraint";
2239
+ const raw = k.expression ?? "";
2240
+ const expr = raw.trim() ? raw : "(empty)";
2241
+ const parsed = (0, import_validation_core2.parseCheck)(raw, k.name);
2242
+ if (!parsed.ok) {
2243
+ out.push({
2244
+ kind: "check-declined",
2245
+ level: "warn",
2246
+ table: table.tsName,
2247
+ constraint: k.name,
2248
+ message: `CHECK ${label} on "${table.tsName}" is not translated: ${parsed.reason}. Expression: ${expr}`,
2249
+ hint: "Only constraints whose meaning is unambiguous are translated, because a validator enforcing a guess rejects rows the database accepts. Your database still enforces this one; nothing DRZL emits does."
2250
+ });
2251
+ continue;
2252
+ }
2253
+ const seen = /* @__PURE__ */ new Set();
2254
+ for (const { column, scalar } of namedColumns(parsed)) {
2255
+ if (seen.has(column)) continue;
2256
+ seen.add(column);
2257
+ const col = byName.get(column);
2258
+ if (!col) {
2259
+ out.push({
2260
+ kind: "check-unknown-column",
2261
+ level: "warn",
2262
+ table: table.tsName,
2263
+ column,
2264
+ constraint: k.name,
2265
+ message: `CHECK ${label} on "${table.tsName}" names "${column}", which is not a column of that table, so nothing enforces it. Expression: ${expr}`,
2266
+ hint: "A constraint is attached to the field it names. Check the spelling, or move a constraint spanning two tables out of the schema."
2267
+ });
2268
+ continue;
2269
+ }
2270
+ if (scalar && (col.arrayDimensions || col.shape)) {
2271
+ out.push({
2272
+ kind: "check-not-scalar",
2273
+ level: "warn",
2274
+ table: table.tsName,
2275
+ column,
2276
+ constraint: k.name,
2277
+ message: `CHECK ${label} on "${table.tsName}" compares ${describeShape(col)} column "${column}" against a scalar literal, which does not describe it, so it is not translated. Expression: ${expr}`,
2278
+ hint: "On an array column only cardinality(col) is read, since it is the one comparison that is about the array rather than about an element."
2279
+ });
2280
+ }
2281
+ }
2282
+ }
2283
+ return out;
2284
+ }
2285
+ function primaryKeyFindings(table) {
2286
+ if (table.readOnly) return [];
2287
+ const pk = table.primaryKey?.columns ?? [];
2288
+ if (!pk.length) {
2289
+ const hasId = table.columns.some((c) => c.name === "id");
2290
+ return [
2291
+ {
2292
+ kind: "no-primary-key",
2293
+ level: "warn",
2294
+ table: table.tsName,
2295
+ message: hasId ? `Table "${table.tsName}" declares no primary key. The service and router generators fall back to a column named "id", which this table happens to have, so they work by coincidence.` : `Table "${table.tsName}" declares no primary key. The service and router generators fall back to a column named "id", which this table does not have, so the generated service will not compile.`,
2296
+ hint: "Declare a primary key, or leave this table out with the config table filter."
2297
+ }
2298
+ ];
2299
+ }
2300
+ if (pk.length > 1) {
2301
+ return [
2302
+ {
2303
+ kind: "partial-primary-key",
2304
+ level: "warn",
2305
+ table: table.tsName,
2306
+ message: `Table "${table.tsName}" has a composite primary key (${pk.join(", ")}). The service and router generators key getById, update and delete on "${pk[0]}" alone, so those operations match on part of the key.`,
2307
+ hint: "Treat the generated service as a starting point for this table and widen the key by hand."
2308
+ }
2309
+ ];
2310
+ }
2311
+ return [];
2312
+ }
2313
+ function buildDoctorReport(analysis, schemaPath) {
2314
+ const findings = [];
2315
+ const errors = analysis.issues.filter((i) => i.level === "error");
2316
+ for (const i of errors) {
2317
+ findings.push({
2318
+ kind: "analyzer",
2319
+ level: "error",
2320
+ ...splitPath(i.path),
2321
+ message: i.message,
2322
+ hint: i.hint
2323
+ });
2324
+ }
2325
+ for (const i of analysis.issues) {
2326
+ if (i.code !== "DRZL_ANL_UNKNOWN_COLUMN") continue;
2327
+ findings.push({
2328
+ kind: "unknown-column",
2329
+ level: "warn",
2330
+ ...splitPath(i.path),
2331
+ message: i.message,
2332
+ hint: i.hint
2333
+ });
2334
+ }
2335
+ for (const t of analysis.tables) findings.push(...checkFindings(t));
2336
+ for (const t of analysis.tables) findings.push(...primaryKeyFindings(t));
2337
+ for (const i of analysis.issues) {
2338
+ if (i.level === "error" || HANDLED_CODES.has(i.code)) continue;
2339
+ findings.push({
2340
+ kind: "analyzer",
2341
+ level: "warn",
2342
+ ...splitPath(i.path),
2343
+ message: i.message,
2344
+ hint: i.hint
2345
+ });
2346
+ }
2347
+ const columns = analysis.tables.reduce((n, t) => n + t.columns.length, 0);
2348
+ const checks = analysis.tables.reduce((n, t) => n + (t.checks?.length ?? 0), 0);
2349
+ return {
2350
+ schema: schemaPath,
2351
+ dialect: analysis.dialect,
2352
+ ok: findings.length === 0,
2353
+ counts: { tables: analysis.tables.length, columns, checks, findings: findings.length },
2354
+ findings
2355
+ };
2356
+ }
2357
+ var SECTIONS = [
2358
+ {
2359
+ kinds: ["unknown-column"],
2360
+ title: "Columns DRZL cannot type",
2361
+ why: "These get a validator that accepts any value."
2362
+ },
2363
+ {
2364
+ kinds: ["check-declined", "check-unknown-column", "check-not-scalar"],
2365
+ title: "CHECK constraints DRZL does not enforce",
2366
+ why: "Your database still enforces these. Nothing DRZL generates does."
2367
+ },
2368
+ {
2369
+ kinds: ["no-primary-key", "partial-primary-key"],
2370
+ title: "Primary keys the generators cannot use",
2371
+ why: "The generated getById, update and delete are keyed on one column."
2372
+ },
2373
+ {
2374
+ kinds: ["analyzer"],
2375
+ title: "Other findings",
2376
+ why: "Reported by the analyzer while reading the schema."
2377
+ }
2378
+ ];
2379
+ function wrap(text, indent, first = indent, width = 96) {
2380
+ const lines = [];
2381
+ let line = "";
2382
+ for (const word of text.split(/\s+/)) {
2383
+ if (line && `${line} ${word}`.length + indent.length > width) {
2384
+ lines.push(line);
2385
+ line = word;
2386
+ } else {
2387
+ line = line ? `${line} ${word}` : word;
2388
+ }
2389
+ }
2390
+ if (line) lines.push(line);
2391
+ return lines.map((l, i) => (i === 0 ? first : indent) + l).join("\n");
2392
+ }
2393
+ function renderDoctorReport(report) {
2394
+ const out = [];
2395
+ const plural = (n, one) => `${n} ${one}${n === 1 ? "" : "s"}`;
2396
+ out.push(import_chalk.default.bold(`DRZL doctor ${report.schema}`));
2397
+ out.push(
2398
+ import_chalk.default.dim(
2399
+ `${report.dialect}, ${plural(report.counts.tables, "table")}, ${plural(report.counts.columns, "column")}, ${plural(report.counts.checks, "CHECK constraint")}`
2400
+ )
2401
+ );
2402
+ out.push("");
2403
+ if (report.ok) {
2404
+ out.push(import_chalk.default.green("Nothing to report."));
2405
+ out.push(import_chalk.default.dim(" Every column has a type DRZL can describe."));
2406
+ out.push(import_chalk.default.dim(" Every CHECK constraint is translated into the generated validators."));
2407
+ out.push(import_chalk.default.dim(" Every table has a primary key the generators can use."));
2408
+ return out.join("\n");
2409
+ }
2410
+ const fatal = report.findings.filter((f) => f.level === "error");
2411
+ if (fatal.length) {
2412
+ out.push(import_chalk.default.red("DRZL could not read this schema"));
2413
+ out.push(import_chalk.default.dim(" Nothing else could be checked."));
2414
+ out.push("");
2415
+ for (const f of fatal) {
2416
+ out.push(wrap(f.message, " ", ` ${import_chalk.default.dim("-")} `));
2417
+ if (f.hint) out.push(import_chalk.default.dim(wrap(f.hint, " ")));
2418
+ }
2419
+ out.push("");
2420
+ }
2421
+ for (const section of SECTIONS) {
2422
+ const mine = report.findings.filter(
2423
+ (f) => f.level !== "error" && section.kinds.includes(f.kind)
2424
+ );
2425
+ if (!mine.length) continue;
2426
+ out.push(import_chalk.default.yellow(`${section.title} (${mine.length})`));
2427
+ out.push(import_chalk.default.dim(` ${section.why}`));
2428
+ out.push("");
2429
+ const groups = /* @__PURE__ */ new Map();
2430
+ for (const f of mine) {
2431
+ const key = f.hint ?? "";
2432
+ groups.set(key, [...groups.get(key) ?? [], f]);
2433
+ }
2434
+ for (const [hint, items] of groups) {
2435
+ for (const f of items) out.push(wrap(f.message, " ", ` ${import_chalk.default.dim("-")} `));
2436
+ if (hint) out.push(import_chalk.default.dim(wrap(hint, " ")));
2437
+ out.push("");
2438
+ }
2439
+ }
2440
+ out.push(
2441
+ import_chalk.default.bold(`${plural(report.counts.findings, "finding")} in ${report.schema}.`) + import_chalk.default.dim(
2442
+ fatal.length ? " Fix the error above and run this again." : " None of these stop DRZL generating; they are what it will not check for you."
2443
+ )
2444
+ );
2445
+ return out.join("\n");
2446
+ }
2447
+
1638
2448
  // src/drift.ts
1639
2449
  var import_node_fs = require("fs");
1640
2450
  var import_node_path = __toESM(require("path"), 1);
@@ -1711,7 +2521,7 @@ async function loadGenerator(specifier, load) {
1711
2521
  }
1712
2522
 
1713
2523
  // src/sponsor.ts
1714
- var import_chalk = __toESM(require("chalk"), 1);
2524
+ var import_chalk2 = __toESM(require("chalk"), 1);
1715
2525
  var import_node_fs2 = require("fs");
1716
2526
  var import_node_path2 = __toESM(require("path"), 1);
1717
2527
  var CACHE_DIR = import_node_path2.default.join(process.cwd(), "node_modules", ".cache", "@drzl");
@@ -1721,13 +2531,13 @@ var shownThisProcess = false;
1721
2531
  var tips = [
1722
2532
  "Pair DRZL watch mode with drizzle-kit to keep schema & API synced.",
1723
2533
  "Templatize your ORPC routers to roll out new endpoints safely.",
1724
- "Need typed validators? Enable the zod, valibot, arktype, or typebox generators.",
2534
+ "Need typed validators? Enable the zod, valibot, arktype, typebox, or effect generators.",
1725
2535
  "Need JSON Schema or OpenAPI? The json-schema generator emits both, with no runtime dependency.",
1726
2536
  "Use output headers to track generated files and trim noisy diffs."
1727
2537
  ];
1728
- var green = (msg) => import_chalk.default.hex("#6ee7b7")(msg);
1729
- var cyan = (msg) => import_chalk.default.cyan(msg);
1730
- var gray = (msg) => import_chalk.default.gray(msg);
2538
+ var green = (msg) => import_chalk2.default.hex("#6ee7b7")(msg);
2539
+ var cyan = (msg) => import_chalk2.default.cyan(msg);
2540
+ var gray = (msg) => import_chalk2.default.gray(msg);
1731
2541
  function maybeShowSponsorMessage({
1732
2542
  reason = "generate",
1733
2543
  minIntervalMs = DEFAULT_INTERVAL_MS,
@@ -1816,13 +2626,13 @@ var CLI_VERSION = readCliVersion();
1816
2626
  function reportGeneratorFailure(kind, e) {
1817
2627
  if (e instanceof GeneratorNotInstalledError) {
1818
2628
  console.error(
1819
- import_chalk2.default.red(`The ${kind} generator is not installed.`),
1820
- import_chalk2.default.yellow(`
2629
+ import_chalk3.default.red(`The ${kind} generator is not installed.`),
2630
+ import_chalk3.default.yellow(`
1821
2631
  Install with: npm install ${e.specifier}`)
1822
2632
  );
1823
2633
  return;
1824
2634
  }
1825
- console.error(import_chalk2.default.red(`The ${kind} generator failed:`), e?.message ?? e);
2635
+ console.error(import_chalk3.default.red(`The ${kind} generator failed:`), e?.message ?? e);
1826
2636
  }
1827
2637
  var program = new import_commander.Command();
1828
2638
  program.name("drzl").description("DRZL - Drizzle Developer Toolkit").version(CLI_VERSION);
@@ -1849,9 +2659,9 @@ program.command("analyze").argument("<schema>", "path to drizzle schema (TS)").o
1849
2659
  } else if (opts.out) {
1850
2660
  const fs3 = await import("fs/promises");
1851
2661
  await fs3.writeFile(opts.out, json, "utf8");
1852
- spinner?.succeed(import_chalk2.default.green(`Analysis written to ${opts.out} in ${ms}ms`));
2662
+ spinner?.succeed(import_chalk3.default.green(`Analysis written to ${opts.out} in ${ms}ms`));
1853
2663
  } else {
1854
- spinner?.succeed(import_chalk2.default.green(`Analyzed in ${ms}ms`));
2664
+ spinner?.succeed(import_chalk3.default.green(`Analyzed in ${ms}ms`));
1855
2665
  console.log(json);
1856
2666
  }
1857
2667
  process.exit(res.issues.some((i) => i.level === "error") ? 2 : 0);
@@ -1861,7 +2671,48 @@ program.command("analyze").argument("<schema>", "path to drizzle schema (TS)").o
1861
2671
  console.log(JSON.stringify({ event: "error", code: "DRZL_CLI_ANALYZE", message: msg }));
1862
2672
  else
1863
2673
  console.error(
1864
- import_chalk2.default.red("Analyze failed (DRZL_CLI_ANALYZE):"),
2674
+ import_chalk3.default.red("Analyze failed (DRZL_CLI_ANALYZE):"),
2675
+ msg,
2676
+ "\nTip: run with --json for structured output."
2677
+ );
2678
+ process.exit(1);
2679
+ }
2680
+ });
2681
+ program.command("doctor").description("Report what DRZL cannot type or enforce in your schema, and why").argument("[schema]", "path to drizzle schema (TS); defaults to the schema in drzl.config").option("-c, --config <path>", "path to drzl.config, read when no schema argument is given").option("--json", "print the report as JSON instead of prose", false).option("--strict", "exit 2 when anything is reported", false).action(async (schema, opts) => {
2682
+ try {
2683
+ let target = schema;
2684
+ if (!target) {
2685
+ const cfg = await loadConfig(opts.config);
2686
+ target = cfg?.schema;
2687
+ }
2688
+ if (!target) {
2689
+ const msg = "No schema given. Pass a path, or run from a directory with a drzl.config.";
2690
+ if (opts.json)
2691
+ console.log(JSON.stringify({ event: "error", code: "DRZL_CLI_DOCTOR", message: msg }));
2692
+ else console.error(import_chalk3.default.red("Doctor failed (DRZL_CLI_DOCTOR):"), msg);
2693
+ process.exit(1);
2694
+ return;
2695
+ }
2696
+ const analyzer = new import_analyzer.SchemaAnalyzer(target);
2697
+ const analysis = await analyzer.analyze({
2698
+ includeRelations: true,
2699
+ validateConstraints: true
2700
+ });
2701
+ const report = buildDoctorReport(analysis, target);
2702
+ if (opts.json) console.log(JSON.stringify(report, null, 2));
2703
+ else console.log(renderDoctorReport(report));
2704
+ if (report.findings.some((f) => f.level === "error")) {
2705
+ process.exit(1);
2706
+ return;
2707
+ }
2708
+ process.exit(opts.strict && report.findings.length ? 2 : 0);
2709
+ } catch (e) {
2710
+ const msg = e?.message ?? String(e);
2711
+ if (opts.json)
2712
+ console.log(JSON.stringify({ event: "error", code: "DRZL_CLI_DOCTOR", message: msg }));
2713
+ else
2714
+ console.error(
2715
+ import_chalk3.default.red("Doctor failed (DRZL_CLI_DOCTOR):"),
1865
2716
  msg,
1866
2717
  "\nTip: run with --json for structured output."
1867
2718
  );
@@ -1876,7 +2727,7 @@ program.command("generate").description("Run configured generators (drzl.config.
1876
2727
  const cfg = await loadConfig(opts.config);
1877
2728
  if (!cfg) {
1878
2729
  console.error(
1879
- import_chalk2.default.red("No config found (DRZL_CFG_001). Create drzl.config.ts or pass --config.")
2730
+ import_chalk3.default.red("No config found (DRZL_CFG_001). Create drzl.config.ts or pass --config.")
1880
2731
  );
1881
2732
  process.exit(2);
1882
2733
  return;
@@ -1921,8 +2772,8 @@ program.command("generate").description("Run configured generators (drzl.config.
1921
2772
  onProgress: ({ index }) => progress.update(index)
1922
2773
  });
1923
2774
  progress.stop();
1924
- (0, import_ora.default)().succeed(import_chalk2.default.green(`Generated (${g.kind}): ${files.length} files`));
1925
- files.forEach((f) => console.log(" -", import_chalk2.default.cyan(f)));
2775
+ (0, import_ora.default)().succeed(import_chalk3.default.green(`Generated (${g.kind}): ${files.length} files`));
2776
+ files.forEach((f) => console.log(" -", import_chalk3.default.cyan(f)));
1926
2777
  } else if (g.kind === "trpc") {
1927
2778
  try {
1928
2779
  const { TRPCGenerator: TRPCGenerator2 } = await loadGenerator(
@@ -1935,8 +2786,8 @@ program.command("generate").description("Run configured generators (drzl.config.
1935
2786
  onProgress: ({ index }) => progress.update(index)
1936
2787
  });
1937
2788
  progress.stop();
1938
- (0, import_ora.default)().succeed(import_chalk2.default.green(`Generated (trpc): ${files.length} files`));
1939
- files.forEach((f) => console.log(" -", import_chalk2.default.cyan(f)));
2789
+ (0, import_ora.default)().succeed(import_chalk3.default.green(`Generated (trpc): ${files.length} files`));
2790
+ files.forEach((f) => console.log(" -", import_chalk3.default.cyan(f)));
1940
2791
  } catch (e) {
1941
2792
  progress.stop();
1942
2793
  reportGeneratorFailure(g.kind, e);
@@ -1965,8 +2816,8 @@ program.command("generate").description("Run configured generators (drzl.config.
1965
2816
  databaseInjection: g.databaseInjection
1966
2817
  });
1967
2818
  progress.stop();
1968
- (0, import_ora.default)().succeed(import_chalk2.default.green(`Generated (service): ${files.length} files`));
1969
- files.forEach((f) => console.log(" -", import_chalk2.default.cyan(f)));
2819
+ (0, import_ora.default)().succeed(import_chalk3.default.green(`Generated (service): ${files.length} files`));
2820
+ files.forEach((f) => console.log(" -", import_chalk3.default.cyan(f)));
1970
2821
  } catch (e) {
1971
2822
  progress.stop();
1972
2823
  reportGeneratorFailure(g.kind, e);
@@ -1984,8 +2835,8 @@ program.command("generate").description("Run configured generators (drzl.config.
1984
2835
  validationOptions(g, cfg, target, { schemaTypes: true })
1985
2836
  );
1986
2837
  progress.stop();
1987
- (0, import_ora.default)().succeed(import_chalk2.default.green(`Generated (zod): ${files.length} files`));
1988
- files.forEach((f) => console.log(" -", import_chalk2.default.cyan(f)));
2838
+ (0, import_ora.default)().succeed(import_chalk3.default.green(`Generated (zod): ${files.length} files`));
2839
+ files.forEach((f) => console.log(" -", import_chalk3.default.cyan(f)));
1989
2840
  } catch (e) {
1990
2841
  progress.stop();
1991
2842
  reportGeneratorFailure(g.kind, e);
@@ -2003,8 +2854,8 @@ program.command("generate").description("Run configured generators (drzl.config.
2003
2854
  validationOptions(g, cfg, target, { schemaTypes: true })
2004
2855
  );
2005
2856
  progress.stop();
2006
- (0, import_ora.default)().succeed(import_chalk2.default.green(`Generated (valibot): ${files.length} files`));
2007
- files.forEach((f) => console.log(" -", import_chalk2.default.cyan(f)));
2857
+ (0, import_ora.default)().succeed(import_chalk3.default.green(`Generated (valibot): ${files.length} files`));
2858
+ files.forEach((f) => console.log(" -", import_chalk3.default.cyan(f)));
2008
2859
  } catch (e) {
2009
2860
  progress.stop();
2010
2861
  reportGeneratorFailure(g.kind, e);
@@ -2022,8 +2873,8 @@ program.command("generate").description("Run configured generators (drzl.config.
2022
2873
  validationOptions(g, cfg, target, { schemaTypes: false })
2023
2874
  );
2024
2875
  progress.stop();
2025
- (0, import_ora.default)().succeed(import_chalk2.default.green(`Generated (arktype): ${files.length} files`));
2026
- files.forEach((f) => console.log(" -", import_chalk2.default.cyan(f)));
2876
+ (0, import_ora.default)().succeed(import_chalk3.default.green(`Generated (arktype): ${files.length} files`));
2877
+ files.forEach((f) => console.log(" -", import_chalk3.default.cyan(f)));
2027
2878
  } catch (e) {
2028
2879
  progress.stop();
2029
2880
  reportGeneratorFailure(g.kind, e);
@@ -2039,8 +2890,8 @@ program.command("generate").description("Run configured generators (drzl.config.
2039
2890
  const target = g.path ?? "src/validators/json-schema";
2040
2891
  const files = await gen.generate(jsonSchemaOptions(g, cfg, target));
2041
2892
  progress.stop();
2042
- (0, import_ora.default)().succeed(import_chalk2.default.green(`Generated (json-schema): ${files.length} files`));
2043
- files.forEach((f) => console.log(" -", import_chalk2.default.cyan(f)));
2893
+ (0, import_ora.default)().succeed(import_chalk3.default.green(`Generated (json-schema): ${files.length} files`));
2894
+ files.forEach((f) => console.log(" -", import_chalk3.default.cyan(f)));
2044
2895
  } catch (e) {
2045
2896
  progress.stop();
2046
2897
  reportGeneratorFailure(g.kind, e);
@@ -2058,8 +2909,27 @@ program.command("generate").description("Run configured generators (drzl.config.
2058
2909
  validationOptions(g, cfg, target, { schemaTypes: true })
2059
2910
  );
2060
2911
  progress.stop();
2061
- (0, import_ora.default)().succeed(import_chalk2.default.green(`Generated (typebox): ${files.length} files`));
2062
- files.forEach((f) => console.log(" -", import_chalk2.default.cyan(f)));
2912
+ (0, import_ora.default)().succeed(import_chalk3.default.green(`Generated (typebox): ${files.length} files`));
2913
+ files.forEach((f) => console.log(" -", import_chalk3.default.cyan(f)));
2914
+ } catch (e) {
2915
+ progress.stop();
2916
+ reportGeneratorFailure(g.kind, e);
2917
+ process.exit(1);
2918
+ }
2919
+ } else if (g.kind === "effect") {
2920
+ try {
2921
+ const { EffectGenerator: EffectGenerator2 } = await loadGenerator(
2922
+ "@drzl/generator-effect",
2923
+ () => Promise.resolve().then(() => (init_dist3(), dist_exports3))
2924
+ );
2925
+ const gen = new EffectGenerator2(analysis);
2926
+ const target = g.path ?? "src/validators/effect";
2927
+ const files = await gen.generate(
2928
+ validationOptions(g, cfg, target, { schemaTypes: true })
2929
+ );
2930
+ progress.stop();
2931
+ (0, import_ora.default)().succeed(import_chalk3.default.green(`Generated (effect): ${files.length} files`));
2932
+ files.forEach((f) => console.log(" -", import_chalk3.default.cyan(f)));
2063
2933
  } catch (e) {
2064
2934
  progress.stop();
2065
2935
  reportGeneratorFailure(g.kind, e);
@@ -2072,22 +2942,22 @@ program.command("generate").description("Run configured generators (drzl.config.
2072
2942
  const drift = diffSnapshots(driftBefore, after);
2073
2943
  await restoreSnapshot(driftBefore, after);
2074
2944
  if (drift.length) {
2075
- console.error(import_chalk2.default.red(`
2945
+ console.error(import_chalk3.default.red(`
2076
2946
  Generated output is out of date (${drift.length} file(s)):`));
2077
2947
  for (const d of drift) {
2078
2948
  const mark = d.status === "added" ? "+" : d.status === "removed" ? "-" : "~";
2079
2949
  console.error(
2080
- ` ${mark} ${import_chalk2.default.yellow(d.status.padEnd(8))} ${path5.relative(process.cwd(), d.file)}`
2950
+ ` ${mark} ${import_chalk3.default.yellow(d.status.padEnd(8))} ${path5.relative(process.cwd(), d.file)}`
2081
2951
  );
2082
2952
  }
2083
2953
  console.error(
2084
- import_chalk2.default.dim(
2954
+ import_chalk3.default.dim(
2085
2955
  "\nRun `drzl generate` and commit the result. Nothing was written by this check."
2086
2956
  )
2087
2957
  );
2088
2958
  process.exit(1);
2089
2959
  }
2090
- console.log(import_chalk2.default.green("Generated output is up to date."));
2960
+ console.log(import_chalk3.default.green("Generated output is up to date."));
2091
2961
  return;
2092
2962
  }
2093
2963
  if (cfg.generators.length) {
@@ -2095,7 +2965,7 @@ Generated output is out of date (${drift.length} file(s)):`));
2095
2965
  }
2096
2966
  } catch (e) {
2097
2967
  console.error(
2098
- import_chalk2.default.red("Generate failed (DRZL_GEN_001):"),
2968
+ import_chalk3.default.red("Generate failed (DRZL_GEN_001):"),
2099
2969
  e?.message ?? e,
2100
2970
  "\nTip: check your drzl.config.ts and template path."
2101
2971
  );
@@ -2115,10 +2985,10 @@ program.command("generate:orpc").argument("<schema>", "path to drizzle schema (T
2115
2985
  template: opts.template,
2116
2986
  includeRelations: !!opts.includeRelations
2117
2987
  });
2118
- console.log(import_chalk2.default.green(`Generated:`), files.map((f) => import_chalk2.default.cyan(f)).join(", "));
2988
+ console.log(import_chalk3.default.green(`Generated:`), files.map((f) => import_chalk3.default.cyan(f)).join(", "));
2119
2989
  maybeShowSponsorMessage({ reason: "generate:orpc" });
2120
2990
  } catch (e) {
2121
- console.error(import_chalk2.default.red("Generate orpc failed:"), e?.message ?? e);
2991
+ console.error(import_chalk3.default.red("Generate orpc failed:"), e?.message ?? e);
2122
2992
  process.exit(1);
2123
2993
  }
2124
2994
  });
@@ -2142,7 +3012,7 @@ program.command("generate:trpc").argument("<schema>", "path to drizzle schema (T
2142
3012
  // cannot become the branch that forgets it.
2143
3013
  servicesDir: opts.servicesDir
2144
3014
  });
2145
- console.log(import_chalk2.default.green(`Generated:`), files.map((f) => import_chalk2.default.cyan(f)).join(", "));
3015
+ console.log(import_chalk3.default.green(`Generated:`), files.map((f) => import_chalk3.default.cyan(f)).join(", "));
2146
3016
  maybeShowSponsorMessage({ reason: "generate:trpc" });
2147
3017
  } catch (e) {
2148
3018
  reportGeneratorFailure("trpc", e);
@@ -2152,7 +3022,7 @@ program.command("generate:trpc").argument("<schema>", "path to drizzle schema (T
2152
3022
  program.command("watch").description("Watch schema and regenerate on changes").option("-c, --config <path>", "path to drzl.config").option("--pipeline <name>", "all | analyze | generate-orpc | generate-trpc", "all").option("--debounce <ms>", "debounce ms", "200").option("--json", "emit JSON logs", false).option("--poll", "force polling (helps WSL/Docker/remote FS)", false).action(async (opts) => {
2153
3023
  let cfg = await loadConfig(opts.config);
2154
3024
  if (!cfg) {
2155
- console.error(import_chalk2.default.red("No config found. Create drzl.config.ts or pass --config."));
3025
+ console.error(import_chalk3.default.red("No config found. Create drzl.config.ts or pass --config."));
2156
3026
  process.exit(2);
2157
3027
  return;
2158
3028
  }
@@ -2244,7 +3114,7 @@ program.command("watch").description("Watch schema and regenerate on changes").o
2244
3114
  })
2245
3115
  );
2246
3116
  } else {
2247
- console.log(import_chalk2.default.green("Analyze complete."));
3117
+ console.log(import_chalk3.default.green("Analyze complete."));
2248
3118
  }
2249
3119
  return;
2250
3120
  }
@@ -2274,8 +3144,8 @@ program.command("watch").description("Watch schema and regenerate on changes").o
2274
3144
  servicesDir
2275
3145
  });
2276
3146
  opts.json ? console.log(JSON.stringify({ event: "generate_complete", kind: g.kind, files })) : console.log(
2277
- import_chalk2.default.green(`Generated (${g.kind}):`),
2278
- files.map((f) => import_chalk2.default.cyan(f)).join(", ")
3147
+ import_chalk3.default.green(`Generated (${g.kind}):`),
3148
+ files.map((f) => import_chalk3.default.cyan(f)).join(", ")
2279
3149
  );
2280
3150
  newFiles.push(...files);
2281
3151
  } else if (g.kind === "trpc") {
@@ -2287,8 +3157,8 @@ program.command("watch").description("Watch schema and regenerate on changes").o
2287
3157
  const gen = new TRPCGenerator2(analysis);
2288
3158
  const { files } = await gen.generate(trpcOptions(g, cfg, servicesDir));
2289
3159
  opts.json ? console.log(JSON.stringify({ event: "generate_complete", kind: g.kind, files })) : console.log(
2290
- import_chalk2.default.green(`Generated (trpc): ${files.length} files`),
2291
- files.map((f) => import_chalk2.default.cyan(f)).join(", ")
3160
+ import_chalk3.default.green(`Generated (trpc): ${files.length} files`),
3161
+ files.map((f) => import_chalk3.default.cyan(f)).join(", ")
2292
3162
  );
2293
3163
  newFiles.push(...files);
2294
3164
  } catch (e) {
@@ -2314,8 +3184,8 @@ program.command("watch").description("Watch schema and regenerate on changes").o
2314
3184
  databaseInjection: g.databaseInjection
2315
3185
  });
2316
3186
  opts.json ? console.log(JSON.stringify({ event: "generate_complete", kind: g.kind, files })) : console.log(
2317
- import_chalk2.default.green(`Generated (service): ${files.length} files`),
2318
- files.map((f) => import_chalk2.default.cyan(f)).join(", ")
3187
+ import_chalk3.default.green(`Generated (service): ${files.length} files`),
3188
+ files.map((f) => import_chalk3.default.cyan(f)).join(", ")
2319
3189
  );
2320
3190
  newFiles.push(...files);
2321
3191
  } catch (e) {
@@ -2334,8 +3204,8 @@ program.command("watch").description("Watch schema and regenerate on changes").o
2334
3204
  validationOptions(g, cfg, target, { schemaTypes: true })
2335
3205
  );
2336
3206
  opts.json ? console.log(JSON.stringify({ event: "generate_complete", kind: g.kind, files })) : console.log(
2337
- import_chalk2.default.green(`Generated (zod): ${files.length} files`),
2338
- files.map((f) => import_chalk2.default.cyan(f)).join(", ")
3207
+ import_chalk3.default.green(`Generated (zod): ${files.length} files`),
3208
+ files.map((f) => import_chalk3.default.cyan(f)).join(", ")
2339
3209
  );
2340
3210
  newFiles.push(...files);
2341
3211
  } catch (e) {
@@ -2354,8 +3224,8 @@ program.command("watch").description("Watch schema and regenerate on changes").o
2354
3224
  validationOptions(g, cfg, target, { schemaTypes: true })
2355
3225
  );
2356
3226
  opts.json ? console.log(JSON.stringify({ event: "generate_complete", kind: g.kind, files })) : console.log(
2357
- import_chalk2.default.green(`Generated (valibot): ${files.length} files`),
2358
- files.map((f) => import_chalk2.default.cyan(f)).join(", ")
3227
+ import_chalk3.default.green(`Generated (valibot): ${files.length} files`),
3228
+ files.map((f) => import_chalk3.default.cyan(f)).join(", ")
2359
3229
  );
2360
3230
  newFiles.push(...files);
2361
3231
  } catch (e) {
@@ -2374,8 +3244,8 @@ program.command("watch").description("Watch schema and regenerate on changes").o
2374
3244
  validationOptions(g, cfg, target, { schemaTypes: false })
2375
3245
  );
2376
3246
  opts.json ? console.log(JSON.stringify({ event: "generate_complete", kind: g.kind, files })) : console.log(
2377
- import_chalk2.default.green(`Generated (arktype): ${files.length} files`),
2378
- files.map((f) => import_chalk2.default.cyan(f)).join(", ")
3247
+ import_chalk3.default.green(`Generated (arktype): ${files.length} files`),
3248
+ files.map((f) => import_chalk3.default.cyan(f)).join(", ")
2379
3249
  );
2380
3250
  newFiles.push(...files);
2381
3251
  } catch (e) {
@@ -2394,8 +3264,28 @@ program.command("watch").description("Watch schema and regenerate on changes").o
2394
3264
  validationOptions(g, cfg, target, { schemaTypes: true })
2395
3265
  );
2396
3266
  opts.json ? console.log(JSON.stringify({ event: "generate_complete", kind: g.kind, files })) : console.log(
2397
- import_chalk2.default.green(`Generated (typebox): ${files.length} files`),
2398
- files.map((f) => import_chalk2.default.cyan(f)).join(", ")
3267
+ import_chalk3.default.green(`Generated (typebox): ${files.length} files`),
3268
+ files.map((f) => import_chalk3.default.cyan(f)).join(", ")
3269
+ );
3270
+ newFiles.push(...files);
3271
+ } catch (e) {
3272
+ reportGeneratorFailure(g.kind, e);
3273
+ return;
3274
+ }
3275
+ } else if (g.kind === "effect") {
3276
+ try {
3277
+ const { EffectGenerator: EffectGenerator2 } = await loadGenerator(
3278
+ "@drzl/generator-effect",
3279
+ () => Promise.resolve().then(() => (init_dist3(), dist_exports3))
3280
+ );
3281
+ const gen = new EffectGenerator2(analysis);
3282
+ const target = g.path ?? "src/validators/effect";
3283
+ const files = await gen.generate(
3284
+ validationOptions(g, cfg, target, { schemaTypes: true })
3285
+ );
3286
+ opts.json ? console.log(JSON.stringify({ event: "generate_complete", kind: g.kind, files })) : console.log(
3287
+ import_chalk3.default.green(`Generated (effect): ${files.length} files`),
3288
+ files.map((f) => import_chalk3.default.cyan(f)).join(", ")
2399
3289
  );
2400
3290
  newFiles.push(...files);
2401
3291
  } catch (e) {
@@ -2412,8 +3302,8 @@ program.command("watch").description("Watch schema and regenerate on changes").o
2412
3302
  const target = g.path ?? "src/validators/json-schema";
2413
3303
  const files = await gen.generate(jsonSchemaOptions(g, cfg, target));
2414
3304
  opts.json ? console.log(JSON.stringify({ event: "generate_complete", kind: g.kind, files })) : console.log(
2415
- import_chalk2.default.green(`Generated (json-schema): ${files.length} files`),
2416
- files.map((f) => import_chalk2.default.cyan(f)).join(", ")
3305
+ import_chalk3.default.green(`Generated (json-schema): ${files.length} files`),
3306
+ files.map((f) => import_chalk3.default.cyan(f)).join(", ")
2417
3307
  );
2418
3308
  newFiles.push(...files);
2419
3309
  } catch (e) {
@@ -2425,8 +3315,8 @@ program.command("watch").description("Watch schema and regenerate on changes").o
2425
3315
  const added = newFiles.filter((f) => !lastFiles.includes(f));
2426
3316
  const removed = lastFiles.filter((f) => !newFiles.includes(f));
2427
3317
  opts.json ? console.log(JSON.stringify({ event: "diff", added, removed })) : (() => {
2428
- if (added.length) console.log(import_chalk2.default.blue(`Added: ${added.join(", ")}`));
2429
- if (removed.length) console.log(import_chalk2.default.yellow(`Removed: ${removed.join(", ")}`));
3318
+ if (added.length) console.log(import_chalk3.default.blue(`Added: ${added.join(", ")}`));
3319
+ if (removed.length) console.log(import_chalk3.default.yellow(`Removed: ${removed.join(", ")}`));
2430
3320
  })();
2431
3321
  if (newFiles.length && !opts.json) {
2432
3322
  const reason = opts.pipeline && opts.pipeline !== "all" ? `watch:${opts.pipeline}` : "watch";
@@ -2434,7 +3324,7 @@ program.command("watch").description("Watch schema and regenerate on changes").o
2434
3324
  }
2435
3325
  lastFiles = newFiles;
2436
3326
  } catch (e) {
2437
- opts.json ? console.log(JSON.stringify({ event: "error", message: String(e?.message ?? e) })) : console.error(import_chalk2.default.red("Watch pipeline failed:"), e?.message ?? e);
3327
+ opts.json ? console.log(JSON.stringify({ event: "error", message: String(e?.message ?? e) })) : console.error(import_chalk3.default.red("Watch pipeline failed:"), e?.message ?? e);
2438
3328
  }
2439
3329
  };
2440
3330
  const debounced = Number(opts.debounce) || 200;
@@ -2459,12 +3349,12 @@ program.command("watch").description("Watch schema and regenerate on changes").o
2459
3349
  );
2460
3350
  } else {
2461
3351
  console.log(
2462
- import_chalk2.default.gray(
3352
+ import_chalk3.default.gray(
2463
3353
  "Watching:\n " + Array.from(currentTargets).map((p) => path5.relative(process.cwd(), p)).join("\n ")
2464
3354
  )
2465
3355
  );
2466
3356
  }
2467
- watcher.on("add", (p) => trigger(p)).on("change", (p) => trigger(p)).on("unlink", (p) => trigger(p)).on("error", (err) => console.error(import_chalk2.default.red("Watcher error:"), err));
3357
+ watcher.on("add", (p) => trigger(p)).on("change", (p) => trigger(p)).on("unlink", (p) => trigger(p)).on("error", (err) => console.error(import_chalk3.default.red("Watcher error:"), err));
2468
3358
  await run();
2469
3359
  });
2470
3360
  program.command("init").description("Scaffold a drzl.config.ts").option("-y, --yes", "accept defaults").action(async (_opts) => {
@@ -2484,9 +3374,9 @@ program.command("init").description("Scaffold a drzl.config.ts").option("-y, --y
2484
3374
  `;
2485
3375
  try {
2486
3376
  await fs3.writeFile(target, template, { flag: "wx" });
2487
- console.log(import_chalk2.default.green(`Created ${target}`));
3377
+ console.log(import_chalk3.default.green(`Created ${target}`));
2488
3378
  } catch (e) {
2489
- console.error(import_chalk2.default.red("Init failed:"), e?.message ?? e);
3379
+ console.error(import_chalk3.default.red("Init failed:"), e?.message ?? e);
2490
3380
  process.exit(1);
2491
3381
  }
2492
3382
  });
@@ -2494,13 +3384,14 @@ function reportWideColumns(issues) {
2494
3384
  const wide = issues.filter((i) => i.code === "DRZL_ANL_UNKNOWN_COLUMN");
2495
3385
  if (!wide.length) return;
2496
3386
  console.warn(
2497
- import_chalk2.default.yellow(`
3387
+ import_chalk3.default.yellow(`
2498
3388
  ${wide.length} column${wide.length === 1 ? "" : "s"} could not be typed:`)
2499
3389
  );
2500
- for (const i of wide.slice(0, 10)) console.warn(import_chalk2.default.gray(` - ${i.message}`));
2501
- if (wide.length > 10) console.warn(import_chalk2.default.gray(` ... and ${wide.length - 10} more`));
3390
+ for (const i of wide.slice(0, 10)) console.warn(import_chalk3.default.gray(` - ${i.message}`));
3391
+ if (wide.length > 10) console.warn(import_chalk3.default.gray(` ... and ${wide.length - 10} more`));
2502
3392
  const hints = [...new Set(wide.map((i) => i.hint).filter(Boolean))];
2503
- for (const h of hints) console.warn(import_chalk2.default.gray(` ${h}`));
3393
+ for (const h of hints) console.warn(import_chalk3.default.gray(` ${h}`));
3394
+ console.warn(import_chalk3.default.gray(" Run `drzl doctor` for the full report."));
2504
3395
  }
2505
3396
  program.parseAsync(process.argv);
2506
3397
  //# sourceMappingURL=cli.cjs.map