|
4 | 4 | *--------------------------------------------------------------------------------------------*/ |
5 | 5 | 'use strict'; |
6 | 6 |
|
7 | | -import * as path from 'path'; |
8 | | -import * as fs from 'fs'; |
9 | 7 | import * as httpRequest from 'request-light'; |
10 | 8 | import * as vscode from 'vscode'; |
11 | 9 | import * as nls from 'vscode-nls'; |
12 | | -import * as minimatch from 'minimatch'; |
13 | 10 |
|
14 | 11 | const localize = nls.loadMessageBundle(); |
15 | 12 |
|
16 | 13 | import { addJSONProviders } from './features/jsonContributions'; |
| 14 | +import { NpmScriptsTreeDataProvider } from './npmView'; |
| 15 | +import { provideNpmScripts, hasNpmScripts, explorerIsEnabled } from './tasks'; |
17 | 16 |
|
18 | | -type AutoDetect = 'on' | 'off'; |
19 | 17 | let taskProvider: vscode.Disposable | undefined; |
20 | 18 |
|
21 | | -export function activate(context: vscode.ExtensionContext): void { |
22 | | - if (!vscode.workspace.workspaceFolders) { |
23 | | - return; |
24 | | - } |
25 | | - |
26 | | - taskProvider = vscode.workspace.registerTaskProvider('npm', { |
27 | | - provideTasks: () => { |
28 | | - return provideNpmScripts(); |
29 | | - }, |
30 | | - resolveTask(_task: vscode.Task): vscode.Task | undefined { |
31 | | - return undefined; |
32 | | - } |
33 | | - }); |
| 19 | +export async function activate(context: vscode.ExtensionContext): Promise<void> { |
| 20 | + taskProvider = registerTaskProvider(context); |
34 | 21 | configureHttpRequest(); |
35 | 22 | vscode.workspace.onDidChangeConfiguration(() => configureHttpRequest()); |
36 | | - |
37 | 23 | context.subscriptions.push(addJSONProviders(httpRequest.xhr)); |
38 | 24 | } |
39 | 25 |
|
40 | | -function configureHttpRequest() { |
41 | | - const httpSettings = vscode.workspace.getConfiguration('http'); |
42 | | - httpRequest.configure(httpSettings.get<string>('proxy', ''), httpSettings.get<boolean>('proxyStrictSSL', true)); |
43 | | -} |
44 | | - |
45 | | -export function deactivate(): void { |
46 | | - if (taskProvider) { |
47 | | - taskProvider.dispose(); |
48 | | - } |
49 | | -} |
50 | | - |
51 | | -async function exists(file: string): Promise<boolean> { |
52 | | - return new Promise<boolean>((resolve, _reject) => { |
53 | | - fs.exists(file, (value) => { |
54 | | - resolve(value); |
55 | | - }); |
56 | | - }); |
57 | | -} |
58 | | - |
59 | | -async function readFile(file: string): Promise<string> { |
60 | | - return new Promise<string>((resolve, reject) => { |
61 | | - fs.readFile(file, (err, data) => { |
62 | | - if (err) { |
63 | | - reject(err); |
64 | | - } |
65 | | - resolve(data.toString()); |
66 | | - }); |
67 | | - }); |
68 | | -} |
69 | | - |
70 | | -interface NpmTaskDefinition extends vscode.TaskDefinition { |
71 | | - script: string; |
72 | | - path?: string; |
73 | | -} |
74 | | - |
75 | | -const buildNames: string[] = ['build', 'compile', 'watch']; |
76 | | -function isBuildTask(name: string): boolean { |
77 | | - for (let buildName of buildNames) { |
78 | | - if (name.indexOf(buildName) !== -1) { |
79 | | - return true; |
80 | | - } |
81 | | - } |
82 | | - return false; |
83 | | -} |
84 | | - |
85 | | -const testNames: string[] = ['test']; |
86 | | -function isTestTask(name: string): boolean { |
87 | | - for (let testName of testNames) { |
88 | | - if (name === testName) { |
89 | | - return true; |
90 | | - } |
91 | | - } |
92 | | - return false; |
93 | | -} |
94 | | - |
95 | | -function isNotPreOrPostScript(script: string): boolean { |
96 | | - return !(script.startsWith('pre') || script.startsWith('post')); |
97 | | -} |
98 | | - |
99 | | -async function provideNpmScripts(): Promise<vscode.Task[]> { |
100 | | - let emptyTasks: vscode.Task[] = []; |
101 | | - let allTasks: vscode.Task[] = []; |
102 | | - |
103 | | - let folders = vscode.workspace.workspaceFolders; |
104 | | - if (!folders) { |
105 | | - return emptyTasks; |
106 | | - } |
107 | | - try { |
108 | | - for (let i = 0; i < folders.length; i++) { |
109 | | - let folder = folders[i]; |
110 | | - if (isEnabled(folder)) { |
111 | | - let relativePattern = new vscode.RelativePattern(folder, '**/package.json'); |
112 | | - let paths = await vscode.workspace.findFiles(relativePattern, '**/node_modules/**'); |
113 | | - for (let j = 0; j < paths.length; j++) { |
114 | | - if (!isExcluded(folder, paths[j])) { |
115 | | - let tasks = await provideNpmScriptsForFolder(paths[j]); |
116 | | - allTasks.push(...tasks); |
117 | | - } |
118 | | - } |
| 26 | +function registerTaskProvider(context: vscode.ExtensionContext): vscode.Disposable | undefined { |
| 27 | + if (vscode.workspace.workspaceFolders) { |
| 28 | + let provider: vscode.TaskProvider = { |
| 29 | + provideTasks: () => { |
| 30 | + return provideNpmScripts(localize); |
| 31 | + }, |
| 32 | + resolveTask(_task: vscode.Task): vscode.Task | undefined { |
| 33 | + return undefined; |
119 | 34 | } |
120 | | - } |
121 | | - return allTasks; |
122 | | - } catch (error) { |
123 | | - return Promise.reject(error); |
| 35 | + }; |
| 36 | + let disposable = vscode.workspace.registerTaskProvider('npm', provider); |
| 37 | + registerExplorer(context, provider); |
| 38 | + return disposable; |
124 | 39 | } |
| 40 | + return undefined; |
125 | 41 | } |
126 | 42 |
|
127 | | -function isEnabled(folder: vscode.WorkspaceFolder): boolean { |
128 | | - return vscode.workspace.getConfiguration('npm', folder.uri).get<AutoDetect>('autoDetect') === 'on'; |
129 | | -} |
130 | | - |
131 | | -function isExcluded(folder: vscode.WorkspaceFolder, packageJsonUri: vscode.Uri) { |
132 | | - function testForExclusionPattern(path: string, pattern: string): boolean { |
133 | | - return minimatch(path, pattern, { dot: true }); |
134 | | - } |
135 | | - |
136 | | - let exclude = vscode.workspace.getConfiguration('npm', folder.uri).get<string | string[]>('exclude'); |
137 | | - |
138 | | - if (exclude) { |
139 | | - if (Array.isArray(exclude)) { |
140 | | - for (let pattern of exclude) { |
141 | | - if (testForExclusionPattern(packageJsonUri.fsPath, pattern)) { |
142 | | - return true; |
143 | | - } |
144 | | - } |
145 | | - } else if (testForExclusionPattern(packageJsonUri.fsPath, exclude)) { |
146 | | - return true; |
| 43 | +async function registerExplorer(context: vscode.ExtensionContext, provider: vscode.TaskProvider) { |
| 44 | + if (explorerIsEnabled()) { |
| 45 | + let treeDataProvider = vscode.window.registerTreeDataProvider('npm', new NpmScriptsTreeDataProvider(context, provider, localize)); |
| 46 | + context.subscriptions.push(treeDataProvider); |
| 47 | + if (await hasNpmScripts()) { |
| 48 | + vscode.commands.executeCommand('setContext', 'hasNpmScripts', true); |
147 | 49 | } |
148 | 50 | } |
149 | | - return false; |
150 | 51 | } |
151 | 52 |
|
152 | | -async function provideNpmScriptsForFolder(packageJsonUri: vscode.Uri): Promise<vscode.Task[]> { |
153 | | - let emptyTasks: vscode.Task[] = []; |
154 | | - |
155 | | - if (packageJsonUri.scheme !== 'file') { |
156 | | - return emptyTasks; |
157 | | - } |
158 | | - |
159 | | - let packageJson = packageJsonUri.fsPath; |
160 | | - |
161 | | - if (!await exists(packageJson)) { |
162 | | - return emptyTasks; |
163 | | - } |
164 | | - |
165 | | - let folder = vscode.workspace.getWorkspaceFolder(packageJsonUri); |
166 | | - if (!folder) { |
167 | | - return emptyTasks; |
168 | | - } |
169 | | - |
170 | | - try { |
171 | | - var contents = await readFile(packageJson); |
172 | | - var json = JSON.parse(contents); |
173 | | - if (!json.scripts) { |
174 | | - return emptyTasks; |
175 | | - } |
176 | | - |
177 | | - const result: vscode.Task[] = []; |
178 | | - Object.keys(json.scripts).filter(isNotPreOrPostScript).forEach(each => { |
179 | | - const task = createTask(each, `run ${each}`, folder!, packageJsonUri); |
180 | | - const lowerCaseTaskName = each.toLowerCase(); |
181 | | - if (isBuildTask(lowerCaseTaskName)) { |
182 | | - task.group = vscode.TaskGroup.Build; |
183 | | - } else if (isTestTask(lowerCaseTaskName)) { |
184 | | - task.group = vscode.TaskGroup.Test; |
185 | | - } |
186 | | - result.push(task); |
187 | | - }); |
188 | | - // always add npm install (without a problem matcher) |
189 | | - // result.push(createTask('install', 'install', rootPath, folder, [])); |
190 | | - return result; |
191 | | - } catch (e) { |
192 | | - let localizedParseError = localize('npm.parseError', 'Npm task detection: failed to parse the file {0}', packageJsonUri); |
193 | | - throw new Error(localizedParseError); |
194 | | - } |
| 53 | +function configureHttpRequest() { |
| 54 | + const httpSettings = vscode.workspace.getConfiguration('http'); |
| 55 | + httpRequest.configure(httpSettings.get<string>('proxy', ''), httpSettings.get<boolean>('proxyStrictSSL', true)); |
195 | 56 | } |
196 | 57 |
|
197 | | -function createTask(script: string, cmd: string, folder: vscode.WorkspaceFolder, packageJsonUri: vscode.Uri, matcher?: any): vscode.Task { |
198 | | - |
199 | | - function getTaskName(script: string, file: string) { |
200 | | - if (file.length) { |
201 | | - return `${script} - ${file.substring(0, file.length - 1)}`; |
202 | | - } |
203 | | - return script; |
204 | | - } |
205 | | - |
206 | | - function getCommandLine(folder: vscode.WorkspaceFolder, cmd: string): string { |
207 | | - let packageManager = vscode.workspace.getConfiguration('npm', folder.uri).get<string>('packageManager', 'npm'); |
208 | | - if (vscode.workspace.getConfiguration('npm', folder.uri).get<boolean>('runSilent')) { |
209 | | - return `${packageManager} --silent ${cmd}`; |
210 | | - } |
211 | | - return `${packageManager} ${cmd}`; |
212 | | - } |
213 | | - |
214 | | - function getRelativePath(folder: vscode.WorkspaceFolder, packageJsonUri: vscode.Uri): string { |
215 | | - let rootUri = folder.uri; |
216 | | - let absolutePath = packageJsonUri.path.substring(0, packageJsonUri.path.length - 'package.json'.length); |
217 | | - return absolutePath.substring(rootUri.path.length + 1); |
218 | | - } |
219 | | - |
220 | | - let kind: NpmTaskDefinition = { |
221 | | - type: 'npm', |
222 | | - script: script |
223 | | - }; |
224 | | - let relativePackageJson = getRelativePath(folder, packageJsonUri); |
225 | | - if (relativePackageJson.length) { |
226 | | - kind.path = getRelativePath(folder, packageJsonUri); |
| 58 | +export function deactivate(): void { |
| 59 | + if (taskProvider) { |
| 60 | + taskProvider.dispose(); |
227 | 61 | } |
228 | | - let taskName = getTaskName(script, relativePackageJson); |
229 | | - let cwd = path.dirname(packageJsonUri.fsPath); |
230 | | - return new vscode.Task(kind, folder, taskName, 'npm', new vscode.ShellExecution(getCommandLine(folder, cmd), { cwd: cwd }), matcher); |
231 | 62 | } |
0 commit comments