Skip to content

Commit

Permalink
Add TSC Task Provider
Browse files Browse the repository at this point in the history
Fixes microsoft#26079

Adds a task provider for building typescript projects.
  • Loading branch information
mjbvz committed May 25, 2017
1 parent 2e755b2 commit c3eec4e
Show file tree
Hide file tree
Showing 4 changed files with 119 additions and 2 deletions.
6 changes: 5 additions & 1 deletion extensions/typescript/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
"license": "MIT",
"publisher": "vscode",
"aiKey": "AIF-d9b70cd4-b9f9-4d70-929b-a071c400b217",
"enableProposedApi": true,
"engines": {
"vscode": "*"
},
Expand Down Expand Up @@ -34,7 +35,10 @@
"onCommand:typescript.selectTypeScriptVersion",
"onCommand:javascript.goToProjectConfig",
"onCommand:typescript.goToProjectConfig",
"onCommand:typescript.openTsServerLog"
"onCommand:typescript.openTsServerLog",
"onCommand:workbench.action.tasks.runTask",
"onCommand:workbench.action.tasks.build",
"onCommand:workbench.action.tasks.test"
],
"main": "./out/typescriptMain",
"contributes": {
Expand Down
110 changes: 110 additions & 0 deletions extensions/typescript/src/features/taskProvider.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
/*---------------------------------------------------------------------------------------------
* 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 fs from 'fs';
import * as path from 'path';
import * as vscode from 'vscode';

import * as Proto from '../protocol';
import TypeScriptServiceClient from '../typescriptServiceClient';


const exists = (file: string): Promise<boolean> =>
new Promise<boolean>((resolve, _reject) => {
fs.exists(file, (value: boolean) => {
resolve(value);
});
});

export default class TypeScriptTaskProvider implements vscode.TaskProvider {

public constructor(
private readonly client: TypeScriptServiceClient
) { }

async provideTasks(token: vscode.CancellationToken): Promise<vscode.Task[]> {
const rootPath = vscode.workspace.rootPath;
if (!rootPath) {
return [];
}

const projects = (await this.getConfigForActiveFile(token)).concat(await this.getConfigsForWorkspace());
const command = await this.getCommand();

return projects
.filter((x, i) => projects.indexOf(x) === i)
.map(configFile => {
const configFileName = path.relative(rootPath, configFile);
const buildTask = new vscode.ShellTask(`tsc: build ${configFileName}`, `${command} -p ${configFile}`, '$tsc');
buildTask.group = vscode.TaskGroup.Build;
return buildTask;
});
}


private async getConfigForActiveFile(token: vscode.CancellationToken): Promise<string[]> {
const editor = vscode.window.activeTextEditor;
if (editor) {
if (path.basename(editor.document.fileName).match(/^tsconfig\.(.\.)?json$/)) {
return [editor.document.fileName];
}
}

const file = this.getActiveTypeScriptFile();
if (!file) {
return [];
}

const res: Proto.ProjectInfoResponse = await this.client.execute(
'projectInfo',
{ file, needFileNameList: false } as protocol.ProjectInfoRequestArgs,
token);

if (!res || !res.body) {
return [];
}

const { configFileName } = res.body;
if (configFileName && configFileName.indexOf('/dev/null/') !== 0) {
return [configFileName];
}
return [];
}

private async getConfigsForWorkspace(): Promise<string[]> {
if (!vscode.workspace.rootPath) {
return [];
}
const rootTsConfig = path.join(vscode.workspace.rootPath, 'tsconfig.json');
if (!await exists(rootTsConfig)) {
return [];
}
return [rootTsConfig];
}

private async getCommand(): Promise<string> {
const platform = process.platform;
if (platform === 'win32' && await exists(path.join(vscode.workspace.rootPath!, 'node_modules', '.bin', 'tsc.cmd'))) {
return path.join('.', 'node_modules', '.bin', 'tsc.cmd');
} else if ((platform === 'linux' || platform === 'darwin') && await exists(path.join(vscode.workspace.rootPath!, 'node_modules', '.bin', 'tsc'))) {
return path.join('.', 'node_modules', '.bin', 'tsc');
} else {
return 'tsc';
}
}

private getActiveTypeScriptFile(): string | null {
const editor = vscode.window.activeTextEditor;
if (editor) {
const document = editor.document;
if (document && (document.languageId === 'typescript' || document.languageId === 'typescriptreact')) {
return this.client.normalizePath(document.uri);
}
}
return null;
}
}
3 changes: 3 additions & 0 deletions extensions/typescript/src/typescriptMain.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ import CodeActionProvider from './features/codeActionProvider';
import ReferenceCodeLensProvider from './features/referencesCodeLensProvider';
import { JsDocCompletionProvider, TryCompleteJsDocCommand } from './features/jsDocCompletionProvider';
import { DirectiveCommentCompletionProvider } from './features/directiveCommentCompletionProvider';
import TypeScriptTaskProvider from './features/taskProvider';

import ImplementationCodeLensProvider from './features/implementationsCodeLensProvider';

Expand Down Expand Up @@ -112,6 +113,8 @@ export function activate(context: ExtensionContext): void {
clientHost.serviceClient.restartTsServer();
}));

context.subscriptions.push(workspace.registerTaskProvider(new TypeScriptTaskProvider(client)));

const goToProjectConfig = (isTypeScript: boolean) => {
const editor = window.activeTextEditor;
if (editor) {
Expand Down
2 changes: 1 addition & 1 deletion src/vs/workbench/api/node/extHostTask.ts
Original file line number Diff line number Diff line change
Expand Up @@ -163,7 +163,7 @@ namespace ProblemMatcher {
if (values === void 0 || values === null) {
return undefined;
}
let result: (string | Problems.ProblemMatcher)[];
let result: (string | Problems.ProblemMatcher)[] = [];
for (let value of values) {
let converted = typeof value === 'string' ? value : fromSingle(value);
if (converted) {
Expand Down

0 comments on commit c3eec4e

Please sign in to comment.