mirror of
https://github.com/Microsoft/vscode
synced 2024-08-28 05:19:39 +00:00
add Debug script command
This commit is contained in:
parent
a765cafa61
commit
2ce1f53e36
|
@ -44,11 +44,15 @@
|
|||
"commands": [
|
||||
{
|
||||
"command": "npm.runScript",
|
||||
"title": "Run Script"
|
||||
"title": "Run"
|
||||
},
|
||||
{
|
||||
"command": "npm.debugScript",
|
||||
"title": "Debug"
|
||||
},
|
||||
{
|
||||
"command": "npm.openScript",
|
||||
"title": "Open Script"
|
||||
"title": "Open"
|
||||
},
|
||||
{
|
||||
"command": "npm.refresh",
|
||||
|
@ -72,6 +76,16 @@
|
|||
"command": "npm.openScript",
|
||||
"when": "view == npm && viewItem == packageJSON",
|
||||
"group": "1_navigation"
|
||||
},
|
||||
{
|
||||
"command": "npm.runScript",
|
||||
"when": "view == npm && viewItem == script",
|
||||
"group": "1_navigation"
|
||||
},
|
||||
{
|
||||
"command": "npm.debugScript",
|
||||
"when": "view == npm && viewItem == script",
|
||||
"group": "1_navigation"
|
||||
}
|
||||
]
|
||||
},
|
||||
|
|
|
@ -5,7 +5,6 @@
|
|||
'use strict';
|
||||
|
||||
import * as path from 'path';
|
||||
import * as fs from 'fs';
|
||||
import * as httpRequest from 'request-light';
|
||||
import * as vscode from 'vscode';
|
||||
import * as nls from 'vscode-nls';
|
||||
|
@ -15,40 +14,11 @@ const localize = nls.loadMessageBundle();
|
|||
|
||||
import { addJSONProviders } from './features/jsonContributions';
|
||||
import { NpmScriptsTreeDataProvider } from './npmView';
|
||||
import { NpmTaskDefinition, ScriptValidator, isWorkspaceFolder } from './tasks';
|
||||
import { NpmTaskDefinition, getScripts } from './tasks';
|
||||
|
||||
type AutoDetect = 'on' | 'off';
|
||||
let taskProvider: vscode.Disposable | undefined;
|
||||
|
||||
class Validator implements ScriptValidator {
|
||||
async scriptIsValid(task: vscode.Task): Promise<boolean> {
|
||||
let uri: vscode.Uri | null = this.getPackageJsonUri(task);
|
||||
if (uri) {
|
||||
let tasks = await provideNpmScriptsForFolder(uri);
|
||||
for (let i = 0; i < tasks.length; i++) {
|
||||
const t = tasks[i];
|
||||
if (isWorkspaceFolder(task.scope) && isWorkspaceFolder(task.scope)) {
|
||||
if (t.name === task.name && t.scope === task.scope && (<vscode.ShellExecution>(t.execution)).commandLine === (<vscode.ShellExecution>(task.execution)).commandLine) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
getPackageJsonUri(task: vscode.Task): vscode.Uri | null {
|
||||
if (isWorkspaceFolder(task.scope)) {
|
||||
if (task.definition.path) {
|
||||
return vscode.Uri.file(path.join(task.scope.uri.fsPath, task.definition.path, 'package.json'));
|
||||
} else {
|
||||
return vscode.Uri.file(path.join(task.scope.uri.fsPath, 'package.json'));
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
export function activate(context: vscode.ExtensionContext): void {
|
||||
let provider: vscode.TaskProvider = {
|
||||
provideTasks: () => {
|
||||
|
@ -60,7 +30,7 @@ export function activate(context: vscode.ExtensionContext): void {
|
|||
};
|
||||
taskProvider = vscode.workspace.registerTaskProvider('npm', provider);
|
||||
|
||||
vscode.window.registerTreeDataProvider('npm', new NpmScriptsTreeDataProvider(context, provider, new Validator()));
|
||||
vscode.window.registerTreeDataProvider('npm', new NpmScriptsTreeDataProvider(context, provider, localize));
|
||||
|
||||
if (!vscode.workspace.workspaceFolders) {
|
||||
return;
|
||||
|
@ -83,25 +53,6 @@ export function deactivate(): void {
|
|||
}
|
||||
}
|
||||
|
||||
async function exists(file: string): Promise<boolean> {
|
||||
return new Promise<boolean>((resolve, _reject) => {
|
||||
fs.exists(file, (value) => {
|
||||
resolve(value);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
async function readFile(file: string): Promise<string> {
|
||||
return new Promise<string>((resolve, reject) => {
|
||||
fs.readFile(file, (err, data) => {
|
||||
if (err) {
|
||||
reject(err);
|
||||
}
|
||||
resolve(data.toString());
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
const buildNames: string[] = ['build', 'compile', 'watch'];
|
||||
function isBuildTask(name: string): boolean {
|
||||
for (let buildName of buildNames) {
|
||||
|
@ -182,46 +133,29 @@ function isExcluded(folder: vscode.WorkspaceFolder, packageJsonUri: vscode.Uri)
|
|||
async function provideNpmScriptsForFolder(packageJsonUri: vscode.Uri): Promise<vscode.Task[]> {
|
||||
let emptyTasks: vscode.Task[] = [];
|
||||
|
||||
if (packageJsonUri.scheme !== 'file') {
|
||||
return emptyTasks;
|
||||
}
|
||||
|
||||
let packageJson = packageJsonUri.fsPath;
|
||||
|
||||
if (!await exists(packageJson)) {
|
||||
return emptyTasks;
|
||||
}
|
||||
|
||||
let folder = vscode.workspace.getWorkspaceFolder(packageJsonUri);
|
||||
if (!folder) {
|
||||
return emptyTasks;
|
||||
}
|
||||
|
||||
try {
|
||||
var contents = await readFile(packageJson);
|
||||
var json = JSON.parse(contents);
|
||||
if (!json.scripts) {
|
||||
return emptyTasks;
|
||||
}
|
||||
|
||||
const result: vscode.Task[] = [];
|
||||
Object.keys(json.scripts).filter(isNotPreOrPostScript).forEach(each => {
|
||||
const task = createTask(each, `run ${each}`, folder!, packageJsonUri);
|
||||
const lowerCaseTaskName = each.toLowerCase();
|
||||
if (isBuildTask(lowerCaseTaskName)) {
|
||||
task.group = vscode.TaskGroup.Build;
|
||||
} else if (isTestTask(lowerCaseTaskName)) {
|
||||
task.group = vscode.TaskGroup.Test;
|
||||
}
|
||||
result.push(task);
|
||||
});
|
||||
// always add npm install (without a problem matcher)
|
||||
// result.push(createTask('install', 'install', rootPath, folder, []));
|
||||
return result;
|
||||
} catch (e) {
|
||||
let localizedParseError = localize('npm.parseError', 'Npm task detection: failed to parse the file {0}', packageJsonUri);
|
||||
throw new Error(localizedParseError);
|
||||
let scripts = await getScripts(packageJsonUri, localize);
|
||||
if (!scripts) {
|
||||
return emptyTasks;
|
||||
}
|
||||
|
||||
const result: vscode.Task[] = [];
|
||||
Object.keys(scripts).filter(isNotPreOrPostScript).forEach(each => {
|
||||
const task = createTask(each, `run ${each}`, folder!, packageJsonUri);
|
||||
const lowerCaseTaskName = each.toLowerCase();
|
||||
if (isBuildTask(lowerCaseTaskName)) {
|
||||
task.group = vscode.TaskGroup.Build;
|
||||
} else if (isTestTask(lowerCaseTaskName)) {
|
||||
task.group = vscode.TaskGroup.Test;
|
||||
}
|
||||
result.push(task);
|
||||
});
|
||||
// always add npm install (without a problem matcher)
|
||||
// result.push(createTask('install', 'install', rootPath, folder, []));
|
||||
return result;
|
||||
}
|
||||
|
||||
function createTask(script: string, cmd: string, folder: vscode.WorkspaceFolder, packageJsonUri: vscode.Uri, matcher?: any): vscode.Task {
|
||||
|
|
|
@ -2,14 +2,15 @@
|
|||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
'use strict';
|
||||
|
||||
import {
|
||||
ExtensionContext, Task, TreeDataProvider, TreeItem, TreeItemCollapsibleState,
|
||||
WorkspaceFolder, workspace, commands, window, EventEmitter, Event,
|
||||
ThemeIcon, Uri, TextDocument, TaskProvider
|
||||
} from 'vscode';
|
||||
import { NpmTaskDefinition, ScriptValidator, isWorkspaceFolder } from './tasks';
|
||||
import * as path from 'path';
|
||||
import {
|
||||
DebugConfiguration, Event, EventEmitter, ExtensionContext, Task, TaskProvider,
|
||||
TextDocument, ThemeIcon, TreeDataProvider, TreeItem, TreeItemCollapsibleState, Uri,
|
||||
WorkspaceFolder, commands, debug, window, workspace
|
||||
} from 'vscode';
|
||||
import { NpmTaskDefinition, getPackageJsonUriFromTask, getScripts, isWorkspaceFolder } from './tasks';
|
||||
|
||||
class Folder extends TreeItem {
|
||||
packages: PackageJSON[] = [];
|
||||
|
@ -70,35 +71,95 @@ class NpmScript extends TreeItem {
|
|||
this.command = {
|
||||
title: 'Run Script',
|
||||
command: 'npm.runScript',
|
||||
arguments: [task]
|
||||
arguments: [this]
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
export class NpmScriptsTreeDataProvider implements TreeDataProvider<TreeItem> {
|
||||
private taskTree: Folder[] | PackageJSON[] | null = null;
|
||||
private validator: ScriptValidator;
|
||||
private taskProvider: TaskProvider;
|
||||
private localize: any;
|
||||
private _onDidChangeTreeData: EventEmitter<TreeItem | null> = new EventEmitter<TreeItem | null>();
|
||||
readonly onDidChangeTreeData: Event<TreeItem | null> = this._onDidChangeTreeData.event;
|
||||
|
||||
|
||||
constructor(context: ExtensionContext, taskProvider: TaskProvider, validator: ScriptValidator) {
|
||||
constructor(context: ExtensionContext, taskProvider: TaskProvider, localize: any) {
|
||||
const subscriptions = context.subscriptions;
|
||||
this.validator = validator;
|
||||
this.taskProvider = taskProvider;
|
||||
this.localize = localize;
|
||||
|
||||
subscriptions.push(commands.registerCommand('npm.runScript', this.runScript, this));
|
||||
subscriptions.push(commands.registerCommand('npm.debugScript', this.debugScript, this));
|
||||
subscriptions.push(commands.registerCommand('npm.openScript', this.openScript, this));
|
||||
subscriptions.push(commands.registerCommand('npm.refresh', this.refresh, this));
|
||||
}
|
||||
|
||||
private async runScript(task: Task) {
|
||||
if (!await this.validator.scriptIsValid(task)) {
|
||||
window.showErrorMessage(`Could not find script '${task.name}' or the script has changed. Try to refresh the view.`);
|
||||
private async scriptIsValid(scripts: any, task: Task): Promise<boolean> {
|
||||
if (scripts[task.name]) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private async runScript(script: NpmScript) {
|
||||
let task = script.task;
|
||||
let uri = getPackageJsonUriFromTask(task);
|
||||
let scripts = await getScripts(uri!, this.localize);
|
||||
|
||||
if (!await this.scriptIsValid(scripts, task)) {
|
||||
window.showErrorMessage(`Could not find script '${task.name}'. Try to refresh the view.`);
|
||||
return;
|
||||
}
|
||||
workspace.executeTask(task);
|
||||
workspace.executeTask(script.task);
|
||||
}
|
||||
|
||||
private async extractPort(scripts: any, task: Task): Promise<number | null> {
|
||||
let script: string = scripts[task.name];
|
||||
let match = script.match(/--inspect-brk=(\d*)/);
|
||||
if (match && match.length === 2) {
|
||||
return parseInt(match[1]);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private async debugScript(script: NpmScript) {
|
||||
let task = script.task;
|
||||
let uri = getPackageJsonUriFromTask(task);
|
||||
let scripts = await getScripts(uri!, this.localize);
|
||||
|
||||
if (!await this.scriptIsValid(scripts, task)) {
|
||||
window.showErrorMessage(`Could not find script '${task.name}'. Try to refresh the view.`);
|
||||
return;
|
||||
}
|
||||
|
||||
let port = await this.extractPort(scripts, task);
|
||||
// let debugArgs = null;
|
||||
// if (!port) {
|
||||
// port = 9229;
|
||||
// debugArgs = ['--', '--nolazy', `--inspect-brk=${port}`];
|
||||
// }
|
||||
if (!port) {
|
||||
window.showErrorMessage(`Could not launch for debugging, the script does not define --inspect-brk=port.`);
|
||||
return;
|
||||
}
|
||||
const config: DebugConfiguration = {
|
||||
type: 'node',
|
||||
request: 'launch',
|
||||
name: `Debug ${task.name}`,
|
||||
runtimeExecutable: 'npm',
|
||||
runtimeArgs: [
|
||||
'run-script',
|
||||
task.name,
|
||||
],
|
||||
port: port
|
||||
};
|
||||
// if (debugArgs) {
|
||||
// config.runtimeArgs.push(...debugArgs);
|
||||
// }
|
||||
if (isWorkspaceFolder(task.scope)) {
|
||||
debug.startDebugging(task.scope, config);
|
||||
}
|
||||
}
|
||||
|
||||
private async openScript(packageJSON: PackageJSON) {
|
||||
|
|
|
@ -2,18 +2,68 @@
|
|||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
'use strict';
|
||||
|
||||
import { TaskDefinition, Task, WorkspaceFolder } from 'vscode';
|
||||
import { TaskDefinition, Task, WorkspaceFolder, Uri } from 'vscode';
|
||||
import * as path from 'path';
|
||||
import * as fs from 'fs';
|
||||
|
||||
export interface NpmTaskDefinition extends TaskDefinition {
|
||||
script: string;
|
||||
path?: string;
|
||||
}
|
||||
|
||||
export interface ScriptValidator {
|
||||
scriptIsValid(task: Task): Promise<boolean>;
|
||||
}
|
||||
|
||||
export function isWorkspaceFolder(value: any): value is WorkspaceFolder {
|
||||
return value && typeof value !== 'number';
|
||||
}
|
||||
}
|
||||
|
||||
export function getPackageJsonUriFromTask(task: Task): Uri | null {
|
||||
if (isWorkspaceFolder(task.scope)) {
|
||||
if (task.definition.path) {
|
||||
return Uri.file(path.join(task.scope.uri.fsPath, task.definition.path, 'package.json'));
|
||||
} else {
|
||||
return Uri.file(path.join(task.scope.uri.fsPath, 'package.json'));
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
export async function exists(file: string): Promise<boolean> {
|
||||
return new Promise<boolean>((resolve, _reject) => {
|
||||
fs.exists(file, (value) => {
|
||||
resolve(value);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
export async function readFile(file: string): Promise<string> {
|
||||
return new Promise<string>((resolve, reject) => {
|
||||
fs.readFile(file, (err, data) => {
|
||||
if (err) {
|
||||
reject(err);
|
||||
}
|
||||
resolve(data.toString());
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
export async function getScripts(packageJsonUri: Uri, localize: any): Promise<any> {
|
||||
|
||||
if (packageJsonUri.scheme !== 'file') {
|
||||
return null;
|
||||
}
|
||||
|
||||
let packageJson = packageJsonUri.fsPath;
|
||||
if (!await exists(packageJson)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
try {
|
||||
var contents = await readFile(packageJson);
|
||||
var json = JSON.parse(contents);
|
||||
return json.scripts;
|
||||
} catch (e) {
|
||||
let localizedParseError = localize('npm.parseError', 'Npm task detection: failed to parse the file {0}', packageJsonUri);
|
||||
throw new Error(localizedParseError);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue