added npmExplorer

This commit is contained in:
Erich Gamma
2018-03-27 22:28:29 +02:00
parent 406b33ab08
commit 526a88aeb0
6 changed files with 251 additions and 6 deletions

View File

@@ -14,11 +14,22 @@ import * as minimatch from 'minimatch';
const localize = nls.loadMessageBundle();
import { addJSONProviders } from './features/jsonContributions';
import { NpmScriptsTreeDataProvider } from './npmView';
import { NpmTaskDefinition, ScriptValidator } from './tasks';
type AutoDetect = 'on' | 'off';
let taskProvider: vscode.Disposable | undefined;
class Validator implements ScriptValidator {
async scriptIsValid(_task: vscode.Task): Promise<boolean> {
// let tasks = await provideNpmScriptsForFolder(packageUri);
return true;
}
}
export function activate(context: vscode.ExtensionContext): void {
vscode.window.registerTreeDataProvider('npm', new NpmScriptsTreeDataProvider(context, new Validator()));
if (!vscode.workspace.workspaceFolders) {
return;
}
@@ -67,11 +78,6 @@ async function readFile(file: string): Promise<string> {
});
}
interface NpmTaskDefinition extends vscode.TaskDefinition {
script: string;
path?: string;
}
const buildNames: string[] = ['build', 'compile', 'watch'];
function isBuildTask(name: string): boolean {
for (let buildName of buildNames) {

View File

@@ -0,0 +1,177 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import {
ExtensionContext, Task, TreeDataProvider, TreeItem, TreeItemCollapsibleState,
WorkspaceFolder, workspace, commands, window, EventEmitter, Event,
ThemeIcon, Uri, TextDocument
} from 'vscode';
import { NpmTaskDefinition, ScriptValidator } from './tasks';
import * as path from 'path';
class Folder extends TreeItem {
packages: PackageJSON[] = [];
constructor(folder: WorkspaceFolder) {
super(folder.name, TreeItemCollapsibleState.Collapsed);
this.contextValue = 'folder';
this.resourceUri = folder.uri;
this.iconPath = ThemeIcon.Folder;
}
addPackage(packageJson: PackageJSON) {
this.packages.push(packageJson);
}
}
const packageName = 'package.json';
class PackageJSON extends TreeItem {
path: string;
folder: Folder;
scripts: NpmScript[] = [];
static getLabel(folderName: string, relativePath: string): string {
if (relativePath.length > 0) {
return path.join(relativePath, packageName);
}
return path.join(folderName, packageName);
}
constructor(folder: Folder, relativePath: string) {
super(PackageJSON.getLabel(folder.label!, relativePath), TreeItemCollapsibleState.Collapsed);
this.folder = folder;
this.path = relativePath;
this.contextValue = 'packageJSON';
this.resourceUri = Uri.file(path.join(folder!.resourceUri!.fsPath, relativePath, packageName));
this.iconPath = ThemeIcon.File;
}
addScript(script: NpmScript) {
this.scripts.push(script);
}
}
class NpmScript extends TreeItem {
task: Task;
package: PackageJSON;
constructor(packageJson: PackageJSON, task: Task) {
super(task.name, TreeItemCollapsibleState.None);
this.contextValue = 'script';
this.package = packageJson;
this.task = task;
this.command = {
title: 'Run Script',
command: 'npm.runScript',
arguments: [task]
};
}
}
export class NpmScriptsTreeDataProvider implements TreeDataProvider<TreeItem> {
private taskTree: Folder[] | PackageJSON[] | null = null;
private validator: ScriptValidator;
private _onDidChangeTreeData: EventEmitter<TreeItem | null> = new EventEmitter<TreeItem | null>();
readonly onDidChangeTreeData: Event<TreeItem | null> = this._onDidChangeTreeData.event;
constructor(context: ExtensionContext, validator: ScriptValidator) {
const subscriptions = context.subscriptions;
this.validator = validator;
subscriptions.push(commands.registerCommand('npm.runScript', this.runScript, this));
subscriptions.push(commands.registerCommand('npm.openScript', this.openScript, this));
subscriptions.push(commands.registerCommand('npm.refresh', this.refresh, this));
}
private runScript(task: Task) {
if (!this.validator.scriptIsValid(task)) {
window.showErrorMessage(`Could not find script ${task.name}`);
return;
}
workspace.executeTask(task);
}
private async openScript(packageJSON: PackageJSON) {
let document: TextDocument = await workspace.openTextDocument(packageJSON.resourceUri!);
window.showTextDocument(document);
}
private refresh() {
this.taskTree = null;
this._onDidChangeTreeData.fire();
}
getTreeItem(element: TreeItem): TreeItem {
return element;
}
getParent(element: TreeItem): TreeItem | null {
if (element instanceof Folder) {
return null;
}
if (element instanceof PackageJSON) {
return element.folder;
}
if (element instanceof NpmScript) {
return element.package;
}
return null;
}
async getChildren(element?: TreeItem): Promise<TreeItem[]> {
if (!this.taskTree) {
let tasks = await workspace.fetchTasks();
let npmTasks = tasks.filter(each => each.definition.type === 'npm');
this.taskTree = this.buildTaskTree(npmTasks);
}
if (element instanceof Folder) {
return element.packages;
}
if (element instanceof PackageJSON) {
return element.scripts;
}
if (element instanceof NpmScript) {
return [];
}
return this.taskTree;
}
private isWorkspaceFolder(value: any): value is WorkspaceFolder {
return value && typeof value !== 'number';
}
private buildTaskTree(tasks: Task[]): Folder[] | PackageJSON[] {
let folders: Map<String, Folder> = new Map();
let packages: Map<String, PackageJSON> = new Map();
let folder = null;
let packageJson = null;
tasks.forEach(each => {
if (this.isWorkspaceFolder(each.scope)) {
folder = folders.get(each.scope.name);
if (!folder) {
folder = new Folder(each.scope);
folders.set(each.scope.name, folder);
}
let definition: NpmTaskDefinition = <NpmTaskDefinition>each.definition;
let path = definition.path ? definition.path : '';
packageJson = packages.get(path);
if (!packageJson) {
packageJson = new PackageJSON(folder, path);
folder.addPackage(packageJson);
packages.set(path, packageJson);
}
let script = new NpmScript(packageJson, each);
packageJson.addScript(script);
}
});
if (folders.size === 1) {
return [...packages.values()];
}
return [...folders.values()];
}
}

View File

@@ -0,0 +1,15 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { TaskDefinition, Task } from 'vscode';
export interface NpmTaskDefinition extends TaskDefinition {
script: string;
path?: string;
}
export interface ScriptValidator {
scriptIsValid(task: Task): Promise<boolean>;
}