@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/{chunk-I4KMDCQR.js → chunk-V2IXXAC2.js} +13 -2
- package/dist/chunk-V2IXXAC2.js.map +1 -0
- package/dist/cli.cjs +986 -95
- package/dist/cli.cjs.map +1 -1
- package/dist/cli.js +406 -67
- package/dist/cli.js.map +1 -1
- package/dist/config.cjs +12 -1
- package/dist/config.cjs.map +1 -1
- package/dist/config.d.cts +4 -2
- package/dist/config.d.ts +4 -2
- package/dist/config.js +1 -1
- package/dist/dist-CZDVFYFW.js +559 -0
- package/dist/dist-CZDVFYFW.js.map +1 -0
- package/package.json +7 -6
- package/dist/chunk-I4KMDCQR.js.map +0 -1
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
|
);
|
|
@@ -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
|
|
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([
|
|
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
|
|
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
|
|
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) =>
|
|
1729
|
-
var cyan = (msg) =>
|
|
1730
|
-
var 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
|
-
|
|
1820
|
-
|
|
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(
|
|
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(
|
|
2662
|
+
spinner?.succeed(import_chalk3.default.green(`Analysis written to ${opts.out} in ${ms}ms`));
|
|
1853
2663
|
} else {
|
|
1854
|
-
spinner?.succeed(
|
|
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
|
-
|
|
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
|
-
|
|
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(
|
|
1925
|
-
files.forEach((f) => console.log(" -",
|
|
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(
|
|
1939
|
-
files.forEach((f) => console.log(" -",
|
|
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(
|
|
1969
|
-
files.forEach((f) => console.log(" -",
|
|
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(
|
|
1988
|
-
files.forEach((f) => console.log(" -",
|
|
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(
|
|
2007
|
-
files.forEach((f) => console.log(" -",
|
|
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(
|
|
2026
|
-
files.forEach((f) => console.log(" -",
|
|
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(
|
|
2043
|
-
files.forEach((f) => console.log(" -",
|
|
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(
|
|
2062
|
-
files.forEach((f) => console.log(" -",
|
|
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(
|
|
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} ${
|
|
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
|
-
|
|
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(
|
|
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
|
-
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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
|
-
|
|
2278
|
-
files.map((f) =>
|
|
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
|
-
|
|
2291
|
-
files.map((f) =>
|
|
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
|
-
|
|
2318
|
-
files.map((f) =>
|
|
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
|
-
|
|
2338
|
-
files.map((f) =>
|
|
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
|
-
|
|
2358
|
-
files.map((f) =>
|
|
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
|
-
|
|
2378
|
-
files.map((f) =>
|
|
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
|
-
|
|
2398
|
-
files.map((f) =>
|
|
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
|
-
|
|
2416
|
-
files.map((f) =>
|
|
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(
|
|
2429
|
-
if (removed.length) console.log(
|
|
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(
|
|
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
|
-
|
|
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(
|
|
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(
|
|
3377
|
+
console.log(import_chalk3.default.green(`Created ${target}`));
|
|
2488
3378
|
} catch (e) {
|
|
2489
|
-
console.error(
|
|
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
|
-
|
|
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(
|
|
2501
|
-
if (wide.length > 10) console.warn(
|
|
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(
|
|
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
|