@mrclrchtr/supi-lsp 11.0.1 → 11.1.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/README.md +1 -1
- package/node_modules/@mrclrchtr/supi-code-runtime/package.json +1 -1
- package/node_modules/@mrclrchtr/supi-core/package.json +1 -1
- package/node_modules/@mrclrchtr/supi-core/src/debug-registry.ts +41 -1
- package/node_modules/ignore/README.md +36 -10
- package/node_modules/ignore/index.d.ts +3 -2
- package/node_modules/ignore/index.js +57 -53
- package/node_modules/ignore/legacy.js +50 -46
- package/node_modules/ignore/package.json +1 -1
- package/node_modules/vscode-jsonrpc/README.md +5 -0
- package/node_modules/vscode-jsonrpc/lib/browser/ril.js +8 -0
- package/node_modules/vscode-jsonrpc/lib/common/connection.js +7 -2
- package/node_modules/vscode-jsonrpc/lib/common/ral.d.ts +8 -0
- package/node_modules/vscode-jsonrpc/lib/node/main.d.ts +14 -0
- package/node_modules/vscode-jsonrpc/lib/node/main.js +6 -4
- package/node_modules/vscode-jsonrpc/lib/node/ril.js +5 -1
- package/node_modules/vscode-jsonrpc/package.json +4 -2
- package/node_modules/vscode-languageserver-protocol/package.json +4 -3
- package/node_modules/vscode-languageserver-types/lib/esm/main.js +2 -2
- package/node_modules/vscode-languageserver-types/lib/umd/main.js +2 -2
- package/node_modules/vscode-languageserver-types/package.json +2 -1
- package/package.json +6 -6
- package/src/client/client.ts +21 -0
- package/src/manager/manager.ts +1 -1
package/README.md
CHANGED
|
@@ -153,7 +153,7 @@ Caller cancellation or deadline stops only that caller's wait. Explicit diagnost
|
|
|
153
153
|
|
|
154
154
|
If another request first opens a document during an active semantic or diagnostic request, the client can synchronize and repeat the request once. The retry retains the caller's original signal and deadline. Content, workspace, close, and lifecycle changes still reject stale results. A diagnostic retry collects new request evidence; it does not promote an old cache. This retry is not route recovery. A second enrollment during the retry still rejects the result. Semantic failure reasons state whether the retry failed or was exhausted. The bounded `request.retry` debug event records the retry reason and outcome with the public call's opaque operation ID, when supplied. A completed RPC alone does not establish accepted semantic evidence.
|
|
155
155
|
|
|
156
|
-
A read-only semantic request can also retry once after an LSP `ContentModified` error (`-32801`). This retry shares the same one-retry budget as enrollment; it does not add another try. The client keeps the original request parameters and checks changes from the first failed input revision. It runs the full input sync before retry and checks current inputs before it accepts a result. An enrollment is still the only input change that can permit a retry. A content, workspace, close, lifecycle, or retirement change blocks it. Client replacement, caller cancellation, and a deadline also block retry. The post-request check rejects a result if inputs change while that attempt runs. This error-code retry applies only to read-only semantic requests. Diagnostics, rename, code actions, and refactors keep the default policy and do not retry `ContentModified`. See the [LSP 3.17 message-ordering rule](https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#messageOrdering), the [retry guard](src/client/client-request-enrollment.ts), and the [client query path](src/client/client.ts).
|
|
156
|
+
A read-only semantic request can also retry once after an LSP `ContentModified` error (`-32801`). This retry shares the same one-retry budget as enrollment; it does not add another try. Before this protocol retry, the client waits 100 ms so an immediate retry does not race the same server analysis. The wait is cancellable, respects the original absolute deadline, and does not delay enrollment-only retries. The client keeps the original request parameters and checks changes from the first failed input revision. It runs the full input sync before retry and checks current inputs before it accepts a result. An enrollment is still the only input change that can permit a retry. A content, workspace, close, lifecycle, or retirement change blocks it. Client replacement, caller cancellation, and a deadline also block retry. The post-request check rejects a result if inputs change while that attempt runs. This error-code retry applies only to read-only semantic requests. Diagnostics, rename, code actions, and refactors keep the default policy and do not retry `ContentModified`. See the [LSP 3.17 message-ordering rule](https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#messageOrdering), the [retry guard](src/client/client-request-enrollment.ts), and the [client query path](src/client/client.ts).
|
|
157
157
|
|
|
158
158
|
Diagnostic collection does not close and reopen a document to obtain confirmation. It does not send a no-op `didChange` for that purpose. Refresh retains unchanged documents and their current server state, and resynchronizes changed or invalidated documents. A client restart may reopen tracked documents to restore client state; that is recovery, not diagnostic confirmation.
|
|
159
159
|
|
|
@@ -14,6 +14,8 @@ export interface DebugRegistryConfig {
|
|
|
14
14
|
enabled: boolean;
|
|
15
15
|
/** What the agent-callable debug tool may return. */
|
|
16
16
|
agentAccess: DebugAgentAccess;
|
|
17
|
+
/** Whether Agent Run retrospective capture is explicitly enabled. */
|
|
18
|
+
agentRunRetrospectivesEnabled: boolean;
|
|
17
19
|
/** Maximum number of session-local events to keep in memory. */
|
|
18
20
|
maxEvents: number;
|
|
19
21
|
}
|
|
@@ -21,6 +23,7 @@ export interface DebugRegistryConfig {
|
|
|
21
23
|
export const DEBUG_REGISTRY_DEFAULTS: DebugRegistryConfig = {
|
|
22
24
|
enabled: false,
|
|
23
25
|
agentAccess: "sanitized",
|
|
26
|
+
agentRunRetrospectivesEnabled: false,
|
|
24
27
|
maxEvents: 100,
|
|
25
28
|
};
|
|
26
29
|
|
|
@@ -75,6 +78,9 @@ export interface DebugEventQueryResult {
|
|
|
75
78
|
/** Receives a sanitized event whenever the registry records one. */
|
|
76
79
|
export type DebugEventListener = (event: DebugEventView) => void;
|
|
77
80
|
|
|
81
|
+
/** Receives sanitized events for persistence; separate from ordinary event subscriptions. */
|
|
82
|
+
export type DebugPersistenceSink = (event: DebugEventView) => void;
|
|
83
|
+
|
|
78
84
|
export interface DebugSummary {
|
|
79
85
|
total: number;
|
|
80
86
|
byLevel: Partial<Record<DebugLevel, number>>;
|
|
@@ -85,6 +91,7 @@ interface DebugRegistryState {
|
|
|
85
91
|
config: DebugRegistryConfig;
|
|
86
92
|
events: DebugEvent[];
|
|
87
93
|
listeners: Set<DebugEventListener>;
|
|
94
|
+
persistenceSinks: Set<DebugPersistenceSink>;
|
|
88
95
|
nextId: number;
|
|
89
96
|
}
|
|
90
97
|
|
|
@@ -111,13 +118,15 @@ function getState(): DebugRegistryState {
|
|
|
111
118
|
config: cloneConfig(DEBUG_REGISTRY_DEFAULTS),
|
|
112
119
|
events: [],
|
|
113
120
|
listeners: new Set(),
|
|
121
|
+
persistenceSinks: new Set(),
|
|
114
122
|
nextId: 1,
|
|
115
123
|
};
|
|
116
124
|
(globalThis as Record<symbol, unknown>)[REGISTRY_KEY] = state;
|
|
117
125
|
}
|
|
118
126
|
// Keep the shared registry compatible with extension reloads that reuse an
|
|
119
|
-
// instance created before
|
|
127
|
+
// instance created before listener sets existed.
|
|
120
128
|
if (!state.listeners) state.listeners = new Set();
|
|
129
|
+
if (!state.persistenceSinks) state.persistenceSinks = new Set();
|
|
121
130
|
return state;
|
|
122
131
|
}
|
|
123
132
|
|
|
@@ -200,6 +209,19 @@ export function isDebugRegistryEnabled(): boolean {
|
|
|
200
209
|
return getState().config.enabled;
|
|
201
210
|
}
|
|
202
211
|
|
|
212
|
+
/**
|
|
213
|
+
* Return whether a retrospective can be captured: Debug and its explicit opt-in
|
|
214
|
+
* must be enabled, and at least one persistence sink must be registered.
|
|
215
|
+
*/
|
|
216
|
+
export function canRecordAgentRunRetrospective(): boolean {
|
|
217
|
+
const state = getState();
|
|
218
|
+
return (
|
|
219
|
+
state.config.enabled &&
|
|
220
|
+
state.config.agentRunRetrospectivesEnabled &&
|
|
221
|
+
state.persistenceSinks.size > 0
|
|
222
|
+
);
|
|
223
|
+
}
|
|
224
|
+
|
|
203
225
|
/** Best-effort redaction helper for data exposed through sanitized debug views. */
|
|
204
226
|
export function redactDebugData<T>(value: T): T {
|
|
205
227
|
return redactValue(value, 8) as T;
|
|
@@ -226,6 +248,16 @@ export function subscribeDebugEvents(listener: DebugEventListener): () => void {
|
|
|
226
248
|
return () => state.listeners.delete(listener);
|
|
227
249
|
}
|
|
228
250
|
|
|
251
|
+
/**
|
|
252
|
+
* Register a sanitized event persistence sink. Sinks are tracked separately from
|
|
253
|
+
* ordinary listeners so eligibility checks only succeed when logging is active.
|
|
254
|
+
*/
|
|
255
|
+
export function subscribeDebugPersistence(sink: DebugPersistenceSink): () => void {
|
|
256
|
+
const state = getState();
|
|
257
|
+
state.persistenceSinks.add(sink);
|
|
258
|
+
return () => state.persistenceSinks.delete(sink);
|
|
259
|
+
}
|
|
260
|
+
|
|
229
261
|
/** Record a session-local debug event if debugging is enabled. */
|
|
230
262
|
export function recordDebugEvent(input: DebugEventInput): DebugEvent | null {
|
|
231
263
|
const state = getState();
|
|
@@ -251,6 +283,13 @@ export function recordDebugEvent(input: DebugEventInput): DebugEvent | null {
|
|
|
251
283
|
// Debug-event consumers must not alter producer behavior.
|
|
252
284
|
}
|
|
253
285
|
}
|
|
286
|
+
for (const sink of state.persistenceSinks) {
|
|
287
|
+
try {
|
|
288
|
+
sink(toSanitizedView(event));
|
|
289
|
+
} catch {
|
|
290
|
+
// Persistence failures must not alter producer behavior.
|
|
291
|
+
}
|
|
292
|
+
}
|
|
254
293
|
return {
|
|
255
294
|
...event,
|
|
256
295
|
data: event.data === undefined ? undefined : redactDebugData(event.data),
|
|
@@ -309,5 +348,6 @@ export function resetDebugRegistry(): void {
|
|
|
309
348
|
state.config = cloneConfig(DEBUG_REGISTRY_DEFAULTS);
|
|
310
349
|
state.events = [];
|
|
311
350
|
state.listeners.clear();
|
|
351
|
+
state.persistenceSinks.clear();
|
|
312
352
|
state.nextId = 1;
|
|
313
353
|
}
|
|
@@ -282,6 +282,12 @@ Returns `function(path)` the filter function.
|
|
|
282
282
|
|
|
283
283
|
> New in 5.0.0
|
|
284
284
|
|
|
285
|
+
**This method is NOT meant for ordinary users or everyday use.** If all you need is to tell whether a `pathname` is ignored, this is not the method you are looking for.
|
|
286
|
+
|
|
287
|
+
`.test()` is meant for packages that build upon `ignore`. Besides whether a `pathname` is ignored, it tells whether a negative pattern unignored it, which such a package can use to control its own caching, such as what to cache and when a cached result can be reused.
|
|
288
|
+
|
|
289
|
+
If you only need to know whether a `pathname` should be ignored, use `.ignores()` instead. It returns that answer as a boolean, and always agrees with `.test(pathname).ignored`.
|
|
290
|
+
|
|
285
291
|
Returns `TestResult`
|
|
286
292
|
|
|
287
293
|
```ts
|
|
@@ -291,7 +297,8 @@ interface TestResult {
|
|
|
291
297
|
// true if a negative pattern matched the `pathname` itself, and no parent
|
|
292
298
|
// directory of it is ignored -- see "When both are false" below
|
|
293
299
|
unignored: boolean
|
|
294
|
-
// The `IgnoreRule` which ignores the pathname
|
|
300
|
+
// The `IgnoreRule` which ignores the pathname: the last rule to match, the
|
|
301
|
+
// one `git check-ignore -v` reports
|
|
295
302
|
rule?: IgnoreRule
|
|
296
303
|
}
|
|
297
304
|
|
|
@@ -339,13 +346,15 @@ To tell the two situations apart, test the parent directories of the `pathname`,
|
|
|
339
346
|
['foobar/'].some(dir => ig2.test(dir).unignored) // true
|
|
340
347
|
```
|
|
341
348
|
|
|
342
|
-
`unignored` is meant for packages that implement their own caching mechanism upon `node-ignore`. To simply tell whether a `pathname` is ignored, use `.ignores()` or check `TestResult::ignored`.
|
|
343
|
-
|
|
344
349
|
## .checkIgnore(target: string): TestResult
|
|
345
350
|
|
|
346
351
|
> new in 7.0.0
|
|
347
352
|
|
|
348
|
-
Debugs gitignore / exclude files
|
|
353
|
+
Debugs gitignore / exclude files the way `git check-ignore -v` does. Usually this method is used for other packages to implement the function of `git check-ignore -v` upon `node-ignore`. Apart from the [known differences](#known-differences-from-git):
|
|
354
|
+
|
|
355
|
+
- `ignored` is what `git check-ignore` answers for `target`.
|
|
356
|
+
- When `ignored` is `true`, `rule` is the rule `git check-ignore -v` reports. Its `pattern` is the pattern as it was added, so trailing spaces that git trims are still there.
|
|
357
|
+
- When the last pattern to match is a negative one, `git check-ignore -v` reports it, while `.checkIgnore()` returns `unignored: true` and no `rule`. For a directory passed with a trailing slash, `unignored` is also `true` when a negative pattern re-includes the directory itself, which `git check-ignore -v` does not report.
|
|
349
358
|
|
|
350
359
|
- **target** `string` the target to test.
|
|
351
360
|
|
|
@@ -471,13 +480,30 @@ not in `git`. For ASCII paths and patterns there is no difference.
|
|
|
471
480
|
code runs against a real repository, pass the value of the repository's
|
|
472
481
|
`core.ignorecase` explicitly.
|
|
473
482
|
|
|
474
|
-
###
|
|
483
|
+
### A run of asterisks
|
|
484
|
+
|
|
485
|
+
`git` reads a run of two or more asterisks as a globstar whenever the run
|
|
486
|
+
fills a path segment: it starts the pattern or follows a `/`, and it ends
|
|
487
|
+
the pattern or comes before a `/`. `ignore` does the same, so `***/foo`,
|
|
488
|
+
`a/***` and `a/***/b` behave exactly as `**/foo`, `a/**` and `a/**/b`.
|
|
489
|
+
|
|
490
|
+
`git` takes two more cases as a globstar, and `ignore` does not:
|
|
491
|
+
|
|
492
|
+
- **A run right after a literal prefix**, as in `a**/b` or `a***/b`. Before
|
|
493
|
+
matching, `git` strips the part of a pattern that holds no wildcard, and
|
|
494
|
+
the run then starts what is left. gitignore(5) lists the positions where
|
|
495
|
+
`**` is special and calls every other run "regular asterisks", which is
|
|
496
|
+
what `ignore` does here.
|
|
497
|
+
- **A run next to an escaped slash**, as in `**\/b` or `x\/**/b`.
|
|
498
|
+
|
|
499
|
+
```js
|
|
500
|
+
ignore().add('a**/b').ignores('axy/z/b') // false; git: true
|
|
501
|
+
ignore().add('**\\/b').ignores('x/y/b') // false; git: true
|
|
502
|
+
ignore().add('x\\/**/b').ignores('x/y/z/b') // false; git: true
|
|
503
|
+
```
|
|
475
504
|
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
pattern before matching, which makes patterns like `***/foo`, `a/***` and
|
|
479
|
-
`a**/b` behave as `**` globstars there. `ignore` follows the documented
|
|
480
|
-
behavior. If you need the globstar, write `**`.
|
|
505
|
+
To get a globstar in either case, give the run a segment of its own, such as
|
|
506
|
+
`a*/**/b`.
|
|
481
507
|
|
|
482
508
|
### `checkIgnore()` and a directory passed with a trailing slash
|
|
483
509
|
|
|
@@ -50,8 +50,9 @@ declare namespace ignore {
|
|
|
50
50
|
*/
|
|
51
51
|
unignored: boolean
|
|
52
52
|
/**
|
|
53
|
-
* The rule that ignores the pathname
|
|
54
|
-
*
|
|
53
|
+
* The rule that ignores the pathname, or the parent directory it is
|
|
54
|
+
* ignored with: the last rule to match, which is the rule
|
|
55
|
+
* `git check-ignore -v` reports. Present exactly when `ignored` is true.
|
|
55
56
|
*/
|
|
56
57
|
rule?: IgnoreRule
|
|
57
58
|
}
|
|
@@ -15,6 +15,8 @@ const ESCAPE = '\\'
|
|
|
15
15
|
const REGEX_LITERAL_SPECIAL = /[.*+?()[\]{}^$|\\/]/
|
|
16
16
|
const BOM = '\uFEFF'
|
|
17
17
|
const REGEX_INVALID_TRAILING_BACKSLASH = /(?:[^\\]|^)\\$/
|
|
18
|
+
// A run of two or more asterisks is a globstar (#175)
|
|
19
|
+
const REGEX_ANCHORED_GLOBSTAR = /^\/\*{2,}$/
|
|
18
20
|
const REGEX_REPLACE_LEADING_EXCAPED_EXCLAMATION = /^\\!/
|
|
19
21
|
const REGEX_REPLACE_LEADING_EXCAPED_HASH = /^\\#/
|
|
20
22
|
const REGEX_SPLITALL_CRLF = /\r?\n/g
|
|
@@ -423,6 +425,21 @@ const REPLACERS = [
|
|
|
423
425
|
ESCAPE + SPACE
|
|
424
426
|
],
|
|
425
427
|
|
|
428
|
+
// git's wildmatch() reads a run of two or more asterisks as one globstar
|
|
429
|
+
// whenever the run fills a path segment: it starts the pattern or follows
|
|
430
|
+
// a `/`, and it ends the pattern or comes before a `/`. A run of two is
|
|
431
|
+
// already `**`; a longer one is folded into `**` here, so the steps
|
|
432
|
+
// below only ever have to know `**`.
|
|
433
|
+
// `***/foo` -> `**/foo`, `a/***/b` -> `a/**/b`, `a/***` -> `a/**`
|
|
434
|
+
// git also takes a run beside a literal prefix (`a***/b`) or beside an
|
|
435
|
+
// escaped slash (`***\/b`) as a globstar, and this does not; the README
|
|
436
|
+
// lists both, under "A run of asterisks".
|
|
437
|
+
[
|
|
438
|
+
/(^|\/)\*{3,}(?=\/|$)/g,
|
|
439
|
+
(_, start) => `${start}**`,
|
|
440
|
+
'*'
|
|
441
|
+
],
|
|
442
|
+
|
|
426
443
|
// Escape metacharacters
|
|
427
444
|
// which is written down by users but means special for regular expressions.
|
|
428
445
|
|
|
@@ -853,6 +870,15 @@ const pinWildcards = source => {
|
|
|
853
870
|
|
|
854
871
|
// @param {pattern}
|
|
855
872
|
const makeRegexPrefix = pattern => {
|
|
873
|
+
// `/**` matches every path, as `**` does. The translation below only finds
|
|
874
|
+
// a globstar beside a slash it keeps, and the leading one is turned into
|
|
875
|
+
// an anchor, so `/**` would come out as `/*` and match one level only.
|
|
876
|
+
// Here rather than in `createRule`, so that `checkSourceOf`, which
|
|
877
|
+
// compiles `/**/` again without its trailing slash, gets it too.
|
|
878
|
+
if (REGEX_ANCHORED_GLOBSTAR.test(pattern)) {
|
|
879
|
+
pattern = '**'
|
|
880
|
+
}
|
|
881
|
+
|
|
856
882
|
const {source, sources} = extractBrackets(pattern)
|
|
857
883
|
|
|
858
884
|
const replaced = REPLACERS.reduce(
|
|
@@ -1271,17 +1297,10 @@ class RuleManager {
|
|
|
1271
1297
|
|
|
1272
1298
|
// Test one single path without recursively checking parent directories
|
|
1273
1299
|
//
|
|
1274
|
-
// -
|
|
1275
|
-
// setting `checkUnignored` to `false` could reduce additional
|
|
1276
|
-
// path matching.
|
|
1277
|
-
// - check `string` either `MODE_IGNORE` or `MODE_CHECK_IGNORE`
|
|
1278
|
-
|
|
1279
|
-
// @returns {TestResult} true if a file is ignored
|
|
1280
|
-
test (path, checkUnignored, mode) {
|
|
1281
|
-
let ignored = false
|
|
1282
|
-
let unignored = false
|
|
1283
|
-
let matchedRule
|
|
1300
|
+
// - mode `string` either `MODE_IGNORE` or `MODE_CHECK_IGNORE`
|
|
1284
1301
|
|
|
1302
|
+
// @returns {TestResult}
|
|
1303
|
+
test (path, mode) {
|
|
1285
1304
|
// Most of a .gitignore is patterns with no slash in them, and running
|
|
1286
1305
|
// those against the whole path makes the regular expression engine walk
|
|
1287
1306
|
// every directory name on the way to the only segment that could match.
|
|
@@ -1296,52 +1315,40 @@ class RuleManager {
|
|
|
1296
1315
|
? basenameOf(path)
|
|
1297
1316
|
: path
|
|
1298
1317
|
|
|
1318
|
+
// The last rule to match decides, as in git, and it is the rule
|
|
1319
|
+
// `git check-ignore -v` reports, so the scan runs from the end and stops
|
|
1320
|
+
// at the first match.
|
|
1299
1321
|
// A plain loop rather than `forEach`, so that `path`, `basename` and
|
|
1300
1322
|
// `shortcut` are locals. As a callback they became closure variables,
|
|
1301
1323
|
// and reaching for one of those once per rule cost 10% of a scan over a
|
|
1302
1324
|
// large rule set -- more than the shortcut they were there to serve.
|
|
1303
|
-
for (let index =
|
|
1325
|
+
for (let index = length - 1; index >= 0; index --) {
|
|
1304
1326
|
const rule = rules[index]
|
|
1305
|
-
|
|
1306
|
-
|
|
1307
|
-
// | ignored : unignored
|
|
1308
|
-
// -------- | ---------------------------------------
|
|
1309
|
-
// negative | 0:0 | 0:1 | 1:0 | 1:1
|
|
1310
|
-
// -------- | ------- | ------- | ------- | --------
|
|
1311
|
-
// 0 | TEST | TEST | SKIP | X
|
|
1312
|
-
// 1 | TESTIF | SKIP | TEST | X
|
|
1313
|
-
|
|
1314
|
-
// - SKIP: always skip
|
|
1315
|
-
// - TEST: always test
|
|
1316
|
-
// - TESTIF: only test if checkUnignored
|
|
1317
|
-
// - X: that never happen
|
|
1318
|
-
const skip = unignored === negative && ignored !== unignored
|
|
1319
|
-
|| negative && !ignored && !unignored && !checkUnignored
|
|
1320
|
-
|
|
1321
|
-
if (!skip && rule[mode].test(
|
|
1327
|
+
|
|
1328
|
+
if (rule[mode].test(
|
|
1322
1329
|
shortcut && rule._basenameOnly
|
|
1323
1330
|
? basename
|
|
1324
1331
|
: path
|
|
1325
1332
|
)) {
|
|
1326
|
-
|
|
1327
|
-
unignored = negative
|
|
1333
|
+
const {negative} = rule
|
|
1328
1334
|
|
|
1329
|
-
|
|
1330
|
-
|
|
1331
|
-
:
|
|
1332
|
-
|
|
1333
|
-
}
|
|
1335
|
+
const ret = {
|
|
1336
|
+
ignored: !negative,
|
|
1337
|
+
unignored: negative
|
|
1338
|
+
}
|
|
1334
1339
|
|
|
1335
|
-
|
|
1336
|
-
|
|
1337
|
-
|
|
1338
|
-
}
|
|
1340
|
+
if (!negative) {
|
|
1341
|
+
ret.rule = rule
|
|
1342
|
+
}
|
|
1339
1343
|
|
|
1340
|
-
|
|
1341
|
-
|
|
1344
|
+
return ret
|
|
1345
|
+
}
|
|
1342
1346
|
}
|
|
1343
1347
|
|
|
1344
|
-
return
|
|
1348
|
+
return {
|
|
1349
|
+
ignored: false,
|
|
1350
|
+
unignored: false
|
|
1351
|
+
}
|
|
1345
1352
|
}
|
|
1346
1353
|
}
|
|
1347
1354
|
|
|
@@ -1457,7 +1464,7 @@ class Ignore {
|
|
|
1457
1464
|
}
|
|
1458
1465
|
|
|
1459
1466
|
// @returns {TestResult}
|
|
1460
|
-
_test (originalPath, cache
|
|
1467
|
+
_test (originalPath, cache) {
|
|
1461
1468
|
const path = originalPath
|
|
1462
1469
|
// Supports nullable path
|
|
1463
1470
|
&& checkPath.convert(originalPath)
|
|
@@ -1470,7 +1477,7 @@ class Ignore {
|
|
|
1470
1477
|
: RETURN_FALSE
|
|
1471
1478
|
)
|
|
1472
1479
|
|
|
1473
|
-
return this._t(path, cache
|
|
1480
|
+
return this._t(path, cache)
|
|
1474
1481
|
}
|
|
1475
1482
|
|
|
1476
1483
|
checkIgnore (path) {
|
|
@@ -1483,7 +1490,7 @@ class Ignore {
|
|
|
1483
1490
|
// Like `git check-ignore`: a directory excluded by itself or by an
|
|
1484
1491
|
// ancestor settles it, and only then is the literal 'abc/' matched
|
|
1485
1492
|
// against the rules (see `checkSourceOf`).
|
|
1486
|
-
const dir = this._t(path, this._testCache
|
|
1493
|
+
const dir = this._t(path, this._testCache)
|
|
1487
1494
|
|
|
1488
1495
|
if (dir.ignored) {
|
|
1489
1496
|
return dir
|
|
@@ -1501,10 +1508,7 @@ class Ignore {
|
|
|
1501
1508
|
path,
|
|
1502
1509
|
|
|
1503
1510
|
// The cache for the result of a certain checking
|
|
1504
|
-
cache
|
|
1505
|
-
|
|
1506
|
-
// Whether should check if the path is unignored
|
|
1507
|
-
checkUnignored
|
|
1511
|
+
cache
|
|
1508
1512
|
) {
|
|
1509
1513
|
if (path in cache) {
|
|
1510
1514
|
return cache[path]
|
|
@@ -1514,18 +1518,18 @@ class Ignore {
|
|
|
1514
1518
|
|
|
1515
1519
|
// If the path contains a parent directory, check the parent first
|
|
1516
1520
|
const parent = parentPath
|
|
1517
|
-
? this._t(parentPath, cache
|
|
1521
|
+
? this._t(parentPath, cache)
|
|
1518
1522
|
: UNDEFINED
|
|
1519
1523
|
|
|
1520
1524
|
return cache[path] = parent && parent.ignored
|
|
1521
1525
|
// > It is not possible to re-include a file if a parent directory of
|
|
1522
1526
|
// > that file is excluded.
|
|
1523
1527
|
? parent
|
|
1524
|
-
: this._rules.test(path,
|
|
1528
|
+
: this._rules.test(path, MODE_IGNORE)
|
|
1525
1529
|
}
|
|
1526
1530
|
|
|
1527
1531
|
ignores (path) {
|
|
1528
|
-
return this._test(path, this._ignoreCache
|
|
1532
|
+
return this._test(path, this._ignoreCache).ignored
|
|
1529
1533
|
}
|
|
1530
1534
|
|
|
1531
1535
|
createFilter () {
|
|
@@ -1538,7 +1542,7 @@ class Ignore {
|
|
|
1538
1542
|
|
|
1539
1543
|
// @returns {TestResult}
|
|
1540
1544
|
test (path) {
|
|
1541
|
-
return this._test(path, this._testCache
|
|
1545
|
+
return this._test(path, this._testCache)
|
|
1542
1546
|
}
|
|
1543
1547
|
}
|
|
1544
1548
|
|
|
@@ -26,6 +26,8 @@ var ESCAPE = '\\';
|
|
|
26
26
|
var REGEX_LITERAL_SPECIAL = /[.*+?()[\]{}^$|\\/]/;
|
|
27
27
|
var BOM = "\uFEFF";
|
|
28
28
|
var REGEX_INVALID_TRAILING_BACKSLASH = /(?:[^\\]|^)\\$/;
|
|
29
|
+
// A run of two or more asterisks is a globstar (#175)
|
|
30
|
+
var REGEX_ANCHORED_GLOBSTAR = /^\/\*{2,}$/;
|
|
29
31
|
var REGEX_REPLACE_LEADING_EXCAPED_EXCLAMATION = /^\\!/;
|
|
30
32
|
var REGEX_REPLACE_LEADING_EXCAPED_HASH = /^\\#/;
|
|
31
33
|
var REGEX_SPLITALL_CRLF = /\r?\n/g;
|
|
@@ -386,6 +388,18 @@ var REPLACERS = [
|
|
|
386
388
|
/(\\+)( ?)/g, function (_, run, space) {
|
|
387
389
|
return space ? run.slice(0, run.length - run.length % 2) + SPACE : run;
|
|
388
390
|
}, ESCAPE + SPACE],
|
|
391
|
+
// git's wildmatch() reads a run of two or more asterisks as one globstar
|
|
392
|
+
// whenever the run fills a path segment: it starts the pattern or follows
|
|
393
|
+
// a `/`, and it ends the pattern or comes before a `/`. A run of two is
|
|
394
|
+
// already `**`; a longer one is folded into `**` here, so the steps
|
|
395
|
+
// below only ever have to know `**`.
|
|
396
|
+
// `***/foo` -> `**/foo`, `a/***/b` -> `a/**/b`, `a/***` -> `a/**`
|
|
397
|
+
// git also takes a run beside a literal prefix (`a***/b`) or beside an
|
|
398
|
+
// escaped slash (`***\/b`) as a globstar, and this does not; the README
|
|
399
|
+
// lists both, under "A run of asterisks".
|
|
400
|
+
[/(^|\/)\*{3,}(?=\/|$)/g, function (_, start) {
|
|
401
|
+
return "".concat(start, "**");
|
|
402
|
+
}, '*'],
|
|
389
403
|
// Escape metacharacters
|
|
390
404
|
// which is written down by users but means special for regular expressions.
|
|
391
405
|
|
|
@@ -754,6 +768,14 @@ var pinWildcards = function pinWildcards(source) {
|
|
|
754
768
|
|
|
755
769
|
// @param {pattern}
|
|
756
770
|
var makeRegexPrefix = function makeRegexPrefix(pattern) {
|
|
771
|
+
// `/**` matches every path, as `**` does. The translation below only finds
|
|
772
|
+
// a globstar beside a slash it keeps, and the leading one is turned into
|
|
773
|
+
// an anchor, so `/**` would come out as `/*` and match one level only.
|
|
774
|
+
// Here rather than in `createRule`, so that `checkSourceOf`, which
|
|
775
|
+
// compiles `/**/` again without its trailing slash, gets it too.
|
|
776
|
+
if (REGEX_ANCHORED_GLOBSTAR.test(pattern)) {
|
|
777
|
+
pattern = '**';
|
|
778
|
+
}
|
|
757
779
|
var _extractBrackets = extractBrackets(pattern),
|
|
758
780
|
source = _extractBrackets.source,
|
|
759
781
|
sources = _extractBrackets.sources;
|
|
@@ -1081,19 +1103,12 @@ var RuleManager = /*#__PURE__*/function () {
|
|
|
1081
1103
|
|
|
1082
1104
|
// Test one single path without recursively checking parent directories
|
|
1083
1105
|
//
|
|
1084
|
-
// -
|
|
1085
|
-
// setting `checkUnignored` to `false` could reduce additional
|
|
1086
|
-
// path matching.
|
|
1087
|
-
// - check `string` either `MODE_IGNORE` or `MODE_CHECK_IGNORE`
|
|
1106
|
+
// - mode `string` either `MODE_IGNORE` or `MODE_CHECK_IGNORE`
|
|
1088
1107
|
|
|
1089
|
-
// @returns {TestResult}
|
|
1108
|
+
// @returns {TestResult}
|
|
1090
1109
|
}, {
|
|
1091
1110
|
key: "test",
|
|
1092
|
-
value: function test(path,
|
|
1093
|
-
var ignored = false;
|
|
1094
|
-
var unignored = false;
|
|
1095
|
-
var matchedRule;
|
|
1096
|
-
|
|
1111
|
+
value: function test(path, mode) {
|
|
1097
1112
|
// Most of a .gitignore is patterns with no slash in them, and running
|
|
1098
1113
|
// those against the whole path makes the regular expression engine walk
|
|
1099
1114
|
// every directory name on the way to the only segment that could match.
|
|
@@ -1104,40 +1119,31 @@ var RuleManager = /*#__PURE__*/function () {
|
|
|
1104
1119
|
var shortcut = this._basenameCount * 2 >= length;
|
|
1105
1120
|
var basename = shortcut ? basenameOf(path) : path;
|
|
1106
1121
|
|
|
1122
|
+
// The last rule to match decides, as in git, and it is the rule
|
|
1123
|
+
// `git check-ignore -v` reports, so the scan runs from the end and stops
|
|
1124
|
+
// at the first match.
|
|
1107
1125
|
// A plain loop rather than `forEach`, so that `path`, `basename` and
|
|
1108
1126
|
// `shortcut` are locals. As a callback they became closure variables,
|
|
1109
1127
|
// and reaching for one of those once per rule cost 10% of a scan over a
|
|
1110
1128
|
// large rule set -- more than the shortcut they were there to serve.
|
|
1111
|
-
for (var index =
|
|
1129
|
+
for (var index = length - 1; index >= 0; index--) {
|
|
1112
1130
|
var rule = rules[index];
|
|
1113
|
-
|
|
1114
|
-
|
|
1115
|
-
|
|
1116
|
-
|
|
1117
|
-
|
|
1118
|
-
|
|
1119
|
-
|
|
1120
|
-
|
|
1121
|
-
|
|
1122
|
-
|
|
1123
|
-
// - TEST: always test
|
|
1124
|
-
// - TESTIF: only test if checkUnignored
|
|
1125
|
-
// - X: that never happen
|
|
1126
|
-
var skip = unignored === negative && ignored !== unignored || negative && !ignored && !unignored && !checkUnignored;
|
|
1127
|
-
if (!skip && rule[mode].test(shortcut && rule._basenameOnly ? basename : path)) {
|
|
1128
|
-
ignored = !negative;
|
|
1129
|
-
unignored = negative;
|
|
1130
|
-
matchedRule = negative ? UNDEFINED : rule;
|
|
1131
|
+
if (rule[mode].test(shortcut && rule._basenameOnly ? basename : path)) {
|
|
1132
|
+
var negative = rule.negative;
|
|
1133
|
+
var ret = {
|
|
1134
|
+
ignored: !negative,
|
|
1135
|
+
unignored: negative
|
|
1136
|
+
};
|
|
1137
|
+
if (!negative) {
|
|
1138
|
+
ret.rule = rule;
|
|
1139
|
+
}
|
|
1140
|
+
return ret;
|
|
1131
1141
|
}
|
|
1132
1142
|
}
|
|
1133
|
-
|
|
1134
|
-
ignored:
|
|
1135
|
-
unignored:
|
|
1143
|
+
return {
|
|
1144
|
+
ignored: false,
|
|
1145
|
+
unignored: false
|
|
1136
1146
|
};
|
|
1137
|
-
if (matchedRule) {
|
|
1138
|
-
ret.rule = matchedRule;
|
|
1139
|
-
}
|
|
1140
|
-
return ret;
|
|
1141
1147
|
}
|
|
1142
1148
|
}]);
|
|
1143
1149
|
return RuleManager;
|
|
@@ -1249,12 +1255,12 @@ var Ignore = /*#__PURE__*/function () {
|
|
|
1249
1255
|
// @returns {TestResult}
|
|
1250
1256
|
}, {
|
|
1251
1257
|
key: "_test",
|
|
1252
|
-
value: function _test(originalPath, cache
|
|
1258
|
+
value: function _test(originalPath, cache) {
|
|
1253
1259
|
var path = originalPath
|
|
1254
1260
|
// Supports nullable path
|
|
1255
1261
|
&& checkPath.convert(originalPath);
|
|
1256
1262
|
checkPath(path, originalPath, this._strictPathCheck ? throwError : RETURN_FALSE);
|
|
1257
|
-
return this._t(path, cache
|
|
1263
|
+
return this._t(path, cache);
|
|
1258
1264
|
}
|
|
1259
1265
|
}, {
|
|
1260
1266
|
key: "checkIgnore",
|
|
@@ -1268,7 +1274,7 @@ var Ignore = /*#__PURE__*/function () {
|
|
|
1268
1274
|
// Like `git check-ignore`: a directory excluded by itself or by an
|
|
1269
1275
|
// ancestor settles it, and only then is the literal 'abc/' matched
|
|
1270
1276
|
// against the rules (see `checkSourceOf`).
|
|
1271
|
-
var dir = this._t(path, this._testCache
|
|
1277
|
+
var dir = this._t(path, this._testCache);
|
|
1272
1278
|
if (dir.ignored) {
|
|
1273
1279
|
return dir;
|
|
1274
1280
|
}
|
|
@@ -1281,25 +1287,23 @@ var Ignore = /*#__PURE__*/function () {
|
|
|
1281
1287
|
// The path to be tested
|
|
1282
1288
|
path,
|
|
1283
1289
|
// The cache for the result of a certain checking
|
|
1284
|
-
cache
|
|
1285
|
-
// Whether should check if the path is unignored
|
|
1286
|
-
checkUnignored) {
|
|
1290
|
+
cache) {
|
|
1287
1291
|
if (path in cache) {
|
|
1288
1292
|
return cache[path];
|
|
1289
1293
|
}
|
|
1290
1294
|
var parentPath = parentOf(path);
|
|
1291
1295
|
|
|
1292
1296
|
// If the path contains a parent directory, check the parent first
|
|
1293
|
-
var parent = parentPath ? this._t(parentPath, cache
|
|
1297
|
+
var parent = parentPath ? this._t(parentPath, cache) : UNDEFINED;
|
|
1294
1298
|
return cache[path] = parent && parent.ignored
|
|
1295
1299
|
// > It is not possible to re-include a file if a parent directory of
|
|
1296
1300
|
// > that file is excluded.
|
|
1297
|
-
? parent : this._rules.test(path,
|
|
1301
|
+
? parent : this._rules.test(path, MODE_IGNORE);
|
|
1298
1302
|
}
|
|
1299
1303
|
}, {
|
|
1300
1304
|
key: "ignores",
|
|
1301
1305
|
value: function ignores(path) {
|
|
1302
|
-
return this._test(path, this._ignoreCache
|
|
1306
|
+
return this._test(path, this._ignoreCache).ignored;
|
|
1303
1307
|
}
|
|
1304
1308
|
}, {
|
|
1305
1309
|
key: "createFilter",
|
|
@@ -1319,7 +1323,7 @@ var Ignore = /*#__PURE__*/function () {
|
|
|
1319
1323
|
}, {
|
|
1320
1324
|
key: "test",
|
|
1321
1325
|
value: function test(path) {
|
|
1322
|
-
return this._test(path, this._testCache
|
|
1326
|
+
return this._test(path, this._testCache);
|
|
1323
1327
|
}
|
|
1324
1328
|
}]);
|
|
1325
1329
|
return Ignore;
|
|
@@ -6,6 +6,11 @@
|
|
|
6
6
|
|
|
7
7
|
This npm module implements the base messaging protocol spoken between a VSCode language server and a VSCode language client.
|
|
8
8
|
|
|
9
|
+
The Node.js entry point requires Node.js 14.17.0 or newer. The runtime abstraction layer exposes
|
|
10
|
+
`RAL().crypto.randomUUID()` for cryptographically generated v4 UUIDs. The browser implementation
|
|
11
|
+
uses native `crypto.randomUUID()` when available and falls back to `crypto.getRandomValues()`,
|
|
12
|
+
including in non-secure contexts. Custom RAL implementations must provide this capability.
|
|
13
|
+
|
|
9
14
|
The npm module can also be used standalone to establish a [JSON-RPC](http://www.jsonrpc.org/) channel between
|
|
10
15
|
a client and a server. Below an example how to setup a JSON-RPC connection. First the client side.
|
|
11
16
|
|
|
@@ -145,6 +145,14 @@ class PromiseImpl {
|
|
|
145
145
|
exports.PromiseImpl = PromiseImpl;
|
|
146
146
|
const _textEncoder = new TextEncoder();
|
|
147
147
|
const _ril = Object.freeze({
|
|
148
|
+
crypto: Object.freeze({
|
|
149
|
+
randomUUID() {
|
|
150
|
+
if (typeof globalThis.crypto.randomUUID === 'function') {
|
|
151
|
+
return globalThis.crypto.randomUUID();
|
|
152
|
+
}
|
|
153
|
+
return '10000000-1000-4000-8000-100000000000'.replace(/[018]/g, c => (+c ^ (globalThis.crypto.getRandomValues(new Uint8Array(1))[0] & (15 >> (+c / 4)))).toString(16));
|
|
154
|
+
}
|
|
155
|
+
}),
|
|
148
156
|
messageBuffer: Object.freeze({
|
|
149
157
|
create: (encoding) => new MessageBuffer(encoding)
|
|
150
158
|
}),
|
|
@@ -418,11 +418,16 @@ function createMessageConnection(messageReader, messageWriter, _logger, options)
|
|
|
418
418
|
}
|
|
419
419
|
finally {
|
|
420
420
|
if (result instanceof Promise) {
|
|
421
|
+
// Both settlements must release the parallelism slot. Written as
|
|
422
|
+
// .then(...).catch(...) the rejection path skipped the decrement, so
|
|
423
|
+
// one failed dispatch left `inFlight` permanently elevated and
|
|
424
|
+
// triggerMessageQueue() bailed out forever after.
|
|
421
425
|
result.then(() => {
|
|
422
|
-
inFlight--;
|
|
423
|
-
triggerMessageQueue();
|
|
424
426
|
}).catch((error) => {
|
|
425
427
|
logger.error(`Processing message queue failed: ${error.toString()}`);
|
|
428
|
+
}).finally(() => {
|
|
429
|
+
inFlight--;
|
|
430
|
+
triggerMessageQueue();
|
|
426
431
|
});
|
|
427
432
|
}
|
|
428
433
|
else {
|
|
@@ -42,7 +42,15 @@ interface _WritableStream {
|
|
|
42
42
|
}
|
|
43
43
|
interface _DuplexStream extends _ReadableStream, _WritableStream {
|
|
44
44
|
}
|
|
45
|
+
/**
|
|
46
|
+
* Runtime abstraction implemented by this npm module.
|
|
47
|
+
* External implementations are not supported. Changes to this interface do not
|
|
48
|
+
* require a major version bump.
|
|
49
|
+
*/
|
|
45
50
|
interface RAL {
|
|
51
|
+
readonly crypto: {
|
|
52
|
+
randomUUID(): string;
|
|
53
|
+
};
|
|
46
54
|
readonly applicationJson: {
|
|
47
55
|
readonly encoder: ContentTypeEncoder;
|
|
48
56
|
readonly decoder: ContentTypeDecoder;
|
|
@@ -46,12 +46,26 @@ export declare class StreamMessageWriter extends WriteableStreamMessageWriter {
|
|
|
46
46
|
export declare function generateRandomPipeName(): string;
|
|
47
47
|
export interface PipeTransport {
|
|
48
48
|
onConnected(): Promise<[MessageReader, MessageWriter]>;
|
|
49
|
+
/**
|
|
50
|
+
* Closes the underlying server if a client hasn't connected yet. Callers
|
|
51
|
+
* should invoke this if they abandon the transport before `onConnected`
|
|
52
|
+
* resolves (for example because the server process failed to start) to
|
|
53
|
+
* avoid leaking the listening pipe.
|
|
54
|
+
*/
|
|
55
|
+
close(): void;
|
|
49
56
|
}
|
|
50
57
|
export declare function createClientPipeTransport(pipeName: string, encoding?: RAL.MessageBufferEncoding): Promise<PipeTransport>;
|
|
51
58
|
export declare function createServerPipeTransport(pipeName: string, encoding?: RAL.MessageBufferEncoding): [MessageReader, MessageWriter];
|
|
52
59
|
export interface SocketTransport {
|
|
53
60
|
port(): number;
|
|
54
61
|
onConnected(): Promise<[MessageReader, MessageWriter]>;
|
|
62
|
+
/**
|
|
63
|
+
* Closes the underlying server if a client hasn't connected yet. Callers
|
|
64
|
+
* should invoke this if they abandon the transport before `onConnected`
|
|
65
|
+
* resolves (for example because the server process failed to start) to
|
|
66
|
+
* avoid leaking the listening socket.
|
|
67
|
+
*/
|
|
68
|
+
close(): void;
|
|
55
69
|
}
|
|
56
70
|
export declare function createClientSocketTransport(port: number, encoding?: RAL.MessageBufferEncoding): Promise<SocketTransport>;
|
|
57
71
|
export declare function createServerSocketTransport(port: number, encoding?: RAL.MessageBufferEncoding): [MessageReader, MessageWriter];
|
|
@@ -84,7 +84,7 @@ class IPCMessageWriter extends api_1.AbstractMessageWriter {
|
|
|
84
84
|
this.errorCount = 0;
|
|
85
85
|
const eventEmitter = this.process;
|
|
86
86
|
eventEmitter.on('error', (error) => this.fireError(error));
|
|
87
|
-
eventEmitter.on('close', () => this.fireClose);
|
|
87
|
+
eventEmitter.on('close', () => this.fireClose());
|
|
88
88
|
}
|
|
89
89
|
write(msg) {
|
|
90
90
|
try {
|
|
@@ -119,7 +119,7 @@ class PortMessageReader extends api_1.AbstractMessageReader {
|
|
|
119
119
|
constructor(port) {
|
|
120
120
|
super();
|
|
121
121
|
this.onData = new api_1.Emitter;
|
|
122
|
-
port.on('close', () => this.fireClose);
|
|
122
|
+
port.on('close', () => this.fireClose());
|
|
123
123
|
port.on('error', (error) => this.fireError(error));
|
|
124
124
|
port.on('message', (message) => {
|
|
125
125
|
this.onData.fire(message);
|
|
@@ -227,7 +227,8 @@ function createClientPipeTransport(pipeName, encoding = 'utf-8') {
|
|
|
227
227
|
server.listen(pipeName, () => {
|
|
228
228
|
server.removeListener('error', reject);
|
|
229
229
|
resolve({
|
|
230
|
-
onConnected: () => { return connected; }
|
|
230
|
+
onConnected: () => { return connected; },
|
|
231
|
+
close: () => { server.close(); }
|
|
231
232
|
});
|
|
232
233
|
});
|
|
233
234
|
});
|
|
@@ -263,7 +264,8 @@ function createClientSocketTransport(port, encoding = 'utf-8') {
|
|
|
263
264
|
const boundPort = address.port;
|
|
264
265
|
resolve({
|
|
265
266
|
port: () => boundPort,
|
|
266
|
-
onConnected: () => { return connected; }
|
|
267
|
+
onConnected: () => { return connected; },
|
|
268
|
+
close: () => { server.close(); }
|
|
267
269
|
});
|
|
268
270
|
});
|
|
269
271
|
});
|
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
* ------------------------------------------------------------------------------------------ */
|
|
6
6
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
7
|
const util_1 = require("util");
|
|
8
|
+
const crypto_1 = require("crypto");
|
|
8
9
|
const api_1 = require("../common/api");
|
|
9
10
|
class MessageBuffer extends api_1.AbstractMessageBuffer {
|
|
10
11
|
static emptyBuffer = Buffer.allocUnsafe(0);
|
|
@@ -30,7 +31,7 @@ class MessageBuffer extends api_1.AbstractMessageBuffer {
|
|
|
30
31
|
return buffer instanceof Buffer ? buffer : Buffer.from(buffer);
|
|
31
32
|
}
|
|
32
33
|
else {
|
|
33
|
-
return buffer instanceof Buffer ? buffer.slice(0, length) : Buffer.from(buffer
|
|
34
|
+
return buffer instanceof Buffer ? buffer.slice(0, length) : Buffer.from(buffer.subarray(0, length));
|
|
34
35
|
}
|
|
35
36
|
}
|
|
36
37
|
allocNative(length) {
|
|
@@ -99,6 +100,9 @@ class WritableStreamWrapper {
|
|
|
99
100
|
}
|
|
100
101
|
}
|
|
101
102
|
const _ril = Object.freeze({
|
|
103
|
+
crypto: Object.freeze({
|
|
104
|
+
randomUUID: () => (0, crypto_1.randomUUID)()
|
|
105
|
+
}),
|
|
102
106
|
messageBuffer: Object.freeze({
|
|
103
107
|
create: (encoding) => new MessageBuffer(encoding)
|
|
104
108
|
}),
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "vscode-jsonrpc",
|
|
3
3
|
"description": "A json rpc implementation over streams",
|
|
4
|
-
"version": "
|
|
4
|
+
"version": "10.0.0",
|
|
5
5
|
"author": "Microsoft Corporation",
|
|
6
6
|
"license": "MIT",
|
|
7
|
+
"homepage": "https://github.com/microsoft/vscode-languageserver-node/tree/main/jsonrpc",
|
|
7
8
|
"repository": {
|
|
8
9
|
"type": "git",
|
|
9
10
|
"url": "https://github.com/Microsoft/vscode-languageserver-node.git",
|
|
@@ -13,7 +14,7 @@
|
|
|
13
14
|
"url": "https://github.com/Microsoft/vscode-languageserver-node/issues"
|
|
14
15
|
},
|
|
15
16
|
"engines": {
|
|
16
|
-
"node": ">=14.
|
|
17
|
+
"node": ">=14.17.0"
|
|
17
18
|
},
|
|
18
19
|
"exports": {
|
|
19
20
|
".": {
|
|
@@ -31,6 +32,7 @@
|
|
|
31
32
|
},
|
|
32
33
|
"devDependencies": {
|
|
33
34
|
"@types/msgpack-lite": "^0.1.12",
|
|
35
|
+
"@types/node": "22.13.14",
|
|
34
36
|
"msgpack-lite": "^0.1.26"
|
|
35
37
|
},
|
|
36
38
|
"scripts": {
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "vscode-languageserver-protocol",
|
|
3
3
|
"description": "VSCode Language Server Protocol implementation",
|
|
4
|
-
"version": "3.18.
|
|
4
|
+
"version": "3.18.5",
|
|
5
5
|
"author": "Microsoft Corporation",
|
|
6
6
|
"license": "MIT",
|
|
7
|
+
"homepage": "https://github.com/microsoft/vscode-languageserver-node/tree/main/protocol",
|
|
7
8
|
"repository": {
|
|
8
9
|
"type": "git",
|
|
9
10
|
"url": "https://github.com/Microsoft/vscode-languageserver-node.git",
|
|
@@ -27,8 +28,8 @@
|
|
|
27
28
|
}
|
|
28
29
|
},
|
|
29
30
|
"dependencies": {
|
|
30
|
-
"vscode-jsonrpc": "
|
|
31
|
-
"vscode-languageserver-types": "3.18.
|
|
31
|
+
"vscode-jsonrpc": "10.0.0",
|
|
32
|
+
"vscode-languageserver-types": "3.18.5"
|
|
32
33
|
},
|
|
33
34
|
"scripts": {
|
|
34
35
|
"prepublishOnly": "npm run all:publish",
|
|
@@ -222,7 +222,7 @@ export var ColorPresentation;
|
|
|
222
222
|
function is(value) {
|
|
223
223
|
const candidate = value;
|
|
224
224
|
return Is.objectLiteral(candidate) && Is.string(candidate.label)
|
|
225
|
-
&& (Is.undefined(candidate.textEdit) || TextEdit.is(candidate))
|
|
225
|
+
&& (Is.undefined(candidate.textEdit) || TextEdit.is(candidate.textEdit))
|
|
226
226
|
&& (Is.undefined(candidate.additionalTextEdits) || Is.typedArray(candidate.additionalTextEdits, TextEdit.is));
|
|
227
227
|
}
|
|
228
228
|
ColorPresentation.is = is;
|
|
@@ -279,7 +279,7 @@ export var FoldingRange;
|
|
|
279
279
|
*/
|
|
280
280
|
function is(value) {
|
|
281
281
|
const candidate = value;
|
|
282
|
-
return Is.objectLiteral(candidate) && Is.uinteger(candidate.startLine) && Is.uinteger(candidate.
|
|
282
|
+
return Is.objectLiteral(candidate) && Is.uinteger(candidate.startLine) && Is.uinteger(candidate.endLine)
|
|
283
283
|
&& (Is.undefined(candidate.startCharacter) || Is.uinteger(candidate.startCharacter))
|
|
284
284
|
&& (Is.undefined(candidate.endCharacter) || Is.uinteger(candidate.endCharacter))
|
|
285
285
|
&& (Is.undefined(candidate.kind) || Is.string(candidate.kind));
|
|
@@ -233,7 +233,7 @@
|
|
|
233
233
|
function is(value) {
|
|
234
234
|
var candidate = value;
|
|
235
235
|
return Is.objectLiteral(candidate) && Is.string(candidate.label)
|
|
236
|
-
&& (Is.undefined(candidate.textEdit) || TextEdit.is(candidate))
|
|
236
|
+
&& (Is.undefined(candidate.textEdit) || TextEdit.is(candidate.textEdit))
|
|
237
237
|
&& (Is.undefined(candidate.additionalTextEdits) || Is.typedArray(candidate.additionalTextEdits, TextEdit.is));
|
|
238
238
|
}
|
|
239
239
|
ColorPresentation.is = is;
|
|
@@ -290,7 +290,7 @@
|
|
|
290
290
|
*/
|
|
291
291
|
function is(value) {
|
|
292
292
|
var candidate = value;
|
|
293
|
-
return Is.objectLiteral(candidate) && Is.uinteger(candidate.startLine) && Is.uinteger(candidate.
|
|
293
|
+
return Is.objectLiteral(candidate) && Is.uinteger(candidate.startLine) && Is.uinteger(candidate.endLine)
|
|
294
294
|
&& (Is.undefined(candidate.startCharacter) || Is.uinteger(candidate.startCharacter))
|
|
295
295
|
&& (Is.undefined(candidate.endCharacter) || Is.uinteger(candidate.endCharacter))
|
|
296
296
|
&& (Is.undefined(candidate.kind) || Is.string(candidate.kind));
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "vscode-languageserver-types",
|
|
3
3
|
"description": "Types used by the Language server for node",
|
|
4
|
-
"version": "3.18.
|
|
4
|
+
"version": "3.18.5",
|
|
5
5
|
"author": "Microsoft Corporation",
|
|
6
6
|
"license": "MIT",
|
|
7
|
+
"homepage": "https://github.com/microsoft/vscode-languageserver-node/tree/main/types",
|
|
7
8
|
"repository": {
|
|
8
9
|
"type": "git",
|
|
9
10
|
"url": "https://github.com/Microsoft/vscode-languageserver-node.git",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mrclrchtr/supi-lsp",
|
|
3
|
-
"version": "11.0
|
|
3
|
+
"version": "11.1.0",
|
|
4
4
|
"description": "Language Server Protocol runtime for SuPi code intelligence",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
@@ -34,11 +34,11 @@
|
|
|
34
34
|
"dependencies": {
|
|
35
35
|
"ignore": "^7.0.5",
|
|
36
36
|
"typescript": "6.0.3",
|
|
37
|
-
"vscode-jsonrpc": "^
|
|
38
|
-
"vscode-languageserver-protocol": "^3.18.
|
|
39
|
-
"vscode-languageserver-types": "^3.18.
|
|
40
|
-
"@mrclrchtr/supi-
|
|
41
|
-
"@mrclrchtr/supi-
|
|
37
|
+
"vscode-jsonrpc": "^10.0.0",
|
|
38
|
+
"vscode-languageserver-protocol": "^3.18.5",
|
|
39
|
+
"vscode-languageserver-types": "^3.18.5",
|
|
40
|
+
"@mrclrchtr/supi-code-runtime": "11.1.0",
|
|
41
|
+
"@mrclrchtr/supi-core": "11.1.0"
|
|
42
42
|
},
|
|
43
43
|
"bundledDependencies": [
|
|
44
44
|
"@mrclrchtr/supi-code-runtime",
|
package/src/client/client.ts
CHANGED
|
@@ -82,6 +82,9 @@ import { SemanticInputSynchronizationError } from "./client-semantic-input-error
|
|
|
82
82
|
import { JsonRpcClient, JsonRpcRequestError } from "./transport.ts";
|
|
83
83
|
|
|
84
84
|
const SHUTDOWN_TIMEOUT_MS = 5_000;
|
|
85
|
+
// ContentModified can outlive the server's progress notifications. Yield before
|
|
86
|
+
// spending the single retry instead of immediately racing the same analysis.
|
|
87
|
+
const CONTENT_MODIFIED_RETRY_DELAY_MS = 100;
|
|
85
88
|
|
|
86
89
|
/** Bounded stderr tail kept for startup-failure error messages. */
|
|
87
90
|
const STDERR_TAIL_MAX_CHARS = 4_000;
|
|
@@ -1498,6 +1501,9 @@ export class LspClient {
|
|
|
1498
1501
|
for (;;) {
|
|
1499
1502
|
const attempt: SemanticRequestAttemptState = { inputRevision: undefined };
|
|
1500
1503
|
try {
|
|
1504
|
+
if (retryGuard.retryReason === "content-modified") {
|
|
1505
|
+
await this.waitForContentModifiedRetry(control);
|
|
1506
|
+
}
|
|
1501
1507
|
const data = await this.runSemanticRequestAttempt<T>({
|
|
1502
1508
|
method,
|
|
1503
1509
|
params,
|
|
@@ -1515,6 +1521,21 @@ export class LspClient {
|
|
|
1515
1521
|
}
|
|
1516
1522
|
}
|
|
1517
1523
|
|
|
1524
|
+
/** Pause only the protocol retry, without extending the caller's deadline. */
|
|
1525
|
+
private async waitForContentModifiedRetry(control?: CodeRequestControl): Promise<void> {
|
|
1526
|
+
let timer: ReturnType<typeof setTimeout> | undefined;
|
|
1527
|
+
try {
|
|
1528
|
+
await raceRequestControl(
|
|
1529
|
+
new Promise<void>((resolve) => {
|
|
1530
|
+
timer = setTimeout(resolve, CONTENT_MODIFIED_RETRY_DELAY_MS);
|
|
1531
|
+
}),
|
|
1532
|
+
control,
|
|
1533
|
+
);
|
|
1534
|
+
} finally {
|
|
1535
|
+
if (timer) clearTimeout(timer);
|
|
1536
|
+
}
|
|
1537
|
+
}
|
|
1538
|
+
|
|
1518
1539
|
/** Return only when another attempt is permitted; retain the cause when retry stops. */
|
|
1519
1540
|
private prepareSemanticRetry(options: {
|
|
1520
1541
|
method: string;
|
package/src/manager/manager.ts
CHANGED
|
@@ -2975,7 +2975,7 @@ export class LspManager {
|
|
|
2975
2975
|
control?: CodeRequestControl,
|
|
2976
2976
|
): Promise<{ kind: "enrolled" } | { kind: "unavailable"; reason: string }> {
|
|
2977
2977
|
throwIfCodeRequestInterrupted(control);
|
|
2978
|
-
const files = [...new Set(filePaths)].sort();
|
|
2978
|
+
const files = [...new Set(filePaths)].sort((a, b) => (a < b ? -1 : a > b ? 1 : 0));
|
|
2979
2979
|
const routeKey = clientKey(client.name, client.root);
|
|
2980
2980
|
if (this.clients.get(routeKey) !== client) {
|
|
2981
2981
|
return { kind: "unavailable", reason: "The semantic route changed during rename planning." };
|