@drzl/validation-core 3.15.0 → 3.16.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
@@ -508,37 +508,55 @@ function insertColumns(table) {
508
508
  }
509
509
  function updateColumns(table) {
510
510
  const pkCols = table.primaryKey?.columns ?? [];
511
- return table.columns.filter((c) => !pkCols.includes(c.name));
511
+ return table.columns.filter((c) => !isGeneratedColumn(c) && !pkCols.includes(c.name));
512
512
  }
513
513
  function selectColumns(table) {
514
514
  return table.columns;
515
515
  }
516
+ var reportedEngines = /* @__PURE__ */ new Set();
517
+ var ENGINE_PACKAGE = { prettier: "prettier", biome: "@biomejs/biome" };
518
+ function reportUnusableFormatter(engine, cause) {
519
+ if (reportedEngines.has(engine)) return;
520
+ reportedEngines.add(engine);
521
+ const pkg = ENGINE_PACKAGE[engine];
522
+ const remedy = engine === "prettier" ? 'Install prettier, which is an optional peer of @drzl/validation-core, or set format.engine to "auto" to accept whatever formatter is present.' : 'drzl formats with Biome by importing @biomejs/biome as a module; run the Biome CLI over the output instead, or set format.engine to "auto" or "prettier".';
523
+ const reason = cause instanceof Error ? cause.message : String(cause);
524
+ console.warn(
525
+ `[drzl] format.engine is "${engine}" but ${pkg} could not be used, so the generated files were left unformatted. ${remedy} Reason: ${reason}`
526
+ );
527
+ }
516
528
  async function formatCode(code, filePath, fmt) {
517
529
  if (fmt && fmt.enabled === false) return code;
518
530
  const engine = fmt?.engine ?? "auto";
519
- try {
520
- if (engine === "prettier" || engine === "auto") {
531
+ if (engine === "prettier" || engine === "auto") {
532
+ try {
521
533
  const prettier = await import("prettier");
522
534
  const cfgRef = fmt?.configPath ?? filePath;
523
535
  const cfg = await prettier.resolveConfig(cfgRef).catch(() => null);
524
536
  return prettier.format(code, { ...cfg ?? {}, parser: "typescript", filepath: filePath });
537
+ } catch (err) {
538
+ if (engine === "prettier") reportUnusableFormatter("prettier", err);
525
539
  }
526
- } catch {
527
540
  }
528
- try {
529
- if (engine === "biome" || engine === "auto") {
541
+ if (engine === "biome" || engine === "auto") {
542
+ try {
530
543
  const dynamicImport = Function("s", "return import(s)");
531
- const biome = await dynamicImport("@biomejs/biome").catch(() => null);
544
+ const biome = await dynamicImport("@biomejs/biome");
532
545
  if (biome?.formatContent) {
533
546
  const res = await biome.formatContent(code, { filePath });
534
- return (res && (res.content || res.formatted)) ?? code;
547
+ const out = res && (res.content || res.formatted);
548
+ if (typeof out === "string") return out;
549
+ throw new Error("@biomejs/biome formatContent returned no formatted content");
535
550
  }
536
551
  if (biome?.format) {
537
552
  const res = await biome.format(code, { filePath });
538
- return res ?? code;
553
+ if (typeof res === "string") return res;
554
+ throw new Error("@biomejs/biome format returned no formatted content");
539
555
  }
556
+ throw new Error("@biomejs/biome exposes neither formatContent nor format");
557
+ } catch (err) {
558
+ if (engine === "biome") reportUnusableFormatter("biome", err);
540
559
  }
541
- } catch {
542
560
  }
543
561
  return code;
544
562
  }
package/dist/index.d.cts CHANGED
@@ -488,6 +488,19 @@ declare const COLUMN_FORMATS: Record<string, string>;
488
488
  declare const CODEPOINT_LENGTH = "[...v].length";
489
489
  declare function isIntegerColumn(c: Column): boolean;
490
490
  declare function insertColumns(table: Table): Column[];
491
+ /**
492
+ * Which columns belong in an update schema.
493
+ *
494
+ * A primary key identifies the row rather than changing it, and a generated column cannot be
495
+ * written at all. This asked only the first question, so every `generatedAlwaysAs` column landed
496
+ * in the patch type. Measured against real servers: all three refuse an UPDATE naming one with any
497
+ * value, including NULL. Postgres 428C9, MySQL 3105, SQLite "cannot UPDATE generated column". The
498
+ * one accepted form is `SET col = DEFAULT`, which no validator can express and no Drizzle `.set()`
499
+ * produces.
500
+ *
501
+ * `isGeneratedColumn` rather than `c.isGenerated`, so this and `insertColumns` cannot drift apart
502
+ * on what counts as generated.
503
+ */
491
504
  declare function updateColumns(table: Table): Column[];
492
505
  declare function selectColumns(table: Table): Column[];
493
506
  /**
@@ -499,9 +512,21 @@ declare function selectColumns(table: Table): Column[];
499
512
  * anyone installing @drzl/cli. It is `--external` in every build script that can reach it, and
500
513
  * no-bundled-formatter.spec.ts builds those scripts and checks.
501
514
  *
502
- * Neither absence is an error. A consumer with no formatter gets the code as rendered, which is
503
- * valid TypeScript that merely looks worse, and losing generated files at the last step would be
504
- * a far worse trade than losing their whitespace.
515
+ * An absent formatter is never fatal. A consumer with no formatter gets the code as rendered,
516
+ * which is valid TypeScript that merely looks worse, and losing generated files at the last step
517
+ * would be a far worse trade than losing their whitespace.
518
+ *
519
+ * Whether it is worth saying so depends on what was asked for, which is the difference between the
520
+ * two branches below. `engine: 'auto'` asked for whatever happens to be installed, so finding
521
+ * nothing is an outcome and the code comes back unchanged in silence. Naming an engine is a
522
+ * request, and an unmet request that produces neither formatted output nor a message reads as
523
+ * "this is fine" when it is not: the consumer configured something, it did not happen, and nothing
524
+ * in the run says which. So a named engine that cannot be loaded warns on stderr and still returns
525
+ * the code, rather than throwing. Throwing would lose a whole generation over whitespace, and the
526
+ * consumer would not even be told what for: every generator branch in the CLI except the oRPC one
527
+ * wraps its `generate()` in a catch that prints "<name> generator missing. Install with: npm
528
+ * install @drzl/generator-<name>", so the headline would name a package they already have and the
529
+ * real reason would arrive as a trailing detail line. Measured, with a throw wired in on purpose.
505
530
  */
506
531
  declare function formatCode(code: string, filePath: string, fmt?: FormatOptions): Promise<any>;
507
532
 
package/dist/index.d.ts CHANGED
@@ -488,6 +488,19 @@ declare const COLUMN_FORMATS: Record<string, string>;
488
488
  declare const CODEPOINT_LENGTH = "[...v].length";
489
489
  declare function isIntegerColumn(c: Column): boolean;
490
490
  declare function insertColumns(table: Table): Column[];
491
+ /**
492
+ * Which columns belong in an update schema.
493
+ *
494
+ * A primary key identifies the row rather than changing it, and a generated column cannot be
495
+ * written at all. This asked only the first question, so every `generatedAlwaysAs` column landed
496
+ * in the patch type. Measured against real servers: all three refuse an UPDATE naming one with any
497
+ * value, including NULL. Postgres 428C9, MySQL 3105, SQLite "cannot UPDATE generated column". The
498
+ * one accepted form is `SET col = DEFAULT`, which no validator can express and no Drizzle `.set()`
499
+ * produces.
500
+ *
501
+ * `isGeneratedColumn` rather than `c.isGenerated`, so this and `insertColumns` cannot drift apart
502
+ * on what counts as generated.
503
+ */
491
504
  declare function updateColumns(table: Table): Column[];
492
505
  declare function selectColumns(table: Table): Column[];
493
506
  /**
@@ -499,9 +512,21 @@ declare function selectColumns(table: Table): Column[];
499
512
  * anyone installing @drzl/cli. It is `--external` in every build script that can reach it, and
500
513
  * no-bundled-formatter.spec.ts builds those scripts and checks.
501
514
  *
502
- * Neither absence is an error. A consumer with no formatter gets the code as rendered, which is
503
- * valid TypeScript that merely looks worse, and losing generated files at the last step would be
504
- * a far worse trade than losing their whitespace.
515
+ * An absent formatter is never fatal. A consumer with no formatter gets the code as rendered,
516
+ * which is valid TypeScript that merely looks worse, and losing generated files at the last step
517
+ * would be a far worse trade than losing their whitespace.
518
+ *
519
+ * Whether it is worth saying so depends on what was asked for, which is the difference between the
520
+ * two branches below. `engine: 'auto'` asked for whatever happens to be installed, so finding
521
+ * nothing is an outcome and the code comes back unchanged in silence. Naming an engine is a
522
+ * request, and an unmet request that produces neither formatted output nor a message reads as
523
+ * "this is fine" when it is not: the consumer configured something, it did not happen, and nothing
524
+ * in the run says which. So a named engine that cannot be loaded warns on stderr and still returns
525
+ * the code, rather than throwing. Throwing would lose a whole generation over whitespace, and the
526
+ * consumer would not even be told what for: every generator branch in the CLI except the oRPC one
527
+ * wraps its `generate()` in a catch that prints "<name> generator missing. Install with: npm
528
+ * install @drzl/generator-<name>", so the headline would name a package they already have and the
529
+ * real reason would arrive as a trailing detail line. Measured, with a throw wired in on purpose.
505
530
  */
506
531
  declare function formatCode(code: string, filePath: string, fmt?: FormatOptions): Promise<any>;
507
532
 
package/dist/index.js CHANGED
@@ -445,37 +445,55 @@ function insertColumns(table) {
445
445
  }
446
446
  function updateColumns(table) {
447
447
  const pkCols = table.primaryKey?.columns ?? [];
448
- return table.columns.filter((c) => !pkCols.includes(c.name));
448
+ return table.columns.filter((c) => !isGeneratedColumn(c) && !pkCols.includes(c.name));
449
449
  }
450
450
  function selectColumns(table) {
451
451
  return table.columns;
452
452
  }
453
+ var reportedEngines = /* @__PURE__ */ new Set();
454
+ var ENGINE_PACKAGE = { prettier: "prettier", biome: "@biomejs/biome" };
455
+ function reportUnusableFormatter(engine, cause) {
456
+ if (reportedEngines.has(engine)) return;
457
+ reportedEngines.add(engine);
458
+ const pkg = ENGINE_PACKAGE[engine];
459
+ const remedy = engine === "prettier" ? 'Install prettier, which is an optional peer of @drzl/validation-core, or set format.engine to "auto" to accept whatever formatter is present.' : 'drzl formats with Biome by importing @biomejs/biome as a module; run the Biome CLI over the output instead, or set format.engine to "auto" or "prettier".';
460
+ const reason = cause instanceof Error ? cause.message : String(cause);
461
+ console.warn(
462
+ `[drzl] format.engine is "${engine}" but ${pkg} could not be used, so the generated files were left unformatted. ${remedy} Reason: ${reason}`
463
+ );
464
+ }
453
465
  async function formatCode(code, filePath, fmt) {
454
466
  if (fmt && fmt.enabled === false) return code;
455
467
  const engine = fmt?.engine ?? "auto";
456
- try {
457
- if (engine === "prettier" || engine === "auto") {
468
+ if (engine === "prettier" || engine === "auto") {
469
+ try {
458
470
  const prettier = await import("prettier");
459
471
  const cfgRef = fmt?.configPath ?? filePath;
460
472
  const cfg = await prettier.resolveConfig(cfgRef).catch(() => null);
461
473
  return prettier.format(code, { ...cfg ?? {}, parser: "typescript", filepath: filePath });
474
+ } catch (err) {
475
+ if (engine === "prettier") reportUnusableFormatter("prettier", err);
462
476
  }
463
- } catch {
464
477
  }
465
- try {
466
- if (engine === "biome" || engine === "auto") {
478
+ if (engine === "biome" || engine === "auto") {
479
+ try {
467
480
  const dynamicImport = Function("s", "return import(s)");
468
- const biome = await dynamicImport("@biomejs/biome").catch(() => null);
481
+ const biome = await dynamicImport("@biomejs/biome");
469
482
  if (biome?.formatContent) {
470
483
  const res = await biome.formatContent(code, { filePath });
471
- return (res && (res.content || res.formatted)) ?? code;
484
+ const out = res && (res.content || res.formatted);
485
+ if (typeof out === "string") return out;
486
+ throw new Error("@biomejs/biome formatContent returned no formatted content");
472
487
  }
473
488
  if (biome?.format) {
474
489
  const res = await biome.format(code, { filePath });
475
- return res ?? code;
490
+ if (typeof res === "string") return res;
491
+ throw new Error("@biomejs/biome format returned no formatted content");
476
492
  }
493
+ throw new Error("@biomejs/biome exposes neither formatContent nor format");
494
+ } catch (err) {
495
+ if (engine === "biome") reportUnusableFormatter("biome", err);
477
496
  }
478
- } catch {
479
497
  }
480
498
  return code;
481
499
  }
package/package.json CHANGED
@@ -1,17 +1,30 @@
1
1
  {
2
2
  "name": "@drzl/validation-core",
3
- "version": "3.15.0",
3
+ "version": "3.16.0",
4
4
  "private": false,
5
5
  "license": "Apache-2.0",
6
6
  "type": "module",
7
- "main": "dist/index.js",
8
- "types": "dist/index.d.ts",
7
+ "main": "./dist/index.cjs",
8
+ "module": "./dist/index.js",
9
+ "types": "./dist/index.d.ts",
10
+ "exports": {
11
+ ".": {
12
+ "import": {
13
+ "types": "./dist/index.d.ts",
14
+ "default": "./dist/index.js"
15
+ },
16
+ "require": {
17
+ "types": "./dist/index.d.cts",
18
+ "default": "./dist/index.cjs"
19
+ }
20
+ }
21
+ },
9
22
  "files": [
10
23
  "dist"
11
24
  ],
12
25
  "sideEffects": false,
13
26
  "dependencies": {
14
- "@drzl/analyzer": "^1.14.0"
27
+ "@drzl/analyzer": "^1.18.0"
15
28
  },
16
29
  "peerDependencies": {
17
30
  "prettier": ">=3"