@valbuild/server 0.123.0 → 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 +53 -0
- package/dist/declarations/src/extractJsonValuesEntry.d.ts +49 -5
- package/dist/declarations/src/fixHandlers.d.ts +29 -0
- package/dist/declarations/src/index.d.ts +2 -1
- package/dist/valbuild-server.cjs.dev.js +258 -64
- package/dist/valbuild-server.cjs.prod.js +258 -64
- package/dist/valbuild-server.esm.js +259 -66
- package/package.json +3 -3
|
@@ -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)) {
|
|
@@ -13472,6 +13506,72 @@ async function extractFileMetadata(filename, _input // TODO: use buffer to deter
|
|
|
13472
13506
|
};
|
|
13473
13507
|
}
|
|
13474
13508
|
|
|
13509
|
+
/**
|
|
13510
|
+
* A gallery entry's key, read as what it actually is.
|
|
13511
|
+
*
|
|
13512
|
+
* A gallery is a record keyed by its entries' file paths. A REMOTE gallery keys
|
|
13513
|
+
* an uploaded entry by the remote URL instead — which encodes that same path —
|
|
13514
|
+
* so every entry has a local path, and the interesting question is whether the
|
|
13515
|
+
* bytes are expected to be at it.
|
|
13516
|
+
*
|
|
13517
|
+
* **They are not, for a remote entry added the ordinary way.** `saveOrUploadFiles`
|
|
13518
|
+
* uploads the remote descriptors to the content host and copies only the local
|
|
13519
|
+
* ones into the working tree, so an image added through the Studio (or over MCP)
|
|
13520
|
+
* and published has no file in the repo, by design — putting one there is what
|
|
13521
|
+
* remote storage exists to avoid. A remote entry CAN have one, because
|
|
13522
|
+
* `val validate --fix` promotes a local file to a remote ref and leaves the file
|
|
13523
|
+
* where it was; so "remote" means "do not require it", never "there is not one".
|
|
13524
|
+
*
|
|
13525
|
+
* One copy, in its own file, because this used to be two: a `remoteKeyToLocalPath`
|
|
13526
|
+
* in `fixHandlers` and a `galleryKeyToLocalPath` in `createFixPatch`, each
|
|
13527
|
+
* normalising the key correctly and each then treating the result as a file that
|
|
13528
|
+
* must exist. That agreement is what made a published remote image report as
|
|
13529
|
+
* missing from both sides at once.
|
|
13530
|
+
*/
|
|
13531
|
+
|
|
13532
|
+
/**
|
|
13533
|
+
* A key that names somewhere else, whether or not it is a ref we can read.
|
|
13534
|
+
*
|
|
13535
|
+
* Case-insensitive, because a scheme is (RFC 3986) — and because
|
|
13536
|
+
* `splitRemoteRef`'s pattern is not, so `HTTPS://…` is precisely one of the
|
|
13537
|
+
* spellings that arrives here unparsed and must not be mistaken for a path.
|
|
13538
|
+
*/
|
|
13539
|
+
function isRemoteUrl(key) {
|
|
13540
|
+
return /^https?:\/\//i.test(key);
|
|
13541
|
+
}
|
|
13542
|
+
function galleryEntryOf(key) {
|
|
13543
|
+
const remoteRefRes = Internal.remote.splitRemoteRef(key);
|
|
13544
|
+
if (remoteRefRes.status === "success") {
|
|
13545
|
+
return {
|
|
13546
|
+
localPath: `/${remoteRefRes.filePath}`,
|
|
13547
|
+
remote: true
|
|
13548
|
+
};
|
|
13549
|
+
}
|
|
13550
|
+
if (isRemoteUrl(key)) {
|
|
13551
|
+
// A URL that is not a ref this version can read: truncated by a hand edit,
|
|
13552
|
+
// a path outside `public/`, a `..` segment — or written by a core version
|
|
13553
|
+
// whose format `splitRemoteRef` rejects.
|
|
13554
|
+
//
|
|
13555
|
+
// Still not a path in the working tree, so the on-disk checks must not run
|
|
13556
|
+
// against it. They would find nothing at `<projectRoot>/https://…`, report
|
|
13557
|
+
// the entry as missing, and `--fix` would DELETE it — the exact failure
|
|
13558
|
+
// this module exists to prevent, arriving at the one moment the key is the
|
|
13559
|
+
// only remaining record of where the bytes went.
|
|
13560
|
+
//
|
|
13561
|
+
// Nothing is being hidden by this: a malformed key is already reported, by
|
|
13562
|
+
// the record schema's own "Invalid remote URL format". That is an error for
|
|
13563
|
+
// a person to look at, not a file for `--fix` to go missing.
|
|
13564
|
+
return {
|
|
13565
|
+
localPath: key,
|
|
13566
|
+
remote: true
|
|
13567
|
+
};
|
|
13568
|
+
}
|
|
13569
|
+
return {
|
|
13570
|
+
localPath: key,
|
|
13571
|
+
remote: false
|
|
13572
|
+
};
|
|
13573
|
+
}
|
|
13574
|
+
|
|
13475
13575
|
/**
|
|
13476
13576
|
* The media path a validation error is about, if it is about media at all.
|
|
13477
13577
|
*
|
|
@@ -13667,14 +13767,6 @@ async function downloadFileFromRemote(ref, filePath) {
|
|
|
13667
13767
|
// record-level fix expands into per-entry errors that should point at the
|
|
13668
13768
|
// individual entry (e.g. `?p="/public/val/logo.png"`) rather than the record.
|
|
13669
13769
|
|
|
13670
|
-
// Gallery entries are keyed by their file path. Remote galleries key uploaded
|
|
13671
|
-
// entries by a remote URL while keeping the file on disk at its local path, so
|
|
13672
|
-
// normalize a remote-URL key back to that local path for on-disk reads.
|
|
13673
|
-
function galleryKeyToLocalPath(key) {
|
|
13674
|
-
const res = Internal.remote.splitRemoteRef(key);
|
|
13675
|
-
return res.status === "success" ? `/${res.filePath}` : key;
|
|
13676
|
-
}
|
|
13677
|
-
|
|
13678
13770
|
// Patch path of the record that holds a media entry. Media keys are file paths
|
|
13679
13771
|
// that can contain dots, which sourceToPatchPath cannot round-trip, so strip
|
|
13680
13772
|
// the (JSON-encoded) key segment off the entry source path and convert the
|
|
@@ -13983,7 +14075,18 @@ async function createFixPatch(config, apply, sourcePath, validationError, remote
|
|
|
13983
14075
|
}
|
|
13984
14076
|
const gallerySource = moduleSource;
|
|
13985
14077
|
for (const [entryKey, storedEntry] of Object.entries(gallerySource)) {
|
|
13986
|
-
const
|
|
14078
|
+
const entry = galleryEntryOf(entryKey);
|
|
14079
|
+
if (entry.remote) {
|
|
14080
|
+
// A remote entry's bytes are on the content host, so there may be no
|
|
14081
|
+
// local file to re-derive its metadata from — and where there is one,
|
|
14082
|
+
// rewriting the metadata from it would invalidate the ref, which has
|
|
14083
|
+
// that metadata baked into its validation hash. Whether a remote
|
|
14084
|
+
// entry is sound is `image:check-remote`'s question, and it already
|
|
14085
|
+
// asks it. Reading the file here reported every published remote
|
|
14086
|
+
// image as unreadable, and with `--fix` REMOVED it from the gallery.
|
|
14087
|
+
continue;
|
|
14088
|
+
}
|
|
14089
|
+
const filename = path__default.join(config.projectRoot, entry.localPath);
|
|
13987
14090
|
let buffer;
|
|
13988
14091
|
try {
|
|
13989
14092
|
buffer = fs.readFileSync(filename);
|
|
@@ -14197,37 +14300,50 @@ async function getFileMetadata(projectRoot, validationError) {
|
|
|
14197
14300
|
}
|
|
14198
14301
|
|
|
14199
14302
|
/**
|
|
14200
|
-
*
|
|
14201
|
-
* its own `*.val.json`, replacing the inline value with
|
|
14202
|
-
* `c.json(() => import("./<key>.val.json"))`.
|
|
14303
|
+
* The two files an extraction touches, as text — nothing written yet.
|
|
14203
14304
|
*
|
|
14204
|
-
*
|
|
14205
|
-
*
|
|
14206
|
-
*
|
|
14207
|
-
*
|
|
14208
|
-
|
|
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.
|
|
14209
14327
|
*
|
|
14210
14328
|
* Root-only, like the rest of the `.jsonValues()` machinery: the entry is looked
|
|
14211
14329
|
* up in the module's root record/router object literal.
|
|
14212
14330
|
*/
|
|
14213
|
-
function
|
|
14214
|
-
|
|
14215
|
-
|
|
14216
|
-
|
|
14217
|
-
|
|
14218
|
-
|
|
14331
|
+
function planJsonValuesEntryExtraction({
|
|
14332
|
+
moduleFilePath,
|
|
14333
|
+
entryKey,
|
|
14334
|
+
content,
|
|
14335
|
+
valTsPath,
|
|
14336
|
+
valTsText
|
|
14337
|
+
}) {
|
|
14219
14338
|
const pathsRes = getNewJsonEntryPaths(moduleFilePath, entryKey);
|
|
14220
14339
|
if (result.isErr(pathsRes)) {
|
|
14221
|
-
|
|
14340
|
+
return result.err(formatPatchSourceError(pathsRes.error));
|
|
14222
14341
|
}
|
|
14223
14342
|
const {
|
|
14224
14343
|
jsonPath,
|
|
14225
14344
|
importPath
|
|
14226
14345
|
} = pathsRes.value;
|
|
14227
|
-
const
|
|
14228
|
-
if (sourceFileHandler.host.fileExists(absoluteJsonPath)) {
|
|
14229
|
-
throw Error(`Cannot extract .jsonValues() entry '${entryKey}' of ${moduleFilePath}: '${jsonPath}' already exists`);
|
|
14230
|
-
}
|
|
14346
|
+
const sourceFile = ts.createSourceFile(valTsPath, valTsText, ts.ScriptTarget.ES2020);
|
|
14231
14347
|
|
|
14232
14348
|
// Remove the inline property, then add the `c.json(...)` reference back. The
|
|
14233
14349
|
// entry moves to the end of the record: entry ORDER in a jsonValues record is
|
|
@@ -14235,14 +14351,70 @@ function extractJsonValuesEntry(moduleFilePath, rootDir, entryKey, content, sour
|
|
|
14235
14351
|
// insert-in-place would mean reimplementing insertValJsonEntry.
|
|
14236
14352
|
const removed = removeValJsonEntry(sourceFile, [], entryKey);
|
|
14237
14353
|
if (result.isErr(removed)) {
|
|
14238
|
-
|
|
14354
|
+
return result.err(`${valTsPath}\n${formatOpsError(removed.error, sourceFile)}`);
|
|
14239
14355
|
}
|
|
14240
14356
|
const inserted = insertValJsonEntry(removed.value, [], entryKey, importPath);
|
|
14241
14357
|
if (result.isErr(inserted)) {
|
|
14242
|
-
|
|
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`);
|
|
14243
14384
|
}
|
|
14244
|
-
|
|
14245
|
-
|
|
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`);
|
|
14398
|
+
}
|
|
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"));
|
|
14246
14418
|
}
|
|
14247
14419
|
function formatOpsError(error, sourceFile) {
|
|
14248
14420
|
if (error instanceof PatchError) {
|
|
@@ -14649,15 +14821,48 @@ async function handleUniqueFolderCheck(ctx) {
|
|
|
14649
14821
|
};
|
|
14650
14822
|
}
|
|
14651
14823
|
|
|
14652
|
-
|
|
14653
|
-
|
|
14654
|
-
|
|
14655
|
-
|
|
14656
|
-
|
|
14657
|
-
|
|
14658
|
-
|
|
14824
|
+
/**
|
|
14825
|
+
* What is out of step between a gallery's entries and its directory.
|
|
14826
|
+
*
|
|
14827
|
+
* Two questions, and they treat a remote entry differently — which is the whole
|
|
14828
|
+
* reason this is separate from the handler around it:
|
|
14829
|
+
*
|
|
14830
|
+
* - **Missing**: an entry with no bytes at its local path. Asked of LOCAL
|
|
14831
|
+
* entries only. A remote entry's bytes live on the content host, and nothing
|
|
14832
|
+
* puts a copy in the working tree: `saveOrUploadFiles` uploads the remote
|
|
14833
|
+
* descriptors and copies only the local ones into the tree, so a remote entry
|
|
14834
|
+
* added through the Studio (or over MCP) has no local file by design, and
|
|
14835
|
+
* demanding one would mean committing remote bytes to git — which is what
|
|
14836
|
+
* remote storage exists to avoid. Whether those bytes really are on the host
|
|
14837
|
+
* is a different check, `image:check-remote`, which already runs for exactly
|
|
14838
|
+
* these entries.
|
|
14839
|
+
* - **Untracked**: a file in the directory that no entry claims. Asked of every
|
|
14840
|
+
* entry, remote included, and that is why they are normalised to their local
|
|
14841
|
+
* path: `val validate --fix` promotes a local file to a remote ref and leaves
|
|
14842
|
+
* the file where it was, so a remote entry can perfectly well have one.
|
|
14843
|
+
*/
|
|
14844
|
+
function checkGalleryFiles(input) {
|
|
14845
|
+
const {
|
|
14846
|
+
directory,
|
|
14847
|
+
projectRoot,
|
|
14848
|
+
fs
|
|
14849
|
+
} = input;
|
|
14850
|
+
const entries = input.entryKeys.map(galleryEntryOf);
|
|
14851
|
+
const trackedFiles = new Set(entries.map(entry => entry.localPath));
|
|
14852
|
+
const missingTrackedFiles = entries.filter(entry => !entry.remote && !fs.fileExists(path__default.join(projectRoot, entry.localPath))).map(entry => entry.localPath);
|
|
14853
|
+
const filesInDir = [];
|
|
14854
|
+
try {
|
|
14855
|
+
const found = fs.readDirectory(path__default.join(projectRoot, directory), undefined, undefined, ["**/*"]);
|
|
14856
|
+
for (const entry of found) {
|
|
14857
|
+
filesInDir.push("/" + path__default.relative(projectRoot, entry).split(path__default.sep).join("/"));
|
|
14858
|
+
}
|
|
14859
|
+
} catch {
|
|
14860
|
+
// directory doesn't exist — no untracked files possible
|
|
14659
14861
|
}
|
|
14660
|
-
return
|
|
14862
|
+
return {
|
|
14863
|
+
missingTrackedFiles,
|
|
14864
|
+
untrackedFiles: filesInDir.filter(f => !trackedFiles.has(f))
|
|
14865
|
+
};
|
|
14661
14866
|
}
|
|
14662
14867
|
async function handleCheckAllFiles(ctx) {
|
|
14663
14868
|
const value = ctx.validationError.value;
|
|
@@ -14677,14 +14882,14 @@ async function handleCheckAllFiles(ctx) {
|
|
|
14677
14882
|
errorMessage: `Could not get source for ${ctx.sourcePath}`
|
|
14678
14883
|
};
|
|
14679
14884
|
}
|
|
14680
|
-
|
|
14681
|
-
|
|
14682
|
-
|
|
14683
|
-
|
|
14684
|
-
|
|
14685
|
-
|
|
14686
|
-
|
|
14687
|
-
|
|
14885
|
+
const {
|
|
14886
|
+
missingTrackedFiles,
|
|
14887
|
+
untrackedFiles
|
|
14888
|
+
} = checkGalleryFiles({
|
|
14889
|
+
entryKeys: Object.keys(source),
|
|
14890
|
+
directory,
|
|
14891
|
+
projectRoot: ctx.projectRoot,
|
|
14892
|
+
fs: ctx.fs
|
|
14688
14893
|
});
|
|
14689
14894
|
if (missingTrackedFiles.length > 0) {
|
|
14690
14895
|
if (!ctx.fix) {
|
|
@@ -14699,18 +14904,6 @@ async function handleCheckAllFiles(ctx) {
|
|
|
14699
14904
|
shouldApplyPatch: true
|
|
14700
14905
|
};
|
|
14701
14906
|
}
|
|
14702
|
-
const dirPath = path__default.join(ctx.projectRoot, directory);
|
|
14703
|
-
const filesInDir = [];
|
|
14704
|
-
try {
|
|
14705
|
-
const entries = ctx.fs.readDirectory(dirPath, undefined, undefined, ["**/*"]);
|
|
14706
|
-
for (const entry of entries) {
|
|
14707
|
-
const relPath = "/" + path__default.relative(ctx.projectRoot, entry).split(path__default.sep).join("/");
|
|
14708
|
-
filesInDir.push(relPath);
|
|
14709
|
-
}
|
|
14710
|
-
} catch {
|
|
14711
|
-
// directory doesn't exist — no untracked files possible
|
|
14712
|
-
}
|
|
14713
|
-
const untrackedFiles = filesInDir.filter(f => !trackedFiles.has(f));
|
|
14714
14907
|
if (untrackedFiles.length > 0) {
|
|
14715
14908
|
return {
|
|
14716
14909
|
success: false,
|
|
@@ -15461,4 +15654,4 @@ function readCapturedReport(snapshotDir) {
|
|
|
15461
15654
|
return JSON.parse(fs.readFileSync(reportPath, "utf-8"));
|
|
15462
15655
|
}
|
|
15463
15656
|
|
|
15464
|
-
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"
|
|
@@ -30,8 +30,8 @@
|
|
|
30
30
|
"zod": "^4.4.3",
|
|
31
31
|
"zod-validation-error": "^5.0.0",
|
|
32
32
|
"@valbuild/core": "0.121.0",
|
|
33
|
-
"@valbuild/
|
|
34
|
-
"@valbuild/
|
|
33
|
+
"@valbuild/ui": "0.123.3",
|
|
34
|
+
"@valbuild/shared": "0.123.3"
|
|
35
35
|
},
|
|
36
36
|
"engines": {
|
|
37
37
|
"node": "^20.19.0 || >=22"
|