diff --git a/extensions/npm/src/main.ts b/extensions/npm/src/main.ts index 67dd1c2f150..4ed886bc55f 100644 --- a/extensions/npm/src/main.ts +++ b/extensions/npm/src/main.ts @@ -4,25 +4,22 @@ *--------------------------------------------------------------------------------------------*/ 'use strict'; -import * as path from 'path'; import * as httpRequest from 'request-light'; import * as vscode from 'vscode'; import * as nls from 'vscode-nls'; -import * as minimatch from 'minimatch'; const localize = nls.loadMessageBundle(); import { addJSONProviders } from './features/jsonContributions'; import { NpmScriptsTreeDataProvider } from './npmView'; -import { NpmTaskDefinition, getScripts, getPackageManager } from './tasks'; +import { provideNpmScripts } from './tasks'; -type AutoDetect = 'on' | 'off'; let taskProvider: vscode.Disposable | undefined; export function activate(context: vscode.ExtensionContext): void { let provider: vscode.TaskProvider = { provideTasks: () => { - return provideNpmScripts(); + return provideNpmScripts(localize); }, resolveTask(_task: vscode.Task): vscode.Task | undefined { return undefined; @@ -52,144 +49,3 @@ export function deactivate(): void { taskProvider.dispose(); } } - -const buildNames: string[] = ['build', 'compile', 'watch']; -function isBuildTask(name: string): boolean { - for (let buildName of buildNames) { - if (name.indexOf(buildName) !== -1) { - return true; - } - } - return false; -} - -const testNames: string[] = ['test']; -function isTestTask(name: string): boolean { - for (let testName of testNames) { - if (name === testName) { - return true; - } - } - return false; -} - -function isNotPreOrPostScript(script: string): boolean { - return !(script.startsWith('pre') || script.startsWith('post')); -} - -async function provideNpmScripts(): Promise { - let emptyTasks: vscode.Task[] = []; - let allTasks: vscode.Task[] = []; - - let folders = vscode.workspace.workspaceFolders; - if (!folders) { - return emptyTasks; - } - try { - for (let i = 0; i < folders.length; i++) { - let folder = folders[i]; - if (isEnabled(folder)) { - let relativePattern = new vscode.RelativePattern(folder, '**/package.json'); - let paths = await vscode.workspace.findFiles(relativePattern, '**/node_modules/**'); - for (let j = 0; j < paths.length; j++) { - if (!isExcluded(folder, paths[j])) { - let tasks = await provideNpmScriptsForFolder(paths[j]); - allTasks.push(...tasks); - } - } - } - } - return allTasks; - } catch (error) { - return Promise.reject(error); - } -} - -function isEnabled(folder: vscode.WorkspaceFolder): boolean { - return vscode.workspace.getConfiguration('npm', folder.uri).get('autoDetect') === 'on'; -} - -function isExcluded(folder: vscode.WorkspaceFolder, packageJsonUri: vscode.Uri) { - function testForExclusionPattern(path: string, pattern: string): boolean { - return minimatch(path, pattern, { dot: true }); - } - - let exclude = vscode.workspace.getConfiguration('npm', folder.uri).get('exclude'); - - if (exclude) { - if (Array.isArray(exclude)) { - for (let pattern of exclude) { - if (testForExclusionPattern(packageJsonUri.fsPath, pattern)) { - return true; - } - } - } else if (testForExclusionPattern(packageJsonUri.fsPath, exclude)) { - return true; - } - } - return false; -} - -async function provideNpmScriptsForFolder(packageJsonUri: vscode.Uri): Promise { - let emptyTasks: vscode.Task[] = []; - - let folder = vscode.workspace.getWorkspaceFolder(packageJsonUri); - if (!folder) { - return emptyTasks; - } - 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 { - - function getTaskName(script: string, file: string) { - if (file.length) { - return `${script} - ${file.substring(0, file.length - 1)}`; - } - return script; - } - - function getCommandLine(folder: vscode.WorkspaceFolder, cmd: string): string { - let packageManager = getPackageManager(folder); - if (vscode.workspace.getConfiguration('npm', folder.uri).get('runSilent')) { - return `${packageManager} --silent ${cmd}`; - } - return `${packageManager} ${cmd}`; - } - - function getRelativePath(folder: vscode.WorkspaceFolder, packageJsonUri: vscode.Uri): string { - let rootUri = folder.uri; - let absolutePath = packageJsonUri.path.substring(0, packageJsonUri.path.length - 'package.json'.length); - return absolutePath.substring(rootUri.path.length + 1); - } - - let kind: NpmTaskDefinition = { - type: 'npm', - script: script - }; - let relativePackageJson = getRelativePath(folder, packageJsonUri); - if (relativePackageJson.length) { - kind.path = getRelativePath(folder, packageJsonUri); - } - let taskName = getTaskName(script, relativePackageJson); - let cwd = path.dirname(packageJsonUri.fsPath); - return new vscode.Task(kind, folder, taskName, 'npm', new vscode.ShellExecution(getCommandLine(folder, cmd), { cwd: cwd }), matcher); -} diff --git a/extensions/npm/src/tasks.ts b/extensions/npm/src/tasks.ts index 6c4db9e1d31..9f10bb91201 100644 --- a/extensions/npm/src/tasks.ts +++ b/extensions/npm/src/tasks.ts @@ -4,15 +4,42 @@ *--------------------------------------------------------------------------------------------*/ 'use strict'; -import { TaskDefinition, Task, WorkspaceFolder, Uri, workspace } from 'vscode'; +import { TaskDefinition, Task, TaskGroup, WorkspaceFolder, RelativePattern, ShellExecution, Uri, workspace } from 'vscode'; import * as path from 'path'; import * as fs from 'fs'; +import * as minimatch from 'minimatch'; export interface NpmTaskDefinition extends TaskDefinition { script: string; path?: string; } +type AutoDetect = 'on' | 'off'; + +const buildNames: string[] = ['build', 'compile', 'watch']; +function isBuildTask(name: string): boolean { + for (let buildName of buildNames) { + if (name.indexOf(buildName) !== -1) { + return true; + } + } + return false; +} + +const testNames: string[] = ['test']; +function isTestTask(name: string): boolean { + for (let testName of testNames) { + if (name === testName) { + return true; + } + } + return false; +} + +function isNotPreOrPostScript(script: string): boolean { + return !(script.startsWith('pre') || script.startsWith('post')); +} + export function isWorkspaceFolder(value: any): value is WorkspaceFolder { return value && typeof value !== 'number'; } @@ -21,6 +48,124 @@ export function getPackageManager(folder: WorkspaceFolder): string { return workspace.getConfiguration('npm', folder.uri).get('packageManager', 'npm'); } +export async function provideNpmScripts(localize: any): Promise { + let emptyTasks: Task[] = []; + let allTasks: Task[] = []; + + let folders = workspace.workspaceFolders; + if (!folders) { + return emptyTasks; + } + try { + for (let i = 0; i < folders.length; i++) { + let folder = folders[i]; + if (isEnabled(folder)) { + let relativePattern = new RelativePattern(folder, '**/package.json'); + let paths = await workspace.findFiles(relativePattern, '**/node_modules/**'); + for (let j = 0; j < paths.length; j++) { + if (!isExcluded(folder, paths[j])) { + let tasks = await provideNpmScriptsForFolder(localize, paths[j]); + allTasks.push(...tasks); + } + } + } + } + return allTasks; + } catch (error) { + return Promise.reject(error); + } +} + +function isEnabled(folder: WorkspaceFolder): boolean { + return workspace.getConfiguration('npm', folder.uri).get('autoDetect') === 'on'; +} + +function isExcluded(folder: WorkspaceFolder, packageJsonUri: Uri) { + function testForExclusionPattern(path: string, pattern: string): boolean { + return minimatch(path, pattern, { dot: true }); + } + + let exclude = workspace.getConfiguration('npm', folder.uri).get('exclude'); + + if (exclude) { + if (Array.isArray(exclude)) { + for (let pattern of exclude) { + if (testForExclusionPattern(packageJsonUri.fsPath, pattern)) { + return true; + } + } + } else if (testForExclusionPattern(packageJsonUri.fsPath, exclude)) { + return true; + } + } + return false; +} + +async function provideNpmScriptsForFolder(localize: any, packageJsonUri: Uri): Promise { + let emptyTasks: Task[] = []; + + let folder = workspace.getWorkspaceFolder(packageJsonUri); + if (!folder) { + return emptyTasks; + } + let scripts = await getScripts(packageJsonUri, localize); + if (!scripts) { + return emptyTasks; + } + + const result: 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 = TaskGroup.Build; + } else if (isTestTask(lowerCaseTaskName)) { + task.group = 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: WorkspaceFolder, packageJsonUri: Uri, matcher?: any): Task { + + function getTaskName(script: string, file: string) { + if (file.length) { + return `${script} - ${file.substring(0, file.length - 1)}`; + } + return script; + } + + function getCommandLine(folder: WorkspaceFolder, cmd: string): string { + let packageManager = getPackageManager(folder); + if (workspace.getConfiguration('npm', folder.uri).get('runSilent')) { + return `${packageManager} --silent ${cmd}`; + } + return `${packageManager} ${cmd}`; + } + + function getRelativePath(folder: WorkspaceFolder, packageJsonUri: Uri): string { + let rootUri = folder.uri; + let absolutePath = packageJsonUri.path.substring(0, packageJsonUri.path.length - 'package.json'.length); + return absolutePath.substring(rootUri.path.length + 1); + } + + let kind: NpmTaskDefinition = { + type: 'npm', + script: script + }; + let relativePackageJson = getRelativePath(folder, packageJsonUri); + if (relativePackageJson.length) { + kind.path = getRelativePath(folder, packageJsonUri); + } + let taskName = getTaskName(script, relativePackageJson); + let cwd = path.dirname(packageJsonUri.fsPath); + return new Task(kind, folder, taskName, 'npm', new ShellExecution(getCommandLine(folder, cmd), { cwd: cwd }), matcher); +} + + export function getPackageJsonUriFromTask(task: Task): Uri | null { if (isWorkspaceFolder(task.scope)) { if (task.definition.path) {