@valbuild/language-server 0.143.1 → 0.144.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +17 -0
- package/README.md +1 -1
- package/dist/declarations/src/diagnostics.d.ts +1 -1
- package/dist/valbuild-language-server.cjs.dev.js +219 -164
- package/dist/valbuild-language-server.cjs.prod.js +219 -164
- package/dist/valbuild-language-server.esm.js +220 -165
- package/package.json +4 -4
|
@@ -183,7 +183,7 @@ var packageJson = {
|
|
|
183
183
|
"lsp",
|
|
184
184
|
"language-server"
|
|
185
185
|
],
|
|
186
|
-
version: "0.
|
|
186
|
+
version: "0.144.0",
|
|
187
187
|
bin: {
|
|
188
188
|
"val-language-server": "./bin.js"
|
|
189
189
|
},
|
|
@@ -1728,8 +1728,8 @@ function longestResolvedPrefixRange(modulePath, modulePathMap) {
|
|
|
1728
1728
|
/**
|
|
1729
1729
|
* Gallery checks core emits unconditionally.
|
|
1730
1730
|
*
|
|
1731
|
-
* `RecordSchema.validate` attaches these to every `s.
|
|
1732
|
-
* / `s.
|
|
1731
|
+
* `RecordSchema.validate` attaches these to every `s.imagedir()` / `s.filedir()`
|
|
1732
|
+
* / `s.videodir()` module whether or not anything is actually wrong (see
|
|
1733
1733
|
* `packages/core/src/schema/record.ts`): they are placeholders asking someone to
|
|
1734
1734
|
* go and look. `val validate` looks by running the matching fix handler, which
|
|
1735
1735
|
* reports success when the directory is unique and every file is accounted for.
|
|
@@ -1839,7 +1839,7 @@ function dropDeferredPlaceholders(validation) {
|
|
|
1839
1839
|
*
|
|
1840
1840
|
* `ImageSchema.validate` reports this (`packages/core/src/schema/image.ts`:
|
|
1841
1841
|
* "The gallery does not have an image at '…'"), and `VideoSchema.validate` the
|
|
1842
|
-
* same for a field picked from an `s.
|
|
1842
|
+
* same for a field picked from an `s.videodir()` ("The set does not have a
|
|
1843
1843
|
* video at '…'"), but neither attaches a `ValidationFix`,
|
|
1844
1844
|
* because the remedy is not a change to this module: either the gallery gains an
|
|
1845
1845
|
* entry, or the file moves into the gallery's directory. Both are edits to
|
|
@@ -2027,6 +2027,144 @@ function toModuleFilePath(valRoot, uri) {
|
|
|
2027
2027
|
return `/${relative.split(path__default["default"].sep).join("/")}`;
|
|
2028
2028
|
}
|
|
2029
2029
|
|
|
2030
|
+
const jsonOps = new patch.JSONOps();
|
|
2031
|
+
|
|
2032
|
+
/**
|
|
2033
|
+
* Turning a fix patch into an edit when the value it fixes is NOT in the
|
|
2034
|
+
* `.val.ts` the diagnostic was reported on.
|
|
2035
|
+
*
|
|
2036
|
+
* A `.jsonValues()` record keeps each entry's value in its own `*.val.json`; the
|
|
2037
|
+
* `.val.ts` holds `c.json(() => import("./x.val.json"))` and nothing below it.
|
|
2038
|
+
* So a fix for, say, an `s.image()` inside an entry produces a patch whose path
|
|
2039
|
+
* starts at the module root (`["/jobb/student", "pageImage", "width"]`) but
|
|
2040
|
+
* whose target lives in another file entirely.
|
|
2041
|
+
*
|
|
2042
|
+
* Applying such a patch to the `.val.ts` cannot work: the walk reaches the
|
|
2043
|
+
* `c.json(...)` call expression and `TSOps` refuses it ("Expression must be a
|
|
2044
|
+
* literal"). That refusal is why an editor silently offered no quick fix at all
|
|
2045
|
+
* for anything inside an entry — `computeFixEdit` saw an error result and
|
|
2046
|
+
* dropped the action.
|
|
2047
|
+
*
|
|
2048
|
+
* The routing here is the same one the Studio's publish and `val validate --fix`
|
|
2049
|
+
* use — {@link classifyJsonValuesOp} to find the entry, {@link rebaseContentOp}
|
|
2050
|
+
* to drop the entry-key prefix — so all three write the same file the same way.
|
|
2051
|
+
* What is specific to the editor is only the last step: the result comes back as
|
|
2052
|
+
* a `TextEdit` against the entry's document rather than as a write to disk, so
|
|
2053
|
+
* the edit goes through the editor's undo stack and respects an unsaved buffer.
|
|
2054
|
+
*/
|
|
2055
|
+
|
|
2056
|
+
function jsonEntryEditFor({
|
|
2057
|
+
patch: patch$1,
|
|
2058
|
+
schema,
|
|
2059
|
+
moduleFilePath,
|
|
2060
|
+
valTsText,
|
|
2061
|
+
valRoot,
|
|
2062
|
+
read
|
|
2063
|
+
}) {
|
|
2064
|
+
if (!schema) {
|
|
2065
|
+
return undefined;
|
|
2066
|
+
}
|
|
2067
|
+
const entry = entryOpsOf(patch$1, schema);
|
|
2068
|
+
if (!entry) {
|
|
2069
|
+
return undefined;
|
|
2070
|
+
}
|
|
2071
|
+
const jsonFilePath = server.findJsonEntryFilePath(moduleFilePath, ts__default["default"].createSourceFile(moduleFilePath, valTsText, ts__default["default"].ScriptTarget.ES2020), entry.entryKey);
|
|
2072
|
+
if (!jsonFilePath) {
|
|
2073
|
+
return undefined;
|
|
2074
|
+
}
|
|
2075
|
+
const absolutePath = path__default["default"].join(valRoot, jsonFilePath);
|
|
2076
|
+
const before = read?.(absolutePath) ?? readFile(absolutePath);
|
|
2077
|
+
if (before === undefined) {
|
|
2078
|
+
return undefined;
|
|
2079
|
+
}
|
|
2080
|
+
let content;
|
|
2081
|
+
try {
|
|
2082
|
+
content = JSON.parse(before);
|
|
2083
|
+
} catch {
|
|
2084
|
+
// A malformed entry file is already reported as a load error; offering an
|
|
2085
|
+
// edit computed from a guess at its contents would be worse than offering
|
|
2086
|
+
// nothing.
|
|
2087
|
+
return undefined;
|
|
2088
|
+
}
|
|
2089
|
+
for (const op of entry.ops) {
|
|
2090
|
+
// Root-only, like the rest of the `.jsonValues()` machinery, so the prefix
|
|
2091
|
+
// to drop is exactly the entry key.
|
|
2092
|
+
const rebased = server.rebaseContentOp(op, 1);
|
|
2093
|
+
if (fp.result.isErr(rebased)) {
|
|
2094
|
+
return undefined;
|
|
2095
|
+
}
|
|
2096
|
+
const applied = patch.applyPatch(patch.deepClone(content), jsonOps, [rebased.value]);
|
|
2097
|
+
if (fp.result.isErr(applied)) {
|
|
2098
|
+
return undefined;
|
|
2099
|
+
}
|
|
2100
|
+
content = applied.value;
|
|
2101
|
+
}
|
|
2102
|
+
// Re-serialising the whole value and diffing it is what keeps this honest:
|
|
2103
|
+
// the alternative is editing JSON text by hand, and the fix would then differ
|
|
2104
|
+
// from what the CLI writes. `minimalTextEdit` narrows the result to the region
|
|
2105
|
+
// that actually changed, so a two-space-indented file (what prettier and the
|
|
2106
|
+
// CLI both produce) yields an edit covering the changed properties and no
|
|
2107
|
+
// more. A file indented differently gets a correct but larger edit.
|
|
2108
|
+
const after = JSON.stringify(content, null, 2) + (before.endsWith("\n") ? "\n" : "");
|
|
2109
|
+
const uri = pathToUri(absolutePath);
|
|
2110
|
+
const edit = minimalTextEdit(before, after, vscodeLanguageserverTextdocument.TextDocument.create(uri, "json", 0, before));
|
|
2111
|
+
return edit && {
|
|
2112
|
+
uri,
|
|
2113
|
+
edit
|
|
2114
|
+
};
|
|
2115
|
+
}
|
|
2116
|
+
|
|
2117
|
+
/**
|
|
2118
|
+
* The ops of `patch`, if every one of them edits the content of ONE
|
|
2119
|
+
* `.jsonValues()` entry. `undefined` for anything else — an ordinary module, a
|
|
2120
|
+
* patch that also touches the `.val.ts`, or one that adds or removes a whole
|
|
2121
|
+
* entry — because those either belong on the `.val.ts` (the caller's existing
|
|
2122
|
+
* path) or need both files written at once, which a single `TextEdit` cannot do.
|
|
2123
|
+
*/
|
|
2124
|
+
function entryOpsOf(patch, schema) {
|
|
2125
|
+
let entryKey;
|
|
2126
|
+
const ops = [];
|
|
2127
|
+
for (const op of patch) {
|
|
2128
|
+
const cls = server.classifyJsonValuesOp(schema, op.path);
|
|
2129
|
+
if (cls.kind !== "entry") {
|
|
2130
|
+
return undefined;
|
|
2131
|
+
}
|
|
2132
|
+
// Nested `.jsonValues()` is rejected as a module error long before a fix is
|
|
2133
|
+
// offered; treat it as out of scope rather than writing to a guessed file.
|
|
2134
|
+
if (cls.recordPath.length > 0 || cls.subPath.length === 0) {
|
|
2135
|
+
return undefined;
|
|
2136
|
+
}
|
|
2137
|
+
// `move` and `copy` carry a second path, and `rebaseContentOp` slices `from`
|
|
2138
|
+
// by the same prefix as `path` -- so an op reaching outside this entry would
|
|
2139
|
+
// have its source silently reinterpreted as a path inside this entry's file.
|
|
2140
|
+
if (op.op === "move" || op.op === "copy") {
|
|
2141
|
+
const fromCls = server.classifyJsonValuesOp(schema, op.from);
|
|
2142
|
+
if (fromCls.kind !== "entry" || fromCls.entryKey !== cls.entryKey) {
|
|
2143
|
+
return undefined;
|
|
2144
|
+
}
|
|
2145
|
+
}
|
|
2146
|
+
if (entryKey !== undefined && entryKey !== cls.entryKey) {
|
|
2147
|
+
return undefined;
|
|
2148
|
+
}
|
|
2149
|
+
entryKey = cls.entryKey;
|
|
2150
|
+
ops.push(op);
|
|
2151
|
+
}
|
|
2152
|
+
if (entryKey === undefined || ops.length === 0) {
|
|
2153
|
+
return undefined;
|
|
2154
|
+
}
|
|
2155
|
+
return {
|
|
2156
|
+
entryKey,
|
|
2157
|
+
ops
|
|
2158
|
+
};
|
|
2159
|
+
}
|
|
2160
|
+
function readFile(filePath) {
|
|
2161
|
+
try {
|
|
2162
|
+
return fs__default["default"].readFileSync(filePath, "utf8");
|
|
2163
|
+
} catch {
|
|
2164
|
+
return undefined;
|
|
2165
|
+
}
|
|
2166
|
+
}
|
|
2167
|
+
|
|
2030
2168
|
/**
|
|
2031
2169
|
* `workspace/executeCommand` handlers.
|
|
2032
2170
|
*
|
|
@@ -2301,9 +2439,11 @@ function createValCommands(deps) {
|
|
|
2301
2439
|
// them in the same edit, so one undo takes back all of it.
|
|
2302
2440
|
const unwritten = [];
|
|
2303
2441
|
for (const other of outcome.otherModulePatches ?? []) {
|
|
2304
|
-
const
|
|
2305
|
-
if (
|
|
2306
|
-
(
|
|
2442
|
+
const otherEdits = await editsForModulePatch(project, other);
|
|
2443
|
+
if (otherEdits) {
|
|
2444
|
+
for (const otherEdit of otherEdits) {
|
|
2445
|
+
(changes[otherEdit.uri] ??= []).push(otherEdit.edit);
|
|
2446
|
+
}
|
|
2307
2447
|
} else {
|
|
2308
2448
|
unwritten.push(other.moduleFilePath);
|
|
2309
2449
|
}
|
|
@@ -2330,31 +2470,84 @@ function createValCommands(deps) {
|
|
|
2330
2470
|
}
|
|
2331
2471
|
|
|
2332
2472
|
/**
|
|
2333
|
-
* The
|
|
2334
|
-
* against the editor's
|
|
2473
|
+
* The edits for a patch to another module than the one the command ran on,
|
|
2474
|
+
* against the editor's buffers when the files are open and the disk
|
|
2475
|
+
* otherwise. `undefined` when any part of it cannot be written: half a rename
|
|
2476
|
+
* is worse than a warning naming the module.
|
|
2477
|
+
*
|
|
2478
|
+
* A `.jsonValues()` entry's value is in its own `*.val.json`, not in the
|
|
2479
|
+
* `.val.ts` — so the ops are split by the entry they land in, and each
|
|
2480
|
+
* entry's go through `jsonEntryEditFor`, the same routing a quick fix inside
|
|
2481
|
+
* an entry uses. Only what is left is applied to the `.val.ts`.
|
|
2335
2482
|
*/
|
|
2336
|
-
function
|
|
2337
|
-
const
|
|
2338
|
-
|
|
2339
|
-
|
|
2340
|
-
|
|
2341
|
-
|
|
2342
|
-
|
|
2343
|
-
|
|
2483
|
+
async function editsForModulePatch(project, other) {
|
|
2484
|
+
const {
|
|
2485
|
+
valRoot
|
|
2486
|
+
} = project;
|
|
2487
|
+
const moduleFile = path__default["default"].join(valRoot, other.moduleFilePath);
|
|
2488
|
+
const uri = pathToUri(moduleFile);
|
|
2489
|
+
const valTsText = readBuffer(moduleFile);
|
|
2490
|
+
if (valTsText === undefined) {
|
|
2491
|
+
return undefined;
|
|
2492
|
+
}
|
|
2493
|
+
const moduleResult = await project.getModule(other.moduleFilePath, {
|
|
2494
|
+
validate: false
|
|
2495
|
+
});
|
|
2496
|
+
const schema = moduleResult.status === "ok" ? moduleResult.content.schema : undefined;
|
|
2497
|
+
const valTsOps = [];
|
|
2498
|
+
const entryOps = new Map();
|
|
2499
|
+
for (const op of other.patch) {
|
|
2500
|
+
const cls = schema && server.classifyJsonValuesOp(schema, op.path);
|
|
2501
|
+
if (cls && cls.kind === "entry") {
|
|
2502
|
+
const ops = entryOps.get(cls.entryKey) ?? [];
|
|
2503
|
+
ops.push(op);
|
|
2504
|
+
entryOps.set(cls.entryKey, ops);
|
|
2505
|
+
} else {
|
|
2506
|
+
valTsOps.push(op);
|
|
2507
|
+
}
|
|
2508
|
+
}
|
|
2509
|
+
const edits = [];
|
|
2510
|
+
for (const ops of entryOps.values()) {
|
|
2511
|
+
const entryEdit = jsonEntryEditFor({
|
|
2512
|
+
patch: ops,
|
|
2513
|
+
schema,
|
|
2514
|
+
moduleFilePath: other.moduleFilePath,
|
|
2515
|
+
valTsText,
|
|
2516
|
+
valRoot,
|
|
2517
|
+
read: readBuffer
|
|
2518
|
+
});
|
|
2519
|
+
if (!entryEdit) {
|
|
2344
2520
|
return undefined;
|
|
2345
2521
|
}
|
|
2346
|
-
|
|
2522
|
+
edits.push(entryEdit);
|
|
2523
|
+
}
|
|
2524
|
+
if (valTsOps.length > 0) {
|
|
2525
|
+
const patched = server.patchSourceFile(valTsText, valTsOps);
|
|
2526
|
+
if (fp.result.isErr(patched)) {
|
|
2527
|
+
return undefined;
|
|
2528
|
+
}
|
|
2529
|
+
const edit = minimalTextEdit(valTsText, patched.value.text, vscodeLanguageserverTextdocument.TextDocument.create(uri, "typescript", 0, valTsText));
|
|
2530
|
+
if (edit) {
|
|
2531
|
+
edits.push({
|
|
2532
|
+
uri,
|
|
2533
|
+
edit
|
|
2534
|
+
});
|
|
2535
|
+
}
|
|
2536
|
+
}
|
|
2537
|
+
return edits;
|
|
2538
|
+
}
|
|
2539
|
+
|
|
2540
|
+
/** A file as the editor has it, falling back to disk. */
|
|
2541
|
+
function readBuffer(fsPath) {
|
|
2542
|
+
const open = deps.getDocument(pathToUri(fsPath));
|
|
2543
|
+
if (open) {
|
|
2544
|
+
return open.getText();
|
|
2347
2545
|
}
|
|
2348
|
-
|
|
2349
|
-
|
|
2350
|
-
|
|
2546
|
+
try {
|
|
2547
|
+
return fs__default["default"].readFileSync(fsPath, "utf8");
|
|
2548
|
+
} catch {
|
|
2351
2549
|
return undefined;
|
|
2352
2550
|
}
|
|
2353
|
-
const otherEdit = minimalTextEdit(otherBefore, otherPatched.value.text, otherDocument);
|
|
2354
|
-
return otherEdit && {
|
|
2355
|
-
uri,
|
|
2356
|
-
edit: otherEdit
|
|
2357
|
-
};
|
|
2358
2551
|
}
|
|
2359
2552
|
return {
|
|
2360
2553
|
async execute(command, args) {
|
|
@@ -2537,144 +2730,6 @@ function valModulesEntryText({
|
|
|
2537
2730
|
return hasElements ? `,\n${indentation}${entry}` : `\n${indentation}${entry}\n${indentation.slice(2)}`;
|
|
2538
2731
|
}
|
|
2539
2732
|
|
|
2540
|
-
const jsonOps = new patch.JSONOps();
|
|
2541
|
-
|
|
2542
|
-
/**
|
|
2543
|
-
* Turning a fix patch into an edit when the value it fixes is NOT in the
|
|
2544
|
-
* `.val.ts` the diagnostic was reported on.
|
|
2545
|
-
*
|
|
2546
|
-
* A `.jsonValues()` record keeps each entry's value in its own `*.val.json`; the
|
|
2547
|
-
* `.val.ts` holds `c.json(() => import("./x.val.json"))` and nothing below it.
|
|
2548
|
-
* So a fix for, say, an `s.image()` inside an entry produces a patch whose path
|
|
2549
|
-
* starts at the module root (`["/jobb/student", "pageImage", "width"]`) but
|
|
2550
|
-
* whose target lives in another file entirely.
|
|
2551
|
-
*
|
|
2552
|
-
* Applying such a patch to the `.val.ts` cannot work: the walk reaches the
|
|
2553
|
-
* `c.json(...)` call expression and `TSOps` refuses it ("Expression must be a
|
|
2554
|
-
* literal"). That refusal is why an editor silently offered no quick fix at all
|
|
2555
|
-
* for anything inside an entry — `computeFixEdit` saw an error result and
|
|
2556
|
-
* dropped the action.
|
|
2557
|
-
*
|
|
2558
|
-
* The routing here is the same one the Studio's publish and `val validate --fix`
|
|
2559
|
-
* use — {@link classifyJsonValuesOp} to find the entry, {@link rebaseContentOp}
|
|
2560
|
-
* to drop the entry-key prefix — so all three write the same file the same way.
|
|
2561
|
-
* What is specific to the editor is only the last step: the result comes back as
|
|
2562
|
-
* a `TextEdit` against the entry's document rather than as a write to disk, so
|
|
2563
|
-
* the edit goes through the editor's undo stack and respects an unsaved buffer.
|
|
2564
|
-
*/
|
|
2565
|
-
|
|
2566
|
-
function jsonEntryEditFor({
|
|
2567
|
-
patch: patch$1,
|
|
2568
|
-
schema,
|
|
2569
|
-
moduleFilePath,
|
|
2570
|
-
valTsText,
|
|
2571
|
-
valRoot,
|
|
2572
|
-
read
|
|
2573
|
-
}) {
|
|
2574
|
-
if (!schema) {
|
|
2575
|
-
return undefined;
|
|
2576
|
-
}
|
|
2577
|
-
const entry = entryOpsOf(patch$1, schema);
|
|
2578
|
-
if (!entry) {
|
|
2579
|
-
return undefined;
|
|
2580
|
-
}
|
|
2581
|
-
const jsonFilePath = server.findJsonEntryFilePath(moduleFilePath, ts__default["default"].createSourceFile(moduleFilePath, valTsText, ts__default["default"].ScriptTarget.ES2020), entry.entryKey);
|
|
2582
|
-
if (!jsonFilePath) {
|
|
2583
|
-
return undefined;
|
|
2584
|
-
}
|
|
2585
|
-
const absolutePath = path__default["default"].join(valRoot, jsonFilePath);
|
|
2586
|
-
const before = read?.(absolutePath) ?? readFile(absolutePath);
|
|
2587
|
-
if (before === undefined) {
|
|
2588
|
-
return undefined;
|
|
2589
|
-
}
|
|
2590
|
-
let content;
|
|
2591
|
-
try {
|
|
2592
|
-
content = JSON.parse(before);
|
|
2593
|
-
} catch {
|
|
2594
|
-
// A malformed entry file is already reported as a load error; offering an
|
|
2595
|
-
// edit computed from a guess at its contents would be worse than offering
|
|
2596
|
-
// nothing.
|
|
2597
|
-
return undefined;
|
|
2598
|
-
}
|
|
2599
|
-
for (const op of entry.ops) {
|
|
2600
|
-
// Root-only, like the rest of the `.jsonValues()` machinery, so the prefix
|
|
2601
|
-
// to drop is exactly the entry key.
|
|
2602
|
-
const rebased = server.rebaseContentOp(op, 1);
|
|
2603
|
-
if (fp.result.isErr(rebased)) {
|
|
2604
|
-
return undefined;
|
|
2605
|
-
}
|
|
2606
|
-
const applied = patch.applyPatch(patch.deepClone(content), jsonOps, [rebased.value]);
|
|
2607
|
-
if (fp.result.isErr(applied)) {
|
|
2608
|
-
return undefined;
|
|
2609
|
-
}
|
|
2610
|
-
content = applied.value;
|
|
2611
|
-
}
|
|
2612
|
-
// Re-serialising the whole value and diffing it is what keeps this honest:
|
|
2613
|
-
// the alternative is editing JSON text by hand, and the fix would then differ
|
|
2614
|
-
// from what the CLI writes. `minimalTextEdit` narrows the result to the region
|
|
2615
|
-
// that actually changed, so a two-space-indented file (what prettier and the
|
|
2616
|
-
// CLI both produce) yields an edit covering the changed properties and no
|
|
2617
|
-
// more. A file indented differently gets a correct but larger edit.
|
|
2618
|
-
const after = JSON.stringify(content, null, 2) + (before.endsWith("\n") ? "\n" : "");
|
|
2619
|
-
const uri = pathToUri(absolutePath);
|
|
2620
|
-
const edit = minimalTextEdit(before, after, vscodeLanguageserverTextdocument.TextDocument.create(uri, "json", 0, before));
|
|
2621
|
-
return edit && {
|
|
2622
|
-
uri,
|
|
2623
|
-
edit
|
|
2624
|
-
};
|
|
2625
|
-
}
|
|
2626
|
-
|
|
2627
|
-
/**
|
|
2628
|
-
* The ops of `patch`, if every one of them edits the content of ONE
|
|
2629
|
-
* `.jsonValues()` entry. `undefined` for anything else — an ordinary module, a
|
|
2630
|
-
* patch that also touches the `.val.ts`, or one that adds or removes a whole
|
|
2631
|
-
* entry — because those either belong on the `.val.ts` (the caller's existing
|
|
2632
|
-
* path) or need both files written at once, which a single `TextEdit` cannot do.
|
|
2633
|
-
*/
|
|
2634
|
-
function entryOpsOf(patch, schema) {
|
|
2635
|
-
let entryKey;
|
|
2636
|
-
const ops = [];
|
|
2637
|
-
for (const op of patch) {
|
|
2638
|
-
const cls = server.classifyJsonValuesOp(schema, op.path);
|
|
2639
|
-
if (cls.kind !== "entry") {
|
|
2640
|
-
return undefined;
|
|
2641
|
-
}
|
|
2642
|
-
// Nested `.jsonValues()` is rejected as a module error long before a fix is
|
|
2643
|
-
// offered; treat it as out of scope rather than writing to a guessed file.
|
|
2644
|
-
if (cls.recordPath.length > 0 || cls.subPath.length === 0) {
|
|
2645
|
-
return undefined;
|
|
2646
|
-
}
|
|
2647
|
-
// `move` and `copy` carry a second path, and `rebaseContentOp` slices `from`
|
|
2648
|
-
// by the same prefix as `path` -- so an op reaching outside this entry would
|
|
2649
|
-
// have its source silently reinterpreted as a path inside this entry's file.
|
|
2650
|
-
if (op.op === "move" || op.op === "copy") {
|
|
2651
|
-
const fromCls = server.classifyJsonValuesOp(schema, op.from);
|
|
2652
|
-
if (fromCls.kind !== "entry" || fromCls.entryKey !== cls.entryKey) {
|
|
2653
|
-
return undefined;
|
|
2654
|
-
}
|
|
2655
|
-
}
|
|
2656
|
-
if (entryKey !== undefined && entryKey !== cls.entryKey) {
|
|
2657
|
-
return undefined;
|
|
2658
|
-
}
|
|
2659
|
-
entryKey = cls.entryKey;
|
|
2660
|
-
ops.push(op);
|
|
2661
|
-
}
|
|
2662
|
-
if (entryKey === undefined || ops.length === 0) {
|
|
2663
|
-
return undefined;
|
|
2664
|
-
}
|
|
2665
|
-
return {
|
|
2666
|
-
entryKey,
|
|
2667
|
-
ops
|
|
2668
|
-
};
|
|
2669
|
-
}
|
|
2670
|
-
function readFile(filePath) {
|
|
2671
|
-
try {
|
|
2672
|
-
return fs__default["default"].readFileSync(filePath, "utf8");
|
|
2673
|
-
} catch {
|
|
2674
|
-
return undefined;
|
|
2675
|
-
}
|
|
2676
|
-
}
|
|
2677
|
-
|
|
2678
2733
|
/**
|
|
2679
2734
|
* What the client announced it will do with a `WorkspaceEdit`.
|
|
2680
2735
|
*
|