Skip to content

Commit faec85d

Browse files
authored
Simplify CLI integration by using the new spawn function instead of manually managing CLI paths and spawning processes. (#131)
fixes #130 --------- Signed-off-by: karan-palan <karanpalan007@gmail.com>
1 parent 51f42e0 commit faec85d

7 files changed

Lines changed: 33 additions & 59 deletions

File tree

Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ vscode: .always
2525
$(INSTALL) -m 0664 vscode/package.json build/vscode/package.json
2626
$(JQ) '.main = "./extension.js"' vscode/package.json > build/vscode/package.json
2727
$(INSTALL) -m 0664 vscode/package-lock.json build/vscode/package-lock.json
28+
cd build/vscode && $(NPM) ci
2829

2930
vscode-test: .always
3031
cd test/vscode && $(NPM) ci

test/vscode/extension.test.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -142,7 +142,8 @@ suite('Extension Test Suite', () => {
142142
await new Promise(resolve => setTimeout(resolve, 10000));
143143

144144
const diagnostics = vscode.languages.getDiagnostics(document.uri);
145-
assert.strictEqual(diagnostics.length, 0, 'Schema with HTTP $ref should have no diagnostic errors');
145+
const errors = diagnostics.filter(d => d.severity === vscode.DiagnosticSeverity.Error);
146+
assert.strictEqual(errors.length, 0, 'Schema with HTTP $ref should have no diagnostic errors');
146147

147148
assert.ok(extension?.isActive, 'Extension should remain active after processing HTTP $ref');
148149
});

vscode/esbuild.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ async function main() {
1414
sourcesContent: false,
1515
platform: 'node',
1616
outfile: path.join(__dirname, '../build/vscode/extension.js'),
17-
external: ['vscode'],
17+
external: ['vscode', '@sourcemeta/jsonschema'],
1818
logLevel: 'silent',
1919
plugins: [
2020
{

vscode/package-lock.json

Lines changed: 4 additions & 4 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

vscode/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@
5656
"lint": "eslint src --ext ts"
5757
},
5858
"dependencies": {
59-
"@sourcemeta/jsonschema": "^13.1.0"
59+
"@sourcemeta/jsonschema": "^13.3.0"
6060
},
6161
"devDependencies": {
6262
"@types/node": "24.x",

vscode/src/commands/CommandExecutor.ts

Lines changed: 23 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -1,62 +1,34 @@
1-
import { spawn } from 'child_process';
2-
import { join } from 'path';
1+
import { spawn } from '@sourcemeta/jsonschema';
32
import { CommandResult } from '../../../protocol/types';
43

54
/**
65
* Execute a CLI command and return the result
76
*/
87
export class CommandExecutor {
9-
private readonly extensionPath: string;
10-
private readonly cliPath: string;
11-
12-
constructor(extensionPath: string) {
13-
this.extensionPath = extensionPath;
14-
this.cliPath = join(extensionPath, 'node_modules', '@sourcemeta', 'jsonschema', 'npm', 'cli.js');
15-
}
16-
178
/**
189
* Execute a command with given arguments
1910
*/
20-
private async executeCommand(args: string[]): Promise<CommandResult> {
21-
return new Promise((resolve, reject) => {
22-
const child = spawn(process.execPath, [this.cliPath, ...args], {
23-
cwd: this.extensionPath,
24-
shell: false,
25-
// Do not open a command prompt on spawning
26-
windowsHide: true
27-
});
28-
29-
let stdout = '';
30-
let stderr = '';
31-
32-
child.stdout.on('data', (data) => {
33-
stdout += data.toString();
34-
});
35-
36-
child.stderr.on('data', (data) => {
37-
stderr += data.toString();
38-
});
39-
40-
child.on('close', (code) => {
41-
const output = stdout || stderr || 'No output';
42-
resolve({
43-
output: output.trim(),
44-
exitCode: code
45-
});
46-
});
47-
48-
child.on('error', (error) => {
49-
reject(error);
50-
});
51-
});
11+
private async executeCommand(args: string[], json: boolean = true): Promise<CommandResult> {
12+
try {
13+
const result = await spawn(args, { json });
14+
const output = json && typeof result.stdout !== 'string'
15+
? JSON.stringify(result.stdout)
16+
: (result.stdout || result.stderr || 'No output');
17+
return {
18+
output: typeof output === 'string' ? output.trim() : JSON.stringify(output).trim(),
19+
exitCode: result.code
20+
};
21+
} catch (error) {
22+
throw error;
23+
}
5224
}
5325

5426
/**
5527
* Get the JSON Schema CLI version
5628
*/
5729
async getVersion(): Promise<string> {
5830
try {
59-
const result = await this.executeCommand(['version']);
31+
const result = await this.executeCommand(['version'], false);
6032
return result.exitCode === 0 ? result.output.trim() : `Error: ${result.output}`;
6133
} catch (error) {
6234
return `Error: ${(error as Error).message}`;
@@ -68,12 +40,12 @@ export class CommandExecutor {
6840
*/
6941
async lint(filePath: string, useHttp: boolean = true): Promise<string> {
7042
try {
71-
const args = ['lint', '--json'];
43+
const args = ['lint'];
7244
if (useHttp) {
7345
args.push('--http');
7446
}
7547
args.push(filePath);
76-
const result = await this.executeCommand(args);
48+
const result = await this.executeCommand(args, true);
7749
return result.output;
7850
} catch (error) {
7951
throw error;
@@ -85,12 +57,12 @@ export class CommandExecutor {
8557
*/
8658
async formatCheck(filePath: string, useHttp: boolean = true): Promise<CommandResult> {
8759
try {
88-
const args = ['fmt', '--check', '--json'];
60+
const args = ['fmt', '--check'];
8961
if (useHttp) {
9062
args.push('--http');
9163
}
9264
args.push(filePath);
93-
return await this.executeCommand(args);
65+
return await this.executeCommand(args, true);
9466
} catch (error) {
9567
throw error;
9668
}
@@ -100,12 +72,12 @@ export class CommandExecutor {
10072
* Run format command on a file
10173
*/
10274
async format(filePath: string, useHttp: boolean = true): Promise<void> {
103-
const args = ['fmt', '--json'];
75+
const args = ['fmt'];
10476
if (useHttp) {
10577
args.push('--http');
10678
}
10779
args.push(filePath);
108-
const result = await this.executeCommand(args);
80+
const result = await this.executeCommand(args, true);
10981
if (result.exitCode !== 0) {
11082
try {
11183
const errorObj = JSON.parse(result.output);
@@ -124,12 +96,12 @@ export class CommandExecutor {
12496
*/
12597
async metaschema(filePath: string, useHttp: boolean = true): Promise<CommandResult> {
12698
try {
127-
const args = ['metaschema', '--json'];
99+
const args = ['metaschema'];
128100
if (useHttp) {
129101
args.push('--http');
130102
}
131103
args.push(filePath);
132-
return await this.executeCommand(args);
104+
return await this.executeCommand(args, true);
133105
} catch (error) {
134106
throw error;
135107
}

vscode/src/extension.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ export async function activate(context: vscode.ExtensionContext): Promise<void>
4343
}
4444

4545
panelManager = new PanelManager(context.extensionPath);
46-
commandExecutor = new CommandExecutor(context.extensionPath);
46+
commandExecutor = new CommandExecutor();
4747
diagnosticManager = new DiagnosticManager();
4848

4949
diagnosticManager.getCollections().forEach(collection => {

0 commit comments

Comments
 (0)