Initial check-in of module validation
This commit is contained in:
Родитель
9ec43ce83a
Коммит
c908c0befc
|
@ -10,6 +10,4 @@
|
|||
"editor.tabSize": 4,
|
||||
"editor.insertSpaces": false,
|
||||
"files.trimTrailingWhitespace": true,
|
||||
"files.autoSave": "afterDelay",
|
||||
"typescript.tsdk": "./node_modules/typescript/lib" // we want to use the TS server from our node_modules folder to control its version
|
||||
}
|
||||
"files.autoSave": "afterDelay"}
|
|
@ -0,0 +1,11 @@
|
|||
- 0.0.21 added command to run `npm start`.
|
||||
- 0.0.20 when commands are run in the terminal, then the **integrated terminal** is used.
|
||||
- 0.0.16 added `npm install ` to the context menu on `package.json` in the explorer.
|
||||
- 0.0.15 added setting to run npm commands with `--silent`.
|
||||
- 0.0.15 tweaks to the README so that the extension is found when searching for node.
|
||||
- 0.0.14 added command to terminate a running script
|
||||
- 0.0.13 save workspace before running scripts, added command to run `npm run build`
|
||||
- 0.0.12 added support for `npm.useRootDirectory`
|
||||
- 0.0.11 added command to run `npm test`.
|
||||
- 0.0.7 adding an icon and changed the display name to 'npm Script Runner'.
|
||||
- 0.0.4 the keybinding was changed from `R` to `N` to avoid conflicts with the default `workbench.action.files.newUntitledFile` command.
|
14
README.md
14
README.md
|
@ -38,17 +38,3 @@ in a terminal window or whether the output form the command is shown in the `Out
|
|||
## Keyboard Shortcuts
|
||||
|
||||
The extension defines a chording keyboard shortcut for the `R` key. As a consequence an existing keybinding for `R` is not executed immediately. If this is not desired, then please bind another key for these commands, see the [customization](https://code.visualstudio.com/docs/customization/keybindings) documentation.
|
||||
|
||||
## Release Notes
|
||||
|
||||
- 0.0.21 added command to run `npm start`.
|
||||
- 0.0.20 when commands are run in the terminal, then the **integrated terminal** is used.
|
||||
- 0.0.16 added `npm install ` to the context menu on `package.json` in the explorer.
|
||||
- 0.0.15 added setting to run npm commands with `--silent`.
|
||||
- 0.0.15 tweaks to the README so that the extension is found when searching for node.
|
||||
- 0.0.14 added command to terminate a running script
|
||||
- 0.0.13 save workspace before running scripts, added command to run `npm run build`
|
||||
- 0.0.12 added support for `npm.useRootDirectory`
|
||||
- 0.0.11 added command to run `npm test`.
|
||||
- 0.0.7 adding an icon and changed the display name to 'npm Script Runner'.
|
||||
- 0.0.4 the keybinding was changed from `R` to `N` to avoid conflicts with the default `workbench.action.files.newUntitledFile` command.
|
||||
|
|
|
@ -20,14 +20,14 @@
|
|||
"Other"
|
||||
],
|
||||
"activationEvents": [
|
||||
"onLanguage:json",
|
||||
"onCommand:npm-script.install",
|
||||
"onCommand:npm-script.run",
|
||||
"onCommand:npm-script.showOutput",
|
||||
"onCommand:npm-script.rerun-last-script",
|
||||
"onCommand:npm-script.terminate-script",
|
||||
"onCommand:npm-script.test",
|
||||
"onCommand:npm-script.start",
|
||||
"onCommand:npm-script.build"
|
||||
"onCommand:npm-script.start"
|
||||
],
|
||||
"main": "./out/src/main",
|
||||
"contributes": {
|
||||
|
@ -155,6 +155,7 @@
|
|||
},
|
||||
"dependencies": {
|
||||
"run-in-terminal": "^0.0.2",
|
||||
"tree-kill": "^1.1.0"
|
||||
"tree-kill": "^1.1.0",
|
||||
"jsonc-parser": "^0.2.3"
|
||||
}
|
||||
}
|
|
@ -0,0 +1,185 @@
|
|||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
export interface ITask<T> {
|
||||
(): T;
|
||||
}
|
||||
|
||||
/**
|
||||
* A helper to prevent accumulation of sequential async tasks.
|
||||
*
|
||||
* Imagine a mail man with the sole task of delivering letters. As soon as
|
||||
* a letter submitted for delivery, he drives to the destination, delivers it
|
||||
* and returns to his base. Imagine that during the trip, N more letters were submitted.
|
||||
* When the mail man returns, he picks those N letters and delivers them all in a
|
||||
* single trip. Even though N+1 submissions occurred, only 2 deliveries were made.
|
||||
*
|
||||
* The throttler implements this via the queue() method, by providing it a task
|
||||
* factory. Following the example:
|
||||
*
|
||||
* var throttler = new Throttler();
|
||||
* var letters = [];
|
||||
*
|
||||
* function letterReceived(l) {
|
||||
* letters.push(l);
|
||||
* throttler.queue(() => { return makeTheTrip(); });
|
||||
* }
|
||||
*/
|
||||
export class Throttler<T> {
|
||||
|
||||
private activePromise: Promise<T>;
|
||||
private queuedPromise: Promise<T>;
|
||||
private queuedPromiseFactory: ITask<Promise<T>>;
|
||||
|
||||
constructor() {
|
||||
this.activePromise = null;
|
||||
this.queuedPromise = null;
|
||||
this.queuedPromiseFactory = null;
|
||||
}
|
||||
|
||||
public queue(promiseFactory: ITask<Promise<T>>): Promise<T> {
|
||||
if (this.activePromise) {
|
||||
this.queuedPromiseFactory = promiseFactory;
|
||||
|
||||
if (!this.queuedPromise) {
|
||||
var onComplete = () => {
|
||||
this.queuedPromise = null;
|
||||
|
||||
var result = this.queue(this.queuedPromiseFactory);
|
||||
this.queuedPromiseFactory = null;
|
||||
|
||||
return result;
|
||||
};
|
||||
|
||||
this.queuedPromise = new Promise<T>((resolve, reject) => {
|
||||
this.activePromise.then(onComplete, onComplete).then(resolve);
|
||||
});
|
||||
}
|
||||
|
||||
return new Promise<T>((resolve, reject) => {
|
||||
this.queuedPromise.then(resolve, reject);
|
||||
});
|
||||
}
|
||||
|
||||
this.activePromise = promiseFactory();
|
||||
|
||||
return new Promise<T>((resolve, reject) => {
|
||||
this.activePromise.then((result: T) => {
|
||||
this.activePromise = null;
|
||||
resolve(result);
|
||||
}, (err: any) => {
|
||||
this.activePromise = null;
|
||||
reject(err);
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A helper to delay execution of a task that is being requested often.
|
||||
*
|
||||
* Following the throttler, now imagine the mail man wants to optimize the number of
|
||||
* trips proactively. The trip itself can be long, so the he decides not to make the trip
|
||||
* as soon as a letter is submitted. Instead he waits a while, in case more
|
||||
* letters are submitted. After said waiting period, if no letters were submitted, he
|
||||
* decides to make the trip. Imagine that N more letters were submitted after the first
|
||||
* one, all within a short period of time between each other. Even though N+1
|
||||
* submissions occurred, only 1 delivery was made.
|
||||
*
|
||||
* The delayer offers this behavior via the trigger() method, into which both the task
|
||||
* to be executed and the waiting period (delay) must be passed in as arguments. Following
|
||||
* the example:
|
||||
*
|
||||
* var delayer = new Delayer(WAITING_PERIOD);
|
||||
* var letters = [];
|
||||
*
|
||||
* function letterReceived(l) {
|
||||
* letters.push(l);
|
||||
* delayer.trigger(() => { return makeTheTrip(); });
|
||||
* }
|
||||
*/
|
||||
export class Delayer<T> {
|
||||
|
||||
public defaultDelay: number;
|
||||
private timeout: NodeJS.Timer;
|
||||
private completionPromise: Promise<T>;
|
||||
private onResolve: (value: T | Thenable<T>) => void;
|
||||
private task: ITask<T>;
|
||||
|
||||
constructor(defaultDelay: number) {
|
||||
this.defaultDelay = defaultDelay;
|
||||
this.timeout = null;
|
||||
this.completionPromise = null;
|
||||
this.onResolve = null;
|
||||
this.task = null;
|
||||
}
|
||||
|
||||
public trigger(task: ITask<T>, delay: number = this.defaultDelay): Promise<T> {
|
||||
this.task = task;
|
||||
this.cancelTimeout();
|
||||
|
||||
if (!this.completionPromise) {
|
||||
this.completionPromise = new Promise<T>((resolve, reject) => {
|
||||
this.onResolve = resolve;
|
||||
}).then(() => {
|
||||
this.completionPromise = null;
|
||||
this.onResolve = null;
|
||||
|
||||
var result = this.task();
|
||||
this.task = null;
|
||||
|
||||
return result;
|
||||
});
|
||||
}
|
||||
|
||||
this.timeout = setTimeout(() => {
|
||||
this.timeout = null;
|
||||
this.onResolve(null);
|
||||
}, delay);
|
||||
|
||||
return this.completionPromise;
|
||||
}
|
||||
|
||||
public isTriggered(): boolean {
|
||||
return this.timeout !== null;
|
||||
}
|
||||
|
||||
public cancel(): void {
|
||||
this.cancelTimeout();
|
||||
|
||||
if (this.completionPromise) {
|
||||
this.completionPromise = null;
|
||||
}
|
||||
}
|
||||
|
||||
private cancelTimeout(): void {
|
||||
if (this.timeout !== null) {
|
||||
clearTimeout(this.timeout);
|
||||
this.timeout = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A helper to delay execution of a task that is being requested often, while
|
||||
* preventing accumulation of consecutive executions, while the task runs.
|
||||
*
|
||||
* Simply combine the two mail man strategies from the Throttler and Delayer
|
||||
* helpers, for an analogy.
|
||||
*/
|
||||
export class ThrottledDelayer<T> extends Delayer<Promise<T>> {
|
||||
|
||||
private throttler: Throttler<T>;
|
||||
|
||||
constructor(defaultDelay: number) {
|
||||
super(defaultDelay);
|
||||
|
||||
this.throttler = new Throttler();
|
||||
}
|
||||
|
||||
public trigger(promiseFactory: ITask<Promise<T>>, delay?: number): Promise<Promise<T>> {
|
||||
return super.trigger(() => this.throttler.queue(promiseFactory), delay);
|
||||
}
|
||||
}
|
253
src/main.ts
253
src/main.ts
|
@ -2,9 +2,19 @@ import * as cp from 'child_process';
|
|||
import * as path from 'path';
|
||||
import * as fs from 'fs';
|
||||
|
||||
import { window, commands, workspace, OutputChannel, ExtensionContext, ViewColumn, QuickPickItem, Terminal } from 'vscode';
|
||||
import {
|
||||
window, commands, workspace, languages, OutputChannel, ExtensionContext, ViewColumn,
|
||||
QuickPickItem, Terminal, DiagnosticCollection, Diagnostic, Range, TextDocument, DiagnosticSeverity,
|
||||
CodeActionProvider, CodeActionContext, CancellationToken, Command
|
||||
} from 'vscode';
|
||||
|
||||
import { runInTerminal } from 'run-in-terminal';
|
||||
import { kill } from 'tree-kill';
|
||||
import { parseTree, Node, } from 'jsonc-parser';
|
||||
import { ThrottledDelayer } from './async';
|
||||
|
||||
let diagnosticCollection: DiagnosticCollection;
|
||||
let delayer: ThrottledDelayer<void> = null;
|
||||
|
||||
interface Script extends QuickPickItem {
|
||||
scriptName: string;
|
||||
|
@ -18,7 +28,49 @@ interface Process {
|
|||
}
|
||||
|
||||
class ProcessItem implements QuickPickItem {
|
||||
constructor (public label: string, public description: string, public pid: number) {}
|
||||
constructor(public label: string, public description: string, public pid: number) { }
|
||||
}
|
||||
|
||||
interface SourceRange {
|
||||
name: {
|
||||
offset: number;
|
||||
length: number;
|
||||
};
|
||||
version: {
|
||||
offset: number;
|
||||
length: number;
|
||||
};
|
||||
}
|
||||
|
||||
interface DependencySourceRanges {
|
||||
[dependency: string]: SourceRange;
|
||||
}
|
||||
|
||||
class NpmCodeActionProvider implements CodeActionProvider {
|
||||
public provideCodeActions(document: TextDocument, range: Range, context: CodeActionContext, token: CancellationToken): Command[] {
|
||||
let cmds: Command[] = [];
|
||||
context.diagnostics.forEach(diag => {
|
||||
if (diag.message.indexOf('[npm] ') === 0) {
|
||||
let [_, moduleName] = /^\[npm\] Module '(\S*)'/.exec(diag.message);
|
||||
cmds.push({
|
||||
title: `run: npm install '${moduleName}'`,
|
||||
command: 'npm-script.installInOutputWindow',
|
||||
arguments: [moduleName]
|
||||
});
|
||||
cmds.push({
|
||||
title: `run: npm install`,
|
||||
command: 'npm-script.installInOutputWindow',
|
||||
arguments: []
|
||||
});
|
||||
cmds.push({
|
||||
title: `validate installed modules`,
|
||||
command: 'npm-script.validate',
|
||||
arguments: []
|
||||
});
|
||||
}
|
||||
});
|
||||
return cmds;
|
||||
}
|
||||
}
|
||||
|
||||
const runningProcesses: Map<number, Process> = new Map();
|
||||
|
@ -29,8 +81,45 @@ let lastScript: Script = null;
|
|||
|
||||
export function activate(context: ExtensionContext) {
|
||||
registerCommands(context);
|
||||
|
||||
diagnosticCollection = languages.createDiagnosticCollection('npm-script-runner');
|
||||
context.subscriptions.push(diagnosticCollection);
|
||||
|
||||
outputChannel = window.createOutputChannel('npm');
|
||||
context.subscriptions.push(outputChannel);
|
||||
|
||||
context.subscriptions.push(languages.registerCodeActionsProvider('json', new NpmCodeActionProvider()));
|
||||
|
||||
workspace.onDidSaveTextDocument(document => {
|
||||
console.log("onDidSaveTextDocument ", document.fileName);
|
||||
validateDocument(document);
|
||||
}, null, context.subscriptions);
|
||||
window.onDidChangeActiveTextEditor(editor => {
|
||||
console.log("onDidChangeActiveTextEditor", editor.document.fileName);
|
||||
if (editor && editor.document) {
|
||||
validateDocument(editor.document);
|
||||
}
|
||||
}, null, context.subscriptions);
|
||||
|
||||
// for now do not remove the markers on close
|
||||
// workspace.onDidCloseTextDocument(document => {
|
||||
// diagnosticCollection.clear();
|
||||
// }, null, context.subscriptions);
|
||||
|
||||
// workaround for onDidOpenTextDocument
|
||||
// workspace.onDidOpenTextDocument(document => {
|
||||
// console.log("onDidOpenTextDocument ", document.fileName);
|
||||
// validateDocument(document);
|
||||
// }, null, context.subscriptions);
|
||||
|
||||
window.visibleTextEditors.forEach(each => {
|
||||
if (each.document) {
|
||||
validateDocument(each.document);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
context.subscriptions.push();
|
||||
}
|
||||
|
||||
export function deactivate() {
|
||||
|
@ -39,6 +128,23 @@ export function deactivate() {
|
|||
}
|
||||
}
|
||||
|
||||
function validateDocument(document: TextDocument) {
|
||||
//console.log('validateDocument ', document.fileName);
|
||||
if (!document || path.basename(document.fileName) !== 'package.json') {
|
||||
return;
|
||||
}
|
||||
if (!delayer) {
|
||||
delayer = new ThrottledDelayer<void>(200);
|
||||
}
|
||||
//console.log('trigger');
|
||||
delayer.trigger(() => doValidate(document));
|
||||
}
|
||||
|
||||
|
||||
function validateAllDocuments() {
|
||||
workspace.textDocuments.forEach(each => validateDocument(each));
|
||||
}
|
||||
|
||||
function registerCommands(context: ExtensionContext) {
|
||||
context.subscriptions.push(
|
||||
commands.registerCommand('npm-script.install', runNpmInstall),
|
||||
|
@ -48,6 +154,8 @@ function registerCommands(context: ExtensionContext) {
|
|||
commands.registerCommand('npm-script.showOutput', showNpmOutput),
|
||||
commands.registerCommand('npm-script.rerun-last-script', rerunLastScript),
|
||||
commands.registerCommand('npm-script.build', runNpmBuild),
|
||||
commands.registerCommand('npm-script.installInOutputWindow', runNpmInstallInOutputWindow),
|
||||
commands.registerCommand('npm-script.validate', validateAllDocuments),
|
||||
commands.registerCommand('npm-script.terminate-script', terminateScript)
|
||||
);
|
||||
}
|
||||
|
@ -59,6 +167,13 @@ function runNpmInstall() {
|
|||
}
|
||||
}
|
||||
|
||||
function runNpmInstallInOutputWindow(arg) {
|
||||
let dirs = getIncludedDirectories();
|
||||
for (let dir of dirs) {
|
||||
runNpmCommand(['install', arg], dir, true);
|
||||
}
|
||||
}
|
||||
|
||||
function runNpmTest() {
|
||||
runNpmCommand(['test']);
|
||||
}
|
||||
|
@ -71,6 +186,102 @@ function runNpmBuild() {
|
|||
runNpmCommand(['run-script', 'build']);
|
||||
}
|
||||
|
||||
function doValidate(document: TextDocument): Promise<void> {
|
||||
//console.log('do validate');
|
||||
return new Promise<void>((resolve, reject) => {
|
||||
|
||||
getInstalledModules().then(result => {
|
||||
let errors = [];
|
||||
let definedDependencies: DependencySourceRanges = {};
|
||||
|
||||
if (!anyModuleErrors(result)) {
|
||||
resolve();
|
||||
}
|
||||
|
||||
let node = parseTree(document.getText(), errors);
|
||||
|
||||
node.children.forEach(child => {
|
||||
let children = child.children;
|
||||
if (children && children.length === 2 && isDependency(children[0].value)) {
|
||||
collectDefinedDependencies(definedDependencies, child.children[1]);
|
||||
}
|
||||
});
|
||||
|
||||
diagnosticCollection.clear();
|
||||
let diagnostics: Diagnostic[] = [];
|
||||
|
||||
for (var moduleName in definedDependencies) {
|
||||
if (definedDependencies.hasOwnProperty(moduleName)) {
|
||||
let diagnostic = getDiagnostic(document, result, moduleName, definedDependencies[moduleName]);
|
||||
if (diagnostic) {
|
||||
diagnostics.push(diagnostic);
|
||||
}
|
||||
}
|
||||
}
|
||||
diagnosticCollection.set(document.uri, diagnostics);
|
||||
//console.log("diagnostic count ", diagnostics.length, " ", document.uri.fsPath);
|
||||
resolve();
|
||||
}, error => {
|
||||
reject(error);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function getDiagnostic(document: TextDocument, result: Object, moduleName: string, source: SourceRange): Diagnostic {
|
||||
let deps = ['dependencies', 'devDependencies'];
|
||||
let diagnostic = null;
|
||||
|
||||
deps.forEach(each => {
|
||||
if (result[each] && result[each][moduleName]) {
|
||||
if (result[each][moduleName]['missing'] === true) {
|
||||
let range = new Range(document.positionAt(source.name.offset), document.positionAt(source.name.offset + source.name.length));
|
||||
diagnostic = new Diagnostic(range, `[npm] Module '${moduleName}' not installed`, DiagnosticSeverity.Warning);
|
||||
}
|
||||
if (result[each][moduleName]['invalid'] === true) {
|
||||
let range = new Range(document.positionAt(source.version.offset), document.positionAt(source.version.offset + source.version.length));
|
||||
diagnostic = new Diagnostic(range, `[npm] Module '${moduleName}' installed version is invalid`, DiagnosticSeverity.Warning);
|
||||
}
|
||||
}
|
||||
});
|
||||
return diagnostic;
|
||||
}
|
||||
|
||||
function anyModuleErrors(result: any): boolean {
|
||||
let problems: string[] = result['problems'];
|
||||
let errorCount = 0;
|
||||
if (problems) {
|
||||
problems.forEach(each => {
|
||||
if (each.startsWith('missing:') || each.startsWith('invalid:')) {
|
||||
errorCount++;
|
||||
}
|
||||
});
|
||||
}
|
||||
return errorCount > 0;
|
||||
}
|
||||
|
||||
function collectDefinedDependencies(deps: Object, node: Node) {
|
||||
node.children.forEach(child => {
|
||||
if (child.type === 'property' && child.children.length === 2) {
|
||||
let dependencyName = child.children[0];
|
||||
let version = child.children[1];
|
||||
deps[dependencyName.value] = {
|
||||
name: {
|
||||
offset: dependencyName.offset,
|
||||
length: dependencyName.length
|
||||
},
|
||||
version: {
|
||||
offset: version.offset,
|
||||
length: version.length
|
||||
}
|
||||
};
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function isDependency(value: string) {
|
||||
return value === 'dependencies' || value === 'devDependencies';
|
||||
}
|
||||
|
||||
function showNpmOutput(): void {
|
||||
outputChannel.show(ViewColumn.Three);
|
||||
}
|
||||
|
@ -120,7 +331,7 @@ function rerunLastScript(): void {
|
|||
}
|
||||
|
||||
function terminateScript(): void {
|
||||
if(useTerminal()) {
|
||||
if (useTerminal()) {
|
||||
window.showInformationMessage('Killing is only supported when the setting "runInTerminal" is "false"');
|
||||
} else {
|
||||
let items: ProcessItem[] = [];
|
||||
|
@ -130,7 +341,7 @@ function terminateScript(): void {
|
|||
});
|
||||
|
||||
window.showQuickPick(items).then((value) => {
|
||||
if(value) {
|
||||
if (value) {
|
||||
outputChannel.appendLine('');
|
||||
outputChannel.appendLine(`Killing process ${value.label} (pid: ${value.pid})`);
|
||||
outputChannel.appendLine('');
|
||||
|
@ -163,7 +374,7 @@ function readScripts(): any {
|
|||
});
|
||||
});
|
||||
}
|
||||
} catch(e) {
|
||||
} catch (e) {
|
||||
window.showInformationMessage(`Cannot read '${fileName}'`);
|
||||
return undefined;
|
||||
}
|
||||
|
@ -177,7 +388,7 @@ function readScripts(): any {
|
|||
return scripts;
|
||||
}
|
||||
|
||||
function runNpmCommand(args: string[], cwd?: string): void {
|
||||
function runNpmCommand(args: string[], cwd?: string, alwaysRunInputWindow = false): void {
|
||||
if (runSilent()) {
|
||||
args.push('--silent');
|
||||
}
|
||||
|
@ -186,7 +397,7 @@ function runNpmCommand(args: string[], cwd?: string): void {
|
|||
cwd = workspace.rootPath;
|
||||
}
|
||||
|
||||
if (useTerminal()) {
|
||||
if (useTerminal() && !alwaysRunInputWindow) {
|
||||
if (typeof window.createTerminal === 'function') {
|
||||
runCommandInIntegratedTerminal(args, cwd);
|
||||
} else {
|
||||
|
@ -199,6 +410,30 @@ function runNpmCommand(args: string[], cwd?: string): void {
|
|||
});
|
||||
}
|
||||
|
||||
function getInstalledModules(): Promise<Object> {
|
||||
return new Promise((resolve, reject) => {
|
||||
let cmd = getNpmBin() + ' ' + 'ls --depth 0 --json';
|
||||
let jsonResult = '';
|
||||
let errors = '';
|
||||
|
||||
let p = cp.exec(cmd, { cwd: workspace.rootPath, env: process.env }, (error: Error, stdout: string, stderr: string) => {
|
||||
reject(error);
|
||||
});
|
||||
|
||||
p.stderr.on('data', (chunk: string) => errors += chunk);
|
||||
p.stdout.on('data', (chunk: string) => jsonResult += chunk);
|
||||
p.on('exit', (code, signal) => {
|
||||
let resp = '';
|
||||
try {
|
||||
resp = JSON.parse(jsonResult);
|
||||
resolve(resp);
|
||||
} catch (e) {
|
||||
reject(e);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function runCommandInOutputWindow(args: string[], cwd: string) {
|
||||
let cmd = getNpmBin() + ' ' + args.join(' ');
|
||||
let p = cp.exec(cmd, { cwd: cwd, env: process.env });
|
||||
|
@ -214,7 +449,7 @@ function runCommandInOutputWindow(args: string[], cwd: string) {
|
|||
p.on('exit', (code, signal) => {
|
||||
runningProcesses.delete(p.pid);
|
||||
|
||||
if(signal === 'SIGTERM') {
|
||||
if (signal === 'SIGTERM') {
|
||||
outputChannel.appendLine('Successfully killed process');
|
||||
outputChannel.appendLine('-----------------------');
|
||||
outputChannel.appendLine('');
|
||||
|
@ -222,6 +457,7 @@ function runCommandInOutputWindow(args: string[], cwd: string) {
|
|||
outputChannel.appendLine('-----------------------');
|
||||
outputChannel.appendLine('');
|
||||
}
|
||||
validateAllDocuments();
|
||||
});
|
||||
|
||||
showNpmOutput();
|
||||
|
@ -267,3 +503,4 @@ function getIncludedDirectories() {
|
|||
function getNpmBin() {
|
||||
return workspace.getConfiguration('npm')['bin'] || 'npm';
|
||||
}
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче