Skip to content

Commit e966759

Browse files
committed
refactor(vscode) add lsp helper runExecutable
1 parent 258f12a commit e966759

File tree

3 files changed

+97
-32
lines changed

3 files changed

+97
-32
lines changed

editors/vscode/client/linter.ts

Lines changed: 2 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ import { join } from 'node:path';
2626
import { ConfigService } from './ConfigService';
2727
import { VSCodeConfig } from './VSCodeConfig';
2828
import { OxcCommands } from './commands';
29+
import { runExecutable } from './lsp_helper';
2930

3031
const languageClientName = 'oxc';
3132

@@ -90,40 +91,9 @@ export async function activate(
9091
return process.env.SERVER_PATH_DEV ?? join(context.extensionPath, `./target/release/oxc_language_server${ext}`);
9192
}
9293

93-
const nodePath = configService.vsCodeConfig.nodePath;
94-
const serverEnv: Record<string, string> = {
95-
...process.env,
96-
RUST_LOG: process.env.RUST_LOG || 'info',
97-
};
98-
if (nodePath) {
99-
serverEnv.PATH = `${nodePath}${process.platform === 'win32' ? ';' : ':'}${process.env.PATH ?? ''}`;
100-
}
101-
10294
const path = await findBinary();
103-
const isNode = path.endsWith('.js') || path.endsWith('.cjs') || path.endsWith('.mjs');
104-
105-
const run: Executable = isNode
106-
? {
107-
command: 'node',
108-
args: [path!, '--lsp'],
109-
options: {
110-
env: serverEnv,
111-
},
112-
}
113-
: {
114-
command: path!,
115-
args: ['--lsp'],
116-
options: {
117-
// On Windows we need to run the binary in a shell to be able to execute the shell npm bin script.
118-
// Searching for the right `.exe` file inside `node_modules/` is not reliable as it depends on
119-
// the package manager used (npm, yarn, pnpm, etc) and the package version.
120-
// The npm bin script is a shell script that points to the actual binary.
121-
// Security: We validated the userDefinedBinary in `configService.getUserServerBinPath()`.
122-
shell: process.platform === 'win32',
123-
env: serverEnv,
124-
},
125-
};
12695

96+
const run: Executable = runExecutable(path, configService.vsCodeConfig.nodePath);
12797
const serverOptions: ServerOptions = {
12898
run,
12999
debug: run,
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
import { Executable } from 'vscode-languageclient/node';
2+
3+
export function runExecutable(path: string, nodePath?: string): Executable {
4+
const serverEnv: Record<string, string> = {
5+
...process.env,
6+
RUST_LOG: process.env.RUST_LOG || 'info',
7+
};
8+
if (nodePath) {
9+
serverEnv.PATH = `${nodePath}${process.platform === 'win32' ? ';' : ':'}${process.env.PATH ?? ''}`;
10+
}
11+
const isNode = path.endsWith('.js') || path.endsWith('.cjs') || path.endsWith('.mjs');
12+
13+
return isNode
14+
? {
15+
command: 'node',
16+
args: [path, '--lsp'],
17+
options: {
18+
env: serverEnv,
19+
},
20+
}
21+
: {
22+
command: path,
23+
args: ['--lsp'],
24+
options: {
25+
// On Windows we need to run the binary in a shell to be able to execute the shell npm bin script.
26+
// Searching for the right `.exe` file inside `node_modules/` is not reliable as it depends on
27+
// the package manager used (npm, yarn, pnpm, etc) and the package version.
28+
// The npm bin script is a shell script that points to the actual binary.
29+
// Security: We validated the userDefinedBinary in `configService.getUserServerBinPath()`.
30+
shell: process.platform === 'win32',
31+
env: serverEnv,
32+
},
33+
};
34+
}
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
import { strictEqual } from 'assert';
2+
import { runExecutable } from '../client/lsp_helper';
3+
4+
suite('runExecutable', () => {
5+
const originalPlatform = process.platform;
6+
const originalEnv = process.env;
7+
8+
teardown(() => {
9+
Object.defineProperty(process, 'platform', { value: originalPlatform });
10+
process.env = originalEnv;
11+
});
12+
13+
test('should create Node.js executable for .js files', () => {
14+
const result = runExecutable('/path/to/server.js');
15+
16+
strictEqual(result.command, 'node');
17+
strictEqual(result.args?.[0], '/path/to/server.js');
18+
strictEqual(result.args?.[1], '--lsp');
19+
});
20+
21+
test('should create Node.js executable for .cjs files', () => {
22+
const result = runExecutable('/path/to/server.cjs');
23+
24+
strictEqual(result.command, 'node');
25+
strictEqual(result.args?.[0], '/path/to/server.cjs');
26+
strictEqual(result.args?.[1], '--lsp');
27+
});
28+
29+
test('should create Node.js executable for .mjs files', () => {
30+
const result = runExecutable('/path/to/server.mjs');
31+
32+
strictEqual(result.command, 'node');
33+
strictEqual(result.args?.[0], '/path/to/server.mjs');
34+
strictEqual(result.args?.[1], '--lsp');
35+
});
36+
37+
test('should create binary executable for non-Node files', () => {
38+
const result = runExecutable('/path/to/oxc-language-server');
39+
40+
strictEqual(result.command, '/path/to/oxc-language-server');
41+
strictEqual(result.args?.[0], '--lsp');
42+
strictEqual(result.options?.shell, false);
43+
});
44+
45+
test('should use shell on Windows for binary executables', () => {
46+
Object.defineProperty(process, 'platform', { value: 'win32' });
47+
48+
const result = runExecutable('/path/to/oxc-language-server');
49+
50+
strictEqual(result.options?.shell, true);
51+
});
52+
53+
test('should prepend nodePath to PATH', () => {
54+
Object.defineProperty(process, 'platform', { value: 'linux' });
55+
process.env.PATH = '/usr/bin:/bin';
56+
57+
const result = runExecutable('/path/to/server', '/custom/node/path');
58+
59+
strictEqual(result.options?.env?.PATH, '/custom/node/path:/usr/bin:/bin');
60+
});
61+
});

0 commit comments

Comments
 (0)