@valbuild/server 0.123.2 → 0.123.3

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/CHANGELOG.md CHANGED
@@ -1,5 +1,27 @@
1
1
  # @valbuild/server
2
2
 
3
+ ## 0.123.3
4
+
5
+ ### Patch Changes
6
+
7
+ - [#623](https://github.com/valbuild/val/pull/623) [`4c9369b`](https://github.com/valbuild/val/commit/4c9369bad3f17e96868262e78a4f47361d85319e) Thanks [@freekh](https://github.com/freekh)! - Add the editor quick fix for a `.jsonValues()` entry written inline: **Val: move entry into its own .val.json**.
8
+
9
+ The language server already reported the problem — "Entry '…' is written inline … Run 'val validate --fix' to move it" — but offered no way to act on it, so the only remedy was to leave the editor and run the CLI. It now offers a quick fix that creates the `*.val.json` with the entry's content and rewrites the `.val.ts` to `c.json(() => import("./…"))`, in one undoable step.
10
+
11
+ The fix is computed from the same code `val validate --fix` runs, so the two write the same files, and it is computed against the buffer you are looking at rather than what is on disk — an unsaved module can be fixed without saving first. It refuses, rather than overwriting, when a file or an unsaved buffer already occupies the target path.
12
+
13
+ Requires an editor that honours file creation inside a workspace edit; VS Code does. In an editor that does not announce it, no action is offered rather than one that would rewrite the module to import a file that never got created.
14
+
15
+ - [#621](https://github.com/valbuild/val/pull/621) [`fb1baff`](https://github.com/valbuild/val/commit/fb1baffead5228d8a86a51af65178b88738d5a64) Thanks [@freekh](https://github.com/freekh)! - Fix `.jsonValues()` validation being silently skipped when the CLI is run through `npx` / `pnpm dlx`.
16
+
17
+ `npx @valbuild/cli validate` reported a `.jsonValues()` module whose entries were still written inline in the `.val.ts` as **valid**, and `--fix` moved nothing into `*.val.json`. Running the CLI installed in the project (`./node_modules/.bin/val validate --fix`) worked, which made this look like a schema or path problem rather than a tooling one.
18
+
19
+ The cause: the project's `*.val.ts` are evaluated with a `require` rooted at the project, so their schemas come from the project's `@valbuild/core`, while `npx`/`dlx` runs the CLI's own second copy. The entry check guarded on `schema instanceof RecordSchema`, which is false across those two copies, and it failed open — the whole check returned "no errors". The guard is now structural, so it holds whichever copy built the schema. If you gate CI on `npx @valbuild/cli validate`, that gate was green for the wrong reason.
20
+
21
+ - Updated dependencies [[`accf4f8`](https://github.com/valbuild/val/commit/accf4f852fe3400d762cc14e80316da741a69a9a), [`356eb11`](https://github.com/valbuild/val/commit/356eb11b5f6a0a02dfec80580c6fccac75d28402), [`aef45ce`](https://github.com/valbuild/val/commit/aef45ce3ef269f1b6221de44a56df0f6a0d9dbbd)]:
22
+ - @valbuild/shared@0.123.3
23
+ - @valbuild/ui@0.123.3
24
+
3
25
  ## 0.123.2
4
26
 
5
27
  ### Patch Changes
@@ -1,17 +1,61 @@
1
1
  import type { Json, ModuleFilePath } from "@valbuild/core";
2
+ import { result } from "@valbuild/core/fp";
2
3
  import { ValSourceFileHandler } from "./ValSourceFileHandler.js";
4
+ /**
5
+ * The two files an extraction touches, as text — nothing written yet.
6
+ *
7
+ * Both paths are project-relative in the `ModuleFilePath` style (a leading
8
+ * slash), because that is what the callers already hold and what
9
+ * {@link getNewJsonEntryPaths} derives. Join them onto the project root to get
10
+ * somewhere to write.
11
+ */
12
+ export type JsonValuesEntryExtraction = {
13
+ /** The `*.val.json` to CREATE. It must not already exist — see the note below. */
14
+ jsonPath: string;
15
+ jsonContent: string;
16
+ /** The `.val.ts` to rewrite, and its complete new text. */
17
+ valTsPath: string;
18
+ valTsContent: string;
19
+ };
20
+ /**
21
+ * Works out what moving ONE inline `.jsonValues()` entry into its own
22
+ * `*.val.json` would change, without changing anything.
23
+ *
24
+ * This is the whole fix for `jsonValues:extract-entry`, minus the writing. It
25
+ * is split out because the two callers cannot share a way of applying it: the
26
+ * CLI writes both files ({@link extractJsonValuesEntry}), while the editor has
27
+ * to hand the same two changes back as a `WorkspaceEdit` so they go through the
28
+ * undo stack and respect an unsaved buffer. Anything that lived in only one of
29
+ * those would be a fix that behaves differently depending on where it was
30
+ * invoked from, which is exactly the drift `codeActions.ts` exists to prevent.
31
+ *
32
+ * It does NOT check whether `jsonPath` already exists: that needs a filesystem,
33
+ * and the editor's answer ("is there a buffer or a file here?") is not the
34
+ * CLI's. Every caller must check before writing — overwriting an unrelated file
35
+ * is not a fix.
36
+ *
37
+ * Root-only, like the rest of the `.jsonValues()` machinery: the entry is looked
38
+ * up in the module's root record/router object literal.
39
+ */
40
+ export declare function planJsonValuesEntryExtraction({ moduleFilePath, entryKey, content, valTsPath, valTsText, }: {
41
+ moduleFilePath: ModuleFilePath;
42
+ entryKey: string;
43
+ /** The entry's value, as it is written inline in the `.val.ts`. */
44
+ content: Json;
45
+ /** Where the `.val.ts` lives, for error messages. */
46
+ valTsPath: string;
47
+ /** Its text — the editor's version of it, where there is an editor. */
48
+ valTsText: string;
49
+ }): result.Result<JsonValuesEntryExtraction, string>;
3
50
  /**
4
51
  * Moves ONE `.jsonValues()` entry that was written inline in the `.val.ts` into
5
52
  * its own `*.val.json`, replacing the inline value with
6
53
  * `c.json(() => import("./<key>.val.json"))`.
7
54
  *
8
- * This is the fix for the `jsonValues:extract-entry` validation error. It is not
9
- * expressible as a patch (a patch edits one `.val.ts` and cannot create the
55
+ * The `val validate --fix` half of {@link planJsonValuesEntryExtraction}. It is
56
+ * not expressible as a patch (a patch edits one `.val.ts` and cannot create the
10
57
  * backing JSON file), so it writes both files directly — JSON first, so a
11
58
  * failure part-way through never leaves the module pointing at a file that does
12
59
  * not exist.
13
- *
14
- * Root-only, like the rest of the `.jsonValues()` machinery: the entry is looked
15
- * up in the module's root record/router object literal.
16
60
  */
17
61
  export declare function extractJsonValuesEntry(moduleFilePath: ModuleFilePath, rootDir: string, entryKey: string, content: Json, sourceFileHandler: ValSourceFileHandler): void;
@@ -36,7 +36,8 @@ export { createModulePathMap, createJsonEntryPathMap, getModulePathRange, } from
36
36
  export { findJsonEntryFilePath } from "./jsonEntryLocation.js";
37
37
  export { classifyJsonValuesOp, rebaseContentOp } from "./patch/jsonValuesPatch.js";
38
38
  export type { JsonValuesOpClass } from "./patch/jsonValuesPatch.js";
39
- export { extractJsonValuesEntry } from "./extractJsonValuesEntry.js";
39
+ export { extractJsonValuesEntry, planJsonValuesEntryExtraction, } from "./extractJsonValuesEntry.js";
40
+ export type { JsonValuesEntryExtraction } from "./extractJsonValuesEntry.js";
40
41
  export type { ModulePathMap } from "./modulePathMap.js";
41
42
  export { ValOpsFS } from "./ValOpsFS.js";
42
43
  export { ValOpsHttp } from "./ValOpsHttp.js";
@@ -1402,6 +1402,43 @@ function resolveExistingJsonPath(moduleFilePath, importPath) {
1402
1402
  * only way to avoid loading every entry twice.
1403
1403
  */
1404
1404
 
1405
+ /**
1406
+ * The part of a `.jsonValues()` record this file calls. Named structurally
1407
+ * because the value may not be an instance of *this* copy of `RecordSchema` —
1408
+ * see {@link isJsonValuesRecord}.
1409
+ */
1410
+
1411
+ /**
1412
+ * Is this a `.jsonValues()` record?
1413
+ *
1414
+ * NOT `schema instanceof RecordSchema`, and the distinction is the whole point.
1415
+ * `loadValModules` evaluates the project's `*.val.ts` with a `require` rooted at
1416
+ * the PROJECT, deliberately, so the schemas are built by whatever
1417
+ * `@valbuild/core` the project resolves. When the CLI is itself installed in
1418
+ * that project, that is this very module and `instanceof` holds. When it is run
1419
+ * through `npx` / `pnpm dlx`, the tool gets its own copy of `@valbuild/core`
1420
+ * beside the project's, and `instanceof` is false for a record that is a record
1421
+ * in every way that matters — same class name, same serialized schema, same
1422
+ * methods, different realm.
1423
+ *
1424
+ * That failed OPEN: the whole check returned "no errors", so
1425
+ * `npx @valbuild/cli validate` called a module with un-extracted entries VALID
1426
+ * and a CI gate on it was green for the wrong reason. `loadValModules` avoids
1427
+ * constructor checks for exactly this reason and says so; this one was the
1428
+ * exception.
1429
+ *
1430
+ * `validateJsonEntryContent` is declared by `RecordSchema` and by nothing else,
1431
+ * so it is the brand — and checking it first keeps the cheap short-circuit
1432
+ * `instanceof` gave us, rather than serializing every non-record schema.
1433
+ */
1434
+ function isJsonValuesRecord(schema) {
1435
+ if (!("validateJsonEntryContent" in schema) || typeof schema.validateJsonEntryContent !== "function") {
1436
+ return false;
1437
+ }
1438
+ const serialized = schema["executeSerialize"]();
1439
+ return serialized.type === "record" && serialized.jsonValues === true;
1440
+ }
1441
+
1405
1442
  /**
1406
1443
  * Validates the content of every `.jsonValues()` entry in a module by loading
1407
1444
  * each backing `*.val.json` (via its lazy import thunk) and checking it against
@@ -1459,10 +1496,7 @@ async function validateJsonValuesEntries(schema, source, modulePath) {
1459
1496
  errors: out,
1460
1497
  loadedEntries
1461
1498
  };
1462
- if (!(schema instanceof core.RecordSchema)) {
1463
- return res;
1464
- }
1465
- if (!schema["executeSerialize"]().jsonValues) {
1499
+ if (!isJsonValuesRecord(schema)) {
1466
1500
  return res;
1467
1501
  }
1468
1502
  if (source === null || typeof source !== "object" || Array.isArray(source)) {
@@ -14300,37 +14334,50 @@ async function getFileMetadata(projectRoot, validationError) {
14300
14334
  }
14301
14335
 
14302
14336
  /**
14303
- * Moves ONE `.jsonValues()` entry that was written inline in the `.val.ts` into
14304
- * its own `*.val.json`, replacing the inline value with
14305
- * `c.json(() => import("./<key>.val.json"))`.
14337
+ * The two files an extraction touches, as text — nothing written yet.
14306
14338
  *
14307
- * This is the fix for the `jsonValues:extract-entry` validation error. It is not
14308
- * expressible as a patch (a patch edits one `.val.ts` and cannot create the
14309
- * backing JSON file), so it writes both files directly — JSON first, so a
14310
- * failure part-way through never leaves the module pointing at a file that does
14311
- * not exist.
14339
+ * Both paths are project-relative in the `ModuleFilePath` style (a leading
14340
+ * slash), because that is what the callers already hold and what
14341
+ * {@link getNewJsonEntryPaths} derives. Join them onto the project root to get
14342
+ * somewhere to write.
14343
+ */
14344
+
14345
+ /**
14346
+ * Works out what moving ONE inline `.jsonValues()` entry into its own
14347
+ * `*.val.json` would change, without changing anything.
14348
+ *
14349
+ * This is the whole fix for `jsonValues:extract-entry`, minus the writing. It
14350
+ * is split out because the two callers cannot share a way of applying it: the
14351
+ * CLI writes both files ({@link extractJsonValuesEntry}), while the editor has
14352
+ * to hand the same two changes back as a `WorkspaceEdit` so they go through the
14353
+ * undo stack and respect an unsaved buffer. Anything that lived in only one of
14354
+ * those would be a fix that behaves differently depending on where it was
14355
+ * invoked from, which is exactly the drift `codeActions.ts` exists to prevent.
14356
+ *
14357
+ * It does NOT check whether `jsonPath` already exists: that needs a filesystem,
14358
+ * and the editor's answer ("is there a buffer or a file here?") is not the
14359
+ * CLI's. Every caller must check before writing — overwriting an unrelated file
14360
+ * is not a fix.
14312
14361
  *
14313
14362
  * Root-only, like the rest of the `.jsonValues()` machinery: the entry is looked
14314
14363
  * up in the module's root record/router object literal.
14315
14364
  */
14316
- function extractJsonValuesEntry(moduleFilePath, rootDir, entryKey, content, sourceFileHandler) {
14317
- const valTsPath = sourceFileHandler.resolveSourceModulePath(getSyntheticContainingPath(rootDir), `.${moduleFilePath.replace(".val.ts", ".val").replace(".val.js", ".val").replace(".val.jsx", ".val").replace(".val.tsx", ".val")}`);
14318
- const sourceFile = sourceFileHandler.getSourceFile(valTsPath);
14319
- if (!sourceFile) {
14320
- throw Error(`Source file ${valTsPath} not found`);
14321
- }
14365
+ function planJsonValuesEntryExtraction({
14366
+ moduleFilePath,
14367
+ entryKey,
14368
+ content,
14369
+ valTsPath,
14370
+ valTsText
14371
+ }) {
14322
14372
  const pathsRes = getNewJsonEntryPaths(moduleFilePath, entryKey);
14323
14373
  if (fp.result.isErr(pathsRes)) {
14324
- throw Error(formatPatchSourceError(pathsRes.error));
14374
+ return fp.result.err(formatPatchSourceError(pathsRes.error));
14325
14375
  }
14326
14376
  const {
14327
14377
  jsonPath,
14328
14378
  importPath
14329
14379
  } = pathsRes.value;
14330
- const absoluteJsonPath = path__namespace["default"].join(rootDir, jsonPath);
14331
- if (sourceFileHandler.host.fileExists(absoluteJsonPath)) {
14332
- throw Error(`Cannot extract .jsonValues() entry '${entryKey}' of ${moduleFilePath}: '${jsonPath}' already exists`);
14333
- }
14380
+ const sourceFile = ts__default["default"].createSourceFile(valTsPath, valTsText, ts__default["default"].ScriptTarget.ES2020);
14334
14381
 
14335
14382
  // Remove the inline property, then add the `c.json(...)` reference back. The
14336
14383
  // entry moves to the end of the record: entry ORDER in a jsonValues record is
@@ -14338,14 +14385,70 @@ function extractJsonValuesEntry(moduleFilePath, rootDir, entryKey, content, sour
14338
14385
  // insert-in-place would mean reimplementing insertValJsonEntry.
14339
14386
  const removed = removeValJsonEntry(sourceFile, [], entryKey);
14340
14387
  if (fp.result.isErr(removed)) {
14341
- throw Error(`${valTsPath}\n${formatOpsError(removed.error, sourceFile)}`);
14388
+ return fp.result.err(`${valTsPath}\n${formatOpsError(removed.error, sourceFile)}`);
14342
14389
  }
14343
14390
  const inserted = insertValJsonEntry(removed.value, [], entryKey, importPath);
14344
14391
  if (fp.result.isErr(inserted)) {
14345
- throw Error(`${valTsPath}\n${formatOpsError(inserted.error, removed.value)}`);
14392
+ return fp.result.err(`${valTsPath}\n${formatOpsError(inserted.error, removed.value)}`);
14393
+ }
14394
+ return fp.result.ok({
14395
+ jsonPath,
14396
+ jsonContent: JSON.stringify(content, null, 2) + "\n",
14397
+ valTsPath,
14398
+ valTsContent: printSourceFile(inserted.value)
14399
+ });
14400
+ }
14401
+
14402
+ /**
14403
+ * Moves ONE `.jsonValues()` entry that was written inline in the `.val.ts` into
14404
+ * its own `*.val.json`, replacing the inline value with
14405
+ * `c.json(() => import("./<key>.val.json"))`.
14406
+ *
14407
+ * The `val validate --fix` half of {@link planJsonValuesEntryExtraction}. It is
14408
+ * not expressible as a patch (a patch edits one `.val.ts` and cannot create the
14409
+ * backing JSON file), so it writes both files directly — JSON first, so a
14410
+ * failure part-way through never leaves the module pointing at a file that does
14411
+ * not exist.
14412
+ */
14413
+ function extractJsonValuesEntry(moduleFilePath, rootDir, entryKey, content, sourceFileHandler) {
14414
+ const valTsPath = sourceFileHandler.resolveSourceModulePath(getSyntheticContainingPath(rootDir), `.${moduleFilePath.replace(".val.ts", ".val").replace(".val.js", ".val").replace(".val.jsx", ".val").replace(".val.tsx", ".val")}`);
14415
+ const valTsText = sourceFileHandler.host.readFile(valTsPath);
14416
+ if (valTsText === undefined) {
14417
+ throw Error(`Source file ${valTsPath} not found`);
14418
+ }
14419
+ const planned = planJsonValuesEntryExtraction({
14420
+ moduleFilePath,
14421
+ entryKey,
14422
+ content,
14423
+ valTsPath,
14424
+ valTsText
14425
+ });
14426
+ if (fp.result.isErr(planned)) {
14427
+ throw Error(planned.error);
14428
+ }
14429
+ const absoluteJsonPath = path__namespace["default"].join(rootDir, planned.value.jsonPath);
14430
+ if (sourceFileHandler.host.fileExists(absoluteJsonPath)) {
14431
+ throw Error(`Cannot extract .jsonValues() entry '${entryKey}' of ${moduleFilePath}: '${planned.value.jsonPath}' already exists`);
14346
14432
  }
14347
- sourceFileHandler.writeFile(absoluteJsonPath, JSON.stringify(content, null, 2) + "\n", "utf8");
14348
- sourceFileHandler.writeSourceFile(inserted.value);
14433
+ sourceFileHandler.writeFile(absoluteJsonPath, planned.value.jsonContent, "utf8");
14434
+ sourceFileHandler.writeFile(valTsPath, planned.value.valTsContent, "utf8");
14435
+ }
14436
+
14437
+ /**
14438
+ * The text of a source file the TS ops produced, exactly as
14439
+ * `ValSourceFileHandler.writeSourceFile` would have written it.
14440
+ *
14441
+ * The unescape undoes the printer's `\uXXXX` output for non-ASCII. Today the
14442
+ * ops splice printed text into `document.text` and this fix only ever prints an
14443
+ * ASCII `c.json(() => import("./..."))`, so nothing here is escaped and the
14444
+ * unescape is a no-op — but `neverAsciiEscape` is off in the printer, so that is
14445
+ * a property of what this fix happens to print, not a guarantee. Kept because
14446
+ * this replaced a `writeSourceFile` call and the text written must not change.
14447
+ *
14448
+ * https://github.com/microsoft/TypeScript/issues/36174
14449
+ */
14450
+ function printSourceFile(sourceFile) {
14451
+ return unescape(sourceFile.text.replace(/\\u/g, "%u"));
14349
14452
  }
14350
14453
  function formatOpsError(error, sourceFile) {
14351
14454
  if (error instanceof patch.PatchError) {
@@ -15655,6 +15758,7 @@ exports.ok = ok;
15655
15758
  exports.parsePersonalAccessTokenFile = parsePersonalAccessTokenFile;
15656
15759
  exports.patchSourceFile = patchSourceFile;
15657
15760
  exports.persistPersonalAccessToken = persistPersonalAccessToken;
15761
+ exports.planJsonValuesEntryExtraction = planJsonValuesEntryExtraction;
15658
15762
  exports.readCapturedReport = readCapturedReport;
15659
15763
  exports.readPatchStore = readPatchStore;
15660
15764
  exports.rebaseContentOp = rebaseContentOp;
@@ -1402,6 +1402,43 @@ function resolveExistingJsonPath(moduleFilePath, importPath) {
1402
1402
  * only way to avoid loading every entry twice.
1403
1403
  */
1404
1404
 
1405
+ /**
1406
+ * The part of a `.jsonValues()` record this file calls. Named structurally
1407
+ * because the value may not be an instance of *this* copy of `RecordSchema` —
1408
+ * see {@link isJsonValuesRecord}.
1409
+ */
1410
+
1411
+ /**
1412
+ * Is this a `.jsonValues()` record?
1413
+ *
1414
+ * NOT `schema instanceof RecordSchema`, and the distinction is the whole point.
1415
+ * `loadValModules` evaluates the project's `*.val.ts` with a `require` rooted at
1416
+ * the PROJECT, deliberately, so the schemas are built by whatever
1417
+ * `@valbuild/core` the project resolves. When the CLI is itself installed in
1418
+ * that project, that is this very module and `instanceof` holds. When it is run
1419
+ * through `npx` / `pnpm dlx`, the tool gets its own copy of `@valbuild/core`
1420
+ * beside the project's, and `instanceof` is false for a record that is a record
1421
+ * in every way that matters — same class name, same serialized schema, same
1422
+ * methods, different realm.
1423
+ *
1424
+ * That failed OPEN: the whole check returned "no errors", so
1425
+ * `npx @valbuild/cli validate` called a module with un-extracted entries VALID
1426
+ * and a CI gate on it was green for the wrong reason. `loadValModules` avoids
1427
+ * constructor checks for exactly this reason and says so; this one was the
1428
+ * exception.
1429
+ *
1430
+ * `validateJsonEntryContent` is declared by `RecordSchema` and by nothing else,
1431
+ * so it is the brand — and checking it first keeps the cheap short-circuit
1432
+ * `instanceof` gave us, rather than serializing every non-record schema.
1433
+ */
1434
+ function isJsonValuesRecord(schema) {
1435
+ if (!("validateJsonEntryContent" in schema) || typeof schema.validateJsonEntryContent !== "function") {
1436
+ return false;
1437
+ }
1438
+ const serialized = schema["executeSerialize"]();
1439
+ return serialized.type === "record" && serialized.jsonValues === true;
1440
+ }
1441
+
1405
1442
  /**
1406
1443
  * Validates the content of every `.jsonValues()` entry in a module by loading
1407
1444
  * each backing `*.val.json` (via its lazy import thunk) and checking it against
@@ -1459,10 +1496,7 @@ async function validateJsonValuesEntries(schema, source, modulePath) {
1459
1496
  errors: out,
1460
1497
  loadedEntries
1461
1498
  };
1462
- if (!(schema instanceof core.RecordSchema)) {
1463
- return res;
1464
- }
1465
- if (!schema["executeSerialize"]().jsonValues) {
1499
+ if (!isJsonValuesRecord(schema)) {
1466
1500
  return res;
1467
1501
  }
1468
1502
  if (source === null || typeof source !== "object" || Array.isArray(source)) {
@@ -14300,37 +14334,50 @@ async function getFileMetadata(projectRoot, validationError) {
14300
14334
  }
14301
14335
 
14302
14336
  /**
14303
- * Moves ONE `.jsonValues()` entry that was written inline in the `.val.ts` into
14304
- * its own `*.val.json`, replacing the inline value with
14305
- * `c.json(() => import("./<key>.val.json"))`.
14337
+ * The two files an extraction touches, as text — nothing written yet.
14306
14338
  *
14307
- * This is the fix for the `jsonValues:extract-entry` validation error. It is not
14308
- * expressible as a patch (a patch edits one `.val.ts` and cannot create the
14309
- * backing JSON file), so it writes both files directly — JSON first, so a
14310
- * failure part-way through never leaves the module pointing at a file that does
14311
- * not exist.
14339
+ * Both paths are project-relative in the `ModuleFilePath` style (a leading
14340
+ * slash), because that is what the callers already hold and what
14341
+ * {@link getNewJsonEntryPaths} derives. Join them onto the project root to get
14342
+ * somewhere to write.
14343
+ */
14344
+
14345
+ /**
14346
+ * Works out what moving ONE inline `.jsonValues()` entry into its own
14347
+ * `*.val.json` would change, without changing anything.
14348
+ *
14349
+ * This is the whole fix for `jsonValues:extract-entry`, minus the writing. It
14350
+ * is split out because the two callers cannot share a way of applying it: the
14351
+ * CLI writes both files ({@link extractJsonValuesEntry}), while the editor has
14352
+ * to hand the same two changes back as a `WorkspaceEdit` so they go through the
14353
+ * undo stack and respect an unsaved buffer. Anything that lived in only one of
14354
+ * those would be a fix that behaves differently depending on where it was
14355
+ * invoked from, which is exactly the drift `codeActions.ts` exists to prevent.
14356
+ *
14357
+ * It does NOT check whether `jsonPath` already exists: that needs a filesystem,
14358
+ * and the editor's answer ("is there a buffer or a file here?") is not the
14359
+ * CLI's. Every caller must check before writing — overwriting an unrelated file
14360
+ * is not a fix.
14312
14361
  *
14313
14362
  * Root-only, like the rest of the `.jsonValues()` machinery: the entry is looked
14314
14363
  * up in the module's root record/router object literal.
14315
14364
  */
14316
- function extractJsonValuesEntry(moduleFilePath, rootDir, entryKey, content, sourceFileHandler) {
14317
- const valTsPath = sourceFileHandler.resolveSourceModulePath(getSyntheticContainingPath(rootDir), `.${moduleFilePath.replace(".val.ts", ".val").replace(".val.js", ".val").replace(".val.jsx", ".val").replace(".val.tsx", ".val")}`);
14318
- const sourceFile = sourceFileHandler.getSourceFile(valTsPath);
14319
- if (!sourceFile) {
14320
- throw Error(`Source file ${valTsPath} not found`);
14321
- }
14365
+ function planJsonValuesEntryExtraction({
14366
+ moduleFilePath,
14367
+ entryKey,
14368
+ content,
14369
+ valTsPath,
14370
+ valTsText
14371
+ }) {
14322
14372
  const pathsRes = getNewJsonEntryPaths(moduleFilePath, entryKey);
14323
14373
  if (fp.result.isErr(pathsRes)) {
14324
- throw Error(formatPatchSourceError(pathsRes.error));
14374
+ return fp.result.err(formatPatchSourceError(pathsRes.error));
14325
14375
  }
14326
14376
  const {
14327
14377
  jsonPath,
14328
14378
  importPath
14329
14379
  } = pathsRes.value;
14330
- const absoluteJsonPath = path__namespace["default"].join(rootDir, jsonPath);
14331
- if (sourceFileHandler.host.fileExists(absoluteJsonPath)) {
14332
- throw Error(`Cannot extract .jsonValues() entry '${entryKey}' of ${moduleFilePath}: '${jsonPath}' already exists`);
14333
- }
14380
+ const sourceFile = ts__default["default"].createSourceFile(valTsPath, valTsText, ts__default["default"].ScriptTarget.ES2020);
14334
14381
 
14335
14382
  // Remove the inline property, then add the `c.json(...)` reference back. The
14336
14383
  // entry moves to the end of the record: entry ORDER in a jsonValues record is
@@ -14338,14 +14385,70 @@ function extractJsonValuesEntry(moduleFilePath, rootDir, entryKey, content, sour
14338
14385
  // insert-in-place would mean reimplementing insertValJsonEntry.
14339
14386
  const removed = removeValJsonEntry(sourceFile, [], entryKey);
14340
14387
  if (fp.result.isErr(removed)) {
14341
- throw Error(`${valTsPath}\n${formatOpsError(removed.error, sourceFile)}`);
14388
+ return fp.result.err(`${valTsPath}\n${formatOpsError(removed.error, sourceFile)}`);
14342
14389
  }
14343
14390
  const inserted = insertValJsonEntry(removed.value, [], entryKey, importPath);
14344
14391
  if (fp.result.isErr(inserted)) {
14345
- throw Error(`${valTsPath}\n${formatOpsError(inserted.error, removed.value)}`);
14392
+ return fp.result.err(`${valTsPath}\n${formatOpsError(inserted.error, removed.value)}`);
14393
+ }
14394
+ return fp.result.ok({
14395
+ jsonPath,
14396
+ jsonContent: JSON.stringify(content, null, 2) + "\n",
14397
+ valTsPath,
14398
+ valTsContent: printSourceFile(inserted.value)
14399
+ });
14400
+ }
14401
+
14402
+ /**
14403
+ * Moves ONE `.jsonValues()` entry that was written inline in the `.val.ts` into
14404
+ * its own `*.val.json`, replacing the inline value with
14405
+ * `c.json(() => import("./<key>.val.json"))`.
14406
+ *
14407
+ * The `val validate --fix` half of {@link planJsonValuesEntryExtraction}. It is
14408
+ * not expressible as a patch (a patch edits one `.val.ts` and cannot create the
14409
+ * backing JSON file), so it writes both files directly — JSON first, so a
14410
+ * failure part-way through never leaves the module pointing at a file that does
14411
+ * not exist.
14412
+ */
14413
+ function extractJsonValuesEntry(moduleFilePath, rootDir, entryKey, content, sourceFileHandler) {
14414
+ const valTsPath = sourceFileHandler.resolveSourceModulePath(getSyntheticContainingPath(rootDir), `.${moduleFilePath.replace(".val.ts", ".val").replace(".val.js", ".val").replace(".val.jsx", ".val").replace(".val.tsx", ".val")}`);
14415
+ const valTsText = sourceFileHandler.host.readFile(valTsPath);
14416
+ if (valTsText === undefined) {
14417
+ throw Error(`Source file ${valTsPath} not found`);
14418
+ }
14419
+ const planned = planJsonValuesEntryExtraction({
14420
+ moduleFilePath,
14421
+ entryKey,
14422
+ content,
14423
+ valTsPath,
14424
+ valTsText
14425
+ });
14426
+ if (fp.result.isErr(planned)) {
14427
+ throw Error(planned.error);
14428
+ }
14429
+ const absoluteJsonPath = path__namespace["default"].join(rootDir, planned.value.jsonPath);
14430
+ if (sourceFileHandler.host.fileExists(absoluteJsonPath)) {
14431
+ throw Error(`Cannot extract .jsonValues() entry '${entryKey}' of ${moduleFilePath}: '${planned.value.jsonPath}' already exists`);
14346
14432
  }
14347
- sourceFileHandler.writeFile(absoluteJsonPath, JSON.stringify(content, null, 2) + "\n", "utf8");
14348
- sourceFileHandler.writeSourceFile(inserted.value);
14433
+ sourceFileHandler.writeFile(absoluteJsonPath, planned.value.jsonContent, "utf8");
14434
+ sourceFileHandler.writeFile(valTsPath, planned.value.valTsContent, "utf8");
14435
+ }
14436
+
14437
+ /**
14438
+ * The text of a source file the TS ops produced, exactly as
14439
+ * `ValSourceFileHandler.writeSourceFile` would have written it.
14440
+ *
14441
+ * The unescape undoes the printer's `\uXXXX` output for non-ASCII. Today the
14442
+ * ops splice printed text into `document.text` and this fix only ever prints an
14443
+ * ASCII `c.json(() => import("./..."))`, so nothing here is escaped and the
14444
+ * unescape is a no-op — but `neverAsciiEscape` is off in the printer, so that is
14445
+ * a property of what this fix happens to print, not a guarantee. Kept because
14446
+ * this replaced a `writeSourceFile` call and the text written must not change.
14447
+ *
14448
+ * https://github.com/microsoft/TypeScript/issues/36174
14449
+ */
14450
+ function printSourceFile(sourceFile) {
14451
+ return unescape(sourceFile.text.replace(/\\u/g, "%u"));
14349
14452
  }
14350
14453
  function formatOpsError(error, sourceFile) {
14351
14454
  if (error instanceof patch.PatchError) {
@@ -15655,6 +15758,7 @@ exports.ok = ok;
15655
15758
  exports.parsePersonalAccessTokenFile = parsePersonalAccessTokenFile;
15656
15759
  exports.patchSourceFile = patchSourceFile;
15657
15760
  exports.persistPersonalAccessToken = persistPersonalAccessToken;
15761
+ exports.planJsonValuesEntryExtraction = planJsonValuesEntryExtraction;
15658
15762
  exports.readCapturedReport = readCapturedReport;
15659
15763
  exports.readPatchStore = readPatchStore;
15660
15764
  exports.rebaseContentOp = rebaseContentOp;
@@ -1,7 +1,7 @@
1
1
  import ts from 'typescript';
2
2
  import { pipe, result, array } from '@valbuild/core/fp';
3
3
  import { PatchError, deepEqual, parseAndValidateArrayIndex, isNotRoot, applyPatch, JSONOps, deepClone, sourceToPatchPath } from '@valbuild/core/patch';
4
- import { derefPatch, Internal, RecordSchema, extractValModules, computeValModuleShas, VAL_EXTENSION, ImageSchema, DEFAULT_CONTENT_HOST, hasRemoteFileSchema } from '@valbuild/core';
4
+ import { derefPatch, Internal, extractValModules, computeValModuleShas, VAL_EXTENSION, ImageSchema, DEFAULT_CONTENT_HOST, hasRemoteFileSchema } from '@valbuild/core';
5
5
  export { hasRemoteFileSchema } from '@valbuild/core';
6
6
  import * as path from 'path';
7
7
  import path__default from 'path';
@@ -1368,6 +1368,43 @@ function resolveExistingJsonPath(moduleFilePath, importPath) {
1368
1368
  * only way to avoid loading every entry twice.
1369
1369
  */
1370
1370
 
1371
+ /**
1372
+ * The part of a `.jsonValues()` record this file calls. Named structurally
1373
+ * because the value may not be an instance of *this* copy of `RecordSchema` —
1374
+ * see {@link isJsonValuesRecord}.
1375
+ */
1376
+
1377
+ /**
1378
+ * Is this a `.jsonValues()` record?
1379
+ *
1380
+ * NOT `schema instanceof RecordSchema`, and the distinction is the whole point.
1381
+ * `loadValModules` evaluates the project's `*.val.ts` with a `require` rooted at
1382
+ * the PROJECT, deliberately, so the schemas are built by whatever
1383
+ * `@valbuild/core` the project resolves. When the CLI is itself installed in
1384
+ * that project, that is this very module and `instanceof` holds. When it is run
1385
+ * through `npx` / `pnpm dlx`, the tool gets its own copy of `@valbuild/core`
1386
+ * beside the project's, and `instanceof` is false for a record that is a record
1387
+ * in every way that matters — same class name, same serialized schema, same
1388
+ * methods, different realm.
1389
+ *
1390
+ * That failed OPEN: the whole check returned "no errors", so
1391
+ * `npx @valbuild/cli validate` called a module with un-extracted entries VALID
1392
+ * and a CI gate on it was green for the wrong reason. `loadValModules` avoids
1393
+ * constructor checks for exactly this reason and says so; this one was the
1394
+ * exception.
1395
+ *
1396
+ * `validateJsonEntryContent` is declared by `RecordSchema` and by nothing else,
1397
+ * so it is the brand — and checking it first keeps the cheap short-circuit
1398
+ * `instanceof` gave us, rather than serializing every non-record schema.
1399
+ */
1400
+ function isJsonValuesRecord(schema) {
1401
+ if (!("validateJsonEntryContent" in schema) || typeof schema.validateJsonEntryContent !== "function") {
1402
+ return false;
1403
+ }
1404
+ const serialized = schema["executeSerialize"]();
1405
+ return serialized.type === "record" && serialized.jsonValues === true;
1406
+ }
1407
+
1371
1408
  /**
1372
1409
  * Validates the content of every `.jsonValues()` entry in a module by loading
1373
1410
  * each backing `*.val.json` (via its lazy import thunk) and checking it against
@@ -1425,10 +1462,7 @@ async function validateJsonValuesEntries(schema, source, modulePath) {
1425
1462
  errors: out,
1426
1463
  loadedEntries
1427
1464
  };
1428
- if (!(schema instanceof RecordSchema)) {
1429
- return res;
1430
- }
1431
- if (!schema["executeSerialize"]().jsonValues) {
1465
+ if (!isJsonValuesRecord(schema)) {
1432
1466
  return res;
1433
1467
  }
1434
1468
  if (source === null || typeof source !== "object" || Array.isArray(source)) {
@@ -14266,37 +14300,50 @@ async function getFileMetadata(projectRoot, validationError) {
14266
14300
  }
14267
14301
 
14268
14302
  /**
14269
- * Moves ONE `.jsonValues()` entry that was written inline in the `.val.ts` into
14270
- * its own `*.val.json`, replacing the inline value with
14271
- * `c.json(() => import("./<key>.val.json"))`.
14303
+ * The two files an extraction touches, as text — nothing written yet.
14272
14304
  *
14273
- * This is the fix for the `jsonValues:extract-entry` validation error. It is not
14274
- * expressible as a patch (a patch edits one `.val.ts` and cannot create the
14275
- * backing JSON file), so it writes both files directly — JSON first, so a
14276
- * failure part-way through never leaves the module pointing at a file that does
14277
- * not exist.
14305
+ * Both paths are project-relative in the `ModuleFilePath` style (a leading
14306
+ * slash), because that is what the callers already hold and what
14307
+ * {@link getNewJsonEntryPaths} derives. Join them onto the project root to get
14308
+ * somewhere to write.
14309
+ */
14310
+
14311
+ /**
14312
+ * Works out what moving ONE inline `.jsonValues()` entry into its own
14313
+ * `*.val.json` would change, without changing anything.
14314
+ *
14315
+ * This is the whole fix for `jsonValues:extract-entry`, minus the writing. It
14316
+ * is split out because the two callers cannot share a way of applying it: the
14317
+ * CLI writes both files ({@link extractJsonValuesEntry}), while the editor has
14318
+ * to hand the same two changes back as a `WorkspaceEdit` so they go through the
14319
+ * undo stack and respect an unsaved buffer. Anything that lived in only one of
14320
+ * those would be a fix that behaves differently depending on where it was
14321
+ * invoked from, which is exactly the drift `codeActions.ts` exists to prevent.
14322
+ *
14323
+ * It does NOT check whether `jsonPath` already exists: that needs a filesystem,
14324
+ * and the editor's answer ("is there a buffer or a file here?") is not the
14325
+ * CLI's. Every caller must check before writing — overwriting an unrelated file
14326
+ * is not a fix.
14278
14327
  *
14279
14328
  * Root-only, like the rest of the `.jsonValues()` machinery: the entry is looked
14280
14329
  * up in the module's root record/router object literal.
14281
14330
  */
14282
- function extractJsonValuesEntry(moduleFilePath, rootDir, entryKey, content, sourceFileHandler) {
14283
- const valTsPath = sourceFileHandler.resolveSourceModulePath(getSyntheticContainingPath(rootDir), `.${moduleFilePath.replace(".val.ts", ".val").replace(".val.js", ".val").replace(".val.jsx", ".val").replace(".val.tsx", ".val")}`);
14284
- const sourceFile = sourceFileHandler.getSourceFile(valTsPath);
14285
- if (!sourceFile) {
14286
- throw Error(`Source file ${valTsPath} not found`);
14287
- }
14331
+ function planJsonValuesEntryExtraction({
14332
+ moduleFilePath,
14333
+ entryKey,
14334
+ content,
14335
+ valTsPath,
14336
+ valTsText
14337
+ }) {
14288
14338
  const pathsRes = getNewJsonEntryPaths(moduleFilePath, entryKey);
14289
14339
  if (result.isErr(pathsRes)) {
14290
- throw Error(formatPatchSourceError(pathsRes.error));
14340
+ return result.err(formatPatchSourceError(pathsRes.error));
14291
14341
  }
14292
14342
  const {
14293
14343
  jsonPath,
14294
14344
  importPath
14295
14345
  } = pathsRes.value;
14296
- const absoluteJsonPath = path__default.join(rootDir, jsonPath);
14297
- if (sourceFileHandler.host.fileExists(absoluteJsonPath)) {
14298
- throw Error(`Cannot extract .jsonValues() entry '${entryKey}' of ${moduleFilePath}: '${jsonPath}' already exists`);
14299
- }
14346
+ const sourceFile = ts.createSourceFile(valTsPath, valTsText, ts.ScriptTarget.ES2020);
14300
14347
 
14301
14348
  // Remove the inline property, then add the `c.json(...)` reference back. The
14302
14349
  // entry moves to the end of the record: entry ORDER in a jsonValues record is
@@ -14304,14 +14351,70 @@ function extractJsonValuesEntry(moduleFilePath, rootDir, entryKey, content, sour
14304
14351
  // insert-in-place would mean reimplementing insertValJsonEntry.
14305
14352
  const removed = removeValJsonEntry(sourceFile, [], entryKey);
14306
14353
  if (result.isErr(removed)) {
14307
- throw Error(`${valTsPath}\n${formatOpsError(removed.error, sourceFile)}`);
14354
+ return result.err(`${valTsPath}\n${formatOpsError(removed.error, sourceFile)}`);
14308
14355
  }
14309
14356
  const inserted = insertValJsonEntry(removed.value, [], entryKey, importPath);
14310
14357
  if (result.isErr(inserted)) {
14311
- throw Error(`${valTsPath}\n${formatOpsError(inserted.error, removed.value)}`);
14358
+ return result.err(`${valTsPath}\n${formatOpsError(inserted.error, removed.value)}`);
14359
+ }
14360
+ return result.ok({
14361
+ jsonPath,
14362
+ jsonContent: JSON.stringify(content, null, 2) + "\n",
14363
+ valTsPath,
14364
+ valTsContent: printSourceFile(inserted.value)
14365
+ });
14366
+ }
14367
+
14368
+ /**
14369
+ * Moves ONE `.jsonValues()` entry that was written inline in the `.val.ts` into
14370
+ * its own `*.val.json`, replacing the inline value with
14371
+ * `c.json(() => import("./<key>.val.json"))`.
14372
+ *
14373
+ * The `val validate --fix` half of {@link planJsonValuesEntryExtraction}. It is
14374
+ * not expressible as a patch (a patch edits one `.val.ts` and cannot create the
14375
+ * backing JSON file), so it writes both files directly — JSON first, so a
14376
+ * failure part-way through never leaves the module pointing at a file that does
14377
+ * not exist.
14378
+ */
14379
+ function extractJsonValuesEntry(moduleFilePath, rootDir, entryKey, content, sourceFileHandler) {
14380
+ const valTsPath = sourceFileHandler.resolveSourceModulePath(getSyntheticContainingPath(rootDir), `.${moduleFilePath.replace(".val.ts", ".val").replace(".val.js", ".val").replace(".val.jsx", ".val").replace(".val.tsx", ".val")}`);
14381
+ const valTsText = sourceFileHandler.host.readFile(valTsPath);
14382
+ if (valTsText === undefined) {
14383
+ throw Error(`Source file ${valTsPath} not found`);
14384
+ }
14385
+ const planned = planJsonValuesEntryExtraction({
14386
+ moduleFilePath,
14387
+ entryKey,
14388
+ content,
14389
+ valTsPath,
14390
+ valTsText
14391
+ });
14392
+ if (result.isErr(planned)) {
14393
+ throw Error(planned.error);
14394
+ }
14395
+ const absoluteJsonPath = path__default.join(rootDir, planned.value.jsonPath);
14396
+ if (sourceFileHandler.host.fileExists(absoluteJsonPath)) {
14397
+ throw Error(`Cannot extract .jsonValues() entry '${entryKey}' of ${moduleFilePath}: '${planned.value.jsonPath}' already exists`);
14312
14398
  }
14313
- sourceFileHandler.writeFile(absoluteJsonPath, JSON.stringify(content, null, 2) + "\n", "utf8");
14314
- sourceFileHandler.writeSourceFile(inserted.value);
14399
+ sourceFileHandler.writeFile(absoluteJsonPath, planned.value.jsonContent, "utf8");
14400
+ sourceFileHandler.writeFile(valTsPath, planned.value.valTsContent, "utf8");
14401
+ }
14402
+
14403
+ /**
14404
+ * The text of a source file the TS ops produced, exactly as
14405
+ * `ValSourceFileHandler.writeSourceFile` would have written it.
14406
+ *
14407
+ * The unescape undoes the printer's `\uXXXX` output for non-ASCII. Today the
14408
+ * ops splice printed text into `document.text` and this fix only ever prints an
14409
+ * ASCII `c.json(() => import("./..."))`, so nothing here is escaped and the
14410
+ * unescape is a no-op — but `neverAsciiEscape` is off in the printer, so that is
14411
+ * a property of what this fix happens to print, not a guarantee. Kept because
14412
+ * this replaced a `writeSourceFile` call and the text written must not change.
14413
+ *
14414
+ * https://github.com/microsoft/TypeScript/issues/36174
14415
+ */
14416
+ function printSourceFile(sourceFile) {
14417
+ return unescape(sourceFile.text.replace(/\\u/g, "%u"));
14315
14418
  }
14316
14419
  function formatOpsError(error, sourceFile) {
14317
14420
  if (error instanceof PatchError) {
@@ -15551,4 +15654,4 @@ function readCapturedReport(snapshotDir) {
15551
15654
  return JSON.parse(fs.readFileSync(reportPath, "utf-8"));
15552
15655
  }
15553
15656
 
15554
- export { DEFAULT_LOGIN_EXPIRES_IN_SECONDS, DEFAULT_LOGIN_HOST, DEFAULT_LOGIN_POLL_INTERVAL_SECONDS, EXTERNAL_RESULT, Service, ValFSHost, ValLoginError, ValModuleLoader, ValOpsFS, ValOpsHttp, ValSourceFileHandler, analyzeValModule, awaitValLoginConfirmation, checkRemoteRef, classifyJsonValuesOp, compareWithCapturedReport, createDefaultValFSHost, createFixPatch, createJsonEntryPathMap, createModulePathMap, createService, createValApiRouter, createValModuleFileInspector, createValOps, createValServer, currentFixHandlers, decodeJwtWithoutVerifying, defineExternal, describePatchStoreProblems, downloadFileFromRemote, encodeJwt, err, evalValConfigFile, extractFileMetadata, extractImageMetadata, extractJsonValuesEntry, findAndEvalValConfigFile, findJsonEntryFilePath, fixHandlers, formatPatchSourceError, formatSyntaxErrorTree, getCachedRemoteFileDir, getCachedRemoteFilePath, getCompilerOptions, getExpire, getFileExt, getModulePathRange, getPersonalAccessTokenPath, getSettings, getValidationErrorFileRef, handleCheckAllFiles, handleExternalUpload, handleFileMetadata, handleJsonValuesExtractEntry, handleRemoteFileCheck, handleRemoteFileDownload, handleRemoteFileUpload, handleRemoteGalleryFileUpload, handleUniqueFolderCheck, initHandlerOptions, isExternalResult, loadValModules, ok, parsePersonalAccessTokenFile, patchSourceFile, persistPersonalAccessToken, readCapturedReport, readPatchStore, rebaseContentOp, replaySnapshot, resolveRemoteFileAuth, safeReadGit, startValLogin, uploadRemoteFile, validateMetadata, verifyJwt };
15657
+ export { DEFAULT_LOGIN_EXPIRES_IN_SECONDS, DEFAULT_LOGIN_HOST, DEFAULT_LOGIN_POLL_INTERVAL_SECONDS, EXTERNAL_RESULT, Service, ValFSHost, ValLoginError, ValModuleLoader, ValOpsFS, ValOpsHttp, ValSourceFileHandler, analyzeValModule, awaitValLoginConfirmation, checkRemoteRef, classifyJsonValuesOp, compareWithCapturedReport, createDefaultValFSHost, createFixPatch, createJsonEntryPathMap, createModulePathMap, createService, createValApiRouter, createValModuleFileInspector, createValOps, createValServer, currentFixHandlers, decodeJwtWithoutVerifying, defineExternal, describePatchStoreProblems, downloadFileFromRemote, encodeJwt, err, evalValConfigFile, extractFileMetadata, extractImageMetadata, extractJsonValuesEntry, findAndEvalValConfigFile, findJsonEntryFilePath, fixHandlers, formatPatchSourceError, formatSyntaxErrorTree, getCachedRemoteFileDir, getCachedRemoteFilePath, getCompilerOptions, getExpire, getFileExt, getModulePathRange, getPersonalAccessTokenPath, getSettings, getValidationErrorFileRef, handleCheckAllFiles, handleExternalUpload, handleFileMetadata, handleJsonValuesExtractEntry, handleRemoteFileCheck, handleRemoteFileDownload, handleRemoteFileUpload, handleRemoteGalleryFileUpload, handleUniqueFolderCheck, initHandlerOptions, isExternalResult, loadValModules, ok, parsePersonalAccessTokenFile, patchSourceFile, persistPersonalAccessToken, planJsonValuesEntryExtraction, readCapturedReport, readPatchStore, rebaseContentOp, replaySnapshot, resolveRemoteFileAuth, safeReadGit, startValLogin, uploadRemoteFile, validateMetadata, verifyJwt };
package/package.json CHANGED
@@ -16,7 +16,7 @@
16
16
  "./package.json": "./package.json"
17
17
  },
18
18
  "types": "dist/valbuild-server.cjs.d.ts",
19
- "version": "0.123.2",
19
+ "version": "0.123.3",
20
20
  "devDependencies": {
21
21
  "@prettier/sync": "^0.6.1",
22
22
  "@types/jest": "^30.0.0"
@@ -29,9 +29,9 @@
29
29
  "typescript": "^6.0.3",
30
30
  "zod": "^4.4.3",
31
31
  "zod-validation-error": "^5.0.0",
32
- "@valbuild/shared": "0.123.2",
33
32
  "@valbuild/core": "0.121.0",
34
- "@valbuild/ui": "0.123.2"
33
+ "@valbuild/ui": "0.123.3",
34
+ "@valbuild/shared": "0.123.3"
35
35
  },
36
36
  "engines": {
37
37
  "node": "^20.19.0 || >=22"