/*--------------------------------------------------------------------------------------------- * Copyright (c) Microsoft Corporation. All rights reserved. * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ 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 { getScriptRunner, getPackageManager, invalidateTasksCache, NpmTaskProvider, hasPackageJson } from './tasks'; import { invalidateHoverScriptsCache, NpmScriptHoverProvider } from './scriptHover'; import { NpmScriptLensProvider } from './npmScriptLens'; import which from 'which'; let treeDataProvider: NpmScriptsTreeDataProvider | undefined; function invalidateScriptCaches() { invalidateHoverScriptsCache(); invalidateTasksCache(); if (treeDataProvider) { treeDataProvider.refresh(); } } export async function activate(context: vscode.ExtensionContext): Promise { configureHttpRequest(); context.subscriptions.push(vscode.workspace.onDidChangeConfiguration(e => { if (e.affectsConfiguration('http.proxy') || e.affectsConfiguration('http.proxyStrictSSL')) { configureHttpRequest(); } })); const npmCommandPath = await getNPMCommandPath(); context.subscriptions.push(addJSONProviders(httpRequest.xhr, npmCommandPath)); registerTaskProvider(context); treeDataProvider = registerExplorer(context); context.subscriptions.push(vscode.workspace.onDidChangeConfiguration((e) => { if (e.affectsConfiguration('npm.exclude') || e.affectsConfiguration('npm.autoDetect') || e.affectsConfiguration('npm.scriptExplorerExclude') || e.affectsConfiguration('npm.runSilent') || e.affectsConfiguration('npm.packageManager') || e.affectsConfiguration('npm.scriptRunner')) { invalidateTasksCache(); if (treeDataProvider) { treeDataProvider.refresh(); } } if (e.affectsConfiguration('npm.scriptExplorerAction')) { if (treeDataProvider) { treeDataProvider.refresh(); } } })); registerHoverProvider(context); context.subscriptions.push(vscode.commands.registerCommand('npm.runSelectedScript', runSelectedScript)); if (await hasPackageJson()) { vscode.commands.executeCommand('setContext', 'npm:showScriptExplorer', true); } context.subscriptions.push(vscode.commands.registerCommand('npm.runScriptFromFolder', selectAndRunScriptFromFolder)); context.subscriptions.push(vscode.commands.registerCommand('npm.refresh', () => { invalidateScriptCaches(); })); context.subscriptions.push(vscode.commands.registerCommand('npm.scriptRunner', (args) => { if (args instanceof vscode.Uri) { return getScriptRunner(args, context, true); } return ''; })); context.subscriptions.push(vscode.commands.registerCommand('npm.packageManager', (args) => { if (args instanceof vscode.Uri) { return getPackageManager(args, context, true); } return ''; })); context.subscriptions.push(new NpmScriptLensProvider()); context.subscriptions.push(vscode.window.registerTerminalQuickFixProvider('ms-vscode.npm-command', { provideTerminalQuickFixes({ outputMatch }) { if (!outputMatch) { return; } const lines = outputMatch.regexMatch[1]; const fixes: vscode.TerminalQuickFixTerminalCommand[] = []; for (const line of lines.split('\n')) { // search from the second char, since the lines might be prefixed with // "npm ERR!" which comes before the actual command suggestion. const begin = line.indexOf('npm', 1); if (begin === -1) { continue; } const end = line.lastIndexOf('#'); fixes.push({ terminalCommand: line.slice(begin, end === -1 ? undefined : end - 1) }); } return fixes; }, })); } async function getNPMCommandPath(): Promise { if (vscode.workspace.isTrusted && canRunNpmInCurrentWorkspace()) { try { return await which(process.platform === 'win32' ? 'npm.cmd' : 'npm'); } catch (e) { return undefined; } } return undefined; } function canRunNpmInCurrentWorkspace() { if (vscode.workspace.workspaceFolders) { return vscode.workspace.workspaceFolders.some(f => f.uri.scheme === 'file'); } return false; } let taskProvider: NpmTaskProvider; function registerTaskProvider(context: vscode.ExtensionContext): vscode.Disposable | undefined { if (vscode.workspace.workspaceFolders) { const watcher = vscode.workspace.createFileSystemWatcher('**/package.json'); watcher.onDidChange((_e) => invalidateScriptCaches()); watcher.onDidDelete((_e) => invalidateScriptCaches()); watcher.onDidCreate((_e) => invalidateScriptCaches()); context.subscriptions.push(watcher); const workspaceWatcher = vscode.workspace.onDidChangeWorkspaceFolders((_e) => invalidateScriptCaches()); context.subscriptions.push(workspaceWatcher); taskProvider = new NpmTaskProvider(context); const disposable = vscode.tasks.registerTaskProvider('npm', taskProvider); context.subscriptions.push(disposable); return disposable; } return undefined; } function registerExplorer(context: vscode.ExtensionContext): NpmScriptsTreeDataProvider | undefined { if (vscode.workspace.workspaceFolders) { const treeDataProvider = new NpmScriptsTreeDataProvider(context, taskProvider!); const view = vscode.window.createTreeView('npm', { treeDataProvider: treeDataProvider, showCollapseAll: true }); context.subscriptions.push(view); return treeDataProvider; } return undefined; } function registerHoverProvider(context: vscode.ExtensionContext): NpmScriptHoverProvider | undefined { if (vscode.workspace.workspaceFolders) { const npmSelector: vscode.DocumentSelector = { language: 'json', scheme: 'file', pattern: '**/package.json' }; const provider = new NpmScriptHoverProvider(context); context.subscriptions.push(vscode.languages.registerHoverProvider(npmSelector, provider)); return provider; } return undefined; } function configureHttpRequest() { const httpSettings = vscode.workspace.getConfiguration('http'); httpRequest.configure(httpSettings.get('proxy', ''), httpSettings.get('proxyStrictSSL', true)); } export function deactivate(): void { }