enable running individual npm scripts in the containing folder

This commit is contained in:
Helen Choi 2019-08-27 19:25:20 -07:00
parent 739ae7737a
commit 1f78795f58
6 changed files with 82 additions and 8 deletions

View file

@ -35,4 +35,6 @@ The extension fetches data from https://registry.npmjs/org and https://registry.
- `npm.enableScriptExplorer` - Enable an explorer view for npm scripts.
- `npm.scriptExplorerAction` - The default click action: `open` or `run`, the default is `open`.
- `npm.scriptCodeLens.enable` - Enable/disable the code lenses to run a script, the default is `false`.
- `npm.enableRunFromFolderContextMenu` - Enable running npm scripts from the context menu of folders in Explorer, the default is `true`.

View file

@ -88,6 +88,10 @@
{
"command": "npm.runSelectedScript",
"title": "%command.runSelectedScript%"
},
{
"command": "npm.runScriptsFromFolder",
"title": "%command.runScriptsFromFolder%"
}
],
"menus": {
@ -172,7 +176,14 @@
"when": "view == npm && viewItem == script",
"group": "navigation@3"
}
]
],
"explorer/context": [
{
"when": "config.npm.enableRunFromFolderContextMenu && explorerViewletVisible && explorerResourceIsFolder",
"command": "npm.runScriptsFromFolder",
"group": "2_workspace"
}
]
},
"configuration": {
"id": "npm",
@ -222,6 +233,12 @@
"scope": "resource",
"description": "%config.npm.enableScriptExplorer%"
},
"npm.enableRunFromFolderContextMenu": {
"type": "boolean",
"default": true,
"scope": "resource",
"description": "%config.npm.enableRunFromFolderContextMenu%"
},
"npm.scriptExplorerAction": {
"type": "string",
"enum": [

View file

@ -8,6 +8,7 @@
"config.npm.enableScriptExplorer": "Enable an explorer view for npm scripts.",
"config.npm.scriptExplorerAction": "The default click action used in the scripts explorer: `open` or `run`, the default is `open`.",
"config.npm.fetchOnlinePackageInfo": "Fetch data from https://registry.npmjs/org and https://registry.bower.io to provide auto-completion and information on hover features on npm dependencies.",
"config.npm.enableRunFromFolderContextMenu": "Enable running scripts from the context menu of a folder in Explorer",
"npm.parseError": "Npm task detection: failed to parse the file {0}",
"taskdef.script": "The npm script to customize.",
"taskdef.path": "The path to the folder of the package.json file that provides the script. Can be omitted.",
@ -17,5 +18,6 @@
"command.debug": "Debug",
"command.openScript": "Open",
"command.runInstall": "Run Install",
"command.runSelectedScript": "Run Script"
"command.runSelectedScript": "Run Script",
"command.runScriptsFromFolder": "Select npm Scripts to Run..."
}

View file

@ -3,11 +3,15 @@
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import * as vscode from 'vscode';
import {
runScript, findScriptAtPosition
} from './tasks';
import * as nls from 'vscode-nls';
import * as vscode from 'vscode';
import {
detectNpmScriptsForFolder,
findScriptAtPosition,
getPackageJsonUriFromTask,
runScript
} from './tasks';
const localize = nls.loadMessageBundle();
@ -28,4 +32,29 @@ export function runSelectedScript() {
let message = localize('noScriptFound', 'Could not find a valid npm script at the selection.');
vscode.window.showErrorMessage(message);
}
}
}
export async function selectAndRunScriptFromFolder(folderInfo: vscode.Uri) {
type TaskMap = { [id: string]: vscode.Task; };
let taskList = await detectNpmScriptsForFolder(folderInfo.path);
if (taskList && taskList.length > 0) {
let taskMap: TaskMap = {};
taskList.forEach(t => {
let uri = getPackageJsonUriFromTask(t);
if (uri && uri.fsPath.length >= folderInfo.fsPath.length) {
let taskName = uri.fsPath.substring(folderInfo.fsPath.length, uri.fsPath.length - '/package.json'.length) + ' > ' + t.name.substring(0, t.name.search('-'));
taskMap[taskName] = t;
}
});
await vscode.window.showQuickPick(Object.keys(taskMap).sort(), {
placeHolder: `Run scripts on folder ${folderInfo.fsPath}...`,
onDidSelectItem: (taskToRun: string) => {
vscode.tasks.executeTask(taskMap[taskToRun]);
}
});
}
else {
vscode.window.showInformationMessage(`No scripts detected in folder ${folderInfo.path}`);
}
}

View file

@ -6,10 +6,10 @@
import * as httpRequest from 'request-light';
import * as vscode from 'vscode';
import { addJSONProviders } from './features/jsonContributions';
import { runSelectedScript, selectAndRunScriptFromFolder } from './commands';
import { NpmScriptsTreeDataProvider } from './npmView';
import { invalidateTasksCache, NpmTaskProvider, hasPackageJson } from './tasks';
import { invalidateHoverScriptsCache, NpmScriptHoverProvider } from './scriptHover';
import { runSelectedScript } from './commands';
let treeDataProvider: NpmScriptsTreeDataProvider | undefined;
@ -45,6 +45,8 @@ export async function activate(context: vscode.ExtensionContext): Promise<void>
if (await hasPackageJson()) {
vscode.commands.executeCommand('setContext', 'npm:showScriptExplorer', true);
}
context.subscriptions.push(vscode.commands.registerCommand('npm.runScriptsFromFolder', selectAndRunScriptFromFolder));
}
function registerTaskProvider(context: vscode.ExtensionContext): vscode.Disposable | undefined {

View file

@ -155,6 +155,28 @@ async function detectNpmScripts(): Promise<Task[]> {
}
}
export async function detectNpmScriptsForFolder(folder: string): Promise<Task[]> {
let allTasks: Task[] = [];
let visitedPackageJsonFiles: Set<string> = new Set();
try {
let relativePattern = new RelativePattern(folder, '**/package.json');
let paths = await workspace.findFiles(relativePattern, '**/node_modules/**');
for (const path of paths) {
if (!visitedPackageJsonFiles.has(path.fsPath)) {
let tasks = await provideNpmScriptsForFolder(path);
visitedPackageJsonFiles.add(path.fsPath);
allTasks.push(...tasks);
}
}
return allTasks;
} catch (error) {
return Promise.reject(error);
}
}
export async function provideNpmScripts(): Promise<Task[]> {
if (!cachedTasks) {
cachedTasks = await detectNpmScripts();