diff --git a/build/npm/postinstall.js b/build/npm/postinstall.js index 8c52bcc0f3e..ad14f3082d3 100644 --- a/build/npm/postinstall.js +++ b/build/npm/postinstall.js @@ -36,7 +36,9 @@ const extensions = [ 'grunt', 'jake', 'merge-conflict', - 'emmet' + 'emmet', + 'npm', + 'jake' ]; extensions.forEach(extension => npmInstall(`extensions/${extension}`)); diff --git a/extensions/npm/.vscode/launch.json b/extensions/npm/.vscode/launch.json new file mode 100644 index 00000000000..da043ff85d9 --- /dev/null +++ b/extensions/npm/.vscode/launch.json @@ -0,0 +1,18 @@ +{ + "version": "0.2.0", + "configurations": [ + { + "name": "Launch Extension", + "type": "extensionHost", + "request": "launch", + "runtimeExecutable": "${execPath}", + "args": [ + "--extensionDevelopmentPath=${workspaceRoot}" + ], + "stopOnEntry": false, + "sourceMaps": true, + "outFiles": ["${workspaceRoot}/client/out/**/*.js"], + "preLaunchTask": "npm" + } + ] +} \ No newline at end of file diff --git a/extensions/npm/.vscode/tasks.json b/extensions/npm/.vscode/tasks.json new file mode 100644 index 00000000000..0a411c1c867 --- /dev/null +++ b/extensions/npm/.vscode/tasks.json @@ -0,0 +1,9 @@ +{ + "version": "0.1.0", + "command": "npm", + "isShellCommand": true, + "showOutput": "silent", + "args": ["run", "compile"], + "isBackground": true, + "problemMatcher": "$tsc-watch" +} \ No newline at end of file diff --git a/extensions/npm/package.json b/extensions/npm/package.json new file mode 100644 index 00000000000..e6a6a3ec4fa --- /dev/null +++ b/extensions/npm/package.json @@ -0,0 +1,48 @@ +{ + "name": "npm", + "publisher": "vscode", + "description": "Extension to add task support for npm scripts.", + "displayName": "Npm support for VSCode", + "version": "0.0.1", + "enableProposedApi": true, + "engines": { + "vscode": "0.10.x" + }, + "categories": [ + "Other" + ], + "scripts": { + "compile": "gulp compile-extension:npm", + "watch": "gulp watch-extension:npm" + }, + "dependencies": { + "vscode-nls": "^2.0.2" + }, + "devDependencies": { + "@types/node": "^7.0.12" + }, + "main": "./out/main", + "activationEvents": [ + "onCommand:workbench.action.tasks.runTask", + "onCommand:workbench.action.tasks.build", + "onCommand:workbench.action.tasks.test" + ], + "contributes": { + "configuration": { + "id": "npm", + "type": "object", + "title": "Npm", + "properties": { + "npm.autoDetect": { + "type": "string", + "enum": [ + "off", + "on" + ], + "default": "on", + "description": "%config.npm.autoDetect%" + } + } + } + } +} \ No newline at end of file diff --git a/extensions/npm/package.nls.json b/extensions/npm/package.nls.json new file mode 100644 index 00000000000..bd7c911cda4 --- /dev/null +++ b/extensions/npm/package.nls.json @@ -0,0 +1,3 @@ +{ + "config.npm.autoDetect": "Controls whether auto detection of npm scripts is on or off. Default is on." +} \ No newline at end of file diff --git a/extensions/npm/src/main.ts b/extensions/npm/src/main.ts new file mode 100644 index 00000000000..9308210ede8 --- /dev/null +++ b/extensions/npm/src/main.ts @@ -0,0 +1,97 @@ +/*--------------------------------------------------------------------------------------------- + * 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 * as path from 'path'; +import * as fs from 'fs'; +import * as vscode from 'vscode'; + +type AutoDetect = 'on' | 'off'; +let taskProvider: vscode.Disposable | undefined; + +export function activate(_context: vscode.ExtensionContext): void { + let workspaceRoot = vscode.workspace.rootPath; + if (!workspaceRoot) { + return; + } + + function onConfigurationChanged() { + let autoDetect = vscode.workspace.getConfiguration('npm').get('autoDetect'); + if (taskProvider && autoDetect === 'off') { + taskProvider.dispose(); + taskProvider = undefined; + } else if (!taskProvider && autoDetect === 'on') { + taskProvider = vscode.workspace.registerTaskProvider({ + provideTasks: () => { + return getNpmScriptsAsTasks(); + } + }); + } + } + vscode.workspace.onDidChangeConfiguration(onConfigurationChanged); + onConfigurationChanged(); +} + +export function deactivate(): void { + if (taskProvider) { + taskProvider.dispose(); + } +} + +async function exists(file: string): Promise { + return new Promise((resolve, _reject) => { + fs.exists(file, (value) => { + resolve(value); + }); + }); +} + +async function readFile(file: string): Promise { + return new Promise((resolve, reject) => { + fs.readFile(file, (err, data) => { + if (err) { + reject(err); + } + resolve(data.toString()); + }); + }); +} + +async function getNpmScriptsAsTasks(): Promise { + let workspaceRoot = vscode.workspace.rootPath; + let emptyTasks: vscode.Task[] = []; + + if (!workspaceRoot) { + return emptyTasks; + } + + let packageJson = path.join(workspaceRoot, 'package.json'); + if (!await exists(packageJson)) { + return emptyTasks; + } + + try { + var contents = await readFile(packageJson); + var json = JSON.parse(contents); + if (!json.scripts) { + return Promise.resolve(emptyTasks); + } + + const result: vscode.Task[] = []; + Object.keys(json.scripts).forEach(each => { + const task = new vscode.ShellTask(`npm: run ${each}`, `npm run ${each}`); + const lowerCaseTaskName = each.toLowerCase(); + if (lowerCaseTaskName === 'build') { + task.group = vscode.TaskGroup.Build; + } else if (lowerCaseTaskName === 'test') { + task.group = vscode.TaskGroup.Test; + } + result.push(task); + }); + return Promise.resolve(result); + } catch (e) { + return Promise.resolve(emptyTasks); + } +} \ No newline at end of file diff --git a/extensions/npm/src/typings/refs.d.ts b/extensions/npm/src/typings/refs.d.ts new file mode 100644 index 00000000000..954bab971e3 --- /dev/null +++ b/extensions/npm/src/typings/refs.d.ts @@ -0,0 +1,8 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +/// +/// +/// diff --git a/extensions/npm/tsconfig.json b/extensions/npm/tsconfig.json new file mode 100644 index 00000000000..e804fa3acd7 --- /dev/null +++ b/extensions/npm/tsconfig.json @@ -0,0 +1,18 @@ +{ + "compilerOptions": { + "target": "es6", + "module": "commonjs", + "lib": [ + "es2016" + ], + "outDir": "./out", + "strictNullChecks": true, + "noImplicitAny": true, + "noImplicitReturns": true, + "noUnusedLocals": true, + "noUnusedParameters": true + }, + "include": [ + "src/**/*" + ] +} \ No newline at end of file