Skip to content

Commit f84c066

Browse files
authored
Add proxy installation check (#42)
1 parent d7d1b22 commit f84c066

File tree

10 files changed

+376
-193
lines changed

10 files changed

+376
-193
lines changed

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
"Testing"
1313
],
1414
"activationEvents": [
15-
"onLanguage:json"
15+
"onStartupFinished"
1616
],
1717
"repository": {
1818
"type": "git",

src/codelens.ts

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,16 @@
11
import * as vscode from 'vscode';
2-
import {isConfigFile, getASTNode, getRangeFromASTNode} from './helpers';
2+
import { isConfigFile, getASTNode, getRangeFromASTNode } from './helpers';
33
import parse from 'json-to-ast';
44

5+
export const registerCodeLens = (context: vscode.ExtensionContext) => {
6+
context.subscriptions.push(
7+
vscode.languages.registerCodeLensProvider(
8+
{ scheme: 'file', language: 'json' },
9+
pluginLensProvider
10+
)
11+
);
12+
};
13+
514
export const pluginLensProvider: vscode.CodeLensProvider = {
615
provideCodeLenses(
716
document: vscode.TextDocument,

src/commands.ts

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
import * as vscode from 'vscode';
2+
import { pluginDocs } from './constants';
3+
4+
export const registerCommands = (context: vscode.ExtensionContext) => {
5+
context.subscriptions.push(
6+
vscode.commands.registerCommand('dev-proxy-toolkit.install', async (platform: NodeJS.Platform) => {
7+
const url = `https://aka.ms/devproxy/install/${platform === 'darwin' ? 'macos' : 'windows'}`;
8+
vscode.env.openExternal(vscode.Uri.parse(url));
9+
}));
10+
11+
context.subscriptions.push(
12+
vscode.commands.registerCommand(
13+
'dev-proxy-toolkit.openPluginDoc',
14+
pluginName => {
15+
const target = vscode.Uri.parse(pluginDocs[pluginName].url);
16+
vscode.env.openExternal(target);
17+
}
18+
)
19+
);
20+
};

src/detect.ts

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
import { exec } from 'child_process';
2+
import { DevProxyInstall } from './types';
3+
import os from 'os';
4+
5+
const getExecutablePath = async (filename: string): Promise<string> => {
6+
const command = getFindCommand();
7+
if (command === '') {
8+
return '';
9+
}
10+
11+
try {
12+
return await executeCommand(`${command} ${filename}`);
13+
} catch (error) {
14+
console.error(error);
15+
return '';
16+
}
17+
};
18+
19+
const getFindCommand = () => {
20+
const platform = os.platform();
21+
let command = '';
22+
if (platform === 'win32') {
23+
command = 'pwsh.exe -c "where.exe devproxy"';
24+
}
25+
if (platform === 'darwin') {
26+
command = '$SHELL -c "which devproxy"';
27+
}
28+
return command;
29+
};
30+
31+
const getVersion = async (filePath: string) => {
32+
if (filePath === '') {
33+
return '';
34+
}
35+
try {
36+
const version = await executeCommand(`${filePath.trim()} --version`);
37+
return version.trim();
38+
} catch (error) {
39+
console.error(error);
40+
return "";
41+
}
42+
};
43+
44+
export const executeCommand = async (cmd: string): Promise<string> => {
45+
return new Promise((resolve, reject) => {
46+
exec(cmd, (error, stdout, stderr) => {
47+
if (error) {
48+
reject(`exec error: ${error}`);
49+
} else if (stderr) {
50+
reject(`stderr: ${stderr}`);
51+
} else {
52+
resolve(stdout);
53+
}
54+
});
55+
});
56+
};
57+
58+
export const detectDevProxyInstall = async (): Promise<DevProxyInstall> => {
59+
const filePath = await getExecutablePath('devproxy');
60+
const version = await getVersion(filePath);
61+
const isInstalled = filePath !== '';
62+
const isBeta = version.includes('beta');
63+
const platform = os.platform();
64+
65+
return {
66+
filePath,
67+
version,
68+
isInstalled,
69+
isBeta,
70+
platform
71+
};
72+
};

src/diagnostics.ts

Lines changed: 124 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,124 @@
1+
import * as vscode from 'vscode';
2+
import parse from "json-to-ast";
3+
import { pluginSnippets } from "./constants";
4+
import { getASTNode, getRangeFromASTNode } from "./helpers";
5+
6+
export const updateDiagnostics = (
7+
document: vscode.TextDocument,
8+
collection: vscode.DiagnosticCollection
9+
): void => {
10+
let diagnostics: vscode.Diagnostic[] = [];
11+
12+
const documentNode = parse(document.getText()) as parse.ObjectNode;
13+
14+
// check if urlsToWatch is empty
15+
const urlsToWatchNode = getASTNode(
16+
documentNode.children,
17+
'Identifier',
18+
'urlsToWatch'
19+
);
20+
if (
21+
urlsToWatchNode &&
22+
(urlsToWatchNode.value as parse.ArrayNode).children.length === 0
23+
) {
24+
diagnostics.push(
25+
new vscode.Diagnostic(
26+
getRangeFromASTNode(urlsToWatchNode),
27+
'Add at least one url to watch.',
28+
vscode.DiagnosticSeverity.Error
29+
)
30+
);
31+
}
32+
33+
// check validity of plugins
34+
const pluginsNode = getASTNode(
35+
documentNode.children,
36+
'Identifier',
37+
'plugins'
38+
);
39+
if (
40+
pluginsNode &&
41+
(pluginsNode.value as parse.ArrayNode).children.length !== 0
42+
) {
43+
const pluginNodes = (pluginsNode.value as parse.ArrayNode)
44+
.children as parse.ObjectNode[];
45+
46+
// check for plugins
47+
if (pluginNodes.length === 0) {
48+
diagnostics.push(
49+
new vscode.Diagnostic(
50+
getRangeFromASTNode(pluginsNode),
51+
'Add at least one plugin',
52+
vscode.DiagnosticSeverity.Error
53+
)
54+
);
55+
}
56+
57+
// does the plugin have a config section?
58+
pluginNodes.forEach((pluginNode: parse.ObjectNode) => {
59+
const pluginNameNode = getASTNode(
60+
pluginNode.children,
61+
'Identifier',
62+
'name'
63+
);
64+
const pluginName = (pluginNameNode?.value as parse.LiteralNode)
65+
.value as string;
66+
const enabledNode = getASTNode(
67+
pluginNode.children,
68+
'Identifier',
69+
'enabled'
70+
);
71+
const isEnabled = (enabledNode?.value as parse.LiteralNode)
72+
.value as boolean;
73+
const pluginSnippet = pluginSnippets[pluginName];
74+
const requiresConfig = pluginSnippet.config
75+
? pluginSnippet.config.required
76+
: false;
77+
78+
if (requiresConfig) {
79+
// check to see if the plugin has a config section
80+
const configSectionNode = getASTNode(
81+
pluginNode.children,
82+
'Identifier',
83+
'configSection'
84+
);
85+
if (!configSectionNode) {
86+
// there is no config section defined on the plugin instance
87+
diagnostics.push(
88+
new vscode.Diagnostic(
89+
getRangeFromASTNode(pluginNode),
90+
`${pluginName} requires a config section.`,
91+
isEnabled
92+
? vscode.DiagnosticSeverity.Error
93+
: vscode.DiagnosticSeverity.Warning
94+
)
95+
);
96+
} else {
97+
// check to see if the config section is in the document
98+
const configSectionName = (
99+
configSectionNode.value as parse.LiteralNode
100+
).value as string;
101+
const configSection = getASTNode(
102+
documentNode.children,
103+
'Identifier',
104+
configSectionName
105+
);
106+
107+
if (!configSection) {
108+
diagnostics.push(
109+
new vscode.Diagnostic(
110+
getRangeFromASTNode(configSectionNode.value),
111+
`${configSectionName} config section is missing. Use '${pluginSnippet.config?.name}' snippet to create one.`,
112+
isEnabled
113+
? vscode.DiagnosticSeverity.Error
114+
: vscode.DiagnosticSeverity.Warning
115+
)
116+
);
117+
}
118+
}
119+
}
120+
});
121+
}
122+
123+
collection.set(document.uri, diagnostics);
124+
};

src/documents.ts

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
import * as vscode from 'vscode';
2+
import { isConfigFile } from './helpers';
3+
import { updateDiagnostics } from './diagnostics';
4+
5+
export const registerDocumentListeners = (context: vscode.ExtensionContext, collection: vscode.DiagnosticCollection) => {
6+
context.subscriptions.push(
7+
vscode.workspace.onDidOpenTextDocument(document => {
8+
if (!isConfigFile(document)) {
9+
return;
10+
}
11+
updateDiagnostics(document, collection);
12+
})
13+
);
14+
15+
context.subscriptions.push(
16+
vscode.workspace.onDidChangeTextDocument(event => {
17+
if (!isConfigFile(event.document)) {
18+
collection.delete(event.document.uri);
19+
return;
20+
}
21+
updateDiagnostics(event.document, collection);
22+
})
23+
);
24+
};

0 commit comments

Comments
 (0)