@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 +22 -0
- package/dist/declarations/src/extractJsonValuesEntry.d.ts +49 -5
- package/dist/declarations/src/index.d.ts +2 -1
- package/dist/valbuild-server.cjs.dev.js +131 -27
- package/dist/valbuild-server.cjs.prod.js +131 -27
- package/dist/valbuild-server.esm.js +132 -29
- package/package.json +3 -3
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
|
-
*
|
|
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
|
|
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
|
-
*
|
|
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
|
-
*
|
|
14308
|
-
*
|
|
14309
|
-
*
|
|
14310
|
-
*
|
|
14311
|
-
|
|
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
|
|
14317
|
-
|
|
14318
|
-
|
|
14319
|
-
|
|
14320
|
-
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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,
|
|
14348
|
-
sourceFileHandler.
|
|
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
|
|
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
|
-
*
|
|
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
|
-
*
|
|
14308
|
-
*
|
|
14309
|
-
*
|
|
14310
|
-
*
|
|
14311
|
-
|
|
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
|
|
14317
|
-
|
|
14318
|
-
|
|
14319
|
-
|
|
14320
|
-
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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,
|
|
14348
|
-
sourceFileHandler.
|
|
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,
|
|
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
|
|
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
|
-
*
|
|
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
|
-
*
|
|
14274
|
-
*
|
|
14275
|
-
*
|
|
14276
|
-
*
|
|
14277
|
-
|
|
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
|
|
14283
|
-
|
|
14284
|
-
|
|
14285
|
-
|
|
14286
|
-
|
|
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
|
-
|
|
14340
|
+
return result.err(formatPatchSourceError(pathsRes.error));
|
|
14291
14341
|
}
|
|
14292
14342
|
const {
|
|
14293
14343
|
jsonPath,
|
|
14294
14344
|
importPath
|
|
14295
14345
|
} = pathsRes.value;
|
|
14296
|
-
const
|
|
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
|
-
|
|
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
|
-
|
|
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,
|
|
14314
|
-
sourceFileHandler.
|
|
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.
|
|
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.
|
|
33
|
+
"@valbuild/ui": "0.123.3",
|
|
34
|
+
"@valbuild/shared": "0.123.3"
|
|
35
35
|
},
|
|
36
36
|
"engines": {
|
|
37
37
|
"node": "^20.19.0 || >=22"
|