@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.cjs +393 -93
- package/dist/cli.cjs.map +1 -1
- package/dist/cli.js +365 -65
- package/dist/cli.js.map +1 -1
- package/package.json +6 -6
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,
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
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
|
|
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
|
-
|
|
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,
|
|
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 &&
|
|
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,
|
|
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,
|
|
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,
|
|
768
|
-
update: build2((0,
|
|
769
|
-
select: build2((0,
|
|
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,
|
|
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,
|
|
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
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
1133
|
+
(0, import_validation_core4.resolveAffix)(opts),
|
|
1134
1134
|
opts?.target ?? "draft-2020-12",
|
|
1135
1135
|
!!opts?.applyDefaults
|
|
1136
1136
|
);
|
|
@@ -1143,7 +1143,7 @@ var init_dist2 = __esm({
|
|
|
1143
1143
|
// src/cli.ts
|
|
1144
1144
|
var import_analyzer = require("@drzl/analyzer");
|
|
1145
1145
|
var import_generator_orpc = require("@drzl/generator-orpc");
|
|
1146
|
-
var
|
|
1146
|
+
var import_chalk3 = __toESM(require("chalk"), 1);
|
|
1147
1147
|
var import_chokidar = __toESM(require("chokidar"), 1);
|
|
1148
1148
|
var import_cli_progress = __toESM(require("cli-progress"), 1);
|
|
1149
1149
|
var import_commander = require("commander");
|
|
@@ -1635,6 +1635,264 @@ function trpcOptions(g, cfg, servicesDir) {
|
|
|
1635
1635
|
};
|
|
1636
1636
|
}
|
|
1637
1637
|
|
|
1638
|
+
// src/doctor.ts
|
|
1639
|
+
var import_validation_core2 = require("@drzl/validation-core");
|
|
1640
|
+
var import_chalk = __toESM(require("chalk"), 1);
|
|
1641
|
+
var HANDLED_CODES = /* @__PURE__ */ new Set(["DRZL_ANL_UNKNOWN_COLUMN"]);
|
|
1642
|
+
function splitPath(path6) {
|
|
1643
|
+
if (!path6) return {};
|
|
1644
|
+
const dot = path6.lastIndexOf(".");
|
|
1645
|
+
if (dot <= 0) return { table: path6 };
|
|
1646
|
+
return { table: path6.slice(0, dot), column: path6.slice(dot + 1) };
|
|
1647
|
+
}
|
|
1648
|
+
function namedColumns(parsed) {
|
|
1649
|
+
const out = [];
|
|
1650
|
+
for (const c of parsed.checks) out.push({ column: c.column, scalar: true });
|
|
1651
|
+
for (const s of parsed.sets ?? []) out.push({ column: s.column, scalar: true });
|
|
1652
|
+
for (const l of parsed.lengths ?? []) out.push({ column: l.column, scalar: false });
|
|
1653
|
+
for (const c of parsed.cardinalities ?? []) out.push({ column: c.column, scalar: false });
|
|
1654
|
+
for (const r of parsed.rows ?? []) {
|
|
1655
|
+
out.push({ column: r.left, scalar: false });
|
|
1656
|
+
out.push({ column: r.right, scalar: false });
|
|
1657
|
+
}
|
|
1658
|
+
return out;
|
|
1659
|
+
}
|
|
1660
|
+
function describeShape(c) {
|
|
1661
|
+
if (c.arrayDimensions) return "an array";
|
|
1662
|
+
switch (c.shape?.kind) {
|
|
1663
|
+
case "json":
|
|
1664
|
+
return "a JSON";
|
|
1665
|
+
case "buffer":
|
|
1666
|
+
return "a binary";
|
|
1667
|
+
case "tuple":
|
|
1668
|
+
case "numberObject":
|
|
1669
|
+
return "a structured";
|
|
1670
|
+
case "numberVector":
|
|
1671
|
+
return "a vector";
|
|
1672
|
+
case "bitstring":
|
|
1673
|
+
return "a bit-string";
|
|
1674
|
+
case "byteString":
|
|
1675
|
+
return "a byte-string";
|
|
1676
|
+
case "custom":
|
|
1677
|
+
return "a customType";
|
|
1678
|
+
default:
|
|
1679
|
+
return "a structured";
|
|
1680
|
+
}
|
|
1681
|
+
}
|
|
1682
|
+
function checkFindings(table) {
|
|
1683
|
+
const out = [];
|
|
1684
|
+
const byName = new Map(table.columns.map((c) => [c.name, c]));
|
|
1685
|
+
for (const k of table.checks ?? []) {
|
|
1686
|
+
const label = k.name ? `"${k.name}"` : "an unnamed constraint";
|
|
1687
|
+
const raw = k.expression ?? "";
|
|
1688
|
+
const expr = raw.trim() ? raw : "(empty)";
|
|
1689
|
+
const parsed = (0, import_validation_core2.parseCheck)(raw, k.name);
|
|
1690
|
+
if (!parsed.ok) {
|
|
1691
|
+
out.push({
|
|
1692
|
+
kind: "check-declined",
|
|
1693
|
+
level: "warn",
|
|
1694
|
+
table: table.tsName,
|
|
1695
|
+
constraint: k.name,
|
|
1696
|
+
message: `CHECK ${label} on "${table.tsName}" is not translated: ${parsed.reason}. Expression: ${expr}`,
|
|
1697
|
+
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."
|
|
1698
|
+
});
|
|
1699
|
+
continue;
|
|
1700
|
+
}
|
|
1701
|
+
const seen = /* @__PURE__ */ new Set();
|
|
1702
|
+
for (const { column, scalar } of namedColumns(parsed)) {
|
|
1703
|
+
if (seen.has(column)) continue;
|
|
1704
|
+
seen.add(column);
|
|
1705
|
+
const col = byName.get(column);
|
|
1706
|
+
if (!col) {
|
|
1707
|
+
out.push({
|
|
1708
|
+
kind: "check-unknown-column",
|
|
1709
|
+
level: "warn",
|
|
1710
|
+
table: table.tsName,
|
|
1711
|
+
column,
|
|
1712
|
+
constraint: k.name,
|
|
1713
|
+
message: `CHECK ${label} on "${table.tsName}" names "${column}", which is not a column of that table, so nothing enforces it. Expression: ${expr}`,
|
|
1714
|
+
hint: "A constraint is attached to the field it names. Check the spelling, or move a constraint spanning two tables out of the schema."
|
|
1715
|
+
});
|
|
1716
|
+
continue;
|
|
1717
|
+
}
|
|
1718
|
+
if (scalar && (col.arrayDimensions || col.shape)) {
|
|
1719
|
+
out.push({
|
|
1720
|
+
kind: "check-not-scalar",
|
|
1721
|
+
level: "warn",
|
|
1722
|
+
table: table.tsName,
|
|
1723
|
+
column,
|
|
1724
|
+
constraint: k.name,
|
|
1725
|
+
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}`,
|
|
1726
|
+
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."
|
|
1727
|
+
});
|
|
1728
|
+
}
|
|
1729
|
+
}
|
|
1730
|
+
}
|
|
1731
|
+
return out;
|
|
1732
|
+
}
|
|
1733
|
+
function primaryKeyFindings(table) {
|
|
1734
|
+
if (table.readOnly) return [];
|
|
1735
|
+
const pk = table.primaryKey?.columns ?? [];
|
|
1736
|
+
if (!pk.length) {
|
|
1737
|
+
const hasId = table.columns.some((c) => c.name === "id");
|
|
1738
|
+
return [
|
|
1739
|
+
{
|
|
1740
|
+
kind: "no-primary-key",
|
|
1741
|
+
level: "warn",
|
|
1742
|
+
table: table.tsName,
|
|
1743
|
+
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.`,
|
|
1744
|
+
hint: "Declare a primary key, or leave this table out with the config table filter."
|
|
1745
|
+
}
|
|
1746
|
+
];
|
|
1747
|
+
}
|
|
1748
|
+
if (pk.length > 1) {
|
|
1749
|
+
return [
|
|
1750
|
+
{
|
|
1751
|
+
kind: "partial-primary-key",
|
|
1752
|
+
level: "warn",
|
|
1753
|
+
table: table.tsName,
|
|
1754
|
+
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.`,
|
|
1755
|
+
hint: "Treat the generated service as a starting point for this table and widen the key by hand."
|
|
1756
|
+
}
|
|
1757
|
+
];
|
|
1758
|
+
}
|
|
1759
|
+
return [];
|
|
1760
|
+
}
|
|
1761
|
+
function buildDoctorReport(analysis, schemaPath) {
|
|
1762
|
+
const findings = [];
|
|
1763
|
+
const errors = analysis.issues.filter((i) => i.level === "error");
|
|
1764
|
+
for (const i of errors) {
|
|
1765
|
+
findings.push({
|
|
1766
|
+
kind: "analyzer",
|
|
1767
|
+
level: "error",
|
|
1768
|
+
...splitPath(i.path),
|
|
1769
|
+
message: i.message,
|
|
1770
|
+
hint: i.hint
|
|
1771
|
+
});
|
|
1772
|
+
}
|
|
1773
|
+
for (const i of analysis.issues) {
|
|
1774
|
+
if (i.code !== "DRZL_ANL_UNKNOWN_COLUMN") continue;
|
|
1775
|
+
findings.push({
|
|
1776
|
+
kind: "unknown-column",
|
|
1777
|
+
level: "warn",
|
|
1778
|
+
...splitPath(i.path),
|
|
1779
|
+
message: i.message,
|
|
1780
|
+
hint: i.hint
|
|
1781
|
+
});
|
|
1782
|
+
}
|
|
1783
|
+
for (const t of analysis.tables) findings.push(...checkFindings(t));
|
|
1784
|
+
for (const t of analysis.tables) findings.push(...primaryKeyFindings(t));
|
|
1785
|
+
for (const i of analysis.issues) {
|
|
1786
|
+
if (i.level === "error" || HANDLED_CODES.has(i.code)) continue;
|
|
1787
|
+
findings.push({
|
|
1788
|
+
kind: "analyzer",
|
|
1789
|
+
level: "warn",
|
|
1790
|
+
...splitPath(i.path),
|
|
1791
|
+
message: i.message,
|
|
1792
|
+
hint: i.hint
|
|
1793
|
+
});
|
|
1794
|
+
}
|
|
1795
|
+
const columns = analysis.tables.reduce((n, t) => n + t.columns.length, 0);
|
|
1796
|
+
const checks = analysis.tables.reduce((n, t) => n + (t.checks?.length ?? 0), 0);
|
|
1797
|
+
return {
|
|
1798
|
+
schema: schemaPath,
|
|
1799
|
+
dialect: analysis.dialect,
|
|
1800
|
+
ok: findings.length === 0,
|
|
1801
|
+
counts: { tables: analysis.tables.length, columns, checks, findings: findings.length },
|
|
1802
|
+
findings
|
|
1803
|
+
};
|
|
1804
|
+
}
|
|
1805
|
+
var SECTIONS = [
|
|
1806
|
+
{
|
|
1807
|
+
kinds: ["unknown-column"],
|
|
1808
|
+
title: "Columns DRZL cannot type",
|
|
1809
|
+
why: "These get a validator that accepts any value."
|
|
1810
|
+
},
|
|
1811
|
+
{
|
|
1812
|
+
kinds: ["check-declined", "check-unknown-column", "check-not-scalar"],
|
|
1813
|
+
title: "CHECK constraints DRZL does not enforce",
|
|
1814
|
+
why: "Your database still enforces these. Nothing DRZL generates does."
|
|
1815
|
+
},
|
|
1816
|
+
{
|
|
1817
|
+
kinds: ["no-primary-key", "partial-primary-key"],
|
|
1818
|
+
title: "Primary keys the generators cannot use",
|
|
1819
|
+
why: "The generated getById, update and delete are keyed on one column."
|
|
1820
|
+
},
|
|
1821
|
+
{
|
|
1822
|
+
kinds: ["analyzer"],
|
|
1823
|
+
title: "Other findings",
|
|
1824
|
+
why: "Reported by the analyzer while reading the schema."
|
|
1825
|
+
}
|
|
1826
|
+
];
|
|
1827
|
+
function wrap(text, indent, first = indent, width = 96) {
|
|
1828
|
+
const lines = [];
|
|
1829
|
+
let line = "";
|
|
1830
|
+
for (const word of text.split(/\s+/)) {
|
|
1831
|
+
if (line && `${line} ${word}`.length + indent.length > width) {
|
|
1832
|
+
lines.push(line);
|
|
1833
|
+
line = word;
|
|
1834
|
+
} else {
|
|
1835
|
+
line = line ? `${line} ${word}` : word;
|
|
1836
|
+
}
|
|
1837
|
+
}
|
|
1838
|
+
if (line) lines.push(line);
|
|
1839
|
+
return lines.map((l, i) => (i === 0 ? first : indent) + l).join("\n");
|
|
1840
|
+
}
|
|
1841
|
+
function renderDoctorReport(report) {
|
|
1842
|
+
const out = [];
|
|
1843
|
+
const plural = (n, one) => `${n} ${one}${n === 1 ? "" : "s"}`;
|
|
1844
|
+
out.push(import_chalk.default.bold(`DRZL doctor ${report.schema}`));
|
|
1845
|
+
out.push(
|
|
1846
|
+
import_chalk.default.dim(
|
|
1847
|
+
`${report.dialect}, ${plural(report.counts.tables, "table")}, ${plural(report.counts.columns, "column")}, ${plural(report.counts.checks, "CHECK constraint")}`
|
|
1848
|
+
)
|
|
1849
|
+
);
|
|
1850
|
+
out.push("");
|
|
1851
|
+
if (report.ok) {
|
|
1852
|
+
out.push(import_chalk.default.green("Nothing to report."));
|
|
1853
|
+
out.push(import_chalk.default.dim(" Every column has a type DRZL can describe."));
|
|
1854
|
+
out.push(import_chalk.default.dim(" Every CHECK constraint is translated into the generated validators."));
|
|
1855
|
+
out.push(import_chalk.default.dim(" Every table has a primary key the generators can use."));
|
|
1856
|
+
return out.join("\n");
|
|
1857
|
+
}
|
|
1858
|
+
const fatal = report.findings.filter((f) => f.level === "error");
|
|
1859
|
+
if (fatal.length) {
|
|
1860
|
+
out.push(import_chalk.default.red("DRZL could not read this schema"));
|
|
1861
|
+
out.push(import_chalk.default.dim(" Nothing else could be checked."));
|
|
1862
|
+
out.push("");
|
|
1863
|
+
for (const f of fatal) {
|
|
1864
|
+
out.push(wrap(f.message, " ", ` ${import_chalk.default.dim("-")} `));
|
|
1865
|
+
if (f.hint) out.push(import_chalk.default.dim(wrap(f.hint, " ")));
|
|
1866
|
+
}
|
|
1867
|
+
out.push("");
|
|
1868
|
+
}
|
|
1869
|
+
for (const section of SECTIONS) {
|
|
1870
|
+
const mine = report.findings.filter(
|
|
1871
|
+
(f) => f.level !== "error" && section.kinds.includes(f.kind)
|
|
1872
|
+
);
|
|
1873
|
+
if (!mine.length) continue;
|
|
1874
|
+
out.push(import_chalk.default.yellow(`${section.title} (${mine.length})`));
|
|
1875
|
+
out.push(import_chalk.default.dim(` ${section.why}`));
|
|
1876
|
+
out.push("");
|
|
1877
|
+
const groups = /* @__PURE__ */ new Map();
|
|
1878
|
+
for (const f of mine) {
|
|
1879
|
+
const key = f.hint ?? "";
|
|
1880
|
+
groups.set(key, [...groups.get(key) ?? [], f]);
|
|
1881
|
+
}
|
|
1882
|
+
for (const [hint, items] of groups) {
|
|
1883
|
+
for (const f of items) out.push(wrap(f.message, " ", ` ${import_chalk.default.dim("-")} `));
|
|
1884
|
+
if (hint) out.push(import_chalk.default.dim(wrap(hint, " ")));
|
|
1885
|
+
out.push("");
|
|
1886
|
+
}
|
|
1887
|
+
}
|
|
1888
|
+
out.push(
|
|
1889
|
+
import_chalk.default.bold(`${plural(report.counts.findings, "finding")} in ${report.schema}.`) + import_chalk.default.dim(
|
|
1890
|
+
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."
|
|
1891
|
+
)
|
|
1892
|
+
);
|
|
1893
|
+
return out.join("\n");
|
|
1894
|
+
}
|
|
1895
|
+
|
|
1638
1896
|
// src/drift.ts
|
|
1639
1897
|
var import_node_fs = require("fs");
|
|
1640
1898
|
var import_node_path = __toESM(require("path"), 1);
|
|
@@ -1711,7 +1969,7 @@ async function loadGenerator(specifier, load) {
|
|
|
1711
1969
|
}
|
|
1712
1970
|
|
|
1713
1971
|
// src/sponsor.ts
|
|
1714
|
-
var
|
|
1972
|
+
var import_chalk2 = __toESM(require("chalk"), 1);
|
|
1715
1973
|
var import_node_fs2 = require("fs");
|
|
1716
1974
|
var import_node_path2 = __toESM(require("path"), 1);
|
|
1717
1975
|
var CACHE_DIR = import_node_path2.default.join(process.cwd(), "node_modules", ".cache", "@drzl");
|
|
@@ -1725,9 +1983,9 @@ var tips = [
|
|
|
1725
1983
|
"Need JSON Schema or OpenAPI? The json-schema generator emits both, with no runtime dependency.",
|
|
1726
1984
|
"Use output headers to track generated files and trim noisy diffs."
|
|
1727
1985
|
];
|
|
1728
|
-
var green = (msg) =>
|
|
1729
|
-
var cyan = (msg) =>
|
|
1730
|
-
var gray = (msg) =>
|
|
1986
|
+
var green = (msg) => import_chalk2.default.hex("#6ee7b7")(msg);
|
|
1987
|
+
var cyan = (msg) => import_chalk2.default.cyan(msg);
|
|
1988
|
+
var gray = (msg) => import_chalk2.default.gray(msg);
|
|
1731
1989
|
function maybeShowSponsorMessage({
|
|
1732
1990
|
reason = "generate",
|
|
1733
1991
|
minIntervalMs = DEFAULT_INTERVAL_MS,
|
|
@@ -1816,13 +2074,13 @@ var CLI_VERSION = readCliVersion();
|
|
|
1816
2074
|
function reportGeneratorFailure(kind, e) {
|
|
1817
2075
|
if (e instanceof GeneratorNotInstalledError) {
|
|
1818
2076
|
console.error(
|
|
1819
|
-
|
|
1820
|
-
|
|
2077
|
+
import_chalk3.default.red(`The ${kind} generator is not installed.`),
|
|
2078
|
+
import_chalk3.default.yellow(`
|
|
1821
2079
|
Install with: npm install ${e.specifier}`)
|
|
1822
2080
|
);
|
|
1823
2081
|
return;
|
|
1824
2082
|
}
|
|
1825
|
-
console.error(
|
|
2083
|
+
console.error(import_chalk3.default.red(`The ${kind} generator failed:`), e?.message ?? e);
|
|
1826
2084
|
}
|
|
1827
2085
|
var program = new import_commander.Command();
|
|
1828
2086
|
program.name("drzl").description("DRZL - Drizzle Developer Toolkit").version(CLI_VERSION);
|
|
@@ -1849,9 +2107,9 @@ program.command("analyze").argument("<schema>", "path to drizzle schema (TS)").o
|
|
|
1849
2107
|
} else if (opts.out) {
|
|
1850
2108
|
const fs3 = await import("fs/promises");
|
|
1851
2109
|
await fs3.writeFile(opts.out, json, "utf8");
|
|
1852
|
-
spinner?.succeed(
|
|
2110
|
+
spinner?.succeed(import_chalk3.default.green(`Analysis written to ${opts.out} in ${ms}ms`));
|
|
1853
2111
|
} else {
|
|
1854
|
-
spinner?.succeed(
|
|
2112
|
+
spinner?.succeed(import_chalk3.default.green(`Analyzed in ${ms}ms`));
|
|
1855
2113
|
console.log(json);
|
|
1856
2114
|
}
|
|
1857
2115
|
process.exit(res.issues.some((i) => i.level === "error") ? 2 : 0);
|
|
@@ -1861,7 +2119,48 @@ program.command("analyze").argument("<schema>", "path to drizzle schema (TS)").o
|
|
|
1861
2119
|
console.log(JSON.stringify({ event: "error", code: "DRZL_CLI_ANALYZE", message: msg }));
|
|
1862
2120
|
else
|
|
1863
2121
|
console.error(
|
|
1864
|
-
|
|
2122
|
+
import_chalk3.default.red("Analyze failed (DRZL_CLI_ANALYZE):"),
|
|
2123
|
+
msg,
|
|
2124
|
+
"\nTip: run with --json for structured output."
|
|
2125
|
+
);
|
|
2126
|
+
process.exit(1);
|
|
2127
|
+
}
|
|
2128
|
+
});
|
|
2129
|
+
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) => {
|
|
2130
|
+
try {
|
|
2131
|
+
let target = schema;
|
|
2132
|
+
if (!target) {
|
|
2133
|
+
const cfg = await loadConfig(opts.config);
|
|
2134
|
+
target = cfg?.schema;
|
|
2135
|
+
}
|
|
2136
|
+
if (!target) {
|
|
2137
|
+
const msg = "No schema given. Pass a path, or run from a directory with a drzl.config.";
|
|
2138
|
+
if (opts.json)
|
|
2139
|
+
console.log(JSON.stringify({ event: "error", code: "DRZL_CLI_DOCTOR", message: msg }));
|
|
2140
|
+
else console.error(import_chalk3.default.red("Doctor failed (DRZL_CLI_DOCTOR):"), msg);
|
|
2141
|
+
process.exit(1);
|
|
2142
|
+
return;
|
|
2143
|
+
}
|
|
2144
|
+
const analyzer = new import_analyzer.SchemaAnalyzer(target);
|
|
2145
|
+
const analysis = await analyzer.analyze({
|
|
2146
|
+
includeRelations: true,
|
|
2147
|
+
validateConstraints: true
|
|
2148
|
+
});
|
|
2149
|
+
const report = buildDoctorReport(analysis, target);
|
|
2150
|
+
if (opts.json) console.log(JSON.stringify(report, null, 2));
|
|
2151
|
+
else console.log(renderDoctorReport(report));
|
|
2152
|
+
if (report.findings.some((f) => f.level === "error")) {
|
|
2153
|
+
process.exit(1);
|
|
2154
|
+
return;
|
|
2155
|
+
}
|
|
2156
|
+
process.exit(opts.strict && report.findings.length ? 2 : 0);
|
|
2157
|
+
} catch (e) {
|
|
2158
|
+
const msg = e?.message ?? String(e);
|
|
2159
|
+
if (opts.json)
|
|
2160
|
+
console.log(JSON.stringify({ event: "error", code: "DRZL_CLI_DOCTOR", message: msg }));
|
|
2161
|
+
else
|
|
2162
|
+
console.error(
|
|
2163
|
+
import_chalk3.default.red("Doctor failed (DRZL_CLI_DOCTOR):"),
|
|
1865
2164
|
msg,
|
|
1866
2165
|
"\nTip: run with --json for structured output."
|
|
1867
2166
|
);
|
|
@@ -1876,7 +2175,7 @@ program.command("generate").description("Run configured generators (drzl.config.
|
|
|
1876
2175
|
const cfg = await loadConfig(opts.config);
|
|
1877
2176
|
if (!cfg) {
|
|
1878
2177
|
console.error(
|
|
1879
|
-
|
|
2178
|
+
import_chalk3.default.red("No config found (DRZL_CFG_001). Create drzl.config.ts or pass --config.")
|
|
1880
2179
|
);
|
|
1881
2180
|
process.exit(2);
|
|
1882
2181
|
return;
|
|
@@ -1921,8 +2220,8 @@ program.command("generate").description("Run configured generators (drzl.config.
|
|
|
1921
2220
|
onProgress: ({ index }) => progress.update(index)
|
|
1922
2221
|
});
|
|
1923
2222
|
progress.stop();
|
|
1924
|
-
(0, import_ora.default)().succeed(
|
|
1925
|
-
files.forEach((f) => console.log(" -",
|
|
2223
|
+
(0, import_ora.default)().succeed(import_chalk3.default.green(`Generated (${g.kind}): ${files.length} files`));
|
|
2224
|
+
files.forEach((f) => console.log(" -", import_chalk3.default.cyan(f)));
|
|
1926
2225
|
} else if (g.kind === "trpc") {
|
|
1927
2226
|
try {
|
|
1928
2227
|
const { TRPCGenerator: TRPCGenerator2 } = await loadGenerator(
|
|
@@ -1935,8 +2234,8 @@ program.command("generate").description("Run configured generators (drzl.config.
|
|
|
1935
2234
|
onProgress: ({ index }) => progress.update(index)
|
|
1936
2235
|
});
|
|
1937
2236
|
progress.stop();
|
|
1938
|
-
(0, import_ora.default)().succeed(
|
|
1939
|
-
files.forEach((f) => console.log(" -",
|
|
2237
|
+
(0, import_ora.default)().succeed(import_chalk3.default.green(`Generated (trpc): ${files.length} files`));
|
|
2238
|
+
files.forEach((f) => console.log(" -", import_chalk3.default.cyan(f)));
|
|
1940
2239
|
} catch (e) {
|
|
1941
2240
|
progress.stop();
|
|
1942
2241
|
reportGeneratorFailure(g.kind, e);
|
|
@@ -1965,8 +2264,8 @@ program.command("generate").description("Run configured generators (drzl.config.
|
|
|
1965
2264
|
databaseInjection: g.databaseInjection
|
|
1966
2265
|
});
|
|
1967
2266
|
progress.stop();
|
|
1968
|
-
(0, import_ora.default)().succeed(
|
|
1969
|
-
files.forEach((f) => console.log(" -",
|
|
2267
|
+
(0, import_ora.default)().succeed(import_chalk3.default.green(`Generated (service): ${files.length} files`));
|
|
2268
|
+
files.forEach((f) => console.log(" -", import_chalk3.default.cyan(f)));
|
|
1970
2269
|
} catch (e) {
|
|
1971
2270
|
progress.stop();
|
|
1972
2271
|
reportGeneratorFailure(g.kind, e);
|
|
@@ -1984,8 +2283,8 @@ program.command("generate").description("Run configured generators (drzl.config.
|
|
|
1984
2283
|
validationOptions(g, cfg, target, { schemaTypes: true })
|
|
1985
2284
|
);
|
|
1986
2285
|
progress.stop();
|
|
1987
|
-
(0, import_ora.default)().succeed(
|
|
1988
|
-
files.forEach((f) => console.log(" -",
|
|
2286
|
+
(0, import_ora.default)().succeed(import_chalk3.default.green(`Generated (zod): ${files.length} files`));
|
|
2287
|
+
files.forEach((f) => console.log(" -", import_chalk3.default.cyan(f)));
|
|
1989
2288
|
} catch (e) {
|
|
1990
2289
|
progress.stop();
|
|
1991
2290
|
reportGeneratorFailure(g.kind, e);
|
|
@@ -2003,8 +2302,8 @@ program.command("generate").description("Run configured generators (drzl.config.
|
|
|
2003
2302
|
validationOptions(g, cfg, target, { schemaTypes: true })
|
|
2004
2303
|
);
|
|
2005
2304
|
progress.stop();
|
|
2006
|
-
(0, import_ora.default)().succeed(
|
|
2007
|
-
files.forEach((f) => console.log(" -",
|
|
2305
|
+
(0, import_ora.default)().succeed(import_chalk3.default.green(`Generated (valibot): ${files.length} files`));
|
|
2306
|
+
files.forEach((f) => console.log(" -", import_chalk3.default.cyan(f)));
|
|
2008
2307
|
} catch (e) {
|
|
2009
2308
|
progress.stop();
|
|
2010
2309
|
reportGeneratorFailure(g.kind, e);
|
|
@@ -2022,8 +2321,8 @@ program.command("generate").description("Run configured generators (drzl.config.
|
|
|
2022
2321
|
validationOptions(g, cfg, target, { schemaTypes: false })
|
|
2023
2322
|
);
|
|
2024
2323
|
progress.stop();
|
|
2025
|
-
(0, import_ora.default)().succeed(
|
|
2026
|
-
files.forEach((f) => console.log(" -",
|
|
2324
|
+
(0, import_ora.default)().succeed(import_chalk3.default.green(`Generated (arktype): ${files.length} files`));
|
|
2325
|
+
files.forEach((f) => console.log(" -", import_chalk3.default.cyan(f)));
|
|
2027
2326
|
} catch (e) {
|
|
2028
2327
|
progress.stop();
|
|
2029
2328
|
reportGeneratorFailure(g.kind, e);
|
|
@@ -2039,8 +2338,8 @@ program.command("generate").description("Run configured generators (drzl.config.
|
|
|
2039
2338
|
const target = g.path ?? "src/validators/json-schema";
|
|
2040
2339
|
const files = await gen.generate(jsonSchemaOptions(g, cfg, target));
|
|
2041
2340
|
progress.stop();
|
|
2042
|
-
(0, import_ora.default)().succeed(
|
|
2043
|
-
files.forEach((f) => console.log(" -",
|
|
2341
|
+
(0, import_ora.default)().succeed(import_chalk3.default.green(`Generated (json-schema): ${files.length} files`));
|
|
2342
|
+
files.forEach((f) => console.log(" -", import_chalk3.default.cyan(f)));
|
|
2044
2343
|
} catch (e) {
|
|
2045
2344
|
progress.stop();
|
|
2046
2345
|
reportGeneratorFailure(g.kind, e);
|
|
@@ -2058,8 +2357,8 @@ program.command("generate").description("Run configured generators (drzl.config.
|
|
|
2058
2357
|
validationOptions(g, cfg, target, { schemaTypes: true })
|
|
2059
2358
|
);
|
|
2060
2359
|
progress.stop();
|
|
2061
|
-
(0, import_ora.default)().succeed(
|
|
2062
|
-
files.forEach((f) => console.log(" -",
|
|
2360
|
+
(0, import_ora.default)().succeed(import_chalk3.default.green(`Generated (typebox): ${files.length} files`));
|
|
2361
|
+
files.forEach((f) => console.log(" -", import_chalk3.default.cyan(f)));
|
|
2063
2362
|
} catch (e) {
|
|
2064
2363
|
progress.stop();
|
|
2065
2364
|
reportGeneratorFailure(g.kind, e);
|
|
@@ -2072,22 +2371,22 @@ program.command("generate").description("Run configured generators (drzl.config.
|
|
|
2072
2371
|
const drift = diffSnapshots(driftBefore, after);
|
|
2073
2372
|
await restoreSnapshot(driftBefore, after);
|
|
2074
2373
|
if (drift.length) {
|
|
2075
|
-
console.error(
|
|
2374
|
+
console.error(import_chalk3.default.red(`
|
|
2076
2375
|
Generated output is out of date (${drift.length} file(s)):`));
|
|
2077
2376
|
for (const d of drift) {
|
|
2078
2377
|
const mark = d.status === "added" ? "+" : d.status === "removed" ? "-" : "~";
|
|
2079
2378
|
console.error(
|
|
2080
|
-
` ${mark} ${
|
|
2379
|
+
` ${mark} ${import_chalk3.default.yellow(d.status.padEnd(8))} ${path5.relative(process.cwd(), d.file)}`
|
|
2081
2380
|
);
|
|
2082
2381
|
}
|
|
2083
2382
|
console.error(
|
|
2084
|
-
|
|
2383
|
+
import_chalk3.default.dim(
|
|
2085
2384
|
"\nRun `drzl generate` and commit the result. Nothing was written by this check."
|
|
2086
2385
|
)
|
|
2087
2386
|
);
|
|
2088
2387
|
process.exit(1);
|
|
2089
2388
|
}
|
|
2090
|
-
console.log(
|
|
2389
|
+
console.log(import_chalk3.default.green("Generated output is up to date."));
|
|
2091
2390
|
return;
|
|
2092
2391
|
}
|
|
2093
2392
|
if (cfg.generators.length) {
|
|
@@ -2095,7 +2394,7 @@ Generated output is out of date (${drift.length} file(s)):`));
|
|
|
2095
2394
|
}
|
|
2096
2395
|
} catch (e) {
|
|
2097
2396
|
console.error(
|
|
2098
|
-
|
|
2397
|
+
import_chalk3.default.red("Generate failed (DRZL_GEN_001):"),
|
|
2099
2398
|
e?.message ?? e,
|
|
2100
2399
|
"\nTip: check your drzl.config.ts and template path."
|
|
2101
2400
|
);
|
|
@@ -2115,10 +2414,10 @@ program.command("generate:orpc").argument("<schema>", "path to drizzle schema (T
|
|
|
2115
2414
|
template: opts.template,
|
|
2116
2415
|
includeRelations: !!opts.includeRelations
|
|
2117
2416
|
});
|
|
2118
|
-
console.log(
|
|
2417
|
+
console.log(import_chalk3.default.green(`Generated:`), files.map((f) => import_chalk3.default.cyan(f)).join(", "));
|
|
2119
2418
|
maybeShowSponsorMessage({ reason: "generate:orpc" });
|
|
2120
2419
|
} catch (e) {
|
|
2121
|
-
console.error(
|
|
2420
|
+
console.error(import_chalk3.default.red("Generate orpc failed:"), e?.message ?? e);
|
|
2122
2421
|
process.exit(1);
|
|
2123
2422
|
}
|
|
2124
2423
|
});
|
|
@@ -2142,7 +2441,7 @@ program.command("generate:trpc").argument("<schema>", "path to drizzle schema (T
|
|
|
2142
2441
|
// cannot become the branch that forgets it.
|
|
2143
2442
|
servicesDir: opts.servicesDir
|
|
2144
2443
|
});
|
|
2145
|
-
console.log(
|
|
2444
|
+
console.log(import_chalk3.default.green(`Generated:`), files.map((f) => import_chalk3.default.cyan(f)).join(", "));
|
|
2146
2445
|
maybeShowSponsorMessage({ reason: "generate:trpc" });
|
|
2147
2446
|
} catch (e) {
|
|
2148
2447
|
reportGeneratorFailure("trpc", e);
|
|
@@ -2152,7 +2451,7 @@ program.command("generate:trpc").argument("<schema>", "path to drizzle schema (T
|
|
|
2152
2451
|
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
2452
|
let cfg = await loadConfig(opts.config);
|
|
2154
2453
|
if (!cfg) {
|
|
2155
|
-
console.error(
|
|
2454
|
+
console.error(import_chalk3.default.red("No config found. Create drzl.config.ts or pass --config."));
|
|
2156
2455
|
process.exit(2);
|
|
2157
2456
|
return;
|
|
2158
2457
|
}
|
|
@@ -2244,7 +2543,7 @@ program.command("watch").description("Watch schema and regenerate on changes").o
|
|
|
2244
2543
|
})
|
|
2245
2544
|
);
|
|
2246
2545
|
} else {
|
|
2247
|
-
console.log(
|
|
2546
|
+
console.log(import_chalk3.default.green("Analyze complete."));
|
|
2248
2547
|
}
|
|
2249
2548
|
return;
|
|
2250
2549
|
}
|
|
@@ -2274,8 +2573,8 @@ program.command("watch").description("Watch schema and regenerate on changes").o
|
|
|
2274
2573
|
servicesDir
|
|
2275
2574
|
});
|
|
2276
2575
|
opts.json ? console.log(JSON.stringify({ event: "generate_complete", kind: g.kind, files })) : console.log(
|
|
2277
|
-
|
|
2278
|
-
files.map((f) =>
|
|
2576
|
+
import_chalk3.default.green(`Generated (${g.kind}):`),
|
|
2577
|
+
files.map((f) => import_chalk3.default.cyan(f)).join(", ")
|
|
2279
2578
|
);
|
|
2280
2579
|
newFiles.push(...files);
|
|
2281
2580
|
} else if (g.kind === "trpc") {
|
|
@@ -2287,8 +2586,8 @@ program.command("watch").description("Watch schema and regenerate on changes").o
|
|
|
2287
2586
|
const gen = new TRPCGenerator2(analysis);
|
|
2288
2587
|
const { files } = await gen.generate(trpcOptions(g, cfg, servicesDir));
|
|
2289
2588
|
opts.json ? console.log(JSON.stringify({ event: "generate_complete", kind: g.kind, files })) : console.log(
|
|
2290
|
-
|
|
2291
|
-
files.map((f) =>
|
|
2589
|
+
import_chalk3.default.green(`Generated (trpc): ${files.length} files`),
|
|
2590
|
+
files.map((f) => import_chalk3.default.cyan(f)).join(", ")
|
|
2292
2591
|
);
|
|
2293
2592
|
newFiles.push(...files);
|
|
2294
2593
|
} catch (e) {
|
|
@@ -2314,8 +2613,8 @@ program.command("watch").description("Watch schema and regenerate on changes").o
|
|
|
2314
2613
|
databaseInjection: g.databaseInjection
|
|
2315
2614
|
});
|
|
2316
2615
|
opts.json ? console.log(JSON.stringify({ event: "generate_complete", kind: g.kind, files })) : console.log(
|
|
2317
|
-
|
|
2318
|
-
files.map((f) =>
|
|
2616
|
+
import_chalk3.default.green(`Generated (service): ${files.length} files`),
|
|
2617
|
+
files.map((f) => import_chalk3.default.cyan(f)).join(", ")
|
|
2319
2618
|
);
|
|
2320
2619
|
newFiles.push(...files);
|
|
2321
2620
|
} catch (e) {
|
|
@@ -2334,8 +2633,8 @@ program.command("watch").description("Watch schema and regenerate on changes").o
|
|
|
2334
2633
|
validationOptions(g, cfg, target, { schemaTypes: true })
|
|
2335
2634
|
);
|
|
2336
2635
|
opts.json ? console.log(JSON.stringify({ event: "generate_complete", kind: g.kind, files })) : console.log(
|
|
2337
|
-
|
|
2338
|
-
files.map((f) =>
|
|
2636
|
+
import_chalk3.default.green(`Generated (zod): ${files.length} files`),
|
|
2637
|
+
files.map((f) => import_chalk3.default.cyan(f)).join(", ")
|
|
2339
2638
|
);
|
|
2340
2639
|
newFiles.push(...files);
|
|
2341
2640
|
} catch (e) {
|
|
@@ -2354,8 +2653,8 @@ program.command("watch").description("Watch schema and regenerate on changes").o
|
|
|
2354
2653
|
validationOptions(g, cfg, target, { schemaTypes: true })
|
|
2355
2654
|
);
|
|
2356
2655
|
opts.json ? console.log(JSON.stringify({ event: "generate_complete", kind: g.kind, files })) : console.log(
|
|
2357
|
-
|
|
2358
|
-
files.map((f) =>
|
|
2656
|
+
import_chalk3.default.green(`Generated (valibot): ${files.length} files`),
|
|
2657
|
+
files.map((f) => import_chalk3.default.cyan(f)).join(", ")
|
|
2359
2658
|
);
|
|
2360
2659
|
newFiles.push(...files);
|
|
2361
2660
|
} catch (e) {
|
|
@@ -2374,8 +2673,8 @@ program.command("watch").description("Watch schema and regenerate on changes").o
|
|
|
2374
2673
|
validationOptions(g, cfg, target, { schemaTypes: false })
|
|
2375
2674
|
);
|
|
2376
2675
|
opts.json ? console.log(JSON.stringify({ event: "generate_complete", kind: g.kind, files })) : console.log(
|
|
2377
|
-
|
|
2378
|
-
files.map((f) =>
|
|
2676
|
+
import_chalk3.default.green(`Generated (arktype): ${files.length} files`),
|
|
2677
|
+
files.map((f) => import_chalk3.default.cyan(f)).join(", ")
|
|
2379
2678
|
);
|
|
2380
2679
|
newFiles.push(...files);
|
|
2381
2680
|
} catch (e) {
|
|
@@ -2394,8 +2693,8 @@ program.command("watch").description("Watch schema and regenerate on changes").o
|
|
|
2394
2693
|
validationOptions(g, cfg, target, { schemaTypes: true })
|
|
2395
2694
|
);
|
|
2396
2695
|
opts.json ? console.log(JSON.stringify({ event: "generate_complete", kind: g.kind, files })) : console.log(
|
|
2397
|
-
|
|
2398
|
-
files.map((f) =>
|
|
2696
|
+
import_chalk3.default.green(`Generated (typebox): ${files.length} files`),
|
|
2697
|
+
files.map((f) => import_chalk3.default.cyan(f)).join(", ")
|
|
2399
2698
|
);
|
|
2400
2699
|
newFiles.push(...files);
|
|
2401
2700
|
} catch (e) {
|
|
@@ -2412,8 +2711,8 @@ program.command("watch").description("Watch schema and regenerate on changes").o
|
|
|
2412
2711
|
const target = g.path ?? "src/validators/json-schema";
|
|
2413
2712
|
const files = await gen.generate(jsonSchemaOptions(g, cfg, target));
|
|
2414
2713
|
opts.json ? console.log(JSON.stringify({ event: "generate_complete", kind: g.kind, files })) : console.log(
|
|
2415
|
-
|
|
2416
|
-
files.map((f) =>
|
|
2714
|
+
import_chalk3.default.green(`Generated (json-schema): ${files.length} files`),
|
|
2715
|
+
files.map((f) => import_chalk3.default.cyan(f)).join(", ")
|
|
2417
2716
|
);
|
|
2418
2717
|
newFiles.push(...files);
|
|
2419
2718
|
} catch (e) {
|
|
@@ -2425,8 +2724,8 @@ program.command("watch").description("Watch schema and regenerate on changes").o
|
|
|
2425
2724
|
const added = newFiles.filter((f) => !lastFiles.includes(f));
|
|
2426
2725
|
const removed = lastFiles.filter((f) => !newFiles.includes(f));
|
|
2427
2726
|
opts.json ? console.log(JSON.stringify({ event: "diff", added, removed })) : (() => {
|
|
2428
|
-
if (added.length) console.log(
|
|
2429
|
-
if (removed.length) console.log(
|
|
2727
|
+
if (added.length) console.log(import_chalk3.default.blue(`Added: ${added.join(", ")}`));
|
|
2728
|
+
if (removed.length) console.log(import_chalk3.default.yellow(`Removed: ${removed.join(", ")}`));
|
|
2430
2729
|
})();
|
|
2431
2730
|
if (newFiles.length && !opts.json) {
|
|
2432
2731
|
const reason = opts.pipeline && opts.pipeline !== "all" ? `watch:${opts.pipeline}` : "watch";
|
|
@@ -2434,7 +2733,7 @@ program.command("watch").description("Watch schema and regenerate on changes").o
|
|
|
2434
2733
|
}
|
|
2435
2734
|
lastFiles = newFiles;
|
|
2436
2735
|
} catch (e) {
|
|
2437
|
-
opts.json ? console.log(JSON.stringify({ event: "error", message: String(e?.message ?? e) })) : console.error(
|
|
2736
|
+
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
2737
|
}
|
|
2439
2738
|
};
|
|
2440
2739
|
const debounced = Number(opts.debounce) || 200;
|
|
@@ -2459,12 +2758,12 @@ program.command("watch").description("Watch schema and regenerate on changes").o
|
|
|
2459
2758
|
);
|
|
2460
2759
|
} else {
|
|
2461
2760
|
console.log(
|
|
2462
|
-
|
|
2761
|
+
import_chalk3.default.gray(
|
|
2463
2762
|
"Watching:\n " + Array.from(currentTargets).map((p) => path5.relative(process.cwd(), p)).join("\n ")
|
|
2464
2763
|
)
|
|
2465
2764
|
);
|
|
2466
2765
|
}
|
|
2467
|
-
watcher.on("add", (p) => trigger(p)).on("change", (p) => trigger(p)).on("unlink", (p) => trigger(p)).on("error", (err) => console.error(
|
|
2766
|
+
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
2767
|
await run();
|
|
2469
2768
|
});
|
|
2470
2769
|
program.command("init").description("Scaffold a drzl.config.ts").option("-y, --yes", "accept defaults").action(async (_opts) => {
|
|
@@ -2484,9 +2783,9 @@ program.command("init").description("Scaffold a drzl.config.ts").option("-y, --y
|
|
|
2484
2783
|
`;
|
|
2485
2784
|
try {
|
|
2486
2785
|
await fs3.writeFile(target, template, { flag: "wx" });
|
|
2487
|
-
console.log(
|
|
2786
|
+
console.log(import_chalk3.default.green(`Created ${target}`));
|
|
2488
2787
|
} catch (e) {
|
|
2489
|
-
console.error(
|
|
2788
|
+
console.error(import_chalk3.default.red("Init failed:"), e?.message ?? e);
|
|
2490
2789
|
process.exit(1);
|
|
2491
2790
|
}
|
|
2492
2791
|
});
|
|
@@ -2494,13 +2793,14 @@ function reportWideColumns(issues) {
|
|
|
2494
2793
|
const wide = issues.filter((i) => i.code === "DRZL_ANL_UNKNOWN_COLUMN");
|
|
2495
2794
|
if (!wide.length) return;
|
|
2496
2795
|
console.warn(
|
|
2497
|
-
|
|
2796
|
+
import_chalk3.default.yellow(`
|
|
2498
2797
|
${wide.length} column${wide.length === 1 ? "" : "s"} could not be typed:`)
|
|
2499
2798
|
);
|
|
2500
|
-
for (const i of wide.slice(0, 10)) console.warn(
|
|
2501
|
-
if (wide.length > 10) console.warn(
|
|
2799
|
+
for (const i of wide.slice(0, 10)) console.warn(import_chalk3.default.gray(` - ${i.message}`));
|
|
2800
|
+
if (wide.length > 10) console.warn(import_chalk3.default.gray(` ... and ${wide.length - 10} more`));
|
|
2502
2801
|
const hints = [...new Set(wide.map((i) => i.hint).filter(Boolean))];
|
|
2503
|
-
for (const h of hints) console.warn(
|
|
2802
|
+
for (const h of hints) console.warn(import_chalk3.default.gray(` ${h}`));
|
|
2803
|
+
console.warn(import_chalk3.default.gray(" Run `drzl doctor` for the full report."));
|
|
2504
2804
|
}
|
|
2505
2805
|
program.parseAsync(process.argv);
|
|
2506
2806
|
//# sourceMappingURL=cli.cjs.map
|