@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
|
@@ -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)) {
|
|
@@ -13506,6 +13540,72 @@ async function extractFileMetadata(filename, _input // TODO: use buffer to deter
|
|
|
13506
13540
|
};
|
|
13507
13541
|
}
|
|
13508
13542
|
|
|
13543
|
+
/**
|
|
13544
|
+
* A gallery entry's key, read as what it actually is.
|
|
13545
|
+
*
|
|
13546
|
+
* A gallery is a record keyed by its entries' file paths. A REMOTE gallery keys
|
|
13547
|
+
* an uploaded entry by the remote URL instead — which encodes that same path —
|
|
13548
|
+
* so every entry has a local path, and the interesting question is whether the
|
|
13549
|
+
* bytes are expected to be at it.
|
|
13550
|
+
*
|
|
13551
|
+
* **They are not, for a remote entry added the ordinary way.** `saveOrUploadFiles`
|
|
13552
|
+
* uploads the remote descriptors to the content host and copies only the local
|
|
13553
|
+
* ones into the working tree, so an image added through the Studio (or over MCP)
|
|
13554
|
+
* and published has no file in the repo, by design — putting one there is what
|
|
13555
|
+
* remote storage exists to avoid. A remote entry CAN have one, because
|
|
13556
|
+
* `val validate --fix` promotes a local file to a remote ref and leaves the file
|
|
13557
|
+
* where it was; so "remote" means "do not require it", never "there is not one".
|
|
13558
|
+
*
|
|
13559
|
+
* One copy, in its own file, because this used to be two: a `remoteKeyToLocalPath`
|
|
13560
|
+
* in `fixHandlers` and a `galleryKeyToLocalPath` in `createFixPatch`, each
|
|
13561
|
+
* normalising the key correctly and each then treating the result as a file that
|
|
13562
|
+
* must exist. That agreement is what made a published remote image report as
|
|
13563
|
+
* missing from both sides at once.
|
|
13564
|
+
*/
|
|
13565
|
+
|
|
13566
|
+
/**
|
|
13567
|
+
* A key that names somewhere else, whether or not it is a ref we can read.
|
|
13568
|
+
*
|
|
13569
|
+
* Case-insensitive, because a scheme is (RFC 3986) — and because
|
|
13570
|
+
* `splitRemoteRef`'s pattern is not, so `HTTPS://…` is precisely one of the
|
|
13571
|
+
* spellings that arrives here unparsed and must not be mistaken for a path.
|
|
13572
|
+
*/
|
|
13573
|
+
function isRemoteUrl(key) {
|
|
13574
|
+
return /^https?:\/\//i.test(key);
|
|
13575
|
+
}
|
|
13576
|
+
function galleryEntryOf(key) {
|
|
13577
|
+
const remoteRefRes = core.Internal.remote.splitRemoteRef(key);
|
|
13578
|
+
if (remoteRefRes.status === "success") {
|
|
13579
|
+
return {
|
|
13580
|
+
localPath: `/${remoteRefRes.filePath}`,
|
|
13581
|
+
remote: true
|
|
13582
|
+
};
|
|
13583
|
+
}
|
|
13584
|
+
if (isRemoteUrl(key)) {
|
|
13585
|
+
// A URL that is not a ref this version can read: truncated by a hand edit,
|
|
13586
|
+
// a path outside `public/`, a `..` segment — or written by a core version
|
|
13587
|
+
// whose format `splitRemoteRef` rejects.
|
|
13588
|
+
//
|
|
13589
|
+
// Still not a path in the working tree, so the on-disk checks must not run
|
|
13590
|
+
// against it. They would find nothing at `<projectRoot>/https://…`, report
|
|
13591
|
+
// the entry as missing, and `--fix` would DELETE it — the exact failure
|
|
13592
|
+
// this module exists to prevent, arriving at the one moment the key is the
|
|
13593
|
+
// only remaining record of where the bytes went.
|
|
13594
|
+
//
|
|
13595
|
+
// Nothing is being hidden by this: a malformed key is already reported, by
|
|
13596
|
+
// the record schema's own "Invalid remote URL format". That is an error for
|
|
13597
|
+
// a person to look at, not a file for `--fix` to go missing.
|
|
13598
|
+
return {
|
|
13599
|
+
localPath: key,
|
|
13600
|
+
remote: true
|
|
13601
|
+
};
|
|
13602
|
+
}
|
|
13603
|
+
return {
|
|
13604
|
+
localPath: key,
|
|
13605
|
+
remote: false
|
|
13606
|
+
};
|
|
13607
|
+
}
|
|
13608
|
+
|
|
13509
13609
|
/**
|
|
13510
13610
|
* The media path a validation error is about, if it is about media at all.
|
|
13511
13611
|
*
|
|
@@ -13701,14 +13801,6 @@ async function downloadFileFromRemote(ref, filePath) {
|
|
|
13701
13801
|
// record-level fix expands into per-entry errors that should point at the
|
|
13702
13802
|
// individual entry (e.g. `?p="/public/val/logo.png"`) rather than the record.
|
|
13703
13803
|
|
|
13704
|
-
// Gallery entries are keyed by their file path. Remote galleries key uploaded
|
|
13705
|
-
// entries by a remote URL while keeping the file on disk at its local path, so
|
|
13706
|
-
// normalize a remote-URL key back to that local path for on-disk reads.
|
|
13707
|
-
function galleryKeyToLocalPath(key) {
|
|
13708
|
-
const res = core.Internal.remote.splitRemoteRef(key);
|
|
13709
|
-
return res.status === "success" ? `/${res.filePath}` : key;
|
|
13710
|
-
}
|
|
13711
|
-
|
|
13712
13804
|
// Patch path of the record that holds a media entry. Media keys are file paths
|
|
13713
13805
|
// that can contain dots, which sourceToPatchPath cannot round-trip, so strip
|
|
13714
13806
|
// the (JSON-encoded) key segment off the entry source path and convert the
|
|
@@ -14017,7 +14109,18 @@ async function createFixPatch(config, apply, sourcePath, validationError, remote
|
|
|
14017
14109
|
}
|
|
14018
14110
|
const gallerySource = moduleSource;
|
|
14019
14111
|
for (const [entryKey, storedEntry] of Object.entries(gallerySource)) {
|
|
14020
|
-
const
|
|
14112
|
+
const entry = galleryEntryOf(entryKey);
|
|
14113
|
+
if (entry.remote) {
|
|
14114
|
+
// A remote entry's bytes are on the content host, so there may be no
|
|
14115
|
+
// local file to re-derive its metadata from — and where there is one,
|
|
14116
|
+
// rewriting the metadata from it would invalidate the ref, which has
|
|
14117
|
+
// that metadata baked into its validation hash. Whether a remote
|
|
14118
|
+
// entry is sound is `image:check-remote`'s question, and it already
|
|
14119
|
+
// asks it. Reading the file here reported every published remote
|
|
14120
|
+
// image as unreadable, and with `--fix` REMOVED it from the gallery.
|
|
14121
|
+
continue;
|
|
14122
|
+
}
|
|
14123
|
+
const filename = path__namespace["default"].join(config.projectRoot, entry.localPath);
|
|
14021
14124
|
let buffer;
|
|
14022
14125
|
try {
|
|
14023
14126
|
buffer = fs__default["default"].readFileSync(filename);
|
|
@@ -14231,37 +14334,50 @@ async function getFileMetadata(projectRoot, validationError) {
|
|
|
14231
14334
|
}
|
|
14232
14335
|
|
|
14233
14336
|
/**
|
|
14234
|
-
*
|
|
14235
|
-
* its own `*.val.json`, replacing the inline value with
|
|
14236
|
-
* `c.json(() => import("./<key>.val.json"))`.
|
|
14337
|
+
* The two files an extraction touches, as text — nothing written yet.
|
|
14237
14338
|
*
|
|
14238
|
-
*
|
|
14239
|
-
*
|
|
14240
|
-
*
|
|
14241
|
-
*
|
|
14242
|
-
|
|
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.
|
|
14243
14361
|
*
|
|
14244
14362
|
* Root-only, like the rest of the `.jsonValues()` machinery: the entry is looked
|
|
14245
14363
|
* up in the module's root record/router object literal.
|
|
14246
14364
|
*/
|
|
14247
|
-
function
|
|
14248
|
-
|
|
14249
|
-
|
|
14250
|
-
|
|
14251
|
-
|
|
14252
|
-
|
|
14365
|
+
function planJsonValuesEntryExtraction({
|
|
14366
|
+
moduleFilePath,
|
|
14367
|
+
entryKey,
|
|
14368
|
+
content,
|
|
14369
|
+
valTsPath,
|
|
14370
|
+
valTsText
|
|
14371
|
+
}) {
|
|
14253
14372
|
const pathsRes = getNewJsonEntryPaths(moduleFilePath, entryKey);
|
|
14254
14373
|
if (fp.result.isErr(pathsRes)) {
|
|
14255
|
-
|
|
14374
|
+
return fp.result.err(formatPatchSourceError(pathsRes.error));
|
|
14256
14375
|
}
|
|
14257
14376
|
const {
|
|
14258
14377
|
jsonPath,
|
|
14259
14378
|
importPath
|
|
14260
14379
|
} = pathsRes.value;
|
|
14261
|
-
const
|
|
14262
|
-
if (sourceFileHandler.host.fileExists(absoluteJsonPath)) {
|
|
14263
|
-
throw Error(`Cannot extract .jsonValues() entry '${entryKey}' of ${moduleFilePath}: '${jsonPath}' already exists`);
|
|
14264
|
-
}
|
|
14380
|
+
const sourceFile = ts__default["default"].createSourceFile(valTsPath, valTsText, ts__default["default"].ScriptTarget.ES2020);
|
|
14265
14381
|
|
|
14266
14382
|
// Remove the inline property, then add the `c.json(...)` reference back. The
|
|
14267
14383
|
// entry moves to the end of the record: entry ORDER in a jsonValues record is
|
|
@@ -14269,14 +14385,70 @@ function extractJsonValuesEntry(moduleFilePath, rootDir, entryKey, content, sour
|
|
|
14269
14385
|
// insert-in-place would mean reimplementing insertValJsonEntry.
|
|
14270
14386
|
const removed = removeValJsonEntry(sourceFile, [], entryKey);
|
|
14271
14387
|
if (fp.result.isErr(removed)) {
|
|
14272
|
-
|
|
14388
|
+
return fp.result.err(`${valTsPath}\n${formatOpsError(removed.error, sourceFile)}`);
|
|
14273
14389
|
}
|
|
14274
14390
|
const inserted = insertValJsonEntry(removed.value, [], entryKey, importPath);
|
|
14275
14391
|
if (fp.result.isErr(inserted)) {
|
|
14276
|
-
|
|
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`);
|
|
14277
14418
|
}
|
|
14278
|
-
|
|
14279
|
-
|
|
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`);
|
|
14432
|
+
}
|
|
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"));
|
|
14280
14452
|
}
|
|
14281
14453
|
function formatOpsError(error, sourceFile) {
|
|
14282
14454
|
if (error instanceof patch.PatchError) {
|
|
@@ -14683,15 +14855,48 @@ async function handleUniqueFolderCheck(ctx) {
|
|
|
14683
14855
|
};
|
|
14684
14856
|
}
|
|
14685
14857
|
|
|
14686
|
-
|
|
14687
|
-
|
|
14688
|
-
|
|
14689
|
-
|
|
14690
|
-
|
|
14691
|
-
|
|
14692
|
-
|
|
14858
|
+
/**
|
|
14859
|
+
* What is out of step between a gallery's entries and its directory.
|
|
14860
|
+
*
|
|
14861
|
+
* Two questions, and they treat a remote entry differently — which is the whole
|
|
14862
|
+
* reason this is separate from the handler around it:
|
|
14863
|
+
*
|
|
14864
|
+
* - **Missing**: an entry with no bytes at its local path. Asked of LOCAL
|
|
14865
|
+
* entries only. A remote entry's bytes live on the content host, and nothing
|
|
14866
|
+
* puts a copy in the working tree: `saveOrUploadFiles` uploads the remote
|
|
14867
|
+
* descriptors and copies only the local ones into the tree, so a remote entry
|
|
14868
|
+
* added through the Studio (or over MCP) has no local file by design, and
|
|
14869
|
+
* demanding one would mean committing remote bytes to git — which is what
|
|
14870
|
+
* remote storage exists to avoid. Whether those bytes really are on the host
|
|
14871
|
+
* is a different check, `image:check-remote`, which already runs for exactly
|
|
14872
|
+
* these entries.
|
|
14873
|
+
* - **Untracked**: a file in the directory that no entry claims. Asked of every
|
|
14874
|
+
* entry, remote included, and that is why they are normalised to their local
|
|
14875
|
+
* path: `val validate --fix` promotes a local file to a remote ref and leaves
|
|
14876
|
+
* the file where it was, so a remote entry can perfectly well have one.
|
|
14877
|
+
*/
|
|
14878
|
+
function checkGalleryFiles(input) {
|
|
14879
|
+
const {
|
|
14880
|
+
directory,
|
|
14881
|
+
projectRoot,
|
|
14882
|
+
fs
|
|
14883
|
+
} = input;
|
|
14884
|
+
const entries = input.entryKeys.map(galleryEntryOf);
|
|
14885
|
+
const trackedFiles = new Set(entries.map(entry => entry.localPath));
|
|
14886
|
+
const missingTrackedFiles = entries.filter(entry => !entry.remote && !fs.fileExists(path__namespace["default"].join(projectRoot, entry.localPath))).map(entry => entry.localPath);
|
|
14887
|
+
const filesInDir = [];
|
|
14888
|
+
try {
|
|
14889
|
+
const found = fs.readDirectory(path__namespace["default"].join(projectRoot, directory), undefined, undefined, ["**/*"]);
|
|
14890
|
+
for (const entry of found) {
|
|
14891
|
+
filesInDir.push("/" + path__namespace["default"].relative(projectRoot, entry).split(path__namespace["default"].sep).join("/"));
|
|
14892
|
+
}
|
|
14893
|
+
} catch {
|
|
14894
|
+
// directory doesn't exist — no untracked files possible
|
|
14693
14895
|
}
|
|
14694
|
-
return
|
|
14896
|
+
return {
|
|
14897
|
+
missingTrackedFiles,
|
|
14898
|
+
untrackedFiles: filesInDir.filter(f => !trackedFiles.has(f))
|
|
14899
|
+
};
|
|
14695
14900
|
}
|
|
14696
14901
|
async function handleCheckAllFiles(ctx) {
|
|
14697
14902
|
const value = ctx.validationError.value;
|
|
@@ -14711,14 +14916,14 @@ async function handleCheckAllFiles(ctx) {
|
|
|
14711
14916
|
errorMessage: `Could not get source for ${ctx.sourcePath}`
|
|
14712
14917
|
};
|
|
14713
14918
|
}
|
|
14714
|
-
|
|
14715
|
-
|
|
14716
|
-
|
|
14717
|
-
|
|
14718
|
-
|
|
14719
|
-
|
|
14720
|
-
|
|
14721
|
-
|
|
14919
|
+
const {
|
|
14920
|
+
missingTrackedFiles,
|
|
14921
|
+
untrackedFiles
|
|
14922
|
+
} = checkGalleryFiles({
|
|
14923
|
+
entryKeys: Object.keys(source),
|
|
14924
|
+
directory,
|
|
14925
|
+
projectRoot: ctx.projectRoot,
|
|
14926
|
+
fs: ctx.fs
|
|
14722
14927
|
});
|
|
14723
14928
|
if (missingTrackedFiles.length > 0) {
|
|
14724
14929
|
if (!ctx.fix) {
|
|
@@ -14733,18 +14938,6 @@ async function handleCheckAllFiles(ctx) {
|
|
|
14733
14938
|
shouldApplyPatch: true
|
|
14734
14939
|
};
|
|
14735
14940
|
}
|
|
14736
|
-
const dirPath = path__namespace["default"].join(ctx.projectRoot, directory);
|
|
14737
|
-
const filesInDir = [];
|
|
14738
|
-
try {
|
|
14739
|
-
const entries = ctx.fs.readDirectory(dirPath, undefined, undefined, ["**/*"]);
|
|
14740
|
-
for (const entry of entries) {
|
|
14741
|
-
const relPath = "/" + path__namespace["default"].relative(ctx.projectRoot, entry).split(path__namespace["default"].sep).join("/");
|
|
14742
|
-
filesInDir.push(relPath);
|
|
14743
|
-
}
|
|
14744
|
-
} catch {
|
|
14745
|
-
// directory doesn't exist — no untracked files possible
|
|
14746
|
-
}
|
|
14747
|
-
const untrackedFiles = filesInDir.filter(f => !trackedFiles.has(f));
|
|
14748
14941
|
if (untrackedFiles.length > 0) {
|
|
14749
14942
|
return {
|
|
14750
14943
|
success: false,
|
|
@@ -15565,6 +15758,7 @@ exports.ok = ok;
|
|
|
15565
15758
|
exports.parsePersonalAccessTokenFile = parsePersonalAccessTokenFile;
|
|
15566
15759
|
exports.patchSourceFile = patchSourceFile;
|
|
15567
15760
|
exports.persistPersonalAccessToken = persistPersonalAccessToken;
|
|
15761
|
+
exports.planJsonValuesEntryExtraction = planJsonValuesEntryExtraction;
|
|
15568
15762
|
exports.readCapturedReport = readCapturedReport;
|
|
15569
15763
|
exports.readPatchStore = readPatchStore;
|
|
15570
15764
|
exports.rebaseContentOp = rebaseContentOp;
|