Skip to content

Commit 7c5d45b

Browse files
authored
fix(vscode): apply trace.server live, drop stale rslint.json watcher, port unicode-bom E2E (#44)
* fix(vscode): update Rslint trace and config handling * docs(vscode): record targeted upstream ports * fix(vscode): scope rslint trace.server to the window
1 parent ba50b1b commit 7c5d45b

14 files changed

Lines changed: 588 additions & 38 deletions

File tree

packages/vscode/AGENTS.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ One extension replacing the standalone `rstack.rslint` and `rstack.rstest` exten
66

77
- `stacks/lint` and `stacks/test` are deliberate near-verbatim copies of the upstream extensions, kept close to upstream so changes can be synced by diffing. Do NOT deduplicate or refactor across the two stacks — the duplication is the point; consolidation is a later, explicit phase.
88
- The copies diverge from upstream in exactly nine ways (the "adaptations" below). When syncing upstream, preserve them. A tenth divergence is either a bug or must be added to this list.
9-
- **Tracked upstream state.** `stacks/lint` is synced to web-infra-dev/rslint `packages/vscode-extension` at **39536fd6** (#1617 — per-document core resolution, `CoreResolver` + `RuntimeManager`, `corePath`, PnP removed) and **892482e0** (#1630`configPath` on `rslint/configRefresh`). `CoreResolver.ts` / `RuntimeManager.ts` / `WorkspaceDocumentRouter.ts` / `Rslint.ts` are the files to diff when syncing further; record the new commits here when you do.
9+
- **Tracked upstream state.** `stacks/lint` is synced to web-infra-dev/rslint `packages/vscode-extension` at **39536fd6** (#1617 — per-document core resolution, `CoreResolver` + `RuntimeManager`, `corePath`, PnP removed) and **892482e0** (#1630`configPath` on `rslint/configRefresh`). Targeted later ports are **84f9c9b5** (#1967 — languageclient-owned live LSP tracing) and **b7176723** (#1951 — remove legacy JSON config watching); the Unicode BOM E2E comes from **5fc197a5** (#1560), with its native-config fixture shape from **b7176723**. `CoreResolver.ts` / `RuntimeManager.ts` / `WorkspaceDocumentRouter.ts` / `Rslint.ts` are the files to diff when syncing further; record the new commits here when you do.
1010
- **Ahead of upstream — offer these back when syncing** (bug fixes, not adaptations): (1) `RuntimeManager.reconcile` resolves the document's core **before** sweeping pending uses (`planDocumentCore`), so a reconcile landing on the key a pending start is already producing adopts that start instead of tearing it down mid-`initialize` — the teardown made vscode-languageclient force-notify ("couldn't create connection to server") whenever the register-time pass, a detection change and `didOpen` landed inside one worker startup window (`tests/stacks/lint/runtimeManager.test.ts`). (2) `Rslint.close()` gives a still-Starting language client a bounded chance to settle before tearing down its transport, so a legitimate mid-start close (document closed during start, core key changed) stops cleanly instead of triggering the same force-notified toasts.
1111

1212
## The nine adaptations
@@ -30,7 +30,7 @@ One extension replacing the standalone `rstack.rslint` and `rstack.rstest` exten
3030
- The shell always activates; per-folder config detection decides which stacks start, and re-runs on config/lockfile changes without a window reload. The per-stack enable settings are coarse kill switches only.
3131
- Reconciles and restarts share one serialized queue (`enqueue`); a reconcile leaves a live stack alone, so the restart path — the commands, and the full pass any relevant settings change triggers — is the only thing that rebuilds one. Do not add a second queue.
3232
- Restart is a shell concern, not a stack one: `rstack.restart` rebuilds every controller, `rstack.<stack>.restart` rebuilds one. A stack must never register its own restart command — a shallower "bounce the tool's process" restart keeps that controller's stale package resolution and version check, which is the bug the command exists to clear.
33-
- A relevant settings change (a gate key, or a key a live controller declares in `restartOnSettings`) triggers **one full restart pass**, never a targeted one. Per-stack selectivity was removed deliberately: settings edits are rare, and deciding per stack between "reconcile handles the gate" and "restart handles the setting" swallowed the restart when one save wrote a gate key at its already-effective value alongside a shared setting. The full pass re-evaluates every gate, so flips in either direction need no special casing.
33+
- A relevant settings change (a gate key, or a key a live controller declares in `restartOnSettings`) triggers **one full restart pass**, never a targeted one. Per-stack selectivity was removed deliberately: settings edits are rare, and deciding per stack between "reconcile handles the gate" and "restart handles the setting" swallowed the restart when one save wrote a gate key at its already-effective value alongside a shared setting. The full pass re-evaluates every gate, so flips in either direction need no special casing. `rstack.rslint.trace.server` and `rstack.fmt.trace.server` are deliberately not restart triggers: vscode-languageclient applies both to running clients through `$/setTrace` and includes the current value when a later client initializes.
3434
- Deprecated `rslint.json` / `rslint.jsonc` are unsupported by decision, not omission — never make them detection signals.
3535
- Never share a child process across stacks: the tools have incompatible cwd semantics (lint LSP anchors on spawn cwd; test worker pins to project root; the `rs fmt` server takes its config root from the workspace folder the client reports, falling back to spawn cwd, with no upward walk either way). The lint and fmt servers now happen to stand in the same directory — the folder root — which changes nothing: they are different CLIs, different protocols and different version gates.
3636
- In Restricted Mode (workspace trust), only the status bar runs — no process spawns, no project code loaded.
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
export default [
2+
{
3+
files: ['**/*.ts'],
4+
languageOptions: {
5+
parserOptions: {
6+
projectService: false,
7+
project: ['./tsconfig.json'],
8+
},
9+
},
10+
rules: {
11+
'unicode-bom': 'error',
12+
'no-var': 'error',
13+
},
14+
},
15+
];
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export const unmarked = 1;
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
{
2+
"compilerOptions": {
3+
"target": "ES2020",
4+
"module": "ESNext",
5+
"strict": true
6+
},
7+
"include": ["src/**/*.ts"]
8+
}

packages/vscode/e2e/lint/runTest.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -235,6 +235,11 @@ async function main(): Promise<void> {
235235
workspace: fixture('jsconfig'),
236236
tests: suiteDir('suite-jsconfig'),
237237
},
238+
{
239+
name: 'Trace output channel tests',
240+
workspace: fixture('jsconfig'),
241+
tests: suiteDir('suite-trace'),
242+
},
238243
{
239244
name: 'Monorepo config tests',
240245
workspace: fixture('monorepo'),
@@ -279,6 +284,11 @@ async function main(): Promise<void> {
279284
workspace: fixture('eslint-plugins'),
280285
tests: suiteDir('suite-eslint-plugins'),
281286
},
287+
{
288+
name: 'unicode-bom tests',
289+
workspace: fixture('unicode-bom'),
290+
tests: suiteDir('suite-unicode-bom'),
291+
},
282292
{
283293
name: 'Generated rule-option-types tests',
284294
workspace: fixture('rule-option-types'),

packages/vscode/e2e/lint/suite-jsconfig/config-transaction.test.ts

Lines changed: 26 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,8 @@
88
// `CONFIG_DISCOVERY_PROTOCOL_VERSION` as a constructor argument. The tests
99
// inject the devDependency's constant; the fixtures currently pin the same
1010
// 0.9.0 release line.
11-
// - The watch-glob test asserts upstream's glob is kept verbatim, lockfiles
12-
// included.
11+
// - The watch-glob test asserts upstream's current JS/TS config list is kept
12+
// verbatim, with this extension's existing lockfile additions.
1313
import * as assert from 'node:assert';
1414

1515
import {
@@ -34,6 +34,7 @@ import {
3434
RelativePattern,
3535
Uri,
3636
type DocumentFilter,
37+
type OutputChannel,
3738
type WorkspaceFolder,
3839
} from 'vscode';
3940

@@ -49,11 +50,31 @@ suite('initial config refresh retry classification', () => {
4950
name: 'second-root',
5051
uri: Uri.file('/workspace/second-root'),
5152
};
52-
const firstOptions = createLanguageClientOptions(firstFolder, undefined);
53-
const secondOptions = createLanguageClientOptions(secondFolder, undefined);
53+
const traceOutputChannel: OutputChannel = {
54+
name: 'Rslint client-options test',
55+
append() {},
56+
appendLine() {},
57+
replace() {},
58+
clear() {},
59+
show() {},
60+
hide() {},
61+
dispose() {},
62+
};
63+
const firstOptions = createLanguageClientOptions(
64+
firstFolder,
65+
undefined,
66+
traceOutputChannel,
67+
);
68+
const secondOptions = createLanguageClientOptions(
69+
secondFolder,
70+
undefined,
71+
traceOutputChannel,
72+
);
5473

5574
assert.strictEqual(firstOptions.workspaceFolder, firstFolder);
5675
assert.strictEqual(secondOptions.workspaceFolder, secondFolder);
76+
assert.strictEqual(firstOptions.traceOutputChannel, traceOutputChannel);
77+
assert.strictEqual(secondOptions.traceOutputChannel, traceOutputChannel);
5778
for (const [options, folder] of [
5879
[firstOptions, firstFolder],
5980
[secondOptions, secondFolder],
@@ -240,7 +261,7 @@ suite('LSP config discovery transactions', () => {
240261
assert.match(CONFIG_REFRESH_WATCH_GLOB, /rslint\.config\.ts/);
241262
assert.match(CONFIG_REFRESH_WATCH_GLOB, /rslint\.config\.mts/);
242263
assert.doesNotMatch(CONFIG_REFRESH_WATCH_GLOB, /rslint\.config\.\*/);
243-
assert.match(CONFIG_REFRESH_WATCH_GLOB, /rslint\.jsonc/);
264+
assert.doesNotMatch(CONFIG_REFRESH_WATCH_GLOB, /rslint\.json/);
244265
assert.match(CONFIG_REFRESH_WATCH_GLOB, /pnpm-lock\.yaml/);
245266
assert.doesNotMatch(CONFIG_REFRESH_WATCH_GLOB, /\.gitignore/);
246267
assert.strictEqual(
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
import { createRun } from '../runSuite';
2+
3+
export const run = createRun();

0 commit comments

Comments
 (0)