@drzl/validation-core 2.0.0 → 3.0.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/index.cjs CHANGED
@@ -100187,6 +100187,7 @@ __export(index_exports2, {
100187
100187
  moduleSpecifier: () => moduleSpecifier,
100188
100188
  pascalCase: () => pascalCase,
100189
100189
  resolveAffix: () => resolveAffix,
100190
+ resolveConfiguredImport: () => resolveConfiguredImport,
100190
100191
  schemaName: () => schemaName,
100191
100192
  selectColumns: () => selectColumns,
100192
100193
  typeName: () => typeName,
@@ -100196,6 +100197,8 @@ __export(index_exports2, {
100196
100197
  module.exports = __toCommonJS(index_exports2);
100197
100198
 
100198
100199
  // src/files.ts
100200
+ var import_node_fs = __toESM(require("fs"), 1);
100201
+ var import_node_path = __toESM(require("path"), 1);
100199
100202
  var IMPORT_EXTENSIONS = ["js", "none", "ts"];
100200
100203
  var DEFAULT_IMPORT_EXTENSION = "js";
100201
100204
  var TS_EXTENSIONS = [
@@ -100219,6 +100222,38 @@ function importSpecifier(relativePath, importExtension = DEFAULT_IMPORT_EXTENSIO
100219
100222
  function moduleSpecifier(tsName, fileSuffix, importExtension = DEFAULT_IMPORT_EXTENSION) {
100220
100223
  return importSpecifier(`./${moduleFileName(tsName, fileSuffix)}`, importExtension);
100221
100224
  }
100225
+ function resolveConfiguredImport(configured, outDirAbs, cwd, importExtension = DEFAULT_IMPORT_EXTENSION) {
100226
+ if (isPackageSpecifier(configured)) return configured;
100227
+ const targetAbs = import_node_path.default.isAbsolute(configured) ? configured : import_node_path.default.resolve(configured.startsWith(".") ? outDirAbs : cwd, configured);
100228
+ const withIndex = pointsAtDirectory(targetAbs) ? `${configured}/index` : configured;
100229
+ if (configured.startsWith(".")) {
100230
+ return importSpecifier(withTsExtension(withIndex), importExtension);
100231
+ }
100232
+ const resolved = pointsAtDirectory(targetAbs) ? import_node_path.default.join(targetAbs, "index") : targetAbs;
100233
+ const rel = import_node_path.default.relative(outDirAbs, resolved).split(import_node_path.default.sep).join("/");
100234
+ const prefixed = !rel ? "." : rel.startsWith(".") ? rel : `./${rel}`;
100235
+ return importSpecifier(withTsExtension(prefixed), importExtension);
100236
+ }
100237
+ function isPackageSpecifier(p5) {
100238
+ if (p5.startsWith(".") || import_node_path.default.isAbsolute(p5)) return false;
100239
+ if (p5.startsWith("@") || p5.includes(":")) return true;
100240
+ return !p5.includes("/");
100241
+ }
100242
+ function pointsAtDirectory(absPath) {
100243
+ try {
100244
+ return import_node_fs.default.statSync(absPath).isDirectory();
100245
+ } catch {
100246
+ for (const ext of [".ts", ".tsx", ".mts", ".cts", ".js", ".mjs", ".cjs"]) {
100247
+ if (import_node_fs.default.existsSync(`${absPath}${ext}`)) return false;
100248
+ }
100249
+ return !/\.[a-z]+$/i.test(import_node_path.default.basename(absPath));
100250
+ }
100251
+ }
100252
+ function withTsExtension(p5) {
100253
+ if (/\.(ts|tsx|mts|cts)$/.test(p5)) return p5;
100254
+ if (/\.(js|mjs|cjs)$/.test(p5)) return p5.replace(/\.(js|mjs|cjs)$/, ".ts");
100255
+ return `${p5}.ts`;
100256
+ }
100222
100257
 
100223
100258
  // src/naming.ts
100224
100259
  var NAME_MODES = ["insert", "update", "select"];
@@ -100327,12 +100362,11 @@ function validateAffix(affix, schemaSuffix) {
100327
100362
  }
100328
100363
 
100329
100364
  // src/index.ts
100330
- function isGeneratedColumn(c5, primaryKeyColumns) {
100331
- return c5.isGenerated || primaryKeyColumns.includes(c5.name);
100365
+ function isGeneratedColumn(c5, _primaryKeyColumns = []) {
100366
+ return c5.isGenerated;
100332
100367
  }
100333
100368
  function insertColumns(table) {
100334
- const pkCols = table.primaryKey?.columns ?? [];
100335
- return table.columns.filter((c5) => !isGeneratedColumn(c5, pkCols));
100369
+ return table.columns.filter((c5) => !isGeneratedColumn(c5));
100336
100370
  }
100337
100371
  function updateColumns(table) {
100338
100372
  const pkCols = table.primaryKey?.columns ?? [];
@@ -100384,6 +100418,7 @@ async function formatCode(code, filePath, fmt) {
100384
100418
  moduleSpecifier,
100385
100419
  pascalCase,
100386
100420
  resolveAffix,
100421
+ resolveConfiguredImport,
100387
100422
  schemaName,
100388
100423
  selectColumns,
100389
100424
  typeName,
package/dist/index.d.cts CHANGED
@@ -52,6 +52,34 @@ declare function importSpecifier(relativePath: string, importExtension?: ImportE
52
52
  * `./users.zod.js`.
53
53
  */
54
54
  declare function moduleSpecifier(tsName: string, fileSuffix: string, importExtension?: ImportExtension): string;
55
+ /**
56
+ * Turn a configured module path into a specifier the generated file can actually import.
57
+ *
58
+ * Options like `validation.importPath`, `dbImportPath` and `schemaImportPath` get written as
59
+ * project-relative paths, `src/validators/zod`, because that is how the rest of the config
60
+ * names directories. Emitted verbatim that is a *bare* specifier: Node and tsc look for a
61
+ * package of that name in node_modules and never consider the local file. The config in the
62
+ * getting-started guide produced three such imports, none of which resolved.
63
+ *
64
+ * Two questions have to be answered, and neither can be guessed from the string alone.
65
+ *
66
+ * **Package or path?** `zod` and `@acme/schemas` are package names and pass through untouched.
67
+ * A path containing a separator, or starting with `.`, is a path.
68
+ *
69
+ * **File or directory?** `src/db/connection` is usually a file and `src/validators/zod` a
70
+ * directory holding a barrel, and they look identical. So the filesystem is asked. Where the
71
+ * target does not exist yet, which happens when this generator runs before the one that writes
72
+ * it, an extensionless path is taken to be a directory, since these options name directories by
73
+ * convention and the one path that can be missing is a generated barrel.
74
+ *
75
+ * A path already relative keeps its own spelling and only has its extension corrected, so
76
+ * anyone who followed the older guidance and wrote `../validators/zod/index.js` is unaffected.
77
+ *
78
+ * @param configured what the user put in the config
79
+ * @param outDirAbs absolute directory the importing file is written to
80
+ * @param cwd project root a non-relative path is resolved against
81
+ */
82
+ declare function resolveConfiguredImport(configured: string, outDirAbs: string, cwd: string, importExtension?: ImportExtension): string;
55
83
 
56
84
  /**
57
85
  * One place that decides what a generated identifier is called.
@@ -195,10 +223,24 @@ interface ValidationRenderer<TOptions extends ValidationGenerateOptions = Valida
195
223
  renderIndex?(analysis: Analysis, opts?: TOptions): string;
196
224
  generate(opts: TOptions): Promise<string[]>;
197
225
  }
198
- declare function isGeneratedColumn(c: Column, primaryKeyColumns: string[]): boolean;
226
+ /**
227
+ * Whether the database generates this column's value, so it cannot be written.
228
+ *
229
+ * `primaryKeyColumns` is accepted for backwards compatibility and no longer consulted. It used
230
+ * to make every primary key count as generated, which dropped it from the insert schema whether
231
+ * or not the database supplied it. Right for a MySQL autoincrement column; wrong for a Postgres
232
+ * `integer('id').primaryKey()`, which Postgres does not generate, and for any natural key such
233
+ * as `text('slug').primaryKey()`. Those inserts became impossible to express: the required
234
+ * column was simply absent, with no way to provide it.
235
+ *
236
+ * Being a key says nothing about who supplies the value. `isGenerated` marks a column that
237
+ * cannot be written; `hasDefault` marks one that need not be, and those stay in the schema as
238
+ * optional.
239
+ */
240
+ declare function isGeneratedColumn(c: Column, _primaryKeyColumns?: string[]): boolean;
199
241
  declare function insertColumns(table: Table): Column[];
200
242
  declare function updateColumns(table: Table): Column[];
201
243
  declare function selectColumns(table: Table): Column[];
202
244
  declare function formatCode(code: string, filePath: string, fmt?: FormatOptions): Promise<any>;
203
245
 
204
- export { AFFIX_PROBE_TABLE, type AffixIssue, type AffixOptions, type AffixValue, DEFAULT_IMPORT_EXTENSION, DEFAULT_MODE_PREFIX, DEFAULT_SCHEMA_SUFFIX, DEFAULT_TYPE_SUFFIX, type FormatOptions, IMPORT_EXTENSIONS, type ImportExtension, NAME_MODES, type NameMode, type ResolvedAffix, type Table, type TableCase, type ValidationGenerateOptions, type ValidationLibrary, type ValidationRenderer, applyTableCase, formatCode, importSpecifier, insertColumns, isGeneratedColumn, moduleFileName, moduleSpecifier, pascalCase, resolveAffix, schemaName, selectColumns, typeName, updateColumns, validateAffix };
246
+ export { AFFIX_PROBE_TABLE, type AffixIssue, type AffixOptions, type AffixValue, DEFAULT_IMPORT_EXTENSION, DEFAULT_MODE_PREFIX, DEFAULT_SCHEMA_SUFFIX, DEFAULT_TYPE_SUFFIX, type FormatOptions, IMPORT_EXTENSIONS, type ImportExtension, NAME_MODES, type NameMode, type ResolvedAffix, type Table, type TableCase, type ValidationGenerateOptions, type ValidationLibrary, type ValidationRenderer, applyTableCase, formatCode, importSpecifier, insertColumns, isGeneratedColumn, moduleFileName, moduleSpecifier, pascalCase, resolveAffix, resolveConfiguredImport, schemaName, selectColumns, typeName, updateColumns, validateAffix };
package/dist/index.d.ts CHANGED
@@ -52,6 +52,34 @@ declare function importSpecifier(relativePath: string, importExtension?: ImportE
52
52
  * `./users.zod.js`.
53
53
  */
54
54
  declare function moduleSpecifier(tsName: string, fileSuffix: string, importExtension?: ImportExtension): string;
55
+ /**
56
+ * Turn a configured module path into a specifier the generated file can actually import.
57
+ *
58
+ * Options like `validation.importPath`, `dbImportPath` and `schemaImportPath` get written as
59
+ * project-relative paths, `src/validators/zod`, because that is how the rest of the config
60
+ * names directories. Emitted verbatim that is a *bare* specifier: Node and tsc look for a
61
+ * package of that name in node_modules and never consider the local file. The config in the
62
+ * getting-started guide produced three such imports, none of which resolved.
63
+ *
64
+ * Two questions have to be answered, and neither can be guessed from the string alone.
65
+ *
66
+ * **Package or path?** `zod` and `@acme/schemas` are package names and pass through untouched.
67
+ * A path containing a separator, or starting with `.`, is a path.
68
+ *
69
+ * **File or directory?** `src/db/connection` is usually a file and `src/validators/zod` a
70
+ * directory holding a barrel, and they look identical. So the filesystem is asked. Where the
71
+ * target does not exist yet, which happens when this generator runs before the one that writes
72
+ * it, an extensionless path is taken to be a directory, since these options name directories by
73
+ * convention and the one path that can be missing is a generated barrel.
74
+ *
75
+ * A path already relative keeps its own spelling and only has its extension corrected, so
76
+ * anyone who followed the older guidance and wrote `../validators/zod/index.js` is unaffected.
77
+ *
78
+ * @param configured what the user put in the config
79
+ * @param outDirAbs absolute directory the importing file is written to
80
+ * @param cwd project root a non-relative path is resolved against
81
+ */
82
+ declare function resolveConfiguredImport(configured: string, outDirAbs: string, cwd: string, importExtension?: ImportExtension): string;
55
83
 
56
84
  /**
57
85
  * One place that decides what a generated identifier is called.
@@ -195,10 +223,24 @@ interface ValidationRenderer<TOptions extends ValidationGenerateOptions = Valida
195
223
  renderIndex?(analysis: Analysis, opts?: TOptions): string;
196
224
  generate(opts: TOptions): Promise<string[]>;
197
225
  }
198
- declare function isGeneratedColumn(c: Column, primaryKeyColumns: string[]): boolean;
226
+ /**
227
+ * Whether the database generates this column's value, so it cannot be written.
228
+ *
229
+ * `primaryKeyColumns` is accepted for backwards compatibility and no longer consulted. It used
230
+ * to make every primary key count as generated, which dropped it from the insert schema whether
231
+ * or not the database supplied it. Right for a MySQL autoincrement column; wrong for a Postgres
232
+ * `integer('id').primaryKey()`, which Postgres does not generate, and for any natural key such
233
+ * as `text('slug').primaryKey()`. Those inserts became impossible to express: the required
234
+ * column was simply absent, with no way to provide it.
235
+ *
236
+ * Being a key says nothing about who supplies the value. `isGenerated` marks a column that
237
+ * cannot be written; `hasDefault` marks one that need not be, and those stay in the schema as
238
+ * optional.
239
+ */
240
+ declare function isGeneratedColumn(c: Column, _primaryKeyColumns?: string[]): boolean;
199
241
  declare function insertColumns(table: Table): Column[];
200
242
  declare function updateColumns(table: Table): Column[];
201
243
  declare function selectColumns(table: Table): Column[];
202
244
  declare function formatCode(code: string, filePath: string, fmt?: FormatOptions): Promise<any>;
203
245
 
204
- export { AFFIX_PROBE_TABLE, type AffixIssue, type AffixOptions, type AffixValue, DEFAULT_IMPORT_EXTENSION, DEFAULT_MODE_PREFIX, DEFAULT_SCHEMA_SUFFIX, DEFAULT_TYPE_SUFFIX, type FormatOptions, IMPORT_EXTENSIONS, type ImportExtension, NAME_MODES, type NameMode, type ResolvedAffix, type Table, type TableCase, type ValidationGenerateOptions, type ValidationLibrary, type ValidationRenderer, applyTableCase, formatCode, importSpecifier, insertColumns, isGeneratedColumn, moduleFileName, moduleSpecifier, pascalCase, resolveAffix, schemaName, selectColumns, typeName, updateColumns, validateAffix };
246
+ export { AFFIX_PROBE_TABLE, type AffixIssue, type AffixOptions, type AffixValue, DEFAULT_IMPORT_EXTENSION, DEFAULT_MODE_PREFIX, DEFAULT_SCHEMA_SUFFIX, DEFAULT_TYPE_SUFFIX, type FormatOptions, IMPORT_EXTENSIONS, type ImportExtension, NAME_MODES, type NameMode, type ResolvedAffix, type Table, type TableCase, type ValidationGenerateOptions, type ValidationLibrary, type ValidationRenderer, applyTableCase, formatCode, importSpecifier, insertColumns, isGeneratedColumn, moduleFileName, moduleSpecifier, pascalCase, resolveAffix, resolveConfiguredImport, schemaName, selectColumns, typeName, updateColumns, validateAffix };
package/dist/index.js CHANGED
@@ -1,6 +1,8 @@
1
1
  import "./chunk-MKBO26DX.js";
2
2
 
3
3
  // src/files.ts
4
+ import nodeFs from "fs";
5
+ import nodePath from "path";
4
6
  var IMPORT_EXTENSIONS = ["js", "none", "ts"];
5
7
  var DEFAULT_IMPORT_EXTENSION = "js";
6
8
  var TS_EXTENSIONS = [
@@ -24,6 +26,38 @@ function importSpecifier(relativePath, importExtension = DEFAULT_IMPORT_EXTENSIO
24
26
  function moduleSpecifier(tsName, fileSuffix, importExtension = DEFAULT_IMPORT_EXTENSION) {
25
27
  return importSpecifier(`./${moduleFileName(tsName, fileSuffix)}`, importExtension);
26
28
  }
29
+ function resolveConfiguredImport(configured, outDirAbs, cwd, importExtension = DEFAULT_IMPORT_EXTENSION) {
30
+ if (isPackageSpecifier(configured)) return configured;
31
+ const targetAbs = nodePath.isAbsolute(configured) ? configured : nodePath.resolve(configured.startsWith(".") ? outDirAbs : cwd, configured);
32
+ const withIndex = pointsAtDirectory(targetAbs) ? `${configured}/index` : configured;
33
+ if (configured.startsWith(".")) {
34
+ return importSpecifier(withTsExtension(withIndex), importExtension);
35
+ }
36
+ const resolved = pointsAtDirectory(targetAbs) ? nodePath.join(targetAbs, "index") : targetAbs;
37
+ const rel = nodePath.relative(outDirAbs, resolved).split(nodePath.sep).join("/");
38
+ const prefixed = !rel ? "." : rel.startsWith(".") ? rel : `./${rel}`;
39
+ return importSpecifier(withTsExtension(prefixed), importExtension);
40
+ }
41
+ function isPackageSpecifier(p) {
42
+ if (p.startsWith(".") || nodePath.isAbsolute(p)) return false;
43
+ if (p.startsWith("@") || p.includes(":")) return true;
44
+ return !p.includes("/");
45
+ }
46
+ function pointsAtDirectory(absPath) {
47
+ try {
48
+ return nodeFs.statSync(absPath).isDirectory();
49
+ } catch {
50
+ for (const ext of [".ts", ".tsx", ".mts", ".cts", ".js", ".mjs", ".cjs"]) {
51
+ if (nodeFs.existsSync(`${absPath}${ext}`)) return false;
52
+ }
53
+ return !/\.[a-z]+$/i.test(nodePath.basename(absPath));
54
+ }
55
+ }
56
+ function withTsExtension(p) {
57
+ if (/\.(ts|tsx|mts|cts)$/.test(p)) return p;
58
+ if (/\.(js|mjs|cjs)$/.test(p)) return p.replace(/\.(js|mjs|cjs)$/, ".ts");
59
+ return `${p}.ts`;
60
+ }
27
61
 
28
62
  // src/naming.ts
29
63
  var NAME_MODES = ["insert", "update", "select"];
@@ -132,12 +166,11 @@ function validateAffix(affix, schemaSuffix) {
132
166
  }
133
167
 
134
168
  // src/index.ts
135
- function isGeneratedColumn(c, primaryKeyColumns) {
136
- return c.isGenerated || primaryKeyColumns.includes(c.name);
169
+ function isGeneratedColumn(c, _primaryKeyColumns = []) {
170
+ return c.isGenerated;
137
171
  }
138
172
  function insertColumns(table) {
139
- const pkCols = table.primaryKey?.columns ?? [];
140
- return table.columns.filter((c) => !isGeneratedColumn(c, pkCols));
173
+ return table.columns.filter((c) => !isGeneratedColumn(c));
141
174
  }
142
175
  function updateColumns(table) {
143
176
  const pkCols = table.primaryKey?.columns ?? [];
@@ -188,6 +221,7 @@ export {
188
221
  moduleSpecifier,
189
222
  pascalCase,
190
223
  resolveAffix,
224
+ resolveConfiguredImport,
191
225
  schemaName,
192
226
  selectColumns,
193
227
  typeName,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@drzl/validation-core",
3
- "version": "2.0.0",
3
+ "version": "3.0.0",
4
4
  "private": false,
5
5
  "license": "Apache-2.0",
6
6
  "type": "module",
@@ -11,7 +11,7 @@
11
11
  ],
12
12
  "sideEffects": false,
13
13
  "dependencies": {
14
- "@drzl/analyzer": "^1.3.0"
14
+ "@drzl/analyzer": "^1.5.0"
15
15
  },
16
16
  "devDependencies": {
17
17
  "tsup": "^8.5.0",