diff --git a/extensions/ql-vscode/src/common/file-tree-nodes.ts b/extensions/ql-vscode/src/common/file-tree-nodes.ts index 3544265ca58..88a954e0e59 100644 --- a/extensions/ql-vscode/src/common/file-tree-nodes.ts +++ b/extensions/ql-vscode/src/common/file-tree-nodes.ts @@ -4,8 +4,12 @@ import { env } from "vscode"; /** * A node in the tree of files. This will be either a `FileTreeDirectory` or a `FileTreeLeaf`. */ -export abstract class FileTreeNode { - constructor(private _path: string, private _name: string) {} +export abstract class FileTreeNode { + constructor( + private _path: string, + private _name: string, + private _data?: T, + ) {} public get path(): string { return this._path; @@ -15,7 +19,11 @@ export abstract class FileTreeNode { return this._name; } - public abstract get children(): readonly FileTreeNode[]; + public get data(): T | undefined { + return this._data; + } + + public abstract get children(): ReadonlyArray>; public abstract finish(): void; } @@ -23,24 +31,24 @@ export abstract class FileTreeNode { /** * A directory containing one or more files or other directories. */ -export class FileTreeDirectory extends FileTreeNode { +export class FileTreeDirectory extends FileTreeNode { constructor( _path: string, _name: string, - private _children: FileTreeNode[] = [], + private _children: Array> = [], ) { super(_path, _name); } - public get children(): readonly FileTreeNode[] { + public get children(): ReadonlyArray> { return this._children; } - public addChild(child: FileTreeNode): void { + public addChild(child: FileTreeNode): void { this._children.push(child); } - public createDirectory(relativePath: string): FileTreeDirectory { + public createDirectory(relativePath: string): FileTreeDirectory { if (relativePath === ".") { return this; } @@ -66,7 +74,7 @@ export class FileTreeDirectory extends FileTreeNode { child.children[0] instanceof FileTreeDirectory ) { // collapse children - const replacement = new FileTreeDirectory( + const replacement = new FileTreeDirectory( child.children[0].path, `${child.name} / ${child.children[0].name}`, Array.from(child.children[0].children), @@ -76,12 +84,12 @@ export class FileTreeDirectory extends FileTreeNode { }); } - private createChildDirectory(name: string): FileTreeDirectory { + private createChildDirectory(name: string): FileTreeDirectory { const existingChild = this._children.find((child) => child.name === name); if (existingChild !== undefined) { - return existingChild as FileTreeDirectory; + return existingChild as FileTreeDirectory; } else { - const newChild = new FileTreeDirectory(join(this.path, name), name); + const newChild = new FileTreeDirectory(join(this.path, name), name); this.addChild(newChild); return newChild; } @@ -91,12 +99,12 @@ export class FileTreeDirectory extends FileTreeNode { /** * A single file. */ -export class FileTreeLeaf extends FileTreeNode { - constructor(_path: string, _name: string) { - super(_path, _name); +export class FileTreeLeaf extends FileTreeNode { + constructor(_path: string, _name: string, _data?: T) { + super(_path, _name, _data); } - public get children(): readonly FileTreeNode[] { + public get children(): ReadonlyArray> { return []; } diff --git a/extensions/ql-vscode/src/queries-panel/query-discovery.ts b/extensions/ql-vscode/src/queries-panel/query-discovery.ts index f7b25ea097b..3b19debe384 100644 --- a/extensions/ql-vscode/src/queries-panel/query-discovery.ts +++ b/extensions/ql-vscode/src/queries-panel/query-discovery.ts @@ -18,7 +18,7 @@ export interface QueryDiscoveryResults { * A tree of directories and query files. * May have multiple roots because of multiple workspaces. */ - queries: FileTreeDirectory[]; + queries: Array>; /** * File system paths to watch. If any ql file changes in these directories @@ -49,7 +49,7 @@ export class QueryDiscovery this.push(this.watcher.onDidChange(this.refresh.bind(this))); } - public get queries(): FileTreeDirectory[] | undefined { + public get queries(): Array> | undefined { return this.results?.queries; } @@ -97,7 +97,7 @@ export class QueryDiscovery */ private async discoverQueries( workspaceFolders: readonly WorkspaceFolder[], - ): Promise { + ): Promise>> { const rootDirectories = []; for (const workspaceFolder of workspaceFolders) { const root = await this.discoverQueriesInWorkspace(workspaceFolder); @@ -110,7 +110,7 @@ export class QueryDiscovery private async discoverQueriesInWorkspace( workspaceFolder: WorkspaceFolder, - ): Promise { + ): Promise | undefined> { const fullPath = workspaceFolder.uri.fsPath; const name = workspaceFolder.name; @@ -124,13 +124,13 @@ export class QueryDiscovery return undefined; } - const rootDirectory = new FileTreeDirectory(fullPath, name); + const rootDirectory = new FileTreeDirectory(fullPath, name); for (const queryPath of resolvedQueries) { const relativePath = normalize(relative(fullPath, queryPath)); const dirName = dirname(relativePath); const parentDirectory = rootDirectory.createDirectory(dirName); parentDirectory.addChild( - new FileTreeLeaf(queryPath, basename(queryPath)), + new FileTreeLeaf(queryPath, basename(queryPath), "language"), ); } diff --git a/extensions/ql-vscode/src/queries-panel/query-tree-data-provider.ts b/extensions/ql-vscode/src/queries-panel/query-tree-data-provider.ts index 0810ded8a63..b0bf7c79fd2 100644 --- a/extensions/ql-vscode/src/queries-panel/query-tree-data-provider.ts +++ b/extensions/ql-vscode/src/queries-panel/query-tree-data-provider.ts @@ -4,7 +4,7 @@ import { DisposableObject } from "../pure/disposable-object"; import { FileTreeNode } from "../common/file-tree-nodes"; export interface QueryDiscoverer { - readonly queries: FileTreeNode[] | undefined; + readonly queries: Array> | undefined; readonly onDidChangeQueries: Event; } @@ -40,11 +40,12 @@ export class QueryTreeDataProvider } private convertFileTreeNode( - fileTreeDirectory: FileTreeNode, + fileTreeDirectory: FileTreeNode, ): QueryTreeViewItem { return new QueryTreeViewItem( fileTreeDirectory.name, fileTreeDirectory.path, + fileTreeDirectory.data, fileTreeDirectory.children.map(this.convertFileTreeNode.bind(this)), ); } diff --git a/extensions/ql-vscode/src/queries-panel/query-tree-view-item.ts b/extensions/ql-vscode/src/queries-panel/query-tree-view-item.ts index 17caea32d63..8a14f8018dc 100644 --- a/extensions/ql-vscode/src/queries-panel/query-tree-view-item.ts +++ b/extensions/ql-vscode/src/queries-panel/query-tree-view-item.ts @@ -4,10 +4,12 @@ export class QueryTreeViewItem extends vscode.TreeItem { constructor( name: string, path: string, + language: string | undefined, public readonly children: QueryTreeViewItem[], ) { super(name); this.tooltip = path; + this.description = language; this.collapsibleState = this.children.length ? vscode.TreeItemCollapsibleState.Collapsed : vscode.TreeItemCollapsibleState.None; diff --git a/extensions/ql-vscode/test/vscode-tests/minimal-workspace/queries-panel/query-tree-data-provider.test.ts b/extensions/ql-vscode/test/vscode-tests/minimal-workspace/queries-panel/query-tree-data-provider.test.ts index 0805286893d..9719441518d 100644 --- a/extensions/ql-vscode/test/vscode-tests/minimal-workspace/queries-panel/query-tree-data-provider.test.ts +++ b/extensions/ql-vscode/test/vscode-tests/minimal-workspace/queries-panel/query-tree-data-provider.test.ts @@ -31,14 +31,22 @@ describe("QueryTreeDataProvider", () => { it("converts FileTreeNode to QueryTreeViewItem", async () => { const dataProvider = new QueryTreeDataProvider({ queries: [ - new FileTreeDirectory("dir1", "dir1", [ - new FileTreeDirectory("dir1/dir2", "dir2", [ - new FileTreeLeaf("dir1/dir2/file1", "file1"), - new FileTreeLeaf("dir1/dir2/file1", "file2"), + new FileTreeDirectory("dir1", "dir1", [ + new FileTreeDirectory("dir1/dir2", "dir2", [ + new FileTreeLeaf( + "dir1/dir2/file1", + "file1", + "javascript", + ), + new FileTreeLeaf( + "dir1/dir2/file1", + "file2", + "javascript", + ), ]), ]), - new FileTreeDirectory("dir3", "dir3", [ - new FileTreeLeaf("dir3/file3", "file3"), + new FileTreeDirectory("dir3", "dir3", [ + new FileTreeLeaf("dir3/file3", "file3", "javascript"), ]), ], onDidChangeQueries: jest.fn(), @@ -70,8 +78,8 @@ describe("QueryTreeDataProvider", () => { const onDidChangeQueriesEmitter = new EventEmitter(); const queryDiscoverer: QueryDiscoverer = { queries: [ - new FileTreeDirectory("dir1", "dir1", [ - new FileTreeLeaf("dir1/file1", "file1"), + new FileTreeDirectory("dir1", "dir1", [ + new FileTreeLeaf("dir1/file1", "file1", "javascript"), ]), ], onDidChangeQueries: onDidChangeQueriesEmitter.event, @@ -81,8 +89,8 @@ describe("QueryTreeDataProvider", () => { expect(dataProvider.getChildren().length).toEqual(1); queryDiscoverer.queries?.push( - new FileTreeDirectory("dir2", "dir2", [ - new FileTreeLeaf("dir2/file2", "file2"), + new FileTreeDirectory("dir2", "dir2", [ + new FileTreeLeaf("dir2/file2", "file2", "javascript"), ]), ); onDidChangeQueriesEmitter.fire();