@drzl/cli 4.17.0 → 4.18.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.js CHANGED
@@ -10,7 +10,7 @@ import {
10
10
  // src/cli.ts
11
11
  import { SchemaAnalyzer } from "@drzl/analyzer";
12
12
  import { ORPCGenerator } from "@drzl/generator-orpc";
13
- import chalk2 from "chalk";
13
+ import chalk3 from "chalk";
14
14
  import chokidar from "chokidar";
15
15
  import cliProgress from "cli-progress";
16
16
  import { Command } from "commander";
@@ -76,6 +76,264 @@ function trpcOptions(g, cfg, servicesDir) {
76
76
  };
77
77
  }
78
78
 
79
+ // src/doctor.ts
80
+ import { parseCheck } from "@drzl/validation-core";
81
+ import chalk from "chalk";
82
+ var HANDLED_CODES = /* @__PURE__ */ new Set(["DRZL_ANL_UNKNOWN_COLUMN"]);
83
+ function splitPath(path5) {
84
+ if (!path5) return {};
85
+ const dot = path5.lastIndexOf(".");
86
+ if (dot <= 0) return { table: path5 };
87
+ return { table: path5.slice(0, dot), column: path5.slice(dot + 1) };
88
+ }
89
+ function namedColumns(parsed) {
90
+ const out = [];
91
+ for (const c of parsed.checks) out.push({ column: c.column, scalar: true });
92
+ for (const s of parsed.sets ?? []) out.push({ column: s.column, scalar: true });
93
+ for (const l of parsed.lengths ?? []) out.push({ column: l.column, scalar: false });
94
+ for (const c of parsed.cardinalities ?? []) out.push({ column: c.column, scalar: false });
95
+ for (const r of parsed.rows ?? []) {
96
+ out.push({ column: r.left, scalar: false });
97
+ out.push({ column: r.right, scalar: false });
98
+ }
99
+ return out;
100
+ }
101
+ function describeShape(c) {
102
+ if (c.arrayDimensions) return "an array";
103
+ switch (c.shape?.kind) {
104
+ case "json":
105
+ return "a JSON";
106
+ case "buffer":
107
+ return "a binary";
108
+ case "tuple":
109
+ case "numberObject":
110
+ return "a structured";
111
+ case "numberVector":
112
+ return "a vector";
113
+ case "bitstring":
114
+ return "a bit-string";
115
+ case "byteString":
116
+ return "a byte-string";
117
+ case "custom":
118
+ return "a customType";
119
+ default:
120
+ return "a structured";
121
+ }
122
+ }
123
+ function checkFindings(table) {
124
+ const out = [];
125
+ const byName = new Map(table.columns.map((c) => [c.name, c]));
126
+ for (const k of table.checks ?? []) {
127
+ const label = k.name ? `"${k.name}"` : "an unnamed constraint";
128
+ const raw = k.expression ?? "";
129
+ const expr = raw.trim() ? raw : "(empty)";
130
+ const parsed = parseCheck(raw, k.name);
131
+ if (!parsed.ok) {
132
+ out.push({
133
+ kind: "check-declined",
134
+ level: "warn",
135
+ table: table.tsName,
136
+ constraint: k.name,
137
+ message: `CHECK ${label} on "${table.tsName}" is not translated: ${parsed.reason}. Expression: ${expr}`,
138
+ 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."
139
+ });
140
+ continue;
141
+ }
142
+ const seen = /* @__PURE__ */ new Set();
143
+ for (const { column, scalar } of namedColumns(parsed)) {
144
+ if (seen.has(column)) continue;
145
+ seen.add(column);
146
+ const col = byName.get(column);
147
+ if (!col) {
148
+ out.push({
149
+ kind: "check-unknown-column",
150
+ level: "warn",
151
+ table: table.tsName,
152
+ column,
153
+ constraint: k.name,
154
+ message: `CHECK ${label} on "${table.tsName}" names "${column}", which is not a column of that table, so nothing enforces it. Expression: ${expr}`,
155
+ hint: "A constraint is attached to the field it names. Check the spelling, or move a constraint spanning two tables out of the schema."
156
+ });
157
+ continue;
158
+ }
159
+ if (scalar && (col.arrayDimensions || col.shape)) {
160
+ out.push({
161
+ kind: "check-not-scalar",
162
+ level: "warn",
163
+ table: table.tsName,
164
+ column,
165
+ constraint: k.name,
166
+ 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}`,
167
+ 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."
168
+ });
169
+ }
170
+ }
171
+ }
172
+ return out;
173
+ }
174
+ function primaryKeyFindings(table) {
175
+ if (table.readOnly) return [];
176
+ const pk = table.primaryKey?.columns ?? [];
177
+ if (!pk.length) {
178
+ const hasId = table.columns.some((c) => c.name === "id");
179
+ return [
180
+ {
181
+ kind: "no-primary-key",
182
+ level: "warn",
183
+ table: table.tsName,
184
+ 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.`,
185
+ hint: "Declare a primary key, or leave this table out with the config table filter."
186
+ }
187
+ ];
188
+ }
189
+ if (pk.length > 1) {
190
+ return [
191
+ {
192
+ kind: "partial-primary-key",
193
+ level: "warn",
194
+ table: table.tsName,
195
+ 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.`,
196
+ hint: "Treat the generated service as a starting point for this table and widen the key by hand."
197
+ }
198
+ ];
199
+ }
200
+ return [];
201
+ }
202
+ function buildDoctorReport(analysis, schemaPath) {
203
+ const findings = [];
204
+ const errors = analysis.issues.filter((i) => i.level === "error");
205
+ for (const i of errors) {
206
+ findings.push({
207
+ kind: "analyzer",
208
+ level: "error",
209
+ ...splitPath(i.path),
210
+ message: i.message,
211
+ hint: i.hint
212
+ });
213
+ }
214
+ for (const i of analysis.issues) {
215
+ if (i.code !== "DRZL_ANL_UNKNOWN_COLUMN") continue;
216
+ findings.push({
217
+ kind: "unknown-column",
218
+ level: "warn",
219
+ ...splitPath(i.path),
220
+ message: i.message,
221
+ hint: i.hint
222
+ });
223
+ }
224
+ for (const t of analysis.tables) findings.push(...checkFindings(t));
225
+ for (const t of analysis.tables) findings.push(...primaryKeyFindings(t));
226
+ for (const i of analysis.issues) {
227
+ if (i.level === "error" || HANDLED_CODES.has(i.code)) continue;
228
+ findings.push({
229
+ kind: "analyzer",
230
+ level: "warn",
231
+ ...splitPath(i.path),
232
+ message: i.message,
233
+ hint: i.hint
234
+ });
235
+ }
236
+ const columns = analysis.tables.reduce((n, t) => n + t.columns.length, 0);
237
+ const checks = analysis.tables.reduce((n, t) => n + (t.checks?.length ?? 0), 0);
238
+ return {
239
+ schema: schemaPath,
240
+ dialect: analysis.dialect,
241
+ ok: findings.length === 0,
242
+ counts: { tables: analysis.tables.length, columns, checks, findings: findings.length },
243
+ findings
244
+ };
245
+ }
246
+ var SECTIONS = [
247
+ {
248
+ kinds: ["unknown-column"],
249
+ title: "Columns DRZL cannot type",
250
+ why: "These get a validator that accepts any value."
251
+ },
252
+ {
253
+ kinds: ["check-declined", "check-unknown-column", "check-not-scalar"],
254
+ title: "CHECK constraints DRZL does not enforce",
255
+ why: "Your database still enforces these. Nothing DRZL generates does."
256
+ },
257
+ {
258
+ kinds: ["no-primary-key", "partial-primary-key"],
259
+ title: "Primary keys the generators cannot use",
260
+ why: "The generated getById, update and delete are keyed on one column."
261
+ },
262
+ {
263
+ kinds: ["analyzer"],
264
+ title: "Other findings",
265
+ why: "Reported by the analyzer while reading the schema."
266
+ }
267
+ ];
268
+ function wrap(text, indent, first = indent, width = 96) {
269
+ const lines = [];
270
+ let line = "";
271
+ for (const word of text.split(/\s+/)) {
272
+ if (line && `${line} ${word}`.length + indent.length > width) {
273
+ lines.push(line);
274
+ line = word;
275
+ } else {
276
+ line = line ? `${line} ${word}` : word;
277
+ }
278
+ }
279
+ if (line) lines.push(line);
280
+ return lines.map((l, i) => (i === 0 ? first : indent) + l).join("\n");
281
+ }
282
+ function renderDoctorReport(report) {
283
+ const out = [];
284
+ const plural = (n, one) => `${n} ${one}${n === 1 ? "" : "s"}`;
285
+ out.push(chalk.bold(`DRZL doctor ${report.schema}`));
286
+ out.push(
287
+ chalk.dim(
288
+ `${report.dialect}, ${plural(report.counts.tables, "table")}, ${plural(report.counts.columns, "column")}, ${plural(report.counts.checks, "CHECK constraint")}`
289
+ )
290
+ );
291
+ out.push("");
292
+ if (report.ok) {
293
+ out.push(chalk.green("Nothing to report."));
294
+ out.push(chalk.dim(" Every column has a type DRZL can describe."));
295
+ out.push(chalk.dim(" Every CHECK constraint is translated into the generated validators."));
296
+ out.push(chalk.dim(" Every table has a primary key the generators can use."));
297
+ return out.join("\n");
298
+ }
299
+ const fatal = report.findings.filter((f) => f.level === "error");
300
+ if (fatal.length) {
301
+ out.push(chalk.red("DRZL could not read this schema"));
302
+ out.push(chalk.dim(" Nothing else could be checked."));
303
+ out.push("");
304
+ for (const f of fatal) {
305
+ out.push(wrap(f.message, " ", ` ${chalk.dim("-")} `));
306
+ if (f.hint) out.push(chalk.dim(wrap(f.hint, " ")));
307
+ }
308
+ out.push("");
309
+ }
310
+ for (const section of SECTIONS) {
311
+ const mine = report.findings.filter(
312
+ (f) => f.level !== "error" && section.kinds.includes(f.kind)
313
+ );
314
+ if (!mine.length) continue;
315
+ out.push(chalk.yellow(`${section.title} (${mine.length})`));
316
+ out.push(chalk.dim(` ${section.why}`));
317
+ out.push("");
318
+ const groups = /* @__PURE__ */ new Map();
319
+ for (const f of mine) {
320
+ const key = f.hint ?? "";
321
+ groups.set(key, [...groups.get(key) ?? [], f]);
322
+ }
323
+ for (const [hint, items] of groups) {
324
+ for (const f of items) out.push(wrap(f.message, " ", ` ${chalk.dim("-")} `));
325
+ if (hint) out.push(chalk.dim(wrap(hint, " ")));
326
+ out.push("");
327
+ }
328
+ }
329
+ out.push(
330
+ chalk.bold(`${plural(report.counts.findings, "finding")} in ${report.schema}.`) + chalk.dim(
331
+ 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."
332
+ )
333
+ );
334
+ return out.join("\n");
335
+ }
336
+
79
337
  // src/drift.ts
80
338
  import { promises as fs } from "fs";
81
339
  import path from "path";
@@ -152,7 +410,7 @@ async function loadGenerator(specifier, load) {
152
410
  }
153
411
 
154
412
  // src/sponsor.ts
155
- import chalk from "chalk";
413
+ import chalk2 from "chalk";
156
414
  import { existsSync, mkdirSync, readFileSync, writeFileSync } from "fs";
157
415
  import path2 from "path";
158
416
  var CACHE_DIR = path2.join(process.cwd(), "node_modules", ".cache", "@drzl");
@@ -166,9 +424,9 @@ var tips = [
166
424
  "Need JSON Schema or OpenAPI? The json-schema generator emits both, with no runtime dependency.",
167
425
  "Use output headers to track generated files and trim noisy diffs."
168
426
  ];
169
- var green = (msg) => chalk.hex("#6ee7b7")(msg);
170
- var cyan = (msg) => chalk.cyan(msg);
171
- var gray = (msg) => chalk.gray(msg);
427
+ var green = (msg) => chalk2.hex("#6ee7b7")(msg);
428
+ var cyan = (msg) => chalk2.cyan(msg);
429
+ var gray = (msg) => chalk2.gray(msg);
172
430
  function maybeShowSponsorMessage({
173
431
  reason = "generate",
174
432
  minIntervalMs = DEFAULT_INTERVAL_MS,
@@ -257,13 +515,13 @@ var CLI_VERSION = readCliVersion();
257
515
  function reportGeneratorFailure(kind, e) {
258
516
  if (e instanceof GeneratorNotInstalledError) {
259
517
  console.error(
260
- chalk2.red(`The ${kind} generator is not installed.`),
261
- chalk2.yellow(`
518
+ chalk3.red(`The ${kind} generator is not installed.`),
519
+ chalk3.yellow(`
262
520
  Install with: npm install ${e.specifier}`)
263
521
  );
264
522
  return;
265
523
  }
266
- console.error(chalk2.red(`The ${kind} generator failed:`), e?.message ?? e);
524
+ console.error(chalk3.red(`The ${kind} generator failed:`), e?.message ?? e);
267
525
  }
268
526
  var program = new Command();
269
527
  program.name("drzl").description("DRZL - Drizzle Developer Toolkit").version(CLI_VERSION);
@@ -290,9 +548,9 @@ program.command("analyze").argument("<schema>", "path to drizzle schema (TS)").o
290
548
  } else if (opts.out) {
291
549
  const fs2 = await import("fs/promises");
292
550
  await fs2.writeFile(opts.out, json, "utf8");
293
- spinner?.succeed(chalk2.green(`Analysis written to ${opts.out} in ${ms}ms`));
551
+ spinner?.succeed(chalk3.green(`Analysis written to ${opts.out} in ${ms}ms`));
294
552
  } else {
295
- spinner?.succeed(chalk2.green(`Analyzed in ${ms}ms`));
553
+ spinner?.succeed(chalk3.green(`Analyzed in ${ms}ms`));
296
554
  console.log(json);
297
555
  }
298
556
  process.exit(res.issues.some((i) => i.level === "error") ? 2 : 0);
@@ -302,7 +560,48 @@ program.command("analyze").argument("<schema>", "path to drizzle schema (TS)").o
302
560
  console.log(JSON.stringify({ event: "error", code: "DRZL_CLI_ANALYZE", message: msg }));
303
561
  else
304
562
  console.error(
305
- chalk2.red("Analyze failed (DRZL_CLI_ANALYZE):"),
563
+ chalk3.red("Analyze failed (DRZL_CLI_ANALYZE):"),
564
+ msg,
565
+ "\nTip: run with --json for structured output."
566
+ );
567
+ process.exit(1);
568
+ }
569
+ });
570
+ 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) => {
571
+ try {
572
+ let target = schema;
573
+ if (!target) {
574
+ const cfg = await loadConfig(opts.config);
575
+ target = cfg?.schema;
576
+ }
577
+ if (!target) {
578
+ const msg = "No schema given. Pass a path, or run from a directory with a drzl.config.";
579
+ if (opts.json)
580
+ console.log(JSON.stringify({ event: "error", code: "DRZL_CLI_DOCTOR", message: msg }));
581
+ else console.error(chalk3.red("Doctor failed (DRZL_CLI_DOCTOR):"), msg);
582
+ process.exit(1);
583
+ return;
584
+ }
585
+ const analyzer = new SchemaAnalyzer(target);
586
+ const analysis = await analyzer.analyze({
587
+ includeRelations: true,
588
+ validateConstraints: true
589
+ });
590
+ const report = buildDoctorReport(analysis, target);
591
+ if (opts.json) console.log(JSON.stringify(report, null, 2));
592
+ else console.log(renderDoctorReport(report));
593
+ if (report.findings.some((f) => f.level === "error")) {
594
+ process.exit(1);
595
+ return;
596
+ }
597
+ process.exit(opts.strict && report.findings.length ? 2 : 0);
598
+ } catch (e) {
599
+ const msg = e?.message ?? String(e);
600
+ if (opts.json)
601
+ console.log(JSON.stringify({ event: "error", code: "DRZL_CLI_DOCTOR", message: msg }));
602
+ else
603
+ console.error(
604
+ chalk3.red("Doctor failed (DRZL_CLI_DOCTOR):"),
306
605
  msg,
307
606
  "\nTip: run with --json for structured output."
308
607
  );
@@ -317,7 +616,7 @@ program.command("generate").description("Run configured generators (drzl.config.
317
616
  const cfg = await loadConfig(opts.config);
318
617
  if (!cfg) {
319
618
  console.error(
320
- chalk2.red("No config found (DRZL_CFG_001). Create drzl.config.ts or pass --config.")
619
+ chalk3.red("No config found (DRZL_CFG_001). Create drzl.config.ts or pass --config.")
321
620
  );
322
621
  process.exit(2);
323
622
  return;
@@ -362,8 +661,8 @@ program.command("generate").description("Run configured generators (drzl.config.
362
661
  onProgress: ({ index }) => progress.update(index)
363
662
  });
364
663
  progress.stop();
365
- ora().succeed(chalk2.green(`Generated (${g.kind}): ${files.length} files`));
366
- files.forEach((f) => console.log(" -", chalk2.cyan(f)));
664
+ ora().succeed(chalk3.green(`Generated (${g.kind}): ${files.length} files`));
665
+ files.forEach((f) => console.log(" -", chalk3.cyan(f)));
367
666
  } else if (g.kind === "trpc") {
368
667
  try {
369
668
  const { TRPCGenerator } = await loadGenerator(
@@ -376,8 +675,8 @@ program.command("generate").description("Run configured generators (drzl.config.
376
675
  onProgress: ({ index }) => progress.update(index)
377
676
  });
378
677
  progress.stop();
379
- ora().succeed(chalk2.green(`Generated (trpc): ${files.length} files`));
380
- files.forEach((f) => console.log(" -", chalk2.cyan(f)));
678
+ ora().succeed(chalk3.green(`Generated (trpc): ${files.length} files`));
679
+ files.forEach((f) => console.log(" -", chalk3.cyan(f)));
381
680
  } catch (e) {
382
681
  progress.stop();
383
682
  reportGeneratorFailure(g.kind, e);
@@ -406,8 +705,8 @@ program.command("generate").description("Run configured generators (drzl.config.
406
705
  databaseInjection: g.databaseInjection
407
706
  });
408
707
  progress.stop();
409
- ora().succeed(chalk2.green(`Generated (service): ${files.length} files`));
410
- files.forEach((f) => console.log(" -", chalk2.cyan(f)));
708
+ ora().succeed(chalk3.green(`Generated (service): ${files.length} files`));
709
+ files.forEach((f) => console.log(" -", chalk3.cyan(f)));
411
710
  } catch (e) {
412
711
  progress.stop();
413
712
  reportGeneratorFailure(g.kind, e);
@@ -425,8 +724,8 @@ program.command("generate").description("Run configured generators (drzl.config.
425
724
  validationOptions(g, cfg, target, { schemaTypes: true })
426
725
  );
427
726
  progress.stop();
428
- ora().succeed(chalk2.green(`Generated (zod): ${files.length} files`));
429
- files.forEach((f) => console.log(" -", chalk2.cyan(f)));
727
+ ora().succeed(chalk3.green(`Generated (zod): ${files.length} files`));
728
+ files.forEach((f) => console.log(" -", chalk3.cyan(f)));
430
729
  } catch (e) {
431
730
  progress.stop();
432
731
  reportGeneratorFailure(g.kind, e);
@@ -444,8 +743,8 @@ program.command("generate").description("Run configured generators (drzl.config.
444
743
  validationOptions(g, cfg, target, { schemaTypes: true })
445
744
  );
446
745
  progress.stop();
447
- ora().succeed(chalk2.green(`Generated (valibot): ${files.length} files`));
448
- files.forEach((f) => console.log(" -", chalk2.cyan(f)));
746
+ ora().succeed(chalk3.green(`Generated (valibot): ${files.length} files`));
747
+ files.forEach((f) => console.log(" -", chalk3.cyan(f)));
449
748
  } catch (e) {
450
749
  progress.stop();
451
750
  reportGeneratorFailure(g.kind, e);
@@ -463,8 +762,8 @@ program.command("generate").description("Run configured generators (drzl.config.
463
762
  validationOptions(g, cfg, target, { schemaTypes: false })
464
763
  );
465
764
  progress.stop();
466
- ora().succeed(chalk2.green(`Generated (arktype): ${files.length} files`));
467
- files.forEach((f) => console.log(" -", chalk2.cyan(f)));
765
+ ora().succeed(chalk3.green(`Generated (arktype): ${files.length} files`));
766
+ files.forEach((f) => console.log(" -", chalk3.cyan(f)));
468
767
  } catch (e) {
469
768
  progress.stop();
470
769
  reportGeneratorFailure(g.kind, e);
@@ -480,8 +779,8 @@ program.command("generate").description("Run configured generators (drzl.config.
480
779
  const target = g.path ?? "src/validators/json-schema";
481
780
  const files = await gen.generate(jsonSchemaOptions(g, cfg, target));
482
781
  progress.stop();
483
- ora().succeed(chalk2.green(`Generated (json-schema): ${files.length} files`));
484
- files.forEach((f) => console.log(" -", chalk2.cyan(f)));
782
+ ora().succeed(chalk3.green(`Generated (json-schema): ${files.length} files`));
783
+ files.forEach((f) => console.log(" -", chalk3.cyan(f)));
485
784
  } catch (e) {
486
785
  progress.stop();
487
786
  reportGeneratorFailure(g.kind, e);
@@ -499,8 +798,8 @@ program.command("generate").description("Run configured generators (drzl.config.
499
798
  validationOptions(g, cfg, target, { schemaTypes: true })
500
799
  );
501
800
  progress.stop();
502
- ora().succeed(chalk2.green(`Generated (typebox): ${files.length} files`));
503
- files.forEach((f) => console.log(" -", chalk2.cyan(f)));
801
+ ora().succeed(chalk3.green(`Generated (typebox): ${files.length} files`));
802
+ files.forEach((f) => console.log(" -", chalk3.cyan(f)));
504
803
  } catch (e) {
505
804
  progress.stop();
506
805
  reportGeneratorFailure(g.kind, e);
@@ -513,22 +812,22 @@ program.command("generate").description("Run configured generators (drzl.config.
513
812
  const drift = diffSnapshots(driftBefore, after);
514
813
  await restoreSnapshot(driftBefore, after);
515
814
  if (drift.length) {
516
- console.error(chalk2.red(`
815
+ console.error(chalk3.red(`
517
816
  Generated output is out of date (${drift.length} file(s)):`));
518
817
  for (const d of drift) {
519
818
  const mark = d.status === "added" ? "+" : d.status === "removed" ? "-" : "~";
520
819
  console.error(
521
- ` ${mark} ${chalk2.yellow(d.status.padEnd(8))} ${path4.relative(process.cwd(), d.file)}`
820
+ ` ${mark} ${chalk3.yellow(d.status.padEnd(8))} ${path4.relative(process.cwd(), d.file)}`
522
821
  );
523
822
  }
524
823
  console.error(
525
- chalk2.dim(
824
+ chalk3.dim(
526
825
  "\nRun `drzl generate` and commit the result. Nothing was written by this check."
527
826
  )
528
827
  );
529
828
  process.exit(1);
530
829
  }
531
- console.log(chalk2.green("Generated output is up to date."));
830
+ console.log(chalk3.green("Generated output is up to date."));
532
831
  return;
533
832
  }
534
833
  if (cfg.generators.length) {
@@ -536,7 +835,7 @@ Generated output is out of date (${drift.length} file(s)):`));
536
835
  }
537
836
  } catch (e) {
538
837
  console.error(
539
- chalk2.red("Generate failed (DRZL_GEN_001):"),
838
+ chalk3.red("Generate failed (DRZL_GEN_001):"),
540
839
  e?.message ?? e,
541
840
  "\nTip: check your drzl.config.ts and template path."
542
841
  );
@@ -556,10 +855,10 @@ program.command("generate:orpc").argument("<schema>", "path to drizzle schema (T
556
855
  template: opts.template,
557
856
  includeRelations: !!opts.includeRelations
558
857
  });
559
- console.log(chalk2.green(`Generated:`), files.map((f) => chalk2.cyan(f)).join(", "));
858
+ console.log(chalk3.green(`Generated:`), files.map((f) => chalk3.cyan(f)).join(", "));
560
859
  maybeShowSponsorMessage({ reason: "generate:orpc" });
561
860
  } catch (e) {
562
- console.error(chalk2.red("Generate orpc failed:"), e?.message ?? e);
861
+ console.error(chalk3.red("Generate orpc failed:"), e?.message ?? e);
563
862
  process.exit(1);
564
863
  }
565
864
  });
@@ -583,7 +882,7 @@ program.command("generate:trpc").argument("<schema>", "path to drizzle schema (T
583
882
  // cannot become the branch that forgets it.
584
883
  servicesDir: opts.servicesDir
585
884
  });
586
- console.log(chalk2.green(`Generated:`), files.map((f) => chalk2.cyan(f)).join(", "));
885
+ console.log(chalk3.green(`Generated:`), files.map((f) => chalk3.cyan(f)).join(", "));
587
886
  maybeShowSponsorMessage({ reason: "generate:trpc" });
588
887
  } catch (e) {
589
888
  reportGeneratorFailure("trpc", e);
@@ -593,7 +892,7 @@ program.command("generate:trpc").argument("<schema>", "path to drizzle schema (T
593
892
  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) => {
594
893
  let cfg = await loadConfig(opts.config);
595
894
  if (!cfg) {
596
- console.error(chalk2.red("No config found. Create drzl.config.ts or pass --config."));
895
+ console.error(chalk3.red("No config found. Create drzl.config.ts or pass --config."));
597
896
  process.exit(2);
598
897
  return;
599
898
  }
@@ -685,7 +984,7 @@ program.command("watch").description("Watch schema and regenerate on changes").o
685
984
  })
686
985
  );
687
986
  } else {
688
- console.log(chalk2.green("Analyze complete."));
987
+ console.log(chalk3.green("Analyze complete."));
689
988
  }
690
989
  return;
691
990
  }
@@ -715,8 +1014,8 @@ program.command("watch").description("Watch schema and regenerate on changes").o
715
1014
  servicesDir
716
1015
  });
717
1016
  opts.json ? console.log(JSON.stringify({ event: "generate_complete", kind: g.kind, files })) : console.log(
718
- chalk2.green(`Generated (${g.kind}):`),
719
- files.map((f) => chalk2.cyan(f)).join(", ")
1017
+ chalk3.green(`Generated (${g.kind}):`),
1018
+ files.map((f) => chalk3.cyan(f)).join(", ")
720
1019
  );
721
1020
  newFiles.push(...files);
722
1021
  } else if (g.kind === "trpc") {
@@ -728,8 +1027,8 @@ program.command("watch").description("Watch schema and regenerate on changes").o
728
1027
  const gen = new TRPCGenerator(analysis);
729
1028
  const { files } = await gen.generate(trpcOptions(g, cfg, servicesDir));
730
1029
  opts.json ? console.log(JSON.stringify({ event: "generate_complete", kind: g.kind, files })) : console.log(
731
- chalk2.green(`Generated (trpc): ${files.length} files`),
732
- files.map((f) => chalk2.cyan(f)).join(", ")
1030
+ chalk3.green(`Generated (trpc): ${files.length} files`),
1031
+ files.map((f) => chalk3.cyan(f)).join(", ")
733
1032
  );
734
1033
  newFiles.push(...files);
735
1034
  } catch (e) {
@@ -755,8 +1054,8 @@ program.command("watch").description("Watch schema and regenerate on changes").o
755
1054
  databaseInjection: g.databaseInjection
756
1055
  });
757
1056
  opts.json ? console.log(JSON.stringify({ event: "generate_complete", kind: g.kind, files })) : console.log(
758
- chalk2.green(`Generated (service): ${files.length} files`),
759
- files.map((f) => chalk2.cyan(f)).join(", ")
1057
+ chalk3.green(`Generated (service): ${files.length} files`),
1058
+ files.map((f) => chalk3.cyan(f)).join(", ")
760
1059
  );
761
1060
  newFiles.push(...files);
762
1061
  } catch (e) {
@@ -775,8 +1074,8 @@ program.command("watch").description("Watch schema and regenerate on changes").o
775
1074
  validationOptions(g, cfg, target, { schemaTypes: true })
776
1075
  );
777
1076
  opts.json ? console.log(JSON.stringify({ event: "generate_complete", kind: g.kind, files })) : console.log(
778
- chalk2.green(`Generated (zod): ${files.length} files`),
779
- files.map((f) => chalk2.cyan(f)).join(", ")
1077
+ chalk3.green(`Generated (zod): ${files.length} files`),
1078
+ files.map((f) => chalk3.cyan(f)).join(", ")
780
1079
  );
781
1080
  newFiles.push(...files);
782
1081
  } catch (e) {
@@ -795,8 +1094,8 @@ program.command("watch").description("Watch schema and regenerate on changes").o
795
1094
  validationOptions(g, cfg, target, { schemaTypes: true })
796
1095
  );
797
1096
  opts.json ? console.log(JSON.stringify({ event: "generate_complete", kind: g.kind, files })) : console.log(
798
- chalk2.green(`Generated (valibot): ${files.length} files`),
799
- files.map((f) => chalk2.cyan(f)).join(", ")
1097
+ chalk3.green(`Generated (valibot): ${files.length} files`),
1098
+ files.map((f) => chalk3.cyan(f)).join(", ")
800
1099
  );
801
1100
  newFiles.push(...files);
802
1101
  } catch (e) {
@@ -815,8 +1114,8 @@ program.command("watch").description("Watch schema and regenerate on changes").o
815
1114
  validationOptions(g, cfg, target, { schemaTypes: false })
816
1115
  );
817
1116
  opts.json ? console.log(JSON.stringify({ event: "generate_complete", kind: g.kind, files })) : console.log(
818
- chalk2.green(`Generated (arktype): ${files.length} files`),
819
- files.map((f) => chalk2.cyan(f)).join(", ")
1117
+ chalk3.green(`Generated (arktype): ${files.length} files`),
1118
+ files.map((f) => chalk3.cyan(f)).join(", ")
820
1119
  );
821
1120
  newFiles.push(...files);
822
1121
  } catch (e) {
@@ -835,8 +1134,8 @@ program.command("watch").description("Watch schema and regenerate on changes").o
835
1134
  validationOptions(g, cfg, target, { schemaTypes: true })
836
1135
  );
837
1136
  opts.json ? console.log(JSON.stringify({ event: "generate_complete", kind: g.kind, files })) : console.log(
838
- chalk2.green(`Generated (typebox): ${files.length} files`),
839
- files.map((f) => chalk2.cyan(f)).join(", ")
1137
+ chalk3.green(`Generated (typebox): ${files.length} files`),
1138
+ files.map((f) => chalk3.cyan(f)).join(", ")
840
1139
  );
841
1140
  newFiles.push(...files);
842
1141
  } catch (e) {
@@ -853,8 +1152,8 @@ program.command("watch").description("Watch schema and regenerate on changes").o
853
1152
  const target = g.path ?? "src/validators/json-schema";
854
1153
  const files = await gen.generate(jsonSchemaOptions(g, cfg, target));
855
1154
  opts.json ? console.log(JSON.stringify({ event: "generate_complete", kind: g.kind, files })) : console.log(
856
- chalk2.green(`Generated (json-schema): ${files.length} files`),
857
- files.map((f) => chalk2.cyan(f)).join(", ")
1155
+ chalk3.green(`Generated (json-schema): ${files.length} files`),
1156
+ files.map((f) => chalk3.cyan(f)).join(", ")
858
1157
  );
859
1158
  newFiles.push(...files);
860
1159
  } catch (e) {
@@ -866,8 +1165,8 @@ program.command("watch").description("Watch schema and regenerate on changes").o
866
1165
  const added = newFiles.filter((f) => !lastFiles.includes(f));
867
1166
  const removed = lastFiles.filter((f) => !newFiles.includes(f));
868
1167
  opts.json ? console.log(JSON.stringify({ event: "diff", added, removed })) : (() => {
869
- if (added.length) console.log(chalk2.blue(`Added: ${added.join(", ")}`));
870
- if (removed.length) console.log(chalk2.yellow(`Removed: ${removed.join(", ")}`));
1168
+ if (added.length) console.log(chalk3.blue(`Added: ${added.join(", ")}`));
1169
+ if (removed.length) console.log(chalk3.yellow(`Removed: ${removed.join(", ")}`));
871
1170
  })();
872
1171
  if (newFiles.length && !opts.json) {
873
1172
  const reason = opts.pipeline && opts.pipeline !== "all" ? `watch:${opts.pipeline}` : "watch";
@@ -875,7 +1174,7 @@ program.command("watch").description("Watch schema and regenerate on changes").o
875
1174
  }
876
1175
  lastFiles = newFiles;
877
1176
  } catch (e) {
878
- opts.json ? console.log(JSON.stringify({ event: "error", message: String(e?.message ?? e) })) : console.error(chalk2.red("Watch pipeline failed:"), e?.message ?? e);
1177
+ opts.json ? console.log(JSON.stringify({ event: "error", message: String(e?.message ?? e) })) : console.error(chalk3.red("Watch pipeline failed:"), e?.message ?? e);
879
1178
  }
880
1179
  };
881
1180
  const debounced = Number(opts.debounce) || 200;
@@ -900,12 +1199,12 @@ program.command("watch").description("Watch schema and regenerate on changes").o
900
1199
  );
901
1200
  } else {
902
1201
  console.log(
903
- chalk2.gray(
1202
+ chalk3.gray(
904
1203
  "Watching:\n " + Array.from(currentTargets).map((p) => path4.relative(process.cwd(), p)).join("\n ")
905
1204
  )
906
1205
  );
907
1206
  }
908
- watcher.on("add", (p) => trigger(p)).on("change", (p) => trigger(p)).on("unlink", (p) => trigger(p)).on("error", (err) => console.error(chalk2.red("Watcher error:"), err));
1207
+ watcher.on("add", (p) => trigger(p)).on("change", (p) => trigger(p)).on("unlink", (p) => trigger(p)).on("error", (err) => console.error(chalk3.red("Watcher error:"), err));
909
1208
  await run();
910
1209
  });
911
1210
  program.command("init").description("Scaffold a drzl.config.ts").option("-y, --yes", "accept defaults").action(async (_opts) => {
@@ -925,9 +1224,9 @@ program.command("init").description("Scaffold a drzl.config.ts").option("-y, --y
925
1224
  `;
926
1225
  try {
927
1226
  await fs2.writeFile(target, template, { flag: "wx" });
928
- console.log(chalk2.green(`Created ${target}`));
1227
+ console.log(chalk3.green(`Created ${target}`));
929
1228
  } catch (e) {
930
- console.error(chalk2.red("Init failed:"), e?.message ?? e);
1229
+ console.error(chalk3.red("Init failed:"), e?.message ?? e);
931
1230
  process.exit(1);
932
1231
  }
933
1232
  });
@@ -935,13 +1234,14 @@ function reportWideColumns(issues) {
935
1234
  const wide = issues.filter((i) => i.code === "DRZL_ANL_UNKNOWN_COLUMN");
936
1235
  if (!wide.length) return;
937
1236
  console.warn(
938
- chalk2.yellow(`
1237
+ chalk3.yellow(`
939
1238
  ${wide.length} column${wide.length === 1 ? "" : "s"} could not be typed:`)
940
1239
  );
941
- for (const i of wide.slice(0, 10)) console.warn(chalk2.gray(` - ${i.message}`));
942
- if (wide.length > 10) console.warn(chalk2.gray(` ... and ${wide.length - 10} more`));
1240
+ for (const i of wide.slice(0, 10)) console.warn(chalk3.gray(` - ${i.message}`));
1241
+ if (wide.length > 10) console.warn(chalk3.gray(` ... and ${wide.length - 10} more`));
943
1242
  const hints = [...new Set(wide.map((i) => i.hint).filter(Boolean))];
944
- for (const h of hints) console.warn(chalk2.gray(` ${h}`));
1243
+ for (const h of hints) console.warn(chalk3.gray(` ${h}`));
1244
+ console.warn(chalk3.gray(" Run `drzl doctor` for the full report."));
945
1245
  }
946
1246
  program.parseAsync(process.argv);
947
1247
  //# sourceMappingURL=cli.js.map