@drzl/cli 4.12.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.
@@ -45,7 +45,7 @@ var AffixSchema = z.object({
45
45
  }).strict();
46
46
  var ImportExtensionSchema = z.enum(IMPORT_EXTENSIONS);
47
47
  var GeneratorSchema = z.object({
48
- kind: z.enum(["orpc", "service", "zod", "valibot", "arktype", "typebox"]),
48
+ kind: z.enum(["orpc", "service", "zod", "valibot", "arktype", "typebox", "json-schema"]),
49
49
  /**
50
50
  * Overrides the top-level `importExtension` for this generator alone, for a project whose
51
51
  * generated directories are compiled by different tsconfigs.
@@ -83,6 +83,16 @@ var GeneratorSchema = z.object({
83
83
  engine: z.enum(["auto", "prettier", "biome"]).default("auto").optional(),
84
84
  configPath: z.string().optional()
85
85
  }).optional(),
86
+ /**
87
+ * Which spelling of JSON Schema the `json-schema` generator emits.
88
+ *
89
+ * OpenAPI 3.0 is not an older superset of the 2020-12 draft, it is a different dialect: a
90
+ * nullable type is `nullable: true` rather than a type array, and an exclusive bound is a
91
+ * boolean flag beside the bound rather than its own keyword. An unknown keyword is not an error
92
+ * in JSON Schema, it is ignored, so emitting the wrong dialect produces a document that
93
+ * validates and then accepts the values the constraints exist to reject.
94
+ */
95
+ target: z.enum(["draft-2020-12", "openapi-3.1", "openapi-3.0"]).optional(),
86
96
  // service generator specific options
87
97
  path: z.string().optional(),
88
98
  dataAccess: z.enum(["stub", "drizzle"]).default("stub").optional(),
@@ -281,6 +291,7 @@ function computeGeneratorOutputDirs(cfg, cwd = process.cwd()) {
281
291
  if (g.kind === "valibot") dirs.add(abs(g.path ?? "src/validators/valibot"));
282
292
  if (g.kind === "arktype") dirs.add(abs(g.path ?? "src/validators/arktype"));
283
293
  if (g.kind === "typebox") dirs.add(abs(g.path ?? "src/validators/typebox"));
294
+ if (g.kind === "json-schema") dirs.add(abs(g.path ?? "src/validators/json-schema"));
284
295
  }
285
296
  return [...dirs];
286
297
  }
@@ -348,4 +359,4 @@ export {
348
359
  filterTables,
349
360
  computeWatchTargets
350
361
  };
351
- //# sourceMappingURL=chunk-C44WWTLF.js.map
362
+ //# sourceMappingURL=chunk-ZYJ4I2I7.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/config.ts"],"sourcesContent":["import type { AffixOptions } from '@drzl/validation-core';\nimport {\n AFFIX_PROBE_TABLE,\n DEFAULT_IMPORT_EXTENSION,\n IMPORT_EXTENSIONS,\n NAME_MODES,\n resolveAffix,\n schemaName,\n validateAffix,\n} from '@drzl/validation-core';\nimport * as fs from 'node:fs';\nimport { createRequire } from 'node:module';\nimport * as path from 'node:path';\nimport { z } from 'zod';\n\nexport const NamingSchema = z\n .object({\n routerSuffix: z.string().default('Router'),\n procedureCase: z.enum(['camel', 'kebab', 'snake']).default('camel'),\n })\n .partial();\n\n/** One affix for every mode, or a per-mode map. Keys match drzl's internal mode names. */\nconst AffixValueSchema = z.union(\n [\n z.string(),\n z\n .object({\n insert: z.string().optional(),\n update: z.string().optional(),\n select: z.string().optional(),\n })\n .strict(),\n ],\n {\n error:\n 'Expected a string to use for every mode, or an object with any of the keys \"insert\", ' +\n '\"update\" and \"select\". Those keys are lowercase, matching the mode names drzl uses ' +\n 'everywhere else.',\n }\n);\n\nconst AffixPartSchema = z\n .object({\n prefix: AffixValueSchema.optional(),\n suffix: AffixValueSchema.optional(),\n })\n .strict();\n\nexport const AffixSchema = z\n .object({\n /**\n * `preserve` (default) keeps today's output: the Drizzle export name goes into the\n * identifier verbatim, so `export const users` yields `InsertusersSchema`. `pascal`\n * upper-camels it first, yielding `InsertUsersSchema`.\n */\n tableCase: z.enum(['preserve', 'pascal']).optional(),\n schema: AffixPartSchema.optional(),\n type: AffixPartSchema.optional(),\n })\n .strict();\n\n/**\n * How every relative specifier drzl invents spells its extension.\n *\n * The generated files land in the consumer's own source tree, so the consumer's\n * `moduleResolution` decides which forms resolve. `js` is the only one that resolves under\n * all of `bundler`, `node10`, `node16` and `nodenext` with no compiler flag, so it is the\n * default. See the `ImportExtension` docs in `@drzl/validation-core` for the measured grid.\n */\nexport const ImportExtensionSchema = z.enum(IMPORT_EXTENSIONS);\n\nexport const GeneratorSchema = z.object({\n kind: z.enum(['orpc', 'service', 'zod', 'valibot', 'arktype', 'typebox', 'json-schema']),\n /**\n * Overrides the top-level `importExtension` for this generator alone, for a project whose\n * generated directories are compiled by different tsconfigs.\n */\n importExtension: ImportExtensionSchema.optional(),\n template: z.string().optional(),\n includeRelations: z.boolean().optional(),\n /**\n * Type `json` and `jsonb` columns from the schema rather than leaving them wide.\n *\n * `.$type<T>()` is a compile-time cast, so no runtime-derived validator can see it and\n * `drizzle-orm/zod` types every json column as its generic `Json`. A generator can reference\n * `typeof <table>.$inferSelect['<column>']` instead, which is the declared type resolved by\n * TypeScript itself, so generics, unions and imported interfaces all work.\n *\n * Off by default because it makes the generated file import your schema module, as a\n * type-only import that disappears at build time.\n */\n // What a date column accepts. Documented on the zod generator and, until now, accepted by the\n // config parser and then dropped on the floor: the generators default it to 'input' themselves,\n // so setting it here changed nothing.\n coerceDates: z.enum(['input', 'all', 'none']).optional(),\n typedJson: z.boolean().optional(),\n // The wider form: every column's static type comes from Drizzle, not just the untyped ones.\n typedColumns: z.boolean().optional(),\n // Reproduce literal column defaults in the insert schema, so parsing fills them in.\n applyDefaults: z.boolean().optional(),\n naming: NamingSchema.optional(),\n outputHeader: z\n .object({\n enabled: z.boolean().default(true).optional(),\n text: z.string().optional(),\n })\n .optional(),\n format: z\n .object({\n enabled: z.boolean().default(true).optional(),\n engine: z.enum(['auto', 'prettier', 'biome']).default('auto').optional(),\n configPath: z.string().optional(),\n })\n .optional(),\n /**\n * Which spelling of JSON Schema the `json-schema` generator emits.\n *\n * OpenAPI 3.0 is not an older superset of the 2020-12 draft, it is a different dialect: a\n * nullable type is `nullable: true` rather than a type array, and an exclusive bound is a\n * boolean flag beside the bound rather than its own keyword. An unknown keyword is not an error\n * in JSON Schema, it is ignored, so emitting the wrong dialect produces a document that\n * validates and then accepts the values the constraints exist to reject.\n */\n target: z.enum(['draft-2020-12', 'openapi-3.1', 'openapi-3.0']).optional(),\n // service generator specific options\n path: z.string().optional(),\n dataAccess: z.enum(['stub', 'drizzle']).default('stub').optional(),\n dbImportPath: z.string().optional(),\n schemaImportPath: z.string().optional(),\n // zod/valibot/arktype generator specific options\n schemaSuffix: z.string().optional(),\n fileSuffix: z.string().optional(),\n /**\n * Prefixes, suffixes and table casing for generated identifiers (zod/valibot/arktype).\n * Omitting it reproduces the output of every previous release exactly.\n */\n affix: AffixSchema.optional(),\n // orpc validation sharing\n validation: z\n .object({\n useShared: z.boolean().default(false).optional(),\n library: z.enum(['zod', 'valibot', 'arktype']).default('zod').optional(),\n importPath: z.string().optional(),\n schemaSuffix: z.string().optional(),\n /**\n * How the validation generator named its exports. Usually left unset: the CLI copies\n * it from the sibling generator whose `kind` matches `library`.\n */\n affix: AffixSchema.optional(),\n })\n .optional(),\n // template options\n templateOptions: z.record(z.string(), z.any()).optional(),\n});\n\nexport const AnalyzerSchema = z.object({\n includeRelations: z.boolean().default(true),\n validateConstraints: z.boolean().default(true),\n includeHeuristicRelations: z.boolean().default(false),\n});\n\nexport const ConfigSchema = z\n .object({\n schema: z.string(),\n outDir: z.string().default('src/api'),\n /**\n * Which tables to generate for, matched against the database table name.\n *\n * There was no way to say this, and every generator loops over every table it finds, so\n * DRZL emitted unauthenticated CRUD over whatever shared the schema file. That is noise for\n * a migrations table and a genuine leak for an auth one: Better Auth puts `user`, `session`,\n * `account` and `verification` alongside your own tables, and `account` holds\n * `accessToken`, `refreshToken`, `idToken` and `password`.\n *\n * Deliberately name-based and explicit rather than detecting any particular library. Auth\n * table names are all renameable, so a built-in list would miss renamed tables and, worse,\n * silently skip an ordinary table that happened to be called `user`, which is usually the\n * application's main entity.\n *\n * `exclude` wins over `include`. Patterns support `*`, matching within a name.\n */\n include: z.array(z.string()).optional(),\n exclude: z.array(z.string()).optional(),\n /**\n * How every relative specifier drzl invents spells its extension, for every generator.\n * A generator may override it. Defaults to `js`, which is the only form that resolves\n * under every `moduleResolution` without a compiler flag.\n */\n importExtension: ImportExtensionSchema.default(DEFAULT_IMPORT_EXTENSION),\n analyzer: AnalyzerSchema.default({\n includeRelations: true,\n validateConstraints: true,\n includeHeuristicRelations: false,\n }),\n generators: z\n .array(GeneratorSchema)\n .min(1)\n .default([{ kind: 'orpc' } as any]),\n })\n // Reject an affix before anything is written, rather than emitting a file that cannot\n // compile. Only `affix` is inspected; the legacy flat `schemaSuffix` is left alone so\n // configs that parse today keep parsing.\n .superRefine((cfg, ctx) => {\n cfg.generators.forEach((g, i) => {\n const report = (base: (string | number)[], affix?: AffixOptions, schemaSuffix?: string) => {\n for (const issue of validateAffix(affix, schemaSuffix)) {\n ctx.addIssue({\n code: 'custom',\n path: ['generators', i, ...base, ...issue.path],\n message: issue.message,\n });\n }\n };\n report(['affix'], g.affix as AffixOptions | undefined, g.schemaSuffix);\n report(\n ['validation', 'affix'],\n g.validation?.affix as AffixOptions | undefined,\n g.validation?.schemaSuffix\n );\n });\n });\n\n// ✨ Separate input vs output types\nexport type DrzlConfigInput = z.input<typeof ConfigSchema>;\nexport type DrzlConfig = z.output<typeof ConfigSchema>;\n\nexport function defineConfig<T extends DrzlConfigInput>(cfg: T): T {\n return cfg;\n}\n\ntype GeneratorConfig = DrzlConfig['generators'][number];\n\nfunction sharedSchemaNames(opts: { affix?: AffixOptions; schemaSuffix?: string }): string[] {\n const resolved = resolveAffix(opts);\n return NAME_MODES.map((mode) => schemaName(mode, AFFIX_PROBE_TABLE, resolved));\n}\n\n/**\n * Fill in cross-generator defaults and refuse configs whose generators would disagree.\n *\n * An oRPC router that imports shared schemas has to spell the exact names the validation\n * generator exported. Both sides used to be configured independently, so they could silently\n * drift into a router that does not compile. When an oRPC generator uses shared validation\n * and exactly one sibling generator produces that library, its `affix` is copied across.\n *\n * Deliberately conservative about the pre-existing flat `schemaSuffix`: a disagreement there\n * is only reported, never repaired, because repairing it would change the bytes an existing\n * config emits.\n *\n * `importExtension` is pushed down here too. A consumer compiles the whole generated tree\n * with one tsconfig, so the setting that has to hold is the same for every generator, and\n * every call site downstream can then read it off the generator without knowing about the\n * top-level default.\n */\nexport function resolveConfig(cfg: DrzlConfig): { config: DrzlConfig; warnings: string[] } {\n const warnings: string[] = [];\n const generators: GeneratorConfig[] = cfg.generators.map((g) => ({\n ...g,\n importExtension: g.importExtension ?? cfg.importExtension,\n }));\n\n for (const g of generators) {\n if (g.kind !== 'orpc') continue;\n const v = g.validation;\n if (!v?.useShared) continue;\n\n const library = v.library ?? 'zod';\n const siblings = generators.filter((s) => s.kind === library);\n // Zero siblings means the user points at a barrel drzl does not generate; more than one\n // means there is no single source of truth. Either way, leave the config alone.\n if (siblings.length !== 1) continue;\n const sibling = siblings[0];\n\n const theirs = sharedSchemaNames({\n affix: sibling.affix as AffixOptions | undefined,\n schemaSuffix: sibling.schemaSuffix,\n });\n\n if (!v.affix) {\n if (sibling.affix) {\n // Bake the sibling's fully resolved naming in, so its own schemaSuffix fallback\n // travels with it and cannot be re-interpreted on the oRPC side.\n g.validation = {\n ...v,\n affix: resolveAffix({\n affix: sibling.affix as AffixOptions,\n schemaSuffix: sibling.schemaSuffix,\n }),\n };\n continue;\n }\n const mine = sharedSchemaNames({ schemaSuffix: v.schemaSuffix });\n if (mine.join(',') !== theirs.join(',')) {\n warnings.push(\n `drzl config: the \"orpc\" generator's validation.schemaSuffix ` +\n `(${JSON.stringify(v.schemaSuffix ?? 'Schema')}) does not match the \"${library}\" ` +\n `generator's schemaSuffix (${JSON.stringify(sibling.schemaSuffix ?? 'Schema')}). ` +\n `The router will import ${mine.join(', ')} but the \"${library}\" generator exports ` +\n `${theirs.join(', ')}, so the generated router will not compile. Set both to the ` +\n `same value, or move to \"affix\", which is inherited automatically.`\n );\n }\n continue;\n }\n\n const mine = sharedSchemaNames({\n affix: v.affix as AffixOptions,\n schemaSuffix: v.schemaSuffix,\n });\n if (mine.join(',') !== theirs.join(',')) {\n throw new Error(\n `drzl config: the \"orpc\" generator imports shared ${library} schemas, but its ` +\n `validation.affix disagrees with the \"${library}\" generator's own naming. The router ` +\n `would import ${mine.join(', ')} while the \"${library}\" generator exports ` +\n `${theirs.join(', ')}. Make them match, or drop validation.affix and let it be ` +\n `inherited from the \"${library}\" generator.`\n );\n }\n }\n\n return { config: { ...cfg, generators }, warnings };\n}\n\n/**\n * Parse, then resolve cross-generator defaults. Both `generate` and `watch` go through\n * loadConfig, so putting the resolution here is what keeps the two duplicated generator\n * dispatch blocks in cli.ts from needing the logic twice.\n */\nfunction finalize(raw: unknown): DrzlConfig {\n const { config, warnings } = resolveConfig(ConfigSchema.parse(raw));\n for (const w of warnings) console.warn(w);\n return config;\n}\n\nexport async function loadConfig(customPath?: string): Promise<DrzlConfig | null> {\n const fsp = await import('node:fs/promises');\n\n const candidates = customPath\n ? [customPath]\n : [\n 'drzl.config.ts',\n 'drzl.config.mjs',\n 'drzl.config.js',\n 'drzl.config.cjs',\n 'drzl.config.json',\n ];\n\n for (const c of candidates) {\n const p = path.resolve(process.cwd(), c);\n try {\n await fsp.access(p);\n } catch {\n continue;\n }\n\n const ext = path.extname(p).toLowerCase();\n\n // JSON: read directly\n if (ext === '.json') {\n const raw = JSON.parse(await fsp.readFile(p, 'utf8'));\n return finalize(raw);\n }\n\n // Everything else (TS/JS/MJS/CJS) -> Jiti with cache-busting\n const { createJiti } = await import('jiti');\n const stat = await fsp.stat(p);\n\n // Passing __filename is safe in CJS; fallback to cwd if not defined.\n const base =\n typeof __filename !== 'undefined' ? __filename : path.join(process.cwd(), 'index.js');\n\n const jiti = createJiti(base, {\n moduleCache: false, // re-evaluate each time\n fsCache: true, // keep transform cache\n cacheVersion: String(stat.mtimeMs), // bump on edit\n interopDefault: true,\n tryNative: false, // <-- prevent native import of .ts\n // debug: true,\n }) as any;\n\n const mod = await jiti.import(p);\n const raw = mod?.default ?? mod;\n return finalize(raw);\n }\n\n return null;\n}\n\n/** Absolute output dirs for all generators (to ignore in watcher). */\nexport function computeGeneratorOutputDirs(cfg: DrzlConfig, cwd = process.cwd()): string[] {\n const abs = (p: string) => path.resolve(cwd, p);\n const dirs = new Set<string>();\n dirs.add(abs(cfg.outDir)); // orpc\n for (const g of cfg.generators) {\n if (g.kind === 'service') dirs.add(abs(g.path ?? 'src/services'));\n if (g.kind === 'zod') dirs.add(abs(g.path ?? 'src/validators/zod'));\n if (g.kind === 'valibot') dirs.add(abs(g.path ?? 'src/validators/valibot'));\n if (g.kind === 'arktype') dirs.add(abs(g.path ?? 'src/validators/arktype'));\n if (g.kind === 'typebox') dirs.add(abs(g.path ?? 'src/validators/typebox'));\n if (g.kind === 'json-schema') dirs.add(abs(g.path ?? 'src/validators/json-schema'));\n }\n return [...dirs];\n}\n\n/** Resolve custom template directories (local path or installed package). */\nexport function resolveTemplateDirsSync(cfg: DrzlConfig, cwd = process.cwd()): string[] {\n const results: string[] = [];\n const req = createRequire(\n typeof __filename !== 'undefined' ? __filename : path.join(process.cwd(), 'index.js')\n );\n\n for (const g of cfg.generators) {\n const t = g.template;\n if (!t || t === 'standard' || t === 'minimal') continue;\n\n // Try package resolution relative to cwd\n let pkgDir: string | null = null;\n try {\n const pkg = req.resolve(`${t}/package.json`, { paths: [cwd] as any });\n pkgDir = path.dirname(pkg);\n } catch {}\n\n if (pkgDir) {\n results.push(pkgDir);\n continue;\n }\n\n // Local path-like template\n if (/[./\\\\]/.test(t)) {\n const abs = path.resolve(cwd, t);\n if (fs.existsSync(abs)) results.push(abs);\n }\n }\n\n return Array.from(new Set(results));\n}\n\n/** Build watch targets (exclude output dirs; watcher will ignore those). */\n/**\n * Narrow an analysis's tables to the ones the config asked for.\n *\n * Matching is on the database table name, anchored, with `*` as the only metacharacter. Anchored\n * matters: `user` must not also drop `users`, and a substring match would. `exclude` is applied\n * after `include`, so the safer direction wins when both name the same table.\n */\nexport function filterTables<T extends { name: string }>(\n tables: T[],\n opts: { include?: string[]; exclude?: string[] }\n): T[] {\n const toRegExp = (pattern: string) =>\n new RegExp(\n '^' +\n pattern\n .split('*')\n .map((part) => part.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&'))\n .join('.*') +\n '$'\n );\n\n const matches = (patterns: string[], name: string) =>\n patterns.some((p) => toRegExp(p).test(name));\n\n let out = tables;\n if (opts.include?.length) out = out.filter((t) => matches(opts.include!, t.name));\n if (opts.exclude?.length) out = out.filter((t) => !matches(opts.exclude!, t.name));\n return out;\n}\n\nexport function computeWatchTargets(cfg: DrzlConfig, cwd = process.cwd()): string[] {\n const abs = (p: string) => path.resolve(cwd, p);\n const schemaAbs = abs(cfg.schema);\n // The schema's directory, not a glob under it. Chokidar removed glob support in v4 and treats\n // `<dir>/**/*.{ts,tsx,js}` as a literal path, so it watched a directory named `**` that does\n // not exist: no event ever fired and `drzl watch` did its initial build and then sat inert.\n // A directory is watched recursively by chokidar itself, and the extension filtering that the\n // glob was doing now happens on the event instead.\n const targets = new Set<string>([\n path.dirname(schemaAbs),\n abs('drzl.config.ts'),\n abs('drzl.config.js'),\n abs('drzl.config.mjs'),\n abs('drzl.config.cjs'),\n ]);\n for (const t of resolveTemplateDirsSync(cfg, cwd)) targets.add(t);\n return [...targets];\n}\n"],"mappings":"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","names":["mine","raw"]}
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");
@@ -33,6 +316,29 @@ var import_commander = require("commander");
33
316
  var path4 = __toESM(require("path"), 1);
34
317
  var import_ora = __toESM(require("ora"), 1);
35
318
 
319
+ // src/validation-options.ts
320
+ function validationOptions(g, cfg, outDir, caps = {}) {
321
+ return {
322
+ outDir,
323
+ outputHeader: g.outputHeader,
324
+ format: g.format,
325
+ schemaSuffix: g.schemaSuffix,
326
+ fileSuffix: g.fileSuffix,
327
+ importExtension: g.importExtension,
328
+ affix: g.affix,
329
+ coerceDates: g.coerceDates,
330
+ applyDefaults: g.applyDefaults,
331
+ // Only where the generator can act on them, so an unsupported option is absent rather than
332
+ // present and ignored.
333
+ ...caps.schemaTypes ? {
334
+ // Needed by both: the reference is resolved relative to the emitted file.
335
+ schemaPath: cfg.schema,
336
+ typedJson: g.typedJson,
337
+ typedColumns: g.typedColumns
338
+ } : {}
339
+ };
340
+ }
341
+
36
342
  // src/config.ts
37
343
  var import_validation_core = require("@drzl/validation-core");
38
344
  var fs = __toESM(require("fs"), 1);
@@ -72,7 +378,7 @@ var AffixSchema = import_zod.z.object({
72
378
  }).strict();
73
379
  var ImportExtensionSchema = import_zod.z.enum(import_validation_core.IMPORT_EXTENSIONS);
74
380
  var GeneratorSchema = import_zod.z.object({
75
- kind: import_zod.z.enum(["orpc", "service", "zod", "valibot", "arktype", "typebox"]),
381
+ kind: import_zod.z.enum(["orpc", "service", "zod", "valibot", "arktype", "typebox", "json-schema"]),
76
382
  /**
77
383
  * Overrides the top-level `importExtension` for this generator alone, for a project whose
78
384
  * generated directories are compiled by different tsconfigs.
@@ -110,6 +416,16 @@ var GeneratorSchema = import_zod.z.object({
110
416
  engine: import_zod.z.enum(["auto", "prettier", "biome"]).default("auto").optional(),
111
417
  configPath: import_zod.z.string().optional()
112
418
  }).optional(),
419
+ /**
420
+ * Which spelling of JSON Schema the `json-schema` generator emits.
421
+ *
422
+ * OpenAPI 3.0 is not an older superset of the 2020-12 draft, it is a different dialect: a
423
+ * nullable type is `nullable: true` rather than a type array, and an exclusive bound is a
424
+ * boolean flag beside the bound rather than its own keyword. An unknown keyword is not an error
425
+ * in JSON Schema, it is ignored, so emitting the wrong dialect produces a document that
426
+ * validates and then accepts the values the constraints exist to reject.
427
+ */
428
+ target: import_zod.z.enum(["draft-2020-12", "openapi-3.1", "openapi-3.0"]).optional(),
113
429
  // service generator specific options
114
430
  path: import_zod.z.string().optional(),
115
431
  dataAccess: import_zod.z.enum(["stub", "drizzle"]).default("stub").optional(),
@@ -305,6 +621,7 @@ function computeGeneratorOutputDirs(cfg, cwd = process.cwd()) {
305
621
  if (g.kind === "valibot") dirs.add(abs(g.path ?? "src/validators/valibot"));
306
622
  if (g.kind === "arktype") dirs.add(abs(g.path ?? "src/validators/arktype"));
307
623
  if (g.kind === "typebox") dirs.add(abs(g.path ?? "src/validators/typebox"));
624
+ if (g.kind === "json-schema") dirs.add(abs(g.path ?? "src/validators/json-schema"));
308
625
  }
309
626
  return [...dirs];
310
627
  }
@@ -544,6 +861,7 @@ program.command("generate").description("Run configured generators (drzl.config.
544
861
  });
545
862
  analysis.tables = filterTables(analysis.tables, cfg);
546
863
  spinner.succeed(`Analysis complete in ${Date.now() - t0}ms`);
864
+ reportWideColumns(analysis.issues);
547
865
  const driftDirs = computeGeneratorOutputDirs(cfg);
548
866
  const driftBefore = opts.check ? await snapshotAll(driftDirs) : null;
549
867
  const progress = new import_cli_progress.default.SingleBar(
@@ -603,22 +921,9 @@ program.command("generate").description("Run configured generators (drzl.config.
603
921
  const { ZodGenerator } = await import("@drzl/generator-zod");
604
922
  const gen = new ZodGenerator(analysis);
605
923
  const target = g.path ?? "src/validators/zod";
606
- const files = await gen.generate({
607
- outDir: target,
608
- outputHeader: g.outputHeader,
609
- format: g.format,
610
- schemaSuffix: g.schemaSuffix,
611
- fileSuffix: g.fileSuffix,
612
- importExtension: g.importExtension,
613
- affix: g.affix,
614
- // Needed by typedJson, which imports the schema back to reference the type
615
- // Drizzle inferred for a json column.
616
- schemaPath: cfg.schema,
617
- typedJson: g.typedJson,
618
- typedColumns: g.typedColumns,
619
- applyDefaults: g.applyDefaults,
620
- coerceDates: g.coerceDates
621
- });
924
+ const files = await gen.generate(
925
+ validationOptions(g, cfg, target, { schemaTypes: true })
926
+ );
622
927
  progress.stop();
623
928
  (0, import_ora.default)().succeed(import_chalk2.default.green(`Generated (zod): ${files.length} files`));
624
929
  files.forEach((f) => console.log(" -", import_chalk2.default.cyan(f)));
@@ -636,20 +941,9 @@ program.command("generate").description("Run configured generators (drzl.config.
636
941
  const { ValibotGenerator } = await import("@drzl/generator-valibot");
637
942
  const gen = new ValibotGenerator(analysis);
638
943
  const target = g.path ?? "src/validators/valibot";
639
- const files = await gen.generate({
640
- outDir: target,
641
- outputHeader: g.outputHeader,
642
- format: g.format,
643
- schemaSuffix: g.schemaSuffix,
644
- fileSuffix: g.fileSuffix,
645
- importExtension: g.importExtension,
646
- affix: g.affix,
647
- applyDefaults: g.applyDefaults,
648
- coerceDates: g.coerceDates,
649
- // Needed by typedColumns, which imports the schema back to reference the type
650
- schemaPath: cfg.schema,
651
- typedColumns: g.typedColumns
652
- });
944
+ const files = await gen.generate(
945
+ validationOptions(g, cfg, target, { schemaTypes: true })
946
+ );
653
947
  progress.stop();
654
948
  (0, import_ora.default)().succeed(import_chalk2.default.green(`Generated (valibot): ${files.length} files`));
655
949
  files.forEach((f) => console.log(" -", import_chalk2.default.cyan(f)));
@@ -667,17 +961,9 @@ program.command("generate").description("Run configured generators (drzl.config.
667
961
  const { ArkTypeGenerator } = await import("@drzl/generator-arktype");
668
962
  const gen = new ArkTypeGenerator(analysis);
669
963
  const target = g.path ?? "src/validators/arktype";
670
- const files = await gen.generate({
671
- outDir: target,
672
- outputHeader: g.outputHeader,
673
- format: g.format,
674
- schemaSuffix: g.schemaSuffix,
675
- fileSuffix: g.fileSuffix,
676
- importExtension: g.importExtension,
677
- affix: g.affix,
678
- applyDefaults: g.applyDefaults,
679
- coerceDates: g.coerceDates
680
- });
964
+ const files = await gen.generate(
965
+ validationOptions(g, cfg, target, { schemaTypes: false })
966
+ );
681
967
  progress.stop();
682
968
  (0, import_ora.default)().succeed(import_chalk2.default.green(`Generated (arktype): ${files.length} files`));
683
969
  files.forEach((f) => console.log(" -", import_chalk2.default.cyan(f)));
@@ -690,33 +976,47 @@ program.command("generate").description("Run configured generators (drzl.config.
690
976
  console.error(import_chalk2.default.gray("Error details:"), e?.message ?? e);
691
977
  process.exit(1);
692
978
  }
979
+ } else if (g.kind === "json-schema") {
980
+ try {
981
+ const { JsonSchemaGenerator: JsonSchemaGenerator2 } = await Promise.resolve().then(() => (init_dist(), dist_exports));
982
+ const gen = new JsonSchemaGenerator2(analysis);
983
+ const target = g.path ?? "src/validators/json-schema";
984
+ const files = await gen.generate({
985
+ // JSON Schema is data, so nothing here references a type from the schema module.
986
+ ...validationOptions(g, cfg, target, { schemaTypes: false }),
987
+ target: g.target
988
+ });
989
+ progress.stop();
990
+ (0, import_ora.default)().succeed(import_chalk2.default.green(`Generated (json-schema): ${files.length} files`));
991
+ files.forEach((f) => console.log(" -", import_chalk2.default.cyan(f)));
992
+ } catch (e) {
993
+ progress.stop();
994
+ console.error(
995
+ import_chalk2.default.red("JSON Schema generator missing."),
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
+ ""
1001
+ );
1002
+ console.error(import_chalk2.default.gray("Error details:"), e?.message ?? e);
1003
+ process.exit(1);
1004
+ }
693
1005
  } else if (g.kind === "typebox") {
694
1006
  try {
695
1007
  const { TypeBoxGenerator } = await import("@drzl/generator-typebox");
696
1008
  const gen = new TypeBoxGenerator(analysis);
697
1009
  const target = g.path ?? "src/validators/typebox";
698
- const files = await gen.generate({
699
- outDir: target,
700
- outputHeader: g.outputHeader,
701
- format: g.format,
702
- schemaSuffix: g.schemaSuffix,
703
- fileSuffix: g.fileSuffix,
704
- importExtension: g.importExtension,
705
- affix: g.affix,
706
- coerceDates: g.coerceDates,
707
- // Needed by typedJson, which imports the schema back to reference the type
708
- schemaPath: cfg.schema,
709
- typedJson: g.typedJson,
710
- typedColumns: g.typedColumns,
711
- applyDefaults: g.applyDefaults
712
- });
1010
+ const files = await gen.generate(
1011
+ validationOptions(g, cfg, target, { schemaTypes: true })
1012
+ );
713
1013
  progress.stop();
714
1014
  (0, import_ora.default)().succeed(import_chalk2.default.green(`Generated (typebox): ${files.length} files`));
715
1015
  files.forEach((f) => console.log(" -", import_chalk2.default.cyan(f)));
716
1016
  } catch (e) {
717
1017
  progress.stop();
718
1018
  console.error(
719
- import_chalk2.default.red("ArkType generator missing."),
1019
+ import_chalk2.default.red("TypeBox generator missing."),
720
1020
  import_chalk2.default.yellow("\nInstall with: npm install @drzl/generator-typebox")
721
1021
  );
722
1022
  console.error(import_chalk2.default.gray("Error details:"), e?.message ?? e);
@@ -863,6 +1163,7 @@ program.command("watch").description("Watch schema and regenerate on changes").o
863
1163
  includeHeuristicRelations: cfg.analyzer.includeHeuristicRelations
864
1164
  });
865
1165
  analysis.tables = filterTables(analysis.tables, cfg);
1166
+ if (!opts.json) reportWideColumns(analysis.issues);
866
1167
  if (opts.pipeline === "analyze") {
867
1168
  if (opts.json) {
868
1169
  console.log(
@@ -1076,5 +1377,17 @@ program.command("init").description("Scaffold a drzl.config.ts").option("-y, --y
1076
1377
  process.exit(1);
1077
1378
  }
1078
1379
  });
1380
+ function reportWideColumns(issues) {
1381
+ const wide = issues.filter((i) => i.code === "DRZL_ANL_UNKNOWN_COLUMN");
1382
+ if (!wide.length) return;
1383
+ console.warn(
1384
+ import_chalk2.default.yellow(`
1385
+ ${wide.length} column${wide.length === 1 ? "" : "s"} could not be typed:`)
1386
+ );
1387
+ for (const i of wide.slice(0, 10)) console.warn(import_chalk2.default.gray(` - ${i.message}`));
1388
+ if (wide.length > 10) console.warn(import_chalk2.default.gray(` ... and ${wide.length - 10} more`));
1389
+ const hints = [...new Set(wide.map((i) => i.hint).filter(Boolean))];
1390
+ for (const h of hints) console.warn(import_chalk2.default.gray(` ${h}`));
1391
+ }
1079
1392
  program.parseAsync(process.argv);
1080
1393
  //# sourceMappingURL=cli.cjs.map