@drzl/cli 4.11.0 → 4.13.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.
@@ -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
@@ -33,6 +33,29 @@ var import_commander = require("commander");
33
33
  var path4 = __toESM(require("path"), 1);
34
34
  var import_ora = __toESM(require("ora"), 1);
35
35
 
36
+ // src/validation-options.ts
37
+ function validationOptions(g, cfg, outDir, caps = {}) {
38
+ return {
39
+ outDir,
40
+ outputHeader: g.outputHeader,
41
+ format: g.format,
42
+ schemaSuffix: g.schemaSuffix,
43
+ fileSuffix: g.fileSuffix,
44
+ importExtension: g.importExtension,
45
+ affix: g.affix,
46
+ coerceDates: g.coerceDates,
47
+ applyDefaults: g.applyDefaults,
48
+ // Only where the generator can act on them, so an unsupported option is absent rather than
49
+ // present and ignored.
50
+ ...caps.schemaTypes ? {
51
+ // Needed by both: the reference is resolved relative to the emitted file.
52
+ schemaPath: cfg.schema,
53
+ typedJson: g.typedJson,
54
+ typedColumns: g.typedColumns
55
+ } : {}
56
+ };
57
+ }
58
+
36
59
  // src/config.ts
37
60
  var import_validation_core = require("@drzl/validation-core");
38
61
  var fs = __toESM(require("fs"), 1);
@@ -72,7 +95,7 @@ var AffixSchema = import_zod.z.object({
72
95
  }).strict();
73
96
  var ImportExtensionSchema = import_zod.z.enum(import_validation_core.IMPORT_EXTENSIONS);
74
97
  var GeneratorSchema = import_zod.z.object({
75
- kind: import_zod.z.enum(["orpc", "service", "zod", "valibot", "arktype", "typebox"]),
98
+ kind: import_zod.z.enum(["orpc", "service", "zod", "valibot", "arktype", "typebox", "json-schema"]),
76
99
  /**
77
100
  * Overrides the top-level `importExtension` for this generator alone, for a project whose
78
101
  * generated directories are compiled by different tsconfigs.
@@ -110,6 +133,16 @@ var GeneratorSchema = import_zod.z.object({
110
133
  engine: import_zod.z.enum(["auto", "prettier", "biome"]).default("auto").optional(),
111
134
  configPath: import_zod.z.string().optional()
112
135
  }).optional(),
136
+ /**
137
+ * Which spelling of JSON Schema the `json-schema` generator emits.
138
+ *
139
+ * OpenAPI 3.0 is not an older superset of the 2020-12 draft, it is a different dialect: a
140
+ * nullable type is `nullable: true` rather than a type array, and an exclusive bound is a
141
+ * boolean flag beside the bound rather than its own keyword. An unknown keyword is not an error
142
+ * in JSON Schema, it is ignored, so emitting the wrong dialect produces a document that
143
+ * validates and then accepts the values the constraints exist to reject.
144
+ */
145
+ target: import_zod.z.enum(["draft-2020-12", "openapi-3.1", "openapi-3.0"]).optional(),
113
146
  // service generator specific options
114
147
  path: import_zod.z.string().optional(),
115
148
  dataAccess: import_zod.z.enum(["stub", "drizzle"]).default("stub").optional(),
@@ -305,6 +338,7 @@ function computeGeneratorOutputDirs(cfg, cwd = process.cwd()) {
305
338
  if (g.kind === "valibot") dirs.add(abs(g.path ?? "src/validators/valibot"));
306
339
  if (g.kind === "arktype") dirs.add(abs(g.path ?? "src/validators/arktype"));
307
340
  if (g.kind === "typebox") dirs.add(abs(g.path ?? "src/validators/typebox"));
341
+ if (g.kind === "json-schema") dirs.add(abs(g.path ?? "src/validators/json-schema"));
308
342
  }
309
343
  return [...dirs];
310
344
  }
@@ -544,6 +578,7 @@ program.command("generate").description("Run configured generators (drzl.config.
544
578
  });
545
579
  analysis.tables = filterTables(analysis.tables, cfg);
546
580
  spinner.succeed(`Analysis complete in ${Date.now() - t0}ms`);
581
+ reportWideColumns(analysis.issues);
547
582
  const driftDirs = computeGeneratorOutputDirs(cfg);
548
583
  const driftBefore = opts.check ? await snapshotAll(driftDirs) : null;
549
584
  const progress = new import_cli_progress.default.SingleBar(
@@ -603,22 +638,9 @@ program.command("generate").description("Run configured generators (drzl.config.
603
638
  const { ZodGenerator } = await import("@drzl/generator-zod");
604
639
  const gen = new ZodGenerator(analysis);
605
640
  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
- });
641
+ const files = await gen.generate(
642
+ validationOptions(g, cfg, target, { schemaTypes: true })
643
+ );
622
644
  progress.stop();
623
645
  (0, import_ora.default)().succeed(import_chalk2.default.green(`Generated (zod): ${files.length} files`));
624
646
  files.forEach((f) => console.log(" -", import_chalk2.default.cyan(f)));
@@ -636,17 +658,9 @@ program.command("generate").description("Run configured generators (drzl.config.
636
658
  const { ValibotGenerator } = await import("@drzl/generator-valibot");
637
659
  const gen = new ValibotGenerator(analysis);
638
660
  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
- });
661
+ const files = await gen.generate(
662
+ validationOptions(g, cfg, target, { schemaTypes: true })
663
+ );
650
664
  progress.stop();
651
665
  (0, import_ora.default)().succeed(import_chalk2.default.green(`Generated (valibot): ${files.length} files`));
652
666
  files.forEach((f) => console.log(" -", import_chalk2.default.cyan(f)));
@@ -664,17 +678,9 @@ program.command("generate").description("Run configured generators (drzl.config.
664
678
  const { ArkTypeGenerator } = await import("@drzl/generator-arktype");
665
679
  const gen = new ArkTypeGenerator(analysis);
666
680
  const target = g.path ?? "src/validators/arktype";
667
- const files = await gen.generate({
668
- outDir: target,
669
- outputHeader: g.outputHeader,
670
- format: g.format,
671
- schemaSuffix: g.schemaSuffix,
672
- fileSuffix: g.fileSuffix,
673
- importExtension: g.importExtension,
674
- affix: g.affix,
675
- applyDefaults: g.applyDefaults,
676
- coerceDates: g.coerceDates
677
- });
681
+ const files = await gen.generate(
682
+ validationOptions(g, cfg, target, { schemaTypes: false })
683
+ );
678
684
  progress.stop();
679
685
  (0, import_ora.default)().succeed(import_chalk2.default.green(`Generated (arktype): ${files.length} files`));
680
686
  files.forEach((f) => console.log(" -", import_chalk2.default.cyan(f)));
@@ -687,33 +693,43 @@ program.command("generate").description("Run configured generators (drzl.config.
687
693
  console.error(import_chalk2.default.gray("Error details:"), e?.message ?? e);
688
694
  process.exit(1);
689
695
  }
696
+ } else if (g.kind === "json-schema") {
697
+ try {
698
+ const { JsonSchemaGenerator } = await import("@drzl/generator-json-schema");
699
+ const gen = new JsonSchemaGenerator(analysis);
700
+ const target = g.path ?? "src/validators/json-schema";
701
+ const files = await gen.generate({
702
+ // JSON Schema is data, so nothing here references a type from the schema module.
703
+ ...validationOptions(g, cfg, target, { schemaTypes: false }),
704
+ target: g.target
705
+ });
706
+ progress.stop();
707
+ (0, import_ora.default)().succeed(import_chalk2.default.green(`Generated (json-schema): ${files.length} files`));
708
+ files.forEach((f) => console.log(" -", import_chalk2.default.cyan(f)));
709
+ } catch (e) {
710
+ progress.stop();
711
+ console.error(
712
+ import_chalk2.default.red("JSON Schema generator missing."),
713
+ import_chalk2.default.yellow("\nInstall with: npm install @drzl/generator-json-schema")
714
+ );
715
+ console.error(import_chalk2.default.gray("Error details:"), e?.message ?? e);
716
+ process.exit(1);
717
+ }
690
718
  } else if (g.kind === "typebox") {
691
719
  try {
692
720
  const { TypeBoxGenerator } = await import("@drzl/generator-typebox");
693
721
  const gen = new TypeBoxGenerator(analysis);
694
722
  const target = g.path ?? "src/validators/typebox";
695
- const files = await gen.generate({
696
- outDir: target,
697
- outputHeader: g.outputHeader,
698
- format: g.format,
699
- schemaSuffix: g.schemaSuffix,
700
- fileSuffix: g.fileSuffix,
701
- importExtension: g.importExtension,
702
- affix: g.affix,
703
- coerceDates: g.coerceDates,
704
- // Needed by typedJson, which imports the schema back to reference the type
705
- schemaPath: cfg.schema,
706
- typedJson: g.typedJson,
707
- typedColumns: g.typedColumns,
708
- applyDefaults: g.applyDefaults
709
- });
723
+ const files = await gen.generate(
724
+ validationOptions(g, cfg, target, { schemaTypes: true })
725
+ );
710
726
  progress.stop();
711
727
  (0, import_ora.default)().succeed(import_chalk2.default.green(`Generated (typebox): ${files.length} files`));
712
728
  files.forEach((f) => console.log(" -", import_chalk2.default.cyan(f)));
713
729
  } catch (e) {
714
730
  progress.stop();
715
731
  console.error(
716
- import_chalk2.default.red("ArkType generator missing."),
732
+ import_chalk2.default.red("TypeBox generator missing."),
717
733
  import_chalk2.default.yellow("\nInstall with: npm install @drzl/generator-typebox")
718
734
  );
719
735
  console.error(import_chalk2.default.gray("Error details:"), e?.message ?? e);
@@ -860,6 +876,7 @@ program.command("watch").description("Watch schema and regenerate on changes").o
860
876
  includeHeuristicRelations: cfg.analyzer.includeHeuristicRelations
861
877
  });
862
878
  analysis.tables = filterTables(analysis.tables, cfg);
879
+ if (!opts.json) reportWideColumns(analysis.issues);
863
880
  if (opts.pipeline === "analyze") {
864
881
  if (opts.json) {
865
882
  console.log(
@@ -1073,5 +1090,17 @@ program.command("init").description("Scaffold a drzl.config.ts").option("-y, --y
1073
1090
  process.exit(1);
1074
1091
  }
1075
1092
  });
1093
+ function reportWideColumns(issues) {
1094
+ const wide = issues.filter((i) => i.code === "DRZL_ANL_UNKNOWN_COLUMN");
1095
+ if (!wide.length) return;
1096
+ console.warn(
1097
+ import_chalk2.default.yellow(`
1098
+ ${wide.length} column${wide.length === 1 ? "" : "s"} could not be typed:`)
1099
+ );
1100
+ for (const i of wide.slice(0, 10)) console.warn(import_chalk2.default.gray(` - ${i.message}`));
1101
+ if (wide.length > 10) console.warn(import_chalk2.default.gray(` ... and ${wide.length - 10} more`));
1102
+ const hints = [...new Set(wide.map((i) => i.hint).filter(Boolean))];
1103
+ for (const h of hints) console.warn(import_chalk2.default.gray(` ${h}`));
1104
+ }
1076
1105
  program.parseAsync(process.argv);
1077
1106
  //# sourceMappingURL=cli.cjs.map