diff --git a/extensions/npm/README.md b/extensions/npm/README.md index 1946e16a958..b6ca6b5ce97 100644 --- a/extensions/npm/README.md +++ b/extensions/npm/README.md @@ -15,3 +15,4 @@ For more information about auto detection of Tasks pls see the [documentation](h - `npm.packageManager` the package manager used to run the scripts: `npm` or `yarn`, the default is `npm`. - `npm.exclude` glob patterns for folders that should be excluded from automatic script detection. The pattern is matched against the **absolute path** of the package.json. For example, to exclude all test folders use '**/test/**'. - `npm.enableScriptExplorer` enable an explorer view for npm scripts. +- `npm.filterPrePostScripts` filter pre or post scripts, the default is `true`. diff --git a/extensions/npm/package.json b/extensions/npm/package.json index 9d468a0cdfc..67f1b63e0fd 100644 --- a/extensions/npm/package.json +++ b/extensions/npm/package.json @@ -151,6 +151,12 @@ "default": false, "scope": "resource", "description": "%config.npm.enableScriptExplorer%" + }, + "npm.filterPrePostScripts": { + "type": "boolean", + "default": true, + "scope": "resource", + "description": "%config.npm.filterPrePostScripts%" } } }, diff --git a/extensions/npm/package.nls.json b/extensions/npm/package.nls.json index 19acf55d865..458779cdbf1 100644 --- a/extensions/npm/package.nls.json +++ b/extensions/npm/package.nls.json @@ -6,6 +6,7 @@ "config.npm.packageManager": "The package manager used to run scripts.", "config.npm.exclude": "Configure glob patterns for folders that should be excluded from automatic script detection.", "config.npm.enableScriptExplorer": "Enable an explorer view for npm scripts.", + "config.npm.filterPrePostScripts": "Filter pre- and postscripts. Default is true.", "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.", diff --git a/extensions/npm/src/main.ts b/extensions/npm/src/main.ts index 0e716dfb6bd..4bc42d28ecb 100644 --- a/extensions/npm/src/main.ts +++ b/extensions/npm/src/main.ts @@ -9,37 +9,37 @@ import * as vscode from 'vscode'; import { addJSONProviders } from './features/jsonContributions'; import { NpmScriptsTreeDataProvider } from './npmView'; -import { provideNpmScripts } from './tasks'; +import { provideNpmScripts, invalidateScriptsCache } from './tasks'; let taskProvider: vscode.Disposable | undefined; export async function activate(context: vscode.ExtensionContext): Promise { taskProvider = registerTaskProvider(context); - registerExplorer(context); + let treeDataProvider = registerExplorer(context); configureHttpRequest(); - vscode.workspace.onDidChangeConfiguration(() => { + vscode.workspace.onDidChangeConfiguration((e) => { configureHttpRequest(); + if (e.affectsConfiguration('npm.filterPrePostScripts')) { + invalidateScriptsCache(); + if (treeDataProvider) { + treeDataProvider.refresh(); + } + } }); context.subscriptions.push(addJSONProviders(httpRequest.xhr)); } function registerTaskProvider(context: vscode.ExtensionContext): vscode.Disposable | undefined { if (vscode.workspace.workspaceFolders) { - let cachedTasks: vscode.Task[] | undefined = undefined; - - let flushCache = () => cachedTasks = undefined; let watcher = vscode.workspace.createFileSystemWatcher('**/package.json'); - watcher.onDidChange((_e) => flushCache()); - watcher.onDidDelete((_e) => flushCache()); - watcher.onDidCreate((_e) => flushCache()); + watcher.onDidChange((_e) => invalidateScriptsCache()); + watcher.onDidDelete((_e) => invalidateScriptsCache()); + watcher.onDidCreate((_e) => invalidateScriptsCache()); context.subscriptions.push(watcher); let provider: vscode.TaskProvider = { provideTasks: async () => { - if (!cachedTasks) { - cachedTasks = await provideNpmScripts(); - } - return cachedTasks; + return provideNpmScripts(); }, resolveTask(_task: vscode.Task): vscode.Task | undefined { return undefined; @@ -50,11 +50,14 @@ function registerTaskProvider(context: vscode.ExtensionContext): vscode.Disposab return undefined; } -async function registerExplorer(context: vscode.ExtensionContext) { +function registerExplorer(context: vscode.ExtensionContext): NpmScriptsTreeDataProvider | undefined { if (vscode.workspace.workspaceFolders) { - let treeDataProvider = vscode.window.registerTreeDataProvider('npm', new NpmScriptsTreeDataProvider(context)); - context.subscriptions.push(treeDataProvider); + let treeDataProvider = new NpmScriptsTreeDataProvider(context); + let disposable = vscode.window.registerTreeDataProvider('npm', treeDataProvider); + context.subscriptions.push(disposable); + return treeDataProvider; } + return undefined; } function configureHttpRequest() { diff --git a/extensions/npm/src/npmView.ts b/extensions/npm/src/npmView.ts index 4bc361b09a6..2a7dd172c69 100644 --- a/extensions/npm/src/npmView.ts +++ b/extensions/npm/src/npmView.ts @@ -251,7 +251,7 @@ export class NpmScriptsTreeDataProvider implements TreeDataProvider { await window.showTextDocument(document, { selection: new Selection(position, position) }); } - private refresh() { + public refresh() { this.taskTree = null; this._onDidChangeTreeData.fire(); } diff --git a/extensions/npm/src/tasks.ts b/extensions/npm/src/tasks.ts index 49eac778c7b..a8c129f0db0 100644 --- a/extensions/npm/src/tasks.ts +++ b/extensions/npm/src/tasks.ts @@ -20,6 +20,12 @@ export interface NpmTaskDefinition extends TaskDefinition { type AutoDetect = 'on' | 'off'; +let cachedTasks: Task[] | undefined = undefined; + +export function invalidateScriptsCache() { + cachedTasks = undefined; +} + const buildNames: string[] = ['build', 'compile', 'watch']; function isBuildTask(name: string): boolean { for (let buildName of buildNames) { @@ -40,8 +46,24 @@ function isTestTask(name: string): boolean { return false; } -function isNotPreOrPostScript(script: string): boolean { - return !(script.startsWith('pre') || script.startsWith('post')); +function getPrePostScripts(scripts: any): Set { + const prePostScripts: Set = new Set([ + 'preuninstall', 'postuninstall', 'prepack', 'postpack', 'preinstall', 'postinstall', + 'prepack', 'postpack', 'prepublish', 'postpublish', 'preversion', 'postversion', + 'prestop', 'poststop', 'prerestart', 'postrestart', 'preshrinkwrap', 'postshrinkwrap', + 'pretest', 'postest', 'prepublishOnly' + ]); + let keys = Object.keys(scripts); + for (let i = 0; i < keys.length; i++) { + const script = keys[i]; + const prepost = ['pre' + script, 'post' + script]; + prepost.forEach(each => { + if (scripts[each]) { + prePostScripts.add(each); + } + }); + } + return prePostScripts; } export function isWorkspaceFolder(value: any): value is WorkspaceFolder { @@ -74,7 +96,8 @@ export async function hasNpmScripts(): Promise { } } -export async function provideNpmScripts(): Promise { +async function detectNpmScripts(): Promise { + let emptyTasks: Task[] = []; let allTasks: Task[] = []; @@ -102,6 +125,13 @@ export async function provideNpmScripts(): Promise { } } +export async function provideNpmScripts(): Promise { + if (!cachedTasks) { + cachedTasks = await detectNpmScripts(); + } + return cachedTasks; +} + function isAutoDetectionEnabled(folder: WorkspaceFolder): boolean { return workspace.getConfiguration('npm', folder.uri).get('autoDetect') === 'on'; } @@ -140,7 +170,10 @@ async function provideNpmScriptsForFolder(packageJsonUri: Uri): Promise } const result: Task[] = []; - Object.keys(scripts).filter(isNotPreOrPostScript).forEach(each => { + + const filterPrePost = workspace.getConfiguration('npm', folder.uri).get('filterPrePostScripts'); + const prePostScripts = filterPrePost ? getPrePostScripts(scripts) : new Set(); + Object.keys(scripts).filter(each => !prePostScripts.has(each)).forEach(each => { const task = createTask(each, `run ${each}`, folder!, packageJsonUri); const lowerCaseTaskName = each.toLowerCase(); if (isBuildTask(lowerCaseTaskName)) {