diff --git a/CHANGELOG.md b/CHANGELOG.md index e2cdf6915..f199fc4b1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,11 @@ # Changelog +## Unreleased + +### Compatibility and upgrade notes + +- Raised the minimum supported VS Code version to **1.101.0** (Node.js 22). (#1850) + ## 3.2.1 - 2026-10-24 ### Improvements and bug fixes @@ -257,7 +263,7 @@ same user/workspace scope). ### Features -* feat: change default of r.lsp.multiServer to false +- feat: change default of r.lsp.multiServer to false **Full Changelog**: @@ -265,16 +271,16 @@ same user/workspace scope). ### Bug Fixes -* fix: correct r.term and r.path setting names in error message +- fix: correct r.term and r.path setting names in error message ### Features -* feat: support multi-root workspaces in single-server mode +- feat: support multi-root workspaces in single-server mode ### Other -* Allow bracketedPaste on win32 platform ([#1631](https://github.com/REditorSupport/vscode-R/issues/1631)) -* feat: default to single language server for multi-root workspaces ([#1682](https://github.com/REditorSupport/vscode-R/issues/1682)) +- Allow bracketedPaste on win32 platform ([#1631](https://github.com/REditorSupport/vscode-R/issues/1631)) +- feat: default to single language server for multi-root workspaces ([#1682](https://github.com/REditorSupport/vscode-R/issues/1682)) **Full Changelog**: @@ -282,13 +288,13 @@ same user/workspace scope). ### Other -* Syntax update and bump to 2.8.6 ([#1605](https://github.com/REditorSupport/vscode-R/issues/1605)) -* Show sidebar icon only when extension is active ([#1579](https://github.com/REditorSupport/vscode-R/issues/1579)) -* Move R and R markdown syntaxes to vscode-R-syntax ([#1606](https://github.com/REditorSupport/vscode-R/issues/1606)) +- Syntax update and bump to 2.8.6 ([#1605](https://github.com/REditorSupport/vscode-R/issues/1605)) +- Show sidebar icon only when extension is active ([#1579](https://github.com/REditorSupport/vscode-R/issues/1579)) +- Move R and R markdown syntaxes to vscode-R-syntax ([#1606](https://github.com/REditorSupport/vscode-R/issues/1606)) ### Refactor -* refactor: restructure files ([#1613](https://github.com/REditorSupport/vscode-R/issues/1613)) +- refactor: restructure files ([#1613](https://github.com/REditorSupport/vscode-R/issues/1613)) **Full Changelog**: diff --git a/README.md b/README.md index 05523c9cf..3d9e82979 100644 --- a/README.md +++ b/README.md @@ -30,7 +30,7 @@ for other changes and upgrade notes. install.packages("languageserver") ``` -3. Install the stable release of this extension from the [VS Code Marketplace](https://marketplace.visualstudio.com/items?itemName=reditorsupport.r) or the [Open VSX Registry](https://open-vsx.org/extension/reditorsupport/r). This release requires VS Code 1.110 or later. +3. Install the stable release of this extension from the [VS Code Marketplace](https://marketplace.visualstudio.com/items?itemName=reditorsupport.r) or the [Open VSX Registry](https://open-vsx.org/extension/reditorsupport/r). This release requires VS Code 1.101.0 or later. ```sh code --install-extension REditorSupport.r diff --git a/esbuild.js b/esbuild.js index 5bdef1db0..41cfad62f 100644 --- a/esbuild.js +++ b/esbuild.js @@ -72,6 +72,7 @@ async function main() { sourcemap: !production, sourcesContent: false, platform: 'node', + target: 'node22', outfile: 'dist/extension.js', external: ['vscode', 'utf-8-validate', 'bufferutil'], logLevel: 'info', diff --git a/package.json b/package.json index 14df82f56..ecab96194 100644 --- a/package.json +++ b/package.json @@ -27,7 +27,7 @@ "R Markdown" ], "engines": { - "vscode": "^1.98.2" + "vscode": "^1.101.0" }, "activationEvents": [ "workspaceContains:**/*.{rproj,Rproj,r,R,rd,Rd,rmd,Rmd}", @@ -2619,7 +2619,7 @@ "@types/mocha": "^8.2.3", "@types/node": "^22.20.5", "@types/sinon": "^10.0.20", - "@types/vscode": "~1.94.0", + "@types/vscode": "~1.101.0", "@types/winreg": "^1.2.36", "@vscode/test-cli": "^0.0.15", "@vscode/test-electron": "^3.1.0", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index fc78cafcd..db4df3fa0 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -52,8 +52,8 @@ importers: specifier: ^10.0.20 version: 10.0.20 '@types/vscode': - specifier: ~1.94.0 - version: 1.94.0 + specifier: ~1.101.0 + version: 1.101.0 '@types/winreg': specifier: ^1.2.36 version: 1.2.36 @@ -835,8 +835,8 @@ packages: '@types/sinonjs__fake-timers@15.0.1': resolution: {integrity: sha512-Ko2tjWJq8oozHzHV+reuvS5KYIRAokHnGbDwGh/J64LntgpbuylF74ipEL24HCyRjf9FOlBiBHWBR1RlVKsI1w==} - '@types/vscode@1.94.0': - resolution: {integrity: sha512-UyQOIUT0pb14XSqJskYnRwD2aG0QrPVefIfrW1djR+/J4KeFQ0i1+hjZoaAmeNf3Z2jleK+R2hv+EboG/m8ruw==} + '@types/vscode@1.101.0': + resolution: {integrity: sha512-ZWf0IWa+NGegdW3iU42AcDTFHWW7fApLdkdnBqwYEtHVIBGbTu0ZNQKP/kX3Ds/uMJXIMQNAojHR4vexCEEz5Q==} '@types/winreg@1.2.36': resolution: {integrity: sha512-DtafHy5A8hbaosXrbr7YdjQZaqVewXmiasRS5J4tYMzt3s1gkh40ixpxgVFfKiQ0JIYetTJABat47v9cpr/sQg==} @@ -3108,7 +3108,7 @@ snapshots: '@types/sinonjs__fake-timers@15.0.1': {} - '@types/vscode@1.94.0': {} + '@types/vscode@1.101.0': {} '@types/winreg@1.2.36': {} diff --git a/src/plotViewer/httpgdClient.ts b/src/plotViewer/httpgdClient.ts index f6c88e6b8..5fef5e2de 100644 --- a/src/plotViewer/httpgdClient.ts +++ b/src/plotViewer/httpgdClient.ts @@ -264,9 +264,7 @@ export class HttpgdClient { } private openWebSocket(): void { - // TODO: Remove this missing-WebSocket compatibility path when the minimum - // extension host provides Node 22. Keep polling for connection failures. - if (typeof globalThis.WebSocket !== 'function' || !this.controller || this.socket) { + if (!this.controller || this.socket) { return; } this.retryAt = Date.now() + this.retryInterval; diff --git a/src/test/node/httpgdClient.test.ts b/src/test/node/httpgdClient.test.ts index 72eba1b51..9511fc3b3 100644 --- a/src/test/node/httpgdClient.test.ts +++ b/src/test/node/httpgdClient.test.ts @@ -47,7 +47,6 @@ suite('Internal httpgd client', () => { let remote: HttpgdState; let ids: string[]; let requests: { path: string; token?: string }[]; - let websocketDescriptor: PropertyDescriptor | undefined; let held: ServerResponse[]; let holdPlots: boolean; let invalidPlots: boolean; @@ -62,12 +61,7 @@ suite('Internal httpgd client', () => { holdPlots = invalidPlots = false; notifications = []; TestWebSocket.instances = []; - websocketDescriptor = Object.getOwnPropertyDescriptor(globalThis, 'WebSocket'); - Object.defineProperty(globalThis, 'WebSocket', { - value: undefined, - configurable: true, - writable: true, - }); + globalThis.WebSocket = TestWebSocket as unknown as typeof WebSocket; server = createServer((request, response) => { const url = new URL(request.url ?? '/', origin); requests.push({ @@ -122,11 +116,7 @@ suite('Internal httpgd client', () => { }); teardown(async () => { client.disconnect(); - if (websocketDescriptor) { - Object.defineProperty(globalThis, 'WebSocket', websocketDescriptor); - } else { - Reflect.deleteProperty(globalThis, 'WebSocket'); - } + globalThis.WebSocket = nativeWebSocket; for (const response of held) { response.destroy(); } @@ -161,9 +151,7 @@ suite('Internal httpgd client', () => { assert.deepStrictEqual(notifications, [['1'], []]); }); test('polls a server on port 10080, including when native WebSocket rejects it', async () => { - if (typeof nativeWebSocket === 'function') { - globalThis.WebSocket = nativeWebSocket; - } + globalThis.WebSocket = nativeWebSocket; await new Promise((resolve, reject) => server.close((error) => (error ? reject(error) : resolve())), ); @@ -186,7 +174,7 @@ suite('Internal httpgd client', () => { await until(() => client.getPlots()[0]?.id === '2'); assert.deepStrictEqual(await client.getPlotBytes({ id: '2', renderer: 'png' }), binary); }); - test('polls without WebSocket and only fetches plots after a state change', async () => { + test('polls when WebSocket cannot connect and only fetches changed plots', async () => { await client.connect(); await until(() => requests.filter((request) => request.path === '/state').length >= 2); assert.strictEqual(requests.filter((request) => request.path === '/plots').length, 1); @@ -196,7 +184,6 @@ suite('Internal httpgd client', () => { assert.deepStrictEqual(notifications, [['1'], ['1', '2']]); }); test('uses native WebSocket notifications and falls back after a disconnect', async () => { - globalThis.WebSocket = TestWebSocket as unknown as typeof WebSocket; await client.connect(); const socket = TestWebSocket.instances[0]; assert.strictEqual(socket.url.protocol, 'ws:'); @@ -215,12 +202,7 @@ suite('Internal httpgd client', () => { TestWebSocket.instances[1].open(); await until(() => requests.filter((request) => request.path === '/plots').length >= 5); }); - test('receives notifications through an actual native WebSocket connection', async function () { - if (typeof nativeWebSocket !== 'function') { - this.skip(); - return; - } - + test('receives notifications through an actual native WebSocket connection', async () => { const handshakeTimeoutMs = 5000; const testOrigin = origin; const actualServer = server; @@ -401,7 +383,6 @@ suite('Internal httpgd client', () => { } }); test('falls back when WebSocket cannot open', async () => { - globalThis.WebSocket = TestWebSocket as unknown as typeof WebSocket; await client.connect(); await until(() => TestWebSocket.instances[0].readyState === 3); ids = ['2']; @@ -409,7 +390,6 @@ suite('Internal httpgd client', () => { await until(() => client.getPlots()[0]?.id === '2'); }); test('serializes plot refreshes and retains updates received during a request', async () => { - globalThis.WebSocket = TestWebSocket as unknown as typeof WebSocket; await client.connect(); const socket = TestWebSocket.instances[0]; socket.open();