@drzl/cli 4.13.0 → 4.13.1
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 +290 -3
- package/dist/cli.cjs.map +1 -1
- package/dist/cli.js +6 -2
- package/dist/cli.js.map +1 -1
- package/dist/dist-5AK7UG3O.js +282 -0
- package/dist/dist-5AK7UG3O.js.map +1 -0
- package/package.json +8 -6
package/dist/cli.cjs
CHANGED
|
@@ -6,6 +6,13 @@ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
|
6
6
|
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
7
7
|
var __getProtoOf = Object.getPrototypeOf;
|
|
8
8
|
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
9
|
+
var __esm = (fn, res) => function __init() {
|
|
10
|
+
return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
|
|
11
|
+
};
|
|
12
|
+
var __export = (target, all) => {
|
|
13
|
+
for (var name in all)
|
|
14
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
15
|
+
};
|
|
9
16
|
var __copyProps = (to, from, except, desc) => {
|
|
10
17
|
if (from && typeof from === "object" || typeof from === "function") {
|
|
11
18
|
for (let key of __getOwnPropNames(from))
|
|
@@ -23,6 +30,282 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
|
|
|
23
30
|
mod
|
|
24
31
|
));
|
|
25
32
|
|
|
33
|
+
// ../generator-json-schema/dist/index.js
|
|
34
|
+
var dist_exports = {};
|
|
35
|
+
__export(dist_exports, {
|
|
36
|
+
JsonSchemaGenerator: () => JsonSchemaGenerator,
|
|
37
|
+
default: () => index_default,
|
|
38
|
+
tableSchemas: () => tableSchemas
|
|
39
|
+
});
|
|
40
|
+
function baseSchema(c, mode, target, checks, sets, lengths) {
|
|
41
|
+
const s = c.shape;
|
|
42
|
+
if (s) {
|
|
43
|
+
switch (s.kind) {
|
|
44
|
+
case "json":
|
|
45
|
+
return {};
|
|
46
|
+
case "custom":
|
|
47
|
+
return {};
|
|
48
|
+
case "buffer":
|
|
49
|
+
return { type: "string", contentEncoding: "base64" };
|
|
50
|
+
case "tuple":
|
|
51
|
+
return target === "openapi-3.0" ? { type: "array", items: { type: "number" }, minItems: s.length, maxItems: s.length } : {
|
|
52
|
+
type: "array",
|
|
53
|
+
prefixItems: Array.from({ length: s.length }, () => ({ type: "number" })),
|
|
54
|
+
minItems: s.length,
|
|
55
|
+
maxItems: s.length
|
|
56
|
+
};
|
|
57
|
+
case "numberVector":
|
|
58
|
+
return {
|
|
59
|
+
type: "array",
|
|
60
|
+
items: { type: "number" },
|
|
61
|
+
...s.length ? { minItems: s.length, maxItems: s.length } : {}
|
|
62
|
+
};
|
|
63
|
+
case "bitstring":
|
|
64
|
+
return {
|
|
65
|
+
type: "string",
|
|
66
|
+
pattern: "^[01]*$",
|
|
67
|
+
...s.length ? s.exact ? { minLength: s.length, maxLength: s.length } : { maxLength: s.length } : {}
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
const set = sets.find((x) => x.column === c.name);
|
|
72
|
+
if (set) return { enum: set.values.map((v) => set.kind === "string" ? v : Number(v)) };
|
|
73
|
+
if (c.enumValues && c.enumValues.length) return { enum: [...c.enumValues] };
|
|
74
|
+
const mine = c.arrayDimensions ? [] : checks.filter((k) => k.column === c.name);
|
|
75
|
+
const eq = mine.find((k) => k.operator === "=");
|
|
76
|
+
if (eq) return { const: eq.kind === "string" ? eq.value : Number(eq.value) };
|
|
77
|
+
switch (c.tsType) {
|
|
78
|
+
case "string": {
|
|
79
|
+
const out = { type: "string" };
|
|
80
|
+
if (c.format === "uuid") out.format = UUID_FORMAT;
|
|
81
|
+
else if (c.format && import_validation_core2.COLUMN_FORMATS[c.format]) out.pattern = import_validation_core2.COLUMN_FORMATS[c.format];
|
|
82
|
+
if (c.maxLength !== void 0) out.maxLength = c.maxLength;
|
|
83
|
+
applyLengths(out, c, lengths);
|
|
84
|
+
return out;
|
|
85
|
+
}
|
|
86
|
+
case "number": {
|
|
87
|
+
const out = { type: (0, import_validation_core2.isIntegerColumn)(c) ? "integer" : "number" };
|
|
88
|
+
if (!c.arrayDimensions) applyNumericBounds(out, c, checks, target);
|
|
89
|
+
return out;
|
|
90
|
+
}
|
|
91
|
+
case "bigint":
|
|
92
|
+
return { type: "string", pattern: "^-?\\d+$" };
|
|
93
|
+
case "boolean":
|
|
94
|
+
return { type: "boolean" };
|
|
95
|
+
case "Date":
|
|
96
|
+
return { type: "string", format: "date-time" };
|
|
97
|
+
case "Uint8Array":
|
|
98
|
+
return { type: "string", contentEncoding: "base64" };
|
|
99
|
+
default:
|
|
100
|
+
return {};
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
function applyLengths(out, c, lengths) {
|
|
104
|
+
for (const k of lengths.filter((x) => x.column === c.name)) {
|
|
105
|
+
const n = Number(k.value);
|
|
106
|
+
if (k.operator === ">=") out.minLength = Math.max(Number(out.minLength ?? 0), n);
|
|
107
|
+
else if (k.operator === ">") out.minLength = Math.max(Number(out.minLength ?? 0), n + 1);
|
|
108
|
+
else if (k.operator === "<=") out.maxLength = Math.min(Number(out.maxLength ?? Infinity), n);
|
|
109
|
+
else if (k.operator === "<") out.maxLength = Math.min(Number(out.maxLength ?? Infinity), n - 1);
|
|
110
|
+
else if (k.operator === "=") {
|
|
111
|
+
out.minLength = n;
|
|
112
|
+
out.maxLength = n;
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
function applyNumericBounds(out, c, checks, target) {
|
|
117
|
+
let min = c.min !== void 0 ? { value: Number(c.min), exclusive: false } : void 0;
|
|
118
|
+
let max = c.max !== void 0 ? { value: Number(c.max), exclusive: false } : void 0;
|
|
119
|
+
for (const k of checks.filter((x) => x.column === c.name && x.kind === "number")) {
|
|
120
|
+
if (k.operator === ">=") min = { value: Number(k.value), exclusive: false };
|
|
121
|
+
else if (k.operator === ">") min = { value: Number(k.value), exclusive: true };
|
|
122
|
+
else if (k.operator === "<=") max = { value: Number(k.value), exclusive: false };
|
|
123
|
+
else if (k.operator === "<") max = { value: Number(k.value), exclusive: true };
|
|
124
|
+
}
|
|
125
|
+
const old = target === "openapi-3.0";
|
|
126
|
+
if (min) {
|
|
127
|
+
if (min.exclusive && !old) out.exclusiveMinimum = min.value;
|
|
128
|
+
else {
|
|
129
|
+
out.minimum = min.value;
|
|
130
|
+
if (min.exclusive) out.exclusiveMinimum = true;
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
if (max) {
|
|
134
|
+
if (max.exclusive && !old) out.exclusiveMaximum = max.value;
|
|
135
|
+
else {
|
|
136
|
+
out.maximum = max.value;
|
|
137
|
+
if (max.exclusive) out.exclusiveMaximum = true;
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
function cardinalityBounds(c, cardinalities) {
|
|
142
|
+
if (!c.arrayDimensions) return {};
|
|
143
|
+
const out = {};
|
|
144
|
+
for (const k of cardinalities.filter((x) => x.column === c.name)) {
|
|
145
|
+
const n = Number(k.value);
|
|
146
|
+
if (k.operator === ">=") out.minItems = n;
|
|
147
|
+
else if (k.operator === ">") out.minItems = n + 1;
|
|
148
|
+
else if (k.operator === "<=") out.maxItems = n;
|
|
149
|
+
else if (k.operator === "<") out.maxItems = n - 1;
|
|
150
|
+
else if (k.operator === "=") {
|
|
151
|
+
out.minItems = n;
|
|
152
|
+
out.maxItems = n;
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
return out;
|
|
156
|
+
}
|
|
157
|
+
function makeNullable(s, target) {
|
|
158
|
+
if (target === "openapi-3.0") return { ...s, nullable: true };
|
|
159
|
+
if (s.type === void 0) {
|
|
160
|
+
if (Array.isArray(s.enum)) return { ...s, enum: [...s.enum, null] };
|
|
161
|
+
if ("const" in s) {
|
|
162
|
+
const { const: k, ...rest } = s;
|
|
163
|
+
return { ...rest, enum: [k, null] };
|
|
164
|
+
}
|
|
165
|
+
return s;
|
|
166
|
+
}
|
|
167
|
+
return { ...s, type: [s.type, "null"] };
|
|
168
|
+
}
|
|
169
|
+
function columnSchema(c, mode, target, checks, sets, lengths, cardinalities, applyDefault) {
|
|
170
|
+
let s = baseSchema(c, mode, target, checks, sets, lengths);
|
|
171
|
+
const dims = c.arrayDimensions ?? 0;
|
|
172
|
+
for (let i = 0; i < dims; i++) {
|
|
173
|
+
s = { type: "array", items: s, ...i === dims - 1 ? cardinalityBounds(c, cardinalities) : {} };
|
|
174
|
+
}
|
|
175
|
+
if (c.nullable) s = makeNullable(s, target);
|
|
176
|
+
if (mode === "insert" && applyDefault && c.defaultValue !== void 0) {
|
|
177
|
+
s = { ...s, default: c.defaultValue };
|
|
178
|
+
}
|
|
179
|
+
return s;
|
|
180
|
+
}
|
|
181
|
+
function rowDescription(rows, cols) {
|
|
182
|
+
const present = new Set(cols.map((c) => c.name));
|
|
183
|
+
const applicable = rows.filter((r) => present.has(r.left) && present.has(r.right));
|
|
184
|
+
if (!applicable.length) return void 0;
|
|
185
|
+
const list = applicable.map((r) => `${r.name ? `${r.name}: ` : ""}${r.left} ${r.operator} ${r.right}`).join("; ");
|
|
186
|
+
return `Row constraints not expressible in JSON Schema: ${list}`;
|
|
187
|
+
}
|
|
188
|
+
function tableSchema(table, cols, mode, target, applyDefaults, parsed) {
|
|
189
|
+
const properties = {};
|
|
190
|
+
const required = [];
|
|
191
|
+
for (const c of cols) {
|
|
192
|
+
properties[c.name] = columnSchema(
|
|
193
|
+
c,
|
|
194
|
+
mode,
|
|
195
|
+
target,
|
|
196
|
+
parsed.checks,
|
|
197
|
+
parsed.sets,
|
|
198
|
+
parsed.lengths,
|
|
199
|
+
parsed.cardinalities,
|
|
200
|
+
applyDefaults
|
|
201
|
+
);
|
|
202
|
+
const supplied = c.hasDefault || mode === "insert" && applyDefaults && c.defaultValue !== void 0;
|
|
203
|
+
if (mode !== "update" && !supplied) required.push(c.name);
|
|
204
|
+
}
|
|
205
|
+
const desc = rowDescription(parsed.rows, cols);
|
|
206
|
+
return {
|
|
207
|
+
...target === "draft-2020-12" ? { $schema: DRAFT } : {},
|
|
208
|
+
$id: `${table.tsName}.${mode}`,
|
|
209
|
+
title: `${mode} ${table.tsName}`,
|
|
210
|
+
...desc ? { description: desc } : {},
|
|
211
|
+
type: "object",
|
|
212
|
+
properties,
|
|
213
|
+
...required.length ? { required } : {},
|
|
214
|
+
additionalProperties: false
|
|
215
|
+
};
|
|
216
|
+
}
|
|
217
|
+
function collect(table) {
|
|
218
|
+
const parsed = (table.checks ?? []).map((k) => (0, import_validation_core2.parseCheck)(k.expression, k.name));
|
|
219
|
+
return {
|
|
220
|
+
checks: parsed.flatMap((p) => p.ok ? p.checks : []),
|
|
221
|
+
sets: parsed.flatMap((p) => p.ok ? p.sets ?? [] : []),
|
|
222
|
+
rows: parsed.flatMap((p) => p.ok ? p.rows ?? [] : []),
|
|
223
|
+
lengths: parsed.flatMap((p) => p.ok ? p.lengths ?? [] : []),
|
|
224
|
+
cardinalities: parsed.flatMap((p) => p.ok ? p.cardinalities ?? [] : [])
|
|
225
|
+
};
|
|
226
|
+
}
|
|
227
|
+
function tableSchemas(table, opts = {}) {
|
|
228
|
+
const target = opts.target ?? "draft-2020-12";
|
|
229
|
+
const parsed = collect(table);
|
|
230
|
+
const build = (cols, mode) => tableSchema(table, cols, mode, target, !!opts.applyDefaults, parsed);
|
|
231
|
+
return {
|
|
232
|
+
insert: build((0, import_validation_core2.insertColumns)(table), "insert"),
|
|
233
|
+
update: build((0, import_validation_core2.updateColumns)(table), "update"),
|
|
234
|
+
select: build((0, import_validation_core2.selectColumns)(table), "select")
|
|
235
|
+
};
|
|
236
|
+
}
|
|
237
|
+
function renderTableModule(table, affix, target, applyDefaults) {
|
|
238
|
+
const T = table.tsName;
|
|
239
|
+
const schemas = tableSchemas(table, { target, applyDefaults });
|
|
240
|
+
const decl = (mode) => `export const ${(0, import_validation_core2.schemaName)(mode, T, affix)} = ${JSON.stringify(schemas[mode], null, 2)} as const;
|
|
241
|
+
|
|
242
|
+
export type ${(0, import_validation_core2.typeName)(mode, T, affix)} = typeof ${(0, import_validation_core2.schemaName)(mode, T, affix)};`;
|
|
243
|
+
return [decl("insert"), decl("update"), decl("select")].join("\n\n") + "\n";
|
|
244
|
+
}
|
|
245
|
+
function buildHeader(h) {
|
|
246
|
+
if (h?.enabled === false) return "";
|
|
247
|
+
const text = h?.text ?? "// Generated by DRZL. Do not edit by hand.";
|
|
248
|
+
return `${text}
|
|
249
|
+
|
|
250
|
+
`;
|
|
251
|
+
}
|
|
252
|
+
var import_validation_core2, DEFAULT_FILE_SUFFIX, DRAFT, UUID_FORMAT, JsonSchemaGenerator, index_default;
|
|
253
|
+
var init_dist = __esm({
|
|
254
|
+
"../generator-json-schema/dist/index.js"() {
|
|
255
|
+
"use strict";
|
|
256
|
+
import_validation_core2 = require("@drzl/validation-core");
|
|
257
|
+
DEFAULT_FILE_SUFFIX = ".schema.ts";
|
|
258
|
+
DRAFT = "https://json-schema.org/draft/2020-12/schema";
|
|
259
|
+
UUID_FORMAT = "uuid";
|
|
260
|
+
JsonSchemaGenerator = class {
|
|
261
|
+
constructor(analysis) {
|
|
262
|
+
this.analysis = analysis;
|
|
263
|
+
this.library = "json-schema";
|
|
264
|
+
}
|
|
265
|
+
async generate(opts) {
|
|
266
|
+
const fs3 = await import("fs/promises");
|
|
267
|
+
const path5 = await import("path");
|
|
268
|
+
const out = path5.resolve(process.cwd(), opts.outDir);
|
|
269
|
+
const files = [];
|
|
270
|
+
await fs3.mkdir(out, { recursive: true });
|
|
271
|
+
const affix = (0, import_validation_core2.resolveAffix)(opts);
|
|
272
|
+
const fileSuffix = opts.fileSuffix ?? DEFAULT_FILE_SUFFIX;
|
|
273
|
+
const target = opts.target ?? "draft-2020-12";
|
|
274
|
+
for (const table of this.analysis.tables) {
|
|
275
|
+
const filePath = path5.join(out, (0, import_validation_core2.moduleFileName)(table.tsName, fileSuffix));
|
|
276
|
+
const code = renderTableModule(table, affix, target, !!opts.applyDefaults);
|
|
277
|
+
const formatted = await (0, import_validation_core2.formatCode)(
|
|
278
|
+
buildHeader(opts.outputHeader) + code,
|
|
279
|
+
filePath,
|
|
280
|
+
opts.format
|
|
281
|
+
);
|
|
282
|
+
await fs3.writeFile(filePath, formatted, "utf8");
|
|
283
|
+
files.push(filePath);
|
|
284
|
+
}
|
|
285
|
+
const indexPath = path5.join(out, "index.ts");
|
|
286
|
+
const index = this.analysis.tables.map((t) => `export * from '${(0, import_validation_core2.moduleSpecifier)(t.tsName, fileSuffix, opts.importExtension)}';`).join("\n") + "\n";
|
|
287
|
+
const indexFormatted = await (0, import_validation_core2.formatCode)(
|
|
288
|
+
buildHeader(opts.outputHeader) + index,
|
|
289
|
+
indexPath,
|
|
290
|
+
opts.format
|
|
291
|
+
);
|
|
292
|
+
await fs3.writeFile(indexPath, indexFormatted, "utf8");
|
|
293
|
+
files.push(indexPath);
|
|
294
|
+
return files;
|
|
295
|
+
}
|
|
296
|
+
renderTable(table, opts) {
|
|
297
|
+
return renderTableModule(
|
|
298
|
+
table,
|
|
299
|
+
(0, import_validation_core2.resolveAffix)(opts),
|
|
300
|
+
opts?.target ?? "draft-2020-12",
|
|
301
|
+
!!opts?.applyDefaults
|
|
302
|
+
);
|
|
303
|
+
}
|
|
304
|
+
};
|
|
305
|
+
index_default = JsonSchemaGenerator;
|
|
306
|
+
}
|
|
307
|
+
});
|
|
308
|
+
|
|
26
309
|
// src/cli.ts
|
|
27
310
|
var import_analyzer = require("@drzl/analyzer");
|
|
28
311
|
var import_generator_orpc = require("@drzl/generator-orpc");
|
|
@@ -695,8 +978,8 @@ program.command("generate").description("Run configured generators (drzl.config.
|
|
|
695
978
|
}
|
|
696
979
|
} else if (g.kind === "json-schema") {
|
|
697
980
|
try {
|
|
698
|
-
const { JsonSchemaGenerator } = await
|
|
699
|
-
const gen = new
|
|
981
|
+
const { JsonSchemaGenerator: JsonSchemaGenerator2 } = await Promise.resolve().then(() => (init_dist(), dist_exports));
|
|
982
|
+
const gen = new JsonSchemaGenerator2(analysis);
|
|
700
983
|
const target = g.path ?? "src/validators/json-schema";
|
|
701
984
|
const files = await gen.generate({
|
|
702
985
|
// JSON Schema is data, so nothing here references a type from the schema module.
|
|
@@ -710,7 +993,11 @@ program.command("generate").description("Run configured generators (drzl.config.
|
|
|
710
993
|
progress.stop();
|
|
711
994
|
console.error(
|
|
712
995
|
import_chalk2.default.red("JSON Schema generator missing."),
|
|
713
|
-
import_chalk2.default.yellow("\nInstall with: npm install @drzl/generator-json-schema")
|
|
996
|
+
import_chalk2.default.yellow("\nInstall with: npm install @drzl/generator-json-schema"),
|
|
997
|
+
// An optional dependency, unlike the other generators, until its npm trusted
|
|
998
|
+
// publisher exists. A missing optional dependency is skipped rather than failing
|
|
999
|
+
// the install, which is what keeps `npm i @drzl/cli` working meanwhile.
|
|
1000
|
+
""
|
|
714
1001
|
);
|
|
715
1002
|
console.error(import_chalk2.default.gray("Error details:"), e?.message ?? e);
|
|
716
1003
|
process.exit(1);
|