@drzl/cli 4.21.0 → 4.23.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-XNNKHBGV.js → chunk-54E2IO7N.js} +491 -65
- package/dist/chunk-54E2IO7N.js.map +1 -0
- package/dist/{dist-K6N4F3XW.js → chunk-KKPDOZOD.js} +221 -39
- package/dist/chunk-KKPDOZOD.js.map +1 -0
- package/dist/cli.cjs +6606 -1471
- package/dist/cli.cjs.map +1 -1
- package/dist/cli.js +2854 -698
- package/dist/cli.js.map +1 -1
- package/dist/config.cjs +497 -64
- package/dist/config.cjs.map +1 -1
- package/dist/config.d.cts +262 -6
- package/dist/config.d.ts +262 -6
- package/dist/config.js +25 -1
- package/dist/dist-KQMPKOFK.js +350 -0
- package/dist/dist-KQMPKOFK.js.map +1 -0
- package/dist/{dist-WHAW3AMQ.js → dist-KX62ETKK.js} +71 -22
- package/dist/dist-KX62ETKK.js.map +1 -0
- package/dist/dist-P24ILO5N.js +431 -0
- package/dist/dist-P24ILO5N.js.map +1 -0
- package/dist/dist-QYH7DRFY.js +27 -0
- package/dist/dist-QYH7DRFY.js.map +1 -0
- package/dist/dist-SGI2I53L.js +434 -0
- package/dist/dist-SGI2I53L.js.map +1 -0
- package/dist/dist-T5376MW7.js +489 -0
- package/dist/dist-T5376MW7.js.map +1 -0
- package/dist/dist-UVP6B4XJ.js +646 -0
- package/dist/dist-UVP6B4XJ.js.map +1 -0
- package/dist/{dist-XBGVORL3.js → dist-ZIHNXQ7U.js} +16 -6
- package/dist/dist-ZIHNXQ7U.js.map +1 -0
- package/dist/drzl.config.schema.json +717 -0
- package/package.json +19 -13
- package/dist/chunk-XNNKHBGV.js.map +0 -1
- package/dist/dist-K6N4F3XW.js.map +0 -1
- package/dist/dist-WHAW3AMQ.js.map +0 -1
- package/dist/dist-XBGVORL3.js.map +0 -1
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
// src/config.ts
|
|
2
2
|
import {
|
|
3
|
+
AFFIX_PREFIX_PATTERN,
|
|
3
4
|
AFFIX_PROBE_TABLE,
|
|
5
|
+
AFFIX_SUFFIX_PATTERN,
|
|
4
6
|
DEFAULT_IMPORT_EXTENSION,
|
|
5
7
|
IMPORT_EXTENSIONS,
|
|
6
8
|
NAME_MODES,
|
|
@@ -13,6 +15,207 @@ import { createRequire } from "module";
|
|
|
13
15
|
import * as path from "path";
|
|
14
16
|
import { z } from "zod";
|
|
15
17
|
|
|
18
|
+
// src/config-errors.ts
|
|
19
|
+
function hasOwn(object, key) {
|
|
20
|
+
return Object.prototype.hasOwnProperty.call(object, key);
|
|
21
|
+
}
|
|
22
|
+
var CONFIG_INVALID_CODE = "DRZL_CFG_002";
|
|
23
|
+
var ConfigValidationError = class extends Error {
|
|
24
|
+
constructor(message) {
|
|
25
|
+
super(message);
|
|
26
|
+
this.code = CONFIG_INVALID_CODE;
|
|
27
|
+
this.name = "ConfigValidationError";
|
|
28
|
+
}
|
|
29
|
+
};
|
|
30
|
+
var MAX_LISTED_PROBLEMS = 8;
|
|
31
|
+
var MAX_VALUE_CHARS = 60;
|
|
32
|
+
function renderConfigPath(segments) {
|
|
33
|
+
if (!segments.length) return "(root)";
|
|
34
|
+
let out = "";
|
|
35
|
+
for (const segment of segments) {
|
|
36
|
+
if (typeof segment === "number") {
|
|
37
|
+
out += `[${segment}]`;
|
|
38
|
+
continue;
|
|
39
|
+
}
|
|
40
|
+
const key = String(segment);
|
|
41
|
+
if (/^[A-Za-z_$][A-Za-z0-9_$]*$/.test(key)) out += out ? `.${key}` : key;
|
|
42
|
+
else out += `[${JSON.stringify(key)}]`;
|
|
43
|
+
}
|
|
44
|
+
return out;
|
|
45
|
+
}
|
|
46
|
+
function describeValue(value) {
|
|
47
|
+
if (value === void 0) return "undefined";
|
|
48
|
+
if (value === null) return "null";
|
|
49
|
+
switch (typeof value) {
|
|
50
|
+
case "boolean":
|
|
51
|
+
return String(value);
|
|
52
|
+
case "number":
|
|
53
|
+
return String(value);
|
|
54
|
+
case "bigint":
|
|
55
|
+
return `${value}n`;
|
|
56
|
+
case "function":
|
|
57
|
+
return "[function]";
|
|
58
|
+
case "symbol":
|
|
59
|
+
return String(value);
|
|
60
|
+
case "string":
|
|
61
|
+
return value.length <= MAX_VALUE_CHARS ? JSON.stringify(value) : `${JSON.stringify(value.slice(0, MAX_VALUE_CHARS))} ... (${value.length} characters)`;
|
|
62
|
+
}
|
|
63
|
+
let json;
|
|
64
|
+
try {
|
|
65
|
+
json = JSON.stringify(value);
|
|
66
|
+
} catch {
|
|
67
|
+
return null;
|
|
68
|
+
}
|
|
69
|
+
if (typeof json !== "string") return null;
|
|
70
|
+
return json.length <= MAX_VALUE_CHARS ? json : null;
|
|
71
|
+
}
|
|
72
|
+
function valueAt(raw, segments) {
|
|
73
|
+
let current = raw;
|
|
74
|
+
for (const segment of segments) {
|
|
75
|
+
if (current === null || typeof current !== "object") return { found: false, value: void 0 };
|
|
76
|
+
if (!hasOwn(current, String(segment))) return { found: false, value: void 0 };
|
|
77
|
+
current = current[segment];
|
|
78
|
+
}
|
|
79
|
+
return { found: true, value: current };
|
|
80
|
+
}
|
|
81
|
+
function editDistance(a, b) {
|
|
82
|
+
if (a === b) return 0;
|
|
83
|
+
if (!a.length) return b.length;
|
|
84
|
+
if (!b.length) return a.length;
|
|
85
|
+
let previous = Array.from({ length: b.length + 1 }, (_, i) => i);
|
|
86
|
+
for (let i = 1; i <= a.length; i++) {
|
|
87
|
+
const current = new Array(b.length + 1);
|
|
88
|
+
current[0] = i;
|
|
89
|
+
for (let j = 1; j <= b.length; j++) {
|
|
90
|
+
const substitution = previous[j - 1] + (a[i - 1] === b[j - 1] ? 0 : 1);
|
|
91
|
+
current[j] = Math.min(current[j - 1] + 1, previous[j] + 1, substitution);
|
|
92
|
+
}
|
|
93
|
+
previous = current;
|
|
94
|
+
}
|
|
95
|
+
return previous[b.length];
|
|
96
|
+
}
|
|
97
|
+
function nearestKey(key, known) {
|
|
98
|
+
const budget = key.length >= 5 ? 2 : 1;
|
|
99
|
+
let best;
|
|
100
|
+
let bestDistance = Number.POSITIVE_INFINITY;
|
|
101
|
+
for (const candidate of known) {
|
|
102
|
+
if (candidate === key) return void 0;
|
|
103
|
+
const distance = editDistance(key, candidate);
|
|
104
|
+
if (distance <= budget && distance < bestDistance) {
|
|
105
|
+
best = candidate;
|
|
106
|
+
bestDistance = distance;
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
return best;
|
|
110
|
+
}
|
|
111
|
+
function objectNodeFor(node) {
|
|
112
|
+
if (!node || typeof node !== "object") return void 0;
|
|
113
|
+
const record = node;
|
|
114
|
+
const anyOf = record.anyOf;
|
|
115
|
+
if (Array.isArray(anyOf)) {
|
|
116
|
+
const branches = anyOf.filter(
|
|
117
|
+
(branch) => branch && typeof branch === "object" && (branch.properties !== void 0 || typeof branch.additionalProperties === "object")
|
|
118
|
+
);
|
|
119
|
+
return branches.length === 1 ? branches[0] : void 0;
|
|
120
|
+
}
|
|
121
|
+
if (record.properties !== void 0 || record.additionalProperties !== void 0) return record;
|
|
122
|
+
return void 0;
|
|
123
|
+
}
|
|
124
|
+
function unknownConfigKeys(raw, schema) {
|
|
125
|
+
const found = [];
|
|
126
|
+
walkForUnknownKeys(raw, schema, [], found);
|
|
127
|
+
return found;
|
|
128
|
+
}
|
|
129
|
+
function walkForUnknownKeys(value, node, segments, found) {
|
|
130
|
+
if (value === null || typeof value !== "object") return;
|
|
131
|
+
if (Array.isArray(value)) {
|
|
132
|
+
const items = node?.items;
|
|
133
|
+
if (!items) return;
|
|
134
|
+
value.forEach((entry, index) => walkForUnknownKeys(entry, items, [...segments, index], found));
|
|
135
|
+
return;
|
|
136
|
+
}
|
|
137
|
+
const object = objectNodeFor(node);
|
|
138
|
+
if (!object) return;
|
|
139
|
+
const properties = object.properties;
|
|
140
|
+
const additional = object.additionalProperties;
|
|
141
|
+
if (!properties) {
|
|
142
|
+
if (additional && typeof additional === "object") {
|
|
143
|
+
for (const [key, entry] of Object.entries(value)) {
|
|
144
|
+
walkForUnknownKeys(entry, additional, [...segments, key], found);
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
return;
|
|
148
|
+
}
|
|
149
|
+
const known = Object.keys(properties);
|
|
150
|
+
for (const [key, entry] of Object.entries(value)) {
|
|
151
|
+
if (hasOwn(properties, key)) {
|
|
152
|
+
walkForUnknownKeys(entry, properties[key], [...segments, key], found);
|
|
153
|
+
continue;
|
|
154
|
+
}
|
|
155
|
+
if (additional === false) continue;
|
|
156
|
+
found.push({ path: [...segments], key, suggestion: nearestKey(key, known) });
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
function unknownKeyWarnings(raw, schema) {
|
|
160
|
+
return unknownConfigKeys(raw, schema).map((unknown) => {
|
|
161
|
+
const where = unknown.path.length ? `in ${renderConfigPath(unknown.path)}` : "at the top level";
|
|
162
|
+
const suggestion = unknown.suggestion ? ` Did you mean "${unknown.suggestion}"?` : "";
|
|
163
|
+
return `drzl config: unknown key "${unknown.key}" ${where}; it is ignored.${suggestion}`;
|
|
164
|
+
});
|
|
165
|
+
}
|
|
166
|
+
function nodeAt(schema, segments) {
|
|
167
|
+
let node = schema;
|
|
168
|
+
for (const segment of segments) {
|
|
169
|
+
if (typeof segment === "number") {
|
|
170
|
+
node = node?.items;
|
|
171
|
+
continue;
|
|
172
|
+
}
|
|
173
|
+
const object = objectNodeFor(node);
|
|
174
|
+
if (!object) return void 0;
|
|
175
|
+
const properties = object.properties;
|
|
176
|
+
if (properties && hasOwn(properties, String(segment))) {
|
|
177
|
+
node = properties[String(segment)];
|
|
178
|
+
continue;
|
|
179
|
+
}
|
|
180
|
+
const additional = object.additionalProperties;
|
|
181
|
+
if (additional && typeof additional === "object") {
|
|
182
|
+
node = additional;
|
|
183
|
+
continue;
|
|
184
|
+
}
|
|
185
|
+
return void 0;
|
|
186
|
+
}
|
|
187
|
+
return objectNodeFor(node);
|
|
188
|
+
}
|
|
189
|
+
function knownKeysAt(schema, segments) {
|
|
190
|
+
const node = nodeAt(schema, segments);
|
|
191
|
+
const properties = node?.properties;
|
|
192
|
+
return properties ? Object.keys(properties) : [];
|
|
193
|
+
}
|
|
194
|
+
function renderIssue(issue, raw, schema) {
|
|
195
|
+
const segments = issue.path ?? [];
|
|
196
|
+
const where = renderConfigPath(segments);
|
|
197
|
+
if (issue.code === "unrecognized_keys" && issue.keys?.length) {
|
|
198
|
+
const known = knownKeysAt(schema, segments);
|
|
199
|
+
return issue.keys.map((key) => {
|
|
200
|
+
const suggestion = nearestKey(key, known);
|
|
201
|
+
return `${where}: unrecognized key "${key}".${suggestion ? ` Did you mean "${suggestion}"?` : ""}`;
|
|
202
|
+
});
|
|
203
|
+
}
|
|
204
|
+
const what = String(issue.message ?? "is not valid").replace(/^Invalid input:\s*/, "");
|
|
205
|
+
const { found, value } = valueAt(raw, segments);
|
|
206
|
+
const shown = found ? describeValue(value) : null;
|
|
207
|
+
return [`${where}: ${what}${shown === null ? "" : ` (found ${shown})`}`];
|
|
208
|
+
}
|
|
209
|
+
function formatConfigProblems(file, issues, raw, schema) {
|
|
210
|
+
const lines = issues.flatMap((issue) => renderIssue(issue, raw, schema));
|
|
211
|
+
const shown = lines.slice(0, MAX_LISTED_PROBLEMS);
|
|
212
|
+
const rest = lines.length - shown.length;
|
|
213
|
+
const header = `${file} is not valid (${CONFIG_INVALID_CODE}). ${lines.length} problem${lines.length === 1 ? "" : "s"}:`;
|
|
214
|
+
const body = shown.map((line) => ` - ${line}`);
|
|
215
|
+
if (rest > 0) body.push(` ... and ${rest} more`);
|
|
216
|
+
return [header, ...body].join("\n");
|
|
217
|
+
}
|
|
218
|
+
|
|
16
219
|
// src/patterns.ts
|
|
17
220
|
function patternToRegExp(pattern) {
|
|
18
221
|
return new RegExp(
|
|
@@ -57,13 +260,13 @@ var NamingSchema = z.object({
|
|
|
57
260
|
routerSuffix: z.string().default("Router"),
|
|
58
261
|
procedureCase: z.enum(["camel", "kebab", "snake"]).default("camel")
|
|
59
262
|
}).partial();
|
|
60
|
-
var
|
|
263
|
+
var affixValueSchema = (pattern) => z.union(
|
|
61
264
|
[
|
|
62
|
-
z.string(),
|
|
265
|
+
z.string().meta({ pattern }),
|
|
63
266
|
z.object({
|
|
64
|
-
insert: z.string().optional(),
|
|
65
|
-
update: z.string().optional(),
|
|
66
|
-
select: z.string().optional()
|
|
267
|
+
insert: z.string().meta({ pattern }).optional(),
|
|
268
|
+
update: z.string().meta({ pattern }).optional(),
|
|
269
|
+
select: z.string().meta({ pattern }).optional()
|
|
67
270
|
}).strict()
|
|
68
271
|
],
|
|
69
272
|
{
|
|
@@ -71,8 +274,8 @@ var AffixValueSchema = z.union(
|
|
|
71
274
|
}
|
|
72
275
|
);
|
|
73
276
|
var AffixPartSchema = z.object({
|
|
74
|
-
prefix:
|
|
75
|
-
suffix:
|
|
277
|
+
prefix: affixValueSchema(AFFIX_PREFIX_PATTERN).optional(),
|
|
278
|
+
suffix: affixValueSchema(AFFIX_SUFFIX_PATTERN).optional()
|
|
76
279
|
}).strict();
|
|
77
280
|
var AffixSchema = z.object({
|
|
78
281
|
/**
|
|
@@ -85,18 +288,34 @@ var AffixSchema = z.object({
|
|
|
85
288
|
type: AffixPartSchema.optional()
|
|
86
289
|
}).strict();
|
|
87
290
|
var ImportExtensionSchema = z.enum(IMPORT_EXTENSIONS);
|
|
291
|
+
var GeneratorKindSchema = z.enum([
|
|
292
|
+
"orpc",
|
|
293
|
+
"trpc",
|
|
294
|
+
"hono",
|
|
295
|
+
"express",
|
|
296
|
+
"fastify",
|
|
297
|
+
"nestjs",
|
|
298
|
+
"graphql",
|
|
299
|
+
"service",
|
|
300
|
+
"zod",
|
|
301
|
+
"valibot",
|
|
302
|
+
"arktype",
|
|
303
|
+
"typebox",
|
|
304
|
+
"effect",
|
|
305
|
+
"json-schema"
|
|
306
|
+
]);
|
|
307
|
+
var GENERATOR_KINDS = GeneratorKindSchema.options;
|
|
88
308
|
var GeneratorSchema = z.object({
|
|
89
|
-
kind:
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
]),
|
|
309
|
+
kind: GeneratorKindSchema,
|
|
310
|
+
/**
|
|
311
|
+
* Which of Hono's two official validator middlewares the emitted routes carry, and therefore
|
|
312
|
+
* which package they import. `hono` only.
|
|
313
|
+
*
|
|
314
|
+
* `standard` is `sValidator` from `@hono/standard-validator`, which takes any Standard Schema
|
|
315
|
+
* and so works with every library `validation.library` can name. `zod` is `zValidator` from
|
|
316
|
+
* `@hono/zod-validator`, which is zod-specific.
|
|
317
|
+
*/
|
|
318
|
+
validator: z.enum(["standard", "zod"]).optional(),
|
|
100
319
|
/**
|
|
101
320
|
* Overrides the top-level `importExtension` for this generator alone, for a project whose
|
|
102
321
|
* generated directories are compiled by different tsconfigs.
|
|
@@ -104,6 +323,17 @@ var GeneratorSchema = z.object({
|
|
|
104
323
|
importExtension: ImportExtensionSchema.optional(),
|
|
105
324
|
template: z.string().optional(),
|
|
106
325
|
includeRelations: z.boolean().optional(),
|
|
326
|
+
/**
|
|
327
|
+
* Write an enum used by two or more columns once under `$defs` in the `json-schema` per-table
|
|
328
|
+
* modules, and `$ref` it at each use.
|
|
329
|
+
*
|
|
330
|
+
* Off by default, and the reason is a consumer pattern rather than a doubt about the keyword. A
|
|
331
|
+
* per-table schema is used whole and one property at a time, and a `$ref` cannot survive being
|
|
332
|
+
* pulled out with its property: `properties[col]` compiled on its own is a dangling reference
|
|
333
|
+
* that ajv refuses outright. The OpenAPI document shares regardless, because a document is only
|
|
334
|
+
* ever read whole.
|
|
335
|
+
*/
|
|
336
|
+
sharedEnums: z.boolean().optional(),
|
|
107
337
|
/**
|
|
108
338
|
* Type `json` and `jsonb` columns from the schema rather than leaving them wide.
|
|
109
339
|
*
|
|
@@ -132,6 +362,27 @@ var GeneratorSchema = z.object({
|
|
|
132
362
|
* fact about the table rather than the row. This checks the half that needs no database.
|
|
133
363
|
*/
|
|
134
364
|
duplicateFinder: z.boolean().optional(),
|
|
365
|
+
/**
|
|
366
|
+
* zod and valibot. Also emit `constraints.ts`: every CHECK, unique constraint, primary and
|
|
367
|
+
* foreign key on each table as plain data, plus `constraintForIssue`, which maps a validation
|
|
368
|
+
* issue back to the constraint that caused it.
|
|
369
|
+
*
|
|
370
|
+
* For building forms. A schema states what a value must look like and never says which
|
|
371
|
+
* constraint said so, so a failed parse hands a form a message and no way to attribute it; and
|
|
372
|
+
* uniqueness and foreign keys, the two constraints no per-row schema can check, are absent from
|
|
373
|
+
* the emitted schemas in every form.
|
|
374
|
+
*
|
|
375
|
+
* Not `meta` written to a second file. `meta` describes a *field* and travels with the schema
|
|
376
|
+
* into `z.toJSONSchema`; this describes the table's *constraints*, carries their names, states
|
|
377
|
+
* each operand as data rather than inside a sentence, and is read without holding a schema.
|
|
378
|
+
*
|
|
379
|
+
* `true` is the shorthand for `{ enabled: true }`. `{ errorMap: false }` emits the data alone,
|
|
380
|
+
* without the matcher.
|
|
381
|
+
*/
|
|
382
|
+
constraints: z.union([
|
|
383
|
+
z.boolean(),
|
|
384
|
+
z.object({ enabled: z.boolean().optional(), errorMap: z.boolean().optional() }).strict()
|
|
385
|
+
]).optional(),
|
|
135
386
|
/**
|
|
136
387
|
* zod only. Attach the facts the analyzer knows and a zod schema cannot state, as `.meta()` on
|
|
137
388
|
* every field and every table schema: the declared SQL type, the primary key, the unique
|
|
@@ -305,7 +556,31 @@ var AnalyzerSchema = z.object({
|
|
|
305
556
|
includeHeuristicRelations: z.boolean().default(false)
|
|
306
557
|
});
|
|
307
558
|
var ConfigSchema = z.object({
|
|
308
|
-
|
|
559
|
+
/**
|
|
560
|
+
* Path to the Drizzle schema module. Optional since drizzle-kit interop: a project that
|
|
561
|
+
* already names its schema in `drizzle.config.ts` should not have to say it twice, so an
|
|
562
|
+
* omitted `schema` falls back to reading the drizzle-kit config (see `drizzleKit`). The
|
|
563
|
+
* "neither file names a schema" error is raised at resolution time, where it can name both
|
|
564
|
+
* files, rather than here, where "Required" could name only this one.
|
|
565
|
+
*/
|
|
566
|
+
schema: z.string().optional(),
|
|
567
|
+
/**
|
|
568
|
+
* Read the schema path from drizzle-kit's own config instead of `schema`.
|
|
569
|
+
*
|
|
570
|
+
* `true` reads `drizzle.config.ts`, then `.js`, then `.json`, the same candidates in the
|
|
571
|
+
* same order drizzle-kit's CLI uses (measured on drizzle-kit 0.31.10). A string reads that
|
|
572
|
+
* file, wherever it is, like kit's own `--config` flag. `false` disables the fallback, so
|
|
573
|
+
* an omitted `schema` is an error even beside a drizzle.config. Unset behaves like `true`
|
|
574
|
+
* whenever `schema` is omitted, and does nothing when `schema` is set: `schema` always
|
|
575
|
+
* wins, with a warning when both are stated.
|
|
576
|
+
*
|
|
577
|
+
* Only kit's `schema` (string or array, entries may be globs) and `dialect` (cross-checked
|
|
578
|
+
* against what the analyzer detects) are read. Everything else in that file describes
|
|
579
|
+
* migrations and database credentials, which DRZL has no use for.
|
|
580
|
+
*/
|
|
581
|
+
drizzleKit: z.union([z.boolean(), z.string()], {
|
|
582
|
+
error: "Expected true (read drizzle.config.ts/.js/.json, the same candidates drizzle-kit uses), false (never read one), or a path to the drizzle-kit config file."
|
|
583
|
+
}).optional(),
|
|
309
584
|
outDir: z.string().default("src/api"),
|
|
310
585
|
/**
|
|
311
586
|
* Which tables to generate for, matched against the database table name.
|
|
@@ -390,10 +665,58 @@ var ConfigSchema = z.object({
|
|
|
390
665
|
function defineConfig(cfg) {
|
|
391
666
|
return cfg;
|
|
392
667
|
}
|
|
393
|
-
var
|
|
668
|
+
var CONFIG_FILE_NAMES = [
|
|
669
|
+
"drzl.config.ts",
|
|
670
|
+
"drzl.config.mjs",
|
|
671
|
+
"drzl.config.js",
|
|
672
|
+
"drzl.config.cjs",
|
|
673
|
+
"drzl.config.json"
|
|
674
|
+
];
|
|
675
|
+
var CONFIG_SCHEMA_ID = "https://use-drzl.github.io/drzl/drzl.config.schema.json";
|
|
676
|
+
function buildConfigJsonSchema() {
|
|
677
|
+
const generated = z.toJSONSchema(ConfigSchema, {
|
|
678
|
+
io: "input",
|
|
679
|
+
target: "draft-7"
|
|
680
|
+
});
|
|
681
|
+
const properties = {
|
|
682
|
+
// Declared so an editor suggests it and does not report the pointer a reader was told to
|
|
683
|
+
// add as an unknown key. `ConfigSchema` is not strict, so the CLI strips it and never sees it.
|
|
684
|
+
$schema: {
|
|
685
|
+
type: "string",
|
|
686
|
+
description: "Path or URL of this schema, for editor completion. Ignored by drzl."
|
|
687
|
+
},
|
|
688
|
+
...generated.properties
|
|
689
|
+
};
|
|
690
|
+
const { $schema, properties: _dropped, ...rest } = generated;
|
|
691
|
+
return {
|
|
692
|
+
$schema,
|
|
693
|
+
$id: CONFIG_SCHEMA_ID,
|
|
694
|
+
title: "DRZL configuration",
|
|
695
|
+
description: "Configuration for the drzl CLI. Also describes drzl.config.ts, which gets the same shape from the defineConfig export of @drzl/cli/config.",
|
|
696
|
+
...rest,
|
|
697
|
+
properties
|
|
698
|
+
};
|
|
699
|
+
}
|
|
700
|
+
var ROUTER_KINDS = /* @__PURE__ */ new Set(["orpc", "trpc", "hono", "express"]);
|
|
701
|
+
var INJECTION_KINDS = /* @__PURE__ */ new Set(["orpc", "trpc"]);
|
|
394
702
|
function trpcOutDir(g, cfg) {
|
|
395
703
|
return g.path ?? cfg.outDir;
|
|
396
704
|
}
|
|
705
|
+
function honoOutDir(g, cfg) {
|
|
706
|
+
return g.path ?? cfg.outDir;
|
|
707
|
+
}
|
|
708
|
+
function expressOutDir(g, cfg) {
|
|
709
|
+
return g.path ?? cfg.outDir;
|
|
710
|
+
}
|
|
711
|
+
function fastifyOutDir(g, cfg) {
|
|
712
|
+
return g.path ?? cfg.outDir;
|
|
713
|
+
}
|
|
714
|
+
function nestjsOutDir(g, cfg) {
|
|
715
|
+
return g.path ?? cfg.outDir;
|
|
716
|
+
}
|
|
717
|
+
function graphqlOutDir(g, cfg) {
|
|
718
|
+
return g.path ?? cfg.outDir;
|
|
719
|
+
}
|
|
397
720
|
function sharedSchemaNames(opts) {
|
|
398
721
|
const resolved = resolveAffix(opts);
|
|
399
722
|
return NAME_MODES.map((mode) => schemaName(mode, AFFIX_PROBE_TABLE, resolved));
|
|
@@ -405,8 +728,66 @@ function resolveConfig(cfg) {
|
|
|
405
728
|
importExtension: g.importExtension ?? cfg.importExtension
|
|
406
729
|
}));
|
|
407
730
|
for (const g of generators) {
|
|
731
|
+
if (g.kind === "fastify") {
|
|
732
|
+
if (g.databaseInjection?.enabled) {
|
|
733
|
+
warnings.push(
|
|
734
|
+
`drzl config: the "fastify" generator sets databaseInjection.enabled, which it does not support. Its handlers are stubs and never call a service, so nothing reads the injected handle. Reach your database from inside the handler bodies you fill in, or use the "trpc" or "orpc" generator, which do delegate to @drzl/generator-service.`
|
|
735
|
+
);
|
|
736
|
+
}
|
|
737
|
+
if (g.validation) {
|
|
738
|
+
warnings.push(
|
|
739
|
+
`drzl config: the "fastify" generator sets "validation", which it does not read. Its route schemas are JSON Schema produced by the same builder as the "json-schema" generator and inlined into the routes, so there is no library to choose and no shared schema module to import. Remove the block.`
|
|
740
|
+
);
|
|
741
|
+
}
|
|
742
|
+
continue;
|
|
743
|
+
}
|
|
744
|
+
if (g.kind === "nestjs") {
|
|
745
|
+
if (g.databaseInjection?.enabled) {
|
|
746
|
+
warnings.push(
|
|
747
|
+
`drzl config: the "nestjs" generator sets databaseInjection.enabled, which it does not support. It emits DTO classes with no handlers at all, so nothing reads the injected handle. Reach your database from the controllers you write around these DTOs, or use the "trpc" or "orpc" generator, which do delegate to @drzl/generator-service.`
|
|
748
|
+
);
|
|
749
|
+
}
|
|
750
|
+
if (g.includeRelations) {
|
|
751
|
+
warnings.push(
|
|
752
|
+
`drzl config: the "nestjs" generator sets includeRelations, which it does not read. Relation lookups are routes, and this generator emits DTO classes for your own controllers rather than routes. Remove the flag.`
|
|
753
|
+
);
|
|
754
|
+
}
|
|
755
|
+
if (g.validation?.useShared || g.validation?.importPath) {
|
|
756
|
+
warnings.push(
|
|
757
|
+
`drzl config: the "nestjs" generator sets validation.useShared or validation.importPath, which it does not read. Its DTO modules are self-contained: the class fields and the schema are generated from the same columns, and wrapping a schema another generator wrote would let the two drift. Only validation.library is read on this kind.`
|
|
758
|
+
);
|
|
759
|
+
}
|
|
760
|
+
if (g.validation?.schemaSuffix || g.validation?.affix) {
|
|
761
|
+
warnings.push(
|
|
762
|
+
`drzl config: the "nestjs" generator sets validation.schemaSuffix or validation.affix, which it does not read. Those options spell the names of shared schema modules, and this generator imports none. Only validation.library is read on this kind.`
|
|
763
|
+
);
|
|
764
|
+
}
|
|
765
|
+
continue;
|
|
766
|
+
}
|
|
767
|
+
if (g.kind === "graphql") {
|
|
768
|
+
if (g.databaseInjection?.enabled) {
|
|
769
|
+
warnings.push(
|
|
770
|
+
`drzl config: the "graphql" generator sets databaseInjection.enabled, which it does not support. It emits SDL and resolver stubs with no handlers at all, so nothing reads the injected handle. Reach your database from the resolvers you write in place of the stubs, or use the "trpc" or "orpc" generator, which do delegate to @drzl/generator-service.`
|
|
771
|
+
);
|
|
772
|
+
}
|
|
773
|
+
if (g.includeRelations) {
|
|
774
|
+
warnings.push(
|
|
775
|
+
`drzl config: the "graphql" generator sets includeRelations, which it does not read. Relation lookups are routes on the router generators, and relation fields on a GraphQL type are resolvers you write against your own data layer. Remove the flag.`
|
|
776
|
+
);
|
|
777
|
+
}
|
|
778
|
+
if (g.validation) {
|
|
779
|
+
warnings.push(
|
|
780
|
+
`drzl config: the "graphql" generator sets "validation", which it does not read. Its schema is GraphQL SDL, GraphQL's own type language, so there is no library to choose and no shared schema module to import. Remove the block.`
|
|
781
|
+
);
|
|
782
|
+
}
|
|
783
|
+
continue;
|
|
784
|
+
}
|
|
408
785
|
if (!ROUTER_KINDS.has(g.kind)) continue;
|
|
409
|
-
if (g.databaseInjection?.enabled) {
|
|
786
|
+
if (g.databaseInjection?.enabled && !INJECTION_KINDS.has(g.kind)) {
|
|
787
|
+
warnings.push(
|
|
788
|
+
`drzl config: the "${g.kind}" generator sets databaseInjection.enabled, which it does not support. Its handlers are stubs and never call a service, so nothing reads the injected handle. Reach your database from inside the handler bodies you fill in, or use the "trpc" or "orpc" generator, which do delegate to @drzl/generator-service.`
|
|
789
|
+
);
|
|
790
|
+
} else if (g.databaseInjection?.enabled) {
|
|
410
791
|
for (const s of generators.filter((x) => x.kind === "service")) {
|
|
411
792
|
if (!s.databaseInjection) {
|
|
412
793
|
s.databaseInjection = g.databaseInjection;
|
|
@@ -463,20 +844,58 @@ function resolveConfig(cfg) {
|
|
|
463
844
|
}
|
|
464
845
|
return { config: { ...cfg, generators }, warnings };
|
|
465
846
|
}
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
847
|
+
var configShape = null;
|
|
848
|
+
function configShapeForReading() {
|
|
849
|
+
return configShape ??= buildConfigJsonSchema();
|
|
850
|
+
}
|
|
851
|
+
function displayConfigPath(file, cwd = process.cwd()) {
|
|
852
|
+
const relative2 = path.relative(cwd, file);
|
|
853
|
+
return relative2 && !relative2.startsWith("..") ? relative2 : file;
|
|
854
|
+
}
|
|
855
|
+
function finalize(raw, file, onWarn) {
|
|
856
|
+
const parsed = ConfigSchema.safeParse(raw);
|
|
857
|
+
if (!parsed.success) {
|
|
858
|
+
throw new ConfigValidationError(
|
|
859
|
+
formatConfigProblems(
|
|
860
|
+
displayConfigPath(file),
|
|
861
|
+
parsed.error.issues,
|
|
862
|
+
raw,
|
|
863
|
+
configShapeForReading()
|
|
864
|
+
)
|
|
865
|
+
);
|
|
866
|
+
}
|
|
867
|
+
for (const w of unknownKeyWarnings(raw, configShapeForReading())) onWarn(w);
|
|
868
|
+
const { config, warnings } = resolveConfig(parsed.data);
|
|
869
|
+
for (const w of warnings) onWarn(w);
|
|
469
870
|
return config;
|
|
470
871
|
}
|
|
471
|
-
async function
|
|
872
|
+
async function importFreshConfigModule(p) {
|
|
472
873
|
const fsp = await import("fs/promises");
|
|
473
|
-
const
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
874
|
+
const ext = path.extname(p).toLowerCase();
|
|
875
|
+
if (ext === ".json") {
|
|
876
|
+
return JSON.parse(await fsp.readFile(p, "utf8"));
|
|
877
|
+
}
|
|
878
|
+
const { createJiti } = await import("jiti");
|
|
879
|
+
const stat = await fsp.stat(p);
|
|
880
|
+
const base = typeof __filename !== "undefined" ? __filename : path.join(process.cwd(), "index.js");
|
|
881
|
+
const jiti = createJiti(base, {
|
|
882
|
+
moduleCache: false,
|
|
883
|
+
// re-evaluate each time
|
|
884
|
+
fsCache: true,
|
|
885
|
+
// keep transform cache
|
|
886
|
+
cacheVersion: String(stat.mtimeMs),
|
|
887
|
+
// bump on edit
|
|
888
|
+
interopDefault: true,
|
|
889
|
+
tryNative: false
|
|
890
|
+
// <-- prevent native import of .ts
|
|
891
|
+
// debug: true,
|
|
892
|
+
});
|
|
893
|
+
const mod = await jiti.import(p);
|
|
894
|
+
return mod?.default ?? mod;
|
|
895
|
+
}
|
|
896
|
+
async function loadConfig(customPath, onWarn = (warning) => console.warn(warning)) {
|
|
897
|
+
const fsp = await import("fs/promises");
|
|
898
|
+
const candidates = customPath ? [customPath] : [...CONFIG_FILE_NAMES];
|
|
480
899
|
for (const c of candidates) {
|
|
481
900
|
const p = path.resolve(process.cwd(), c);
|
|
482
901
|
try {
|
|
@@ -484,38 +903,31 @@ async function loadConfig(customPath) {
|
|
|
484
903
|
} catch {
|
|
485
904
|
continue;
|
|
486
905
|
}
|
|
487
|
-
|
|
488
|
-
if (ext === ".json") {
|
|
489
|
-
const raw2 = JSON.parse(await fsp.readFile(p, "utf8"));
|
|
490
|
-
return finalize(raw2);
|
|
491
|
-
}
|
|
492
|
-
const { createJiti } = await import("jiti");
|
|
493
|
-
const stat = await fsp.stat(p);
|
|
494
|
-
const base = typeof __filename !== "undefined" ? __filename : path.join(process.cwd(), "index.js");
|
|
495
|
-
const jiti = createJiti(base, {
|
|
496
|
-
moduleCache: false,
|
|
497
|
-
// re-evaluate each time
|
|
498
|
-
fsCache: true,
|
|
499
|
-
// keep transform cache
|
|
500
|
-
cacheVersion: String(stat.mtimeMs),
|
|
501
|
-
// bump on edit
|
|
502
|
-
interopDefault: true,
|
|
503
|
-
tryNative: false
|
|
504
|
-
// <-- prevent native import of .ts
|
|
505
|
-
// debug: true,
|
|
506
|
-
});
|
|
507
|
-
const mod = await jiti.import(p);
|
|
508
|
-
const raw = mod?.default ?? mod;
|
|
509
|
-
return finalize(raw);
|
|
906
|
+
return finalize(await importFreshConfigModule(p), p, onWarn);
|
|
510
907
|
}
|
|
511
908
|
return null;
|
|
512
909
|
}
|
|
910
|
+
function configFromKinds(kinds, schema, onWarn = () => {
|
|
911
|
+
}) {
|
|
912
|
+
const parsed = ConfigSchema.parse({
|
|
913
|
+
...schema ? { schema } : {},
|
|
914
|
+
generators: kinds.map((kind) => ({ kind }))
|
|
915
|
+
});
|
|
916
|
+
const { config, warnings } = resolveConfig(parsed);
|
|
917
|
+
for (const w of warnings) onWarn(w);
|
|
918
|
+
return config;
|
|
919
|
+
}
|
|
513
920
|
function computeGeneratorOutputDirs(cfg, cwd = process.cwd()) {
|
|
514
921
|
const abs = (p) => path.resolve(cwd, p);
|
|
515
922
|
const dirs = /* @__PURE__ */ new Set();
|
|
516
923
|
dirs.add(abs(cfg.outDir));
|
|
517
924
|
for (const g of cfg.generators) {
|
|
518
925
|
if (g.kind === "trpc") dirs.add(abs(trpcOutDir(g, cfg)));
|
|
926
|
+
if (g.kind === "hono") dirs.add(abs(honoOutDir(g, cfg)));
|
|
927
|
+
if (g.kind === "express") dirs.add(abs(expressOutDir(g, cfg)));
|
|
928
|
+
if (g.kind === "fastify") dirs.add(abs(fastifyOutDir(g, cfg)));
|
|
929
|
+
if (g.kind === "nestjs") dirs.add(abs(nestjsOutDir(g, cfg)));
|
|
930
|
+
if (g.kind === "graphql") dirs.add(abs(graphqlOutDir(g, cfg)));
|
|
519
931
|
if (g.kind === "service") dirs.add(abs(g.path ?? "src/services"));
|
|
520
932
|
if (g.kind === "zod") dirs.add(abs(g.path ?? "src/validators/zod"));
|
|
521
933
|
if (g.kind === "valibot") dirs.add(abs(g.path ?? "src/validators/valibot"));
|
|
@@ -563,22 +975,24 @@ function tableFilterWarnings(tables, opts) {
|
|
|
563
975
|
...ambiguousPatternWarnings(opts.exclude ?? [], tables, "exclude")
|
|
564
976
|
];
|
|
565
977
|
}
|
|
566
|
-
function computeWatchTargets(cfg, cwd = process.cwd()) {
|
|
978
|
+
function computeWatchTargets(cfg, cwd = process.cwd(), source) {
|
|
567
979
|
const abs = (p) => path.resolve(cwd, p);
|
|
568
|
-
const
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
abs(
|
|
572
|
-
|
|
573
|
-
abs(
|
|
574
|
-
|
|
575
|
-
]);
|
|
980
|
+
const targets = new Set(CONFIG_FILE_NAMES.map(abs));
|
|
981
|
+
if (source) {
|
|
982
|
+
for (const d of source.watchDirs) targets.add(abs(d));
|
|
983
|
+
if (source.drizzleKitConfigPath) targets.add(abs(source.drizzleKitConfigPath));
|
|
984
|
+
} else if (cfg.schema) {
|
|
985
|
+
targets.add(path.dirname(abs(cfg.schema)));
|
|
986
|
+
}
|
|
576
987
|
for (const t of resolveTemplateDirsSync(cfg, cwd)) targets.add(t);
|
|
577
988
|
return [...targets];
|
|
578
989
|
}
|
|
579
990
|
|
|
580
991
|
export {
|
|
992
|
+
ConfigValidationError,
|
|
993
|
+
nearestKey,
|
|
581
994
|
matchesAny,
|
|
995
|
+
tableAliases,
|
|
582
996
|
matchesTable,
|
|
583
997
|
displayTableName,
|
|
584
998
|
addressableName,
|
|
@@ -587,18 +1001,30 @@ export {
|
|
|
587
1001
|
NamingSchema,
|
|
588
1002
|
AffixSchema,
|
|
589
1003
|
ImportExtensionSchema,
|
|
1004
|
+
GeneratorKindSchema,
|
|
1005
|
+
GENERATOR_KINDS,
|
|
590
1006
|
GeneratorSchema,
|
|
591
1007
|
ColumnRulesSchema,
|
|
592
1008
|
AnalyzerSchema,
|
|
593
1009
|
ConfigSchema,
|
|
594
1010
|
defineConfig,
|
|
1011
|
+
CONFIG_FILE_NAMES,
|
|
1012
|
+
CONFIG_SCHEMA_ID,
|
|
1013
|
+
buildConfigJsonSchema,
|
|
595
1014
|
trpcOutDir,
|
|
1015
|
+
honoOutDir,
|
|
1016
|
+
expressOutDir,
|
|
1017
|
+
fastifyOutDir,
|
|
1018
|
+
nestjsOutDir,
|
|
1019
|
+
graphqlOutDir,
|
|
596
1020
|
resolveConfig,
|
|
1021
|
+
importFreshConfigModule,
|
|
597
1022
|
loadConfig,
|
|
1023
|
+
configFromKinds,
|
|
598
1024
|
computeGeneratorOutputDirs,
|
|
599
1025
|
resolveTemplateDirsSync,
|
|
600
1026
|
filterTables,
|
|
601
1027
|
tableFilterWarnings,
|
|
602
1028
|
computeWatchTargets
|
|
603
1029
|
};
|
|
604
|
-
//# sourceMappingURL=chunk-
|
|
1030
|
+
//# sourceMappingURL=chunk-54E2IO7N.js.map
|