Name updates.
This commit is contained in:
@@ -3,7 +3,7 @@ import { Disposable } from "../pure/disposable-object";
|
||||
import { AppEventEmitter } from "./events";
|
||||
import { Logger } from "./logging";
|
||||
import { Memento } from "./memento";
|
||||
import { ExtensionCommandManager } from "./commands";
|
||||
import { AppCommandManager } from "./commands";
|
||||
|
||||
export interface App {
|
||||
createEventEmitter<T>(): AppEventEmitter<T>;
|
||||
@@ -16,7 +16,7 @@ export interface App {
|
||||
readonly workspaceStoragePath?: string;
|
||||
readonly workspaceState: Memento;
|
||||
readonly credentials: Credentials;
|
||||
readonly commandManager: ExtensionCommandManager;
|
||||
readonly commands: AppCommandManager;
|
||||
}
|
||||
|
||||
export enum AppMode {
|
||||
|
||||
@@ -7,8 +7,8 @@ import { CommandManager } from "../packages/commands";
|
||||
* the implementation in the corresponding `getCommands` function.
|
||||
*/
|
||||
|
||||
// Commands directly in the extension
|
||||
export type ExtensionCommands = {
|
||||
// Base commands not tied directly to a module like e.g. variant analysis.
|
||||
export type BaseCommands = {
|
||||
"codeQL.openDocumentation": () => Promise<void>;
|
||||
};
|
||||
|
||||
@@ -19,6 +19,6 @@ export type VariantAnalysisCommands = {
|
||||
) => Promise<void>;
|
||||
};
|
||||
|
||||
export type AllCommands = ExtensionCommands & VariantAnalysisCommands;
|
||||
export type AllCommands = BaseCommands & VariantAnalysisCommands;
|
||||
|
||||
export type ExtensionCommandManager = CommandManager<AllCommands>;
|
||||
export type AppCommandManager = CommandManager<AllCommands>;
|
||||
|
||||
@@ -3,16 +3,23 @@ import { commandRunner } from "../../commandRunner";
|
||||
import { CommandFunction, CommandManager } from "../../packages/commands";
|
||||
|
||||
/**
|
||||
* Intializes a command manager for VSCode, wrapping the commandRunner
|
||||
* Create a command manager for VSCode, wrapping the commandRunner
|
||||
* and vscode.executeCommand.
|
||||
*/
|
||||
export function initializeVSCodeCommandManager<
|
||||
export function createVSCodeCommandManager<
|
||||
Commands extends Record<string, CommandFunction>,
|
||||
>(): CommandManager<Commands> {
|
||||
return new CommandManager(commandRunner, wrappedExecuteCommand);
|
||||
return new CommandManager(commandRunner, wrapExecuteCommand);
|
||||
}
|
||||
|
||||
async function wrappedExecuteCommand<
|
||||
/**
|
||||
* wrapExecuteCommand wraps commands.executeCommand to satisfy that the
|
||||
* type is a Promise. Type script does not seem to be smart enough
|
||||
* to figure out that `ReturnType<Commands[CommandName]>` is actually
|
||||
* a Promise, so we need to add a second layer of wrapping and unwrapping
|
||||
* (The `Promise<Awaited<` part) to get the right types.
|
||||
*/
|
||||
async function wrapExecuteCommand<
|
||||
Commands extends Record<string, CommandFunction>,
|
||||
CommandName extends keyof Commands & string = keyof Commands & string,
|
||||
>(
|
||||
|
||||
@@ -6,19 +6,19 @@ import { AppEventEmitter } from "../events";
|
||||
import { extLogger, Logger } from "../logging";
|
||||
import { Memento } from "../memento";
|
||||
import { VSCodeAppEventEmitter } from "./events";
|
||||
import { ExtensionCommandManager } from "../commands";
|
||||
import { initializeVSCodeCommandManager } from "./commands";
|
||||
import { AppCommandManager } from "../commands";
|
||||
import { createVSCodeCommandManager } from "./commands";
|
||||
|
||||
export class ExtensionApp implements App {
|
||||
public readonly credentials: VSCodeCredentials;
|
||||
public readonly commandManager: ExtensionCommandManager;
|
||||
public readonly commands: AppCommandManager;
|
||||
|
||||
public constructor(
|
||||
public readonly extensionContext: vscode.ExtensionContext,
|
||||
) {
|
||||
this.credentials = new VSCodeCredentials();
|
||||
this.commandManager = initializeVSCodeCommandManager();
|
||||
extensionContext.subscriptions.push(this.commandManager);
|
||||
this.commands = createVSCodeCommandManager();
|
||||
extensionContext.subscriptions.push(this.commands);
|
||||
}
|
||||
|
||||
public get extensionPath(): string {
|
||||
|
||||
@@ -136,7 +136,7 @@ import { RepositoriesFilterSortStateWithIds } from "./pure/variant-analysis-filt
|
||||
import { DbModule } from "./databases/db-module";
|
||||
import { redactableError } from "./pure/errors";
|
||||
import { QueryHistoryDirs } from "./query-history/query-history-dirs";
|
||||
import { AllCommands, ExtensionCommands } from "./common/commands";
|
||||
import { AllCommands, BaseCommands } from "./common/commands";
|
||||
|
||||
/**
|
||||
* extension.ts
|
||||
@@ -168,7 +168,10 @@ let isInstallingOrUpdatingDistribution = false;
|
||||
const extensionId = "GitHub.vscode-codeql";
|
||||
const extension = extensions.getExtension(extensionId);
|
||||
|
||||
function getCommands(): ExtensionCommands {
|
||||
/**
|
||||
* Return all commands that are not tied to the more specific managers.
|
||||
*/
|
||||
function getCommands(): BaseCommands {
|
||||
return {
|
||||
"codeQL.openDocumentation": async () => {
|
||||
await env.openExternal(Uri.parse("https://codeql.github.com/docs/"));
|
||||
@@ -1206,10 +1209,7 @@ async function activateWithInstalledDistribution(
|
||||
};
|
||||
|
||||
for (const [commandName, command] of Object.entries(allCommands)) {
|
||||
app.commandManager.registerCommand(
|
||||
commandName as keyof AllCommands,
|
||||
command,
|
||||
);
|
||||
app.commands.register(commandName as keyof AllCommands, command);
|
||||
}
|
||||
|
||||
ctx.subscriptions.push(
|
||||
|
||||
@@ -5,9 +5,7 @@
|
||||
* and then allow other parts to call those commands in a well-typed manner.
|
||||
*/
|
||||
|
||||
export interface Disposable {
|
||||
dispose(): void;
|
||||
}
|
||||
import { Disposable } from "./Disposable";
|
||||
|
||||
/**
|
||||
* A command function is a completely untyped command.
|
||||
@@ -32,7 +30,7 @@ export class CommandManager<
|
||||
constructor(
|
||||
private readonly commandRegister: <T extends CommandName>(
|
||||
commandName: T,
|
||||
definition: Commands[T],
|
||||
fn: Commands[T],
|
||||
) => Disposable,
|
||||
private readonly commandExecute: <T extends CommandName>(
|
||||
commandName: T,
|
||||
@@ -43,7 +41,7 @@ export class CommandManager<
|
||||
/**
|
||||
* Register a command with the specified name and implementation.
|
||||
*/
|
||||
registerCommand<T extends CommandName>(
|
||||
register<T extends CommandName>(
|
||||
commandName: T,
|
||||
definition: Commands[T],
|
||||
): void {
|
||||
@@ -53,7 +51,7 @@ export class CommandManager<
|
||||
/**
|
||||
* Execute a command with the specified name and the provided arguments.
|
||||
*/
|
||||
executeCommand<T extends CommandName>(
|
||||
execute<T extends CommandName>(
|
||||
commandName: T,
|
||||
...args: Parameters<Commands[T]>
|
||||
): Promise<Awaited<ReturnType<Commands[T]>>> {
|
||||
|
||||
7
extensions/ql-vscode/src/packages/commands/Disposable.ts
Normal file
7
extensions/ql-vscode/src/packages/commands/Disposable.ts
Normal file
@@ -0,0 +1,7 @@
|
||||
/**
|
||||
* This interface mirrors the vscode.Disaposable class, so that
|
||||
* the command manager does not depend on vscode directly.
|
||||
*/
|
||||
export interface Disposable {
|
||||
dispose(): void;
|
||||
}
|
||||
@@ -62,10 +62,7 @@ import { URLSearchParams } from "url";
|
||||
import { DbManager } from "../databases/db-manager";
|
||||
import { App } from "../common/app";
|
||||
import { redactableError } from "../pure/errors";
|
||||
import {
|
||||
ExtensionCommandManager,
|
||||
VariantAnalysisCommands,
|
||||
} from "../common/commands";
|
||||
import { AppCommandManager, VariantAnalysisCommands } from "../common/commands";
|
||||
|
||||
export class VariantAnalysisManager
|
||||
extends DisposableObject
|
||||
@@ -135,8 +132,8 @@ export class VariantAnalysisManager
|
||||
};
|
||||
}
|
||||
|
||||
get commandManager(): ExtensionCommandManager {
|
||||
return this.app.commandManager;
|
||||
get commandManager(): AppCommandManager {
|
||||
return this.app.commands;
|
||||
}
|
||||
|
||||
public async runVariantAnalysis(
|
||||
|
||||
@@ -2,7 +2,7 @@ import {
|
||||
VariantAnalysis,
|
||||
VariantAnalysisScannedRepositoryState,
|
||||
} from "./shared/variant-analysis";
|
||||
import { ExtensionCommandManager } from "../common/commands";
|
||||
import { AppCommandManager } from "../common/commands";
|
||||
|
||||
export interface VariantAnalysisViewInterface {
|
||||
variantAnalysisId: number;
|
||||
@@ -12,7 +12,7 @@ export interface VariantAnalysisViewInterface {
|
||||
export interface VariantAnalysisViewManager<
|
||||
T extends VariantAnalysisViewInterface,
|
||||
> {
|
||||
commandManager: ExtensionCommandManager;
|
||||
commandManager: AppCommandManager;
|
||||
|
||||
registerView(view: T): void;
|
||||
unregisterView(view: T): void;
|
||||
|
||||
@@ -145,7 +145,7 @@ export class VariantAnalysisView
|
||||
);
|
||||
break;
|
||||
case "openLogs":
|
||||
await this.manager.commandManager.executeCommand(
|
||||
await this.manager.commandManager.execute(
|
||||
"codeQL.openVariantAnalysisLogs",
|
||||
this.variantAnalysisId,
|
||||
);
|
||||
|
||||
@@ -6,7 +6,7 @@ import { createMockLogger } from "./loggerMock";
|
||||
import { createMockMemento } from "../mock-memento";
|
||||
import { testCredentialsWithStub } from "../factories/authentication";
|
||||
import { Credentials } from "../../src/common/authentication";
|
||||
import { ExtensionCommandManager } from "../../src/common/commands";
|
||||
import { AppCommandManager } from "../../src/common/commands";
|
||||
import { createMockCommandManager } from "./commandsMock";
|
||||
|
||||
export function createMockApp({
|
||||
@@ -17,7 +17,7 @@ export function createMockApp({
|
||||
executeCommand = jest.fn(() => Promise.resolve()),
|
||||
workspaceState = createMockMemento(),
|
||||
credentials = testCredentialsWithStub(),
|
||||
commandManager = createMockCommandManager(),
|
||||
commands = createMockCommandManager(),
|
||||
}: {
|
||||
extensionPath?: string;
|
||||
workspaceStoragePath?: string;
|
||||
@@ -26,7 +26,7 @@ export function createMockApp({
|
||||
executeCommand?: () => Promise<void>;
|
||||
workspaceState?: Memento;
|
||||
credentials?: Credentials;
|
||||
commandManager?: ExtensionCommandManager;
|
||||
commands?: AppCommandManager;
|
||||
}): App {
|
||||
return {
|
||||
mode: AppMode.Test,
|
||||
@@ -39,7 +39,7 @@ export function createMockApp({
|
||||
createEventEmitter,
|
||||
executeCommand,
|
||||
credentials,
|
||||
commandManager,
|
||||
commands,
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -1,9 +1,6 @@
|
||||
import { ExtensionCommandManager } from "../../src/common/commands";
|
||||
import {
|
||||
CommandFunction,
|
||||
CommandManager,
|
||||
Disposable,
|
||||
} from "../../src/packages/commands";
|
||||
import { AppCommandManager } from "../../src/common/commands";
|
||||
import { CommandFunction, CommandManager } from "../../src/packages/commands";
|
||||
import { Disposable } from "../../src/packages/commands/Disposable";
|
||||
|
||||
export function createMockCommandManager({
|
||||
registerCommand = jest.fn(),
|
||||
@@ -11,6 +8,6 @@ export function createMockCommandManager({
|
||||
}: {
|
||||
registerCommand?: (commandName: string, fn: CommandFunction) => Disposable;
|
||||
executeCommand?: (commandName: string, ...args: any[]) => Promise<any>;
|
||||
} = {}): ExtensionCommandManager {
|
||||
} = {}): AppCommandManager {
|
||||
return new CommandManager(registerCommand, executeCommand);
|
||||
}
|
||||
|
||||
@@ -11,7 +11,7 @@ describe("CommandManager", () => {
|
||||
jest.fn(),
|
||||
);
|
||||
const myCommand = jest.fn();
|
||||
commandManager.registerCommand("abc", myCommand);
|
||||
commandManager.register("abc", myCommand);
|
||||
expect(commandRegister).toHaveBeenCalledTimes(1);
|
||||
expect(commandRegister).toHaveBeenCalledWith("abc", myCommand);
|
||||
});
|
||||
@@ -28,22 +28,22 @@ describe("CommandManager", () => {
|
||||
);
|
||||
|
||||
// @ts-expect-error wrong command name should give a type error
|
||||
commandManager.registerCommand("abc", jest.fn());
|
||||
commandManager.register("abc", jest.fn());
|
||||
|
||||
commandManager.registerCommand(
|
||||
commandManager.register(
|
||||
"codeQL.openVariantAnalysisLogs",
|
||||
// @ts-expect-error wrong function parameter type should give a type error
|
||||
async (variantAnalysisId: string): Promise<number> => 10,
|
||||
);
|
||||
|
||||
commandManager.registerCommand(
|
||||
commandManager.register(
|
||||
"codeQL.openVariantAnalysisLogs",
|
||||
// @ts-expect-error wrong function return type should give a type error
|
||||
async (variantAnalysisId: number): Promise<string> => "hello",
|
||||
);
|
||||
|
||||
// Working types
|
||||
commandManager.registerCommand(
|
||||
commandManager.register(
|
||||
"codeQL.openVariantAnalysisLogs",
|
||||
async (variantAnalysisId: number): Promise<number> =>
|
||||
variantAnalysisId * 10,
|
||||
@@ -61,8 +61,8 @@ describe("CommandManager", () => {
|
||||
commandRegister,
|
||||
jest.fn(),
|
||||
);
|
||||
commandManager.registerCommand("abc", jest.fn());
|
||||
commandManager.registerCommand("def", jest.fn());
|
||||
commandManager.register("abc", jest.fn());
|
||||
commandManager.register("def", jest.fn());
|
||||
expect(dispose1).not.toHaveBeenCalled();
|
||||
expect(dispose2).not.toHaveBeenCalled();
|
||||
commandManager.dispose();
|
||||
@@ -76,7 +76,7 @@ describe("CommandManager", () => {
|
||||
jest.fn(),
|
||||
commandExecute,
|
||||
);
|
||||
const result = await commandManager.executeCommand("abc", "hello", true);
|
||||
const result = await commandManager.execute("abc", "hello", true);
|
||||
expect(result).toEqual(7);
|
||||
expect(commandExecute).toHaveBeenCalledTimes(1);
|
||||
expect(commandExecute).toHaveBeenCalledWith("abc", "hello", true);
|
||||
@@ -94,18 +94,18 @@ describe("CommandManager", () => {
|
||||
);
|
||||
|
||||
// @ts-expect-error wrong command name should give a type error
|
||||
await commandManager.executeCommand("abc", 4);
|
||||
await commandManager.execute("abc", 4);
|
||||
|
||||
await commandManager.executeCommand(
|
||||
await commandManager.execute(
|
||||
"codeQL.openVariantAnalysisLogs",
|
||||
// @ts-expect-error wrong argument type should give a type error
|
||||
"xyz",
|
||||
);
|
||||
|
||||
// @ts-expect-error wrong number of arguments should give a type error
|
||||
await commandManager.executeCommand("codeQL.openVariantAnalysisLogs", 2, 3);
|
||||
await commandManager.execute("codeQL.openVariantAnalysisLogs", 2, 3);
|
||||
|
||||
// Working types
|
||||
await commandManager.executeCommand("codeQL.openVariantAnalysisLogs", 7);
|
||||
await commandManager.execute("codeQL.openVariantAnalysisLogs", 7);
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user