@drzl/cli 4.30.0 → 4.32.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-3REB46XD.js → chunk-BDIJ6WMG.js} +78 -3
- package/dist/chunk-BDIJ6WMG.js.map +1 -0
- package/dist/cli.cjs +174 -20
- package/dist/cli.cjs.map +1 -1
- package/dist/cli.js +103 -20
- package/dist/cli.js.map +1 -1
- package/dist/config.cjs +81 -4
- package/dist/config.cjs.map +1 -1
- package/dist/config.d.cts +43 -3
- package/dist/config.d.ts +43 -3
- package/dist/config.js +7 -3
- package/dist/drzl.config.schema.json +16 -1
- package/package.json +5 -3
- package/dist/chunk-3REB46XD.js.map +0 -1
package/dist/cli.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/cli.ts","../src/output.ts","../src/express-options.ts","../src/fastify-options.ts","../src/generator-loader.ts","../src/graphql-options.ts","../src/hono-options.ts","../src/validation-options.ts","../src/json-schema-options.ts","../src/ai-options.ts","../src/effect-http-options.ts","../src/h3-options.ts","../src/mcp-options.ts","../src/next-options.ts","../src/tanstack-start-options.ts","../src/nestjs-options.ts","../src/orpc-options.ts","../src/service-options.ts","../src/trpc-options.ts","../src/generator-registry.ts","../src/kind-selection.ts","../src/schema-outcome.ts","../src/column-filter.ts","../src/doctor.ts","../src/explain.ts","../src/drizzle-kit.ts","../src/drift.ts","../src/emit-plan.ts","../src/unified-diff.ts","../src/watch-loop.ts","../src/init.ts","../src/sponsor.ts","../src/version.ts"],"sourcesContent":["#!/usr/bin/env node\nimport { qualifiedTableName, SchemaAnalyzer } from '@drzl/analyzer';\nimport chokidar from 'chokidar';\nimport { Command } from 'commander';\nimport * as path from 'node:path';\nimport {\n EXIT_FAILED,\n EXIT_FINDINGS,\n EXIT_OK,\n messageOf,\n jsonFailure,\n Output,\n} from './output.js';\nimport {\n computeGeneratorOutputDirs,\n computeWatchTargets,\n configFromKinds,\n DrzlConfig,\n filterTables,\n loadConfig,\n tableFilterWarnings,\n type GeneratorKind,\n} from './config.js';\nimport {\n entryFor,\n GENERATOR_BY_KIND,\n resolveServicesDir,\n runGenerator,\n runGeneratorWithOptions,\n} from './generator-registry.js';\nimport {\n emptySelectionMessage,\n KindSelectionError,\n kindList,\n parseOnly,\n resolveWatchSelection,\n selectGenerators,\n type WatchSelection,\n} from './kind-selection.js';\nimport { ConfigValidationError } from './config-errors.js';\nimport {\n describeSchemaTarget,\n nothingToGenerate,\n schemaLoadFailure,\n type SchemaProblem,\n} from './schema-outcome.js';\nimport { filterColumns } from './column-filter.js';\nimport {\n ambiguousTableProblem,\n explainTable,\n matchTable,\n noSuchTableProblem,\n renderExplanation,\n renderIndex,\n summarize,\n type TableMatch,\n} from './explain.js';\nimport {\n dialectMismatchWarning,\n resolveSchemaSource,\n type ResolvedSchemaSource,\n} from './drizzle-kit.js';\nimport { buildDoctorReport, renderDoctorReport } from './doctor.js';\nimport { snapshotAll } from './drift.js';\nimport {\n describeCounts,\n displayPath,\n driftStatusOf,\n EmitPlan,\n pendingChanges,\n verifyNothingWasWritten,\n type EmittedFile,\n type FileVerdict,\n} from './emit-plan.js';\nimport { unifiedDiff } from './unified-diff.js';\nimport { createRebuildScheduler, resolveDebounce } from './watch-loop.js';\nimport { GeneratorNotInstalledError } from './generator-loader.js';\nimport { detectSchema, INIT_GENERATOR_CHOICES, runInit } from './init.js';\nimport { maybeShowSponsorMessage } from './sponsor.js';\nimport { CLI_VERSION } from './version.js';\n\n/**\n * Say what went wrong with a generator, distinguishing the two things that can.\n *\n * Every branch below used to print \"<name> generator missing. Install with: npm install\n * @drzl/generator-<name>\" for anything at all that threw, with the real reason on a trailing\n * \"Error details\" line. A generator that was installed and merely failed therefore sent its user\n * to reinstall a package they already had, and the sentence that would have told them what\n * actually happened was the one written as a footnote.\n *\n * `loadGenerator` marks the one case that is an install problem, so the package name comes off the\n * error rather than being repeated here beside the `import()` that already spells it.\n */\nfunction reportGeneratorFailure(out: Output, kind: string, e: unknown): string {\n if (e instanceof GeneratorNotInstalledError) {\n out.error(`The ${kind} generator is not installed.`);\n out.hint(`Install with: npm install ${e.specifier}`);\n return `The ${kind} generator is not installed. Install with: npm install ${e.specifier}`;\n }\n const detail = messageOf(e);\n out.error(`The ${kind} generator failed:`, detail);\n return `The ${kind} generator failed: ${detail}`;\n}\n\n/**\n * The output layer for one command invocation.\n *\n * Built per run rather than as a module singleton, so `--quiet` and `--json` are answered once and\n * every writer downstream shares that answer. See `output.ts` for the stream and colour rules.\n */\nfunction outputFor(opts: { quiet?: boolean; json?: boolean }): Output {\n return new Output({ quiet: !!opts.quiet, json: !!opts.json });\n}\n\n/**\n * The code a thrown value reports, when it is one of ours.\n *\n * `instanceof`, rather than reading `e.code`, because that property is Node's own convention:\n * `ENOENT` off a failed `readFile` would otherwise be published in the `--json` document as\n * though it were a DRZL identifier.\n */\nfunction drzlErrorCode(error: unknown, fallback: string): string {\n return error instanceof ConfigValidationError ? error.code : fallback;\n}\n\n/**\n * A run that has nothing to generate from, reported and stopped (items 70 and 71).\n *\n * `EXIT_FAILED`, not `EXIT_FINDINGS`: an empty schema is not something the command was asked to\n * look for, it is the command being unable to do the work. The hint is a hint, so `--quiet` drops\n * it and the failure itself survives, which is the rule every other error here follows.\n */\nfunction reportSchemaProblem(out: Output, command: string, problem: SchemaProblem): never {\n if (out.json) out.jsonData(jsonFailure(command, problem.code, problem.message));\n else {\n out.error(problem.message);\n out.hint(problem.hint);\n }\n process.exit(EXIT_FAILED);\n}\n\n/**\n * How many drifted files `--check` prints a diff for.\n *\n * A cap rather than no cap, because the case that produces the most drift is the one where a diff\n * helps least: a bumped generator version rewrites the header of every file, and a CI log holding\n * eight hundred near-identical hunks is a log nobody opens. Twenty is enough to read.\n *\n * The number of files beyond it is always stated, and every file is still named in the list above\n * the diffs, so nothing is hidden: what is capped is the explanation, never the finding.\n */\nconst DIFF_FILE_CAP = 20;\n\n/**\n * Show what changed in each drifted file (item 81).\n *\n * On stderr, with the rest of the narration, for the reason `--check`'s file list is: the diff is\n * a report about the work rather than the work, and `drzl generate --check > out.txt` should not\n * put a patch in the file. `--quiet` drops these and keeps the list, which is the finding.\n */\nfunction printCheckDiffs(out: Output, drift: EmittedFile[]): void {\n const shown = drift.slice(0, DIFF_FILE_CAP);\n for (const d of shown) {\n const label = displayPath(d.file);\n const text = unifiedDiff(d.before ?? '', d.after, {\n fromLabel: `a/${label}`,\n toLabel: `b/${label}`,\n });\n if (!text) continue;\n out.note('');\n for (const line of text.split('\\n')) {\n if (!line) continue;\n // Coloured per line rather than per hunk, so a redirected stream gets the same text with no\n // escapes at all; `errStyle` has already answered that question for this stream.\n if (line.startsWith('+++') || line.startsWith('---')) out.note(out.errStyle.bold(line));\n else if (line.startsWith('@@')) out.note(out.errStyle.cyan(line));\n else if (line.startsWith('+')) out.note(out.errStyle.green(line));\n else if (line.startsWith('-')) out.note(out.errStyle.red(line));\n else out.note(out.errStyle.gray(line));\n }\n }\n if (drift.length > shown.length) {\n out.note('');\n out.note(\n out.errStyle.gray(\n `${drift.length - shown.length} more file(s) differ. Diffs are capped at ` +\n `${DIFF_FILE_CAP} files; every drifted file is named in the list above.`\n )\n );\n }\n}\n\n/**\n * The two flags every command carries, declared once so none of them can be the one that forgets.\n *\n * Item 73 was that `--json` existed on three commands out of seven and `--quiet` on none, which\n * makes both unusable from a script: a caller cannot write `drzl <anything> --json` and know it\n * will work.\n */\nfunction withOutputFlags(command: Command): Command {\n return command\n .option('--json', 'write one JSON document to stdout and nothing else', false)\n .option('-q, --quiet', 'drop the progress narration on stderr; errors still print', false);\n}\n\nconst program = new Command();\nprogram.name('drzl').description('DRZL - Drizzle Developer Toolkit').version(CLI_VERSION);\nprogram.addHelpText(\n 'afterAll',\n `\\nNeed a template, adapter, or generator DRZL doesn't ship yet?\\n→ DM @omardulaimidev on X: https://x.com/omardulaimidev\\n`\n);\n\nwithOutputFlags(\n program\n .command('analyze')\n .argument('<schema>', 'path to drizzle schema (TS)')\n .option('--relations', 'include relations', true)\n .option('--validate', 'validate constraints', true)\n .option('--out <file>', 'write analysis JSON to file')\n).action(async (schema: string, opts: any) => {\n const out = outputFor(opts);\n try {\n const analyzer = new SchemaAnalyzer(schema);\n const spinner = out.spinner('Analyzing schema...');\n const start = Date.now();\n const res = await analyzer.analyze({\n includeRelations: !!opts.relations,\n validateConstraints: !!opts.validate,\n });\n const ms = Date.now() - start;\n\n // A schema the analyzer could not open or could not import comes back as an error-level issue\n // rather than as a throw, and the analysis it returns is empty. That is a run that could not\n // happen, so it is EXIT_FAILED. Every other error-level issue describes a schema that *was*\n // read and has something wrong in it, which is the EXIT_FINDINGS case: `analyze` printed a\n // usable document and is telling the caller to look at it.\n const unreadable = res.issues.some(\n (i) => i.level === 'error' && (i.code === 'DRZL_ANL_NOFILE' || i.code === 'DRZL_ANL_IMPORT')\n );\n const errors = res.issues.some((i) => i.level === 'error');\n const code = unreadable ? EXIT_FAILED : errors ? EXIT_FINDINGS : EXIT_OK;\n\n if (opts.out && !opts.json) {\n const fs = await import('node:fs/promises');\n // The bare `Analysis`, because that is what the option says it writes. The envelope belongs\n // to a command's answer on stdout, not to a file of analysis someone asked to keep.\n await fs.writeFile(opts.out, JSON.stringify(res, null, 2), 'utf8');\n spinner.succeed(`Analysis written to ${opts.out} in ${ms}ms`);\n } else {\n spinner.succeed(`Analyzed in ${ms}ms`);\n // The analysis's own keys at the top level, so every existing reader of `.issues`, `.tables`\n // and `.dialect` keeps working, with the envelope merged in beside them. No `ok` here, for\n // the reason spelled out on `doctor` below: on a report command that name already belongs to\n // a statement about the schema, and the run's answer is `exitCode`.\n // Indented, because `verify-packed.sh` redirects this to a file and a person reads it.\n const document = opts.json ? { command: 'analyze', exitCode: code, ...res } : res;\n out.data(JSON.stringify(document, null, 2));\n }\n process.exit(code);\n } catch (e: any) {\n const msg = messageOf(e);\n if (opts.json) out.jsonData(jsonFailure('analyze', 'DRZL_CLI_ANALYZE', msg));\n else {\n out.error('Analyze failed (DRZL_CLI_ANALYZE):', msg);\n out.hint('Tip: run with --json for structured output.');\n }\n process.exit(EXIT_FAILED);\n }\n});\n\nwithOutputFlags(\n program\n .command('doctor')\n .description('Report what DRZL cannot type or enforce in your schema, and why')\n .argument('[schema]', 'path to drizzle schema (TS); defaults to the schema in drzl.config')\n .option('-c, --config <path>', 'path to drzl.config, read when no schema argument is given')\n .option('--strict', 'exit 2 when anything is reported', false)\n).action(async (schema: string | undefined, opts: any) => {\n const out = outputFor(opts);\n {\n try {\n // A schema path argument, like `analyze`, or the one already named in the config, since a\n // user who has a config should not have to retype the path they put in it. Resolution\n // goes through the same `resolveSchemaSource` as `generate`, so a config whose schema\n // comes from drizzle-kit's config gets a doctor report too; its failure messages name\n // both files, which is strictly more useful than the generic line below.\n let target: string | string[] | undefined = schema;\n if (!target) {\n const cfg = await loadConfig(opts.config, (w) => out.warn(w));\n if (cfg) target = (await resolveSchemaSource(cfg)).schema;\n }\n if (!target) {\n const msg = 'No schema given. Pass a path, or run from a directory with a drzl.config.';\n if (opts.json) out.jsonData(jsonFailure('doctor', 'DRZL_CLI_DOCTOR', msg));\n else out.error('Doctor failed (DRZL_CLI_DOCTOR):', msg);\n process.exit(EXIT_FAILED);\n return;\n }\n\n const analyzer = new SchemaAnalyzer(target);\n // Both on, unconditionally. Doctor's job is to look at everything, and a warning that only\n // appears when relations are read would be hidden by a flag turning them off.\n const analysis = await analyzer.analyze({\n includeRelations: true,\n validateConstraints: true,\n });\n const report = buildDoctorReport(\n analysis,\n Array.isArray(target) ? target.join(', ') : target\n );\n\n // An error-level finding means the schema was never read: the file is missing, or importing\n // it threw. There is no report to act on, so that exits like `analyze`'s failure path rather\n // than pretending the empty analysis was a clean bill of health.\n //\n // Zero otherwise, and that is the whole point. A schema carrying a customType or a CHECK\n // this parser will not guess at is normal and usable, and a doctor that failed every\n // pipeline reading one would be switched off within a week. `--strict` is the opt-in.\n const unreadable = report.findings.some((f) => f.level === 'error');\n const code = unreadable\n ? EXIT_FAILED\n : opts.strict && report.findings.length\n ? EXIT_FINDINGS\n : EXIT_OK;\n\n // The report's own keys at the top level, so every reader of `.findings` and `.counts`\n // keeps working, with the envelope's three keys merged in beside them. `ok` is about\n // whether DRZL could run, not about whether the schema is clean: a report full of findings\n // is a successful doctor run, which is why it is `!unreadable` rather than `report.ok`.\n // `command` and `exitCode` first, the report's own keys after, and the order matters: this\n // report has published an `ok` of its own since it shipped, and it means \"nothing to report\n // about the schema\", which is not the same question as \"could DRZL run\". The report's\n // meaning is the one that survives, and the run's answer is `exitCode`. That is also why the\n // envelope defines no `ok` for the two report commands; see docs/cli/output.md.\n if (opts.json)\n out.data(JSON.stringify({ command: 'doctor', exitCode: code, ...report }, null, 2));\n else out.data(renderDoctorReport(report, out.outStyle));\n\n process.exit(code);\n } catch (e: any) {\n const msg = messageOf(e);\n const code = drzlErrorCode(e, 'DRZL_CLI_DOCTOR');\n if (opts.json) out.jsonData(jsonFailure('doctor', code, msg));\n else if (e instanceof ConfigValidationError) {\n // Already a report naming each key, so it prints as it is. See the same branch in\n // `generate` for why a second header over it would say less.\n out.error(msg);\n } else {\n out.error('Doctor failed (DRZL_CLI_DOCTOR):', msg);\n out.hint('Tip: run with --json for structured output.');\n }\n process.exit(EXIT_FAILED);\n }\n }\n});\n\n/**\n * Where `drzl explain` reads the schema from, in the order the answers are trustworthy.\n *\n * `--schema` is what the caller said, so it wins outright. Then the config, through the same\n * `resolveSchemaSource` every other command uses, so a drizzle-kit project needs no drzl config at\n * all. Then item 66's loading-based detection, which is what makes `drzl explain users` work in a\n * fresh checkout with nothing configured: a candidate is confirmed by importing it and finding\n * Drizzle tables, not by its name.\n *\n * Never throws for want of a config. A diagnostic command that refuses to run until you have\n * configured it is the one that gets reached for last.\n */\nasync function explainSchemaSource(\n opts: { schema?: string; config?: string },\n out: Output\n): Promise<\n | { schema: string | string[]; label: string; note?: string; config?: DrzlConfig }\n | undefined\n> {\n // An explicit `--schema` reads no config at all, and so applies no filters. The flag says \"look\n // at this file\", and narrowing it by a config that was written about a different one would\n // report columns as removed that nothing removed.\n if (opts.schema) return { schema: opts.schema, label: opts.schema };\n\n const cfg = await loadConfig(opts.config, (w) => out.warn(w));\n if (cfg) {\n const source = await resolveSchemaSource(cfg);\n for (const w of source.warnings) out.warn(w);\n return {\n schema: source.schema,\n label: describeSchemaTarget(source.schema),\n config: cfg,\n ...(source.source === 'drizzle-kit' && source.drizzleKitConfigPath\n ? { note: `Schema from ${path.relative(process.cwd(), source.drizzleKitConfigPath)}` }\n : {}),\n };\n }\n\n const detected = await detectSchema(process.cwd());\n if (!detected.schema) return undefined;\n return {\n schema: detected.schema,\n label: detected.schema,\n note: detected.notes[detected.notes.length - 1],\n };\n}\n\nwithOutputFlags(\n program\n .command('explain')\n .description('Show what DRZL understood about one table, and what it did not')\n .argument(\n '[table]',\n 'the table to explain, by database name, qualified name or export name; omit for the list'\n )\n .option('-c, --config <path>', 'path to drzl.config, read when --schema is not given')\n .option('-s, --schema <path>', 'path to the schema, overriding the config')\n).action(async (tableName: string | undefined, opts: any) => {\n const out = outputFor(opts);\n /** Every failure this command has, reported the one way the output contract describes. */\n const fail = (problem: { code: string; message: string; hint: string }): never => {\n if (out.json) out.jsonData(jsonFailure('explain', problem.code, problem.message));\n else {\n out.error(problem.message);\n out.hint(problem.hint);\n }\n process.exit(EXIT_FAILED);\n };\n try {\n const source = await explainSchemaSource(opts, out);\n if (!source) {\n fail({\n code: 'DRZL_CFG_001',\n message:\n 'No schema found (DRZL_CFG_001). There is no drzl.config, no drizzle-kit config, and ' +\n 'no schema in the usual locations.',\n hint: 'Pass --schema <path>, or run `drzl init` to write a config.',\n });\n return;\n }\n if (source.note) out.note(out.errStyle.gray(source.note));\n\n const spinner = out.spinner('Reading the schema...');\n const analysis = await new SchemaAnalyzer(source.schema).analyze({\n // Both on, for the reason `doctor` turns both on: this command's job is to say everything\n // that is known, and a relation that appears only under a flag is one a reader would be\n // told is absent.\n includeRelations: true,\n validateConstraints: true,\n });\n spinner.stop();\n\n // The analyzer's own verdict, not a guess from an empty table list: a module that would not\n // import and a module that declares nothing are different mistakes in different files, and\n // `schema-outcome.ts` is where that distinction already lives. Nothing about the sentence is\n // reworded here beyond what did not happen, which for this command is never a file.\n const problem =\n schemaLoadFailure(analysis.issues, source.schema, 'There is nothing to explain.') ??\n nothingToGenerate({\n schema: source.schema,\n analyzed: analysis.tables,\n remaining: analysis.tables,\n consequence: 'There is nothing to explain.',\n });\n if (problem) reportSchemaProblem(out, 'explain', problem);\n\n const context = { schema: source.label, dialect: analysis.dialect };\n\n if (!tableName) {\n const tables = summarize(analysis);\n if (out.json) out.jsonData({ command: 'explain', exitCode: EXIT_OK, ...context, tables });\n else out.data(renderIndex(tables, context, out.outStyle));\n process.exit(EXIT_OK);\n }\n\n const match = matchTable(analysis.tables, tableName);\n if (match.kind === 'ambiguous') fail(ambiguousTableProblem(tableName, match.hits));\n if (match.kind === 'none') {\n fail(noSuchTableProblem(tableName, analysis.tables, match.suggestion));\n }\n\n // The filters are read but never applied to the search: a table this config excludes is\n // exactly the one whose absence from the output needs explaining, and a command that could not\n // find it would be answering \"why is my table missing\" with \"there is no such table\".\n const cfg = source.config;\n let keptTables: string[] | undefined;\n let keptColumns: string[] | undefined;\n if (cfg) {\n keptTables = filterTables(analysis.tables, cfg).map((t) => qualifiedTableName(t));\n try {\n const narrowed = filterColumns(\n [(match as Extract<TableMatch, { kind: 'found' }>).table],\n cfg.columns\n );\n keptColumns = narrowed.tables[0]?.columns.map((c) => c.name);\n } catch {\n // A `columns` rule this config cannot honour is `generate`'s error to raise, and raising it\n // here would leave a reader with no explanation at all of the table they asked about.\n keptColumns = undefined;\n }\n }\n\n const explanation = explainTable(\n analysis,\n match as Extract<TableMatch, { kind: 'found' }>,\n { keptTables, keptColumns }\n );\n if (out.json) {\n out.jsonData({ command: 'explain', exitCode: EXIT_OK, ...context, table: explanation });\n } else {\n out.data(renderExplanation(explanation, context, out.outStyle));\n }\n process.exit(EXIT_OK);\n } catch (e: any) {\n const msg = messageOf(e);\n const code = drzlErrorCode(e, 'DRZL_CLI_EXPLAIN');\n if (opts.json) out.jsonData(jsonFailure('explain', code, msg));\n else if (e instanceof ConfigValidationError) out.error(msg);\n else {\n out.error('Explain failed (DRZL_CLI_EXPLAIN):', msg);\n out.hint('Tip: run with --json for structured output.');\n }\n process.exit(EXIT_FAILED);\n }\n});\n\nwithOutputFlags(\n program\n .command('generate')\n .description('Run configured generators (drzl.config.*)')\n .option('-c, --config <path>', 'path to drzl.config')\n .option('-s, --schema <path>', 'path to the schema, overriding the config')\n .option(\n '--only <kinds>',\n `run only these generator kinds, comma separated: ${kindList()}`\n )\n .option(\n '--check',\n 'regenerate and fail if the result differs from what is on disk, without changing it'\n )\n .option('--dry-run', 'report what would be written, and write nothing', false)\n).action(async (opts: any) => {\n const out = outputFor(opts);\n /**\n * Whether this run writes anything at all.\n *\n * `--check` and `--dry-run` are the same run with different reports at the end: both compute\n * every file's content, neither puts any of it on disk. `--check` then asks whether anything\n * differs and fails if it does; `--dry-run` prints what it found and succeeds either way.\n * Passing both is not an error, it is a `--check` that also says nothing was written, which is\n * already what `--check` says.\n */\n const planning = !!opts.check || !!opts.dryRun;\n /** Everything the `--json` document reports, filled in as the run makes it true. */\n const emitted: Array<{\n kind: string;\n files: string[];\n changes: Array<{ file: string; status: FileVerdict }>;\n }> = [];\n const warnings: string[] = [];\n /** A warning goes to stderr for a human and into the document for a machine, never both. */\n const warn = (text: string) => {\n warnings.push(text);\n out.warn(text);\n };\n {\n try {\n // Read before the config, so an unknown kind is refused by name before anything is loaded\n // rather than being applied to a config as a filter that matches nothing.\n const only = parseOnly(opts.only);\n // The config's own warnings go through `warn`, so they reach the `--json` document and\n // `--quiet` removes them, exactly like every other warning this command produces. They used\n // to be written with `console.warn` from inside `loadConfig`, which neither flag could see.\n let cfg = await loadConfig(opts.config, warn);\n if (!cfg && only) {\n // The config route with the config inlined, which is what replaces `generate:orpc` and\n // `generate:trpc`: `drzl generate --schema src/db/schema.ts --only orpc` is those commands\n // for all fourteen kinds, and every config feature still applies because there is a real\n // config here. `--schema` may be omitted, in which case the drizzle-kit config answers for\n // it exactly as it does for a config file with no `schema` key.\n cfg = configFromKinds([...only], opts.schema, warn);\n }\n if (!cfg) {\n const msg = 'No config found (DRZL_CFG_001). Create drzl.config.ts or pass --config.';\n // Was exit 2 until now, which the scheme reserves for a run that found something. A\n // config that is not there is a run that could not start.\n if (opts.json) out.jsonData(jsonFailure('generate', 'DRZL_CFG_001', msg));\n else {\n out.error(msg);\n // The one-command route, named here because this is where somebody who has no config\n // finds out they need one. `--only` on its own is enough to run without a file.\n out.hint('Or run one generator with no config: drzl generate --schema <path> --only <kind>.');\n }\n process.exit(EXIT_FAILED);\n return;\n }\n // `--schema` beats both the config's `schema` and the drizzle-kit fallback, which is what\n // the flag says and is how `explain -s` already behaves. `drizzleKit` is dropped with it so\n // a config that sets both does not draw the \"schema wins, remove one of the two\" warning\n // about a key the caller did not write.\n if (opts.schema) {\n const { drizzleKit: _fromConfig, ...rest } = cfg;\n cfg = { ...rest, schema: opts.schema };\n }\n // Refused before the schema is read, because it is a mistake in the command line rather than\n // anything about the project: the kinds are real and this config has none of them.\n const nothingSelected = emptySelectionMessage(only, cfg.generators);\n if (nothingSelected) {\n if (opts.json) out.jsonData(jsonFailure('generate', 'DRZL_CLI_ONLY', nothingSelected));\n else {\n out.error(nothingSelected);\n out.hint('Add it to \"generators\" in your config, or name a kind that is already there.');\n }\n process.exit(EXIT_FAILED);\n return;\n }\n // Where the schema comes from: `schema` in the drzl config, or, when that is omitted,\n // the drizzle-kit config, so a kit user never states the path twice. Resolved before the\n // spinner starts, because it throws the \"neither file names a schema\" error.\n const source = await resolveSchemaSource(cfg);\n for (const w of source.warnings) warn(w);\n // `typedJson`/`typedColumns` need one module to import tables from (`schemaPath` in\n // validation-options.ts). A drizzle-kit source resolved to exactly one file is that\n // module, so the option keeps working; several files have no single module, and the\n // generators already say so at their own call sites when they want types with no path.\n if (!cfg.schema && Array.isArray(source.schema) && source.schema.length === 1) {\n cfg = { ...cfg, schema: source.schema[0] };\n }\n if (source.source === 'drizzle-kit') {\n const n = (source.schema as string[]).length;\n // Narration, so stderr. It says where DRZL looked, not what it produced, and it used to\n // sit on stdout in front of the file list anyone was parsing.\n out.note(\n out.errStyle.gray(\n `Schema from ${path.relative(process.cwd(), source.drizzleKitConfigPath!)} ` +\n `(${n} file${n === 1 ? '' : 's'})`\n )\n );\n }\n const analyzer = new SchemaAnalyzer(source.schema);\n const spinner = out.spinner('Analyzing...');\n const t0 = Date.now();\n const analysis = await analyzer.analyze({\n includeRelations: cfg.analyzer.includeRelations,\n validateConstraints: cfg.analyzer.validateConstraints,\n includeHeuristicRelations: cfg.analyzer.includeHeuristicRelations,\n });\n // Item 70, and before the tick rather than after it: a module that never loaded has not\n // been analysed, and \"Analysis complete\" over the top of it is the green tick this item was\n // filed about. Everything below reads `analysis.tables`, which is empty here for a reason\n // that has nothing to do with the schema's contents.\n const loadFailure = schemaLoadFailure(analysis.issues, source.schema);\n if (loadFailure) {\n spinner.stop();\n reportSchemaProblem(out, 'generate', loadFailure);\n }\n // After the spinner rather than before it, because `filterColumns` throws on a config it\n // cannot honour and a thrown error under a live ora spinner prints into a line the spinner\n // then overwrites.\n spinner.succeed(`Analysis complete in ${Date.now() - t0}ms`);\n // The cross-check the interop makes possible: the drizzle-kit config states a dialect,\n // the analyzer measures one, and a contradiction usually means the schema paths or the\n // dialect line are stale. A warning rather than an error, because generation follows the\n // schema either way. After the spinner for the same overwrite reason as above.\n const dialectWarning = dialectMismatchWarning({\n configPath: source.drizzleKitConfigPath ?? '',\n declared: source.drizzleKitDialect,\n analyzed: analysis.dialect,\n });\n if (dialectWarning) warn(dialectWarning);\n // Both filters are applied before any generator sees the analysis, so every one of them\n // honours them without needing to know the options exist.\n //\n // Columns first. Both orders leave the same tables, since one narrows columns and the other\n // drops whole tables, but only this one lets a `columns` entry name a table that `exclude`\n // also removes without that reading as a typo, and a typo is refused.\n const narrowed = filterColumns(analysis.tables, cfg.columns);\n // Before the filter runs, so the tables it reports on are the ones the pattern really\n // reached rather than what survived it.\n const filterWarnings = tableFilterWarnings(narrowed.tables, cfg);\n analysis.tables = filterTables(narrowed.tables, cfg);\n for (const w of [...narrowed.warnings, ...filterWarnings]) warn(w);\n for (const w of wideColumnWarning(analysis.issues)) warn(w);\n // Item 71, after the filters so it can tell the two empty states apart, and before\n // `--check` snapshots anything so a check on a schema that produces nothing fails rather\n // than comparing an empty tree with itself and reporting it up to date.\n const empty = nothingToGenerate({\n schema: source.schema,\n analyzed: narrowed.tables,\n remaining: analysis.tables,\n });\n if (empty) reportSchemaProblem(out, 'generate', empty);\n // Where every generator writes, which is both the set `--check` and `--dry-run` have to know\n // the current contents of, and the set they have to prove they left alone afterwards.\n const outputDirs = computeGeneratorOutputDirs(cfg);\n // Read once, up front, for two jobs at the same time: it is the \"what is on disk now\" half\n // of every per-file verdict below, so the plan never reads a file itself, and it is the\n // baseline `verifyNothingWasWritten` compares against at the end. Only for a run that writes\n // nothing; an ordinary `generate` reads each file as it emits it, which costs one read per\n // generated file rather than one per file in the output tree.\n const existing = planning ? await snapshotAll(outputDirs) : undefined;\n /**\n * Every file this run produces, with the content already there beside it.\n *\n * Handed to each generator as `fileSink`, so the content is captured at the moment it would\n * be written rather than inferred afterwards from what landed on disk. Items 68, 80 and 81\n * all read this one object.\n */\n const plan = new EmitPlan({ write: !planning, existing });\n const total = analysis.tables.length || 1;\n // Whether this draws anything at all is `shouldShowProgress`'s decision: a terminal, no\n // `--quiet`, no `--json`, and enough tables that the bar will move (item 72).\n const progress = out.progress(total);\n /** One completed generator, reported the same way whichever branch produced it. */\n const generated = (kind: string, files: string[]) => {\n progress.stop();\n // A path the generator says it wrote that never reached the sink is a generator that\n // ignored `fileSink`, which on a user's machine means an installed generator package older\n // than this CLI. Under `--dry-run` or `--check` that is a run writing to a tree it promised\n // not to touch, so it stops here rather than reporting a plan that is not what happened.\n // `verifyNothingWasWritten` catches the same thing from the other side; this one can name\n // the generator.\n const missed = plan.unrecorded(files);\n if (missed.length && planning) {\n const message =\n `The ${kind} generator wrote ${missed.length} file(s) directly instead of reporting ` +\n `them, so this run could not be a preview. Update @drzl/generator-${kind} to a ` +\n `version that supports --dry-run. First file: ${displayPath(missed[0])}`;\n if (opts.json) out.jsonData(jsonFailure('generate', 'DRZL_GEN_003', message));\n else out.error(message);\n process.exit(EXIT_FAILED);\n }\n const verdicts = plan.verdictsFor(files).filter(Boolean) as EmittedFile[];\n // One entry per generator *entry*, keyed by nothing: a config may list two generators of\n // the same kind pointed at different paths, and a lookup by kind would report the first\n // one's verdicts twice.\n emitted.push({\n kind,\n files,\n changes: verdicts.map((v) => ({ file: v.file, status: v.verdict })),\n });\n if (opts.json) return;\n if (out.quiet) return;\n // Item 80: the count is what the run cost, the verdicts are what it did. A generator that\n // rewrote twelve identical files and one changed one used to report \"13 files\", which is\n // true and is not the sentence anyone was looking for.\n //\n // The verb changes with the mode, because \"Generated\" over a run that wrote nothing is the\n // same class of untruth as the green tick items 70 and 71 were filed about.\n out.succeed(\n out.errStyle.green(\n `${planning ? 'Would write' : 'Generated'} (${kind}): ${files.length} files`\n ) + out.errStyle.gray(` (${describeCounts(plan.counts(files))})`)\n );\n // Only the files that are not the same as before, and named relative to the working\n // directory, because this is the short list a person scans. The full absolute list is\n // still on stdout below, unchanged, for whatever is parsing it. Skipped under `--check`,\n // which prints the same files again below with their drift status and a diff each.\n for (const v of verdicts) {\n if (opts.check) break;\n if (v.verdict === 'unchanged') continue;\n const mark = v.verdict === 'created' ? '+' : '~';\n out.note(' ' + out.errStyle.cyan(mark + ' ' + displayPath(v.file)));\n }\n // stdout, and deliberately: for `generate` the list of files written is the answer, and a\n // caller without `--json` has nothing else to read. `--quiet` is what removes it. Under\n // `--dry-run` it is the list that *would* be written, which is the same answer to the same\n // question and keeps `drzl generate --dry-run > files.txt` working.\n for (const f of files) out.data(' - ' + out.outStyle.cyan(f));\n };\n /** One generator that threw. Reports it in whichever shape was asked for, then stops. */\n const failGenerator = (kind: string, e: unknown): never => {\n progress.stop();\n // Prints for a human and returns the same sentence for the document; the writers inside\n // it are already no-ops under `--json`, so neither shape can be the one that goes stale.\n const message = reportGeneratorFailure(out, kind, e);\n if (opts.json) out.jsonData(jsonFailure('generate', 'DRZL_GEN_002', message));\n process.exit(EXIT_FAILED);\n };\n // Where the service generator is actually writing, so a router template that imports\n // services spells a path that exists. The templates default it to `src/services`, and with\n // nothing passed that default was used no matter where the services really went, emitting an\n // import of a module that was never created. One function, shared with `watch`, so the two\n // commands cannot arrive at different answers.\n const servicesDir = resolveServicesDir(cfg);\n for (const g of selectGenerators(cfg.generators, only)) {\n // Per generator rather than once outside the loop. The bar used to be started before the\n // loop and stopped by whichever branch ran first, so in a config with two generators the\n // second updated a bar that was already stopped and drew nothing at all.\n progress.start();\n // The registry, not a fourteen-way `if`. The four copies of that chain are what let an\n // option reach one command and not the other; see `generator-registry.ts`.\n const entry = GENERATOR_BY_KIND.get(g.kind);\n if (!entry) continue;\n try {\n const files = await runGenerator(entry, g, cfg, {\n analysis,\n servicesDir,\n fileSink: plan,\n onProgress: ({ index }) => progress.update(index),\n });\n generated(g.kind, files);\n } catch (e: any) {\n failGenerator(g.kind, e);\n }\n }\n /**\n * The `generators` array both document shapes carry, with the verdicts merged in.\n *\n * `files` keeps its absolute paths, because that is what it has always published and a\n * script resolving them is entitled to keep working. `changes` is relative, because it is\n * new and a document naming somebody's home directory in every entry is worse to read and\n * impossible to compare across machines.\n */\n const generatorsDocument = () =>\n emitted.map((e) => ({\n kind: e.kind,\n files: e.files,\n changes: e.changes.map((c) => ({ file: displayPath(c.file), status: c.status })),\n }));\n\n if (planning) {\n // The claim `--dry-run` and `--check` make, checked rather than asserted. `existing` is the\n // snapshot taken before any generator ran, so anything that differs now was written by a\n // generator that ignored the sink, and it is put back before this reports.\n const wrote = await verifyNothingWasWritten(outputDirs, existing!);\n if (wrote.length) {\n const message =\n `${wrote.length} file(s) were written by a run that promised to write none, and have ` +\n `been restored. This means an installed generator package is older than this CLI. ` +\n `Update your @drzl/generator-* packages. First file: ${displayPath(wrote[0])}`;\n if (opts.json) out.jsonData(jsonFailure('generate', 'DRZL_GEN_003', message));\n else out.error(message);\n process.exit(EXIT_FAILED);\n }\n }\n\n if (opts.check) {\n const drift = pendingChanges(plan);\n const upToDate = drift.length === 0;\n // Drift is EXIT_FINDINGS, not EXIT_FAILED, and that is the whole reason the scheme has two\n // failure codes. The check ran perfectly: it regenerated in memory, compared, wrote\n // nothing, and is reporting what it found. A CI job that wants to show a diff acts on that\n // differently from a config it could not read, and until 4.23 both were 1.\n const code = upToDate ? EXIT_OK : EXIT_FINDINGS;\n\n if (opts.json) {\n out.jsonData({\n ok: true,\n command: 'generate',\n exitCode: code,\n check: {\n upToDate,\n drift: drift.map((d, i) => ({\n file: displayPath(d.file),\n status: driftStatusOf(d.verdict),\n // Item 81. Beyond the cap the entry is still here with its status, and only the\n // diff is absent, so a machine reading this never loses a file.\n diff:\n i < DIFF_FILE_CAP\n ? unifiedDiff(d.before ?? '', d.after, {\n fromLabel: `a/${displayPath(d.file)}`,\n toLabel: `b/${displayPath(d.file)}`,\n })\n : null,\n })),\n diffFileCap: DIFF_FILE_CAP,\n },\n generators: generatorsDocument(),\n warnings,\n });\n process.exit(code);\n }\n\n if (!upToDate) {\n out.error(`\\nGenerated output is out of date (${drift.length} file(s)):`);\n for (const d of drift) {\n const status = driftStatusOf(d.verdict);\n const mark = status === 'added' ? '+' : '~';\n out.error(\n ` ${mark} ${out.errStyle.yellow(status.padEnd(8))} ${displayPath(d.file)}`\n );\n }\n // Item 81: the list says which files, the diff says what about them. Printed after the\n // list rather than instead of it, so a reader who only wants the names still gets them\n // on the first few lines, and `--quiet` keeps the list and drops the diffs, since the\n // list is the finding and the diff is the explanation.\n printCheckDiffs(out, drift);\n out.hint('\\nRun `drzl generate` and commit the result. Nothing was written by this check.');\n process.exit(code);\n }\n out.succeed(out.errStyle.green('Generated output is up to date.'));\n process.exit(code);\n }\n\n if (opts.json) {\n out.jsonData({\n ok: true,\n command: 'generate',\n exitCode: EXIT_OK,\n check: null,\n dryRun: !!opts.dryRun,\n generators: generatorsDocument(),\n warnings,\n });\n return;\n }\n\n if (opts.dryRun) {\n // Item 68, and `EXIT_OK` on purpose. A dry run that computed its answer did what it was\n // asked; `2` is for a run that found what it was told to look for, and \"this file would\n // change\" is not a finding here, it is the answer. A preview of a project that has never\n // been generated would otherwise exit non-zero for being new, and the flag people reach\n // for before their first `generate` would look like a failure. `--check` is the flag whose\n // question is \"is anything stale\", and it still answers `2`.\n const counts = plan.counts();\n out.succeed(\n out.errStyle.green(`Dry run: ${counts.total} file(s) would be written`) +\n out.errStyle.gray(` (${describeCounts(counts)}). Nothing was written.`)\n );\n process.exit(EXIT_OK);\n }\n\n if (cfg.generators.length) {\n maybeShowSponsorMessage({ reason: 'generate', out });\n }\n } catch (e: any) {\n const msg = messageOf(e);\n const code = drzlErrorCode(e, 'DRZL_GEN_001');\n // A `--only` value that is not a kind is a mistake in the command line, so it is reported as\n // itself rather than under \"Generate failed\", whose tip points at the config file.\n if (e instanceof KindSelectionError) {\n if (opts.json) out.jsonData(jsonFailure('generate', e.code, msg));\n else {\n out.error(msg);\n if (e.hint) out.hint(e.hint);\n }\n process.exit(EXIT_FAILED);\n }\n if (opts.json) out.jsonData(jsonFailure('generate', code, msg));\n else if (e instanceof ConfigValidationError) {\n // Already a report about named keys, so it prints as it is: prefixing it with \"Generate\n // failed\" would put a second header over a message that has one, and the generic tip\n // below tells a reader to check the file the message is already about.\n out.error(msg);\n } else {\n out.error('Generate failed (DRZL_GEN_001):', msg);\n out.hint('Tip: check your drzl.config.ts and template path.');\n }\n process.exit(EXIT_FAILED);\n }\n }\n});\n\n/**\n * Refuse to generate from a schema that was never read, or that declares nothing.\n *\n * `generate:orpc no-such-file.ts` used to exit 0, having written a `placeholder.orpc.ts` whose\n * contents read \"No tables detected in analysis\". Item 67 stopped the first half of that; the\n * second half survived it, because a schema that imports cleanly and exports nothing produces the\n * identical placeholder and the identical exit 0, measured again here. Both are `EXIT_FAILED`\n * now, and neither writes a file.\n *\n * The two are told apart by `schema-outcome.ts`, which reads the analyzer's own verdict rather\n * than guessing from an empty table list.\n */\nfunction schemaProblemFor(\n analysis: {\n issues: Array<{ level?: string; code?: string; message?: string }>;\n tables: Array<{ name: string }>;\n },\n schema: string\n): SchemaProblem | undefined {\n return (\n schemaLoadFailure(analysis.issues, schema) ??\n nothingToGenerate({ schema, analyzed: analysis.tables, remaining: analysis.tables })\n );\n}\n\n/**\n * The one line a per-kind command prints before it does the work.\n *\n * `generate:orpc` shipped when oRPC was the only generator and `generate:trpc` arrived with the\n * tRPC generator; the twelve generators added since added no command, so the split is chronological\n * rather than principled. Both are also strictly less capable than the route they are being\n * replaced by: no config at all means no table or column filters, no naming, no format, no\n * `importExtension`, no shared validation, no `databaseInjection`, no drizzle-kit schema\n * resolution, and, because they bypass the write plan, no `--check`, no `--dry-run` and no drift\n * verdicts.\n *\n * Deprecated rather than deleted: they keep working, byte for byte, and 5.0 is where they go. The\n * line names the replacement command line verbatim so the fix is a copy and a paste, and it goes\n * through `Output.warn`, which means `--quiet` and `--json` both drop it. That matters more than it\n * looks: `--json` promises one document on stdout and nothing at all on stderr, so a notice written\n * to a stream directly would break the contract a script is relying on for the sake of a sentence\n * no script can read.\n *\n * Options with no flag on `generate` are named as config keys rather than silently omitted, and\n * only when the caller actually passed them, which `getOptionValueSource` answers exactly rather\n * than by comparing against a default the caller may have typed on purpose.\n */\nfunction deprecationNotice(\n command: 'generate:orpc' | 'generate:trpc',\n kind: GeneratorKind,\n schema: string,\n cmd: Command\n): string {\n const replacement = `drzl generate --schema ${schema} --only ${kind}`;\n const CONFIG_KEYS: Record<string, string> = {\n outDir: 'outDir',\n template: 'template',\n includeRelations: 'includeRelations',\n servicesDir: \"the service generator's path\",\n };\n const moved = Object.keys(CONFIG_KEYS).filter(\n (name) => cmd.getOptionValueSource(name) === 'cli'\n );\n const tail = moved.length\n ? ` (${moved.map((name) => CONFIG_KEYS[name]).join(', ')} ${\n moved.length === 1 ? 'moves' : 'move'\n } into drzl.config.ts)`\n : '';\n return `${command} is deprecated and will be removed in 5.0. Run this instead: ${replacement}${tail}`;\n}\n\nwithOutputFlags(\n program\n .command('generate:orpc')\n .description('Deprecated. Use `drzl generate --schema <path> --only orpc`')\n .argument('<schema>', 'path to drizzle schema (TS)')\n .option('-o, --outDir <dir>', 'output directory', 'src/api')\n .option('--template <name>', 'template name', 'standard')\n .option('--includeRelations', 'include relation endpoints')\n).action(async (schema: string, opts: any, cmd: Command) => {\n const out = outputFor(opts);\n out.warn(deprecationNotice('generate:orpc', 'orpc', schema, cmd));\n try {\n const analyzer = new SchemaAnalyzer(schema);\n const analysis = await analyzer.analyze({\n includeRelations: !!opts.includeRelations,\n validateConstraints: true,\n });\n const problem = schemaProblemFor(analysis, schema);\n if (problem) reportSchemaProblem(out, 'generate:orpc', problem);\n // The registry loads it and normalises what it hands back; the options are this command's own,\n // unchanged, which is what keeps its output identical to the release before this one.\n const files = await runGeneratorWithOptions(entryFor('orpc'), analysis, {\n outputDir: opts.outDir,\n template: opts.template,\n includeRelations: !!opts.includeRelations,\n });\n if (opts.json) {\n out.jsonData({\n ok: true,\n command: 'generate:orpc',\n exitCode: EXIT_OK,\n generators: [{ kind: 'orpc', files }],\n });\n return;\n }\n if (!out.quiet) {\n out.data(out.outStyle.green('Generated:') + ' ' + files.map((f) => out.outStyle.cyan(f)).join(', '));\n }\n maybeShowSponsorMessage({ reason: 'generate:orpc', out });\n } catch (e: any) {\n // An absent generator package goes through the same reporter both dispatch loops use, so it\n // names itself and the install line. This command reached the generator through a static\n // import until now, which meant an absent package took the process down before the action ran\n // at all, with a stack trace and no sentence. Everything else keeps the wording this command\n // has always printed, which covers the analyzer as much as the generator.\n let message: string;\n if (e instanceof GeneratorNotInstalledError) {\n message = reportGeneratorFailure(out, 'orpc', e);\n } else {\n message = messageOf(e);\n out.error('Generate orpc failed:', message);\n }\n if (opts.json) out.jsonData(jsonFailure('generate:orpc', 'DRZL_CLI_ORPC', message));\n process.exit(EXIT_FAILED);\n }\n});\n\nwithOutputFlags(\n program\n .command('generate:trpc')\n .description('Deprecated. Use `drzl generate --schema <path> --only trpc`')\n .argument('<schema>', 'path to drizzle schema (TS)')\n .option('-o, --outDir <dir>', 'output directory', 'src/api')\n .option('--template <name>', 'standard | service', 'standard')\n .option('--includeRelations', 'include relation endpoints')\n .option('--servicesDir <dir>', 'where the service generator writes', 'src/services')\n).action(async (schema: string, opts: any, cmd: Command) => {\n const out = outputFor(opts);\n out.warn(deprecationNotice('generate:trpc', 'trpc', schema, cmd));\n try {\n const analyzer = new SchemaAnalyzer(schema);\n const analysis = await analyzer.analyze({\n includeRelations: !!opts.includeRelations,\n validateConstraints: true,\n });\n const problem = schemaProblemFor(analysis, schema);\n if (problem) reportSchemaProblem(out, 'generate:trpc', problem);\n const files = await runGeneratorWithOptions(entryFor('trpc'), analysis, {\n outputDir: opts.outDir,\n template: opts.template,\n includeRelations: !!opts.includeRelations,\n // Only consulted by `--template service`, and passed unconditionally so this command\n // cannot become the branch that forgets it.\n servicesDir: opts.servicesDir,\n });\n if (opts.json) {\n out.jsonData({\n ok: true,\n command: 'generate:trpc',\n exitCode: EXIT_OK,\n generators: [{ kind: 'trpc', files }],\n });\n return;\n }\n if (!out.quiet) {\n out.data(\n out.outStyle.green('Generated:') +\n ' ' +\n files.map((f: string) => out.outStyle.cyan(f)).join(', ')\n );\n }\n maybeShowSponsorMessage({ reason: 'generate:trpc', out });\n } catch (e: any) {\n const message = reportGeneratorFailure(out, 'trpc', e);\n if (opts.json) out.jsonData(jsonFailure('generate:trpc', 'DRZL_CLI_TRPC', message));\n process.exit(EXIT_FAILED);\n }\n});\n\nprogram\n .command('watch')\n .description('Watch schema and regenerate on changes')\n .option('-c, --config <path>', 'path to drzl.config')\n .option(\n '--only <kinds>',\n `rebuild only these generator kinds, comma separated: ${kindList()}`\n )\n .option(\n '--pipeline <name>',\n 'all | analyze | generate-<kind>, the older spelling of --only',\n 'all'\n )\n .option('--debounce <ms>', 'wait this long after the last change before rebuilding', '200')\n .option('--clear', 'clear the terminal before each rebuild', false)\n .option('--json', 'emit JSON logs', false)\n .option('-q, --quiet', 'drop the progress narration on stderr; errors still print', false)\n .option('--poll', 'force polling (helps WSL/Docker/remote FS)', false)\n .action(async (opts: any) => {\n // `watch` has no answer to give: it is narration until it is stopped. So everything human it\n // prints goes to stderr, and stdout carries only the `--json` event stream, which is the one\n // thing here a program reads.\n const out = outputFor(opts);\n\n /**\n * Which kinds this watcher rebuilds, from `--only` or from the `--pipeline` spelling it\n * replaces.\n *\n * Read before the watcher exists, and fatal, unlike everything else this command refuses.\n * A schema that will not parse is an ordinary intermediate state and the watcher waits it out;\n * a flag value that is not a generator kind cannot become one however many times the schema is\n * saved, so reporting it and then watching would be a process that never does anything and\n * never says why. `--pipeline generate-zod` was exactly that until now: it named no branch, so\n * the watcher started, printed its watch list, and regenerated nothing for as long as it ran.\n */\n let selection: WatchSelection;\n try {\n selection = resolveWatchSelection(opts);\n } catch (e: any) {\n if (e instanceof KindSelectionError) {\n if (opts.json) out.jsonData(jsonFailure('watch', e.code, e.message));\n else {\n out.error(e.message);\n if (e.hint) out.hint(e.hint);\n }\n } else out.error(messageOf(e));\n process.exit(EXIT_FAILED);\n return;\n }\n\n /**\n * A schema `watch` has nothing to generate from, reported without stopping (items 70, 71).\n *\n * The one place in this change where the failure is not an exit code, and deliberately. A\n * watcher exists to be running while the schema is being edited, and the states this reports\n * are all ordinary intermediate ones: a file saved mid-expression does not parse, a file\n * being written from scratch declares no tables yet, and a table filter is usually adjusted\n * with the watcher up. Exiting on any of them would mean the user has to restart the watcher\n * to recover from a typo, which is the opposite of what the command is for. So it says what is\n * wrong, writes nothing, and waits for the next save, exactly as `run`'s own catch already\n * does for a generator that throws.\n */\n const reportWatchProblem = (problem: SchemaProblem) => {\n if (opts.json) {\n out.jsonData({ event: 'error', code: problem.code, message: problem.message });\n return;\n }\n out.error(problem.message);\n out.hint(problem.hint);\n };\n\n /**\n * Wipe the terminal before a rebuild, if that was asked for and there is a terminal (item 75).\n *\n * Three things were wrong with the `console.clear()` this replaces, and only the first is the\n * one the plan item names.\n *\n * It was not optional. Every rebuild wiped the screen, taking the previous rebuild's errors\n * and the startup banner listing the watched directories with it, so the answer to \"what did\n * it say last time\" was always \"it is gone\". A watcher a person leaves running all day is the\n * last place to throw away scrollback without being asked.\n *\n * It was decided from the wrong stream. `console.clear()` writes to stdout and does nothing\n * when stdout is not a terminal, but everything this command prints for a human is on stderr.\n * So `drzl watch > events.json` on a terminal left the terminal uncleared, and the stream that\n * would have been cleared was the one carrying the JSON. That is the same defect item 77 fixed\n * for colour, arrived at from the other direction.\n *\n * It also wrote the escape to a stream a program may be reading. Node happens to make that\n * harmless by checking `isTTY` first, which is why nothing leaked, but the check belonged to\n * the stream being cleared rather than to whichever one `console` was bound to.\n *\n * `2J` erases the display and `3J` the scrollback, then the cursor goes home. Sent together,\n * because erasing the display alone leaves the previous rebuild one scroll away and the point\n * of asking for this is a screen holding only the current run.\n */\n const clearScreen = () => {\n if (!opts.clear || opts.json || out.quiet) return;\n if (!out.stderr.isTTY) return;\n out.stderr.write('\\u001b[2J\\u001b[3J\\u001b[H');\n };\n\n // Wrapped, unlike the reload inside `run`, which has its own catch. A config that does not\n // validate throws out of here, and with nothing around it the rejection escapes the action\n // and Node prints a stack trace over the report that names each offending key.\n let loaded: DrzlConfig | null;\n try {\n loaded = await loadConfig(opts.config, (w) => out.warn(w));\n } catch (e: any) {\n out.error(messageOf(e));\n process.exit(EXIT_FAILED);\n return;\n }\n if (!loaded) {\n out.error('No config found (DRZL_CFG_001). Create drzl.config.ts or pass --config.');\n process.exit(EXIT_FAILED);\n return;\n }\n // Through a second binding rather than narrowing the first, so `cfg` stays non-nullable for\n // the closures below: `run` and the watcher callbacks capture it, and a `let` a closure reads\n // does not keep the narrowing a guard in this scope gave it.\n let cfg: DrzlConfig = loaded;\n\n const abs = (p: string) => path.resolve(process.cwd(), p);\n const isInside = (child: string, parent: string) => {\n const rel = path.relative(parent, child);\n return !!rel && !rel.startsWith('..') && !path.isAbsolute(rel);\n };\n\n // Resolved before the watcher exists, because the directories to watch depend on it: a\n // schema read from drizzle-kit's config lives wherever that config says, and a watcher\n // that does not cover those directories never fires. A resolution failure here is a\n // startup failure, exactly like a missing config; inside `run` the same failure is caught\n // and reported, so a broken edit mid-watch can be fixed by the next save.\n let source: ResolvedSchemaSource;\n try {\n source = await resolveSchemaSource(cfg);\n } catch (e: any) {\n out.error(messageOf(e));\n process.exit(EXIT_FAILED);\n return;\n }\n for (const w of source.warnings) out.warn(w);\n\n const ignoredOutDirs = new Set<string>(computeGeneratorOutputDirs(cfg).map(abs));\n const currentTargets = new Set<string>(\n computeWatchTargets(cfg, process.cwd(), source).map(abs)\n );\n\n const syncWatcherTargets = (watcher: import('chokidar').FSWatcher, next: Set<string>) => {\n const add: string[] = [];\n const del: string[] = [];\n for (const p of next) if (!currentTargets.has(p)) add.push(p);\n for (const p of currentTargets) if (!next.has(p)) del.push(p);\n if (add.length) watcher.add(add);\n if (del.length) watcher.unwatch(del);\n currentTargets.clear();\n next.forEach((p) => currentTargets.add(p));\n };\n\n const rebuildIgnoreDirsFrom = (cfgNow: DrzlConfig) => {\n ignoredOutDirs.clear();\n for (const d of computeGeneratorOutputDirs(cfgNow)) ignoredOutDirs.add(abs(d));\n };\n\n // Watch targets are directories now, because chokidar v4 dropped glob support. The\n // extensions the old `**/*.{ts,tsx,js}` glob selected therefore have to be filtered here\n // instead, or every unrelated file in the schema's directory would trigger a rebuild.\n const WATCHED_EXTENSIONS = new Set(['.ts', '.tsx', '.js', '.mjs', '.cjs']);\n\n const ignoredFn = (p: string, stats?: { isDirectory(): boolean }) => {\n const full = abs(p);\n for (const dir of ignoredOutDirs) {\n if (full === dir || isInside(full, dir)) return true;\n }\n // A directory is never ignored: chokidar has to descend into it to reach the files.\n if (stats?.isDirectory()) return false;\n const ext = path.extname(full);\n // Without stats chokidar is asking about a path it has not resolved yet. An extensionless\n // one is almost certainly a directory, so let it through and decide once it is known.\n if (!ext) return false;\n return !WATCHED_EXTENSIONS.has(ext);\n };\n\n const watcher = chokidar.watch(Array.from(currentTargets), {\n ignoreInitial: true,\n awaitWriteFinish: { stabilityThreshold: 400, pollInterval: 50 },\n usePolling: !!opts.poll,\n ignored: ignoredFn,\n });\n\n const logTrigger = (type: 'add' | 'change' | 'unlink', file: string) => {\n if (opts.json) out.jsonData({ event: 'trigger', type, file });\n };\n\n watcher\n .on('add', (p) => {\n logTrigger('add', p);\n trigger(p);\n })\n .on('change', (p) => {\n logTrigger('change', p);\n trigger(p);\n })\n .on('unlink', (p) => {\n logTrigger('unlink', p);\n trigger(p);\n });\n\n let lastFiles: string[] = [];\n\n /**\n * One generator finishing a watch rebuild, reported the same way for every kind.\n *\n * The event keys are the ones `--json` has always emitted, because a watch feeding a script is\n * the only reader that shape has. The human form is narration, so it goes to stderr with\n * everything else this command prints.\n */\n const watchGenerated = (kind: string, files: string[]) => {\n if (opts.json) {\n out.jsonData({ event: 'generate_complete', kind, files });\n return;\n }\n out.succeed(\n out.errStyle.green(`Generated (${kind}): ${files.length} files`) +\n (files.length ? ' ' + files.map((f) => out.errStyle.cyan(f)).join(', ') : '')\n );\n };\n\n const run = async () => {\n try {\n const reloaded = await loadConfig(opts.config, (w) => out.warn(w));\n if (!reloaded) throw new Error('Config disappeared during watch.');\n cfg = reloaded;\n\n // Re-resolved on every rebuild, for the same reason the config is: an edit to\n // drizzle.config.ts mid-watch changes which files are the schema, and a new file that\n // matches its glob has to join the set. The watch targets are recomputed from the\n // fresh resolution, so a schema directory added to the kit config starts being\n // watched on the rebuild that first read it.\n source = await resolveSchemaSource(cfg);\n // The same single-file fill `generate` makes, for the same consumer (`schemaPath` in\n // validation-options.ts), so the two dispatch loops hand the generators the same\n // options and the branch-parity contract holds for interop configs too.\n if (!cfg.schema && Array.isArray(source.schema) && source.schema.length === 1) {\n cfg = { ...cfg, schema: source.schema[0] };\n }\n\n rebuildIgnoreDirsFrom(cfg);\n const nextTargets = new Set<string>(\n computeWatchTargets(cfg, process.cwd(), source).map(abs)\n );\n syncWatcherTargets(watcher, nextTargets);\n\n clearScreen();\n\n if (opts.json) {\n out.jsonData({\n event: 'watch_config_applied',\n targets: Array.from(currentTargets),\n ignored: Array.from(ignoredOutDirs),\n });\n }\n\n // After the clear above, or the warning would be wiped before anyone saw it.\n for (const w of source.warnings) out.warn(w);\n\n const analyzer = new SchemaAnalyzer(source.schema);\n const analysis = await analyzer.analyze({\n includeRelations: cfg.analyzer.includeRelations,\n validateConstraints: cfg.analyzer.validateConstraints,\n includeHeuristicRelations: cfg.analyzer.includeHeuristicRelations,\n });\n // The same cross-check `generate` makes, in the same wording, so the two commands\n // cannot disagree about what a contradictory dialect line means.\n const dialectWarning = dialectMismatchWarning({\n configPath: source.drizzleKitConfigPath ?? '',\n declared: source.drizzleKitDialect,\n analyzed: analysis.dialect,\n });\n if (dialectWarning) out.warn(dialectWarning);\n const loadFailure = schemaLoadFailure(analysis.issues, source.schema);\n if (loadFailure) {\n reportWatchProblem(loadFailure);\n return;\n }\n // Same order and the same reasons as `generate`. A config edited mid-watch that names a\n // column that does not exist throws here, and `run`'s own catch reports it and keeps\n // watching, so the next save can fix it.\n const narrowed = filterColumns(analysis.tables, cfg.columns);\n const filterWarnings = tableFilterWarnings(narrowed.tables, cfg);\n analysis.tables = filterTables(narrowed.tables, cfg);\n for (const w of [...narrowed.warnings, ...filterWarnings]) out.warn(w);\n for (const w of wideColumnWarning(analysis.issues)) out.warn(w);\n\n if (selection.analyzeOnly) {\n if (opts.json) {\n out.jsonData({\n event: 'analyze_complete',\n issues: analysis.issues,\n tables: analysis.tables.length,\n });\n } else {\n out.succeed('Analyze complete.');\n }\n return;\n }\n\n // Item 71, and after the analyze pipeline rather than before it, so the two commands that\n // report an analysis agree: `drzl analyze` on a schema with no tables exits 0 and prints\n // an analysis with none, because that is a true answer to the question it was asked.\n // Generating from it is a different question, and the answer to that one is that there is\n // nothing to write.\n const empty = nothingToGenerate({\n schema: source.schema,\n analyzed: narrowed.tables,\n remaining: analysis.tables,\n });\n if (empty) {\n reportWatchProblem(empty);\n return;\n }\n\n const newFiles: string[] = [];\n\n // Where the service generator is really writing, so a router template that imports\n // services spells a path that exists. `generate` has always computed this; `watch` did\n // not, so a rebuild silently emitted the default. One function now, shared by both.\n const servicesDir = resolveServicesDir(cfg);\n\n // A selection that names a kind this config does not is reported and waited out rather\n // than fatal, unlike an unknown kind on the command line: the config is reloaded on every\n // rebuild, so adding the generator to it is a save away.\n const unmatched = emptySelectionMessage(selection.kinds, cfg.generators);\n if (unmatched) {\n if (opts.json) out.jsonData({ event: 'error', code: 'DRZL_CLI_ONLY', message: unmatched });\n else {\n out.error(unmatched);\n out.hint('Add it to \"generators\" in your config, or name a kind that is already there.');\n }\n return;\n }\n\n for (const g of selectGenerators(cfg.generators, selection.kinds)) {\n // The registry, the same list `generate` dispatches over. Two hand-written copies of\n // this chain are what let five validation options reach one command and not the other,\n // and what left `watch` with no json-schema branch at all for a while.\n const entry = GENERATOR_BY_KIND.get(g.kind);\n if (!entry) continue;\n try {\n const files = await runGenerator(entry, g, cfg, { analysis, servicesDir });\n watchGenerated(g.kind, files);\n newFiles.push(...files);\n } catch (e: any) {\n reportGeneratorFailure(out, g.kind, e);\n return;\n }\n }\n\n const added = newFiles.filter((f) => !lastFiles.includes(f));\n const removed = lastFiles.filter((f) => !newFiles.includes(f));\n if (opts.json) {\n out.jsonData({ event: 'diff', added, removed });\n } else {\n if (added.length) out.note(out.errStyle.blue(`Added: ${added.join(', ')}`));\n if (removed.length) out.warn(`Removed: ${removed.join(', ')}`);\n }\n if (newFiles.length) {\n // The kinds this rebuild ran, however they were named. `--pipeline generate-trpc` and\n // `--only trpc` are the same run and now report the same reason.\n const reason = selection.kinds ? `watch:${[...selection.kinds].join(',')}` : 'watch';\n maybeShowSponsorMessage({ reason, out });\n }\n lastFiles = newFiles;\n } catch (e: any) {\n const msg = messageOf(e);\n if (opts.json) out.jsonData({ event: 'error', message: msg });\n else out.error('Watch pipeline failed:', msg);\n }\n };\n\n // Item 75. The debounce that was here collapsed the wait and not the work, so a change\n // arriving during a rebuild started a second one on top of it; see `watch-loop.ts` for the\n // measurement. `run` itself is unchanged, and the scheduler decides when it happens.\n const scheduler = createRebuildScheduler({\n run,\n debounceMs: resolveDebounce(opts.debounce, (w) => out.warn(w)),\n });\n\n const trigger = (file?: string) => {\n if (file) {\n const full = abs(file);\n for (const dir of ignoredOutDirs) {\n if (full === dir || isInside(full, dir)) return;\n }\n }\n scheduler.trigger();\n };\n\n if (opts.json) {\n out.jsonData({\n event: 'watching',\n targets: Array.from(currentTargets),\n ignored: Array.from(ignoredOutDirs),\n });\n } else {\n out.note(\n out.errStyle.gray(\n 'Watching:\\n ' +\n Array.from(currentTargets)\n .map((p) => path.relative(process.cwd(), p))\n .join('\\n ')\n )\n );\n }\n\n watcher\n .on('add', (p) => trigger(p))\n .on('change', (p) => trigger(p))\n .on('unlink', (p) => trigger(p))\n .on('error', (err) => out.error('Watcher error:', messageOf(err)));\n\n // Through the same guard as every later rebuild, so a save landing during the startup build\n // waits for it rather than racing it. The watcher is attached by now, which is exactly when\n // that becomes possible.\n await scheduler.runNow();\n });\n\nwithOutputFlags(\n program\n .command('init')\n .description('Scaffold a drzl.config.ts, finding your schema and asking what to generate')\n .option('-y, --yes', 'take the defaults and ask nothing')\n .option('--schema <path>', 'the schema file to write into the config, skipping detection')\n .option(\n '--generators <list>',\n `comma-separated: ${INIT_GENERATOR_CHOICES.map((c) => c.kind).join(', ')}`\n )\n).action(async (opts: any) => {\n const out = outputFor(opts);\n const failures: string[] = [];\n // Every prompt has a flag, and every flag skips its prompt. That equivalence is what keeps\n // the interactive command usable from CI: nothing can only be answered by a human.\n //\n // `--json` forces the non-interactive path as well as the shape. A prompt written into a\n // document is a question nobody will answer and a document nobody can parse, and `--json` is\n // only ever passed by something that is not a person.\n const outcome = await runInit({\n cwd: process.cwd(),\n yes: !!opts.yes || !!opts.json,\n schemaFlag: opts.schema,\n generatorsFlag: opts.generators,\n stdin: process.stdin,\n stdout: process.stdout,\n env: process.env,\n // Narration on stderr, all of it: what `init` produces is a file on disk, and the lines it\n // prints are a report about that.\n log: (s) => out.note(s.startsWith('Created ') ? out.errStyle.green(s) : out.errStyle.gray(s)),\n error: (s) => {\n failures.push(s);\n out.error(s);\n },\n });\n if (opts.json) {\n out.jsonData(\n outcome.code === 0\n ? {\n ok: true,\n command: 'init',\n exitCode: EXIT_OK,\n written: outcome.written,\n schema: outcome.plan?.schema ?? null,\n schemaSource: outcome.plan?.schemaSource ?? null,\n generators: outcome.plan?.generators ?? [],\n }\n : jsonFailure('init', 'DRZL_CLI_INIT', failures.join(' ') || 'init did not write a config')\n );\n }\n process.exit(outcome.code === 0 ? EXIT_OK : EXIT_FAILED);\n});\n\n/**\n * Tell the user which columns got a validator that accepts anything.\n *\n * This is the user-facing half of a check `verify-packed.sh` runs on this repository. Two real\n * bugs took exactly this shape, `.array()` and `pgEnum` columns coming back untyped on\n * drizzle-orm 0.4x, and the only way anyone noticed was reading the generated file. A user whose\n * schema uses a type nobody here has modelled gets the same silence, and no gate of ours helps\n * them.\n *\n * Printed once with a count rather than a line per column, so a schema with fifty custom types\n * stays readable.\n */\nfunction wideColumnWarning(\n issues: Array<{ code?: string; message?: string; hint?: string }>\n): string[] {\n const wide = issues.filter((i) => i.code === 'DRZL_ANL_UNKNOWN_COLUMN');\n if (!wide.length) return [];\n // One string rather than a write per line. The caller both prints it and puts it in the\n // `--json` document, and a warning split across six writes cannot be put in a document at all\n // without the two shapes drifting apart.\n const lines = [`\\n${wide.length} column${wide.length === 1 ? '' : 's'} could not be typed:`];\n for (const i of wide.slice(0, 10)) lines.push(` - ${i.message}`);\n if (wide.length > 10) lines.push(` ... and ${wide.length - 10} more`);\n // One hint for the set, since they are almost always the same two.\n for (const h of [...new Set(wide.map((i) => i.hint).filter(Boolean))]) lines.push(` ${h}`);\n // Untypeable columns are the only thing this line can see. A CHECK constraint the generators\n // decline produces no output at all and so cannot be counted here without parsing every one of\n // them on the generate path, which is what `doctor` is for.\n lines.push(' Run `drzl doctor` for the full report.');\n return [lines.join('\\n')];\n}\n\nprogram.parseAsync(process.argv);\n","/**\n * Everything the CLI writes: which stream, in what shape, and whether it carries colour.\n *\n * Five plan items are one layer, and this file is that layer (items 72, 73, 74, 76, 77). Before it\n * existed, each of the seven commands answered those questions for itself by reaching for `chalk`,\n * `ora`, `cli-progress` and `console.log` at the call site, and the answers disagreed. Four of the\n * disagreements were measured against the built 4.22.0 CLI, each command run with stdout and stderr\n * on separate channels so the two could be told apart:\n *\n * - **`NO_COLOR` did nothing at all (item 76).** `chalk@6.0.0` vendors its own `supports-color`,\n * and that copy contains the string `FORCE_COLOR` ten times and the string `NO_COLOR` zero\n * times. Measured: on a pty with `NO_COLOR=1`, `chalk.level` is still 3 and `chalk.green('x')`\n * still returns `\u001b[32mx\u001b[39m`. `drzl doctor` emitted the same 32 escape sequences with\n * the variable set as without it.\n *\n * - **Colour was decided from the wrong stream (items 76, 77).** chalk's default instance takes\n * its level from `supportsColor.stdout` alone (`const colorLevel = stdoutColor ? ... : 0`), and\n * the CLI writes most of its narration to stderr. So `drzl generate > out.txt` with a terminal\n * still on stderr turned the warnings on that terminal colourless, because a *different* stream\n * had been redirected. chalk exposes `supportsColor.stderr` as well; nothing used it.\n *\n * - **An escape leaked into piped output regardless (item 77).** Not from chalk, which does check\n * `isTTY`, but from `ora`'s success symbol: `log-symbols` colours it with `yoctocolors`, which\n * reads `TERM`, `COLORTERM`, `FORCE_COLOR` and `NO_COLOR` and never asks whether the stream is a\n * terminal. Measured on an ordinary developer machine where `TERM` is set: `drzl analyze 2> log`\n * wrote `\u001b[32m✔\u001b[39m Analyzed in 46ms` into the file. So the symbol is rendered\n * here now and `ora` is asked only to spin.\n *\n * - **Narration sat on stdout (item 73).** The sponsor tip was written with `console.log`, so\n * `drzl generate | ...` fed 246 bytes of advertisement into whatever was parsing the file list.\n * `--json` cannot be a contract while anything but the document shares that stream.\n *\n * The rule the rest of the CLI follows from here: **stdout carries the answer, stderr carries the\n * narration.** Under `--json` stdout carries exactly one JSON document and nothing else, on\n * success and on failure alike, so `drzl <cmd> --json | jq .` parses with no filtering.\n */\nimport { Chalk, type ChalkInstance } from 'chalk';\nimport cliProgress from 'cli-progress';\nimport ora, { type Ora } from 'ora';\n\n/** The subset of a stream this module needs, so tests can pass an ordinary object. */\nexport interface OutputStream {\n write(chunk: string): unknown;\n isTTY?: boolean;\n columns?: number;\n}\n\nexport type Env = Record<string, string | undefined>;\n\nexport type ColorLevel = 0 | 1 | 2 | 3;\n\n/**\n * The three exit codes, and there are only three on purpose.\n *\n * Before this, `2` meant \"the analysis found errors\" from `analyze`, \"findings were reported and\n * you asked for strictness\" from `doctor`, and \"there is no config file\" from `generate` and\n * `watch`; `1` meant \"the schema could not be read\" from `doctor` but \"a generator threw\" from\n * `generate`. Three commands used the same number for three unrelated events, which is the same as\n * having no scheme.\n *\n * The distinction worth encoding is the one a pipeline acts on differently: work that could not be\n * done at all, against work that was done and turned something up. A build reacts to the first by\n * stopping, and to the second by showing a diff or a report. Everything else is prose and belongs\n * in the message.\n */\nexport const EXIT_OK = 0;\n/** DRZL could not do the work: bad config, unreadable schema, a generator threw, a write failed. */\nexport const EXIT_FAILED = 1;\n/**\n * DRZL did the work and found what it was asked to look for: `generate --check` drift,\n * `doctor --strict` findings, `analyze` error-level issues.\n */\nexport const EXIT_FINDINGS = 2;\n\n/**\n * How many tables make a progress bar worth drawing.\n *\n * Measured rather than chosen. The generator loop the bar covers costs about 105ms fixed plus\n * 3.6ms per table on this machine (1 table 109ms, 10 tables 181ms, 50 tables 354ms, 100 tables\n * 561ms, 200 tables 901ms, 400 tables 1549ms), and `cli-progress` redraws at 10fps. A bar drawn\n * over a shorter loop therefore paints one frame reading `0%` and is then wiped by `stop()`\n * without ever advancing, which is exactly what item 72 reports: a full-width bar appearing for a\n * single table and saying nothing.\n *\n * 25 tables is where the loop first outlasts a frame, so the bar is only ever drawn when it will\n * move at least once. Below it the run is already described by the two lines around it: the\n * analysis time, and the file count per generator.\n */\nexport const PROGRESS_MIN_TABLES = 25;\n\n/**\n * Whether a stream should carry colour, and how much.\n *\n * Asked once per stream rather than once per process. That is the whole of item 77 and half of\n * item 76: `drzl generate > file` leaves stderr a terminal and stdout a file, and the two answers\n * differ.\n *\n * `NO_COLOR` beats `FORCE_COLOR`, which is the one place this departs from chalk. The reason is\n * which of them a human sets: `NO_COLOR` goes in a shell profile and is a standing preference,\n * while `FORCE_COLOR` is overwhelmingly injected by a wrapper (CI runners set it, and so does the\n * shell this was developed in, which set `FORCE_COLOR=3` and made every command look like a colour\n * leak until it was stripped). A wrapper's guess must not overrule a person's refusal. It also\n * makes every colour rule testable through an ordinary pipe, with no pseudo-terminal, because\n * `FORCE_COLOR=1` turns colour on where a pipe would have it off.\n *\n * `NO_COLOR` follows no-color.org: any value except the empty string counts as set.\n */\nexport function colorLevelFor(stream: OutputStream, env: Env): ColorLevel {\n if (env.NO_COLOR !== undefined && env.NO_COLOR !== '') return 0;\n if (env.TERM === 'dumb') return 0;\n\n const forced = env.FORCE_COLOR;\n if (forced !== undefined) {\n if (forced === 'false' || forced === '0') return 0;\n if (forced === '' || forced === 'true') return 1;\n const n = Number.parseInt(forced, 10);\n if (Number.isInteger(n)) return Math.min(Math.max(n, 0), 3) as ColorLevel;\n return 1;\n }\n\n if (!stream.isTTY) return 0;\n // A terminal that says it can do more is believed, and one that says nothing gets the sixteen\n // colours every terminal emulator has had for thirty years.\n if (env.COLORTERM === 'truecolor' || env.COLORTERM === '24bit') return 3;\n if (env.TERM?.includes('256')) return 2;\n return 1;\n}\n\n/** Whether a progress bar earns its place. Split out so the four reasons can be tested apart. */\nexport function shouldShowProgress(opts: {\n tables: number;\n stderr: OutputStream;\n quiet: boolean;\n json: boolean;\n}): boolean {\n if (opts.quiet || opts.json) return false;\n if (!opts.stderr.isTTY) return false;\n return opts.tables >= PROGRESS_MIN_TABLES;\n}\n\n/** What `createProgress` hands back, so the call site never touches `cli-progress` directly. */\nexport interface Progress {\n start(): void;\n update(value: number): void;\n stop(): void;\n}\n\n/** A progress bar, or a shaped hole where one would have been. */\nfunction createProgress(enabled: boolean, total: number, stream: OutputStream): Progress {\n if (!enabled) {\n return { start() {}, update() {}, stop() {} };\n }\n const bar = new cliProgress.SingleBar(\n { hideCursor: true, stream: stream as NodeJS.WritableStream },\n cliProgress.Presets.shades_classic\n );\n // `running` is what makes `start` and `stop` safe to call in any order. The dispatch loop calls\n // `stop()` from thirteen branches and from their catch blocks, and before this the bar was\n // started once outside the loop, so the second generator in a config updated a bar that the\n // first had already stopped.\n let running = false;\n return {\n start() {\n if (running) return;\n bar.start(total, 0);\n running = true;\n },\n update(value: number) {\n if (running) bar.update(value);\n },\n stop() {\n if (!running) return;\n bar.stop();\n running = false;\n },\n };\n}\n\n/** A spinner, or a shaped hole. Never renders the completion symbol itself; see `Output.succeed`. */\nexport interface Spinner {\n succeed(text: string): void;\n fail(text: string): void;\n stop(): void;\n}\n\nexport interface OutputOptions {\n stdout?: OutputStream;\n stderr?: OutputStream;\n env?: Env;\n quiet?: boolean;\n json?: boolean;\n}\n\n/**\n * Every write the CLI makes, with the stream and the colour already decided.\n *\n * `data` is the only method that reaches stdout. Everything else is narration and goes to stderr,\n * where `--quiet` can drop it without touching either the answer or the exit code.\n */\nexport class Output {\n readonly stdout: OutputStream;\n readonly stderr: OutputStream;\n readonly env: Env;\n readonly quiet: boolean;\n readonly json: boolean;\n /** Chalk bound to stdout's answer. */\n readonly outStyle: ChalkInstance;\n /** Chalk bound to stderr's answer, which is a different question. */\n readonly errStyle: ChalkInstance;\n\n constructor(options: OutputOptions = {}) {\n this.stdout = options.stdout ?? process.stdout;\n this.stderr = options.stderr ?? process.stderr;\n this.env = options.env ?? process.env;\n this.quiet = options.quiet ?? false;\n this.json = options.json ?? false;\n this.outStyle = new Chalk({ level: colorLevelFor(this.stdout, this.env) });\n this.errStyle = new Chalk({ level: colorLevelFor(this.stderr, this.env) });\n }\n\n /** The command's answer. Never suppressed by `--quiet`, because then nothing would be left. */\n data(text: string): void {\n this.stdout.write(text.endsWith('\\n') ? text : text + '\\n');\n }\n\n /**\n * The one JSON document `--json` promises, and the reason nothing else may touch stdout.\n *\n * Stringified without indentation on purpose: this is a machine's copy, `jq` formats it for a\n * human, and the two commands that already print an indented document (`analyze`, `doctor`) keep\n * doing so through `data` because their shape is a published contract.\n */\n jsonData(payload: unknown): void {\n this.data(JSON.stringify(payload));\n }\n\n /** Narration. Dropped by `--quiet` and by `--json`. */\n note(text: string): void {\n if (this.quiet || this.json) return;\n this.stderr.write(text + '\\n');\n }\n\n /** A warning: narration a user asked to be quiet still does not need. */\n warn(text: string): void {\n if (this.quiet || this.json) return;\n this.stderr.write(this.errStyle.yellow(text) + '\\n');\n }\n\n /**\n * A failure. Never suppressed by anything, because a script that cannot tell a success from a\n * swallowed failure is worse off than one with no `--quiet` at all.\n *\n * Under `--json` the machine-readable failure goes to stdout as the document, so this stays\n * quiet there rather than printing the same fact twice in two shapes.\n */\n error(text: string, detail?: string): void {\n if (this.json) return;\n const line = this.errStyle.red(text) + (detail ? ' ' + detail : '');\n this.stderr.write(line + '\\n');\n }\n\n /** A hint under an error. Suppressed by `--quiet`: the error above it already said what broke. */\n hint(text: string): void {\n if (this.quiet || this.json) return;\n this.stderr.write(this.errStyle.dim(text) + '\\n');\n }\n\n /**\n * A spinner on stderr, or nothing.\n *\n * `ora` is constructed only when stderr is a terminal. Given a pipe it still writes its text\n * once as `- Analyzing...`, which is a line nobody reading a log wants, and given `NO_COLOR` it\n * writes a coloured symbol anyway. Both are avoided by not building it.\n */\n spinner(text: string): Spinner {\n const live: Ora | null =\n !this.quiet && !this.json && this.stderr.isTTY\n ? ora({\n text,\n stream: this.stderr as NodeJS.WritableStream,\n // ora paints its own frame cyan through its own chalk, which is a second colour\n // decision beside this one and does not read `NO_COLOR` either. Measured with the\n // variable set: everything else on the line went plain and the spinner frame arrived\n // as `[36m⠋[39m`. `false` is ora's documented way to turn that off.\n color: this.errStyle.level > 0 ? 'cyan' : false,\n }).start()\n : null;\n return {\n succeed: (done: string) => {\n live?.stop();\n this.succeed(done);\n },\n fail: (done: string) => {\n live?.stop();\n this.error(done);\n },\n stop: () => live?.stop(),\n };\n }\n\n /**\n * A completed step.\n *\n * The tick is rendered here rather than by `ora.succeed`, which is the fix for the escape that\n * reached piped output: `log-symbols` colours the symbol from the environment alone and never\n * looks at the stream, so `drzl analyze 2> log` used to write `\u001b[32m✔\u001b[39m` into\n * the file. Here the symbol goes through the same per-stream decision as everything else.\n */\n succeed(text: string): void {\n if (this.quiet || this.json) return;\n this.stderr.write(this.errStyle.green('✔') + ' ' + text + '\\n');\n }\n\n /** A progress bar for `tables` items, or a no-op. See `shouldShowProgress` for the four gates. */\n progress(tables: number): Progress {\n return createProgress(\n shouldShowProgress({\n tables,\n stderr: this.stderr,\n quiet: this.quiet,\n json: this.json,\n }),\n tables,\n this.stderr\n );\n }\n\n /**\n * Whether an unrequested extra, such as the sponsor tip, should be shown at all.\n *\n * A terminal is the only place an aside has a reader. Piped into a file it is noise in someone's\n * log, and under `--json` it would be noise in the middle of a document.\n */\n get wantsAsides(): boolean {\n return !this.quiet && !this.json && Boolean(this.stderr.isTTY);\n }\n}\n\n/** The failure document every command emits under `--json`, whatever went wrong. */\nexport interface JsonFailure {\n ok: false;\n command: string;\n code: string;\n message: string;\n exitCode: number;\n}\n\n/**\n * The failure half of the `--json` contract.\n *\n * A `--json` run writes one document on stdout whether it worked or not, because the case people\n * script against is the one that fails, and a command whose failure exists only as prose on stderr\n * forces every caller to parse English.\n *\n * `ok: false` appears here and nowhere in the shared envelope, which is deliberate: `doctor` has\n * published an `ok` of its own since it shipped, meaning \"nothing to report about your schema\",\n * and that is a different question from whether the run worked. Redefining it would break a\n * documented field and carrying both spellings would let them disagree, so the run's answer is\n * `exitCode` on every document, and `ok` keeps its own meaning where it already had one. A failure\n * document has no payload to collide with, so it says `ok: false` plainly.\n */\nexport function jsonFailure(\n command: string,\n code: string,\n message: string,\n exitCode: number = EXIT_FAILED\n): JsonFailure {\n return { ok: false, command, code, message, exitCode };\n}\n\n/**\n * The message off a thrown value, whatever was thrown.\n *\n * Whole, not the first line. The config validator throws a zod error whose message is a formatted\n * JSON array, and the first line of that is `[`, so truncating it would turn \"your config names no\n * generators\" into a bracket. The `--json` document carries the same string, where newlines cost\n * nothing.\n */\nexport function messageOf(value: unknown): string {\n const message = (value as { message?: string })?.message;\n return String(message ?? value);\n}\n","/**\n * The options `@drzl/generator-express` receives, built in one place.\n *\n * `generate` and `watch` each dispatch over `cfg.generators` in their own loop, and every branch\n * in both used to assemble its own options object by hand. Four documented options have already\n * been found dead that way, which is why every router branch now calls a shared builder and a\n * branch-parity spec compares the bytes the two commands write:\n * `packages/cli/test/express-branch-parity.spec.ts` for this one.\n *\n * There is no `validator` here, unlike `honoOptions`, because the Express generator has exactly\n * one middleware and emits it: Express has no official validator packages for a config to choose\n * between. There is no `servicesDir` and no `databaseInjection` either, deliberately: this\n * generator emits stub handlers and never calls a service, so passing either would be wiring an\n * option nothing reads. `resolveConfig` warns when a config sets `databaseInjection` on this\n * generator for the same reason.\n */\nimport { expressOutDir } from './config.js';\n\n/** A generator entry from the config, loosely typed because the config schema owns its shape. */\ntype GeneratorConfig = {\n path?: string;\n includeRelations?: unknown;\n naming?: unknown;\n outputHeader?: unknown;\n format?: unknown;\n importExtension?: unknown;\n validation?: unknown;\n};\n\nexport function expressOptions(\n g: GeneratorConfig,\n cfg: { outDir: string }\n): Record<string, unknown> {\n return {\n outputDir: expressOutDir(g, cfg),\n includeRelations: g.includeRelations,\n naming: g.naming,\n outputHeader: g.outputHeader,\n format: g.format,\n importExtension: g.importExtension,\n validation: g.validation,\n };\n}\n","/**\n * The options `@drzl/generator-fastify` receives, built in one place.\n *\n * `generate` and `watch` each dispatch over `cfg.generators` in their own loop, and every branch\n * in both used to assemble its own options object by hand. Four documented options have already\n * been found dead that way, which is why every router branch now calls a shared builder and a\n * branch-parity spec compares the bytes the two commands write:\n * `packages/cli/test/fastify-branch-parity.spec.ts` for this one.\n *\n * There is no `validation` here, unlike the hono and express builders, because the Fastify\n * generator has no validation library to choose and no shared schema module to import: its route\n * schemas are JSON Schema produced by the same builder as the `json-schema` generator and\n * inlined into the routes, and Fastify's own AJV is the validator. `resolveConfig` warns when a\n * config sets `validation` on this generator for the same reason. There is no `servicesDir` and\n * no `databaseInjection` either, deliberately: this generator emits stub handlers and never\n * calls a service, so passing either would be wiring an option nothing reads, and `resolveConfig`\n * warns about `databaseInjection` too.\n */\nimport { fastifyOutDir } from './config.js';\n\n/** A generator entry from the config, loosely typed because the config schema owns its shape. */\ntype GeneratorConfig = {\n path?: string;\n includeRelations?: unknown;\n naming?: unknown;\n outputHeader?: unknown;\n format?: unknown;\n importExtension?: unknown;\n};\n\nexport function fastifyOptions(\n g: GeneratorConfig,\n cfg: { outDir: string }\n): Record<string, unknown> {\n return {\n outputDir: fastifyOutDir(g, cfg),\n includeRelations: g.includeRelations,\n naming: g.naming,\n outputHeader: g.outputHeader,\n format: g.format,\n importExtension: g.importExtension,\n };\n}\n","/**\n * Loading an optional generator package, and telling absence apart from failure.\n *\n * Every validation generator is loaded on demand, because a project that only wants zod should not\n * have to install five. That makes \"the package is not installed\" a real, expected outcome worth a\n * helpful message. It does not make it the only outcome: a generator that is installed and running\n * can throw for any reason a program can throw, and the CLI reported all of those as a missing npm\n * package too, with the true reason printed underneath as a detail.\n *\n * Node reports an unresolvable import as `ERR_MODULE_NOT_FOUND`, and reports the same code when\n * the module resolved and something *it* imported did not. The code alone therefore does not\n * separate the two; the message does, because it names the specifier that failed to resolve.\n */\n\n/** A generator package that is not installed. Everything else is somebody's real error. */\nexport class GeneratorNotInstalledError extends Error {\n constructor(\n readonly specifier: string,\n /** What Node threw, kept so nothing is discarded on the way to the message. */\n readonly reason: unknown\n ) {\n super(`${specifier} is not installed`);\n this.name = 'GeneratorNotInstalledError';\n }\n}\n\n/**\n * Whether `err` is Node refusing to resolve `specifier` itself.\n *\n * Measured on Node 22, from an ESM entry and from a CJS one, since the CLI ships both builds and\n * the bundler leaves `import()` as `import()` in each:\n *\n * absent package ERR_MODULE_NOT_FOUND, `Cannot find package '<specifier>' imported…`\n * present, inner dep absent ERR_MODULE_NOT_FOUND, naming the *inner* specifier instead\n * present, main file gone ERR_MODULE_NOT_FOUND, naming the resolved file path\n * throws while evaluating no `code` at all, and whatever message the generator threw\n *\n * Only the first is an install problem, and only the first quotes the specifier that was asked\n * for, which is what this matches on.\n */\nexport function isPackageMissing(err: unknown, specifier: string): boolean {\n const code = (err as { code?: unknown } | null | undefined)?.code;\n if (code !== 'ERR_MODULE_NOT_FOUND') return false;\n const message = (err as { message?: unknown } | null | undefined)?.message;\n return typeof message === 'string' && message.includes(`'${specifier}'`);\n}\n\n/**\n * Run `load` and re-throw a missing package as `GeneratorNotInstalledError`.\n *\n * `load` is a thunk rather than a specifier so the caller keeps a literal `import('@drzl/…')` in\n * its own source, which is what lets the bundler see the dependency. Anything it throws that is\n * not this package's own absence comes out unchanged.\n */\nexport async function loadGenerator<T>(specifier: string, load: () => Promise<T>): Promise<T> {\n try {\n return await load();\n } catch (e) {\n if (isPackageMissing(e, specifier)) throw new GeneratorNotInstalledError(specifier, e);\n throw e;\n }\n}\n","/**\n * The options `@drzl/generator-graphql` receives, built in one place.\n *\n * `generate` and `watch` each dispatch over `cfg.generators` in their own loop, and every branch\n * in both used to assemble its own options object by hand. Four documented options have already\n * been found dead that way, which is why every generator branch now calls a shared builder and a\n * branch-parity spec compares the bytes the two commands write:\n * `packages/cli/test/graphql-branch-parity.spec.ts` for this one.\n *\n * There is no `includeRelations` here, unlike the router builders: relation fields on a GraphQL\n * type are resolvers the consumer writes, not routes this generator emits. There is no\n * `servicesDir` and no `databaseInjection` either, for the stronger form of the same reason:\n * the emitted resolvers are stubs. And there is no `validation` at all, unlike every kind that\n * takes one: the emitted schema is GraphQL SDL, GraphQL's own type language, so there is no\n * library to choose, and `resolveConfig` warns about the whole block on this kind.\n */\nimport { graphqlOutDir } from './config.js';\n\n/** A generator entry from the config, loosely typed because the config schema owns its shape. */\ntype GeneratorConfig = {\n path?: string;\n naming?: unknown;\n outputHeader?: unknown;\n format?: unknown;\n importExtension?: unknown;\n};\n\nexport function graphqlOptions(\n g: GeneratorConfig,\n cfg: { outDir: string }\n): Record<string, unknown> {\n return {\n outputDir: graphqlOutDir(g, cfg),\n naming: g.naming,\n outputHeader: g.outputHeader,\n format: g.format,\n importExtension: g.importExtension,\n };\n}\n","/**\n * The options `@drzl/generator-hono` receives, built in one place.\n *\n * `generate` and `watch` each dispatch over `cfg.generators` in their own loop, and every branch\n * in both used to assemble its own options object by hand. Three documented options have already\n * been found dead that way: `typedJson` never reached typebox, `coerceDates` and `applyDefaults`\n * reached nothing but zod, and `servicesDir` was passed by `generate`'s oRPC branch and not by\n * `watch`'s, so a watch rebuild emitted a service import pointing at the default directory\n * whatever the config said. None of those is visible in the wiring: the option parses, the\n * generator defaults it, and the feature simply does nothing.\n *\n * One builder means the two call sites are the same object by construction rather than by review.\n * It also gives the drift something to be asserted against, which is what\n * `packages/cli/test/hono-branch-parity.spec.ts` does by running both commands and comparing the\n * bytes they wrote.\n *\n * There is no `servicesDir` and no `databaseInjection` here, and their absence is deliberate\n * rather than an omission: this generator emits stub handlers and never calls a service, so\n * passing either would be wiring an option nothing reads. `resolveConfig` warns when a config\n * sets `databaseInjection` on this generator for the same reason.\n */\nimport { honoOutDir } from './config.js';\n\n/** A generator entry from the config, loosely typed because the config schema owns its shape. */\ntype GeneratorConfig = {\n path?: string;\n includeRelations?: unknown;\n naming?: unknown;\n validator?: unknown;\n outputHeader?: unknown;\n format?: unknown;\n importExtension?: unknown;\n validation?: unknown;\n};\n\nexport function honoOptions(g: GeneratorConfig, cfg: { outDir: string }): Record<string, unknown> {\n return {\n outputDir: honoOutDir(g, cfg),\n includeRelations: g.includeRelations,\n naming: g.naming,\n validator: g.validator,\n outputHeader: g.outputHeader,\n format: g.format,\n importExtension: g.importExtension,\n validation: g.validation,\n };\n}\n","/**\n * The options every validation generator receives, built in one place.\n *\n * Each generator branch used to assemble this by hand, and three documented options were\n * found silently dead as a result: `typedJson` never reached typebox, and `coerceDates` and\n * `applyDefaults` never reached anything but zod. The config parsed them, the CLI dropped them,\n * and the feature simply did nothing while nothing said so. Building it once removes the class\n * rather than fixing each instance.\n *\n * What stays per-generator is a real capability rather than an oversight, which is why it is\n * named as one.\n */\n\n/**\n * A generator entry from the config, loosely typed because the config schema owns its shape.\n *\n * Exported so a builder that wraps this one names the same keys rather than restating them: every\n * key listed in two places is a key the two can drift on, which is the failure this file exists to\n * remove.\n */\nexport type ValidationGeneratorConfig = {\n outputHeader?: unknown;\n format?: unknown;\n schemaSuffix?: unknown;\n fileSuffix?: unknown;\n importExtension?: unknown;\n affix?: unknown;\n coerceDates?: unknown;\n applyDefaults?: unknown;\n typedJson?: unknown;\n typedColumns?: unknown;\n duplicateFinder?: unknown;\n constraints?: unknown;\n nestedSchemas?: unknown;\n nestedDepth?: unknown;\n branded?: unknown;\n standardSchema?: unknown;\n meta?: unknown;\n};\n\nexport interface GeneratorCapabilities {\n /**\n * Whether the generator can reference a type from the schema module.\n *\n * `typedJson` and `typedColumns` both work by importing the table back and reading\n * `typeof table.$inferSelect['col']`, so a generator that cannot embed a TypeScript type in its\n * output cannot use either. ArkType is the case: it emits one string per field, and a type\n * reference has nowhere to live inside a string DSL.\n */\n schemaTypes?: boolean;\n /**\n * Whether the generator has a `~standard` key to add.\n *\n * TypeBox is the only one that has: zod, valibot and arktype put one on every schema they build,\n * measured on 4.4.3, 1.4.2 and 2.2.3, so there is nothing for the option to do there and setting\n * it would read as a promise that something changed.\n */\n standardSchema?: boolean;\n /**\n * Whether the generator can attach metadata to what it emits.\n *\n * zod is the only one so far, and deliberately: it is the one validator here whose metadata has\n * a destination outside itself, since `z.toJSONSchema` copies arbitrary keys through into the\n * document an OpenAPI consumer reads. The other four each have a facility of their own and each\n * needs its own measurement of where the metadata has to attach, which is the whole difficulty;\n * building four on the strength of one measurement is how three of them come to be subtly wrong.\n */\n meta?: boolean;\n /**\n * Whether the generator emits the constraint ledger beside its schemas.\n *\n * zod and valibot so far, and the boundary is measured rather than conservative. The ledger\n * carries the exact message the emitted schema attaches for each constraint, which is what the\n * error map keys on, and those two enforce the same set of constraints in the same words.\n *\n * ArkType is the case that says why this is a flag. Measured on 2.2.3 against the same table:\n * it folds `cardinality(tags) > 0` into its own DSL, moves a `length()` check onto the object\n * so the issue names no column, reports DRZL's wording in `expected` rather than in `message`,\n * and emits nothing at all for `name <> 'x'`. A ledger claiming that constraint is enforced\n * would be wrong there, and it would be wrong silently.\n */\n constraints?: boolean;\n}\n\nexport function validationOptions(\n g: ValidationGeneratorConfig,\n cfg: { schema?: unknown },\n outDir: string,\n caps: GeneratorCapabilities = {}\n): Record<string, unknown> {\n return {\n outDir,\n outputHeader: g.outputHeader,\n format: g.format,\n schemaSuffix: g.schemaSuffix,\n fileSuffix: g.fileSuffix,\n importExtension: g.importExtension,\n affix: g.affix,\n coerceDates: g.coerceDates,\n applyDefaults: g.applyDefaults,\n duplicateFinder: g.duplicateFinder,\n nestedSchemas: g.nestedSchemas,\n nestedDepth: g.nestedDepth,\n // Every validation generator can express a brand, including TypeBox, which has no brand\n // helper and gets one from `TUnsafe` instead. So this needs no capability flag: an option\n // that reached only four of the five would be the class of defect this file exists to\n // remove.\n branded: g.branded,\n // Only where the generator can act on them, so an unsupported option is absent rather than\n // present and ignored.\n ...(caps.schemaTypes\n ? {\n // Needed by both: the reference is resolved relative to the emitted file.\n schemaPath: cfg.schema,\n typedJson: g.typedJson,\n typedColumns: g.typedColumns,\n }\n : {}),\n ...(caps.standardSchema ? { standardSchema: g.standardSchema } : {}),\n ...(caps.meta ? { meta: g.meta } : {}),\n ...(caps.constraints ? { constraints: g.constraints } : {}),\n };\n}\n","/**\n * The options `@drzl/generator-json-schema` receives, built in one place.\n *\n * `generate` and `watch` each dispatch over `cfg.generators` in their own loop, and the json-schema\n * branch was assembled by hand in both. That arrangement has already dropped options silently more\n * than once here: five validation options never reached a watch rebuild, and `watch` had no\n * json-schema branch at all for a while, so that directory went stale from the first save onward.\n * None of it is visible in the wiring, because the option parses, the generator defaults it, and\n * the feature simply does nothing.\n *\n * One builder makes the two call sites the same object by construction rather than by review, and\n * `packages/cli/test/openapi-branch-parity.e2e.spec.ts` runs both commands and compares the bytes.\n */\nimport { validationOptions, type ValidationGeneratorConfig } from './validation-options.js';\n\n/** A generator entry from the config, loosely typed because the config schema owns its shape. */\ntype GeneratorConfig = ValidationGeneratorConfig & {\n path?: string;\n target?: unknown;\n components?: unknown;\n document?: unknown;\n includeRelations?: unknown;\n sharedEnums?: unknown;\n};\n\nexport function jsonSchemaOptions(\n g: GeneratorConfig,\n cfg: { schema?: unknown },\n outDir: string\n): Record<string, unknown> {\n return {\n // JSON Schema is data, so nothing it emits references a type from the schema module.\n ...validationOptions(g, cfg, outDir, { schemaTypes: false }),\n target: g.target,\n components: g.components,\n document: g.document,\n // Read only while emitting a document, where it adds `/users/{id}/posts`. The per-table\n // schemas are flat whatever it says.\n includeRelations: g.includeRelations,\n // The mirror image: read only for the per-table modules, since the document shares regardless.\n sharedEnums: g.sharedEnums,\n };\n}\n","/**\n * The options `@drzl/generator-ai` receives, built in one place.\n *\n * `generate` and `watch` each dispatch over `cfg.generators` in their own loop, and every branch in\n * both used to assemble its own options object by hand. Four documented options have already been\n * found dead that way, which is why every generator branch now calls a shared builder and a\n * branch-parity spec compares the bytes the two commands write:\n * `packages/cli/test/ai-branch-parity.spec.ts` for this one.\n *\n * There is no `includeRelations` and no `databaseInjection` here, for the reasons the config parser\n * reports rather than silently honours: a relation lookup is a route and this generator emits\n * tools, and the emitted `execute` bodies are stubs that read no injected handle.\n */\nimport { aiOutDir } from './config.js';\n\n/** A generator entry from the config, loosely typed because the config schema owns its shape. */\ntype GeneratorConfig = {\n path?: string;\n naming?: unknown;\n outputHeader?: unknown;\n format?: unknown;\n importExtension?: unknown;\n validation?: unknown;\n};\n\nexport function aiOptions(g: GeneratorConfig, cfg: { outDir: string }): Record<string, unknown> {\n return {\n outputDir: aiOutDir(g, cfg),\n naming: g.naming,\n outputHeader: g.outputHeader,\n format: g.format,\n importExtension: g.importExtension,\n validation: g.validation,\n };\n}\n","/**\n * The options `@drzl/generator-effect-http` receives, built in one place.\n *\n * `generate` and `watch` each dispatch over `cfg.generators` in their own loop, and every branch in\n * both used to assemble its own options object by hand. Four documented options have already been\n * found dead that way, which is why every generator branch now calls a shared builder and a\n * branch-parity spec compares the bytes the two commands write:\n * `packages/cli/test/effect-http-branch-parity.spec.ts` for this one.\n *\n * This builder does one thing none of the others do, and the reason is that this generator has one\n * mode rather than two. It emits no schemas of its own: its endpoints declare the Effect Schema modules a\n * validation generator wrote, which is where the CHECK bounds a caller is held to come from. So\n * `useShared` is not a choice here, and the import path is derived from the sibling generator's own\n * `path` rather than left for the user to repeat. A config that names both generators and nothing\n * else is therefore complete, and a config that points somewhere specific still wins.\n */\nimport { effectHttpOutDir } from './config.js';\n\n/** A generator entry from the config, loosely typed because the config schema owns its shape. */\ntype GeneratorConfig = {\n path?: string;\n naming?: unknown;\n outputHeader?: unknown;\n format?: unknown;\n importExtension?: unknown;\n apiName?: unknown;\n validation?: {\n useShared?: boolean;\n /**\n * Accepted loosely and never read: the config enum lists the three libraries a validator\n * generator emits, `effect` is not among them, and this generator has no choice to make. The\n * config parser reports a value set here; the builder simply overrides it below.\n */\n library?: string;\n importPath?: string;\n schemaSuffix?: string;\n affix?: unknown;\n };\n};\n\n/** Where the effect generator writes when its entry names no `path`, repeated from the registry. */\nconst VALIDATOR_DEFAULT_DIRS: Record<string, string> = { effect: 'src/validators/effect' };\n\n/**\n * A generator's own `path`, spelled the way `validation.importPath` is read.\n *\n * The two look identical and are resolved against different roots. A `path` is always relative to\n * the project, which is why every generator does `path.resolve(process.cwd(), opts.outputDir)`. An\n * `importPath` beginning with `./` is deliberately relative to the *output* directory instead, so\n * a project that keeps its schemas beside its actions can say `./schemas` and mean it.\n *\n * So a `path` of `./out/schemas` copied straight across becomes `out/next/out/schemas`, which\n * resolves to nothing. Stripping the prefix is what makes the derived value mean what the sibling\n * entry said. Measured twice: once through the packed gate on the MCP generator, once here.\n */\nfunction projectRelative(p: string): string {\n return p.startsWith('./') ? p.slice(2) : p;\n}\n\nexport function effectHttpOptions(\n g: GeneratorConfig,\n cfg: { outDir: string; generators: ReadonlyArray<{ kind: string; path?: string }> }\n): Record<string, unknown> {\n const library = 'effect';\n // The sibling that writes the schemas these actions parse. Exactly one, or none: two generators\n // of the same kind mean there is no single source of truth, and the generator's own error is a\n // better answer than picking one of them here.\n const siblings = cfg.generators.filter((s) => s.kind === library);\n const derived =\n siblings.length === 1\n ? projectRelative(siblings[0].path ?? VALIDATOR_DEFAULT_DIRS[library])\n : undefined;\n\n return {\n outputDir: effectHttpOutDir(g, cfg),\n apiName: g.apiName,\n naming: g.naming,\n outputHeader: g.outputHeader,\n format: g.format,\n importExtension: g.importExtension,\n validation: {\n ...g.validation,\n library,\n useShared: true,\n importPath: g.validation?.importPath ?? derived,\n },\n };\n}\n","/**\n * The options `@drzl/generator-h3` receives, built in one place.\n *\n * `generate` and `watch` each dispatch over `cfg.generators` in their own loop, and every branch in\n * both used to assemble its own options object by hand. Four documented options have already been\n * found dead that way, which is why every generator branch now calls a shared builder and a\n * branch-parity spec compares the bytes the two commands write:\n * `packages/cli/test/h3-branch-parity.spec.ts` for this one.\n *\n * This builder does one thing none of the others do, and the reason is that this generator has one\n * mode rather than two. It emits no schemas of its own: its route handlers validate with the constrained schemas a\n * validation generator wrote, which is where the CHECK bounds a caller is held to come from. So\n * `useShared` is not a choice here, and the import path is derived from the sibling generator's own\n * `path` rather than left for the user to repeat. A config that names both generators and nothing\n * else is therefore complete, and a config that points somewhere specific still wins.\n */\nimport { h3OutDir } from './config.js';\n\n/** A generator entry from the config, loosely typed because the config schema owns its shape. */\ntype GeneratorConfig = {\n path?: string;\n naming?: unknown;\n outputHeader?: unknown;\n format?: unknown;\n importExtension?: unknown;\n h3?: unknown;\n validation?: {\n useShared?: boolean;\n library?: 'zod' | 'valibot' | 'arktype';\n importPath?: string;\n schemaSuffix?: string;\n affix?: unknown;\n };\n};\n\n/** Where each validation generator writes when its entry names no `path`, repeated from the registry. */\nconst VALIDATOR_DEFAULT_DIRS: Record<string, string> = {\n zod: 'src/validators/zod',\n valibot: 'src/validators/valibot',\n arktype: 'src/validators/arktype',\n};\n\n/**\n * A generator's own `path`, spelled the way `validation.importPath` is read.\n *\n * The two look identical and are resolved against different roots. A `path` is always relative to\n * the project, which is why every generator does `path.resolve(process.cwd(), opts.outputDir)`. An\n * `importPath` beginning with `./` is deliberately relative to the *output* directory instead, so\n * a project that keeps its schemas beside its actions can say `./schemas` and mean it.\n *\n * So a `path` of `./out/schemas` copied straight across becomes `out/next/out/schemas`, which\n * resolves to nothing. Stripping the prefix is what makes the derived value mean what the sibling\n * entry said. Measured twice: once through the packed gate on the MCP generator, once here.\n */\nfunction projectRelative(p: string): string {\n return p.startsWith('./') ? p.slice(2) : p;\n}\n\nexport function h3Options(\n g: GeneratorConfig,\n cfg: { outDir: string; generators: ReadonlyArray<{ kind: string; path?: string }> }\n): Record<string, unknown> {\n const library = g.validation?.library ?? 'zod';\n // The sibling that writes the schemas these actions parse. Exactly one, or none: two generators\n // of the same kind mean there is no single source of truth, and the generator's own error is a\n // better answer than picking one of them here.\n const siblings = cfg.generators.filter((s) => s.kind === library);\n const derived =\n siblings.length === 1\n ? projectRelative(siblings[0].path ?? VALIDATOR_DEFAULT_DIRS[library])\n : undefined;\n\n return {\n outputDir: h3OutDir(g, cfg),\n h3: g.h3,\n naming: g.naming,\n outputHeader: g.outputHeader,\n format: g.format,\n importExtension: g.importExtension,\n validation: {\n ...g.validation,\n library,\n useShared: true,\n importPath: g.validation?.importPath ?? derived,\n },\n };\n}\n","/**\n * The options `@drzl/generator-mcp` receives, built in one place.\n *\n * `generate` and `watch` each dispatch over `cfg.generators` in their own loop, and every branch\n * in both used to assemble its own options object by hand. Four documented options have already\n * been found dead that way, which is why every generator branch now calls a shared builder and a\n * branch-parity spec compares the bytes the two commands write:\n * `packages/cli/test/mcp-branch-parity.spec.ts` for this one.\n *\n * There is no `databaseInjection` here, for the reason the config parser reports rather than\n * silently honours: the emitted tool handlers are stubs, so nothing would read an injected handle.\n * `includeRelations` is absent too, since a relation lookup is a route and this generator emits\n * tools rather than routes.\n */\nimport { mcpOutDir } from './config.js';\n\n/** A generator entry from the config, loosely typed because the config schema owns its shape. */\ntype GeneratorConfig = {\n path?: string;\n sdk?: unknown;\n serverName?: unknown;\n serverVersion?: unknown;\n stdio?: unknown;\n naming?: unknown;\n outputHeader?: unknown;\n format?: unknown;\n importExtension?: unknown;\n validation?: unknown;\n};\n\nexport function mcpOptions(g: GeneratorConfig, cfg: { outDir: string }): Record<string, unknown> {\n return {\n outputDir: mcpOutDir(g, cfg),\n sdk: g.sdk,\n serverName: g.serverName,\n serverVersion: g.serverVersion,\n stdio: g.stdio,\n naming: g.naming,\n outputHeader: g.outputHeader,\n format: g.format,\n importExtension: g.importExtension,\n validation: g.validation,\n };\n}\n","/**\n * The options `@drzl/generator-next` receives, built in one place.\n *\n * `generate` and `watch` each dispatch over `cfg.generators` in their own loop, and every branch in\n * both used to assemble its own options object by hand. Four documented options have already been\n * found dead that way, which is why every generator branch now calls a shared builder and a\n * branch-parity spec compares the bytes the two commands write:\n * `packages/cli/test/next-branch-parity.spec.ts` for this one.\n *\n * This builder does one thing none of the others do, and the reason is that this generator has one\n * mode rather than two. It emits no schemas of its own: its actions parse the constrained schemas a\n * validation generator wrote, which is where the CHECK bounds a form reports come from. So\n * `useShared` is not a choice here, and the import path is derived from the sibling generator's own\n * `path` rather than left for the user to repeat. A config that names both generators and nothing\n * else is therefore complete, and a config that points somewhere specific still wins.\n */\nimport { nextOutDir } from './config.js';\n\n/** A generator entry from the config, loosely typed because the config schema owns its shape. */\ntype GeneratorConfig = {\n path?: string;\n naming?: unknown;\n outputHeader?: unknown;\n format?: unknown;\n importExtension?: unknown;\n validation?: {\n useShared?: boolean;\n library?: 'zod' | 'valibot' | 'arktype';\n importPath?: string;\n schemaSuffix?: string;\n affix?: unknown;\n };\n};\n\n/** Where each validation generator writes when its entry names no `path`, repeated from the registry. */\nconst VALIDATOR_DEFAULT_DIRS: Record<string, string> = {\n zod: 'src/validators/zod',\n valibot: 'src/validators/valibot',\n arktype: 'src/validators/arktype',\n};\n\n/**\n * A generator's own `path`, spelled the way `validation.importPath` is read.\n *\n * The two look identical and are resolved against different roots. A `path` is always relative to\n * the project, which is why every generator does `path.resolve(process.cwd(), opts.outputDir)`. An\n * `importPath` beginning with `./` is deliberately relative to the *output* directory instead, so\n * a project that keeps its schemas beside its actions can say `./schemas` and mean it.\n *\n * So a `path` of `./out/schemas` copied straight across becomes `out/next/out/schemas`, which\n * resolves to nothing. Stripping the prefix is what makes the derived value mean what the sibling\n * entry said. Measured twice: once through the packed gate on the MCP generator, once here.\n */\nfunction projectRelative(p: string): string {\n return p.startsWith('./') ? p.slice(2) : p;\n}\n\nexport function nextOptions(\n g: GeneratorConfig,\n cfg: { outDir: string; generators: ReadonlyArray<{ kind: string; path?: string }> }\n): Record<string, unknown> {\n const library = g.validation?.library ?? 'zod';\n // The sibling that writes the schemas these actions parse. Exactly one, or none: two generators\n // of the same kind mean there is no single source of truth, and the generator's own error is a\n // better answer than picking one of them here.\n const siblings = cfg.generators.filter((s) => s.kind === library);\n const derived =\n siblings.length === 1\n ? projectRelative(siblings[0].path ?? VALIDATOR_DEFAULT_DIRS[library])\n : undefined;\n\n return {\n outputDir: nextOutDir(g, cfg),\n naming: g.naming,\n outputHeader: g.outputHeader,\n format: g.format,\n importExtension: g.importExtension,\n validation: {\n ...g.validation,\n library,\n useShared: true,\n importPath: g.validation?.importPath ?? derived,\n },\n };\n}\n","/**\n * The options `@drzl/generator-tanstack-start` receives, built in one place.\n *\n * `generate` and `watch` each dispatch over `cfg.generators` in their own loop, and every branch in\n * both used to assemble its own options object by hand. Four documented options have already been\n * found dead that way, which is why every generator branch now calls a shared builder and a\n * branch-parity spec compares the bytes the two commands write:\n * `packages/cli/test/tanstack-start-branch-parity.spec.ts` for this one.\n *\n * This builder does one thing none of the others do, and the reason is that this generator has one\n * mode rather than two. It emits no schemas of its own: its server functions validate with the constrained schemas a\n * validation generator wrote, which is where the CHECK bounds a caller is held to come from. So\n * `useShared` is not a choice here, and the import path is derived from the sibling generator's own\n * `path` rather than left for the user to repeat. A config that names both generators and nothing\n * else is therefore complete, and a config that points somewhere specific still wins.\n */\nimport { tanstackStartOutDir } from './config.js';\n\n/** A generator entry from the config, loosely typed because the config schema owns its shape. */\ntype GeneratorConfig = {\n path?: string;\n naming?: unknown;\n outputHeader?: unknown;\n format?: unknown;\n importExtension?: unknown;\n validation?: {\n useShared?: boolean;\n library?: 'zod' | 'valibot' | 'arktype';\n importPath?: string;\n schemaSuffix?: string;\n affix?: unknown;\n };\n};\n\n/** Where each validation generator writes when its entry names no `path`, repeated from the registry. */\nconst VALIDATOR_DEFAULT_DIRS: Record<string, string> = {\n zod: 'src/validators/zod',\n valibot: 'src/validators/valibot',\n arktype: 'src/validators/arktype',\n};\n\n/**\n * A generator's own `path`, spelled the way `validation.importPath` is read.\n *\n * The two look identical and are resolved against different roots. A `path` is always relative to\n * the project, which is why every generator does `path.resolve(process.cwd(), opts.outputDir)`. An\n * `importPath` beginning with `./` is deliberately relative to the *output* directory instead, so\n * a project that keeps its schemas beside its actions can say `./schemas` and mean it.\n *\n * So a `path` of `./out/schemas` copied straight across becomes `out/next/out/schemas`, which\n * resolves to nothing. Stripping the prefix is what makes the derived value mean what the sibling\n * entry said. Measured twice: once through the packed gate on the MCP generator, once here.\n */\nfunction projectRelative(p: string): string {\n return p.startsWith('./') ? p.slice(2) : p;\n}\n\nexport function tanstackStartOptions(\n g: GeneratorConfig,\n cfg: { outDir: string; generators: ReadonlyArray<{ kind: string; path?: string }> }\n): Record<string, unknown> {\n const library = g.validation?.library ?? 'zod';\n // The sibling that writes the schemas these actions parse. Exactly one, or none: two generators\n // of the same kind mean there is no single source of truth, and the generator's own error is a\n // better answer than picking one of them here.\n const siblings = cfg.generators.filter((s) => s.kind === library);\n const derived =\n siblings.length === 1\n ? projectRelative(siblings[0].path ?? VALIDATOR_DEFAULT_DIRS[library])\n : undefined;\n\n return {\n outputDir: tanstackStartOutDir(g, cfg),\n naming: g.naming,\n outputHeader: g.outputHeader,\n format: g.format,\n importExtension: g.importExtension,\n validation: {\n ...g.validation,\n library,\n useShared: true,\n importPath: g.validation?.importPath ?? derived,\n },\n };\n}\n","/**\n * The options `@drzl/generator-nestjs` receives, built in one place.\n *\n * `generate` and `watch` each dispatch over `cfg.generators` in their own loop, and every branch\n * in both used to assemble its own options object by hand. Four documented options have already\n * been found dead that way, which is why every generator branch now calls a shared builder and a\n * branch-parity spec compares the bytes the two commands write:\n * `packages/cli/test/nestjs-branch-parity.spec.ts` for this one.\n *\n * There is no `includeRelations` here, unlike the router builders: relation lookups are routes,\n * and this generator emits DTO classes rather than routes, so the flag would be wiring an option\n * nothing reads. There is no `servicesDir` and no `databaseInjection` either, for the stronger\n * form of the same reason: there are no handlers at all. `validation` is forwarded whole; the\n * generator reads `library` and `resolveConfig` warns about every other key on this kind.\n */\nimport { nestjsOutDir } from './config.js';\n\n/** A generator entry from the config, loosely typed because the config schema owns its shape. */\ntype GeneratorConfig = {\n path?: string;\n naming?: unknown;\n outputHeader?: unknown;\n format?: unknown;\n importExtension?: unknown;\n validation?: unknown;\n};\n\nexport function nestjsOptions(\n g: GeneratorConfig,\n cfg: { outDir: string }\n): Record<string, unknown> {\n return {\n outputDir: nestjsOutDir(g, cfg),\n naming: g.naming,\n outputHeader: g.outputHeader,\n format: g.format,\n importExtension: g.importExtension,\n validation: g.validation,\n };\n}\n","/**\n * The options `@drzl/generator-orpc` receives, built in one place.\n *\n * The last kind to get one. `generate` and `watch` each assembled this object by hand, and the\n * two copies agreed only because somebody kept checking: `servicesDir` reached the tRPC branch of\n * one command and not the other for a whole release, which is the same shape of defect one file\n * along. The builders for the other thirteen kinds exist for that reason and this one completes\n * the set, so the registry can hand every generator its options the same way.\n *\n * `outputDir` is `cfg.outDir` and never `g.path`, which is oRPC's own arrangement rather than an\n * omission: this generator has always written where the top-level setting says, and\n * `computeGeneratorOutputDirs` adds `cfg.outDir` unconditionally for it. A `path` on an oRPC entry\n * is ignored, as it always has been, and moving it now would relocate the output of every existing\n * config that happens to set one.\n */\n\n/** A generator entry from the config, loosely typed because the config schema owns its shape. */\ntype GeneratorConfig = {\n template?: unknown;\n includeRelations?: unknown;\n naming?: unknown;\n outputHeader?: unknown;\n format?: unknown;\n templateOptions?: unknown;\n importExtension?: unknown;\n validation?: unknown;\n databaseInjection?: unknown;\n};\n\nexport function orpcOptions(\n g: GeneratorConfig,\n cfg: { outDir: string },\n servicesDir: string\n): Record<string, unknown> {\n return {\n outputDir: cfg.outDir,\n template: g.template,\n includeRelations: g.includeRelations,\n naming: g.naming,\n outputHeader: g.outputHeader,\n format: g.format,\n templateOptions: g.templateOptions,\n importExtension: g.importExtension,\n validation: g.validation,\n // Documented on this generator since it was added and unreachable from a config file for most\n // of that time, because the config schema had no such key and zod stripped it in silence.\n databaseInjection: g.databaseInjection,\n // Where the service generator is actually writing, so a router template that imports services\n // spells a path that exists. The templates default this to `src/services`, which is right only\n // by coincidence for a config that puts them elsewhere.\n servicesDir,\n };\n}\n","/**\n * The options `@drzl/generator-service` receives, built in one place.\n *\n * Assembled by hand in both dispatch loops until now, and one of them was already missing a key:\n * `databaseInjection` is what gives a generated service a `db` parameter, and a router generated\n * in injection mode calls `Service.getById(ctx.db, id)`. The two halves of one generated project\n * therefore disagreed about the signature whenever the option was set.\n *\n * `outDir`, not `outputDir`. This generator spells it the short way and the routers spell it the\n * long way, which is a difference in their published option types rather than a choice this file\n * gets to make.\n */\nimport type { ValidationGeneratorConfig } from './validation-options.js';\n\n/** A generator entry from the config, loosely typed because the config schema owns its shape. */\ntype GeneratorConfig = Pick<ValidationGeneratorConfig, 'outputHeader' | 'format'> & {\n dataAccess?: unknown;\n dbImportPath?: unknown;\n schemaImportPath?: unknown;\n importExtension?: unknown;\n databaseInjection?: unknown;\n};\n\nexport function serviceOptions(g: GeneratorConfig, outDir: string): Record<string, unknown> {\n return {\n outDir,\n outputHeader: g.outputHeader,\n format: g.format,\n dataAccess: g.dataAccess,\n dbImportPath: g.dbImportPath,\n schemaImportPath: g.schemaImportPath,\n importExtension: g.importExtension,\n databaseInjection: g.databaseInjection,\n };\n}\n","/**\n * The options `@drzl/generator-trpc` receives, built in one place.\n *\n * `generate` and `watch` each dispatch over `cfg.generators` in their own loop, and every branch\n * in both assembles its own options object by hand. Three documented options have already been\n * found dead that way: `typedJson` never reached typebox, `coerceDates` and `applyDefaults`\n * reached nothing but zod, and `servicesDir` is passed by `generate`'s oRPC branch and not by\n * `watch`'s, so a watch rebuild emits a service import pointing at the default directory whatever\n * the config says. None of those is visible in the wiring: the option parses, the generator\n * defaults it, and the feature simply does nothing.\n *\n * One builder means the two call sites are the same object by construction rather than by review.\n * It also gives the drift something to be asserted against, which is what\n * `packages/cli/test/trpc-branch-parity.spec.ts` does by running both commands and comparing the\n * bytes they wrote.\n */\nimport { trpcOutDir } from './config.js';\n\n/** A generator entry from the config, loosely typed because the config schema owns its shape. */\ntype GeneratorConfig = {\n path?: string;\n template?: unknown;\n includeRelations?: unknown;\n naming?: unknown;\n outputHeader?: unknown;\n format?: unknown;\n importExtension?: unknown;\n validation?: unknown;\n databaseInjection?: unknown;\n};\n\nexport function trpcOptions(\n g: GeneratorConfig,\n cfg: { outDir: string },\n servicesDir: string\n): Record<string, unknown> {\n return {\n outputDir: trpcOutDir(g, cfg),\n template: g.template,\n includeRelations: g.includeRelations,\n naming: g.naming,\n outputHeader: g.outputHeader,\n format: g.format,\n importExtension: g.importExtension,\n validation: g.validation,\n databaseInjection: g.databaseInjection,\n // Where the service generator is actually writing, so `template: 'service'` emits an import\n // of a module that exists. The generator defaults this to `src/services`, which is right only\n // by coincidence for a config that puts them elsewhere.\n servicesDir,\n };\n}\n","/**\n * Every generator DRZL can run, as data rather than as control flow.\n *\n * The same fourteen-way dispatch was written out four times: once inside `generate`, once inside\n * `watch`, and once each in `generate:orpc` and `generate:trpc`. Every copy repeated the package\n * name, the `import()`, the constructor, the default output directory and the call to the options\n * builder, and the copies were kept in step by review alone. Review is measurably not enough for\n * this: `servicesDir` reached one loop's tRPC branch and not the other's for a release,\n * five validation options never reached a watch rebuild at all, and `watch` had no json-schema\n * branch for a while, so that directory went stale from the first save onward. None of it was\n * visible in the wiring, because a dropped option parses, the generator defaults it, and the\n * feature silently does nothing.\n *\n * So each generator states those five facts once, here, and the commands loop over this list. A\n * new generator is one entry: adding it to the config enum and forgetting a dispatch branch is no\n * longer a state the code can be in, and `packages/cli/test/generator-registry.spec.ts` asserts\n * the registry and the config enum name the same kinds.\n *\n * The import thunks stay literal `import('@drzl/generator-…')` expressions rather than being built\n * from `specifier`, because that literal is what the bundler sees; a computed specifier would be\n * left as a runtime lookup with nothing declaring the dependency.\n */\nimport {\n aiOutDir,\n effectHttpOutDir,\n expressOutDir,\n h3OutDir,\n fastifyOutDir,\n graphqlOutDir,\n honoOutDir,\n mcpOutDir,\n nestjsOutDir,\n nextOutDir,\n tanstackStartOutDir,\n trpcOutDir,\n type DrzlConfig,\n type GeneratorKind,\n} from './config.js';\nimport { expressOptions } from './express-options.js';\nimport { fastifyOptions } from './fastify-options.js';\nimport { loadGenerator } from './generator-loader.js';\nimport { graphqlOptions } from './graphql-options.js';\nimport { honoOptions } from './hono-options.js';\nimport { jsonSchemaOptions } from './json-schema-options.js';\nimport { aiOptions } from './ai-options.js';\nimport { effectHttpOptions } from './effect-http-options.js';\nimport { h3Options } from './h3-options.js';\nimport { mcpOptions } from './mcp-options.js';\nimport { nextOptions } from './next-options.js';\nimport { tanstackStartOptions } from './tanstack-start-options.js';\nimport { nestjsOptions } from './nestjs-options.js';\nimport { orpcOptions } from './orpc-options.js';\nimport { serviceOptions } from './service-options.js';\nimport { trpcOptions } from './trpc-options.js';\nimport { validationOptions } from './validation-options.js';\n\n/** One entry of `cfg.generators`, as loosely typed here as the option builders take it. */\ntype GeneratorConfig = DrzlConfig['generators'][number];\n\n/**\n * What a generator hands back.\n *\n * Two shapes, because the packages really do differ: the routers resolve to `{ files }` and the\n * validation generators resolve to the array itself. Normalised by `filesOf` at the one call site\n * rather than by changing seven published signatures.\n */\ntype GenerateResult = string[] | { files: string[] };\n\ninterface GeneratorInstance {\n generate(options: Record<string, unknown>): Promise<GenerateResult>;\n}\n\n/** What the registry knows about one generator, and the whole of what a new one has to state. */\nexport interface GeneratorEntry {\n /** The kind a config names it by, which is also what `--only` accepts. */\n readonly kind: GeneratorKind;\n /** The npm package that carries it, named in the \"not installed\" message. */\n readonly specifier: string;\n /** A literal `import()`, so the bundler can see the dependency. */\n readonly load: () => Promise<unknown>;\n /** The constructor off that module, applied to an analysis. */\n readonly construct: (module: any, analysis: unknown) => GeneratorInstance;\n /**\n * Where this generator writes, given its config entry.\n *\n * The routers fall back to the top-level `outDir` and the rest have a default directory of their\n * own. `computeGeneratorOutputDirs` has to arrive at the same answer, because the directory a\n * watcher fails to ignore is a directory it regenerates from forever, and\n * `packages/cli/test/generator-registry.spec.ts` compares the two.\n */\n readonly outputDir: (g: GeneratorConfig, cfg: DrzlConfig) => string;\n /** The options object it receives, built by the shared builder for its kind. */\n readonly options: (\n g: GeneratorConfig,\n cfg: DrzlConfig,\n ctx: { outDir: string; servicesDir: string }\n ) => Record<string, unknown>;\n}\n\n/**\n * The default directory each generator writes to when its entry names no `path`.\n *\n * Spelled here as well as in `computeGeneratorOutputDirs` for one reason worth keeping: that\n * function is exported from the package's `./config` entry and has been since before the registry\n * existed, so it stays where its consumers expect it. The two are held together by a test rather\n * than by a comment.\n */\nconst VALIDATOR_DEFAULT_DIRS = {\n zod: 'src/validators/zod',\n valibot: 'src/validators/valibot',\n arktype: 'src/validators/arktype',\n typebox: 'src/validators/typebox',\n effect: 'src/validators/effect',\n 'json-schema': 'src/validators/json-schema',\n} as const;\n\n/** Where the service generator writes when its entry names no `path`. */\nexport const SERVICES_DEFAULT_DIR = 'src/services';\n\n/**\n * Where the service generator is writing for this config, whether or not it is being run.\n *\n * The router templates emit an import of a generated service, and the path in that import has to\n * be the path the service generator really used. Computed from the config rather than defaulted\n * inside the templates, because the template's own default is right only by coincidence for a\n * config that puts services elsewhere. `generate` has always computed it; `watch` did not, so a\n * rebuild silently emitted the default.\n */\nexport function resolveServicesDir(cfg: DrzlConfig): string {\n return cfg.generators.find((g) => g.kind === 'service')?.path ?? SERVICES_DEFAULT_DIR;\n}\n\nexport const GENERATORS: readonly GeneratorEntry[] = [\n {\n kind: 'orpc',\n specifier: '@drzl/generator-orpc',\n load: () => import('@drzl/generator-orpc'),\n construct: (m, analysis) => new m.ORPCGenerator(analysis),\n // `cfg.outDir` and never `g.path`: see `orpcOptions` for why that is this generator's own\n // arrangement rather than an oversight to correct here.\n outputDir: (_g, cfg) => cfg.outDir,\n options: (g, cfg, ctx) => orpcOptions(g, cfg, ctx.servicesDir),\n },\n {\n kind: 'trpc',\n // This one and seven others were `optionalDependencies` until every one of them had been\n // published: a package that has never existed cannot publish through npm's trusted-publisher\n // OIDC flow, so its first version goes out by hand, and naming it as a hard dependency in the\n // same release breaks `npm i @drzl/cli` for everyone until it does exist. An optional\n // dependency is skipped by the installer instead, which made that release safe.\n //\n // The side effect was invisible and lasted longer than the reason: tsup externalises\n // `dependencies` and `peerDependencies` and bundles everything else, so those eight travelled\n // inside `dist` while the other six were resolved from `node_modules`. All fourteen are on the\n // registry now and all fourteen are `dependencies`, which is what makes every one of them a\n // package that can genuinely be absent, and `loadGenerator` tell absence apart from failure\n // for every kind rather than for six of them.\n specifier: '@drzl/generator-trpc',\n load: () => import('@drzl/generator-trpc'),\n construct: (m, analysis) => new m.TRPCGenerator(analysis),\n outputDir: (g, cfg) => trpcOutDir(g, cfg),\n options: (g, cfg, ctx) => trpcOptions(g, cfg, ctx.servicesDir),\n },\n {\n kind: 'hono',\n specifier: '@drzl/generator-hono',\n load: () => import('@drzl/generator-hono'),\n construct: (m, analysis) => new m.HonoGenerator(analysis),\n outputDir: (g, cfg) => honoOutDir(g, cfg),\n options: (g, cfg) => honoOptions(g, cfg),\n },\n {\n kind: 'express',\n specifier: '@drzl/generator-express',\n load: () => import('@drzl/generator-express'),\n construct: (m, analysis) => new m.ExpressGenerator(analysis),\n outputDir: (g, cfg) => expressOutDir(g, cfg),\n options: (g, cfg) => expressOptions(g, cfg),\n },\n {\n kind: 'fastify',\n specifier: '@drzl/generator-fastify',\n load: () => import('@drzl/generator-fastify'),\n construct: (m, analysis) => new m.FastifyGenerator(analysis),\n outputDir: (g, cfg) => fastifyOutDir(g, cfg),\n options: (g, cfg) => fastifyOptions(g, cfg),\n },\n {\n kind: 'nestjs',\n specifier: '@drzl/generator-nestjs',\n load: () => import('@drzl/generator-nestjs'),\n construct: (m, analysis) => new m.NestJSGenerator(analysis),\n outputDir: (g, cfg) => nestjsOutDir(g, cfg),\n options: (g, cfg) => nestjsOptions(g, cfg),\n },\n {\n kind: 'graphql',\n specifier: '@drzl/generator-graphql',\n load: () => import('@drzl/generator-graphql'),\n construct: (m, analysis) => new m.GraphQLGenerator(analysis),\n outputDir: (g, cfg) => graphqlOutDir(g, cfg),\n options: (g, cfg) => graphqlOptions(g, cfg),\n },\n {\n kind: 'mcp',\n // This one and the three below spent one release each in `optionalDependencies`, because a\n // package that has never existed cannot publish through npm's trusted-publisher OIDC flow and\n // naming it as a hard dependency in the release that introduces it breaks `npm i @drzl/cli`\n // for everyone until the first publish lands. All four are on the registry now, so all four\n // are ordinary dependencies. `scripts/verify/stages/33-registry-deps.sh` gates both halves of\n // that rule and is what reported the promotion was due.\n specifier: '@drzl/generator-mcp',\n load: () => import('@drzl/generator-mcp'),\n construct: (m, analysis) => new m.MCPGenerator(analysis),\n outputDir: (g, cfg) => mcpOutDir(g, cfg),\n options: (g, cfg) => mcpOptions(g, cfg),\n },\n {\n kind: 'next',\n specifier: '@drzl/generator-next',\n load: () => import('@drzl/generator-next'),\n construct: (m, analysis) => new m.NextGenerator(analysis),\n outputDir: (g, cfg) => nextOutDir(g, cfg),\n options: (g, cfg) => nextOptions(g, cfg),\n },\n {\n kind: 'ai',\n specifier: '@drzl/generator-ai',\n load: () => import('@drzl/generator-ai'),\n construct: (m, analysis) => new m.AIGenerator(analysis),\n outputDir: (g, cfg) => aiOutDir(g, cfg),\n options: (g, cfg) => aiOptions(g, cfg),\n },\n {\n kind: 'tanstack-start',\n specifier: '@drzl/generator-tanstack-start',\n load: () => import('@drzl/generator-tanstack-start'),\n construct: (m, analysis) => new m.TanStackStartGenerator(analysis),\n outputDir: (g, cfg) => tanstackStartOutDir(g, cfg),\n options: (g, cfg) => tanstackStartOptions(g, cfg),\n },\n {\n kind: 'h3',\n specifier: '@drzl/generator-h3',\n load: () => import('@drzl/generator-h3'),\n construct: (m, analysis) => new m.H3Generator(analysis),\n outputDir: (g, cfg) => h3OutDir(g, cfg),\n options: (g, cfg) => h3Options(g, cfg),\n },\n {\n kind: 'effect-http',\n specifier: '@drzl/generator-effect-http',\n load: () => import('@drzl/generator-effect-http'),\n construct: (m, analysis) => new m.EffectHttpGenerator(analysis),\n outputDir: (g, cfg) => effectHttpOutDir(g, cfg),\n options: (g, cfg) => effectHttpOptions(g, cfg),\n },\n {\n kind: 'service',\n specifier: '@drzl/generator-service',\n load: () => import('@drzl/generator-service'),\n construct: (m, analysis) => new m.ServiceGenerator(analysis),\n outputDir: (g) => g.path ?? SERVICES_DEFAULT_DIR,\n options: (g, _cfg, ctx) => serviceOptions(g, ctx.outDir),\n },\n {\n kind: 'zod',\n specifier: '@drzl/generator-zod',\n load: () => import('@drzl/generator-zod'),\n construct: (m, analysis) => new m.ZodGenerator(analysis),\n outputDir: (g) => g.path ?? VALIDATOR_DEFAULT_DIRS.zod,\n // `meta` is zod-only; see `GeneratorCapabilities.meta` for why it is not passed to the other\n // four rather than being passed and ignored.\n options: (g, cfg, ctx) =>\n validationOptions(g, cfg, ctx.outDir, {\n schemaTypes: true,\n meta: true,\n constraints: true,\n }),\n },\n {\n kind: 'valibot',\n specifier: '@drzl/generator-valibot',\n load: () => import('@drzl/generator-valibot'),\n construct: (m, analysis) => new m.ValibotGenerator(analysis),\n outputDir: (g) => g.path ?? VALIDATOR_DEFAULT_DIRS.valibot,\n options: (g, cfg, ctx) =>\n validationOptions(g, cfg, ctx.outDir, { schemaTypes: true, constraints: true }),\n },\n {\n kind: 'arktype',\n specifier: '@drzl/generator-arktype',\n load: () => import('@drzl/generator-arktype'),\n construct: (m, analysis) => new m.ArkTypeGenerator(analysis),\n outputDir: (g) => g.path ?? VALIDATOR_DEFAULT_DIRS.arktype,\n options: (g, cfg, ctx) => validationOptions(g, cfg, ctx.outDir, { schemaTypes: false }),\n },\n {\n kind: 'typebox',\n specifier: '@drzl/generator-typebox',\n load: () => import('@drzl/generator-typebox'),\n construct: (m, analysis) => new m.TypeBoxGenerator(analysis),\n outputDir: (g) => g.path ?? VALIDATOR_DEFAULT_DIRS.typebox,\n options: (g, cfg, ctx) =>\n validationOptions(g, cfg, ctx.outDir, { schemaTypes: true, standardSchema: true }),\n },\n {\n kind: 'effect',\n specifier: '@drzl/generator-effect',\n load: () => import('@drzl/generator-effect'),\n construct: (m, analysis) => new m.EffectGenerator(analysis),\n outputDir: (g) => g.path ?? VALIDATOR_DEFAULT_DIRS.effect,\n options: (g, cfg, ctx) => validationOptions(g, cfg, ctx.outDir, { schemaTypes: true }),\n },\n {\n kind: 'json-schema',\n specifier: '@drzl/generator-json-schema',\n load: () => import('@drzl/generator-json-schema'),\n construct: (m, analysis) => new m.JsonSchemaGenerator(analysis),\n outputDir: (g) => g.path ?? VALIDATOR_DEFAULT_DIRS['json-schema'],\n options: (g, cfg, ctx) => jsonSchemaOptions(g, cfg, ctx.outDir),\n },\n];\n\n/** The registry by kind, since every dispatch is a lookup rather than a scan. */\nexport const GENERATOR_BY_KIND: ReadonlyMap<GeneratorKind, GeneratorEntry> = new Map(\n GENERATORS.map((entry) => [entry.kind, entry])\n);\n\n/**\n * The entry for a kind the caller already knows is real.\n *\n * Unreachable in a released build: the only kinds that reach it come from the config enum, and the\n * registry is asserted against that enum by test. It throws rather than returning `undefined` so a\n * kind added to the enum with no entry fails loudly at its first use instead of generating nothing.\n */\nexport function entryFor(kind: GeneratorKind): GeneratorEntry {\n const entry = GENERATOR_BY_KIND.get(kind);\n if (!entry) throw new Error(`No generator is registered for kind \"${kind}\".`);\n return entry;\n}\n\n/** The files a generator wrote, whichever of the two shapes it resolved to. */\nfunction filesOf(result: GenerateResult): string[] {\n return Array.isArray(result) ? result : result.files;\n}\n\n/** Everything a run needs beyond the config entry itself. */\nexport interface GeneratorRunContext {\n analysis: unknown;\n /**\n * Where the service generator is really writing, so a router template that imports services\n * spells a path that exists. Read by the oRPC and tRPC builders and ignored by the rest.\n */\n servicesDir: string;\n /**\n * The write plan, when the caller is keeping one. Absent for `watch`, which writes straight to\n * disk, and the key is omitted rather than passed as `undefined` so a generator that asks\n * whether it was given a sink gets the same answer it did before this existed.\n */\n fileSink?: unknown;\n /** Per-table progress, for the bar. Only the router generators report it. */\n onProgress?: (progress: { index: number }) => void;\n}\n\n/**\n * Load one generator, build its options, run it, and say which files it wrote.\n *\n * The one place any of that happens. A package that is not installed comes back out of\n * `loadGenerator` as `GeneratorNotInstalledError`, which is what lets the caller print the install\n * line instead of a stack trace; everything else the generator throws comes out unchanged, so a\n * generator that is present and merely failing says what really went wrong.\n */\nexport async function runGenerator(\n entry: GeneratorEntry,\n g: GeneratorConfig,\n cfg: DrzlConfig,\n ctx: GeneratorRunContext\n): Promise<string[]> {\n return runGeneratorWithOptions(entry, ctx.analysis, {\n ...entry.options(g, cfg, {\n outDir: entry.outputDir(g, cfg),\n servicesDir: ctx.servicesDir,\n }),\n ...(ctx.fileSink ? { fileSink: ctx.fileSink } : {}),\n ...(ctx.onProgress ? { onProgress: ctx.onProgress } : {}),\n });\n}\n\n/**\n * Load one generator and run it against options the caller built itself.\n *\n * For the two deprecated per-kind commands, which pass the small option set they have always\n * passed rather than the config-shaped one. They share the loading, the constructor and the\n * two-shaped result with everything else, which is all four copies of that down to one; what they\n * keep is their own options, deliberately, because a command being kept alive for compatibility\n * has to keep emitting the bytes it emitted.\n */\nexport async function runGeneratorWithOptions(\n entry: GeneratorEntry,\n analysis: unknown,\n options: Record<string, unknown>\n): Promise<string[]> {\n const module = await loadGenerator(entry.specifier, entry.load);\n return filesOf(await entry.construct(module, analysis).generate(options));\n}\n","/**\n * Which generator kinds a run was asked for: `--only`, and the `--pipeline` spelling it replaces.\n *\n * There were three vocabularies for one idea. A config says `orpc`, a command was called\n * `generate:orpc`, and a watch flag said `generate-orpc`, and the third one covered seven of the\n * fourteen kinds: `--pipeline generate-zod` matched no branch, so the watcher started, reported\n * nothing wrong, and regenerated nothing for as long as it ran. That is the defect this file was\n * written against, and `packages/cli/test/kind-selection.spec.ts` and the watch end-to-end spec\n * both fire on it.\n *\n * `--only` is the surviving spelling and takes the config's own words, so there is one vocabulary\n * left. `--pipeline` keeps working as an alias, because it is on published command lines, and it\n * now reaches every kind rather than half of them.\n *\n * The valid values come from `GeneratorKindSchema`, which is the enum the config parser and the\n * published JSON Schema are both built from. A kind added there is accepted here on the same\n * commit, and a value that is not one of them is refused by name rather than matching nothing.\n */\nimport { GENERATOR_KINDS, type GeneratorKind } from './config.js';\n\n/** The prefix `--pipeline` puts in front of a kind. */\nconst PIPELINE_PREFIX = 'generate-';\n\n/** A `--only` or `--pipeline` value the CLI will not guess at. Carries its own message. */\nexport class KindSelectionError extends Error {\n constructor(\n /** The code the `--json` failure document reports. */\n readonly code: string,\n message: string,\n /** The line printed under the error, when there is a way out worth naming. */\n readonly hint?: string\n ) {\n super(message);\n this.name = 'KindSelectionError';\n }\n}\n\n/** Every kind, as one comma-separated list, for a message that has to show what is allowed. */\nexport function kindList(): string {\n return GENERATOR_KINDS.join(', ');\n}\n\nfunction isKind(value: string): value is GeneratorKind {\n return (GENERATOR_KINDS as readonly string[]).includes(value);\n}\n\n/**\n * The kinds `--only <list>` names, or `undefined` when the flag was not passed.\n *\n * An empty set is never returned: a flag that was passed and selected nothing is a mistake worth\n * a message, not a run that quietly does nothing.\n */\nexport function parseOnly(value: unknown, flag = '--only'): Set<GeneratorKind> | undefined {\n if (value === undefined || value === null) return undefined;\n const requested = String(value)\n .split(',')\n .map((part) => part.trim())\n .filter(Boolean);\n if (!requested.length) {\n throw new KindSelectionError(\n 'DRZL_CLI_ONLY',\n `${flag} was given no kind. Pass one or more of: ${kindList()}.`\n );\n }\n const kinds = new Set<GeneratorKind>();\n for (const name of requested) {\n if (isKind(name)) {\n kinds.add(name);\n continue;\n }\n // The `generate-orpc` spelling is what `--pipeline` takes and what a reader coming from it\n // will type first, so it is named rather than listed among fourteen alternatives.\n const bare = name.startsWith(PIPELINE_PREFIX) ? name.slice(PIPELINE_PREFIX.length) : '';\n throw new KindSelectionError(\n 'DRZL_CLI_ONLY',\n `${flag}: there is no generator kind \"${name}\".`,\n isKind(bare)\n ? `Write it the way the config does: ${flag} ${bare}.`\n : `Valid kinds are: ${kindList()}.`\n );\n }\n return kinds;\n}\n\n/** What `watch` was asked to do, once `--pipeline` and `--only` have both been read. */\nexport interface WatchSelection {\n /** `--pipeline analyze`: report the analysis and run no generator. */\n analyzeOnly: boolean;\n /** The kinds to run, or `undefined` for every kind the config names. */\n kinds?: Set<GeneratorKind>;\n}\n\n/**\n * Read `--pipeline` and `--only` together.\n *\n * `--pipeline analyze` keeps the meaning it has always had. `--pipeline all` is the default and\n * selects nothing, which is how \"every generator in the config\" is spelled. Anything else is\n * `generate-<kind>`, which is `--only <kind>` written the old way.\n *\n * Passing both a narrowing `--pipeline` and `--only` is refused rather than resolved. Any rule for\n * combining them, intersection or last-wins, is one a reader would have to look up, and the two\n * flags mean the same thing.\n */\nexport function resolveWatchSelection(opts: {\n pipeline?: unknown;\n only?: unknown;\n}): WatchSelection {\n const only = parseOnly(opts.only);\n const pipeline =\n opts.pipeline === undefined || opts.pipeline === null ? 'all' : String(opts.pipeline);\n\n if (pipeline === 'analyze') {\n if (only) {\n throw new KindSelectionError(\n 'DRZL_CLI_ONLY',\n '--pipeline analyze runs no generator, so it cannot be combined with --only.',\n 'Drop one of the two.'\n );\n }\n return { analyzeOnly: true };\n }\n\n if (pipeline === 'all') return { analyzeOnly: false, kinds: only };\n\n if (only) {\n throw new KindSelectionError(\n 'DRZL_CLI_ONLY',\n '--pipeline and --only say the same thing, so passing both is ambiguous.',\n `Use --only ${[...only].join(',')} on its own; --pipeline is the older spelling.`\n );\n }\n\n const bare = pipeline.startsWith(PIPELINE_PREFIX) ? pipeline.slice(PIPELINE_PREFIX.length) : '';\n if (!isKind(bare)) {\n throw new KindSelectionError(\n 'DRZL_CLI_ONLY',\n `--pipeline: there is no pipeline called \"${pipeline}\".`,\n // A bare kind is the mirror image of the mistake `parseOnly` names, and the answer is the\n // flag that takes bare kinds rather than the list of sixteen values this one takes.\n isKind(pipeline)\n ? `That is a generator kind, so it goes to the newer flag: --only ${pipeline}.`\n : `Use --only <kind>, or one of: all, analyze, ${GENERATOR_KINDS.map(\n (k) => PIPELINE_PREFIX + k\n ).join(', ')}.`\n );\n }\n return { analyzeOnly: false, kinds: new Set([bare]) };\n}\n\n/**\n * The generator entries a selection keeps, in the order the config wrote them.\n *\n * Order matters and is the config's: two entries of the same kind pointed at different paths both\n * survive, and a selection is a filter rather than a reordering.\n */\nexport function selectGenerators<T extends { kind: string }>(\n generators: readonly T[],\n kinds: Set<GeneratorKind> | undefined\n): T[] {\n if (!kinds) return [...generators];\n return generators.filter((g) => kinds.has(g.kind as GeneratorKind));\n}\n\n/**\n * Why a selection matched nothing, as a sentence, or `undefined` when it matched something.\n *\n * A `--only` that selects no configured generator is the silent no-op this whole change exists to\n * remove, so it is reported with both halves of the mismatch: what was asked for, and what the\n * config actually names.\n */\nexport function emptySelectionMessage(\n kinds: Set<GeneratorKind> | undefined,\n configured: readonly { kind: string }[],\n flag = '--only'\n): string | undefined {\n if (!kinds || selectGenerators(configured, kinds).length) return undefined;\n const asked = [...kinds].join(', ');\n const names = [...new Set(configured.map((g) => g.kind))];\n return (\n `${flag} ${asked} matched no generator in this config, which names: ` +\n `${names.join(', ') || 'none'}.`\n );\n}\n","/**\n * Whether a run has anything to generate from, and which of the three reasons it has not.\n *\n * Items 70 and 71 are one moment for the user (\"I ran generate and got nothing useful\") and three\n * different causes, and the fixes have nothing in common: fix your import, export your tables,\n * loosen your filter. Measured on the built 4.22.0 CLI, every one of them printed a green tick and\n * exited 0, having written a barrel with no exports in it:\n *\n * | input | exit | wrote |\n * | ------------------------------------------------ | ---- | -------------- |\n * | a schema module that throws on import | 0 | `out/index.ts` |\n * | a schema importing a package that is not there | 0 | `out/index.ts` |\n * | a schema with a syntax error | 0 | `out/index.ts` |\n * | `schema:` naming a file that does not exist | 0 | `out/index.ts` |\n * | a module that exports no tables | 0 | `out/index.ts` |\n * | a module that exports things that are not tables | 0 | `out/index.ts` |\n * | every table removed by `include`/`exclude` | 0 | `out/index.ts` |\n *\n * The distinction is not guessed at here. The analyzer already separates the three answers, which\n * is what `init` was built on in item 67 and what this reuses:\n *\n * - a module it could not run -> `DRZL_ANL_NOFILE` or `DRZL_ANL_IMPORT`, an error-level issue\n * - a module that is not one -> no issues, and `tables` empty\n * - a real schema -> `tables` non-empty\n *\n * Surfacing that rather than re-deriving it is what keeps the two messages honest: the first says\n * DRZL never read your file and repeats the reason, the second says DRZL read it and it declares\n * nothing.\n */\n\n/** DRZL could not read the schema at all: the file is missing, or importing it threw. */\nexport const SCHEMA_UNREADABLE_CODE = 'DRZL_SCHEMA_001';\n/** DRZL read the schema, and it declares no Drizzle tables. */\nexport const SCHEMA_EMPTY_CODE = 'DRZL_SCHEMA_002';\n/** The schema declares tables and the config's own filters removed all of them. */\nexport const SCHEMA_FILTERED_CODE = 'DRZL_SCHEMA_003';\n\nexport interface SchemaProblem {\n /** The stable identifier, which is also what the `--json` failure document carries. */\n code: string;\n /** The failure itself. Printed in red, never suppressed, and named in the document. */\n message: string;\n /** How to fix it. Printed dim under the message, and dropped by `--quiet` like every hint. */\n hint: string;\n}\n\n/**\n * The clause that closes a hint by saying what did not happen because of this.\n *\n * A parameter rather than a constant, because these three problems are not `generate`'s alone any\n * more: `drzl explain` reaches every one of them and has never written a file in its life, so\n * \"Nothing was generated.\" there is a sentence about a thing the command does not do. The default\n * keeps every existing caller's text byte for byte.\n */\nexport const NOTHING_GENERATED = 'Nothing was generated.';\n\n/** The least this file needs to know about an analyzer issue. */\nexport interface AnalyzerIssue {\n code?: string;\n level?: string;\n message?: string;\n}\n\n/** The two analyzer codes that mean \"there is nothing to work with\", as opposed to a description. */\nconst UNREADABLE_CODES = new Set(['DRZL_ANL_NOFILE', 'DRZL_ANL_IMPORT']);\n\n/** The first line of a message. A module resolution failure carries its whole require stack. */\nfunction firstLine(message: string): string {\n return String(message).split('\\n')[0].trim();\n}\n\n/** What to call the schema in a sentence: the path as the config spells it, or the file count. */\nexport function describeSchemaTarget(schema: string | readonly string[]): string {\n if (typeof schema === 'string') return schema;\n if (schema.length === 1) return schema[0];\n return `${schema.length} schema files`;\n}\n\n/**\n * Item 70: the module never loaded, so nothing downstream means anything.\n *\n * The single-path message is built here rather than taken from the analyzer, because the\n * analyzer's is `Failed to import schema: <error>` and deliberately keeps those historical bytes,\n * which do not name the file. Naming the file is the point of the item: a user with four schema\n * modules and one bad import needs to be told which one, and the message that stops saying so is\n * the regression worth a test.\n */\nexport function schemaLoadFailure(\n issues: readonly AnalyzerIssue[],\n schema: string | readonly string[],\n consequence: string = NOTHING_GENERATED\n): SchemaProblem | undefined {\n const blocking = issues.filter(\n (issue) => issue.level === 'error' && issue.code && UNREADABLE_CODES.has(issue.code)\n );\n if (!blocking.length) return undefined;\n\n const first = blocking[0];\n const more = blocking.length > 1 ? ` (and ${blocking.length - 1} more)` : '';\n const single = typeof schema === 'string' ? schema : schema.length === 1 ? schema[0] : undefined;\n\n if (first.code === 'DRZL_ANL_NOFILE') {\n const named = single ?? afterPrefix(first.message, 'Schema file not found:');\n return {\n code: SCHEMA_UNREADABLE_CODE,\n message: `Schema file not found (${SCHEMA_UNREADABLE_CODE}): ${named}${more}`,\n hint:\n 'Check the \"schema\" path in your drzl config, or point --config at another one. ' +\n consequence,\n };\n }\n\n const reason = single\n ? firstLine(afterPrefix(first.message, 'Failed to import schema:'))\n : firstLine(String(first.message ?? ''));\n const message = single\n ? `Could not load the schema module ${single} (${SCHEMA_UNREADABLE_CODE}): ${reason}${more}`\n : `Could not load a schema module (${SCHEMA_UNREADABLE_CODE}): ${reason}${more}`;\n\n return {\n code: SCHEMA_UNREADABLE_CODE,\n message,\n hint: single\n ? `Fix that error and run again. \\`drzl analyze ${single}\\` prints it in full. ${consequence}`\n : `Fix that error and run again. ${consequence}`,\n };\n}\n\n/** A message with a known prefix taken off, or the message unchanged when it has none. */\nfunction afterPrefix(message: string | undefined, prefix: string): string {\n const text = String(message ?? '');\n return text.startsWith(prefix) ? text.slice(prefix.length).trim() : text;\n}\n\n/**\n * Item 71: the module loaded and the run would emit nothing but a barrel.\n *\n * Two codes rather than one, because the schema declaring nothing and the config's filter removing\n * everything are different mistakes in different files. The filtered case names the tables that\n * were really there, which is the fact that turns \"why is my output empty\" into \"my pattern is\n * wrong\", and it is the only place the CLI can say it: the filter has already run by then.\n */\nexport function nothingToGenerate(opts: {\n schema: string | readonly string[];\n /** The tables the analyzer found, before `include`, `exclude` and `columns` were applied. */\n analyzed: readonly { name: string }[];\n /** The tables left for the generators. */\n remaining: readonly { name: string }[];\n /** What did not happen because of this. See `NOTHING_GENERATED`. */\n consequence?: string;\n}): SchemaProblem | undefined {\n if (opts.remaining.length > 0) return undefined;\n const target = describeSchemaTarget(opts.schema);\n const consequence = opts.consequence ?? NOTHING_GENERATED;\n\n if (!opts.analyzed.length) {\n return {\n code: SCHEMA_EMPTY_CODE,\n message: `No Drizzle tables found in ${target} (${SCHEMA_EMPTY_CODE}).`,\n hint:\n 'That module imported cleanly and exported no tables, so every generator would write an ' +\n 'empty barrel. Export them from it, for example: export const users = pgTable(...). ' +\n consequence,\n };\n }\n\n const names = opts.analyzed.map((table) => table.name);\n const shown = names.slice(0, 6).join(', ');\n const rest = names.length > 6 ? `, and ${names.length - 6} more` : '';\n return {\n code: SCHEMA_FILTERED_CODE,\n message:\n `Every table was removed by this config's filters (${SCHEMA_FILTERED_CODE}). ` +\n `${target} declares ${names.length} table${names.length === 1 ? '' : 's'}: ${shown}${rest}.`,\n hint:\n 'Check \"include\" and \"exclude\" in your drzl config. A pattern is matched against the whole ' +\n 'database table name, with * as the only metacharacter. ' +\n consequence,\n };\n}\n","/**\n * Choosing which *columns* DRZL generates for.\n *\n * `include`/`exclude` answers \"which tables\". This answers \"which columns of them\", which the\n * config had no way to say at all. A schema DRZL must read in full still holds columns that should\n * not reach a generated file: a `passwordHash` no client should ever be handed, an internal note\n * column, a `tenantId` the server sets from the session and a request body must not carry. The\n * only previous answer was to edit the emitted file, which the next `drzl generate` overwrites.\n *\n * ## Where this runs\n *\n * On the `Analysis`, once, before any generator is constructed, at the same seam `filterTables`\n * already uses. Not inside `@drzl/analyzer`, which reads a schema module and has no config: `drzl\n * analyze` must keep printing what is really there, and a user asking \"what does DRZL see\" has to\n * get the truth rather than their own config read back to them. And not inside each generator:\n * there are nine of them plus two template packages, each with its own idea of a mode, and the one\n * that forgot would emit a schema silently wider than the config asked for. Narrowing the analysis\n * is also what keeps the validators, the OpenAPI document, the emitted `.meta()` facts and the\n * service layer describing the same columns, since all of them read this one object.\n *\n * ## Why the narrowing is more than `columns`\n *\n * A table states its columns twice: once as `columns`, and again by name in `primaryKey`,\n * `unique`, `indexes`, `foreignKeys` and `checks`. Dropping a column from the first list and\n * leaving the others is not a smaller schema, it is an inconsistent one, and each stale name has a\n * different consequence:\n *\n * - `unique` reaches emitted TypeScript verbatim. `findDuplicate<Table>` declares\n * `columns: [\"email\"]` against the insert row type, so a unique key naming a column that type no\n * longer has is a generated file that does not compile. Narrowed.\n * - `foreignKeys` drives the relation lookup procedures in the tRPC and oRPC generators, both of\n * which already resolve the column against `columns` and skip when it is gone. Narrowed, which\n * changes no output and stops the analysis asserting a key over a column it does not have.\n * - `indexes` is read by nothing today. Narrowed anyway, on the same grounds.\n * - `checks` is deliberately *not* narrowed. Every generator already drops a row check naming a\n * column the mode does not carry, so nothing breaks, and the constraint really does still exist\n * in the database: leaving it lets `meta` keep listing it as unenforced, which is the honest\n * answer. A warning says so.\n * - `primaryKey` cannot be narrowed, because omitting a key column is refused outright. See below.\n */\nimport type { Table } from '@drzl/analyzer';\nimport { parseCheck } from '@drzl/validation-core';\nimport { namedColumns } from './doctor.js';\nimport {\n addressableName,\n ambiguousPatternWarnings,\n displayTableName,\n hasNamedSchemas,\n matchesAny,\n matchesTable,\n} from './patterns.js';\n\n/** What to do with one table's columns. Both are patterns, in the language `patterns.ts` defines. */\nexport interface ColumnRules {\n /** Drop these. Applied after `pick`, so it wins where both name the same column. */\n omit?: string[];\n /** Keep only these. */\n pick?: string[];\n}\n\n/**\n * Keyed by table pattern, matched against the database table name exactly as `include` is, and\n * against the schema-qualified name too: `reporting.users` names one of two same-named tables and\n * `reporting.*` names a whole schema.\n */\nexport type ColumnFilter = Record<string, ColumnRules>;\n\nexport interface ColumnFilterResult {\n tables: Table[];\n /** Printed by the caller. Nothing here stops generation. */\n warnings: string[];\n}\n\n/** Every column name a CHECK talks about, whatever kind of constraint it turned out to be. */\nfunction checkedColumns(expression: string | undefined, name: string | undefined): string[] {\n const parsed = parseCheck(expression, name);\n if (!parsed.ok) return [];\n return [...new Set(namedColumns(parsed).map((n) => n.column))];\n}\n\n/**\n * Narrow every table's columns to what the config asked for.\n *\n * Throws on anything that cannot be honoured, with every such problem in one message: a config is\n * edited once and rerun, and reporting the first of four typos three times is three wasted runs.\n * Returns warnings for what *is* honoured but changes what the output can do.\n *\n * Call this **before** `filterTables`. Both orders produce the same tables, since one narrows\n * columns and the other drops whole tables, but only this order lets a `columns` entry name a\n * table that `exclude` also removes without that reading as a typo.\n */\nexport function filterColumns(tables: Table[], spec: ColumnFilter | undefined): ColumnFilterResult {\n const entries = Object.entries(spec ?? {});\n if (!entries.length) return { tables, warnings: [] };\n\n const errors: string[] = [];\n const warnings: string[] = [];\n // Only where the analysis really has more than one schema. A project with one has no `public.`\n // to write, so offering it as the spelling to copy names something its schema file never says.\n const nameForConfig = hasNamedSchemas(tables) ? addressableName : displayTableName;\n\n /**\n * Every pattern has to name something that exists.\n *\n * This is the loud half, and it is the reason the option is safe to reach for. `omit:\n * ['passwrodHash']` that silently does nothing is not a no-op: it is the leak the option was\n * reached for, wearing the shape of a fix, and nothing downstream can tell the difference\n * between a column that was never there and one that was already dropped.\n *\n * A column pattern is required to match in *at least one* of the tables its entry matched, not\n * in all of them. Requiring all would make a wildcard table key useless, and dropping\n * `deleted_at` from every `app_*` table that has one is the main thing a wildcard key is for.\n */\n for (const [tablePattern, rules] of entries) {\n const matched = tables.filter((t) => matchesTable([tablePattern], t));\n if (!matched.length) {\n errors.push(\n `columns[${JSON.stringify(tablePattern)}] matches no table. ` +\n `The schema declares: ${tables.map(nameForConfig).join(', ') || '(no tables)'}.`\n );\n continue;\n }\n const available = [...new Set(matched.flatMap((t) => t.columns.map((c) => c.name)))];\n for (const which of ['pick', 'omit'] as const) {\n for (const pattern of rules[which] ?? []) {\n if (available.some((name) => matchesAny([pattern], name))) continue;\n errors.push(\n `columns[${JSON.stringify(tablePattern)}].${which} names ${JSON.stringify(pattern)}, ` +\n `which matches no column of ${matched.map(nameForConfig).join(', ')}. ` +\n `Available: ${available.join(', ')}.`\n );\n }\n }\n }\n\n // Said once per pattern, before anything is narrowed, because the consequence is that the rules\n // below run over more tables than the writer had in mind and every one of them is a real table.\n warnings.push(\n ...ambiguousPatternWarnings(\n entries.map(([p]) => p),\n tables,\n 'columns'\n )\n );\n\n const out = tables.map((table) => {\n const mine = entries.filter(([pattern]) => matchesTable([pattern], table));\n if (!mine.length) return table;\n\n // Applied in the order the entries are written, so a reader works down the config the way they\n // read it. Within one entry `pick` narrows and then `omit` removes, which is the same\n // precedence `exclude` already has over `include`: the direction that takes something away\n // wins, because that is the safe direction for the thing this option exists to remove.\n let keep = table.columns;\n for (const [, rules] of mine) {\n if (rules.pick?.length) keep = keep.filter((c) => matchesAny(rules.pick!, c.name));\n if (rules.omit?.length) keep = keep.filter((c) => !matchesAny(rules.omit!, c.name));\n }\n if (keep.length === table.columns.length) return table;\n\n const kept = new Set(keep.map((c) => c.name));\n const dropped = table.columns.filter((c) => !kept.has(c.name));\n\n if (!keep.length) {\n errors.push(\n `columns leaves table \"${displayTableName(table)}\" with no columns at all. An empty schema describes ` +\n `no row, so this is never a narrower API. Exclude the table instead, with the top-level ` +\n `\"exclude\" option.`\n );\n return table;\n }\n\n /**\n * A primary key column is refused rather than narrowed, and it is the one hard no here.\n *\n * The key is what addresses a row, and every generator that addresses one reads it\n * differently, so the consequence of dropping it depends on which generators happen to be\n * configured: the tRPC generator resolves the key against `columns` and silently drops byId,\n * update and delete; the oRPC generator never reads the key at all and keeps emitting\n * procedures typed `{ id: number }`; the service generator falls back to a column literally\n * named `id` and emits `eq(users.id, id)`, which does not compile when the key was called\n * something else; the OpenAPI document drops its `/{id}` paths; and zod's `meta` would publish\n * a primary key whose column the schema no longer describes. One config, five outcomes, none\n * of them announced.\n *\n * Refusing is also the reversible direction. An error can be relaxed to a warning later\n * without breaking a config that works; a warning cannot be tightened into an error without\n * breaking one.\n */\n const lostKey = (table.primaryKey?.columns ?? []).filter((n) => !kept.has(n));\n if (lostKey.length) {\n errors.push(\n `columns drops ${lostKey.map((n) => JSON.stringify(n)).join(', ')} from table ` +\n `\"${displayTableName(table)}\", which is part of its primary key ` +\n `(${table.primaryKey?.columns.join(', ')}). The generated getById, update and delete ` +\n `address rows by that key, so the emitted schemas would describe a row nothing can ` +\n `address. Keep the key, or leave the whole table out with the top-level \"exclude\" option.`\n );\n return table;\n }\n\n /**\n * A NOT NULL column with no default is warned about and then dropped, which is the other half\n * of the same judgement.\n *\n * It really does produce an insert schema that cannot describe a whole row. It is also the\n * multi-tenant pattern: a NOT NULL `tenantId` the server takes from the session is exactly a\n * column a request body must not carry, and refusing it would remove one of the two things\n * this option is for. An insert schema describes a request, not a row, so the narrower\n * statement is true; what is not obvious is who then supplies the rest, and that is what the\n * warning says. If a generated service in `drizzle` mode is handed the narrowed body, its\n * `create` parameter is Drizzle's own `$inferInsert` and the missing column is a compile error\n * in the generated project, which is loud on its own.\n */\n for (const c of dropped) {\n if (c.nullable || c.hasDefault || c.isGenerated || table.readOnly) continue;\n warnings.push(\n `drzl config: the \"columns\" option drops \"${c.name}\" from table \"${displayTableName(table)}\", and the ` +\n `database requires it: NOT NULL with no default. The emitted insert schema therefore ` +\n `describes a payload that is not a complete row, so whatever calls db.insert has to ` +\n `supply \"${c.name}\" itself.`\n );\n }\n\n // A CHECK naming a dropped column stops being enforced by anything DRZL emits. The generators\n // already skip it rather than emitting a comparison against a field that is not there, so this\n // is a warning and not an error, but it is exactly the silent kind of loss `drzl doctor` was\n // written for.\n for (const k of table.checks ?? []) {\n // Only names this filter really took away. A CHECK naming a column the table never had is a\n // different finding with a section of its own in `drzl doctor`, and claiming it here would\n // blame the config for something that was already wrong.\n const lost = checkedColumns(k.expression, k.name).filter(\n (n) => !kept.has(n) && table.columns.some((c) => c.name === n)\n );\n if (!lost.length) continue;\n warnings.push(\n `drzl config: CHECK ${k.name ? `\"${k.name}\"` : '(unnamed)'} on table \"${displayTableName(table)}\" ` +\n `names ${lost.map((n) => JSON.stringify(n)).join(', ')}, which the \"columns\" option ` +\n `drops, so nothing DRZL emits enforces it. Your database still does.`\n );\n }\n\n return {\n ...table,\n columns: keep,\n unique: (table.unique ?? []).filter((k) => k.columns.every((n) => kept.has(n))),\n indexes: (table.indexes ?? []).filter((i) => i.columns.every((n) => kept.has(n))),\n ...(table.foreignKeys\n ? { foreignKeys: table.foreignKeys.filter((f) => f.columns.every((n) => kept.has(n))) }\n : {}),\n };\n });\n\n if (errors.length) {\n throw new Error(\n `drzl config: the \"columns\" option cannot be honoured.\\n` +\n errors.map((e) => ` - ${e}`).join('\\n')\n );\n }\n\n return { tables: out, warnings };\n}\n","/**\n * The report behind `drzl doctor`: what DRZL will not check for you, and why.\n *\n * `drzl analyze` already prints the whole `Analysis` as JSON. This is not that. The analysis is a\n * description of the schema and the reader has to know which fields mean trouble; this is the list\n * of things that will silently not work, each with the sentence that says what to do about it.\n *\n * The point of the command is the *silent* half. A generator that cannot type a column emits a\n * validator accepting any value, and a CHECK the parser declines is simply absent from the output:\n * both produce a file that looks finished. `drzl generate` prints a one-line count for the first\n * and says nothing at all about the second.\n *\n * Two of the sections here read something the analyzer does not know:\n *\n * - **CHECK constraints.** `parseCheck` lives in `@drzl/validation-core` and every validation\n * generator calls it; the analyzer never does. It carries the raw expression through and has no\n * opinion on whether anything can be made of it. So the only way to say \"this constraint is in\n * your schema and nothing DRZL emits enforces it\" is to run the generators' own parser, which is\n * what this file does.\n * - **Primary keys.** The service generator keys `getById`, `update` and `delete` on\n * `table.primaryKey?.columns[0] ?? 'id'`, and the router templates take an `id` input to match.\n * A table with no primary key therefore gets a service referencing a column that may not exist,\n * and a composite key gets one keyed on half of it. The analysis states the key correctly; the\n * consequence is the generator's.\n *\n * Deliberately *not* reported, and each for a measured reason:\n *\n * - A CHECK that DRZL does translate. `age >= 18` folds into `.gte(18)` and `start < end` becomes\n * an object-level refinement; listing them as findings would drown the ones that matter.\n * - `cardinality(col)` landing on a column with no elements to count. Unreachable from a working\n * schema: Postgres has no `cardinality(integer)`, so the DDL is refused before DRZL sees it.\n *\n * `length(col)` and `octet_length(col)` used to be on that list and are not any more, for two\n * reasons that both stopped being true at once. The five validation generators now ask\n * `lengthMeasure` the same question rather than each applying its own guard, so one sentence is\n * true of all of them; and the clause is reachable, because MySQL has `OCTET_LENGTH` and a\n * `varbinary(n)` column whose byte count in JavaScript is not the one the server took. See\n * `check-uncountable`.\n */\nimport type { Analysis, Column, Issue, Table } from '@drzl/analyzer';\nimport { lengthMeasure, parseCheck, type LengthCheck } from '@drzl/validation-core';\nimport { Chalk, type ChalkInstance } from 'chalk';\n\n/**\n * The styling this report uses when the caller does not say.\n *\n * Level 0, so a caller who forgets gets plain text rather than escape sequences in a file. This\n * file used to import chalk's default instance, which decides colour from `process.stdout` alone\n * and ignores `NO_COLOR` entirely, so `drzl doctor` printed the same 32 escapes with the variable\n * set as without it. The decision belongs to `output.ts` and is passed in.\n */\nconst PLAIN: ChalkInstance = new Chalk({ level: 0 });\n\nexport type DoctorFindingKind =\n /** A column whose validator will accept any value. */\n | 'unknown-column'\n /**\n * A CHECK nothing DRZL emits enforces.\n *\n * Usually one the shared parser refused outright. Also a clause it *reads* and no generator can\n * state: `col IS NULL` narrows a column to null alone, which would mean replacing the column's\n * type rather than wrapping it. Reported the same way, because the two are the same fact to the\n * reader: the constraint is in the schema and the generated schemas do not check it.\n */\n | 'check-declined'\n /** A CHECK naming a column the table does not have. */\n | 'check-unknown-column'\n /** A CHECK comparing an array or structured column against a scalar literal. */\n | 'check-not-scalar'\n /**\n * A CHECK counting a column whose count JavaScript cannot take the way the database did.\n *\n * `CHECK (octet_length(bin) <= 8)` on a MySQL `varbinary(8)` is the reachable case: the value\n * arrives as a string produced by a lossy decode, so neither its characters nor their UTF-8\n * re-encoding is the server's byte count, and any predicate written from it would be enforcing a\n * different constraint. Reported rather than silently dropped, for the same reason `IS NULL` is:\n * the parser reading an expression must not be the same event as the report forgetting it.\n */\n | 'check-uncountable'\n /** A table the generators cannot key. */\n | 'no-primary-key'\n /** A table keyed on more columns than the generators use. */\n | 'partial-primary-key'\n /** Anything else the analyzer said, passed through rather than dropped. */\n | 'analyzer';\n\nexport interface DoctorFinding {\n kind: DoctorFindingKind;\n level: 'warn' | 'error';\n /** Table this is about, as the analysis names it. Absent for a finding about the whole schema. */\n table?: string;\n column?: string;\n /** Constraint name, where the finding is about a CHECK. */\n constraint?: string;\n message: string;\n hint?: string;\n}\n\nexport interface DoctorReport {\n /** The schema path as the user spelled it, so the report names the file they asked about. */\n schema: string;\n dialect: string;\n /** True only when there is nothing at all to say. */\n ok: boolean;\n counts: { tables: number; columns: number; checks: number; findings: number };\n findings: DoctorFinding[];\n}\n\n/** Issue codes with a section of their own, so the catch-all does not print them twice. */\nconst HANDLED_CODES = new Set(['DRZL_ANL_UNKNOWN_COLUMN']);\n\n/**\n * Split an issue `path` into its table and column halves.\n *\n * The analyzer writes `table.column` for a column issue and a bare table name otherwise. Table\n * names are JavaScript identifiers, so the last dot is the separator and there is no ambiguity.\n */\nfunction splitPath(path: string | undefined): { table?: string; column?: string } {\n if (!path) return {};\n const dot = path.lastIndexOf('.');\n if (dot <= 0) return { table: path };\n return { table: path.slice(0, dot), column: path.slice(dot + 1) };\n}\n\n/**\n * Every column name a parsed CHECK talks about, paired with the kind of constraint it came from.\n *\n * Exported because the column filter needs the same answer: a constraint stops being enforced when\n * any column it names is dropped, and \"which columns does this name\" has to mean one thing.\n */\nexport function namedColumns(parsed: Extract<ReturnType<typeof parseCheck>, { ok: true }>) {\n const out: Array<{ column: string; scalar: boolean }> = [];\n // A comparison against a literal and an `IN` list are both statements about a scalar value, so\n // neither describes an array or a structured column. The other three kinds are not: a length or\n // a cardinality is a statement about a count, and a row check is a comparison of two columns.\n for (const c of parsed.checks) out.push({ column: c.column, scalar: true });\n for (const s of parsed.sets ?? []) out.push({ column: s.column, scalar: true });\n for (const l of parsed.lengths ?? []) out.push({ column: l.column, scalar: false });\n for (const c of parsed.cardinalities ?? []) out.push({ column: c.column, scalar: false });\n // A null test is the one clause that describes every column shape alike: an array, a json\n // payload and a scalar are each either there or not. So it names its column without claiming\n // the column is scalar, which would report `CHECK (tags IS NOT NULL)` as a mismatch it is not.\n for (const n of parsed.nulls ?? []) out.push({ column: n.column, scalar: false });\n for (const r of parsed.rows ?? []) {\n out.push({ column: r.left, scalar: false });\n out.push({ column: r.right, scalar: false });\n }\n return out;\n}\n\n/**\n * What a column is, for a sentence about a constraint that does not fit it.\n *\n * Every `ColumnShape` kind has an arm, so a shape added later reads as \"a structured column\" rather\n * than as a wrong noun. `arrayDimensions` is checked first because an array carries its element's\n * shape and it is the array the constraint failed to describe.\n */\nfunction describeShape(c: Column): string {\n if (c.arrayDimensions) return 'an array';\n switch (c.shape?.kind) {\n case 'json':\n return 'a JSON';\n case 'buffer':\n return 'a binary';\n case 'tuple':\n case 'numberObject':\n return 'a structured';\n case 'numberVector':\n return 'a vector';\n case 'bitstring':\n return 'a bit-string';\n case 'byteString':\n return 'a byte-string';\n case 'custom':\n return 'a customType';\n default:\n return 'a structured';\n }\n}\n\n/** What the clause asked to be counted, in the words the expression used. */\nconst countNoun = (l: LengthCheck) => (l.unit === 'bytes' ? 'byte count' : 'character count');\n\n/**\n * What to do about a count nothing can take, or the generic sentence.\n *\n * Only the byte-string column has an answer, and it is the only one reachable from a schema a\n * database accepted, so the rest get the generic form rather than invented advice.\n */\nfunction countHint(c: Column): string {\n if (c.shape?.kind === 'byteString')\n return (\n 'A binary(n)/varbinary(n) column hands the caller a string produced by a lossy decode, so ' +\n 'its width is code points coming out and bytes going in and neither is a count of the ' +\n 'value in hand. The column already caps itself at n bytes; a second bound stated here ' +\n 'would be a different measurement. Leave this one to the database.'\n );\n return (\n 'Only constraints whose meaning is unambiguous are translated, because a validator ' +\n 'enforcing a guess rejects rows the database accepts. Your database still enforces ' +\n 'this one; nothing DRZL emits does.'\n );\n}\n\n/**\n * The generic advice for a declined CHECK, or something the reader can act on.\n *\n * The generic sentence is true of every refusal and therefore says nothing about any of them. Two\n * of the refusals have a fix, and a reader who has just been told their constraint is not enforced\n * has earned being told what to do instead of being told the rule again.\n *\n * Matched on the parser's own reason rather than on a code, because the reason is what the parser\n * already returns and a second vocabulary beside it is a second thing to keep in step. The default\n * is the generic sentence, so a reason added later is worded generically rather than wrongly.\n */\nfunction declineHint(reason: string): string {\n if (/combined with/.test(reason))\n return (\n 'Postgres computes numeric arithmetic exactly and JavaScript computes it in binary ' +\n 'floating point, so `x + y <= 0.3` accepts (0.1, 0.2) in the database and rejects it in ' +\n 'JavaScript. The right translation depends on whether the columns are numeric, double ' +\n 'precision or bigint, and the expression does not say. Put the result in a generated ' +\n 'column and constrain that, or leave this one to the database.'\n );\n if (/\\bOR\\b/.test(reason))\n return (\n 'A disjunction is read only where the whole of it pins one column to a set of values, ' +\n \"such as `status = 'a' OR status = 'b'`, which becomes the same enum an IN list does. \" +\n 'Anything else is refused whole rather than in part: a row satisfying the other branch is ' +\n 'one the database accepts, and enforcing one branch would turn it away.'\n );\n return (\n 'Only constraints whose meaning is unambiguous are translated, because a validator ' +\n 'enforcing a guess rejects rows the database accepts. Your database still enforces ' +\n 'this one; nothing DRZL emits does.'\n );\n}\n\nfunction checkFindings(table: Table): DoctorFinding[] {\n const out: DoctorFinding[] = [];\n const byName = new Map(table.columns.map((c) => [c.name, c]));\n for (const k of table.checks ?? []) {\n const label = k.name ? `\"${k.name}\"` : 'an unnamed constraint';\n const raw = k.expression ?? '';\n // A constraint whose expression the analyzer could not render at all is the one case where\n // printing the expression verbatim says nothing, and a line ending in \"Expression:\" reads\n // like the report itself is broken.\n const expr = raw.trim() ? raw : '(empty)';\n const parsed = parseCheck(raw, k.name, table.dialect);\n if (!parsed.ok) {\n out.push({\n kind: 'check-declined',\n level: 'warn',\n table: table.tsName,\n constraint: k.name,\n message: `CHECK ${label} on \"${table.tsName}\" is not translated: ${parsed.reason}. Expression: ${expr}`,\n hint: declineHint(parsed.reason),\n });\n continue;\n }\n\n // A clause that parsed and that nothing enforces. `col IS NULL` is the only one: narrowing a\n // field to null *alone* would mean replacing the column's type rather than wrapping it, and no\n // generator has a hook for that. Reported here rather than left silent, because the parser\n // learning to read an expression must not be the same event as the doctor forgetting it: the\n // constraint went from \"declined, here is why\" to absent from the report entirely.\n for (const n of parsed.nulls ?? []) {\n if (n.notNull) continue;\n out.push({\n kind: 'check-declined',\n level: 'warn',\n table: table.tsName,\n constraint: k.name,\n message:\n `CHECK ${label} on \"${table.tsName}\" holds \"${n.column} IS NULL\", which narrows the ` +\n `column to NULL alone and no generated schema states. Expression: ${expr}`,\n hint:\n 'A column that may only ever be NULL is usually a constraint written the wrong way ' +\n 'round. Drop the column, or state the rule as a CHECK on the column that decides it.',\n });\n }\n\n // A count clause the emitted schemas drop. Per clause rather than per column, because the\n // sentence names the function that was written and `length` and `octet_length` can both be on\n // one column at once.\n for (const l of parsed.lengths ?? []) {\n const col = byName.get(l.column);\n if (!col || lengthMeasure(col, l)) continue;\n out.push({\n kind: 'check-uncountable',\n level: 'warn',\n table: table.tsName,\n column: l.column,\n constraint: k.name,\n message:\n `CHECK ${label} on \"${table.tsName}\" counts ${describeShape(col)} column ` +\n `\"${l.column}\", whose ${countNoun(l)} in JavaScript is not the one the database took, ` +\n `so it is not translated. Expression: ${expr}`,\n hint: countHint(col),\n });\n }\n\n // Reported once per column rather than once per clause, so `a >= 1 AND a <= 9` on a missing\n // column is one line and not two.\n const seen = new Set<string>();\n for (const { column, scalar } of namedColumns(parsed)) {\n if (seen.has(column)) continue;\n seen.add(column);\n const col = byName.get(column);\n if (!col) {\n out.push({\n kind: 'check-unknown-column',\n level: 'warn',\n table: table.tsName,\n column,\n constraint: k.name,\n message: `CHECK ${label} on \"${table.tsName}\" names \"${column}\", which is not a column of that table, so nothing enforces it. Expression: ${expr}`,\n hint:\n 'A constraint is attached to the field it names. Check the spelling, or move a ' +\n 'constraint spanning two tables out of the schema.',\n });\n continue;\n }\n if (scalar && (col.arrayDimensions || col.shape)) {\n out.push({\n kind: 'check-not-scalar',\n level: 'warn',\n table: table.tsName,\n column,\n constraint: k.name,\n message: `CHECK ${label} on \"${table.tsName}\" compares ${describeShape(col)} column \"${column}\" against a scalar literal, which does not describe it, so it is not translated. Expression: ${expr}`,\n hint:\n 'On an array column only cardinality(col) is read, since it is the one comparison ' +\n 'that is about the array rather than about an element.',\n });\n }\n }\n }\n return out;\n}\n\nfunction primaryKeyFindings(table: Table): DoctorFinding[] {\n // A read-only relation takes no writes and gets no keyed route, so it needs no key.\n if (table.readOnly) return [];\n const pk = table.primaryKey?.columns ?? [];\n if (!pk.length) {\n const hasId = table.columns.some((c) => c.name === 'id');\n return [\n {\n kind: 'no-primary-key',\n level: 'warn',\n table: table.tsName,\n message: hasId\n ? `Table \"${table.tsName}\" declares no primary key. The service and router generators fall back to a column named \"id\", which this table happens to have, so they work by coincidence.`\n : `Table \"${table.tsName}\" declares no primary key. The service and router generators fall back to a column named \"id\", which this table does not have, so the generated service will not compile.`,\n hint: 'Declare a primary key, or leave this table out with the config table filter.',\n },\n ];\n }\n if (pk.length > 1) {\n return [\n {\n kind: 'partial-primary-key',\n level: 'warn',\n table: table.tsName,\n message: `Table \"${table.tsName}\" has a composite primary key (${pk.join(', ')}). The service and router generators key getById, update and delete on \"${pk[0]}\" alone, so those operations match on part of the key.`,\n hint: 'Treat the generated service as a starting point for this table and widen the key by hand.',\n },\n ];\n }\n return [];\n}\n\n/**\n * Everything worth saying about one analysis, in the order it should be read.\n *\n * Ordered worst-first, and within that silent-first. A schema that could not be analyzed comes\n * first because nothing after it is trustworthy. Untypeable columns and dropped constraints come\n * next because they are invisible: the generated file exists, compiles and validates nothing. The\n * primary-key findings come after because one half of that pair announces itself as a compile\n * error. The catch-all is last.\n */\nexport function buildDoctorReport(analysis: Analysis, schemaPath: string): DoctorReport {\n const findings: DoctorFinding[] = [];\n\n const errors = analysis.issues.filter((i: Issue) => i.level === 'error');\n for (const i of errors) {\n findings.push({\n kind: 'analyzer',\n level: 'error',\n ...splitPath(i.path),\n message: i.message,\n hint: i.hint,\n });\n }\n\n for (const i of analysis.issues) {\n if (i.code !== 'DRZL_ANL_UNKNOWN_COLUMN') continue;\n findings.push({\n kind: 'unknown-column',\n level: 'warn',\n ...splitPath(i.path),\n message: i.message,\n hint: i.hint,\n });\n }\n\n for (const t of analysis.tables) findings.push(...checkFindings(t));\n for (const t of analysis.tables) findings.push(...primaryKeyFindings(t));\n\n for (const i of analysis.issues) {\n if (i.level === 'error' || HANDLED_CODES.has(i.code)) continue;\n findings.push({\n kind: 'analyzer',\n level: 'warn',\n ...splitPath(i.path),\n message: i.message,\n hint: i.hint,\n });\n }\n\n const columns = analysis.tables.reduce((n, t) => n + t.columns.length, 0);\n const checks = analysis.tables.reduce((n, t) => n + (t.checks?.length ?? 0), 0);\n return {\n schema: schemaPath,\n dialect: analysis.dialect,\n ok: findings.length === 0,\n counts: { tables: analysis.tables.length, columns, checks, findings: findings.length },\n findings,\n };\n}\n\n/** Sections, in report order, each with the sentence that says why its contents matter. */\nconst SECTIONS: Array<{ kinds: DoctorFindingKind[]; title: string; why: string }> = [\n {\n kinds: ['unknown-column'],\n title: 'Columns DRZL cannot type',\n why: 'These get a validator that accepts any value.',\n },\n {\n kinds: ['check-declined', 'check-unknown-column', 'check-not-scalar', 'check-uncountable'],\n title: 'CHECK constraints DRZL does not enforce',\n why: 'Your database still enforces these. Nothing DRZL generates does.',\n },\n {\n kinds: ['no-primary-key', 'partial-primary-key'],\n title: 'Primary keys the generators cannot use',\n why: 'The generated getById, update and delete are keyed on one column.',\n },\n {\n kinds: ['analyzer'],\n title: 'Other findings',\n why: 'Reported by the analyzer while reading the schema.',\n },\n];\n\n/**\n * Wrap a sentence under a fixed indent, so it does not run off a narrow terminal.\n *\n * `first` is the prefix the opening line carries instead of the indent, which is what gives a\n * finding its bullet and its continuation lines a hanging indent under the text rather than under\n * the bullet.\n */\nfunction wrap(text: string, indent: string, first = indent, width = 96): string {\n const lines: string[] = [];\n let line = '';\n for (const word of text.split(/\\s+/)) {\n if (line && `${line} ${word}`.length + indent.length > width) {\n lines.push(line);\n line = word;\n } else {\n line = line ? `${line} ${word}` : word;\n }\n }\n if (line) lines.push(line);\n return lines.map((l, i) => (i === 0 ? first : indent) + l).join('\\n');\n}\n\n/**\n * The human-readable report.\n *\n * A clean schema prints what was looked at rather than nothing, because an empty page cannot be\n * told apart from a command that failed to run.\n */\nexport function renderDoctorReport(report: DoctorReport, style: ChalkInstance = PLAIN): string {\n const chalk = style;\n const out: string[] = [];\n const plural = (n: number, one: string) => `${n} ${one}${n === 1 ? '' : 's'}`;\n\n out.push(chalk.bold(`DRZL doctor ${report.schema}`));\n out.push(\n chalk.dim(\n `${report.dialect}, ${plural(report.counts.tables, 'table')}, ` +\n `${plural(report.counts.columns, 'column')}, ${plural(report.counts.checks, 'CHECK constraint')}`\n )\n );\n out.push('');\n\n if (report.ok) {\n out.push(chalk.green('Nothing to report.'));\n out.push(chalk.dim(' Every column has a type DRZL can describe.'));\n out.push(chalk.dim(' Every CHECK constraint is translated into the generated validators.'));\n out.push(chalk.dim(' Every table has a primary key the generators can use.'));\n return out.join('\\n');\n }\n\n // Ahead of the sections rather than inside one. An error means the schema was never read, so\n // every count above is zero and every section below is empty, and printing that under \"Other\n // findings\" at the foot of the page buries the only sentence that matters.\n const fatal = report.findings.filter((f) => f.level === 'error');\n if (fatal.length) {\n out.push(chalk.red('DRZL could not read this schema'));\n out.push(chalk.dim(' Nothing else could be checked.'));\n out.push('');\n for (const f of fatal) {\n out.push(wrap(f.message, ' ', ` ${chalk.dim('-')} `));\n if (f.hint) out.push(chalk.dim(wrap(f.hint, ' ')));\n }\n out.push('');\n }\n\n for (const section of SECTIONS) {\n const mine = report.findings.filter(\n (f) => f.level !== 'error' && section.kinds.includes(f.kind)\n );\n if (!mine.length) continue;\n out.push(chalk.yellow(`${section.title} (${mine.length})`));\n out.push(chalk.dim(` ${section.why}`));\n out.push('');\n // One hint per distinct sentence, under the findings that share it: the same advice repeated\n // under twenty columns is the thing that makes a report unreadable.\n const groups = new Map<string, DoctorFinding[]>();\n for (const f of mine) {\n const key = f.hint ?? '';\n groups.set(key, [...(groups.get(key) ?? []), f]);\n }\n for (const [hint, items] of groups) {\n for (const f of items) out.push(wrap(f.message, ' ', ` ${chalk.dim('-')} `));\n if (hint) out.push(chalk.dim(wrap(hint, ' ')));\n out.push('');\n }\n }\n\n out.push(\n chalk.bold(`${plural(report.counts.findings, 'finding')} in ${report.schema}.`) +\n chalk.dim(\n fatal.length\n ? ' Fix the error above and run this again.'\n : ' None of these stop DRZL generating; they are what it will not check for you.'\n )\n );\n return out.join('\\n');\n}\n","/**\n * `drzl explain <table>`: what DRZL understood about one table, and what it did not.\n *\n * The command exists for one moment: a generated schema is wrong, and the reader has no way to\n * tell whether the analyzer misread the column, dropped the CHECK, failed to follow the relation,\n * or read all three correctly and the generator is at fault. Today that question is answered by\n * reading `drzl analyze --json` output, which is the whole analysis of the whole schema with\n * nothing pointed out, or by reading the emitted validator and inferring backwards.\n *\n * Three sources are read, and none of them is re-derived here:\n *\n * - **The analyzer**, for the table itself: the resolved `tsType`, the declared `sqlType`,\n * nullability, defaults, keys, foreign keys, enum members and every measured fact\n * (`min`/`max`/`integer`/`allowsNaN`/`allowsInfinity`/`format`/`maxLength`/`maxBytes`).\n * - **`tableConstraints` from `@drzl/validation-core`**, for whether a generated schema actually\n * checks each constraint. That function is what the emitted constraint ledger is built from, so\n * `explain` and the generated modules cannot disagree about what is enforced. It is also where\n * a CHECK's classification lives: a clause the shared parser declined comes back as an\n * `unenforced` entry with the parser's own reason, which is the sentence this command exists to\n * surface.\n * - **The analysis's own `issues`**, filtered to this table, for a column type nobody has modelled\n * and a relation the analyzer could not follow.\n *\n * The two questions it deliberately answers together are \"what is here\" and \"what is silently not\n * here\". A column DRZL cannot type still emits a validator, a CHECK the parser declines is simply\n * absent from the output, and a `varchar(255)` on an enum column never reaches the schema as a\n * width. All three produce a file that looks finished, and all three are named here.\n *\n * It writes nothing. `--dry-run` has no meaning for a command that has never had a write path.\n */\nimport type { Analysis, Column, Issue, Relation, Table } from '@drzl/analyzer';\nimport { qualifiedForeignTable, qualifiedTableName } from '@drzl/analyzer';\nimport { tableConstraints, type ConstraintFacts } from '@drzl/validation-core';\nimport { Chalk, type ChalkInstance } from 'chalk';\nimport { nearestKey } from './config-errors.js';\nimport { addressableName, displayTableName, tableAliases } from './patterns.js';\n\n/**\n * The styling used when a caller does not pass one.\n *\n * Level 0, so a caller who forgets gets plain text rather than escape sequences in a file. The\n * decision belongs to `output.ts`, which asks it per stream; see the same constant in `doctor.ts`.\n */\nconst PLAIN: ChalkInstance = new Chalk({ level: 0 });\n\n/* ------------------------------------------------------------------------------------------ */\n/* Finding the table */\n/* ------------------------------------------------------------------------------------------ */\n\n/** Which of a table's three names the query matched. */\nexport type MatchedOn =\n /** The bare database name, `users`. */\n | 'name'\n /** The qualified database name, `reporting.users`, or `public.users` for the default schema. */\n | 'qualified'\n /** The TypeScript export name, which is not always the database name. */\n | 'tsName';\n\nexport interface TableHit {\n table: Table;\n matchedOn: MatchedOn;\n}\n\nexport type TableMatch =\n | ({ kind: 'found'; exact: boolean } & TableHit)\n /** Two or more tables answer to that name. Never resolved silently; see `matchTable`. */\n | { kind: 'ambiguous'; exact: boolean; hits: TableHit[] }\n | { kind: 'none'; suggestion?: string };\n\n/**\n * Every name one table answers to, most specific first.\n *\n * `tableAliases` supplies the two database spellings, so `explain` and the config's `include`\n * and `exclude` agree about what `public.users` means without either restating it. The export\n * name is the third, because a reader looking at their own schema file knows\n * `export const orgMembers` and may never have seen the string `organisation_members`.\n *\n * Order is the order a hit is reported in, and the qualified name is first: a table in a named\n * SQL schema is identified by that spelling and by no other, so a query that used it should be\n * reported as having used it.\n */\nfunction namesOf(table: Table): Record<MatchedOn, string> {\n const [bare, qualified] = tableAliases(table);\n return { qualified, name: bare, tsName: table.tsName };\n}\n\nconst MATCH_ORDER: MatchedOn[] = ['qualified', 'name', 'tsName'];\n\n/** What each of the three names is called in a sentence. */\nconst MATCH_LABELS: Record<MatchedOn, string> = {\n qualified: 'the schema-qualified name',\n name: 'the database name',\n tsName: 'the export name',\n};\n\n/** Every table whose names contain `query`, under the given case folding, one hit per table. */\nfunction hitsFor(tables: readonly Table[], query: string, fold: (s: string) => string): TableHit[] {\n const wanted = fold(query);\n const hits: TableHit[] = [];\n for (const table of tables) {\n const names = namesOf(table);\n const matchedOn = MATCH_ORDER.find((key) => fold(names[key]) === wanted);\n if (matchedOn) hits.push({ table, matchedOn });\n }\n return hits;\n}\n\nconst same = (s: string) => s;\nconst folded = (s: string) => s.toLowerCase();\n\n/**\n * The table a query names, or why it names none.\n *\n * Exact before case-insensitive, and both over all three names at once. The two rounds are\n * separate passes rather than one pass with a fallback comparison, because a schema holding both\n * `users` and `Users` has an exact answer for each, and a single case-insensitive pass would call\n * both of them ambiguous.\n *\n * Ambiguity is reported rather than resolved. It is reachable from an ordinary schema: two\n * `pgSchema` tables share one bare name, and a table's export name can be another table's\n * database name. Picking the first would answer a question about one table with facts about a\n * different one, which is the single worst thing a command whose whole job is diagnosis can do.\n *\n * An ambiguous exact round stops there rather than falling through to the case-insensitive one.\n * Loosening the comparison can only add hits, so the second round cannot resolve what the first\n * could not.\n */\nexport function matchTable(tables: readonly Table[], query: string): TableMatch {\n for (const [exact, fold] of [\n [true, same],\n [false, folded],\n ] as const) {\n const hits = hitsFor(tables, query, fold);\n if (hits.length === 1) return { kind: 'found', exact, ...hits[0] };\n if (hits.length > 1) return { kind: 'ambiguous', exact, hits };\n }\n // Only ever reached when nothing matched under either folding, so the suggestion is about a\n // misspelling rather than about a case difference, which the second round has already forgiven.\n const known = tables.flatMap((t) => {\n const names = namesOf(t);\n return t.tsName === names.name ? [names.name] : [names.name, names.tsName];\n });\n return { kind: 'none', suggestion: nearestKey(query, known) };\n}\n\n/* ------------------------------------------------------------------------------------------ */\n/* The explanation */\n/* ------------------------------------------------------------------------------------------ */\n\n/** How a column's default arrives, which decides whether any generated schema can state it. */\nexport type ExplainDefault =\n /** `.default('GB')`: a literal a schema can reproduce. */\n | { kind: 'literal'; value: unknown }\n /** A `sql` default the analyzer rendered back to text. */\n | { kind: 'expression'; text: string }\n /**\n * `defaultNow()`, `defaultRandom()`, `$defaultFn` and a `serial`'s sequence: the value exists\n * only at insert time, so the field is optional on insert and no schema states what it becomes.\n */\n | { kind: 'runtime' };\n\n/**\n * One measured fact about a column, and whether any generated schema says it.\n *\n * `stated` is not decided here. A width, a byte cap and a set of members are each read by every\n * validation generator through the same guards `tableConstraints` applies, so the verdict comes\n * off that function's output rather than from a second copy of the rule; see `capStated`.\n */\nexport interface ExplainFact {\n text: string;\n stated: boolean;\n /** Why nothing states it, when nothing does. */\n reason?: string;\n}\n\nexport interface ExplainColumn {\n name: string;\n tsType: string;\n /** The coarse family label, `TEXT` for every one of varchar, char and text. */\n dbType: string;\n /** The type as the database declares it, `varchar(255)`, absent where Drizzle would not say. */\n sqlType?: string;\n nullable: boolean;\n hasDefault: boolean;\n default: ExplainDefault | null;\n isGenerated: boolean;\n inPrimaryKey: boolean;\n /** Named by a single-column UNIQUE constraint. A composite one is in `unique` instead. */\n unique: boolean;\n references?: {\n table: string;\n schema?: string;\n column: string;\n onDelete?: string;\n onUpdate?: string;\n };\n enumValues?: string[];\n arrayDimensions?: number;\n shape?: Column['shape'];\n facts: ExplainFact[];\n}\n\n/** A relation with this table at one end, in the direction the analysis recorded it. */\nexport interface ExplainRelation extends Relation {\n /** Whether this table is the `from` end. */\n outgoing: boolean;\n}\n\n/**\n * Something in this table that DRZL read and could not use.\n *\n * The section the command exists for. Every entry here is a place where the generated output is\n * quietly narrower than the schema, and none of them is visible in the generated files.\n */\nexport interface ExplainGap {\n kind:\n /** A CHECK, or one clause of one, that no generated schema enforces. */\n | 'check'\n /** A column whose validator will accept any value. */\n | 'column'\n /** A relation the analyzer could not follow. */\n | 'relation'\n /** Anything else the analyzer said about this table. */\n | 'analyzer';\n /** The column or constraint it is about, where it is about one. */\n subject?: string;\n message: string;\n hint?: string;\n}\n\nexport interface TableExplanation {\n /** The database table name, which is not always the export name. */\n name: string;\n /** The TypeScript export name. */\n tsName: string;\n /** The SQL schema, present only where the table declares one. */\n schema?: string;\n /** `reporting.users`, or the bare `users` for a table in the default schema. */\n qualified: string;\n /** `public.users`: the one spelling that addresses this table and no other. */\n addressable: string;\n /** Set for a materialized view, which takes no writes, so no insert or update schema is emitted. */\n readOnly: boolean;\n /** Which name the query matched, and whether it matched without case folding. */\n matchedOn: MatchedOn;\n matchedExactly: boolean;\n /** True when this config's `include`/`exclude` removes the table, so no generator sees it. */\n excludedByConfig?: boolean;\n /** Columns this config's `columns` filter removes, in declaration order. */\n columnsRemovedByConfig?: string[];\n columns: ExplainColumn[];\n primaryKey: { name?: string; columns: string[]; generated: boolean } | null;\n unique: { name?: string; columns: string[] }[];\n indexes: { name?: string; columns: string[] }[];\n foreignKeys: {\n name?: string;\n columns: string[];\n references: { table: string; columns: string[] };\n onDelete?: string;\n onUpdate?: string;\n }[];\n relations: ExplainRelation[];\n /**\n * Every constraint on the table with the verdict a generated schema gives it, verbatim from\n * `tableConstraints`. The primary key, every UNIQUE, every foreign key, every CHECK and the\n * declared widths, each with `enforced` and, where it is false, the reason per clause.\n */\n constraints: ConstraintFacts[];\n /** What DRZL read and could not use. Empty when the whole table was understood. */\n gaps: ExplainGap[];\n}\n\n/** One line of the index a bare `drzl explain` prints. */\nexport interface TableSummary {\n name: string;\n tsName: string;\n schema?: string;\n qualified: string;\n columns: number;\n checks: number;\n /** How many entries `drzl explain <this table>` would list under \"Not understood\". */\n gaps: number;\n}\n\n/** The literal a `.default()` stored, as it would read in a schema file. */\nfunction renderLiteral(value: unknown): string {\n if (typeof value === 'string') return `'${value.replace(/'/g, \"\\\\'\")}'`;\n if (value === null) return 'null';\n if (typeof value === 'bigint') return `${value}n`;\n if (value instanceof Date) return value.toISOString();\n if (typeof value === 'object') return JSON.stringify(value);\n return String(value);\n}\n\n/** How a column's default arrives, or nothing where it has none. */\nfunction defaultOf(column: Column): ExplainDefault | null {\n if (column.defaultValue !== undefined) return { kind: 'literal', value: column.defaultValue };\n if (column.defaultExpression) return { kind: 'expression', text: column.defaultExpression };\n return column.hasDefault ? { kind: 'runtime' } : null;\n}\n\n/** A default in one cell of the column table. */\nfunction describeDefault(value: ExplainDefault | null): string {\n if (!value) return '';\n if (value.kind === 'literal') return `default ${renderLiteral(value.value)}`;\n if (value.kind === 'expression') return `default ${value.text}`;\n return 'has default';\n}\n\n/** What a `ColumnShape` is, in a sentence. Every kind has an arm, so a new one cannot go unnamed. */\nfunction describeShape(shape: NonNullable<Column['shape']>): string {\n switch (shape.kind) {\n case 'buffer':\n return 'binary payload, carried as a Uint8Array';\n case 'json':\n return 'any JSON value, checked recursively';\n case 'tuple':\n return `tuple of ${shape.length} numbers`;\n case 'numberObject':\n return `object of numbers: ${shape.fields.join(', ')}`;\n case 'numberVector':\n return shape.length ? `numeric vector of ${shape.length}` : 'numeric vector';\n case 'custom':\n return shape.sqlType\n ? `customType, declared ${shape.sqlType}, with no runtime shape to read`\n : 'customType, with no runtime shape to read';\n case 'bitstring':\n if (shape.length === undefined) return 'string of 0 and 1';\n return shape.exact\n ? `string of ${shape.length} digits, each 0 or 1`\n : `string of at most ${shape.length} digits, each 0 or 1`;\n case 'byteString':\n return shape.length ? `bytes, declared width ${shape.length}` : 'bytes';\n }\n}\n\n/**\n * Why a declared width never reaches the emitted schema.\n *\n * The branches of `statesCap` in `@drzl/validation-core`, in its order, so the sentence names the\n * same reason the guard acted on. Whether it is stated is not decided here; that comes off\n * `tableConstraints`, which calls the real guard. This only puts the reason into words, and the\n * last arm is a generic sentence rather than a guess, so a branch added there is worded vaguely\n * instead of wrongly.\n */\nfunction capReason(column: Column, narrowedBySet: boolean): string {\n if (column.shape)\n return `\"${column.name}\" is a structured column, whose value space is not stated as a width`;\n if (narrowedBySet)\n return `a CHECK narrows \"${column.name}\" to a set of literals, which states its value space instead`;\n if (column.enumValues?.length)\n return `\"${column.name}\" is an enum, and its members state its value space instead`;\n if (column.tsType !== 'string')\n return `\"${column.name}\" does not arrive as a string, so there is nothing to measure`;\n if (column.format)\n return `the ${column.format} format replaces the width on \"${column.name}\" rather than adding to it`;\n return `the generated schemas state \"${column.name}\" some other way`;\n}\n\n/**\n * Everything measured about a column that a validator can act on, with the verdict beside it.\n *\n * The order is the order it reads: what the value is, then how wide, then what it may hold.\n */\nfunction factsFor(\n column: Column,\n opts: { capStated: boolean; narrowedBySet: boolean }\n): ExplainFact[] {\n const facts: ExplainFact[] = [];\n const state = (text: string) => facts.push({ text, stated: true });\n\n if (column.arrayDimensions) {\n state(\n column.arrayDimensions === 1\n ? 'an array of the type above'\n : `an array of ${column.arrayDimensions} dimensions`\n );\n }\n if (column.shape) state(describeShape(column.shape));\n if (column.enumValues?.length) {\n state(`one of ${column.enumValues.map((v) => `'${v}'`).join(', ')}`);\n }\n if (column.format) state(`text in the ${column.format} format the database parses`);\n\n if (column.min !== undefined && column.max !== undefined) {\n state(`${column.min} to ${column.max}`);\n } else if (column.min !== undefined) state(`at least ${column.min}`);\n else if (column.max !== undefined) state(`at most ${column.max}`);\n if (column.integer === true) state('whole numbers only');\n if (column.integer === false) state('fractions allowed');\n\n // A range cannot say either of these: `>=`/`<=` refuses an infinity whatever the two numbers\n // are, and NaN compares false against both ends, so a bounded float column described by its\n // range alone refuses values the database stores and hands back. The generators render them\n // beside the range rather than as a wider one, which is why both are worth printing.\n if (column.allowsNaN !== undefined) {\n state(column.allowsNaN ? 'NaN is stored and returned' : 'NaN is refused');\n }\n if (column.allowsInfinity !== undefined) {\n state(column.allowsInfinity ? 'Infinity is stored and returned' : 'Infinity is refused');\n }\n\n for (const [value, text] of [\n [column.maxLength, `at most ${column.maxLength} characters`],\n [column.maxBytes, `at most ${column.maxBytes} bytes`],\n ] as const) {\n if (value === undefined) continue;\n facts.push(\n opts.capStated\n ? { text, stated: true }\n : { text, stated: false, reason: capReason(column, opts.narrowedBySet) }\n );\n }\n\n const value = defaultOf(column);\n if (value?.kind === 'literal') state(`defaults to ${renderLiteral(value.value)}`);\n else if (value?.kind === 'expression') state(`defaults to ${value.text}, evaluated by the database`);\n else if (value?.kind === 'runtime') {\n facts.push({\n text: 'has a default',\n stated: false,\n reason:\n 'the value is produced at insert time, by the database or by a Drizzle function, so the ' +\n 'field is optional on insert and no schema states what it becomes',\n });\n }\n if (column.isGenerated) {\n state('generated by the database, so it is left out of insert and update schemas');\n }\n return facts;\n}\n\n/**\n * Whether an analyzer issue is about this table.\n *\n * Matched against all three names, because the analyzer does not use one consistently and could\n * not: a column warning is keyed on the export name, a relation warning on the qualified database\n * name, and the extra-config warning on the table name. An issue about the schema as a whole\n * carries no `path` at all and is not about any table, so it never lands here.\n */\nfunction issueTouches(issue: Issue, table: Table): boolean {\n if (!issue.path) return false;\n const names = namesOf(table);\n const own = [names.qualified, names.name, names.tsName, table.name];\n if (own.includes(issue.path)) return true;\n const dot = issue.path.lastIndexOf('.');\n return dot > 0 && own.includes(issue.path.slice(0, dot));\n}\n\n/** The column half of a `table.column` issue path, when it has one. */\nfunction issueColumn(issue: Issue, table: Table): string | undefined {\n const path = issue.path ?? '';\n const names = namesOf(table);\n for (const prefix of [names.qualified, names.tsName, names.name, table.name]) {\n if (path.startsWith(`${prefix}.`)) {\n const rest = path.slice(prefix.length + 1);\n if (table.columns.some((c) => c.name === rest)) return rest;\n }\n }\n return undefined;\n}\n\n/** Which analyzer codes are about a relation rather than about the table's own shape. */\nconst RELATION_CODES = new Set(['DRZL_ANL_RELATIONS', 'DRZL_ANL_REL_V2']);\n\n/**\n * Everything DRZL read and could not use, in the order it costs a reader most to not know.\n *\n * Constraints first, because a declined CHECK is the case where the generated file exists,\n * compiles, validates, and enforces less than the database does with nothing anywhere saying so.\n */\nfunction gapsFor(table: Table, constraints: ConstraintFacts[], issues: readonly Issue[]) {\n const gaps: ExplainGap[] = [];\n\n for (const constraint of constraints) {\n for (const part of constraint.unenforced ?? []) {\n gaps.push({\n kind: 'check',\n subject: constraint.name ?? constraint.id,\n // `part.part` already carries the constraint name where the declaration had one, because\n // that is the text an emitted schema would have attached. The renderer prefixes `subject`\n // only when it is not already there, so a named CHECK is not announced twice.\n message: `${part.part} is not enforced: ${part.reason}.`,\n hint: 'Your database still enforces it. Nothing DRZL generates does.',\n });\n }\n }\n\n for (const issue of issues) {\n if (issue.level === 'info') continue;\n if (!issueTouches(issue, table)) continue;\n const subject = issueColumn(issue, table);\n gaps.push({\n kind: RELATION_CODES.has(issue.code) ? 'relation' : subject ? 'column' : 'analyzer',\n ...(subject ? { subject } : {}),\n message: issue.message,\n ...(issue.hint ? { hint: issue.hint } : {}),\n });\n }\n return gaps;\n}\n\nexport interface ExplainOptions {\n /** Table names this config's `include`/`exclude` leaves in place, when a config was read. */\n keptTables?: readonly string[];\n /** Column names this config's `columns` filter leaves on this table, when one was read. */\n keptColumns?: readonly string[];\n}\n\n/**\n * Everything worth saying about one table.\n *\n * A pure function of the analysis and the match, so the renderer, the `--json` document and the\n * tests all read one answer rather than three.\n */\nexport function explainTable(\n analysis: Analysis,\n match: Extract<TableMatch, { kind: 'found' }>,\n options: ExplainOptions = {}\n): TableExplanation {\n const table = match.table;\n const qualified = qualifiedTableName(table);\n const constraints = tableConstraints(table).constraints;\n\n // Which columns a generated schema really caps, taken off the shared guard rather than from a\n // second copy of it here: `tableConstraints` emits a `maxLength`/`maxBytes` constraint for a\n // column exactly when the emitted schemas state one.\n const capped = new Set(\n constraints\n .filter((c) => c.kind === 'maxLength' || c.kind === 'maxBytes')\n .flatMap((c) => c.columns)\n );\n const narrowedBySet = new Set(\n constraints.filter((c) => c.values).map((c) => c.values!.column)\n );\n\n const primaryKeyColumns = new Set(table.primaryKey?.columns ?? []);\n const singleColumnUnique = new Set(\n (table.unique ?? []).filter((u) => u.columns.length === 1).map((u) => u.columns[0])\n );\n\n const columns: ExplainColumn[] = table.columns.map((column) => ({\n name: column.name,\n tsType: column.tsType,\n dbType: column.dbType,\n ...(column.sqlType ? { sqlType: column.sqlType } : {}),\n nullable: column.nullable,\n hasDefault: column.hasDefault,\n default: defaultOf(column),\n isGenerated: column.isGenerated,\n inPrimaryKey: primaryKeyColumns.has(column.name),\n unique: singleColumnUnique.has(column.name),\n ...(column.references ? { references: column.references } : {}),\n ...(column.enumValues ? { enumValues: column.enumValues } : {}),\n ...(column.arrayDimensions ? { arrayDimensions: column.arrayDimensions } : {}),\n ...(column.shape ? { shape: column.shape } : {}),\n facts: factsFor(column, {\n capStated: capped.has(column.name),\n narrowedBySet: narrowedBySet.has(column.name),\n }),\n }));\n\n const relations: ExplainRelation[] = analysis.relations\n .filter((r) => r.from === qualified || r.to === qualified || r.via === qualified)\n .map((r) => ({ ...r, outgoing: r.from === qualified }));\n\n // A key is \"generated\" when the database fills it in without being told, which is the question\n // a reader has about an insert schema. `isGenerated` alone answers it for an identity column and\n // not for a `serial`, whose sequence arrives as an ordinary default with nothing else naming it.\n const keyColumns = table.columns.filter((c) => primaryKeyColumns.has(c.name));\n const primaryKey = table.primaryKey?.columns.length\n ? {\n ...(table.primaryKey.name ? { name: table.primaryKey.name } : {}),\n columns: [...table.primaryKey.columns],\n generated: keyColumns.length > 0 && keyColumns.every((c) => c.isGenerated || c.hasDefault),\n }\n : null;\n\n const removed = options.keptColumns\n ? table.columns.map((c) => c.name).filter((name) => !options.keptColumns!.includes(name))\n : [];\n\n return {\n name: table.name,\n tsName: table.tsName,\n ...(table.schema ? { schema: table.schema } : {}),\n qualified,\n addressable: addressableName(table),\n readOnly: !!table.readOnly,\n matchedOn: match.matchedOn,\n matchedExactly: match.exact,\n ...(options.keptTables && !options.keptTables.includes(qualified)\n ? { excludedByConfig: true }\n : {}),\n ...(removed.length ? { columnsRemovedByConfig: removed } : {}),\n columns,\n primaryKey,\n unique: (table.unique ?? []).map((u) => ({\n ...(u.name ? { name: u.name } : {}),\n columns: [...u.columns],\n })),\n indexes: (table.indexes ?? []).map((i) => ({\n ...(i.name ? { name: i.name } : {}),\n columns: [...i.columns],\n })),\n foreignKeys: (table.foreignKeys ?? []).map((fk) => ({\n ...(fk.name ? { name: fk.name } : {}),\n columns: [...fk.columns],\n references: { table: qualifiedForeignTable(fk), columns: [...fk.foreignColumns] },\n ...(fk.onDelete ? { onDelete: fk.onDelete } : {}),\n ...(fk.onUpdate ? { onUpdate: fk.onUpdate } : {}),\n })),\n relations,\n constraints,\n gaps: gapsFor(table, constraints, analysis.issues),\n };\n}\n\n/**\n * One line per table, with the number of things DRZL did not understand about each.\n *\n * The last number is why this exists rather than being left to `analyze`, which prints the whole\n * analysis as JSON and points at nothing in it. A reader with forty tables and one wrong file gets\n * told which table to run `explain` on instead of reading forty.\n */\nexport function summarize(analysis: Analysis): TableSummary[] {\n return analysis.tables.map((table) => ({\n name: table.name,\n tsName: table.tsName,\n ...(table.schema ? { schema: table.schema } : {}),\n qualified: qualifiedTableName(table),\n columns: table.columns.length,\n checks: table.checks?.length ?? 0,\n gaps: gapsFor(table, tableConstraints(table).constraints, analysis.issues).length,\n }));\n}\n\n/* ------------------------------------------------------------------------------------------ */\n/* Rendering */\n/* ------------------------------------------------------------------------------------------ */\n\n/**\n * How wide the report lays itself out.\n *\n * 80 rather than the 96 `doctor` wraps its prose at, because this one prints aligned rows and a\n * row that wraps is worse than a paragraph that does: the eye loses the column. Everything with a\n * computed width is fitted inside this, and the only cells allowed past it are the last one on a\n * line, where an overflow costs a soft wrap and nothing else.\n */\nconst WIDTH = 80;\n\nconst pad = (text: string, width: number) => text + ' '.repeat(Math.max(0, width - text.length));\n\n/** The widest of a set of strings, which is the column width every row is padded to. */\nconst widest = (values: string[]) => values.reduce((n, v) => Math.max(n, v.length), 0);\n\n/** Wrap a sentence under a fixed indent. Same shape as `doctor`'s, at this file's width. */\nfunction wrap(text: string, indent: string, first = indent): string {\n const lines: string[] = [];\n let line = '';\n for (const word of String(text).split(/\\s+/)) {\n if (line && `${line} ${word}`.length + indent.length > WIDTH) {\n lines.push(line);\n line = word;\n } else {\n line = line ? `${line} ${word}` : word;\n }\n }\n if (line) lines.push(line);\n return lines.map((l, i) => (i === 0 ? first : indent) + l).join('\\n');\n}\n\n/**\n * The TypeScript type as a reader of the generated schema would write it.\n *\n * `tsType` is the *element* type on an array column, because Drizzle gives an array no class of\n * its own and the analyzer records the depth separately. Printing it bare said `string` for a\n * `text[]`, which is the exact misreading that produced the array defect `arrayDimensions` was\n * added to fix, so the suffix is put back here.\n */\nfunction renderTsType(column: ExplainColumn): string {\n return column.tsType + '[]'.repeat(column.arrayDimensions ?? 0);\n}\n\n/** The short markers beside a column: what it is to the table, rather than what it holds. */\nfunction columnNotes(column: ExplainColumn): string {\n const notes: string[] = [];\n if (column.inPrimaryKey) notes.push('pk');\n if (column.unique) notes.push('unique');\n if (column.references) {\n notes.push(`fk -> ${column.references.table}.${column.references.column}`);\n }\n if (column.isGenerated) notes.push('generated');\n const value = describeDefault(column.default);\n if (value && !column.isGenerated) notes.push(value);\n return notes.join(', ');\n}\n\n/** The rule and the verdict for one constraint, as the reader needs to read them: side by side. */\nfunction constraintLines(\n constraint: ConstraintFacts,\n style: ChalkInstance,\n labelWidth: number\n): string[] {\n const label = constraint.name ?? '';\n const verdict = constraint.enforced\n ? style.green('enforced')\n : style.yellow('not enforced by any generated schema');\n const out = [` ${pad(label, labelWidth)} ${constraint.rule}`];\n out.push(` ${' '.repeat(labelWidth)} ${verdict}`);\n for (const part of constraint.unenforced ?? []) {\n out.push(style.dim(wrap(part.reason, ' '.repeat(labelWidth + 4))));\n }\n return out;\n}\n\n/**\n * The human report.\n *\n * Grouped rather than one flat list, because the questions are different: \"did DRZL read my column\n * right\" is answered by the first two sections and \"is my constraint enforced\" by the next three,\n * and a reader arrives holding exactly one of them.\n */\nexport function renderExplanation(\n explanation: TableExplanation,\n context: { schema: string; dialect: string },\n style: ChalkInstance = PLAIN\n): string {\n const out: string[] = [];\n const plural = (n: number, one: string) => `${n} ${one}${n === 1 ? '' : 's'}`;\n\n out.push(style.bold(explanation.qualified) + style.dim(` ${context.schema}`));\n const identity = [\n context.dialect,\n `table \"${explanation.name}\"`,\n `export \"${explanation.tsName}\"`,\n plural(explanation.columns.length, 'column'),\n ];\n if (explanation.readOnly) identity.push('read-only, so no insert or update schema is emitted');\n out.push(style.dim(' ' + identity.join(', ')));\n if (!explanation.matchedExactly) {\n // Said out loud, because a case-folded match is the one way this report can be about a table\n // the reader did not think they were asking for.\n out.push(style.dim(` matched on ${MATCH_LABELS[explanation.matchedOn]}, ignoring case`));\n }\n if (explanation.excludedByConfig) {\n out.push('');\n out.push(style.yellow(' This config\\'s include/exclude removes this table.'));\n out.push(style.dim(' No generator sees it, so nothing below reaches any emitted file.'));\n }\n if (explanation.columnsRemovedByConfig?.length) {\n out.push('');\n out.push(\n style.yellow(\n ` This config's columns filter removes ${explanation.columnsRemovedByConfig.length} of ` +\n `these columns: ${explanation.columnsRemovedByConfig.join(', ')}.`\n )\n );\n }\n out.push('');\n\n // ---- columns -------------------------------------------------------------------------------\n out.push(style.bold('Columns'));\n const tsTypes = explanation.columns.map(renderTsType);\n const nameWidth = widest(['COLUMN', ...explanation.columns.map((c) => c.name)]);\n const tsWidth = widest(['TS TYPE', ...tsTypes]);\n const sqlWidth = widest(['SQL TYPE', ...explanation.columns.map((c) => c.sqlType ?? c.dbType)]);\n out.push(\n style.dim(\n ` ${pad('COLUMN', nameWidth)} ${pad('TS TYPE', tsWidth)} ` +\n `${pad('SQL TYPE', sqlWidth)} NULL`\n )\n );\n explanation.columns.forEach((column, i) => {\n // `sqlType` is what the database declares and is the answer a reader came for; `dbType` is a\n // coarse family label and stands in only where Drizzle's builder would not answer at all.\n const sql = column.sqlType ?? column.dbType;\n const notes = columnNotes(column);\n const nullable = column.nullable ? 'yes' : 'no';\n out.push(\n ` ${pad(column.name, nameWidth)} ${pad(tsTypes[i], tsWidth)} ` +\n `${pad(sql, sqlWidth)} ` +\n // Padded only when something follows it: a trailing run of spaces on every second row is\n // invisible in a terminal and is the first thing a test diff shows.\n (notes ? `${pad(nullable, 4)} ${style.dim(notes)}` : nullable)\n );\n });\n\n // ---- the measured facts --------------------------------------------------------------------\n const withFacts = explanation.columns.filter((c) => c.facts.length);\n if (withFacts.length) {\n out.push('');\n out.push(style.bold('What the generators read off each column'));\n const factWidth = widest(withFacts.map((c) => c.name));\n for (const column of withFacts) {\n let first = true;\n for (const fact of column.facts) {\n const label = first ? pad(column.name, factWidth) : ' '.repeat(factWidth);\n first = false;\n out.push(` ${label} ${fact.stated ? fact.text : style.yellow(fact.text)}`);\n if (fact.stated) continue;\n out.push(\n style.dim(\n wrap(\n `not stated by any generated schema: ${fact.reason}`,\n ' '.repeat(factWidth + 4)\n )\n )\n );\n }\n }\n }\n\n // ---- keys, foreign keys, relations ---------------------------------------------------------\n out.push('');\n out.push(style.bold('Keys'));\n if (explanation.primaryKey) {\n const pk = explanation.primaryKey;\n out.push(\n ` PRIMARY KEY (${pk.columns.join(', ')})` +\n (pk.generated ? style.dim(' filled in by the database') : '')\n );\n if (pk.columns.length > 1) {\n out.push(\n style.dim(\n wrap(\n 'The service and router generators key getById, update and delete on ' +\n `\"${pk.columns[0]}\" alone, so those operations match on part of this key.`,\n ' '\n )\n )\n );\n }\n } else {\n out.push(style.yellow(' No primary key.'));\n out.push(\n style.dim(\n wrap(\n 'The service and router generators fall back to a column named \"id\".',\n ' '\n )\n )\n );\n }\n for (const unique of explanation.unique) {\n out.push(` UNIQUE (${unique.columns.join(', ')})` + (unique.name ? style.dim(` ${unique.name}`) : ''));\n }\n for (const index of explanation.indexes) {\n out.push(style.dim(` INDEX (${index.columns.join(', ')})${index.name ? ` ${index.name}` : ''}`));\n }\n\n if (explanation.foreignKeys.length) {\n out.push('');\n out.push(style.bold('Foreign keys'));\n for (const fk of explanation.foreignKeys) {\n const actions = [\n fk.onDelete ? `ON DELETE ${fk.onDelete}` : '',\n fk.onUpdate ? `ON UPDATE ${fk.onUpdate}` : '',\n ]\n .filter(Boolean)\n .join(' ');\n out.push(\n ` (${fk.columns.join(', ')}) -> ${fk.references.table} ` +\n `(${fk.references.columns.join(', ')})` +\n (actions ? style.dim(` ${actions}`) : '')\n );\n }\n }\n\n if (explanation.relations.length) {\n out.push('');\n out.push(style.bold('Relations'));\n for (const relation of explanation.relations) {\n const via = relation.via ? ` through ${relation.via}` : '';\n out.push(\n ` ${relation.from} -> ${relation.to}${via}` + style.dim(` ${relation.kind}`)\n );\n }\n }\n\n // ---- constraints ---------------------------------------------------------------------------\n const checks = explanation.constraints.filter((c) => c.kind === 'check');\n if (checks.length) {\n out.push('');\n out.push(style.bold('CHECK constraints, as DRZL parsed them'));\n const labelWidth = widest(checks.map((c) => c.name ?? ''));\n for (const check of checks) out.push(...constraintLines(check, style, labelWidth));\n }\n\n // ---- what was not understood ---------------------------------------------------------------\n out.push('');\n if (!explanation.gaps.length) {\n out.push(style.green('Nothing about this table was dropped or left unrecognised.'));\n return out.join('\\n');\n }\n out.push(style.yellow(`Not understood (${explanation.gaps.length})`));\n out.push(style.dim(' These are in your schema and are not in anything DRZL generates.'));\n out.push('');\n // One hint under the findings that share it, so the same sentence is not repeated under twenty\n // columns. Same grouping as `doctor`, for the same reason.\n const groups = new Map<string, ExplainGap[]>();\n for (const gap of explanation.gaps) {\n const key = gap.hint ?? '';\n groups.set(key, [...(groups.get(key) ?? []), gap]);\n }\n for (const [hint, items] of groups) {\n for (const gap of items) {\n const named = gap.subject && !gap.message.startsWith(gap.subject);\n out.push(wrap((named ? `${gap.subject}: ` : '') + gap.message, ' ', ` ${style.dim('-')} `));\n }\n if (hint) out.push(style.dim(wrap(hint, ' ')));\n out.push('');\n }\n return out.join('\\n').replace(/\\n+$/, '');\n}\n\n/** The index a bare `drzl explain` prints. */\nexport function renderIndex(\n tables: TableSummary[],\n context: { schema: string; dialect: string },\n style: ChalkInstance = PLAIN\n): string {\n const out: string[] = [];\n const plural = (n: number, one: string) => `${n} ${one}${n === 1 ? '' : 's'}`;\n\n out.push(style.bold(context.schema) + style.dim(` ${context.dialect}`));\n out.push(style.dim(` ${plural(tables.length, 'table')}`));\n out.push('');\n\n const nameWidth = widest(['TABLE', ...tables.map((t) => t.qualified)]);\n const tsWidth = widest(['EXPORT', ...tables.map((t) => t.tsName)]);\n out.push(style.dim(` ${pad('TABLE', nameWidth)} ${pad('EXPORT', tsWidth)} COLUMNS`));\n for (const table of tables) {\n const columns = String(table.columns);\n out.push(\n ` ${pad(table.qualified, nameWidth)} ${pad(table.tsName, tsWidth)} ` +\n (table.gaps\n ? `${pad(columns, 7)} ` +\n style.yellow(`${plural(table.gaps, 'thing')} not understood`)\n : columns)\n );\n }\n out.push('');\n out.push(style.dim(' drzl explain <table> for one of them in full'));\n return out.join('\\n');\n}\n\n/* ------------------------------------------------------------------------------------------ */\n/* The two ways a name fails */\n/* ------------------------------------------------------------------------------------------ */\n\n/** No such table (DRZL_EXPLAIN_001), or the name reaches more than one (DRZL_EXPLAIN_002). */\nexport const NO_SUCH_TABLE_CODE = 'DRZL_EXPLAIN_001';\nexport const AMBIGUOUS_TABLE_CODE = 'DRZL_EXPLAIN_002';\n\n/** How many table names a failure message lists before it stops. */\nconst NAME_CAP = 12;\n\n/**\n * \"There is no such table\", with the tables there are.\n *\n * The list is the point. A reader who mistypes a name, or who is looking at the wrong schema file\n * entirely, learns which from the same line, and the two are not otherwise distinguishable: an\n * empty output and a wrong output look the same from outside.\n */\nexport function noSuchTableProblem(\n query: string,\n tables: readonly Table[],\n suggestion: string | undefined\n): { code: string; message: string; hint: string } {\n const names = tables.map((t) => displayTableName(t));\n const shown = names.slice(0, NAME_CAP).join(', ');\n const rest = names.length > NAME_CAP ? `, and ${names.length - NAME_CAP} more` : '';\n return {\n code: NO_SUCH_TABLE_CODE,\n message:\n `No table called \"${query}\" (${NO_SUCH_TABLE_CODE}). ` +\n (names.length\n ? `This schema declares ${names.length} table${names.length === 1 ? '' : 's'}: ${shown}${rest}.`\n : 'This schema declares no tables.'),\n hint: suggestion\n ? `Did you mean \"${suggestion}\"?`\n : 'A table is matched by its database name, by its schema-qualified name, or by the name it ' +\n 'is exported under, ignoring case where nothing matches exactly.',\n };\n}\n\n/**\n * \"That name reaches more than one table\", with both of them and the spelling that separates them.\n *\n * Reachable from an ordinary schema, and silently picking one would answer a question about one\n * table with facts about another.\n */\nexport function ambiguousTableProblem(\n query: string,\n hits: readonly TableHit[]\n): { code: string; message: string; hint: string } {\n const named = hits\n .map((hit) => `${addressableName(hit.table)} (exported as ${hit.table.tsName})`)\n .join(', ');\n return {\n code: AMBIGUOUS_TABLE_CODE,\n message: `\"${query}\" names ${hits.length} tables (${AMBIGUOUS_TABLE_CODE}): ${named}.`,\n hint: `Name one of them exactly, for example \"${addressableName(hits[0].table)}\".`,\n };\n}\n","/**\n * drizzle-kit interop: read the schema path from `drizzle.config.ts`, so a drizzle-kit user\n * does not have to state it a second time in `drzl.config.ts`.\n *\n * Everything here mirrors drizzle-kit's measured behavior, read from the published dist of\n * drizzle-kit 0.31.10 rather than from its docs or from memory:\n *\n * - `Config.schema` is `string | string[]` and entries may be glob patterns (`index.d.mts`).\n * - The CLI's default config candidates are `drizzle.config.ts`, then `.js`, then `.json`,\n * in that order and nothing else (`drizzleConfigFromFile` in `bin.cjs`); a custom path can\n * be anything its `--config` flag can name, which `drizzleKit: '<path>'` mirrors.\n * - `prepareFilenames` (bin.cjs) expands each entry with glob.sync, expands a directory\n * match one level with readdir rather than recursively, unions the results, and hard-errors\n * when nothing matched. It also computes the list of code extensions (.ts .js .cjs .mjs\n * .mts .cts) into a variable it never reads, and then requires every match; DRZL applies\n * that filter for real, which is strictly friendlier than crashing on a README.md sitting\n * in the schema directory.\n * - `defineConfig` is the identity function (`index.mjs`), so evaluating the config module\n * yields the plain object and no drizzle-kit installation is needed to read it.\n *\n * Globs are expanded with `node:fs.globSync`, present since Node 22.0 and quiet on the CLI's\n * `engines` floor (measured: `*`, `**`, `{a,b}` and literal paths all behave; no\n * ExperimentalWarning on stderr on 22.22). No new dependency, and the config itself is loaded\n * through the same jiti path as `drzl.config.ts` (`importFreshConfigModule`), so the two\n * config files cannot drift onto different loaders.\n */\nimport type { Dialect } from '@drzl/analyzer';\nimport * as fs from 'node:fs';\nimport * as path from 'node:path';\nimport { importFreshConfigModule } from './config.js';\n\n/** The default candidates drizzle-kit's own CLI tries, in its order. `.mjs`/`.cjs` are not\n * candidates because they are not drizzle-kit's; a project using one names it explicitly via\n * `drizzleKit: './drizzle.config.mjs'`, exactly as it must pass `--config` to kit itself. */\nexport const DRIZZLE_KIT_CONFIG_CANDIDATES = [\n 'drizzle.config.ts',\n 'drizzle.config.js',\n 'drizzle.config.json',\n] as const;\n\n/** The extensions drizzle-kit's `prepareFilenames` names as schema code. */\nconst CODE_EXTENSIONS = new Set(['.ts', '.js', '.cjs', '.mjs', '.mts', '.cts']);\n\nexport interface DrizzleKitConfig {\n /** Absolute path of the file this came from. */\n path: string;\n schema?: string | string[];\n dialect?: string;\n casing?: string;\n}\n\n/**\n * Where the schema will be read from, decided once and handed to both `generate` and `watch`,\n * so the two commands cannot resolve differently.\n */\nexport interface ResolvedSchemaSource {\n source: 'drzl' | 'drizzle-kit';\n /**\n * What `SchemaAnalyzer` is constructed with: the drzl config's `schema` string verbatim, or\n * the expanded, sorted, absolute file list from the drizzle-kit config.\n */\n schema: string | string[];\n /**\n * Absolute directories that must be watched for schema edits. For a glob this is its static\n * base, so a file created later that matches the pattern still raises an event; a missing\n * entry here is the infinite-blindness half of the watch-loop rules.\n */\n watchDirs: string[];\n /** Absolute path of the drizzle-kit config consulted, when source is 'drizzle-kit'. */\n drizzleKitConfigPath?: string;\n /** The dialect that config declares, verbatim, for the post-analysis cross-check. */\n drizzleKitDialect?: string;\n warnings: string[];\n}\n\n/** The first existing default candidate, in drizzle-kit's own order, or null. */\nexport function findDrizzleKitConfig(cwd: string): string | null {\n for (const name of DRIZZLE_KIT_CONFIG_CANDIDATES) {\n const p = path.join(cwd, name);\n if (fs.existsSync(p)) return p;\n }\n return null;\n}\n\n/** Load and narrow a drizzle-kit config file. Throws with the file named on anything wrong. */\nexport async function loadDrizzleKitConfig(p: string): Promise<DrizzleKitConfig> {\n let raw: unknown;\n try {\n raw = await importFreshConfigModule(p);\n } catch (e) {\n throw new Error(\n `drzl config: failed to load the drizzle-kit config at ${p}: ${(e as any)?.message ?? e}`\n );\n }\n if (!raw || typeof raw !== 'object') {\n throw new Error(`drzl config: ${p} did not export a drizzle-kit config object.`);\n }\n const record = raw as Record<string, unknown>;\n const schema = record.schema;\n if (\n schema !== undefined &&\n typeof schema !== 'string' &&\n !(Array.isArray(schema) && schema.every((s) => typeof s === 'string'))\n ) {\n throw new Error(\n `drzl config: \"schema\" in ${p} must be a string or an array of strings, matching ` +\n `drizzle-kit's own Config type.`\n );\n }\n return {\n path: p,\n schema: schema as string | string[] | undefined,\n dialect: typeof record.dialect === 'string' ? record.dialect : undefined,\n casing: typeof record.casing === 'string' ? record.casing : undefined,\n };\n}\n\n/** Whether glob would treat any part of this entry as a pattern rather than a name. */\nfunction hasGlobMagic(entry: string): boolean {\n return /[*?{}[\\]]/.test(entry) || /[!@+]\\(/.test(entry);\n}\n\n/**\n * The longest leading run of pattern-free path segments, as an absolute directory: what a\n * watcher can actually watch on behalf of a glob.\n */\nfunction staticGlobBase(entry: string, cwd: string): string {\n const segments = entry.split('/');\n const kept: string[] = [];\n for (const s of segments) {\n if (hasGlobMagic(s)) break;\n kept.push(s);\n }\n // The last static segment before the magic may itself be a filename prefix; treating it as a\n // directory is still right, because resolve of `src/db` under a pattern `src/db/*.ts` IS the\n // directory. An entirely magic entry watches the cwd.\n const joined = kept.join('/');\n const base = path.resolve(cwd, joined || '.');\n // `src/*.ts` keeps `src`; `schema-*.ts` keeps nothing and must not watch a file named after\n // the prefix, so anything that is not an existing directory falls back to its dirname.\n if (fs.existsSync(base) && fs.statSync(base).isDirectory()) return base;\n return path.dirname(base);\n}\n\n/** One level of a directory, files only: exactly what kit's `prepareFilenames` does. */\nfunction filesOneLevel(dir: string): string[] {\n const out: string[] = [];\n for (const name of fs.readdirSync(dir)) {\n const full = path.join(dir, name);\n if (!fs.lstatSync(full).isDirectory()) out.push(full);\n }\n return out;\n}\n\n/**\n * Expand drizzle-kit `schema` entries into concrete files plus the directories a watcher\n * needs. Deterministic: the file list is deduplicated and sorted, so everything downstream\n * (first-wins export merging in the analyzer above all) is stable across runs.\n */\nexport function expandSchemaPaths(\n entries: string | string[],\n cwd: string\n): { files: string[]; watchDirs: string[] } {\n const list = typeof entries === 'string' ? [entries] : entries;\n const files = new Set<string>();\n const watchDirs = new Set<string>();\n\n for (const entry of list) {\n if (hasGlobMagic(entry)) {\n watchDirs.add(staticGlobBase(entry, cwd));\n for (const match of fs.globSync(entry, { cwd })) {\n const full = path.resolve(cwd, match);\n if (fs.existsSync(full) && fs.statSync(full).isDirectory()) {\n for (const f of filesOneLevel(full)) files.add(f);\n } else {\n files.add(full);\n }\n }\n continue;\n }\n const full = path.resolve(cwd, entry);\n let stat: fs.Stats | null = null;\n try {\n stat = fs.statSync(full);\n } catch {\n // A missing literal entry contributes nothing, exactly as glob.sync returns [] for it in\n // kit; the caller's \"matched no schema files\" check is what reports an all-typo config.\n // Its directory is still watched, so creating the file later wakes the watcher.\n watchDirs.add(path.dirname(full));\n continue;\n }\n if (stat.isDirectory()) {\n watchDirs.add(full);\n for (const f of filesOneLevel(full)) files.add(f);\n } else {\n watchDirs.add(path.dirname(full));\n files.add(full);\n }\n }\n\n const kept = [...files].filter((f) => CODE_EXTENSIONS.has(path.extname(f).toLowerCase()));\n return { files: kept.sort(), watchDirs: [...watchDirs] };\n}\n\n/**\n * drizzle-kit's dialect vocabulary mapped onto the analyzer's, `null` when there is no\n * confident mapping (in which case the cross-check stays quiet rather than guessing).\n * `turso` is libsql, which is SQLite on the wire, which is what the analyzer detects.\n */\nexport function mapDrizzleKitDialect(declared: string | undefined): Dialect | null {\n if (!declared) return null;\n const map: Record<string, Dialect> = {\n postgresql: 'postgres',\n mysql: 'mysql',\n sqlite: 'sqlite',\n turso: 'sqlite',\n singlestore: 'singlestore',\n gel: 'gel',\n };\n if (declared in map) return map[declared];\n // A future kit dialect that already speaks the analyzer's name (say, 'cockroach') maps to\n // itself rather than silently losing the cross-check.\n const analyzerDialects: readonly Dialect[] = [\n 'sqlite',\n 'postgres',\n 'mysql',\n 'singlestore',\n 'mssql',\n 'cockroach',\n 'gel',\n ];\n return (analyzerDialects as readonly string[]).includes(declared) ? (declared as Dialect) : null;\n}\n\n/**\n * The warning for a drizzle-kit config whose `dialect` contradicts what the analyzer measured,\n * or null when there is nothing to say: agreement, an unmappable declaration, or an analysis\n * that could not identify a dialect at all (which already warned as DRZL_ANL_DIALECT).\n */\nexport function dialectMismatchWarning(args: {\n configPath: string;\n declared: string | undefined;\n analyzed: Dialect;\n}): string | null {\n const expected = mapDrizzleKitDialect(args.declared);\n if (!expected) return null;\n if (args.analyzed === 'unknown') return null;\n if (args.analyzed === expected) return null;\n return (\n `drzl: ${args.configPath} declares dialect \"${args.declared}\", but the schema analyzed ` +\n `as \"${args.analyzed}\". DRZL follows the schema; if the schema files are the right ones, ` +\n `the dialect in that config is stale.`\n );\n}\n\n/**\n * Decide where the schema comes from. Precedence, in order:\n *\n * 1. `schema` in the drzl config wins outright. If `drizzleKit` is also set to something\n * that would read a file, that is two sources for one fact, so it warns and reads only\n * `schema`; this config parser has shipped silently-dead keys twice before.\n * 2. Otherwise `drizzleKit` decides: `false` refuses the fallback, a string names the file,\n * and `true` or unset searches drizzle-kit's own default candidates. Unset behaving like\n * `true` is deliberate: `schema` was required until this feature existed, so no\n * pre-existing config can reach the fallback, and the CLI announces the file it read.\n * 3. Neither yielding a schema is an error that names both files and what to do.\n */\nexport async function resolveSchemaSource(\n cfg: { schema?: string; drizzleKit?: boolean | string },\n cwd = process.cwd()\n): Promise<ResolvedSchemaSource> {\n if (cfg.schema) {\n const warnings: string[] = [];\n if (cfg.drizzleKit === true || typeof cfg.drizzleKit === 'string') {\n warnings.push(\n `drzl config: both \"schema\" and \"drizzleKit\" are set. \"schema\" wins, so the ` +\n `drizzle-kit config was not read; remove one of the two to silence this.`\n );\n }\n return {\n source: 'drzl',\n schema: cfg.schema,\n watchDirs: [path.dirname(path.resolve(cwd, cfg.schema))],\n warnings,\n };\n }\n\n if (cfg.drizzleKit === false) {\n throw new Error(\n `drzl config: no \"schema\" is set and \"drizzleKit\" is false, so the drizzle-kit fallback ` +\n `is disabled. Set \"schema\".`\n );\n }\n\n let configPath: string;\n if (typeof cfg.drizzleKit === 'string') {\n configPath = path.resolve(cwd, cfg.drizzleKit);\n if (!fs.existsSync(configPath)) {\n throw new Error(`drzl config: \"drizzleKit\" points at ${configPath}, which does not exist.`);\n }\n } else {\n const found = findDrizzleKitConfig(cwd);\n if (!found) {\n const looked = DRIZZLE_KIT_CONFIG_CANDIDATES.join(', ');\n throw new Error(\n cfg.drizzleKit === true\n ? `drzl config: \"drizzleKit\" is set, but no drizzle-kit config was found (looked ` +\n `for ${looked} in ${cwd}). Create one, or point \"drizzleKit\" at its path.`\n : `drzl config: no \"schema\" is set and no drizzle-kit config was found (looked for ` +\n `${looked} in ${cwd}). Set \"schema\" in your drzl config, or add \"drizzleKit\" ` +\n `naming your drizzle-kit config file.`\n );\n }\n configPath = found;\n }\n\n const kit = await loadDrizzleKitConfig(configPath);\n if (kit.schema === undefined) {\n throw new Error(\n `drzl config: ${configPath} has no \"schema\" entry, so there is nothing to analyze. Set ` +\n `\"schema\" there, or set \"schema\" in your drzl config.`\n );\n }\n const { files, watchDirs } = expandSchemaPaths(kit.schema, cwd);\n if (!files.length) {\n const shown = (typeof kit.schema === 'string' ? [kit.schema] : kit.schema)\n .map((s) => JSON.stringify(s))\n .join(', ');\n throw new Error(\n `drzl config: the \"schema\" patterns in ${configPath} matched no schema files: ${shown}. ` +\n `DRZL expands them the way drizzle-kit does; check them against your tree.`\n );\n }\n return {\n source: 'drizzle-kit',\n schema: files,\n watchDirs,\n drizzleKitConfigPath: configPath,\n drizzleKitDialect: kit.dialect,\n warnings: [],\n };\n}\n","/**\n * Drift detection for generated output.\n *\n * No runtime validator can offer this. `drizzle-orm/zod` and friends derive schemas in memory at\n * import time, so there is nothing on disk to have drifted and nothing for CI to compare. It is\n * only available to a code generator, which makes it one of the few things DRZL can do that the\n * first-party modules structurally cannot.\n *\n * The check is: regenerate, and require the result to equal what is committed. That catches the\n * two failures that actually happen, someone editing generated files by hand and someone\n * changing the schema without regenerating, and it catches them in CI rather than in review.\n *\n * Content-neutral by construction. Redirecting output to a temporary directory would not work:\n * generated files contain paths computed relative to their own location, so a different output\n * directory produces legitimately different bytes and every file would report as drifted. So the\n * real directories are snapshotted first, regeneration is allowed to overwrite them, and the\n * snapshot is put back if anything changed. Either way the tree ends as it began.\n */\nimport { promises as fs } from 'node:fs';\nimport path from 'node:path';\n\nexport interface DriftEntry {\n file: string;\n status: 'changed' | 'added' | 'removed';\n}\n\n/** Every file under `dir`, keyed by its path relative to `dir`. Missing directory means empty. */\nexport async function snapshotDir(dir: string): Promise<Map<string, string>> {\n const out = new Map<string, string>();\n async function walk(current: string) {\n let entries;\n try {\n entries = await fs.readdir(current, { withFileTypes: true });\n } catch {\n return; // Nothing generated there yet, which a first run should report as additions.\n }\n for (const e of entries) {\n const full = path.join(current, e.name);\n if (e.isDirectory()) await walk(full);\n else out.set(path.relative(dir, full), await fs.readFile(full, 'utf8'));\n }\n }\n await walk(dir);\n return out;\n}\n\n/** Snapshot several directories at once, keys prefixed by directory so they cannot collide. */\nexport async function snapshotAll(dirs: string[]): Promise<Map<string, string>> {\n const all = new Map<string, string>();\n for (const dir of dirs) {\n for (const [rel, content] of await snapshotDir(dir)) {\n all.set(path.join(dir, rel), content);\n }\n }\n return all;\n}\n\n/** What changed between two snapshots. */\nexport function diffSnapshots(\n before: Map<string, string>,\n after: Map<string, string>\n): DriftEntry[] {\n const out: DriftEntry[] = [];\n for (const [file, content] of after) {\n if (!before.has(file)) out.push({ file, status: 'added' });\n else if (before.get(file) !== content) out.push({ file, status: 'changed' });\n }\n for (const file of before.keys()) {\n if (!after.has(file)) out.push({ file, status: 'removed' });\n }\n return out.sort((a, b) => a.file.localeCompare(b.file));\n}\n\n/**\n * Put a snapshot back, so a failed check leaves the tree exactly as it found it.\n *\n * A file that regeneration created and the snapshot does not know about is deleted, since it was\n * not there before the check ran.\n */\nexport async function restoreSnapshot(\n before: Map<string, string>,\n after: Map<string, string>\n): Promise<void> {\n for (const [file, content] of before) {\n await fs.mkdir(path.dirname(file), { recursive: true });\n await fs.writeFile(file, content, 'utf8');\n }\n for (const file of after.keys()) {\n if (!before.has(file)) await fs.rm(file, { force: true });\n }\n}\n","/**\n * What a generate run is about to put on disk, and how that differs from what is there (plan items\n * 68, 80, 81).\n *\n * The three items read as three features and are one mechanism. `--dry-run` is \"compute this and\n * stop\", `generate` reporting what changed is \"compute this and write it\", and `--check` is\n * \"compute this, do not write it, and show the difference\". All three need exactly one fact per\n * file: the content about to be written, beside the content already there. So that fact is\n * produced once, here, and the three commands differ only in what they do with it.\n *\n * ## The plan is the sink\n *\n * Generators hand their writes to a `FileSink` (see `emit.ts` in `@drzl/validation-core`). This\n * class is that sink. In `write` mode it records and then writes; in `plan` mode it records and\n * stops. Nothing else about a run changes between the two, which is what makes a dry run an honest\n * preview rather than a second implementation that can drift from the real one.\n *\n * ## Why `--check` no longer writes\n *\n * `--check` used to snapshot the output directories, let the generators overwrite them for real,\n * compare, and put the snapshot back. That works and was tested, but it means the one command\n * documented as never touching your tree is the command that rewrites every generated file on\n * every CI run, and a process killed between the write and the restore leaves the tree modified\n * with no record of it. On the plan it compares without writing at all, so there is no window.\n *\n * The snapshot is still taken, for a different job: see `verifyNothingWasWritten`.\n */\nimport { promises as fs } from 'node:fs';\nimport path from 'node:path';\nimport type { FileSink } from '@drzl/validation-core';\nimport { diffSnapshots, restoreSnapshot, snapshotAll } from './drift.js';\n\n/** What happened, or would happen, to one file. */\nexport type FileVerdict = 'created' | 'changed' | 'unchanged';\n\nexport interface EmittedFile {\n /** Absolute path, exactly as the generator spelled it. */\n file: string;\n verdict: FileVerdict;\n /** What is on disk now, or `null` when nothing is. */\n before: string | null;\n /** What the run produced for it. */\n after: string;\n}\n\nexport interface EmitCounts {\n total: number;\n created: number;\n changed: number;\n unchanged: number;\n}\n\nexport interface EmitPlanOptions {\n /**\n * Whether the recorded writes also reach the filesystem.\n *\n * `false` is `--dry-run` and `--check`. Nothing is written and no directory is created, which is\n * the whole claim those two flags make.\n */\n write: boolean;\n /**\n * Content already on disk, keyed by absolute path, when the caller has it.\n *\n * `--check` and `--dry-run` snapshot the output directories before the run anyway, so handing\n * that map over here saves reading every file a second time. A path missing from the map is\n * taken to be absent from disk, which is why this must only ever be a snapshot of directories\n * that cover everything the run can write. Omitted, each file is read as it is emitted, which is\n * what an ordinary `generate` does.\n */\n existing?: Map<string, string>;\n}\n\nexport class EmitPlan implements FileSink {\n readonly writes: boolean;\n private readonly existing?: Map<string, string>;\n private readonly byFile = new Map<string, EmittedFile>();\n private readonly dirs = new Set<string>();\n\n constructor(options: EmitPlanOptions) {\n this.writes = options.write;\n this.existing = options.existing;\n }\n\n async mkdir(dir: string): Promise<void> {\n this.dirs.add(dir);\n if (this.writes) await fs.mkdir(dir, { recursive: true });\n }\n\n async writeFile(file: string, contents: string): Promise<void> {\n // The first recording of a path owns its `before`. Two generators pointed at one directory,\n // or one generator writing a file twice, would otherwise have the second write compare itself\n // against the first write's output and report `unchanged` for a file that really did change.\n const prior = this.byFile.get(file);\n const before = prior ? prior.before : await this.read(file);\n this.byFile.set(file, {\n file,\n before,\n after: contents,\n verdict: before === null ? 'created' : before === contents ? 'unchanged' : 'changed',\n });\n if (!this.writes) return;\n // A byte-identical write is a no-op with a side effect: it moves the file's mtime, and an mtime\n // is what every watcher downstream keys on. A `drzl generate` over an up-to-date tree therefore\n // restarted a dev server, re-ran a type checker and invalidated a bundler cache for a tree that\n // had not changed. Skipping the write makes the command idempotent at the filesystem level,\n // which is what it already claims to be in its own output when it prints `unchanged`.\n //\n // Compared against what is on disk *now* rather than against what was there when the run\n // started. The two differ for a path written twice in one run, which is what happens when two\n // generators share an output directory: the first write has already put different bytes there,\n // so \"identical to what was there before the run\" stops meaning \"identical to what is there\".\n const onDisk = prior ? (this.wrote.has(file) ? prior.after : prior.before) : before;\n if (onDisk === contents) return;\n await fs.writeFile(file, contents, 'utf8');\n this.wrote.add(file);\n }\n\n /** Paths this run has actually put bytes on disk for, which is not every path it recorded. */\n private readonly wrote = new Set<string>();\n\n private async read(file: string): Promise<string | null> {\n if (this.existing) return this.existing.get(file) ?? null;\n try {\n return await fs.readFile(file, 'utf8');\n } catch {\n return null;\n }\n }\n\n /** Every directory a generator asked for, whether or not it was created. */\n get directories(): string[] {\n return [...this.dirs];\n }\n\n /** Every recorded file, in the order it was first written. */\n get files(): EmittedFile[] {\n return [...this.byFile.values()];\n }\n\n /**\n * The verdicts for a list of paths, in the order given.\n *\n * A path with no verdict is a path the generator reported writing without routing it through\n * the sink, which is the one shape a version mismatch takes: a `@drzl/cli` that knows about\n * `fileSink` beside a generator package that predates it. It is returned rather than thrown on\n * so the caller can name the generator; see `unrecorded`.\n */\n verdictsFor(paths: string[]): Array<EmittedFile | undefined> {\n return paths.map((p) => this.byFile.get(p));\n }\n\n /** The paths a generator claims to have written that never reached this sink. */\n unrecorded(paths: string[]): string[] {\n return paths.filter((p) => !this.byFile.has(p));\n }\n\n counts(paths?: string[]): EmitCounts {\n const entries = paths ? (this.verdictsFor(paths).filter(Boolean) as EmittedFile[]) : this.files;\n const counts: EmitCounts = { total: entries.length, created: 0, changed: 0, unchanged: 0 };\n for (const e of entries) counts[e.verdict]++;\n return counts;\n }\n}\n\n/** `3 created, 1 changed, 8 unchanged`, with the zeroes left out. */\nexport function describeCounts(counts: EmitCounts): string {\n const parts: string[] = [];\n if (counts.created) parts.push(`${counts.created} created`);\n if (counts.changed) parts.push(`${counts.changed} changed`);\n if (counts.unchanged) parts.push(`${counts.unchanged} unchanged`);\n return parts.join(', ') || 'nothing to write';\n}\n\n/** The files a plan would not leave alone. `--check` calls this drift; a dry run calls it the news. */\nexport function pendingChanges(plan: EmitPlan): EmittedFile[] {\n return plan.files\n .filter((f) => f.verdict !== 'unchanged')\n .sort((a, b) => a.file.localeCompare(b.file));\n}\n\n/**\n * The `--check` drift statuses, kept exactly as they were published.\n *\n * `created` is reported as `added`, because that is the word the `--json` contract, the docs and\n * every CI job reading them have used since `--check` shipped. `removed` is still a value of the\n * published union and is still produced by `drift.ts`; the plan cannot produce one, since a plan\n * is a list of writes and a write never deletes. Reporting every file in an output directory that\n * the run did not emit would produce them, and was deliberately not done: `outDir` is whatever the\n * config says, a project that points it at `src` would have every hand-written module in the tree\n * reported as drift, and turning that into a failing CI job is not a change anyone asked for.\n */\nexport function driftStatusOf(verdict: FileVerdict): 'added' | 'changed' {\n return verdict === 'created' ? 'added' : 'changed';\n}\n\n/**\n * Prove that a plan-mode run really wrote nothing, and put the tree back if it did.\n *\n * This is a guard against one specific failure, and it is worth its cost because that failure is\n * silent and destructive. `fileSink` is an option, so a generator package that predates it accepts\n * it, ignores it, and writes to disk. Inside this repository that cannot happen, since everything\n * is built together; on a user's machine `@drzl/cli` and the generators are separate packages on\n * separate versions, and npm is free to install a new CLI beside an old generator.\n *\n * The comparison is the snapshot the run already took for its `before` content, against the same\n * directories afterwards. Anything that differs is restored, and the caller is told, because a\n * `--dry-run` that quietly rewrote the tree is the worst outcome this feature has.\n *\n * Returns the paths that were written, empty when the run behaved.\n */\nexport async function verifyNothingWasWritten(\n dirs: string[],\n before: Map<string, string>\n): Promise<string[]> {\n const after = await snapshotAll(dirs);\n const drift = diffSnapshots(before, after);\n if (!drift.length) return [];\n await restoreSnapshot(before, after);\n return drift.map((d) => d.file).sort();\n}\n\n/** A path as a reader of the terminal wants to see it: relative to where they ran the command. */\nexport function displayPath(file: string, cwd = process.cwd()): string {\n const rel = path.relative(cwd, file);\n return rel && !rel.startsWith('..') ? rel : file;\n}\n","/**\n * A unified diff of two texts, written here rather than installed (plan item 81).\n *\n * `generate --check` named the files that had drifted and stopped there, which tells a reviewer\n * that something is stale and nothing about what. The diff is the part that turns a red CI job\n * into a decision: a regenerated header, a column that gained a length cap, and a hand-edit\n * somebody made to a generated file all read identically as \"changed\".\n *\n * ## Why not a dependency\n *\n * `diff` (jsdiff) is the obvious choice and is already resolvable in this workspace, but only as a\n * transitive dependency of `ts-node`, which is a devDependency of the CLI package. Relying on that\n * would be relying on a hoist. Adding it as a real dependency of `@drzl/cli` costs a package on\n * every install of a CLI whose whole job is to write files, in exchange for about a hundred lines\n * of a published algorithm, and this repository publishes through npm's trusted-publisher OIDC\n * flow where every new dependency is another thing to keep resolvable. So it is here, with the\n * property test that matters: applying the emitted diff to the \"before\" text has to reproduce the\n * \"after\" text exactly, which is the only check that can tell a plausible-looking diff from a\n * correct one.\n *\n * ## Format\n *\n * Unified, because it is the format `git`, `patch`, review tools and every developer already read,\n * and because it greps: a line beginning `+` or `-` is a change, and the `@@` header names where.\n * The alternative worth considering was a side-by-side or a word-level diff, which reads better\n * for prose and worse for generated code, where the interesting change is usually one whole line.\n *\n * ## Caps\n *\n * Myers is O((N+M)D): fast when the two texts are close, which is the case that matters, and\n * quadratic when they are not. Both bounds below are stated in the output when they bite, because\n * a diff that silently stops is worse than no diff: a reviewer who cannot see the truncation reads\n * the visible hunks as the whole story.\n */\n\n/** The two bounds, and the context width. */\nexport interface DiffLimits {\n /** Longest file, in lines, this will diff line by line. */\n maxLines: number;\n /** Largest edit script, in inserted plus deleted lines, before it gives up. */\n maxEdits: number;\n /** Unchanged lines kept around each hunk. Three is what `diff -u` and `git` use. */\n context: number;\n}\n\nexport const DEFAULT_DIFF_LIMITS: DiffLimits = {\n maxLines: 4000,\n maxEdits: 1500,\n context: 3,\n};\n\ntype Op = { kind: 'equal' | 'insert' | 'delete'; a: number; b: number };\n\n/**\n * Split into lines, keeping the fact of a trailing newline separate.\n *\n * `'a\\nb\\n'.split('\\n')` is `['a', 'b', '']`, and that empty string is not a line; carrying it\n * would put a spurious empty line at the end of every hunk that reaches the end of a file. So it\n * is dropped and remembered, which is also what produces the `\` marker\n * when only one side has it.\n */\nfunction toLines(text: string): { lines: string[]; newlineAtEnd: boolean } {\n if (text === '') return { lines: [], newlineAtEnd: true };\n const newlineAtEnd = text.endsWith('\\n');\n const lines = text.split('\\n');\n if (newlineAtEnd) lines.pop();\n return { lines, newlineAtEnd };\n}\n\n/**\n * Myers' shortest edit script, capped.\n *\n * The published greedy algorithm: for each edit distance `d`, walk the diagonals reachable with\n * `d` edits and take the furthest point on each. `trace` keeps the frontier per `d` so the path\n * can be walked back afterwards, which is what turns \"the distance is 4\" into \"these four lines\".\n *\n * Returns `null` when the distance exceeds `maxEdits`, which the caller reports rather than hides.\n */\nfunction shortestEdit(a: string[], b: string[], maxEdits: number): Int32Array[] | null {\n const n = a.length;\n const m = b.length;\n const max = n + m;\n const offset = max;\n const v = new Int32Array(2 * max + 1);\n const trace: Int32Array[] = [];\n const limit = Math.min(max, maxEdits);\n\n for (let d = 0; d <= limit; d++) {\n trace.push(Int32Array.prototype.slice.call(v));\n for (let k = -d; k <= d; k += 2) {\n let x: number;\n if (k === -d || (k !== d && v[k - 1 + offset] < v[k + 1 + offset])) x = v[k + 1 + offset];\n else x = v[k - 1 + offset] + 1;\n let y = x - k;\n while (x < n && y < m && a[x] === b[y]) {\n x++;\n y++;\n }\n v[k + offset] = x;\n if (x >= n && y >= m) return trace;\n }\n }\n return null;\n}\n\n/** Walk the frontier back from the end, producing the operations in order. */\nfunction backtrack(trace: Int32Array[], a: string[], b: string[]): Op[] {\n const max = a.length + b.length;\n const offset = max;\n let x = a.length;\n let y = b.length;\n const ops: Op[] = [];\n\n for (let d = trace.length - 1; d >= 0; d--) {\n const v = trace[d];\n const k = x - y;\n let prevK: number;\n if (k === -d || (k !== d && v[k - 1 + offset] < v[k + 1 + offset])) prevK = k + 1;\n else prevK = k - 1;\n const prevX = v[prevK + offset];\n const prevY = prevX - prevK;\n\n while (x > prevX && y > prevY) {\n x--;\n y--;\n ops.push({ kind: 'equal', a: x, b: y });\n }\n if (d > 0) {\n if (x === prevX) {\n y--;\n ops.push({ kind: 'insert', a: x, b: y });\n } else {\n x--;\n ops.push({ kind: 'delete', a: x, b: y });\n }\n }\n }\n ops.reverse();\n return ops;\n}\n\n/**\n * The operations turning `a` into `b`, or `null` when a cap was hit.\n *\n * Common leading and trailing lines are stripped before Myers runs and put back as `equal`\n * afterwards. That is not an optimisation for its own sake: the pair this is asked about is\n * almost always a generated file against the same file with one table changed, where the shared\n * head and tail are the whole file bar a few lines, and stripping them takes the edit distance\n * that Myers has to search from thousands to single figures.\n */\nexport function diffLines(a: string[], b: string[], maxEdits: number): Op[] | null {\n let head = 0;\n while (head < a.length && head < b.length && a[head] === b[head]) head++;\n let tail = 0;\n while (\n tail < a.length - head &&\n tail < b.length - head &&\n a[a.length - 1 - tail] === b[b.length - 1 - tail]\n ) {\n tail++;\n }\n\n const midA = a.slice(head, a.length - tail);\n const midB = b.slice(head, b.length - tail);\n\n // Nothing left to compare once the shared head and tail are gone. Myers is skipped rather than\n // handed two empty arrays, where its `v` array is a single element and every neighbour lookup\n // reads past the end.\n let mid: Op[] = [];\n if (midA.length || midB.length) {\n const trace = shortestEdit(midA, midB, maxEdits);\n if (!trace) return null;\n mid = backtrack(trace, midA, midB);\n }\n\n const ops: Op[] = [];\n for (let i = 0; i < head; i++) ops.push({ kind: 'equal', a: i, b: i });\n for (const op of mid) ops.push({ kind: op.kind, a: op.a + head, b: op.b + head });\n for (let i = 0; i < tail; i++) {\n ops.push({ kind: 'equal', a: a.length - tail + i, b: b.length - tail + i });\n }\n return ops;\n}\n\nexport interface UnifiedDiffOptions {\n /** What the left side is called in the `---` header. */\n fromLabel: string;\n /** What the right side is called in the `+++` header. */\n toLabel: string;\n limits?: Partial<DiffLimits>;\n}\n\n/**\n * A unified diff, or a single line saying why there is not one.\n *\n * Returns the empty string when the two texts are identical, so a caller can treat \"no diff\" and\n * \"nothing to say\" the same way.\n */\nexport function unifiedDiff(before: string, after: string, opts: UnifiedDiffOptions): string {\n if (before === after) return '';\n const limits: DiffLimits = { ...DEFAULT_DIFF_LIMITS, ...(opts.limits ?? {}) };\n\n const from = toLines(before);\n const to = toLines(after);\n // A file that lost or gained only its final newline still differs, and every line of it still\n // compares equal, so without this the diff would be empty for a file the check has just called\n // out of date. Marking the last line of a side that has no trailing newline makes it a real\n // difference to Myers, and the marker is what `diff` itself prints for the same case.\n const beforeLines = withNoNewlineMark(from);\n const afterLines = withNoNewlineMark(to);\n\n if (from.lines.length > limits.maxLines || to.lines.length > limits.maxLines) {\n return (\n `--- ${opts.fromLabel}\\n+++ ${opts.toLabel}\\n` +\n `@@ no line diff @@\\n` +\n ` ${from.lines.length} lines on disk, ${to.lines.length} lines regenerated. ` +\n `Not diffed: the file is longer than the ${limits.maxLines}-line cap.\\n`\n );\n }\n\n const ops = diffLines(beforeLines, afterLines, limits.maxEdits);\n if (!ops) {\n return (\n `--- ${opts.fromLabel}\\n+++ ${opts.toLabel}\\n` +\n `@@ no line diff @@\\n` +\n ` ${from.lines.length} lines on disk, ${to.lines.length} lines regenerated. ` +\n `Not diffed: the two differ by more than the ${limits.maxEdits}-edit cap, ` +\n `so the whole file is effectively new.\\n`\n );\n }\n\n const hunks = buildHunks(ops, beforeLines, afterLines, limits.context);\n if (!hunks.length) return '';\n return `--- ${opts.fromLabel}\\n+++ ${opts.toLabel}\\n${hunks.join('')}`;\n}\n\nconst NO_NEWLINE = '\\\';\n\n/**\n * The sentinel a line with no newline after it carries while it is being compared.\n *\n * Two NUL characters and a word, because it has to be something a line of generated TypeScript\n * cannot be. It never reaches the output: `renderLine` strips it and prints the marker instead.\n */\nconst NO_NEWLINE_MARK = '\\u0000\\u0000drzl:no-newline';\n\nfunction withNoNewlineMark(side: { lines: string[]; newlineAtEnd: boolean }): string[] {\n if (side.newlineAtEnd || !side.lines.length) return side.lines;\n const marked = side.lines.slice();\n marked[marked.length - 1] += NO_NEWLINE_MARK;\n return marked;\n}\n\n/** One diff line: its prefix, its text, and the marker underneath it when it had no newline. */\nfunction renderLine(prefix: string, line: string, into: string[]): void {\n if (line.endsWith(NO_NEWLINE_MARK)) {\n into.push(prefix + line.slice(0, -NO_NEWLINE_MARK.length));\n into.push(NO_NEWLINE);\n return;\n }\n into.push(prefix + line);\n}\n\n/** Group the operations into hunks with `context` unchanged lines around each run of changes. */\nfunction buildHunks(\n ops: Op[],\n beforeLines: string[],\n afterLines: string[],\n context: number\n): string[] {\n const changed: number[] = [];\n ops.forEach((op, i) => {\n if (op.kind !== 'equal') changed.push(i);\n });\n if (!changed.length) return [];\n\n /** Ranges of operation indices to print, merged where their context windows touch. */\n const ranges: Array<[number, number]> = [];\n for (const i of changed) {\n const start = Math.max(0, i - context);\n const end = Math.min(ops.length - 1, i + context);\n const last = ranges[ranges.length - 1];\n if (last && start <= last[1] + 1) last[1] = Math.max(last[1], end);\n else ranges.push([start, end]);\n }\n\n const hunks: string[] = [];\n for (const [start, end] of ranges) {\n let aStart = -1;\n let bStart = -1;\n let aCount = 0;\n let bCount = 0;\n const body: string[] = [];\n\n for (let i = start; i <= end; i++) {\n const op = ops[i];\n if (op.kind === 'equal' || op.kind === 'delete') {\n if (aStart < 0) aStart = op.a;\n aCount++;\n }\n if (op.kind === 'equal' || op.kind === 'insert') {\n if (bStart < 0) bStart = op.b;\n bCount++;\n }\n if (op.kind === 'equal') renderLine(' ', beforeLines[op.a], body);\n else if (op.kind === 'delete') renderLine('-', beforeLines[op.a], body);\n else renderLine('+', afterLines[op.b], body);\n }\n\n // A hunk covering nothing on one side is numbered from 0, which is what `diff -u` emits for a\n // pure insertion into an empty file.\n const aFrom = aCount === 0 ? 0 : aStart + 1;\n const bFrom = bCount === 0 ? 0 : bStart + 1;\n hunks.push(`@@ -${aFrom},${aCount} +${bFrom},${bCount} @@\\n${body.join('\\n')}\\n`);\n }\n return hunks;\n}\n","/**\n * When `drzl watch` rebuilds, and how many rebuilds one burst of saves is allowed to become\n * (plan item 75).\n *\n * ## What was measured\n *\n * The watcher already had a debounce, so the item reads as done until you watch it run. The\n * debounce covers the *wait* and not the *work*: `setTimeout(run, 200)` collapses changes arriving\n * within 200ms of each other and then starts a rebuild that takes as long as it takes. Every\n * change arriving during that rebuild starts another one 200ms later, on top of the first, writing\n * the same files.\n *\n * Measured against the shipped 4.22 build, with a 600-table schema where one rebuild takes about\n * 1.4s, saving two files alternately 700ms apart:\n *\n * 32370ms START in flight 1\n * 33195ms START in flight 2\n * 33814ms START in flight 3\n * 34379ms END in flight 2\n * 34475ms START in flight 3\n * 35174ms START in flight 4 <- four rebuilds writing one output directory\n *\n * Six saves, six rebuilds, four of them running at once. Each one reloads the config, re-resolves\n * the schema, re-runs the analysis and rewrites every generated file, so the last writer wins per\n * file with no ordering between them.\n *\n * Chokidar's own `awaitWriteFinish` is why this is not worse: with a 400ms stability threshold, one\n * save of one file arrives as exactly one event, so the ordinary case never reached the overlap.\n * The bursts that do reach it are the ones that span a rebuild, which is any refactor across a\n * schema split into several modules.\n *\n * ## What this does about it\n *\n * One rebuild in flight at a time, and a change arriving during one is remembered rather than\n * dropped, so it gets exactly one rebuild afterwards however many changes arrived. The alternative,\n * refusing a change while busy, loses edits, which is worse than the overlap it fixes.\n */\n\n/** What `--debounce` means when it is not given, or is given something that is not a number. */\nexport const DEFAULT_WATCH_DEBOUNCE_MS = 200;\n\n/**\n * How long `watch` waits after the last change before rebuilding.\n *\n * 200ms is kept, and it is kept because it was measured rather than because it was already there.\n * With the `awaitWriteFinish: { stabilityThreshold: 400 }` this watcher passes chokidar, one\n * logical save reaches the trigger as a single event in every shape tested, and the widest gap\n * inside one burst was 9ms, from a tool rewriting two files back to back. With `awaitWriteFinish`\n * off, which is what a future version of this file might reach for to cut the 400ms it adds to\n * every rebuild, the same bursts spread out: a chunked write became five events with a 62ms\n * maximum gap, an atomic save became three events spanning 101ms, and format-on-save became two\n * events 121ms apart. 200ms covers the widest of those with headroom and is short enough that a\n * save still feels immediate. Every one of those numbers was taken with chokidar 5 on this\n * filesystem, under both inotify and polling.\n *\n * `0` is accepted and means \"rebuild on the next tick\", which is what the tests want and what\n * somebody debugging the watcher wants. It was previously impossible: `Number(opts.debounce) ||\n * 200` reads `0` as absent and silently used 200, and read `--debounce banana` as absent too. A\n * value that cannot be honoured now says so rather than being quietly replaced.\n */\nexport function resolveDebounce(value: unknown, warn: (message: string) => void): number {\n if (value === undefined || value === null || value === '') return DEFAULT_WATCH_DEBOUNCE_MS;\n const ms = Number(value);\n if (!Number.isFinite(ms) || ms < 0) {\n warn(\n `--debounce ${String(value)} is not a number of milliseconds. ` +\n `Using ${DEFAULT_WATCH_DEBOUNCE_MS}ms.`\n );\n return DEFAULT_WATCH_DEBOUNCE_MS;\n }\n return ms;\n}\n\nexport interface RebuildScheduler {\n /** A file changed. Rebuild after the debounce, or after the rebuild already running. */\n trigger(): void;\n /** Rebuild now, skipping the debounce, still one at a time. The startup build uses this. */\n runNow(): Promise<void>;\n /** Drop a pending debounce. Nothing calls this in the CLI; tests and a shutdown path do. */\n cancel(): void;\n /** Whether a rebuild is in flight. Exposed for tests rather than for the CLI. */\n readonly busy: boolean;\n}\n\nexport interface RebuildSchedulerOptions {\n run: () => Promise<void>;\n debounceMs: number;\n /**\n * Injected so a test does not have to spend real milliseconds.\n *\n * Defaults to the global timers. A fake clock is the difference between a debounce test that\n * takes 5ms and one that takes a second and is flaky on a loaded CI machine.\n */\n timers?: {\n setTimeout: (fn: () => void, ms: number) => unknown;\n clearTimeout: (handle: unknown) => void;\n };\n}\n\nexport function createRebuildScheduler(options: RebuildSchedulerOptions): RebuildScheduler {\n const timers = options.timers ?? {\n setTimeout: (fn: () => void, ms: number) => setTimeout(fn, ms),\n clearTimeout: (handle: unknown) => clearTimeout(handle as NodeJS.Timeout),\n };\n\n let handle: unknown = null;\n let running = false;\n let pending = false;\n\n const drain = async () => {\n if (running) {\n // Remembered, not merged: the rebuild in flight has already read the old file, so a change\n // that arrives now needs its own pass. One pass, however many changes arrive, because they\n // will all be on disk by the time it reads them.\n pending = true;\n return;\n }\n running = true;\n try {\n await options.run();\n while (pending) {\n pending = false;\n await options.run();\n }\n } finally {\n running = false;\n pending = false;\n }\n };\n\n return {\n trigger() {\n if (handle !== null) timers.clearTimeout(handle);\n handle = timers.setTimeout(() => {\n handle = null;\n void drain();\n }, options.debounceMs);\n },\n runNow() {\n return drain();\n },\n cancel() {\n if (handle !== null) timers.clearTimeout(handle);\n handle = null;\n },\n get busy() {\n return running;\n },\n };\n}\n","/**\n * `drzl init`: find the schema, ask what to generate, write a config that runs.\n *\n * Three defects were fixed here at once, and they are one command's worth of work because each\n * one is the reason the next is hard to see (plan items 65, 66, 67).\n *\n * **The schema path was invented (67).** `init` wrote `schema: 'src/db/schema.ts'` whether or\n * not that file existed. Measured on the shipped 4.22.0 CLI, in an empty directory: `init`\n * exits 0, and the `drzl generate` that follows it analyzes nothing, writes\n * `src/api/placeholder.orpc.ts` reading \"No tables detected in analysis\", and also exits 0. The\n * first two commands a new user runs therefore both report success having read no schema at\n * all. So detection is not a convenience here; it is what stops the product from lying on its\n * first run.\n *\n * Detection validates a candidate by loading it and counting Drizzle tables, never by\n * `existsSync`. The analyzer separates the three answers cleanly, which is what makes the rule\n * possible (measured against `@drzl/analyzer` 1.20.1):\n *\n * - a real schema -> `tables.length > 0`, no issues\n * - a file that is not one -> `tables.length === 0`, no issues, dialect 'unknown'\n * - a file it could not run -> `tables.length === 0` plus a `DRZL_ANL_IMPORT` error issue\n *\n * The middle case is rejected and the walk continues, because a `schema.ts` that exports a\n * connection string is worse than no detection: it produces exactly the silent placeholder run\n * above. The last case is adopted with a warning rather than rejected, because \"DRZL could not\n * import it\" is usually \"you have not run install yet\", and the file is still obviously the\n * schema the user meant.\n *\n * **The default generator was a router (66).** `@drzl/generator-zod` is a hard dependency of\n * `@drzl/cli`, so it is on disk beside the CLI that scaffolds this config. That used to be the\n * whole rule, because six of the seven route generators were `optionalDependencies` an installer\n * skips when they are missing; all fourteen are hard dependencies now, so being installed no\n * longer tells one kind from another. What `INIT_GENERATOR_CHOICES` still offers is the set this\n * file knows how to write a config for, and a test asserts every entry against `package.json` so\n * a kind the CLI does not depend on cannot be added to the list.\n *\n * **`--yes` did nothing (65).** The flag was declared and the action ignored its options object,\n * so `init` and `init --yes` were byte-identical. The flag is kept and given the meaning it\n * always advertised, because the non-interactive path is the important one: `init` runs under\n * `npx`, in CI and under agents far more often than it runs under a human. Prompts are the\n * addition, and they are guarded so that they can never be the reason a pipeline stops:\n * `isInteractive` requires stdin AND stdout to be TTYs and `CI` to be unset, and no readline\n * interface is constructed otherwise.\n */\nimport { SchemaAnalyzer } from '@drzl/analyzer';\nimport * as fs from 'node:fs';\nimport * as path from 'node:path';\nimport type * as readline from 'node:readline/promises';\nimport { CONFIG_FILE_NAMES } from './config.js';\nimport { resolveSchemaSource } from './drizzle-kit.js';\n\n/** A generator `init` is willing to scaffold. */\nexport interface InitGeneratorChoice {\n kind: string;\n /** The npm package the kind loads, which must be a hard dependency of `@drzl/cli`. */\n packageName: string;\n label: string;\n}\n\n/**\n * What `init` offers, in the order the prompt lists it. The first entry is the default.\n *\n * Every kind here is a `dependencies` entry of `@drzl/cli`, enforced against `package.json` by\n * `init.spec.ts`, so a config this command writes never names a package the CLI does not bring\n * with it. That used to exclude eight kinds on its own, when they were `optionalDependencies` an\n * installer skips; every kind clears it now, and it stays as the floor rather than as the filter.\n *\n * What the list is short for is this file: `generatorLine` writes two shapes, an oRPC entry and a\n * validator entry with a `path`, and `ROUTER_KINDS` is the one kind the scaffold adds an `outDir`\n * for. The six other route generators each resolve their output directory their own way\n * (`trpcOutDir`, `honoOutDir` and the rest in `config.ts`), and none of those rules is written\n * here. Offering them would scaffold a config this command does not know the shape of, which is a\n * different job from installing one.\n */\nexport const INIT_GENERATOR_CHOICES: readonly InitGeneratorChoice[] = [\n { kind: 'zod', packageName: '@drzl/generator-zod', label: 'Zod validators' },\n { kind: 'valibot', packageName: '@drzl/generator-valibot', label: 'Valibot validators' },\n { kind: 'arktype', packageName: '@drzl/generator-arktype', label: 'ArkType validators' },\n { kind: 'typebox', packageName: '@drzl/generator-typebox', label: 'TypeBox validators' },\n { kind: 'orpc', packageName: '@drzl/generator-orpc', label: 'oRPC router' },\n];\n\n/** The kind chosen when nothing says otherwise: `--yes`, a non-TTY, or an empty prompt answer. */\nexport const DEFAULT_GENERATOR_KIND = INIT_GENERATOR_CHOICES[0].kind;\n\n/** The kinds that write routers, and so need an `outDir` in the scaffold. */\nconst ROUTER_KINDS = new Set(['orpc']);\n\n/**\n * Where a Drizzle schema conventionally lives, most specific first, as stems without an\n * extension.\n *\n * Not invented. `src/db/schema.ts` and `src/db/schemas/index.ts` are the two paths this\n * repository's own docs use (34 and 8 occurrences across `docs/`, the READMEs and `examples/`),\n * and the rest are the same two shapes under the other roots frameworks put source in, plus\n * `drizzle/`, which is where a kit `out` directory conventionally sits. Being wrong about any\n * one of them costs nothing: an entry that does not exist is never opened, and an entry that\n * exists still has to declare tables before it is used.\n *\n * Every stem ends in `schema` or `schemas`, and that is a rule rather than a coincidence: a\n * candidate is validated by importing it, and importing `src/db/index.ts` on the guess that it\n * might re-export tables would just as often open a database connection. A module named for the\n * schema is one that declares rather than connects.\n */\nexport const SCHEMA_CANDIDATE_STEMS: readonly string[] = [\n 'src/db/schema',\n 'src/db/schema/index',\n 'src/db/schemas/index',\n 'src/lib/db/schema',\n 'src/lib/db/schema/index',\n 'src/schema',\n 'src/schema/index',\n 'src/schemas/index',\n 'app/db/schema',\n 'lib/db/schema',\n 'db/schema',\n 'db/schema/index',\n 'drizzle/schema',\n 'schema',\n];\n\n/** Extensions tried for each stem, in order. */\nconst CANDIDATE_EXTENSIONS = ['.ts', '.js'] as const;\n\n/** Every conventional candidate path, in the order they are tried. */\nexport function schemaCandidates(): string[] {\n const out: string[] = [];\n for (const stem of SCHEMA_CANDIDATE_STEMS) {\n for (const ext of CANDIDATE_EXTENSIONS) out.push(`${stem}${ext}`);\n }\n return out;\n}\n\nexport type CandidateVerdict =\n /** Imported, and Drizzle tables came back. */\n | 'confirmed'\n /** Present, but could not be imported at all, so it is neither proved nor disproved. */\n | 'unverified'\n /** Imported cleanly and declares no tables, so it is not a schema. */\n | 'rejected';\n\nexport interface CandidateReport {\n verdict: CandidateVerdict;\n tables: number;\n /** The import failure, when there was one. */\n reason?: string;\n}\n\n/**\n * Load a candidate and decide what it is. Never throws: an analyzer that blows up on a file is\n * itself an answer, and the caller has more candidates to try.\n */\nexport async function classifySchemaCandidate(target: string | string[]): Promise<CandidateReport> {\n let analysis: Awaited<ReturnType<SchemaAnalyzer['analyze']>>;\n try {\n // Relations and constraint validation are both off. Neither changes whether a table exists,\n // and both cost time on a file that is about to be thrown away.\n analysis = await new SchemaAnalyzer(target).analyze({\n includeRelations: false,\n validateConstraints: false,\n });\n } catch (e: any) {\n return { verdict: 'unverified', tables: 0, reason: firstLine(String(e?.message ?? e)) };\n }\n if (analysis.tables.length > 0) {\n return { verdict: 'confirmed', tables: analysis.tables.length };\n }\n const importError = analysis.issues.find(\n (i) => i.level === 'error' && i.code === 'DRZL_ANL_IMPORT'\n );\n if (importError)\n return { verdict: 'unverified', tables: 0, reason: firstLine(importError.message) };\n return { verdict: 'rejected', tables: 0 };\n}\n\n/**\n * The first line of a message, for a reason printed inline. A module resolution failure carries\n * its whole \"Require stack\" behind the first newline, and pasting that into the middle of a\n * sentence buries the sentence.\n */\nfunction firstLine(message: string): string {\n return String(message).split('\\n')[0].trim();\n}\n\nexport interface SchemaDetection {\n source: 'drizzle-kit' | 'convention' | 'none';\n /**\n * The relative path to write as `schema`, or undefined when the config should state none: a\n * drizzle-kit project states it once in its own config, and a project with no schema at all\n * must not be handed a path that is not there.\n */\n schema?: string;\n /** The drizzle-kit config consulted, when one answered. */\n drizzleKitConfig?: string;\n verdict?: CandidateVerdict;\n tables: number;\n /** Lines worth printing: what was found, or what was looked for and rejected. */\n notes: string[];\n}\n\n/**\n * Decide where the schema is, drizzle-kit first.\n *\n * The kit config is asked first because it is the only source that is a statement of fact\n * rather than a guess: the user wrote the path there themselves. `resolveSchemaSource` is the\n * whole of item 59's walk (candidate order, jiti load, glob expansion, kit's own one-level\n * directory expansion), so `init` and `generate` can never disagree about what that config\n * says.\n */\nexport async function detectSchema(cwd: string): Promise<SchemaDetection> {\n const notes: string[] = [];\n\n let kitFiles: string[] | null = null;\n let kitPath: string | undefined;\n try {\n // No `schema` and no `drizzleKit` key: exactly the shape that makes `resolveSchemaSource`\n // walk drizzle-kit's own default candidates. It throws when there is no kit config, which\n // is the common case and not an error here.\n const source = await resolveSchemaSource({}, cwd);\n if (source.source === 'drizzle-kit') {\n kitFiles = source.schema as string[];\n kitPath = source.drizzleKitConfigPath;\n }\n } catch {\n kitFiles = null;\n }\n\n if (kitFiles && kitPath) {\n const rel = path.relative(cwd, kitPath) || path.basename(kitPath);\n const report = await classifySchemaCandidate(kitFiles);\n if (report.verdict === 'confirmed' || report.verdict === 'unverified') {\n notes.push(\n report.verdict === 'confirmed'\n ? `Schema from ${rel} (${kitFiles.length} file${kitFiles.length === 1 ? '' : 's'}, ` +\n `${report.tables} table${report.tables === 1 ? '' : 's'})`\n : `Schema from ${rel}, which DRZL could not import yet: ${report.reason}`\n );\n return {\n source: 'drizzle-kit',\n drizzleKitConfig: rel,\n verdict: report.verdict,\n tables: report.tables,\n notes,\n };\n }\n notes.push(`${rel} names schema files that declare no Drizzle tables; looking elsewhere.`);\n }\n\n // Confirmed wins outright: the walk returns on the first confirmed candidate and only\n // collects the unverified ones, so a real schema further down the list beats a file near the\n // top that DRZL could not import. Within one verdict the convention order decides.\n const present = schemaCandidates().filter((c) => fs.existsSync(path.resolve(cwd, c)));\n const unverified: Array<{ file: string; report: CandidateReport }> = [];\n for (const file of present) {\n const report = await classifySchemaCandidate(path.resolve(cwd, file));\n if (report.verdict === 'confirmed') {\n notes.push(\n `Schema found at ${file} (${report.tables} table${report.tables === 1 ? '' : 's'})`\n );\n return {\n source: 'convention',\n schema: file,\n verdict: 'confirmed',\n tables: report.tables,\n notes,\n };\n }\n if (report.verdict === 'unverified') unverified.push({ file, report });\n else notes.push(`${file} exists but declares no Drizzle tables; not using it.`);\n }\n if (unverified.length) {\n const { file, report } = unverified[0];\n notes.push(`Schema assumed to be ${file}; DRZL could not import it: ${report.reason}`);\n return { source: 'convention', schema: file, verdict: 'unverified', tables: 0, notes };\n }\n\n notes.push(\n present.length\n ? 'No file DRZL looked at declares any Drizzle tables.'\n : 'No drizzle-kit config and no schema in the usual locations.'\n );\n return { source: 'none', tables: 0, notes };\n}\n\nexport interface InitPlan {\n /** What to write as `schema`, or undefined to write none. */\n schema?: string;\n schemaSource: SchemaDetection['source'];\n /** Deduplicated, in `INIT_GENERATOR_CHOICES` order. */\n generators: string[];\n}\n\n/** The `generators` entry each kind scaffolds as. */\nfunction generatorLine(kind: string): string {\n if (kind === 'orpc') return `{ kind: 'orpc', template: 'standard', includeRelations: true }`;\n return `{ kind: '${kind}', path: 'src/validators/${kind}' }`;\n}\n\n/**\n * The config file text.\n *\n * `import type` plus `satisfies`, never `defineConfig`. The scaffold has to keep working under\n * `npx @drzl/cli init` in a project with no local `@drzl/cli` to resolve, and a type-only import\n * is erased before jiti ever executes the module. A value import would make the very first\n * `drzl generate` fail on a module that is not installed, and the annotation is what gives the\n * first config anyone sees editor completion.\n */\nexport function renderInitConfig(plan: InitPlan): string {\n const lines: string[] = [];\n lines.push(`import type { DrzlConfigInput } from '@drzl/cli/config';`);\n lines.push('');\n lines.push('export default {');\n\n if (plan.schema) {\n lines.push(` schema: '${plan.schema}',`);\n } else if (plan.schemaSource === 'drizzle-kit') {\n lines.push(` // No \"schema\" here on purpose: DRZL reads it from your drizzle-kit config, so`);\n lines.push(\n ` // the path is written once. Set \"schema\" to override it, or \"drizzleKit\": false`\n );\n lines.push(` // to refuse the fallback.`);\n } else {\n lines.push(` // Set this to your Drizzle schema file, for example 'src/db/schema.ts'. DRZL`);\n lines.push(` // found no drizzle-kit config and no schema declaring tables in the usual`);\n lines.push(` // locations, and will not name a file that is not there.`);\n lines.push(` // schema: 'src/db/schema.ts',`);\n }\n\n const hasRouter = plan.generators.some((k) => ROUTER_KINDS.has(k));\n if (hasRouter) lines.push(` outDir: 'src/api',`);\n lines.push(` analyzer: { includeRelations: true, validateConstraints: true },`);\n lines.push(' generators: [');\n const others = INIT_GENERATOR_CHOICES.filter((c) => !plan.generators.includes(c.kind))\n .map((c) => `'${c.kind}'`)\n .join(', ');\n if (others) lines.push(` // Other kinds this CLI already has installed: ${others}.`);\n // Only where it can bite. Two router generators default to the same `outDir` and would each\n // write an `index.ts` into it, so the second silently overwrites the first; a config with no\n // router in it cannot reach that, and the line is noise there.\n if (hasRouter) {\n lines.push(' // A second router generator needs its own \"path\"; they share \"outDir\".');\n }\n // Trailing commas and a closing semicolon. Without them Prettier rewrites the scaffold the\n // first time a project formats anything, putting a diff on a file nobody edited. Measured:\n // `prettier --single-quote --check` on the emitted config passes, and the only thing Prettier\n // still changes under its own defaults is the quote style, which no scaffold can satisfy both\n // ways at once.\n for (const kind of plan.generators) lines.push(` ${generatorLine(kind)},`);\n lines.push(' ],');\n lines.push('} satisfies DrzlConfigInput;');\n return lines.join('\\n') + '\\n';\n}\n\n/**\n * Whether to ask anything at all.\n *\n * Both streams, not just stdin. A question printed down a redirected stdout is invisible, so\n * waiting for its answer is a hang from the only point of view that matters. `CI` is checked\n * too because some runners do allocate a pty, and a hung `init` in a pipeline is a worse defect\n * than the one prompts were added to fix.\n */\nexport function isInteractive(ctx: {\n stdin: { isTTY?: boolean };\n stdout: { isTTY?: boolean };\n env: Record<string, string | undefined>;\n}): boolean {\n if (ctx.env.CI) return false;\n return Boolean(ctx.stdin.isTTY) && Boolean(ctx.stdout.isTTY);\n}\n\n/**\n * One question. `null` means there are no more answers coming, from any cause: the stream\n * closed, or the user pressed Ctrl+D, which readline in TTY mode reports by rejecting with an\n * AbortError rather than by closing. Callers take their default and stop asking.\n */\nasync function ask(rl: readline.Interface, question: string): Promise<string | null> {\n const closed = new Promise<null>((resolve) => rl.once('close', () => resolve(null)));\n try {\n return await Promise.race([rl.question(question), closed]);\n } catch {\n return null;\n }\n}\n\nexport interface PromptResult extends InitPlan {\n /** True when input ran out and the remaining questions took their defaults. */\n endedEarly: boolean;\n}\n\n/**\n * Ask what the flags did not already answer.\n *\n * The streams are parameters rather than `process.stdin`/`process.stdout` so the prompt logic is\n * driven by a test on ordinary pipes. Deciding *whether* to call this is `isInteractive`'s job,\n * and it is the only thing that reads `isTTY`.\n */\nexport async function promptForPlan(args: {\n input: NodeJS.ReadableStream;\n output: NodeJS.WritableStream;\n detection: SchemaDetection;\n cwd: string;\n schemaFromFlag?: string;\n generatorsFromFlag?: string[];\n}): Promise<PromptResult> {\n const { input, output, detection, cwd } = args;\n const write = (s: string) => output.write(s + '\\n');\n\n let schema = args.schemaFromFlag ?? detection.schema;\n let schemaSource: SchemaDetection['source'] = args.schemaFromFlag\n ? 'convention'\n : detection.source;\n let generators = args.generatorsFromFlag;\n let endedEarly = false;\n\n // Loaded here rather than at the top of the module, so a runtime whose `node:readline/promises`\n // is missing or partial cannot break the non-interactive path, which is the one that runs under\n // `npx`, in CI and under Bun and Deno. If it cannot be loaded at all, the defaults are taken\n // and nothing is asked: a command that degrades to `--yes` is a nuisance, and one that throws\n // where it used to write a config is a regression.\n let readlineModule: typeof readline;\n try {\n readlineModule = await import('node:readline/promises');\n } catch {\n return {\n schema,\n schemaSource,\n generators: normalizeGenerators(generators) ?? [DEFAULT_GENERATOR_KIND],\n endedEarly: true,\n };\n }\n const rl = readlineModule.createInterface({ input, output });\n try {\n if (args.schemaFromFlag === undefined) {\n for (const note of detection.notes) write(note);\n const prompt =\n detection.source === 'drizzle-kit'\n ? 'Schema file, or Enter to keep reading it from your drizzle-kit config: '\n : detection.schema\n ? `Schema file [${detection.schema}]: `\n : 'Schema file (Enter to leave it unset): ';\n const answer = await ask(rl, prompt);\n if (answer === null) endedEarly = true;\n else if (answer.trim()) {\n const typed = answer.trim();\n const report = await classifySchemaCandidate(path.resolve(cwd, typed));\n if (report.verdict === 'confirmed') {\n write(` ${typed}: ${report.tables} table${report.tables === 1 ? '' : 's'}`);\n } else if (report.verdict === 'unverified') {\n write(` ${typed}: DRZL could not import it (${report.reason}). Using it anyway.`);\n } else {\n write(` ${typed}: no Drizzle tables found in it. Using it anyway.`);\n }\n schema = typed;\n schemaSource = 'convention';\n }\n }\n\n if (generators === undefined && !endedEarly) {\n write('What should DRZL generate?');\n INIT_GENERATOR_CHOICES.forEach((c, i) => write(` ${i + 1}) ${c.label}`));\n // Bounded, so a stream of nonsense cannot keep this open. Every exit from the loop either\n // has an answer or falls through to the default.\n for (let attempt = 0; attempt < 3; attempt++) {\n const answer = await ask(rl, `Choice [1, ${INIT_GENERATOR_CHOICES[0].label}]: `);\n if (answer === null) {\n endedEarly = true;\n break;\n }\n const raw = answer.trim().toLowerCase();\n if (!raw) break;\n const byIndex = Number(raw);\n const picked =\n Number.isInteger(byIndex) && byIndex >= 1 && byIndex <= INIT_GENERATOR_CHOICES.length\n ? INIT_GENERATOR_CHOICES[byIndex - 1]\n : INIT_GENERATOR_CHOICES.find((c) => c.kind === raw);\n if (picked) {\n generators = [picked.kind];\n break;\n }\n write(` \"${answer.trim()}\" is not one of the choices.`);\n }\n }\n } finally {\n rl.close();\n }\n\n return {\n schema,\n schemaSource,\n generators: normalizeGenerators(generators) ?? [DEFAULT_GENERATOR_KIND],\n endedEarly,\n };\n}\n\n/**\n * Deduplicate and order a kind list, or throw naming the offender. Returns undefined for\n * undefined so a missing flag stays a question rather than becoming an empty answer.\n */\nexport function normalizeGenerators(kinds: string[] | undefined): string[] | undefined {\n if (kinds === undefined) return undefined;\n const known = new Set(INIT_GENERATOR_CHOICES.map((c) => c.kind));\n for (const k of kinds) {\n if (!known.has(k)) {\n throw new Error(\n `drzl init: \"${k}\" is not a generator init can scaffold. Choose from ` +\n `${[...known].join(', ')}. Every other kind is installed and works; add it to ` +\n `drzl.config by hand, following the entry for it in the docs.`\n );\n }\n }\n const picked = INIT_GENERATOR_CHOICES.filter((c) => kinds.includes(c.kind)).map((c) => c.kind);\n return picked.length ? picked : undefined;\n}\n\n/** Split a `--generators zod,orpc` value. */\nexport function parseGeneratorsFlag(value: string | undefined): string[] | undefined {\n if (value === undefined) return undefined;\n const parts = value\n .split(',')\n .map((s) => s.trim().toLowerCase())\n .filter(Boolean);\n if (!parts.length) throw new Error('drzl init: --generators was given no kinds.');\n return parts;\n}\n\nexport interface InitOutcome {\n code: number;\n /** Absolute path written, when one was. */\n written?: string;\n plan?: InitPlan;\n}\n\n/**\n * The whole command. Returns an exit code rather than calling `process.exit`, so a test can run\n * it in-process and so the caller owns the one exit in the CLI.\n */\nexport async function runInit(args: {\n cwd: string;\n yes?: boolean;\n schemaFlag?: string;\n generatorsFlag?: string;\n stdin: NodeJS.ReadableStream & { isTTY?: boolean };\n stdout: NodeJS.WritableStream & { isTTY?: boolean };\n env: Record<string, string | undefined>;\n log: (s: string) => void;\n error: (s: string) => void;\n}): Promise<InitOutcome> {\n const target = path.resolve(args.cwd, 'drzl.config.ts');\n\n // Before any detection, and before any question. Everything that follows costs a jiti import\n // of the user's schema, and none of it is worth doing for a config that will not be written.\n //\n // Every config name, not just `drzl.config.ts`. `loadConfig` tries the five names in a fixed\n // order with `.ts` first, so writing a `.ts` scaffold beside an existing `drzl.config.json`\n // does not overwrite that file and does something worse: it shadows it, and the next\n // `drzl generate` silently runs the scaffold instead of the config the user wrote. Measured on\n // 4.22.0, which checked only the one name.\n const existing = CONFIG_FILE_NAMES.find((name) => fs.existsSync(path.resolve(args.cwd, name)));\n if (existing) {\n args.error(\n `drzl init: ${existing} already exists, so nothing was written. Delete it, or edit it by ` +\n `hand; init never overwrites a config, and will not write one that shadows it either.`\n );\n return { code: 1 };\n }\n\n let fromFlag: string[] | undefined;\n try {\n fromFlag = normalizeGenerators(parseGeneratorsFlag(args.generatorsFlag));\n } catch (e: any) {\n args.error(String(e?.message ?? e));\n return { code: 1 };\n }\n\n const detection = await detectSchema(args.cwd);\n\n let plan: InitPlan;\n const interactive =\n !args.yes && isInteractive({ stdin: args.stdin, stdout: args.stdout, env: args.env });\n\n if (interactive) {\n const result = await promptForPlan({\n input: args.stdin,\n output: args.stdout,\n detection,\n cwd: args.cwd,\n schemaFromFlag: args.schemaFlag,\n generatorsFromFlag: fromFlag,\n });\n plan = {\n schema: result.schema,\n schemaSource: result.schemaSource,\n generators: result.generators,\n };\n } else {\n for (const note of detection.notes) args.log(note);\n plan = {\n schema: args.schemaFlag ?? detection.schema,\n schemaSource: args.schemaFlag ? 'convention' : detection.source,\n generators: fromFlag ?? [DEFAULT_GENERATOR_KIND],\n };\n // An explicit flag is always obeyed, because a user may be scaffolding before writing the\n // schema, but it is never obeyed silently: this is the one path that can put a path DRZL\n // could not confirm into the config, and detection's whole point is that such a config runs\n // and reports success having read nothing.\n if (args.schemaFlag) {\n const full = path.resolve(args.cwd, args.schemaFlag);\n if (!fs.existsSync(full)) {\n args.log(`--schema ${args.schemaFlag} is not there yet. Writing it anyway.`);\n } else if ((await classifySchemaCandidate(full)).verdict === 'rejected') {\n args.log(`--schema ${args.schemaFlag} declares no Drizzle tables. Writing it anyway.`);\n }\n }\n }\n\n // `wx`, so two `init` runs racing each other cannot both believe they created the file. The\n // existsSync above is the message; this is the guarantee.\n try {\n fs.writeFileSync(target, renderInitConfig(plan), { flag: 'wx' });\n } catch (e: any) {\n if (e?.code === 'EEXIST') {\n args.error(\n `drzl init: drzl.config.ts already exists, so nothing was written. init never ` +\n `overwrites a config.`\n );\n return { code: 1 };\n }\n args.error(`drzl init: could not write ${target}: ${e?.message ?? e}`);\n return { code: 1 };\n }\n\n args.log(`Created ${target}`);\n args.log(` generators: ${plan.generators.join(', ')}`);\n if (plan.schema) args.log(` schema: ${plan.schema}`);\n else if (plan.schemaSource === 'drizzle-kit') args.log(' schema: from your drizzle-kit config');\n else\n args.log(\n ' schema: not set. Fill in \"schema\" before running `drzl generate`, or add a ' +\n 'drizzle-kit config.'\n );\n return { code: 0, written: target, plan };\n}\n","import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs';\nimport path from 'node:path';\nimport { Output } from './output.js';\n\nexport interface SponsorMessageOptions {\n reason?: string;\n minIntervalMs?: number;\n force?: boolean;\n /**\n * Where to write, and whether to write at all.\n *\n * This used to be `console.log`, which put an advertisement on stdout in the middle of the file\n * list a script was parsing: 246 bytes of it, measured on 4.22.0. It is narration, so it goes to\n * stderr, and `Output.wantsAsides` is what decides whether an unrequested aside has a reader:\n * not under `--quiet`, not under `--json`, and not when stderr is a pipe, because a tip written\n * into somebody's build log is only noise. The pre-existing `CI` gate below is the same idea\n * arrived at one environment at a time.\n */\n out?: Output;\n}\n\ninterface SponsorCachePayload {\n runs: number;\n lastShownAt?: number;\n lastReason?: string;\n}\n\nconst CACHE_DIR = path.join(process.cwd(), 'node_modules', '.cache', '@drzl');\nconst CACHE_FILE = path.join(CACHE_DIR, 'sponsor-message.json');\nconst DEFAULT_INTERVAL_MS = 1000 * 60 * 15; // 15 minutes\nlet shownThisProcess = false;\n\nconst tips = [\n 'Pair DRZL watch mode with drizzle-kit to keep schema & API synced.',\n 'Templatize your ORPC routers to roll out new endpoints safely.',\n 'Need typed validators? Enable the zod, valibot, arktype, typebox, or effect generators.',\n 'Need JSON Schema or OpenAPI? The json-schema generator emits both, with no runtime dependency.',\n 'Use output headers to track generated files and trim noisy diffs.',\n];\n\nexport function maybeShowSponsorMessage({\n reason = 'generate',\n minIntervalMs = DEFAULT_INTERVAL_MS,\n force = false,\n out = new Output(),\n}: SponsorMessageOptions = {}) {\n const green = (msg: string) => out.errStyle.hex('#6ee7b7')(msg);\n const cyan = (msg: string) => out.errStyle.cyan(msg);\n const gray = (msg: string) => out.errStyle.gray(msg);\n\n const hideViaEnv = process.env.DRZL_HIDE_SPONSOR?.toLowerCase();\n const hideRequested = hideViaEnv === '1' || hideViaEnv === 'true';\n if (hideRequested || (process.env.CI && !force) || (shownThisProcess && !force)) return;\n if (!out.wantsAsides && !force) return;\n\n try {\n mkdirSync(CACHE_DIR, { recursive: true });\n const payload = readCache();\n payload.runs += 1;\n\n const now = Date.now();\n const shouldShow = force || now - (payload.lastShownAt ?? 0) >= minIntervalMs;\n\n if (shouldShow) {\n payload.lastShownAt = now;\n payload.lastReason = reason;\n }\n\n writeCache(payload);\n\n if (!shouldShow) return;\n\n shownThisProcess = true;\n const tip = tips[payload.runs % tips.length];\n\n out.stderr.write(\n `\\n${cyan(`🚀 DRZL finished a ${reason} run (#${payload.runs.toLocaleString()}).`)}\\n\\n` +\n `${green('✨ Sponsors keep DRZL shipping. Consider supporting ongoing dev:')}\\n` +\n ` ${green('GitHub Sponsors')} ${gray('→ https://github.com/sponsors/omar-dulaimi')}\\n\\n` +\n `${green('Pro tip:')} ${tip}\\n\\n`\n );\n } catch {\n // Swallow to avoid impacting generator success paths\n }\n}\n\nfunction readCache(): SponsorCachePayload {\n if (!existsSync(CACHE_FILE)) {\n return { runs: 0 };\n }\n try {\n const data = JSON.parse(readFileSync(CACHE_FILE, 'utf8')) as SponsorCachePayload;\n if (typeof data.runs !== 'number') return { runs: 0 };\n return data;\n } catch {\n return { runs: 0 };\n }\n}\n\nfunction writeCache(payload: SponsorCachePayload) {\n writeFileSync(CACHE_FILE, JSON.stringify(payload, null, 2), 'utf8');\n}\n","/**\n * The version `drzl --version` prints, read from the manifest that ships beside the build.\n *\n * It used to be the literal `'0.0.1'`, passed to `program.version()` when the CLI was scaffolded\n * and never touched again. That was true of exactly one release, the first: the registry lists 29\n * versions of `@drzl/cli`, and the other 28 printed `0.0.1` as well. Reading the manifest is the\n * only form that cannot drift, because it is the same file the registry took the version from.\n *\n * Nothing here falls back. A build that cannot find its own manifest, or finds someone else's, has\n * resolved somewhere it did not intend to, and a placeholder standing in for that is how the\n * original defect stayed invisible for 28 releases.\n */\nimport { readFileSync } from 'node:fs';\nimport * as path from 'node:path';\nimport { fileURLToPath } from 'node:url';\n\n/** The name the manifest beside this build must carry, which is what makes it ours. */\nconst PACKAGE_NAME = '@drzl/cli';\n\n/**\n * The directory holding the file this code ends up in, in every form it is reached.\n *\n * Three of them: `dist/cli.js`, `dist/cli.cjs`, and this file unbundled under ts-node, all three\n * run and checked. Only the CommonJS bundle has no `import.meta`; `tsup.config.ts` gives that\n * build a real value for `import.meta.url` rather than esbuild's empty one, so this needs no\n * branch. If that config is ever dropped, `fileURLToPath(undefined)` throws on load, so the\n * CommonJS bundle stops working loudly instead of reporting the wrong directory.\n */\nfunction moduleDir(): string {\n return path.dirname(fileURLToPath(import.meta.url));\n}\n\n/**\n * The `version` a named manifest declares, or a throw naming what was wrong with it.\n *\n * Split out from the caller below only so the three ways it refuses can be exercised without a\n * build. Nothing in the CLI passes a path.\n */\nexport function readVersionFrom(manifestPath: string): string {\n let raw: string;\n try {\n raw = readFileSync(manifestPath, 'utf8');\n } catch (e: any) {\n throw new Error(\n `${PACKAGE_NAME} cannot read its own version: no manifest at ${manifestPath} ` +\n `(${e?.message ?? String(e)}).`\n );\n }\n\n const manifest = JSON.parse(raw) as { name?: unknown; version?: unknown };\n\n if (manifest.name !== PACKAGE_NAME) {\n throw new Error(\n `${PACKAGE_NAME} looked for its own version in ${manifestPath} and found ` +\n `${JSON.stringify(manifest.name)}, so this build is not sitting where it thinks it is.`\n );\n }\n\n if (typeof manifest.version !== 'string' || manifest.version.length === 0) {\n throw new Error(`${manifestPath} declares no version, so there is nothing to report.`);\n }\n\n return manifest.version;\n}\n\n/**\n * The `version` field of this package's own manifest.\n *\n * Both bundles sit one level below it, in `dist/`, and so does `src/` when this file is run\n * unbundled, so one `..` covers every way it is reached. All three were run.\n */\nexport function readCliVersion(): string {\n return readVersionFrom(path.join(moduleDir(), '..', 'package.json'));\n}\n\nexport const CLI_VERSION = readCliVersion();\n"],"mappings":"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","names":["qualifiedTableName","SchemaAnalyzer","path","VALIDATOR_DEFAULT_DIRS","projectRelative","VALIDATOR_DEFAULT_DIRS","projectRelative","VALIDATOR_DEFAULT_DIRS","projectRelative","VALIDATOR_DEFAULT_DIRS","parseCheck","Chalk","path","parseCheck","Chalk","PLAIN","Chalk","describeShape","value","path","wrap","full","fs","path","fs","path","fs","path","handle","fs","path","firstLine","resolve","existsSync","writeFileSync","path","path","existsSync","writeFileSync","readFileSync","path","SchemaAnalyzer","fs","qualifiedTableName","watcher"]}
|
|
1
|
+
{"version":3,"sources":["../src/cli.ts","../src/output.ts","../src/express-options.ts","../src/fastify-options.ts","../src/generator-loader.ts","../src/graphql-options.ts","../src/hono-options.ts","../src/validation-options.ts","../src/json-schema-options.ts","../src/ai-options.ts","../src/effect-http-options.ts","../src/ts-rest-options.ts","../src/elysia-options.ts","../src/h3-options.ts","../src/mcp-options.ts","../src/next-options.ts","../src/tanstack-start-options.ts","../src/nestjs-options.ts","../src/orpc-options.ts","../src/service-options.ts","../src/trpc-options.ts","../src/generator-registry.ts","../src/kind-selection.ts","../src/schema-outcome.ts","../src/column-filter.ts","../src/doctor.ts","../src/explain.ts","../src/drizzle-kit.ts","../src/drift.ts","../src/emit-plan.ts","../src/unified-diff.ts","../src/watch-loop.ts","../src/init.ts","../src/sponsor.ts","../src/version.ts"],"sourcesContent":["#!/usr/bin/env node\nimport { qualifiedTableName, SchemaAnalyzer } from '@drzl/analyzer';\nimport chokidar from 'chokidar';\nimport { Command } from 'commander';\nimport * as path from 'node:path';\nimport {\n EXIT_FAILED,\n EXIT_FINDINGS,\n EXIT_OK,\n messageOf,\n jsonFailure,\n Output,\n} from './output.js';\nimport {\n computeGeneratorOutputDirs,\n computeWatchTargets,\n configFromKinds,\n DrzlConfig,\n filterTables,\n loadConfig,\n tableFilterWarnings,\n type GeneratorKind,\n} from './config.js';\nimport {\n entryFor,\n GENERATOR_BY_KIND,\n resolveServicesDir,\n runGenerator,\n runGeneratorWithOptions,\n} from './generator-registry.js';\nimport {\n emptySelectionMessage,\n KindSelectionError,\n kindList,\n parseOnly,\n resolveWatchSelection,\n selectGenerators,\n type WatchSelection,\n} from './kind-selection.js';\nimport { ConfigValidationError } from './config-errors.js';\nimport {\n describeSchemaTarget,\n nothingToGenerate,\n schemaLoadFailure,\n type SchemaProblem,\n} from './schema-outcome.js';\nimport { filterColumns } from './column-filter.js';\nimport {\n ambiguousTableProblem,\n explainTable,\n matchTable,\n noSuchTableProblem,\n renderExplanation,\n renderIndex,\n summarize,\n type TableMatch,\n} from './explain.js';\nimport {\n dialectMismatchWarning,\n resolveSchemaSource,\n type ResolvedSchemaSource,\n} from './drizzle-kit.js';\nimport { buildDoctorReport, renderDoctorReport } from './doctor.js';\nimport { snapshotAll } from './drift.js';\nimport {\n describeCounts,\n displayPath,\n driftStatusOf,\n EmitPlan,\n pendingChanges,\n verifyNothingWasWritten,\n type EmittedFile,\n type FileVerdict,\n} from './emit-plan.js';\nimport { unifiedDiff } from './unified-diff.js';\nimport { createRebuildScheduler, resolveDebounce } from './watch-loop.js';\nimport { GeneratorNotInstalledError } from './generator-loader.js';\nimport { detectSchema, INIT_GENERATOR_CHOICES, runInit } from './init.js';\nimport { maybeShowSponsorMessage } from './sponsor.js';\nimport { CLI_VERSION } from './version.js';\n\n/**\n * Say what went wrong with a generator, distinguishing the two things that can.\n *\n * Every branch below used to print \"<name> generator missing. Install with: npm install\n * @drzl/generator-<name>\" for anything at all that threw, with the real reason on a trailing\n * \"Error details\" line. A generator that was installed and merely failed therefore sent its user\n * to reinstall a package they already had, and the sentence that would have told them what\n * actually happened was the one written as a footnote.\n *\n * `loadGenerator` marks the one case that is an install problem, so the package name comes off the\n * error rather than being repeated here beside the `import()` that already spells it.\n */\nfunction reportGeneratorFailure(out: Output, kind: string, e: unknown): string {\n if (e instanceof GeneratorNotInstalledError) {\n out.error(`The ${kind} generator is not installed.`);\n out.hint(`Install with: npm install ${e.specifier}`);\n return `The ${kind} generator is not installed. Install with: npm install ${e.specifier}`;\n }\n const detail = messageOf(e);\n out.error(`The ${kind} generator failed:`, detail);\n return `The ${kind} generator failed: ${detail}`;\n}\n\n/**\n * The output layer for one command invocation.\n *\n * Built per run rather than as a module singleton, so `--quiet` and `--json` are answered once and\n * every writer downstream shares that answer. See `output.ts` for the stream and colour rules.\n */\nfunction outputFor(opts: { quiet?: boolean; json?: boolean }): Output {\n return new Output({ quiet: !!opts.quiet, json: !!opts.json });\n}\n\n/**\n * The code a thrown value reports, when it is one of ours.\n *\n * `instanceof`, rather than reading `e.code`, because that property is Node's own convention:\n * `ENOENT` off a failed `readFile` would otherwise be published in the `--json` document as\n * though it were a DRZL identifier.\n */\nfunction drzlErrorCode(error: unknown, fallback: string): string {\n return error instanceof ConfigValidationError ? error.code : fallback;\n}\n\n/**\n * A run that has nothing to generate from, reported and stopped (items 70 and 71).\n *\n * `EXIT_FAILED`, not `EXIT_FINDINGS`: an empty schema is not something the command was asked to\n * look for, it is the command being unable to do the work. The hint is a hint, so `--quiet` drops\n * it and the failure itself survives, which is the rule every other error here follows.\n */\nfunction reportSchemaProblem(out: Output, command: string, problem: SchemaProblem): never {\n if (out.json) out.jsonData(jsonFailure(command, problem.code, problem.message));\n else {\n out.error(problem.message);\n out.hint(problem.hint);\n }\n process.exit(EXIT_FAILED);\n}\n\n/**\n * How many drifted files `--check` prints a diff for.\n *\n * A cap rather than no cap, because the case that produces the most drift is the one where a diff\n * helps least: a bumped generator version rewrites the header of every file, and a CI log holding\n * eight hundred near-identical hunks is a log nobody opens. Twenty is enough to read.\n *\n * The number of files beyond it is always stated, and every file is still named in the list above\n * the diffs, so nothing is hidden: what is capped is the explanation, never the finding.\n */\nconst DIFF_FILE_CAP = 20;\n\n/**\n * Show what changed in each drifted file (item 81).\n *\n * On stderr, with the rest of the narration, for the reason `--check`'s file list is: the diff is\n * a report about the work rather than the work, and `drzl generate --check > out.txt` should not\n * put a patch in the file. `--quiet` drops these and keeps the list, which is the finding.\n */\nfunction printCheckDiffs(out: Output, drift: EmittedFile[]): void {\n const shown = drift.slice(0, DIFF_FILE_CAP);\n for (const d of shown) {\n const label = displayPath(d.file);\n const text = unifiedDiff(d.before ?? '', d.after, {\n fromLabel: `a/${label}`,\n toLabel: `b/${label}`,\n });\n if (!text) continue;\n out.note('');\n for (const line of text.split('\\n')) {\n if (!line) continue;\n // Coloured per line rather than per hunk, so a redirected stream gets the same text with no\n // escapes at all; `errStyle` has already answered that question for this stream.\n if (line.startsWith('+++') || line.startsWith('---')) out.note(out.errStyle.bold(line));\n else if (line.startsWith('@@')) out.note(out.errStyle.cyan(line));\n else if (line.startsWith('+')) out.note(out.errStyle.green(line));\n else if (line.startsWith('-')) out.note(out.errStyle.red(line));\n else out.note(out.errStyle.gray(line));\n }\n }\n if (drift.length > shown.length) {\n out.note('');\n out.note(\n out.errStyle.gray(\n `${drift.length - shown.length} more file(s) differ. Diffs are capped at ` +\n `${DIFF_FILE_CAP} files; every drifted file is named in the list above.`\n )\n );\n }\n}\n\n/**\n * The two flags every command carries, declared once so none of them can be the one that forgets.\n *\n * Item 73 was that `--json` existed on three commands out of seven and `--quiet` on none, which\n * makes both unusable from a script: a caller cannot write `drzl <anything> --json` and know it\n * will work.\n */\nfunction withOutputFlags(command: Command): Command {\n return command\n .option('--json', 'write one JSON document to stdout and nothing else', false)\n .option('-q, --quiet', 'drop the progress narration on stderr; errors still print', false);\n}\n\nconst program = new Command();\nprogram.name('drzl').description('DRZL - Drizzle Developer Toolkit').version(CLI_VERSION);\nprogram.addHelpText(\n 'afterAll',\n `\\nNeed a template, adapter, or generator DRZL doesn't ship yet?\\n→ DM @omardulaimidev on X: https://x.com/omardulaimidev\\n`\n);\n\nwithOutputFlags(\n program\n .command('analyze')\n .argument('<schema>', 'path to drizzle schema (TS)')\n .option('--relations', 'include relations', true)\n .option('--validate', 'validate constraints', true)\n .option('--out <file>', 'write analysis JSON to file')\n).action(async (schema: string, opts: any) => {\n const out = outputFor(opts);\n try {\n const analyzer = new SchemaAnalyzer(schema);\n const spinner = out.spinner('Analyzing schema...');\n const start = Date.now();\n const res = await analyzer.analyze({\n includeRelations: !!opts.relations,\n validateConstraints: !!opts.validate,\n });\n const ms = Date.now() - start;\n\n // A schema the analyzer could not open or could not import comes back as an error-level issue\n // rather than as a throw, and the analysis it returns is empty. That is a run that could not\n // happen, so it is EXIT_FAILED. Every other error-level issue describes a schema that *was*\n // read and has something wrong in it, which is the EXIT_FINDINGS case: `analyze` printed a\n // usable document and is telling the caller to look at it.\n const unreadable = res.issues.some(\n (i) => i.level === 'error' && (i.code === 'DRZL_ANL_NOFILE' || i.code === 'DRZL_ANL_IMPORT')\n );\n const errors = res.issues.some((i) => i.level === 'error');\n const code = unreadable ? EXIT_FAILED : errors ? EXIT_FINDINGS : EXIT_OK;\n\n if (opts.out && !opts.json) {\n const fs = await import('node:fs/promises');\n // The bare `Analysis`, because that is what the option says it writes. The envelope belongs\n // to a command's answer on stdout, not to a file of analysis someone asked to keep.\n await fs.writeFile(opts.out, JSON.stringify(res, null, 2), 'utf8');\n spinner.succeed(`Analysis written to ${opts.out} in ${ms}ms`);\n } else {\n spinner.succeed(`Analyzed in ${ms}ms`);\n // The analysis's own keys at the top level, so every existing reader of `.issues`, `.tables`\n // and `.dialect` keeps working, with the envelope merged in beside them. No `ok` here, for\n // the reason spelled out on `doctor` below: on a report command that name already belongs to\n // a statement about the schema, and the run's answer is `exitCode`.\n // Indented, because `verify-packed.sh` redirects this to a file and a person reads it.\n const document = opts.json ? { command: 'analyze', exitCode: code, ...res } : res;\n out.data(JSON.stringify(document, null, 2));\n }\n process.exit(code);\n } catch (e: any) {\n const msg = messageOf(e);\n if (opts.json) out.jsonData(jsonFailure('analyze', 'DRZL_CLI_ANALYZE', msg));\n else {\n out.error('Analyze failed (DRZL_CLI_ANALYZE):', msg);\n out.hint('Tip: run with --json for structured output.');\n }\n process.exit(EXIT_FAILED);\n }\n});\n\nwithOutputFlags(\n program\n .command('doctor')\n .description('Report what DRZL cannot type or enforce in your schema, and why')\n .argument('[schema]', 'path to drizzle schema (TS); defaults to the schema in drzl.config')\n .option('-c, --config <path>', 'path to drzl.config, read when no schema argument is given')\n .option('--strict', 'exit 2 when anything is reported', false)\n).action(async (schema: string | undefined, opts: any) => {\n const out = outputFor(opts);\n {\n try {\n // A schema path argument, like `analyze`, or the one already named in the config, since a\n // user who has a config should not have to retype the path they put in it. Resolution\n // goes through the same `resolveSchemaSource` as `generate`, so a config whose schema\n // comes from drizzle-kit's config gets a doctor report too; its failure messages name\n // both files, which is strictly more useful than the generic line below.\n let target: string | string[] | undefined = schema;\n if (!target) {\n const cfg = await loadConfig(opts.config, (w) => out.warn(w));\n if (cfg) target = (await resolveSchemaSource(cfg)).schema;\n }\n if (!target) {\n const msg = 'No schema given. Pass a path, or run from a directory with a drzl.config.';\n if (opts.json) out.jsonData(jsonFailure('doctor', 'DRZL_CLI_DOCTOR', msg));\n else out.error('Doctor failed (DRZL_CLI_DOCTOR):', msg);\n process.exit(EXIT_FAILED);\n return;\n }\n\n const analyzer = new SchemaAnalyzer(target);\n // Both on, unconditionally. Doctor's job is to look at everything, and a warning that only\n // appears when relations are read would be hidden by a flag turning them off.\n const analysis = await analyzer.analyze({\n includeRelations: true,\n validateConstraints: true,\n });\n const report = buildDoctorReport(\n analysis,\n Array.isArray(target) ? target.join(', ') : target\n );\n\n // An error-level finding means the schema was never read: the file is missing, or importing\n // it threw. There is no report to act on, so that exits like `analyze`'s failure path rather\n // than pretending the empty analysis was a clean bill of health.\n //\n // Zero otherwise, and that is the whole point. A schema carrying a customType or a CHECK\n // this parser will not guess at is normal and usable, and a doctor that failed every\n // pipeline reading one would be switched off within a week. `--strict` is the opt-in.\n const unreadable = report.findings.some((f) => f.level === 'error');\n const code = unreadable\n ? EXIT_FAILED\n : opts.strict && report.findings.length\n ? EXIT_FINDINGS\n : EXIT_OK;\n\n // The report's own keys at the top level, so every reader of `.findings` and `.counts`\n // keeps working, with the envelope's three keys merged in beside them. `ok` is about\n // whether DRZL could run, not about whether the schema is clean: a report full of findings\n // is a successful doctor run, which is why it is `!unreadable` rather than `report.ok`.\n // `command` and `exitCode` first, the report's own keys after, and the order matters: this\n // report has published an `ok` of its own since it shipped, and it means \"nothing to report\n // about the schema\", which is not the same question as \"could DRZL run\". The report's\n // meaning is the one that survives, and the run's answer is `exitCode`. That is also why the\n // envelope defines no `ok` for the two report commands; see docs/cli/output.md.\n if (opts.json)\n out.data(JSON.stringify({ command: 'doctor', exitCode: code, ...report }, null, 2));\n else out.data(renderDoctorReport(report, out.outStyle));\n\n process.exit(code);\n } catch (e: any) {\n const msg = messageOf(e);\n const code = drzlErrorCode(e, 'DRZL_CLI_DOCTOR');\n if (opts.json) out.jsonData(jsonFailure('doctor', code, msg));\n else if (e instanceof ConfigValidationError) {\n // Already a report naming each key, so it prints as it is. See the same branch in\n // `generate` for why a second header over it would say less.\n out.error(msg);\n } else {\n out.error('Doctor failed (DRZL_CLI_DOCTOR):', msg);\n out.hint('Tip: run with --json for structured output.');\n }\n process.exit(EXIT_FAILED);\n }\n }\n});\n\n/**\n * Where `drzl explain` reads the schema from, in the order the answers are trustworthy.\n *\n * `--schema` is what the caller said, so it wins outright. Then the config, through the same\n * `resolveSchemaSource` every other command uses, so a drizzle-kit project needs no drzl config at\n * all. Then item 66's loading-based detection, which is what makes `drzl explain users` work in a\n * fresh checkout with nothing configured: a candidate is confirmed by importing it and finding\n * Drizzle tables, not by its name.\n *\n * Never throws for want of a config. A diagnostic command that refuses to run until you have\n * configured it is the one that gets reached for last.\n */\nasync function explainSchemaSource(\n opts: { schema?: string; config?: string },\n out: Output\n): Promise<\n | { schema: string | string[]; label: string; note?: string; config?: DrzlConfig }\n | undefined\n> {\n // An explicit `--schema` reads no config at all, and so applies no filters. The flag says \"look\n // at this file\", and narrowing it by a config that was written about a different one would\n // report columns as removed that nothing removed.\n if (opts.schema) return { schema: opts.schema, label: opts.schema };\n\n const cfg = await loadConfig(opts.config, (w) => out.warn(w));\n if (cfg) {\n const source = await resolveSchemaSource(cfg);\n for (const w of source.warnings) out.warn(w);\n return {\n schema: source.schema,\n label: describeSchemaTarget(source.schema),\n config: cfg,\n ...(source.source === 'drizzle-kit' && source.drizzleKitConfigPath\n ? { note: `Schema from ${path.relative(process.cwd(), source.drizzleKitConfigPath)}` }\n : {}),\n };\n }\n\n const detected = await detectSchema(process.cwd());\n if (!detected.schema) return undefined;\n return {\n schema: detected.schema,\n label: detected.schema,\n note: detected.notes[detected.notes.length - 1],\n };\n}\n\nwithOutputFlags(\n program\n .command('explain')\n .description('Show what DRZL understood about one table, and what it did not')\n .argument(\n '[table]',\n 'the table to explain, by database name, qualified name or export name; omit for the list'\n )\n .option('-c, --config <path>', 'path to drzl.config, read when --schema is not given')\n .option('-s, --schema <path>', 'path to the schema, overriding the config')\n).action(async (tableName: string | undefined, opts: any) => {\n const out = outputFor(opts);\n /** Every failure this command has, reported the one way the output contract describes. */\n const fail = (problem: { code: string; message: string; hint: string }): never => {\n if (out.json) out.jsonData(jsonFailure('explain', problem.code, problem.message));\n else {\n out.error(problem.message);\n out.hint(problem.hint);\n }\n process.exit(EXIT_FAILED);\n };\n try {\n const source = await explainSchemaSource(opts, out);\n if (!source) {\n fail({\n code: 'DRZL_CFG_001',\n message:\n 'No schema found (DRZL_CFG_001). There is no drzl.config, no drizzle-kit config, and ' +\n 'no schema in the usual locations.',\n hint: 'Pass --schema <path>, or run `drzl init` to write a config.',\n });\n return;\n }\n if (source.note) out.note(out.errStyle.gray(source.note));\n\n const spinner = out.spinner('Reading the schema...');\n const analysis = await new SchemaAnalyzer(source.schema).analyze({\n // Both on, for the reason `doctor` turns both on: this command's job is to say everything\n // that is known, and a relation that appears only under a flag is one a reader would be\n // told is absent.\n includeRelations: true,\n validateConstraints: true,\n });\n spinner.stop();\n\n // The analyzer's own verdict, not a guess from an empty table list: a module that would not\n // import and a module that declares nothing are different mistakes in different files, and\n // `schema-outcome.ts` is where that distinction already lives. Nothing about the sentence is\n // reworded here beyond what did not happen, which for this command is never a file.\n const problem =\n schemaLoadFailure(analysis.issues, source.schema, 'There is nothing to explain.') ??\n nothingToGenerate({\n schema: source.schema,\n analyzed: analysis.tables,\n remaining: analysis.tables,\n consequence: 'There is nothing to explain.',\n });\n if (problem) reportSchemaProblem(out, 'explain', problem);\n\n const context = { schema: source.label, dialect: analysis.dialect };\n\n if (!tableName) {\n const tables = summarize(analysis);\n if (out.json) out.jsonData({ command: 'explain', exitCode: EXIT_OK, ...context, tables });\n else out.data(renderIndex(tables, context, out.outStyle));\n process.exit(EXIT_OK);\n }\n\n const match = matchTable(analysis.tables, tableName);\n if (match.kind === 'ambiguous') fail(ambiguousTableProblem(tableName, match.hits));\n if (match.kind === 'none') {\n fail(noSuchTableProblem(tableName, analysis.tables, match.suggestion));\n }\n\n // The filters are read but never applied to the search: a table this config excludes is\n // exactly the one whose absence from the output needs explaining, and a command that could not\n // find it would be answering \"why is my table missing\" with \"there is no such table\".\n const cfg = source.config;\n let keptTables: string[] | undefined;\n let keptColumns: string[] | undefined;\n if (cfg) {\n keptTables = filterTables(analysis.tables, cfg).map((t) => qualifiedTableName(t));\n try {\n const narrowed = filterColumns(\n [(match as Extract<TableMatch, { kind: 'found' }>).table],\n cfg.columns\n );\n keptColumns = narrowed.tables[0]?.columns.map((c) => c.name);\n } catch {\n // A `columns` rule this config cannot honour is `generate`'s error to raise, and raising it\n // here would leave a reader with no explanation at all of the table they asked about.\n keptColumns = undefined;\n }\n }\n\n const explanation = explainTable(\n analysis,\n match as Extract<TableMatch, { kind: 'found' }>,\n { keptTables, keptColumns }\n );\n if (out.json) {\n out.jsonData({ command: 'explain', exitCode: EXIT_OK, ...context, table: explanation });\n } else {\n out.data(renderExplanation(explanation, context, out.outStyle));\n }\n process.exit(EXIT_OK);\n } catch (e: any) {\n const msg = messageOf(e);\n const code = drzlErrorCode(e, 'DRZL_CLI_EXPLAIN');\n if (opts.json) out.jsonData(jsonFailure('explain', code, msg));\n else if (e instanceof ConfigValidationError) out.error(msg);\n else {\n out.error('Explain failed (DRZL_CLI_EXPLAIN):', msg);\n out.hint('Tip: run with --json for structured output.');\n }\n process.exit(EXIT_FAILED);\n }\n});\n\nwithOutputFlags(\n program\n .command('generate')\n .description('Run configured generators (drzl.config.*)')\n .option('-c, --config <path>', 'path to drzl.config')\n .option('-s, --schema <path>', 'path to the schema, overriding the config')\n .option(\n '--only <kinds>',\n `run only these generator kinds, comma separated: ${kindList()}`\n )\n .option(\n '--check',\n 'regenerate and fail if the result differs from what is on disk, without changing it'\n )\n .option('--dry-run', 'report what would be written, and write nothing', false)\n).action(async (opts: any) => {\n const out = outputFor(opts);\n /**\n * Whether this run writes anything at all.\n *\n * `--check` and `--dry-run` are the same run with different reports at the end: both compute\n * every file's content, neither puts any of it on disk. `--check` then asks whether anything\n * differs and fails if it does; `--dry-run` prints what it found and succeeds either way.\n * Passing both is not an error, it is a `--check` that also says nothing was written, which is\n * already what `--check` says.\n */\n const planning = !!opts.check || !!opts.dryRun;\n /** Everything the `--json` document reports, filled in as the run makes it true. */\n const emitted: Array<{\n kind: string;\n files: string[];\n changes: Array<{ file: string; status: FileVerdict }>;\n }> = [];\n const warnings: string[] = [];\n /** A warning goes to stderr for a human and into the document for a machine, never both. */\n const warn = (text: string) => {\n warnings.push(text);\n out.warn(text);\n };\n {\n try {\n // Read before the config, so an unknown kind is refused by name before anything is loaded\n // rather than being applied to a config as a filter that matches nothing.\n const only = parseOnly(opts.only);\n // The config's own warnings go through `warn`, so they reach the `--json` document and\n // `--quiet` removes them, exactly like every other warning this command produces. They used\n // to be written with `console.warn` from inside `loadConfig`, which neither flag could see.\n let cfg = await loadConfig(opts.config, warn);\n if (!cfg && only) {\n // The config route with the config inlined, which is what replaces `generate:orpc` and\n // `generate:trpc`: `drzl generate --schema src/db/schema.ts --only orpc` is those commands\n // for all fourteen kinds, and every config feature still applies because there is a real\n // config here. `--schema` may be omitted, in which case the drizzle-kit config answers for\n // it exactly as it does for a config file with no `schema` key.\n cfg = configFromKinds([...only], opts.schema, warn);\n }\n if (!cfg) {\n const msg = 'No config found (DRZL_CFG_001). Create drzl.config.ts or pass --config.';\n // Was exit 2 until now, which the scheme reserves for a run that found something. A\n // config that is not there is a run that could not start.\n if (opts.json) out.jsonData(jsonFailure('generate', 'DRZL_CFG_001', msg));\n else {\n out.error(msg);\n // The one-command route, named here because this is where somebody who has no config\n // finds out they need one. `--only` on its own is enough to run without a file.\n out.hint('Or run one generator with no config: drzl generate --schema <path> --only <kind>.');\n }\n process.exit(EXIT_FAILED);\n return;\n }\n // `--schema` beats both the config's `schema` and the drizzle-kit fallback, which is what\n // the flag says and is how `explain -s` already behaves. `drizzleKit` is dropped with it so\n // a config that sets both does not draw the \"schema wins, remove one of the two\" warning\n // about a key the caller did not write.\n if (opts.schema) {\n const { drizzleKit: _fromConfig, ...rest } = cfg;\n cfg = { ...rest, schema: opts.schema };\n }\n // Refused before the schema is read, because it is a mistake in the command line rather than\n // anything about the project: the kinds are real and this config has none of them.\n const nothingSelected = emptySelectionMessage(only, cfg.generators);\n if (nothingSelected) {\n if (opts.json) out.jsonData(jsonFailure('generate', 'DRZL_CLI_ONLY', nothingSelected));\n else {\n out.error(nothingSelected);\n out.hint('Add it to \"generators\" in your config, or name a kind that is already there.');\n }\n process.exit(EXIT_FAILED);\n return;\n }\n // Where the schema comes from: `schema` in the drzl config, or, when that is omitted,\n // the drizzle-kit config, so a kit user never states the path twice. Resolved before the\n // spinner starts, because it throws the \"neither file names a schema\" error.\n const source = await resolveSchemaSource(cfg);\n for (const w of source.warnings) warn(w);\n // `typedJson`/`typedColumns` need one module to import tables from (`schemaPath` in\n // validation-options.ts). A drizzle-kit source resolved to exactly one file is that\n // module, so the option keeps working; several files have no single module, and the\n // generators already say so at their own call sites when they want types with no path.\n if (!cfg.schema && Array.isArray(source.schema) && source.schema.length === 1) {\n cfg = { ...cfg, schema: source.schema[0] };\n }\n if (source.source === 'drizzle-kit') {\n const n = (source.schema as string[]).length;\n // Narration, so stderr. It says where DRZL looked, not what it produced, and it used to\n // sit on stdout in front of the file list anyone was parsing.\n out.note(\n out.errStyle.gray(\n `Schema from ${path.relative(process.cwd(), source.drizzleKitConfigPath!)} ` +\n `(${n} file${n === 1 ? '' : 's'})`\n )\n );\n }\n const analyzer = new SchemaAnalyzer(source.schema);\n const spinner = out.spinner('Analyzing...');\n const t0 = Date.now();\n const analysis = await analyzer.analyze({\n includeRelations: cfg.analyzer.includeRelations,\n validateConstraints: cfg.analyzer.validateConstraints,\n includeHeuristicRelations: cfg.analyzer.includeHeuristicRelations,\n });\n // Item 70, and before the tick rather than after it: a module that never loaded has not\n // been analysed, and \"Analysis complete\" over the top of it is the green tick this item was\n // filed about. Everything below reads `analysis.tables`, which is empty here for a reason\n // that has nothing to do with the schema's contents.\n const loadFailure = schemaLoadFailure(analysis.issues, source.schema);\n if (loadFailure) {\n spinner.stop();\n reportSchemaProblem(out, 'generate', loadFailure);\n }\n // After the spinner rather than before it, because `filterColumns` throws on a config it\n // cannot honour and a thrown error under a live ora spinner prints into a line the spinner\n // then overwrites.\n spinner.succeed(`Analysis complete in ${Date.now() - t0}ms`);\n // The cross-check the interop makes possible: the drizzle-kit config states a dialect,\n // the analyzer measures one, and a contradiction usually means the schema paths or the\n // dialect line are stale. A warning rather than an error, because generation follows the\n // schema either way. After the spinner for the same overwrite reason as above.\n const dialectWarning = dialectMismatchWarning({\n configPath: source.drizzleKitConfigPath ?? '',\n declared: source.drizzleKitDialect,\n analyzed: analysis.dialect,\n });\n if (dialectWarning) warn(dialectWarning);\n // Both filters are applied before any generator sees the analysis, so every one of them\n // honours them without needing to know the options exist.\n //\n // Columns first. Both orders leave the same tables, since one narrows columns and the other\n // drops whole tables, but only this one lets a `columns` entry name a table that `exclude`\n // also removes without that reading as a typo, and a typo is refused.\n const narrowed = filterColumns(analysis.tables, cfg.columns);\n // Before the filter runs, so the tables it reports on are the ones the pattern really\n // reached rather than what survived it.\n const filterWarnings = tableFilterWarnings(narrowed.tables, cfg);\n analysis.tables = filterTables(narrowed.tables, cfg);\n for (const w of [...narrowed.warnings, ...filterWarnings]) warn(w);\n for (const w of wideColumnWarning(analysis.issues)) warn(w);\n // Item 71, after the filters so it can tell the two empty states apart, and before\n // `--check` snapshots anything so a check on a schema that produces nothing fails rather\n // than comparing an empty tree with itself and reporting it up to date.\n const empty = nothingToGenerate({\n schema: source.schema,\n analyzed: narrowed.tables,\n remaining: analysis.tables,\n });\n if (empty) reportSchemaProblem(out, 'generate', empty);\n // Where every generator writes, which is both the set `--check` and `--dry-run` have to know\n // the current contents of, and the set they have to prove they left alone afterwards.\n const outputDirs = computeGeneratorOutputDirs(cfg);\n // Read once, up front, for two jobs at the same time: it is the \"what is on disk now\" half\n // of every per-file verdict below, so the plan never reads a file itself, and it is the\n // baseline `verifyNothingWasWritten` compares against at the end. Only for a run that writes\n // nothing; an ordinary `generate` reads each file as it emits it, which costs one read per\n // generated file rather than one per file in the output tree.\n const existing = planning ? await snapshotAll(outputDirs) : undefined;\n /**\n * Every file this run produces, with the content already there beside it.\n *\n * Handed to each generator as `fileSink`, so the content is captured at the moment it would\n * be written rather than inferred afterwards from what landed on disk. Items 68, 80 and 81\n * all read this one object.\n */\n const plan = new EmitPlan({ write: !planning, existing });\n const total = analysis.tables.length || 1;\n // Whether this draws anything at all is `shouldShowProgress`'s decision: a terminal, no\n // `--quiet`, no `--json`, and enough tables that the bar will move (item 72).\n const progress = out.progress(total);\n /** One completed generator, reported the same way whichever branch produced it. */\n const generated = (kind: string, files: string[]) => {\n progress.stop();\n // A path the generator says it wrote that never reached the sink is a generator that\n // ignored `fileSink`, which on a user's machine means an installed generator package older\n // than this CLI. Under `--dry-run` or `--check` that is a run writing to a tree it promised\n // not to touch, so it stops here rather than reporting a plan that is not what happened.\n // `verifyNothingWasWritten` catches the same thing from the other side; this one can name\n // the generator.\n const missed = plan.unrecorded(files);\n if (missed.length && planning) {\n const message =\n `The ${kind} generator wrote ${missed.length} file(s) directly instead of reporting ` +\n `them, so this run could not be a preview. Update @drzl/generator-${kind} to a ` +\n `version that supports --dry-run. First file: ${displayPath(missed[0])}`;\n if (opts.json) out.jsonData(jsonFailure('generate', 'DRZL_GEN_003', message));\n else out.error(message);\n process.exit(EXIT_FAILED);\n }\n const verdicts = plan.verdictsFor(files).filter(Boolean) as EmittedFile[];\n // One entry per generator *entry*, keyed by nothing: a config may list two generators of\n // the same kind pointed at different paths, and a lookup by kind would report the first\n // one's verdicts twice.\n emitted.push({\n kind,\n files,\n changes: verdicts.map((v) => ({ file: v.file, status: v.verdict })),\n });\n if (opts.json) return;\n if (out.quiet) return;\n // Item 80: the count is what the run cost, the verdicts are what it did. A generator that\n // rewrote twelve identical files and one changed one used to report \"13 files\", which is\n // true and is not the sentence anyone was looking for.\n //\n // The verb changes with the mode, because \"Generated\" over a run that wrote nothing is the\n // same class of untruth as the green tick items 70 and 71 were filed about.\n out.succeed(\n out.errStyle.green(\n `${planning ? 'Would write' : 'Generated'} (${kind}): ${files.length} files`\n ) + out.errStyle.gray(` (${describeCounts(plan.counts(files))})`)\n );\n // Only the files that are not the same as before, and named relative to the working\n // directory, because this is the short list a person scans. The full absolute list is\n // still on stdout below, unchanged, for whatever is parsing it. Skipped under `--check`,\n // which prints the same files again below with their drift status and a diff each.\n for (const v of verdicts) {\n if (opts.check) break;\n if (v.verdict === 'unchanged') continue;\n const mark = v.verdict === 'created' ? '+' : '~';\n out.note(' ' + out.errStyle.cyan(mark + ' ' + displayPath(v.file)));\n }\n // stdout, and deliberately: for `generate` the list of files written is the answer, and a\n // caller without `--json` has nothing else to read. `--quiet` is what removes it. Under\n // `--dry-run` it is the list that *would* be written, which is the same answer to the same\n // question and keeps `drzl generate --dry-run > files.txt` working.\n for (const f of files) out.data(' - ' + out.outStyle.cyan(f));\n };\n /** One generator that threw. Reports it in whichever shape was asked for, then stops. */\n const failGenerator = (kind: string, e: unknown): never => {\n progress.stop();\n // Prints for a human and returns the same sentence for the document; the writers inside\n // it are already no-ops under `--json`, so neither shape can be the one that goes stale.\n const message = reportGeneratorFailure(out, kind, e);\n if (opts.json) out.jsonData(jsonFailure('generate', 'DRZL_GEN_002', message));\n process.exit(EXIT_FAILED);\n };\n // Where the service generator is actually writing, so a router template that imports\n // services spells a path that exists. The templates default it to `src/services`, and with\n // nothing passed that default was used no matter where the services really went, emitting an\n // import of a module that was never created. One function, shared with `watch`, so the two\n // commands cannot arrive at different answers.\n const servicesDir = resolveServicesDir(cfg);\n for (const g of selectGenerators(cfg.generators, only)) {\n // Per generator rather than once outside the loop. The bar used to be started before the\n // loop and stopped by whichever branch ran first, so in a config with two generators the\n // second updated a bar that was already stopped and drew nothing at all.\n progress.start();\n // The registry, not a fourteen-way `if`. The four copies of that chain are what let an\n // option reach one command and not the other; see `generator-registry.ts`.\n const entry = GENERATOR_BY_KIND.get(g.kind);\n if (!entry) continue;\n try {\n const files = await runGenerator(entry, g, cfg, {\n analysis,\n servicesDir,\n fileSink: plan,\n onProgress: ({ index }) => progress.update(index),\n });\n generated(g.kind, files);\n } catch (e: any) {\n failGenerator(g.kind, e);\n }\n }\n /**\n * The `generators` array both document shapes carry, with the verdicts merged in.\n *\n * `files` keeps its absolute paths, because that is what it has always published and a\n * script resolving them is entitled to keep working. `changes` is relative, because it is\n * new and a document naming somebody's home directory in every entry is worse to read and\n * impossible to compare across machines.\n */\n const generatorsDocument = () =>\n emitted.map((e) => ({\n kind: e.kind,\n files: e.files,\n changes: e.changes.map((c) => ({ file: displayPath(c.file), status: c.status })),\n }));\n\n if (planning) {\n // The claim `--dry-run` and `--check` make, checked rather than asserted. `existing` is the\n // snapshot taken before any generator ran, so anything that differs now was written by a\n // generator that ignored the sink, and it is put back before this reports.\n const wrote = await verifyNothingWasWritten(outputDirs, existing!);\n if (wrote.length) {\n const message =\n `${wrote.length} file(s) were written by a run that promised to write none, and have ` +\n `been restored. This means an installed generator package is older than this CLI. ` +\n `Update your @drzl/generator-* packages. First file: ${displayPath(wrote[0])}`;\n if (opts.json) out.jsonData(jsonFailure('generate', 'DRZL_GEN_003', message));\n else out.error(message);\n process.exit(EXIT_FAILED);\n }\n }\n\n if (opts.check) {\n const drift = pendingChanges(plan);\n const upToDate = drift.length === 0;\n // Drift is EXIT_FINDINGS, not EXIT_FAILED, and that is the whole reason the scheme has two\n // failure codes. The check ran perfectly: it regenerated in memory, compared, wrote\n // nothing, and is reporting what it found. A CI job that wants to show a diff acts on that\n // differently from a config it could not read, and until 4.23 both were 1.\n const code = upToDate ? EXIT_OK : EXIT_FINDINGS;\n\n if (opts.json) {\n out.jsonData({\n ok: true,\n command: 'generate',\n exitCode: code,\n check: {\n upToDate,\n drift: drift.map((d, i) => ({\n file: displayPath(d.file),\n status: driftStatusOf(d.verdict),\n // Item 81. Beyond the cap the entry is still here with its status, and only the\n // diff is absent, so a machine reading this never loses a file.\n diff:\n i < DIFF_FILE_CAP\n ? unifiedDiff(d.before ?? '', d.after, {\n fromLabel: `a/${displayPath(d.file)}`,\n toLabel: `b/${displayPath(d.file)}`,\n })\n : null,\n })),\n diffFileCap: DIFF_FILE_CAP,\n },\n generators: generatorsDocument(),\n warnings,\n });\n process.exit(code);\n }\n\n if (!upToDate) {\n out.error(`\\nGenerated output is out of date (${drift.length} file(s)):`);\n for (const d of drift) {\n const status = driftStatusOf(d.verdict);\n const mark = status === 'added' ? '+' : '~';\n out.error(\n ` ${mark} ${out.errStyle.yellow(status.padEnd(8))} ${displayPath(d.file)}`\n );\n }\n // Item 81: the list says which files, the diff says what about them. Printed after the\n // list rather than instead of it, so a reader who only wants the names still gets them\n // on the first few lines, and `--quiet` keeps the list and drops the diffs, since the\n // list is the finding and the diff is the explanation.\n printCheckDiffs(out, drift);\n out.hint('\\nRun `drzl generate` and commit the result. Nothing was written by this check.');\n process.exit(code);\n }\n out.succeed(out.errStyle.green('Generated output is up to date.'));\n process.exit(code);\n }\n\n if (opts.json) {\n out.jsonData({\n ok: true,\n command: 'generate',\n exitCode: EXIT_OK,\n check: null,\n dryRun: !!opts.dryRun,\n generators: generatorsDocument(),\n warnings,\n });\n return;\n }\n\n if (opts.dryRun) {\n // Item 68, and `EXIT_OK` on purpose. A dry run that computed its answer did what it was\n // asked; `2` is for a run that found what it was told to look for, and \"this file would\n // change\" is not a finding here, it is the answer. A preview of a project that has never\n // been generated would otherwise exit non-zero for being new, and the flag people reach\n // for before their first `generate` would look like a failure. `--check` is the flag whose\n // question is \"is anything stale\", and it still answers `2`.\n const counts = plan.counts();\n out.succeed(\n out.errStyle.green(`Dry run: ${counts.total} file(s) would be written`) +\n out.errStyle.gray(` (${describeCounts(counts)}). Nothing was written.`)\n );\n process.exit(EXIT_OK);\n }\n\n if (cfg.generators.length) {\n maybeShowSponsorMessage({ reason: 'generate', out });\n }\n } catch (e: any) {\n const msg = messageOf(e);\n const code = drzlErrorCode(e, 'DRZL_GEN_001');\n // A `--only` value that is not a kind is a mistake in the command line, so it is reported as\n // itself rather than under \"Generate failed\", whose tip points at the config file.\n if (e instanceof KindSelectionError) {\n if (opts.json) out.jsonData(jsonFailure('generate', e.code, msg));\n else {\n out.error(msg);\n if (e.hint) out.hint(e.hint);\n }\n process.exit(EXIT_FAILED);\n }\n if (opts.json) out.jsonData(jsonFailure('generate', code, msg));\n else if (e instanceof ConfigValidationError) {\n // Already a report about named keys, so it prints as it is: prefixing it with \"Generate\n // failed\" would put a second header over a message that has one, and the generic tip\n // below tells a reader to check the file the message is already about.\n out.error(msg);\n } else {\n out.error('Generate failed (DRZL_GEN_001):', msg);\n out.hint('Tip: check your drzl.config.ts and template path.');\n }\n process.exit(EXIT_FAILED);\n }\n }\n});\n\n/**\n * Refuse to generate from a schema that was never read, or that declares nothing.\n *\n * `generate:orpc no-such-file.ts` used to exit 0, having written a `placeholder.orpc.ts` whose\n * contents read \"No tables detected in analysis\". Item 67 stopped the first half of that; the\n * second half survived it, because a schema that imports cleanly and exports nothing produces the\n * identical placeholder and the identical exit 0, measured again here. Both are `EXIT_FAILED`\n * now, and neither writes a file.\n *\n * The two are told apart by `schema-outcome.ts`, which reads the analyzer's own verdict rather\n * than guessing from an empty table list.\n */\nfunction schemaProblemFor(\n analysis: {\n issues: Array<{ level?: string; code?: string; message?: string }>;\n tables: Array<{ name: string }>;\n },\n schema: string\n): SchemaProblem | undefined {\n return (\n schemaLoadFailure(analysis.issues, schema) ??\n nothingToGenerate({ schema, analyzed: analysis.tables, remaining: analysis.tables })\n );\n}\n\n/**\n * The one line a per-kind command prints before it does the work.\n *\n * `generate:orpc` shipped when oRPC was the only generator and `generate:trpc` arrived with the\n * tRPC generator; the twelve generators added since added no command, so the split is chronological\n * rather than principled. Both are also strictly less capable than the route they are being\n * replaced by: no config at all means no table or column filters, no naming, no format, no\n * `importExtension`, no shared validation, no `databaseInjection`, no drizzle-kit schema\n * resolution, and, because they bypass the write plan, no `--check`, no `--dry-run` and no drift\n * verdicts.\n *\n * Deprecated rather than deleted: they keep working, byte for byte, and 5.0 is where they go. The\n * line names the replacement command line verbatim so the fix is a copy and a paste, and it goes\n * through `Output.warn`, which means `--quiet` and `--json` both drop it. That matters more than it\n * looks: `--json` promises one document on stdout and nothing at all on stderr, so a notice written\n * to a stream directly would break the contract a script is relying on for the sake of a sentence\n * no script can read.\n *\n * Options with no flag on `generate` are named as config keys rather than silently omitted, and\n * only when the caller actually passed them, which `getOptionValueSource` answers exactly rather\n * than by comparing against a default the caller may have typed on purpose.\n */\nfunction deprecationNotice(\n command: 'generate:orpc' | 'generate:trpc',\n kind: GeneratorKind,\n schema: string,\n cmd: Command\n): string {\n const replacement = `drzl generate --schema ${schema} --only ${kind}`;\n const CONFIG_KEYS: Record<string, string> = {\n outDir: 'outDir',\n template: 'template',\n includeRelations: 'includeRelations',\n servicesDir: \"the service generator's path\",\n };\n const moved = Object.keys(CONFIG_KEYS).filter(\n (name) => cmd.getOptionValueSource(name) === 'cli'\n );\n const tail = moved.length\n ? ` (${moved.map((name) => CONFIG_KEYS[name]).join(', ')} ${\n moved.length === 1 ? 'moves' : 'move'\n } into drzl.config.ts)`\n : '';\n return `${command} is deprecated and will be removed in 5.0. Run this instead: ${replacement}${tail}`;\n}\n\nwithOutputFlags(\n program\n .command('generate:orpc')\n .description('Deprecated. Use `drzl generate --schema <path> --only orpc`')\n .argument('<schema>', 'path to drizzle schema (TS)')\n .option('-o, --outDir <dir>', 'output directory', 'src/api')\n .option('--template <name>', 'template name', 'standard')\n .option('--includeRelations', 'include relation endpoints')\n).action(async (schema: string, opts: any, cmd: Command) => {\n const out = outputFor(opts);\n out.warn(deprecationNotice('generate:orpc', 'orpc', schema, cmd));\n try {\n const analyzer = new SchemaAnalyzer(schema);\n const analysis = await analyzer.analyze({\n includeRelations: !!opts.includeRelations,\n validateConstraints: true,\n });\n const problem = schemaProblemFor(analysis, schema);\n if (problem) reportSchemaProblem(out, 'generate:orpc', problem);\n // The registry loads it and normalises what it hands back; the options are this command's own,\n // unchanged, which is what keeps its output identical to the release before this one.\n const files = await runGeneratorWithOptions(entryFor('orpc'), analysis, {\n outputDir: opts.outDir,\n template: opts.template,\n includeRelations: !!opts.includeRelations,\n });\n if (opts.json) {\n out.jsonData({\n ok: true,\n command: 'generate:orpc',\n exitCode: EXIT_OK,\n generators: [{ kind: 'orpc', files }],\n });\n return;\n }\n if (!out.quiet) {\n out.data(out.outStyle.green('Generated:') + ' ' + files.map((f) => out.outStyle.cyan(f)).join(', '));\n }\n maybeShowSponsorMessage({ reason: 'generate:orpc', out });\n } catch (e: any) {\n // An absent generator package goes through the same reporter both dispatch loops use, so it\n // names itself and the install line. This command reached the generator through a static\n // import until now, which meant an absent package took the process down before the action ran\n // at all, with a stack trace and no sentence. Everything else keeps the wording this command\n // has always printed, which covers the analyzer as much as the generator.\n let message: string;\n if (e instanceof GeneratorNotInstalledError) {\n message = reportGeneratorFailure(out, 'orpc', e);\n } else {\n message = messageOf(e);\n out.error('Generate orpc failed:', message);\n }\n if (opts.json) out.jsonData(jsonFailure('generate:orpc', 'DRZL_CLI_ORPC', message));\n process.exit(EXIT_FAILED);\n }\n});\n\nwithOutputFlags(\n program\n .command('generate:trpc')\n .description('Deprecated. Use `drzl generate --schema <path> --only trpc`')\n .argument('<schema>', 'path to drizzle schema (TS)')\n .option('-o, --outDir <dir>', 'output directory', 'src/api')\n .option('--template <name>', 'standard | service', 'standard')\n .option('--includeRelations', 'include relation endpoints')\n .option('--servicesDir <dir>', 'where the service generator writes', 'src/services')\n).action(async (schema: string, opts: any, cmd: Command) => {\n const out = outputFor(opts);\n out.warn(deprecationNotice('generate:trpc', 'trpc', schema, cmd));\n try {\n const analyzer = new SchemaAnalyzer(schema);\n const analysis = await analyzer.analyze({\n includeRelations: !!opts.includeRelations,\n validateConstraints: true,\n });\n const problem = schemaProblemFor(analysis, schema);\n if (problem) reportSchemaProblem(out, 'generate:trpc', problem);\n const files = await runGeneratorWithOptions(entryFor('trpc'), analysis, {\n outputDir: opts.outDir,\n template: opts.template,\n includeRelations: !!opts.includeRelations,\n // Only consulted by `--template service`, and passed unconditionally so this command\n // cannot become the branch that forgets it.\n servicesDir: opts.servicesDir,\n });\n if (opts.json) {\n out.jsonData({\n ok: true,\n command: 'generate:trpc',\n exitCode: EXIT_OK,\n generators: [{ kind: 'trpc', files }],\n });\n return;\n }\n if (!out.quiet) {\n out.data(\n out.outStyle.green('Generated:') +\n ' ' +\n files.map((f: string) => out.outStyle.cyan(f)).join(', ')\n );\n }\n maybeShowSponsorMessage({ reason: 'generate:trpc', out });\n } catch (e: any) {\n const message = reportGeneratorFailure(out, 'trpc', e);\n if (opts.json) out.jsonData(jsonFailure('generate:trpc', 'DRZL_CLI_TRPC', message));\n process.exit(EXIT_FAILED);\n }\n});\n\nprogram\n .command('watch')\n .description('Watch schema and regenerate on changes')\n .option('-c, --config <path>', 'path to drzl.config')\n .option(\n '--only <kinds>',\n `rebuild only these generator kinds, comma separated: ${kindList()}`\n )\n .option(\n '--pipeline <name>',\n 'all | analyze | generate-<kind>, the older spelling of --only',\n 'all'\n )\n .option('--debounce <ms>', 'wait this long after the last change before rebuilding', '200')\n .option('--clear', 'clear the terminal before each rebuild', false)\n .option('--json', 'emit JSON logs', false)\n .option('-q, --quiet', 'drop the progress narration on stderr; errors still print', false)\n .option('--poll', 'force polling (helps WSL/Docker/remote FS)', false)\n .action(async (opts: any) => {\n // `watch` has no answer to give: it is narration until it is stopped. So everything human it\n // prints goes to stderr, and stdout carries only the `--json` event stream, which is the one\n // thing here a program reads.\n const out = outputFor(opts);\n\n /**\n * Which kinds this watcher rebuilds, from `--only` or from the `--pipeline` spelling it\n * replaces.\n *\n * Read before the watcher exists, and fatal, unlike everything else this command refuses.\n * A schema that will not parse is an ordinary intermediate state and the watcher waits it out;\n * a flag value that is not a generator kind cannot become one however many times the schema is\n * saved, so reporting it and then watching would be a process that never does anything and\n * never says why. `--pipeline generate-zod` was exactly that until now: it named no branch, so\n * the watcher started, printed its watch list, and regenerated nothing for as long as it ran.\n */\n let selection: WatchSelection;\n try {\n selection = resolveWatchSelection(opts);\n } catch (e: any) {\n if (e instanceof KindSelectionError) {\n if (opts.json) out.jsonData(jsonFailure('watch', e.code, e.message));\n else {\n out.error(e.message);\n if (e.hint) out.hint(e.hint);\n }\n } else out.error(messageOf(e));\n process.exit(EXIT_FAILED);\n return;\n }\n\n /**\n * A schema `watch` has nothing to generate from, reported without stopping (items 70, 71).\n *\n * The one place in this change where the failure is not an exit code, and deliberately. A\n * watcher exists to be running while the schema is being edited, and the states this reports\n * are all ordinary intermediate ones: a file saved mid-expression does not parse, a file\n * being written from scratch declares no tables yet, and a table filter is usually adjusted\n * with the watcher up. Exiting on any of them would mean the user has to restart the watcher\n * to recover from a typo, which is the opposite of what the command is for. So it says what is\n * wrong, writes nothing, and waits for the next save, exactly as `run`'s own catch already\n * does for a generator that throws.\n */\n const reportWatchProblem = (problem: SchemaProblem) => {\n if (opts.json) {\n out.jsonData({ event: 'error', code: problem.code, message: problem.message });\n return;\n }\n out.error(problem.message);\n out.hint(problem.hint);\n };\n\n /**\n * Wipe the terminal before a rebuild, if that was asked for and there is a terminal (item 75).\n *\n * Three things were wrong with the `console.clear()` this replaces, and only the first is the\n * one the plan item names.\n *\n * It was not optional. Every rebuild wiped the screen, taking the previous rebuild's errors\n * and the startup banner listing the watched directories with it, so the answer to \"what did\n * it say last time\" was always \"it is gone\". A watcher a person leaves running all day is the\n * last place to throw away scrollback without being asked.\n *\n * It was decided from the wrong stream. `console.clear()` writes to stdout and does nothing\n * when stdout is not a terminal, but everything this command prints for a human is on stderr.\n * So `drzl watch > events.json` on a terminal left the terminal uncleared, and the stream that\n * would have been cleared was the one carrying the JSON. That is the same defect item 77 fixed\n * for colour, arrived at from the other direction.\n *\n * It also wrote the escape to a stream a program may be reading. Node happens to make that\n * harmless by checking `isTTY` first, which is why nothing leaked, but the check belonged to\n * the stream being cleared rather than to whichever one `console` was bound to.\n *\n * `2J` erases the display and `3J` the scrollback, then the cursor goes home. Sent together,\n * because erasing the display alone leaves the previous rebuild one scroll away and the point\n * of asking for this is a screen holding only the current run.\n */\n const clearScreen = () => {\n if (!opts.clear || opts.json || out.quiet) return;\n if (!out.stderr.isTTY) return;\n out.stderr.write('\\u001b[2J\\u001b[3J\\u001b[H');\n };\n\n // Wrapped, unlike the reload inside `run`, which has its own catch. A config that does not\n // validate throws out of here, and with nothing around it the rejection escapes the action\n // and Node prints a stack trace over the report that names each offending key.\n let loaded: DrzlConfig | null;\n try {\n loaded = await loadConfig(opts.config, (w) => out.warn(w));\n } catch (e: any) {\n out.error(messageOf(e));\n process.exit(EXIT_FAILED);\n return;\n }\n if (!loaded) {\n out.error('No config found (DRZL_CFG_001). Create drzl.config.ts or pass --config.');\n process.exit(EXIT_FAILED);\n return;\n }\n // Through a second binding rather than narrowing the first, so `cfg` stays non-nullable for\n // the closures below: `run` and the watcher callbacks capture it, and a `let` a closure reads\n // does not keep the narrowing a guard in this scope gave it.\n let cfg: DrzlConfig = loaded;\n\n const abs = (p: string) => path.resolve(process.cwd(), p);\n const isInside = (child: string, parent: string) => {\n const rel = path.relative(parent, child);\n return !!rel && !rel.startsWith('..') && !path.isAbsolute(rel);\n };\n\n // Resolved before the watcher exists, because the directories to watch depend on it: a\n // schema read from drizzle-kit's config lives wherever that config says, and a watcher\n // that does not cover those directories never fires. A resolution failure here is a\n // startup failure, exactly like a missing config; inside `run` the same failure is caught\n // and reported, so a broken edit mid-watch can be fixed by the next save.\n let source: ResolvedSchemaSource;\n try {\n source = await resolveSchemaSource(cfg);\n } catch (e: any) {\n out.error(messageOf(e));\n process.exit(EXIT_FAILED);\n return;\n }\n for (const w of source.warnings) out.warn(w);\n\n const ignoredOutDirs = new Set<string>(computeGeneratorOutputDirs(cfg).map(abs));\n const currentTargets = new Set<string>(\n computeWatchTargets(cfg, process.cwd(), source).map(abs)\n );\n\n const syncWatcherTargets = (watcher: import('chokidar').FSWatcher, next: Set<string>) => {\n const add: string[] = [];\n const del: string[] = [];\n for (const p of next) if (!currentTargets.has(p)) add.push(p);\n for (const p of currentTargets) if (!next.has(p)) del.push(p);\n if (add.length) watcher.add(add);\n if (del.length) watcher.unwatch(del);\n currentTargets.clear();\n next.forEach((p) => currentTargets.add(p));\n };\n\n const rebuildIgnoreDirsFrom = (cfgNow: DrzlConfig) => {\n ignoredOutDirs.clear();\n for (const d of computeGeneratorOutputDirs(cfgNow)) ignoredOutDirs.add(abs(d));\n };\n\n // Watch targets are directories now, because chokidar v4 dropped glob support. The\n // extensions the old `**/*.{ts,tsx,js}` glob selected therefore have to be filtered here\n // instead, or every unrelated file in the schema's directory would trigger a rebuild.\n const WATCHED_EXTENSIONS = new Set(['.ts', '.tsx', '.js', '.mjs', '.cjs']);\n\n const ignoredFn = (p: string, stats?: { isDirectory(): boolean }) => {\n const full = abs(p);\n for (const dir of ignoredOutDirs) {\n if (full === dir || isInside(full, dir)) return true;\n }\n // A directory is never ignored: chokidar has to descend into it to reach the files.\n if (stats?.isDirectory()) return false;\n const ext = path.extname(full);\n // Without stats chokidar is asking about a path it has not resolved yet. An extensionless\n // one is almost certainly a directory, so let it through and decide once it is known.\n if (!ext) return false;\n return !WATCHED_EXTENSIONS.has(ext);\n };\n\n const watcher = chokidar.watch(Array.from(currentTargets), {\n ignoreInitial: true,\n awaitWriteFinish: { stabilityThreshold: 400, pollInterval: 50 },\n usePolling: !!opts.poll,\n ignored: ignoredFn,\n });\n\n const logTrigger = (type: 'add' | 'change' | 'unlink', file: string) => {\n if (opts.json) out.jsonData({ event: 'trigger', type, file });\n };\n\n watcher\n .on('add', (p) => {\n logTrigger('add', p);\n trigger(p);\n })\n .on('change', (p) => {\n logTrigger('change', p);\n trigger(p);\n })\n .on('unlink', (p) => {\n logTrigger('unlink', p);\n trigger(p);\n });\n\n let lastFiles: string[] = [];\n\n /**\n * One generator finishing a watch rebuild, reported the same way for every kind.\n *\n * The event keys are the ones `--json` has always emitted, because a watch feeding a script is\n * the only reader that shape has. The human form is narration, so it goes to stderr with\n * everything else this command prints.\n */\n const watchGenerated = (kind: string, files: string[]) => {\n if (opts.json) {\n out.jsonData({ event: 'generate_complete', kind, files });\n return;\n }\n out.succeed(\n out.errStyle.green(`Generated (${kind}): ${files.length} files`) +\n (files.length ? ' ' + files.map((f) => out.errStyle.cyan(f)).join(', ') : '')\n );\n };\n\n const run = async () => {\n try {\n const reloaded = await loadConfig(opts.config, (w) => out.warn(w));\n if (!reloaded) throw new Error('Config disappeared during watch.');\n cfg = reloaded;\n\n // Re-resolved on every rebuild, for the same reason the config is: an edit to\n // drizzle.config.ts mid-watch changes which files are the schema, and a new file that\n // matches its glob has to join the set. The watch targets are recomputed from the\n // fresh resolution, so a schema directory added to the kit config starts being\n // watched on the rebuild that first read it.\n source = await resolveSchemaSource(cfg);\n // The same single-file fill `generate` makes, for the same consumer (`schemaPath` in\n // validation-options.ts), so the two dispatch loops hand the generators the same\n // options and the branch-parity contract holds for interop configs too.\n if (!cfg.schema && Array.isArray(source.schema) && source.schema.length === 1) {\n cfg = { ...cfg, schema: source.schema[0] };\n }\n\n rebuildIgnoreDirsFrom(cfg);\n const nextTargets = new Set<string>(\n computeWatchTargets(cfg, process.cwd(), source).map(abs)\n );\n syncWatcherTargets(watcher, nextTargets);\n\n clearScreen();\n\n if (opts.json) {\n out.jsonData({\n event: 'watch_config_applied',\n targets: Array.from(currentTargets),\n ignored: Array.from(ignoredOutDirs),\n });\n }\n\n // After the clear above, or the warning would be wiped before anyone saw it.\n for (const w of source.warnings) out.warn(w);\n\n const analyzer = new SchemaAnalyzer(source.schema);\n const analysis = await analyzer.analyze({\n includeRelations: cfg.analyzer.includeRelations,\n validateConstraints: cfg.analyzer.validateConstraints,\n includeHeuristicRelations: cfg.analyzer.includeHeuristicRelations,\n });\n // The same cross-check `generate` makes, in the same wording, so the two commands\n // cannot disagree about what a contradictory dialect line means.\n const dialectWarning = dialectMismatchWarning({\n configPath: source.drizzleKitConfigPath ?? '',\n declared: source.drizzleKitDialect,\n analyzed: analysis.dialect,\n });\n if (dialectWarning) out.warn(dialectWarning);\n const loadFailure = schemaLoadFailure(analysis.issues, source.schema);\n if (loadFailure) {\n reportWatchProblem(loadFailure);\n return;\n }\n // Same order and the same reasons as `generate`. A config edited mid-watch that names a\n // column that does not exist throws here, and `run`'s own catch reports it and keeps\n // watching, so the next save can fix it.\n const narrowed = filterColumns(analysis.tables, cfg.columns);\n const filterWarnings = tableFilterWarnings(narrowed.tables, cfg);\n analysis.tables = filterTables(narrowed.tables, cfg);\n for (const w of [...narrowed.warnings, ...filterWarnings]) out.warn(w);\n for (const w of wideColumnWarning(analysis.issues)) out.warn(w);\n\n if (selection.analyzeOnly) {\n if (opts.json) {\n out.jsonData({\n event: 'analyze_complete',\n issues: analysis.issues,\n tables: analysis.tables.length,\n });\n } else {\n out.succeed('Analyze complete.');\n }\n return;\n }\n\n // Item 71, and after the analyze pipeline rather than before it, so the two commands that\n // report an analysis agree: `drzl analyze` on a schema with no tables exits 0 and prints\n // an analysis with none, because that is a true answer to the question it was asked.\n // Generating from it is a different question, and the answer to that one is that there is\n // nothing to write.\n const empty = nothingToGenerate({\n schema: source.schema,\n analyzed: narrowed.tables,\n remaining: analysis.tables,\n });\n if (empty) {\n reportWatchProblem(empty);\n return;\n }\n\n const newFiles: string[] = [];\n\n // Where the service generator is really writing, so a router template that imports\n // services spells a path that exists. `generate` has always computed this; `watch` did\n // not, so a rebuild silently emitted the default. One function now, shared by both.\n const servicesDir = resolveServicesDir(cfg);\n\n // A selection that names a kind this config does not is reported and waited out rather\n // than fatal, unlike an unknown kind on the command line: the config is reloaded on every\n // rebuild, so adding the generator to it is a save away.\n const unmatched = emptySelectionMessage(selection.kinds, cfg.generators);\n if (unmatched) {\n if (opts.json) out.jsonData({ event: 'error', code: 'DRZL_CLI_ONLY', message: unmatched });\n else {\n out.error(unmatched);\n out.hint('Add it to \"generators\" in your config, or name a kind that is already there.');\n }\n return;\n }\n\n for (const g of selectGenerators(cfg.generators, selection.kinds)) {\n // The registry, the same list `generate` dispatches over. Two hand-written copies of\n // this chain are what let five validation options reach one command and not the other,\n // and what left `watch` with no json-schema branch at all for a while.\n const entry = GENERATOR_BY_KIND.get(g.kind);\n if (!entry) continue;\n try {\n const files = await runGenerator(entry, g, cfg, { analysis, servicesDir });\n watchGenerated(g.kind, files);\n newFiles.push(...files);\n } catch (e: any) {\n reportGeneratorFailure(out, g.kind, e);\n return;\n }\n }\n\n const added = newFiles.filter((f) => !lastFiles.includes(f));\n const removed = lastFiles.filter((f) => !newFiles.includes(f));\n if (opts.json) {\n out.jsonData({ event: 'diff', added, removed });\n } else {\n if (added.length) out.note(out.errStyle.blue(`Added: ${added.join(', ')}`));\n if (removed.length) out.warn(`Removed: ${removed.join(', ')}`);\n }\n if (newFiles.length) {\n // The kinds this rebuild ran, however they were named. `--pipeline generate-trpc` and\n // `--only trpc` are the same run and now report the same reason.\n const reason = selection.kinds ? `watch:${[...selection.kinds].join(',')}` : 'watch';\n maybeShowSponsorMessage({ reason, out });\n }\n lastFiles = newFiles;\n } catch (e: any) {\n const msg = messageOf(e);\n if (opts.json) out.jsonData({ event: 'error', message: msg });\n else out.error('Watch pipeline failed:', msg);\n }\n };\n\n // Item 75. The debounce that was here collapsed the wait and not the work, so a change\n // arriving during a rebuild started a second one on top of it; see `watch-loop.ts` for the\n // measurement. `run` itself is unchanged, and the scheduler decides when it happens.\n const scheduler = createRebuildScheduler({\n run,\n debounceMs: resolveDebounce(opts.debounce, (w) => out.warn(w)),\n });\n\n const trigger = (file?: string) => {\n if (file) {\n const full = abs(file);\n for (const dir of ignoredOutDirs) {\n if (full === dir || isInside(full, dir)) return;\n }\n }\n scheduler.trigger();\n };\n\n if (opts.json) {\n out.jsonData({\n event: 'watching',\n targets: Array.from(currentTargets),\n ignored: Array.from(ignoredOutDirs),\n });\n } else {\n out.note(\n out.errStyle.gray(\n 'Watching:\\n ' +\n Array.from(currentTargets)\n .map((p) => path.relative(process.cwd(), p))\n .join('\\n ')\n )\n );\n }\n\n watcher\n .on('add', (p) => trigger(p))\n .on('change', (p) => trigger(p))\n .on('unlink', (p) => trigger(p))\n .on('error', (err) => out.error('Watcher error:', messageOf(err)));\n\n // Through the same guard as every later rebuild, so a save landing during the startup build\n // waits for it rather than racing it. The watcher is attached by now, which is exactly when\n // that becomes possible.\n await scheduler.runNow();\n });\n\nwithOutputFlags(\n program\n .command('init')\n .description('Scaffold a drzl.config.ts, finding your schema and asking what to generate')\n .option('-y, --yes', 'take the defaults and ask nothing')\n .option('--schema <path>', 'the schema file to write into the config, skipping detection')\n .option(\n '--generators <list>',\n `comma-separated: ${INIT_GENERATOR_CHOICES.map((c) => c.kind).join(', ')}`\n )\n).action(async (opts: any) => {\n const out = outputFor(opts);\n const failures: string[] = [];\n // Every prompt has a flag, and every flag skips its prompt. That equivalence is what keeps\n // the interactive command usable from CI: nothing can only be answered by a human.\n //\n // `--json` forces the non-interactive path as well as the shape. A prompt written into a\n // document is a question nobody will answer and a document nobody can parse, and `--json` is\n // only ever passed by something that is not a person.\n const outcome = await runInit({\n cwd: process.cwd(),\n yes: !!opts.yes || !!opts.json,\n schemaFlag: opts.schema,\n generatorsFlag: opts.generators,\n stdin: process.stdin,\n stdout: process.stdout,\n env: process.env,\n // Narration on stderr, all of it: what `init` produces is a file on disk, and the lines it\n // prints are a report about that.\n log: (s) => out.note(s.startsWith('Created ') ? out.errStyle.green(s) : out.errStyle.gray(s)),\n error: (s) => {\n failures.push(s);\n out.error(s);\n },\n });\n if (opts.json) {\n out.jsonData(\n outcome.code === 0\n ? {\n ok: true,\n command: 'init',\n exitCode: EXIT_OK,\n written: outcome.written,\n schema: outcome.plan?.schema ?? null,\n schemaSource: outcome.plan?.schemaSource ?? null,\n generators: outcome.plan?.generators ?? [],\n }\n : jsonFailure('init', 'DRZL_CLI_INIT', failures.join(' ') || 'init did not write a config')\n );\n }\n process.exit(outcome.code === 0 ? EXIT_OK : EXIT_FAILED);\n});\n\n/**\n * Tell the user which columns got a validator that accepts anything.\n *\n * This is the user-facing half of a check `verify-packed.sh` runs on this repository. Two real\n * bugs took exactly this shape, `.array()` and `pgEnum` columns coming back untyped on\n * drizzle-orm 0.4x, and the only way anyone noticed was reading the generated file. A user whose\n * schema uses a type nobody here has modelled gets the same silence, and no gate of ours helps\n * them.\n *\n * Printed once with a count rather than a line per column, so a schema with fifty custom types\n * stays readable.\n */\nfunction wideColumnWarning(\n issues: Array<{ code?: string; message?: string; hint?: string }>\n): string[] {\n const wide = issues.filter((i) => i.code === 'DRZL_ANL_UNKNOWN_COLUMN');\n if (!wide.length) return [];\n // One string rather than a write per line. The caller both prints it and puts it in the\n // `--json` document, and a warning split across six writes cannot be put in a document at all\n // without the two shapes drifting apart.\n const lines = [`\\n${wide.length} column${wide.length === 1 ? '' : 's'} could not be typed:`];\n for (const i of wide.slice(0, 10)) lines.push(` - ${i.message}`);\n if (wide.length > 10) lines.push(` ... and ${wide.length - 10} more`);\n // One hint for the set, since they are almost always the same two.\n for (const h of [...new Set(wide.map((i) => i.hint).filter(Boolean))]) lines.push(` ${h}`);\n // Untypeable columns are the only thing this line can see. A CHECK constraint the generators\n // decline produces no output at all and so cannot be counted here without parsing every one of\n // them on the generate path, which is what `doctor` is for.\n lines.push(' Run `drzl doctor` for the full report.');\n return [lines.join('\\n')];\n}\n\nprogram.parseAsync(process.argv);\n","/**\n * Everything the CLI writes: which stream, in what shape, and whether it carries colour.\n *\n * Five plan items are one layer, and this file is that layer (items 72, 73, 74, 76, 77). Before it\n * existed, each of the seven commands answered those questions for itself by reaching for `chalk`,\n * `ora`, `cli-progress` and `console.log` at the call site, and the answers disagreed. Four of the\n * disagreements were measured against the built 4.22.0 CLI, each command run with stdout and stderr\n * on separate channels so the two could be told apart:\n *\n * - **`NO_COLOR` did nothing at all (item 76).** `chalk@6.0.0` vendors its own `supports-color`,\n * and that copy contains the string `FORCE_COLOR` ten times and the string `NO_COLOR` zero\n * times. Measured: on a pty with `NO_COLOR=1`, `chalk.level` is still 3 and `chalk.green('x')`\n * still returns `\u001b[32mx\u001b[39m`. `drzl doctor` emitted the same 32 escape sequences with\n * the variable set as without it.\n *\n * - **Colour was decided from the wrong stream (items 76, 77).** chalk's default instance takes\n * its level from `supportsColor.stdout` alone (`const colorLevel = stdoutColor ? ... : 0`), and\n * the CLI writes most of its narration to stderr. So `drzl generate > out.txt` with a terminal\n * still on stderr turned the warnings on that terminal colourless, because a *different* stream\n * had been redirected. chalk exposes `supportsColor.stderr` as well; nothing used it.\n *\n * - **An escape leaked into piped output regardless (item 77).** Not from chalk, which does check\n * `isTTY`, but from `ora`'s success symbol: `log-symbols` colours it with `yoctocolors`, which\n * reads `TERM`, `COLORTERM`, `FORCE_COLOR` and `NO_COLOR` and never asks whether the stream is a\n * terminal. Measured on an ordinary developer machine where `TERM` is set: `drzl analyze 2> log`\n * wrote `\u001b[32m✔\u001b[39m Analyzed in 46ms` into the file. So the symbol is rendered\n * here now and `ora` is asked only to spin.\n *\n * - **Narration sat on stdout (item 73).** The sponsor tip was written with `console.log`, so\n * `drzl generate | ...` fed 246 bytes of advertisement into whatever was parsing the file list.\n * `--json` cannot be a contract while anything but the document shares that stream.\n *\n * The rule the rest of the CLI follows from here: **stdout carries the answer, stderr carries the\n * narration.** Under `--json` stdout carries exactly one JSON document and nothing else, on\n * success and on failure alike, so `drzl <cmd> --json | jq .` parses with no filtering.\n */\nimport { Chalk, type ChalkInstance } from 'chalk';\nimport cliProgress from 'cli-progress';\nimport ora, { type Ora } from 'ora';\n\n/** The subset of a stream this module needs, so tests can pass an ordinary object. */\nexport interface OutputStream {\n write(chunk: string): unknown;\n isTTY?: boolean;\n columns?: number;\n}\n\nexport type Env = Record<string, string | undefined>;\n\nexport type ColorLevel = 0 | 1 | 2 | 3;\n\n/**\n * The three exit codes, and there are only three on purpose.\n *\n * Before this, `2` meant \"the analysis found errors\" from `analyze`, \"findings were reported and\n * you asked for strictness\" from `doctor`, and \"there is no config file\" from `generate` and\n * `watch`; `1` meant \"the schema could not be read\" from `doctor` but \"a generator threw\" from\n * `generate`. Three commands used the same number for three unrelated events, which is the same as\n * having no scheme.\n *\n * The distinction worth encoding is the one a pipeline acts on differently: work that could not be\n * done at all, against work that was done and turned something up. A build reacts to the first by\n * stopping, and to the second by showing a diff or a report. Everything else is prose and belongs\n * in the message.\n */\nexport const EXIT_OK = 0;\n/** DRZL could not do the work: bad config, unreadable schema, a generator threw, a write failed. */\nexport const EXIT_FAILED = 1;\n/**\n * DRZL did the work and found what it was asked to look for: `generate --check` drift,\n * `doctor --strict` findings, `analyze` error-level issues.\n */\nexport const EXIT_FINDINGS = 2;\n\n/**\n * How many tables make a progress bar worth drawing.\n *\n * Measured rather than chosen. The generator loop the bar covers costs about 105ms fixed plus\n * 3.6ms per table on this machine (1 table 109ms, 10 tables 181ms, 50 tables 354ms, 100 tables\n * 561ms, 200 tables 901ms, 400 tables 1549ms), and `cli-progress` redraws at 10fps. A bar drawn\n * over a shorter loop therefore paints one frame reading `0%` and is then wiped by `stop()`\n * without ever advancing, which is exactly what item 72 reports: a full-width bar appearing for a\n * single table and saying nothing.\n *\n * 25 tables is where the loop first outlasts a frame, so the bar is only ever drawn when it will\n * move at least once. Below it the run is already described by the two lines around it: the\n * analysis time, and the file count per generator.\n */\nexport const PROGRESS_MIN_TABLES = 25;\n\n/**\n * Whether a stream should carry colour, and how much.\n *\n * Asked once per stream rather than once per process. That is the whole of item 77 and half of\n * item 76: `drzl generate > file` leaves stderr a terminal and stdout a file, and the two answers\n * differ.\n *\n * `NO_COLOR` beats `FORCE_COLOR`, which is the one place this departs from chalk. The reason is\n * which of them a human sets: `NO_COLOR` goes in a shell profile and is a standing preference,\n * while `FORCE_COLOR` is overwhelmingly injected by a wrapper (CI runners set it, and so does the\n * shell this was developed in, which set `FORCE_COLOR=3` and made every command look like a colour\n * leak until it was stripped). A wrapper's guess must not overrule a person's refusal. It also\n * makes every colour rule testable through an ordinary pipe, with no pseudo-terminal, because\n * `FORCE_COLOR=1` turns colour on where a pipe would have it off.\n *\n * `NO_COLOR` follows no-color.org: any value except the empty string counts as set.\n */\nexport function colorLevelFor(stream: OutputStream, env: Env): ColorLevel {\n if (env.NO_COLOR !== undefined && env.NO_COLOR !== '') return 0;\n if (env.TERM === 'dumb') return 0;\n\n const forced = env.FORCE_COLOR;\n if (forced !== undefined) {\n if (forced === 'false' || forced === '0') return 0;\n if (forced === '' || forced === 'true') return 1;\n const n = Number.parseInt(forced, 10);\n if (Number.isInteger(n)) return Math.min(Math.max(n, 0), 3) as ColorLevel;\n return 1;\n }\n\n if (!stream.isTTY) return 0;\n // A terminal that says it can do more is believed, and one that says nothing gets the sixteen\n // colours every terminal emulator has had for thirty years.\n if (env.COLORTERM === 'truecolor' || env.COLORTERM === '24bit') return 3;\n if (env.TERM?.includes('256')) return 2;\n return 1;\n}\n\n/** Whether a progress bar earns its place. Split out so the four reasons can be tested apart. */\nexport function shouldShowProgress(opts: {\n tables: number;\n stderr: OutputStream;\n quiet: boolean;\n json: boolean;\n}): boolean {\n if (opts.quiet || opts.json) return false;\n if (!opts.stderr.isTTY) return false;\n return opts.tables >= PROGRESS_MIN_TABLES;\n}\n\n/** What `createProgress` hands back, so the call site never touches `cli-progress` directly. */\nexport interface Progress {\n start(): void;\n update(value: number): void;\n stop(): void;\n}\n\n/** A progress bar, or a shaped hole where one would have been. */\nfunction createProgress(enabled: boolean, total: number, stream: OutputStream): Progress {\n if (!enabled) {\n return { start() {}, update() {}, stop() {} };\n }\n const bar = new cliProgress.SingleBar(\n { hideCursor: true, stream: stream as NodeJS.WritableStream },\n cliProgress.Presets.shades_classic\n );\n // `running` is what makes `start` and `stop` safe to call in any order. The dispatch loop calls\n // `stop()` from thirteen branches and from their catch blocks, and before this the bar was\n // started once outside the loop, so the second generator in a config updated a bar that the\n // first had already stopped.\n let running = false;\n return {\n start() {\n if (running) return;\n bar.start(total, 0);\n running = true;\n },\n update(value: number) {\n if (running) bar.update(value);\n },\n stop() {\n if (!running) return;\n bar.stop();\n running = false;\n },\n };\n}\n\n/** A spinner, or a shaped hole. Never renders the completion symbol itself; see `Output.succeed`. */\nexport interface Spinner {\n succeed(text: string): void;\n fail(text: string): void;\n stop(): void;\n}\n\nexport interface OutputOptions {\n stdout?: OutputStream;\n stderr?: OutputStream;\n env?: Env;\n quiet?: boolean;\n json?: boolean;\n}\n\n/**\n * Every write the CLI makes, with the stream and the colour already decided.\n *\n * `data` is the only method that reaches stdout. Everything else is narration and goes to stderr,\n * where `--quiet` can drop it without touching either the answer or the exit code.\n */\nexport class Output {\n readonly stdout: OutputStream;\n readonly stderr: OutputStream;\n readonly env: Env;\n readonly quiet: boolean;\n readonly json: boolean;\n /** Chalk bound to stdout's answer. */\n readonly outStyle: ChalkInstance;\n /** Chalk bound to stderr's answer, which is a different question. */\n readonly errStyle: ChalkInstance;\n\n constructor(options: OutputOptions = {}) {\n this.stdout = options.stdout ?? process.stdout;\n this.stderr = options.stderr ?? process.stderr;\n this.env = options.env ?? process.env;\n this.quiet = options.quiet ?? false;\n this.json = options.json ?? false;\n this.outStyle = new Chalk({ level: colorLevelFor(this.stdout, this.env) });\n this.errStyle = new Chalk({ level: colorLevelFor(this.stderr, this.env) });\n }\n\n /** The command's answer. Never suppressed by `--quiet`, because then nothing would be left. */\n data(text: string): void {\n this.stdout.write(text.endsWith('\\n') ? text : text + '\\n');\n }\n\n /**\n * The one JSON document `--json` promises, and the reason nothing else may touch stdout.\n *\n * Stringified without indentation on purpose: this is a machine's copy, `jq` formats it for a\n * human, and the two commands that already print an indented document (`analyze`, `doctor`) keep\n * doing so through `data` because their shape is a published contract.\n */\n jsonData(payload: unknown): void {\n this.data(JSON.stringify(payload));\n }\n\n /** Narration. Dropped by `--quiet` and by `--json`. */\n note(text: string): void {\n if (this.quiet || this.json) return;\n this.stderr.write(text + '\\n');\n }\n\n /** A warning: narration a user asked to be quiet still does not need. */\n warn(text: string): void {\n if (this.quiet || this.json) return;\n this.stderr.write(this.errStyle.yellow(text) + '\\n');\n }\n\n /**\n * A failure. Never suppressed by anything, because a script that cannot tell a success from a\n * swallowed failure is worse off than one with no `--quiet` at all.\n *\n * Under `--json` the machine-readable failure goes to stdout as the document, so this stays\n * quiet there rather than printing the same fact twice in two shapes.\n */\n error(text: string, detail?: string): void {\n if (this.json) return;\n const line = this.errStyle.red(text) + (detail ? ' ' + detail : '');\n this.stderr.write(line + '\\n');\n }\n\n /** A hint under an error. Suppressed by `--quiet`: the error above it already said what broke. */\n hint(text: string): void {\n if (this.quiet || this.json) return;\n this.stderr.write(this.errStyle.dim(text) + '\\n');\n }\n\n /**\n * A spinner on stderr, or nothing.\n *\n * `ora` is constructed only when stderr is a terminal. Given a pipe it still writes its text\n * once as `- Analyzing...`, which is a line nobody reading a log wants, and given `NO_COLOR` it\n * writes a coloured symbol anyway. Both are avoided by not building it.\n */\n spinner(text: string): Spinner {\n const live: Ora | null =\n !this.quiet && !this.json && this.stderr.isTTY\n ? ora({\n text,\n stream: this.stderr as NodeJS.WritableStream,\n // ora paints its own frame cyan through its own chalk, which is a second colour\n // decision beside this one and does not read `NO_COLOR` either. Measured with the\n // variable set: everything else on the line went plain and the spinner frame arrived\n // as `[36m⠋[39m`. `false` is ora's documented way to turn that off.\n color: this.errStyle.level > 0 ? 'cyan' : false,\n }).start()\n : null;\n return {\n succeed: (done: string) => {\n live?.stop();\n this.succeed(done);\n },\n fail: (done: string) => {\n live?.stop();\n this.error(done);\n },\n stop: () => live?.stop(),\n };\n }\n\n /**\n * A completed step.\n *\n * The tick is rendered here rather than by `ora.succeed`, which is the fix for the escape that\n * reached piped output: `log-symbols` colours the symbol from the environment alone and never\n * looks at the stream, so `drzl analyze 2> log` used to write `\u001b[32m✔\u001b[39m` into\n * the file. Here the symbol goes through the same per-stream decision as everything else.\n */\n succeed(text: string): void {\n if (this.quiet || this.json) return;\n this.stderr.write(this.errStyle.green('✔') + ' ' + text + '\\n');\n }\n\n /** A progress bar for `tables` items, or a no-op. See `shouldShowProgress` for the four gates. */\n progress(tables: number): Progress {\n return createProgress(\n shouldShowProgress({\n tables,\n stderr: this.stderr,\n quiet: this.quiet,\n json: this.json,\n }),\n tables,\n this.stderr\n );\n }\n\n /**\n * Whether an unrequested extra, such as the sponsor tip, should be shown at all.\n *\n * A terminal is the only place an aside has a reader. Piped into a file it is noise in someone's\n * log, and under `--json` it would be noise in the middle of a document.\n */\n get wantsAsides(): boolean {\n return !this.quiet && !this.json && Boolean(this.stderr.isTTY);\n }\n}\n\n/** The failure document every command emits under `--json`, whatever went wrong. */\nexport interface JsonFailure {\n ok: false;\n command: string;\n code: string;\n message: string;\n exitCode: number;\n}\n\n/**\n * The failure half of the `--json` contract.\n *\n * A `--json` run writes one document on stdout whether it worked or not, because the case people\n * script against is the one that fails, and a command whose failure exists only as prose on stderr\n * forces every caller to parse English.\n *\n * `ok: false` appears here and nowhere in the shared envelope, which is deliberate: `doctor` has\n * published an `ok` of its own since it shipped, meaning \"nothing to report about your schema\",\n * and that is a different question from whether the run worked. Redefining it would break a\n * documented field and carrying both spellings would let them disagree, so the run's answer is\n * `exitCode` on every document, and `ok` keeps its own meaning where it already had one. A failure\n * document has no payload to collide with, so it says `ok: false` plainly.\n */\nexport function jsonFailure(\n command: string,\n code: string,\n message: string,\n exitCode: number = EXIT_FAILED\n): JsonFailure {\n return { ok: false, command, code, message, exitCode };\n}\n\n/**\n * The message off a thrown value, whatever was thrown.\n *\n * Whole, not the first line. The config validator throws a zod error whose message is a formatted\n * JSON array, and the first line of that is `[`, so truncating it would turn \"your config names no\n * generators\" into a bracket. The `--json` document carries the same string, where newlines cost\n * nothing.\n */\nexport function messageOf(value: unknown): string {\n const message = (value as { message?: string })?.message;\n return String(message ?? value);\n}\n","/**\n * The options `@drzl/generator-express` receives, built in one place.\n *\n * `generate` and `watch` each dispatch over `cfg.generators` in their own loop, and every branch\n * in both used to assemble its own options object by hand. Four documented options have already\n * been found dead that way, which is why every router branch now calls a shared builder and a\n * branch-parity spec compares the bytes the two commands write:\n * `packages/cli/test/express-branch-parity.spec.ts` for this one.\n *\n * There is no `validator` here, unlike `honoOptions`, because the Express generator has exactly\n * one middleware and emits it: Express has no official validator packages for a config to choose\n * between. There is no `servicesDir` and no `databaseInjection` either, deliberately: this\n * generator emits stub handlers and never calls a service, so passing either would be wiring an\n * option nothing reads. `resolveConfig` warns when a config sets `databaseInjection` on this\n * generator for the same reason.\n */\nimport { expressOutDir } from './config.js';\n\n/** A generator entry from the config, loosely typed because the config schema owns its shape. */\ntype GeneratorConfig = {\n path?: string;\n includeRelations?: unknown;\n naming?: unknown;\n outputHeader?: unknown;\n format?: unknown;\n importExtension?: unknown;\n validation?: unknown;\n};\n\nexport function expressOptions(\n g: GeneratorConfig,\n cfg: { outDir: string }\n): Record<string, unknown> {\n return {\n outputDir: expressOutDir(g, cfg),\n includeRelations: g.includeRelations,\n naming: g.naming,\n outputHeader: g.outputHeader,\n format: g.format,\n importExtension: g.importExtension,\n validation: g.validation,\n };\n}\n","/**\n * The options `@drzl/generator-fastify` receives, built in one place.\n *\n * `generate` and `watch` each dispatch over `cfg.generators` in their own loop, and every branch\n * in both used to assemble its own options object by hand. Four documented options have already\n * been found dead that way, which is why every router branch now calls a shared builder and a\n * branch-parity spec compares the bytes the two commands write:\n * `packages/cli/test/fastify-branch-parity.spec.ts` for this one.\n *\n * There is no `validation` here, unlike the hono and express builders, because the Fastify\n * generator has no validation library to choose and no shared schema module to import: its route\n * schemas are JSON Schema produced by the same builder as the `json-schema` generator and\n * inlined into the routes, and Fastify's own AJV is the validator. `resolveConfig` warns when a\n * config sets `validation` on this generator for the same reason. There is no `servicesDir` and\n * no `databaseInjection` either, deliberately: this generator emits stub handlers and never\n * calls a service, so passing either would be wiring an option nothing reads, and `resolveConfig`\n * warns about `databaseInjection` too.\n */\nimport { fastifyOutDir } from './config.js';\n\n/** A generator entry from the config, loosely typed because the config schema owns its shape. */\ntype GeneratorConfig = {\n path?: string;\n includeRelations?: unknown;\n naming?: unknown;\n outputHeader?: unknown;\n format?: unknown;\n importExtension?: unknown;\n};\n\nexport function fastifyOptions(\n g: GeneratorConfig,\n cfg: { outDir: string }\n): Record<string, unknown> {\n return {\n outputDir: fastifyOutDir(g, cfg),\n includeRelations: g.includeRelations,\n naming: g.naming,\n outputHeader: g.outputHeader,\n format: g.format,\n importExtension: g.importExtension,\n };\n}\n","/**\n * Loading an optional generator package, and telling absence apart from failure.\n *\n * Every validation generator is loaded on demand, because a project that only wants zod should not\n * have to install five. That makes \"the package is not installed\" a real, expected outcome worth a\n * helpful message. It does not make it the only outcome: a generator that is installed and running\n * can throw for any reason a program can throw, and the CLI reported all of those as a missing npm\n * package too, with the true reason printed underneath as a detail.\n *\n * Node reports an unresolvable import as `ERR_MODULE_NOT_FOUND`, and reports the same code when\n * the module resolved and something *it* imported did not. The code alone therefore does not\n * separate the two; the message does, because it names the specifier that failed to resolve.\n */\n\n/** A generator package that is not installed. Everything else is somebody's real error. */\nexport class GeneratorNotInstalledError extends Error {\n constructor(\n readonly specifier: string,\n /** What Node threw, kept so nothing is discarded on the way to the message. */\n readonly reason: unknown\n ) {\n super(`${specifier} is not installed`);\n this.name = 'GeneratorNotInstalledError';\n }\n}\n\n/**\n * Whether `err` is Node refusing to resolve `specifier` itself.\n *\n * Measured on Node 22, from an ESM entry and from a CJS one, since the CLI ships both builds and\n * the bundler leaves `import()` as `import()` in each:\n *\n * absent package ERR_MODULE_NOT_FOUND, `Cannot find package '<specifier>' imported…`\n * present, inner dep absent ERR_MODULE_NOT_FOUND, naming the *inner* specifier instead\n * present, main file gone ERR_MODULE_NOT_FOUND, naming the resolved file path\n * throws while evaluating no `code` at all, and whatever message the generator threw\n *\n * Only the first is an install problem, and only the first quotes the specifier that was asked\n * for, which is what this matches on.\n */\nexport function isPackageMissing(err: unknown, specifier: string): boolean {\n const code = (err as { code?: unknown } | null | undefined)?.code;\n if (code !== 'ERR_MODULE_NOT_FOUND') return false;\n const message = (err as { message?: unknown } | null | undefined)?.message;\n return typeof message === 'string' && message.includes(`'${specifier}'`);\n}\n\n/**\n * Run `load` and re-throw a missing package as `GeneratorNotInstalledError`.\n *\n * `load` is a thunk rather than a specifier so the caller keeps a literal `import('@drzl/…')` in\n * its own source, which is what lets the bundler see the dependency. Anything it throws that is\n * not this package's own absence comes out unchanged.\n */\nexport async function loadGenerator<T>(specifier: string, load: () => Promise<T>): Promise<T> {\n try {\n return await load();\n } catch (e) {\n if (isPackageMissing(e, specifier)) throw new GeneratorNotInstalledError(specifier, e);\n throw e;\n }\n}\n","/**\n * The options `@drzl/generator-graphql` receives, built in one place.\n *\n * `generate` and `watch` each dispatch over `cfg.generators` in their own loop, and every branch\n * in both used to assemble its own options object by hand. Four documented options have already\n * been found dead that way, which is why every generator branch now calls a shared builder and a\n * branch-parity spec compares the bytes the two commands write:\n * `packages/cli/test/graphql-branch-parity.spec.ts` for this one.\n *\n * There is no `includeRelations` here, unlike the router builders: relation fields on a GraphQL\n * type are resolvers the consumer writes, not routes this generator emits. There is no\n * `servicesDir` and no `databaseInjection` either, for the stronger form of the same reason:\n * the emitted resolvers are stubs. And there is no `validation` at all, unlike every kind that\n * takes one: the emitted schema is GraphQL SDL, GraphQL's own type language, so there is no\n * library to choose, and `resolveConfig` warns about the whole block on this kind.\n */\nimport { graphqlOutDir } from './config.js';\n\n/** A generator entry from the config, loosely typed because the config schema owns its shape. */\ntype GeneratorConfig = {\n path?: string;\n naming?: unknown;\n outputHeader?: unknown;\n format?: unknown;\n importExtension?: unknown;\n};\n\nexport function graphqlOptions(\n g: GeneratorConfig,\n cfg: { outDir: string }\n): Record<string, unknown> {\n return {\n outputDir: graphqlOutDir(g, cfg),\n naming: g.naming,\n outputHeader: g.outputHeader,\n format: g.format,\n importExtension: g.importExtension,\n };\n}\n","/**\n * The options `@drzl/generator-hono` receives, built in one place.\n *\n * `generate` and `watch` each dispatch over `cfg.generators` in their own loop, and every branch\n * in both used to assemble its own options object by hand. Three documented options have already\n * been found dead that way: `typedJson` never reached typebox, `coerceDates` and `applyDefaults`\n * reached nothing but zod, and `servicesDir` was passed by `generate`'s oRPC branch and not by\n * `watch`'s, so a watch rebuild emitted a service import pointing at the default directory\n * whatever the config said. None of those is visible in the wiring: the option parses, the\n * generator defaults it, and the feature simply does nothing.\n *\n * One builder means the two call sites are the same object by construction rather than by review.\n * It also gives the drift something to be asserted against, which is what\n * `packages/cli/test/hono-branch-parity.spec.ts` does by running both commands and comparing the\n * bytes they wrote.\n *\n * There is no `servicesDir` and no `databaseInjection` here, and their absence is deliberate\n * rather than an omission: this generator emits stub handlers and never calls a service, so\n * passing either would be wiring an option nothing reads. `resolveConfig` warns when a config\n * sets `databaseInjection` on this generator for the same reason.\n */\nimport { honoOutDir } from './config.js';\n\n/** A generator entry from the config, loosely typed because the config schema owns its shape. */\ntype GeneratorConfig = {\n path?: string;\n includeRelations?: unknown;\n naming?: unknown;\n validator?: unknown;\n outputHeader?: unknown;\n format?: unknown;\n importExtension?: unknown;\n validation?: unknown;\n};\n\nexport function honoOptions(g: GeneratorConfig, cfg: { outDir: string }): Record<string, unknown> {\n return {\n outputDir: honoOutDir(g, cfg),\n includeRelations: g.includeRelations,\n naming: g.naming,\n validator: g.validator,\n outputHeader: g.outputHeader,\n format: g.format,\n importExtension: g.importExtension,\n validation: g.validation,\n };\n}\n","/**\n * The options every validation generator receives, built in one place.\n *\n * Each generator branch used to assemble this by hand, and three documented options were\n * found silently dead as a result: `typedJson` never reached typebox, and `coerceDates` and\n * `applyDefaults` never reached anything but zod. The config parsed them, the CLI dropped them,\n * and the feature simply did nothing while nothing said so. Building it once removes the class\n * rather than fixing each instance.\n *\n * What stays per-generator is a real capability rather than an oversight, which is why it is\n * named as one.\n */\n\n/**\n * A generator entry from the config, loosely typed because the config schema owns its shape.\n *\n * Exported so a builder that wraps this one names the same keys rather than restating them: every\n * key listed in two places is a key the two can drift on, which is the failure this file exists to\n * remove.\n */\nexport type ValidationGeneratorConfig = {\n outputHeader?: unknown;\n format?: unknown;\n schemaSuffix?: unknown;\n fileSuffix?: unknown;\n importExtension?: unknown;\n affix?: unknown;\n coerceDates?: unknown;\n applyDefaults?: unknown;\n typedJson?: unknown;\n typedColumns?: unknown;\n duplicateFinder?: unknown;\n constraints?: unknown;\n nestedSchemas?: unknown;\n nestedDepth?: unknown;\n branded?: unknown;\n standardSchema?: unknown;\n meta?: unknown;\n};\n\nexport interface GeneratorCapabilities {\n /**\n * Whether the generator can reference a type from the schema module.\n *\n * `typedJson` and `typedColumns` both work by importing the table back and reading\n * `typeof table.$inferSelect['col']`, so a generator that cannot embed a TypeScript type in its\n * output cannot use either. ArkType is the case: it emits one string per field, and a type\n * reference has nowhere to live inside a string DSL.\n */\n schemaTypes?: boolean;\n /**\n * Whether the generator has a `~standard` key to add.\n *\n * TypeBox is the only one that has: zod, valibot and arktype put one on every schema they build,\n * measured on 4.4.3, 1.4.2 and 2.2.3, so there is nothing for the option to do there and setting\n * it would read as a promise that something changed.\n */\n standardSchema?: boolean;\n /**\n * Whether the generator can attach metadata to what it emits.\n *\n * zod is the only one so far, and deliberately: it is the one validator here whose metadata has\n * a destination outside itself, since `z.toJSONSchema` copies arbitrary keys through into the\n * document an OpenAPI consumer reads. The other four each have a facility of their own and each\n * needs its own measurement of where the metadata has to attach, which is the whole difficulty;\n * building four on the strength of one measurement is how three of them come to be subtly wrong.\n */\n meta?: boolean;\n /**\n * Whether the generator emits the constraint ledger beside its schemas.\n *\n * zod and valibot so far, and the boundary is measured rather than conservative. The ledger\n * carries the exact message the emitted schema attaches for each constraint, which is what the\n * error map keys on, and those two enforce the same set of constraints in the same words.\n *\n * ArkType is the case that says why this is a flag. Measured on 2.2.3 against the same table:\n * it folds `cardinality(tags) > 0` into its own DSL, moves a `length()` check onto the object\n * so the issue names no column, reports DRZL's wording in `expected` rather than in `message`,\n * and emits nothing at all for `name <> 'x'`. A ledger claiming that constraint is enforced\n * would be wrong there, and it would be wrong silently.\n */\n constraints?: boolean;\n}\n\nexport function validationOptions(\n g: ValidationGeneratorConfig,\n cfg: { schema?: unknown },\n outDir: string,\n caps: GeneratorCapabilities = {}\n): Record<string, unknown> {\n return {\n outDir,\n outputHeader: g.outputHeader,\n format: g.format,\n schemaSuffix: g.schemaSuffix,\n fileSuffix: g.fileSuffix,\n importExtension: g.importExtension,\n affix: g.affix,\n coerceDates: g.coerceDates,\n applyDefaults: g.applyDefaults,\n duplicateFinder: g.duplicateFinder,\n nestedSchemas: g.nestedSchemas,\n nestedDepth: g.nestedDepth,\n // Every validation generator can express a brand, including TypeBox, which has no brand\n // helper and gets one from `TUnsafe` instead. So this needs no capability flag: an option\n // that reached only four of the five would be the class of defect this file exists to\n // remove.\n branded: g.branded,\n // Only where the generator can act on them, so an unsupported option is absent rather than\n // present and ignored.\n ...(caps.schemaTypes\n ? {\n // Needed by both: the reference is resolved relative to the emitted file.\n schemaPath: cfg.schema,\n typedJson: g.typedJson,\n typedColumns: g.typedColumns,\n }\n : {}),\n ...(caps.standardSchema ? { standardSchema: g.standardSchema } : {}),\n ...(caps.meta ? { meta: g.meta } : {}),\n ...(caps.constraints ? { constraints: g.constraints } : {}),\n };\n}\n","/**\n * The options `@drzl/generator-json-schema` receives, built in one place.\n *\n * `generate` and `watch` each dispatch over `cfg.generators` in their own loop, and the json-schema\n * branch was assembled by hand in both. That arrangement has already dropped options silently more\n * than once here: five validation options never reached a watch rebuild, and `watch` had no\n * json-schema branch at all for a while, so that directory went stale from the first save onward.\n * None of it is visible in the wiring, because the option parses, the generator defaults it, and\n * the feature simply does nothing.\n *\n * One builder makes the two call sites the same object by construction rather than by review, and\n * `packages/cli/test/openapi-branch-parity.e2e.spec.ts` runs both commands and compares the bytes.\n */\nimport { validationOptions, type ValidationGeneratorConfig } from './validation-options.js';\n\n/** A generator entry from the config, loosely typed because the config schema owns its shape. */\ntype GeneratorConfig = ValidationGeneratorConfig & {\n path?: string;\n target?: unknown;\n components?: unknown;\n document?: unknown;\n includeRelations?: unknown;\n sharedEnums?: unknown;\n};\n\nexport function jsonSchemaOptions(\n g: GeneratorConfig,\n cfg: { schema?: unknown },\n outDir: string\n): Record<string, unknown> {\n return {\n // JSON Schema is data, so nothing it emits references a type from the schema module.\n ...validationOptions(g, cfg, outDir, { schemaTypes: false }),\n target: g.target,\n components: g.components,\n document: g.document,\n // Read only while emitting a document, where it adds `/users/{id}/posts`. The per-table\n // schemas are flat whatever it says.\n includeRelations: g.includeRelations,\n // The mirror image: read only for the per-table modules, since the document shares regardless.\n sharedEnums: g.sharedEnums,\n };\n}\n","/**\n * The options `@drzl/generator-ai` receives, built in one place.\n *\n * `generate` and `watch` each dispatch over `cfg.generators` in their own loop, and every branch in\n * both used to assemble its own options object by hand. Four documented options have already been\n * found dead that way, which is why every generator branch now calls a shared builder and a\n * branch-parity spec compares the bytes the two commands write:\n * `packages/cli/test/ai-branch-parity.spec.ts` for this one.\n *\n * There is no `includeRelations` and no `databaseInjection` here, for the reasons the config parser\n * reports rather than silently honours: a relation lookup is a route and this generator emits\n * tools, and the emitted `execute` bodies are stubs that read no injected handle.\n */\nimport { aiOutDir } from './config.js';\n\n/** A generator entry from the config, loosely typed because the config schema owns its shape. */\ntype GeneratorConfig = {\n path?: string;\n naming?: unknown;\n outputHeader?: unknown;\n format?: unknown;\n importExtension?: unknown;\n validation?: unknown;\n};\n\nexport function aiOptions(g: GeneratorConfig, cfg: { outDir: string }): Record<string, unknown> {\n return {\n outputDir: aiOutDir(g, cfg),\n naming: g.naming,\n outputHeader: g.outputHeader,\n format: g.format,\n importExtension: g.importExtension,\n validation: g.validation,\n };\n}\n","/**\n * The options `@drzl/generator-effect-http` receives, built in one place.\n *\n * `generate` and `watch` each dispatch over `cfg.generators` in their own loop, and every branch in\n * both used to assemble its own options object by hand. Four documented options have already been\n * found dead that way, which is why every generator branch now calls a shared builder and a\n * branch-parity spec compares the bytes the two commands write:\n * `packages/cli/test/effect-http-branch-parity.spec.ts` for this one.\n *\n * This builder does one thing none of the others do, and the reason is that this generator has one\n * mode rather than two. It emits no schemas of its own: its endpoints declare the Effect Schema modules a\n * validation generator wrote, which is where the CHECK bounds a caller is held to come from. So\n * `useShared` is not a choice here, and the import path is derived from the sibling generator's own\n * `path` rather than left for the user to repeat. A config that names both generators and nothing\n * else is therefore complete, and a config that points somewhere specific still wins.\n */\nimport { effectHttpOutDir } from './config.js';\n\n/** A generator entry from the config, loosely typed because the config schema owns its shape. */\ntype GeneratorConfig = {\n path?: string;\n naming?: unknown;\n outputHeader?: unknown;\n format?: unknown;\n importExtension?: unknown;\n apiName?: unknown;\n validation?: {\n useShared?: boolean;\n /**\n * Accepted loosely and never read: the config enum lists the three libraries a validator\n * generator emits, `effect` is not among them, and this generator has no choice to make. The\n * config parser reports a value set here; the builder simply overrides it below.\n */\n library?: string;\n importPath?: string;\n schemaSuffix?: string;\n affix?: unknown;\n };\n};\n\n/** Where the effect generator writes when its entry names no `path`, repeated from the registry. */\nconst VALIDATOR_DEFAULT_DIRS: Record<string, string> = { effect: 'src/validators/effect' };\n\n/**\n * A generator's own `path`, spelled the way `validation.importPath` is read.\n *\n * The two look identical and are resolved against different roots. A `path` is always relative to\n * the project, which is why every generator does `path.resolve(process.cwd(), opts.outputDir)`. An\n * `importPath` beginning with `./` is deliberately relative to the *output* directory instead, so\n * a project that keeps its schemas beside its actions can say `./schemas` and mean it.\n *\n * So a `path` of `./out/schemas` copied straight across becomes `out/next/out/schemas`, which\n * resolves to nothing. Stripping the prefix is what makes the derived value mean what the sibling\n * entry said. Measured twice: once through the packed gate on the MCP generator, once here.\n */\nfunction projectRelative(p: string): string {\n return p.startsWith('./') ? p.slice(2) : p;\n}\n\nexport function effectHttpOptions(\n g: GeneratorConfig,\n cfg: { outDir: string; generators: ReadonlyArray<{ kind: string; path?: string }> }\n): Record<string, unknown> {\n const library = 'effect';\n // The sibling that writes the schemas these actions parse. Exactly one, or none: two generators\n // of the same kind mean there is no single source of truth, and the generator's own error is a\n // better answer than picking one of them here.\n const siblings = cfg.generators.filter((s) => s.kind === library);\n const derived =\n siblings.length === 1\n ? projectRelative(siblings[0].path ?? VALIDATOR_DEFAULT_DIRS[library])\n : undefined;\n\n return {\n outputDir: effectHttpOutDir(g, cfg),\n apiName: g.apiName,\n naming: g.naming,\n outputHeader: g.outputHeader,\n format: g.format,\n importExtension: g.importExtension,\n validation: {\n ...g.validation,\n library,\n useShared: true,\n importPath: g.validation?.importPath ?? derived,\n },\n };\n}\n","/**\n * The options `@drzl/generator-ts-rest` receives, built in one place.\n *\n * `generate` and `watch` each dispatch over `cfg.generators` in their own loop, and every branch in\n * both used to assemble its own options object by hand. Four documented options have already been\n * found dead that way, which is why every generator branch now calls a shared builder and a\n * branch-parity spec compares the bytes the two commands write:\n * `packages/cli/test/ts-rest-branch-parity.spec.ts` for this one.\n *\n * Like the `h3`, `next` and `tanstack-start` builders, this one has a single mode rather than two.\n * A ts-rest contract is nothing but its schemas, so `useShared` is not a choice here, and the\n * import path is derived from the sibling validation generator's own `path` rather than left for\n * the user to repeat. A config that names both generators and nothing else is therefore complete,\n * and a config that points somewhere specific still wins.\n */\nimport { tsRestOutDir } from './config.js';\n\n/** A generator entry from the config, loosely typed because the config schema owns its shape. */\ntype GeneratorConfig = {\n path?: string;\n naming?: unknown;\n outputHeader?: unknown;\n format?: unknown;\n importExtension?: unknown;\n contractName?: string;\n pathPrefix?: string;\n validation?: {\n useShared?: boolean;\n /**\n * Widened to the config's own union rather than to what this generator supports.\n *\n * `validation.library` accepts `typebox` because the `elysia` generator can use it: Elysia's\n * validator slot takes a TypeBox schema natively. No other router can, and the config parser\n * reports naming it on one of them. This builder therefore falls back rather than passing a\n * value the generator has no dialect for, which would otherwise reach a `LIBS[lib]` lookup and\n * come back undefined.\n */\n library?: 'zod' | 'valibot' | 'arktype' | 'typebox';\n importPath?: string;\n schemaSuffix?: string;\n affix?: unknown;\n };\n};\n\n/** Where each validation generator writes when its entry names no `path`, repeated from the registry. */\nconst VALIDATOR_DEFAULT_DIRS: Record<string, string> = {\n zod: 'src/validators/zod',\n valibot: 'src/validators/valibot',\n arktype: 'src/validators/arktype',\n};\n\n/**\n * A generator's own `path`, spelled the way `validation.importPath` is read.\n *\n * The two look identical and are resolved against different roots. A `path` is always relative to\n * the project, which is why every generator does `path.resolve(process.cwd(), opts.outputDir)`. An\n * `importPath` beginning with `./` is deliberately relative to the *output* directory instead, so\n * a project that keeps its schemas beside its contract can say `./schemas` and mean it.\n *\n * So a `path` of `./out/schemas` copied straight across becomes `out/contract/out/schemas`, which\n * resolves to nothing. Stripping the prefix is what makes the derived value mean what the sibling\n * entry said. Measured on the MCP generator through the packed gate, and again on this one.\n */\nfunction projectRelative(p: string): string {\n return p.startsWith('./') ? p.slice(2) : p;\n}\n\nexport function tsRestOptions(\n g: GeneratorConfig,\n cfg: { outDir: string; generators: ReadonlyArray<{ kind: string; path?: string }> }\n): Record<string, unknown> {\n // `typebox` is accepted by the config for the `elysia` generator alone, and the parser reports\n // it on any other kind. Falling back keeps the emitted output valid for a config that ignored\n // that warning, rather than looking up a dialect that does not exist.\n const configured = g.validation?.library ?? 'zod';\n const library = configured === 'typebox' ? 'zod' : configured;\n // The sibling that writes the schemas this contract declares. Exactly one, or none: two\n // generators of the same kind mean there is no single source of truth, and the generator's own\n // error is a better answer than picking one of them here.\n const siblings = cfg.generators.filter((s) => s.kind === library);\n const derived =\n siblings.length === 1\n ? projectRelative(siblings[0].path ?? VALIDATOR_DEFAULT_DIRS[library])\n : undefined;\n\n return {\n outputDir: tsRestOutDir(g, cfg),\n contractName: g.contractName,\n pathPrefix: g.pathPrefix,\n naming: g.naming,\n outputHeader: g.outputHeader,\n format: g.format,\n importExtension: g.importExtension,\n validation: {\n ...g.validation,\n library,\n useShared: true,\n importPath: g.validation?.importPath ?? derived,\n },\n };\n}\n","/**\n * The options `@drzl/generator-elysia` receives, built in one place.\n *\n * `generate` and `watch` each dispatch over `cfg.generators` in their own loop, and every branch in\n * both used to assemble its own options object by hand. Four documented options have already been\n * found dead that way, which is why every generator branch now calls a shared builder and a\n * branch-parity spec compares the bytes the two commands write:\n * `packages/cli/test/elysia-branch-parity.spec.ts` for this one.\n *\n * Like the `h3`, `next`, `tanstack-start` and `ts-rest` builders, this one has a single mode rather\n * than two: the generator emits no schemas of its own, so `useShared` is not a choice and the import\n * path is derived from the sibling validation generator's own `path`.\n *\n * It defaults to zod like every other router, and TypeBox is worth a note rather than the default.\n * Elysia's own `t` *is* TypeBox and this is the only kind whose validator slot accepts a TypeBox\n * schema, so a Bun project probably wants it. But TypeBox ships separate `.d.ts` and `.d.mts`\n * declarations whose types are branded with distinct `unique symbol`s, and Elysia's own types are\n * declared as CommonJS, so under `moduleResolution: node16` or `nodenext` the two resolve to\n * different copies and a TypeBox schema is not assignable to Elysia's slot. Measured against\n * elysia@1.4.29 and @sinclair/typebox@0.34.52. It compiles cleanly under `bundler`, which is what\n * Bun projects use, so the option is worth having and the default is not.\n */\nimport { elysiaOutDir } from './config.js';\n\n/** A generator entry from the config, loosely typed because the config schema owns its shape. */\ntype GeneratorConfig = {\n path?: string;\n naming?: unknown;\n outputHeader?: unknown;\n format?: unknown;\n importExtension?: unknown;\n appName?: string;\n prefix?: string;\n validation?: {\n useShared?: boolean;\n library?: 'zod' | 'valibot' | 'arktype' | 'typebox';\n importPath?: string;\n schemaSuffix?: string;\n affix?: unknown;\n };\n};\n\n/** Where each validation generator writes when its entry names no `path`, repeated from the registry. */\nconst VALIDATOR_DEFAULT_DIRS: Record<string, string> = {\n zod: 'src/validators/zod',\n valibot: 'src/validators/valibot',\n arktype: 'src/validators/arktype',\n typebox: 'src/validators/typebox',\n};\n\n/**\n * A generator's own `path`, spelled the way `validation.importPath` is read.\n *\n * The two look identical and are resolved against different roots. A `path` is always relative to\n * the project, which is why every generator does `path.resolve(process.cwd(), opts.outputDir)`. An\n * `importPath` beginning with `./` is deliberately relative to the *output* directory instead, so\n * a project that keeps its schemas beside its routes can say `./schemas` and mean it.\n *\n * So a `path` of `./out/schemas` copied straight across becomes `out/routes/out/schemas`, which\n * resolves to nothing. Stripping the prefix is what makes the derived value mean what the sibling\n * entry said. Measured on the MCP generator through the packed gate, and again since.\n */\nfunction projectRelative(p: string): string {\n return p.startsWith('./') ? p.slice(2) : p;\n}\n\nexport function elysiaOptions(\n g: GeneratorConfig,\n cfg: { outDir: string; generators: ReadonlyArray<{ kind: string; path?: string }> }\n): Record<string, unknown> {\n const library = g.validation?.library ?? 'zod';\n // The sibling that writes the schemas these routes validate with. Exactly one, or none: two\n // generators of the same kind mean there is no single source of truth, and the generator's own\n // error is a better answer than picking one of them here.\n const siblings = cfg.generators.filter((s) => s.kind === library);\n const derived =\n siblings.length === 1\n ? projectRelative(siblings[0].path ?? VALIDATOR_DEFAULT_DIRS[library])\n : undefined;\n\n return {\n outputDir: elysiaOutDir(g, cfg),\n appName: g.appName,\n prefix: g.prefix,\n naming: g.naming,\n outputHeader: g.outputHeader,\n format: g.format,\n importExtension: g.importExtension,\n validation: {\n ...g.validation,\n library,\n useShared: true,\n importPath: g.validation?.importPath ?? derived,\n },\n };\n}\n","/**\n * The options `@drzl/generator-h3` receives, built in one place.\n *\n * `generate` and `watch` each dispatch over `cfg.generators` in their own loop, and every branch in\n * both used to assemble its own options object by hand. Four documented options have already been\n * found dead that way, which is why every generator branch now calls a shared builder and a\n * branch-parity spec compares the bytes the two commands write:\n * `packages/cli/test/h3-branch-parity.spec.ts` for this one.\n *\n * This builder does one thing none of the others do, and the reason is that this generator has one\n * mode rather than two. It emits no schemas of its own: its route handlers validate with the constrained schemas a\n * validation generator wrote, which is where the CHECK bounds a caller is held to come from. So\n * `useShared` is not a choice here, and the import path is derived from the sibling generator's own\n * `path` rather than left for the user to repeat. A config that names both generators and nothing\n * else is therefore complete, and a config that points somewhere specific still wins.\n */\nimport { h3OutDir } from './config.js';\n\n/** A generator entry from the config, loosely typed because the config schema owns its shape. */\ntype GeneratorConfig = {\n path?: string;\n naming?: unknown;\n outputHeader?: unknown;\n format?: unknown;\n importExtension?: unknown;\n h3?: unknown;\n validation?: {\n useShared?: boolean;\n /**\n * Widened to the config's own union rather than to what this generator supports.\n *\n * `validation.library` accepts `typebox` because the `elysia` generator can use it: Elysia's\n * validator slot takes a TypeBox schema natively. No other router can, and the config parser\n * reports naming it on one of them. This builder therefore falls back rather than passing a\n * value the generator has no dialect for, which would otherwise reach a `LIBS[lib]` lookup and\n * come back undefined.\n */\n library?: 'zod' | 'valibot' | 'arktype' | 'typebox';\n importPath?: string;\n schemaSuffix?: string;\n affix?: unknown;\n };\n};\n\n/** Where each validation generator writes when its entry names no `path`, repeated from the registry. */\nconst VALIDATOR_DEFAULT_DIRS: Record<string, string> = {\n zod: 'src/validators/zod',\n valibot: 'src/validators/valibot',\n arktype: 'src/validators/arktype',\n};\n\n/**\n * A generator's own `path`, spelled the way `validation.importPath` is read.\n *\n * The two look identical and are resolved against different roots. A `path` is always relative to\n * the project, which is why every generator does `path.resolve(process.cwd(), opts.outputDir)`. An\n * `importPath` beginning with `./` is deliberately relative to the *output* directory instead, so\n * a project that keeps its schemas beside its actions can say `./schemas` and mean it.\n *\n * So a `path` of `./out/schemas` copied straight across becomes `out/next/out/schemas`, which\n * resolves to nothing. Stripping the prefix is what makes the derived value mean what the sibling\n * entry said. Measured twice: once through the packed gate on the MCP generator, once here.\n */\nfunction projectRelative(p: string): string {\n return p.startsWith('./') ? p.slice(2) : p;\n}\n\nexport function h3Options(\n g: GeneratorConfig,\n cfg: { outDir: string; generators: ReadonlyArray<{ kind: string; path?: string }> }\n): Record<string, unknown> {\n // `typebox` is accepted by the config for the `elysia` generator alone, and the parser reports\n // it on any other kind. Falling back keeps the emitted output valid for a config that ignored\n // that warning, rather than looking up a dialect that does not exist.\n const configured = g.validation?.library ?? 'zod';\n const library = configured === 'typebox' ? 'zod' : configured;\n // The sibling that writes the schemas these actions parse. Exactly one, or none: two generators\n // of the same kind mean there is no single source of truth, and the generator's own error is a\n // better answer than picking one of them here.\n const siblings = cfg.generators.filter((s) => s.kind === library);\n const derived =\n siblings.length === 1\n ? projectRelative(siblings[0].path ?? VALIDATOR_DEFAULT_DIRS[library])\n : undefined;\n\n return {\n outputDir: h3OutDir(g, cfg),\n h3: g.h3,\n naming: g.naming,\n outputHeader: g.outputHeader,\n format: g.format,\n importExtension: g.importExtension,\n validation: {\n ...g.validation,\n library,\n useShared: true,\n importPath: g.validation?.importPath ?? derived,\n },\n };\n}\n","/**\n * The options `@drzl/generator-mcp` receives, built in one place.\n *\n * `generate` and `watch` each dispatch over `cfg.generators` in their own loop, and every branch\n * in both used to assemble its own options object by hand. Four documented options have already\n * been found dead that way, which is why every generator branch now calls a shared builder and a\n * branch-parity spec compares the bytes the two commands write:\n * `packages/cli/test/mcp-branch-parity.spec.ts` for this one.\n *\n * There is no `databaseInjection` here, for the reason the config parser reports rather than\n * silently honours: the emitted tool handlers are stubs, so nothing would read an injected handle.\n * `includeRelations` is absent too, since a relation lookup is a route and this generator emits\n * tools rather than routes.\n */\nimport { mcpOutDir } from './config.js';\n\n/** A generator entry from the config, loosely typed because the config schema owns its shape. */\ntype GeneratorConfig = {\n path?: string;\n sdk?: unknown;\n serverName?: unknown;\n serverVersion?: unknown;\n stdio?: unknown;\n naming?: unknown;\n outputHeader?: unknown;\n format?: unknown;\n importExtension?: unknown;\n validation?: unknown;\n};\n\nexport function mcpOptions(g: GeneratorConfig, cfg: { outDir: string }): Record<string, unknown> {\n return {\n outputDir: mcpOutDir(g, cfg),\n sdk: g.sdk,\n serverName: g.serverName,\n serverVersion: g.serverVersion,\n stdio: g.stdio,\n naming: g.naming,\n outputHeader: g.outputHeader,\n format: g.format,\n importExtension: g.importExtension,\n validation: g.validation,\n };\n}\n","/**\n * The options `@drzl/generator-next` receives, built in one place.\n *\n * `generate` and `watch` each dispatch over `cfg.generators` in their own loop, and every branch in\n * both used to assemble its own options object by hand. Four documented options have already been\n * found dead that way, which is why every generator branch now calls a shared builder and a\n * branch-parity spec compares the bytes the two commands write:\n * `packages/cli/test/next-branch-parity.spec.ts` for this one.\n *\n * This builder does one thing none of the others do, and the reason is that this generator has one\n * mode rather than two. It emits no schemas of its own: its actions parse the constrained schemas a\n * validation generator wrote, which is where the CHECK bounds a form reports come from. So\n * `useShared` is not a choice here, and the import path is derived from the sibling generator's own\n * `path` rather than left for the user to repeat. A config that names both generators and nothing\n * else is therefore complete, and a config that points somewhere specific still wins.\n */\nimport { nextOutDir } from './config.js';\n\n/** A generator entry from the config, loosely typed because the config schema owns its shape. */\ntype GeneratorConfig = {\n path?: string;\n naming?: unknown;\n outputHeader?: unknown;\n format?: unknown;\n importExtension?: unknown;\n validation?: {\n useShared?: boolean;\n /**\n * Widened to the config's own union rather than to what this generator supports.\n *\n * `validation.library` accepts `typebox` because the `elysia` generator can use it: Elysia's\n * validator slot takes a TypeBox schema natively. No other router can, and the config parser\n * reports naming it on one of them. This builder therefore falls back rather than passing a\n * value the generator has no dialect for, which would otherwise reach a `LIBS[lib]` lookup and\n * come back undefined.\n */\n library?: 'zod' | 'valibot' | 'arktype' | 'typebox';\n importPath?: string;\n schemaSuffix?: string;\n affix?: unknown;\n };\n};\n\n/** Where each validation generator writes when its entry names no `path`, repeated from the registry. */\nconst VALIDATOR_DEFAULT_DIRS: Record<string, string> = {\n zod: 'src/validators/zod',\n valibot: 'src/validators/valibot',\n arktype: 'src/validators/arktype',\n};\n\n/**\n * A generator's own `path`, spelled the way `validation.importPath` is read.\n *\n * The two look identical and are resolved against different roots. A `path` is always relative to\n * the project, which is why every generator does `path.resolve(process.cwd(), opts.outputDir)`. An\n * `importPath` beginning with `./` is deliberately relative to the *output* directory instead, so\n * a project that keeps its schemas beside its actions can say `./schemas` and mean it.\n *\n * So a `path` of `./out/schemas` copied straight across becomes `out/next/out/schemas`, which\n * resolves to nothing. Stripping the prefix is what makes the derived value mean what the sibling\n * entry said. Measured twice: once through the packed gate on the MCP generator, once here.\n */\nfunction projectRelative(p: string): string {\n return p.startsWith('./') ? p.slice(2) : p;\n}\n\nexport function nextOptions(\n g: GeneratorConfig,\n cfg: { outDir: string; generators: ReadonlyArray<{ kind: string; path?: string }> }\n): Record<string, unknown> {\n // `typebox` is accepted by the config for the `elysia` generator alone, and the parser reports\n // it on any other kind. Falling back keeps the emitted output valid for a config that ignored\n // that warning, rather than looking up a dialect that does not exist.\n const configured = g.validation?.library ?? 'zod';\n const library = configured === 'typebox' ? 'zod' : configured;\n // The sibling that writes the schemas these actions parse. Exactly one, or none: two generators\n // of the same kind mean there is no single source of truth, and the generator's own error is a\n // better answer than picking one of them here.\n const siblings = cfg.generators.filter((s) => s.kind === library);\n const derived =\n siblings.length === 1\n ? projectRelative(siblings[0].path ?? VALIDATOR_DEFAULT_DIRS[library])\n : undefined;\n\n return {\n outputDir: nextOutDir(g, cfg),\n naming: g.naming,\n outputHeader: g.outputHeader,\n format: g.format,\n importExtension: g.importExtension,\n validation: {\n ...g.validation,\n library,\n useShared: true,\n importPath: g.validation?.importPath ?? derived,\n },\n };\n}\n","/**\n * The options `@drzl/generator-tanstack-start` receives, built in one place.\n *\n * `generate` and `watch` each dispatch over `cfg.generators` in their own loop, and every branch in\n * both used to assemble its own options object by hand. Four documented options have already been\n * found dead that way, which is why every generator branch now calls a shared builder and a\n * branch-parity spec compares the bytes the two commands write:\n * `packages/cli/test/tanstack-start-branch-parity.spec.ts` for this one.\n *\n * This builder does one thing none of the others do, and the reason is that this generator has one\n * mode rather than two. It emits no schemas of its own: its server functions validate with the constrained schemas a\n * validation generator wrote, which is where the CHECK bounds a caller is held to come from. So\n * `useShared` is not a choice here, and the import path is derived from the sibling generator's own\n * `path` rather than left for the user to repeat. A config that names both generators and nothing\n * else is therefore complete, and a config that points somewhere specific still wins.\n */\nimport { tanstackStartOutDir } from './config.js';\n\n/** A generator entry from the config, loosely typed because the config schema owns its shape. */\ntype GeneratorConfig = {\n path?: string;\n naming?: unknown;\n outputHeader?: unknown;\n format?: unknown;\n importExtension?: unknown;\n validation?: {\n useShared?: boolean;\n /**\n * Widened to the config's own union rather than to what this generator supports.\n *\n * `validation.library` accepts `typebox` because the `elysia` generator can use it: Elysia's\n * validator slot takes a TypeBox schema natively. No other router can, and the config parser\n * reports naming it on one of them. This builder therefore falls back rather than passing a\n * value the generator has no dialect for, which would otherwise reach a `LIBS[lib]` lookup and\n * come back undefined.\n */\n library?: 'zod' | 'valibot' | 'arktype' | 'typebox';\n importPath?: string;\n schemaSuffix?: string;\n affix?: unknown;\n };\n};\n\n/** Where each validation generator writes when its entry names no `path`, repeated from the registry. */\nconst VALIDATOR_DEFAULT_DIRS: Record<string, string> = {\n zod: 'src/validators/zod',\n valibot: 'src/validators/valibot',\n arktype: 'src/validators/arktype',\n};\n\n/**\n * A generator's own `path`, spelled the way `validation.importPath` is read.\n *\n * The two look identical and are resolved against different roots. A `path` is always relative to\n * the project, which is why every generator does `path.resolve(process.cwd(), opts.outputDir)`. An\n * `importPath` beginning with `./` is deliberately relative to the *output* directory instead, so\n * a project that keeps its schemas beside its actions can say `./schemas` and mean it.\n *\n * So a `path` of `./out/schemas` copied straight across becomes `out/next/out/schemas`, which\n * resolves to nothing. Stripping the prefix is what makes the derived value mean what the sibling\n * entry said. Measured twice: once through the packed gate on the MCP generator, once here.\n */\nfunction projectRelative(p: string): string {\n return p.startsWith('./') ? p.slice(2) : p;\n}\n\nexport function tanstackStartOptions(\n g: GeneratorConfig,\n cfg: { outDir: string; generators: ReadonlyArray<{ kind: string; path?: string }> }\n): Record<string, unknown> {\n // `typebox` is accepted by the config for the `elysia` generator alone, and the parser reports\n // it on any other kind. Falling back keeps the emitted output valid for a config that ignored\n // that warning, rather than looking up a dialect that does not exist.\n const configured = g.validation?.library ?? 'zod';\n const library = configured === 'typebox' ? 'zod' : configured;\n // The sibling that writes the schemas these actions parse. Exactly one, or none: two generators\n // of the same kind mean there is no single source of truth, and the generator's own error is a\n // better answer than picking one of them here.\n const siblings = cfg.generators.filter((s) => s.kind === library);\n const derived =\n siblings.length === 1\n ? projectRelative(siblings[0].path ?? VALIDATOR_DEFAULT_DIRS[library])\n : undefined;\n\n return {\n outputDir: tanstackStartOutDir(g, cfg),\n naming: g.naming,\n outputHeader: g.outputHeader,\n format: g.format,\n importExtension: g.importExtension,\n validation: {\n ...g.validation,\n library,\n useShared: true,\n importPath: g.validation?.importPath ?? derived,\n },\n };\n}\n","/**\n * The options `@drzl/generator-nestjs` receives, built in one place.\n *\n * `generate` and `watch` each dispatch over `cfg.generators` in their own loop, and every branch\n * in both used to assemble its own options object by hand. Four documented options have already\n * been found dead that way, which is why every generator branch now calls a shared builder and a\n * branch-parity spec compares the bytes the two commands write:\n * `packages/cli/test/nestjs-branch-parity.spec.ts` for this one.\n *\n * There is no `includeRelations` here, unlike the router builders: relation lookups are routes,\n * and this generator emits DTO classes rather than routes, so the flag would be wiring an option\n * nothing reads. There is no `servicesDir` and no `databaseInjection` either, for the stronger\n * form of the same reason: there are no handlers at all. `validation` is forwarded whole; the\n * generator reads `library` and `resolveConfig` warns about every other key on this kind.\n */\nimport { nestjsOutDir } from './config.js';\n\n/** A generator entry from the config, loosely typed because the config schema owns its shape. */\ntype GeneratorConfig = {\n path?: string;\n naming?: unknown;\n outputHeader?: unknown;\n format?: unknown;\n importExtension?: unknown;\n validation?: unknown;\n};\n\nexport function nestjsOptions(\n g: GeneratorConfig,\n cfg: { outDir: string }\n): Record<string, unknown> {\n return {\n outputDir: nestjsOutDir(g, cfg),\n naming: g.naming,\n outputHeader: g.outputHeader,\n format: g.format,\n importExtension: g.importExtension,\n validation: g.validation,\n };\n}\n","/**\n * The options `@drzl/generator-orpc` receives, built in one place.\n *\n * The last kind to get one. `generate` and `watch` each assembled this object by hand, and the\n * two copies agreed only because somebody kept checking: `servicesDir` reached the tRPC branch of\n * one command and not the other for a whole release, which is the same shape of defect one file\n * along. The builders for the other thirteen kinds exist for that reason and this one completes\n * the set, so the registry can hand every generator its options the same way.\n *\n * `outputDir` is `cfg.outDir` and never `g.path`, which is oRPC's own arrangement rather than an\n * omission: this generator has always written where the top-level setting says, and\n * `computeGeneratorOutputDirs` adds `cfg.outDir` unconditionally for it. A `path` on an oRPC entry\n * is ignored, as it always has been, and moving it now would relocate the output of every existing\n * config that happens to set one.\n */\n\n/** A generator entry from the config, loosely typed because the config schema owns its shape. */\ntype GeneratorConfig = {\n template?: unknown;\n includeRelations?: unknown;\n naming?: unknown;\n outputHeader?: unknown;\n format?: unknown;\n templateOptions?: unknown;\n importExtension?: unknown;\n validation?: unknown;\n databaseInjection?: unknown;\n};\n\nexport function orpcOptions(\n g: GeneratorConfig,\n cfg: { outDir: string },\n servicesDir: string\n): Record<string, unknown> {\n return {\n outputDir: cfg.outDir,\n template: g.template,\n includeRelations: g.includeRelations,\n naming: g.naming,\n outputHeader: g.outputHeader,\n format: g.format,\n templateOptions: g.templateOptions,\n importExtension: g.importExtension,\n validation: g.validation,\n // Documented on this generator since it was added and unreachable from a config file for most\n // of that time, because the config schema had no such key and zod stripped it in silence.\n databaseInjection: g.databaseInjection,\n // Where the service generator is actually writing, so a router template that imports services\n // spells a path that exists. The templates default this to `src/services`, which is right only\n // by coincidence for a config that puts them elsewhere.\n servicesDir,\n };\n}\n","/**\n * The options `@drzl/generator-service` receives, built in one place.\n *\n * Assembled by hand in both dispatch loops until now, and one of them was already missing a key:\n * `databaseInjection` is what gives a generated service a `db` parameter, and a router generated\n * in injection mode calls `Service.getById(ctx.db, id)`. The two halves of one generated project\n * therefore disagreed about the signature whenever the option was set.\n *\n * `outDir`, not `outputDir`. This generator spells it the short way and the routers spell it the\n * long way, which is a difference in their published option types rather than a choice this file\n * gets to make.\n */\nimport type { ValidationGeneratorConfig } from './validation-options.js';\n\n/** A generator entry from the config, loosely typed because the config schema owns its shape. */\ntype GeneratorConfig = Pick<ValidationGeneratorConfig, 'outputHeader' | 'format'> & {\n dataAccess?: unknown;\n dbImportPath?: unknown;\n schemaImportPath?: unknown;\n importExtension?: unknown;\n databaseInjection?: unknown;\n};\n\nexport function serviceOptions(g: GeneratorConfig, outDir: string): Record<string, unknown> {\n return {\n outDir,\n outputHeader: g.outputHeader,\n format: g.format,\n dataAccess: g.dataAccess,\n dbImportPath: g.dbImportPath,\n schemaImportPath: g.schemaImportPath,\n importExtension: g.importExtension,\n databaseInjection: g.databaseInjection,\n };\n}\n","/**\n * The options `@drzl/generator-trpc` receives, built in one place.\n *\n * `generate` and `watch` each dispatch over `cfg.generators` in their own loop, and every branch\n * in both assembles its own options object by hand. Three documented options have already been\n * found dead that way: `typedJson` never reached typebox, `coerceDates` and `applyDefaults`\n * reached nothing but zod, and `servicesDir` is passed by `generate`'s oRPC branch and not by\n * `watch`'s, so a watch rebuild emits a service import pointing at the default directory whatever\n * the config says. None of those is visible in the wiring: the option parses, the generator\n * defaults it, and the feature simply does nothing.\n *\n * One builder means the two call sites are the same object by construction rather than by review.\n * It also gives the drift something to be asserted against, which is what\n * `packages/cli/test/trpc-branch-parity.spec.ts` does by running both commands and comparing the\n * bytes they wrote.\n */\nimport { trpcOutDir } from './config.js';\n\n/** A generator entry from the config, loosely typed because the config schema owns its shape. */\ntype GeneratorConfig = {\n path?: string;\n template?: unknown;\n includeRelations?: unknown;\n naming?: unknown;\n outputHeader?: unknown;\n format?: unknown;\n importExtension?: unknown;\n validation?: unknown;\n databaseInjection?: unknown;\n};\n\nexport function trpcOptions(\n g: GeneratorConfig,\n cfg: { outDir: string },\n servicesDir: string\n): Record<string, unknown> {\n return {\n outputDir: trpcOutDir(g, cfg),\n template: g.template,\n includeRelations: g.includeRelations,\n naming: g.naming,\n outputHeader: g.outputHeader,\n format: g.format,\n importExtension: g.importExtension,\n validation: g.validation,\n databaseInjection: g.databaseInjection,\n // Where the service generator is actually writing, so `template: 'service'` emits an import\n // of a module that exists. The generator defaults this to `src/services`, which is right only\n // by coincidence for a config that puts them elsewhere.\n servicesDir,\n };\n}\n","/**\n * Every generator DRZL can run, as data rather than as control flow.\n *\n * The same fourteen-way dispatch was written out four times: once inside `generate`, once inside\n * `watch`, and once each in `generate:orpc` and `generate:trpc`. Every copy repeated the package\n * name, the `import()`, the constructor, the default output directory and the call to the options\n * builder, and the copies were kept in step by review alone. Review is measurably not enough for\n * this: `servicesDir` reached one loop's tRPC branch and not the other's for a release,\n * five validation options never reached a watch rebuild at all, and `watch` had no json-schema\n * branch for a while, so that directory went stale from the first save onward. None of it was\n * visible in the wiring, because a dropped option parses, the generator defaults it, and the\n * feature silently does nothing.\n *\n * So each generator states those five facts once, here, and the commands loop over this list. A\n * new generator is one entry: adding it to the config enum and forgetting a dispatch branch is no\n * longer a state the code can be in, and `packages/cli/test/generator-registry.spec.ts` asserts\n * the registry and the config enum name the same kinds.\n *\n * The import thunks stay literal `import('@drzl/generator-…')` expressions rather than being built\n * from `specifier`, because that literal is what the bundler sees; a computed specifier would be\n * left as a runtime lookup with nothing declaring the dependency.\n */\nimport {\n aiOutDir,\n effectHttpOutDir,\n tsRestOutDir,\n elysiaOutDir,\n expressOutDir,\n h3OutDir,\n fastifyOutDir,\n graphqlOutDir,\n honoOutDir,\n mcpOutDir,\n nestjsOutDir,\n nextOutDir,\n tanstackStartOutDir,\n trpcOutDir,\n type DrzlConfig,\n type GeneratorKind,\n} from './config.js';\nimport { expressOptions } from './express-options.js';\nimport { fastifyOptions } from './fastify-options.js';\nimport { loadGenerator } from './generator-loader.js';\nimport { graphqlOptions } from './graphql-options.js';\nimport { honoOptions } from './hono-options.js';\nimport { jsonSchemaOptions } from './json-schema-options.js';\nimport { aiOptions } from './ai-options.js';\nimport { effectHttpOptions } from './effect-http-options.js';\nimport { tsRestOptions } from './ts-rest-options.js';\nimport { elysiaOptions } from './elysia-options.js';\nimport { h3Options } from './h3-options.js';\nimport { mcpOptions } from './mcp-options.js';\nimport { nextOptions } from './next-options.js';\nimport { tanstackStartOptions } from './tanstack-start-options.js';\nimport { nestjsOptions } from './nestjs-options.js';\nimport { orpcOptions } from './orpc-options.js';\nimport { serviceOptions } from './service-options.js';\nimport { trpcOptions } from './trpc-options.js';\nimport { validationOptions } from './validation-options.js';\n\n/** One entry of `cfg.generators`, as loosely typed here as the option builders take it. */\ntype GeneratorConfig = DrzlConfig['generators'][number];\n\n/**\n * What a generator hands back.\n *\n * Two shapes, because the packages really do differ: the routers resolve to `{ files }` and the\n * validation generators resolve to the array itself. Normalised by `filesOf` at the one call site\n * rather than by changing seven published signatures.\n */\ntype GenerateResult = string[] | { files: string[] };\n\ninterface GeneratorInstance {\n generate(options: Record<string, unknown>): Promise<GenerateResult>;\n}\n\n/** What the registry knows about one generator, and the whole of what a new one has to state. */\nexport interface GeneratorEntry {\n /** The kind a config names it by, which is also what `--only` accepts. */\n readonly kind: GeneratorKind;\n /** The npm package that carries it, named in the \"not installed\" message. */\n readonly specifier: string;\n /** A literal `import()`, so the bundler can see the dependency. */\n readonly load: () => Promise<unknown>;\n /** The constructor off that module, applied to an analysis. */\n readonly construct: (module: any, analysis: unknown) => GeneratorInstance;\n /**\n * Where this generator writes, given its config entry.\n *\n * The routers fall back to the top-level `outDir` and the rest have a default directory of their\n * own. `computeGeneratorOutputDirs` has to arrive at the same answer, because the directory a\n * watcher fails to ignore is a directory it regenerates from forever, and\n * `packages/cli/test/generator-registry.spec.ts` compares the two.\n */\n readonly outputDir: (g: GeneratorConfig, cfg: DrzlConfig) => string;\n /** The options object it receives, built by the shared builder for its kind. */\n readonly options: (\n g: GeneratorConfig,\n cfg: DrzlConfig,\n ctx: { outDir: string; servicesDir: string }\n ) => Record<string, unknown>;\n}\n\n/**\n * The default directory each generator writes to when its entry names no `path`.\n *\n * Spelled here as well as in `computeGeneratorOutputDirs` for one reason worth keeping: that\n * function is exported from the package's `./config` entry and has been since before the registry\n * existed, so it stays where its consumers expect it. The two are held together by a test rather\n * than by a comment.\n */\nconst VALIDATOR_DEFAULT_DIRS = {\n zod: 'src/validators/zod',\n valibot: 'src/validators/valibot',\n arktype: 'src/validators/arktype',\n typebox: 'src/validators/typebox',\n effect: 'src/validators/effect',\n 'json-schema': 'src/validators/json-schema',\n} as const;\n\n/** Where the service generator writes when its entry names no `path`. */\nexport const SERVICES_DEFAULT_DIR = 'src/services';\n\n/**\n * Where the service generator is writing for this config, whether or not it is being run.\n *\n * The router templates emit an import of a generated service, and the path in that import has to\n * be the path the service generator really used. Computed from the config rather than defaulted\n * inside the templates, because the template's own default is right only by coincidence for a\n * config that puts services elsewhere. `generate` has always computed it; `watch` did not, so a\n * rebuild silently emitted the default.\n */\nexport function resolveServicesDir(cfg: DrzlConfig): string {\n return cfg.generators.find((g) => g.kind === 'service')?.path ?? SERVICES_DEFAULT_DIR;\n}\n\nexport const GENERATORS: readonly GeneratorEntry[] = [\n {\n kind: 'orpc',\n specifier: '@drzl/generator-orpc',\n load: () => import('@drzl/generator-orpc'),\n construct: (m, analysis) => new m.ORPCGenerator(analysis),\n // `cfg.outDir` and never `g.path`: see `orpcOptions` for why that is this generator's own\n // arrangement rather than an oversight to correct here.\n outputDir: (_g, cfg) => cfg.outDir,\n options: (g, cfg, ctx) => orpcOptions(g, cfg, ctx.servicesDir),\n },\n {\n kind: 'trpc',\n // This one and seven others were `optionalDependencies` until every one of them had been\n // published: a package that has never existed cannot publish through npm's trusted-publisher\n // OIDC flow, so its first version goes out by hand, and naming it as a hard dependency in the\n // same release breaks `npm i @drzl/cli` for everyone until it does exist. An optional\n // dependency is skipped by the installer instead, which made that release safe.\n //\n // The side effect was invisible and lasted longer than the reason: tsup externalises\n // `dependencies` and `peerDependencies` and bundles everything else, so those eight travelled\n // inside `dist` while the other six were resolved from `node_modules`. All fourteen are on the\n // registry now and all fourteen are `dependencies`, which is what makes every one of them a\n // package that can genuinely be absent, and `loadGenerator` tell absence apart from failure\n // for every kind rather than for six of them.\n specifier: '@drzl/generator-trpc',\n load: () => import('@drzl/generator-trpc'),\n construct: (m, analysis) => new m.TRPCGenerator(analysis),\n outputDir: (g, cfg) => trpcOutDir(g, cfg),\n options: (g, cfg, ctx) => trpcOptions(g, cfg, ctx.servicesDir),\n },\n {\n kind: 'hono',\n specifier: '@drzl/generator-hono',\n load: () => import('@drzl/generator-hono'),\n construct: (m, analysis) => new m.HonoGenerator(analysis),\n outputDir: (g, cfg) => honoOutDir(g, cfg),\n options: (g, cfg) => honoOptions(g, cfg),\n },\n {\n kind: 'express',\n specifier: '@drzl/generator-express',\n load: () => import('@drzl/generator-express'),\n construct: (m, analysis) => new m.ExpressGenerator(analysis),\n outputDir: (g, cfg) => expressOutDir(g, cfg),\n options: (g, cfg) => expressOptions(g, cfg),\n },\n {\n kind: 'fastify',\n specifier: '@drzl/generator-fastify',\n load: () => import('@drzl/generator-fastify'),\n construct: (m, analysis) => new m.FastifyGenerator(analysis),\n outputDir: (g, cfg) => fastifyOutDir(g, cfg),\n options: (g, cfg) => fastifyOptions(g, cfg),\n },\n {\n kind: 'nestjs',\n specifier: '@drzl/generator-nestjs',\n load: () => import('@drzl/generator-nestjs'),\n construct: (m, analysis) => new m.NestJSGenerator(analysis),\n outputDir: (g, cfg) => nestjsOutDir(g, cfg),\n options: (g, cfg) => nestjsOptions(g, cfg),\n },\n {\n kind: 'graphql',\n specifier: '@drzl/generator-graphql',\n load: () => import('@drzl/generator-graphql'),\n construct: (m, analysis) => new m.GraphQLGenerator(analysis),\n outputDir: (g, cfg) => graphqlOutDir(g, cfg),\n options: (g, cfg) => graphqlOptions(g, cfg),\n },\n {\n kind: 'mcp',\n // This one and the three below spent one release each in `optionalDependencies`, because a\n // package that has never existed cannot publish through npm's trusted-publisher OIDC flow and\n // naming it as a hard dependency in the release that introduces it breaks `npm i @drzl/cli`\n // for everyone until the first publish lands. All four are on the registry now, so all four\n // are ordinary dependencies. `scripts/verify/stages/33-registry-deps.sh` gates both halves of\n // that rule and is what reported the promotion was due.\n specifier: '@drzl/generator-mcp',\n load: () => import('@drzl/generator-mcp'),\n construct: (m, analysis) => new m.MCPGenerator(analysis),\n outputDir: (g, cfg) => mcpOutDir(g, cfg),\n options: (g, cfg) => mcpOptions(g, cfg),\n },\n {\n kind: 'next',\n specifier: '@drzl/generator-next',\n load: () => import('@drzl/generator-next'),\n construct: (m, analysis) => new m.NextGenerator(analysis),\n outputDir: (g, cfg) => nextOutDir(g, cfg),\n options: (g, cfg) => nextOptions(g, cfg),\n },\n {\n kind: 'ai',\n specifier: '@drzl/generator-ai',\n load: () => import('@drzl/generator-ai'),\n construct: (m, analysis) => new m.AIGenerator(analysis),\n outputDir: (g, cfg) => aiOutDir(g, cfg),\n options: (g, cfg) => aiOptions(g, cfg),\n },\n {\n kind: 'tanstack-start',\n specifier: '@drzl/generator-tanstack-start',\n load: () => import('@drzl/generator-tanstack-start'),\n construct: (m, analysis) => new m.TanStackStartGenerator(analysis),\n outputDir: (g, cfg) => tanstackStartOutDir(g, cfg),\n options: (g, cfg) => tanstackStartOptions(g, cfg),\n },\n {\n kind: 'h3',\n specifier: '@drzl/generator-h3',\n load: () => import('@drzl/generator-h3'),\n construct: (m, analysis) => new m.H3Generator(analysis),\n outputDir: (g, cfg) => h3OutDir(g, cfg),\n options: (g, cfg) => h3Options(g, cfg),\n },\n {\n kind: 'effect-http',\n specifier: '@drzl/generator-effect-http',\n load: () => import('@drzl/generator-effect-http'),\n construct: (m, analysis) => new m.EffectHttpGenerator(analysis),\n outputDir: (g, cfg) => effectHttpOutDir(g, cfg),\n options: (g, cfg) => effectHttpOptions(g, cfg),\n },\n {\n kind: 'ts-rest',\n specifier: '@drzl/generator-ts-rest',\n load: () => import('@drzl/generator-ts-rest'),\n construct: (m, analysis) => new m.TsRestGenerator(analysis),\n outputDir: (g, cfg) => tsRestOutDir(g, cfg),\n options: (g, cfg) => tsRestOptions(g, cfg),\n },\n {\n kind: 'elysia',\n specifier: '@drzl/generator-elysia',\n load: () => import('@drzl/generator-elysia'),\n construct: (m, analysis) => new m.ElysiaGenerator(analysis),\n outputDir: (g, cfg) => elysiaOutDir(g, cfg),\n options: (g, cfg) => elysiaOptions(g, cfg),\n },\n {\n kind: 'service',\n specifier: '@drzl/generator-service',\n load: () => import('@drzl/generator-service'),\n construct: (m, analysis) => new m.ServiceGenerator(analysis),\n outputDir: (g) => g.path ?? SERVICES_DEFAULT_DIR,\n options: (g, _cfg, ctx) => serviceOptions(g, ctx.outDir),\n },\n {\n kind: 'zod',\n specifier: '@drzl/generator-zod',\n load: () => import('@drzl/generator-zod'),\n construct: (m, analysis) => new m.ZodGenerator(analysis),\n outputDir: (g) => g.path ?? VALIDATOR_DEFAULT_DIRS.zod,\n // `meta` is zod-only; see `GeneratorCapabilities.meta` for why it is not passed to the other\n // four rather than being passed and ignored.\n options: (g, cfg, ctx) =>\n validationOptions(g, cfg, ctx.outDir, {\n schemaTypes: true,\n meta: true,\n constraints: true,\n }),\n },\n {\n kind: 'valibot',\n specifier: '@drzl/generator-valibot',\n load: () => import('@drzl/generator-valibot'),\n construct: (m, analysis) => new m.ValibotGenerator(analysis),\n outputDir: (g) => g.path ?? VALIDATOR_DEFAULT_DIRS.valibot,\n options: (g, cfg, ctx) =>\n validationOptions(g, cfg, ctx.outDir, { schemaTypes: true, constraints: true }),\n },\n {\n kind: 'arktype',\n specifier: '@drzl/generator-arktype',\n load: () => import('@drzl/generator-arktype'),\n construct: (m, analysis) => new m.ArkTypeGenerator(analysis),\n outputDir: (g) => g.path ?? VALIDATOR_DEFAULT_DIRS.arktype,\n options: (g, cfg, ctx) => validationOptions(g, cfg, ctx.outDir, { schemaTypes: false }),\n },\n {\n kind: 'typebox',\n specifier: '@drzl/generator-typebox',\n load: () => import('@drzl/generator-typebox'),\n construct: (m, analysis) => new m.TypeBoxGenerator(analysis),\n outputDir: (g) => g.path ?? VALIDATOR_DEFAULT_DIRS.typebox,\n options: (g, cfg, ctx) =>\n validationOptions(g, cfg, ctx.outDir, { schemaTypes: true, standardSchema: true }),\n },\n {\n kind: 'effect',\n specifier: '@drzl/generator-effect',\n load: () => import('@drzl/generator-effect'),\n construct: (m, analysis) => new m.EffectGenerator(analysis),\n outputDir: (g) => g.path ?? VALIDATOR_DEFAULT_DIRS.effect,\n options: (g, cfg, ctx) => validationOptions(g, cfg, ctx.outDir, { schemaTypes: true }),\n },\n {\n kind: 'json-schema',\n specifier: '@drzl/generator-json-schema',\n load: () => import('@drzl/generator-json-schema'),\n construct: (m, analysis) => new m.JsonSchemaGenerator(analysis),\n outputDir: (g) => g.path ?? VALIDATOR_DEFAULT_DIRS['json-schema'],\n options: (g, cfg, ctx) => jsonSchemaOptions(g, cfg, ctx.outDir),\n },\n];\n\n/** The registry by kind, since every dispatch is a lookup rather than a scan. */\nexport const GENERATOR_BY_KIND: ReadonlyMap<GeneratorKind, GeneratorEntry> = new Map(\n GENERATORS.map((entry) => [entry.kind, entry])\n);\n\n/**\n * The entry for a kind the caller already knows is real.\n *\n * Unreachable in a released build: the only kinds that reach it come from the config enum, and the\n * registry is asserted against that enum by test. It throws rather than returning `undefined` so a\n * kind added to the enum with no entry fails loudly at its first use instead of generating nothing.\n */\nexport function entryFor(kind: GeneratorKind): GeneratorEntry {\n const entry = GENERATOR_BY_KIND.get(kind);\n if (!entry) throw new Error(`No generator is registered for kind \"${kind}\".`);\n return entry;\n}\n\n/** The files a generator wrote, whichever of the two shapes it resolved to. */\nfunction filesOf(result: GenerateResult): string[] {\n return Array.isArray(result) ? result : result.files;\n}\n\n/** Everything a run needs beyond the config entry itself. */\nexport interface GeneratorRunContext {\n analysis: unknown;\n /**\n * Where the service generator is really writing, so a router template that imports services\n * spells a path that exists. Read by the oRPC and tRPC builders and ignored by the rest.\n */\n servicesDir: string;\n /**\n * The write plan, when the caller is keeping one. Absent for `watch`, which writes straight to\n * disk, and the key is omitted rather than passed as `undefined` so a generator that asks\n * whether it was given a sink gets the same answer it did before this existed.\n */\n fileSink?: unknown;\n /** Per-table progress, for the bar. Only the router generators report it. */\n onProgress?: (progress: { index: number }) => void;\n}\n\n/**\n * Load one generator, build its options, run it, and say which files it wrote.\n *\n * The one place any of that happens. A package that is not installed comes back out of\n * `loadGenerator` as `GeneratorNotInstalledError`, which is what lets the caller print the install\n * line instead of a stack trace; everything else the generator throws comes out unchanged, so a\n * generator that is present and merely failing says what really went wrong.\n */\nexport async function runGenerator(\n entry: GeneratorEntry,\n g: GeneratorConfig,\n cfg: DrzlConfig,\n ctx: GeneratorRunContext\n): Promise<string[]> {\n return runGeneratorWithOptions(entry, ctx.analysis, {\n ...entry.options(g, cfg, {\n outDir: entry.outputDir(g, cfg),\n servicesDir: ctx.servicesDir,\n }),\n ...(ctx.fileSink ? { fileSink: ctx.fileSink } : {}),\n ...(ctx.onProgress ? { onProgress: ctx.onProgress } : {}),\n });\n}\n\n/**\n * Load one generator and run it against options the caller built itself.\n *\n * For the two deprecated per-kind commands, which pass the small option set they have always\n * passed rather than the config-shaped one. They share the loading, the constructor and the\n * two-shaped result with everything else, which is all four copies of that down to one; what they\n * keep is their own options, deliberately, because a command being kept alive for compatibility\n * has to keep emitting the bytes it emitted.\n */\nexport async function runGeneratorWithOptions(\n entry: GeneratorEntry,\n analysis: unknown,\n options: Record<string, unknown>\n): Promise<string[]> {\n const module = await loadGenerator(entry.specifier, entry.load);\n return filesOf(await entry.construct(module, analysis).generate(options));\n}\n","/**\n * Which generator kinds a run was asked for: `--only`, and the `--pipeline` spelling it replaces.\n *\n * There were three vocabularies for one idea. A config says `orpc`, a command was called\n * `generate:orpc`, and a watch flag said `generate-orpc`, and the third one covered seven of the\n * fourteen kinds: `--pipeline generate-zod` matched no branch, so the watcher started, reported\n * nothing wrong, and regenerated nothing for as long as it ran. That is the defect this file was\n * written against, and `packages/cli/test/kind-selection.spec.ts` and the watch end-to-end spec\n * both fire on it.\n *\n * `--only` is the surviving spelling and takes the config's own words, so there is one vocabulary\n * left. `--pipeline` keeps working as an alias, because it is on published command lines, and it\n * now reaches every kind rather than half of them.\n *\n * The valid values come from `GeneratorKindSchema`, which is the enum the config parser and the\n * published JSON Schema are both built from. A kind added there is accepted here on the same\n * commit, and a value that is not one of them is refused by name rather than matching nothing.\n */\nimport { GENERATOR_KINDS, type GeneratorKind } from './config.js';\n\n/** The prefix `--pipeline` puts in front of a kind. */\nconst PIPELINE_PREFIX = 'generate-';\n\n/** A `--only` or `--pipeline` value the CLI will not guess at. Carries its own message. */\nexport class KindSelectionError extends Error {\n constructor(\n /** The code the `--json` failure document reports. */\n readonly code: string,\n message: string,\n /** The line printed under the error, when there is a way out worth naming. */\n readonly hint?: string\n ) {\n super(message);\n this.name = 'KindSelectionError';\n }\n}\n\n/** Every kind, as one comma-separated list, for a message that has to show what is allowed. */\nexport function kindList(): string {\n return GENERATOR_KINDS.join(', ');\n}\n\nfunction isKind(value: string): value is GeneratorKind {\n return (GENERATOR_KINDS as readonly string[]).includes(value);\n}\n\n/**\n * The kinds `--only <list>` names, or `undefined` when the flag was not passed.\n *\n * An empty set is never returned: a flag that was passed and selected nothing is a mistake worth\n * a message, not a run that quietly does nothing.\n */\nexport function parseOnly(value: unknown, flag = '--only'): Set<GeneratorKind> | undefined {\n if (value === undefined || value === null) return undefined;\n const requested = String(value)\n .split(',')\n .map((part) => part.trim())\n .filter(Boolean);\n if (!requested.length) {\n throw new KindSelectionError(\n 'DRZL_CLI_ONLY',\n `${flag} was given no kind. Pass one or more of: ${kindList()}.`\n );\n }\n const kinds = new Set<GeneratorKind>();\n for (const name of requested) {\n if (isKind(name)) {\n kinds.add(name);\n continue;\n }\n // The `generate-orpc` spelling is what `--pipeline` takes and what a reader coming from it\n // will type first, so it is named rather than listed among fourteen alternatives.\n const bare = name.startsWith(PIPELINE_PREFIX) ? name.slice(PIPELINE_PREFIX.length) : '';\n throw new KindSelectionError(\n 'DRZL_CLI_ONLY',\n `${flag}: there is no generator kind \"${name}\".`,\n isKind(bare)\n ? `Write it the way the config does: ${flag} ${bare}.`\n : `Valid kinds are: ${kindList()}.`\n );\n }\n return kinds;\n}\n\n/** What `watch` was asked to do, once `--pipeline` and `--only` have both been read. */\nexport interface WatchSelection {\n /** `--pipeline analyze`: report the analysis and run no generator. */\n analyzeOnly: boolean;\n /** The kinds to run, or `undefined` for every kind the config names. */\n kinds?: Set<GeneratorKind>;\n}\n\n/**\n * Read `--pipeline` and `--only` together.\n *\n * `--pipeline analyze` keeps the meaning it has always had. `--pipeline all` is the default and\n * selects nothing, which is how \"every generator in the config\" is spelled. Anything else is\n * `generate-<kind>`, which is `--only <kind>` written the old way.\n *\n * Passing both a narrowing `--pipeline` and `--only` is refused rather than resolved. Any rule for\n * combining them, intersection or last-wins, is one a reader would have to look up, and the two\n * flags mean the same thing.\n */\nexport function resolveWatchSelection(opts: {\n pipeline?: unknown;\n only?: unknown;\n}): WatchSelection {\n const only = parseOnly(opts.only);\n const pipeline =\n opts.pipeline === undefined || opts.pipeline === null ? 'all' : String(opts.pipeline);\n\n if (pipeline === 'analyze') {\n if (only) {\n throw new KindSelectionError(\n 'DRZL_CLI_ONLY',\n '--pipeline analyze runs no generator, so it cannot be combined with --only.',\n 'Drop one of the two.'\n );\n }\n return { analyzeOnly: true };\n }\n\n if (pipeline === 'all') return { analyzeOnly: false, kinds: only };\n\n if (only) {\n throw new KindSelectionError(\n 'DRZL_CLI_ONLY',\n '--pipeline and --only say the same thing, so passing both is ambiguous.',\n `Use --only ${[...only].join(',')} on its own; --pipeline is the older spelling.`\n );\n }\n\n const bare = pipeline.startsWith(PIPELINE_PREFIX) ? pipeline.slice(PIPELINE_PREFIX.length) : '';\n if (!isKind(bare)) {\n throw new KindSelectionError(\n 'DRZL_CLI_ONLY',\n `--pipeline: there is no pipeline called \"${pipeline}\".`,\n // A bare kind is the mirror image of the mistake `parseOnly` names, and the answer is the\n // flag that takes bare kinds rather than the list of sixteen values this one takes.\n isKind(pipeline)\n ? `That is a generator kind, so it goes to the newer flag: --only ${pipeline}.`\n : `Use --only <kind>, or one of: all, analyze, ${GENERATOR_KINDS.map(\n (k) => PIPELINE_PREFIX + k\n ).join(', ')}.`\n );\n }\n return { analyzeOnly: false, kinds: new Set([bare]) };\n}\n\n/**\n * The generator entries a selection keeps, in the order the config wrote them.\n *\n * Order matters and is the config's: two entries of the same kind pointed at different paths both\n * survive, and a selection is a filter rather than a reordering.\n */\nexport function selectGenerators<T extends { kind: string }>(\n generators: readonly T[],\n kinds: Set<GeneratorKind> | undefined\n): T[] {\n if (!kinds) return [...generators];\n return generators.filter((g) => kinds.has(g.kind as GeneratorKind));\n}\n\n/**\n * Why a selection matched nothing, as a sentence, or `undefined` when it matched something.\n *\n * A `--only` that selects no configured generator is the silent no-op this whole change exists to\n * remove, so it is reported with both halves of the mismatch: what was asked for, and what the\n * config actually names.\n */\nexport function emptySelectionMessage(\n kinds: Set<GeneratorKind> | undefined,\n configured: readonly { kind: string }[],\n flag = '--only'\n): string | undefined {\n if (!kinds || selectGenerators(configured, kinds).length) return undefined;\n const asked = [...kinds].join(', ');\n const names = [...new Set(configured.map((g) => g.kind))];\n return (\n `${flag} ${asked} matched no generator in this config, which names: ` +\n `${names.join(', ') || 'none'}.`\n );\n}\n","/**\n * Whether a run has anything to generate from, and which of the three reasons it has not.\n *\n * Items 70 and 71 are one moment for the user (\"I ran generate and got nothing useful\") and three\n * different causes, and the fixes have nothing in common: fix your import, export your tables,\n * loosen your filter. Measured on the built 4.22.0 CLI, every one of them printed a green tick and\n * exited 0, having written a barrel with no exports in it:\n *\n * | input | exit | wrote |\n * | ------------------------------------------------ | ---- | -------------- |\n * | a schema module that throws on import | 0 | `out/index.ts` |\n * | a schema importing a package that is not there | 0 | `out/index.ts` |\n * | a schema with a syntax error | 0 | `out/index.ts` |\n * | `schema:` naming a file that does not exist | 0 | `out/index.ts` |\n * | a module that exports no tables | 0 | `out/index.ts` |\n * | a module that exports things that are not tables | 0 | `out/index.ts` |\n * | every table removed by `include`/`exclude` | 0 | `out/index.ts` |\n *\n * The distinction is not guessed at here. The analyzer already separates the three answers, which\n * is what `init` was built on in item 67 and what this reuses:\n *\n * - a module it could not run -> `DRZL_ANL_NOFILE` or `DRZL_ANL_IMPORT`, an error-level issue\n * - a module that is not one -> no issues, and `tables` empty\n * - a real schema -> `tables` non-empty\n *\n * Surfacing that rather than re-deriving it is what keeps the two messages honest: the first says\n * DRZL never read your file and repeats the reason, the second says DRZL read it and it declares\n * nothing.\n */\n\n/** DRZL could not read the schema at all: the file is missing, or importing it threw. */\nexport const SCHEMA_UNREADABLE_CODE = 'DRZL_SCHEMA_001';\n/** DRZL read the schema, and it declares no Drizzle tables. */\nexport const SCHEMA_EMPTY_CODE = 'DRZL_SCHEMA_002';\n/** The schema declares tables and the config's own filters removed all of them. */\nexport const SCHEMA_FILTERED_CODE = 'DRZL_SCHEMA_003';\n\nexport interface SchemaProblem {\n /** The stable identifier, which is also what the `--json` failure document carries. */\n code: string;\n /** The failure itself. Printed in red, never suppressed, and named in the document. */\n message: string;\n /** How to fix it. Printed dim under the message, and dropped by `--quiet` like every hint. */\n hint: string;\n}\n\n/**\n * The clause that closes a hint by saying what did not happen because of this.\n *\n * A parameter rather than a constant, because these three problems are not `generate`'s alone any\n * more: `drzl explain` reaches every one of them and has never written a file in its life, so\n * \"Nothing was generated.\" there is a sentence about a thing the command does not do. The default\n * keeps every existing caller's text byte for byte.\n */\nexport const NOTHING_GENERATED = 'Nothing was generated.';\n\n/** The least this file needs to know about an analyzer issue. */\nexport interface AnalyzerIssue {\n code?: string;\n level?: string;\n message?: string;\n}\n\n/** The two analyzer codes that mean \"there is nothing to work with\", as opposed to a description. */\nconst UNREADABLE_CODES = new Set(['DRZL_ANL_NOFILE', 'DRZL_ANL_IMPORT']);\n\n/** The first line of a message. A module resolution failure carries its whole require stack. */\nfunction firstLine(message: string): string {\n return String(message).split('\\n')[0].trim();\n}\n\n/** What to call the schema in a sentence: the path as the config spells it, or the file count. */\nexport function describeSchemaTarget(schema: string | readonly string[]): string {\n if (typeof schema === 'string') return schema;\n if (schema.length === 1) return schema[0];\n return `${schema.length} schema files`;\n}\n\n/**\n * Item 70: the module never loaded, so nothing downstream means anything.\n *\n * The single-path message is built here rather than taken from the analyzer, because the\n * analyzer's is `Failed to import schema: <error>` and deliberately keeps those historical bytes,\n * which do not name the file. Naming the file is the point of the item: a user with four schema\n * modules and one bad import needs to be told which one, and the message that stops saying so is\n * the regression worth a test.\n */\nexport function schemaLoadFailure(\n issues: readonly AnalyzerIssue[],\n schema: string | readonly string[],\n consequence: string = NOTHING_GENERATED\n): SchemaProblem | undefined {\n const blocking = issues.filter(\n (issue) => issue.level === 'error' && issue.code && UNREADABLE_CODES.has(issue.code)\n );\n if (!blocking.length) return undefined;\n\n const first = blocking[0];\n const more = blocking.length > 1 ? ` (and ${blocking.length - 1} more)` : '';\n const single = typeof schema === 'string' ? schema : schema.length === 1 ? schema[0] : undefined;\n\n if (first.code === 'DRZL_ANL_NOFILE') {\n const named = single ?? afterPrefix(first.message, 'Schema file not found:');\n return {\n code: SCHEMA_UNREADABLE_CODE,\n message: `Schema file not found (${SCHEMA_UNREADABLE_CODE}): ${named}${more}`,\n hint:\n 'Check the \"schema\" path in your drzl config, or point --config at another one. ' +\n consequence,\n };\n }\n\n const reason = single\n ? firstLine(afterPrefix(first.message, 'Failed to import schema:'))\n : firstLine(String(first.message ?? ''));\n const message = single\n ? `Could not load the schema module ${single} (${SCHEMA_UNREADABLE_CODE}): ${reason}${more}`\n : `Could not load a schema module (${SCHEMA_UNREADABLE_CODE}): ${reason}${more}`;\n\n return {\n code: SCHEMA_UNREADABLE_CODE,\n message,\n hint: single\n ? `Fix that error and run again. \\`drzl analyze ${single}\\` prints it in full. ${consequence}`\n : `Fix that error and run again. ${consequence}`,\n };\n}\n\n/** A message with a known prefix taken off, or the message unchanged when it has none. */\nfunction afterPrefix(message: string | undefined, prefix: string): string {\n const text = String(message ?? '');\n return text.startsWith(prefix) ? text.slice(prefix.length).trim() : text;\n}\n\n/**\n * Item 71: the module loaded and the run would emit nothing but a barrel.\n *\n * Two codes rather than one, because the schema declaring nothing and the config's filter removing\n * everything are different mistakes in different files. The filtered case names the tables that\n * were really there, which is the fact that turns \"why is my output empty\" into \"my pattern is\n * wrong\", and it is the only place the CLI can say it: the filter has already run by then.\n */\nexport function nothingToGenerate(opts: {\n schema: string | readonly string[];\n /** The tables the analyzer found, before `include`, `exclude` and `columns` were applied. */\n analyzed: readonly { name: string }[];\n /** The tables left for the generators. */\n remaining: readonly { name: string }[];\n /** What did not happen because of this. See `NOTHING_GENERATED`. */\n consequence?: string;\n}): SchemaProblem | undefined {\n if (opts.remaining.length > 0) return undefined;\n const target = describeSchemaTarget(opts.schema);\n const consequence = opts.consequence ?? NOTHING_GENERATED;\n\n if (!opts.analyzed.length) {\n return {\n code: SCHEMA_EMPTY_CODE,\n message: `No Drizzle tables found in ${target} (${SCHEMA_EMPTY_CODE}).`,\n hint:\n 'That module imported cleanly and exported no tables, so every generator would write an ' +\n 'empty barrel. Export them from it, for example: export const users = pgTable(...). ' +\n consequence,\n };\n }\n\n const names = opts.analyzed.map((table) => table.name);\n const shown = names.slice(0, 6).join(', ');\n const rest = names.length > 6 ? `, and ${names.length - 6} more` : '';\n return {\n code: SCHEMA_FILTERED_CODE,\n message:\n `Every table was removed by this config's filters (${SCHEMA_FILTERED_CODE}). ` +\n `${target} declares ${names.length} table${names.length === 1 ? '' : 's'}: ${shown}${rest}.`,\n hint:\n 'Check \"include\" and \"exclude\" in your drzl config. A pattern is matched against the whole ' +\n 'database table name, with * as the only metacharacter. ' +\n consequence,\n };\n}\n","/**\n * Choosing which *columns* DRZL generates for.\n *\n * `include`/`exclude` answers \"which tables\". This answers \"which columns of them\", which the\n * config had no way to say at all. A schema DRZL must read in full still holds columns that should\n * not reach a generated file: a `passwordHash` no client should ever be handed, an internal note\n * column, a `tenantId` the server sets from the session and a request body must not carry. The\n * only previous answer was to edit the emitted file, which the next `drzl generate` overwrites.\n *\n * ## Where this runs\n *\n * On the `Analysis`, once, before any generator is constructed, at the same seam `filterTables`\n * already uses. Not inside `@drzl/analyzer`, which reads a schema module and has no config: `drzl\n * analyze` must keep printing what is really there, and a user asking \"what does DRZL see\" has to\n * get the truth rather than their own config read back to them. And not inside each generator:\n * there are nine of them plus two template packages, each with its own idea of a mode, and the one\n * that forgot would emit a schema silently wider than the config asked for. Narrowing the analysis\n * is also what keeps the validators, the OpenAPI document, the emitted `.meta()` facts and the\n * service layer describing the same columns, since all of them read this one object.\n *\n * ## Why the narrowing is more than `columns`\n *\n * A table states its columns twice: once as `columns`, and again by name in `primaryKey`,\n * `unique`, `indexes`, `foreignKeys` and `checks`. Dropping a column from the first list and\n * leaving the others is not a smaller schema, it is an inconsistent one, and each stale name has a\n * different consequence:\n *\n * - `unique` reaches emitted TypeScript verbatim. `findDuplicate<Table>` declares\n * `columns: [\"email\"]` against the insert row type, so a unique key naming a column that type no\n * longer has is a generated file that does not compile. Narrowed.\n * - `foreignKeys` drives the relation lookup procedures in the tRPC and oRPC generators, both of\n * which already resolve the column against `columns` and skip when it is gone. Narrowed, which\n * changes no output and stops the analysis asserting a key over a column it does not have.\n * - `indexes` is read by nothing today. Narrowed anyway, on the same grounds.\n * - `checks` is deliberately *not* narrowed. Every generator already drops a row check naming a\n * column the mode does not carry, so nothing breaks, and the constraint really does still exist\n * in the database: leaving it lets `meta` keep listing it as unenforced, which is the honest\n * answer. A warning says so.\n * - `primaryKey` cannot be narrowed, because omitting a key column is refused outright. See below.\n */\nimport type { Table } from '@drzl/analyzer';\nimport { parseCheck } from '@drzl/validation-core';\nimport { namedColumns } from './doctor.js';\nimport {\n addressableName,\n ambiguousPatternWarnings,\n displayTableName,\n hasNamedSchemas,\n matchesAny,\n matchesTable,\n} from './patterns.js';\n\n/** What to do with one table's columns. Both are patterns, in the language `patterns.ts` defines. */\nexport interface ColumnRules {\n /** Drop these. Applied after `pick`, so it wins where both name the same column. */\n omit?: string[];\n /** Keep only these. */\n pick?: string[];\n}\n\n/**\n * Keyed by table pattern, matched against the database table name exactly as `include` is, and\n * against the schema-qualified name too: `reporting.users` names one of two same-named tables and\n * `reporting.*` names a whole schema.\n */\nexport type ColumnFilter = Record<string, ColumnRules>;\n\nexport interface ColumnFilterResult {\n tables: Table[];\n /** Printed by the caller. Nothing here stops generation. */\n warnings: string[];\n}\n\n/** Every column name a CHECK talks about, whatever kind of constraint it turned out to be. */\nfunction checkedColumns(expression: string | undefined, name: string | undefined): string[] {\n const parsed = parseCheck(expression, name);\n if (!parsed.ok) return [];\n return [...new Set(namedColumns(parsed).map((n) => n.column))];\n}\n\n/**\n * Narrow every table's columns to what the config asked for.\n *\n * Throws on anything that cannot be honoured, with every such problem in one message: a config is\n * edited once and rerun, and reporting the first of four typos three times is three wasted runs.\n * Returns warnings for what *is* honoured but changes what the output can do.\n *\n * Call this **before** `filterTables`. Both orders produce the same tables, since one narrows\n * columns and the other drops whole tables, but only this order lets a `columns` entry name a\n * table that `exclude` also removes without that reading as a typo.\n */\nexport function filterColumns(tables: Table[], spec: ColumnFilter | undefined): ColumnFilterResult {\n const entries = Object.entries(spec ?? {});\n if (!entries.length) return { tables, warnings: [] };\n\n const errors: string[] = [];\n const warnings: string[] = [];\n // Only where the analysis really has more than one schema. A project with one has no `public.`\n // to write, so offering it as the spelling to copy names something its schema file never says.\n const nameForConfig = hasNamedSchemas(tables) ? addressableName : displayTableName;\n\n /**\n * Every pattern has to name something that exists.\n *\n * This is the loud half, and it is the reason the option is safe to reach for. `omit:\n * ['passwrodHash']` that silently does nothing is not a no-op: it is the leak the option was\n * reached for, wearing the shape of a fix, and nothing downstream can tell the difference\n * between a column that was never there and one that was already dropped.\n *\n * A column pattern is required to match in *at least one* of the tables its entry matched, not\n * in all of them. Requiring all would make a wildcard table key useless, and dropping\n * `deleted_at` from every `app_*` table that has one is the main thing a wildcard key is for.\n */\n for (const [tablePattern, rules] of entries) {\n const matched = tables.filter((t) => matchesTable([tablePattern], t));\n if (!matched.length) {\n errors.push(\n `columns[${JSON.stringify(tablePattern)}] matches no table. ` +\n `The schema declares: ${tables.map(nameForConfig).join(', ') || '(no tables)'}.`\n );\n continue;\n }\n const available = [...new Set(matched.flatMap((t) => t.columns.map((c) => c.name)))];\n for (const which of ['pick', 'omit'] as const) {\n for (const pattern of rules[which] ?? []) {\n if (available.some((name) => matchesAny([pattern], name))) continue;\n errors.push(\n `columns[${JSON.stringify(tablePattern)}].${which} names ${JSON.stringify(pattern)}, ` +\n `which matches no column of ${matched.map(nameForConfig).join(', ')}. ` +\n `Available: ${available.join(', ')}.`\n );\n }\n }\n }\n\n // Said once per pattern, before anything is narrowed, because the consequence is that the rules\n // below run over more tables than the writer had in mind and every one of them is a real table.\n warnings.push(\n ...ambiguousPatternWarnings(\n entries.map(([p]) => p),\n tables,\n 'columns'\n )\n );\n\n const out = tables.map((table) => {\n const mine = entries.filter(([pattern]) => matchesTable([pattern], table));\n if (!mine.length) return table;\n\n // Applied in the order the entries are written, so a reader works down the config the way they\n // read it. Within one entry `pick` narrows and then `omit` removes, which is the same\n // precedence `exclude` already has over `include`: the direction that takes something away\n // wins, because that is the safe direction for the thing this option exists to remove.\n let keep = table.columns;\n for (const [, rules] of mine) {\n if (rules.pick?.length) keep = keep.filter((c) => matchesAny(rules.pick!, c.name));\n if (rules.omit?.length) keep = keep.filter((c) => !matchesAny(rules.omit!, c.name));\n }\n if (keep.length === table.columns.length) return table;\n\n const kept = new Set(keep.map((c) => c.name));\n const dropped = table.columns.filter((c) => !kept.has(c.name));\n\n if (!keep.length) {\n errors.push(\n `columns leaves table \"${displayTableName(table)}\" with no columns at all. An empty schema describes ` +\n `no row, so this is never a narrower API. Exclude the table instead, with the top-level ` +\n `\"exclude\" option.`\n );\n return table;\n }\n\n /**\n * A primary key column is refused rather than narrowed, and it is the one hard no here.\n *\n * The key is what addresses a row, and every generator that addresses one reads it\n * differently, so the consequence of dropping it depends on which generators happen to be\n * configured: the tRPC generator resolves the key against `columns` and silently drops byId,\n * update and delete; the oRPC generator never reads the key at all and keeps emitting\n * procedures typed `{ id: number }`; the service generator falls back to a column literally\n * named `id` and emits `eq(users.id, id)`, which does not compile when the key was called\n * something else; the OpenAPI document drops its `/{id}` paths; and zod's `meta` would publish\n * a primary key whose column the schema no longer describes. One config, five outcomes, none\n * of them announced.\n *\n * Refusing is also the reversible direction. An error can be relaxed to a warning later\n * without breaking a config that works; a warning cannot be tightened into an error without\n * breaking one.\n */\n const lostKey = (table.primaryKey?.columns ?? []).filter((n) => !kept.has(n));\n if (lostKey.length) {\n errors.push(\n `columns drops ${lostKey.map((n) => JSON.stringify(n)).join(', ')} from table ` +\n `\"${displayTableName(table)}\", which is part of its primary key ` +\n `(${table.primaryKey?.columns.join(', ')}). The generated getById, update and delete ` +\n `address rows by that key, so the emitted schemas would describe a row nothing can ` +\n `address. Keep the key, or leave the whole table out with the top-level \"exclude\" option.`\n );\n return table;\n }\n\n /**\n * A NOT NULL column with no default is warned about and then dropped, which is the other half\n * of the same judgement.\n *\n * It really does produce an insert schema that cannot describe a whole row. It is also the\n * multi-tenant pattern: a NOT NULL `tenantId` the server takes from the session is exactly a\n * column a request body must not carry, and refusing it would remove one of the two things\n * this option is for. An insert schema describes a request, not a row, so the narrower\n * statement is true; what is not obvious is who then supplies the rest, and that is what the\n * warning says. If a generated service in `drizzle` mode is handed the narrowed body, its\n * `create` parameter is Drizzle's own `$inferInsert` and the missing column is a compile error\n * in the generated project, which is loud on its own.\n */\n for (const c of dropped) {\n if (c.nullable || c.hasDefault || c.isGenerated || table.readOnly) continue;\n warnings.push(\n `drzl config: the \"columns\" option drops \"${c.name}\" from table \"${displayTableName(table)}\", and the ` +\n `database requires it: NOT NULL with no default. The emitted insert schema therefore ` +\n `describes a payload that is not a complete row, so whatever calls db.insert has to ` +\n `supply \"${c.name}\" itself.`\n );\n }\n\n // A CHECK naming a dropped column stops being enforced by anything DRZL emits. The generators\n // already skip it rather than emitting a comparison against a field that is not there, so this\n // is a warning and not an error, but it is exactly the silent kind of loss `drzl doctor` was\n // written for.\n for (const k of table.checks ?? []) {\n // Only names this filter really took away. A CHECK naming a column the table never had is a\n // different finding with a section of its own in `drzl doctor`, and claiming it here would\n // blame the config for something that was already wrong.\n const lost = checkedColumns(k.expression, k.name).filter(\n (n) => !kept.has(n) && table.columns.some((c) => c.name === n)\n );\n if (!lost.length) continue;\n warnings.push(\n `drzl config: CHECK ${k.name ? `\"${k.name}\"` : '(unnamed)'} on table \"${displayTableName(table)}\" ` +\n `names ${lost.map((n) => JSON.stringify(n)).join(', ')}, which the \"columns\" option ` +\n `drops, so nothing DRZL emits enforces it. Your database still does.`\n );\n }\n\n return {\n ...table,\n columns: keep,\n unique: (table.unique ?? []).filter((k) => k.columns.every((n) => kept.has(n))),\n indexes: (table.indexes ?? []).filter((i) => i.columns.every((n) => kept.has(n))),\n ...(table.foreignKeys\n ? { foreignKeys: table.foreignKeys.filter((f) => f.columns.every((n) => kept.has(n))) }\n : {}),\n };\n });\n\n if (errors.length) {\n throw new Error(\n `drzl config: the \"columns\" option cannot be honoured.\\n` +\n errors.map((e) => ` - ${e}`).join('\\n')\n );\n }\n\n return { tables: out, warnings };\n}\n","/**\n * The report behind `drzl doctor`: what DRZL will not check for you, and why.\n *\n * `drzl analyze` already prints the whole `Analysis` as JSON. This is not that. The analysis is a\n * description of the schema and the reader has to know which fields mean trouble; this is the list\n * of things that will silently not work, each with the sentence that says what to do about it.\n *\n * The point of the command is the *silent* half. A generator that cannot type a column emits a\n * validator accepting any value, and a CHECK the parser declines is simply absent from the output:\n * both produce a file that looks finished. `drzl generate` prints a one-line count for the first\n * and says nothing at all about the second.\n *\n * Two of the sections here read something the analyzer does not know:\n *\n * - **CHECK constraints.** `parseCheck` lives in `@drzl/validation-core` and every validation\n * generator calls it; the analyzer never does. It carries the raw expression through and has no\n * opinion on whether anything can be made of it. So the only way to say \"this constraint is in\n * your schema and nothing DRZL emits enforces it\" is to run the generators' own parser, which is\n * what this file does.\n * - **Primary keys.** The service generator keys `getById`, `update` and `delete` on\n * `table.primaryKey?.columns[0] ?? 'id'`, and the router templates take an `id` input to match.\n * A table with no primary key therefore gets a service referencing a column that may not exist,\n * and a composite key gets one keyed on half of it. The analysis states the key correctly; the\n * consequence is the generator's.\n *\n * Deliberately *not* reported, and each for a measured reason:\n *\n * - A CHECK that DRZL does translate. `age >= 18` folds into `.gte(18)` and `start < end` becomes\n * an object-level refinement; listing them as findings would drown the ones that matter.\n * - `cardinality(col)` landing on a column with no elements to count. Unreachable from a working\n * schema: Postgres has no `cardinality(integer)`, so the DDL is refused before DRZL sees it.\n *\n * `length(col)` and `octet_length(col)` used to be on that list and are not any more, for two\n * reasons that both stopped being true at once. The five validation generators now ask\n * `lengthMeasure` the same question rather than each applying its own guard, so one sentence is\n * true of all of them; and the clause is reachable, because MySQL has `OCTET_LENGTH` and a\n * `varbinary(n)` column whose byte count in JavaScript is not the one the server took. See\n * `check-uncountable`.\n */\nimport type { Analysis, Column, Issue, Table } from '@drzl/analyzer';\nimport { lengthMeasure, parseCheck, type LengthCheck } from '@drzl/validation-core';\nimport { Chalk, type ChalkInstance } from 'chalk';\n\n/**\n * The styling this report uses when the caller does not say.\n *\n * Level 0, so a caller who forgets gets plain text rather than escape sequences in a file. This\n * file used to import chalk's default instance, which decides colour from `process.stdout` alone\n * and ignores `NO_COLOR` entirely, so `drzl doctor` printed the same 32 escapes with the variable\n * set as without it. The decision belongs to `output.ts` and is passed in.\n */\nconst PLAIN: ChalkInstance = new Chalk({ level: 0 });\n\nexport type DoctorFindingKind =\n /** A column whose validator will accept any value. */\n | 'unknown-column'\n /**\n * A CHECK nothing DRZL emits enforces.\n *\n * Usually one the shared parser refused outright. Also a clause it *reads* and no generator can\n * state: `col IS NULL` narrows a column to null alone, which would mean replacing the column's\n * type rather than wrapping it. Reported the same way, because the two are the same fact to the\n * reader: the constraint is in the schema and the generated schemas do not check it.\n */\n | 'check-declined'\n /** A CHECK naming a column the table does not have. */\n | 'check-unknown-column'\n /** A CHECK comparing an array or structured column against a scalar literal. */\n | 'check-not-scalar'\n /**\n * A CHECK counting a column whose count JavaScript cannot take the way the database did.\n *\n * `CHECK (octet_length(bin) <= 8)` on a MySQL `varbinary(8)` is the reachable case: the value\n * arrives as a string produced by a lossy decode, so neither its characters nor their UTF-8\n * re-encoding is the server's byte count, and any predicate written from it would be enforcing a\n * different constraint. Reported rather than silently dropped, for the same reason `IS NULL` is:\n * the parser reading an expression must not be the same event as the report forgetting it.\n */\n | 'check-uncountable'\n /** A table the generators cannot key. */\n | 'no-primary-key'\n /** A table keyed on more columns than the generators use. */\n | 'partial-primary-key'\n /** Anything else the analyzer said, passed through rather than dropped. */\n | 'analyzer';\n\nexport interface DoctorFinding {\n kind: DoctorFindingKind;\n level: 'warn' | 'error';\n /** Table this is about, as the analysis names it. Absent for a finding about the whole schema. */\n table?: string;\n column?: string;\n /** Constraint name, where the finding is about a CHECK. */\n constraint?: string;\n message: string;\n hint?: string;\n}\n\nexport interface DoctorReport {\n /** The schema path as the user spelled it, so the report names the file they asked about. */\n schema: string;\n dialect: string;\n /** True only when there is nothing at all to say. */\n ok: boolean;\n counts: { tables: number; columns: number; checks: number; findings: number };\n findings: DoctorFinding[];\n}\n\n/** Issue codes with a section of their own, so the catch-all does not print them twice. */\nconst HANDLED_CODES = new Set(['DRZL_ANL_UNKNOWN_COLUMN']);\n\n/**\n * Split an issue `path` into its table and column halves.\n *\n * The analyzer writes `table.column` for a column issue and a bare table name otherwise. Table\n * names are JavaScript identifiers, so the last dot is the separator and there is no ambiguity.\n */\nfunction splitPath(path: string | undefined): { table?: string; column?: string } {\n if (!path) return {};\n const dot = path.lastIndexOf('.');\n if (dot <= 0) return { table: path };\n return { table: path.slice(0, dot), column: path.slice(dot + 1) };\n}\n\n/**\n * Every column name a parsed CHECK talks about, paired with the kind of constraint it came from.\n *\n * Exported because the column filter needs the same answer: a constraint stops being enforced when\n * any column it names is dropped, and \"which columns does this name\" has to mean one thing.\n */\nexport function namedColumns(parsed: Extract<ReturnType<typeof parseCheck>, { ok: true }>) {\n const out: Array<{ column: string; scalar: boolean }> = [];\n // A comparison against a literal and an `IN` list are both statements about a scalar value, so\n // neither describes an array or a structured column. The other three kinds are not: a length or\n // a cardinality is a statement about a count, and a row check is a comparison of two columns.\n for (const c of parsed.checks) out.push({ column: c.column, scalar: true });\n for (const s of parsed.sets ?? []) out.push({ column: s.column, scalar: true });\n for (const l of parsed.lengths ?? []) out.push({ column: l.column, scalar: false });\n for (const c of parsed.cardinalities ?? []) out.push({ column: c.column, scalar: false });\n // A null test is the one clause that describes every column shape alike: an array, a json\n // payload and a scalar are each either there or not. So it names its column without claiming\n // the column is scalar, which would report `CHECK (tags IS NOT NULL)` as a mismatch it is not.\n for (const n of parsed.nulls ?? []) out.push({ column: n.column, scalar: false });\n for (const r of parsed.rows ?? []) {\n out.push({ column: r.left, scalar: false });\n out.push({ column: r.right, scalar: false });\n }\n return out;\n}\n\n/**\n * What a column is, for a sentence about a constraint that does not fit it.\n *\n * Every `ColumnShape` kind has an arm, so a shape added later reads as \"a structured column\" rather\n * than as a wrong noun. `arrayDimensions` is checked first because an array carries its element's\n * shape and it is the array the constraint failed to describe.\n */\nfunction describeShape(c: Column): string {\n if (c.arrayDimensions) return 'an array';\n switch (c.shape?.kind) {\n case 'json':\n return 'a JSON';\n case 'buffer':\n return 'a binary';\n case 'tuple':\n case 'numberObject':\n return 'a structured';\n case 'numberVector':\n return 'a vector';\n case 'bitstring':\n return 'a bit-string';\n case 'byteString':\n return 'a byte-string';\n case 'custom':\n return 'a customType';\n default:\n return 'a structured';\n }\n}\n\n/** What the clause asked to be counted, in the words the expression used. */\nconst countNoun = (l: LengthCheck) => (l.unit === 'bytes' ? 'byte count' : 'character count');\n\n/**\n * What to do about a count nothing can take, or the generic sentence.\n *\n * Only the byte-string column has an answer, and it is the only one reachable from a schema a\n * database accepted, so the rest get the generic form rather than invented advice.\n */\nfunction countHint(c: Column): string {\n if (c.shape?.kind === 'byteString')\n return (\n 'A binary(n)/varbinary(n) column hands the caller a string produced by a lossy decode, so ' +\n 'its width is code points coming out and bytes going in and neither is a count of the ' +\n 'value in hand. The column already caps itself at n bytes; a second bound stated here ' +\n 'would be a different measurement. Leave this one to the database.'\n );\n return (\n 'Only constraints whose meaning is unambiguous are translated, because a validator ' +\n 'enforcing a guess rejects rows the database accepts. Your database still enforces ' +\n 'this one; nothing DRZL emits does.'\n );\n}\n\n/**\n * The generic advice for a declined CHECK, or something the reader can act on.\n *\n * The generic sentence is true of every refusal and therefore says nothing about any of them. Two\n * of the refusals have a fix, and a reader who has just been told their constraint is not enforced\n * has earned being told what to do instead of being told the rule again.\n *\n * Matched on the parser's own reason rather than on a code, because the reason is what the parser\n * already returns and a second vocabulary beside it is a second thing to keep in step. The default\n * is the generic sentence, so a reason added later is worded generically rather than wrongly.\n */\nfunction declineHint(reason: string): string {\n if (/combined with/.test(reason))\n return (\n 'Postgres computes numeric arithmetic exactly and JavaScript computes it in binary ' +\n 'floating point, so `x + y <= 0.3` accepts (0.1, 0.2) in the database and rejects it in ' +\n 'JavaScript. The right translation depends on whether the columns are numeric, double ' +\n 'precision or bigint, and the expression does not say. Put the result in a generated ' +\n 'column and constrain that, or leave this one to the database.'\n );\n if (/\\bOR\\b/.test(reason))\n return (\n 'A disjunction is read only where the whole of it pins one column to a set of values, ' +\n \"such as `status = 'a' OR status = 'b'`, which becomes the same enum an IN list does. \" +\n 'Anything else is refused whole rather than in part: a row satisfying the other branch is ' +\n 'one the database accepts, and enforcing one branch would turn it away.'\n );\n return (\n 'Only constraints whose meaning is unambiguous are translated, because a validator ' +\n 'enforcing a guess rejects rows the database accepts. Your database still enforces ' +\n 'this one; nothing DRZL emits does.'\n );\n}\n\nfunction checkFindings(table: Table): DoctorFinding[] {\n const out: DoctorFinding[] = [];\n const byName = new Map(table.columns.map((c) => [c.name, c]));\n for (const k of table.checks ?? []) {\n const label = k.name ? `\"${k.name}\"` : 'an unnamed constraint';\n const raw = k.expression ?? '';\n // A constraint whose expression the analyzer could not render at all is the one case where\n // printing the expression verbatim says nothing, and a line ending in \"Expression:\" reads\n // like the report itself is broken.\n const expr = raw.trim() ? raw : '(empty)';\n const parsed = parseCheck(raw, k.name, table.dialect);\n if (!parsed.ok) {\n out.push({\n kind: 'check-declined',\n level: 'warn',\n table: table.tsName,\n constraint: k.name,\n message: `CHECK ${label} on \"${table.tsName}\" is not translated: ${parsed.reason}. Expression: ${expr}`,\n hint: declineHint(parsed.reason),\n });\n continue;\n }\n\n // A clause that parsed and that nothing enforces. `col IS NULL` is the only one: narrowing a\n // field to null *alone* would mean replacing the column's type rather than wrapping it, and no\n // generator has a hook for that. Reported here rather than left silent, because the parser\n // learning to read an expression must not be the same event as the doctor forgetting it: the\n // constraint went from \"declined, here is why\" to absent from the report entirely.\n for (const n of parsed.nulls ?? []) {\n if (n.notNull) continue;\n out.push({\n kind: 'check-declined',\n level: 'warn',\n table: table.tsName,\n constraint: k.name,\n message:\n `CHECK ${label} on \"${table.tsName}\" holds \"${n.column} IS NULL\", which narrows the ` +\n `column to NULL alone and no generated schema states. Expression: ${expr}`,\n hint:\n 'A column that may only ever be NULL is usually a constraint written the wrong way ' +\n 'round. Drop the column, or state the rule as a CHECK on the column that decides it.',\n });\n }\n\n // A count clause the emitted schemas drop. Per clause rather than per column, because the\n // sentence names the function that was written and `length` and `octet_length` can both be on\n // one column at once.\n for (const l of parsed.lengths ?? []) {\n const col = byName.get(l.column);\n if (!col || lengthMeasure(col, l)) continue;\n out.push({\n kind: 'check-uncountable',\n level: 'warn',\n table: table.tsName,\n column: l.column,\n constraint: k.name,\n message:\n `CHECK ${label} on \"${table.tsName}\" counts ${describeShape(col)} column ` +\n `\"${l.column}\", whose ${countNoun(l)} in JavaScript is not the one the database took, ` +\n `so it is not translated. Expression: ${expr}`,\n hint: countHint(col),\n });\n }\n\n // Reported once per column rather than once per clause, so `a >= 1 AND a <= 9` on a missing\n // column is one line and not two.\n const seen = new Set<string>();\n for (const { column, scalar } of namedColumns(parsed)) {\n if (seen.has(column)) continue;\n seen.add(column);\n const col = byName.get(column);\n if (!col) {\n out.push({\n kind: 'check-unknown-column',\n level: 'warn',\n table: table.tsName,\n column,\n constraint: k.name,\n message: `CHECK ${label} on \"${table.tsName}\" names \"${column}\", which is not a column of that table, so nothing enforces it. Expression: ${expr}`,\n hint:\n 'A constraint is attached to the field it names. Check the spelling, or move a ' +\n 'constraint spanning two tables out of the schema.',\n });\n continue;\n }\n if (scalar && (col.arrayDimensions || col.shape)) {\n out.push({\n kind: 'check-not-scalar',\n level: 'warn',\n table: table.tsName,\n column,\n constraint: k.name,\n message: `CHECK ${label} on \"${table.tsName}\" compares ${describeShape(col)} column \"${column}\" against a scalar literal, which does not describe it, so it is not translated. Expression: ${expr}`,\n hint:\n 'On an array column only cardinality(col) is read, since it is the one comparison ' +\n 'that is about the array rather than about an element.',\n });\n }\n }\n }\n return out;\n}\n\nfunction primaryKeyFindings(table: Table): DoctorFinding[] {\n // A read-only relation takes no writes and gets no keyed route, so it needs no key.\n if (table.readOnly) return [];\n const pk = table.primaryKey?.columns ?? [];\n if (!pk.length) {\n const hasId = table.columns.some((c) => c.name === 'id');\n return [\n {\n kind: 'no-primary-key',\n level: 'warn',\n table: table.tsName,\n message: hasId\n ? `Table \"${table.tsName}\" declares no primary key. The service and router generators fall back to a column named \"id\", which this table happens to have, so they work by coincidence.`\n : `Table \"${table.tsName}\" declares no primary key. The service and router generators fall back to a column named \"id\", which this table does not have, so the generated service will not compile.`,\n hint: 'Declare a primary key, or leave this table out with the config table filter.',\n },\n ];\n }\n if (pk.length > 1) {\n return [\n {\n kind: 'partial-primary-key',\n level: 'warn',\n table: table.tsName,\n message: `Table \"${table.tsName}\" has a composite primary key (${pk.join(', ')}). The service and router generators key getById, update and delete on \"${pk[0]}\" alone, so those operations match on part of the key.`,\n hint: 'Treat the generated service as a starting point for this table and widen the key by hand.',\n },\n ];\n }\n return [];\n}\n\n/**\n * Everything worth saying about one analysis, in the order it should be read.\n *\n * Ordered worst-first, and within that silent-first. A schema that could not be analyzed comes\n * first because nothing after it is trustworthy. Untypeable columns and dropped constraints come\n * next because they are invisible: the generated file exists, compiles and validates nothing. The\n * primary-key findings come after because one half of that pair announces itself as a compile\n * error. The catch-all is last.\n */\nexport function buildDoctorReport(analysis: Analysis, schemaPath: string): DoctorReport {\n const findings: DoctorFinding[] = [];\n\n const errors = analysis.issues.filter((i: Issue) => i.level === 'error');\n for (const i of errors) {\n findings.push({\n kind: 'analyzer',\n level: 'error',\n ...splitPath(i.path),\n message: i.message,\n hint: i.hint,\n });\n }\n\n for (const i of analysis.issues) {\n if (i.code !== 'DRZL_ANL_UNKNOWN_COLUMN') continue;\n findings.push({\n kind: 'unknown-column',\n level: 'warn',\n ...splitPath(i.path),\n message: i.message,\n hint: i.hint,\n });\n }\n\n for (const t of analysis.tables) findings.push(...checkFindings(t));\n for (const t of analysis.tables) findings.push(...primaryKeyFindings(t));\n\n for (const i of analysis.issues) {\n if (i.level === 'error' || HANDLED_CODES.has(i.code)) continue;\n findings.push({\n kind: 'analyzer',\n level: 'warn',\n ...splitPath(i.path),\n message: i.message,\n hint: i.hint,\n });\n }\n\n const columns = analysis.tables.reduce((n, t) => n + t.columns.length, 0);\n const checks = analysis.tables.reduce((n, t) => n + (t.checks?.length ?? 0), 0);\n return {\n schema: schemaPath,\n dialect: analysis.dialect,\n ok: findings.length === 0,\n counts: { tables: analysis.tables.length, columns, checks, findings: findings.length },\n findings,\n };\n}\n\n/** Sections, in report order, each with the sentence that says why its contents matter. */\nconst SECTIONS: Array<{ kinds: DoctorFindingKind[]; title: string; why: string }> = [\n {\n kinds: ['unknown-column'],\n title: 'Columns DRZL cannot type',\n why: 'These get a validator that accepts any value.',\n },\n {\n kinds: ['check-declined', 'check-unknown-column', 'check-not-scalar', 'check-uncountable'],\n title: 'CHECK constraints DRZL does not enforce',\n why: 'Your database still enforces these. Nothing DRZL generates does.',\n },\n {\n kinds: ['no-primary-key', 'partial-primary-key'],\n title: 'Primary keys the generators cannot use',\n why: 'The generated getById, update and delete are keyed on one column.',\n },\n {\n kinds: ['analyzer'],\n title: 'Other findings',\n why: 'Reported by the analyzer while reading the schema.',\n },\n];\n\n/**\n * Wrap a sentence under a fixed indent, so it does not run off a narrow terminal.\n *\n * `first` is the prefix the opening line carries instead of the indent, which is what gives a\n * finding its bullet and its continuation lines a hanging indent under the text rather than under\n * the bullet.\n */\nfunction wrap(text: string, indent: string, first = indent, width = 96): string {\n const lines: string[] = [];\n let line = '';\n for (const word of text.split(/\\s+/)) {\n if (line && `${line} ${word}`.length + indent.length > width) {\n lines.push(line);\n line = word;\n } else {\n line = line ? `${line} ${word}` : word;\n }\n }\n if (line) lines.push(line);\n return lines.map((l, i) => (i === 0 ? first : indent) + l).join('\\n');\n}\n\n/**\n * The human-readable report.\n *\n * A clean schema prints what was looked at rather than nothing, because an empty page cannot be\n * told apart from a command that failed to run.\n */\nexport function renderDoctorReport(report: DoctorReport, style: ChalkInstance = PLAIN): string {\n const chalk = style;\n const out: string[] = [];\n const plural = (n: number, one: string) => `${n} ${one}${n === 1 ? '' : 's'}`;\n\n out.push(chalk.bold(`DRZL doctor ${report.schema}`));\n out.push(\n chalk.dim(\n `${report.dialect}, ${plural(report.counts.tables, 'table')}, ` +\n `${plural(report.counts.columns, 'column')}, ${plural(report.counts.checks, 'CHECK constraint')}`\n )\n );\n out.push('');\n\n if (report.ok) {\n out.push(chalk.green('Nothing to report.'));\n out.push(chalk.dim(' Every column has a type DRZL can describe.'));\n out.push(chalk.dim(' Every CHECK constraint is translated into the generated validators.'));\n out.push(chalk.dim(' Every table has a primary key the generators can use.'));\n return out.join('\\n');\n }\n\n // Ahead of the sections rather than inside one. An error means the schema was never read, so\n // every count above is zero and every section below is empty, and printing that under \"Other\n // findings\" at the foot of the page buries the only sentence that matters.\n const fatal = report.findings.filter((f) => f.level === 'error');\n if (fatal.length) {\n out.push(chalk.red('DRZL could not read this schema'));\n out.push(chalk.dim(' Nothing else could be checked.'));\n out.push('');\n for (const f of fatal) {\n out.push(wrap(f.message, ' ', ` ${chalk.dim('-')} `));\n if (f.hint) out.push(chalk.dim(wrap(f.hint, ' ')));\n }\n out.push('');\n }\n\n for (const section of SECTIONS) {\n const mine = report.findings.filter(\n (f) => f.level !== 'error' && section.kinds.includes(f.kind)\n );\n if (!mine.length) continue;\n out.push(chalk.yellow(`${section.title} (${mine.length})`));\n out.push(chalk.dim(` ${section.why}`));\n out.push('');\n // One hint per distinct sentence, under the findings that share it: the same advice repeated\n // under twenty columns is the thing that makes a report unreadable.\n const groups = new Map<string, DoctorFinding[]>();\n for (const f of mine) {\n const key = f.hint ?? '';\n groups.set(key, [...(groups.get(key) ?? []), f]);\n }\n for (const [hint, items] of groups) {\n for (const f of items) out.push(wrap(f.message, ' ', ` ${chalk.dim('-')} `));\n if (hint) out.push(chalk.dim(wrap(hint, ' ')));\n out.push('');\n }\n }\n\n out.push(\n chalk.bold(`${plural(report.counts.findings, 'finding')} in ${report.schema}.`) +\n chalk.dim(\n fatal.length\n ? ' Fix the error above and run this again.'\n : ' None of these stop DRZL generating; they are what it will not check for you.'\n )\n );\n return out.join('\\n');\n}\n","/**\n * `drzl explain <table>`: what DRZL understood about one table, and what it did not.\n *\n * The command exists for one moment: a generated schema is wrong, and the reader has no way to\n * tell whether the analyzer misread the column, dropped the CHECK, failed to follow the relation,\n * or read all three correctly and the generator is at fault. Today that question is answered by\n * reading `drzl analyze --json` output, which is the whole analysis of the whole schema with\n * nothing pointed out, or by reading the emitted validator and inferring backwards.\n *\n * Three sources are read, and none of them is re-derived here:\n *\n * - **The analyzer**, for the table itself: the resolved `tsType`, the declared `sqlType`,\n * nullability, defaults, keys, foreign keys, enum members and every measured fact\n * (`min`/`max`/`integer`/`allowsNaN`/`allowsInfinity`/`format`/`maxLength`/`maxBytes`).\n * - **`tableConstraints` from `@drzl/validation-core`**, for whether a generated schema actually\n * checks each constraint. That function is what the emitted constraint ledger is built from, so\n * `explain` and the generated modules cannot disagree about what is enforced. It is also where\n * a CHECK's classification lives: a clause the shared parser declined comes back as an\n * `unenforced` entry with the parser's own reason, which is the sentence this command exists to\n * surface.\n * - **The analysis's own `issues`**, filtered to this table, for a column type nobody has modelled\n * and a relation the analyzer could not follow.\n *\n * The two questions it deliberately answers together are \"what is here\" and \"what is silently not\n * here\". A column DRZL cannot type still emits a validator, a CHECK the parser declines is simply\n * absent from the output, and a `varchar(255)` on an enum column never reaches the schema as a\n * width. All three produce a file that looks finished, and all three are named here.\n *\n * It writes nothing. `--dry-run` has no meaning for a command that has never had a write path.\n */\nimport type { Analysis, Column, Issue, Relation, Table } from '@drzl/analyzer';\nimport { qualifiedForeignTable, qualifiedTableName } from '@drzl/analyzer';\nimport { tableConstraints, type ConstraintFacts } from '@drzl/validation-core';\nimport { Chalk, type ChalkInstance } from 'chalk';\nimport { nearestKey } from './config-errors.js';\nimport { addressableName, displayTableName, tableAliases } from './patterns.js';\n\n/**\n * The styling used when a caller does not pass one.\n *\n * Level 0, so a caller who forgets gets plain text rather than escape sequences in a file. The\n * decision belongs to `output.ts`, which asks it per stream; see the same constant in `doctor.ts`.\n */\nconst PLAIN: ChalkInstance = new Chalk({ level: 0 });\n\n/* ------------------------------------------------------------------------------------------ */\n/* Finding the table */\n/* ------------------------------------------------------------------------------------------ */\n\n/** Which of a table's three names the query matched. */\nexport type MatchedOn =\n /** The bare database name, `users`. */\n | 'name'\n /** The qualified database name, `reporting.users`, or `public.users` for the default schema. */\n | 'qualified'\n /** The TypeScript export name, which is not always the database name. */\n | 'tsName';\n\nexport interface TableHit {\n table: Table;\n matchedOn: MatchedOn;\n}\n\nexport type TableMatch =\n | ({ kind: 'found'; exact: boolean } & TableHit)\n /** Two or more tables answer to that name. Never resolved silently; see `matchTable`. */\n | { kind: 'ambiguous'; exact: boolean; hits: TableHit[] }\n | { kind: 'none'; suggestion?: string };\n\n/**\n * Every name one table answers to, most specific first.\n *\n * `tableAliases` supplies the two database spellings, so `explain` and the config's `include`\n * and `exclude` agree about what `public.users` means without either restating it. The export\n * name is the third, because a reader looking at their own schema file knows\n * `export const orgMembers` and may never have seen the string `organisation_members`.\n *\n * Order is the order a hit is reported in, and the qualified name is first: a table in a named\n * SQL schema is identified by that spelling and by no other, so a query that used it should be\n * reported as having used it.\n */\nfunction namesOf(table: Table): Record<MatchedOn, string> {\n const [bare, qualified] = tableAliases(table);\n return { qualified, name: bare, tsName: table.tsName };\n}\n\nconst MATCH_ORDER: MatchedOn[] = ['qualified', 'name', 'tsName'];\n\n/** What each of the three names is called in a sentence. */\nconst MATCH_LABELS: Record<MatchedOn, string> = {\n qualified: 'the schema-qualified name',\n name: 'the database name',\n tsName: 'the export name',\n};\n\n/** Every table whose names contain `query`, under the given case folding, one hit per table. */\nfunction hitsFor(tables: readonly Table[], query: string, fold: (s: string) => string): TableHit[] {\n const wanted = fold(query);\n const hits: TableHit[] = [];\n for (const table of tables) {\n const names = namesOf(table);\n const matchedOn = MATCH_ORDER.find((key) => fold(names[key]) === wanted);\n if (matchedOn) hits.push({ table, matchedOn });\n }\n return hits;\n}\n\nconst same = (s: string) => s;\nconst folded = (s: string) => s.toLowerCase();\n\n/**\n * The table a query names, or why it names none.\n *\n * Exact before case-insensitive, and both over all three names at once. The two rounds are\n * separate passes rather than one pass with a fallback comparison, because a schema holding both\n * `users` and `Users` has an exact answer for each, and a single case-insensitive pass would call\n * both of them ambiguous.\n *\n * Ambiguity is reported rather than resolved. It is reachable from an ordinary schema: two\n * `pgSchema` tables share one bare name, and a table's export name can be another table's\n * database name. Picking the first would answer a question about one table with facts about a\n * different one, which is the single worst thing a command whose whole job is diagnosis can do.\n *\n * An ambiguous exact round stops there rather than falling through to the case-insensitive one.\n * Loosening the comparison can only add hits, so the second round cannot resolve what the first\n * could not.\n */\nexport function matchTable(tables: readonly Table[], query: string): TableMatch {\n for (const [exact, fold] of [\n [true, same],\n [false, folded],\n ] as const) {\n const hits = hitsFor(tables, query, fold);\n if (hits.length === 1) return { kind: 'found', exact, ...hits[0] };\n if (hits.length > 1) return { kind: 'ambiguous', exact, hits };\n }\n // Only ever reached when nothing matched under either folding, so the suggestion is about a\n // misspelling rather than about a case difference, which the second round has already forgiven.\n const known = tables.flatMap((t) => {\n const names = namesOf(t);\n return t.tsName === names.name ? [names.name] : [names.name, names.tsName];\n });\n return { kind: 'none', suggestion: nearestKey(query, known) };\n}\n\n/* ------------------------------------------------------------------------------------------ */\n/* The explanation */\n/* ------------------------------------------------------------------------------------------ */\n\n/** How a column's default arrives, which decides whether any generated schema can state it. */\nexport type ExplainDefault =\n /** `.default('GB')`: a literal a schema can reproduce. */\n | { kind: 'literal'; value: unknown }\n /** A `sql` default the analyzer rendered back to text. */\n | { kind: 'expression'; text: string }\n /**\n * `defaultNow()`, `defaultRandom()`, `$defaultFn` and a `serial`'s sequence: the value exists\n * only at insert time, so the field is optional on insert and no schema states what it becomes.\n */\n | { kind: 'runtime' };\n\n/**\n * One measured fact about a column, and whether any generated schema says it.\n *\n * `stated` is not decided here. A width, a byte cap and a set of members are each read by every\n * validation generator through the same guards `tableConstraints` applies, so the verdict comes\n * off that function's output rather than from a second copy of the rule; see `capStated`.\n */\nexport interface ExplainFact {\n text: string;\n stated: boolean;\n /** Why nothing states it, when nothing does. */\n reason?: string;\n}\n\nexport interface ExplainColumn {\n name: string;\n tsType: string;\n /** The coarse family label, `TEXT` for every one of varchar, char and text. */\n dbType: string;\n /** The type as the database declares it, `varchar(255)`, absent where Drizzle would not say. */\n sqlType?: string;\n nullable: boolean;\n hasDefault: boolean;\n default: ExplainDefault | null;\n isGenerated: boolean;\n inPrimaryKey: boolean;\n /** Named by a single-column UNIQUE constraint. A composite one is in `unique` instead. */\n unique: boolean;\n references?: {\n table: string;\n schema?: string;\n column: string;\n onDelete?: string;\n onUpdate?: string;\n };\n enumValues?: string[];\n arrayDimensions?: number;\n shape?: Column['shape'];\n facts: ExplainFact[];\n}\n\n/** A relation with this table at one end, in the direction the analysis recorded it. */\nexport interface ExplainRelation extends Relation {\n /** Whether this table is the `from` end. */\n outgoing: boolean;\n}\n\n/**\n * Something in this table that DRZL read and could not use.\n *\n * The section the command exists for. Every entry here is a place where the generated output is\n * quietly narrower than the schema, and none of them is visible in the generated files.\n */\nexport interface ExplainGap {\n kind:\n /** A CHECK, or one clause of one, that no generated schema enforces. */\n | 'check'\n /** A column whose validator will accept any value. */\n | 'column'\n /** A relation the analyzer could not follow. */\n | 'relation'\n /** Anything else the analyzer said about this table. */\n | 'analyzer';\n /** The column or constraint it is about, where it is about one. */\n subject?: string;\n message: string;\n hint?: string;\n}\n\nexport interface TableExplanation {\n /** The database table name, which is not always the export name. */\n name: string;\n /** The TypeScript export name. */\n tsName: string;\n /** The SQL schema, present only where the table declares one. */\n schema?: string;\n /** `reporting.users`, or the bare `users` for a table in the default schema. */\n qualified: string;\n /** `public.users`: the one spelling that addresses this table and no other. */\n addressable: string;\n /** Set for a materialized view, which takes no writes, so no insert or update schema is emitted. */\n readOnly: boolean;\n /** Which name the query matched, and whether it matched without case folding. */\n matchedOn: MatchedOn;\n matchedExactly: boolean;\n /** True when this config's `include`/`exclude` removes the table, so no generator sees it. */\n excludedByConfig?: boolean;\n /** Columns this config's `columns` filter removes, in declaration order. */\n columnsRemovedByConfig?: string[];\n columns: ExplainColumn[];\n primaryKey: { name?: string; columns: string[]; generated: boolean } | null;\n unique: { name?: string; columns: string[] }[];\n indexes: { name?: string; columns: string[] }[];\n foreignKeys: {\n name?: string;\n columns: string[];\n references: { table: string; columns: string[] };\n onDelete?: string;\n onUpdate?: string;\n }[];\n relations: ExplainRelation[];\n /**\n * Every constraint on the table with the verdict a generated schema gives it, verbatim from\n * `tableConstraints`. The primary key, every UNIQUE, every foreign key, every CHECK and the\n * declared widths, each with `enforced` and, where it is false, the reason per clause.\n */\n constraints: ConstraintFacts[];\n /** What DRZL read and could not use. Empty when the whole table was understood. */\n gaps: ExplainGap[];\n}\n\n/** One line of the index a bare `drzl explain` prints. */\nexport interface TableSummary {\n name: string;\n tsName: string;\n schema?: string;\n qualified: string;\n columns: number;\n checks: number;\n /** How many entries `drzl explain <this table>` would list under \"Not understood\". */\n gaps: number;\n}\n\n/** The literal a `.default()` stored, as it would read in a schema file. */\nfunction renderLiteral(value: unknown): string {\n if (typeof value === 'string') return `'${value.replace(/'/g, \"\\\\'\")}'`;\n if (value === null) return 'null';\n if (typeof value === 'bigint') return `${value}n`;\n if (value instanceof Date) return value.toISOString();\n if (typeof value === 'object') return JSON.stringify(value);\n return String(value);\n}\n\n/** How a column's default arrives, or nothing where it has none. */\nfunction defaultOf(column: Column): ExplainDefault | null {\n if (column.defaultValue !== undefined) return { kind: 'literal', value: column.defaultValue };\n if (column.defaultExpression) return { kind: 'expression', text: column.defaultExpression };\n return column.hasDefault ? { kind: 'runtime' } : null;\n}\n\n/** A default in one cell of the column table. */\nfunction describeDefault(value: ExplainDefault | null): string {\n if (!value) return '';\n if (value.kind === 'literal') return `default ${renderLiteral(value.value)}`;\n if (value.kind === 'expression') return `default ${value.text}`;\n return 'has default';\n}\n\n/** What a `ColumnShape` is, in a sentence. Every kind has an arm, so a new one cannot go unnamed. */\nfunction describeShape(shape: NonNullable<Column['shape']>): string {\n switch (shape.kind) {\n case 'buffer':\n return 'binary payload, carried as a Uint8Array';\n case 'json':\n return 'any JSON value, checked recursively';\n case 'tuple':\n return `tuple of ${shape.length} numbers`;\n case 'numberObject':\n return `object of numbers: ${shape.fields.join(', ')}`;\n case 'numberVector':\n return shape.length ? `numeric vector of ${shape.length}` : 'numeric vector';\n case 'custom':\n return shape.sqlType\n ? `customType, declared ${shape.sqlType}, with no runtime shape to read`\n : 'customType, with no runtime shape to read';\n case 'bitstring':\n if (shape.length === undefined) return 'string of 0 and 1';\n return shape.exact\n ? `string of ${shape.length} digits, each 0 or 1`\n : `string of at most ${shape.length} digits, each 0 or 1`;\n case 'byteString':\n return shape.length ? `bytes, declared width ${shape.length}` : 'bytes';\n }\n}\n\n/**\n * Why a declared width never reaches the emitted schema.\n *\n * The branches of `statesCap` in `@drzl/validation-core`, in its order, so the sentence names the\n * same reason the guard acted on. Whether it is stated is not decided here; that comes off\n * `tableConstraints`, which calls the real guard. This only puts the reason into words, and the\n * last arm is a generic sentence rather than a guess, so a branch added there is worded vaguely\n * instead of wrongly.\n */\nfunction capReason(column: Column, narrowedBySet: boolean): string {\n if (column.shape)\n return `\"${column.name}\" is a structured column, whose value space is not stated as a width`;\n if (narrowedBySet)\n return `a CHECK narrows \"${column.name}\" to a set of literals, which states its value space instead`;\n if (column.enumValues?.length)\n return `\"${column.name}\" is an enum, and its members state its value space instead`;\n if (column.tsType !== 'string')\n return `\"${column.name}\" does not arrive as a string, so there is nothing to measure`;\n if (column.format)\n return `the ${column.format} format replaces the width on \"${column.name}\" rather than adding to it`;\n return `the generated schemas state \"${column.name}\" some other way`;\n}\n\n/**\n * Everything measured about a column that a validator can act on, with the verdict beside it.\n *\n * The order is the order it reads: what the value is, then how wide, then what it may hold.\n */\nfunction factsFor(\n column: Column,\n opts: { capStated: boolean; narrowedBySet: boolean }\n): ExplainFact[] {\n const facts: ExplainFact[] = [];\n const state = (text: string) => facts.push({ text, stated: true });\n\n if (column.arrayDimensions) {\n state(\n column.arrayDimensions === 1\n ? 'an array of the type above'\n : `an array of ${column.arrayDimensions} dimensions`\n );\n }\n if (column.shape) state(describeShape(column.shape));\n if (column.enumValues?.length) {\n state(`one of ${column.enumValues.map((v) => `'${v}'`).join(', ')}`);\n }\n if (column.format) state(`text in the ${column.format} format the database parses`);\n\n if (column.min !== undefined && column.max !== undefined) {\n state(`${column.min} to ${column.max}`);\n } else if (column.min !== undefined) state(`at least ${column.min}`);\n else if (column.max !== undefined) state(`at most ${column.max}`);\n if (column.integer === true) state('whole numbers only');\n if (column.integer === false) state('fractions allowed');\n\n // A range cannot say either of these: `>=`/`<=` refuses an infinity whatever the two numbers\n // are, and NaN compares false against both ends, so a bounded float column described by its\n // range alone refuses values the database stores and hands back. The generators render them\n // beside the range rather than as a wider one, which is why both are worth printing.\n if (column.allowsNaN !== undefined) {\n state(column.allowsNaN ? 'NaN is stored and returned' : 'NaN is refused');\n }\n if (column.allowsInfinity !== undefined) {\n state(column.allowsInfinity ? 'Infinity is stored and returned' : 'Infinity is refused');\n }\n\n for (const [value, text] of [\n [column.maxLength, `at most ${column.maxLength} characters`],\n [column.maxBytes, `at most ${column.maxBytes} bytes`],\n ] as const) {\n if (value === undefined) continue;\n facts.push(\n opts.capStated\n ? { text, stated: true }\n : { text, stated: false, reason: capReason(column, opts.narrowedBySet) }\n );\n }\n\n const value = defaultOf(column);\n if (value?.kind === 'literal') state(`defaults to ${renderLiteral(value.value)}`);\n else if (value?.kind === 'expression') state(`defaults to ${value.text}, evaluated by the database`);\n else if (value?.kind === 'runtime') {\n facts.push({\n text: 'has a default',\n stated: false,\n reason:\n 'the value is produced at insert time, by the database or by a Drizzle function, so the ' +\n 'field is optional on insert and no schema states what it becomes',\n });\n }\n if (column.isGenerated) {\n state('generated by the database, so it is left out of insert and update schemas');\n }\n return facts;\n}\n\n/**\n * Whether an analyzer issue is about this table.\n *\n * Matched against all three names, because the analyzer does not use one consistently and could\n * not: a column warning is keyed on the export name, a relation warning on the qualified database\n * name, and the extra-config warning on the table name. An issue about the schema as a whole\n * carries no `path` at all and is not about any table, so it never lands here.\n */\nfunction issueTouches(issue: Issue, table: Table): boolean {\n if (!issue.path) return false;\n const names = namesOf(table);\n const own = [names.qualified, names.name, names.tsName, table.name];\n if (own.includes(issue.path)) return true;\n const dot = issue.path.lastIndexOf('.');\n return dot > 0 && own.includes(issue.path.slice(0, dot));\n}\n\n/** The column half of a `table.column` issue path, when it has one. */\nfunction issueColumn(issue: Issue, table: Table): string | undefined {\n const path = issue.path ?? '';\n const names = namesOf(table);\n for (const prefix of [names.qualified, names.tsName, names.name, table.name]) {\n if (path.startsWith(`${prefix}.`)) {\n const rest = path.slice(prefix.length + 1);\n if (table.columns.some((c) => c.name === rest)) return rest;\n }\n }\n return undefined;\n}\n\n/** Which analyzer codes are about a relation rather than about the table's own shape. */\nconst RELATION_CODES = new Set(['DRZL_ANL_RELATIONS', 'DRZL_ANL_REL_V2']);\n\n/**\n * Everything DRZL read and could not use, in the order it costs a reader most to not know.\n *\n * Constraints first, because a declined CHECK is the case where the generated file exists,\n * compiles, validates, and enforces less than the database does with nothing anywhere saying so.\n */\nfunction gapsFor(table: Table, constraints: ConstraintFacts[], issues: readonly Issue[]) {\n const gaps: ExplainGap[] = [];\n\n for (const constraint of constraints) {\n for (const part of constraint.unenforced ?? []) {\n gaps.push({\n kind: 'check',\n subject: constraint.name ?? constraint.id,\n // `part.part` already carries the constraint name where the declaration had one, because\n // that is the text an emitted schema would have attached. The renderer prefixes `subject`\n // only when it is not already there, so a named CHECK is not announced twice.\n message: `${part.part} is not enforced: ${part.reason}.`,\n hint: 'Your database still enforces it. Nothing DRZL generates does.',\n });\n }\n }\n\n for (const issue of issues) {\n if (issue.level === 'info') continue;\n if (!issueTouches(issue, table)) continue;\n const subject = issueColumn(issue, table);\n gaps.push({\n kind: RELATION_CODES.has(issue.code) ? 'relation' : subject ? 'column' : 'analyzer',\n ...(subject ? { subject } : {}),\n message: issue.message,\n ...(issue.hint ? { hint: issue.hint } : {}),\n });\n }\n return gaps;\n}\n\nexport interface ExplainOptions {\n /** Table names this config's `include`/`exclude` leaves in place, when a config was read. */\n keptTables?: readonly string[];\n /** Column names this config's `columns` filter leaves on this table, when one was read. */\n keptColumns?: readonly string[];\n}\n\n/**\n * Everything worth saying about one table.\n *\n * A pure function of the analysis and the match, so the renderer, the `--json` document and the\n * tests all read one answer rather than three.\n */\nexport function explainTable(\n analysis: Analysis,\n match: Extract<TableMatch, { kind: 'found' }>,\n options: ExplainOptions = {}\n): TableExplanation {\n const table = match.table;\n const qualified = qualifiedTableName(table);\n const constraints = tableConstraints(table).constraints;\n\n // Which columns a generated schema really caps, taken off the shared guard rather than from a\n // second copy of it here: `tableConstraints` emits a `maxLength`/`maxBytes` constraint for a\n // column exactly when the emitted schemas state one.\n const capped = new Set(\n constraints\n .filter((c) => c.kind === 'maxLength' || c.kind === 'maxBytes')\n .flatMap((c) => c.columns)\n );\n const narrowedBySet = new Set(\n constraints.filter((c) => c.values).map((c) => c.values!.column)\n );\n\n const primaryKeyColumns = new Set(table.primaryKey?.columns ?? []);\n const singleColumnUnique = new Set(\n (table.unique ?? []).filter((u) => u.columns.length === 1).map((u) => u.columns[0])\n );\n\n const columns: ExplainColumn[] = table.columns.map((column) => ({\n name: column.name,\n tsType: column.tsType,\n dbType: column.dbType,\n ...(column.sqlType ? { sqlType: column.sqlType } : {}),\n nullable: column.nullable,\n hasDefault: column.hasDefault,\n default: defaultOf(column),\n isGenerated: column.isGenerated,\n inPrimaryKey: primaryKeyColumns.has(column.name),\n unique: singleColumnUnique.has(column.name),\n ...(column.references ? { references: column.references } : {}),\n ...(column.enumValues ? { enumValues: column.enumValues } : {}),\n ...(column.arrayDimensions ? { arrayDimensions: column.arrayDimensions } : {}),\n ...(column.shape ? { shape: column.shape } : {}),\n facts: factsFor(column, {\n capStated: capped.has(column.name),\n narrowedBySet: narrowedBySet.has(column.name),\n }),\n }));\n\n const relations: ExplainRelation[] = analysis.relations\n .filter((r) => r.from === qualified || r.to === qualified || r.via === qualified)\n .map((r) => ({ ...r, outgoing: r.from === qualified }));\n\n // A key is \"generated\" when the database fills it in without being told, which is the question\n // a reader has about an insert schema. `isGenerated` alone answers it for an identity column and\n // not for a `serial`, whose sequence arrives as an ordinary default with nothing else naming it.\n const keyColumns = table.columns.filter((c) => primaryKeyColumns.has(c.name));\n const primaryKey = table.primaryKey?.columns.length\n ? {\n ...(table.primaryKey.name ? { name: table.primaryKey.name } : {}),\n columns: [...table.primaryKey.columns],\n generated: keyColumns.length > 0 && keyColumns.every((c) => c.isGenerated || c.hasDefault),\n }\n : null;\n\n const removed = options.keptColumns\n ? table.columns.map((c) => c.name).filter((name) => !options.keptColumns!.includes(name))\n : [];\n\n return {\n name: table.name,\n tsName: table.tsName,\n ...(table.schema ? { schema: table.schema } : {}),\n qualified,\n addressable: addressableName(table),\n readOnly: !!table.readOnly,\n matchedOn: match.matchedOn,\n matchedExactly: match.exact,\n ...(options.keptTables && !options.keptTables.includes(qualified)\n ? { excludedByConfig: true }\n : {}),\n ...(removed.length ? { columnsRemovedByConfig: removed } : {}),\n columns,\n primaryKey,\n unique: (table.unique ?? []).map((u) => ({\n ...(u.name ? { name: u.name } : {}),\n columns: [...u.columns],\n })),\n indexes: (table.indexes ?? []).map((i) => ({\n ...(i.name ? { name: i.name } : {}),\n columns: [...i.columns],\n })),\n foreignKeys: (table.foreignKeys ?? []).map((fk) => ({\n ...(fk.name ? { name: fk.name } : {}),\n columns: [...fk.columns],\n references: { table: qualifiedForeignTable(fk), columns: [...fk.foreignColumns] },\n ...(fk.onDelete ? { onDelete: fk.onDelete } : {}),\n ...(fk.onUpdate ? { onUpdate: fk.onUpdate } : {}),\n })),\n relations,\n constraints,\n gaps: gapsFor(table, constraints, analysis.issues),\n };\n}\n\n/**\n * One line per table, with the number of things DRZL did not understand about each.\n *\n * The last number is why this exists rather than being left to `analyze`, which prints the whole\n * analysis as JSON and points at nothing in it. A reader with forty tables and one wrong file gets\n * told which table to run `explain` on instead of reading forty.\n */\nexport function summarize(analysis: Analysis): TableSummary[] {\n return analysis.tables.map((table) => ({\n name: table.name,\n tsName: table.tsName,\n ...(table.schema ? { schema: table.schema } : {}),\n qualified: qualifiedTableName(table),\n columns: table.columns.length,\n checks: table.checks?.length ?? 0,\n gaps: gapsFor(table, tableConstraints(table).constraints, analysis.issues).length,\n }));\n}\n\n/* ------------------------------------------------------------------------------------------ */\n/* Rendering */\n/* ------------------------------------------------------------------------------------------ */\n\n/**\n * How wide the report lays itself out.\n *\n * 80 rather than the 96 `doctor` wraps its prose at, because this one prints aligned rows and a\n * row that wraps is worse than a paragraph that does: the eye loses the column. Everything with a\n * computed width is fitted inside this, and the only cells allowed past it are the last one on a\n * line, where an overflow costs a soft wrap and nothing else.\n */\nconst WIDTH = 80;\n\nconst pad = (text: string, width: number) => text + ' '.repeat(Math.max(0, width - text.length));\n\n/** The widest of a set of strings, which is the column width every row is padded to. */\nconst widest = (values: string[]) => values.reduce((n, v) => Math.max(n, v.length), 0);\n\n/** Wrap a sentence under a fixed indent. Same shape as `doctor`'s, at this file's width. */\nfunction wrap(text: string, indent: string, first = indent): string {\n const lines: string[] = [];\n let line = '';\n for (const word of String(text).split(/\\s+/)) {\n if (line && `${line} ${word}`.length + indent.length > WIDTH) {\n lines.push(line);\n line = word;\n } else {\n line = line ? `${line} ${word}` : word;\n }\n }\n if (line) lines.push(line);\n return lines.map((l, i) => (i === 0 ? first : indent) + l).join('\\n');\n}\n\n/**\n * The TypeScript type as a reader of the generated schema would write it.\n *\n * `tsType` is the *element* type on an array column, because Drizzle gives an array no class of\n * its own and the analyzer records the depth separately. Printing it bare said `string` for a\n * `text[]`, which is the exact misreading that produced the array defect `arrayDimensions` was\n * added to fix, so the suffix is put back here.\n */\nfunction renderTsType(column: ExplainColumn): string {\n return column.tsType + '[]'.repeat(column.arrayDimensions ?? 0);\n}\n\n/** The short markers beside a column: what it is to the table, rather than what it holds. */\nfunction columnNotes(column: ExplainColumn): string {\n const notes: string[] = [];\n if (column.inPrimaryKey) notes.push('pk');\n if (column.unique) notes.push('unique');\n if (column.references) {\n notes.push(`fk -> ${column.references.table}.${column.references.column}`);\n }\n if (column.isGenerated) notes.push('generated');\n const value = describeDefault(column.default);\n if (value && !column.isGenerated) notes.push(value);\n return notes.join(', ');\n}\n\n/** The rule and the verdict for one constraint, as the reader needs to read them: side by side. */\nfunction constraintLines(\n constraint: ConstraintFacts,\n style: ChalkInstance,\n labelWidth: number\n): string[] {\n const label = constraint.name ?? '';\n const verdict = constraint.enforced\n ? style.green('enforced')\n : style.yellow('not enforced by any generated schema');\n const out = [` ${pad(label, labelWidth)} ${constraint.rule}`];\n out.push(` ${' '.repeat(labelWidth)} ${verdict}`);\n for (const part of constraint.unenforced ?? []) {\n out.push(style.dim(wrap(part.reason, ' '.repeat(labelWidth + 4))));\n }\n return out;\n}\n\n/**\n * The human report.\n *\n * Grouped rather than one flat list, because the questions are different: \"did DRZL read my column\n * right\" is answered by the first two sections and \"is my constraint enforced\" by the next three,\n * and a reader arrives holding exactly one of them.\n */\nexport function renderExplanation(\n explanation: TableExplanation,\n context: { schema: string; dialect: string },\n style: ChalkInstance = PLAIN\n): string {\n const out: string[] = [];\n const plural = (n: number, one: string) => `${n} ${one}${n === 1 ? '' : 's'}`;\n\n out.push(style.bold(explanation.qualified) + style.dim(` ${context.schema}`));\n const identity = [\n context.dialect,\n `table \"${explanation.name}\"`,\n `export \"${explanation.tsName}\"`,\n plural(explanation.columns.length, 'column'),\n ];\n if (explanation.readOnly) identity.push('read-only, so no insert or update schema is emitted');\n out.push(style.dim(' ' + identity.join(', ')));\n if (!explanation.matchedExactly) {\n // Said out loud, because a case-folded match is the one way this report can be about a table\n // the reader did not think they were asking for.\n out.push(style.dim(` matched on ${MATCH_LABELS[explanation.matchedOn]}, ignoring case`));\n }\n if (explanation.excludedByConfig) {\n out.push('');\n out.push(style.yellow(' This config\\'s include/exclude removes this table.'));\n out.push(style.dim(' No generator sees it, so nothing below reaches any emitted file.'));\n }\n if (explanation.columnsRemovedByConfig?.length) {\n out.push('');\n out.push(\n style.yellow(\n ` This config's columns filter removes ${explanation.columnsRemovedByConfig.length} of ` +\n `these columns: ${explanation.columnsRemovedByConfig.join(', ')}.`\n )\n );\n }\n out.push('');\n\n // ---- columns -------------------------------------------------------------------------------\n out.push(style.bold('Columns'));\n const tsTypes = explanation.columns.map(renderTsType);\n const nameWidth = widest(['COLUMN', ...explanation.columns.map((c) => c.name)]);\n const tsWidth = widest(['TS TYPE', ...tsTypes]);\n const sqlWidth = widest(['SQL TYPE', ...explanation.columns.map((c) => c.sqlType ?? c.dbType)]);\n out.push(\n style.dim(\n ` ${pad('COLUMN', nameWidth)} ${pad('TS TYPE', tsWidth)} ` +\n `${pad('SQL TYPE', sqlWidth)} NULL`\n )\n );\n explanation.columns.forEach((column, i) => {\n // `sqlType` is what the database declares and is the answer a reader came for; `dbType` is a\n // coarse family label and stands in only where Drizzle's builder would not answer at all.\n const sql = column.sqlType ?? column.dbType;\n const notes = columnNotes(column);\n const nullable = column.nullable ? 'yes' : 'no';\n out.push(\n ` ${pad(column.name, nameWidth)} ${pad(tsTypes[i], tsWidth)} ` +\n `${pad(sql, sqlWidth)} ` +\n // Padded only when something follows it: a trailing run of spaces on every second row is\n // invisible in a terminal and is the first thing a test diff shows.\n (notes ? `${pad(nullable, 4)} ${style.dim(notes)}` : nullable)\n );\n });\n\n // ---- the measured facts --------------------------------------------------------------------\n const withFacts = explanation.columns.filter((c) => c.facts.length);\n if (withFacts.length) {\n out.push('');\n out.push(style.bold('What the generators read off each column'));\n const factWidth = widest(withFacts.map((c) => c.name));\n for (const column of withFacts) {\n let first = true;\n for (const fact of column.facts) {\n const label = first ? pad(column.name, factWidth) : ' '.repeat(factWidth);\n first = false;\n out.push(` ${label} ${fact.stated ? fact.text : style.yellow(fact.text)}`);\n if (fact.stated) continue;\n out.push(\n style.dim(\n wrap(\n `not stated by any generated schema: ${fact.reason}`,\n ' '.repeat(factWidth + 4)\n )\n )\n );\n }\n }\n }\n\n // ---- keys, foreign keys, relations ---------------------------------------------------------\n out.push('');\n out.push(style.bold('Keys'));\n if (explanation.primaryKey) {\n const pk = explanation.primaryKey;\n out.push(\n ` PRIMARY KEY (${pk.columns.join(', ')})` +\n (pk.generated ? style.dim(' filled in by the database') : '')\n );\n if (pk.columns.length > 1) {\n out.push(\n style.dim(\n wrap(\n 'The service and router generators key getById, update and delete on ' +\n `\"${pk.columns[0]}\" alone, so those operations match on part of this key.`,\n ' '\n )\n )\n );\n }\n } else {\n out.push(style.yellow(' No primary key.'));\n out.push(\n style.dim(\n wrap(\n 'The service and router generators fall back to a column named \"id\".',\n ' '\n )\n )\n );\n }\n for (const unique of explanation.unique) {\n out.push(` UNIQUE (${unique.columns.join(', ')})` + (unique.name ? style.dim(` ${unique.name}`) : ''));\n }\n for (const index of explanation.indexes) {\n out.push(style.dim(` INDEX (${index.columns.join(', ')})${index.name ? ` ${index.name}` : ''}`));\n }\n\n if (explanation.foreignKeys.length) {\n out.push('');\n out.push(style.bold('Foreign keys'));\n for (const fk of explanation.foreignKeys) {\n const actions = [\n fk.onDelete ? `ON DELETE ${fk.onDelete}` : '',\n fk.onUpdate ? `ON UPDATE ${fk.onUpdate}` : '',\n ]\n .filter(Boolean)\n .join(' ');\n out.push(\n ` (${fk.columns.join(', ')}) -> ${fk.references.table} ` +\n `(${fk.references.columns.join(', ')})` +\n (actions ? style.dim(` ${actions}`) : '')\n );\n }\n }\n\n if (explanation.relations.length) {\n out.push('');\n out.push(style.bold('Relations'));\n for (const relation of explanation.relations) {\n const via = relation.via ? ` through ${relation.via}` : '';\n out.push(\n ` ${relation.from} -> ${relation.to}${via}` + style.dim(` ${relation.kind}`)\n );\n }\n }\n\n // ---- constraints ---------------------------------------------------------------------------\n const checks = explanation.constraints.filter((c) => c.kind === 'check');\n if (checks.length) {\n out.push('');\n out.push(style.bold('CHECK constraints, as DRZL parsed them'));\n const labelWidth = widest(checks.map((c) => c.name ?? ''));\n for (const check of checks) out.push(...constraintLines(check, style, labelWidth));\n }\n\n // ---- what was not understood ---------------------------------------------------------------\n out.push('');\n if (!explanation.gaps.length) {\n out.push(style.green('Nothing about this table was dropped or left unrecognised.'));\n return out.join('\\n');\n }\n out.push(style.yellow(`Not understood (${explanation.gaps.length})`));\n out.push(style.dim(' These are in your schema and are not in anything DRZL generates.'));\n out.push('');\n // One hint under the findings that share it, so the same sentence is not repeated under twenty\n // columns. Same grouping as `doctor`, for the same reason.\n const groups = new Map<string, ExplainGap[]>();\n for (const gap of explanation.gaps) {\n const key = gap.hint ?? '';\n groups.set(key, [...(groups.get(key) ?? []), gap]);\n }\n for (const [hint, items] of groups) {\n for (const gap of items) {\n const named = gap.subject && !gap.message.startsWith(gap.subject);\n out.push(wrap((named ? `${gap.subject}: ` : '') + gap.message, ' ', ` ${style.dim('-')} `));\n }\n if (hint) out.push(style.dim(wrap(hint, ' ')));\n out.push('');\n }\n return out.join('\\n').replace(/\\n+$/, '');\n}\n\n/** The index a bare `drzl explain` prints. */\nexport function renderIndex(\n tables: TableSummary[],\n context: { schema: string; dialect: string },\n style: ChalkInstance = PLAIN\n): string {\n const out: string[] = [];\n const plural = (n: number, one: string) => `${n} ${one}${n === 1 ? '' : 's'}`;\n\n out.push(style.bold(context.schema) + style.dim(` ${context.dialect}`));\n out.push(style.dim(` ${plural(tables.length, 'table')}`));\n out.push('');\n\n const nameWidth = widest(['TABLE', ...tables.map((t) => t.qualified)]);\n const tsWidth = widest(['EXPORT', ...tables.map((t) => t.tsName)]);\n out.push(style.dim(` ${pad('TABLE', nameWidth)} ${pad('EXPORT', tsWidth)} COLUMNS`));\n for (const table of tables) {\n const columns = String(table.columns);\n out.push(\n ` ${pad(table.qualified, nameWidth)} ${pad(table.tsName, tsWidth)} ` +\n (table.gaps\n ? `${pad(columns, 7)} ` +\n style.yellow(`${plural(table.gaps, 'thing')} not understood`)\n : columns)\n );\n }\n out.push('');\n out.push(style.dim(' drzl explain <table> for one of them in full'));\n return out.join('\\n');\n}\n\n/* ------------------------------------------------------------------------------------------ */\n/* The two ways a name fails */\n/* ------------------------------------------------------------------------------------------ */\n\n/** No such table (DRZL_EXPLAIN_001), or the name reaches more than one (DRZL_EXPLAIN_002). */\nexport const NO_SUCH_TABLE_CODE = 'DRZL_EXPLAIN_001';\nexport const AMBIGUOUS_TABLE_CODE = 'DRZL_EXPLAIN_002';\n\n/** How many table names a failure message lists before it stops. */\nconst NAME_CAP = 12;\n\n/**\n * \"There is no such table\", with the tables there are.\n *\n * The list is the point. A reader who mistypes a name, or who is looking at the wrong schema file\n * entirely, learns which from the same line, and the two are not otherwise distinguishable: an\n * empty output and a wrong output look the same from outside.\n */\nexport function noSuchTableProblem(\n query: string,\n tables: readonly Table[],\n suggestion: string | undefined\n): { code: string; message: string; hint: string } {\n const names = tables.map((t) => displayTableName(t));\n const shown = names.slice(0, NAME_CAP).join(', ');\n const rest = names.length > NAME_CAP ? `, and ${names.length - NAME_CAP} more` : '';\n return {\n code: NO_SUCH_TABLE_CODE,\n message:\n `No table called \"${query}\" (${NO_SUCH_TABLE_CODE}). ` +\n (names.length\n ? `This schema declares ${names.length} table${names.length === 1 ? '' : 's'}: ${shown}${rest}.`\n : 'This schema declares no tables.'),\n hint: suggestion\n ? `Did you mean \"${suggestion}\"?`\n : 'A table is matched by its database name, by its schema-qualified name, or by the name it ' +\n 'is exported under, ignoring case where nothing matches exactly.',\n };\n}\n\n/**\n * \"That name reaches more than one table\", with both of them and the spelling that separates them.\n *\n * Reachable from an ordinary schema, and silently picking one would answer a question about one\n * table with facts about another.\n */\nexport function ambiguousTableProblem(\n query: string,\n hits: readonly TableHit[]\n): { code: string; message: string; hint: string } {\n const named = hits\n .map((hit) => `${addressableName(hit.table)} (exported as ${hit.table.tsName})`)\n .join(', ');\n return {\n code: AMBIGUOUS_TABLE_CODE,\n message: `\"${query}\" names ${hits.length} tables (${AMBIGUOUS_TABLE_CODE}): ${named}.`,\n hint: `Name one of them exactly, for example \"${addressableName(hits[0].table)}\".`,\n };\n}\n","/**\n * drizzle-kit interop: read the schema path from `drizzle.config.ts`, so a drizzle-kit user\n * does not have to state it a second time in `drzl.config.ts`.\n *\n * Everything here mirrors drizzle-kit's measured behavior, read from the published dist of\n * drizzle-kit 0.31.10 rather than from its docs or from memory:\n *\n * - `Config.schema` is `string | string[]` and entries may be glob patterns (`index.d.mts`).\n * - The CLI's default config candidates are `drizzle.config.ts`, then `.js`, then `.json`,\n * in that order and nothing else (`drizzleConfigFromFile` in `bin.cjs`); a custom path can\n * be anything its `--config` flag can name, which `drizzleKit: '<path>'` mirrors.\n * - `prepareFilenames` (bin.cjs) expands each entry with glob.sync, expands a directory\n * match one level with readdir rather than recursively, unions the results, and hard-errors\n * when nothing matched. It also computes the list of code extensions (.ts .js .cjs .mjs\n * .mts .cts) into a variable it never reads, and then requires every match; DRZL applies\n * that filter for real, which is strictly friendlier than crashing on a README.md sitting\n * in the schema directory.\n * - `defineConfig` is the identity function (`index.mjs`), so evaluating the config module\n * yields the plain object and no drizzle-kit installation is needed to read it.\n *\n * Globs are expanded with `node:fs.globSync`, present since Node 22.0 and quiet on the CLI's\n * `engines` floor (measured: `*`, `**`, `{a,b}` and literal paths all behave; no\n * ExperimentalWarning on stderr on 22.22). No new dependency, and the config itself is loaded\n * through the same jiti path as `drzl.config.ts` (`importFreshConfigModule`), so the two\n * config files cannot drift onto different loaders.\n */\nimport type { Dialect } from '@drzl/analyzer';\nimport * as fs from 'node:fs';\nimport * as path from 'node:path';\nimport { importFreshConfigModule } from './config.js';\n\n/** The default candidates drizzle-kit's own CLI tries, in its order. `.mjs`/`.cjs` are not\n * candidates because they are not drizzle-kit's; a project using one names it explicitly via\n * `drizzleKit: './drizzle.config.mjs'`, exactly as it must pass `--config` to kit itself. */\nexport const DRIZZLE_KIT_CONFIG_CANDIDATES = [\n 'drizzle.config.ts',\n 'drizzle.config.js',\n 'drizzle.config.json',\n] as const;\n\n/** The extensions drizzle-kit's `prepareFilenames` names as schema code. */\nconst CODE_EXTENSIONS = new Set(['.ts', '.js', '.cjs', '.mjs', '.mts', '.cts']);\n\nexport interface DrizzleKitConfig {\n /** Absolute path of the file this came from. */\n path: string;\n schema?: string | string[];\n dialect?: string;\n casing?: string;\n}\n\n/**\n * Where the schema will be read from, decided once and handed to both `generate` and `watch`,\n * so the two commands cannot resolve differently.\n */\nexport interface ResolvedSchemaSource {\n source: 'drzl' | 'drizzle-kit';\n /**\n * What `SchemaAnalyzer` is constructed with: the drzl config's `schema` string verbatim, or\n * the expanded, sorted, absolute file list from the drizzle-kit config.\n */\n schema: string | string[];\n /**\n * Absolute directories that must be watched for schema edits. For a glob this is its static\n * base, so a file created later that matches the pattern still raises an event; a missing\n * entry here is the infinite-blindness half of the watch-loop rules.\n */\n watchDirs: string[];\n /** Absolute path of the drizzle-kit config consulted, when source is 'drizzle-kit'. */\n drizzleKitConfigPath?: string;\n /** The dialect that config declares, verbatim, for the post-analysis cross-check. */\n drizzleKitDialect?: string;\n warnings: string[];\n}\n\n/** The first existing default candidate, in drizzle-kit's own order, or null. */\nexport function findDrizzleKitConfig(cwd: string): string | null {\n for (const name of DRIZZLE_KIT_CONFIG_CANDIDATES) {\n const p = path.join(cwd, name);\n if (fs.existsSync(p)) return p;\n }\n return null;\n}\n\n/** Load and narrow a drizzle-kit config file. Throws with the file named on anything wrong. */\nexport async function loadDrizzleKitConfig(p: string): Promise<DrizzleKitConfig> {\n let raw: unknown;\n try {\n raw = await importFreshConfigModule(p);\n } catch (e) {\n throw new Error(\n `drzl config: failed to load the drizzle-kit config at ${p}: ${(e as any)?.message ?? e}`\n );\n }\n if (!raw || typeof raw !== 'object') {\n throw new Error(`drzl config: ${p} did not export a drizzle-kit config object.`);\n }\n const record = raw as Record<string, unknown>;\n const schema = record.schema;\n if (\n schema !== undefined &&\n typeof schema !== 'string' &&\n !(Array.isArray(schema) && schema.every((s) => typeof s === 'string'))\n ) {\n throw new Error(\n `drzl config: \"schema\" in ${p} must be a string or an array of strings, matching ` +\n `drizzle-kit's own Config type.`\n );\n }\n return {\n path: p,\n schema: schema as string | string[] | undefined,\n dialect: typeof record.dialect === 'string' ? record.dialect : undefined,\n casing: typeof record.casing === 'string' ? record.casing : undefined,\n };\n}\n\n/** Whether glob would treat any part of this entry as a pattern rather than a name. */\nfunction hasGlobMagic(entry: string): boolean {\n return /[*?{}[\\]]/.test(entry) || /[!@+]\\(/.test(entry);\n}\n\n/**\n * The longest leading run of pattern-free path segments, as an absolute directory: what a\n * watcher can actually watch on behalf of a glob.\n */\nfunction staticGlobBase(entry: string, cwd: string): string {\n const segments = entry.split('/');\n const kept: string[] = [];\n for (const s of segments) {\n if (hasGlobMagic(s)) break;\n kept.push(s);\n }\n // The last static segment before the magic may itself be a filename prefix; treating it as a\n // directory is still right, because resolve of `src/db` under a pattern `src/db/*.ts` IS the\n // directory. An entirely magic entry watches the cwd.\n const joined = kept.join('/');\n const base = path.resolve(cwd, joined || '.');\n // `src/*.ts` keeps `src`; `schema-*.ts` keeps nothing and must not watch a file named after\n // the prefix, so anything that is not an existing directory falls back to its dirname.\n if (fs.existsSync(base) && fs.statSync(base).isDirectory()) return base;\n return path.dirname(base);\n}\n\n/** One level of a directory, files only: exactly what kit's `prepareFilenames` does. */\nfunction filesOneLevel(dir: string): string[] {\n const out: string[] = [];\n for (const name of fs.readdirSync(dir)) {\n const full = path.join(dir, name);\n if (!fs.lstatSync(full).isDirectory()) out.push(full);\n }\n return out;\n}\n\n/**\n * Expand drizzle-kit `schema` entries into concrete files plus the directories a watcher\n * needs. Deterministic: the file list is deduplicated and sorted, so everything downstream\n * (first-wins export merging in the analyzer above all) is stable across runs.\n */\nexport function expandSchemaPaths(\n entries: string | string[],\n cwd: string\n): { files: string[]; watchDirs: string[] } {\n const list = typeof entries === 'string' ? [entries] : entries;\n const files = new Set<string>();\n const watchDirs = new Set<string>();\n\n for (const entry of list) {\n if (hasGlobMagic(entry)) {\n watchDirs.add(staticGlobBase(entry, cwd));\n for (const match of fs.globSync(entry, { cwd })) {\n const full = path.resolve(cwd, match);\n if (fs.existsSync(full) && fs.statSync(full).isDirectory()) {\n for (const f of filesOneLevel(full)) files.add(f);\n } else {\n files.add(full);\n }\n }\n continue;\n }\n const full = path.resolve(cwd, entry);\n let stat: fs.Stats | null = null;\n try {\n stat = fs.statSync(full);\n } catch {\n // A missing literal entry contributes nothing, exactly as glob.sync returns [] for it in\n // kit; the caller's \"matched no schema files\" check is what reports an all-typo config.\n // Its directory is still watched, so creating the file later wakes the watcher.\n watchDirs.add(path.dirname(full));\n continue;\n }\n if (stat.isDirectory()) {\n watchDirs.add(full);\n for (const f of filesOneLevel(full)) files.add(f);\n } else {\n watchDirs.add(path.dirname(full));\n files.add(full);\n }\n }\n\n const kept = [...files].filter((f) => CODE_EXTENSIONS.has(path.extname(f).toLowerCase()));\n return { files: kept.sort(), watchDirs: [...watchDirs] };\n}\n\n/**\n * drizzle-kit's dialect vocabulary mapped onto the analyzer's, `null` when there is no\n * confident mapping (in which case the cross-check stays quiet rather than guessing).\n * `turso` is libsql, which is SQLite on the wire, which is what the analyzer detects.\n */\nexport function mapDrizzleKitDialect(declared: string | undefined): Dialect | null {\n if (!declared) return null;\n const map: Record<string, Dialect> = {\n postgresql: 'postgres',\n mysql: 'mysql',\n sqlite: 'sqlite',\n turso: 'sqlite',\n singlestore: 'singlestore',\n gel: 'gel',\n };\n if (declared in map) return map[declared];\n // A future kit dialect that already speaks the analyzer's name (say, 'cockroach') maps to\n // itself rather than silently losing the cross-check.\n const analyzerDialects: readonly Dialect[] = [\n 'sqlite',\n 'postgres',\n 'mysql',\n 'singlestore',\n 'mssql',\n 'cockroach',\n 'gel',\n ];\n return (analyzerDialects as readonly string[]).includes(declared) ? (declared as Dialect) : null;\n}\n\n/**\n * The warning for a drizzle-kit config whose `dialect` contradicts what the analyzer measured,\n * or null when there is nothing to say: agreement, an unmappable declaration, or an analysis\n * that could not identify a dialect at all (which already warned as DRZL_ANL_DIALECT).\n */\nexport function dialectMismatchWarning(args: {\n configPath: string;\n declared: string | undefined;\n analyzed: Dialect;\n}): string | null {\n const expected = mapDrizzleKitDialect(args.declared);\n if (!expected) return null;\n if (args.analyzed === 'unknown') return null;\n if (args.analyzed === expected) return null;\n return (\n `drzl: ${args.configPath} declares dialect \"${args.declared}\", but the schema analyzed ` +\n `as \"${args.analyzed}\". DRZL follows the schema; if the schema files are the right ones, ` +\n `the dialect in that config is stale.`\n );\n}\n\n/**\n * Decide where the schema comes from. Precedence, in order:\n *\n * 1. `schema` in the drzl config wins outright. If `drizzleKit` is also set to something\n * that would read a file, that is two sources for one fact, so it warns and reads only\n * `schema`; this config parser has shipped silently-dead keys twice before.\n * 2. Otherwise `drizzleKit` decides: `false` refuses the fallback, a string names the file,\n * and `true` or unset searches drizzle-kit's own default candidates. Unset behaving like\n * `true` is deliberate: `schema` was required until this feature existed, so no\n * pre-existing config can reach the fallback, and the CLI announces the file it read.\n * 3. Neither yielding a schema is an error that names both files and what to do.\n */\nexport async function resolveSchemaSource(\n cfg: { schema?: string; drizzleKit?: boolean | string },\n cwd = process.cwd()\n): Promise<ResolvedSchemaSource> {\n if (cfg.schema) {\n const warnings: string[] = [];\n if (cfg.drizzleKit === true || typeof cfg.drizzleKit === 'string') {\n warnings.push(\n `drzl config: both \"schema\" and \"drizzleKit\" are set. \"schema\" wins, so the ` +\n `drizzle-kit config was not read; remove one of the two to silence this.`\n );\n }\n return {\n source: 'drzl',\n schema: cfg.schema,\n watchDirs: [path.dirname(path.resolve(cwd, cfg.schema))],\n warnings,\n };\n }\n\n if (cfg.drizzleKit === false) {\n throw new Error(\n `drzl config: no \"schema\" is set and \"drizzleKit\" is false, so the drizzle-kit fallback ` +\n `is disabled. Set \"schema\".`\n );\n }\n\n let configPath: string;\n if (typeof cfg.drizzleKit === 'string') {\n configPath = path.resolve(cwd, cfg.drizzleKit);\n if (!fs.existsSync(configPath)) {\n throw new Error(`drzl config: \"drizzleKit\" points at ${configPath}, which does not exist.`);\n }\n } else {\n const found = findDrizzleKitConfig(cwd);\n if (!found) {\n const looked = DRIZZLE_KIT_CONFIG_CANDIDATES.join(', ');\n throw new Error(\n cfg.drizzleKit === true\n ? `drzl config: \"drizzleKit\" is set, but no drizzle-kit config was found (looked ` +\n `for ${looked} in ${cwd}). Create one, or point \"drizzleKit\" at its path.`\n : `drzl config: no \"schema\" is set and no drizzle-kit config was found (looked for ` +\n `${looked} in ${cwd}). Set \"schema\" in your drzl config, or add \"drizzleKit\" ` +\n `naming your drizzle-kit config file.`\n );\n }\n configPath = found;\n }\n\n const kit = await loadDrizzleKitConfig(configPath);\n if (kit.schema === undefined) {\n throw new Error(\n `drzl config: ${configPath} has no \"schema\" entry, so there is nothing to analyze. Set ` +\n `\"schema\" there, or set \"schema\" in your drzl config.`\n );\n }\n const { files, watchDirs } = expandSchemaPaths(kit.schema, cwd);\n if (!files.length) {\n const shown = (typeof kit.schema === 'string' ? [kit.schema] : kit.schema)\n .map((s) => JSON.stringify(s))\n .join(', ');\n throw new Error(\n `drzl config: the \"schema\" patterns in ${configPath} matched no schema files: ${shown}. ` +\n `DRZL expands them the way drizzle-kit does; check them against your tree.`\n );\n }\n return {\n source: 'drizzle-kit',\n schema: files,\n watchDirs,\n drizzleKitConfigPath: configPath,\n drizzleKitDialect: kit.dialect,\n warnings: [],\n };\n}\n","/**\n * Drift detection for generated output.\n *\n * No runtime validator can offer this. `drizzle-orm/zod` and friends derive schemas in memory at\n * import time, so there is nothing on disk to have drifted and nothing for CI to compare. It is\n * only available to a code generator, which makes it one of the few things DRZL can do that the\n * first-party modules structurally cannot.\n *\n * The check is: regenerate, and require the result to equal what is committed. That catches the\n * two failures that actually happen, someone editing generated files by hand and someone\n * changing the schema without regenerating, and it catches them in CI rather than in review.\n *\n * Content-neutral by construction. Redirecting output to a temporary directory would not work:\n * generated files contain paths computed relative to their own location, so a different output\n * directory produces legitimately different bytes and every file would report as drifted. So the\n * real directories are snapshotted first, regeneration is allowed to overwrite them, and the\n * snapshot is put back if anything changed. Either way the tree ends as it began.\n */\nimport { promises as fs } from 'node:fs';\nimport path from 'node:path';\n\nexport interface DriftEntry {\n file: string;\n status: 'changed' | 'added' | 'removed';\n}\n\n/** Every file under `dir`, keyed by its path relative to `dir`. Missing directory means empty. */\nexport async function snapshotDir(dir: string): Promise<Map<string, string>> {\n const out = new Map<string, string>();\n async function walk(current: string) {\n let entries;\n try {\n entries = await fs.readdir(current, { withFileTypes: true });\n } catch {\n return; // Nothing generated there yet, which a first run should report as additions.\n }\n for (const e of entries) {\n const full = path.join(current, e.name);\n if (e.isDirectory()) await walk(full);\n else out.set(path.relative(dir, full), await fs.readFile(full, 'utf8'));\n }\n }\n await walk(dir);\n return out;\n}\n\n/** Snapshot several directories at once, keys prefixed by directory so they cannot collide. */\nexport async function snapshotAll(dirs: string[]): Promise<Map<string, string>> {\n const all = new Map<string, string>();\n for (const dir of dirs) {\n for (const [rel, content] of await snapshotDir(dir)) {\n all.set(path.join(dir, rel), content);\n }\n }\n return all;\n}\n\n/** What changed between two snapshots. */\nexport function diffSnapshots(\n before: Map<string, string>,\n after: Map<string, string>\n): DriftEntry[] {\n const out: DriftEntry[] = [];\n for (const [file, content] of after) {\n if (!before.has(file)) out.push({ file, status: 'added' });\n else if (before.get(file) !== content) out.push({ file, status: 'changed' });\n }\n for (const file of before.keys()) {\n if (!after.has(file)) out.push({ file, status: 'removed' });\n }\n return out.sort((a, b) => a.file.localeCompare(b.file));\n}\n\n/**\n * Put a snapshot back, so a failed check leaves the tree exactly as it found it.\n *\n * A file that regeneration created and the snapshot does not know about is deleted, since it was\n * not there before the check ran.\n */\nexport async function restoreSnapshot(\n before: Map<string, string>,\n after: Map<string, string>\n): Promise<void> {\n for (const [file, content] of before) {\n await fs.mkdir(path.dirname(file), { recursive: true });\n await fs.writeFile(file, content, 'utf8');\n }\n for (const file of after.keys()) {\n if (!before.has(file)) await fs.rm(file, { force: true });\n }\n}\n","/**\n * What a generate run is about to put on disk, and how that differs from what is there (plan items\n * 68, 80, 81).\n *\n * The three items read as three features and are one mechanism. `--dry-run` is \"compute this and\n * stop\", `generate` reporting what changed is \"compute this and write it\", and `--check` is\n * \"compute this, do not write it, and show the difference\". All three need exactly one fact per\n * file: the content about to be written, beside the content already there. So that fact is\n * produced once, here, and the three commands differ only in what they do with it.\n *\n * ## The plan is the sink\n *\n * Generators hand their writes to a `FileSink` (see `emit.ts` in `@drzl/validation-core`). This\n * class is that sink. In `write` mode it records and then writes; in `plan` mode it records and\n * stops. Nothing else about a run changes between the two, which is what makes a dry run an honest\n * preview rather than a second implementation that can drift from the real one.\n *\n * ## Why `--check` no longer writes\n *\n * `--check` used to snapshot the output directories, let the generators overwrite them for real,\n * compare, and put the snapshot back. That works and was tested, but it means the one command\n * documented as never touching your tree is the command that rewrites every generated file on\n * every CI run, and a process killed between the write and the restore leaves the tree modified\n * with no record of it. On the plan it compares without writing at all, so there is no window.\n *\n * The snapshot is still taken, for a different job: see `verifyNothingWasWritten`.\n */\nimport { promises as fs } from 'node:fs';\nimport path from 'node:path';\nimport type { FileSink } from '@drzl/validation-core';\nimport { diffSnapshots, restoreSnapshot, snapshotAll } from './drift.js';\n\n/** What happened, or would happen, to one file. */\nexport type FileVerdict = 'created' | 'changed' | 'unchanged';\n\nexport interface EmittedFile {\n /** Absolute path, exactly as the generator spelled it. */\n file: string;\n verdict: FileVerdict;\n /** What is on disk now, or `null` when nothing is. */\n before: string | null;\n /** What the run produced for it. */\n after: string;\n}\n\nexport interface EmitCounts {\n total: number;\n created: number;\n changed: number;\n unchanged: number;\n}\n\nexport interface EmitPlanOptions {\n /**\n * Whether the recorded writes also reach the filesystem.\n *\n * `false` is `--dry-run` and `--check`. Nothing is written and no directory is created, which is\n * the whole claim those two flags make.\n */\n write: boolean;\n /**\n * Content already on disk, keyed by absolute path, when the caller has it.\n *\n * `--check` and `--dry-run` snapshot the output directories before the run anyway, so handing\n * that map over here saves reading every file a second time. A path missing from the map is\n * taken to be absent from disk, which is why this must only ever be a snapshot of directories\n * that cover everything the run can write. Omitted, each file is read as it is emitted, which is\n * what an ordinary `generate` does.\n */\n existing?: Map<string, string>;\n}\n\nexport class EmitPlan implements FileSink {\n readonly writes: boolean;\n private readonly existing?: Map<string, string>;\n private readonly byFile = new Map<string, EmittedFile>();\n private readonly dirs = new Set<string>();\n\n constructor(options: EmitPlanOptions) {\n this.writes = options.write;\n this.existing = options.existing;\n }\n\n async mkdir(dir: string): Promise<void> {\n this.dirs.add(dir);\n if (this.writes) await fs.mkdir(dir, { recursive: true });\n }\n\n async writeFile(file: string, contents: string): Promise<void> {\n // The first recording of a path owns its `before`. Two generators pointed at one directory,\n // or one generator writing a file twice, would otherwise have the second write compare itself\n // against the first write's output and report `unchanged` for a file that really did change.\n const prior = this.byFile.get(file);\n const before = prior ? prior.before : await this.read(file);\n this.byFile.set(file, {\n file,\n before,\n after: contents,\n verdict: before === null ? 'created' : before === contents ? 'unchanged' : 'changed',\n });\n if (!this.writes) return;\n // A byte-identical write is a no-op with a side effect: it moves the file's mtime, and an mtime\n // is what every watcher downstream keys on. A `drzl generate` over an up-to-date tree therefore\n // restarted a dev server, re-ran a type checker and invalidated a bundler cache for a tree that\n // had not changed. Skipping the write makes the command idempotent at the filesystem level,\n // which is what it already claims to be in its own output when it prints `unchanged`.\n //\n // Compared against what is on disk *now* rather than against what was there when the run\n // started. The two differ for a path written twice in one run, which is what happens when two\n // generators share an output directory: the first write has already put different bytes there,\n // so \"identical to what was there before the run\" stops meaning \"identical to what is there\".\n const onDisk = prior ? (this.wrote.has(file) ? prior.after : prior.before) : before;\n if (onDisk === contents) return;\n await fs.writeFile(file, contents, 'utf8');\n this.wrote.add(file);\n }\n\n /** Paths this run has actually put bytes on disk for, which is not every path it recorded. */\n private readonly wrote = new Set<string>();\n\n private async read(file: string): Promise<string | null> {\n if (this.existing) return this.existing.get(file) ?? null;\n try {\n return await fs.readFile(file, 'utf8');\n } catch {\n return null;\n }\n }\n\n /** Every directory a generator asked for, whether or not it was created. */\n get directories(): string[] {\n return [...this.dirs];\n }\n\n /** Every recorded file, in the order it was first written. */\n get files(): EmittedFile[] {\n return [...this.byFile.values()];\n }\n\n /**\n * The verdicts for a list of paths, in the order given.\n *\n * A path with no verdict is a path the generator reported writing without routing it through\n * the sink, which is the one shape a version mismatch takes: a `@drzl/cli` that knows about\n * `fileSink` beside a generator package that predates it. It is returned rather than thrown on\n * so the caller can name the generator; see `unrecorded`.\n */\n verdictsFor(paths: string[]): Array<EmittedFile | undefined> {\n return paths.map((p) => this.byFile.get(p));\n }\n\n /** The paths a generator claims to have written that never reached this sink. */\n unrecorded(paths: string[]): string[] {\n return paths.filter((p) => !this.byFile.has(p));\n }\n\n counts(paths?: string[]): EmitCounts {\n const entries = paths ? (this.verdictsFor(paths).filter(Boolean) as EmittedFile[]) : this.files;\n const counts: EmitCounts = { total: entries.length, created: 0, changed: 0, unchanged: 0 };\n for (const e of entries) counts[e.verdict]++;\n return counts;\n }\n}\n\n/** `3 created, 1 changed, 8 unchanged`, with the zeroes left out. */\nexport function describeCounts(counts: EmitCounts): string {\n const parts: string[] = [];\n if (counts.created) parts.push(`${counts.created} created`);\n if (counts.changed) parts.push(`${counts.changed} changed`);\n if (counts.unchanged) parts.push(`${counts.unchanged} unchanged`);\n return parts.join(', ') || 'nothing to write';\n}\n\n/** The files a plan would not leave alone. `--check` calls this drift; a dry run calls it the news. */\nexport function pendingChanges(plan: EmitPlan): EmittedFile[] {\n return plan.files\n .filter((f) => f.verdict !== 'unchanged')\n .sort((a, b) => a.file.localeCompare(b.file));\n}\n\n/**\n * The `--check` drift statuses, kept exactly as they were published.\n *\n * `created` is reported as `added`, because that is the word the `--json` contract, the docs and\n * every CI job reading them have used since `--check` shipped. `removed` is still a value of the\n * published union and is still produced by `drift.ts`; the plan cannot produce one, since a plan\n * is a list of writes and a write never deletes. Reporting every file in an output directory that\n * the run did not emit would produce them, and was deliberately not done: `outDir` is whatever the\n * config says, a project that points it at `src` would have every hand-written module in the tree\n * reported as drift, and turning that into a failing CI job is not a change anyone asked for.\n */\nexport function driftStatusOf(verdict: FileVerdict): 'added' | 'changed' {\n return verdict === 'created' ? 'added' : 'changed';\n}\n\n/**\n * Prove that a plan-mode run really wrote nothing, and put the tree back if it did.\n *\n * This is a guard against one specific failure, and it is worth its cost because that failure is\n * silent and destructive. `fileSink` is an option, so a generator package that predates it accepts\n * it, ignores it, and writes to disk. Inside this repository that cannot happen, since everything\n * is built together; on a user's machine `@drzl/cli` and the generators are separate packages on\n * separate versions, and npm is free to install a new CLI beside an old generator.\n *\n * The comparison is the snapshot the run already took for its `before` content, against the same\n * directories afterwards. Anything that differs is restored, and the caller is told, because a\n * `--dry-run` that quietly rewrote the tree is the worst outcome this feature has.\n *\n * Returns the paths that were written, empty when the run behaved.\n */\nexport async function verifyNothingWasWritten(\n dirs: string[],\n before: Map<string, string>\n): Promise<string[]> {\n const after = await snapshotAll(dirs);\n const drift = diffSnapshots(before, after);\n if (!drift.length) return [];\n await restoreSnapshot(before, after);\n return drift.map((d) => d.file).sort();\n}\n\n/** A path as a reader of the terminal wants to see it: relative to where they ran the command. */\nexport function displayPath(file: string, cwd = process.cwd()): string {\n const rel = path.relative(cwd, file);\n return rel && !rel.startsWith('..') ? rel : file;\n}\n","/**\n * A unified diff of two texts, written here rather than installed (plan item 81).\n *\n * `generate --check` named the files that had drifted and stopped there, which tells a reviewer\n * that something is stale and nothing about what. The diff is the part that turns a red CI job\n * into a decision: a regenerated header, a column that gained a length cap, and a hand-edit\n * somebody made to a generated file all read identically as \"changed\".\n *\n * ## Why not a dependency\n *\n * `diff` (jsdiff) is the obvious choice and is already resolvable in this workspace, but only as a\n * transitive dependency of `ts-node`, which is a devDependency of the CLI package. Relying on that\n * would be relying on a hoist. Adding it as a real dependency of `@drzl/cli` costs a package on\n * every install of a CLI whose whole job is to write files, in exchange for about a hundred lines\n * of a published algorithm, and this repository publishes through npm's trusted-publisher OIDC\n * flow where every new dependency is another thing to keep resolvable. So it is here, with the\n * property test that matters: applying the emitted diff to the \"before\" text has to reproduce the\n * \"after\" text exactly, which is the only check that can tell a plausible-looking diff from a\n * correct one.\n *\n * ## Format\n *\n * Unified, because it is the format `git`, `patch`, review tools and every developer already read,\n * and because it greps: a line beginning `+` or `-` is a change, and the `@@` header names where.\n * The alternative worth considering was a side-by-side or a word-level diff, which reads better\n * for prose and worse for generated code, where the interesting change is usually one whole line.\n *\n * ## Caps\n *\n * Myers is O((N+M)D): fast when the two texts are close, which is the case that matters, and\n * quadratic when they are not. Both bounds below are stated in the output when they bite, because\n * a diff that silently stops is worse than no diff: a reviewer who cannot see the truncation reads\n * the visible hunks as the whole story.\n */\n\n/** The two bounds, and the context width. */\nexport interface DiffLimits {\n /** Longest file, in lines, this will diff line by line. */\n maxLines: number;\n /** Largest edit script, in inserted plus deleted lines, before it gives up. */\n maxEdits: number;\n /** Unchanged lines kept around each hunk. Three is what `diff -u` and `git` use. */\n context: number;\n}\n\nexport const DEFAULT_DIFF_LIMITS: DiffLimits = {\n maxLines: 4000,\n maxEdits: 1500,\n context: 3,\n};\n\ntype Op = { kind: 'equal' | 'insert' | 'delete'; a: number; b: number };\n\n/**\n * Split into lines, keeping the fact of a trailing newline separate.\n *\n * `'a\\nb\\n'.split('\\n')` is `['a', 'b', '']`, and that empty string is not a line; carrying it\n * would put a spurious empty line at the end of every hunk that reaches the end of a file. So it\n * is dropped and remembered, which is also what produces the `\` marker\n * when only one side has it.\n */\nfunction toLines(text: string): { lines: string[]; newlineAtEnd: boolean } {\n if (text === '') return { lines: [], newlineAtEnd: true };\n const newlineAtEnd = text.endsWith('\\n');\n const lines = text.split('\\n');\n if (newlineAtEnd) lines.pop();\n return { lines, newlineAtEnd };\n}\n\n/**\n * Myers' shortest edit script, capped.\n *\n * The published greedy algorithm: for each edit distance `d`, walk the diagonals reachable with\n * `d` edits and take the furthest point on each. `trace` keeps the frontier per `d` so the path\n * can be walked back afterwards, which is what turns \"the distance is 4\" into \"these four lines\".\n *\n * Returns `null` when the distance exceeds `maxEdits`, which the caller reports rather than hides.\n */\nfunction shortestEdit(a: string[], b: string[], maxEdits: number): Int32Array[] | null {\n const n = a.length;\n const m = b.length;\n const max = n + m;\n const offset = max;\n const v = new Int32Array(2 * max + 1);\n const trace: Int32Array[] = [];\n const limit = Math.min(max, maxEdits);\n\n for (let d = 0; d <= limit; d++) {\n trace.push(Int32Array.prototype.slice.call(v));\n for (let k = -d; k <= d; k += 2) {\n let x: number;\n if (k === -d || (k !== d && v[k - 1 + offset] < v[k + 1 + offset])) x = v[k + 1 + offset];\n else x = v[k - 1 + offset] + 1;\n let y = x - k;\n while (x < n && y < m && a[x] === b[y]) {\n x++;\n y++;\n }\n v[k + offset] = x;\n if (x >= n && y >= m) return trace;\n }\n }\n return null;\n}\n\n/** Walk the frontier back from the end, producing the operations in order. */\nfunction backtrack(trace: Int32Array[], a: string[], b: string[]): Op[] {\n const max = a.length + b.length;\n const offset = max;\n let x = a.length;\n let y = b.length;\n const ops: Op[] = [];\n\n for (let d = trace.length - 1; d >= 0; d--) {\n const v = trace[d];\n const k = x - y;\n let prevK: number;\n if (k === -d || (k !== d && v[k - 1 + offset] < v[k + 1 + offset])) prevK = k + 1;\n else prevK = k - 1;\n const prevX = v[prevK + offset];\n const prevY = prevX - prevK;\n\n while (x > prevX && y > prevY) {\n x--;\n y--;\n ops.push({ kind: 'equal', a: x, b: y });\n }\n if (d > 0) {\n if (x === prevX) {\n y--;\n ops.push({ kind: 'insert', a: x, b: y });\n } else {\n x--;\n ops.push({ kind: 'delete', a: x, b: y });\n }\n }\n }\n ops.reverse();\n return ops;\n}\n\n/**\n * The operations turning `a` into `b`, or `null` when a cap was hit.\n *\n * Common leading and trailing lines are stripped before Myers runs and put back as `equal`\n * afterwards. That is not an optimisation for its own sake: the pair this is asked about is\n * almost always a generated file against the same file with one table changed, where the shared\n * head and tail are the whole file bar a few lines, and stripping them takes the edit distance\n * that Myers has to search from thousands to single figures.\n */\nexport function diffLines(a: string[], b: string[], maxEdits: number): Op[] | null {\n let head = 0;\n while (head < a.length && head < b.length && a[head] === b[head]) head++;\n let tail = 0;\n while (\n tail < a.length - head &&\n tail < b.length - head &&\n a[a.length - 1 - tail] === b[b.length - 1 - tail]\n ) {\n tail++;\n }\n\n const midA = a.slice(head, a.length - tail);\n const midB = b.slice(head, b.length - tail);\n\n // Nothing left to compare once the shared head and tail are gone. Myers is skipped rather than\n // handed two empty arrays, where its `v` array is a single element and every neighbour lookup\n // reads past the end.\n let mid: Op[] = [];\n if (midA.length || midB.length) {\n const trace = shortestEdit(midA, midB, maxEdits);\n if (!trace) return null;\n mid = backtrack(trace, midA, midB);\n }\n\n const ops: Op[] = [];\n for (let i = 0; i < head; i++) ops.push({ kind: 'equal', a: i, b: i });\n for (const op of mid) ops.push({ kind: op.kind, a: op.a + head, b: op.b + head });\n for (let i = 0; i < tail; i++) {\n ops.push({ kind: 'equal', a: a.length - tail + i, b: b.length - tail + i });\n }\n return ops;\n}\n\nexport interface UnifiedDiffOptions {\n /** What the left side is called in the `---` header. */\n fromLabel: string;\n /** What the right side is called in the `+++` header. */\n toLabel: string;\n limits?: Partial<DiffLimits>;\n}\n\n/**\n * A unified diff, or a single line saying why there is not one.\n *\n * Returns the empty string when the two texts are identical, so a caller can treat \"no diff\" and\n * \"nothing to say\" the same way.\n */\nexport function unifiedDiff(before: string, after: string, opts: UnifiedDiffOptions): string {\n if (before === after) return '';\n const limits: DiffLimits = { ...DEFAULT_DIFF_LIMITS, ...(opts.limits ?? {}) };\n\n const from = toLines(before);\n const to = toLines(after);\n // A file that lost or gained only its final newline still differs, and every line of it still\n // compares equal, so without this the diff would be empty for a file the check has just called\n // out of date. Marking the last line of a side that has no trailing newline makes it a real\n // difference to Myers, and the marker is what `diff` itself prints for the same case.\n const beforeLines = withNoNewlineMark(from);\n const afterLines = withNoNewlineMark(to);\n\n if (from.lines.length > limits.maxLines || to.lines.length > limits.maxLines) {\n return (\n `--- ${opts.fromLabel}\\n+++ ${opts.toLabel}\\n` +\n `@@ no line diff @@\\n` +\n ` ${from.lines.length} lines on disk, ${to.lines.length} lines regenerated. ` +\n `Not diffed: the file is longer than the ${limits.maxLines}-line cap.\\n`\n );\n }\n\n const ops = diffLines(beforeLines, afterLines, limits.maxEdits);\n if (!ops) {\n return (\n `--- ${opts.fromLabel}\\n+++ ${opts.toLabel}\\n` +\n `@@ no line diff @@\\n` +\n ` ${from.lines.length} lines on disk, ${to.lines.length} lines regenerated. ` +\n `Not diffed: the two differ by more than the ${limits.maxEdits}-edit cap, ` +\n `so the whole file is effectively new.\\n`\n );\n }\n\n const hunks = buildHunks(ops, beforeLines, afterLines, limits.context);\n if (!hunks.length) return '';\n return `--- ${opts.fromLabel}\\n+++ ${opts.toLabel}\\n${hunks.join('')}`;\n}\n\nconst NO_NEWLINE = '\\\';\n\n/**\n * The sentinel a line with no newline after it carries while it is being compared.\n *\n * Two NUL characters and a word, because it has to be something a line of generated TypeScript\n * cannot be. It never reaches the output: `renderLine` strips it and prints the marker instead.\n */\nconst NO_NEWLINE_MARK = '\\u0000\\u0000drzl:no-newline';\n\nfunction withNoNewlineMark(side: { lines: string[]; newlineAtEnd: boolean }): string[] {\n if (side.newlineAtEnd || !side.lines.length) return side.lines;\n const marked = side.lines.slice();\n marked[marked.length - 1] += NO_NEWLINE_MARK;\n return marked;\n}\n\n/** One diff line: its prefix, its text, and the marker underneath it when it had no newline. */\nfunction renderLine(prefix: string, line: string, into: string[]): void {\n if (line.endsWith(NO_NEWLINE_MARK)) {\n into.push(prefix + line.slice(0, -NO_NEWLINE_MARK.length));\n into.push(NO_NEWLINE);\n return;\n }\n into.push(prefix + line);\n}\n\n/** Group the operations into hunks with `context` unchanged lines around each run of changes. */\nfunction buildHunks(\n ops: Op[],\n beforeLines: string[],\n afterLines: string[],\n context: number\n): string[] {\n const changed: number[] = [];\n ops.forEach((op, i) => {\n if (op.kind !== 'equal') changed.push(i);\n });\n if (!changed.length) return [];\n\n /** Ranges of operation indices to print, merged where their context windows touch. */\n const ranges: Array<[number, number]> = [];\n for (const i of changed) {\n const start = Math.max(0, i - context);\n const end = Math.min(ops.length - 1, i + context);\n const last = ranges[ranges.length - 1];\n if (last && start <= last[1] + 1) last[1] = Math.max(last[1], end);\n else ranges.push([start, end]);\n }\n\n const hunks: string[] = [];\n for (const [start, end] of ranges) {\n let aStart = -1;\n let bStart = -1;\n let aCount = 0;\n let bCount = 0;\n const body: string[] = [];\n\n for (let i = start; i <= end; i++) {\n const op = ops[i];\n if (op.kind === 'equal' || op.kind === 'delete') {\n if (aStart < 0) aStart = op.a;\n aCount++;\n }\n if (op.kind === 'equal' || op.kind === 'insert') {\n if (bStart < 0) bStart = op.b;\n bCount++;\n }\n if (op.kind === 'equal') renderLine(' ', beforeLines[op.a], body);\n else if (op.kind === 'delete') renderLine('-', beforeLines[op.a], body);\n else renderLine('+', afterLines[op.b], body);\n }\n\n // A hunk covering nothing on one side is numbered from 0, which is what `diff -u` emits for a\n // pure insertion into an empty file.\n const aFrom = aCount === 0 ? 0 : aStart + 1;\n const bFrom = bCount === 0 ? 0 : bStart + 1;\n hunks.push(`@@ -${aFrom},${aCount} +${bFrom},${bCount} @@\\n${body.join('\\n')}\\n`);\n }\n return hunks;\n}\n","/**\n * When `drzl watch` rebuilds, and how many rebuilds one burst of saves is allowed to become\n * (plan item 75).\n *\n * ## What was measured\n *\n * The watcher already had a debounce, so the item reads as done until you watch it run. The\n * debounce covers the *wait* and not the *work*: `setTimeout(run, 200)` collapses changes arriving\n * within 200ms of each other and then starts a rebuild that takes as long as it takes. Every\n * change arriving during that rebuild starts another one 200ms later, on top of the first, writing\n * the same files.\n *\n * Measured against the shipped 4.22 build, with a 600-table schema where one rebuild takes about\n * 1.4s, saving two files alternately 700ms apart:\n *\n * 32370ms START in flight 1\n * 33195ms START in flight 2\n * 33814ms START in flight 3\n * 34379ms END in flight 2\n * 34475ms START in flight 3\n * 35174ms START in flight 4 <- four rebuilds writing one output directory\n *\n * Six saves, six rebuilds, four of them running at once. Each one reloads the config, re-resolves\n * the schema, re-runs the analysis and rewrites every generated file, so the last writer wins per\n * file with no ordering between them.\n *\n * Chokidar's own `awaitWriteFinish` is why this is not worse: with a 400ms stability threshold, one\n * save of one file arrives as exactly one event, so the ordinary case never reached the overlap.\n * The bursts that do reach it are the ones that span a rebuild, which is any refactor across a\n * schema split into several modules.\n *\n * ## What this does about it\n *\n * One rebuild in flight at a time, and a change arriving during one is remembered rather than\n * dropped, so it gets exactly one rebuild afterwards however many changes arrived. The alternative,\n * refusing a change while busy, loses edits, which is worse than the overlap it fixes.\n */\n\n/** What `--debounce` means when it is not given, or is given something that is not a number. */\nexport const DEFAULT_WATCH_DEBOUNCE_MS = 200;\n\n/**\n * How long `watch` waits after the last change before rebuilding.\n *\n * 200ms is kept, and it is kept because it was measured rather than because it was already there.\n * With the `awaitWriteFinish: { stabilityThreshold: 400 }` this watcher passes chokidar, one\n * logical save reaches the trigger as a single event in every shape tested, and the widest gap\n * inside one burst was 9ms, from a tool rewriting two files back to back. With `awaitWriteFinish`\n * off, which is what a future version of this file might reach for to cut the 400ms it adds to\n * every rebuild, the same bursts spread out: a chunked write became five events with a 62ms\n * maximum gap, an atomic save became three events spanning 101ms, and format-on-save became two\n * events 121ms apart. 200ms covers the widest of those with headroom and is short enough that a\n * save still feels immediate. Every one of those numbers was taken with chokidar 5 on this\n * filesystem, under both inotify and polling.\n *\n * `0` is accepted and means \"rebuild on the next tick\", which is what the tests want and what\n * somebody debugging the watcher wants. It was previously impossible: `Number(opts.debounce) ||\n * 200` reads `0` as absent and silently used 200, and read `--debounce banana` as absent too. A\n * value that cannot be honoured now says so rather than being quietly replaced.\n */\nexport function resolveDebounce(value: unknown, warn: (message: string) => void): number {\n if (value === undefined || value === null || value === '') return DEFAULT_WATCH_DEBOUNCE_MS;\n const ms = Number(value);\n if (!Number.isFinite(ms) || ms < 0) {\n warn(\n `--debounce ${String(value)} is not a number of milliseconds. ` +\n `Using ${DEFAULT_WATCH_DEBOUNCE_MS}ms.`\n );\n return DEFAULT_WATCH_DEBOUNCE_MS;\n }\n return ms;\n}\n\nexport interface RebuildScheduler {\n /** A file changed. Rebuild after the debounce, or after the rebuild already running. */\n trigger(): void;\n /** Rebuild now, skipping the debounce, still one at a time. The startup build uses this. */\n runNow(): Promise<void>;\n /** Drop a pending debounce. Nothing calls this in the CLI; tests and a shutdown path do. */\n cancel(): void;\n /** Whether a rebuild is in flight. Exposed for tests rather than for the CLI. */\n readonly busy: boolean;\n}\n\nexport interface RebuildSchedulerOptions {\n run: () => Promise<void>;\n debounceMs: number;\n /**\n * Injected so a test does not have to spend real milliseconds.\n *\n * Defaults to the global timers. A fake clock is the difference between a debounce test that\n * takes 5ms and one that takes a second and is flaky on a loaded CI machine.\n */\n timers?: {\n setTimeout: (fn: () => void, ms: number) => unknown;\n clearTimeout: (handle: unknown) => void;\n };\n}\n\nexport function createRebuildScheduler(options: RebuildSchedulerOptions): RebuildScheduler {\n const timers = options.timers ?? {\n setTimeout: (fn: () => void, ms: number) => setTimeout(fn, ms),\n clearTimeout: (handle: unknown) => clearTimeout(handle as NodeJS.Timeout),\n };\n\n let handle: unknown = null;\n let running = false;\n let pending = false;\n\n const drain = async () => {\n if (running) {\n // Remembered, not merged: the rebuild in flight has already read the old file, so a change\n // that arrives now needs its own pass. One pass, however many changes arrive, because they\n // will all be on disk by the time it reads them.\n pending = true;\n return;\n }\n running = true;\n try {\n await options.run();\n while (pending) {\n pending = false;\n await options.run();\n }\n } finally {\n running = false;\n pending = false;\n }\n };\n\n return {\n trigger() {\n if (handle !== null) timers.clearTimeout(handle);\n handle = timers.setTimeout(() => {\n handle = null;\n void drain();\n }, options.debounceMs);\n },\n runNow() {\n return drain();\n },\n cancel() {\n if (handle !== null) timers.clearTimeout(handle);\n handle = null;\n },\n get busy() {\n return running;\n },\n };\n}\n","/**\n * `drzl init`: find the schema, ask what to generate, write a config that runs.\n *\n * Three defects were fixed here at once, and they are one command's worth of work because each\n * one is the reason the next is hard to see (plan items 65, 66, 67).\n *\n * **The schema path was invented (67).** `init` wrote `schema: 'src/db/schema.ts'` whether or\n * not that file existed. Measured on the shipped 4.22.0 CLI, in an empty directory: `init`\n * exits 0, and the `drzl generate` that follows it analyzes nothing, writes\n * `src/api/placeholder.orpc.ts` reading \"No tables detected in analysis\", and also exits 0. The\n * first two commands a new user runs therefore both report success having read no schema at\n * all. So detection is not a convenience here; it is what stops the product from lying on its\n * first run.\n *\n * Detection validates a candidate by loading it and counting Drizzle tables, never by\n * `existsSync`. The analyzer separates the three answers cleanly, which is what makes the rule\n * possible (measured against `@drzl/analyzer` 1.20.1):\n *\n * - a real schema -> `tables.length > 0`, no issues\n * - a file that is not one -> `tables.length === 0`, no issues, dialect 'unknown'\n * - a file it could not run -> `tables.length === 0` plus a `DRZL_ANL_IMPORT` error issue\n *\n * The middle case is rejected and the walk continues, because a `schema.ts` that exports a\n * connection string is worse than no detection: it produces exactly the silent placeholder run\n * above. The last case is adopted with a warning rather than rejected, because \"DRZL could not\n * import it\" is usually \"you have not run install yet\", and the file is still obviously the\n * schema the user meant.\n *\n * **The default generator was a router (66).** `@drzl/generator-zod` is a hard dependency of\n * `@drzl/cli`, so it is on disk beside the CLI that scaffolds this config. That used to be the\n * whole rule, because six of the seven route generators were `optionalDependencies` an installer\n * skips when they are missing; all fourteen are hard dependencies now, so being installed no\n * longer tells one kind from another. What `INIT_GENERATOR_CHOICES` still offers is the set this\n * file knows how to write a config for, and a test asserts every entry against `package.json` so\n * a kind the CLI does not depend on cannot be added to the list.\n *\n * **`--yes` did nothing (65).** The flag was declared and the action ignored its options object,\n * so `init` and `init --yes` were byte-identical. The flag is kept and given the meaning it\n * always advertised, because the non-interactive path is the important one: `init` runs under\n * `npx`, in CI and under agents far more often than it runs under a human. Prompts are the\n * addition, and they are guarded so that they can never be the reason a pipeline stops:\n * `isInteractive` requires stdin AND stdout to be TTYs and `CI` to be unset, and no readline\n * interface is constructed otherwise.\n */\nimport { SchemaAnalyzer } from '@drzl/analyzer';\nimport * as fs from 'node:fs';\nimport * as path from 'node:path';\nimport type * as readline from 'node:readline/promises';\nimport { CONFIG_FILE_NAMES } from './config.js';\nimport { resolveSchemaSource } from './drizzle-kit.js';\n\n/** A generator `init` is willing to scaffold. */\nexport interface InitGeneratorChoice {\n kind: string;\n /** The npm package the kind loads, which must be a hard dependency of `@drzl/cli`. */\n packageName: string;\n label: string;\n}\n\n/**\n * What `init` offers, in the order the prompt lists it. The first entry is the default.\n *\n * Every kind here is a `dependencies` entry of `@drzl/cli`, enforced against `package.json` by\n * `init.spec.ts`, so a config this command writes never names a package the CLI does not bring\n * with it. That used to exclude eight kinds on its own, when they were `optionalDependencies` an\n * installer skips; every kind clears it now, and it stays as the floor rather than as the filter.\n *\n * What the list is short for is this file: `generatorLine` writes two shapes, an oRPC entry and a\n * validator entry with a `path`, and `ROUTER_KINDS` is the one kind the scaffold adds an `outDir`\n * for. The six other route generators each resolve their output directory their own way\n * (`trpcOutDir`, `honoOutDir` and the rest in `config.ts`), and none of those rules is written\n * here. Offering them would scaffold a config this command does not know the shape of, which is a\n * different job from installing one.\n */\nexport const INIT_GENERATOR_CHOICES: readonly InitGeneratorChoice[] = [\n { kind: 'zod', packageName: '@drzl/generator-zod', label: 'Zod validators' },\n { kind: 'valibot', packageName: '@drzl/generator-valibot', label: 'Valibot validators' },\n { kind: 'arktype', packageName: '@drzl/generator-arktype', label: 'ArkType validators' },\n { kind: 'typebox', packageName: '@drzl/generator-typebox', label: 'TypeBox validators' },\n { kind: 'orpc', packageName: '@drzl/generator-orpc', label: 'oRPC router' },\n];\n\n/** The kind chosen when nothing says otherwise: `--yes`, a non-TTY, or an empty prompt answer. */\nexport const DEFAULT_GENERATOR_KIND = INIT_GENERATOR_CHOICES[0].kind;\n\n/** The kinds that write routers, and so need an `outDir` in the scaffold. */\nconst ROUTER_KINDS = new Set(['orpc']);\n\n/**\n * Where a Drizzle schema conventionally lives, most specific first, as stems without an\n * extension.\n *\n * Not invented. `src/db/schema.ts` and `src/db/schemas/index.ts` are the two paths this\n * repository's own docs use (34 and 8 occurrences across `docs/`, the READMEs and `examples/`),\n * and the rest are the same two shapes under the other roots frameworks put source in, plus\n * `drizzle/`, which is where a kit `out` directory conventionally sits. Being wrong about any\n * one of them costs nothing: an entry that does not exist is never opened, and an entry that\n * exists still has to declare tables before it is used.\n *\n * Every stem ends in `schema` or `schemas`, and that is a rule rather than a coincidence: a\n * candidate is validated by importing it, and importing `src/db/index.ts` on the guess that it\n * might re-export tables would just as often open a database connection. A module named for the\n * schema is one that declares rather than connects.\n */\nexport const SCHEMA_CANDIDATE_STEMS: readonly string[] = [\n 'src/db/schema',\n 'src/db/schema/index',\n 'src/db/schemas/index',\n 'src/lib/db/schema',\n 'src/lib/db/schema/index',\n 'src/schema',\n 'src/schema/index',\n 'src/schemas/index',\n 'app/db/schema',\n 'lib/db/schema',\n 'db/schema',\n 'db/schema/index',\n 'drizzle/schema',\n 'schema',\n];\n\n/** Extensions tried for each stem, in order. */\nconst CANDIDATE_EXTENSIONS = ['.ts', '.js'] as const;\n\n/** Every conventional candidate path, in the order they are tried. */\nexport function schemaCandidates(): string[] {\n const out: string[] = [];\n for (const stem of SCHEMA_CANDIDATE_STEMS) {\n for (const ext of CANDIDATE_EXTENSIONS) out.push(`${stem}${ext}`);\n }\n return out;\n}\n\nexport type CandidateVerdict =\n /** Imported, and Drizzle tables came back. */\n | 'confirmed'\n /** Present, but could not be imported at all, so it is neither proved nor disproved. */\n | 'unverified'\n /** Imported cleanly and declares no tables, so it is not a schema. */\n | 'rejected';\n\nexport interface CandidateReport {\n verdict: CandidateVerdict;\n tables: number;\n /** The import failure, when there was one. */\n reason?: string;\n}\n\n/**\n * Load a candidate and decide what it is. Never throws: an analyzer that blows up on a file is\n * itself an answer, and the caller has more candidates to try.\n */\nexport async function classifySchemaCandidate(target: string | string[]): Promise<CandidateReport> {\n let analysis: Awaited<ReturnType<SchemaAnalyzer['analyze']>>;\n try {\n // Relations and constraint validation are both off. Neither changes whether a table exists,\n // and both cost time on a file that is about to be thrown away.\n analysis = await new SchemaAnalyzer(target).analyze({\n includeRelations: false,\n validateConstraints: false,\n });\n } catch (e: any) {\n return { verdict: 'unverified', tables: 0, reason: firstLine(String(e?.message ?? e)) };\n }\n if (analysis.tables.length > 0) {\n return { verdict: 'confirmed', tables: analysis.tables.length };\n }\n const importError = analysis.issues.find(\n (i) => i.level === 'error' && i.code === 'DRZL_ANL_IMPORT'\n );\n if (importError)\n return { verdict: 'unverified', tables: 0, reason: firstLine(importError.message) };\n return { verdict: 'rejected', tables: 0 };\n}\n\n/**\n * The first line of a message, for a reason printed inline. A module resolution failure carries\n * its whole \"Require stack\" behind the first newline, and pasting that into the middle of a\n * sentence buries the sentence.\n */\nfunction firstLine(message: string): string {\n return String(message).split('\\n')[0].trim();\n}\n\nexport interface SchemaDetection {\n source: 'drizzle-kit' | 'convention' | 'none';\n /**\n * The relative path to write as `schema`, or undefined when the config should state none: a\n * drizzle-kit project states it once in its own config, and a project with no schema at all\n * must not be handed a path that is not there.\n */\n schema?: string;\n /** The drizzle-kit config consulted, when one answered. */\n drizzleKitConfig?: string;\n verdict?: CandidateVerdict;\n tables: number;\n /** Lines worth printing: what was found, or what was looked for and rejected. */\n notes: string[];\n}\n\n/**\n * Decide where the schema is, drizzle-kit first.\n *\n * The kit config is asked first because it is the only source that is a statement of fact\n * rather than a guess: the user wrote the path there themselves. `resolveSchemaSource` is the\n * whole of item 59's walk (candidate order, jiti load, glob expansion, kit's own one-level\n * directory expansion), so `init` and `generate` can never disagree about what that config\n * says.\n */\nexport async function detectSchema(cwd: string): Promise<SchemaDetection> {\n const notes: string[] = [];\n\n let kitFiles: string[] | null = null;\n let kitPath: string | undefined;\n try {\n // No `schema` and no `drizzleKit` key: exactly the shape that makes `resolveSchemaSource`\n // walk drizzle-kit's own default candidates. It throws when there is no kit config, which\n // is the common case and not an error here.\n const source = await resolveSchemaSource({}, cwd);\n if (source.source === 'drizzle-kit') {\n kitFiles = source.schema as string[];\n kitPath = source.drizzleKitConfigPath;\n }\n } catch {\n kitFiles = null;\n }\n\n if (kitFiles && kitPath) {\n const rel = path.relative(cwd, kitPath) || path.basename(kitPath);\n const report = await classifySchemaCandidate(kitFiles);\n if (report.verdict === 'confirmed' || report.verdict === 'unverified') {\n notes.push(\n report.verdict === 'confirmed'\n ? `Schema from ${rel} (${kitFiles.length} file${kitFiles.length === 1 ? '' : 's'}, ` +\n `${report.tables} table${report.tables === 1 ? '' : 's'})`\n : `Schema from ${rel}, which DRZL could not import yet: ${report.reason}`\n );\n return {\n source: 'drizzle-kit',\n drizzleKitConfig: rel,\n verdict: report.verdict,\n tables: report.tables,\n notes,\n };\n }\n notes.push(`${rel} names schema files that declare no Drizzle tables; looking elsewhere.`);\n }\n\n // Confirmed wins outright: the walk returns on the first confirmed candidate and only\n // collects the unverified ones, so a real schema further down the list beats a file near the\n // top that DRZL could not import. Within one verdict the convention order decides.\n const present = schemaCandidates().filter((c) => fs.existsSync(path.resolve(cwd, c)));\n const unverified: Array<{ file: string; report: CandidateReport }> = [];\n for (const file of present) {\n const report = await classifySchemaCandidate(path.resolve(cwd, file));\n if (report.verdict === 'confirmed') {\n notes.push(\n `Schema found at ${file} (${report.tables} table${report.tables === 1 ? '' : 's'})`\n );\n return {\n source: 'convention',\n schema: file,\n verdict: 'confirmed',\n tables: report.tables,\n notes,\n };\n }\n if (report.verdict === 'unverified') unverified.push({ file, report });\n else notes.push(`${file} exists but declares no Drizzle tables; not using it.`);\n }\n if (unverified.length) {\n const { file, report } = unverified[0];\n notes.push(`Schema assumed to be ${file}; DRZL could not import it: ${report.reason}`);\n return { source: 'convention', schema: file, verdict: 'unverified', tables: 0, notes };\n }\n\n notes.push(\n present.length\n ? 'No file DRZL looked at declares any Drizzle tables.'\n : 'No drizzle-kit config and no schema in the usual locations.'\n );\n return { source: 'none', tables: 0, notes };\n}\n\nexport interface InitPlan {\n /** What to write as `schema`, or undefined to write none. */\n schema?: string;\n schemaSource: SchemaDetection['source'];\n /** Deduplicated, in `INIT_GENERATOR_CHOICES` order. */\n generators: string[];\n}\n\n/** The `generators` entry each kind scaffolds as. */\nfunction generatorLine(kind: string): string {\n if (kind === 'orpc') return `{ kind: 'orpc', template: 'standard', includeRelations: true }`;\n return `{ kind: '${kind}', path: 'src/validators/${kind}' }`;\n}\n\n/**\n * The config file text.\n *\n * `import type` plus `satisfies`, never `defineConfig`. The scaffold has to keep working under\n * `npx @drzl/cli init` in a project with no local `@drzl/cli` to resolve, and a type-only import\n * is erased before jiti ever executes the module. A value import would make the very first\n * `drzl generate` fail on a module that is not installed, and the annotation is what gives the\n * first config anyone sees editor completion.\n */\nexport function renderInitConfig(plan: InitPlan): string {\n const lines: string[] = [];\n lines.push(`import type { DrzlConfigInput } from '@drzl/cli/config';`);\n lines.push('');\n lines.push('export default {');\n\n if (plan.schema) {\n lines.push(` schema: '${plan.schema}',`);\n } else if (plan.schemaSource === 'drizzle-kit') {\n lines.push(` // No \"schema\" here on purpose: DRZL reads it from your drizzle-kit config, so`);\n lines.push(\n ` // the path is written once. Set \"schema\" to override it, or \"drizzleKit\": false`\n );\n lines.push(` // to refuse the fallback.`);\n } else {\n lines.push(` // Set this to your Drizzle schema file, for example 'src/db/schema.ts'. DRZL`);\n lines.push(` // found no drizzle-kit config and no schema declaring tables in the usual`);\n lines.push(` // locations, and will not name a file that is not there.`);\n lines.push(` // schema: 'src/db/schema.ts',`);\n }\n\n const hasRouter = plan.generators.some((k) => ROUTER_KINDS.has(k));\n if (hasRouter) lines.push(` outDir: 'src/api',`);\n lines.push(` analyzer: { includeRelations: true, validateConstraints: true },`);\n lines.push(' generators: [');\n const others = INIT_GENERATOR_CHOICES.filter((c) => !plan.generators.includes(c.kind))\n .map((c) => `'${c.kind}'`)\n .join(', ');\n if (others) lines.push(` // Other kinds this CLI already has installed: ${others}.`);\n // Only where it can bite. Two router generators default to the same `outDir` and would each\n // write an `index.ts` into it, so the second silently overwrites the first; a config with no\n // router in it cannot reach that, and the line is noise there.\n if (hasRouter) {\n lines.push(' // A second router generator needs its own \"path\"; they share \"outDir\".');\n }\n // Trailing commas and a closing semicolon. Without them Prettier rewrites the scaffold the\n // first time a project formats anything, putting a diff on a file nobody edited. Measured:\n // `prettier --single-quote --check` on the emitted config passes, and the only thing Prettier\n // still changes under its own defaults is the quote style, which no scaffold can satisfy both\n // ways at once.\n for (const kind of plan.generators) lines.push(` ${generatorLine(kind)},`);\n lines.push(' ],');\n lines.push('} satisfies DrzlConfigInput;');\n return lines.join('\\n') + '\\n';\n}\n\n/**\n * Whether to ask anything at all.\n *\n * Both streams, not just stdin. A question printed down a redirected stdout is invisible, so\n * waiting for its answer is a hang from the only point of view that matters. `CI` is checked\n * too because some runners do allocate a pty, and a hung `init` in a pipeline is a worse defect\n * than the one prompts were added to fix.\n */\nexport function isInteractive(ctx: {\n stdin: { isTTY?: boolean };\n stdout: { isTTY?: boolean };\n env: Record<string, string | undefined>;\n}): boolean {\n if (ctx.env.CI) return false;\n return Boolean(ctx.stdin.isTTY) && Boolean(ctx.stdout.isTTY);\n}\n\n/**\n * One question. `null` means there are no more answers coming, from any cause: the stream\n * closed, or the user pressed Ctrl+D, which readline in TTY mode reports by rejecting with an\n * AbortError rather than by closing. Callers take their default and stop asking.\n */\nasync function ask(rl: readline.Interface, question: string): Promise<string | null> {\n const closed = new Promise<null>((resolve) => rl.once('close', () => resolve(null)));\n try {\n return await Promise.race([rl.question(question), closed]);\n } catch {\n return null;\n }\n}\n\nexport interface PromptResult extends InitPlan {\n /** True when input ran out and the remaining questions took their defaults. */\n endedEarly: boolean;\n}\n\n/**\n * Ask what the flags did not already answer.\n *\n * The streams are parameters rather than `process.stdin`/`process.stdout` so the prompt logic is\n * driven by a test on ordinary pipes. Deciding *whether* to call this is `isInteractive`'s job,\n * and it is the only thing that reads `isTTY`.\n */\nexport async function promptForPlan(args: {\n input: NodeJS.ReadableStream;\n output: NodeJS.WritableStream;\n detection: SchemaDetection;\n cwd: string;\n schemaFromFlag?: string;\n generatorsFromFlag?: string[];\n}): Promise<PromptResult> {\n const { input, output, detection, cwd } = args;\n const write = (s: string) => output.write(s + '\\n');\n\n let schema = args.schemaFromFlag ?? detection.schema;\n let schemaSource: SchemaDetection['source'] = args.schemaFromFlag\n ? 'convention'\n : detection.source;\n let generators = args.generatorsFromFlag;\n let endedEarly = false;\n\n // Loaded here rather than at the top of the module, so a runtime whose `node:readline/promises`\n // is missing or partial cannot break the non-interactive path, which is the one that runs under\n // `npx`, in CI and under Bun and Deno. If it cannot be loaded at all, the defaults are taken\n // and nothing is asked: a command that degrades to `--yes` is a nuisance, and one that throws\n // where it used to write a config is a regression.\n let readlineModule: typeof readline;\n try {\n readlineModule = await import('node:readline/promises');\n } catch {\n return {\n schema,\n schemaSource,\n generators: normalizeGenerators(generators) ?? [DEFAULT_GENERATOR_KIND],\n endedEarly: true,\n };\n }\n const rl = readlineModule.createInterface({ input, output });\n try {\n if (args.schemaFromFlag === undefined) {\n for (const note of detection.notes) write(note);\n const prompt =\n detection.source === 'drizzle-kit'\n ? 'Schema file, or Enter to keep reading it from your drizzle-kit config: '\n : detection.schema\n ? `Schema file [${detection.schema}]: `\n : 'Schema file (Enter to leave it unset): ';\n const answer = await ask(rl, prompt);\n if (answer === null) endedEarly = true;\n else if (answer.trim()) {\n const typed = answer.trim();\n const report = await classifySchemaCandidate(path.resolve(cwd, typed));\n if (report.verdict === 'confirmed') {\n write(` ${typed}: ${report.tables} table${report.tables === 1 ? '' : 's'}`);\n } else if (report.verdict === 'unverified') {\n write(` ${typed}: DRZL could not import it (${report.reason}). Using it anyway.`);\n } else {\n write(` ${typed}: no Drizzle tables found in it. Using it anyway.`);\n }\n schema = typed;\n schemaSource = 'convention';\n }\n }\n\n if (generators === undefined && !endedEarly) {\n write('What should DRZL generate?');\n INIT_GENERATOR_CHOICES.forEach((c, i) => write(` ${i + 1}) ${c.label}`));\n // Bounded, so a stream of nonsense cannot keep this open. Every exit from the loop either\n // has an answer or falls through to the default.\n for (let attempt = 0; attempt < 3; attempt++) {\n const answer = await ask(rl, `Choice [1, ${INIT_GENERATOR_CHOICES[0].label}]: `);\n if (answer === null) {\n endedEarly = true;\n break;\n }\n const raw = answer.trim().toLowerCase();\n if (!raw) break;\n const byIndex = Number(raw);\n const picked =\n Number.isInteger(byIndex) && byIndex >= 1 && byIndex <= INIT_GENERATOR_CHOICES.length\n ? INIT_GENERATOR_CHOICES[byIndex - 1]\n : INIT_GENERATOR_CHOICES.find((c) => c.kind === raw);\n if (picked) {\n generators = [picked.kind];\n break;\n }\n write(` \"${answer.trim()}\" is not one of the choices.`);\n }\n }\n } finally {\n rl.close();\n }\n\n return {\n schema,\n schemaSource,\n generators: normalizeGenerators(generators) ?? [DEFAULT_GENERATOR_KIND],\n endedEarly,\n };\n}\n\n/**\n * Deduplicate and order a kind list, or throw naming the offender. Returns undefined for\n * undefined so a missing flag stays a question rather than becoming an empty answer.\n */\nexport function normalizeGenerators(kinds: string[] | undefined): string[] | undefined {\n if (kinds === undefined) return undefined;\n const known = new Set(INIT_GENERATOR_CHOICES.map((c) => c.kind));\n for (const k of kinds) {\n if (!known.has(k)) {\n throw new Error(\n `drzl init: \"${k}\" is not a generator init can scaffold. Choose from ` +\n `${[...known].join(', ')}. Every other kind is installed and works; add it to ` +\n `drzl.config by hand, following the entry for it in the docs.`\n );\n }\n }\n const picked = INIT_GENERATOR_CHOICES.filter((c) => kinds.includes(c.kind)).map((c) => c.kind);\n return picked.length ? picked : undefined;\n}\n\n/** Split a `--generators zod,orpc` value. */\nexport function parseGeneratorsFlag(value: string | undefined): string[] | undefined {\n if (value === undefined) return undefined;\n const parts = value\n .split(',')\n .map((s) => s.trim().toLowerCase())\n .filter(Boolean);\n if (!parts.length) throw new Error('drzl init: --generators was given no kinds.');\n return parts;\n}\n\nexport interface InitOutcome {\n code: number;\n /** Absolute path written, when one was. */\n written?: string;\n plan?: InitPlan;\n}\n\n/**\n * The whole command. Returns an exit code rather than calling `process.exit`, so a test can run\n * it in-process and so the caller owns the one exit in the CLI.\n */\nexport async function runInit(args: {\n cwd: string;\n yes?: boolean;\n schemaFlag?: string;\n generatorsFlag?: string;\n stdin: NodeJS.ReadableStream & { isTTY?: boolean };\n stdout: NodeJS.WritableStream & { isTTY?: boolean };\n env: Record<string, string | undefined>;\n log: (s: string) => void;\n error: (s: string) => void;\n}): Promise<InitOutcome> {\n const target = path.resolve(args.cwd, 'drzl.config.ts');\n\n // Before any detection, and before any question. Everything that follows costs a jiti import\n // of the user's schema, and none of it is worth doing for a config that will not be written.\n //\n // Every config name, not just `drzl.config.ts`. `loadConfig` tries the five names in a fixed\n // order with `.ts` first, so writing a `.ts` scaffold beside an existing `drzl.config.json`\n // does not overwrite that file and does something worse: it shadows it, and the next\n // `drzl generate` silently runs the scaffold instead of the config the user wrote. Measured on\n // 4.22.0, which checked only the one name.\n const existing = CONFIG_FILE_NAMES.find((name) => fs.existsSync(path.resolve(args.cwd, name)));\n if (existing) {\n args.error(\n `drzl init: ${existing} already exists, so nothing was written. Delete it, or edit it by ` +\n `hand; init never overwrites a config, and will not write one that shadows it either.`\n );\n return { code: 1 };\n }\n\n let fromFlag: string[] | undefined;\n try {\n fromFlag = normalizeGenerators(parseGeneratorsFlag(args.generatorsFlag));\n } catch (e: any) {\n args.error(String(e?.message ?? e));\n return { code: 1 };\n }\n\n const detection = await detectSchema(args.cwd);\n\n let plan: InitPlan;\n const interactive =\n !args.yes && isInteractive({ stdin: args.stdin, stdout: args.stdout, env: args.env });\n\n if (interactive) {\n const result = await promptForPlan({\n input: args.stdin,\n output: args.stdout,\n detection,\n cwd: args.cwd,\n schemaFromFlag: args.schemaFlag,\n generatorsFromFlag: fromFlag,\n });\n plan = {\n schema: result.schema,\n schemaSource: result.schemaSource,\n generators: result.generators,\n };\n } else {\n for (const note of detection.notes) args.log(note);\n plan = {\n schema: args.schemaFlag ?? detection.schema,\n schemaSource: args.schemaFlag ? 'convention' : detection.source,\n generators: fromFlag ?? [DEFAULT_GENERATOR_KIND],\n };\n // An explicit flag is always obeyed, because a user may be scaffolding before writing the\n // schema, but it is never obeyed silently: this is the one path that can put a path DRZL\n // could not confirm into the config, and detection's whole point is that such a config runs\n // and reports success having read nothing.\n if (args.schemaFlag) {\n const full = path.resolve(args.cwd, args.schemaFlag);\n if (!fs.existsSync(full)) {\n args.log(`--schema ${args.schemaFlag} is not there yet. Writing it anyway.`);\n } else if ((await classifySchemaCandidate(full)).verdict === 'rejected') {\n args.log(`--schema ${args.schemaFlag} declares no Drizzle tables. Writing it anyway.`);\n }\n }\n }\n\n // `wx`, so two `init` runs racing each other cannot both believe they created the file. The\n // existsSync above is the message; this is the guarantee.\n try {\n fs.writeFileSync(target, renderInitConfig(plan), { flag: 'wx' });\n } catch (e: any) {\n if (e?.code === 'EEXIST') {\n args.error(\n `drzl init: drzl.config.ts already exists, so nothing was written. init never ` +\n `overwrites a config.`\n );\n return { code: 1 };\n }\n args.error(`drzl init: could not write ${target}: ${e?.message ?? e}`);\n return { code: 1 };\n }\n\n args.log(`Created ${target}`);\n args.log(` generators: ${plan.generators.join(', ')}`);\n if (plan.schema) args.log(` schema: ${plan.schema}`);\n else if (plan.schemaSource === 'drizzle-kit') args.log(' schema: from your drizzle-kit config');\n else\n args.log(\n ' schema: not set. Fill in \"schema\" before running `drzl generate`, or add a ' +\n 'drizzle-kit config.'\n );\n return { code: 0, written: target, plan };\n}\n","import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs';\nimport path from 'node:path';\nimport { Output } from './output.js';\n\nexport interface SponsorMessageOptions {\n reason?: string;\n minIntervalMs?: number;\n force?: boolean;\n /**\n * Where to write, and whether to write at all.\n *\n * This used to be `console.log`, which put an advertisement on stdout in the middle of the file\n * list a script was parsing: 246 bytes of it, measured on 4.22.0. It is narration, so it goes to\n * stderr, and `Output.wantsAsides` is what decides whether an unrequested aside has a reader:\n * not under `--quiet`, not under `--json`, and not when stderr is a pipe, because a tip written\n * into somebody's build log is only noise. The pre-existing `CI` gate below is the same idea\n * arrived at one environment at a time.\n */\n out?: Output;\n}\n\ninterface SponsorCachePayload {\n runs: number;\n lastShownAt?: number;\n lastReason?: string;\n}\n\nconst CACHE_DIR = path.join(process.cwd(), 'node_modules', '.cache', '@drzl');\nconst CACHE_FILE = path.join(CACHE_DIR, 'sponsor-message.json');\nconst DEFAULT_INTERVAL_MS = 1000 * 60 * 15; // 15 minutes\nlet shownThisProcess = false;\n\nconst tips = [\n 'Pair DRZL watch mode with drizzle-kit to keep schema & API synced.',\n 'Templatize your ORPC routers to roll out new endpoints safely.',\n 'Need typed validators? Enable the zod, valibot, arktype, typebox, or effect generators.',\n 'Need JSON Schema or OpenAPI? The json-schema generator emits both, with no runtime dependency.',\n 'Use output headers to track generated files and trim noisy diffs.',\n];\n\nexport function maybeShowSponsorMessage({\n reason = 'generate',\n minIntervalMs = DEFAULT_INTERVAL_MS,\n force = false,\n out = new Output(),\n}: SponsorMessageOptions = {}) {\n const green = (msg: string) => out.errStyle.hex('#6ee7b7')(msg);\n const cyan = (msg: string) => out.errStyle.cyan(msg);\n const gray = (msg: string) => out.errStyle.gray(msg);\n\n const hideViaEnv = process.env.DRZL_HIDE_SPONSOR?.toLowerCase();\n const hideRequested = hideViaEnv === '1' || hideViaEnv === 'true';\n if (hideRequested || (process.env.CI && !force) || (shownThisProcess && !force)) return;\n if (!out.wantsAsides && !force) return;\n\n try {\n mkdirSync(CACHE_DIR, { recursive: true });\n const payload = readCache();\n payload.runs += 1;\n\n const now = Date.now();\n const shouldShow = force || now - (payload.lastShownAt ?? 0) >= minIntervalMs;\n\n if (shouldShow) {\n payload.lastShownAt = now;\n payload.lastReason = reason;\n }\n\n writeCache(payload);\n\n if (!shouldShow) return;\n\n shownThisProcess = true;\n const tip = tips[payload.runs % tips.length];\n\n out.stderr.write(\n `\\n${cyan(`🚀 DRZL finished a ${reason} run (#${payload.runs.toLocaleString()}).`)}\\n\\n` +\n `${green('✨ Sponsors keep DRZL shipping. Consider supporting ongoing dev:')}\\n` +\n ` ${green('GitHub Sponsors')} ${gray('→ https://github.com/sponsors/omar-dulaimi')}\\n\\n` +\n `${green('Pro tip:')} ${tip}\\n\\n`\n );\n } catch {\n // Swallow to avoid impacting generator success paths\n }\n}\n\nfunction readCache(): SponsorCachePayload {\n if (!existsSync(CACHE_FILE)) {\n return { runs: 0 };\n }\n try {\n const data = JSON.parse(readFileSync(CACHE_FILE, 'utf8')) as SponsorCachePayload;\n if (typeof data.runs !== 'number') return { runs: 0 };\n return data;\n } catch {\n return { runs: 0 };\n }\n}\n\nfunction writeCache(payload: SponsorCachePayload) {\n writeFileSync(CACHE_FILE, JSON.stringify(payload, null, 2), 'utf8');\n}\n","/**\n * The version `drzl --version` prints, read from the manifest that ships beside the build.\n *\n * It used to be the literal `'0.0.1'`, passed to `program.version()` when the CLI was scaffolded\n * and never touched again. That was true of exactly one release, the first: the registry lists 29\n * versions of `@drzl/cli`, and the other 28 printed `0.0.1` as well. Reading the manifest is the\n * only form that cannot drift, because it is the same file the registry took the version from.\n *\n * Nothing here falls back. A build that cannot find its own manifest, or finds someone else's, has\n * resolved somewhere it did not intend to, and a placeholder standing in for that is how the\n * original defect stayed invisible for 28 releases.\n */\nimport { readFileSync } from 'node:fs';\nimport * as path from 'node:path';\nimport { fileURLToPath } from 'node:url';\n\n/** The name the manifest beside this build must carry, which is what makes it ours. */\nconst PACKAGE_NAME = '@drzl/cli';\n\n/**\n * The directory holding the file this code ends up in, in every form it is reached.\n *\n * Three of them: `dist/cli.js`, `dist/cli.cjs`, and this file unbundled under ts-node, all three\n * run and checked. Only the CommonJS bundle has no `import.meta`; `tsup.config.ts` gives that\n * build a real value for `import.meta.url` rather than esbuild's empty one, so this needs no\n * branch. If that config is ever dropped, `fileURLToPath(undefined)` throws on load, so the\n * CommonJS bundle stops working loudly instead of reporting the wrong directory.\n */\nfunction moduleDir(): string {\n return path.dirname(fileURLToPath(import.meta.url));\n}\n\n/**\n * The `version` a named manifest declares, or a throw naming what was wrong with it.\n *\n * Split out from the caller below only so the three ways it refuses can be exercised without a\n * build. Nothing in the CLI passes a path.\n */\nexport function readVersionFrom(manifestPath: string): string {\n let raw: string;\n try {\n raw = readFileSync(manifestPath, 'utf8');\n } catch (e: any) {\n throw new Error(\n `${PACKAGE_NAME} cannot read its own version: no manifest at ${manifestPath} ` +\n `(${e?.message ?? String(e)}).`\n );\n }\n\n const manifest = JSON.parse(raw) as { name?: unknown; version?: unknown };\n\n if (manifest.name !== PACKAGE_NAME) {\n throw new Error(\n `${PACKAGE_NAME} looked for its own version in ${manifestPath} and found ` +\n `${JSON.stringify(manifest.name)}, so this build is not sitting where it thinks it is.`\n );\n }\n\n if (typeof manifest.version !== 'string' || manifest.version.length === 0) {\n throw new Error(`${manifestPath} declares no version, so there is nothing to report.`);\n }\n\n return manifest.version;\n}\n\n/**\n * The `version` field of this package's own manifest.\n *\n * Both bundles sit one level below it, in `dist/`, and so does `src/` when this file is run\n * unbundled, so one `..` covers every way it is reached. All three were run.\n */\nexport function readCliVersion(): string {\n return readVersionFrom(path.join(moduleDir(), '..', 'package.json'));\n}\n\nexport const CLI_VERSION = readCliVersion();\n"],"mappings":"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","names":["qualifiedTableName","SchemaAnalyzer","path","VALIDATOR_DEFAULT_DIRS","projectRelative","VALIDATOR_DEFAULT_DIRS","projectRelative","VALIDATOR_DEFAULT_DIRS","projectRelative","VALIDATOR_DEFAULT_DIRS","projectRelative","VALIDATOR_DEFAULT_DIRS","projectRelative","VALIDATOR_DEFAULT_DIRS","parseCheck","Chalk","path","parseCheck","Chalk","PLAIN","Chalk","describeShape","value","path","wrap","full","fs","path","fs","path","fs","path","handle","fs","path","firstLine","resolve","existsSync","writeFileSync","path","path","existsSync","writeFileSync","readFileSync","path","SchemaAnalyzer","fs","qualifiedTableName","watcher"]}
|