From 7176f690f3c6785121ebc738edd34c2299ddc2af Mon Sep 17 00:00:00 2001 From: Robert Date: Mon, 6 Mar 2023 10:56:27 +0000 Subject: [PATCH 001/156] Add listeners for unhandled errors to web views --- .../ql-vscode/src/compare/compare-view.ts | 10 ++++ extensions/ql-vscode/src/interface.ts | 7 +++ extensions/ql-vscode/src/pure/errors.ts | 24 +++++++-- .../ql-vscode/src/pure/interface-types.ts | 15 ++++-- .../variant-analysis/variant-analysis-view.ts | 13 ++++- .../ql-vscode/src/view/common/errors.ts | 51 +++++++++++++++++++ .../ql-vscode/src/view/compare/Compare.tsx | 3 ++ .../ql-vscode/src/view/results/results.tsx | 6 +++ .../view/variant-analysis/VariantAnalysis.tsx | 3 ++ 9 files changed, 124 insertions(+), 8 deletions(-) create mode 100644 extensions/ql-vscode/src/view/common/errors.ts diff --git a/extensions/ql-vscode/src/compare/compare-view.ts b/extensions/ql-vscode/src/compare/compare-view.ts index 46c35562a..9ffa224a4 100644 --- a/extensions/ql-vscode/src/compare/compare-view.ts +++ b/extensions/ql-vscode/src/compare/compare-view.ts @@ -20,6 +20,8 @@ import { assertNever, getErrorMessage } from "../pure/helpers-pure"; import { HistoryItemLabelProvider } from "../query-history/history-item-label-provider"; import { AbstractWebview, WebviewPanelConfig } from "../abstract-webview"; import { telemetryListener } from "../telemetry"; +import { redactableError } from "../pure/errors"; +import { showAndLogExceptionWithTelemetry } from "../helpers"; interface ComparePair { from: CompletedLocalQueryInfo; @@ -139,6 +141,14 @@ export class CompareView extends AbstractWebview< telemetryListener?.sendUIInteraction(msg.action); break; + case "unhandledError": + void showAndLogExceptionWithTelemetry( + redactableError( + msg.error, + )`Unhandled error in result comparison view: ${msg.error.message}`, + ); + break; + default: assertNever(msg); } diff --git a/extensions/ql-vscode/src/interface.ts b/extensions/ql-vscode/src/interface.ts index 17655fa7c..055008e1d 100644 --- a/extensions/ql-vscode/src/interface.ts +++ b/extensions/ql-vscode/src/interface.ts @@ -295,6 +295,13 @@ export class ResultsView extends AbstractWebview< case "telemetry": telemetryListener?.sendUIInteraction(msg.action); break; + case "unhandledError": + void showAndLogExceptionWithTelemetry( + redactableError( + msg.error, + )`Unhandled error in results view: ${msg.error.message}`, + ); + break; default: assertNever(msg); } diff --git a/extensions/ql-vscode/src/pure/errors.ts b/extensions/ql-vscode/src/pure/errors.ts index dd42ebd74..50990daa6 100644 --- a/extensions/ql-vscode/src/pure/errors.ts +++ b/extensions/ql-vscode/src/pure/errors.ts @@ -1,6 +1,6 @@ export class RedactableError extends Error { constructor( - cause: Error | undefined, + cause: ErrorLike | undefined, private readonly strings: TemplateStringsArray, private readonly values: unknown[], ) { @@ -54,19 +54,35 @@ export function redactableError( ...values: unknown[] ): RedactableError; export function redactableError( - error: Error, + error: ErrorLike, ): (strings: TemplateStringsArray, ...values: unknown[]) => RedactableError; export function redactableError( - errorOrStrings: Error | TemplateStringsArray, + errorOrStrings: ErrorLike | TemplateStringsArray, ...values: unknown[] ): | ((strings: TemplateStringsArray, ...values: unknown[]) => RedactableError) | RedactableError { - if (errorOrStrings instanceof Error) { + if (isErrorLike(errorOrStrings)) { return (strings: TemplateStringsArray, ...values: unknown[]) => new RedactableError(errorOrStrings, strings, values); } else { return new RedactableError(undefined, errorOrStrings, values); } } + +export interface ErrorLike { + message: string; + stack?: string; +} + +function isErrorLike(error: any): error is ErrorLike { + if ( + error.message !== undefined && + typeof error.message === "string" && + (error.stack === undefined || typeof error.stack === "string") + ) { + return true; + } + return false; +} diff --git a/extensions/ql-vscode/src/pure/interface-types.ts b/extensions/ql-vscode/src/pure/interface-types.ts index bbc4b0903..38810275d 100644 --- a/extensions/ql-vscode/src/pure/interface-types.ts +++ b/extensions/ql-vscode/src/pure/interface-types.ts @@ -12,6 +12,7 @@ import { VariantAnalysisScannedRepositoryState, } from "../variant-analysis/shared/variant-analysis"; import { RepositoriesFilterSortStateWithIds } from "./variant-analysis-filter-sort"; +import { ErrorLike } from "./errors"; /** * This module contains types and code that are shared between @@ -189,7 +190,8 @@ export type FromResultsViewMsg = | ViewLoadedMsg | ChangePage | OpenFileMsg - | TelemetryMessage; + | TelemetryMessage + | UnhandledErrorMessage; /** * Message from the results view to open a database source @@ -291,7 +293,8 @@ export type FromCompareViewMessage = | ChangeCompareMessage | ViewSourceFileMsg | OpenQueryMessage - | TelemetryMessage; + | TelemetryMessage + | UnhandledErrorMessage; /** * Message from the compare view to request opening a query. @@ -439,6 +442,11 @@ export interface TelemetryMessage { action: string; } +export interface UnhandledErrorMessage { + t: "unhandledError"; + error: ErrorLike; +} + export type ToVariantAnalysisMessage = | SetVariantAnalysisMessage | SetRepoResultsMessage @@ -453,4 +461,5 @@ export type FromVariantAnalysisMessage = | ExportResultsMessage | OpenLogsMessage | CancelVariantAnalysisMessage - | TelemetryMessage; + | TelemetryMessage + | UnhandledErrorMessage; diff --git a/extensions/ql-vscode/src/variant-analysis/variant-analysis-view.ts b/extensions/ql-vscode/src/variant-analysis/variant-analysis-view.ts index e41a85205..7b3f16a9a 100644 --- a/extensions/ql-vscode/src/variant-analysis/variant-analysis-view.ts +++ b/extensions/ql-vscode/src/variant-analysis/variant-analysis-view.ts @@ -15,8 +15,12 @@ import { VariantAnalysisViewInterface, VariantAnalysisViewManager, } from "./variant-analysis-view-manager"; -import { showAndLogWarningMessage } from "../helpers"; +import { + showAndLogExceptionWithTelemetry, + showAndLogWarningMessage, +} from "../helpers"; import { telemetryListener } from "../telemetry"; +import { redactableError } from "../pure/errors"; export class VariantAnalysisView extends AbstractWebview @@ -153,6 +157,13 @@ export class VariantAnalysisView case "telemetry": telemetryListener?.sendUIInteraction(msg.action); break; + case "unhandledError": + void showAndLogExceptionWithTelemetry( + redactableError( + msg.error, + )`Unhandled error in variant analysis results view: ${msg.error.message}`, + ); + break; default: assertNever(msg); } diff --git a/extensions/ql-vscode/src/view/common/errors.ts b/extensions/ql-vscode/src/view/common/errors.ts new file mode 100644 index 000000000..f74132ca4 --- /dev/null +++ b/extensions/ql-vscode/src/view/common/errors.ts @@ -0,0 +1,51 @@ +import { useEffect } from "react"; +import { getErrorMessage, getErrorStack } from "../../pure/helpers-pure"; +import { vscode } from "../vscode-api"; + +const unhandledErrorListener = (event: ErrorEvent) => { + vscode.postMessage({ + t: "unhandledError", + error: { + message: getErrorMessage(event.error), + stack: getErrorStack(event.error), + }, + }); +}; + +const unhandledRejectionListener = (event: PromiseRejectionEvent) => { + vscode.postMessage({ + t: "unhandledError", + error: { + message: getErrorMessage(event.reason), + stack: getErrorStack(event.reason), + }, + }); +}; + +/** + * A react effect that handles adding listeners for unhandled errors / rejected promises. + * When an error is detected a "unhandledError" message is posted to the view. + */ +export function useUnhandledErrorListener() { + useEffect(() => { + registerUnhandledErrorListener(); + return unregisterUnhandledErrorListener; + }, []); +} + +/** + * Adds listeners for unhandled errors / rejected promises. + * When an error is detected a "unhandledError" message is posted to the view. + */ +export function registerUnhandledErrorListener() { + window.addEventListener("error", unhandledErrorListener); + window.addEventListener("unhandledrejection", unhandledRejectionListener); +} + +/** + * Remove listeners for unhandled errors / rejected promises. + */ +export function unregisterUnhandledErrorListener() { + window.removeEventListener("error", unhandledErrorListener); + window.removeEventListener("unhandledrejection", unhandledRejectionListener); +} diff --git a/extensions/ql-vscode/src/view/compare/Compare.tsx b/extensions/ql-vscode/src/view/compare/Compare.tsx index 00aef5449..ce07d9085 100644 --- a/extensions/ql-vscode/src/view/compare/Compare.tsx +++ b/extensions/ql-vscode/src/view/compare/Compare.tsx @@ -10,6 +10,7 @@ import { vscode } from "../vscode-api"; import CompareTable from "./CompareTable"; import "../results/resultsView.css"; +import { useUnhandledErrorListener } from "../common/errors"; const emptyComparison: SetComparisonsMessage = { t: "setComparisons", @@ -23,6 +24,8 @@ const emptyComparison: SetComparisonsMessage = { }; export function Compare(_: Record): JSX.Element { + useUnhandledErrorListener(); + const [comparison, setComparison] = useState(emptyComparison); diff --git a/extensions/ql-vscode/src/view/results/results.tsx b/extensions/ql-vscode/src/view/results/results.tsx index 9d900ee7b..88ba264a5 100644 --- a/extensions/ql-vscode/src/view/results/results.tsx +++ b/extensions/ql-vscode/src/view/results/results.tsx @@ -14,6 +14,10 @@ import { NavigateMsg, ResultSet, } from "../../pure/interface-types"; +import { + registerUnhandledErrorListener, + unregisterUnhandledErrorListener, +} from "../common/errors"; import { EventHandlers as EventHandlerList } from "./event-handler-list"; import { ResultTables } from "./result-tables"; @@ -307,12 +311,14 @@ export class ResultsApp extends React.Component< componentDidMount(): void { this.vscodeMessageHandler = this.vscodeMessageHandler.bind(this); window.addEventListener("message", this.vscodeMessageHandler); + registerUnhandledErrorListener(); } componentWillUnmount(): void { if (this.vscodeMessageHandler) { window.removeEventListener("message", this.vscodeMessageHandler); } + unregisterUnhandledErrorListener(); } private vscodeMessageHandler(evt: MessageEvent) { diff --git a/extensions/ql-vscode/src/view/variant-analysis/VariantAnalysis.tsx b/extensions/ql-vscode/src/view/variant-analysis/VariantAnalysis.tsx index cf4a0df25..704ae2e31 100644 --- a/extensions/ql-vscode/src/view/variant-analysis/VariantAnalysis.tsx +++ b/extensions/ql-vscode/src/view/variant-analysis/VariantAnalysis.tsx @@ -14,6 +14,7 @@ import { ToVariantAnalysisMessage } from "../../pure/interface-types"; import { vscode } from "../vscode-api"; import { defaultFilterSortState } from "../../pure/variant-analysis-filter-sort"; import { useTelemetryOnChange } from "../common/telemetry"; +import { useUnhandledErrorListener } from "../common/errors"; export type VariantAnalysisProps = { variantAnalysis?: VariantAnalysisDomainModel; @@ -50,6 +51,8 @@ export function VariantAnalysis({ repoStates: initialRepoStates = [], repoResults: initialRepoResults = [], }: VariantAnalysisProps): JSX.Element { + useUnhandledErrorListener(); + const [variantAnalysis, setVariantAnalysis] = useState< VariantAnalysisDomainModel | undefined >(initialVariantAnalysis); From d8c2562bb1d013a807d4d6c0c212f285e3f930e9 Mon Sep 17 00:00:00 2001 From: Robert Date: Tue, 7 Mar 2023 15:05:49 +0000 Subject: [PATCH 002/156] Move listener registration to webview.tsx --- .../ql-vscode/src/view/common/errors.ts | 20 ------------------- .../ql-vscode/src/view/compare/Compare.tsx | 3 --- .../ql-vscode/src/view/results/results.tsx | 6 ------ .../view/variant-analysis/VariantAnalysis.tsx | 3 --- extensions/ql-vscode/src/view/webview.tsx | 3 +++ 5 files changed, 3 insertions(+), 32 deletions(-) diff --git a/extensions/ql-vscode/src/view/common/errors.ts b/extensions/ql-vscode/src/view/common/errors.ts index f74132ca4..d4eb11192 100644 --- a/extensions/ql-vscode/src/view/common/errors.ts +++ b/extensions/ql-vscode/src/view/common/errors.ts @@ -1,4 +1,3 @@ -import { useEffect } from "react"; import { getErrorMessage, getErrorStack } from "../../pure/helpers-pure"; import { vscode } from "../vscode-api"; @@ -22,17 +21,6 @@ const unhandledRejectionListener = (event: PromiseRejectionEvent) => { }); }; -/** - * A react effect that handles adding listeners for unhandled errors / rejected promises. - * When an error is detected a "unhandledError" message is posted to the view. - */ -export function useUnhandledErrorListener() { - useEffect(() => { - registerUnhandledErrorListener(); - return unregisterUnhandledErrorListener; - }, []); -} - /** * Adds listeners for unhandled errors / rejected promises. * When an error is detected a "unhandledError" message is posted to the view. @@ -41,11 +29,3 @@ export function registerUnhandledErrorListener() { window.addEventListener("error", unhandledErrorListener); window.addEventListener("unhandledrejection", unhandledRejectionListener); } - -/** - * Remove listeners for unhandled errors / rejected promises. - */ -export function unregisterUnhandledErrorListener() { - window.removeEventListener("error", unhandledErrorListener); - window.removeEventListener("unhandledrejection", unhandledRejectionListener); -} diff --git a/extensions/ql-vscode/src/view/compare/Compare.tsx b/extensions/ql-vscode/src/view/compare/Compare.tsx index ce07d9085..00aef5449 100644 --- a/extensions/ql-vscode/src/view/compare/Compare.tsx +++ b/extensions/ql-vscode/src/view/compare/Compare.tsx @@ -10,7 +10,6 @@ import { vscode } from "../vscode-api"; import CompareTable from "./CompareTable"; import "../results/resultsView.css"; -import { useUnhandledErrorListener } from "../common/errors"; const emptyComparison: SetComparisonsMessage = { t: "setComparisons", @@ -24,8 +23,6 @@ const emptyComparison: SetComparisonsMessage = { }; export function Compare(_: Record): JSX.Element { - useUnhandledErrorListener(); - const [comparison, setComparison] = useState(emptyComparison); diff --git a/extensions/ql-vscode/src/view/results/results.tsx b/extensions/ql-vscode/src/view/results/results.tsx index 88ba264a5..9d900ee7b 100644 --- a/extensions/ql-vscode/src/view/results/results.tsx +++ b/extensions/ql-vscode/src/view/results/results.tsx @@ -14,10 +14,6 @@ import { NavigateMsg, ResultSet, } from "../../pure/interface-types"; -import { - registerUnhandledErrorListener, - unregisterUnhandledErrorListener, -} from "../common/errors"; import { EventHandlers as EventHandlerList } from "./event-handler-list"; import { ResultTables } from "./result-tables"; @@ -311,14 +307,12 @@ export class ResultsApp extends React.Component< componentDidMount(): void { this.vscodeMessageHandler = this.vscodeMessageHandler.bind(this); window.addEventListener("message", this.vscodeMessageHandler); - registerUnhandledErrorListener(); } componentWillUnmount(): void { if (this.vscodeMessageHandler) { window.removeEventListener("message", this.vscodeMessageHandler); } - unregisterUnhandledErrorListener(); } private vscodeMessageHandler(evt: MessageEvent) { diff --git a/extensions/ql-vscode/src/view/variant-analysis/VariantAnalysis.tsx b/extensions/ql-vscode/src/view/variant-analysis/VariantAnalysis.tsx index 704ae2e31..cf4a0df25 100644 --- a/extensions/ql-vscode/src/view/variant-analysis/VariantAnalysis.tsx +++ b/extensions/ql-vscode/src/view/variant-analysis/VariantAnalysis.tsx @@ -14,7 +14,6 @@ import { ToVariantAnalysisMessage } from "../../pure/interface-types"; import { vscode } from "../vscode-api"; import { defaultFilterSortState } from "../../pure/variant-analysis-filter-sort"; import { useTelemetryOnChange } from "../common/telemetry"; -import { useUnhandledErrorListener } from "../common/errors"; export type VariantAnalysisProps = { variantAnalysis?: VariantAnalysisDomainModel; @@ -51,8 +50,6 @@ export function VariantAnalysis({ repoStates: initialRepoStates = [], repoResults: initialRepoResults = [], }: VariantAnalysisProps): JSX.Element { - useUnhandledErrorListener(); - const [variantAnalysis, setVariantAnalysis] = useState< VariantAnalysisDomainModel | undefined >(initialVariantAnalysis); diff --git a/extensions/ql-vscode/src/view/webview.tsx b/extensions/ql-vscode/src/view/webview.tsx index 72d084a44..8b736dd90 100644 --- a/extensions/ql-vscode/src/view/webview.tsx +++ b/extensions/ql-vscode/src/view/webview.tsx @@ -5,8 +5,11 @@ import { WebviewDefinition } from "./webview-definition"; // Allow all views to use Codicons import "@vscode/codicons/dist/codicon.css"; +import { registerUnhandledErrorListener } from "./common/errors"; const render = () => { + registerUnhandledErrorListener(); + const element = document.getElementById("root"); if (!element) { From d87911a8037e797c2e24b6eafeb0ea0a02de36b8 Mon Sep 17 00:00:00 2001 From: Anders Starcke Henriksen Date: Thu, 9 Mar 2023 14:15:27 +0100 Subject: [PATCH 003/156] Basic implementation of command manager. --- .../src/packages/commands/CommandManager.ts | 48 +++++++- .../packages/commands/CommandManager.test.ts | 113 +++++++++++++++++- 2 files changed, 155 insertions(+), 6 deletions(-) diff --git a/extensions/ql-vscode/src/packages/commands/CommandManager.ts b/extensions/ql-vscode/src/packages/commands/CommandManager.ts index c0b1d38f2..c67f3bb7b 100644 --- a/extensions/ql-vscode/src/packages/commands/CommandManager.ts +++ b/extensions/ql-vscode/src/packages/commands/CommandManager.ts @@ -1 +1,47 @@ -export class CommandManager {} +export interface Disposable { + dispose(): void; +} + +export type CommandFunction = (...args: any[]) => Promise; + +export class CommandManager< + Commands extends Record, + CommandName extends keyof Commands & string = keyof Commands & string, +> implements Disposable +{ + // TODO: should this be a map? + // TODO: handle multiple command names + private commands: Disposable[] = []; + + constructor( + private readonly commandRegister: ( + commandName: T, + definition: Commands[T], + ) => Disposable, + private readonly commandExecute: ( + commandName: T, + ...args: Parameters + ) => Promise>, + ) {} + + registerCommand( + commandName: T, + definition: Commands[T], + ): void { + this.commands.push(this.commandRegister(commandName, definition)); + } + + executeCommand( + commandName: T, + ...args: Parameters + ): Promise> { + return this.commandExecute(commandName, ...args); + } + + dispose(): void { + this.commands.forEach((cmd) => { + cmd.dispose(); + }); + this.commands = []; + } +} diff --git a/extensions/ql-vscode/test/unit-tests/packages/commands/CommandManager.test.ts b/extensions/ql-vscode/test/unit-tests/packages/commands/CommandManager.test.ts index 40b78d932..3d7f05fbb 100644 --- a/extensions/ql-vscode/test/unit-tests/packages/commands/CommandManager.test.ts +++ b/extensions/ql-vscode/test/unit-tests/packages/commands/CommandManager.test.ts @@ -1,8 +1,111 @@ -import { CommandManager } from "../../../../src/packages/commands"; +import { + CommandFunction, + CommandManager, +} from "../../../../src/packages/commands"; -describe(CommandManager.name, () => { - it("can create a command manager", () => { - const commandManager = new CommandManager(); - expect(commandManager).not.toBeUndefined(); +describe("CommandManager", () => { + it("can register a command", () => { + const commandRegister = jest.fn(); + const commandManager = new CommandManager>( + commandRegister, + jest.fn(), + ); + const myCommand = jest.fn(); + commandManager.registerCommand("abc", myCommand); + expect(commandRegister).toHaveBeenCalledTimes(1); + expect(commandRegister).toHaveBeenCalledWith("abc", myCommand); + }); + + it("can register typed commands", async () => { + const commands = { + "codeQL.openVariantAnalysisLogs": async (variantAnalysisId: number) => { + return variantAnalysisId * 10; + }, + }; + const commandManager = new CommandManager( + jest.fn(), + jest.fn(), + ); + + // @ts-expect-error wrong command name should give a type error + commandManager.registerCommand("abc", jest.fn()); + + commandManager.registerCommand( + "codeQL.openVariantAnalysisLogs", + // @ts-expect-error wrong function parameter type should give a type error + async (variantAnalysisId: string): Promise => 10, + ); + + commandManager.registerCommand( + "codeQL.openVariantAnalysisLogs", + // @ts-expect-error wrong function return type should give a type error + async (variantAnalysisId: number): Promise => "hello", + ); + + // Working types + commandManager.registerCommand( + "codeQL.openVariantAnalysisLogs", + async (variantAnalysisId: number): Promise => + variantAnalysisId * 10, + ); + }); + + it("can dispose of its commands", () => { + const dispose1 = jest.fn(); + const dispose2 = jest.fn(); + const commandRegister = jest + .fn() + .mockReturnValueOnce({ dispose: dispose1 }) + .mockReturnValueOnce({ dispose: dispose2 }); + const commandManager = new CommandManager>( + commandRegister, + jest.fn(), + ); + commandManager.registerCommand("abc", jest.fn()); + commandManager.registerCommand("def", jest.fn()); + expect(dispose1).not.toHaveBeenCalled(); + expect(dispose2).not.toHaveBeenCalled(); + commandManager.dispose(); + expect(dispose1).toHaveBeenCalledTimes(1); + expect(dispose2).toHaveBeenCalledTimes(1); + }); + + it("can execute a command", async () => { + const commandExecute = jest.fn().mockReturnValue(7); + const commandManager = new CommandManager>( + jest.fn(), + commandExecute, + ); + const result = await commandManager.executeCommand("abc", "hello", true); + expect(result).toEqual(7); + expect(commandExecute).toHaveBeenCalledTimes(1); + expect(commandExecute).toHaveBeenCalledWith("abc", "hello", true); + }); + + it("can execute typed commands", async () => { + const commands = { + "codeQL.openVariantAnalysisLogs": async (variantAnalysisId: number) => { + return variantAnalysisId * 10; + }, + }; + const commandManager = new CommandManager( + jest.fn(), + jest.fn(), + ); + + // @ts-expect-error wrong command name should give a type error + await commandManager.executeCommand("abc", 4); + + await commandManager.executeCommand( + "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); + + // Working types + await commandManager.executeCommand("codeQL.openVariantAnalysisLogs", 7); }); }); From 61974a7664fd00e438c87977f51551a7a5167c49 Mon Sep 17 00:00:00 2001 From: Anders Starcke Henriksen Date: Thu, 9 Mar 2023 15:31:02 +0100 Subject: [PATCH 004/156] Register concrete command from extension. --- extensions/ql-vscode/src/commands.ts | 28 +++++++++++++++++++ extensions/ql-vscode/src/extension.ts | 27 ++++++++++++++++++ .../src/packages/commands/CommandManager.ts | 4 +-- 3 files changed, 57 insertions(+), 2 deletions(-) create mode 100644 extensions/ql-vscode/src/commands.ts diff --git a/extensions/ql-vscode/src/commands.ts b/extensions/ql-vscode/src/commands.ts new file mode 100644 index 000000000..e0e0f7ca0 --- /dev/null +++ b/extensions/ql-vscode/src/commands.ts @@ -0,0 +1,28 @@ +import { commands } from "vscode"; +import { commandRunner } from "./commandRunner"; +import { CommandFunction, CommandManager } from "./packages/commands"; + +export function initializeVSCodeCommandManager< + Commands extends Record, +>(): CommandManager { + return new CommandManager(commandRunner, wrappedExecuteCommand); +} + +async function wrappedExecuteCommand< + Commands extends Record, + CommandName extends keyof Commands & string = keyof Commands & string, +>( + commandName: CommandName, + ...args: Parameters +): Promise>> { + return await commands.executeCommand< + Awaited> + >(commandName, ...args); +} + +export type ExtensionCommands = { + "codeQL.openVariantAnalysisLogs": ( + variantAnalysisId: number, + ) => Promise; +}; +export type AllCommands = ExtensionCommands; diff --git a/extensions/ql-vscode/src/extension.ts b/extensions/ql-vscode/src/extension.ts index 2d6349939..3b7ceb7f6 100644 --- a/extensions/ql-vscode/src/extension.ts +++ b/extensions/ql-vscode/src/extension.ts @@ -137,6 +137,11 @@ 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, + initializeVSCodeCommandManager, +} from "./commands"; /** * extension.ts @@ -168,6 +173,16 @@ let isInstallingOrUpdatingDistribution = false; const extensionId = "GitHub.vscode-codeql"; const extension = extensions.getExtension(extensionId); +function getCommands( + variantAnalysisManager: VariantAnalysisManager, +): ExtensionCommands { + return { + "codeQL.openVariantAnalysisLogs": async (variantAnalysisId: number) => { + await variantAnalysisManager.openVariantAnalysisLogs(variantAnalysisId); + }, + }; +} + /** * If the user tries to execute vscode commands after extension activation is failed, give * a sensible error message. @@ -1153,6 +1168,7 @@ async function activateWithInstalledDistribution( ), ); + /* ctx.subscriptions.push( commandRunner( "codeQL.openVariantAnalysisLogs", @@ -1161,6 +1177,17 @@ async function activateWithInstalledDistribution( }, ), ); +*/ + + const vsCommandRunner = initializeVSCodeCommandManager(); + ctx.subscriptions.push(vsCommandRunner); + const allCommands: Partial = { + ...getCommands(variantAnalysisManager), + }; + + for (const [commandName, command] of Object.entries(allCommands)) { + vsCommandRunner.registerCommand(commandName as keyof AllCommands, command); + } ctx.subscriptions.push( commandRunner( diff --git a/extensions/ql-vscode/src/packages/commands/CommandManager.ts b/extensions/ql-vscode/src/packages/commands/CommandManager.ts index c67f3bb7b..5176dda03 100644 --- a/extensions/ql-vscode/src/packages/commands/CommandManager.ts +++ b/extensions/ql-vscode/src/packages/commands/CommandManager.ts @@ -21,7 +21,7 @@ export class CommandManager< private readonly commandExecute: ( commandName: T, ...args: Parameters - ) => Promise>, + ) => Promise>>, ) {} registerCommand( @@ -34,7 +34,7 @@ export class CommandManager< executeCommand( commandName: T, ...args: Parameters - ): Promise> { + ): Promise>> { return this.commandExecute(commandName, ...args); } From 088e9aa9588d001c7eb1af575427f834593cda4e Mon Sep 17 00:00:00 2001 From: Koen Vlaswinkel Date: Fri, 10 Mar 2023 16:35:22 +0100 Subject: [PATCH 005/156] Add command manager to app --- extensions/ql-vscode/src/common/app.ts | 2 ++ extensions/ql-vscode/src/common/commands.ts | 11 +++++++++++ .../src/{ => common/vscode}/commands.ts | 11 ++--------- .../ql-vscode/src/common/vscode/vscode-app.ts | 5 +++++ extensions/ql-vscode/src/extension.ts | 13 +++++-------- extensions/ql-vscode/test/__mocks__/appMock.ts | 5 +++++ .../ql-vscode/test/__mocks__/commandsMock.ts | 16 ++++++++++++++++ 7 files changed, 46 insertions(+), 17 deletions(-) create mode 100644 extensions/ql-vscode/src/common/commands.ts rename extensions/ql-vscode/src/{ => common/vscode}/commands.ts (68%) create mode 100644 extensions/ql-vscode/test/__mocks__/commandsMock.ts diff --git a/extensions/ql-vscode/src/common/app.ts b/extensions/ql-vscode/src/common/app.ts index 67506a5fa..da0bdfa5b 100644 --- a/extensions/ql-vscode/src/common/app.ts +++ b/extensions/ql-vscode/src/common/app.ts @@ -3,6 +3,7 @@ import { Disposable } from "../pure/disposable-object"; import { AppEventEmitter } from "./events"; import { Logger } from "./logging"; import { Memento } from "./memento"; +import { ExtensionCommandManager } from "./commands"; export interface App { createEventEmitter(): AppEventEmitter; @@ -15,6 +16,7 @@ export interface App { readonly workspaceStoragePath?: string; readonly workspaceState: Memento; readonly credentials: Credentials; + readonly commandManager: ExtensionCommandManager; } export enum AppMode { diff --git a/extensions/ql-vscode/src/common/commands.ts b/extensions/ql-vscode/src/common/commands.ts new file mode 100644 index 000000000..b9717538a --- /dev/null +++ b/extensions/ql-vscode/src/common/commands.ts @@ -0,0 +1,11 @@ +import { CommandManager } from "../packages/commands"; + +export type ExtensionCommands = { + "codeQL.openVariantAnalysisLogs": ( + variantAnalysisId: number, + ) => Promise; +}; + +export type AllCommands = ExtensionCommands; + +export type ExtensionCommandManager = CommandManager; diff --git a/extensions/ql-vscode/src/commands.ts b/extensions/ql-vscode/src/common/vscode/commands.ts similarity index 68% rename from extensions/ql-vscode/src/commands.ts rename to extensions/ql-vscode/src/common/vscode/commands.ts index e0e0f7ca0..bcbfd557a 100644 --- a/extensions/ql-vscode/src/commands.ts +++ b/extensions/ql-vscode/src/common/vscode/commands.ts @@ -1,6 +1,6 @@ import { commands } from "vscode"; -import { commandRunner } from "./commandRunner"; -import { CommandFunction, CommandManager } from "./packages/commands"; +import { commandRunner } from "../../commandRunner"; +import { CommandFunction, CommandManager } from "../../packages/commands"; export function initializeVSCodeCommandManager< Commands extends Record, @@ -19,10 +19,3 @@ async function wrappedExecuteCommand< Awaited> >(commandName, ...args); } - -export type ExtensionCommands = { - "codeQL.openVariantAnalysisLogs": ( - variantAnalysisId: number, - ) => Promise; -}; -export type AllCommands = ExtensionCommands; diff --git a/extensions/ql-vscode/src/common/vscode/vscode-app.ts b/extensions/ql-vscode/src/common/vscode/vscode-app.ts index 8f54341b6..2b434c4fa 100644 --- a/extensions/ql-vscode/src/common/vscode/vscode-app.ts +++ b/extensions/ql-vscode/src/common/vscode/vscode-app.ts @@ -6,14 +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"; export class ExtensionApp implements App { public readonly credentials: VSCodeCredentials; + public readonly commandManager: ExtensionCommandManager; public constructor( public readonly extensionContext: vscode.ExtensionContext, ) { this.credentials = new VSCodeCredentials(); + this.commandManager = initializeVSCodeCommandManager(); + extensionContext.subscriptions.push(this.commandManager); } public get extensionPath(): string { diff --git a/extensions/ql-vscode/src/extension.ts b/extensions/ql-vscode/src/extension.ts index 3b7ceb7f6..f3b45a556 100644 --- a/extensions/ql-vscode/src/extension.ts +++ b/extensions/ql-vscode/src/extension.ts @@ -137,11 +137,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, - initializeVSCodeCommandManager, -} from "./commands"; +import { AllCommands, ExtensionCommands } from "./common/commands"; /** * extension.ts @@ -1179,14 +1175,15 @@ async function activateWithInstalledDistribution( ); */ - const vsCommandRunner = initializeVSCodeCommandManager(); - ctx.subscriptions.push(vsCommandRunner); const allCommands: Partial = { ...getCommands(variantAnalysisManager), }; for (const [commandName, command] of Object.entries(allCommands)) { - vsCommandRunner.registerCommand(commandName as keyof AllCommands, command); + app.commandManager.registerCommand( + commandName as keyof AllCommands, + command, + ); } ctx.subscriptions.push( diff --git a/extensions/ql-vscode/test/__mocks__/appMock.ts b/extensions/ql-vscode/test/__mocks__/appMock.ts index e5f74be29..b07796c00 100644 --- a/extensions/ql-vscode/test/__mocks__/appMock.ts +++ b/extensions/ql-vscode/test/__mocks__/appMock.ts @@ -6,6 +6,8 @@ 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 { createMockCommandManager } from "./commandsMock"; export function createMockApp({ extensionPath = "/mock/extension/path", @@ -15,6 +17,7 @@ export function createMockApp({ executeCommand = jest.fn(() => Promise.resolve()), workspaceState = createMockMemento(), credentials = testCredentialsWithStub(), + commandManager = createMockCommandManager(), }: { extensionPath?: string; workspaceStoragePath?: string; @@ -23,6 +26,7 @@ export function createMockApp({ executeCommand?: () => Promise; workspaceState?: Memento; credentials?: Credentials; + commandManager?: ExtensionCommandManager; }): App { return { mode: AppMode.Test, @@ -35,6 +39,7 @@ export function createMockApp({ createEventEmitter, executeCommand, credentials, + commandManager, }; } diff --git a/extensions/ql-vscode/test/__mocks__/commandsMock.ts b/extensions/ql-vscode/test/__mocks__/commandsMock.ts new file mode 100644 index 000000000..21151e48e --- /dev/null +++ b/extensions/ql-vscode/test/__mocks__/commandsMock.ts @@ -0,0 +1,16 @@ +import { ExtensionCommandManager } from "../../src/common/commands"; +import { + CommandFunction, + CommandManager, + Disposable, +} from "../../src/packages/commands"; + +export function createMockCommandManager({ + registerCommand = jest.fn(), + executeCommand = jest.fn(), +}: { + registerCommand?: (commandName: string, fn: CommandFunction) => Disposable; + executeCommand?: (commandName: string, ...args: any[]) => Promise; +} = {}): ExtensionCommandManager { + return new CommandManager(registerCommand, executeCommand); +} From e97ffd2f27f3d3e2542814e6a46bbcbec4a2bfb3 Mon Sep 17 00:00:00 2001 From: Koen Vlaswinkel Date: Fri, 10 Mar 2023 16:37:20 +0100 Subject: [PATCH 006/156] Use command manager executeCommand --- .../src/variant-analysis/variant-analysis-manager.ts | 9 ++++++++- .../src/variant-analysis/variant-analysis-view.ts | 4 +++- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/extensions/ql-vscode/src/variant-analysis/variant-analysis-manager.ts b/extensions/ql-vscode/src/variant-analysis/variant-analysis-manager.ts index af42da85c..13a4449cf 100644 --- a/extensions/ql-vscode/src/variant-analysis/variant-analysis-manager.ts +++ b/extensions/ql-vscode/src/variant-analysis/variant-analysis-manager.ts @@ -268,7 +268,14 @@ export class VariantAnalysisManager } if (!this.views.has(variantAnalysisId)) { // The view will register itself with the manager, so we don't need to do anything here. - this.track(new VariantAnalysisView(this.ctx, variantAnalysisId, this)); + this.track( + new VariantAnalysisView( + this.ctx, + this.app.commandManager, + variantAnalysisId, + this, + ), + ); } const variantAnalysisView = this.views.get(variantAnalysisId)!; diff --git a/extensions/ql-vscode/src/variant-analysis/variant-analysis-view.ts b/extensions/ql-vscode/src/variant-analysis/variant-analysis-view.ts index e41a85205..f058ab454 100644 --- a/extensions/ql-vscode/src/variant-analysis/variant-analysis-view.ts +++ b/extensions/ql-vscode/src/variant-analysis/variant-analysis-view.ts @@ -17,6 +17,7 @@ import { } from "./variant-analysis-view-manager"; import { showAndLogWarningMessage } from "../helpers"; import { telemetryListener } from "../telemetry"; +import { ExtensionCommandManager } from "../common/commands"; export class VariantAnalysisView extends AbstractWebview @@ -26,6 +27,7 @@ export class VariantAnalysisView public constructor( ctx: ExtensionContext, + private readonly commandManager: ExtensionCommandManager, public readonly variantAnalysisId: number, private readonly manager: VariantAnalysisViewManager, ) { @@ -145,7 +147,7 @@ export class VariantAnalysisView ); break; case "openLogs": - await commands.executeCommand( + await this.commandManager.executeCommand( "codeQL.openVariantAnalysisLogs", this.variantAnalysisId, ); From df86adbbfa74d2ad44258cb27b1b5150d1758e2a Mon Sep 17 00:00:00 2001 From: Koen Vlaswinkel Date: Fri, 10 Mar 2023 16:49:30 +0100 Subject: [PATCH 007/156] Split variant analysis and extension commands --- extensions/ql-vscode/src/common/commands.ts | 6 +++- extensions/ql-vscode/src/extension.ts | 30 ++++--------------- .../variant-analysis-manager.ts | 9 ++++++ 3 files changed, 20 insertions(+), 25 deletions(-) diff --git a/extensions/ql-vscode/src/common/commands.ts b/extensions/ql-vscode/src/common/commands.ts index b9717538a..969b67a11 100644 --- a/extensions/ql-vscode/src/common/commands.ts +++ b/extensions/ql-vscode/src/common/commands.ts @@ -1,11 +1,15 @@ import { CommandManager } from "../packages/commands"; export type ExtensionCommands = { + "codeQL.openDocumentation": () => Promise; +}; + +export type VariantAnalysisCommands = { "codeQL.openVariantAnalysisLogs": ( variantAnalysisId: number, ) => Promise; }; -export type AllCommands = ExtensionCommands; +export type AllCommands = ExtensionCommands & VariantAnalysisCommands; export type ExtensionCommandManager = CommandManager; diff --git a/extensions/ql-vscode/src/extension.ts b/extensions/ql-vscode/src/extension.ts index f3b45a556..5152d18c6 100644 --- a/extensions/ql-vscode/src/extension.ts +++ b/extensions/ql-vscode/src/extension.ts @@ -169,12 +169,10 @@ let isInstallingOrUpdatingDistribution = false; const extensionId = "GitHub.vscode-codeql"; const extension = extensions.getExtension(extensionId); -function getCommands( - variantAnalysisManager: VariantAnalysisManager, -): ExtensionCommands { +function getCommands(): ExtensionCommands { return { - "codeQL.openVariantAnalysisLogs": async (variantAnalysisId: number) => { - await variantAnalysisManager.openVariantAnalysisLogs(variantAnalysisId); + "codeQL.openDocumentation": async () => { + await env.openExternal(Uri.parse("https://codeql.github.com/docs/")); }, }; } @@ -1164,19 +1162,9 @@ async function activateWithInstalledDistribution( ), ); - /* - ctx.subscriptions.push( - commandRunner( - "codeQL.openVariantAnalysisLogs", - async (variantAnalysisId: number) => { - await variantAnalysisManager.openVariantAnalysisLogs(variantAnalysisId); - }, - ), - ); -*/ - - const allCommands: Partial = { - ...getCommands(variantAnalysisManager), + const allCommands: AllCommands = { + ...getCommands(), + ...variantAnalysisManager.getCommands(), }; for (const [commandName, command] of Object.entries(allCommands)) { @@ -1383,12 +1371,6 @@ async function activateWithInstalledDistribution( ), ); - ctx.subscriptions.push( - commandRunner("codeQL.openDocumentation", async () => - env.openExternal(Uri.parse("https://codeql.github.com/docs/")), - ), - ); - ctx.subscriptions.push( commandRunner("codeQL.copyVersion", async () => { const text = `CodeQL extension version: ${ diff --git a/extensions/ql-vscode/src/variant-analysis/variant-analysis-manager.ts b/extensions/ql-vscode/src/variant-analysis/variant-analysis-manager.ts index 13a4449cf..6a63e59bb 100644 --- a/extensions/ql-vscode/src/variant-analysis/variant-analysis-manager.ts +++ b/extensions/ql-vscode/src/variant-analysis/variant-analysis-manager.ts @@ -62,6 +62,7 @@ import { URLSearchParams } from "url"; import { DbManager } from "../databases/db-manager"; import { App } from "../common/app"; import { redactableError } from "../pure/errors"; +import { VariantAnalysisCommands } from "../common/commands"; export class VariantAnalysisManager extends DisposableObject @@ -123,6 +124,14 @@ export class VariantAnalysisManager ); } + getCommands(): VariantAnalysisCommands { + return { + "codeQL.openVariantAnalysisLogs": async (variantAnalysisId: number) => { + await this.openVariantAnalysisLogs(variantAnalysisId); + }, + }; + } + public async runVariantAnalysis( uri: Uri | undefined, progress: ProgressCallback, From 2457d4bd9d96547994bffa0470f6a7e05d4b2242 Mon Sep 17 00:00:00 2001 From: Koen Vlaswinkel Date: Fri, 10 Mar 2023 16:56:06 +0100 Subject: [PATCH 008/156] Remove command manager argument to variant analysis view --- .../variant-analysis-manager.ts | 18 +++++++++--------- .../variant-analysis-view-manager.ts | 3 +++ .../variant-analysis/variant-analysis-view.ts | 4 +--- 3 files changed, 13 insertions(+), 12 deletions(-) diff --git a/extensions/ql-vscode/src/variant-analysis/variant-analysis-manager.ts b/extensions/ql-vscode/src/variant-analysis/variant-analysis-manager.ts index 6a63e59bb..57065ff87 100644 --- a/extensions/ql-vscode/src/variant-analysis/variant-analysis-manager.ts +++ b/extensions/ql-vscode/src/variant-analysis/variant-analysis-manager.ts @@ -62,7 +62,10 @@ import { URLSearchParams } from "url"; import { DbManager } from "../databases/db-manager"; import { App } from "../common/app"; import { redactableError } from "../pure/errors"; -import { VariantAnalysisCommands } from "../common/commands"; +import { + ExtensionCommandManager, + VariantAnalysisCommands, +} from "../common/commands"; export class VariantAnalysisManager extends DisposableObject @@ -132,6 +135,10 @@ export class VariantAnalysisManager }; } + get commandManager(): ExtensionCommandManager { + return this.app.commandManager; + } + public async runVariantAnalysis( uri: Uri | undefined, progress: ProgressCallback, @@ -277,14 +284,7 @@ export class VariantAnalysisManager } if (!this.views.has(variantAnalysisId)) { // The view will register itself with the manager, so we don't need to do anything here. - this.track( - new VariantAnalysisView( - this.ctx, - this.app.commandManager, - variantAnalysisId, - this, - ), - ); + this.track(new VariantAnalysisView(this.ctx, variantAnalysisId, this)); } const variantAnalysisView = this.views.get(variantAnalysisId)!; diff --git a/extensions/ql-vscode/src/variant-analysis/variant-analysis-view-manager.ts b/extensions/ql-vscode/src/variant-analysis/variant-analysis-view-manager.ts index 7f307c42d..c0d83c949 100644 --- a/extensions/ql-vscode/src/variant-analysis/variant-analysis-view-manager.ts +++ b/extensions/ql-vscode/src/variant-analysis/variant-analysis-view-manager.ts @@ -2,6 +2,7 @@ import { VariantAnalysis, VariantAnalysisScannedRepositoryState, } from "./shared/variant-analysis"; +import { ExtensionCommandManager } from "../common/commands"; export interface VariantAnalysisViewInterface { variantAnalysisId: number; @@ -11,6 +12,8 @@ export interface VariantAnalysisViewInterface { export interface VariantAnalysisViewManager< T extends VariantAnalysisViewInterface, > { + commandManager: ExtensionCommandManager; + registerView(view: T): void; unregisterView(view: T): void; getView(variantAnalysisId: number): T | undefined; diff --git a/extensions/ql-vscode/src/variant-analysis/variant-analysis-view.ts b/extensions/ql-vscode/src/variant-analysis/variant-analysis-view.ts index f058ab454..b85c237a8 100644 --- a/extensions/ql-vscode/src/variant-analysis/variant-analysis-view.ts +++ b/extensions/ql-vscode/src/variant-analysis/variant-analysis-view.ts @@ -17,7 +17,6 @@ import { } from "./variant-analysis-view-manager"; import { showAndLogWarningMessage } from "../helpers"; import { telemetryListener } from "../telemetry"; -import { ExtensionCommandManager } from "../common/commands"; export class VariantAnalysisView extends AbstractWebview @@ -27,7 +26,6 @@ export class VariantAnalysisView public constructor( ctx: ExtensionContext, - private readonly commandManager: ExtensionCommandManager, public readonly variantAnalysisId: number, private readonly manager: VariantAnalysisViewManager, ) { @@ -147,7 +145,7 @@ export class VariantAnalysisView ); break; case "openLogs": - await this.commandManager.executeCommand( + await this.manager.commandManager.executeCommand( "codeQL.openVariantAnalysisLogs", this.variantAnalysisId, ); From 5d85da552690af8412ce74528f5967e5fdcb29bf Mon Sep 17 00:00:00 2001 From: Andrew Eisenberg Date: Mon, 13 Feb 2023 14:54:19 -0800 Subject: [PATCH 009/156] Refactor `generateQueryPack` Creates a handful of new functions and adds documentation. This commit has no behavioural changes. --- .../src/variant-analysis/run-remote-query.ts | 156 ++++++++++++------ 1 file changed, 103 insertions(+), 53 deletions(-) diff --git a/extensions/ql-vscode/src/variant-analysis/run-remote-query.ts b/extensions/ql-vscode/src/variant-analysis/run-remote-query.ts index 8b64aa8c7..c76c0dbc7 100644 --- a/extensions/ql-vscode/src/variant-analysis/run-remote-query.ts +++ b/extensions/ql-vscode/src/variant-analysis/run-remote-query.ts @@ -70,42 +70,24 @@ async function generateQueryPack( const originalPackRoot = await findPackRoot(queryFile); const packRelativePath = relative(originalPackRoot, queryFile); const targetQueryFileName = join(queryPackDir, packRelativePath); + const workspaceFolders = getOnDiskWorkspaceFolders(); let language: string | undefined; + + // Check if the query is already in a query pack. + // If so, copy the entire query pack to the temporary directory. + // Otherwise, copy only the query file to the temporary directory + // and generate a synthetic query pack. if (await getQlPackPath(originalPackRoot)) { // don't include ql files. We only want the queryFile to be copied. - const toCopy = await cliServer.packPacklist(originalPackRoot, false); - - // also copy the lock file (either new name or old name) and the query file itself. These are not included in the packlist. - [ - join(originalPackRoot, "qlpack.lock.yml"), - join(originalPackRoot, "codeql-pack.lock.yml"), + await copyExistingQueryPack( + cliServer, + originalPackRoot, queryFile, - ].forEach((absolutePath) => { - if (absolutePath) { - toCopy.push(absolutePath); - } - }); - - let copiedCount = 0; - await copy(originalPackRoot, queryPackDir, { - filter: (file: string) => - // copy file if it is in the packlist, or it is a parent directory of a file in the packlist - !!toCopy.find((f) => { - // Normalized paths ensure that Windows drive letters are capitalized consistently. - const normalizedPath = Uri.file(f).fsPath; - const matches = - normalizedPath === file || normalizedPath.startsWith(file + sep); - if (matches) { - copiedCount++; - } - return matches; - }), - }); - - void extLogger.log(`Copied ${copiedCount} files to ${queryPackDir}`); - - await fixPackFile(queryPackDir, packRelativePath); + queryPackDir, + packRelativePath, + workspaceFolders, + ); language = await findLanguage(cliServer, Uri.file(targetQueryFileName)); } else { @@ -114,20 +96,14 @@ async function generateQueryPack( // copy only the query file to the query pack directory // and generate a synthetic query pack - void extLogger.log(`Copying ${queryFile} to ${queryPackDir}`); - await copy(queryFile, targetQueryFileName); - void extLogger.log("Generating synthetic query pack"); - const syntheticQueryPack = { - name: QUERY_PACK_NAME, - version: "0.0.0", - dependencies: { - [`codeql/${language}-all`]: "*", - }, - defaultSuite: generateDefaultSuite(packRelativePath), - }; - await writeFile( - join(queryPackDir, FALLBACK_QLPACK_FILENAME), - dump(syntheticQueryPack), + await createNewQueryPack( + queryFile, + queryPackDir, + targetQueryFileName, + language, + packRelativePath, + cliServer, + workspaceFolders, ); } if (!language) { @@ -154,7 +130,6 @@ async function generateQueryPack( `Compiling and bundling query pack from ${queryPackDir} to ${bundlePath}. (This may take a while.)`, ); await cliServer.packInstall(queryPackDir); - const workspaceFolders = getOnDiskWorkspaceFolders(); await cliServer.packBundle( queryPackDir, workspaceFolders, @@ -168,6 +143,79 @@ async function generateQueryPack( }; } +async function createNewQueryPack( + queryFile: string, + queryPackDir: string, + targetQueryFileName: string, + language: string | undefined, + packRelativePath: string, + cliServer: cli.CodeQLCliServer, + workspaceFolders: string[], +) { + void extLogger.log(`Copying ${queryFile} to ${queryPackDir}`); + await copy(queryFile, targetQueryFileName); + void extLogger.log("Generating synthetic query pack"); + const syntheticQueryPack = { + name: QUERY_PACK_NAME, + version: "0.0.0", + dependencies: { + [`codeql/${language}-all`]: "*", + }, + defaultSuite: generateDefaultSuite(packRelativePath), + }; + await writeFile( + join(queryPackDir, FALLBACK_QLPACK_FILENAME), + dump(syntheticQueryPack), + ); +} + +async function copyExistingQueryPack( + cliServer: cli.CodeQLCliServer, + originalPackRoot: string, + queryFile: string, + queryPackDir: string, + packRelativePath: string, + workspaceFolders: string[], +) { + const toCopy = await cliServer.packPacklist(originalPackRoot, false); + + // also copy the lock file (either new name or old name) and the query file itself. These are not included in the packlist. + [ + join(originalPackRoot, "qlpack.lock.yml"), + join(originalPackRoot, "codeql-pack.lock.yml"), + queryFile, + ].forEach((absolutePath) => { + if (absolutePath) { + toCopy.push(absolutePath); + } + }); + + let copiedCount = 0; + await copy(originalPackRoot, queryPackDir, { + filter: (file: string) => + // copy file if it is in the packlist, or it is a parent directory of a file in the packlist + !!toCopy.find((f) => { + // Normalized paths ensure that Windows drive letters are capitalized consistently. + const normalizedPath = Uri.file(f).fsPath; + const matches = + normalizedPath === file || normalizedPath.startsWith(file + sep); + if (matches) { + copiedCount++; + } + return matches; + }), + }); + + void extLogger.log(`Copied ${copiedCount} files to ${queryPackDir}`); + + await fixPackFile( + queryPackDir, + packRelativePath, + cliServer, + workspaceFolders, + ); +} + async function findPackRoot(queryFile: string): Promise { // recursively find the directory containing qlpack.yml or codeql-pack.yml let dir = dirname(queryFile); @@ -316,6 +364,8 @@ export async function prepareRemoteQueryRun( async function fixPackFile( queryPackDir: string, packRelativePath: string, + cliServer: cli.CodeQLCliServer, + workspaceFolders: string[], ): Promise { const packPath = await getQlPackPath(queryPackDir); @@ -329,19 +379,19 @@ async function fixPackFile( } const qlpack = load(await readFile(packPath, "utf8")) as QlPack; - // update pack name qlpack.name = QUERY_PACK_NAME; - - // update default suite - delete qlpack.defaultSuiteFile; - qlpack.defaultSuite = generateDefaultSuite(packRelativePath); - - // remove any ${workspace} version references + updateDefaultSuite(qlpack, packRelativePath); removeWorkspaceRefs(qlpack); await writeFile(packPath, dump(qlpack)); } + +function updateDefaultSuite(qlpack: QlPack, packRelativePath: string) { + delete qlpack.defaultSuiteFile; + qlpack.defaultSuite = generateDefaultSuite(packRelativePath); +} + function generateDefaultSuite(packRelativePath: string) { return [ { From fe123b3187e863f8dd7fcc8d9cce9129f59a4cdf Mon Sep 17 00:00:00 2001 From: Andrew Eisenberg Date: Mon, 13 Feb 2023 14:57:17 -0800 Subject: [PATCH 010/156] Inject extension pack dependencies into MRVA packs If the user requests that extension packs be included in their MRVA run, then do the following: 1. Search the workspace for all extension packs 2. Add each extension pack as an explicit and direct dependency on the generated pack. It is ok to use `*` as a dependency since we are guaranteed that exactly one version of each injected extension pack dependency is available when the pack is being compiled. If we find multiple paths to an extension pack of the same name, this is an error since it is ambiguous which path to use. --- .../src/variant-analysis/run-remote-query.ts | 29 +++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/extensions/ql-vscode/src/variant-analysis/run-remote-query.ts b/extensions/ql-vscode/src/variant-analysis/run-remote-query.ts index c76c0dbc7..0ae572c60 100644 --- a/extensions/ql-vscode/src/variant-analysis/run-remote-query.ts +++ b/extensions/ql-vscode/src/variant-analysis/run-remote-query.ts @@ -163,6 +163,9 @@ async function createNewQueryPack( }, defaultSuite: generateDefaultSuite(packRelativePath), }; + if (await cliServer.useExtensionPacks()) { + injectExtensionPacks(cliServer, syntheticQueryPack, workspaceFolders); + } await writeFile( join(queryPackDir, FALLBACK_QLPACK_FILENAME), dump(syntheticQueryPack), @@ -382,10 +385,36 @@ async function fixPackFile( qlpack.name = QUERY_PACK_NAME; updateDefaultSuite(qlpack, packRelativePath); removeWorkspaceRefs(qlpack); + if (await cliServer.useExtensionPacks()) { + injectExtensionPacks(cliServer, qlpack, workspaceFolders); + } await writeFile(packPath, dump(qlpack)); } +function injectExtensionPacks( + cliServer: cli.CodeQLCliServer, + qlpack: QlPack, + workspaceFolders: string[], +) { + const extensionPacks = cliServer.resolveQlpacks(workspaceFolders, true); + Object.entries(extensionPacks).forEach(([name, paths]) => { + // We are guaranteed that there is at least one path found for each extension pack. + // If there are multiple paths, then we have a problem. This means that there is + // ambiguity in which path to use. This is an error. + if (paths.length > 1) { + throw new Error( + `Multiple versions of extension pack '${name}' found: ${paths.join( + ", ", + )}`, + ); + } + // Add this extension pack as a dependency. It doesn't matter which + // version we specify, since we are guaranteed that the extension pack + // is resolved from source at the given path. + qlpack.dependencies[name] = "*"; + }); +} function updateDefaultSuite(qlpack: QlPack, packRelativePath: string) { delete qlpack.defaultSuiteFile; From d990f316d179e1c69eb2b5722182da445a7e3744 Mon Sep 17 00:00:00 2001 From: Anders Starcke Henriksen Date: Mon, 13 Mar 2023 12:16:38 +0100 Subject: [PATCH 011/156] Fix tests. --- extensions/ql-vscode/test/factories/extension-context.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/extensions/ql-vscode/test/factories/extension-context.ts b/extensions/ql-vscode/test/factories/extension-context.ts index d871e77d6..8c90b330c 100644 --- a/extensions/ql-vscode/test/factories/extension-context.ts +++ b/extensions/ql-vscode/test/factories/extension-context.ts @@ -19,5 +19,6 @@ export function createMockExtensionContext({ globalStorageUri: vscode.Uri.file(globalStoragePath), storageUri: vscode.Uri.file(workspaceStoragePath), workspaceState: createMockMemento(), + subscriptions: [], } as any as vscode.ExtensionContext; } From a7bb74190f120abae652dbbbc319fe1fd63a7414 Mon Sep 17 00:00:00 2001 From: Koen Vlaswinkel Date: Mon, 13 Mar 2023 14:10:00 +0100 Subject: [PATCH 012/156] Unify `commandRunner` implementations The `commandRunnerWithProgress` implementation isn't actually any different from `commandRunner`, except for the call to `withProgress` and support for an `outputLogger` argument. Therefore, this will simply make `commandRunnerWithProgress` a wrapper around `commandRunner`, removing quite some duplication in the process. --- extensions/ql-vscode/src/commandRunner.ts | 89 ++++++++--------------- 1 file changed, 31 insertions(+), 58 deletions(-) diff --git a/extensions/ql-vscode/src/commandRunner.ts b/extensions/ql-vscode/src/commandRunner.ts index 4ff281c04..688d6fdb2 100644 --- a/extensions/ql-vscode/src/commandRunner.ts +++ b/extensions/ql-vscode/src/commandRunner.ts @@ -121,6 +121,7 @@ export function withProgress( export function commandRunner( commandId: string, task: NoProgressTask, + outputLogger = extLogger, ): Disposable { return commands.registerCommand(commandId, async (...args: any[]) => { const startTime = Date.now(); @@ -134,64 +135,6 @@ export function commandRunner( getErrorMessage(e) || e } (${commandId})`; const errorStack = getErrorStack(e); - if (e instanceof UserCancellationException) { - // User has cancelled this action manually - if (e.silent) { - void extLogger.log(errorMessage.fullMessage); - } else { - void showAndLogWarningMessage(errorMessage.fullMessage); - } - } else { - // Include the full stack in the error log only. - const fullMessage = errorStack - ? `${errorMessage.fullMessage}\n${errorStack}` - : errorMessage.fullMessage; - void showAndLogExceptionWithTelemetry(errorMessage, { - fullMessage, - extraTelemetryProperties: { - command: commandId, - }, - }); - } - return undefined; - } finally { - const executionTime = Date.now() - startTime; - telemetryListener?.sendCommandUsage(commandId, executionTime, error); - } - }); -} - -/** - * A generic wrapper for command registration. This wrapper adds uniform error handling, - * progress monitoring, and cancellation for commands. - * - * @param commandId The ID of the command to register. - * @param task The task to run. It is passed directly to `commands.registerCommand`. Any - * arguments to the command handler are passed on to the task after the progress callback - * and cancellation token. - * @param progressOptions Progress options to be sent to the progress monitor. - */ -export function commandRunnerWithProgress( - commandId: string, - task: ProgressTask, - progressOptions: Partial, - outputLogger = extLogger, -): Disposable { - return commands.registerCommand(commandId, async (...args: any[]) => { - const startTime = Date.now(); - let error: Error | undefined; - const progressOptionsWithDefaults = { - location: ProgressLocation.Notification, - ...progressOptions, - }; - try { - return await withProgress(progressOptionsWithDefaults, task, ...args); - } catch (e) { - error = asError(e); - const errorMessage = redactableError`${ - getErrorMessage(e) || e - } (${commandId})`; - const errorStack = getErrorStack(e); if (e instanceof UserCancellationException) { // User has cancelled this action manually if (e.silent) { @@ -222,6 +165,36 @@ export function commandRunnerWithProgress( }); } +/** + * A generic wrapper for command registration. This wrapper adds uniform error handling, + * progress monitoring, and cancellation for commands. + * + * @param commandId The ID of the command to register. + * @param task The task to run. It is passed directly to `commands.registerCommand`. Any + * arguments to the command handler are passed on to the task after the progress callback + * and cancellation token. + * @param progressOptions Progress options to be sent to the progress monitor. + */ +export function commandRunnerWithProgress( + commandId: string, + task: ProgressTask, + progressOptions: Partial, + outputLogger = extLogger, +): Disposable { + return commandRunner( + commandId, + async (...args: any[]) => { + const progressOptionsWithDefaults = { + location: ProgressLocation.Notification, + ...progressOptions, + }; + + return withProgress(progressOptionsWithDefaults, task, ...args); + }, + outputLogger, + ); +} + /** * Displays a progress monitor that indicates how much progess has been made * reading from a stream. From 79d15cc602e8221f8ad13187270c212131013030 Mon Sep 17 00:00:00 2001 From: Anders Starcke Henriksen Date: Mon, 13 Mar 2023 14:36:28 +0100 Subject: [PATCH 013/156] Add comments. --- extensions/ql-vscode/src/common/commands.ts | 9 +++++++ .../ql-vscode/src/common/vscode/commands.ts | 4 +++ .../src/packages/commands/CommandManager.ts | 25 +++++++++++++++++++ 3 files changed, 38 insertions(+) diff --git a/extensions/ql-vscode/src/common/commands.ts b/extensions/ql-vscode/src/common/commands.ts index 969b67a11..ebc0dc82d 100644 --- a/extensions/ql-vscode/src/common/commands.ts +++ b/extensions/ql-vscode/src/common/commands.ts @@ -1,9 +1,18 @@ import { CommandManager } from "../packages/commands"; +/** + * Contains type definitions for all commands used by the extension. + * + * To add a new command first define its type here, then provide + * the implementation in the corresponding `getCommands` function. + */ + +// Commands directly in the extension export type ExtensionCommands = { "codeQL.openDocumentation": () => Promise; }; +// Commands tied to variant analysis export type VariantAnalysisCommands = { "codeQL.openVariantAnalysisLogs": ( variantAnalysisId: number, diff --git a/extensions/ql-vscode/src/common/vscode/commands.ts b/extensions/ql-vscode/src/common/vscode/commands.ts index bcbfd557a..5e9055b85 100644 --- a/extensions/ql-vscode/src/common/vscode/commands.ts +++ b/extensions/ql-vscode/src/common/vscode/commands.ts @@ -2,6 +2,10 @@ import { commands } from "vscode"; import { commandRunner } from "../../commandRunner"; import { CommandFunction, CommandManager } from "../../packages/commands"; +/** + * Intializes a command manager for VSCode, wrapping the commandRunner + * and vscode.executeCommand. + */ export function initializeVSCodeCommandManager< Commands extends Record, >(): CommandManager { diff --git a/extensions/ql-vscode/src/packages/commands/CommandManager.ts b/extensions/ql-vscode/src/packages/commands/CommandManager.ts index 5176dda03..a9bb79167 100644 --- a/extensions/ql-vscode/src/packages/commands/CommandManager.ts +++ b/extensions/ql-vscode/src/packages/commands/CommandManager.ts @@ -1,9 +1,25 @@ +/** + * Contains a generic implementation of typed commands. + * + * This allows different parts of the extension to register commands with a certain type, + * and then allow other parts to call those commands in a well-typed manner. + */ + export interface Disposable { dispose(): void; } +/** + * A command function is a completely untyped command. + */ export type CommandFunction = (...args: any[]) => Promise; +/** + * The command manager basically takes a single input, the type + * of all the known commands. The second parameter is provided by + * default (and should not be needed by the caller) it is a + * technicality to allow the type system to look up commands. + */ export class CommandManager< Commands extends Record, CommandName extends keyof Commands & string = keyof Commands & string, @@ -24,6 +40,9 @@ export class CommandManager< ) => Promise>>, ) {} + /** + * Register a command with the specified name and implementation. + */ registerCommand( commandName: T, definition: Commands[T], @@ -31,6 +50,9 @@ export class CommandManager< this.commands.push(this.commandRegister(commandName, definition)); } + /** + * Execute a command with the specified name and the provided arguments. + */ executeCommand( commandName: T, ...args: Parameters @@ -38,6 +60,9 @@ export class CommandManager< return this.commandExecute(commandName, ...args); } + /** + * Dispose the manager, disposing all the registered commands. + */ dispose(): void { this.commands.forEach((cmd) => { cmd.dispose(); From 26467162618d45ae5f0f24c004829008f22ed23a Mon Sep 17 00:00:00 2001 From: Koen Vlaswinkel Date: Mon, 13 Mar 2023 14:51:32 +0100 Subject: [PATCH 014/156] Remove args from `ProgressTask` This removes the `args` from the `ProgressTask` passed to `withProgress`. The `args` is only used by the `commandRunnerWithProgress` and can easily be replaced by an anonymous function that passes the `args` instead. This will simplify the `ProgressTask` interface and make it easier to use. --- extensions/ql-vscode/src/commandRunner.ts | 42 ++++++++++++++--------- 1 file changed, 26 insertions(+), 16 deletions(-) diff --git a/extensions/ql-vscode/src/commandRunner.ts b/extensions/ql-vscode/src/commandRunner.ts index 688d6fdb2..46680615b 100644 --- a/extensions/ql-vscode/src/commandRunner.ts +++ b/extensions/ql-vscode/src/commandRunner.ts @@ -42,22 +42,35 @@ export interface ProgressUpdate { export type ProgressCallback = (p: ProgressUpdate) => void; +/** + * A task that reports progress. + * + * @param progress a progress handler function. Call this + * function with a `ProgressUpdate` instance in order to + * denote some progress being achieved on this task. + * @param token a cancellation token + */ +export type ProgressTask = ( + progress: ProgressCallback, + token: CancellationToken, +) => Thenable; + /** * A task that handles command invocations from `commandRunner` * and includes a progress monitor. * * * Arguments passed to the command handler are passed along, - * untouched to this `ProgressTask` instance. + * untouched to this `ProgressTaskWithArgs` instance. * * @param progress a progress handler function. Call this * function with a `ProgressUpdate` instance in order to * denote some progress being achieved on this task. - * @param token a cencellation token + * @param token a cancellation token * @param args arguments passed to this task passed on from * `commands.registerCommand`. */ -export type ProgressTask = ( +export type ProgressTaskWithArgs = ( progress: ProgressCallback, token: CancellationToken, ...args: any[] @@ -92,20 +105,15 @@ type NoProgressTask = (...args: any[]) => Promise; export function withProgress( options: ProgressOptions, task: ProgressTask, - ...args: any[] ): Thenable { let progressAchieved = 0; return Window.withProgress(options, (progress, token) => { - return task( - (p) => { - const { message, step, maxStep } = p; - const increment = (100 * (step - progressAchieved)) / maxStep; - progressAchieved = step; - progress.report({ message, increment }); - }, - token, - ...args, - ); + return task((p) => { + const { message, step, maxStep } = p; + const increment = (100 * (step - progressAchieved)) / maxStep; + progressAchieved = step; + progress.report({ message, increment }); + }, token); }); } @@ -177,7 +185,7 @@ export function commandRunner( */ export function commandRunnerWithProgress( commandId: string, - task: ProgressTask, + task: ProgressTaskWithArgs, progressOptions: Partial, outputLogger = extLogger, ): Disposable { @@ -189,7 +197,9 @@ export function commandRunnerWithProgress( ...progressOptions, }; - return withProgress(progressOptionsWithDefaults, task, ...args); + return withProgress(progressOptionsWithDefaults, (progress, token) => + task(progress, token, ...args), + ); }, outputLogger, ); From 4969a085316d68a9d0e61a5d36e770021eb77f10 Mon Sep 17 00:00:00 2001 From: Koen Vlaswinkel Date: Mon, 13 Mar 2023 15:13:55 +0100 Subject: [PATCH 015/156] Make progress options optional This will make the progress options passed to `withProgress` optional by moving it to be the second argument and setting a default value for the `location`. This will make it much easier to use from a variety of commands. --- extensions/ql-vscode/src/commandRunner.ts | 48 ++++++++++++------- .../src/contextual/templateProvider.ts | 20 ++++---- extensions/ql-vscode/src/extension.ts | 21 ++++---- extensions/ql-vscode/src/local-databases.ts | 6 +-- 4 files changed, 53 insertions(+), 42 deletions(-) diff --git a/extensions/ql-vscode/src/commandRunner.ts b/extensions/ql-vscode/src/commandRunner.ts index 46680615b..6f316be2b 100644 --- a/extensions/ql-vscode/src/commandRunner.ts +++ b/extensions/ql-vscode/src/commandRunner.ts @@ -1,6 +1,6 @@ import { CancellationToken, - ProgressOptions, + ProgressOptions as VSCodeProgressOptions, window as Window, commands, Disposable, @@ -42,6 +42,11 @@ export interface ProgressUpdate { export type ProgressCallback = (p: ProgressUpdate) => void; +// Make certain properties within a type optional +type Optional = Pick, K> & Omit; + +export type ProgressOptions = Optional; + /** * A task that reports progress. * @@ -103,18 +108,29 @@ type NoProgressTask = (...args: any[]) => Promise; * request). */ export function withProgress( - options: ProgressOptions, task: ProgressTask, + { + location = ProgressLocation.Notification, + title, + cancellable, + }: ProgressOptions = {}, ): Thenable { let progressAchieved = 0; - return Window.withProgress(options, (progress, token) => { - return task((p) => { - const { message, step, maxStep } = p; - const increment = (100 * (step - progressAchieved)) / maxStep; - progressAchieved = step; - progress.report({ message, increment }); - }, token); - }); + return Window.withProgress( + { + location, + title, + cancellable, + }, + (progress, token) => { + return task((p) => { + const { message, step, maxStep } = p; + const increment = (100 * (step - progressAchieved)) / maxStep; + progressAchieved = step; + progress.report({ message, increment }); + }, token); + }, + ); } /** @@ -186,19 +202,15 @@ export function commandRunner( export function commandRunnerWithProgress( commandId: string, task: ProgressTaskWithArgs, - progressOptions: Partial, + progressOptions: ProgressOptions, outputLogger = extLogger, ): Disposable { return commandRunner( commandId, async (...args: any[]) => { - const progressOptionsWithDefaults = { - location: ProgressLocation.Notification, - ...progressOptions, - }; - - return withProgress(progressOptionsWithDefaults, (progress, token) => - task(progress, token, ...args), + return withProgress( + (progress, token) => task(progress, token, ...args), + progressOptions, ); }, outputLogger, diff --git a/extensions/ql-vscode/src/contextual/templateProvider.ts b/extensions/ql-vscode/src/contextual/templateProvider.ts index 448d36732..1e2865d99 100644 --- a/extensions/ql-vscode/src/contextual/templateProvider.ts +++ b/extensions/ql-vscode/src/contextual/templateProvider.ts @@ -73,11 +73,6 @@ export class TemplateQueryDefinitionProvider implements DefinitionProvider { private async getDefinitions(uriString: string): Promise { return withProgress( - { - location: ProgressLocation.Notification, - cancellable: true, - title: "Finding definitions", - }, async (progress, token) => { return getLocationsForUriString( this.cli, @@ -91,6 +86,11 @@ export class TemplateQueryDefinitionProvider implements DefinitionProvider { (src, _dest) => src === uriString, ); }, + { + location: ProgressLocation.Notification, + cancellable: true, + title: "Finding definitions", + }, ); } } @@ -136,11 +136,6 @@ export class TemplateQueryReferenceProvider implements ReferenceProvider { private async getReferences(uriString: string): Promise { return withProgress( - { - location: ProgressLocation.Notification, - cancellable: true, - title: "Finding references", - }, async (progress, token) => { return getLocationsForUriString( this.cli, @@ -154,6 +149,11 @@ export class TemplateQueryReferenceProvider implements ReferenceProvider { (src, _dest) => src === uriString, ); }, + { + location: ProgressLocation.Notification, + cancellable: true, + title: "Finding references", + }, ); } } diff --git a/extensions/ql-vscode/src/extension.ts b/extensions/ql-vscode/src/extension.ts index e1ca5caef..eb9420b82 100644 --- a/extensions/ql-vscode/src/extension.ts +++ b/extensions/ql-vscode/src/extension.ts @@ -9,7 +9,6 @@ import { extensions, languages, ProgressLocation, - ProgressOptions, QuickPickItem, Range, Uri, @@ -322,16 +321,16 @@ export async function activate( await commands.executeCommand("workbench.action.reloadWindow"); } } else { - const progressOptions: ProgressOptions = { - title: progressTitle, - location: ProgressLocation.Notification, - }; - - await withProgress(progressOptions, (progress) => - distributionManager.installExtensionManagedDistributionRelease( - result.updatedRelease, - progress, - ), + await withProgress( + (progress) => + distributionManager.installExtensionManagedDistributionRelease( + result.updatedRelease, + progress, + ), + { + title: progressTitle, + location: ProgressLocation.Notification, + }, ); await ctx.globalState.update(shouldUpdateOnNextActivationKey, false); diff --git a/extensions/ql-vscode/src/local-databases.ts b/extensions/ql-vscode/src/local-databases.ts index 8ba756df7..c1d281474 100644 --- a/extensions/ql-vscode/src/local-databases.ts +++ b/extensions/ql-vscode/src/local-databases.ts @@ -795,9 +795,6 @@ export class DatabaseManager extends DisposableObject { public async loadPersistedState(): Promise { return withProgress( - { - location: vscode.ProgressLocation.Notification, - }, async (progress, token) => { const currentDatabaseUri = this.ctx.workspaceState.get(CURRENT_DB); @@ -861,6 +858,9 @@ export class DatabaseManager extends DisposableObject { void this.logger.log("Finished loading persisted databases."); }, + { + location: vscode.ProgressLocation.Notification, + }, ); } From 3aa24ebb2c5d3173053040ae2259b9fa0a74d076 Mon Sep 17 00:00:00 2001 From: Koen Vlaswinkel Date: Mon, 13 Mar 2023 16:16:16 +0100 Subject: [PATCH 016/156] Remove direct dependency on babel-loader The extension Webpack config does not use `babel-loader`, so we can remove it as a direct dependency. `babel-loader` is still included in our `node_modules` because Storybook depends on it, but the version is now completely managed by Storybook rather than us. --- extensions/ql-vscode/package-lock.json | 1 - extensions/ql-vscode/package.json | 3 +-- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/extensions/ql-vscode/package-lock.json b/extensions/ql-vscode/package-lock.json index 875046111..0b7967103 100644 --- a/extensions/ql-vscode/package-lock.json +++ b/extensions/ql-vscode/package-lock.json @@ -105,7 +105,6 @@ "@vscode/vsce": "^2.15.0", "ansi-colors": "^4.1.1", "applicationinsights": "^2.3.5", - "babel-loader": "^8.2.5", "cross-env": "^7.0.3", "css-loader": "~3.1.0", "del": "^6.0.0", diff --git a/extensions/ql-vscode/package.json b/extensions/ql-vscode/package.json index 6a2e4a438..40b2a3930 100644 --- a/extensions/ql-vscode/package.json +++ b/extensions/ql-vscode/package.json @@ -1069,7 +1069,7 @@ { "command": "codeQL.viewCfgContextEditor", "when": "false" - }, + }, { "command": "codeQLVariantAnalysisRepositories.openConfigFile", "when": "false" @@ -1498,7 +1498,6 @@ "@vscode/vsce": "^2.15.0", "ansi-colors": "^4.1.1", "applicationinsights": "^2.3.5", - "babel-loader": "^8.2.5", "cross-env": "^7.0.3", "css-loader": "~3.1.0", "del": "^6.0.0", From fc8b13b8bee6d605aa967648ad7d125b02c292b8 Mon Sep 17 00:00:00 2001 From: Dave Bartolomeo Date: Mon, 13 Mar 2023 15:10:30 -0400 Subject: [PATCH 017/156] Use `TeeLogger` instead of `additionalLogLocation:` option --- .../ql-vscode/src/common/logging/index.ts | 1 + .../ql-vscode/src/common/logging/logger.ts | 10 ---- .../src/common/logging/tee-logger.ts | 49 +++++++++++++++++ .../logging/vscode/output-channel-logger.ts | 52 ------------------- .../legacy-query-server/queryserver-client.ts | 27 ++-------- .../src/legacy-query-server/run-queries.ts | 38 +++++++------- .../query-history/query-history-manager.ts | 2 - extensions/ql-vscode/src/query-results.ts | 9 ---- .../ql-vscode/src/query-serialization.ts | 4 -- .../src/query-server/queryserver-client.ts | 28 ++-------- .../ql-vscode/src/query-server/run-queries.ts | 13 +++-- .../ql-vscode/src/run-queries-shared.ts | 9 +--- .../ql-vscode/test/__mocks__/loggerMock.ts | 1 - .../logging/output-channel-logger.test.ts | 30 +++++------ 14 files changed, 103 insertions(+), 170 deletions(-) create mode 100644 extensions/ql-vscode/src/common/logging/tee-logger.ts diff --git a/extensions/ql-vscode/src/common/logging/index.ts b/extensions/ql-vscode/src/common/logging/index.ts index 35ed72fd7..7bc5d444b 100644 --- a/extensions/ql-vscode/src/common/logging/index.ts +++ b/extensions/ql-vscode/src/common/logging/index.ts @@ -1,3 +1,4 @@ export * from "./logger"; +export * from "./tee-logger"; export * from "./vscode/loggers"; export * from "./vscode/output-channel-logger"; diff --git a/extensions/ql-vscode/src/common/logging/logger.ts b/extensions/ql-vscode/src/common/logging/logger.ts index 89fc1e54b..61187585a 100644 --- a/extensions/ql-vscode/src/common/logging/logger.ts +++ b/extensions/ql-vscode/src/common/logging/logger.ts @@ -1,9 +1,6 @@ export interface LogOptions { // If false, don't output a trailing newline for the log entry. Default true. trailingNewline?: boolean; - - // If specified, add this log entry to the log file at the specified location. - additionalLogLocation?: string; } export interface Logger { @@ -25,11 +22,4 @@ export interface Logger { * @param preserveFocus When `true` the channel will not take focus. */ show(preserveFocus?: boolean): void; - - /** - * Remove the log at the specified location. - * - * @param location log to remove - */ - removeAdditionalLogLocation(location: string | undefined): void; } diff --git a/extensions/ql-vscode/src/common/logging/tee-logger.ts b/extensions/ql-vscode/src/common/logging/tee-logger.ts new file mode 100644 index 000000000..c64ac93e6 --- /dev/null +++ b/extensions/ql-vscode/src/common/logging/tee-logger.ts @@ -0,0 +1,49 @@ +import { appendFile, ensureFile } from "fs-extra"; +import { isAbsolute } from "path"; +import { Logger, LogOptions } from "./logger"; + +/** + * An implementation of {@link Logger} that sends the output both to another {@link Logger} + * and to a file. + * + * The first time a message is written, an additional banner is written to the underlying logger + * pointing the user to the "side log" file. + */ +export class TeeLogger implements Logger { + private emittedRedirectMessage = false; + + public constructor( + private readonly logger: Logger, + private readonly location: string, + ) { + if (!isAbsolute(location)) { + throw new Error( + `Additional Log Location must be an absolute path: ${location}`, + ); + } + } + + async log(message: string, options = {} as LogOptions): Promise { + if (!this.emittedRedirectMessage) { + this.emittedRedirectMessage = true; + const msg = `| Log being saved to ${this.location} |`; + const separator = new Array(msg.length).fill("-").join(""); + await this.logger.log(separator); + await this.logger.log(msg); + await this.logger.log(separator); + } + + const trailingNewline = options.trailingNewline ?? true; + await ensureFile(this.location); + + await appendFile(this.location, message + (trailingNewline ? "\n" : ""), { + encoding: "utf8", + }); + + await this.logger.log(message, options); + } + + show(preserveFocus?: boolean): void { + this.logger.show(preserveFocus); + } +} diff --git a/extensions/ql-vscode/src/common/logging/vscode/output-channel-logger.ts b/extensions/ql-vscode/src/common/logging/vscode/output-channel-logger.ts index ed0baa0e2..4ea5db56d 100644 --- a/extensions/ql-vscode/src/common/logging/vscode/output-channel-logger.ts +++ b/extensions/ql-vscode/src/common/logging/vscode/output-channel-logger.ts @@ -1,6 +1,4 @@ import { window as Window, OutputChannel, Progress } from "vscode"; -import { ensureFile, appendFile } from "fs-extra"; -import { isAbsolute } from "path"; import { Logger, LogOptions } from "../logger"; import { DisposableObject } from "../../../pure/disposable-object"; @@ -9,10 +7,6 @@ import { DisposableObject } from "../../../pure/disposable-object"; */ export class OutputChannelLogger extends DisposableObject implements Logger { public readonly outputChannel: OutputChannel; - private readonly additionalLocations = new Map< - string, - AdditionalLogLocation - >(); isCustomLogDirectory: boolean; constructor(title: string) { @@ -32,27 +26,6 @@ export class OutputChannelLogger extends DisposableObject implements Logger { } else { this.outputChannel.append(message); } - - if (options.additionalLogLocation) { - if (!isAbsolute(options.additionalLogLocation)) { - throw new Error( - `Additional Log Location must be an absolute path: ${options.additionalLogLocation}`, - ); - } - const logPath = options.additionalLogLocation; - let additional = this.additionalLocations.get(logPath); - if (!additional) { - const msg = `| Log being saved to ${logPath} |`; - const separator = new Array(msg.length).fill("-").join(""); - this.outputChannel.appendLine(separator); - this.outputChannel.appendLine(msg); - this.outputChannel.appendLine(separator); - additional = new AdditionalLogLocation(logPath); - this.additionalLocations.set(logPath, additional); - } - - await additional.log(message, options); - } } catch (e) { if (e instanceof Error && e.message === "Channel has been closed") { // Output channel is closed logging to console instead @@ -69,31 +42,6 @@ export class OutputChannelLogger extends DisposableObject implements Logger { show(preserveFocus?: boolean): void { this.outputChannel.show(preserveFocus); } - - removeAdditionalLogLocation(location: string | undefined): void { - if (location) { - this.additionalLocations.delete(location); - } - } -} - -class AdditionalLogLocation { - constructor(private location: string) {} - - async log(message: string, options = {} as LogOptions): Promise { - if (options.trailingNewline === undefined) { - options.trailingNewline = true; - } - await ensureFile(this.location); - - await appendFile( - this.location, - message + (options.trailingNewline ? "\n" : ""), - { - encoding: "utf8", - }, - ); - } } export type ProgressReporter = Progress<{ message: string }>; diff --git a/extensions/ql-vscode/src/legacy-query-server/queryserver-client.ts b/extensions/ql-vscode/src/legacy-query-server/queryserver-client.ts index 36146da31..3cec4d0e7 100644 --- a/extensions/ql-vscode/src/legacy-query-server/queryserver-client.ts +++ b/extensions/ql-vscode/src/legacy-query-server/queryserver-client.ts @@ -1,4 +1,3 @@ -import { dirname } from "path"; import { ensureFile } from "fs-extra"; import { DisposableObject } from "../pure/disposable-object"; @@ -13,10 +12,8 @@ import { progress, ProgressMessage, WithProgressId, - compileQuery, } from "../pure/legacy-messages"; import { ProgressCallback, ProgressTask } from "../commandRunner"; -import { findQueryLogFile } from "../run-queries-shared"; import { ServerProcess } from "../json-rpc-server"; type WithProgressReporting = ( @@ -56,7 +53,7 @@ export class QueryServerClient extends DisposableObject { this.queryServerStartListeners.push(e); }; - public activeQueryLogFile: string | undefined; + public activeQueryLogger: Logger; constructor( readonly config: QueryServerConfig, @@ -65,6 +62,9 @@ export class QueryServerClient extends DisposableObject { withProgressReporting: WithProgressReporting, ) { super(); + // Since no query is active when we initialize, just point the "active query logger" to the + // default logger. + this.activeQueryLogger = this.logger; // When the query server configuration changes, restart the query server. if (config.onDidChangeConfiguration !== undefined) { this.push( @@ -177,9 +177,8 @@ export class QueryServerClient extends DisposableObject { args, this.logger, (data) => - this.logger.log(data.toString(), { + this.activeQueryLogger.log(data.toString(), { trailingNewline: false, - additionalLogLocation: this.activeQueryLogFile, }), undefined, // no listener for stdout progressReporter, @@ -240,8 +239,6 @@ export class QueryServerClient extends DisposableObject { ): Promise { const id = this.nextProgress++; this.progressCallbacks[id] = progress; - - this.updateActiveQuery(type.method, parameter); try { if (this.serverProcess === undefined) { throw new Error("No query server process found."); @@ -255,18 +252,4 @@ export class QueryServerClient extends DisposableObject { delete this.progressCallbacks[id]; } } - - /** - * Updates the active query every time there is a new request to compile. - * The active query is used to specify the side log. - * - * This isn't ideal because in situations where there are queries running - * in parallel, each query's log messages are interleaved. Fixing this - * properly will require a change in the query server. - */ - private updateActiveQuery(method: string, parameter: any): void { - if (method === compileQuery.method) { - this.activeQueryLogFile = findQueryLogFile(dirname(parameter.resultPath)); - } - } } diff --git a/extensions/ql-vscode/src/legacy-query-server/run-queries.ts b/extensions/ql-vscode/src/legacy-query-server/run-queries.ts index 0326d5c24..a60f8da49 100644 --- a/extensions/ql-vscode/src/legacy-query-server/run-queries.ts +++ b/extensions/ql-vscode/src/legacy-query-server/run-queries.ts @@ -15,7 +15,7 @@ import { } from "../helpers"; import { ProgressCallback } from "../commandRunner"; import { QueryMetadata } from "../pure/interface-types"; -import { extLogger } from "../common"; +import { extLogger, Logger, TeeLogger } from "../common"; import * as messages from "../pure/legacy-messages"; import { InitialQueryInfo, LocalQueryInfo } from "../query-results"; import * as qsClient from "./queryserver-client"; @@ -66,7 +66,8 @@ export class QueryInProgress { dbItem: DatabaseItem, progress: ProgressCallback, token: CancellationToken, - queryInfo?: LocalQueryInfo, + logger: Logger, + queryInfo: LocalQueryInfo | undefined, ): Promise { if (!dbItem.contents || dbItem.error) { throw new Error("Can't run query on invalid database."); @@ -137,7 +138,7 @@ export class QueryInProgress { await this.queryEvalInfo.addQueryLogs( queryInfo, qs.cliServer, - qs.logger, + logger, ); } else { void showAndLogWarningMessage( @@ -162,6 +163,7 @@ export class QueryInProgress { program: messages.QlProgram, progress: ProgressCallback, token: CancellationToken, + logger: Logger, ): Promise { let compiled: messages.CheckQueryResult | undefined; try { @@ -190,6 +192,11 @@ export class QueryInProgress { target, }; + // Update the active query logger every time there is a new request to compile. + // This isn't ideal because in situations where there are queries running + // in parallel, each query's log messages are interleaved. Fixing this + // properly will require a change in the query server. + qs.activeQueryLogger = logger; compiled = await qs.sendRequest( messages.compileQuery, params, @@ -197,9 +204,7 @@ export class QueryInProgress { progress, ); } finally { - void qs.logger.log(" - - - COMPILATION DONE - - - ", { - additionalLogLocation: this.queryEvalInfo.logPath, - }); + void logger.log(" - - - COMPILATION DONE - - - "); } return (compiled?.messages || []).filter( (msg) => msg.severity === messages.Severity.ERROR, @@ -386,6 +391,8 @@ export async function compileAndRunQueryAgainstDatabase( metadata, templates, ); + const logger = new TeeLogger(qs.logger, query.queryEvalInfo.logPath); + await query.queryEvalInfo.createTimestampFile(); let upgradeDir: tmp.DirectoryResult | undefined; @@ -402,7 +409,7 @@ export async function compileAndRunQueryAgainstDatabase( ); let errors; try { - errors = await query.compile(qs, qlProgram, progress, token); + errors = await query.compile(qs, qlProgram, progress, token, logger); } catch (e) { if ( e instanceof ResponseError && @@ -422,6 +429,7 @@ export async function compileAndRunQueryAgainstDatabase( dbItem, progress, token, + logger, queryInfo, ); if (result.resultType !== messages.QueryResultType.SUCCESS) { @@ -439,18 +447,14 @@ export async function compileAndRunQueryAgainstDatabase( result, successful: result.resultType === messages.QueryResultType.SUCCESS, logFileLocation: result.logFileLocation, - dispose: () => { - qs.logger.removeAdditionalLogLocation(result.logFileLocation); - }, }; } else { // Error dialogs are limited in size and scrollability, // so we include a general description of the problem, // and direct the user to the output window for the detailed compilation messages. // However we don't show quick eval errors there so we need to display them anyway. - void qs.logger.log( + void logger.log( `Failed to compile query ${initialInfo.queryPath} against database scheme ${qlProgram.dbschemePath}:`, - { additionalLogLocation: query.queryEvalInfo.logPath }, ); const formattedMessages: string[] = []; @@ -459,9 +463,7 @@ export async function compileAndRunQueryAgainstDatabase( const message = error.message || "[no error message available]"; const formatted = `ERROR: ${message} (${error.position.fileName}:${error.position.line}:${error.position.column}:${error.position.endLine}:${error.position.endColumn})`; formattedMessages.push(formatted); - void qs.logger.log(formatted, { - additionalLogLocation: query.queryEvalInfo.logPath, - }); + void logger.log(formatted); } if (initialInfo.isQuickEval && formattedMessages.length <= 2) { // If there are more than 2 error messages, they will not be displayed well in a popup @@ -484,9 +486,8 @@ export async function compileAndRunQueryAgainstDatabase( try { await upgradeDir?.cleanup(); } catch (e) { - void qs.logger.log( + void logger.log( `Could not clean up the upgrades dir. Reason: ${getErrorMessage(e)}`, - { additionalLogLocation: query.queryEvalInfo.logPath }, ); } } @@ -535,9 +536,6 @@ function createSyntheticResult( runId: 0, }, successful: false, - dispose: () => { - /**/ - }, }; } diff --git a/extensions/ql-vscode/src/query-history/query-history-manager.ts b/extensions/ql-vscode/src/query-history/query-history-manager.ts index daffbb9d5..83b9694e5 100644 --- a/extensions/ql-vscode/src/query-history/query-history-manager.ts +++ b/extensions/ql-vscode/src/query-history/query-history-manager.ts @@ -556,7 +556,6 @@ export class QueryHistoryManager extends DisposableObject { !(await pathExists(item.completedQuery?.query.querySaveDir)) ) { this.treeDataProvider.remove(item); - item.completedQuery?.dispose(); } }), ); @@ -577,7 +576,6 @@ export class QueryHistoryManager extends DisposableObject { // Removing in progress local queries is not supported. They must be cancelled first. if (item.status !== QueryStatus.InProgress) { this.treeDataProvider.remove(item); - item.completedQuery?.dispose(); // User has explicitly asked for this query to be removed. // We need to delete it from disk as well. diff --git a/extensions/ql-vscode/src/query-results.ts b/extensions/ql-vscode/src/query-results.ts index c9f3f2d93..33100bde8 100644 --- a/extensions/ql-vscode/src/query-results.ts +++ b/extensions/ql-vscode/src/query-results.ts @@ -55,11 +55,6 @@ export class CompletedQueryInfo implements QueryWithResults { readonly logFileLocation?: string; resultCount: number; - /** - * This dispose method is called when the query is removed from the history view. - */ - dispose: () => void; - /** * Map from result set name to SortedResultSetInfo. */ @@ -85,10 +80,6 @@ export class CompletedQueryInfo implements QueryWithResults { this.message = evaluation.message; this.successful = evaluation.successful; - // Use the dispose method from the evaluation. - // The dispose will clean up any additional log locations that this - // query may have created. - this.dispose = evaluation.dispose; this.sortedResultsInfo = {}; this.resultCount = 0; diff --git a/extensions/ql-vscode/src/query-serialization.ts b/extensions/ql-vscode/src/query-serialization.ts index c2611a06b..a83d4a1a8 100644 --- a/extensions/ql-vscode/src/query-serialization.ts +++ b/extensions/ql-vscode/src/query-serialization.ts @@ -55,10 +55,6 @@ export async function deserializeQueryHistory( q.completedQuery.query, QueryEvaluationInfo.prototype, ); - // deserialized queries do not need to be disposed - q.completedQuery.dispose = () => { - /**/ - }; // Previously, there was a typo in the completedQuery type. There was a field // `sucessful` and it was renamed to `successful`. We need to handle this case. diff --git a/extensions/ql-vscode/src/query-server/queryserver-client.ts b/extensions/ql-vscode/src/query-server/queryserver-client.ts index 824e3bae8..80bda904c 100644 --- a/extensions/ql-vscode/src/query-server/queryserver-client.ts +++ b/extensions/ql-vscode/src/query-server/queryserver-client.ts @@ -1,4 +1,3 @@ -import { dirname } from "path"; import { ensureFile } from "fs-extra"; import { DisposableObject } from "../pure/disposable-object"; @@ -12,9 +11,7 @@ import { ProgressMessage, WithProgressId, } from "../pure/new-messages"; -import * as messages from "../pure/new-messages"; import { ProgressCallback, ProgressTask } from "../commandRunner"; -import { findQueryLogFile } from "../run-queries-shared"; import { ServerProcess } from "../json-rpc-server"; type ServerOpts = { @@ -53,7 +50,7 @@ export class QueryServerClient extends DisposableObject { this.queryServerStartListeners.push(e); }; - public activeQueryLogFile: string | undefined; + public activeQueryLogger: Logger; constructor( readonly config: QueryServerConfig, @@ -62,6 +59,9 @@ export class QueryServerClient extends DisposableObject { withProgressReporting: WithProgressReporting, ) { super(); + // Since no query is active when we initialize, just point the "active query logger" to the + // default logger. + this.activeQueryLogger = this.logger; // When the query server configuration changes, restart the query server. if (config.onDidChangeConfiguration !== undefined) { this.push( @@ -167,9 +167,8 @@ export class QueryServerClient extends DisposableObject { args, this.logger, (data) => - this.logger.log(data.toString(), { + this.activeQueryLogger.log(data.toString(), { trailingNewline: false, - additionalLogLocation: this.activeQueryLogFile, }), undefined, // no listener for stdout progressReporter, @@ -210,7 +209,6 @@ export class QueryServerClient extends DisposableObject { const id = this.nextProgress++; this.progressCallbacks[id] = progress; - this.updateActiveQuery(type.method, parameter); try { if (this.serverProcess === undefined) { throw new Error("No query server process found."); @@ -224,20 +222,4 @@ export class QueryServerClient extends DisposableObject { delete this.progressCallbacks[id]; } } - - /** - * Updates the active query every time there is a new request to compile. - * The active query is used to specify the side log. - * - * This isn't ideal because in situations where there are queries running - * in parallel, each query's log messages are interleaved. Fixing this - * properly will require a change in the query server. - */ - private updateActiveQuery(method: string, parameter: any): void { - if (method === messages.runQuery.method) { - this.activeQueryLogFile = findQueryLogFile( - dirname(dirname((parameter as messages.RunQueryParams).outputPath)), - ); - } - } } diff --git a/extensions/ql-vscode/src/query-server/run-queries.ts b/extensions/ql-vscode/src/query-server/run-queries.ts index f9ee0a6d7..f63203d89 100644 --- a/extensions/ql-vscode/src/query-server/run-queries.ts +++ b/extensions/ql-vscode/src/query-server/run-queries.ts @@ -9,7 +9,7 @@ import { showAndLogWarningMessage, tryGetQueryMetadata, } from "../helpers"; -import { extLogger } from "../common"; +import { extLogger, TeeLogger } from "../common"; import * as messages from "../pure/new-messages"; import { QueryResultType } from "../pure/legacy-messages"; import { InitialQueryInfo, LocalQueryInfo } from "../query-results"; @@ -88,9 +88,15 @@ export async function compileAndRunQueryAgainstDatabase( target, extensionPacks, }; + const logger = new TeeLogger(qs.logger, query.logPath); await query.createTimestampFile(); let result: messages.RunQueryResult | undefined; try { + // Update the active query logger every time there is a new request to compile. + // This isn't ideal because in situations where there are queries running + // in parallel, each query's log messages are interleaved. Fixing this + // properly will require a change in the query server. + qs.activeQueryLogger = logger; result = await qs.sendRequest( messages.runQuery, queryToRun, @@ -105,7 +111,7 @@ export async function compileAndRunQueryAgainstDatabase( } finally { if (queryInfo) { if (await query.hasEvalLog()) { - await query.addQueryLogs(queryInfo, qs.cliServer, qs.logger); + await query.addQueryLogs(queryInfo, qs.cliServer, logger); } else { void showAndLogWarningMessage( `Failed to write structured evaluator log to ${query.evalLogPath}.`, @@ -160,8 +166,5 @@ export async function compileAndRunQueryAgainstDatabase( }, message, successful, - dispose: () => { - qs.logger.removeAdditionalLogLocation(undefined); - }, }; } diff --git a/extensions/ql-vscode/src/run-queries-shared.ts b/extensions/ql-vscode/src/run-queries-shared.ts index 66f85e7e1..41fae0321 100644 --- a/extensions/ql-vscode/src/run-queries-shared.ts +++ b/extensions/ql-vscode/src/run-queries-shared.ts @@ -298,12 +298,8 @@ export class QueryEvaluationInfo { this.evalLogEndSummaryPath, "utf-8", ); - void logger.log(" --- Evaluator Log Summary --- ", { - additionalLogLocation: this.logPath, - }); - void logger.log(endSummaryContent, { - additionalLogLocation: this.logPath, - }); + void logger.log(" --- Evaluator Log Summary --- "); + void logger.log(endSummaryContent); } catch (e) { void showAndLogWarningMessage( `Could not read structured evaluator log end of summary file at ${this.evalLogEndSummaryPath}.`, @@ -436,7 +432,6 @@ export class QueryEvaluationInfo { export interface QueryWithResults { readonly query: QueryEvaluationInfo; readonly logFileLocation?: string; - readonly dispose: () => void; readonly successful?: boolean; readonly message?: string; readonly result: legacyMessages.EvaluationResult; diff --git a/extensions/ql-vscode/test/__mocks__/loggerMock.ts b/extensions/ql-vscode/test/__mocks__/loggerMock.ts index 665720357..ff69b0f6e 100644 --- a/extensions/ql-vscode/test/__mocks__/loggerMock.ts +++ b/extensions/ql-vscode/test/__mocks__/loggerMock.ts @@ -4,6 +4,5 @@ export function createMockLogger(): Logger { return { log: jest.fn(() => Promise.resolve()), show: jest.fn(), - removeAdditionalLogLocation: jest.fn(), }; } diff --git a/extensions/ql-vscode/test/common/logging/output-channel-logger.test.ts b/extensions/ql-vscode/test/common/logging/output-channel-logger.test.ts index a15bea5aa..b05ebdb17 100644 --- a/extensions/ql-vscode/test/common/logging/output-channel-logger.test.ts +++ b/extensions/ql-vscode/test/common/logging/output-channel-logger.test.ts @@ -1,7 +1,7 @@ import { readdirSync, readFileSync } from "fs-extra"; import { join } from "path"; import * as tmp from "tmp"; -import { OutputChannelLogger } from "../../../src/common"; +import { Logger, OutputChannelLogger, TeeLogger } from "../../../src/common"; jest.setTimeout(999999); @@ -58,16 +58,19 @@ describe("OutputChannelLogger tests", function () { expect(mockOutputChannel.appendLine).not.toBeCalledWith("yyy"); expect(mockOutputChannel.append).toBeCalledWith("yyy"); - await logger.log("zzz", createLogOptions("hucairz")); + const hucairz = createSideLogger(logger, "hucairz"); + await hucairz.log("zzz"); // should have created 1 side log expect(readdirSync(tempFolders.storagePath.name)).toEqual(["hucairz"]); }); it("should create a side log", async () => { - await logger.log("xxx", createLogOptions("first")); - await logger.log("yyy", createLogOptions("second")); - await logger.log("zzz", createLogOptions("first", false)); + const first = createSideLogger(logger, "first"); + await first.log("xxx"); + const second = createSideLogger(logger, "second"); + await second.log("yyy"); + await first.log("zzz", { trailingNewline: false }); await logger.log("aaa"); // expect 2 side logs @@ -82,16 +85,13 @@ describe("OutputChannelLogger tests", function () { ).toBe("yyy\n"); }); - function createLogOptions( + function createSideLogger( + logger: Logger, additionalLogLocation: string, - trailingNewline?: boolean, - ) { - return { - additionalLogLocation: join( - tempFolders.storagePath.name, - additionalLogLocation, - ), - trailingNewline, - }; + ): Logger { + return new TeeLogger( + logger, + join(tempFolders.storagePath.name, additionalLogLocation), + ); } }); From 56095d365c3af8b944271c22c0acdfdf580fde9a Mon Sep 17 00:00:00 2001 From: Dave Bartolomeo Date: Mon, 13 Mar 2023 17:28:53 -0400 Subject: [PATCH 018/156] Fix test code --- .../test/factories/query-history/local-query-history-item.ts | 2 -- .../no-workspace/query-history/query-history-manager.test.ts | 2 -- .../test/vscode-tests/no-workspace/query-results.test.ts | 1 - .../test/vscode-tests/no-workspace/query-serialization.test.ts | 1 - .../test/vscode-tests/no-workspace/run-queries.test.ts | 1 + 5 files changed, 1 insertion(+), 6 deletions(-) diff --git a/extensions/ql-vscode/test/factories/query-history/local-query-history-item.ts b/extensions/ql-vscode/test/factories/query-history/local-query-history-item.ts index 157f60f3b..a67de64b0 100644 --- a/extensions/ql-vscode/test/factories/query-history/local-query-history-item.ts +++ b/extensions/ql-vscode/test/factories/query-history/local-query-history-item.ts @@ -74,7 +74,6 @@ export function createMockQueryWithResults({ hasInterpretedResults?: boolean; hasMetadata?: boolean; }): QueryWithResults { - const dispose = jest.fn(); const deleteQuery = jest.fn(); const metadata = hasMetadata ? ({ name: "query-name" } as QueryMetadata) @@ -87,7 +86,6 @@ export function createMockQueryWithResults({ metadata, } as unknown as QueryEvaluationInfo, successful: didRunSuccessfully, - dispose, result: { evaluationTime: 1, queryId: 0, diff --git a/extensions/ql-vscode/test/vscode-tests/no-workspace/query-history/query-history-manager.test.ts b/extensions/ql-vscode/test/vscode-tests/no-workspace/query-history/query-history-manager.test.ts index 07dfbe51d..b02ba6833 100644 --- a/extensions/ql-vscode/test/vscode-tests/no-workspace/query-history/query-history-manager.test.ts +++ b/extensions/ql-vscode/test/vscode-tests/no-workspace/query-history/query-history-manager.test.ts @@ -344,7 +344,6 @@ describe("QueryHistoryManager", () => { }); it("should remove the item", () => { - expect(toDelete.completedQuery!.dispose).toBeCalledTimes(1); expect(queryHistoryManager.treeDataProvider.allHistory).toEqual( expect.not.arrayContaining([toDelete]), ); @@ -387,7 +386,6 @@ describe("QueryHistoryManager", () => { }); it("should remove the item", () => { - expect(toDelete.completedQuery!.dispose).toBeCalledTimes(1); expect(queryHistoryManager.treeDataProvider.allHistory).toEqual( expect.not.arrayContaining([toDelete]), ); diff --git a/extensions/ql-vscode/test/vscode-tests/no-workspace/query-results.test.ts b/extensions/ql-vscode/test/vscode-tests/no-workspace/query-results.test.ts index 14992fee2..e32078ccc 100644 --- a/extensions/ql-vscode/test/vscode-tests/no-workspace/query-results.test.ts +++ b/extensions/ql-vscode/test/vscode-tests/no-workspace/query-results.test.ts @@ -470,7 +470,6 @@ describe("query-results", () => { query: query.queryEvalInfo, successful: didRunSuccessfully, message: "foo", - dispose: jest.fn(), result: { evaluationTime: 1, queryId: 0, diff --git a/extensions/ql-vscode/test/vscode-tests/no-workspace/query-serialization.test.ts b/extensions/ql-vscode/test/vscode-tests/no-workspace/query-serialization.test.ts index 5b22b9aef..4eea14a61 100644 --- a/extensions/ql-vscode/test/vscode-tests/no-workspace/query-serialization.test.ts +++ b/extensions/ql-vscode/test/vscode-tests/no-workspace/query-serialization.test.ts @@ -259,7 +259,6 @@ describe("serialize and deserialize", () => { query: query.queryEvalInfo, successful: didRunSuccessfully, message: "foo", - dispose: jest.fn(), result: { evaluationTime: 1, queryId: 0, diff --git a/extensions/ql-vscode/test/vscode-tests/no-workspace/run-queries.test.ts b/extensions/ql-vscode/test/vscode-tests/no-workspace/run-queries.test.ts index f7f74c5e3..d576b1004 100644 --- a/extensions/ql-vscode/test/vscode-tests/no-workspace/run-queries.test.ts +++ b/extensions/ql-vscode/test/vscode-tests/no-workspace/run-queries.test.ts @@ -190,6 +190,7 @@ describe("run-queries", () => { mockQlProgram, mockProgress as any, mockCancel as any, + qs.logger, ); expect(results).toEqual([{ message: "err", severity: Severity.ERROR }]); From a1d8aac3919ae9e5c082a29c1d65f4b3d998b6db Mon Sep 17 00:00:00 2001 From: Dave Bartolomeo Date: Mon, 13 Mar 2023 17:33:52 -0400 Subject: [PATCH 019/156] Better handling of I/O errors when writing to side log --- .../src/common/logging/tee-logger.ts | 31 +++++++++++++++---- 1 file changed, 25 insertions(+), 6 deletions(-) diff --git a/extensions/ql-vscode/src/common/logging/tee-logger.ts b/extensions/ql-vscode/src/common/logging/tee-logger.ts index c64ac93e6..ddd6162eb 100644 --- a/extensions/ql-vscode/src/common/logging/tee-logger.ts +++ b/extensions/ql-vscode/src/common/logging/tee-logger.ts @@ -1,5 +1,6 @@ import { appendFile, ensureFile } from "fs-extra"; import { isAbsolute } from "path"; +import { getErrorMessage } from "../../pure/helpers-pure"; import { Logger, LogOptions } from "./logger"; /** @@ -11,6 +12,7 @@ import { Logger, LogOptions } from "./logger"; */ export class TeeLogger implements Logger { private emittedRedirectMessage = false; + private error = false; public constructor( private readonly logger: Logger, @@ -33,14 +35,31 @@ export class TeeLogger implements Logger { await this.logger.log(separator); } - const trailingNewline = options.trailingNewline ?? true; - await ensureFile(this.location); + if (!this.error) { + try { + const trailingNewline = options.trailingNewline ?? true; + await ensureFile(this.location); - await appendFile(this.location, message + (trailingNewline ? "\n" : ""), { - encoding: "utf8", - }); + await appendFile( + this.location, + message + (trailingNewline ? "\n" : ""), + { + encoding: "utf8", + }, + ); + } catch (e) { + // Write an error message to the primary log, and stop trying to write to the side log. + this.error = true; + const errorMessage = getErrorMessage(e); + await this.logger.log( + `Error writing to additional log file: ${errorMessage}`, + ); + } + } - await this.logger.log(message, options); + if (!this.error) { + await this.logger.log(message, options); + } } show(preserveFocus?: boolean): void { From 964640c757412993601f434388f5da434ce9cd29 Mon Sep 17 00:00:00 2001 From: Koen Vlaswinkel Date: Tue, 14 Mar 2023 11:00:59 +0100 Subject: [PATCH 020/156] Remove default location values in withProgress calls --- .../src/contextual/templateProvider.ts | 3 - extensions/ql-vscode/src/extension.ts | 1 - extensions/ql-vscode/src/local-databases.ts | 116 ++++++++---------- 3 files changed, 54 insertions(+), 66 deletions(-) diff --git a/extensions/ql-vscode/src/contextual/templateProvider.ts b/extensions/ql-vscode/src/contextual/templateProvider.ts index 1e2865d99..4b53146d4 100644 --- a/extensions/ql-vscode/src/contextual/templateProvider.ts +++ b/extensions/ql-vscode/src/contextual/templateProvider.ts @@ -4,7 +4,6 @@ import { Location, LocationLink, Position, - ProgressLocation, ReferenceContext, ReferenceProvider, TextDocument, @@ -87,7 +86,6 @@ export class TemplateQueryDefinitionProvider implements DefinitionProvider { ); }, { - location: ProgressLocation.Notification, cancellable: true, title: "Finding definitions", }, @@ -150,7 +148,6 @@ export class TemplateQueryReferenceProvider implements ReferenceProvider { ); }, { - location: ProgressLocation.Notification, cancellable: true, title: "Finding references", }, diff --git a/extensions/ql-vscode/src/extension.ts b/extensions/ql-vscode/src/extension.ts index eb9420b82..5b4edf7cd 100644 --- a/extensions/ql-vscode/src/extension.ts +++ b/extensions/ql-vscode/src/extension.ts @@ -329,7 +329,6 @@ export async function activate( ), { title: progressTitle, - location: ProgressLocation.Notification, }, ); diff --git a/extensions/ql-vscode/src/local-databases.ts b/extensions/ql-vscode/src/local-databases.ts index c1d281474..9542ef767 100644 --- a/extensions/ql-vscode/src/local-databases.ts +++ b/extensions/ql-vscode/src/local-databases.ts @@ -794,74 +794,66 @@ export class DatabaseManager extends DisposableObject { } public async loadPersistedState(): Promise { - return withProgress( - async (progress, token) => { - const currentDatabaseUri = - this.ctx.workspaceState.get(CURRENT_DB); - const databases = this.ctx.workspaceState.get( - DB_LIST, - [], + return withProgress(async (progress, token) => { + const currentDatabaseUri = + this.ctx.workspaceState.get(CURRENT_DB); + const databases = this.ctx.workspaceState.get( + DB_LIST, + [], + ); + let step = 0; + progress({ + maxStep: databases.length, + message: "Loading persisted databases", + step, + }); + try { + void this.logger.log( + `Found ${databases.length} persisted databases: ${databases + .map((db) => db.uri) + .join(", ")}`, ); - let step = 0; - progress({ - maxStep: databases.length, - message: "Loading persisted databases", - step, - }); - try { - void this.logger.log( - `Found ${databases.length} persisted databases: ${databases - .map((db) => db.uri) - .join(", ")}`, - ); - for (const database of databases) { - progress({ - maxStep: databases.length, - message: `Loading ${ - database.options?.displayName || "databases" - }`, - step: ++step, - }); + for (const database of databases) { + progress({ + maxStep: databases.length, + message: `Loading ${database.options?.displayName || "databases"}`, + step: ++step, + }); - const databaseItem = - await this.createDatabaseItemFromPersistedState( - progress, - token, - database, - ); - try { - await databaseItem.refresh(); - await this.registerDatabase(progress, token, databaseItem); - if (currentDatabaseUri === database.uri) { - await this.setCurrentDatabaseItem(databaseItem, true); - } - void this.logger.log( - `Loaded database ${databaseItem.name} at URI ${database.uri}.`, - ); - } catch (e) { - // When loading from persisted state, leave invalid databases in the list. They will be - // marked as invalid, and cannot be set as the current database. - void this.logger.log( - `Error loading database ${database.uri}: ${e}.`, - ); + const databaseItem = await this.createDatabaseItemFromPersistedState( + progress, + token, + database, + ); + try { + await databaseItem.refresh(); + await this.registerDatabase(progress, token, databaseItem); + if (currentDatabaseUri === database.uri) { + await this.setCurrentDatabaseItem(databaseItem, true); } + void this.logger.log( + `Loaded database ${databaseItem.name} at URI ${database.uri}.`, + ); + } catch (e) { + // When loading from persisted state, leave invalid databases in the list. They will be + // marked as invalid, and cannot be set as the current database. + void this.logger.log( + `Error loading database ${database.uri}: ${e}.`, + ); } - await this.updatePersistedDatabaseList(); - } catch (e) { - // database list had an unexpected type - nothing to be done? - void showAndLogExceptionWithTelemetry( - redactableError( - asError(e), - )`Database list loading failed: ${getErrorMessage(e)}`, - ); } + await this.updatePersistedDatabaseList(); + } catch (e) { + // database list had an unexpected type - nothing to be done? + void showAndLogExceptionWithTelemetry( + redactableError( + asError(e), + )`Database list loading failed: ${getErrorMessage(e)}`, + ); + } - void this.logger.log("Finished loading persisted databases."); - }, - { - location: vscode.ProgressLocation.Notification, - }, - ); + void this.logger.log("Finished loading persisted databases."); + }); } public get databaseItems(): readonly DatabaseItem[] { From c3b023cf4ba412da947ec82b8bbd4d7ab1671ed9 Mon Sep 17 00:00:00 2001 From: Koen Vlaswinkel Date: Tue, 14 Mar 2023 13:09:27 +0100 Subject: [PATCH 021/156] Convert run variant analysis command to new commands package --- extensions/ql-vscode/src/common/commands.ts | 3 ++ extensions/ql-vscode/src/extension.ts | 49 ------------------- .../variant-analysis-manager.ts | 32 +++++++++++- 3 files changed, 34 insertions(+), 50 deletions(-) diff --git a/extensions/ql-vscode/src/common/commands.ts b/extensions/ql-vscode/src/common/commands.ts index ebc0dc82d..727f59610 100644 --- a/extensions/ql-vscode/src/common/commands.ts +++ b/extensions/ql-vscode/src/common/commands.ts @@ -1,4 +1,5 @@ import { CommandManager } from "../packages/commands"; +import type { Uri } from "vscode"; /** * Contains type definitions for all commands used by the extension. @@ -17,6 +18,8 @@ export type VariantAnalysisCommands = { "codeQL.openVariantAnalysisLogs": ( variantAnalysisId: number, ) => Promise; + "codeQL.runVariantAnalysis": (uri?: Uri) => Promise; + "codeQL.runVariantAnalysisContextEditor": (uri?: Uri) => Promise; }; export type AllCommands = ExtensionCommands & VariantAnalysisCommands; diff --git a/extensions/ql-vscode/src/extension.ts b/extensions/ql-vscode/src/extension.ts index eedff0247..c44a2bf2a 100644 --- a/extensions/ql-vscode/src/extension.ts +++ b/extensions/ql-vscode/src/extension.ts @@ -1151,55 +1151,6 @@ async function activateWithInstalledDistribution( ), ); - async function runVariantAnalysis( - progress: ProgressCallback, - token: CancellationToken, - uri: Uri | undefined, - ): Promise { - progress({ - maxStep: 5, - step: 0, - message: "Getting credentials", - }); - - await variantAnalysisManager.runVariantAnalysis( - uri || window.activeTextEditor?.document.uri, - progress, - token, - ); - } - - ctx.subscriptions.push( - commandRunnerWithProgress( - "codeQL.runVariantAnalysis", - async ( - progress: ProgressCallback, - token: CancellationToken, - uri: Uri | undefined, - ) => await runVariantAnalysis(progress, token, uri), - { - title: "Run Variant Analysis", - cancellable: true, - }, - ), - ); - - // Since we are tracking extension usage through commands, this command mirrors the "codeQL.runVariantAnalysis" command - ctx.subscriptions.push( - commandRunnerWithProgress( - "codeQL.runVariantAnalysisContextEditor", - async ( - progress: ProgressCallback, - token: CancellationToken, - uri: Uri | undefined, - ) => await runVariantAnalysis(progress, token, uri), - { - title: "Run Variant Analysis", - cancellable: true, - }, - ), - ); - const allCommands: AllCommands = { ...getCommands(), ...variantAnalysisManager.getCommands(), diff --git a/extensions/ql-vscode/src/variant-analysis/variant-analysis-manager.ts b/extensions/ql-vscode/src/variant-analysis/variant-analysis-manager.ts index 57065ff87..c9caefba1 100644 --- a/extensions/ql-vscode/src/variant-analysis/variant-analysis-manager.ts +++ b/extensions/ql-vscode/src/variant-analysis/variant-analysis-manager.ts @@ -51,7 +51,11 @@ import { import { readFile, readJson, remove, pathExists, outputJson } from "fs-extra"; import { EOL } from "os"; import { cancelVariantAnalysis } from "./gh-api/gh-actions-api-client"; -import { ProgressCallback, UserCancellationException } from "../commandRunner"; +import { + ProgressCallback, + UserCancellationException, + withProgress, +} from "../commandRunner"; import { CodeQLCliServer } from "../cli"; import { defaultFilterSortState, @@ -132,6 +136,11 @@ export class VariantAnalysisManager "codeQL.openVariantAnalysisLogs": async (variantAnalysisId: number) => { await this.openVariantAnalysisLogs(variantAnalysisId); }, + "codeQL.runVariantAnalysis": async (uri?: Uri) => + this.runVariantAnalysisFromCommand(uri), + // Since we are tracking extension usage through commands, this command mirrors the "codeQL.runVariantAnalysis" command + "codeQL.runVariantAnalysisContextEditor": async (uri?: Uri) => + this.runVariantAnalysisFromCommand(uri), }; } @@ -139,11 +148,32 @@ export class VariantAnalysisManager return this.app.commandManager; } + private async runVariantAnalysisFromCommand(uri?: Uri) { + return withProgress( + async (progress, token) => + this.runVariantAnalysis( + uri || Window.activeTextEditor?.document.uri, + progress, + token, + ), + { + title: "Run Variant Analysis", + cancellable: true, + }, + ); + } + public async runVariantAnalysis( uri: Uri | undefined, progress: ProgressCallback, token: CancellationToken, ): Promise { + progress({ + maxStep: 5, + step: 0, + message: "Getting credentials", + }); + const { actionBranch, base64Pack, From b888ca07aebcdb7145cf7f8af3674f3160a7add7 Mon Sep 17 00:00:00 2001 From: Koen Vlaswinkel Date: Tue, 14 Mar 2023 16:10:32 +0100 Subject: [PATCH 022/156] Extract variable for React root --- extensions/ql-vscode/src/view/webview.tsx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/extensions/ql-vscode/src/view/webview.tsx b/extensions/ql-vscode/src/view/webview.tsx index a2f8a6f47..0d134fdb0 100644 --- a/extensions/ql-vscode/src/view/webview.tsx +++ b/extensions/ql-vscode/src/view/webview.tsx @@ -26,7 +26,8 @@ const render = () => { // eslint-disable-next-line @typescript-eslint/no-var-requires const view: WebviewDefinition = require(`./${viewName}/index.tsx`).default; - createRoot(element).render( + const root = createRoot(element); + root.render( // Post a message to the extension when fully loaded. See https://github.com/reactwg/react-18/discussions/5 ("What about the render callback?")
vscode.postMessage({ t: "viewLoaded", viewName })}> {view.component} From db967443ddf312ba599b9729eff4377da851bed8 Mon Sep 17 00:00:00 2001 From: Koen Vlaswinkel Date: Tue, 14 Mar 2023 16:12:48 +0100 Subject: [PATCH 023/156] Remove `viewLoaded` callback comment This removes the comment about the `viewLoaded` callback since it refers to upgrade instructions. --- extensions/ql-vscode/src/view/webview.tsx | 1 - 1 file changed, 1 deletion(-) diff --git a/extensions/ql-vscode/src/view/webview.tsx b/extensions/ql-vscode/src/view/webview.tsx index 0d134fdb0..6663518be 100644 --- a/extensions/ql-vscode/src/view/webview.tsx +++ b/extensions/ql-vscode/src/view/webview.tsx @@ -28,7 +28,6 @@ const render = () => { const root = createRoot(element); root.render( - // Post a message to the extension when fully loaded. See https://github.com/reactwg/react-18/discussions/5 ("What about the render callback?")
vscode.postMessage({ t: "viewLoaded", viewName })}> {view.component}
, From 250dc15fe5410edca19bfd0c041a0b5d78f4e9d8 Mon Sep 17 00:00:00 2001 From: Andrew Eisenberg Date: Tue, 28 Feb 2023 08:22:46 -0800 Subject: [PATCH 024/156] Add extension packs to variant analysis queries This change allows the `codeQL.runningQueries.useExtensionPacks` setting to be respected when running variant analysis queries. When set to `all`, before uploading the generated query pack, all extension packs in the workspace will be injected as dependencies into the qlpack file. --- extensions/ql-vscode/src/cli.ts | 29 ++++++++- extensions/ql-vscode/src/pure/ql.ts | 4 ++ extensions/ql-vscode/src/quick-query.ts | 2 +- .../src/variant-analysis/run-remote-query.ts | 59 ++++++++++--------- .../data-extension-pack/extension-file.yml | 12 ++++ .../data-extension-pack/qlpack.yml | 8 +++ .../variant-analysis-manager.test.ts | 34 ++++++++++- 7 files changed, 115 insertions(+), 33 deletions(-) create mode 100644 extensions/ql-vscode/test/vscode-tests/cli-integration/data-extension-pack/extension-file.yml create mode 100644 extensions/ql-vscode/test/vscode-tests/cli-integration/data-extension-pack/qlpack.yml diff --git a/extensions/ql-vscode/src/cli.ts b/extensions/ql-vscode/src/cli.ts index 321357da1..ae24e905b 100644 --- a/extensions/ql-vscode/src/cli.ts +++ b/extensions/ql-vscode/src/cli.ts @@ -1284,11 +1284,25 @@ export class CodeQLCliServer implements Disposable { ); } - async packInstall(dir: string, forceUpdate = false) { + async packInstall( + dir: string, + { forceUpdate = false, workspaceFolders = [] as string[] } = {}, + ) { const args = [dir]; if (forceUpdate) { args.push("--mode", "update"); } + if (workspaceFolders?.length > 0) { + if (await this.cliConstraints.supportsAdditionalPacksInstall()) { + args.push( + // Allow prerelease packs from the ql submodule. + "--allow-prerelease", + // Allow the use of --additional-packs argument without issueing a warning + "--no-strict-mode", + ...this.getAdditionalPacksArg(workspaceFolders), + ); + } + } return this.runJsonCodeQlCliCommandWithAuthentication( ["pack", "install"], args, @@ -1692,6 +1706,13 @@ export class CliVersionConstraint { */ public static CLI_VERSION_WITH_QLPACKS_KIND = new SemVer("2.12.3"); + /** + * CLI version that supports the `--additional-packs` option for the `pack install` command. + */ + public static CLI_VERSION_WITH_ADDITIONAL_PACKS_INSTALL = new SemVer( + "2.12.4", + ); + constructor(private readonly cli: CodeQLCliServer) { /**/ } @@ -1755,4 +1776,10 @@ export class CliVersionConstraint { CliVersionConstraint.CLI_VERSION_WITH_QLPACKS_KIND, ); } + + async supportsAdditionalPacksInstall() { + return this.isVersionAtLeast( + CliVersionConstraint.CLI_VERSION_WITH_ADDITIONAL_PACKS_INSTALL, + ); + } } diff --git a/extensions/ql-vscode/src/pure/ql.ts b/extensions/ql-vscode/src/pure/ql.ts index 62c2f006a..6bb08d674 100644 --- a/extensions/ql-vscode/src/pure/ql.ts +++ b/extensions/ql-vscode/src/pure/ql.ts @@ -2,6 +2,10 @@ import { join } from "path"; import { pathExists } from "fs-extra"; export const QLPACK_FILENAMES = ["qlpack.yml", "codeql-pack.yml"]; +export const QLPACK_LOCK_FILENAMES = [ + "qlpack.lock.yml", + "codeql-pack.lock.yml", +]; export const FALLBACK_QLPACK_FILENAME = QLPACK_FILENAMES[0]; export async function getQlPackPath( diff --git a/extensions/ql-vscode/src/quick-query.ts b/extensions/ql-vscode/src/quick-query.ts index 7829896d7..4008bdda3 100644 --- a/extensions/ql-vscode/src/quick-query.ts +++ b/extensions/ql-vscode/src/quick-query.ts @@ -143,7 +143,7 @@ export async function displayQuickQuery( if (shouldRewrite) { await cliServer.clearCache(); - await cliServer.packInstall(queriesDir, true); + await cliServer.packInstall(queriesDir, { forceUpdate: true }); } await Window.showTextDocument(await workspace.openTextDocument(qlFile)); diff --git a/extensions/ql-vscode/src/variant-analysis/run-remote-query.ts b/extensions/ql-vscode/src/variant-analysis/run-remote-query.ts index 0ae572c60..2eb1d8a1b 100644 --- a/extensions/ql-vscode/src/variant-analysis/run-remote-query.ts +++ b/extensions/ql-vscode/src/variant-analysis/run-remote-query.ts @@ -34,6 +34,7 @@ import { getQlPackPath, FALLBACK_QLPACK_FILENAME, QLPACK_FILENAMES, + QLPACK_LOCK_FILENAMES, } from "../pure/ql"; export interface QlPack { @@ -86,7 +87,6 @@ async function generateQueryPack( queryFile, queryPackDir, packRelativePath, - workspaceFolders, ); language = await findLanguage(cliServer, Uri.file(targetQueryFileName)); @@ -102,8 +102,6 @@ async function generateQueryPack( targetQueryFileName, language, packRelativePath, - cliServer, - workspaceFolders, ); } if (!language) { @@ -125,11 +123,21 @@ async function generateQueryPack( precompilationOpts = ["--no-precompile"]; } + if (await cliServer.useExtensionPacks()) { + await injectExtensionPacks(cliServer, queryPackDir, workspaceFolders); + } + + await cliServer.packInstall(queryPackDir, { + workspaceFolders, + }); + + // Clear the CLI cache so that the most recent qlpack lock file is used. + await cliServer.clearCache(); + const bundlePath = await getPackedBundlePath(queryPackDir); void extLogger.log( `Compiling and bundling query pack from ${queryPackDir} to ${bundlePath}. (This may take a while.)`, ); - await cliServer.packInstall(queryPackDir); await cliServer.packBundle( queryPackDir, workspaceFolders, @@ -149,8 +157,6 @@ async function createNewQueryPack( targetQueryFileName: string, language: string | undefined, packRelativePath: string, - cliServer: cli.CodeQLCliServer, - workspaceFolders: string[], ) { void extLogger.log(`Copying ${queryFile} to ${queryPackDir}`); await copy(queryFile, targetQueryFileName); @@ -163,9 +169,6 @@ async function createNewQueryPack( }, defaultSuite: generateDefaultSuite(packRelativePath), }; - if (await cliServer.useExtensionPacks()) { - injectExtensionPacks(cliServer, syntheticQueryPack, workspaceFolders); - } await writeFile( join(queryPackDir, FALLBACK_QLPACK_FILENAME), dump(syntheticQueryPack), @@ -178,14 +181,12 @@ async function copyExistingQueryPack( queryFile: string, queryPackDir: string, packRelativePath: string, - workspaceFolders: string[], ) { const toCopy = await cliServer.packPacklist(originalPackRoot, false); - // also copy the lock file (either new name or old name) and the query file itself. These are not included in the packlist. [ - join(originalPackRoot, "qlpack.lock.yml"), - join(originalPackRoot, "codeql-pack.lock.yml"), + // also copy the lock file (either new name or old name) and the query file itself. These are not included in the packlist. + ...QLPACK_LOCK_FILENAMES.map((f) => join(originalPackRoot, f)), queryFile, ].forEach((absolutePath) => { if (absolutePath) { @@ -211,12 +212,7 @@ async function copyExistingQueryPack( void extLogger.log(`Copied ${copiedCount} files to ${queryPackDir}`); - await fixPackFile( - queryPackDir, - packRelativePath, - cliServer, - workspaceFolders, - ); + await fixPackFile(queryPackDir, packRelativePath); } async function findPackRoot(queryFile: string): Promise { @@ -367,8 +363,6 @@ export async function prepareRemoteQueryRun( async function fixPackFile( queryPackDir: string, packRelativePath: string, - cliServer: cli.CodeQLCliServer, - workspaceFolders: string[], ): Promise { const packPath = await getQlPackPath(queryPackDir); @@ -385,19 +379,26 @@ async function fixPackFile( qlpack.name = QUERY_PACK_NAME; updateDefaultSuite(qlpack, packRelativePath); removeWorkspaceRefs(qlpack); - if (await cliServer.useExtensionPacks()) { - injectExtensionPacks(cliServer, qlpack, workspaceFolders); - } await writeFile(packPath, dump(qlpack)); } -function injectExtensionPacks( +async function injectExtensionPacks( cliServer: cli.CodeQLCliServer, - qlpack: QlPack, + queryPackDir: string, workspaceFolders: string[], ) { - const extensionPacks = cliServer.resolveQlpacks(workspaceFolders, true); + const qlpackFile = await getQlPackPath(queryPackDir); + if (!qlpackFile) { + throw new Error( + `Could not find ${QLPACK_FILENAMES.join( + " or ", + )} file in '${queryPackDir}'`, + ); + } + const syntheticQueryPack = load(await readFile(qlpackFile, "utf8")) as QlPack; + + const extensionPacks = await cliServer.resolveQlpacks(workspaceFolders, true); Object.entries(extensionPacks).forEach(([name, paths]) => { // We are guaranteed that there is at least one path found for each extension pack. // If there are multiple paths, then we have a problem. This means that there is @@ -412,8 +413,10 @@ function injectExtensionPacks( // Add this extension pack as a dependency. It doesn't matter which // version we specify, since we are guaranteed that the extension pack // is resolved from source at the given path. - qlpack.dependencies[name] = "*"; + syntheticQueryPack.dependencies[name] = "*"; }); + await writeFile(qlpackFile, dump(syntheticQueryPack)); + await cliServer.clearCache(); } function updateDefaultSuite(qlpack: QlPack, packRelativePath: string) { diff --git a/extensions/ql-vscode/test/vscode-tests/cli-integration/data-extension-pack/extension-file.yml b/extensions/ql-vscode/test/vscode-tests/cli-integration/data-extension-pack/extension-file.yml new file mode 100644 index 000000000..e2c26ddff --- /dev/null +++ b/extensions/ql-vscode/test/vscode-tests/cli-integration/data-extension-pack/extension-file.yml @@ -0,0 +1,12 @@ +extensions: + - addsTo: + pack: codeql/javascript-all + extensible: sourceModel + data: + - [ "@example/read-write-user-data", "Member[readUserData].ReturnValue.Awaited", "remote" ] + + - addsTo: + pack: codeql/javascript-all + extensible: sinkModel + data: + - [ "@example/read-write-user-data", "Member[writeUserData].Argument[0]", "command-line-injection" ] diff --git a/extensions/ql-vscode/test/vscode-tests/cli-integration/data-extension-pack/qlpack.yml b/extensions/ql-vscode/test/vscode-tests/cli-integration/data-extension-pack/qlpack.yml new file mode 100644 index 000000000..b834c739b --- /dev/null +++ b/extensions/ql-vscode/test/vscode-tests/cli-integration/data-extension-pack/qlpack.yml @@ -0,0 +1,8 @@ +name: github/extension-pack-for-testing +version: 0.0.0 +library: true +extensionTargets: + github/remote-query-pack: "*" + +dataExtensions: + - extension-file.yml diff --git a/extensions/ql-vscode/test/vscode-tests/cli-integration/variant-analysis/variant-analysis-manager.test.ts b/extensions/ql-vscode/test/vscode-tests/cli-integration/variant-analysis/variant-analysis-manager.test.ts index e0a81a209..40a82af4e 100644 --- a/extensions/ql-vscode/test/vscode-tests/cli-integration/variant-analysis/variant-analysis-manager.test.ts +++ b/extensions/ql-vscode/test/vscode-tests/cli-integration/variant-analysis/variant-analysis-manager.test.ts @@ -12,7 +12,7 @@ import * as ghApiClient from "../../../../src/variant-analysis/gh-api/gh-api-cli import { join } from "path"; import { VariantAnalysisManager } from "../../../../src/variant-analysis/variant-analysis-manager"; -import { CodeQLCliServer } from "../../../../src/cli"; +import { CliVersionConstraint, CodeQLCliServer } from "../../../../src/cli"; import { fixWorkspaceReferences, restoreWorkspaceReferences, @@ -255,6 +255,30 @@ describe("Variant Analysis Manager", () => { qlxFilesThatExist: ["subfolder/in-pack.qlx"], }); }); + + it("should run a remote query with extension packs inside a qlpack", async () => { + if (!(await cli.cliConstraints.supportsQlpacksKind())) { + console.log( + `Skipping test because qlpacks kind is only suppported in CLI version ${CliVersionConstraint.CLI_VERSION_WITH_QLPACKS_KIND} or later.`, + ); + return; + } + await cli.setUseExtensionPacks(true); + await doVariantAnalysisTest({ + queryPath: "data-remote-qlpack-nested/subfolder/in-pack.ql", + filesThatExist: [ + "subfolder/in-pack.ql", + "otherfolder/lib.qll", + ".codeql/libraries/semmle/targets-extension/0.0.0/ext/extension.yml", + ], + filesThatDoNotExist: ["subfolder/not-in-pack.ql"], + qlxFilesThatExist: ["subfolder/in-pack.qlx"], + dependenciesToCheck: [ + "codeql/javascript-all", + "semmle/targets-extension", + ], + }); + }); }); async function doVariantAnalysisTest({ @@ -262,11 +286,13 @@ describe("Variant Analysis Manager", () => { filesThatExist, qlxFilesThatExist, filesThatDoNotExist, + dependenciesToCheck = ["codeql/javascript-all"], }: { queryPath: string; filesThatExist: string[]; qlxFilesThatExist: string[]; filesThatDoNotExist: string[]; + dependenciesToCheck?: string[]; }) { const fileUri = getFile(queryPath); await variantAnalysisManager.runVariantAnalysis( @@ -328,8 +354,10 @@ describe("Variant Analysis Manager", () => { const actualLockKeys = Object.keys(qlpackLockContents.dependencies); - // The lock file should contain at least codeql/javascript-all. - expect(actualLockKeys).toContain("codeql/javascript-all"); + // The lock file should contain at least the specified dependencies. + dependenciesToCheck.forEach((dep) => + expect(actualLockKeys).toContain(dep), + ); } function getFile(file: string): Uri { From 23e1715c4aee9d0ebad4fb06a05a4410b41f7570 Mon Sep 17 00:00:00 2001 From: Robert Date: Tue, 14 Mar 2023 17:27:48 +0000 Subject: [PATCH 025/156] Move DistributionUpdateConfig to top level --- extensions/ql-vscode/src/extension.ts | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/extensions/ql-vscode/src/extension.ts b/extensions/ql-vscode/src/extension.ts index 5b4edf7cd..cc0e91978 100644 --- a/extensions/ql-vscode/src/extension.ts +++ b/extensions/ql-vscode/src/extension.ts @@ -211,6 +211,12 @@ export interface CodeQLExtensionInterface { readonly dispose: () => void; } +interface DistributionUpdateConfig { + isUserInitiated: boolean; + shouldDisplayMessageWhenNoUpdates: boolean; + allowAutoUpdating: boolean; +} + // This is the minimum version of vscode that we _want_ to support. We want to update the language server library, but that // requires 1.67 or later. If we change the minimum version in the package.json, then anyone on an older version of vscode // silently be unable to upgrade. So, the solution is to first bump the minimum version here and release. Then @@ -267,12 +273,6 @@ export async function activate( // Checking the vscode version should not block extension activation. void assertVSCodeVersionGreaterThan(MIN_VERSION, ctx); - interface DistributionUpdateConfig { - isUserInitiated: boolean; - shouldDisplayMessageWhenNoUpdates: boolean; - allowAutoUpdating: boolean; - } - async function installOrUpdateDistributionWithProgressTitle( progressTitle: string, config: DistributionUpdateConfig, From 82f494141567440bf1f3e9d917f6d346dd78f33b Mon Sep 17 00:00:00 2001 From: Robert Date: Tue, 14 Mar 2023 17:30:49 +0000 Subject: [PATCH 026/156] Move shouldUpdateOnNextActivationKey to top level --- extensions/ql-vscode/src/extension.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/extensions/ql-vscode/src/extension.ts b/extensions/ql-vscode/src/extension.ts index cc0e91978..a49567052 100644 --- a/extensions/ql-vscode/src/extension.ts +++ b/extensions/ql-vscode/src/extension.ts @@ -217,6 +217,8 @@ interface DistributionUpdateConfig { allowAutoUpdating: boolean; } +const shouldUpdateOnNextActivationKey = "shouldUpdateOnNextActivation"; + // This is the minimum version of vscode that we _want_ to support. We want to update the language server library, but that // requires 1.67 or later. If we change the minimum version in the package.json, then anyone on an older version of vscode // silently be unable to upgrade. So, the solution is to first bump the minimum version here and release. Then @@ -262,8 +264,6 @@ export async function activate( ctx, ); - const shouldUpdateOnNextActivationKey = "shouldUpdateOnNextActivation"; - registerErrorStubs([checkForUpdatesCommand], (command) => async () => { void showAndLogErrorMessage( `Can't execute ${command}: waiting to finish loading CodeQL CLI.`, From ada5f51e85f18136ba613de4e4b35cfdbf0303ae Mon Sep 17 00:00:00 2001 From: Robert Date: Tue, 14 Mar 2023 17:31:11 +0000 Subject: [PATCH 027/156] Move codeQlVersionRange to top level --- extensions/ql-vscode/src/extension.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/extensions/ql-vscode/src/extension.ts b/extensions/ql-vscode/src/extension.ts index a49567052..1530af55d 100644 --- a/extensions/ql-vscode/src/extension.ts +++ b/extensions/ql-vscode/src/extension.ts @@ -219,6 +219,8 @@ interface DistributionUpdateConfig { const shouldUpdateOnNextActivationKey = "shouldUpdateOnNextActivation"; +const codeQlVersionRange = DEFAULT_DISTRIBUTION_VERSION_RANGE; + // This is the minimum version of vscode that we _want_ to support. We want to update the language server library, but that // requires 1.67 or later. If we change the minimum version in the package.json, then anyone on an older version of vscode // silently be unable to upgrade. So, the solution is to first bump the minimum version here and release. Then @@ -257,7 +259,6 @@ export async function activate( ); ctx.subscriptions.push(distributionConfigListener); - const codeQlVersionRange = DEFAULT_DISTRIBUTION_VERSION_RANGE; const distributionManager = new DistributionManager( distributionConfigListener, codeQlVersionRange, From 8d3ae78db2b7ee3ed280526244d5324d7f3ec3bc Mon Sep 17 00:00:00 2001 From: Robert Date: Tue, 14 Mar 2023 17:32:15 +0000 Subject: [PATCH 028/156] Move installOrUpdateDistributionWithProgressTitle to top level --- extensions/ql-vscode/src/extension.ts | 148 ++++++++++++++------------ 1 file changed, 77 insertions(+), 71 deletions(-) diff --git a/extensions/ql-vscode/src/extension.ts b/extensions/ql-vscode/src/extension.ts index 1530af55d..b1ab87066 100644 --- a/extensions/ql-vscode/src/extension.ts +++ b/extensions/ql-vscode/src/extension.ts @@ -274,76 +274,6 @@ export async function activate( // Checking the vscode version should not block extension activation. void assertVSCodeVersionGreaterThan(MIN_VERSION, ctx); - async function installOrUpdateDistributionWithProgressTitle( - progressTitle: string, - config: DistributionUpdateConfig, - ): Promise { - const minSecondsSinceLastUpdateCheck = config.isUserInitiated ? 0 : 86400; - const noUpdatesLoggingFunc = config.shouldDisplayMessageWhenNoUpdates - ? showAndLogInformationMessage - : async (message: string) => void extLogger.log(message); - const result = - await distributionManager.checkForUpdatesToExtensionManagedDistribution( - minSecondsSinceLastUpdateCheck, - ); - - // We do want to auto update if there is no distribution at all - const allowAutoUpdating = - config.allowAutoUpdating || - !(await distributionManager.hasDistribution()); - - switch (result.kind) { - case DistributionUpdateCheckResultKind.AlreadyCheckedRecentlyResult: - void extLogger.log( - "Didn't perform CodeQL CLI update check since a check was already performed within the previous " + - `${minSecondsSinceLastUpdateCheck} seconds.`, - ); - break; - case DistributionUpdateCheckResultKind.AlreadyUpToDate: - await noUpdatesLoggingFunc("CodeQL CLI already up to date."); - break; - case DistributionUpdateCheckResultKind.InvalidLocation: - await noUpdatesLoggingFunc( - "CodeQL CLI is installed externally so could not be updated.", - ); - break; - case DistributionUpdateCheckResultKind.UpdateAvailable: - if (beganMainExtensionActivation || !allowAutoUpdating) { - const updateAvailableMessage = - `Version "${result.updatedRelease.name}" of the CodeQL CLI is now available. ` + - "Do you wish to upgrade?"; - await ctx.globalState.update(shouldUpdateOnNextActivationKey, true); - if ( - await showInformationMessageWithAction( - updateAvailableMessage, - "Restart and Upgrade", - ) - ) { - await commands.executeCommand("workbench.action.reloadWindow"); - } - } else { - await withProgress( - (progress) => - distributionManager.installExtensionManagedDistributionRelease( - result.updatedRelease, - progress, - ), - { - title: progressTitle, - }, - ); - - await ctx.globalState.update(shouldUpdateOnNextActivationKey, false); - void showAndLogInformationMessage( - `CodeQL CLI updated to version "${result.updatedRelease.name}".`, - ); - } - break; - default: - assertNever(result); - } - } - async function installOrUpdateDistribution( config: DistributionUpdateConfig, ): Promise { @@ -364,7 +294,12 @@ export async function activate( : "Installing CodeQL CLI"; try { - await installOrUpdateDistributionWithProgressTitle(messageText, config); + await installOrUpdateDistributionWithProgressTitle( + ctx, + distributionManager, + messageText, + config, + ); } catch (e) { // Don't rethrow the exception, because if the config is changed, we want to be able to retry installing // or updating the distribution. @@ -525,6 +460,77 @@ export async function activate( return codeQlExtension; } +async function installOrUpdateDistributionWithProgressTitle( + ctx: ExtensionContext, + distributionManager: DistributionManager, + progressTitle: string, + config: DistributionUpdateConfig, +): Promise { + const minSecondsSinceLastUpdateCheck = config.isUserInitiated ? 0 : 86400; + const noUpdatesLoggingFunc = config.shouldDisplayMessageWhenNoUpdates + ? showAndLogInformationMessage + : async (message: string) => void extLogger.log(message); + const result = + await distributionManager.checkForUpdatesToExtensionManagedDistribution( + minSecondsSinceLastUpdateCheck, + ); + + // We do want to auto update if there is no distribution at all + const allowAutoUpdating = + config.allowAutoUpdating || !(await distributionManager.hasDistribution()); + + switch (result.kind) { + case DistributionUpdateCheckResultKind.AlreadyCheckedRecentlyResult: + void extLogger.log( + "Didn't perform CodeQL CLI update check since a check was already performed within the previous " + + `${minSecondsSinceLastUpdateCheck} seconds.`, + ); + break; + case DistributionUpdateCheckResultKind.AlreadyUpToDate: + await noUpdatesLoggingFunc("CodeQL CLI already up to date."); + break; + case DistributionUpdateCheckResultKind.InvalidLocation: + await noUpdatesLoggingFunc( + "CodeQL CLI is installed externally so could not be updated.", + ); + break; + case DistributionUpdateCheckResultKind.UpdateAvailable: + if (beganMainExtensionActivation || !allowAutoUpdating) { + const updateAvailableMessage = + `Version "${result.updatedRelease.name}" of the CodeQL CLI is now available. ` + + "Do you wish to upgrade?"; + await ctx.globalState.update(shouldUpdateOnNextActivationKey, true); + if ( + await showInformationMessageWithAction( + updateAvailableMessage, + "Restart and Upgrade", + ) + ) { + await commands.executeCommand("workbench.action.reloadWindow"); + } + } else { + await withProgress( + (progress) => + distributionManager.installExtensionManagedDistributionRelease( + result.updatedRelease, + progress, + ), + { + title: progressTitle, + }, + ); + + await ctx.globalState.update(shouldUpdateOnNextActivationKey, false); + void showAndLogInformationMessage( + `CodeQL CLI updated to version "${result.updatedRelease.name}".`, + ); + } + break; + default: + assertNever(result); + } +} + const PACK_GLOBS = [ "**/codeql-pack.yml", "**/qlpack.yml", From 118be4a19afa60330357b1a2ef2f1196e058ef07 Mon Sep 17 00:00:00 2001 From: Robert Date: Tue, 14 Mar 2023 17:36:30 +0000 Subject: [PATCH 029/156] Move installOrUpdateDistribution to top level --- extensions/ql-vscode/src/extension.ts | 120 +++++++++++++------------- 1 file changed, 60 insertions(+), 60 deletions(-) diff --git a/extensions/ql-vscode/src/extension.ts b/extensions/ql-vscode/src/extension.ts index b1ab87066..dd0d26366 100644 --- a/extensions/ql-vscode/src/extension.ts +++ b/extensions/ql-vscode/src/extension.ts @@ -274,65 +274,6 @@ export async function activate( // Checking the vscode version should not block extension activation. void assertVSCodeVersionGreaterThan(MIN_VERSION, ctx); - async function installOrUpdateDistribution( - config: DistributionUpdateConfig, - ): Promise { - if (isInstallingOrUpdatingDistribution) { - throw new Error("Already installing or updating CodeQL CLI"); - } - isInstallingOrUpdatingDistribution = true; - const codeQlInstalled = - (await distributionManager.getCodeQlPathWithoutVersionCheck()) !== - undefined; - const willUpdateCodeQl = ctx.globalState.get( - shouldUpdateOnNextActivationKey, - ); - const messageText = willUpdateCodeQl - ? "Updating CodeQL CLI" - : codeQlInstalled - ? "Checking for updates to CodeQL CLI" - : "Installing CodeQL CLI"; - - try { - await installOrUpdateDistributionWithProgressTitle( - ctx, - distributionManager, - messageText, - config, - ); - } catch (e) { - // Don't rethrow the exception, because if the config is changed, we want to be able to retry installing - // or updating the distribution. - const alertFunction = - codeQlInstalled && !config.isUserInitiated - ? showAndLogWarningMessage - : showAndLogErrorMessage; - const taskDescription = `${ - willUpdateCodeQl - ? "update" - : codeQlInstalled - ? "check for updates to" - : "install" - } CodeQL CLI`; - - if (e instanceof GithubRateLimitedError) { - void alertFunction( - `Rate limited while trying to ${taskDescription}. Please try again after ` + - `your rate limit window resets at ${e.rateLimitResetDate.toLocaleString( - env.language, - )}.`, - ); - } else if (e instanceof GithubApiError) { - void alertFunction( - `Encountered GitHub API error while trying to ${taskDescription}. ${e}`, - ); - } - void alertFunction(`Unable to ${taskDescription}. ${e}`); - } finally { - isInstallingOrUpdatingDistribution = false; - } - } - async function getDistributionDisplayingDistributionWarnings(): Promise { const result = await distributionManager.getDistribution(); switch (result.kind) { @@ -380,7 +321,7 @@ export async function activate( async function installOrUpdateThenTryActivate( config: DistributionUpdateConfig, ): Promise> { - await installOrUpdateDistribution(config); + await installOrUpdateDistribution(ctx, distributionManager, config); // Display the warnings even if the extension has already activated. const distributionResult = @@ -531,6 +472,65 @@ async function installOrUpdateDistributionWithProgressTitle( } } +async function installOrUpdateDistribution( + ctx: ExtensionContext, + distributionManager: DistributionManager, + config: DistributionUpdateConfig, +): Promise { + if (isInstallingOrUpdatingDistribution) { + throw new Error("Already installing or updating CodeQL CLI"); + } + isInstallingOrUpdatingDistribution = true; + const codeQlInstalled = + (await distributionManager.getCodeQlPathWithoutVersionCheck()) !== + undefined; + const willUpdateCodeQl = ctx.globalState.get(shouldUpdateOnNextActivationKey); + const messageText = willUpdateCodeQl + ? "Updating CodeQL CLI" + : codeQlInstalled + ? "Checking for updates to CodeQL CLI" + : "Installing CodeQL CLI"; + + try { + await installOrUpdateDistributionWithProgressTitle( + ctx, + distributionManager, + messageText, + config, + ); + } catch (e) { + // Don't rethrow the exception, because if the config is changed, we want to be able to retry installing + // or updating the distribution. + const alertFunction = + codeQlInstalled && !config.isUserInitiated + ? showAndLogWarningMessage + : showAndLogErrorMessage; + const taskDescription = `${ + willUpdateCodeQl + ? "update" + : codeQlInstalled + ? "check for updates to" + : "install" + } CodeQL CLI`; + + if (e instanceof GithubRateLimitedError) { + void alertFunction( + `Rate limited while trying to ${taskDescription}. Please try again after ` + + `your rate limit window resets at ${e.rateLimitResetDate.toLocaleString( + env.language, + )}.`, + ); + } else if (e instanceof GithubApiError) { + void alertFunction( + `Encountered GitHub API error while trying to ${taskDescription}. ${e}`, + ); + } + void alertFunction(`Unable to ${taskDescription}. ${e}`); + } finally { + isInstallingOrUpdatingDistribution = false; + } +} + const PACK_GLOBS = [ "**/codeql-pack.yml", "**/qlpack.yml", From a8f67d72f5c2cfd728d500d1349ef9211b1feaae Mon Sep 17 00:00:00 2001 From: Robert Date: Tue, 14 Mar 2023 17:38:36 +0000 Subject: [PATCH 030/156] Move getDistributionDisplayingDistributionWarnings to top level --- extensions/ql-vscode/src/extension.ts | 92 ++++++++++++++------------- 1 file changed, 47 insertions(+), 45 deletions(-) diff --git a/extensions/ql-vscode/src/extension.ts b/extensions/ql-vscode/src/extension.ts index dd0d26366..f4c150e63 100644 --- a/extensions/ql-vscode/src/extension.ts +++ b/extensions/ql-vscode/src/extension.ts @@ -274,50 +274,6 @@ export async function activate( // Checking the vscode version should not block extension activation. void assertVSCodeVersionGreaterThan(MIN_VERSION, ctx); - async function getDistributionDisplayingDistributionWarnings(): Promise { - const result = await distributionManager.getDistribution(); - switch (result.kind) { - case FindDistributionResultKind.CompatibleDistribution: - void extLogger.log( - `Found compatible version of CodeQL CLI (version ${result.version.raw})`, - ); - break; - case FindDistributionResultKind.IncompatibleDistribution: { - const fixGuidanceMessage = (() => { - switch (result.distribution.kind) { - case DistributionKind.ExtensionManaged: - return 'Please update the CodeQL CLI by running the "CodeQL: Check for CLI Updates" command.'; - case DistributionKind.CustomPathConfig: - return `Please update the \"CodeQL CLI Executable Path\" setting to point to a CLI in the version range ${codeQlVersionRange}.`; - case DistributionKind.PathEnvironmentVariable: - return ( - `Please update the CodeQL CLI on your PATH to a version compatible with ${codeQlVersionRange}, or ` + - `set the \"CodeQL CLI Executable Path\" setting to the path of a CLI version compatible with ${codeQlVersionRange}.` - ); - } - })(); - - void showAndLogWarningMessage( - `The current version of the CodeQL CLI (${result.version.raw}) ` + - `is incompatible with this extension. ${fixGuidanceMessage}`, - ); - break; - } - case FindDistributionResultKind.UnknownCompatibilityDistribution: - void showAndLogWarningMessage( - "Compatibility with the configured CodeQL CLI could not be determined. " + - "You may experience problems using the extension.", - ); - break; - case FindDistributionResultKind.NoDistribution: - void showAndLogErrorMessage("The CodeQL CLI could not be found."); - break; - default: - assertNever(result); - } - return result; - } - async function installOrUpdateThenTryActivate( config: DistributionUpdateConfig, ): Promise> { @@ -325,7 +281,7 @@ export async function activate( // Display the warnings even if the extension has already activated. const distributionResult = - await getDistributionDisplayingDistributionWarnings(); + await getDistributionDisplayingDistributionWarnings(distributionManager); let extensionInterface: CodeQLExtensionInterface | Record = {}; if ( @@ -531,6 +487,52 @@ async function installOrUpdateDistribution( } } +async function getDistributionDisplayingDistributionWarnings( + distributionManager: DistributionManager, +): Promise { + const result = await distributionManager.getDistribution(); + switch (result.kind) { + case FindDistributionResultKind.CompatibleDistribution: + void extLogger.log( + `Found compatible version of CodeQL CLI (version ${result.version.raw})`, + ); + break; + case FindDistributionResultKind.IncompatibleDistribution: { + const fixGuidanceMessage = (() => { + switch (result.distribution.kind) { + case DistributionKind.ExtensionManaged: + return 'Please update the CodeQL CLI by running the "CodeQL: Check for CLI Updates" command.'; + case DistributionKind.CustomPathConfig: + return `Please update the \"CodeQL CLI Executable Path\" setting to point to a CLI in the version range ${codeQlVersionRange}.`; + case DistributionKind.PathEnvironmentVariable: + return ( + `Please update the CodeQL CLI on your PATH to a version compatible with ${codeQlVersionRange}, or ` + + `set the \"CodeQL CLI Executable Path\" setting to the path of a CLI version compatible with ${codeQlVersionRange}.` + ); + } + })(); + + void showAndLogWarningMessage( + `The current version of the CodeQL CLI (${result.version.raw}) ` + + `is incompatible with this extension. ${fixGuidanceMessage}`, + ); + break; + } + case FindDistributionResultKind.UnknownCompatibilityDistribution: + void showAndLogWarningMessage( + "Compatibility with the configured CodeQL CLI could not be determined. " + + "You may experience problems using the extension.", + ); + break; + case FindDistributionResultKind.NoDistribution: + void showAndLogErrorMessage("The CodeQL CLI could not be found."); + break; + default: + assertNever(result); + } + return result; +} + const PACK_GLOBS = [ "**/codeql-pack.yml", "**/qlpack.yml", From ee759abea911e66bf7aa259f36cfa4a547e862ad Mon Sep 17 00:00:00 2001 From: Robert Date: Tue, 14 Mar 2023 17:40:39 +0000 Subject: [PATCH 031/156] Move installOrUpdateThenTryActivate to top level --- extensions/ql-vscode/src/extension.ts | 138 +++++++++++++++----------- 1 file changed, 80 insertions(+), 58 deletions(-) diff --git a/extensions/ql-vscode/src/extension.ts b/extensions/ql-vscode/src/extension.ts index f4c150e63..31fe6be34 100644 --- a/extensions/ql-vscode/src/extension.ts +++ b/extensions/ql-vscode/src/extension.ts @@ -274,64 +274,32 @@ export async function activate( // Checking the vscode version should not block extension activation. void assertVSCodeVersionGreaterThan(MIN_VERSION, ctx); - async function installOrUpdateThenTryActivate( - config: DistributionUpdateConfig, - ): Promise> { - await installOrUpdateDistribution(ctx, distributionManager, config); - - // Display the warnings even if the extension has already activated. - const distributionResult = - await getDistributionDisplayingDistributionWarnings(distributionManager); - let extensionInterface: CodeQLExtensionInterface | Record = - {}; - if ( - !beganMainExtensionActivation && - distributionResult.kind !== FindDistributionResultKind.NoDistribution - ) { - extensionInterface = await activateWithInstalledDistribution( + ctx.subscriptions.push( + distributionConfigListener.onDidChangeConfiguration(() => + installOrUpdateThenTryActivate( ctx, distributionManager, distributionConfigListener, - ); - } else if ( - distributionResult.kind === FindDistributionResultKind.NoDistribution - ) { - registerErrorStubs([checkForUpdatesCommand], (command) => async () => { - const installActionName = "Install CodeQL CLI"; - const chosenAction = await showAndLogErrorMessage( - `Can't execute ${command}: missing CodeQL CLI.`, - { - items: [installActionName], - }, - ); - if (chosenAction === installActionName) { - await installOrUpdateThenTryActivate({ - isUserInitiated: true, - shouldDisplayMessageWhenNoUpdates: false, - allowAutoUpdating: true, - }); - } - }); - } - return extensionInterface; - } - - ctx.subscriptions.push( - distributionConfigListener.onDidChangeConfiguration(() => - installOrUpdateThenTryActivate({ - isUserInitiated: true, - shouldDisplayMessageWhenNoUpdates: false, - allowAutoUpdating: true, - }), + { + isUserInitiated: true, + shouldDisplayMessageWhenNoUpdates: false, + allowAutoUpdating: true, + }, + ), ), ); ctx.subscriptions.push( commandRunner(checkForUpdatesCommand, () => - installOrUpdateThenTryActivate({ - isUserInitiated: true, - shouldDisplayMessageWhenNoUpdates: true, - allowAutoUpdating: true, - }), + installOrUpdateThenTryActivate( + ctx, + distributionManager, + distributionConfigListener, + { + isUserInitiated: true, + shouldDisplayMessageWhenNoUpdates: true, + allowAutoUpdating: true, + }, + ), ), ); @@ -341,14 +309,19 @@ export async function activate( variantAnalysisViewSerializer, ); - const codeQlExtension = await installOrUpdateThenTryActivate({ - isUserInitiated: !!ctx.globalState.get(shouldUpdateOnNextActivationKey), - shouldDisplayMessageWhenNoUpdates: false, + const codeQlExtension = await installOrUpdateThenTryActivate( + ctx, + distributionManager, + distributionConfigListener, + { + isUserInitiated: !!ctx.globalState.get(shouldUpdateOnNextActivationKey), + shouldDisplayMessageWhenNoUpdates: false, - // only auto update on startup if the user has previously requested an update - // otherwise, ask user to accept the update - allowAutoUpdating: !!ctx.globalState.get(shouldUpdateOnNextActivationKey), - }); + // only auto update on startup if the user has previously requested an update + // otherwise, ask user to accept the update + allowAutoUpdating: !!ctx.globalState.get(shouldUpdateOnNextActivationKey), + }, + ); variantAnalysisViewSerializer.onExtensionLoaded( codeQlExtension.variantAnalysisManager, @@ -533,6 +506,55 @@ async function getDistributionDisplayingDistributionWarnings( return result; } +async function installOrUpdateThenTryActivate( + ctx: ExtensionContext, + distributionManager: DistributionManager, + distributionConfigListener: DistributionConfigListener, + config: DistributionUpdateConfig, +): Promise> { + await installOrUpdateDistribution(ctx, distributionManager, config); + + // Display the warnings even if the extension has already activated. + const distributionResult = + await getDistributionDisplayingDistributionWarnings(distributionManager); + let extensionInterface: CodeQLExtensionInterface | Record = {}; + if ( + !beganMainExtensionActivation && + distributionResult.kind !== FindDistributionResultKind.NoDistribution + ) { + extensionInterface = await activateWithInstalledDistribution( + ctx, + distributionManager, + distributionConfigListener, + ); + } else if ( + distributionResult.kind === FindDistributionResultKind.NoDistribution + ) { + registerErrorStubs([checkForUpdatesCommand], (command) => async () => { + const installActionName = "Install CodeQL CLI"; + const chosenAction = await showAndLogErrorMessage( + `Can't execute ${command}: missing CodeQL CLI.`, + { + items: [installActionName], + }, + ); + if (chosenAction === installActionName) { + await installOrUpdateThenTryActivate( + ctx, + distributionManager, + distributionConfigListener, + { + isUserInitiated: true, + shouldDisplayMessageWhenNoUpdates: false, + allowAutoUpdating: true, + }, + ); + } + }); + } + return extensionInterface; +} + const PACK_GLOBS = [ "**/codeql-pack.yml", "**/qlpack.yml", From b05977516e46b22bcfdad958551a7b5653f4ca07 Mon Sep 17 00:00:00 2001 From: Robert Date: Tue, 14 Mar 2023 17:43:07 +0000 Subject: [PATCH 032/156] Move showResultsForComparison to top level --- extensions/ql-vscode/src/extension.ts | 33 ++++++++++++++------------- 1 file changed, 17 insertions(+), 16 deletions(-) diff --git a/extensions/ql-vscode/src/extension.ts b/extensions/ql-vscode/src/extension.ts index 31fe6be34..0fd2e9913 100644 --- a/extensions/ql-vscode/src/extension.ts +++ b/extensions/ql-vscode/src/extension.ts @@ -701,7 +701,7 @@ async function activateWithInstalledDistribution( queryHistoryConfigurationListener, labelProvider, async (from: CompletedLocalQueryInfo, to: CompletedLocalQueryInfo) => - showResultsForComparison(from, to), + showResultsForComparison(compareView, from, to), ); ctx.subscriptions.push(qhm); @@ -729,21 +729,6 @@ async function activateWithInstalledDistribution( void extLogger.log("Initializing source archive filesystem provider."); archiveFilesystemProvider_activate(ctx); - async function showResultsForComparison( - from: CompletedLocalQueryInfo, - to: CompletedLocalQueryInfo, - ): Promise { - try { - await compareView.showResults(from, to); - } catch (e) { - void showAndLogExceptionWithTelemetry( - redactableError(asError(e))`Failed to show results: ${getErrorMessage( - e, - )}`, - ); - } - } - async function showResultsForCompletedQuery( query: CompletedLocalQueryInfo, forceReveal: WebviewReveal, @@ -1729,6 +1714,22 @@ async function activateWithInstalledDistribution( }; } +async function showResultsForComparison( + compareView: CompareView, + from: CompletedLocalQueryInfo, + to: CompletedLocalQueryInfo, +): Promise { + try { + await compareView.showResults(from, to); + } catch (e) { + void showAndLogExceptionWithTelemetry( + redactableError(asError(e))`Failed to show results: ${getErrorMessage( + e, + )}`, + ); + } +} + function addUnhandledRejectionListener() { const handler = (error: unknown) => { // This listener will be triggered for errors from other extensions as From c366342f955faca17b79889b149d8f9aaf016ffd Mon Sep 17 00:00:00 2001 From: Robert Date: Tue, 14 Mar 2023 17:43:58 +0000 Subject: [PATCH 033/156] Move showResultsForCompletedQuery to top level --- extensions/ql-vscode/src/extension.ts | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/extensions/ql-vscode/src/extension.ts b/extensions/ql-vscode/src/extension.ts index 0fd2e9913..b722a6d35 100644 --- a/extensions/ql-vscode/src/extension.ts +++ b/extensions/ql-vscode/src/extension.ts @@ -636,7 +636,11 @@ async function activateWithInstalledDistribution( const queryHistoryConfigurationListener = new QueryHistoryConfigListener(); ctx.subscriptions.push(queryHistoryConfigurationListener); const showResults = async (item: CompletedLocalQueryInfo) => - showResultsForCompletedQuery(item, WebviewReveal.Forced); + showResultsForCompletedQuery( + localQueryResultsView, + item, + WebviewReveal.Forced, + ); const queryStorageDir = join(ctx.globalStorageUri.fsPath, "queries"); await ensureDir(queryStorageDir); const labelProvider = new HistoryItemLabelProvider( @@ -729,13 +733,6 @@ async function activateWithInstalledDistribution( void extLogger.log("Initializing source archive filesystem provider."); archiveFilesystemProvider_activate(ctx); - async function showResultsForCompletedQuery( - query: CompletedLocalQueryInfo, - forceReveal: WebviewReveal, - ): Promise { - await localQueryResultsView.showResults(query, forceReveal, false); - } - async function compileAndRunQuery( quickEval: boolean, selectedQuery: Uri | undefined, @@ -780,6 +777,7 @@ async function activateWithInstalledDistribution( ); qhm.completeQuery(item, completedQueryInfo); await showResultsForCompletedQuery( + localQueryResultsView, item as CompletedLocalQueryInfo, WebviewReveal.Forced, ); @@ -1730,6 +1728,14 @@ async function showResultsForComparison( } } +async function showResultsForCompletedQuery( + localQueryResultsView: ResultsView, + query: CompletedLocalQueryInfo, + forceReveal: WebviewReveal, +): Promise { + await localQueryResultsView.showResults(query, forceReveal, false); +} + function addUnhandledRejectionListener() { const handler = (error: unknown) => { // This listener will be triggered for errors from other extensions as From e2e197f4d93b937926459e59a279cbb4fbcd121a Mon Sep 17 00:00:00 2001 From: Robert Date: Tue, 14 Mar 2023 17:46:37 +0000 Subject: [PATCH 034/156] Move compileAndRunQuery to top level --- extensions/ql-vscode/src/extension.ts | 247 ++++++++++++++++++-------- 1 file changed, 177 insertions(+), 70 deletions(-) diff --git a/extensions/ql-vscode/src/extension.ts b/extensions/ql-vscode/src/extension.ts index b722a6d35..211d4717b 100644 --- a/extensions/ql-vscode/src/extension.ts +++ b/extensions/ql-vscode/src/extension.ts @@ -733,68 +733,6 @@ async function activateWithInstalledDistribution( void extLogger.log("Initializing source archive filesystem provider."); archiveFilesystemProvider_activate(ctx); - async function compileAndRunQuery( - quickEval: boolean, - selectedQuery: Uri | undefined, - progress: ProgressCallback, - token: CancellationToken, - databaseItem: DatabaseItem | undefined, - range?: Range, - ): Promise { - if (qs !== undefined) { - // If no databaseItem is specified, use the database currently selected in the Databases UI - databaseItem = - databaseItem || (await databaseUI.getDatabaseItem(progress, token)); - if (databaseItem === undefined) { - throw new Error("Can't run query without a selected database"); - } - const databaseInfo = { - name: databaseItem.name, - databaseUri: databaseItem.databaseUri.toString(), - }; - - // handle cancellation from the history view. - const source = new CancellationTokenSource(); - token.onCancellationRequested(() => source.cancel()); - - const initialInfo = await createInitialQueryInfo( - selectedQuery, - databaseInfo, - quickEval, - range, - ); - const item = new LocalQueryInfo(initialInfo, source); - qhm.addQuery(item); - try { - const completedQueryInfo = await qs.compileAndRunQueryAgainstDatabase( - databaseItem, - initialInfo, - queryStorageDir, - progress, - source.token, - undefined, - item, - ); - qhm.completeQuery(item, completedQueryInfo); - await showResultsForCompletedQuery( - localQueryResultsView, - item as CompletedLocalQueryInfo, - WebviewReveal.Forced, - ); - // Note we must update the query history view after showing results as the - // display and sorting might depend on the number of results - } catch (e) { - const err = asError(e); - err.message = `Error running query: ${err.message}`; - item.failureReason = err.message; - throw e; - } finally { - await qhm.refreshTreeView(); - source.dispose(); - } - } - } - async function compileAndRunQueryOnMultipleDatabases( progress: ProgressCallback, token: CancellationToken, @@ -839,6 +777,11 @@ async function activateWithInstalledDistribution( for (const item of quickpick) { try { await compileAndRunQuery( + qs, + qhm, + databaseUI, + localQueryResultsView, + queryStorageDir, false, uri, progress, @@ -954,7 +897,19 @@ async function activateWithInstalledDistribution( progress: ProgressCallback, token: CancellationToken, uri: Uri | undefined, - ) => await compileAndRunQuery(false, uri, progress, token, undefined), + ) => + await compileAndRunQuery( + qs, + qhm, + databaseUI, + localQueryResultsView, + queryStorageDir, + false, + uri, + progress, + token, + undefined, + ), { title: "Running query", cancellable: true, @@ -973,7 +928,19 @@ async function activateWithInstalledDistribution( progress: ProgressCallback, token: CancellationToken, uri: Uri | undefined, - ) => await compileAndRunQuery(false, uri, progress, token, undefined), + ) => + await compileAndRunQuery( + qs, + qhm, + databaseUI, + localQueryResultsView, + queryStorageDir, + false, + uri, + progress, + token, + undefined, + ), { title: "Running query", cancellable: true, @@ -1068,6 +1035,11 @@ async function activateWithInstalledDistribution( await Promise.all( queryUris.map(async (uri) => compileAndRunQuery( + qs, + qhm, + databaseUI, + localQueryResultsView, + queryStorageDir, false, uri, wrappedProgress, @@ -1094,7 +1066,19 @@ async function activateWithInstalledDistribution( progress: ProgressCallback, token: CancellationToken, uri: Uri | undefined, - ) => await compileAndRunQuery(true, uri, progress, token, undefined), + ) => + await compileAndRunQuery( + qs, + qhm, + databaseUI, + localQueryResultsView, + queryStorageDir, + true, + uri, + progress, + token, + undefined, + ), { title: "Running query", cancellable: true, @@ -1112,7 +1096,19 @@ async function activateWithInstalledDistribution( progress: ProgressCallback, token: CancellationToken, uri: Uri | undefined, - ) => await compileAndRunQuery(true, uri, progress, token, undefined), + ) => + await compileAndRunQuery( + qs, + qhm, + databaseUI, + localQueryResultsView, + queryStorageDir, + true, + uri, + progress, + token, + undefined, + ), { title: "Running query", cancellable: true, @@ -1131,7 +1127,19 @@ async function activateWithInstalledDistribution( uri: Uri, range: Range, ) => - await compileAndRunQuery(true, uri, progress, token, undefined, range), + await compileAndRunQuery( + qs, + qhm, + databaseUI, + localQueryResultsView, + queryStorageDir, + true, + uri, + progress, + token, + undefined, + range, + ), { title: "Running query", cancellable: true, @@ -1610,7 +1618,18 @@ async function activateWithInstalledDistribution( window.activeTextEditor?.document, ); if (res) { - await compileAndRunQuery(false, res[0], progress, token, undefined); + await compileAndRunQuery( + qs, + qhm, + databaseUI, + localQueryResultsView, + queryStorageDir, + false, + res[0], + progress, + token, + undefined, + ); } }, { @@ -1629,7 +1648,18 @@ async function activateWithInstalledDistribution( window.activeTextEditor?.document, ); if (res) { - await compileAndRunQuery(false, res[0], progress, token, undefined); + await compileAndRunQuery( + qs, + qhm, + databaseUI, + localQueryResultsView, + queryStorageDir, + false, + res[0], + progress, + token, + undefined, + ); } }, { @@ -1648,7 +1678,18 @@ async function activateWithInstalledDistribution( window.activeTextEditor?.document, ); if (res) { - await compileAndRunQuery(false, res[0], progress, token, undefined); + await compileAndRunQuery( + qs, + qhm, + databaseUI, + localQueryResultsView, + queryStorageDir, + false, + res[0], + progress, + token, + undefined, + ); } }, { @@ -1735,6 +1776,72 @@ async function showResultsForCompletedQuery( ): Promise { await localQueryResultsView.showResults(query, forceReveal, false); } +async function compileAndRunQuery( + qs: QueryRunner, + qhm: QueryHistoryManager, + databaseUI: DatabaseUI, + localQueryResultsView: ResultsView, + queryStorageDir: string, + quickEval: boolean, + selectedQuery: Uri | undefined, + progress: ProgressCallback, + token: CancellationToken, + databaseItem: DatabaseItem | undefined, + range?: Range, +): Promise { + if (qs !== undefined) { + // If no databaseItem is specified, use the database currently selected in the Databases UI + databaseItem = + databaseItem || (await databaseUI.getDatabaseItem(progress, token)); + if (databaseItem === undefined) { + throw new Error("Can't run query without a selected database"); + } + const databaseInfo = { + name: databaseItem.name, + databaseUri: databaseItem.databaseUri.toString(), + }; + + // handle cancellation from the history view. + const source = new CancellationTokenSource(); + token.onCancellationRequested(() => source.cancel()); + + const initialInfo = await createInitialQueryInfo( + selectedQuery, + databaseInfo, + quickEval, + range, + ); + const item = new LocalQueryInfo(initialInfo, source); + qhm.addQuery(item); + try { + const completedQueryInfo = await qs.compileAndRunQueryAgainstDatabase( + databaseItem, + initialInfo, + queryStorageDir, + progress, + source.token, + undefined, + item, + ); + qhm.completeQuery(item, completedQueryInfo); + await showResultsForCompletedQuery( + localQueryResultsView, + item as CompletedLocalQueryInfo, + WebviewReveal.Forced, + ); + // Note we must update the query history view after showing results as the + // display and sorting might depend on the number of results + } catch (e) { + const err = asError(e); + err.message = `Error running query: ${err.message}`; + item.failureReason = err.message; + throw e; + } finally { + await qhm.refreshTreeView(); + source.dispose(); + } + } +} function addUnhandledRejectionListener() { const handler = (error: unknown) => { From c3f4a012a990527ac834e7fc575daaa77e71b2f6 Mon Sep 17 00:00:00 2001 From: Robert Date: Tue, 14 Mar 2023 17:49:07 +0000 Subject: [PATCH 035/156] Move DatabaseQuickPickItem to top level --- extensions/ql-vscode/src/extension.ts | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/extensions/ql-vscode/src/extension.ts b/extensions/ql-vscode/src/extension.ts index 211d4717b..3127b4d65 100644 --- a/extensions/ql-vscode/src/extension.ts +++ b/extensions/ql-vscode/src/extension.ts @@ -217,6 +217,10 @@ interface DistributionUpdateConfig { allowAutoUpdating: boolean; } +interface DatabaseQuickPickItem extends QuickPickItem { + databaseItem: DatabaseItem; +} + const shouldUpdateOnNextActivationKey = "shouldUpdateOnNextActivation"; const codeQlVersionRange = DEFAULT_DISTRIBUTION_VERSION_RANGE; @@ -950,9 +954,6 @@ async function activateWithInstalledDistribution( queryServerLogger, ), ); - interface DatabaseQuickPickItem extends QuickPickItem { - databaseItem: DatabaseItem; - } ctx.subscriptions.push( commandRunnerWithProgress( "codeQL.runQueryOnMultipleDatabases", From d8371708b3f3a79c9dc61792d37736a6e9b717b0 Mon Sep 17 00:00:00 2001 From: Robert Date: Tue, 14 Mar 2023 17:49:58 +0000 Subject: [PATCH 036/156] Move compileAndRunQueryOnMultipleDatabases to top level --- extensions/ql-vscode/src/extension.ts | 181 +++++++++++++++----------- 1 file changed, 106 insertions(+), 75 deletions(-) diff --git a/extensions/ql-vscode/src/extension.ts b/extensions/ql-vscode/src/extension.ts index 3127b4d65..bb3996323 100644 --- a/extensions/ql-vscode/src/extension.ts +++ b/extensions/ql-vscode/src/extension.ts @@ -737,79 +737,6 @@ async function activateWithInstalledDistribution( void extLogger.log("Initializing source archive filesystem provider."); archiveFilesystemProvider_activate(ctx); - async function compileAndRunQueryOnMultipleDatabases( - progress: ProgressCallback, - token: CancellationToken, - uri: Uri | undefined, - ): Promise { - let filteredDBs = dbm.databaseItems; - if (filteredDBs.length === 0) { - void showAndLogErrorMessage( - "No databases found. Please add a suitable database to your workspace.", - ); - return; - } - // If possible, only show databases with the right language (otherwise show all databases). - const queryLanguage = await findLanguage(cliServer, uri); - if (queryLanguage) { - filteredDBs = dbm.databaseItems.filter( - (db) => db.language === queryLanguage, - ); - if (filteredDBs.length === 0) { - void showAndLogErrorMessage( - `No databases found for language ${queryLanguage}. Please add a suitable database to your workspace.`, - ); - return; - } - } - const quickPickItems = filteredDBs.map((dbItem) => ({ - databaseItem: dbItem, - label: dbItem.name, - description: dbItem.language, - })); - /** - * Databases that were selected in the quick pick menu. - */ - const quickpick = await window.showQuickPick( - quickPickItems, - { canPickMany: true, ignoreFocusOut: true }, - ); - if (quickpick !== undefined) { - // Collect all skipped databases and display them at the end (instead of popping up individual errors) - const skippedDatabases = []; - const errors = []; - for (const item of quickpick) { - try { - await compileAndRunQuery( - qs, - qhm, - databaseUI, - localQueryResultsView, - queryStorageDir, - false, - uri, - progress, - token, - item.databaseItem, - ); - } catch (e) { - skippedDatabases.push(item.label); - errors.push(getErrorMessage(e)); - } - } - if (skippedDatabases.length > 0) { - void extLogger.log(`Errors:\n${errors.join("\n")}`); - void showAndLogWarningMessage( - `The following databases were skipped:\n${skippedDatabases.join( - "\n", - )}.\nFor details about the errors, see the logs.`, - ); - } - } else { - void showAndLogErrorMessage("No databases selected."); - } - } - const qhelpTmpDir = dirSync({ prefix: "qhelp_", keep: false, @@ -961,7 +888,19 @@ async function activateWithInstalledDistribution( progress: ProgressCallback, token: CancellationToken, uri: Uri | undefined, - ) => await compileAndRunQueryOnMultipleDatabases(progress, token, uri), + ) => + await compileAndRunQueryOnMultipleDatabases( + cliServer, + qs, + qhm, + dbm, + databaseUI, + localQueryResultsView, + queryStorageDir, + progress, + token, + uri, + ), { title: "Running query on selected databases", cancellable: true, @@ -976,7 +915,19 @@ async function activateWithInstalledDistribution( progress: ProgressCallback, token: CancellationToken, uri: Uri | undefined, - ) => await compileAndRunQueryOnMultipleDatabases(progress, token, uri), + ) => + await compileAndRunQueryOnMultipleDatabases( + cliServer, + qs, + qhm, + dbm, + databaseUI, + localQueryResultsView, + queryStorageDir, + progress, + token, + uri, + ), { title: "Running query on selected databases", cancellable: true, @@ -1844,6 +1795,86 @@ async function compileAndRunQuery( } } +async function compileAndRunQueryOnMultipleDatabases( + cliServer: CodeQLCliServer, + qs: QueryRunner, + qhm: QueryHistoryManager, + dbm: DatabaseManager, + databaseUI: DatabaseUI, + localQueryResultsView: ResultsView, + queryStorageDir: string, + progress: ProgressCallback, + token: CancellationToken, + uri: Uri | undefined, +): Promise { + let filteredDBs = dbm.databaseItems; + if (filteredDBs.length === 0) { + void showAndLogErrorMessage( + "No databases found. Please add a suitable database to your workspace.", + ); + return; + } + // If possible, only show databases with the right language (otherwise show all databases). + const queryLanguage = await findLanguage(cliServer, uri); + if (queryLanguage) { + filteredDBs = dbm.databaseItems.filter( + (db) => db.language === queryLanguage, + ); + if (filteredDBs.length === 0) { + void showAndLogErrorMessage( + `No databases found for language ${queryLanguage}. Please add a suitable database to your workspace.`, + ); + return; + } + } + const quickPickItems = filteredDBs.map((dbItem) => ({ + databaseItem: dbItem, + label: dbItem.name, + description: dbItem.language, + })); + /** + * Databases that were selected in the quick pick menu. + */ + const quickpick = await window.showQuickPick( + quickPickItems, + { canPickMany: true, ignoreFocusOut: true }, + ); + if (quickpick !== undefined) { + // Collect all skipped databases and display them at the end (instead of popping up individual errors) + const skippedDatabases = []; + const errors = []; + for (const item of quickpick) { + try { + await compileAndRunQuery( + qs, + qhm, + databaseUI, + localQueryResultsView, + queryStorageDir, + false, + uri, + progress, + token, + item.databaseItem, + ); + } catch (e) { + skippedDatabases.push(item.label); + errors.push(getErrorMessage(e)); + } + } + if (skippedDatabases.length > 0) { + void extLogger.log(`Errors:\n${errors.join("\n")}`); + void showAndLogWarningMessage( + `The following databases were skipped:\n${skippedDatabases.join( + "\n", + )}.\nFor details about the errors, see the logs.`, + ); + } + } else { + void showAndLogErrorMessage("No databases selected."); + } +} + function addUnhandledRejectionListener() { const handler = (error: unknown) => { // This listener will be triggered for errors from other extensions as From 165542d11523643237b56c8ad030cd29dbc35800 Mon Sep 17 00:00:00 2001 From: Robert Date: Tue, 14 Mar 2023 17:51:57 +0000 Subject: [PATCH 037/156] Move previewQueryHelp to top level --- extensions/ql-vscode/src/extension.ts | 61 +++++++++++++++------------ 1 file changed, 34 insertions(+), 27 deletions(-) diff --git a/extensions/ql-vscode/src/extension.ts b/extensions/ql-vscode/src/extension.ts index bb3996323..759d40be9 100644 --- a/extensions/ql-vscode/src/extension.ts +++ b/extensions/ql-vscode/src/extension.ts @@ -136,6 +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 { DirResult } from "tmp"; /** * extension.ts @@ -744,32 +745,6 @@ async function activateWithInstalledDistribution( }); ctx.subscriptions.push({ dispose: qhelpTmpDir.removeCallback }); - async function previewQueryHelp(selectedQuery: Uri): Promise { - // selectedQuery is unpopulated when executing through the command palette - const pathToQhelp = selectedQuery - ? selectedQuery.fsPath - : window.activeTextEditor?.document.uri.fsPath; - if (pathToQhelp) { - // Create temporary directory - const relativePathToMd = `${basename(pathToQhelp, ".qhelp")}.md`; - const absolutePathToMd = join(qhelpTmpDir.name, relativePathToMd); - const uri = Uri.file(absolutePathToMd); - try { - await cliServer.generateQueryHelp(pathToQhelp, absolutePathToMd); - await commands.executeCommand("markdown.showPreviewToSide", uri); - } catch (e) { - const errorMessage = getErrorMessage(e).includes( - "Generating qhelp in markdown", - ) - ? redactableError`Could not generate markdown from ${pathToQhelp}: Bad formatting in .qhelp file.` - : redactableError`Could not open a preview of the generated file (${absolutePathToMd}).`; - void showAndLogExceptionWithTelemetry(errorMessage, { - fullMessage: `${errorMessage}\n${getErrorMessage(e)}`, - }); - } - } - } - async function openReferencedFile(selectedQuery: Uri): Promise { // If no file is selected, the path of the file in the editor is selected const path = @@ -1316,7 +1291,9 @@ async function activateWithInstalledDistribution( ); ctx.subscriptions.push( - commandRunner("codeQL.previewQueryHelp", previewQueryHelp), + commandRunner("codeQL.previewQueryHelp", async (selectedQuery: Uri) => { + await previewQueryHelp(cliServer, selectedQuery, qhelpTmpDir); + }), ); ctx.subscriptions.push( @@ -1875,6 +1852,36 @@ async function compileAndRunQueryOnMultipleDatabases( } } +async function previewQueryHelp( + cliServer: CodeQLCliServer, + selectedQuery: Uri, + qhelpTmpDir: DirResult, +): Promise { + // selectedQuery is unpopulated when executing through the command palette + const pathToQhelp = selectedQuery + ? selectedQuery.fsPath + : window.activeTextEditor?.document.uri.fsPath; + if (pathToQhelp) { + // Create temporary directory + const relativePathToMd = `${basename(pathToQhelp, ".qhelp")}.md`; + const absolutePathToMd = join(qhelpTmpDir.name, relativePathToMd); + const uri = Uri.file(absolutePathToMd); + try { + await cliServer.generateQueryHelp(pathToQhelp, absolutePathToMd); + await commands.executeCommand("markdown.showPreviewToSide", uri); + } catch (e) { + const errorMessage = getErrorMessage(e).includes( + "Generating qhelp in markdown", + ) + ? redactableError`Could not generate markdown from ${pathToQhelp}: Bad formatting in .qhelp file.` + : redactableError`Could not open a preview of the generated file (${absolutePathToMd}).`; + void showAndLogExceptionWithTelemetry(errorMessage, { + fullMessage: `${errorMessage}\n${getErrorMessage(e)}`, + }); + } + } +} + function addUnhandledRejectionListener() { const handler = (error: unknown) => { // This listener will be triggered for errors from other extensions as From 9d59abd0a84ad94cbe05f2da8a36d3f6fc27d504 Mon Sep 17 00:00:00 2001 From: Robert Date: Tue, 14 Mar 2023 17:53:50 +0000 Subject: [PATCH 038/156] Move openReferencedFile to top level --- extensions/ql-vscode/src/extension.ts | 41 ++++++++++++++++++--------- 1 file changed, 27 insertions(+), 14 deletions(-) diff --git a/extensions/ql-vscode/src/extension.ts b/extensions/ql-vscode/src/extension.ts index 759d40be9..db117e8ed 100644 --- a/extensions/ql-vscode/src/extension.ts +++ b/extensions/ql-vscode/src/extension.ts @@ -745,17 +745,6 @@ async function activateWithInstalledDistribution( }); ctx.subscriptions.push({ dispose: qhelpTmpDir.removeCallback }); - async function openReferencedFile(selectedQuery: Uri): Promise { - // If no file is selected, the path of the file in the editor is selected - const path = - selectedQuery?.fsPath || window.activeTextEditor?.document.uri.fsPath; - if (qs !== undefined && path) { - const resolved = await cliServer.resolveQlref(path); - const uri = Uri.file(resolved.resolvedPath); - await window.showTextDocument(uri, { preview: false }); - } - } - ctx.subscriptions.push(tmpDirDisposal); void extLogger.log("Initializing CodeQL language server."); @@ -1274,19 +1263,28 @@ async function activateWithInstalledDistribution( ); ctx.subscriptions.push( - commandRunner("codeQL.openReferencedFile", openReferencedFile), + commandRunner("codeQL.openReferencedFile", async (selectedQuery: Uri) => { + await openReferencedFile(qs, cliServer, selectedQuery); + }), ); // Since we are tracking extension usage through commands, this command mirrors the "codeQL.openReferencedFile" command ctx.subscriptions.push( - commandRunner("codeQL.openReferencedFileContextEditor", openReferencedFile), + commandRunner( + "codeQL.openReferencedFileContextEditor", + async (selectedQuery: Uri) => { + await openReferencedFile(qs, cliServer, selectedQuery); + }, + ), ); // Since we are tracking extension usage through commands, this command mirrors the "codeQL.openReferencedFile" command ctx.subscriptions.push( commandRunner( "codeQL.openReferencedFileContextExplorer", - openReferencedFile, + async (selectedQuery: Uri) => { + await openReferencedFile(qs, cliServer, selectedQuery); + }, ), ); @@ -1882,6 +1880,21 @@ async function previewQueryHelp( } } +async function openReferencedFile( + qs: QueryRunner, + cliServer: CodeQLCliServer, + selectedQuery: Uri, +): Promise { + // If no file is selected, the path of the file in the editor is selected + const path = + selectedQuery?.fsPath || window.activeTextEditor?.document.uri.fsPath; + if (qs !== undefined && path) { + const resolved = await cliServer.resolveQlref(path); + const uri = Uri.file(resolved.resolvedPath); + await window.showTextDocument(uri, { preview: false }); + } +} + function addUnhandledRejectionListener() { const handler = (error: unknown) => { // This listener will be triggered for errors from other extensions as From 764830e69dd152c5b64dcf78b7210f7babfd25c9 Mon Sep 17 00:00:00 2001 From: Robert Date: Tue, 14 Mar 2023 17:55:35 +0000 Subject: [PATCH 039/156] Move runVariantAnalysis to top level --- extensions/ql-vscode/src/extension.ts | 43 ++++++++++++++------------- 1 file changed, 23 insertions(+), 20 deletions(-) diff --git a/extensions/ql-vscode/src/extension.ts b/extensions/ql-vscode/src/extension.ts index db117e8ed..863e16b02 100644 --- a/extensions/ql-vscode/src/extension.ts +++ b/extensions/ql-vscode/src/extension.ts @@ -1080,24 +1080,6 @@ async function activateWithInstalledDistribution( ), ); - async function runVariantAnalysis( - progress: ProgressCallback, - token: CancellationToken, - uri: Uri | undefined, - ): Promise { - progress({ - maxStep: 5, - step: 0, - message: "Getting credentials", - }); - - await variantAnalysisManager.runVariantAnalysis( - uri || window.activeTextEditor?.document.uri, - progress, - token, - ); - } - ctx.subscriptions.push( commandRunnerWithProgress( "codeQL.runVariantAnalysis", @@ -1105,7 +1087,8 @@ async function activateWithInstalledDistribution( progress: ProgressCallback, token: CancellationToken, uri: Uri | undefined, - ) => await runVariantAnalysis(progress, token, uri), + ) => + await runVariantAnalysis(variantAnalysisManager, progress, token, uri), { title: "Run Variant Analysis", cancellable: true, @@ -1121,7 +1104,8 @@ async function activateWithInstalledDistribution( progress: ProgressCallback, token: CancellationToken, uri: Uri | undefined, - ) => await runVariantAnalysis(progress, token, uri), + ) => + await runVariantAnalysis(variantAnalysisManager, progress, token, uri), { title: "Run Variant Analysis", cancellable: true, @@ -1895,6 +1879,25 @@ async function openReferencedFile( } } +async function runVariantAnalysis( + variantAnalysisManager: VariantAnalysisManager, + progress: ProgressCallback, + token: CancellationToken, + uri: Uri | undefined, +): Promise { + progress({ + maxStep: 5, + step: 0, + message: "Getting credentials", + }); + + await variantAnalysisManager.runVariantAnalysis( + uri || window.activeTextEditor?.document.uri, + progress, + token, + ); +} + function addUnhandledRejectionListener() { const handler = (error: unknown) => { // This listener will be triggered for errors from other extensions as From 7571304fb2ee61058549954deed813c9d7cbccf1 Mon Sep 17 00:00:00 2001 From: Robert Date: Tue, 14 Mar 2023 17:57:23 +0000 Subject: [PATCH 040/156] Move viewAst to top level --- extensions/ql-vscode/src/extension.ts | 59 +++++++++++++++++++-------- 1 file changed, 41 insertions(+), 18 deletions(-) diff --git a/extensions/ql-vscode/src/extension.ts b/extensions/ql-vscode/src/extension.ts index 863e16b02..ea6622680 100644 --- a/extensions/ql-vscode/src/extension.ts +++ b/extensions/ql-vscode/src/extension.ts @@ -1459,21 +1459,6 @@ async function activateWithInstalledDistribution( ctx.subscriptions.push(astViewer); - async function viewAst( - progress: ProgressCallback, - token: CancellationToken, - selectedFile: Uri, - ): Promise { - const ast = await printAstTemplateProvider.provideAst( - progress, - token, - selectedFile ?? window.activeTextEditor?.document.uri, - ); - if (ast) { - astViewer.updateRoots(await ast.getRoots(), ast.db, ast.fileName); - } - } - ctx.subscriptions.push( commandRunnerWithProgress( "codeQL.viewAst", @@ -1481,7 +1466,14 @@ async function activateWithInstalledDistribution( progress: ProgressCallback, token: CancellationToken, selectedFile: Uri, - ) => await viewAst(progress, token, selectedFile), + ) => + await viewAst( + astViewer, + printAstTemplateProvider, + progress, + token, + selectedFile, + ), { cancellable: true, title: "Calculate AST", @@ -1497,7 +1489,14 @@ async function activateWithInstalledDistribution( progress: ProgressCallback, token: CancellationToken, selectedFile: Uri, - ) => await viewAst(progress, token, selectedFile), + ) => + await viewAst( + astViewer, + printAstTemplateProvider, + progress, + token, + selectedFile, + ), { cancellable: true, title: "Calculate AST", @@ -1513,7 +1512,14 @@ async function activateWithInstalledDistribution( progress: ProgressCallback, token: CancellationToken, selectedFile: Uri, - ) => await viewAst(progress, token, selectedFile), + ) => + await viewAst( + astViewer, + printAstTemplateProvider, + progress, + token, + selectedFile, + ), { cancellable: true, title: "Calculate AST", @@ -1898,6 +1904,23 @@ async function runVariantAnalysis( ); } +async function viewAst( + astViewer: AstViewer, + printAstTemplateProvider: TemplatePrintAstProvider, + progress: ProgressCallback, + token: CancellationToken, + selectedFile: Uri, +): Promise { + const ast = await printAstTemplateProvider.provideAst( + progress, + token, + selectedFile ?? window.activeTextEditor?.document.uri, + ); + if (ast) { + astViewer.updateRoots(await ast.getRoots(), ast.db, ast.fileName); + } +} + function addUnhandledRejectionListener() { const handler = (error: unknown) => { // This listener will be triggered for errors from other extensions as From ebd18cd245793bb6ecb611244af76025ea70f86d Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 15 Mar 2023 02:21:22 +0000 Subject: [PATCH 041/156] Bump webpack from 5.73.0 to 5.76.0 in /extensions/ql-vscode Bumps [webpack](https://github.com/webpack/webpack) from 5.73.0 to 5.76.0. - [Release notes](https://github.com/webpack/webpack/releases) - [Commits](https://github.com/webpack/webpack/compare/v5.73.0...v5.76.0) --- updated-dependencies: - dependency-name: webpack dependency-type: direct:development ... Signed-off-by: dependabot[bot] --- extensions/ql-vscode/package-lock.json | 38 +++++++++++++------------- extensions/ql-vscode/package.json | 2 +- 2 files changed, 20 insertions(+), 20 deletions(-) diff --git a/extensions/ql-vscode/package-lock.json b/extensions/ql-vscode/package-lock.json index 0b7967103..0b00888cd 100644 --- a/extensions/ql-vscode/package-lock.json +++ b/extensions/ql-vscode/package-lock.json @@ -142,7 +142,7 @@ "ts-node": "^10.7.0", "ts-protoc-gen": "^0.9.0", "typescript": "^4.5.5", - "webpack": "^5.62.2", + "webpack": "^5.76.0", "webpack-cli": "^4.6.0" }, "engines": { @@ -40359,9 +40359,9 @@ "integrity": "sha1-JFNCdeKnvGvnvIZhHMFq4KVlSHE=" }, "node_modules/webpack": { - "version": "5.73.0", - "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.73.0.tgz", - "integrity": "sha512-svjudQRPPa0YiOYa2lM/Gacw0r6PvxptHj4FuEKQ2kX05ZLkjbVc5MnPs6its5j7IZljnIqSVo/OsY2X0IpHGA==", + "version": "5.76.0", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.76.0.tgz", + "integrity": "sha512-l5sOdYBDunyf72HW8dF23rFtWq/7Zgvt/9ftMof71E/yUb1YLOBmTgA2K4vQthB3kotMrSj609txVE0dnr2fjA==", "dev": true, "dependencies": { "@types/eslint-scope": "^3.7.3", @@ -40369,11 +40369,11 @@ "@webassemblyjs/ast": "1.11.1", "@webassemblyjs/wasm-edit": "1.11.1", "@webassemblyjs/wasm-parser": "1.11.1", - "acorn": "^8.4.1", + "acorn": "^8.7.1", "acorn-import-assertions": "^1.7.6", "browserslist": "^4.14.5", "chrome-trace-event": "^1.0.2", - "enhanced-resolve": "^5.9.3", + "enhanced-resolve": "^5.10.0", "es-module-lexer": "^0.9.0", "eslint-scope": "5.1.1", "events": "^3.2.0", @@ -40386,7 +40386,7 @@ "schema-utils": "^3.1.0", "tapable": "^2.1.1", "terser-webpack-plugin": "^5.1.3", - "watchpack": "^2.3.1", + "watchpack": "^2.4.0", "webpack-sources": "^3.2.3" }, "bin": { @@ -40758,9 +40758,9 @@ } }, "node_modules/webpack/node_modules/enhanced-resolve": { - "version": "5.9.3", - "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.9.3.tgz", - "integrity": "sha512-Bq9VSor+kjvW3f9/MiiR4eE3XYgOl7/rS8lnSxbRbF3kS0B2r+Y9w5krBWxZgDxASVZbdYrn5wT4j/Wb0J9qow==", + "version": "5.12.0", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.12.0.tgz", + "integrity": "sha512-QHTXI/sZQmko1cbDoNAa3mJ5qhWUUNAq3vR0/YiD379fWQrcfuoX1+HW2S0MTt7XmoPLapdaDKUtelUSPic7hQ==", "dev": true, "dependencies": { "graceful-fs": "^4.2.4", @@ -72205,9 +72205,9 @@ "integrity": "sha1-JFNCdeKnvGvnvIZhHMFq4KVlSHE=" }, "webpack": { - "version": "5.73.0", - "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.73.0.tgz", - "integrity": "sha512-svjudQRPPa0YiOYa2lM/Gacw0r6PvxptHj4FuEKQ2kX05ZLkjbVc5MnPs6its5j7IZljnIqSVo/OsY2X0IpHGA==", + "version": "5.76.0", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.76.0.tgz", + "integrity": "sha512-l5sOdYBDunyf72HW8dF23rFtWq/7Zgvt/9ftMof71E/yUb1YLOBmTgA2K4vQthB3kotMrSj609txVE0dnr2fjA==", "dev": true, "requires": { "@types/eslint-scope": "^3.7.3", @@ -72215,11 +72215,11 @@ "@webassemblyjs/ast": "1.11.1", "@webassemblyjs/wasm-edit": "1.11.1", "@webassemblyjs/wasm-parser": "1.11.1", - "acorn": "^8.4.1", + "acorn": "^8.7.1", "acorn-import-assertions": "^1.7.6", "browserslist": "^4.14.5", "chrome-trace-event": "^1.0.2", - "enhanced-resolve": "^5.9.3", + "enhanced-resolve": "^5.10.0", "es-module-lexer": "^0.9.0", "eslint-scope": "5.1.1", "events": "^3.2.0", @@ -72232,7 +72232,7 @@ "schema-utils": "^3.1.0", "tapable": "^2.1.1", "terser-webpack-plugin": "^5.1.3", - "watchpack": "^2.3.1", + "watchpack": "^2.4.0", "webpack-sources": "^3.2.3" }, "dependencies": { @@ -72261,9 +72261,9 @@ } }, "enhanced-resolve": { - "version": "5.9.3", - "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.9.3.tgz", - "integrity": "sha512-Bq9VSor+kjvW3f9/MiiR4eE3XYgOl7/rS8lnSxbRbF3kS0B2r+Y9w5krBWxZgDxASVZbdYrn5wT4j/Wb0J9qow==", + "version": "5.12.0", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.12.0.tgz", + "integrity": "sha512-QHTXI/sZQmko1cbDoNAa3mJ5qhWUUNAq3vR0/YiD379fWQrcfuoX1+HW2S0MTt7XmoPLapdaDKUtelUSPic7hQ==", "dev": true, "requires": { "graceful-fs": "^4.2.4", diff --git a/extensions/ql-vscode/package.json b/extensions/ql-vscode/package.json index 40b2a3930..a065d268e 100644 --- a/extensions/ql-vscode/package.json +++ b/extensions/ql-vscode/package.json @@ -1535,7 +1535,7 @@ "ts-node": "^10.7.0", "ts-protoc-gen": "^0.9.0", "typescript": "^4.5.5", - "webpack": "^5.62.2", + "webpack": "^5.76.0", "webpack-cli": "^4.6.0" }, "lint-staged": { From 639c8728ddeceb5a1f469c2ceb27e634ed4f37fb Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 15 Mar 2023 09:22:59 +0000 Subject: [PATCH 042/156] Bump lint-staged from 10.2.11 to 13.2.0 in /extensions/ql-vscode Bumps [lint-staged](https://github.com/okonet/lint-staged) from 10.2.11 to 13.2.0. - [Release notes](https://github.com/okonet/lint-staged/releases) - [Commits](https://github.com/okonet/lint-staged/compare/v10.2.11...v13.2.0) --- updated-dependencies: - dependency-name: lint-staged dependency-type: direct:development update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- extensions/ql-vscode/package-lock.json | 1188 ++++++++++++------------ extensions/ql-vscode/package.json | 2 +- 2 files changed, 603 insertions(+), 587 deletions(-) diff --git a/extensions/ql-vscode/package-lock.json b/extensions/ql-vscode/package-lock.json index 0b00888cd..8805e7185 100644 --- a/extensions/ql-vscode/package-lock.json +++ b/extensions/ql-vscode/package-lock.json @@ -129,7 +129,7 @@ "jest": "^29.0.3", "jest-environment-jsdom": "^29.0.3", "jest-runner-vscode": "^3.0.1", - "lint-staged": "~10.2.2", + "lint-staged": "~13.2.0", "mini-css-extract-plugin": "^2.6.1", "npm-run-all": "^4.1.5", "patch-package": "^6.5.0", @@ -15764,6 +15764,15 @@ "integrity": "sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ==", "dev": true }, + "node_modules/astral-regex": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-2.0.0.tgz", + "integrity": "sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, "node_modules/async": { "version": "3.2.3", "resolved": "https://registry.npmjs.org/async/-/async-3.2.3.tgz", @@ -18115,70 +18124,69 @@ } }, "node_modules/cli-truncate": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/cli-truncate/-/cli-truncate-2.1.0.tgz", - "integrity": "sha512-n8fOixwDD6b/ObinzTrp1ZKFzbgvKZvuz/TvejnLn1aQfC6r52XEx85FmuC+3HI+JM7coBRXUvNqEU2PHVrHpg==", + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/cli-truncate/-/cli-truncate-3.1.0.tgz", + "integrity": "sha512-wfOBkjXteqSnI59oPcJkcPl/ZmwvMMOj340qUIY1SKZCv0B9Cf4D4fAucRkIKQmsIuYK3x1rrgU7MeGRruiuiA==", "dev": true, "dependencies": { - "slice-ansi": "^3.0.0", - "string-width": "^4.2.0" + "slice-ansi": "^5.0.0", + "string-width": "^5.0.0" }, "engines": { - "node": ">=8" - } - }, - "node_modules/cli-truncate/node_modules/ansi-styles": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.2.1.tgz", - "integrity": "sha512-9VGjrMsG1vePxcSweQsN20KY/c4zN0h9fLjqAbwbPfahM3t+NL+M9HC8xeXG2I8pX5NoamTGNuomEUFI7fcUjA==", - "dev": true, - "dependencies": { - "@types/color-name": "^1.1.1", - "color-convert": "^2.0.1" + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" }, - "engines": { - "node": ">=8" + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/cli-truncate/node_modules/astral-regex": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-2.0.0.tgz", - "integrity": "sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==", + "node_modules/cli-truncate/node_modules/ansi-regex": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", + "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==", "dev": true, "engines": { - "node": ">=8" - } - }, - "node_modules/cli-truncate/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "dependencies": { - "color-name": "~1.1.4" + "node": ">=12" }, - "engines": { - "node": ">=7.0.0" + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" } }, - "node_modules/cli-truncate/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "node_modules/cli-truncate/node_modules/emoji-regex": { + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", + "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", "dev": true }, - "node_modules/cli-truncate/node_modules/slice-ansi": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-3.0.0.tgz", - "integrity": "sha512-pSyv7bSTC7ig9Dcgbw9AuRNUb5k5V6oDudjZoMBSr13qpLBG7tB+zgCkARjq7xIUgdz5P1Qe8u+rSGdouOOIyQ==", + "node_modules/cli-truncate/node_modules/string-width": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", + "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", "dev": true, "dependencies": { - "ansi-styles": "^4.0.0", - "astral-regex": "^2.0.0", - "is-fullwidth-code-point": "^3.0.0" + "eastasianwidth": "^0.2.0", + "emoji-regex": "^9.2.2", + "strip-ansi": "^7.0.1" }, "engines": { - "node": ">=8" + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/cli-truncate/node_modules/strip-ansi": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.0.1.tgz", + "integrity": "sha512-cXNxvT8dFNRVfhVME3JAe98mkXDYN2O1l7jmcwMnOslDeESg1rF/OZMtK0nRAhiari1unG5cD4jG3rapUAkLbw==", + "dev": true, + "dependencies": { + "ansi-regex": "^6.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" } }, "node_modules/cli-width": { @@ -18444,12 +18452,12 @@ } }, "node_modules/commander": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-5.1.0.tgz", - "integrity": "sha512-P0CysNDQ7rtVw4QIQtm+MRxV66vKFSvlsQvGYXZWR3qFU0jlMKHZZZgw8e+8DSah4UDKMqnknRDQz+xuQXQ/Zg==", + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-10.0.0.tgz", + "integrity": "sha512-zS5PnTI22FIRM6ylNW8G4Ap0IEOyk62fhLSD0+uHRT9McRCLGpkVNvao4bjimpK/GShynyQkFFxHhwMcETmduA==", "dev": true, "engines": { - "node": ">= 6" + "node": ">=14" } }, "node_modules/common-path-prefix": { @@ -20236,18 +20244,6 @@ "url": "https://github.com/sindresorhus/execa?sponsor=1" } }, - "node_modules/detect-package-manager/node_modules/get-stream": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", - "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/detect-package-manager/node_modules/human-signals": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", @@ -20582,6 +20578,12 @@ "object.defaults": "^1.1.0" } }, + "node_modules/eastasianwidth": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", + "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==", + "dev": true + }, "node_modules/easy-stack": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/easy-stack/-/easy-stack-1.0.1.tgz", @@ -22439,23 +22441,26 @@ "dev": true }, "node_modules/execa": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/execa/-/execa-4.0.3.tgz", - "integrity": "sha512-WFDXGHckXPWZX19t1kCsXzOpqX9LWYNqn4C+HqZlk/V0imTkzJZqf87ZBhvpHaftERYknpk0fjSylnXVlVgI0A==", + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/execa/-/execa-7.1.1.tgz", + "integrity": "sha512-wH0eMf/UXckdUYnO21+HDztteVv05rq2GXksxT4fCGeHkBhw1DROXh40wcjMcRqDOWE7iPJ4n3M7e2+YFP+76Q==", "dev": true, "dependencies": { - "cross-spawn": "^7.0.0", - "get-stream": "^5.0.0", - "human-signals": "^1.1.1", - "is-stream": "^2.0.0", + "cross-spawn": "^7.0.3", + "get-stream": "^6.0.1", + "human-signals": "^4.3.0", + "is-stream": "^3.0.0", "merge-stream": "^2.0.0", - "npm-run-path": "^4.0.0", - "onetime": "^5.1.0", - "signal-exit": "^3.0.2", - "strip-final-newline": "^2.0.0" + "npm-run-path": "^5.1.0", + "onetime": "^6.0.0", + "signal-exit": "^3.0.7", + "strip-final-newline": "^3.0.0" }, "engines": { - "node": ">=10" + "node": "^14.18.0 || ^16.14.0 || >=18.0.0" + }, + "funding": { + "url": "https://github.com/sindresorhus/execa?sponsor=1" } }, "node_modules/execa/node_modules/cross-spawn": { @@ -22472,6 +22477,72 @@ "node": ">= 8" } }, + "node_modules/execa/node_modules/is-stream": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-3.0.0.tgz", + "integrity": "sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA==", + "dev": true, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/execa/node_modules/mimic-fn": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-4.0.0.tgz", + "integrity": "sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/execa/node_modules/npm-run-path": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-5.1.0.tgz", + "integrity": "sha512-sJOdmRGrY2sjNTRMbSvluQqg+8X7ZK61yvzBEIDhz4f8z1TZFYABsqjjCBd/0PUNE9M6QDgHJXQkGUEm7Q+l9Q==", + "dev": true, + "dependencies": { + "path-key": "^4.0.0" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/execa/node_modules/npm-run-path/node_modules/path-key": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-4.0.0.tgz", + "integrity": "sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/execa/node_modules/onetime": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-6.0.0.tgz", + "integrity": "sha512-1FlR+gjXK7X+AsAHso35MnyN5KqGwJRi/31ft6x0M194ht7S+rWAvd7PHss9xSKMzE0asv1pyIHaJYq+BbacAQ==", + "dev": true, + "dependencies": { + "mimic-fn": "^4.0.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/execa/node_modules/path-key": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", @@ -22502,6 +22573,18 @@ "node": ">=8" } }, + "node_modules/execa/node_modules/strip-final-newline": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-3.0.0.tgz", + "integrity": "sha512-dOESqjYr96iWYylGObzd39EuNTa5VJxyvVAEm5Jnh7KGo75V43Hk1odPQkNDyXNmUR6k+gEiDVXnjB8HJ3crXw==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/execa/node_modules/which": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", @@ -24061,12 +24144,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/get-own-enumerable-property-symbols": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/get-own-enumerable-property-symbols/-/get-own-enumerable-property-symbols-3.0.2.tgz", - "integrity": "sha512-I0UBV/XOz1XkIJHEUDMZAbzCThU/H8DxmSfmdGcKPnVhu2VfFqr34jr9777IyaTYvxjedWhqVIilEDsCdP5G6g==", - "dev": true - }, "node_modules/get-package-type": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/get-package-type/-/get-package-type-0.1.0.tgz", @@ -24087,25 +24164,15 @@ } }, "node_modules/get-stream": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.1.0.tgz", - "integrity": "sha512-EXr1FOzrzTfGeL0gQdeFEvOMm2mzMOglyiOXSTpPC+iAjAKftbr3jpCMWynogwYnM+eSj9sHGc6wjIcDvYiygw==", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", + "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", "dev": true, - "dependencies": { - "pump": "^3.0.0" - }, "engines": { - "node": ">=8" - } - }, - "node_modules/get-stream/node_modules/pump": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", - "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", - "dev": true, - "dependencies": { - "end-of-stream": "^1.1.0", - "once": "^1.3.1" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/get-symbol-description": { @@ -25353,12 +25420,12 @@ "dev": true }, "node_modules/human-signals": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-1.1.1.tgz", - "integrity": "sha512-SEQu7vl8KjNL2eoGBLF3+wAjpsNfA9XMlXAYj/3EdaNfAlxKthD1xjEQfGOUhllCGGJVNY34bRr6lPINhNjyZw==", + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-4.3.0.tgz", + "integrity": "sha512-zyzVyMjpGBX2+6cDVZeFPCdtOtdsxOeseRhB9tkQ6xXmGUNrcnBzdEKPy3VPNYz+4gy1oukVOXcrJCunSyc6QQ==", "dev": true, "engines": { - "node": ">=8.12.0" + "node": ">=14.18.0" } }, "node_modules/husky": { @@ -25984,15 +26051,6 @@ "node": ">=0.10.0" } }, - "node_modules/is-obj": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-1.0.1.tgz", - "integrity": "sha1-PkcprB9f3gJc19g6iW2rn09n2w8=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/is-object": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/is-object/-/is-object-1.0.1.tgz", @@ -26065,15 +26123,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/is-regexp": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-regexp/-/is-regexp-1.0.0.tgz", - "integrity": "sha1-/S2INUXEa6xaYz57mgnof6LLUGk=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/is-relative": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-relative/-/is-relative-1.0.0.tgz", @@ -26555,18 +26604,6 @@ "url": "https://github.com/sindresorhus/execa?sponsor=1" } }, - "node_modules/jest-changed-files/node_modules/get-stream": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", - "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/jest-changed-files/node_modules/human-signals": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", @@ -31220,6 +31257,15 @@ "node": ">= 0.8" } }, + "node_modules/lilconfig": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-2.1.0.tgz", + "integrity": "sha512-utWOt/GHzuUxnLKxB6dk81RoOeoNeHgbrXiuGk4yyF5qlRz+iIVWu56E2fqGHFrXz0QNUhLB/8nKqvRH66JKGQ==", + "dev": true, + "engines": { + "node": ">=10" + } + }, "node_modules/lines-and-columns": { "version": "1.1.6", "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.1.6.tgz", @@ -31236,42 +31282,33 @@ } }, "node_modules/lint-staged": { - "version": "10.2.11", - "resolved": "https://registry.npmjs.org/lint-staged/-/lint-staged-10.2.11.tgz", - "integrity": "sha512-LRRrSogzbixYaZItE2APaS4l2eJMjjf5MbclRZpLJtcQJShcvUzKXsNeZgsLIZ0H0+fg2tL4B59fU9wHIHtFIA==", + "version": "13.2.0", + "resolved": "https://registry.npmjs.org/lint-staged/-/lint-staged-13.2.0.tgz", + "integrity": "sha512-GbyK5iWinax5Dfw5obm2g2ccUiZXNGtAS4mCbJ0Lv4rq6iEtfBSjOYdcbOtAIFtM114t0vdpViDDetjVTSd8Vw==", "dev": true, "dependencies": { - "chalk": "^4.0.0", - "cli-truncate": "2.1.0", - "commander": "^5.1.0", - "cosmiconfig": "^6.0.0", - "debug": "^4.1.1", - "dedent": "^0.7.0", - "enquirer": "^2.3.5", - "execa": "^4.0.1", - "listr2": "^2.1.0", - "log-symbols": "^4.0.0", - "micromatch": "^4.0.2", + "chalk": "5.2.0", + "cli-truncate": "^3.1.0", + "commander": "^10.0.0", + "debug": "^4.3.4", + "execa": "^7.0.0", + "lilconfig": "2.1.0", + "listr2": "^5.0.7", + "micromatch": "^4.0.5", "normalize-path": "^3.0.0", - "please-upgrade-node": "^3.2.0", - "string-argv": "0.3.1", - "stringify-object": "^3.3.0" + "object-inspect": "^1.12.3", + "pidtree": "^0.6.0", + "string-argv": "^0.3.1", + "yaml": "^2.2.1" }, "bin": { "lint-staged": "bin/lint-staged.js" - } - }, - "node_modules/lint-staged/node_modules/ansi-styles": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.2.1.tgz", - "integrity": "sha512-9VGjrMsG1vePxcSweQsN20KY/c4zN0h9fLjqAbwbPfahM3t+NL+M9HC8xeXG2I8pX5NoamTGNuomEUFI7fcUjA==", - "dev": true, - "dependencies": { - "@types/color-name": "^1.1.1", - "color-convert": "^2.0.1" }, "engines": { - "node": ">=8" + "node": "^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/lint-staged" } }, "node_modules/lint-staged/node_modules/braces": { @@ -31287,43 +31324,32 @@ } }, "node_modules/lint-staged/node_modules/chalk": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz", - "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==", + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.2.0.tgz", + "integrity": "sha512-ree3Gqw/nazQAPuJJEy+avdl7QfZMcUvmHIKgEZkGL+xOBzRvup5Hxo6LHuMceSxOabuJLJm5Yp/92R9eMmMvA==", "dev": true, - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, "engines": { - "node": ">=10" - } - }, - "node_modules/lint-staged/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "dependencies": { - "color-name": "~1.1.4" + "node": "^12.17.0 || ^14.13 || >=16.0.0" }, - "engines": { - "node": ">=7.0.0" + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" } }, - "node_modules/lint-staged/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, "node_modules/lint-staged/node_modules/debug": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", - "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", "dev": true, "dependencies": { - "ms": "^2.1.1" + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } } }, "node_modules/lint-staged/node_modules/fill-range": { @@ -31338,15 +31364,6 @@ "node": ">=8" } }, - "node_modules/lint-staged/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, "node_modules/lint-staged/node_modules/is-number": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", @@ -31357,16 +31374,16 @@ } }, "node_modules/lint-staged/node_modules/micromatch": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.2.tgz", - "integrity": "sha512-y7FpHSbMUMoyPbYUSzO6PaZ6FyRnQOpHuKwbo1G+Knck95XVU4QAiKdGEnj5wwoS7PlOgthX/09u5iFJ+aYf5Q==", + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", + "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", "dev": true, "dependencies": { - "braces": "^3.0.1", - "picomatch": "^2.0.5" + "braces": "^3.0.2", + "picomatch": "^2.3.1" }, "engines": { - "node": ">=8" + "node": ">=8.6" } }, "node_modules/lint-staged/node_modules/ms": { @@ -31375,16 +31392,16 @@ "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", "dev": true }, - "node_modules/lint-staged/node_modules/supports-color": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.1.0.tgz", - "integrity": "sha512-oRSIpR8pxT1Wr2FquTNnGet79b3BWljqOuoW/h4oBhxJ/HUbX5nX6JSruTkvXDCFMwDPvsaTTbvMLKZWSy0R5g==", + "node_modules/lint-staged/node_modules/pidtree": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/pidtree/-/pidtree-0.6.0.tgz", + "integrity": "sha512-eG2dWTVw5bzqGRztnHExczNxt5VGsE6OwTeCG3fdUf9KBsZzO3R5OIIIzWR+iZA0NtZ+RDVdaoE2dK1cn6jH4g==", "dev": true, - "dependencies": { - "has-flag": "^4.0.0" + "bin": { + "pidtree": "bin/pidtree.js" }, "engines": { - "node": ">=8" + "node": ">=0.10" } }, "node_modules/lint-staged/node_modules/to-regex-range": { @@ -31399,54 +31416,76 @@ "node": ">=8.0" } }, + "node_modules/lint-staged/node_modules/yaml": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.2.1.tgz", + "integrity": "sha512-e0WHiYql7+9wr4cWMx3TVQrNwejKaEe7/rHNmQmqRjazfOP5W8PB6Jpebb5o6fIapbz9o9+2ipcaTM2ZwDI6lw==", + "dev": true, + "engines": { + "node": ">= 14" + } + }, "node_modules/listenercount": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/listenercount/-/listenercount-1.0.1.tgz", "integrity": "sha1-hMinKrWcRyUyFIDJdeZQg0LnCTc=" }, "node_modules/listr2": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/listr2/-/listr2-2.2.0.tgz", - "integrity": "sha512-Q8qbd7rgmEwDo1nSyHaWQeztfGsdL6rb4uh7BA+Q80AZiDET5rVntiU1+13mu2ZTDVaBVbvAD1Db11rnu3l9sg==", + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/listr2/-/listr2-5.0.8.tgz", + "integrity": "sha512-mC73LitKHj9w6v30nLNGPetZIlfpUniNSsxxrbaPcWOjDb92SHPzJPi/t+v1YC/lxKz/AJ9egOjww0qUuFxBpA==", "dev": true, "dependencies": { - "chalk": "^4.0.0", "cli-truncate": "^2.1.0", - "figures": "^3.2.0", - "indent-string": "^4.0.0", + "colorette": "^2.0.19", "log-update": "^4.0.0", "p-map": "^4.0.0", - "rxjs": "^6.5.5", - "through": "^2.3.8" + "rfdc": "^1.3.0", + "rxjs": "^7.8.0", + "through": "^2.3.8", + "wrap-ansi": "^7.0.0" }, "engines": { - "node": ">=10.0.0" + "node": "^14.13.1 || >=16.0.0" + }, + "peerDependencies": { + "enquirer": ">= 2.3.0 < 3" + }, + "peerDependenciesMeta": { + "enquirer": { + "optional": true + } } }, "node_modules/listr2/node_modules/ansi-styles": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.2.1.tgz", - "integrity": "sha512-9VGjrMsG1vePxcSweQsN20KY/c4zN0h9fLjqAbwbPfahM3t+NL+M9HC8xeXG2I8pX5NoamTGNuomEUFI7fcUjA==", + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", "dev": true, "dependencies": { - "@types/color-name": "^1.1.1", "color-convert": "^2.0.1" }, "engines": { "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/listr2/node_modules/chalk": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz", - "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==", + "node_modules/listr2/node_modules/cli-truncate": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/cli-truncate/-/cli-truncate-2.1.0.tgz", + "integrity": "sha512-n8fOixwDD6b/ObinzTrp1ZKFzbgvKZvuz/TvejnLn1aQfC6r52XEx85FmuC+3HI+JM7coBRXUvNqEU2PHVrHpg==", "dev": true, "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" + "slice-ansi": "^3.0.0", + "string-width": "^4.2.0" }, "engines": { - "node": ">=10" + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/listr2/node_modules/color-convert": { @@ -31467,25 +31506,41 @@ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", "dev": true }, - "node_modules/listr2/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "node_modules/listr2/node_modules/colorette": { + "version": "2.0.19", + "resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.19.tgz", + "integrity": "sha512-3tlv/dIP7FWvj3BsbHrGLJ6l/oKh1O3TcgBqMn+yyCagOxc23fyzDS6HypQbgxWbkpDnf52p1LuR4eWDQ/K9WQ==", + "dev": true + }, + "node_modules/listr2/node_modules/slice-ansi": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-3.0.0.tgz", + "integrity": "sha512-pSyv7bSTC7ig9Dcgbw9AuRNUb5k5V6oDudjZoMBSr13qpLBG7tB+zgCkARjq7xIUgdz5P1Qe8u+rSGdouOOIyQ==", "dev": true, + "dependencies": { + "ansi-styles": "^4.0.0", + "astral-regex": "^2.0.0", + "is-fullwidth-code-point": "^3.0.0" + }, "engines": { "node": ">=8" } }, - "node_modules/listr2/node_modules/supports-color": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.1.0.tgz", - "integrity": "sha512-oRSIpR8pxT1Wr2FquTNnGet79b3BWljqOuoW/h4oBhxJ/HUbX5nX6JSruTkvXDCFMwDPvsaTTbvMLKZWSy0R5g==", + "node_modules/listr2/node_modules/wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", "dev": true, "dependencies": { - "has-flag": "^4.0.0" + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" }, "engines": { - "node": ">=8" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" } }, "node_modules/load-json-file": { @@ -31704,28 +31759,24 @@ }, "engines": { "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/log-update/node_modules/ansi-styles": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.2.1.tgz", - "integrity": "sha512-9VGjrMsG1vePxcSweQsN20KY/c4zN0h9fLjqAbwbPfahM3t+NL+M9HC8xeXG2I8pX5NoamTGNuomEUFI7fcUjA==", + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", "dev": true, "dependencies": { - "@types/color-name": "^1.1.1", "color-convert": "^2.0.1" }, "engines": { "node": ">=8" - } - }, - "node_modules/log-update/node_modules/astral-regex": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-2.0.0.tgz", - "integrity": "sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==", - "dev": true, - "engines": { - "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, "node_modules/log-update/node_modules/color-convert": { @@ -31758,6 +31809,9 @@ }, "engines": { "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/slice-ansi?sponsor=1" } }, "node_modules/log-update/node_modules/wrap-ansi": { @@ -32774,14 +32828,6 @@ "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-6.2.1.tgz", "integrity": "sha512-JLyh7xT1kizaEvcaXOQwOc2/Yhw6KZOvPf1S8401UyLk86CU79LN3vl7ztXGm/pZ+YjoyAJ4rxmHwbkBXJX+yw==" }, - "node_modules/msw/node_modules/rxjs": { - "version": "7.5.7", - "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.5.7.tgz", - "integrity": "sha512-z9MzKh/UcOqB3i20H6rtrlaE/CgjLOvheWK/9ILrbhROGTweAi1BaFsTT9FbwZi5Trr1qNRs+MXkhmR06awzQA==", - "dependencies": { - "tslib": "^2.1.0" - } - }, "node_modules/msw/node_modules/supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", @@ -32793,11 +32839,6 @@ "node": ">=8" } }, - "node_modules/msw/node_modules/tslib": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.0.tgz", - "integrity": "sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ==" - }, "node_modules/msw/node_modules/type-fest": { "version": "2.19.0", "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-2.19.0.tgz", @@ -33373,9 +33414,9 @@ } }, "node_modules/object-inspect": { - "version": "1.12.2", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.2.tgz", - "integrity": "sha512-z+cPxW0QGUp0mcqcsgQyLVRDoXFQbXOwBaqyF7VIgI4TWNQsDHrBpUQslRmIfAoYWdYzs6UlKJtB2XJpTaNSpQ==", + "version": "1.12.3", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.3.tgz", + "integrity": "sha512-geUvdk7c+eizMNUDkRpW1wJwgfOiOeHbxBR/hLXK1aT6zmVSO0jsQcs7fj6MGw89jC/cjGfLcNOrtMYtGqm81g==", "funding": { "url": "https://github.com/sponsors/ljharb" } @@ -34498,15 +34539,6 @@ "node": ">=8" } }, - "node_modules/please-upgrade-node": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/please-upgrade-node/-/please-upgrade-node-3.2.0.tgz", - "integrity": "sha512-gQR3WpIgNIKwBMVLkpMUeR3e1/E1y42bqDQZfql+kDeXd8COYfM8PQA4X6y7a8u9Ua9FHmsrrmirW2vHs45hWg==", - "dev": true, - "dependencies": { - "semver-compare": "^1.0.0" - } - }, "node_modules/plugin-error": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/plugin-error/-/plugin-error-1.0.1.tgz", @@ -36224,6 +36256,12 @@ "node": ">=0.10.0" } }, + "node_modules/rfdc": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/rfdc/-/rfdc-1.3.0.tgz", + "integrity": "sha512-V2hovdzFbOi77/WajaSMXk2OLm+xNIeQdMMuB7icj7bk6zi2F8GGAxigcnDFpJHbNyNcgyJDiP+8nOrY5cZGrA==", + "dev": true + }, "node_modules/rimraf": { "version": "2.7.1", "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", @@ -36305,17 +36343,18 @@ "integrity": "sha512-PdhdWy89SiZogBLaw42zdeqtRJ//zFd2PgQavcICDUgJT5oW10QCRKbJ6bg4r0/UY2M6BWd5tkxuGFRvCkgfHQ==" }, "node_modules/rxjs": { - "version": "6.6.0", - "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.6.0.tgz", - "integrity": "sha512-3HMA8z/Oz61DUHe+SdOiQyzIf4tOx5oQHmMir7IZEu6TMqCLHT4LRcmNaUS0NwOz8VLvmmBduMsoaUvMaIiqzg==", - "dev": true, + "version": "7.8.0", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.0.tgz", + "integrity": "sha512-F2+gxDshqmIub1KdvZkaEfGDwLNpPvk9Fs6LD/MyQxNgMds/WH9OdDDXOmxUZpME+iSK3rQCctkL0DYyytUqMg==", "dependencies": { - "tslib": "^1.9.0" - }, - "engines": { - "npm": ">=2.0.0" + "tslib": "^2.1.0" } }, + "node_modules/rxjs/node_modules/tslib": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", + "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==" + }, "node_modules/safe-buffer": { "version": "5.1.2", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", @@ -36531,12 +36570,6 @@ "node": ">=10" } }, - "node_modules/semver-compare": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/semver-compare/-/semver-compare-1.0.0.tgz", - "integrity": "sha1-De4hahyUGrN+nvsXiPavxf9VN/w=", - "dev": true - }, "node_modules/semver-greatest-satisfied-range": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/semver-greatest-satisfied-range/-/semver-greatest-satisfied-range-1.1.0.tgz", @@ -36836,6 +36869,46 @@ "node": ">=8" } }, + "node_modules/slice-ansi": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-5.0.0.tgz", + "integrity": "sha512-FC+lgizVPfie0kkhqUScwRu1O/lF6NOgJmlCgK+/LYxDCTk8sGelYaHDhFcDN+Sn3Cv+3VSa4Byeo+IMCzpMgQ==", + "dev": true, + "dependencies": { + "ansi-styles": "^6.0.0", + "is-fullwidth-code-point": "^4.0.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/slice-ansi?sponsor=1" + } + }, + "node_modules/slice-ansi/node_modules/ansi-styles": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", + "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/slice-ansi/node_modules/is-fullwidth-code-point": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-4.0.0.tgz", + "integrity": "sha512-O4L094N2/dZ7xqVdrXhh9r1KODPJpFms8B5sGdJLPy664AgvXsreZUyCQQNItZRDlYug4xStLjNp/sz3HvBowQ==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/snapdragon": { "version": "0.8.2", "resolved": "https://registry.npmjs.org/snapdragon/-/snapdragon-0.8.2.tgz", @@ -37416,20 +37489,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/stringify-object": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/stringify-object/-/stringify-object-3.3.0.tgz", - "integrity": "sha512-rHqiFh1elqCQ9WPLIC8I0Q/g/wj5J1eMkyoiD6eoQApWHP0FtlK7rqnhmabL5VUY9JQCcqwwvlOaSuutekgyrw==", - "dev": true, - "dependencies": { - "get-own-enumerable-property-symbols": "^3.0.0", - "is-obj": "^1.0.1", - "is-regexp": "^1.0.0" - }, - "engines": { - "node": ">=4" - } - }, "node_modules/strip-ansi": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", @@ -40496,18 +40555,6 @@ "url": "https://github.com/sindresorhus/execa?sponsor=1" } }, - "node_modules/webpack-cli/node_modules/get-stream": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.0.tgz", - "integrity": "sha512-A1B3Bh1UmL0bidM/YX2NsCOTnGJePL9rO/M+Mw3m9f2gUpfokS0hi5Eah0WSUEWZdZhIZtMjkIYS7mDfOqNHbg==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/webpack-cli/node_modules/human-signals": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", @@ -53264,6 +53311,12 @@ "integrity": "sha512-eBvWn1lvIApYMhzQMsu9ciLfkBY499mFZlNqG+/9WR7PVlroQw0vG30cOQQbaKz3sCEc44TAOu2ykzqXSNnwag==", "dev": true }, + "astral-regex": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-2.0.0.tgz", + "integrity": "sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==", + "dev": true + }, "async": { "version": "3.2.3", "resolved": "https://registry.npmjs.org/async/-/async-3.2.3.tgz", @@ -55078,55 +55131,45 @@ } }, "cli-truncate": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/cli-truncate/-/cli-truncate-2.1.0.tgz", - "integrity": "sha512-n8fOixwDD6b/ObinzTrp1ZKFzbgvKZvuz/TvejnLn1aQfC6r52XEx85FmuC+3HI+JM7coBRXUvNqEU2PHVrHpg==", + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/cli-truncate/-/cli-truncate-3.1.0.tgz", + "integrity": "sha512-wfOBkjXteqSnI59oPcJkcPl/ZmwvMMOj340qUIY1SKZCv0B9Cf4D4fAucRkIKQmsIuYK3x1rrgU7MeGRruiuiA==", "dev": true, "requires": { - "slice-ansi": "^3.0.0", - "string-width": "^4.2.0" + "slice-ansi": "^5.0.0", + "string-width": "^5.0.0" }, "dependencies": { - "ansi-styles": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.2.1.tgz", - "integrity": "sha512-9VGjrMsG1vePxcSweQsN20KY/c4zN0h9fLjqAbwbPfahM3t+NL+M9HC8xeXG2I8pX5NoamTGNuomEUFI7fcUjA==", - "dev": true, - "requires": { - "@types/color-name": "^1.1.1", - "color-convert": "^2.0.1" - } - }, - "astral-regex": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-2.0.0.tgz", - "integrity": "sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==", + "ansi-regex": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", + "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==", "dev": true }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "requires": { - "color-name": "~1.1.4" - } - }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "emoji-regex": { + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", + "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", "dev": true }, - "slice-ansi": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-3.0.0.tgz", - "integrity": "sha512-pSyv7bSTC7ig9Dcgbw9AuRNUb5k5V6oDudjZoMBSr13qpLBG7tB+zgCkARjq7xIUgdz5P1Qe8u+rSGdouOOIyQ==", + "string-width": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", + "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", "dev": true, "requires": { - "ansi-styles": "^4.0.0", - "astral-regex": "^2.0.0", - "is-fullwidth-code-point": "^3.0.0" + "eastasianwidth": "^0.2.0", + "emoji-regex": "^9.2.2", + "strip-ansi": "^7.0.1" + } + }, + "strip-ansi": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.0.1.tgz", + "integrity": "sha512-cXNxvT8dFNRVfhVME3JAe98mkXDYN2O1l7jmcwMnOslDeESg1rF/OZMtK0nRAhiari1unG5cD4jG3rapUAkLbw==", + "dev": true, + "requires": { + "ansi-regex": "^6.0.1" } } } @@ -55338,9 +55381,9 @@ "dev": true }, "commander": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-5.1.0.tgz", - "integrity": "sha512-P0CysNDQ7rtVw4QIQtm+MRxV66vKFSvlsQvGYXZWR3qFU0jlMKHZZZgw8e+8DSah4UDKMqnknRDQz+xuQXQ/Zg==", + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-10.0.0.tgz", + "integrity": "sha512-zS5PnTI22FIRM6ylNW8G4Ap0IEOyk62fhLSD0+uHRT9McRCLGpkVNvao4bjimpK/GShynyQkFFxHhwMcETmduA==", "dev": true }, "common-path-prefix": { @@ -56737,12 +56780,6 @@ "strip-final-newline": "^2.0.0" } }, - "get-stream": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", - "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", - "dev": true - }, "human-signals": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", @@ -57012,6 +57049,12 @@ "object.defaults": "^1.1.0" } }, + "eastasianwidth": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", + "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==", + "dev": true + }, "easy-stack": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/easy-stack/-/easy-stack-1.0.1.tgz", @@ -58332,20 +58375,20 @@ "dev": true }, "execa": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/execa/-/execa-4.0.3.tgz", - "integrity": "sha512-WFDXGHckXPWZX19t1kCsXzOpqX9LWYNqn4C+HqZlk/V0imTkzJZqf87ZBhvpHaftERYknpk0fjSylnXVlVgI0A==", + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/execa/-/execa-7.1.1.tgz", + "integrity": "sha512-wH0eMf/UXckdUYnO21+HDztteVv05rq2GXksxT4fCGeHkBhw1DROXh40wcjMcRqDOWE7iPJ4n3M7e2+YFP+76Q==", "dev": true, "requires": { - "cross-spawn": "^7.0.0", - "get-stream": "^5.0.0", - "human-signals": "^1.1.1", - "is-stream": "^2.0.0", + "cross-spawn": "^7.0.3", + "get-stream": "^6.0.1", + "human-signals": "^4.3.0", + "is-stream": "^3.0.0", "merge-stream": "^2.0.0", - "npm-run-path": "^4.0.0", - "onetime": "^5.1.0", - "signal-exit": "^3.0.2", - "strip-final-newline": "^2.0.0" + "npm-run-path": "^5.1.0", + "onetime": "^6.0.0", + "signal-exit": "^3.0.7", + "strip-final-newline": "^3.0.0" }, "dependencies": { "cross-spawn": { @@ -58359,6 +58402,44 @@ "which": "^2.0.1" } }, + "is-stream": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-3.0.0.tgz", + "integrity": "sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA==", + "dev": true + }, + "mimic-fn": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-4.0.0.tgz", + "integrity": "sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw==", + "dev": true + }, + "npm-run-path": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-5.1.0.tgz", + "integrity": "sha512-sJOdmRGrY2sjNTRMbSvluQqg+8X7ZK61yvzBEIDhz4f8z1TZFYABsqjjCBd/0PUNE9M6QDgHJXQkGUEm7Q+l9Q==", + "dev": true, + "requires": { + "path-key": "^4.0.0" + }, + "dependencies": { + "path-key": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-4.0.0.tgz", + "integrity": "sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ==", + "dev": true + } + } + }, + "onetime": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-6.0.0.tgz", + "integrity": "sha512-1FlR+gjXK7X+AsAHso35MnyN5KqGwJRi/31ft6x0M194ht7S+rWAvd7PHss9xSKMzE0asv1pyIHaJYq+BbacAQ==", + "dev": true, + "requires": { + "mimic-fn": "^4.0.0" + } + }, "path-key": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", @@ -58380,6 +58461,12 @@ "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", "dev": true }, + "strip-final-newline": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-3.0.0.tgz", + "integrity": "sha512-dOESqjYr96iWYylGObzd39EuNTa5VJxyvVAEm5Jnh7KGo75V43Hk1odPQkNDyXNmUR6k+gEiDVXnjB8HJ3crXw==", + "dev": true + }, "which": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", @@ -59620,12 +59707,6 @@ "has-symbols": "^1.0.3" } }, - "get-own-enumerable-property-symbols": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/get-own-enumerable-property-symbols/-/get-own-enumerable-property-symbols-3.0.2.tgz", - "integrity": "sha512-I0UBV/XOz1XkIJHEUDMZAbzCThU/H8DxmSfmdGcKPnVhu2VfFqr34jr9777IyaTYvxjedWhqVIilEDsCdP5G6g==", - "dev": true - }, "get-package-type": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/get-package-type/-/get-package-type-0.1.0.tgz", @@ -59640,25 +59721,10 @@ "optional": true }, "get-stream": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.1.0.tgz", - "integrity": "sha512-EXr1FOzrzTfGeL0gQdeFEvOMm2mzMOglyiOXSTpPC+iAjAKftbr3jpCMWynogwYnM+eSj9sHGc6wjIcDvYiygw==", - "dev": true, - "requires": { - "pump": "^3.0.0" - }, - "dependencies": { - "pump": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", - "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", - "dev": true, - "requires": { - "end-of-stream": "^1.1.0", - "once": "^1.3.1" - } - } - } + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", + "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", + "dev": true }, "get-symbol-description": { "version": "1.0.0", @@ -60621,9 +60687,9 @@ } }, "human-signals": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-1.1.1.tgz", - "integrity": "sha512-SEQu7vl8KjNL2eoGBLF3+wAjpsNfA9XMlXAYj/3EdaNfAlxKthD1xjEQfGOUhllCGGJVNY34bRr6lPINhNjyZw==", + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-4.3.0.tgz", + "integrity": "sha512-zyzVyMjpGBX2+6cDVZeFPCdtOtdsxOeseRhB9tkQ6xXmGUNrcnBzdEKPy3VPNYz+4gy1oukVOXcrJCunSyc6QQ==", "dev": true }, "husky": { @@ -61073,12 +61139,6 @@ "has-tostringtag": "^1.0.0" } }, - "is-obj": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-1.0.1.tgz", - "integrity": "sha1-PkcprB9f3gJc19g6iW2rn09n2w8=", - "dev": true - }, "is-object": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/is-object/-/is-object-1.0.1.tgz", @@ -61133,12 +61193,6 @@ "has-tostringtag": "^1.0.0" } }, - "is-regexp": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-regexp/-/is-regexp-1.0.0.tgz", - "integrity": "sha1-/S2INUXEa6xaYz57mgnof6LLUGk=", - "dev": true - }, "is-relative": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-relative/-/is-relative-1.0.0.tgz", @@ -61559,12 +61613,6 @@ "strip-final-newline": "^2.0.0" } }, - "get-stream": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", - "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", - "dev": true - }, "human-signals": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", @@ -65058,6 +65106,12 @@ "resolve": "^1.1.7" } }, + "lilconfig": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-2.1.0.tgz", + "integrity": "sha512-utWOt/GHzuUxnLKxB6dk81RoOeoNeHgbrXiuGk4yyF5qlRz+iIVWu56E2fqGHFrXz0QNUhLB/8nKqvRH66JKGQ==", + "dev": true + }, "lines-and-columns": { "version": "1.1.6", "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.1.6.tgz", @@ -65074,38 +65128,26 @@ } }, "lint-staged": { - "version": "10.2.11", - "resolved": "https://registry.npmjs.org/lint-staged/-/lint-staged-10.2.11.tgz", - "integrity": "sha512-LRRrSogzbixYaZItE2APaS4l2eJMjjf5MbclRZpLJtcQJShcvUzKXsNeZgsLIZ0H0+fg2tL4B59fU9wHIHtFIA==", + "version": "13.2.0", + "resolved": "https://registry.npmjs.org/lint-staged/-/lint-staged-13.2.0.tgz", + "integrity": "sha512-GbyK5iWinax5Dfw5obm2g2ccUiZXNGtAS4mCbJ0Lv4rq6iEtfBSjOYdcbOtAIFtM114t0vdpViDDetjVTSd8Vw==", "dev": true, "requires": { - "chalk": "^4.0.0", - "cli-truncate": "2.1.0", - "commander": "^5.1.0", - "cosmiconfig": "^6.0.0", - "debug": "^4.1.1", - "dedent": "^0.7.0", - "enquirer": "^2.3.5", - "execa": "^4.0.1", - "listr2": "^2.1.0", - "log-symbols": "^4.0.0", - "micromatch": "^4.0.2", + "chalk": "5.2.0", + "cli-truncate": "^3.1.0", + "commander": "^10.0.0", + "debug": "^4.3.4", + "execa": "^7.0.0", + "lilconfig": "2.1.0", + "listr2": "^5.0.7", + "micromatch": "^4.0.5", "normalize-path": "^3.0.0", - "please-upgrade-node": "^3.2.0", - "string-argv": "0.3.1", - "stringify-object": "^3.3.0" + "object-inspect": "^1.12.3", + "pidtree": "^0.6.0", + "string-argv": "^0.3.1", + "yaml": "^2.2.1" }, "dependencies": { - "ansi-styles": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.2.1.tgz", - "integrity": "sha512-9VGjrMsG1vePxcSweQsN20KY/c4zN0h9fLjqAbwbPfahM3t+NL+M9HC8xeXG2I8pX5NoamTGNuomEUFI7fcUjA==", - "dev": true, - "requires": { - "@types/color-name": "^1.1.1", - "color-convert": "^2.0.1" - } - }, "braces": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", @@ -65116,37 +65158,18 @@ } }, "chalk": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz", - "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==", - "dev": true, - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - } - }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "requires": { - "color-name": "~1.1.4" - } - }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.2.0.tgz", + "integrity": "sha512-ree3Gqw/nazQAPuJJEy+avdl7QfZMcUvmHIKgEZkGL+xOBzRvup5Hxo6LHuMceSxOabuJLJm5Yp/92R9eMmMvA==", "dev": true }, "debug": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", - "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", "dev": true, "requires": { - "ms": "^2.1.1" + "ms": "2.1.2" } }, "fill-range": { @@ -65158,12 +65181,6 @@ "to-regex-range": "^5.0.1" } }, - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true - }, "is-number": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", @@ -65171,13 +65188,13 @@ "dev": true }, "micromatch": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.2.tgz", - "integrity": "sha512-y7FpHSbMUMoyPbYUSzO6PaZ6FyRnQOpHuKwbo1G+Knck95XVU4QAiKdGEnj5wwoS7PlOgthX/09u5iFJ+aYf5Q==", + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", + "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", "dev": true, "requires": { - "braces": "^3.0.1", - "picomatch": "^2.0.5" + "braces": "^3.0.2", + "picomatch": "^2.3.1" } }, "ms": { @@ -65186,14 +65203,11 @@ "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", "dev": true }, - "supports-color": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.1.0.tgz", - "integrity": "sha512-oRSIpR8pxT1Wr2FquTNnGet79b3BWljqOuoW/h4oBhxJ/HUbX5nX6JSruTkvXDCFMwDPvsaTTbvMLKZWSy0R5g==", - "dev": true, - "requires": { - "has-flag": "^4.0.0" - } + "pidtree": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/pidtree/-/pidtree-0.6.0.tgz", + "integrity": "sha512-eG2dWTVw5bzqGRztnHExczNxt5VGsE6OwTeCG3fdUf9KBsZzO3R5OIIIzWR+iZA0NtZ+RDVdaoE2dK1cn6jH4g==", + "dev": true }, "to-regex-range": { "version": "5.0.1", @@ -65203,6 +65217,12 @@ "requires": { "is-number": "^7.0.0" } + }, + "yaml": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.2.1.tgz", + "integrity": "sha512-e0WHiYql7+9wr4cWMx3TVQrNwejKaEe7/rHNmQmqRjazfOP5W8PB6Jpebb5o6fIapbz9o9+2ipcaTM2ZwDI6lw==", + "dev": true } } }, @@ -65212,39 +65232,38 @@ "integrity": "sha1-hMinKrWcRyUyFIDJdeZQg0LnCTc=" }, "listr2": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/listr2/-/listr2-2.2.0.tgz", - "integrity": "sha512-Q8qbd7rgmEwDo1nSyHaWQeztfGsdL6rb4uh7BA+Q80AZiDET5rVntiU1+13mu2ZTDVaBVbvAD1Db11rnu3l9sg==", + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/listr2/-/listr2-5.0.8.tgz", + "integrity": "sha512-mC73LitKHj9w6v30nLNGPetZIlfpUniNSsxxrbaPcWOjDb92SHPzJPi/t+v1YC/lxKz/AJ9egOjww0qUuFxBpA==", "dev": true, "requires": { - "chalk": "^4.0.0", "cli-truncate": "^2.1.0", - "figures": "^3.2.0", - "indent-string": "^4.0.0", + "colorette": "^2.0.19", "log-update": "^4.0.0", "p-map": "^4.0.0", - "rxjs": "^6.5.5", - "through": "^2.3.8" + "rfdc": "^1.3.0", + "rxjs": "^7.8.0", + "through": "^2.3.8", + "wrap-ansi": "^7.0.0" }, "dependencies": { "ansi-styles": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.2.1.tgz", - "integrity": "sha512-9VGjrMsG1vePxcSweQsN20KY/c4zN0h9fLjqAbwbPfahM3t+NL+M9HC8xeXG2I8pX5NoamTGNuomEUFI7fcUjA==", + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", "dev": true, "requires": { - "@types/color-name": "^1.1.1", "color-convert": "^2.0.1" } }, - "chalk": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz", - "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==", + "cli-truncate": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/cli-truncate/-/cli-truncate-2.1.0.tgz", + "integrity": "sha512-n8fOixwDD6b/ObinzTrp1ZKFzbgvKZvuz/TvejnLn1aQfC6r52XEx85FmuC+3HI+JM7coBRXUvNqEU2PHVrHpg==", "dev": true, "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" + "slice-ansi": "^3.0.0", + "string-width": "^4.2.0" } }, "color-convert": { @@ -65262,19 +65281,32 @@ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", "dev": true }, - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "colorette": { + "version": "2.0.19", + "resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.19.tgz", + "integrity": "sha512-3tlv/dIP7FWvj3BsbHrGLJ6l/oKh1O3TcgBqMn+yyCagOxc23fyzDS6HypQbgxWbkpDnf52p1LuR4eWDQ/K9WQ==", "dev": true }, - "supports-color": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.1.0.tgz", - "integrity": "sha512-oRSIpR8pxT1Wr2FquTNnGet79b3BWljqOuoW/h4oBhxJ/HUbX5nX6JSruTkvXDCFMwDPvsaTTbvMLKZWSy0R5g==", + "slice-ansi": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-3.0.0.tgz", + "integrity": "sha512-pSyv7bSTC7ig9Dcgbw9AuRNUb5k5V6oDudjZoMBSr13qpLBG7tB+zgCkARjq7xIUgdz5P1Qe8u+rSGdouOOIyQ==", "dev": true, "requires": { - "has-flag": "^4.0.0" + "ansi-styles": "^4.0.0", + "astral-regex": "^2.0.0", + "is-fullwidth-code-point": "^3.0.0" + } + }, + "wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "requires": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" } } } @@ -65464,21 +65496,14 @@ }, "dependencies": { "ansi-styles": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.2.1.tgz", - "integrity": "sha512-9VGjrMsG1vePxcSweQsN20KY/c4zN0h9fLjqAbwbPfahM3t+NL+M9HC8xeXG2I8pX5NoamTGNuomEUFI7fcUjA==", + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", "dev": true, "requires": { - "@types/color-name": "^1.1.1", "color-convert": "^2.0.1" } }, - "astral-regex": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-2.0.0.tgz", - "integrity": "sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==", - "dev": true - }, "color-convert": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", @@ -66313,14 +66338,6 @@ "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-6.2.1.tgz", "integrity": "sha512-JLyh7xT1kizaEvcaXOQwOc2/Yhw6KZOvPf1S8401UyLk86CU79LN3vl7ztXGm/pZ+YjoyAJ4rxmHwbkBXJX+yw==" }, - "rxjs": { - "version": "7.5.7", - "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.5.7.tgz", - "integrity": "sha512-z9MzKh/UcOqB3i20H6rtrlaE/CgjLOvheWK/9ILrbhROGTweAi1BaFsTT9FbwZi5Trr1qNRs+MXkhmR06awzQA==", - "requires": { - "tslib": "^2.1.0" - } - }, "supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", @@ -66329,11 +66346,6 @@ "has-flag": "^4.0.0" } }, - "tslib": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.0.tgz", - "integrity": "sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ==" - }, "type-fest": { "version": "2.19.0", "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-2.19.0.tgz", @@ -66802,9 +66814,9 @@ } }, "object-inspect": { - "version": "1.12.2", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.2.tgz", - "integrity": "sha512-z+cPxW0QGUp0mcqcsgQyLVRDoXFQbXOwBaqyF7VIgI4TWNQsDHrBpUQslRmIfAoYWdYzs6UlKJtB2XJpTaNSpQ==" + "version": "1.12.3", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.3.tgz", + "integrity": "sha512-geUvdk7c+eizMNUDkRpW1wJwgfOiOeHbxBR/hLXK1aT6zmVSO0jsQcs7fj6MGw89jC/cjGfLcNOrtMYtGqm81g==" }, "object-keys": { "version": "1.1.1", @@ -67656,15 +67668,6 @@ } } }, - "please-upgrade-node": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/please-upgrade-node/-/please-upgrade-node-3.2.0.tgz", - "integrity": "sha512-gQR3WpIgNIKwBMVLkpMUeR3e1/E1y42bqDQZfql+kDeXd8COYfM8PQA4X6y7a8u9Ua9FHmsrrmirW2vHs45hWg==", - "dev": true, - "requires": { - "semver-compare": "^1.0.0" - } - }, "plugin-error": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/plugin-error/-/plugin-error-1.0.1.tgz", @@ -68987,6 +68990,12 @@ "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", "dev": true }, + "rfdc": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/rfdc/-/rfdc-1.3.0.tgz", + "integrity": "sha512-V2hovdzFbOi77/WajaSMXk2OLm+xNIeQdMMuB7icj7bk6zi2F8GGAxigcnDFpJHbNyNcgyJDiP+8nOrY5cZGrA==", + "dev": true + }, "rimraf": { "version": "2.7.1", "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", @@ -69045,12 +69054,18 @@ "integrity": "sha512-PdhdWy89SiZogBLaw42zdeqtRJ//zFd2PgQavcICDUgJT5oW10QCRKbJ6bg4r0/UY2M6BWd5tkxuGFRvCkgfHQ==" }, "rxjs": { - "version": "6.6.0", - "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.6.0.tgz", - "integrity": "sha512-3HMA8z/Oz61DUHe+SdOiQyzIf4tOx5oQHmMir7IZEu6TMqCLHT4LRcmNaUS0NwOz8VLvmmBduMsoaUvMaIiqzg==", - "dev": true, + "version": "7.8.0", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.0.tgz", + "integrity": "sha512-F2+gxDshqmIub1KdvZkaEfGDwLNpPvk9Fs6LD/MyQxNgMds/WH9OdDDXOmxUZpME+iSK3rQCctkL0DYyytUqMg==", "requires": { - "tslib": "^1.9.0" + "tslib": "^2.1.0" + }, + "dependencies": { + "tslib": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", + "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==" + } } }, "safe-buffer": { @@ -69243,12 +69258,6 @@ } } }, - "semver-compare": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/semver-compare/-/semver-compare-1.0.0.tgz", - "integrity": "sha1-De4hahyUGrN+nvsXiPavxf9VN/w=", - "dev": true - }, "semver-greatest-satisfied-range": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/semver-greatest-satisfied-range/-/semver-greatest-satisfied-range-1.1.0.tgz", @@ -69474,6 +69483,30 @@ "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", "dev": true }, + "slice-ansi": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-5.0.0.tgz", + "integrity": "sha512-FC+lgizVPfie0kkhqUScwRu1O/lF6NOgJmlCgK+/LYxDCTk8sGelYaHDhFcDN+Sn3Cv+3VSa4Byeo+IMCzpMgQ==", + "dev": true, + "requires": { + "ansi-styles": "^6.0.0", + "is-fullwidth-code-point": "^4.0.0" + }, + "dependencies": { + "ansi-styles": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", + "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", + "dev": true + }, + "is-fullwidth-code-point": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-4.0.0.tgz", + "integrity": "sha512-O4L094N2/dZ7xqVdrXhh9r1KODPJpFms8B5sGdJLPy664AgvXsreZUyCQQNItZRDlYug4xStLjNp/sz3HvBowQ==", + "dev": true + } + } + }, "snapdragon": { "version": "0.8.2", "resolved": "https://registry.npmjs.org/snapdragon/-/snapdragon-0.8.2.tgz", @@ -69961,17 +69994,6 @@ "es-abstract": "^1.19.5" } }, - "stringify-object": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/stringify-object/-/stringify-object-3.3.0.tgz", - "integrity": "sha512-rHqiFh1elqCQ9WPLIC8I0Q/g/wj5J1eMkyoiD6eoQApWHP0FtlK7rqnhmabL5VUY9JQCcqwwvlOaSuutekgyrw==", - "dev": true, - "requires": { - "get-own-enumerable-property-symbols": "^3.0.0", - "is-obj": "^1.0.1", - "is-regexp": "^1.0.0" - } - }, "strip-ansi": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", @@ -72351,12 +72373,6 @@ "strip-final-newline": "^2.0.0" } }, - "get-stream": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.0.tgz", - "integrity": "sha512-A1B3Bh1UmL0bidM/YX2NsCOTnGJePL9rO/M+Mw3m9f2gUpfokS0hi5Eah0WSUEWZdZhIZtMjkIYS7mDfOqNHbg==", - "dev": true - }, "human-signals": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", diff --git a/extensions/ql-vscode/package.json b/extensions/ql-vscode/package.json index a065d268e..6c9e444eb 100644 --- a/extensions/ql-vscode/package.json +++ b/extensions/ql-vscode/package.json @@ -1522,7 +1522,7 @@ "jest": "^29.0.3", "jest-environment-jsdom": "^29.0.3", "jest-runner-vscode": "^3.0.1", - "lint-staged": "~10.2.2", + "lint-staged": "~13.2.0", "mini-css-extract-plugin": "^2.6.1", "npm-run-all": "^4.1.5", "patch-package": "^6.5.0", From 969fdb6337c45e654a696a80017719b31e66e440 Mon Sep 17 00:00:00 2001 From: Robert Date: Wed, 15 Mar 2023 10:21:12 +0000 Subject: [PATCH 043/156] Make type checking all use typeof --- extensions/ql-vscode/src/pure/errors.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/extensions/ql-vscode/src/pure/errors.ts b/extensions/ql-vscode/src/pure/errors.ts index 50990daa6..8153dd7a2 100644 --- a/extensions/ql-vscode/src/pure/errors.ts +++ b/extensions/ql-vscode/src/pure/errors.ts @@ -78,9 +78,8 @@ export interface ErrorLike { function isErrorLike(error: any): error is ErrorLike { if ( - error.message !== undefined && typeof error.message === "string" && - (error.stack === undefined || typeof error.stack === "string") + (typeof error.stack === "undefined" || typeof error.stack === "string") ) { return true; } From 5303ec67cb47c69dc7b22846dc0acd6e0bd7740b Mon Sep 17 00:00:00 2001 From: Anders Starcke Henriksen Date: Wed, 15 Mar 2023 11:52:30 +0100 Subject: [PATCH 044/156] Name updates. --- extensions/ql-vscode/src/common/app.ts | 4 ++-- extensions/ql-vscode/src/common/commands.ts | 8 +++---- .../ql-vscode/src/common/vscode/commands.ts | 15 ++++++++---- .../ql-vscode/src/common/vscode/vscode-app.ts | 10 ++++---- extensions/ql-vscode/src/extension.ts | 12 +++++----- .../src/packages/commands/CommandManager.ts | 10 ++++---- .../src/packages/commands/Disposable.ts | 7 ++++++ .../variant-analysis-manager.ts | 9 +++---- .../variant-analysis-view-manager.ts | 4 ++-- .../variant-analysis/variant-analysis-view.ts | 2 +- .../ql-vscode/test/__mocks__/appMock.ts | 8 +++---- .../ql-vscode/test/__mocks__/commandsMock.ts | 11 ++++----- .../packages/commands/CommandManager.test.ts | 24 +++++++++---------- 13 files changed, 65 insertions(+), 59 deletions(-) create mode 100644 extensions/ql-vscode/src/packages/commands/Disposable.ts diff --git a/extensions/ql-vscode/src/common/app.ts b/extensions/ql-vscode/src/common/app.ts index da0bdfa5b..278ea2b9d 100644 --- a/extensions/ql-vscode/src/common/app.ts +++ b/extensions/ql-vscode/src/common/app.ts @@ -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(): AppEventEmitter; @@ -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 { diff --git a/extensions/ql-vscode/src/common/commands.ts b/extensions/ql-vscode/src/common/commands.ts index ebc0dc82d..d4ceada59 100644 --- a/extensions/ql-vscode/src/common/commands.ts +++ b/extensions/ql-vscode/src/common/commands.ts @@ -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; }; @@ -19,6 +19,6 @@ export type VariantAnalysisCommands = { ) => Promise; }; -export type AllCommands = ExtensionCommands & VariantAnalysisCommands; +export type AllCommands = BaseCommands & VariantAnalysisCommands; -export type ExtensionCommandManager = CommandManager; +export type AppCommandManager = CommandManager; diff --git a/extensions/ql-vscode/src/common/vscode/commands.ts b/extensions/ql-vscode/src/common/vscode/commands.ts index 5e9055b85..86e32faa4 100644 --- a/extensions/ql-vscode/src/common/vscode/commands.ts +++ b/extensions/ql-vscode/src/common/vscode/commands.ts @@ -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, >(): CommandManager { - 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` is actually + * a Promise, so we need to add a second layer of wrapping and unwrapping + * (The `Promise, CommandName extends keyof Commands & string = keyof Commands & string, >( diff --git a/extensions/ql-vscode/src/common/vscode/vscode-app.ts b/extensions/ql-vscode/src/common/vscode/vscode-app.ts index 2b434c4fa..1ae588278 100644 --- a/extensions/ql-vscode/src/common/vscode/vscode-app.ts +++ b/extensions/ql-vscode/src/common/vscode/vscode-app.ts @@ -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 { diff --git a/extensions/ql-vscode/src/extension.ts b/extensions/ql-vscode/src/extension.ts index eedff0247..4620d49f4 100644 --- a/extensions/ql-vscode/src/extension.ts +++ b/extensions/ql-vscode/src/extension.ts @@ -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( diff --git a/extensions/ql-vscode/src/packages/commands/CommandManager.ts b/extensions/ql-vscode/src/packages/commands/CommandManager.ts index a9bb79167..c328d9bed 100644 --- a/extensions/ql-vscode/src/packages/commands/CommandManager.ts +++ b/extensions/ql-vscode/src/packages/commands/CommandManager.ts @@ -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: ( commandName: T, - definition: Commands[T], + fn: Commands[T], ) => Disposable, private readonly commandExecute: ( commandName: T, @@ -43,7 +41,7 @@ export class CommandManager< /** * Register a command with the specified name and implementation. */ - registerCommand( + register( 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( + execute( commandName: T, ...args: Parameters ): Promise>> { diff --git a/extensions/ql-vscode/src/packages/commands/Disposable.ts b/extensions/ql-vscode/src/packages/commands/Disposable.ts new file mode 100644 index 000000000..3a6dd5c17 --- /dev/null +++ b/extensions/ql-vscode/src/packages/commands/Disposable.ts @@ -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; +} diff --git a/extensions/ql-vscode/src/variant-analysis/variant-analysis-manager.ts b/extensions/ql-vscode/src/variant-analysis/variant-analysis-manager.ts index 57065ff87..c7ebbebf1 100644 --- a/extensions/ql-vscode/src/variant-analysis/variant-analysis-manager.ts +++ b/extensions/ql-vscode/src/variant-analysis/variant-analysis-manager.ts @@ -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( diff --git a/extensions/ql-vscode/src/variant-analysis/variant-analysis-view-manager.ts b/extensions/ql-vscode/src/variant-analysis/variant-analysis-view-manager.ts index c0d83c949..9f17a4bd4 100644 --- a/extensions/ql-vscode/src/variant-analysis/variant-analysis-view-manager.ts +++ b/extensions/ql-vscode/src/variant-analysis/variant-analysis-view-manager.ts @@ -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; diff --git a/extensions/ql-vscode/src/variant-analysis/variant-analysis-view.ts b/extensions/ql-vscode/src/variant-analysis/variant-analysis-view.ts index b85c237a8..ef9a47bc5 100644 --- a/extensions/ql-vscode/src/variant-analysis/variant-analysis-view.ts +++ b/extensions/ql-vscode/src/variant-analysis/variant-analysis-view.ts @@ -145,7 +145,7 @@ export class VariantAnalysisView ); break; case "openLogs": - await this.manager.commandManager.executeCommand( + await this.manager.commandManager.execute( "codeQL.openVariantAnalysisLogs", this.variantAnalysisId, ); diff --git a/extensions/ql-vscode/test/__mocks__/appMock.ts b/extensions/ql-vscode/test/__mocks__/appMock.ts index b07796c00..6a4b05ba8 100644 --- a/extensions/ql-vscode/test/__mocks__/appMock.ts +++ b/extensions/ql-vscode/test/__mocks__/appMock.ts @@ -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; 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, }; } diff --git a/extensions/ql-vscode/test/__mocks__/commandsMock.ts b/extensions/ql-vscode/test/__mocks__/commandsMock.ts index 21151e48e..16e92606b 100644 --- a/extensions/ql-vscode/test/__mocks__/commandsMock.ts +++ b/extensions/ql-vscode/test/__mocks__/commandsMock.ts @@ -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; -} = {}): ExtensionCommandManager { +} = {}): AppCommandManager { return new CommandManager(registerCommand, executeCommand); } diff --git a/extensions/ql-vscode/test/unit-tests/packages/commands/CommandManager.test.ts b/extensions/ql-vscode/test/unit-tests/packages/commands/CommandManager.test.ts index 3d7f05fbb..96bede0b6 100644 --- a/extensions/ql-vscode/test/unit-tests/packages/commands/CommandManager.test.ts +++ b/extensions/ql-vscode/test/unit-tests/packages/commands/CommandManager.test.ts @@ -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 => 10, ); - commandManager.registerCommand( + commandManager.register( "codeQL.openVariantAnalysisLogs", // @ts-expect-error wrong function return type should give a type error async (variantAnalysisId: number): Promise => "hello", ); // Working types - commandManager.registerCommand( + commandManager.register( "codeQL.openVariantAnalysisLogs", async (variantAnalysisId: number): Promise => 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); }); }); From 3fe069975abef21d7afcb23871aa9bdabe046126 Mon Sep 17 00:00:00 2001 From: Robert Date: Wed, 15 Mar 2023 12:26:58 +0000 Subject: [PATCH 045/156] Avoid reporting errors twice --- .../ql-vscode/src/view/common/errors.ts | 51 ++++++++++++++----- 1 file changed, 37 insertions(+), 14 deletions(-) diff --git a/extensions/ql-vscode/src/view/common/errors.ts b/extensions/ql-vscode/src/view/common/errors.ts index d4eb11192..e6a443de1 100644 --- a/extensions/ql-vscode/src/view/common/errors.ts +++ b/extensions/ql-vscode/src/view/common/errors.ts @@ -1,24 +1,47 @@ import { getErrorMessage, getErrorStack } from "../../pure/helpers-pure"; import { vscode } from "../vscode-api"; +// Keep track of previous errors that have happened. +// The listeners for uncaught errors and rejections can get triggered +// twice for each error. This is believed to be an effect caused +// by React's error boundaries. Adding an error boundary stops +// this duplicate reporting for errors that happen during component +// rendering, but unfortunately errors from event handlers and +// timeouts are still duplicated and there does not appear to be +// a way around this. +const previousErrors: Set = new Set(); + +function shouldReportError(error: Error): boolean { + const seenBefore = previousErrors.has(error); + previousErrors.add(error); + setTimeout(() => { + previousErrors.delete(error); + }, 1000); + return !seenBefore; +} + const unhandledErrorListener = (event: ErrorEvent) => { - vscode.postMessage({ - t: "unhandledError", - error: { - message: getErrorMessage(event.error), - stack: getErrorStack(event.error), - }, - }); + if (shouldReportError(event.error)) { + vscode.postMessage({ + t: "unhandledError", + error: { + message: getErrorMessage(event.error), + stack: getErrorStack(event.error), + }, + }); + } }; const unhandledRejectionListener = (event: PromiseRejectionEvent) => { - vscode.postMessage({ - t: "unhandledError", - error: { - message: getErrorMessage(event.reason), - stack: getErrorStack(event.reason), - }, - }); + if (shouldReportError(event.reason)) { + vscode.postMessage({ + t: "unhandledError", + error: { + message: getErrorMessage(event.reason), + stack: getErrorStack(event.reason), + }, + }); + } }; /** From e81d58533629902b19112d3b78b7d3feff53864a Mon Sep 17 00:00:00 2001 From: Robert Date: Wed, 15 Mar 2023 13:36:57 +0000 Subject: [PATCH 046/156] Swap arguments so command arg comes last --- extensions/ql-vscode/src/extension.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/extensions/ql-vscode/src/extension.ts b/extensions/ql-vscode/src/extension.ts index ea6622680..53f1169a3 100644 --- a/extensions/ql-vscode/src/extension.ts +++ b/extensions/ql-vscode/src/extension.ts @@ -1274,7 +1274,7 @@ async function activateWithInstalledDistribution( ctx.subscriptions.push( commandRunner("codeQL.previewQueryHelp", async (selectedQuery: Uri) => { - await previewQueryHelp(cliServer, selectedQuery, qhelpTmpDir); + await previewQueryHelp(cliServer, qhelpTmpDir, selectedQuery); }), ); @@ -1842,8 +1842,8 @@ async function compileAndRunQueryOnMultipleDatabases( async function previewQueryHelp( cliServer: CodeQLCliServer, - selectedQuery: Uri, qhelpTmpDir: DirResult, + selectedQuery: Uri, ): Promise { // selectedQuery is unpopulated when executing through the command palette const pathToQhelp = selectedQuery From fe554ee2a75378ddb74dd07eaaa6658a6dca1b17 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 15 Mar 2023 16:09:35 +0000 Subject: [PATCH 047/156] Bump glob-promise from 4.2.2 to 6.0.2 in /extensions/ql-vscode Bumps [glob-promise](https://github.com/ahmadnassri/node-glob-promise) from 4.2.2 to 6.0.2. - [Release notes](https://github.com/ahmadnassri/node-glob-promise/releases) - [Commits](https://github.com/ahmadnassri/node-glob-promise/compare/v4.2.2...v6.0.2) --- updated-dependencies: - dependency-name: glob-promise dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- extensions/ql-vscode/package-lock.json | 56 ++++++++++++++++++-------- extensions/ql-vscode/package.json | 2 +- 2 files changed, 40 insertions(+), 18 deletions(-) diff --git a/extensions/ql-vscode/package-lock.json b/extensions/ql-vscode/package-lock.json index 0b00888cd..97952802d 100644 --- a/extensions/ql-vscode/package-lock.json +++ b/extensions/ql-vscode/package-lock.json @@ -23,7 +23,7 @@ "d3": "^7.6.1", "d3-graphviz": "^5.0.2", "fs-extra": "^10.0.1", - "glob-promise": "^4.2.2", + "glob-promise": "^6.0.2", "immutable": "^4.0.0", "js-yaml": "^4.1.0", "minimist": "~1.2.6", @@ -13354,6 +13354,7 @@ "version": "7.1.3", "resolved": "https://registry.npmjs.org/@types/glob/-/glob-7.1.3.tgz", "integrity": "sha512-SEYeGAIQIQX8NN6LDKprLjbrd5dARM5EXsd8GI/A5l0apYI1fGMWgPHSe4ZKL4eozlAyI+doUE9XbYS4xCkQ1w==", + "dev": true, "dependencies": { "@types/minimatch": "*", "@types/node": "*" @@ -13593,9 +13594,9 @@ } }, "node_modules/@types/minimatch": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-3.0.3.tgz", - "integrity": "sha512-tHq6qdbT9U1IRSGf14CL0pUlULksvY9OZ+5eEgl1N7t+OA3tGvNpxJCzuKQlsNgCVwbAs670L1vcVQi8j9HjnA==" + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-5.1.2.tgz", + "integrity": "sha512-K0VQKziLUWkVKiRVrx4a40iPaxTUefQmjtkQofBkYRcoaaL/8rhwDWww9qWbrgicNOgnpIsMxyNIUM4+n6dUIA==" }, "node_modules/@types/ms": { "version": "0.7.31", @@ -24175,21 +24176,30 @@ } }, "node_modules/glob-promise": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/glob-promise/-/glob-promise-4.2.2.tgz", - "integrity": "sha512-xcUzJ8NWN5bktoTIX7eOclO1Npxd/dyVqUJxlLIDasT4C7KZyqlPIwkdJ0Ypiy3p2ZKahTjK4M9uC3sNSfNMzw==", + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-promise/-/glob-promise-6.0.2.tgz", + "integrity": "sha512-Ni2aDyD1ekD6x8/+K4hDriRDbzzfuK4yKpqSymJ4P7IxbtARiOOuU+k40kbHM0sLIlbf1Qh0qdMkAHMZYE6XJQ==", "dependencies": { - "@types/glob": "^7.1.3" + "@types/glob": "^8.0.0" }, "engines": { - "node": ">=12" + "node": ">=16" }, "funding": { "type": "individual", "url": "https://github.com/sponsors/ahmadnassri" }, "peerDependencies": { - "glob": "^7.1.6" + "glob": "^8.0.3" + } + }, + "node_modules/glob-promise/node_modules/@types/glob": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/@types/glob/-/glob-8.1.0.tgz", + "integrity": "sha512-IO+MJPVhoqz+28h1qLAcBEH2+xHMK6MTyHJc7MTnnYb6wsoLR29POVGJ7LycmVXIqyy/4/2ShP5sUwTXuOwb/w==", + "dependencies": { + "@types/minimatch": "^5.1.2", + "@types/node": "*" } }, "node_modules/glob-stream": { @@ -51288,6 +51298,7 @@ "version": "7.1.3", "resolved": "https://registry.npmjs.org/@types/glob/-/glob-7.1.3.tgz", "integrity": "sha512-SEYeGAIQIQX8NN6LDKprLjbrd5dARM5EXsd8GI/A5l0apYI1fGMWgPHSe4ZKL4eozlAyI+doUE9XbYS4xCkQ1w==", + "dev": true, "requires": { "@types/minimatch": "*", "@types/node": "*" @@ -51512,9 +51523,9 @@ } }, "@types/minimatch": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-3.0.3.tgz", - "integrity": "sha512-tHq6qdbT9U1IRSGf14CL0pUlULksvY9OZ+5eEgl1N7t+OA3tGvNpxJCzuKQlsNgCVwbAs670L1vcVQi8j9HjnA==" + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-5.1.2.tgz", + "integrity": "sha512-K0VQKziLUWkVKiRVrx4a40iPaxTUefQmjtkQofBkYRcoaaL/8rhwDWww9qWbrgicNOgnpIsMxyNIUM4+n6dUIA==" }, "@types/ms": { "version": "0.7.31", @@ -59709,11 +59720,22 @@ } }, "glob-promise": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/glob-promise/-/glob-promise-4.2.2.tgz", - "integrity": "sha512-xcUzJ8NWN5bktoTIX7eOclO1Npxd/dyVqUJxlLIDasT4C7KZyqlPIwkdJ0Ypiy3p2ZKahTjK4M9uC3sNSfNMzw==", + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-promise/-/glob-promise-6.0.2.tgz", + "integrity": "sha512-Ni2aDyD1ekD6x8/+K4hDriRDbzzfuK4yKpqSymJ4P7IxbtARiOOuU+k40kbHM0sLIlbf1Qh0qdMkAHMZYE6XJQ==", "requires": { - "@types/glob": "^7.1.3" + "@types/glob": "^8.0.0" + }, + "dependencies": { + "@types/glob": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/@types/glob/-/glob-8.1.0.tgz", + "integrity": "sha512-IO+MJPVhoqz+28h1qLAcBEH2+xHMK6MTyHJc7MTnnYb6wsoLR29POVGJ7LycmVXIqyy/4/2ShP5sUwTXuOwb/w==", + "requires": { + "@types/minimatch": "^5.1.2", + "@types/node": "*" + } + } } }, "glob-stream": { diff --git a/extensions/ql-vscode/package.json b/extensions/ql-vscode/package.json index a065d268e..b9bd189d9 100644 --- a/extensions/ql-vscode/package.json +++ b/extensions/ql-vscode/package.json @@ -1416,7 +1416,7 @@ "d3": "^7.6.1", "d3-graphviz": "^5.0.2", "fs-extra": "^10.0.1", - "glob-promise": "^4.2.2", + "glob-promise": "^6.0.2", "immutable": "^4.0.0", "js-yaml": "^4.1.0", "minimist": "~1.2.6", From 0fa0fa3523affea09e393521e507d97758d13cac Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 15 Mar 2023 16:10:41 +0000 Subject: [PATCH 048/156] Bump tar-stream from 2.2.0 to 3.0.0 in /extensions/ql-vscode Bumps [tar-stream](https://github.com/mafintosh/tar-stream) from 2.2.0 to 3.0.0. - [Release notes](https://github.com/mafintosh/tar-stream/releases) - [Commits](https://github.com/mafintosh/tar-stream/compare/v2.2.0...v3.0.0) --- updated-dependencies: - dependency-name: tar-stream dependency-type: direct:development update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- extensions/ql-vscode/package-lock.json | 266 +++++++++++++++++++++---- extensions/ql-vscode/package.json | 2 +- 2 files changed, 233 insertions(+), 35 deletions(-) diff --git a/extensions/ql-vscode/package-lock.json b/extensions/ql-vscode/package-lock.json index 0b00888cd..f0c39934e 100644 --- a/extensions/ql-vscode/package-lock.json +++ b/extensions/ql-vscode/package-lock.json @@ -134,7 +134,7 @@ "npm-run-all": "^4.1.5", "patch-package": "^6.5.0", "prettier": "^2.7.1", - "tar-stream": "^2.2.0", + "tar-stream": "^3.0.0", "through2": "^4.0.2", "ts-jest": "^29.0.1", "ts-json-schema-generator": "^1.1.2", @@ -14949,6 +14949,18 @@ "integrity": "sha512-j2afSsaIENvHZN2B8GOpF566vZ5WVk5opAiMTvWgaQT8DkbOqsTfvNAvHoRGU2zzP8cPoqys+xHTRDWW8L+/BA==", "dev": true }, + "node_modules/abort-controller": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/abort-controller/-/abort-controller-3.0.0.tgz", + "integrity": "sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==", + "dev": true, + "dependencies": { + "event-target-shim": "^5.0.0" + }, + "engines": { + "node": ">=6.5" + } + }, "node_modules/accepts": { "version": "1.3.8", "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", @@ -15372,6 +15384,21 @@ "node": ">= 6" } }, + "node_modules/archiver/node_modules/tar-stream": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-2.2.0.tgz", + "integrity": "sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==", + "dependencies": { + "bl": "^4.0.3", + "end-of-stream": "^1.4.1", + "fs-constants": "^1.0.0", + "inherits": "^2.0.3", + "readable-stream": "^3.1.1" + }, + "engines": { + "node": ">=6" + } + }, "node_modules/archy": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/archy/-/archy-1.0.0.tgz", @@ -15918,6 +15945,12 @@ "typed-rest-client": "^1.8.4" } }, + "node_modules/b4a": { + "version": "1.6.2", + "resolved": "https://registry.npmjs.org/b4a/-/b4a-1.6.2.tgz", + "integrity": "sha512-YFqjbZ8iqX/wWJVmF1SSOB5TYDwsPd/sZzhSdu2PskElf55PjEe+0MhsEPgoa5eTK1VS/WqJMz9qwIFwZta+3g==", + "dev": true + }, "node_modules/babel-jest": { "version": "29.3.1", "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-29.3.1.tgz", @@ -22409,6 +22442,15 @@ "node": ">=4.0.0" } }, + "node_modules/event-target-shim": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/event-target-shim/-/event-target-shim-5.0.1.tgz", + "integrity": "sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==", + "dev": true, + "engines": { + "node": ">=6" + } + }, "node_modules/eventemitter3": { "version": "4.0.7", "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz", @@ -25400,9 +25442,23 @@ } }, "node_modules/ieee754": { - "version": "1.1.13", - "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.1.13.tgz", - "integrity": "sha512-4vf7I2LYV/HaWerSo3XmlMkp5eZ83i+/CDluXi/IGTs/O1sejBNhTtnxzmRZfvOUqj7lZjqHkeTvpgSFDlWZTg==" + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] }, "node_modules/iferr": { "version": "0.1.5", @@ -37783,10 +37839,25 @@ "once": "^1.3.1" } }, - "node_modules/tar-stream": { + "node_modules/tar-fs/node_modules/readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "dev": true, + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/tar-fs/node_modules/tar-stream": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-2.2.0.tgz", "integrity": "sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==", + "dev": true, "dependencies": { "bl": "^4.0.3", "end-of-stream": "^1.4.1", @@ -37798,17 +37869,65 @@ "node": ">=6" } }, - "node_modules/tar-stream/node_modules/readable-stream": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", - "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", + "node_modules/tar-stream": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-3.0.0.tgz", + "integrity": "sha512-O6OfUKBbQOqAhh6owTWmA730J/yZCYcpmZ1DBj2YX51ZQrt7d7NgzrR+CnO9wP6nt/viWZW2XeXLavX3/ZEbEg==", + "dev": true, "dependencies": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" + "b4a": "^1.6.1", + "bl": "^6.0.0", + "streamx": "^2.12.5" + } + }, + "node_modules/tar-stream/node_modules/bl": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/bl/-/bl-6.0.0.tgz", + "integrity": "sha512-Ik9BVIMdcWzSOCpzDv2XpQ4rJ4oZBuk3ck6MgiOv0EopdgtohN2uSCrrLlkH1Jf0KnpZZMBA3D0bUMbCdj/jgA==", + "dev": true, + "dependencies": { + "buffer": "^6.0.3", + "inherits": "^2.0.4", + "readable-stream": "^4.2.0" + } + }, + "node_modules/tar-stream/node_modules/buffer": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz", + "integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "dependencies": { + "base64-js": "^1.3.1", + "ieee754": "^1.2.1" + } + }, + "node_modules/tar-stream/node_modules/readable-stream": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-4.3.0.tgz", + "integrity": "sha512-MuEnA0lbSi7JS8XM+WNJlWZkHAAdm7gETHdFK//Q/mChGyj2akEFtdLZh32jSdkWGbRwCW9pn6g3LWDdDeZnBQ==", + "dev": true, + "dependencies": { + "abort-controller": "^3.0.0", + "buffer": "^6.0.3", + "events": "^3.3.0", + "process": "^0.11.10" }, "engines": { - "node": ">= 6" + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" } }, "node_modules/tar/node_modules/chownr": { @@ -52632,6 +52751,15 @@ "integrity": "sha512-j2afSsaIENvHZN2B8GOpF566vZ5WVk5opAiMTvWgaQT8DkbOqsTfvNAvHoRGU2zzP8cPoqys+xHTRDWW8L+/BA==", "dev": true }, + "abort-controller": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/abort-controller/-/abort-controller-3.0.0.tgz", + "integrity": "sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==", + "dev": true, + "requires": { + "event-target-shim": "^5.0.0" + } + }, "accepts": { "version": "1.3.8", "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", @@ -52933,6 +53061,18 @@ "string_decoder": "^1.1.1", "util-deprecate": "^1.0.1" } + }, + "tar-stream": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-2.2.0.tgz", + "integrity": "sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==", + "requires": { + "bl": "^4.0.3", + "end-of-stream": "^1.4.1", + "fs-constants": "^1.0.0", + "inherits": "^2.0.3", + "readable-stream": "^3.1.1" + } } } }, @@ -53380,6 +53520,12 @@ "typed-rest-client": "^1.8.4" } }, + "b4a": { + "version": "1.6.2", + "resolved": "https://registry.npmjs.org/b4a/-/b4a-1.6.2.tgz", + "integrity": "sha512-YFqjbZ8iqX/wWJVmF1SSOB5TYDwsPd/sZzhSdu2PskElf55PjEe+0MhsEPgoa5eTK1VS/WqJMz9qwIFwZta+3g==", + "dev": true + }, "babel-jest": { "version": "29.3.1", "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-29.3.1.tgz", @@ -58305,6 +58451,12 @@ "integrity": "sha512-z7IyloorXvKbFx9Bpie2+vMJKKx1fH1EN5yiTfp8CiLOTptSYy1g8H4yDpGlEdshL1PBiFtBHepF2cNsqeEeFQ==", "dev": true }, + "event-target-shim": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/event-target-shim/-/event-target-shim-5.0.1.tgz", + "integrity": "sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==", + "dev": true + }, "eventemitter3": { "version": "4.0.7", "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz", @@ -60650,9 +60802,9 @@ } }, "ieee754": { - "version": "1.1.13", - "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.1.13.tgz", - "integrity": "sha512-4vf7I2LYV/HaWerSo3XmlMkp5eZ83i+/CDluXi/IGTs/O1sejBNhTtnxzmRZfvOUqj7lZjqHkeTvpgSFDlWZTg==" + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==" }, "iferr": { "version": "0.1.5", @@ -70257,30 +70409,76 @@ "end-of-stream": "^1.1.0", "once": "^1.3.1" } - } - } - }, - "tar-stream": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-2.2.0.tgz", - "integrity": "sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==", - "requires": { - "bl": "^4.0.3", - "end-of-stream": "^1.4.1", - "fs-constants": "^1.0.0", - "inherits": "^2.0.3", - "readable-stream": "^3.1.1" - }, - "dependencies": { + }, "readable-stream": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", - "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "dev": true, "requires": { "inherits": "^2.0.3", "string_decoder": "^1.1.1", "util-deprecate": "^1.0.1" } + }, + "tar-stream": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-2.2.0.tgz", + "integrity": "sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==", + "dev": true, + "requires": { + "bl": "^4.0.3", + "end-of-stream": "^1.4.1", + "fs-constants": "^1.0.0", + "inherits": "^2.0.3", + "readable-stream": "^3.1.1" + } + } + } + }, + "tar-stream": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-3.0.0.tgz", + "integrity": "sha512-O6OfUKBbQOqAhh6owTWmA730J/yZCYcpmZ1DBj2YX51ZQrt7d7NgzrR+CnO9wP6nt/viWZW2XeXLavX3/ZEbEg==", + "dev": true, + "requires": { + "b4a": "^1.6.1", + "bl": "^6.0.0", + "streamx": "^2.12.5" + }, + "dependencies": { + "bl": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/bl/-/bl-6.0.0.tgz", + "integrity": "sha512-Ik9BVIMdcWzSOCpzDv2XpQ4rJ4oZBuk3ck6MgiOv0EopdgtohN2uSCrrLlkH1Jf0KnpZZMBA3D0bUMbCdj/jgA==", + "dev": true, + "requires": { + "buffer": "^6.0.3", + "inherits": "^2.0.4", + "readable-stream": "^4.2.0" + } + }, + "buffer": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz", + "integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==", + "dev": true, + "requires": { + "base64-js": "^1.3.1", + "ieee754": "^1.2.1" + } + }, + "readable-stream": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-4.3.0.tgz", + "integrity": "sha512-MuEnA0lbSi7JS8XM+WNJlWZkHAAdm7gETHdFK//Q/mChGyj2akEFtdLZh32jSdkWGbRwCW9pn6g3LWDdDeZnBQ==", + "dev": true, + "requires": { + "abort-controller": "^3.0.0", + "buffer": "^6.0.3", + "events": "^3.3.0", + "process": "^0.11.10" + } } } }, diff --git a/extensions/ql-vscode/package.json b/extensions/ql-vscode/package.json index a065d268e..ff3cc3dd9 100644 --- a/extensions/ql-vscode/package.json +++ b/extensions/ql-vscode/package.json @@ -1527,7 +1527,7 @@ "npm-run-all": "^4.1.5", "patch-package": "^6.5.0", "prettier": "^2.7.1", - "tar-stream": "^2.2.0", + "tar-stream": "^3.0.0", "through2": "^4.0.2", "ts-jest": "^29.0.1", "ts-json-schema-generator": "^1.1.2", From 84f60ccb8c85805a2b492cfc64af8a06c94fff08 Mon Sep 17 00:00:00 2001 From: Robert Date: Wed, 15 Mar 2023 16:05:42 +0000 Subject: [PATCH 049/156] Avoid duplicate use of the codeQLQueryHistory.removeHistoryItem command --- extensions/ql-vscode/package.json | 28 +++++++++++++++---- .../query-history/query-history-manager.ts | 14 +++++++++- 2 files changed, 36 insertions(+), 6 deletions(-) diff --git a/extensions/ql-vscode/package.json b/extensions/ql-vscode/package.json index a065d268e..c5ac73b90 100644 --- a/extensions/ql-vscode/package.json +++ b/extensions/ql-vscode/package.json @@ -554,7 +554,17 @@ "icon": "$(preview)" }, { - "command": "codeQLQueryHistory.removeHistoryItem", + "command": "codeQLQueryHistory.removeHistoryItemTitleMenu", + "title": "Delete", + "icon": "$(trash)" + }, + { + "command": "codeQLQueryHistory.removeHistoryItemContextMenu", + "title": "Delete", + "icon": "$(trash)" + }, + { + "command": "codeQLQueryHistory.removeHistoryItemContextInline", "title": "Delete", "icon": "$(trash)" }, @@ -751,7 +761,7 @@ "group": "navigation" }, { - "command": "codeQLQueryHistory.removeHistoryItem", + "command": "codeQLQueryHistory.removeHistoryItemTitleMenu", "when": "view == codeQLQueryHistory", "group": "navigation" }, @@ -853,12 +863,12 @@ "when": "view == codeQLQueryHistory" }, { - "command": "codeQLQueryHistory.removeHistoryItem", + "command": "codeQLQueryHistory.removeHistoryItemContextMenu", "group": "7_queryHistory@0", "when": "viewItem == interpretedResultsItem || viewItem == rawResultsItem || viewItem == remoteResultsItem || viewItem == cancelledRemoteResultsItemWithoutLogs || viewItem == cancelledResultsItem || viewItem == cancelledRemoteResultsItem" }, { - "command": "codeQLQueryHistory.removeHistoryItem", + "command": "codeQLQueryHistory.removeHistoryItemContextInline", "group": "inline", "when": "viewItem == interpretedResultsItem || viewItem == rawResultsItem || viewItem == remoteResultsItem || viewItem == cancelledRemoteResultsItemWithoutLogs || viewItem == cancelledResultsItem || viewItem == cancelledRemoteResultsItem" }, @@ -1159,7 +1169,15 @@ "when": "false" }, { - "command": "codeQLQueryHistory.removeHistoryItem", + "command": "codeQLQueryHistory.removeHistoryItemTitleMenu", + "when": "false" + }, + { + "command": "codeQLQueryHistory.removeHistoryItemContextMenu", + "when": "false" + }, + { + "command": "codeQLQueryHistory.removeHistoryItemContextInline", "when": "false" }, { diff --git a/extensions/ql-vscode/src/query-history/query-history-manager.ts b/extensions/ql-vscode/src/query-history/query-history-manager.ts index 83b9694e5..279792ee5 100644 --- a/extensions/ql-vscode/src/query-history/query-history-manager.ts +++ b/extensions/ql-vscode/src/query-history/query-history-manager.ts @@ -210,7 +210,19 @@ export class QueryHistoryManager extends DisposableObject { ); this.push( commandRunner( - "codeQLQueryHistory.removeHistoryItem", + "codeQLQueryHistory.removeHistoryItemTitleMenu", + this.handleRemoveHistoryItem.bind(this), + ), + ); + this.push( + commandRunner( + "codeQLQueryHistory.removeHistoryItemContextMenu", + this.handleRemoveHistoryItem.bind(this), + ), + ); + this.push( + commandRunner( + "codeQLQueryHistory.removeHistoryItemContextInline", this.handleRemoveHistoryItem.bind(this), ), ); From e6f543670a90511225bed265b03ea0ffe4c541bb Mon Sep 17 00:00:00 2001 From: Robert Date: Wed, 15 Mar 2023 16:49:32 +0000 Subject: [PATCH 050/156] Split up codeQLQueryHistory.openQuery command --- extensions/ql-vscode/package.json | 17 +++++++++++++---- .../src/query-history/query-history-manager.ts | 8 +++++++- 2 files changed, 20 insertions(+), 5 deletions(-) diff --git a/extensions/ql-vscode/package.json b/extensions/ql-vscode/package.json index fa8ba1274..990b925a5 100644 --- a/extensions/ql-vscode/package.json +++ b/extensions/ql-vscode/package.json @@ -544,7 +544,12 @@ "title": "CodeQL: Check for CLI Updates" }, { - "command": "codeQLQueryHistory.openQuery", + "command": "codeQLQueryHistory.openQueryTitleMenu", + "title": "View Query", + "icon": "$(edit)" + }, + { + "command": "codeQLQueryHistory.openQueryContextMenu", "title": "View Query", "icon": "$(edit)" }, @@ -751,7 +756,7 @@ "group": "navigation" }, { - "command": "codeQLQueryHistory.openQuery", + "command": "codeQLQueryHistory.openQueryTitleMenu", "when": "view == codeQLQueryHistory", "group": "navigation" }, @@ -858,7 +863,7 @@ "group": "inline" }, { - "command": "codeQLQueryHistory.openQuery", + "command": "codeQLQueryHistory.openQueryContextMenu", "group": "2_queryHistory@0", "when": "view == codeQLQueryHistory" }, @@ -1165,7 +1170,11 @@ "when": "false" }, { - "command": "codeQLQueryHistory.openQuery", + "command": "codeQLQueryHistory.openQueryTitleMenu", + "when": "false" + }, + { + "command": "codeQLQueryHistory.openQueryContextMenu", "when": "false" }, { diff --git a/extensions/ql-vscode/src/query-history/query-history-manager.ts b/extensions/ql-vscode/src/query-history/query-history-manager.ts index 279792ee5..14e5ec8ea 100644 --- a/extensions/ql-vscode/src/query-history/query-history-manager.ts +++ b/extensions/ql-vscode/src/query-history/query-history-manager.ts @@ -204,7 +204,13 @@ export class QueryHistoryManager extends DisposableObject { void extLogger.log("Registering query history panel commands."); this.push( commandRunner( - "codeQLQueryHistory.openQuery", + "codeQLQueryHistory.openQueryTitleMenu", + this.handleOpenQuery.bind(this), + ), + ); + this.push( + commandRunner( + "codeQLQueryHistory.openQueryContextMenu", this.handleOpenQuery.bind(this), ), ); From 34ab4090500a1c603518e6de8f07986c8937bb16 Mon Sep 17 00:00:00 2001 From: Robert Date: Wed, 15 Mar 2023 17:06:17 +0000 Subject: [PATCH 051/156] Remove codeQL.openVariantAnalysisQueryFile command --- extensions/ql-vscode/src/extension.ts | 9 --------- .../ql-vscode/src/query-history/query-history-manager.ts | 3 +-- .../variant-analysis/variant-analysis-view-manager.ts | 1 + .../src/variant-analysis/variant-analysis-view.ts | 5 +---- 4 files changed, 3 insertions(+), 15 deletions(-) diff --git a/extensions/ql-vscode/src/extension.ts b/extensions/ql-vscode/src/extension.ts index 5225e2deb..b6522377f 100644 --- a/extensions/ql-vscode/src/extension.ts +++ b/extensions/ql-vscode/src/extension.ts @@ -1216,15 +1216,6 @@ async function activateWithInstalledDistribution( ), ); - ctx.subscriptions.push( - commandRunner( - "codeQL.openVariantAnalysisQueryFile", - async (variantAnalysisId: number) => { - await variantAnalysisManager.openQueryFile(variantAnalysisId); - }, - ), - ); - ctx.subscriptions.push( commandRunner("codeQL.openReferencedFile", async (selectedQuery: Uri) => { await openReferencedFile(qs, cliServer, selectedQuery); diff --git a/extensions/ql-vscode/src/query-history/query-history-manager.ts b/extensions/ql-vscode/src/query-history/query-history-manager.ts index 279792ee5..f5dd7cf9a 100644 --- a/extensions/ql-vscode/src/query-history/query-history-manager.ts +++ b/extensions/ql-vscode/src/query-history/query-history-manager.ts @@ -522,8 +522,7 @@ export class QueryHistoryManager extends DisposableObject { } if (finalSingleItem.t === "variant-analysis") { - await commands.executeCommand( - "codeQL.openVariantAnalysisQueryFile", + await this.variantAnalysisManager.openQueryFile( finalSingleItem.variantAnalysis.id, ); return; diff --git a/extensions/ql-vscode/src/variant-analysis/variant-analysis-view-manager.ts b/extensions/ql-vscode/src/variant-analysis/variant-analysis-view-manager.ts index 9f17a4bd4..1fa1fe46d 100644 --- a/extensions/ql-vscode/src/variant-analysis/variant-analysis-view-manager.ts +++ b/extensions/ql-vscode/src/variant-analysis/variant-analysis-view-manager.ts @@ -24,4 +24,5 @@ export interface VariantAnalysisViewManager< getRepoStates( variantAnalysisId: number, ): Promise; + openQueryFile(variantAnalysisId: number): Promise; } diff --git a/extensions/ql-vscode/src/variant-analysis/variant-analysis-view.ts b/extensions/ql-vscode/src/variant-analysis/variant-analysis-view.ts index ef9a47bc5..77bd7b0e2 100644 --- a/extensions/ql-vscode/src/variant-analysis/variant-analysis-view.ts +++ b/extensions/ql-vscode/src/variant-analysis/variant-analysis-view.ts @@ -119,10 +119,7 @@ export class VariantAnalysisView ); break; case "openQueryFile": - void commands.executeCommand( - "codeQL.openVariantAnalysisQueryFile", - this.variantAnalysisId, - ); + await this.manager.openQueryFile(this.variantAnalysisId); break; case "openQueryText": void commands.executeCommand( From 29bb7ce01ee03cb326a0def1d6526fe8c073a560 Mon Sep 17 00:00:00 2001 From: Robert Date: Thu, 16 Mar 2023 10:39:02 +0000 Subject: [PATCH 052/156] Emit telemetry when opening variant analysis query file --- .../ql-vscode/src/view/variant-analysis/VariantAnalysis.tsx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/extensions/ql-vscode/src/view/variant-analysis/VariantAnalysis.tsx b/extensions/ql-vscode/src/view/variant-analysis/VariantAnalysis.tsx index cf4a0df25..6c2f27051 100644 --- a/extensions/ql-vscode/src/view/variant-analysis/VariantAnalysis.tsx +++ b/extensions/ql-vscode/src/view/variant-analysis/VariantAnalysis.tsx @@ -13,7 +13,7 @@ import { VariantAnalysisLoading } from "./VariantAnalysisLoading"; import { ToVariantAnalysisMessage } from "../../pure/interface-types"; import { vscode } from "../vscode-api"; import { defaultFilterSortState } from "../../pure/variant-analysis-filter-sort"; -import { useTelemetryOnChange } from "../common/telemetry"; +import { sendTelemetry, useTelemetryOnChange } from "../common/telemetry"; export type VariantAnalysisProps = { variantAnalysis?: VariantAnalysisDomainModel; @@ -25,6 +25,7 @@ const openQueryFile = () => { vscode.postMessage({ t: "openQueryFile", }); + sendTelemetry("variant-analysis-open-query-file"); }; const openQueryText = () => { From 64531f5a6f0c271c574eb96470be0785384c969d Mon Sep 17 00:00:00 2001 From: Robert Date: Thu, 16 Mar 2023 10:54:29 +0000 Subject: [PATCH 053/156] Check undefined instead of using typeof --- extensions/ql-vscode/src/pure/errors.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/extensions/ql-vscode/src/pure/errors.ts b/extensions/ql-vscode/src/pure/errors.ts index 8153dd7a2..28300d1fa 100644 --- a/extensions/ql-vscode/src/pure/errors.ts +++ b/extensions/ql-vscode/src/pure/errors.ts @@ -79,7 +79,7 @@ export interface ErrorLike { function isErrorLike(error: any): error is ErrorLike { if ( typeof error.message === "string" && - (typeof error.stack === "undefined" || typeof error.stack === "string") + (error.stack === undefined || typeof error.stack === "string") ) { return true; } From f2f1b1d6a393ec8e6f7cb70dc2db371cbab07438 Mon Sep 17 00:00:00 2001 From: Robert Date: Thu, 16 Mar 2023 10:59:02 +0000 Subject: [PATCH 054/156] Collect common messages --- .../ql-vscode/src/pure/interface-types.ts | 43 +++++++++---------- 1 file changed, 21 insertions(+), 22 deletions(-) diff --git a/extensions/ql-vscode/src/pure/interface-types.ts b/extensions/ql-vscode/src/pure/interface-types.ts index 38810275d..f5e8608a5 100644 --- a/extensions/ql-vscode/src/pure/interface-types.ts +++ b/extensions/ql-vscode/src/pure/interface-types.ts @@ -183,15 +183,13 @@ export type IntoResultsViewMsg = * A message sent from the results view. */ export type FromResultsViewMsg = + | CommonFromViewMessages | ViewSourceFileMsg | ToggleDiagnostics | ChangeRawResultsSortMsg | ChangeInterpretedResultsSortMsg - | ViewLoadedMsg | ChangePage - | OpenFileMsg - | TelemetryMessage - | UnhandledErrorMessage; + | OpenFileMsg; /** * Message from the results view to open a database source @@ -233,6 +231,21 @@ interface ViewLoadedMsg { viewName: string; } +interface TelemetryMessage { + t: "telemetry"; + action: string; +} + +interface UnhandledErrorMessage { + t: "unhandledError"; + error: ErrorLike; +} + +type CommonFromViewMessages = + | ViewLoadedMsg + | TelemetryMessage + | UnhandledErrorMessage; + /** * Message from the results view to signal a request to change the * page. @@ -289,12 +302,10 @@ interface ChangeInterpretedResultsSortMsg { * Message from the compare view to the extension. */ export type FromCompareViewMessage = - | ViewLoadedMsg + | CommonFromViewMessages | ChangeCompareMessage | ViewSourceFileMsg - | OpenQueryMessage - | TelemetryMessage - | UnhandledErrorMessage; + | OpenQueryMessage; /** * Message from the compare view to request opening a query. @@ -437,29 +448,17 @@ export interface CancelVariantAnalysisMessage { t: "cancelVariantAnalysis"; } -export interface TelemetryMessage { - t: "telemetry"; - action: string; -} - -export interface UnhandledErrorMessage { - t: "unhandledError"; - error: ErrorLike; -} - export type ToVariantAnalysisMessage = | SetVariantAnalysisMessage | SetRepoResultsMessage | SetRepoStatesMessage; export type FromVariantAnalysisMessage = - | ViewLoadedMsg + | CommonFromViewMessages | RequestRepositoryResultsMessage | OpenQueryFileMessage | OpenQueryTextMessage | CopyRepositoryListMessage | ExportResultsMessage | OpenLogsMessage - | CancelVariantAnalysisMessage - | TelemetryMessage - | UnhandledErrorMessage; + | CancelVariantAnalysisMessage; From cc53cd54c4a3bfc379a433d46ae804e004429b44 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 16 Mar 2023 09:38:00 -0700 Subject: [PATCH 055/156] Bump webpack-cli from 4.6.0 to 5.0.1 in /extensions/ql-vscode (#2181) Bumps [webpack-cli](https://github.com/webpack/webpack-cli) from 4.6.0 to 5.0.1. - [Release notes](https://github.com/webpack/webpack-cli/releases) - [Changelog](https://github.com/webpack/webpack-cli/blob/master/CHANGELOG.md) - [Commits](https://github.com/webpack/webpack-cli/compare/webpack-cli@4.6.0...webpack-cli@5.0.1) --- updated-dependencies: - dependency-name: webpack-cli dependency-type: direct:development update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- extensions/ql-vscode/package-lock.json | 282 +++++++++---------------- extensions/ql-vscode/package.json | 2 +- 2 files changed, 106 insertions(+), 178 deletions(-) diff --git a/extensions/ql-vscode/package-lock.json b/extensions/ql-vscode/package-lock.json index 8805e7185..8a22abe83 100644 --- a/extensions/ql-vscode/package-lock.json +++ b/extensions/ql-vscode/package-lock.json @@ -143,7 +143,7 @@ "ts-protoc-gen": "^0.9.0", "typescript": "^4.5.5", "webpack": "^5.76.0", - "webpack-cli": "^4.6.0" + "webpack-cli": "^5.0.1" }, "engines": { "node": "^16.13.0", @@ -14876,34 +14876,42 @@ } }, "node_modules/@webpack-cli/configtest": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/@webpack-cli/configtest/-/configtest-1.0.2.tgz", - "integrity": "sha512-3OBzV2fBGZ5TBfdW50cha1lHDVf9vlvRXnjpVbJBa20pSZQaSkMJZiwA8V2vD9ogyeXn8nU5s5A6mHyf5jhMzA==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@webpack-cli/configtest/-/configtest-2.0.1.tgz", + "integrity": "sha512-njsdJXJSiS2iNbQVS0eT8A/KPnmyH4pv1APj2K0d1wrZcBLw+yppxOy4CGqa0OxDJkzfL/XELDhD8rocnIwB5A==", "dev": true, + "engines": { + "node": ">=14.15.0" + }, "peerDependencies": { - "webpack": "4.x.x || 5.x.x", - "webpack-cli": "4.x.x" + "webpack": "5.x.x", + "webpack-cli": "5.x.x" } }, "node_modules/@webpack-cli/info": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/@webpack-cli/info/-/info-1.2.3.tgz", - "integrity": "sha512-lLek3/T7u40lTqzCGpC6CAbY6+vXhdhmwFRxZLMnRm6/sIF/7qMpT8MocXCRQfz0JAh63wpbXLMnsQ5162WS7Q==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@webpack-cli/info/-/info-2.0.1.tgz", + "integrity": "sha512-fE1UEWTwsAxRhrJNikE7v4EotYflkEhBL7EbajfkPlf6E37/2QshOy/D48Mw8G5XMFlQtS6YV42vtbG9zBpIQA==", "dev": true, - "dependencies": { - "envinfo": "^7.7.3" + "engines": { + "node": ">=14.15.0" }, "peerDependencies": { - "webpack-cli": "4.x.x" + "webpack": "5.x.x", + "webpack-cli": "5.x.x" } }, "node_modules/@webpack-cli/serve": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/@webpack-cli/serve/-/serve-1.3.1.tgz", - "integrity": "sha512-0qXvpeYO6vaNoRBI52/UsbcaBydJCggoBBnIo/ovQQdn6fug0BgwsjorV1hVS7fMqGVTZGcVxv8334gjmbj5hw==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@webpack-cli/serve/-/serve-2.0.1.tgz", + "integrity": "sha512-0G7tNyS+yW8TdgHwZKlDWYXFA6OJQnoLCQvYKkQP0Q2X205PSQ6RNUj0M+1OB/9gRQaUZ/ccYfaxd0nhaWKfjw==", "dev": true, + "engines": { + "node": ">=14.15.0" + }, "peerDependencies": { - "webpack-cli": "4.x.x" + "webpack": "5.x.x", + "webpack-cli": "5.x.x" }, "peerDependenciesMeta": { "webpack-dev-server": { @@ -20707,18 +20715,6 @@ "node": ">=6.9.0" } }, - "node_modules/enquirer": { - "version": "2.3.6", - "resolved": "https://registry.npmjs.org/enquirer/-/enquirer-2.3.6.tgz", - "integrity": "sha512-yjNnPr315/FjS4zIsUxYguYUPP2e1NK4d7E7ZOLiyYCcbFBiTMyID+2wvm2w6+pZ/odMA7cRkjhsPbltwBOrLg==", - "dev": true, - "dependencies": { - "ansi-colors": "^4.1.1" - }, - "engines": { - "node": ">=8.6" - } - }, "node_modules/entities": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/entities/-/entities-2.2.0.tgz", @@ -20729,9 +20725,9 @@ } }, "node_modules/envinfo": { - "version": "7.7.4", - "resolved": "https://registry.npmjs.org/envinfo/-/envinfo-7.7.4.tgz", - "integrity": "sha512-TQXTYFVVwwluWSFis6K2XKxgrD22jEv0FTuLCQI+OjH7rn93+iY0fSSFM5lrSxFY+H1+B0/cvvlamr3UsBivdQ==", + "version": "7.8.1", + "resolved": "https://registry.npmjs.org/envinfo/-/envinfo-7.8.1.tgz", + "integrity": "sha512-/o+BXHmB7ocbHEAs6F2EnG0ogybVVUdkRunTT2glZU9XAaGmhqskrvKwqXuDfNjEO0LZKWdejEEpnq8aM0tOaw==", "dev": true, "bin": { "envinfo": "dist/cli.js" @@ -39887,12 +39883,6 @@ "integrity": "sha512-dsNgbLaTrd6l3MMxTtouOCFw4CBFc/3a+GgYA2YyrJvyQ1u6q4pcu3ktLoUZ/VN/Aw9WsauazbgsgdfVWgAKQg==", "dev": true }, - "node_modules/v8-compile-cache": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz", - "integrity": "sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA==", - "dev": true - }, "node_modules/v8-compile-cache-lib": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.0.tgz", @@ -40465,42 +40455,42 @@ } }, "node_modules/webpack-cli": { - "version": "4.6.0", - "resolved": "https://registry.npmjs.org/webpack-cli/-/webpack-cli-4.6.0.tgz", - "integrity": "sha512-9YV+qTcGMjQFiY7Nb1kmnupvb1x40lfpj8pwdO/bom+sQiP4OBMKjHq29YQrlDWDPZO9r/qWaRRywKaRDKqBTA==", + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/webpack-cli/-/webpack-cli-5.0.1.tgz", + "integrity": "sha512-S3KVAyfwUqr0Mo/ur3NzIp6jnerNpo7GUO6so51mxLi1spqsA17YcMXy0WOIJtBSnj748lthxC6XLbNKh/ZC+A==", "dev": true, "dependencies": { "@discoveryjs/json-ext": "^0.5.0", - "@webpack-cli/configtest": "^1.0.2", - "@webpack-cli/info": "^1.2.3", - "@webpack-cli/serve": "^1.3.1", - "colorette": "^1.2.1", - "commander": "^7.0.0", - "enquirer": "^2.3.6", - "execa": "^5.0.0", + "@webpack-cli/configtest": "^2.0.1", + "@webpack-cli/info": "^2.0.1", + "@webpack-cli/serve": "^2.0.1", + "colorette": "^2.0.14", + "commander": "^9.4.1", + "cross-spawn": "^7.0.3", + "envinfo": "^7.7.3", "fastest-levenshtein": "^1.0.12", "import-local": "^3.0.2", - "interpret": "^2.2.0", - "rechoir": "^0.7.0", - "v8-compile-cache": "^2.2.0", + "interpret": "^3.1.1", + "rechoir": "^0.8.0", "webpack-merge": "^5.7.3" }, "bin": { "webpack-cli": "bin/cli.js" }, "engines": { - "node": ">=10.13.0" + "node": ">=14.15.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" }, "peerDependencies": { - "webpack": "4.x.x || 5.x.x" + "webpack": "5.x.x" }, "peerDependenciesMeta": { "@webpack-cli/generators": { "optional": true }, - "@webpack-cli/migrate": { - "optional": true - }, "webpack-bundle-analyzer": { "optional": true }, @@ -40509,13 +40499,19 @@ } } }, + "node_modules/webpack-cli/node_modules/colorette": { + "version": "2.0.19", + "resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.19.tgz", + "integrity": "sha512-3tlv/dIP7FWvj3BsbHrGLJ6l/oKh1O3TcgBqMn+yyCagOxc23fyzDS6HypQbgxWbkpDnf52p1LuR4eWDQ/K9WQ==", + "dev": true + }, "node_modules/webpack-cli/node_modules/commander": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz", - "integrity": "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==", + "version": "9.5.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-9.5.0.tgz", + "integrity": "sha512-KRs7WVDKg86PWiuAqhDrAQnTXZKraVcCc6vFdL14qrZ/DcWwuRo7VoiYXalXO7S5GKpqYiVEwCbgFDfxNHKJBQ==", "dev": true, "engines": { - "node": ">= 10" + "node": "^12.20.0 || >=14" } }, "node_modules/webpack-cli/node_modules/cross-spawn": { @@ -40532,45 +40528,13 @@ "node": ">= 8" } }, - "node_modules/webpack-cli/node_modules/execa": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/execa/-/execa-5.0.0.tgz", - "integrity": "sha512-ov6w/2LCiuyO4RLYGdpFGjkcs0wMTgGE8PrkTHikeUy5iJekXyPIKUjifk5CsE0pt7sMCrMZ3YNqoCj6idQOnQ==", - "dev": true, - "dependencies": { - "cross-spawn": "^7.0.3", - "get-stream": "^6.0.0", - "human-signals": "^2.1.0", - "is-stream": "^2.0.0", - "merge-stream": "^2.0.0", - "npm-run-path": "^4.0.1", - "onetime": "^5.1.2", - "signal-exit": "^3.0.3", - "strip-final-newline": "^2.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sindresorhus/execa?sponsor=1" - } - }, - "node_modules/webpack-cli/node_modules/human-signals": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", - "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==", - "dev": true, - "engines": { - "node": ">=10.17.0" - } - }, "node_modules/webpack-cli/node_modules/interpret": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/interpret/-/interpret-2.2.0.tgz", - "integrity": "sha512-Ju0Bz/cEia55xDwUWEa8+olFpCiQoypjnQySseKtmjNrnps3P+xfpUmGr90T7yjlVJmOtybRvPXhKMbHr+fWnw==", + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/interpret/-/interpret-3.1.1.tgz", + "integrity": "sha512-6xwYfHbajpoF0xLW+iwLkhwgvLoZDfjYfoFNu8ftMoXINzwuymNLd9u/KmwtdT2GbR+/Cz66otEGEVVUHX9QLQ==", "dev": true, "engines": { - "node": ">= 0.10" + "node": ">=10.13.0" } }, "node_modules/webpack-cli/node_modules/path-key": { @@ -40583,15 +40547,15 @@ } }, "node_modules/webpack-cli/node_modules/rechoir": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.7.0.tgz", - "integrity": "sha512-ADsDEH2bvbjltXEP+hTIAmeFekTFK0V2BTxMkok6qILyAJEXV0AFfoWcAq4yfll5VdIMd/RVXq0lR+wQi5ZU3Q==", + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.8.0.tgz", + "integrity": "sha512-/vxpCXddiX8NGfGO/mTafwjq4aFa/71pvamip0++IQk3zG8cbCj0fifNPrjjF1XMXUne91jL9OoxmdykoEtifQ==", "dev": true, "dependencies": { - "resolve": "^1.9.0" + "resolve": "^1.20.0" }, "engines": { - "node": ">= 0.10" + "node": ">= 10.13.0" } }, "node_modules/webpack-cli/node_modules/shebang-command": { @@ -52624,24 +52588,21 @@ } }, "@webpack-cli/configtest": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/@webpack-cli/configtest/-/configtest-1.0.2.tgz", - "integrity": "sha512-3OBzV2fBGZ5TBfdW50cha1lHDVf9vlvRXnjpVbJBa20pSZQaSkMJZiwA8V2vD9ogyeXn8nU5s5A6mHyf5jhMzA==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@webpack-cli/configtest/-/configtest-2.0.1.tgz", + "integrity": "sha512-njsdJXJSiS2iNbQVS0eT8A/KPnmyH4pv1APj2K0d1wrZcBLw+yppxOy4CGqa0OxDJkzfL/XELDhD8rocnIwB5A==", "dev": true }, "@webpack-cli/info": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/@webpack-cli/info/-/info-1.2.3.tgz", - "integrity": "sha512-lLek3/T7u40lTqzCGpC6CAbY6+vXhdhmwFRxZLMnRm6/sIF/7qMpT8MocXCRQfz0JAh63wpbXLMnsQ5162WS7Q==", - "dev": true, - "requires": { - "envinfo": "^7.7.3" - } + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@webpack-cli/info/-/info-2.0.1.tgz", + "integrity": "sha512-fE1UEWTwsAxRhrJNikE7v4EotYflkEhBL7EbajfkPlf6E37/2QshOy/D48Mw8G5XMFlQtS6YV42vtbG9zBpIQA==", + "dev": true }, "@webpack-cli/serve": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/@webpack-cli/serve/-/serve-1.3.1.tgz", - "integrity": "sha512-0qXvpeYO6vaNoRBI52/UsbcaBydJCggoBBnIo/ovQQdn6fug0BgwsjorV1hVS7fMqGVTZGcVxv8334gjmbj5hw==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@webpack-cli/serve/-/serve-2.0.1.tgz", + "integrity": "sha512-0G7tNyS+yW8TdgHwZKlDWYXFA6OJQnoLCQvYKkQP0Q2X205PSQ6RNUj0M+1OB/9gRQaUZ/ccYfaxd0nhaWKfjw==", "dev": true }, "@xmldom/xmldom": { @@ -57162,15 +57123,6 @@ "tapable": "^1.0.0" } }, - "enquirer": { - "version": "2.3.6", - "resolved": "https://registry.npmjs.org/enquirer/-/enquirer-2.3.6.tgz", - "integrity": "sha512-yjNnPr315/FjS4zIsUxYguYUPP2e1NK4d7E7ZOLiyYCcbFBiTMyID+2wvm2w6+pZ/odMA7cRkjhsPbltwBOrLg==", - "dev": true, - "requires": { - "ansi-colors": "^4.1.1" - } - }, "entities": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/entities/-/entities-2.2.0.tgz", @@ -57178,9 +57130,9 @@ "dev": true }, "envinfo": { - "version": "7.7.4", - "resolved": "https://registry.npmjs.org/envinfo/-/envinfo-7.7.4.tgz", - "integrity": "sha512-TQXTYFVVwwluWSFis6K2XKxgrD22jEv0FTuLCQI+OjH7rn93+iY0fSSFM5lrSxFY+H1+B0/cvvlamr3UsBivdQ==", + "version": "7.8.1", + "resolved": "https://registry.npmjs.org/envinfo/-/envinfo-7.8.1.tgz", + "integrity": "sha512-/o+BXHmB7ocbHEAs6F2EnG0ogybVVUdkRunTT2glZU9XAaGmhqskrvKwqXuDfNjEO0LZKWdejEEpnq8aM0tOaw==", "dev": true }, "errno": { @@ -71789,12 +71741,6 @@ "integrity": "sha512-dsNgbLaTrd6l3MMxTtouOCFw4CBFc/3a+GgYA2YyrJvyQ1u6q4pcu3ktLoUZ/VN/Aw9WsauazbgsgdfVWgAKQg==", "dev": true }, - "v8-compile-cache": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz", - "integrity": "sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA==", - "dev": true - }, "v8-compile-cache-lib": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.0.tgz", @@ -72318,31 +72264,36 @@ } }, "webpack-cli": { - "version": "4.6.0", - "resolved": "https://registry.npmjs.org/webpack-cli/-/webpack-cli-4.6.0.tgz", - "integrity": "sha512-9YV+qTcGMjQFiY7Nb1kmnupvb1x40lfpj8pwdO/bom+sQiP4OBMKjHq29YQrlDWDPZO9r/qWaRRywKaRDKqBTA==", + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/webpack-cli/-/webpack-cli-5.0.1.tgz", + "integrity": "sha512-S3KVAyfwUqr0Mo/ur3NzIp6jnerNpo7GUO6so51mxLi1spqsA17YcMXy0WOIJtBSnj748lthxC6XLbNKh/ZC+A==", "dev": true, "requires": { "@discoveryjs/json-ext": "^0.5.0", - "@webpack-cli/configtest": "^1.0.2", - "@webpack-cli/info": "^1.2.3", - "@webpack-cli/serve": "^1.3.1", - "colorette": "^1.2.1", - "commander": "^7.0.0", - "enquirer": "^2.3.6", - "execa": "^5.0.0", + "@webpack-cli/configtest": "^2.0.1", + "@webpack-cli/info": "^2.0.1", + "@webpack-cli/serve": "^2.0.1", + "colorette": "^2.0.14", + "commander": "^9.4.1", + "cross-spawn": "^7.0.3", + "envinfo": "^7.7.3", "fastest-levenshtein": "^1.0.12", "import-local": "^3.0.2", - "interpret": "^2.2.0", - "rechoir": "^0.7.0", - "v8-compile-cache": "^2.2.0", + "interpret": "^3.1.1", + "rechoir": "^0.8.0", "webpack-merge": "^5.7.3" }, "dependencies": { + "colorette": { + "version": "2.0.19", + "resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.19.tgz", + "integrity": "sha512-3tlv/dIP7FWvj3BsbHrGLJ6l/oKh1O3TcgBqMn+yyCagOxc23fyzDS6HypQbgxWbkpDnf52p1LuR4eWDQ/K9WQ==", + "dev": true + }, "commander": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz", - "integrity": "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==", + "version": "9.5.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-9.5.0.tgz", + "integrity": "sha512-KRs7WVDKg86PWiuAqhDrAQnTXZKraVcCc6vFdL14qrZ/DcWwuRo7VoiYXalXO7S5GKpqYiVEwCbgFDfxNHKJBQ==", "dev": true }, "cross-spawn": { @@ -72356,33 +72307,10 @@ "which": "^2.0.1" } }, - "execa": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/execa/-/execa-5.0.0.tgz", - "integrity": "sha512-ov6w/2LCiuyO4RLYGdpFGjkcs0wMTgGE8PrkTHikeUy5iJekXyPIKUjifk5CsE0pt7sMCrMZ3YNqoCj6idQOnQ==", - "dev": true, - "requires": { - "cross-spawn": "^7.0.3", - "get-stream": "^6.0.0", - "human-signals": "^2.1.0", - "is-stream": "^2.0.0", - "merge-stream": "^2.0.0", - "npm-run-path": "^4.0.1", - "onetime": "^5.1.2", - "signal-exit": "^3.0.3", - "strip-final-newline": "^2.0.0" - } - }, - "human-signals": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", - "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==", - "dev": true - }, "interpret": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/interpret/-/interpret-2.2.0.tgz", - "integrity": "sha512-Ju0Bz/cEia55xDwUWEa8+olFpCiQoypjnQySseKtmjNrnps3P+xfpUmGr90T7yjlVJmOtybRvPXhKMbHr+fWnw==", + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/interpret/-/interpret-3.1.1.tgz", + "integrity": "sha512-6xwYfHbajpoF0xLW+iwLkhwgvLoZDfjYfoFNu8ftMoXINzwuymNLd9u/KmwtdT2GbR+/Cz66otEGEVVUHX9QLQ==", "dev": true }, "path-key": { @@ -72392,12 +72320,12 @@ "dev": true }, "rechoir": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.7.0.tgz", - "integrity": "sha512-ADsDEH2bvbjltXEP+hTIAmeFekTFK0V2BTxMkok6qILyAJEXV0AFfoWcAq4yfll5VdIMd/RVXq0lR+wQi5ZU3Q==", + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.8.0.tgz", + "integrity": "sha512-/vxpCXddiX8NGfGO/mTafwjq4aFa/71pvamip0++IQk3zG8cbCj0fifNPrjjF1XMXUne91jL9OoxmdykoEtifQ==", "dev": true, "requires": { - "resolve": "^1.9.0" + "resolve": "^1.20.0" } }, "shebang-command": { diff --git a/extensions/ql-vscode/package.json b/extensions/ql-vscode/package.json index 990b925a5..4cb7f0903 100644 --- a/extensions/ql-vscode/package.json +++ b/extensions/ql-vscode/package.json @@ -1563,7 +1563,7 @@ "ts-protoc-gen": "^0.9.0", "typescript": "^4.5.5", "webpack": "^5.76.0", - "webpack-cli": "^4.6.0" + "webpack-cli": "^5.0.1" }, "lint-staged": { "./**/*.{json,css,scss}": [ From 8a5273058bf357d6a1bdc650f61b2221893ed468 Mon Sep 17 00:00:00 2001 From: Charis Kyriakou Date: Fri, 17 Mar 2023 09:25:03 +0000 Subject: [PATCH 056/156] Add new data flow paths view (empty) (#2172) --- extensions/ql-vscode/package.json | 1 + extensions/ql-vscode/src/interface-utils.ts | 6 +- .../ql-vscode/src/pure/interface-types.ts | 10 ++ .../variant-analysis/data-flow-paths-view.ts | 68 +++++++++++ .../shared/data-flow-paths.ts | 8 ++ .../data-flow-paths/DataFlowPathsView.tsx | 48 ++++++++ .../__tests__/DataFlowPathsView.spec.tsx | 24 ++++ .../src/view/data-flow-paths/index.tsx | 9 ++ .../shared/data-flow-paths.ts | 106 ++++++++++++++++++ 9 files changed, 279 insertions(+), 1 deletion(-) create mode 100644 extensions/ql-vscode/src/variant-analysis/data-flow-paths-view.ts create mode 100644 extensions/ql-vscode/src/variant-analysis/shared/data-flow-paths.ts create mode 100644 extensions/ql-vscode/src/view/data-flow-paths/DataFlowPathsView.tsx create mode 100644 extensions/ql-vscode/src/view/data-flow-paths/__tests__/DataFlowPathsView.spec.tsx create mode 100644 extensions/ql-vscode/src/view/data-flow-paths/index.tsx create mode 100644 extensions/ql-vscode/test/factories/variant-analysis/shared/data-flow-paths.ts diff --git a/extensions/ql-vscode/package.json b/extensions/ql-vscode/package.json index f60718c2c..f35d28e36 100644 --- a/extensions/ql-vscode/package.json +++ b/extensions/ql-vscode/package.json @@ -56,6 +56,7 @@ "onCommand:codeQL.restartQueryServer", "onWebviewPanel:resultsView", "onWebviewPanel:codeQL.variantAnalysis", + "onWebviewPanel:codeQL.dataFlowPaths", "onFileSystem:codeql-zip-archive" ], "main": "./out/extension", diff --git a/extensions/ql-vscode/src/interface-utils.ts b/extensions/ql-vscode/src/interface-utils.ts index da01c3135..68232dacd 100644 --- a/extensions/ql-vscode/src/interface-utils.ts +++ b/extensions/ql-vscode/src/interface-utils.ts @@ -109,7 +109,11 @@ export function tryResolveLocation( } } -export type WebviewView = "results" | "compare" | "variant-analysis"; +export type WebviewView = + | "results" + | "compare" + | "variant-analysis" + | "data-flow-paths"; export interface WebviewMessage { t: string; diff --git a/extensions/ql-vscode/src/pure/interface-types.ts b/extensions/ql-vscode/src/pure/interface-types.ts index f5e8608a5..aa0ff600c 100644 --- a/extensions/ql-vscode/src/pure/interface-types.ts +++ b/extensions/ql-vscode/src/pure/interface-types.ts @@ -13,6 +13,7 @@ import { } from "../variant-analysis/shared/variant-analysis"; import { RepositoriesFilterSortStateWithIds } from "./variant-analysis-filter-sort"; import { ErrorLike } from "./errors"; +import { DataFlowPaths } from "../variant-analysis/shared/data-flow-paths"; /** * This module contains types and code that are shared between @@ -462,3 +463,12 @@ export type FromVariantAnalysisMessage = | ExportResultsMessage | OpenLogsMessage | CancelVariantAnalysisMessage; + +export interface SetDataFlowPathsMessage { + t: "setDataFlowPaths"; + dataFlowPaths: DataFlowPaths; +} + +export type ToDataFlowPathsMessage = SetDataFlowPathsMessage; + +export type FromDataFlowPathsMessage = CommonFromViewMessages; diff --git a/extensions/ql-vscode/src/variant-analysis/data-flow-paths-view.ts b/extensions/ql-vscode/src/variant-analysis/data-flow-paths-view.ts new file mode 100644 index 000000000..cfaf568db --- /dev/null +++ b/extensions/ql-vscode/src/variant-analysis/data-flow-paths-view.ts @@ -0,0 +1,68 @@ +import { ExtensionContext, ViewColumn } from "vscode"; +import { AbstractWebview, WebviewPanelConfig } from "../abstract-webview"; +import { assertNever } from "../pure/helpers-pure"; +import { telemetryListener } from "../telemetry"; +import { + FromDataFlowPathsMessage, + ToDataFlowPathsMessage, +} from "../pure/interface-types"; +import { DataFlowPaths } from "./shared/data-flow-paths"; +import { showAndLogExceptionWithTelemetry } from "../helpers"; +import { redactableError } from "../pure/errors"; + +export class DataFlowPathsView extends AbstractWebview< + ToDataFlowPathsMessage, + FromDataFlowPathsMessage +> { + public static readonly viewType = "codeQL.dataFlowPaths"; + + public constructor(ctx: ExtensionContext) { + super(ctx); + } + + public async showDataFlows(dataFlowPaths: DataFlowPaths) { + const panel = await this.getPanel(); + panel.reveal(undefined, true); + + await this.waitForPanelLoaded(); + + await this.postMessage({ + t: "setDataFlowPaths", + dataFlowPaths, + }); + } + + protected async getPanelConfig(): Promise { + return { + viewId: DataFlowPathsView.viewType, + title: "Data Flow Paths", + viewColumn: ViewColumn.Active, + preserveFocus: true, + view: "data-flow-paths", + }; + } + + protected onPanelDispose(): void { + // Nothing to dispose + } + + protected async onMessage(msg: FromDataFlowPathsMessage): Promise { + switch (msg.t) { + case "viewLoaded": + this.onWebViewLoaded(); + break; + case "telemetry": + telemetryListener?.sendUIInteraction(msg.action); + break; + case "unhandledError": + void showAndLogExceptionWithTelemetry( + redactableError( + msg.error, + )`Unhandled error in data flow paths view: ${msg.error.message}`, + ); + break; + default: + assertNever(msg); + } + } +} diff --git a/extensions/ql-vscode/src/variant-analysis/shared/data-flow-paths.ts b/extensions/ql-vscode/src/variant-analysis/shared/data-flow-paths.ts new file mode 100644 index 000000000..7ed20b69f --- /dev/null +++ b/extensions/ql-vscode/src/variant-analysis/shared/data-flow-paths.ts @@ -0,0 +1,8 @@ +import { AnalysisMessage, CodeFlow, ResultSeverity } from "./analysis-result"; + +export interface DataFlowPaths { + codeFlows: CodeFlow[]; + ruleDescription: string; + message: AnalysisMessage; + severity: ResultSeverity; +} diff --git a/extensions/ql-vscode/src/view/data-flow-paths/DataFlowPathsView.tsx b/extensions/ql-vscode/src/view/data-flow-paths/DataFlowPathsView.tsx new file mode 100644 index 000000000..e4c6960fd --- /dev/null +++ b/extensions/ql-vscode/src/view/data-flow-paths/DataFlowPathsView.tsx @@ -0,0 +1,48 @@ +import * as React from "react"; +import { useEffect, useState } from "react"; +import { ToDataFlowPathsMessage } from "../../pure/interface-types"; +import { DataFlowPaths } from "../../variant-analysis/shared/data-flow-paths"; + +export type DataFlowPathsViewProps = { + dataFlowPaths?: DataFlowPaths; +}; + +export function DataFlowPathsView({ + dataFlowPaths: initialDataFlowPaths, +}: DataFlowPathsViewProps): JSX.Element { + const [dataFlowPaths, setDataFlowPaths] = useState( + initialDataFlowPaths, + ); + + useEffect(() => { + const listener = (evt: MessageEvent) => { + if (evt.origin === window.origin) { + const msg: ToDataFlowPathsMessage = evt.data; + if (msg.t === "setDataFlowPaths") { + setDataFlowPaths(msg.dataFlowPaths); + } + } else { + // sanitize origin + const origin = evt.origin.replace(/\n|\r/g, ""); + console.error(`Invalid event origin ${origin}`); + } + }; + window.addEventListener("message", listener); + + return () => { + window.removeEventListener("message", listener); + }; + }, []); + + if (!dataFlowPaths) { + return <>Loading data flow paths; + } + + // For now, just render the data flows as JSON. + return ( + <> + Loaded +
{JSON.stringify(dataFlowPaths)}
+ + ); +} diff --git a/extensions/ql-vscode/src/view/data-flow-paths/__tests__/DataFlowPathsView.spec.tsx b/extensions/ql-vscode/src/view/data-flow-paths/__tests__/DataFlowPathsView.spec.tsx new file mode 100644 index 000000000..da11f818f --- /dev/null +++ b/extensions/ql-vscode/src/view/data-flow-paths/__tests__/DataFlowPathsView.spec.tsx @@ -0,0 +1,24 @@ +import * as React from "react"; +import { render as reactRender, screen } from "@testing-library/react"; +import { + DataFlowPathsView, + DataFlowPathsViewProps, +} from "../DataFlowPathsView"; +import { createMockDataFlowPaths } from "../../../../test/factories/variant-analysis/shared/data-flow-paths"; + +describe(DataFlowPathsView.name, () => { + const render = (props: Partial) => + reactRender(); + + it("renders a loading data flow paths view", () => { + render({}); + + expect(screen.getByText("Loading data flow paths")).toBeInTheDocument(); + }); + + it("renders a data flow paths view", () => { + render({ dataFlowPaths: createMockDataFlowPaths() }); + + expect(screen.getByText("Loaded")).toBeInTheDocument(); + }); +}); diff --git a/extensions/ql-vscode/src/view/data-flow-paths/index.tsx b/extensions/ql-vscode/src/view/data-flow-paths/index.tsx new file mode 100644 index 000000000..5fd13430b --- /dev/null +++ b/extensions/ql-vscode/src/view/data-flow-paths/index.tsx @@ -0,0 +1,9 @@ +import * as React from "react"; +import { WebviewDefinition } from "../webview-definition"; +import { DataFlowPathsView } from "./DataFlowPathsView"; + +const definition: WebviewDefinition = { + component: , +}; + +export default definition; diff --git a/extensions/ql-vscode/test/factories/variant-analysis/shared/data-flow-paths.ts b/extensions/ql-vscode/test/factories/variant-analysis/shared/data-flow-paths.ts new file mode 100644 index 000000000..189924211 --- /dev/null +++ b/extensions/ql-vscode/test/factories/variant-analysis/shared/data-flow-paths.ts @@ -0,0 +1,106 @@ +import { CodeFlow } from "../../../../src/variant-analysis/shared/analysis-result"; +import { DataFlowPaths } from "../../../../src/variant-analysis/shared/data-flow-paths"; + +export function createMockDataFlowPaths(): DataFlowPaths { + const codeFlows: CodeFlow[] = [ + { + threadFlows: [ + { + fileLink: { + fileLinkPrefix: + "https://github.com/PowerShell/PowerShell/blob/450d884668ca477c6581ce597958f021fac30bff", + filePath: + "src/System.Management.Automation/help/UpdatableHelpSystem.cs", + }, + codeSnippet: { + startLine: 1260, + endLine: 1260, + text: " string extractPath = Path.Combine(destination, entry.FullName);", + }, + highlightedRegion: { + startLine: 1260, + startColumn: 72, + endLine: 1260, + endColumn: 86, + }, + message: { + tokens: [ + { + t: "text", + text: "access to property FullName : String", + }, + ], + }, + }, + { + fileLink: { + fileLinkPrefix: + "https://github.com/PowerShell/PowerShell/blob/450d884668ca477c6581ce597958f021fac30bff", + filePath: + "src/System.Management.Automation/help/UpdatableHelpSystem.cs", + }, + codeSnippet: { + startLine: 1260, + endLine: 1260, + text: " string extractPath = Path.Combine(destination, entry.FullName);", + }, + highlightedRegion: { + startLine: 1260, + startColumn: 46, + endLine: 1260, + endColumn: 87, + }, + message: { + tokens: [ + { + t: "text", + text: "call to method Combine : String", + }, + ], + }, + }, + { + fileLink: { + fileLinkPrefix: + "https://github.com/PowerShell/PowerShell/blob/450d884668ca477c6581ce597958f021fac30bff", + filePath: + "src/System.Management.Automation/help/UpdatableHelpSystem.cs", + }, + codeSnippet: { + startLine: 1261, + endLine: 1261, + text: " entry.ExtractToFile(extractPath);", + }, + highlightedRegion: { + startLine: 1261, + startColumn: 45, + endLine: 1261, + endColumn: 56, + }, + message: { + tokens: [ + { + t: "text", + text: "access to local variable extractPath", + }, + ], + }, + }, + ], + }, + ]; + + return { + codeFlows, + ruleDescription: "ZipSlip vulnerability", + message: { + tokens: [ + { + t: "text", + text: "This zip file may have a dangerous path", + }, + ], + }, + severity: "Warning", + }; +} From fce51ca9a221c187306982eda67032abc0deec61 Mon Sep 17 00:00:00 2001 From: Koen Vlaswinkel Date: Wed, 15 Mar 2023 15:41:53 +0100 Subject: [PATCH 057/156] Convert query history commands to typed commands --- extensions/ql-vscode/package.json | 2 +- extensions/ql-vscode/src/common/commands.ts | 46 ++++- extensions/ql-vscode/src/extension.ts | 1 + .../query-history/query-history-manager.ts | 194 ++++-------------- 4 files changed, 86 insertions(+), 157 deletions(-) diff --git a/extensions/ql-vscode/package.json b/extensions/ql-vscode/package.json index f35d28e36..9d3afca17 100644 --- a/extensions/ql-vscode/package.json +++ b/extensions/ql-vscode/package.json @@ -644,7 +644,7 @@ }, { "command": "codeQLQueryHistory.openOnGithub", - "title": "View Logs" + "title": "Open on GitHub" }, { "command": "codeQLQueryHistory.copyRepoList", diff --git a/extensions/ql-vscode/src/common/commands.ts b/extensions/ql-vscode/src/common/commands.ts index df9a653fa..dcd175df0 100644 --- a/extensions/ql-vscode/src/common/commands.ts +++ b/extensions/ql-vscode/src/common/commands.ts @@ -1,5 +1,13 @@ -import { CommandManager } from "../packages/commands"; +import type { CommandManager } from "../packages/commands"; import type { Uri } from "vscode"; +import type { QueryHistoryInfo } from "../query-history/query-history-info"; + +// A command function matching the signature that VS Code calls when +// a command on a selection is invoked. +export type SelectionCommandFunction = ( + singleItem: Item, + multiSelect: Item[], +) => Promise; /** * Contains type definitions for all commands used by the extension. @@ -13,6 +21,38 @@ export type BaseCommands = { "codeQL.openDocumentation": () => Promise; }; +// Commands used for the query history panel +export type QueryHistoryCommands = { + // Commands in the "navigation" group + "codeQLQueryHistory.sortByName": () => Promise; + "codeQLQueryHistory.sortByDate": () => Promise; + "codeQLQueryHistory.sortByCount": () => Promise; + + // Commands in the context menu or in the hover menu + "codeQLQueryHistory.openQueryTitleMenu": SelectionCommandFunction; + "codeQLQueryHistory.openQueryContextMenu": SelectionCommandFunction; + "codeQLQueryHistory.removeHistoryItemTitleMenu": SelectionCommandFunction; + "codeQLQueryHistory.removeHistoryItemContextMenu": SelectionCommandFunction; + "codeQLQueryHistory.removeHistoryItemContextInline": SelectionCommandFunction; + "codeQLQueryHistory.renameItem": SelectionCommandFunction; + "codeQLQueryHistory.compareWith": SelectionCommandFunction; + "codeQLQueryHistory.showEvalLog": SelectionCommandFunction; + "codeQLQueryHistory.showEvalLogSummary": SelectionCommandFunction; + "codeQLQueryHistory.showEvalLogViewer": SelectionCommandFunction; + "codeQLQueryHistory.showQueryLog": SelectionCommandFunction; + "codeQLQueryHistory.showQueryText": SelectionCommandFunction; + "codeQLQueryHistory.openQueryDirectory": SelectionCommandFunction; + "codeQLQueryHistory.cancel": SelectionCommandFunction; + "codeQLQueryHistory.exportResults": SelectionCommandFunction; + "codeQLQueryHistory.viewCsvResults": SelectionCommandFunction; + "codeQLQueryHistory.viewCsvAlerts": SelectionCommandFunction; + "codeQLQueryHistory.viewSarifAlerts": SelectionCommandFunction; + "codeQLQueryHistory.viewDil": SelectionCommandFunction; + "codeQLQueryHistory.itemClicked": SelectionCommandFunction; + "codeQLQueryHistory.openOnGithub": SelectionCommandFunction; + "codeQLQueryHistory.copyRepoList": SelectionCommandFunction; +}; + // Commands tied to variant analysis export type VariantAnalysisCommands = { "codeQL.openVariantAnalysisLogs": ( @@ -22,6 +62,8 @@ export type VariantAnalysisCommands = { "codeQL.runVariantAnalysisContextEditor": (uri?: Uri) => Promise; }; -export type AllCommands = BaseCommands & VariantAnalysisCommands; +export type AllCommands = BaseCommands & + QueryHistoryCommands & + VariantAnalysisCommands; export type AppCommandManager = CommandManager; diff --git a/extensions/ql-vscode/src/extension.ts b/extensions/ql-vscode/src/extension.ts index 5225e2deb..27beb7b32 100644 --- a/extensions/ql-vscode/src/extension.ts +++ b/extensions/ql-vscode/src/extension.ts @@ -1094,6 +1094,7 @@ async function activateWithInstalledDistribution( const allCommands: AllCommands = { ...getCommands(), + ...qhm.getCommands(), ...variantAnalysisManager.getCommands(), }; diff --git a/extensions/ql-vscode/src/query-history/query-history-manager.ts b/extensions/ql-vscode/src/query-history/query-history-manager.ts index 14e5ec8ea..46f938848 100644 --- a/extensions/ql-vscode/src/query-history/query-history-manager.ts +++ b/extensions/ql-vscode/src/query-history/query-history-manager.ts @@ -25,7 +25,6 @@ import { import { extLogger } from "../common"; import { URLSearchParams } from "url"; import { DisposableObject } from "../pure/disposable-object"; -import { commandRunner } from "../commandRunner"; import { ONE_HOUR_IN_MS, TWO_HOURS_IN_MS } from "../pure/time"; import { asError, @@ -66,6 +65,7 @@ import { getTotalResultCount } from "../variant-analysis/shared/variant-analysis import { HistoryTreeDataProvider } from "./history-tree-data-provider"; import { redactableError } from "../pure/errors"; import { QueryHistoryDirs } from "./query-history-dirs"; +import { QueryHistoryCommands } from "../common/commands"; /** * query-history-manager.ts @@ -201,159 +201,6 @@ export class QueryHistoryManager extends DisposableObject { }), ); - void extLogger.log("Registering query history panel commands."); - this.push( - commandRunner( - "codeQLQueryHistory.openQueryTitleMenu", - this.handleOpenQuery.bind(this), - ), - ); - this.push( - commandRunner( - "codeQLQueryHistory.openQueryContextMenu", - this.handleOpenQuery.bind(this), - ), - ); - this.push( - commandRunner( - "codeQLQueryHistory.removeHistoryItemTitleMenu", - this.handleRemoveHistoryItem.bind(this), - ), - ); - this.push( - commandRunner( - "codeQLQueryHistory.removeHistoryItemContextMenu", - this.handleRemoveHistoryItem.bind(this), - ), - ); - this.push( - commandRunner( - "codeQLQueryHistory.removeHistoryItemContextInline", - this.handleRemoveHistoryItem.bind(this), - ), - ); - this.push( - commandRunner( - "codeQLQueryHistory.sortByName", - this.handleSortByName.bind(this), - ), - ); - this.push( - commandRunner( - "codeQLQueryHistory.sortByDate", - this.handleSortByDate.bind(this), - ), - ); - this.push( - commandRunner( - "codeQLQueryHistory.sortByCount", - this.handleSortByCount.bind(this), - ), - ); - this.push( - commandRunner( - "codeQLQueryHistory.renameItem", - this.handleRenameItem.bind(this), - ), - ); - this.push( - commandRunner( - "codeQLQueryHistory.compareWith", - this.handleCompareWith.bind(this), - ), - ); - this.push( - commandRunner( - "codeQLQueryHistory.showQueryLog", - this.handleShowQueryLog.bind(this), - ), - ); - this.push( - commandRunner( - "codeQLQueryHistory.openQueryDirectory", - this.handleOpenQueryDirectory.bind(this), - ), - ); - this.push( - commandRunner( - "codeQLQueryHistory.showEvalLog", - this.handleShowEvalLog.bind(this), - ), - ); - this.push( - commandRunner( - "codeQLQueryHistory.showEvalLogSummary", - this.handleShowEvalLogSummary.bind(this), - ), - ); - this.push( - commandRunner( - "codeQLQueryHistory.showEvalLogViewer", - this.handleShowEvalLogViewer.bind(this), - ), - ); - this.push( - commandRunner("codeQLQueryHistory.cancel", this.handleCancel.bind(this)), - ); - this.push( - commandRunner( - "codeQLQueryHistory.showQueryText", - this.handleShowQueryText.bind(this), - ), - ); - this.push( - commandRunner( - "codeQLQueryHistory.exportResults", - this.handleExportResults.bind(this), - ), - ); - this.push( - commandRunner( - "codeQLQueryHistory.viewCsvResults", - this.handleViewCsvResults.bind(this), - ), - ); - this.push( - commandRunner( - "codeQLQueryHistory.viewCsvAlerts", - this.handleViewCsvAlerts.bind(this), - ), - ); - this.push( - commandRunner( - "codeQLQueryHistory.viewSarifAlerts", - this.handleViewSarifAlerts.bind(this), - ), - ); - this.push( - commandRunner( - "codeQLQueryHistory.viewDil", - this.handleViewDil.bind(this), - ), - ); - this.push( - commandRunner( - "codeQLQueryHistory.itemClicked", - async (item: LocalQueryInfo) => { - return this.handleItemClicked(item, [item]); - }, - ), - ); - this.push( - commandRunner( - "codeQLQueryHistory.openOnGithub", - async (item: LocalQueryInfo) => { - return this.handleOpenOnGithub(item, [item]); - }, - ), - ); - this.push( - commandRunner( - "codeQLQueryHistory.copyRepoList", - this.handleCopyRepoList.bind(this), - ), - ); - // There are two configuration items that affect the query history: // 1. The ttl for query history items. // 2. The default label for query history items. @@ -388,6 +235,45 @@ export class QueryHistoryManager extends DisposableObject { this.registerToVariantAnalysisEvents(); } + public getCommands(): QueryHistoryCommands { + return { + "codeQLQueryHistory.sortByName": this.handleSortByName.bind(this), + "codeQLQueryHistory.sortByDate": this.handleSortByDate.bind(this), + "codeQLQueryHistory.sortByCount": this.handleSortByCount.bind(this), + + "codeQLQueryHistory.openQueryTitleMenu": this.handleOpenQuery.bind(this), + "codeQLQueryHistory.openQueryContextMenu": + this.handleOpenQuery.bind(this), + "codeQLQueryHistory.removeHistoryItemTitleMenu": + this.handleRemoveHistoryItem.bind(this), + "codeQLQueryHistory.removeHistoryItemContextMenu": + this.handleRemoveHistoryItem.bind(this), + "codeQLQueryHistory.removeHistoryItemContextInline": + this.handleRemoveHistoryItem.bind(this), + "codeQLQueryHistory.renameItem": this.handleRenameItem.bind(this), + "codeQLQueryHistory.compareWith": this.handleCompareWith.bind(this), + "codeQLQueryHistory.showEvalLog": this.handleShowEvalLog.bind(this), + "codeQLQueryHistory.showEvalLogSummary": + this.handleShowEvalLogSummary.bind(this), + "codeQLQueryHistory.showEvalLogViewer": + this.handleShowEvalLogViewer.bind(this), + "codeQLQueryHistory.showQueryLog": this.handleShowQueryLog.bind(this), + "codeQLQueryHistory.showQueryText": this.handleShowQueryText.bind(this), + "codeQLQueryHistory.openQueryDirectory": + this.handleOpenQueryDirectory.bind(this), + "codeQLQueryHistory.cancel": this.handleCancel.bind(this), + "codeQLQueryHistory.exportResults": this.handleExportResults.bind(this), + "codeQLQueryHistory.viewCsvResults": this.handleViewCsvResults.bind(this), + "codeQLQueryHistory.viewCsvAlerts": this.handleViewCsvAlerts.bind(this), + "codeQLQueryHistory.viewSarifAlerts": + this.handleViewSarifAlerts.bind(this), + "codeQLQueryHistory.viewDil": this.handleViewDil.bind(this), + "codeQLQueryHistory.itemClicked": this.handleItemClicked.bind(this), + "codeQLQueryHistory.openOnGithub": this.handleOpenOnGithub.bind(this), + "codeQLQueryHistory.copyRepoList": this.handleCopyRepoList.bind(this), + }; + } + public completeQuery(info: LocalQueryInfo, results: QueryWithResults): void { info.completeThisQuery(results); this._onDidCompleteQuery.fire(info); From 5be08d7c92e89592451c566fa23ea49a1dd449a9 Mon Sep 17 00:00:00 2001 From: Koen Vlaswinkel Date: Fri, 17 Mar 2023 12:29:25 +0100 Subject: [PATCH 058/156] Revert change to context menu name --- extensions/ql-vscode/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/extensions/ql-vscode/package.json b/extensions/ql-vscode/package.json index 9d3afca17..f35d28e36 100644 --- a/extensions/ql-vscode/package.json +++ b/extensions/ql-vscode/package.json @@ -644,7 +644,7 @@ }, { "command": "codeQLQueryHistory.openOnGithub", - "title": "Open on GitHub" + "title": "View Logs" }, { "command": "codeQLQueryHistory.copyRepoList", From 7914403da02df397d2226807731754f8fa995b27 Mon Sep 17 00:00:00 2001 From: Charis Kyriakou Date: Fri, 17 Mar 2023 13:30:32 +0000 Subject: [PATCH 059/156] Wire up data flow paths view (#2182) --- extensions/ql-vscode/CHANGELOG.md | 2 + .../ql-vscode/src/pure/interface-types.ts | 8 +- .../src/stories/common/CodePaths.stories.tsx | 9 +- .../data-flow-paths/DataFlowPaths.stories.tsx | 19 ++ .../variant-analysis/variant-analysis-view.ts | 12 + .../src/view/common/CodePaths/CodePaths.tsx | 49 ++--- .../common/CodePaths/CodePathsOverlay.tsx | 112 ---------- .../CodePaths/__tests__/CodePaths.spec.tsx | 17 +- .../view/data-flow-paths/DataFlowPaths.tsx | 71 ++++++ .../data-flow-paths/DataFlowPathsView.tsx | 23 +- .../__tests__/DataFlowPaths.spec.tsx | 31 +++ .../__tests__/DataFlowPathsView.spec.tsx | 11 +- .../shared/data-flow-paths.ts | 208 ++++++++++-------- 13 files changed, 299 insertions(+), 273 deletions(-) create mode 100644 extensions/ql-vscode/src/stories/data-flow-paths/DataFlowPaths.stories.tsx delete mode 100644 extensions/ql-vscode/src/view/common/CodePaths/CodePathsOverlay.tsx create mode 100644 extensions/ql-vscode/src/view/data-flow-paths/DataFlowPaths.tsx create mode 100644 extensions/ql-vscode/src/view/data-flow-paths/__tests__/DataFlowPaths.spec.tsx diff --git a/extensions/ql-vscode/CHANGELOG.md b/extensions/ql-vscode/CHANGELOG.md index 83c4cd4c8..385bf6f25 100644 --- a/extensions/ql-vscode/CHANGELOG.md +++ b/extensions/ql-vscode/CHANGELOG.md @@ -2,6 +2,8 @@ ## [UNRELEASED] +- Show data flow paths of a variant analysis in a new tab + ## 1.8.0 - 9 March 2023 - Send telemetry about unhandled errors happening within the extension. [#2125](https://github.com/github/vscode-codeql/pull/2125) diff --git a/extensions/ql-vscode/src/pure/interface-types.ts b/extensions/ql-vscode/src/pure/interface-types.ts index aa0ff600c..2d68b39d2 100644 --- a/extensions/ql-vscode/src/pure/interface-types.ts +++ b/extensions/ql-vscode/src/pure/interface-types.ts @@ -449,6 +449,11 @@ export interface CancelVariantAnalysisMessage { t: "cancelVariantAnalysis"; } +export interface ShowDataFlowPathsMessage { + t: "showDataFlowPaths"; + dataFlowPaths: DataFlowPaths; +} + export type ToVariantAnalysisMessage = | SetVariantAnalysisMessage | SetRepoResultsMessage @@ -462,7 +467,8 @@ export type FromVariantAnalysisMessage = | CopyRepositoryListMessage | ExportResultsMessage | OpenLogsMessage - | CancelVariantAnalysisMessage; + | CancelVariantAnalysisMessage + | ShowDataFlowPathsMessage; export interface SetDataFlowPathsMessage { t: "setDataFlowPaths"; diff --git a/extensions/ql-vscode/src/stories/common/CodePaths.stories.tsx b/extensions/ql-vscode/src/stories/common/CodePaths.stories.tsx index 5b68f1c2d..793c66099 100644 --- a/extensions/ql-vscode/src/stories/common/CodePaths.stories.tsx +++ b/extensions/ql-vscode/src/stories/common/CodePaths.stories.tsx @@ -1,7 +1,6 @@ import * as React from "react"; import { ComponentStory, ComponentMeta } from "@storybook/react"; -import { ThemeProvider } from "@primer/react"; import { CodePaths } from "../../view/common"; import type { CodeFlow } from "../../variant-analysis/shared/analysis-result"; @@ -9,13 +8,7 @@ import type { CodeFlow } from "../../variant-analysis/shared/analysis-result"; export default { title: "Code Paths", component: CodePaths, - decorators: [ - (Story) => ( - - - - ), - ], + decorators: [(Story) => ], } as ComponentMeta; const Template: ComponentStory = (args) => ( diff --git a/extensions/ql-vscode/src/stories/data-flow-paths/DataFlowPaths.stories.tsx b/extensions/ql-vscode/src/stories/data-flow-paths/DataFlowPaths.stories.tsx new file mode 100644 index 000000000..dd1598360 --- /dev/null +++ b/extensions/ql-vscode/src/stories/data-flow-paths/DataFlowPaths.stories.tsx @@ -0,0 +1,19 @@ +import * as React from "react"; + +import { ComponentMeta, ComponentStory } from "@storybook/react"; + +import { DataFlowPaths as DataFlowPathsComponent } from "../../view/data-flow-paths/DataFlowPaths"; +import { createMockDataFlowPaths } from "../../../test/factories/variant-analysis/shared/data-flow-paths"; +export default { + title: "Data Flow Paths/Data Flow Paths", + component: DataFlowPathsComponent, +} as ComponentMeta; + +const Template: ComponentStory = (args) => ( + +); + +export const PowerShell = Template.bind({}); +PowerShell.args = { + dataFlowPaths: createMockDataFlowPaths(), +}; diff --git a/extensions/ql-vscode/src/variant-analysis/variant-analysis-view.ts b/extensions/ql-vscode/src/variant-analysis/variant-analysis-view.ts index 351e5afbf..c46860fa6 100644 --- a/extensions/ql-vscode/src/variant-analysis/variant-analysis-view.ts +++ b/extensions/ql-vscode/src/variant-analysis/variant-analysis-view.ts @@ -21,12 +21,15 @@ import { } from "../helpers"; import { telemetryListener } from "../telemetry"; import { redactableError } from "../pure/errors"; +import { DataFlowPathsView } from "./data-flow-paths-view"; +import { DataFlowPaths } from "./shared/data-flow-paths"; export class VariantAnalysisView extends AbstractWebview implements VariantAnalysisViewInterface { public static readonly viewType = "codeQL.variantAnalysis"; + private readonly dataFlowPathsView: DataFlowPathsView; public constructor( ctx: ExtensionContext, @@ -36,6 +39,8 @@ export class VariantAnalysisView super(ctx); manager.registerView(this); + + this.dataFlowPathsView = new DataFlowPathsView(ctx); } public async openView() { @@ -151,6 +156,9 @@ export class VariantAnalysisView this.variantAnalysisId, ); break; + case "showDataFlowPaths": + await this.showDataFlows(msg.dataFlowPaths); + break; case "telemetry": telemetryListener?.sendUIInteraction(msg.action); break; @@ -201,4 +209,8 @@ export class VariantAnalysisView ? `${variantAnalysis.query.name} - Variant Analysis Results` : `Variant Analysis ${this.variantAnalysisId} - Results`; } + + private async showDataFlows(dataFlows: DataFlowPaths): Promise { + await this.dataFlowPathsView.showDataFlows(dataFlows); + } } diff --git a/extensions/ql-vscode/src/view/common/CodePaths/CodePaths.tsx b/extensions/ql-vscode/src/view/common/CodePaths/CodePaths.tsx index 90bd3b44e..e7bb09f5b 100644 --- a/extensions/ql-vscode/src/view/common/CodePaths/CodePaths.tsx +++ b/extensions/ql-vscode/src/view/common/CodePaths/CodePaths.tsx @@ -1,17 +1,13 @@ import * as React from "react"; -import { useRef, useState } from "react"; import styled from "styled-components"; import { VSCodeLink } from "@vscode/webview-ui-toolkit/react"; -import { Overlay, ThemeProvider } from "@primer/react"; - import { AnalysisMessage, CodeFlow, ResultSeverity, } from "../../../variant-analysis/shared/analysis-result"; -import { CodePathsOverlay } from "./CodePathsOverlay"; -import { useTelemetryOnChange } from "../telemetry"; +import { vscode } from "../../vscode-api"; const ShowPathsLink = styled(VSCodeLink)` cursor: pointer; @@ -24,46 +20,27 @@ export type CodePathsProps = { severity: ResultSeverity; }; -const filterIsOpenTelemetry = (v: boolean) => v; - export const CodePaths = ({ codeFlows, ruleDescription, message, severity, }: CodePathsProps) => { - const [isOpen, setIsOpen] = useState(false); - useTelemetryOnChange(isOpen, "code-path-is-open", { - filterTelemetryOnValue: filterIsOpenTelemetry, - }); - - const linkRef = useRef(null); - - const closeOverlay = () => setIsOpen(false); + const onShowPathsClick = () => { + vscode.postMessage({ + t: "showDataFlowPaths", + dataFlowPaths: { + codeFlows, + ruleDescription, + message, + severity, + }, + }); + }; return ( <> - setIsOpen(true)} ref={linkRef}> - Show paths - - {isOpen && ( - - - - - - )} + Show paths ); }; diff --git a/extensions/ql-vscode/src/view/common/CodePaths/CodePathsOverlay.tsx b/extensions/ql-vscode/src/view/common/CodePaths/CodePathsOverlay.tsx deleted file mode 100644 index 7ba11898a..000000000 --- a/extensions/ql-vscode/src/view/common/CodePaths/CodePathsOverlay.tsx +++ /dev/null @@ -1,112 +0,0 @@ -import * as React from "react"; -import { useState } from "react"; -import styled from "styled-components"; - -import { - AnalysisMessage, - CodeFlow, - ResultSeverity, -} from "../../../variant-analysis/shared/analysis-result"; -import { useTelemetryOnChange } from "../telemetry"; -import { SectionTitle } from "../SectionTitle"; -import { VerticalSpace } from "../VerticalSpace"; -import { CodeFlowsDropdown } from "./CodeFlowsDropdown"; -import { CodePath } from "./CodePath"; - -const StyledCloseButton = styled.button` - position: absolute; - top: 1em; - right: 4em; - background-color: var(--vscode-editor-background); - color: var(--vscode-editor-foreground); - border: none; - cursor: pointer; - - &:focus-visible { - outline: none; - } -`; - -const OverlayContainer = styled.div` - height: 100%; - width: 100%; - padding: 2em; - position: fixed; - top: 0; - left: 0; - background-color: var(--vscode-editor-background); - color: var(--vscode-editor-foreground); - overflow-y: scroll; -`; - -const CloseButton = ({ onClick }: { onClick: () => void }) => ( - - - -); - -const PathsContainer = styled.div` - display: flex; - justify-content: center; - align-items: center; -`; - -const PathDetailsContainer = styled.div` - padding: 0; - border: 0; -`; - -const PathDropdownContainer = styled.div` - flex-grow: 1; - padding: 0 0 0 0.2em; - border: none; -`; - -type CodePathsOverlayProps = { - codeFlows: CodeFlow[]; - ruleDescription: string; - message: AnalysisMessage; - severity: ResultSeverity; - onClose: () => void; -}; - -export const CodePathsOverlay = ({ - codeFlows, - ruleDescription, - message, - severity, - onClose, -}: CodePathsOverlayProps) => { - const [selectedCodeFlow, setSelectedCodeFlow] = useState(codeFlows[0]); - useTelemetryOnChange(selectedCodeFlow, "code-flow-selected"); - - return ( - - - - {ruleDescription} - - - - - {codeFlows.length} paths available:{" "} - {selectedCodeFlow.threadFlows.length} steps in - - - - - - - - - - - ); -}; diff --git a/extensions/ql-vscode/src/view/common/CodePaths/__tests__/CodePaths.spec.tsx b/extensions/ql-vscode/src/view/common/CodePaths/__tests__/CodePaths.spec.tsx index a45ed417b..1ff6135e1 100644 --- a/extensions/ql-vscode/src/view/common/CodePaths/__tests__/CodePaths.spec.tsx +++ b/extensions/ql-vscode/src/view/common/CodePaths/__tests__/CodePaths.spec.tsx @@ -18,20 +18,25 @@ describe(CodePaths.name, () => { />, ); - it("renders correctly when unexpanded", () => { + it("renders 'show paths' link", () => { render(); expect(screen.getByText("Show paths")).toBeInTheDocument(); - expect(screen.queryByText("Code snippet text")).not.toBeInTheDocument(); - expect(screen.queryByText("Rule description")).not.toBeInTheDocument(); }); - it("renders correctly when expanded", async () => { + it("posts extension message when 'show paths' link clicked", async () => { render(); await userEvent.click(screen.getByText("Show paths")); - expect(screen.getByText("Code snippet text")).toBeInTheDocument(); - expect(screen.getByText("Rule description")).toBeInTheDocument(); + expect((window as any).vsCodeApi.postMessage).toHaveBeenCalledWith({ + t: "showDataFlowPaths", + dataFlowPaths: { + codeFlows: createMockCodeFlows(), + ruleDescription: "Rule description", + message: createMockAnalysisMessage(), + severity: "Recommendation", + }, + }); }); }); diff --git a/extensions/ql-vscode/src/view/data-flow-paths/DataFlowPaths.tsx b/extensions/ql-vscode/src/view/data-flow-paths/DataFlowPaths.tsx new file mode 100644 index 000000000..7bccc0bed --- /dev/null +++ b/extensions/ql-vscode/src/view/data-flow-paths/DataFlowPaths.tsx @@ -0,0 +1,71 @@ +import * as React from "react"; +import styled from "styled-components"; +import { useState } from "react"; + +import { useTelemetryOnChange } from "../common/telemetry"; +import { CodeFlowsDropdown } from "../common/CodePaths/CodeFlowsDropdown"; +import { SectionTitle, VerticalSpace } from "../common"; +import { CodePath } from "../common/CodePaths/CodePath"; +import { DataFlowPaths as DataFlowPathsDomainModel } from "../../variant-analysis/shared/data-flow-paths"; + +const PathsContainer = styled.div` + display: flex; + justify-content: center; + align-items: center; +`; + +const PathDetailsContainer = styled.div` + padding: 0; + border: 0; +`; + +const PathDropdownContainer = styled.div` + flex-grow: 1; + padding: 0 0 0 0.2em; + border: none; +`; + +export type DataFlowPathsProps = { + dataFlowPaths: DataFlowPathsDomainModel; +}; + +export const DataFlowPaths = ({ + dataFlowPaths, +}: { + dataFlowPaths: DataFlowPathsDomainModel; +}): JSX.Element => { + const [selectedCodeFlow, setSelectedCodeFlow] = useState( + dataFlowPaths.codeFlows[0], + ); + useTelemetryOnChange(selectedCodeFlow, "code-flow-selected"); + + const { codeFlows, ruleDescription, message, severity } = dataFlowPaths; + + return ( + <> + + {ruleDescription} + + + + + {codeFlows.length} paths available:{" "} + {selectedCodeFlow?.threadFlows.length} steps in + + + + + + + + + + ); +}; diff --git a/extensions/ql-vscode/src/view/data-flow-paths/DataFlowPathsView.tsx b/extensions/ql-vscode/src/view/data-flow-paths/DataFlowPathsView.tsx index e4c6960fd..de3d490a7 100644 --- a/extensions/ql-vscode/src/view/data-flow-paths/DataFlowPathsView.tsx +++ b/extensions/ql-vscode/src/view/data-flow-paths/DataFlowPathsView.tsx @@ -1,18 +1,19 @@ import * as React from "react"; import { useEffect, useState } from "react"; import { ToDataFlowPathsMessage } from "../../pure/interface-types"; -import { DataFlowPaths } from "../../variant-analysis/shared/data-flow-paths"; +import { DataFlowPaths as DataFlowPathsDomainModel } from "../../variant-analysis/shared/data-flow-paths"; +import { DataFlowPaths } from "./DataFlowPaths"; export type DataFlowPathsViewProps = { - dataFlowPaths?: DataFlowPaths; + dataFlowPaths?: DataFlowPathsDomainModel; }; export function DataFlowPathsView({ dataFlowPaths: initialDataFlowPaths, }: DataFlowPathsViewProps): JSX.Element { - const [dataFlowPaths, setDataFlowPaths] = useState( - initialDataFlowPaths, - ); + const [dataFlowPaths, setDataFlowPaths] = useState< + DataFlowPathsDomainModel | undefined + >(initialDataFlowPaths); useEffect(() => { const listener = (evt: MessageEvent) => { @@ -20,6 +21,10 @@ export function DataFlowPathsView({ const msg: ToDataFlowPathsMessage = evt.data; if (msg.t === "setDataFlowPaths") { setDataFlowPaths(msg.dataFlowPaths); + + // Scroll to the top of the page when we're rendering + // new data flow paths. + window.scrollTo(0, 0); } } else { // sanitize origin @@ -38,11 +43,5 @@ export function DataFlowPathsView({ return <>Loading data flow paths; } - // For now, just render the data flows as JSON. - return ( - <> - Loaded -
{JSON.stringify(dataFlowPaths)}
- - ); + return ; } diff --git a/extensions/ql-vscode/src/view/data-flow-paths/__tests__/DataFlowPaths.spec.tsx b/extensions/ql-vscode/src/view/data-flow-paths/__tests__/DataFlowPaths.spec.tsx new file mode 100644 index 000000000..02efd2105 --- /dev/null +++ b/extensions/ql-vscode/src/view/data-flow-paths/__tests__/DataFlowPaths.spec.tsx @@ -0,0 +1,31 @@ +import * as React from "react"; +import { render as reactRender, screen } from "@testing-library/react"; +import { DataFlowPaths, DataFlowPathsProps } from "../DataFlowPaths"; +import { createMockDataFlowPaths } from "../../../../test/factories/variant-analysis/shared/data-flow-paths"; + +describe(DataFlowPaths.name, () => { + const render = (props: DataFlowPathsProps) => + reactRender(); + + it("renders data flow paths", () => { + const dataFlowPaths = createMockDataFlowPaths(); + + render({ dataFlowPaths }); + + expect(screen.getByText(dataFlowPaths.ruleDescription)).toBeInTheDocument(); + expect( + screen.getByText("1 paths available", { exact: false }), + ).toBeInTheDocument(); + expect( + screen.getByText("3 steps in", { + exact: false, + }), + ).toBeInTheDocument(); + + expect( + screen.getByText("This zip file may have a dangerous path", { + exact: false, + }), + ).toBeInTheDocument(); + }); +}); diff --git a/extensions/ql-vscode/src/view/data-flow-paths/__tests__/DataFlowPathsView.spec.tsx b/extensions/ql-vscode/src/view/data-flow-paths/__tests__/DataFlowPathsView.spec.tsx index da11f818f..7baefc06c 100644 --- a/extensions/ql-vscode/src/view/data-flow-paths/__tests__/DataFlowPathsView.spec.tsx +++ b/extensions/ql-vscode/src/view/data-flow-paths/__tests__/DataFlowPathsView.spec.tsx @@ -4,6 +4,7 @@ import { DataFlowPathsView, DataFlowPathsViewProps, } from "../DataFlowPathsView"; +import { createMockCodeFlows } from "../../../../test/factories/variant-analysis/shared/CodeFlow"; import { createMockDataFlowPaths } from "../../../../test/factories/variant-analysis/shared/data-flow-paths"; describe(DataFlowPathsView.name, () => { @@ -17,8 +18,14 @@ describe(DataFlowPathsView.name, () => { }); it("renders a data flow paths view", () => { - render({ dataFlowPaths: createMockDataFlowPaths() }); + const dataFlowPaths = createMockDataFlowPaths({ + ruleDescription: "Rule description", + codeFlows: createMockCodeFlows(), + }); - expect(screen.getByText("Loaded")).toBeInTheDocument(); + render({ dataFlowPaths }); + + expect(screen.queryByText("Code snippet text")).toBeInTheDocument(); + expect(screen.getByText("Rule description")).toBeInTheDocument(); }); }); diff --git a/extensions/ql-vscode/test/factories/variant-analysis/shared/data-flow-paths.ts b/extensions/ql-vscode/test/factories/variant-analysis/shared/data-flow-paths.ts index 189924211..9f0ae98ac 100644 --- a/extensions/ql-vscode/test/factories/variant-analysis/shared/data-flow-paths.ts +++ b/extensions/ql-vscode/test/factories/variant-analysis/shared/data-flow-paths.ts @@ -1,106 +1,122 @@ -import { CodeFlow } from "../../../../src/variant-analysis/shared/analysis-result"; +import { + AnalysisMessage, + CodeFlow, + ResultSeverity, +} from "../../../../src/variant-analysis/shared/analysis-result"; import { DataFlowPaths } from "../../../../src/variant-analysis/shared/data-flow-paths"; -export function createMockDataFlowPaths(): DataFlowPaths { - const codeFlows: CodeFlow[] = [ - { - threadFlows: [ - { - fileLink: { - fileLinkPrefix: - "https://github.com/PowerShell/PowerShell/blob/450d884668ca477c6581ce597958f021fac30bff", - filePath: - "src/System.Management.Automation/help/UpdatableHelpSystem.cs", - }, - codeSnippet: { - startLine: 1260, - endLine: 1260, - text: " string extractPath = Path.Combine(destination, entry.FullName);", - }, - highlightedRegion: { - startLine: 1260, - startColumn: 72, - endLine: 1260, - endColumn: 86, - }, - message: { - tokens: [ - { - t: "text", - text: "access to property FullName : String", - }, - ], - }, +const defaultCodeFlows: CodeFlow[] = [ + { + threadFlows: [ + { + fileLink: { + fileLinkPrefix: + "https://github.com/PowerShell/PowerShell/blob/450d884668ca477c6581ce597958f021fac30bff", + filePath: + "src/System.Management.Automation/help/UpdatableHelpSystem.cs", }, - { - fileLink: { - fileLinkPrefix: - "https://github.com/PowerShell/PowerShell/blob/450d884668ca477c6581ce597958f021fac30bff", - filePath: - "src/System.Management.Automation/help/UpdatableHelpSystem.cs", - }, - codeSnippet: { - startLine: 1260, - endLine: 1260, - text: " string extractPath = Path.Combine(destination, entry.FullName);", - }, - highlightedRegion: { - startLine: 1260, - startColumn: 46, - endLine: 1260, - endColumn: 87, - }, - message: { - tokens: [ - { - t: "text", - text: "call to method Combine : String", - }, - ], - }, + codeSnippet: { + startLine: 1260, + endLine: 1260, + text: " string extractPath = Path.Combine(destination, entry.FullName);", }, - { - fileLink: { - fileLinkPrefix: - "https://github.com/PowerShell/PowerShell/blob/450d884668ca477c6581ce597958f021fac30bff", - filePath: - "src/System.Management.Automation/help/UpdatableHelpSystem.cs", - }, - codeSnippet: { - startLine: 1261, - endLine: 1261, - text: " entry.ExtractToFile(extractPath);", - }, - highlightedRegion: { - startLine: 1261, - startColumn: 45, - endLine: 1261, - endColumn: 56, - }, - message: { - tokens: [ - { - t: "text", - text: "access to local variable extractPath", - }, - ], - }, + highlightedRegion: { + startLine: 1260, + startColumn: 72, + endLine: 1260, + endColumn: 86, }, - ], - }, - ]; + message: { + tokens: [ + { + t: "text", + text: "access to property FullName : String", + }, + ], + }, + }, + { + fileLink: { + fileLinkPrefix: + "https://github.com/PowerShell/PowerShell/blob/450d884668ca477c6581ce597958f021fac30bff", + filePath: + "src/System.Management.Automation/help/UpdatableHelpSystem.cs", + }, + codeSnippet: { + startLine: 1260, + endLine: 1260, + text: " string extractPath = Path.Combine(destination, entry.FullName);", + }, + highlightedRegion: { + startLine: 1260, + startColumn: 46, + endLine: 1260, + endColumn: 87, + }, + message: { + tokens: [ + { + t: "text", + text: "call to method Combine : String", + }, + ], + }, + }, + { + fileLink: { + fileLinkPrefix: + "https://github.com/PowerShell/PowerShell/blob/450d884668ca477c6581ce597958f021fac30bff", + filePath: + "src/System.Management.Automation/help/UpdatableHelpSystem.cs", + }, + codeSnippet: { + startLine: 1261, + endLine: 1261, + text: " entry.ExtractToFile(extractPath);", + }, + highlightedRegion: { + startLine: 1261, + startColumn: 45, + endLine: 1261, + endColumn: 56, + }, + message: { + tokens: [ + { + t: "text", + text: "access to local variable extractPath", + }, + ], + }, + }, + ], + }, +]; +const defaultMessage: AnalysisMessage = { + tokens: [ + { + t: "text", + text: "This zip file may have a dangerous path", + }, + ], +}; + +export function createMockDataFlowPaths({ + codeFlows = defaultCodeFlows, + ruleDescription = "ZipSlip vulnerability", + message = defaultMessage, + severity = "Warning", +}: { + codeFlows?: CodeFlow[]; + ruleDescription?: string; + message?: AnalysisMessage; + severity?: ResultSeverity; +} = {}): DataFlowPaths { return { codeFlows, - ruleDescription: "ZipSlip vulnerability", - message: { - tokens: [ - { - t: "text", - text: "This zip file may have a dangerous path", - }, - ], - }, - severity: "Warning", + ruleDescription, + message, + severity, }; } From 50e89ba1a38c09efdb4d3c9ab330fd0f4ba91571 Mon Sep 17 00:00:00 2001 From: Charis Kyriakou Date: Fri, 17 Mar 2023 13:46:43 +0000 Subject: [PATCH 060/156] Remove primer packages --- CONTRIBUTING.md | 2 +- extensions/ql-vscode/package-lock.json | 581 +------------------------ extensions/ql-vscode/package.json | 2 - 3 files changed, 24 insertions(+), 561 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 8719e252a..01d89b1e4 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -2,7 +2,7 @@ [fork]: https://github.com/github/vscode-codeql/fork [pr]: https://github.com/github/vscode-codeql/compare -[style]: https://primer.style +[style]: https://github.com/microsoft/vscode-webview-ui-toolkit [code-of-conduct]: CODE_OF_CONDUCT.md Hi there! We're thrilled that you'd like to contribute to this project. Your help is essential for keeping it great. diff --git a/extensions/ql-vscode/package-lock.json b/extensions/ql-vscode/package-lock.json index a911f2b45..afeef5346 100644 --- a/extensions/ql-vscode/package-lock.json +++ b/extensions/ql-vscode/package-lock.json @@ -12,8 +12,6 @@ "dependencies": { "@octokit/plugin-retry": "^3.0.9", "@octokit/rest": "^19.0.4", - "@primer/octicons-react": "^17.6.0", - "@primer/react": "^35.0.0", "@vscode/codicons": "^0.0.31", "@vscode/webview-ui-toolkit": "^1.0.1", "ajv": "^8.11.0", @@ -2255,6 +2253,7 @@ "version": "7.18.9", "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.18.9.tgz", "integrity": "sha512-lkqXDcvlFT5rvEjiu6+QYO+1GXrEHRo2LOtS7E4GtX5ESIZOgepqsZBVIj6Pv+a6zqsya9VCgiK1KAK4BvJDAw==", + "dev": true, "dependencies": { "regenerator-runtime": "^0.13.4" }, @@ -5976,96 +5975,6 @@ "url": "https://opencollective.com/webpack" } }, - "node_modules/@primer/behaviors": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@primer/behaviors/-/behaviors-1.1.0.tgz", - "integrity": "sha512-Ej2OUc3ZIFaR7WwIUqESO1DTzmpb7wc8xbTVRT9s52jZQDjN7g5iljoK3ocYZm+BIAcKn3MvcwB42hEk4Ga4xQ==" - }, - "node_modules/@primer/octicons-react": { - "version": "17.6.0", - "resolved": "https://registry.npmjs.org/@primer/octicons-react/-/octicons-react-17.6.0.tgz", - "integrity": "sha512-jn1fWag3eU6BvOltMS2MqLPNh39D45cpegsTO2Qhb8SlJoUsj/ZO1qbJgYd9ibvZo8evDyXx3syh4kDbxJQFsg==", - "engines": { - "node": ">=8" - }, - "peerDependencies": { - "react": ">=15" - } - }, - "node_modules/@primer/primitives": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/@primer/primitives/-/primitives-7.1.1.tgz", - "integrity": "sha512-+Gwo89YK1OFi6oubTlah/zPxxzMNaMLy+inECAYI646KIFdzzhAsKWb3z5tSOu5Ff7no4isRV64rWfMSKLZclw==" - }, - "node_modules/@primer/react": { - "version": "35.0.0", - "resolved": "https://registry.npmjs.org/@primer/react/-/react-35.0.0.tgz", - "integrity": "sha512-pjraRDHoT6Lwmto31ZN+WrtNCDA6lieOhr+4XC1z8wuq/JSGJVB3gHePi2/yIZldy2WoK55O1lsyp8llUiakog==", - "dependencies": { - "@primer/behaviors": "1.1.0", - "@primer/octicons-react": "16.1.1", - "@primer/primitives": "7.1.1", - "@radix-ui/react-polymorphic": "0.0.14", - "@react-aria/ssr": "3.1.0", - "@styled-system/css": "5.1.5", - "@styled-system/props": "5.1.5", - "@styled-system/theme-get": "5.1.2", - "@types/styled-components": "5.1.11", - "@types/styled-system": "5.1.12", - "@types/styled-system__css": "5.0.16", - "@types/styled-system__theme-get": "5.0.1", - "classnames": "2.3.1", - "color2k": "1.2.4", - "deepmerge": "4.2.2", - "focus-visible": "5.2.0", - "history": "5.0.0", - "styled-system": "5.1.5" - }, - "engines": { - "node": ">=12", - "npm": ">=7" - }, - "peerDependencies": { - "react": "^17.0.0", - "react-dom": "^17.0.0", - "styled-components": "4.x || 5.x" - } - }, - "node_modules/@primer/react/node_modules/@primer/octicons-react": { - "version": "16.1.1", - "resolved": "https://registry.npmjs.org/@primer/octicons-react/-/octicons-react-16.1.1.tgz", - "integrity": "sha512-xCxQ5z23ol7yDuJs85Lc4ARzyoay+b3zOhAKkEMU7chk0xi2hT2OnRP23QUudNNDPTGozX268RGYLexUa6P4xw==", - "engines": { - "node": ">=8" - }, - "peerDependencies": { - "react": ">=15" - } - }, - "node_modules/@primer/react/node_modules/classnames": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/classnames/-/classnames-2.3.1.tgz", - "integrity": "sha512-OlQdbZ7gLfGarSqxesMesDa5uz7KFbID8Kpq/SxIoNGDqY8lSYs0D+hhtBXhcdB3rcbXArFr7vlHheLk1voeNA==" - }, - "node_modules/@radix-ui/react-polymorphic": { - "version": "0.0.14", - "resolved": "https://registry.npmjs.org/@radix-ui/react-polymorphic/-/react-polymorphic-0.0.14.tgz", - "integrity": "sha512-9nsMZEDU3LeIUeHJrpkkhZVxu/9Fc7P2g2I3WR+uA9mTbNC3hGaabi0dV6wg0CfHb+m4nSs1pejbE/5no3MJTA==", - "peerDependencies": { - "react": "^16.8 || ^17.0" - } - }, - "node_modules/@react-aria/ssr": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/@react-aria/ssr/-/ssr-3.1.0.tgz", - "integrity": "sha512-RxqQKmE8sO7TGdrcSlHTcVzMP450hqowtBSd2bBS9oPlcokVkaGq28c3Rwa8ty5ctw4EBCjXqjP7xdcKMGDzug==", - "dependencies": { - "@babel/runtime": "^7.6.2" - }, - "peerDependencies": { - "react": "^16.8.0 || ^17.0.0-rc.1" - } - }, "node_modules/@sinclair/typebox": { "version": "0.24.41", "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.24.41.tgz", @@ -12536,124 +12445,6 @@ "node": ">=8" } }, - "node_modules/@styled-system/background": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/@styled-system/background/-/background-5.1.2.tgz", - "integrity": "sha512-jtwH2C/U6ssuGSvwTN3ri/IyjdHb8W9X/g8Y0JLcrH02G+BW3OS8kZdHphF1/YyRklnrKrBT2ngwGUK6aqqV3A==", - "dependencies": { - "@styled-system/core": "^5.1.2" - } - }, - "node_modules/@styled-system/border": { - "version": "5.1.5", - "resolved": "https://registry.npmjs.org/@styled-system/border/-/border-5.1.5.tgz", - "integrity": "sha512-JvddhNrnhGigtzWRCVuAHepniyVi6hBlimxWDVAdcTuk7aRn9BYJUwfHslURtwYFsF5FoEs8Zmr1oZq2M1AP0A==", - "dependencies": { - "@styled-system/core": "^5.1.2" - } - }, - "node_modules/@styled-system/color": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/@styled-system/color/-/color-5.1.2.tgz", - "integrity": "sha512-1kCkeKDZkt4GYkuFNKc7vJQMcOmTl3bJY3YBUs7fCNM6mMYJeT1pViQ2LwBSBJytj3AB0o4IdLBoepgSgGl5MA==", - "dependencies": { - "@styled-system/core": "^5.1.2" - } - }, - "node_modules/@styled-system/core": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/@styled-system/core/-/core-5.1.2.tgz", - "integrity": "sha512-XclBDdNIy7OPOsN4HBsawG2eiWfCcuFt6gxKn1x4QfMIgeO6TOlA2pZZ5GWZtIhCUqEPTgIBta6JXsGyCkLBYw==", - "dependencies": { - "object-assign": "^4.1.1" - } - }, - "node_modules/@styled-system/css": { - "version": "5.1.5", - "resolved": "https://registry.npmjs.org/@styled-system/css/-/css-5.1.5.tgz", - "integrity": "sha512-XkORZdS5kypzcBotAMPBoeckDs9aSZVkvrAlq5K3xP8IMAUek+x2O4NtwoSgkYkWWzVBu6DGdFZLR790QWGG+A==" - }, - "node_modules/@styled-system/flexbox": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/@styled-system/flexbox/-/flexbox-5.1.2.tgz", - "integrity": "sha512-6hHV52+eUk654Y1J2v77B8iLeBNtc+SA3R4necsu2VVinSD7+XY5PCCEzBFaWs42dtOEDIa2lMrgL0YBC01mDQ==", - "dependencies": { - "@styled-system/core": "^5.1.2" - } - }, - "node_modules/@styled-system/grid": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/@styled-system/grid/-/grid-5.1.2.tgz", - "integrity": "sha512-K3YiV1KyHHzgdNuNlaw8oW2ktMuGga99o1e/NAfTEi5Zsa7JXxzwEnVSDSBdJC+z6R8WYTCYRQC6bkVFcvdTeg==", - "dependencies": { - "@styled-system/core": "^5.1.2" - } - }, - "node_modules/@styled-system/layout": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/@styled-system/layout/-/layout-5.1.2.tgz", - "integrity": "sha512-wUhkMBqSeacPFhoE9S6UF3fsMEKFv91gF4AdDWp0Aym1yeMPpqz9l9qS/6vjSsDPF7zOb5cOKC3tcKKOMuDCPw==", - "dependencies": { - "@styled-system/core": "^5.1.2" - } - }, - "node_modules/@styled-system/position": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/@styled-system/position/-/position-5.1.2.tgz", - "integrity": "sha512-60IZfMXEOOZe3l1mCu6sj/2NAyUmES2kR9Kzp7s2D3P4qKsZWxD1Se1+wJvevb+1TP+ZMkGPEYYXRyU8M1aF5A==", - "dependencies": { - "@styled-system/core": "^5.1.2" - } - }, - "node_modules/@styled-system/props": { - "version": "5.1.5", - "resolved": "https://registry.npmjs.org/@styled-system/props/-/props-5.1.5.tgz", - "integrity": "sha512-FXhbzq2KueZpGaHxaDm8dowIEWqIMcgsKs6tBl6Y6S0njG9vC8dBMI6WSLDnzMoSqIX3nSKHmOmpzpoihdDewg==", - "dependencies": { - "styled-system": "^5.1.5" - } - }, - "node_modules/@styled-system/shadow": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/@styled-system/shadow/-/shadow-5.1.2.tgz", - "integrity": "sha512-wqniqYb7XuZM7K7C0d1Euxc4eGtqEe/lvM0WjuAFsQVImiq6KGT7s7is+0bNI8O4Dwg27jyu4Lfqo/oIQXNzAg==", - "dependencies": { - "@styled-system/core": "^5.1.2" - } - }, - "node_modules/@styled-system/space": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/@styled-system/space/-/space-5.1.2.tgz", - "integrity": "sha512-+zzYpR8uvfhcAbaPXhH8QgDAV//flxqxSjHiS9cDFQQUSznXMQmxJegbhcdEF7/eNnJgHeIXv1jmny78kipgBA==", - "dependencies": { - "@styled-system/core": "^5.1.2" - } - }, - "node_modules/@styled-system/theme-get": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/@styled-system/theme-get/-/theme-get-5.1.2.tgz", - "integrity": "sha512-afAYdRqrKfNIbVgmn/2Qet1HabxmpRnzhFwttbGr6F/mJ4RDS/Cmn+KHwHvNXangQsWw/5TfjpWV+rgcqqIcJQ==", - "dependencies": { - "@styled-system/core": "^5.1.2" - } - }, - "node_modules/@styled-system/typography": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/@styled-system/typography/-/typography-5.1.2.tgz", - "integrity": "sha512-BxbVUnN8N7hJ4aaPOd7wEsudeT7CxarR+2hns8XCX1zp0DFfbWw4xYa/olA0oQaqx7F1hzDg+eRaGzAJbF+jOg==", - "dependencies": { - "@styled-system/core": "^5.1.2" - } - }, - "node_modules/@styled-system/variant": { - "version": "5.1.5", - "resolved": "https://registry.npmjs.org/@styled-system/variant/-/variant-5.1.5.tgz", - "integrity": "sha512-Yn8hXAFoWIro8+Q5J8YJd/mP85Teiut3fsGVR9CAxwgNfIAiqlYxsk5iHU7VHJks/0KjL4ATSjmbtCDC/4l1qw==", - "dependencies": { - "@styled-system/core": "^5.1.2", - "@styled-system/css": "^5.1.5" - } - }, "node_modules/@testing-library/dom": { "version": "8.17.1", "resolved": "https://registry.npmjs.org/@testing-library/dom/-/dom-8.17.1.tgz", @@ -13424,15 +13215,6 @@ "@types/unist": "*" } }, - "node_modules/@types/hoist-non-react-statics": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/@types/hoist-non-react-statics/-/hoist-non-react-statics-3.3.1.tgz", - "integrity": "sha512-iMIqiko6ooLrTh1joXodJK5X9xeEALT1kM5G3ZLhD3hszxBdIEd5C75U834D9mLcINgD4OyZf5uQXjkuYydWvA==", - "dependencies": { - "@types/react": "*", - "hoist-non-react-statics": "^3.3.0" - } - }, "node_modules/@types/html-minifier-terser": { "version": "6.1.0", "resolved": "https://registry.npmjs.org/@types/html-minifier-terser/-/html-minifier-terser-6.1.0.tgz", @@ -13667,7 +13449,8 @@ "node_modules/@types/prop-types": { "version": "15.7.3", "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.3.tgz", - "integrity": "sha512-KfRL3PuHmqQLOG+2tGpRO26Ctg+Cq1E01D2DMriKEATHgWLfeNDmq9e29Q9WIky0dQ3NPkd1mzYH8Lm936Z9qw==" + "integrity": "sha512-KfRL3PuHmqQLOG+2tGpRO26Ctg+Cq1E01D2DMriKEATHgWLfeNDmq9e29Q9WIky0dQ3NPkd1mzYH8Lm936Z9qw==", + "dev": true }, "node_modules/@types/qs": { "version": "6.9.7", @@ -13679,6 +13462,7 @@ "version": "17.0.39", "resolved": "https://registry.npmjs.org/@types/react/-/react-17.0.39.tgz", "integrity": "sha512-UVavlfAxDd/AgAacMa60Azl7ygyQNRwC/DsHZmKgNvPmRR5p70AJ5Q9EAmL2NWOJmeV+vVUI4IAP7GZrN8h8Ug==", + "dev": true, "dependencies": { "@types/prop-types": "*", "@types/scheduler": "*", @@ -13703,7 +13487,8 @@ "node_modules/@types/scheduler": { "version": "0.16.2", "resolved": "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.16.2.tgz", - "integrity": "sha512-hppQEBDmlwhFAXKJX2KnWLYu5yMfi91yazPb2l+lbJiwW+wdo1gNeRA+3RgNSO39WYX2euey41KEwnqesU2Jew==" + "integrity": "sha512-hppQEBDmlwhFAXKJX2KnWLYu5yMfi91yazPb2l+lbJiwW+wdo1gNeRA+3RgNSO39WYX2euey41KEwnqesU2Jew==", + "dev": true }, "node_modules/@types/semver": { "version": "7.2.0", @@ -13753,37 +13538,6 @@ "@types/stream-chain": "*" } }, - "node_modules/@types/styled-components": { - "version": "5.1.11", - "resolved": "https://registry.npmjs.org/@types/styled-components/-/styled-components-5.1.11.tgz", - "integrity": "sha512-u8g3bSw9KUiZY+S++gh+LlURGraqBe3MC5I5dygrNjGDHWWQfsmZZRTJ9K9oHU2CqWtxChWmJkDI/gp+TZPQMw==", - "dependencies": { - "@types/hoist-non-react-statics": "*", - "@types/react": "*", - "csstype": "^3.0.2" - } - }, - "node_modules/@types/styled-system": { - "version": "5.1.12", - "resolved": "https://registry.npmjs.org/@types/styled-system/-/styled-system-5.1.12.tgz", - "integrity": "sha512-7x4BYKKfK9QewfsFC2x5r9BK/OrfX+JF/1P21jKPMHruawDw9gvG7bTZgTVk6YkzDO2JUlsk4i8hdiAepAhD0g==", - "dependencies": { - "csstype": "^3.0.2" - } - }, - "node_modules/@types/styled-system__css": { - "version": "5.0.16", - "resolved": "https://registry.npmjs.org/@types/styled-system__css/-/styled-system__css-5.0.16.tgz", - "integrity": "sha512-Cji5miCIpR27m8yzH6y3cLU6106N4GVyPgUhBQ4nL7VxgoeAtRdAriKdGTnRgJzSpT3HyB7h5G//cDWOl0M1jQ==", - "dependencies": { - "csstype": "^3.0.2" - } - }, - "node_modules/@types/styled-system__theme-get": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/@types/styled-system__theme-get/-/styled-system__theme-get-5.0.1.tgz", - "integrity": "sha512-+i4VZ5wuYKMU8oKPmUlzc9r2RhpSNOK061Khtrr7X0sOQEcIyhUtrDusuMkp5ZR3D05Xopn3zybTPyUSQkKGAA==" - }, "node_modules/@types/tapable": { "version": "1.0.8", "resolved": "https://registry.npmjs.org/@types/tapable/-/tapable-1.0.8.tgz", @@ -18460,11 +18214,6 @@ "color-support": "bin.js" } }, - "node_modules/color2k": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/color2k/-/color2k-1.2.4.tgz", - "integrity": "sha512-DiwdBwc0BryPFFXoCrW8XQGXl2rEtMToODybxZjKnN5IJXt/tV/FsN02pCK/b7KcWvJEioz3c74lQSmayFvS4Q==" - }, "node_modules/colorette": { "version": "1.2.2", "resolved": "https://registry.npmjs.org/colorette/-/colorette-1.2.2.tgz", @@ -19363,7 +19112,8 @@ "node_modules/csstype": { "version": "3.0.10", "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.0.10.tgz", - "integrity": "sha512-2u44ZG2OcNUO9HDp/Jl8C07x6pU/eTR3ncV91SiK3dhG9TWvRVsCoJw14Ckx5DgWkzGA3waZWO3d7pgqpUI/XA==" + "integrity": "sha512-2u44ZG2OcNUO9HDp/Jl8C07x6pU/eTR3ncV91SiK3dhG9TWvRVsCoJw14Ckx5DgWkzGA3waZWO3d7pgqpUI/XA==", + "dev": true }, "node_modules/currently-unhandled": { "version": "0.4.1", @@ -19957,6 +19707,7 @@ "version": "4.2.2", "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.2.2.tgz", "integrity": "sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg==", + "dev": true, "engines": { "node": ">=0.10.0" } @@ -23675,11 +23426,6 @@ "node": ">=10" } }, - "node_modules/focus-visible": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/focus-visible/-/focus-visible-5.2.0.tgz", - "integrity": "sha512-Rwix9pBtC1Nuy5wysTmKy+UjbDJpIfg8eHjw0rjZ1mX4GNLz1Bmd16uDpI3Gk1i70Fgcs8Csg2lPm8HULFg9DQ==" - }, "node_modules/for-each": { "version": "0.3.3", "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz", @@ -25200,14 +24946,6 @@ "resolved": "https://registry.npmjs.org/headers-polyfill/-/headers-polyfill-3.1.2.tgz", "integrity": "sha512-tWCK4biJ6hcLqTviLXVR9DTRfYGQMXEIUj3gwJ2rZ5wO/at3XtkI4g8mCvFdUF9l1KMBNCfmNAdnahm1cgavQA==" }, - "node_modules/history": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/history/-/history-5.0.0.tgz", - "integrity": "sha512-3NyRMKIiFSJmIPdq7FxkNMJkQ7ZEtVblOQ38VtKaA0zZMW1Eo6Q6W8oDKEflr1kNNTItSnk4JMCO1deeSgbLLg==", - "dependencies": { - "@babel/runtime": "^7.7.6" - } - }, "node_modules/hmac-drbg": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/hmac-drbg/-/hmac-drbg-1.0.1.tgz", @@ -35718,7 +35456,8 @@ "node_modules/regenerator-runtime": { "version": "0.13.11", "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz", - "integrity": "sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg==" + "integrity": "sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg==", + "dev": true }, "node_modules/regenerator-transform": { "version": "0.15.0", @@ -37757,26 +37496,6 @@ "node": ">=4" } }, - "node_modules/styled-system": { - "version": "5.1.5", - "resolved": "https://registry.npmjs.org/styled-system/-/styled-system-5.1.5.tgz", - "integrity": "sha512-7VoD0o2R3RKzOzPK0jYrVnS8iJdfkKsQJNiLRDjikOpQVqQHns/DXWaPZOH4tIKkhAT7I6wIsy9FWTWh2X3q+A==", - "dependencies": { - "@styled-system/background": "^5.1.2", - "@styled-system/border": "^5.1.5", - "@styled-system/color": "^5.1.2", - "@styled-system/core": "^5.1.2", - "@styled-system/flexbox": "^5.1.2", - "@styled-system/grid": "^5.1.2", - "@styled-system/layout": "^5.1.2", - "@styled-system/position": "^5.1.2", - "@styled-system/shadow": "^5.1.2", - "@styled-system/space": "^5.1.2", - "@styled-system/typography": "^5.1.2", - "@styled-system/variant": "^5.1.5", - "object-assign": "^4.1.1" - } - }, "node_modules/supports-color": { "version": "6.1.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", @@ -42928,6 +42647,7 @@ "version": "7.18.9", "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.18.9.tgz", "integrity": "sha512-lkqXDcvlFT5rvEjiu6+QYO+1GXrEHRo2LOtS7E4GtX5ESIZOgepqsZBVIj6Pv+a6zqsya9VCgiK1KAK4BvJDAw==", + "dev": true, "requires": { "regenerator-runtime": "^0.13.4" } @@ -45802,71 +45522,6 @@ } } }, - "@primer/behaviors": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@primer/behaviors/-/behaviors-1.1.0.tgz", - "integrity": "sha512-Ej2OUc3ZIFaR7WwIUqESO1DTzmpb7wc8xbTVRT9s52jZQDjN7g5iljoK3ocYZm+BIAcKn3MvcwB42hEk4Ga4xQ==" - }, - "@primer/octicons-react": { - "version": "17.6.0", - "resolved": "https://registry.npmjs.org/@primer/octicons-react/-/octicons-react-17.6.0.tgz", - "integrity": "sha512-jn1fWag3eU6BvOltMS2MqLPNh39D45cpegsTO2Qhb8SlJoUsj/ZO1qbJgYd9ibvZo8evDyXx3syh4kDbxJQFsg==" - }, - "@primer/primitives": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/@primer/primitives/-/primitives-7.1.1.tgz", - "integrity": "sha512-+Gwo89YK1OFi6oubTlah/zPxxzMNaMLy+inECAYI646KIFdzzhAsKWb3z5tSOu5Ff7no4isRV64rWfMSKLZclw==" - }, - "@primer/react": { - "version": "35.0.0", - "resolved": "https://registry.npmjs.org/@primer/react/-/react-35.0.0.tgz", - "integrity": "sha512-pjraRDHoT6Lwmto31ZN+WrtNCDA6lieOhr+4XC1z8wuq/JSGJVB3gHePi2/yIZldy2WoK55O1lsyp8llUiakog==", - "requires": { - "@primer/behaviors": "1.1.0", - "@primer/octicons-react": "16.1.1", - "@primer/primitives": "7.1.1", - "@radix-ui/react-polymorphic": "0.0.14", - "@react-aria/ssr": "3.1.0", - "@styled-system/css": "5.1.5", - "@styled-system/props": "5.1.5", - "@styled-system/theme-get": "5.1.2", - "@types/styled-components": "5.1.11", - "@types/styled-system": "5.1.12", - "@types/styled-system__css": "5.0.16", - "@types/styled-system__theme-get": "5.0.1", - "classnames": "2.3.1", - "color2k": "1.2.4", - "deepmerge": "4.2.2", - "focus-visible": "5.2.0", - "history": "5.0.0", - "styled-system": "5.1.5" - }, - "dependencies": { - "@primer/octicons-react": { - "version": "16.1.1", - "resolved": "https://registry.npmjs.org/@primer/octicons-react/-/octicons-react-16.1.1.tgz", - "integrity": "sha512-xCxQ5z23ol7yDuJs85Lc4ARzyoay+b3zOhAKkEMU7chk0xi2hT2OnRP23QUudNNDPTGozX268RGYLexUa6P4xw==" - }, - "classnames": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/classnames/-/classnames-2.3.1.tgz", - "integrity": "sha512-OlQdbZ7gLfGarSqxesMesDa5uz7KFbID8Kpq/SxIoNGDqY8lSYs0D+hhtBXhcdB3rcbXArFr7vlHheLk1voeNA==" - } - } - }, - "@radix-ui/react-polymorphic": { - "version": "0.0.14", - "resolved": "https://registry.npmjs.org/@radix-ui/react-polymorphic/-/react-polymorphic-0.0.14.tgz", - "integrity": "sha512-9nsMZEDU3LeIUeHJrpkkhZVxu/9Fc7P2g2I3WR+uA9mTbNC3hGaabi0dV6wg0CfHb+m4nSs1pejbE/5no3MJTA==" - }, - "@react-aria/ssr": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/@react-aria/ssr/-/ssr-3.1.0.tgz", - "integrity": "sha512-RxqQKmE8sO7TGdrcSlHTcVzMP450hqowtBSd2bBS9oPlcokVkaGq28c3Rwa8ty5ctw4EBCjXqjP7xdcKMGDzug==", - "requires": { - "@babel/runtime": "^7.6.2" - } - }, "@sinclair/typebox": { "version": "0.24.41", "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.24.41.tgz", @@ -50672,124 +50327,6 @@ } } }, - "@styled-system/background": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/@styled-system/background/-/background-5.1.2.tgz", - "integrity": "sha512-jtwH2C/U6ssuGSvwTN3ri/IyjdHb8W9X/g8Y0JLcrH02G+BW3OS8kZdHphF1/YyRklnrKrBT2ngwGUK6aqqV3A==", - "requires": { - "@styled-system/core": "^5.1.2" - } - }, - "@styled-system/border": { - "version": "5.1.5", - "resolved": "https://registry.npmjs.org/@styled-system/border/-/border-5.1.5.tgz", - "integrity": "sha512-JvddhNrnhGigtzWRCVuAHepniyVi6hBlimxWDVAdcTuk7aRn9BYJUwfHslURtwYFsF5FoEs8Zmr1oZq2M1AP0A==", - "requires": { - "@styled-system/core": "^5.1.2" - } - }, - "@styled-system/color": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/@styled-system/color/-/color-5.1.2.tgz", - "integrity": "sha512-1kCkeKDZkt4GYkuFNKc7vJQMcOmTl3bJY3YBUs7fCNM6mMYJeT1pViQ2LwBSBJytj3AB0o4IdLBoepgSgGl5MA==", - "requires": { - "@styled-system/core": "^5.1.2" - } - }, - "@styled-system/core": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/@styled-system/core/-/core-5.1.2.tgz", - "integrity": "sha512-XclBDdNIy7OPOsN4HBsawG2eiWfCcuFt6gxKn1x4QfMIgeO6TOlA2pZZ5GWZtIhCUqEPTgIBta6JXsGyCkLBYw==", - "requires": { - "object-assign": "^4.1.1" - } - }, - "@styled-system/css": { - "version": "5.1.5", - "resolved": "https://registry.npmjs.org/@styled-system/css/-/css-5.1.5.tgz", - "integrity": "sha512-XkORZdS5kypzcBotAMPBoeckDs9aSZVkvrAlq5K3xP8IMAUek+x2O4NtwoSgkYkWWzVBu6DGdFZLR790QWGG+A==" - }, - "@styled-system/flexbox": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/@styled-system/flexbox/-/flexbox-5.1.2.tgz", - "integrity": "sha512-6hHV52+eUk654Y1J2v77B8iLeBNtc+SA3R4necsu2VVinSD7+XY5PCCEzBFaWs42dtOEDIa2lMrgL0YBC01mDQ==", - "requires": { - "@styled-system/core": "^5.1.2" - } - }, - "@styled-system/grid": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/@styled-system/grid/-/grid-5.1.2.tgz", - "integrity": "sha512-K3YiV1KyHHzgdNuNlaw8oW2ktMuGga99o1e/NAfTEi5Zsa7JXxzwEnVSDSBdJC+z6R8WYTCYRQC6bkVFcvdTeg==", - "requires": { - "@styled-system/core": "^5.1.2" - } - }, - "@styled-system/layout": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/@styled-system/layout/-/layout-5.1.2.tgz", - "integrity": "sha512-wUhkMBqSeacPFhoE9S6UF3fsMEKFv91gF4AdDWp0Aym1yeMPpqz9l9qS/6vjSsDPF7zOb5cOKC3tcKKOMuDCPw==", - "requires": { - "@styled-system/core": "^5.1.2" - } - }, - "@styled-system/position": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/@styled-system/position/-/position-5.1.2.tgz", - "integrity": "sha512-60IZfMXEOOZe3l1mCu6sj/2NAyUmES2kR9Kzp7s2D3P4qKsZWxD1Se1+wJvevb+1TP+ZMkGPEYYXRyU8M1aF5A==", - "requires": { - "@styled-system/core": "^5.1.2" - } - }, - "@styled-system/props": { - "version": "5.1.5", - "resolved": "https://registry.npmjs.org/@styled-system/props/-/props-5.1.5.tgz", - "integrity": "sha512-FXhbzq2KueZpGaHxaDm8dowIEWqIMcgsKs6tBl6Y6S0njG9vC8dBMI6WSLDnzMoSqIX3nSKHmOmpzpoihdDewg==", - "requires": { - "styled-system": "^5.1.5" - } - }, - "@styled-system/shadow": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/@styled-system/shadow/-/shadow-5.1.2.tgz", - "integrity": "sha512-wqniqYb7XuZM7K7C0d1Euxc4eGtqEe/lvM0WjuAFsQVImiq6KGT7s7is+0bNI8O4Dwg27jyu4Lfqo/oIQXNzAg==", - "requires": { - "@styled-system/core": "^5.1.2" - } - }, - "@styled-system/space": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/@styled-system/space/-/space-5.1.2.tgz", - "integrity": "sha512-+zzYpR8uvfhcAbaPXhH8QgDAV//flxqxSjHiS9cDFQQUSznXMQmxJegbhcdEF7/eNnJgHeIXv1jmny78kipgBA==", - "requires": { - "@styled-system/core": "^5.1.2" - } - }, - "@styled-system/theme-get": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/@styled-system/theme-get/-/theme-get-5.1.2.tgz", - "integrity": "sha512-afAYdRqrKfNIbVgmn/2Qet1HabxmpRnzhFwttbGr6F/mJ4RDS/Cmn+KHwHvNXangQsWw/5TfjpWV+rgcqqIcJQ==", - "requires": { - "@styled-system/core": "^5.1.2" - } - }, - "@styled-system/typography": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/@styled-system/typography/-/typography-5.1.2.tgz", - "integrity": "sha512-BxbVUnN8N7hJ4aaPOd7wEsudeT7CxarR+2hns8XCX1zp0DFfbWw4xYa/olA0oQaqx7F1hzDg+eRaGzAJbF+jOg==", - "requires": { - "@styled-system/core": "^5.1.2" - } - }, - "@styled-system/variant": { - "version": "5.1.5", - "resolved": "https://registry.npmjs.org/@styled-system/variant/-/variant-5.1.5.tgz", - "integrity": "sha512-Yn8hXAFoWIro8+Q5J8YJd/mP85Teiut3fsGVR9CAxwgNfIAiqlYxsk5iHU7VHJks/0KjL4ATSjmbtCDC/4l1qw==", - "requires": { - "@styled-system/core": "^5.1.2", - "@styled-system/css": "^5.1.5" - } - }, "@testing-library/dom": { "version": "8.17.1", "resolved": "https://registry.npmjs.org/@testing-library/dom/-/dom-8.17.1.tgz", @@ -51497,15 +51034,6 @@ "@types/unist": "*" } }, - "@types/hoist-non-react-statics": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/@types/hoist-non-react-statics/-/hoist-non-react-statics-3.3.1.tgz", - "integrity": "sha512-iMIqiko6ooLrTh1joXodJK5X9xeEALT1kM5G3ZLhD3hszxBdIEd5C75U834D9mLcINgD4OyZf5uQXjkuYydWvA==", - "requires": { - "@types/react": "*", - "hoist-non-react-statics": "^3.3.0" - } - }, "@types/html-minifier-terser": { "version": "6.1.0", "resolved": "https://registry.npmjs.org/@types/html-minifier-terser/-/html-minifier-terser-6.1.0.tgz", @@ -51725,7 +51253,8 @@ "@types/prop-types": { "version": "15.7.3", "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.3.tgz", - "integrity": "sha512-KfRL3PuHmqQLOG+2tGpRO26Ctg+Cq1E01D2DMriKEATHgWLfeNDmq9e29Q9WIky0dQ3NPkd1mzYH8Lm936Z9qw==" + "integrity": "sha512-KfRL3PuHmqQLOG+2tGpRO26Ctg+Cq1E01D2DMriKEATHgWLfeNDmq9e29Q9WIky0dQ3NPkd1mzYH8Lm936Z9qw==", + "dev": true }, "@types/qs": { "version": "6.9.7", @@ -51737,6 +51266,7 @@ "version": "17.0.39", "resolved": "https://registry.npmjs.org/@types/react/-/react-17.0.39.tgz", "integrity": "sha512-UVavlfAxDd/AgAacMa60Azl7ygyQNRwC/DsHZmKgNvPmRR5p70AJ5Q9EAmL2NWOJmeV+vVUI4IAP7GZrN8h8Ug==", + "dev": true, "requires": { "@types/prop-types": "*", "@types/scheduler": "*", @@ -51761,7 +51291,8 @@ "@types/scheduler": { "version": "0.16.2", "resolved": "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.16.2.tgz", - "integrity": "sha512-hppQEBDmlwhFAXKJX2KnWLYu5yMfi91yazPb2l+lbJiwW+wdo1gNeRA+3RgNSO39WYX2euey41KEwnqesU2Jew==" + "integrity": "sha512-hppQEBDmlwhFAXKJX2KnWLYu5yMfi91yazPb2l+lbJiwW+wdo1gNeRA+3RgNSO39WYX2euey41KEwnqesU2Jew==", + "dev": true }, "@types/semver": { "version": "7.2.0", @@ -51811,37 +51342,6 @@ "@types/stream-chain": "*" } }, - "@types/styled-components": { - "version": "5.1.11", - "resolved": "https://registry.npmjs.org/@types/styled-components/-/styled-components-5.1.11.tgz", - "integrity": "sha512-u8g3bSw9KUiZY+S++gh+LlURGraqBe3MC5I5dygrNjGDHWWQfsmZZRTJ9K9oHU2CqWtxChWmJkDI/gp+TZPQMw==", - "requires": { - "@types/hoist-non-react-statics": "*", - "@types/react": "*", - "csstype": "^3.0.2" - } - }, - "@types/styled-system": { - "version": "5.1.12", - "resolved": "https://registry.npmjs.org/@types/styled-system/-/styled-system-5.1.12.tgz", - "integrity": "sha512-7x4BYKKfK9QewfsFC2x5r9BK/OrfX+JF/1P21jKPMHruawDw9gvG7bTZgTVk6YkzDO2JUlsk4i8hdiAepAhD0g==", - "requires": { - "csstype": "^3.0.2" - } - }, - "@types/styled-system__css": { - "version": "5.0.16", - "resolved": "https://registry.npmjs.org/@types/styled-system__css/-/styled-system__css-5.0.16.tgz", - "integrity": "sha512-Cji5miCIpR27m8yzH6y3cLU6106N4GVyPgUhBQ4nL7VxgoeAtRdAriKdGTnRgJzSpT3HyB7h5G//cDWOl0M1jQ==", - "requires": { - "csstype": "^3.0.2" - } - }, - "@types/styled-system__theme-get": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/@types/styled-system__theme-get/-/styled-system__theme-get-5.0.1.tgz", - "integrity": "sha512-+i4VZ5wuYKMU8oKPmUlzc9r2RhpSNOK061Khtrr7X0sOQEcIyhUtrDusuMkp5ZR3D05Xopn3zybTPyUSQkKGAA==" - }, "@types/tapable": { "version": "1.0.8", "resolved": "https://registry.npmjs.org/@types/tapable/-/tapable-1.0.8.tgz", @@ -55472,11 +54972,6 @@ "integrity": "sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg==", "dev": true }, - "color2k": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/color2k/-/color2k-1.2.4.tgz", - "integrity": "sha512-DiwdBwc0BryPFFXoCrW8XQGXl2rEtMToODybxZjKnN5IJXt/tV/FsN02pCK/b7KcWvJEioz3c74lQSmayFvS4Q==" - }, "colorette": { "version": "1.2.2", "resolved": "https://registry.npmjs.org/colorette/-/colorette-1.2.2.tgz", @@ -56202,7 +55697,8 @@ "csstype": { "version": "3.0.10", "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.0.10.tgz", - "integrity": "sha512-2u44ZG2OcNUO9HDp/Jl8C07x6pU/eTR3ncV91SiK3dhG9TWvRVsCoJw14Ckx5DgWkzGA3waZWO3d7pgqpUI/XA==" + "integrity": "sha512-2u44ZG2OcNUO9HDp/Jl8C07x6pU/eTR3ncV91SiK3dhG9TWvRVsCoJw14Ckx5DgWkzGA3waZWO3d7pgqpUI/XA==", + "dev": true }, "currently-unhandled": { "version": "0.4.1", @@ -56652,7 +56148,8 @@ "deepmerge": { "version": "4.2.2", "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.2.2.tgz", - "integrity": "sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg==" + "integrity": "sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg==", + "dev": true }, "default-browser-id": { "version": "1.0.4", @@ -59433,11 +58930,6 @@ "tslib": "^1.9.3" } }, - "focus-visible": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/focus-visible/-/focus-visible-5.2.0.tgz", - "integrity": "sha512-Rwix9pBtC1Nuy5wysTmKy+UjbDJpIfg8eHjw0rjZ1mX4GNLz1Bmd16uDpI3Gk1i70Fgcs8Csg2lPm8HULFg9DQ==" - }, "for-each": { "version": "0.3.3", "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz", @@ -60607,14 +60099,6 @@ "resolved": "https://registry.npmjs.org/headers-polyfill/-/headers-polyfill-3.1.2.tgz", "integrity": "sha512-tWCK4biJ6hcLqTviLXVR9DTRfYGQMXEIUj3gwJ2rZ5wO/at3XtkI4g8mCvFdUF9l1KMBNCfmNAdnahm1cgavQA==" }, - "history": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/history/-/history-5.0.0.tgz", - "integrity": "sha512-3NyRMKIiFSJmIPdq7FxkNMJkQ7ZEtVblOQ38VtKaA0zZMW1Eo6Q6W8oDKEflr1kNNTItSnk4JMCO1deeSgbLLg==", - "requires": { - "@babel/runtime": "^7.7.6" - } - }, "hmac-drbg": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/hmac-drbg/-/hmac-drbg-1.0.1.tgz", @@ -68656,7 +68140,8 @@ "regenerator-runtime": { "version": "0.13.11", "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz", - "integrity": "sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg==" + "integrity": "sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg==", + "dev": true }, "regenerator-transform": { "version": "0.15.0", @@ -70264,26 +69749,6 @@ } } }, - "styled-system": { - "version": "5.1.5", - "resolved": "https://registry.npmjs.org/styled-system/-/styled-system-5.1.5.tgz", - "integrity": "sha512-7VoD0o2R3RKzOzPK0jYrVnS8iJdfkKsQJNiLRDjikOpQVqQHns/DXWaPZOH4tIKkhAT7I6wIsy9FWTWh2X3q+A==", - "requires": { - "@styled-system/background": "^5.1.2", - "@styled-system/border": "^5.1.5", - "@styled-system/color": "^5.1.2", - "@styled-system/core": "^5.1.2", - "@styled-system/flexbox": "^5.1.2", - "@styled-system/grid": "^5.1.2", - "@styled-system/layout": "^5.1.2", - "@styled-system/position": "^5.1.2", - "@styled-system/shadow": "^5.1.2", - "@styled-system/space": "^5.1.2", - "@styled-system/typography": "^5.1.2", - "@styled-system/variant": "^5.1.5", - "object-assign": "^4.1.1" - } - }, "supports-color": { "version": "6.1.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", diff --git a/extensions/ql-vscode/package.json b/extensions/ql-vscode/package.json index f35d28e36..6285c2cf1 100644 --- a/extensions/ql-vscode/package.json +++ b/extensions/ql-vscode/package.json @@ -1433,8 +1433,6 @@ "dependencies": { "@octokit/plugin-retry": "^3.0.9", "@octokit/rest": "^19.0.4", - "@primer/octicons-react": "^17.6.0", - "@primer/react": "^35.0.0", "@vscode/codicons": "^0.0.31", "@vscode/webview-ui-toolkit": "^1.0.1", "ajv": "^8.11.0", From 2d463654061af027cdbae4716945701ad45ce3c0 Mon Sep 17 00:00:00 2001 From: Charis Kyriakou Date: Fri, 17 Mar 2023 14:19:22 +0000 Subject: [PATCH 061/156] Add styled-components as a top level dependency --- extensions/ql-vscode/package-lock.json | 87 +++++++++++++++++++------- extensions/ql-vscode/package.json | 1 + 2 files changed, 66 insertions(+), 22 deletions(-) diff --git a/extensions/ql-vscode/package-lock.json b/extensions/ql-vscode/package-lock.json index afeef5346..a673eaf66 100644 --- a/extensions/ql-vscode/package-lock.json +++ b/extensions/ql-vscode/package-lock.json @@ -89,6 +89,7 @@ "@types/semver": "~7.2.0", "@types/stream-chain": "~2.0.1", "@types/stream-json": "~1.7.1", + "@types/styled-components": "^5.1.11", "@types/tar-stream": "^2.2.2", "@types/through2": "^2.0.36", "@types/tmp": "^0.1.0", @@ -2524,17 +2525,17 @@ } }, "node_modules/@emotion/is-prop-valid": { - "version": "0.8.8", - "resolved": "https://registry.npmjs.org/@emotion/is-prop-valid/-/is-prop-valid-0.8.8.tgz", - "integrity": "sha512-u5WtneEAr5IDG2Wv65yhunPSMLIpuKsbuOktRojfrEiEvRyC85LgPMZI63cr7NUqT8ZIGdSVg8ZKGxIug4lXcA==", + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@emotion/is-prop-valid/-/is-prop-valid-1.2.0.tgz", + "integrity": "sha512-3aDpDprjM0AwaxGE09bOPkNxHpBd+kA6jty3RnaEXdweX1DF1U3VQpPYb0g1IStAuK7SVQ1cy+bNBBKp4W3Fjg==", "dependencies": { - "@emotion/memoize": "0.7.4" + "@emotion/memoize": "^0.8.0" } }, "node_modules/@emotion/memoize": { - "version": "0.7.4", - "resolved": "https://registry.npmjs.org/@emotion/memoize/-/memoize-0.7.4.tgz", - "integrity": "sha512-Ja/Vfqe3HpuzRsG1oBtWTHk2PGZ7GR+2Vz5iYGelAw8dx32K0y7PjVuxK6z1nMpZOqAFsRUPCkK1YjJ56qJlgw==" + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/@emotion/memoize/-/memoize-0.8.0.tgz", + "integrity": "sha512-G/YwXTkv7Den9mXDO7AhLWkE3q+I92B+VqAE+dYG4NGPaHZGvt3G8Q0p9vmE+sq7rTGphUbAvmQ9YpbfMQGGlA==" }, "node_modules/@emotion/stylis": { "version": "0.8.5", @@ -13215,6 +13216,16 @@ "@types/unist": "*" } }, + "node_modules/@types/hoist-non-react-statics": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/@types/hoist-non-react-statics/-/hoist-non-react-statics-3.3.1.tgz", + "integrity": "sha512-iMIqiko6ooLrTh1joXodJK5X9xeEALT1kM5G3ZLhD3hszxBdIEd5C75U834D9mLcINgD4OyZf5uQXjkuYydWvA==", + "dev": true, + "dependencies": { + "@types/react": "*", + "hoist-non-react-statics": "^3.3.0" + } + }, "node_modules/@types/html-minifier-terser": { "version": "6.1.0", "resolved": "https://registry.npmjs.org/@types/html-minifier-terser/-/html-minifier-terser-6.1.0.tgz", @@ -13538,6 +13549,17 @@ "@types/stream-chain": "*" } }, + "node_modules/@types/styled-components": { + "version": "5.1.26", + "resolved": "https://registry.npmjs.org/@types/styled-components/-/styled-components-5.1.26.tgz", + "integrity": "sha512-KuKJ9Z6xb93uJiIyxo/+ksS7yLjS1KzG6iv5i78dhVg/X3u5t1H7juRWqVmodIdz6wGVaIApo1u01kmFRdJHVw==", + "dev": true, + "dependencies": { + "@types/hoist-non-react-statics": "*", + "@types/react": "*", + "csstype": "^3.0.2" + } + }, "node_modules/@types/tapable": { "version": "1.0.8", "resolved": "https://registry.npmjs.org/@types/tapable/-/tapable-1.0.8.tgz", @@ -37457,13 +37479,13 @@ } }, "node_modules/styled-components": { - "version": "5.3.3", - "resolved": "https://registry.npmjs.org/styled-components/-/styled-components-5.3.3.tgz", - "integrity": "sha512-++4iHwBM7ZN+x6DtPPWkCI4vdtwumQ+inA/DdAsqYd4SVgUKJie5vXyzotA00ttcFdQkCng7zc6grwlfIfw+lw==", + "version": "5.3.9", + "resolved": "https://registry.npmjs.org/styled-components/-/styled-components-5.3.9.tgz", + "integrity": "sha512-Aj3kb13B75DQBo2oRwRa/APdB5rSmwUfN5exyarpX+x/tlM/rwZA2vVk2vQgVSP6WKaZJHWwiFrzgHt+CLtB4A==", "dependencies": { "@babel/helper-module-imports": "^7.0.0", "@babel/traverse": "^7.4.5", - "@emotion/is-prop-valid": "^0.8.8", + "@emotion/is-prop-valid": "^1.1.0", "@emotion/stylis": "^0.8.4", "@emotion/unitless": "^0.7.4", "babel-plugin-styled-components": ">= 1.12.0", @@ -42870,17 +42892,17 @@ "dev": true }, "@emotion/is-prop-valid": { - "version": "0.8.8", - "resolved": "https://registry.npmjs.org/@emotion/is-prop-valid/-/is-prop-valid-0.8.8.tgz", - "integrity": "sha512-u5WtneEAr5IDG2Wv65yhunPSMLIpuKsbuOktRojfrEiEvRyC85LgPMZI63cr7NUqT8ZIGdSVg8ZKGxIug4lXcA==", + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@emotion/is-prop-valid/-/is-prop-valid-1.2.0.tgz", + "integrity": "sha512-3aDpDprjM0AwaxGE09bOPkNxHpBd+kA6jty3RnaEXdweX1DF1U3VQpPYb0g1IStAuK7SVQ1cy+bNBBKp4W3Fjg==", "requires": { - "@emotion/memoize": "0.7.4" + "@emotion/memoize": "^0.8.0" } }, "@emotion/memoize": { - "version": "0.7.4", - "resolved": "https://registry.npmjs.org/@emotion/memoize/-/memoize-0.7.4.tgz", - "integrity": "sha512-Ja/Vfqe3HpuzRsG1oBtWTHk2PGZ7GR+2Vz5iYGelAw8dx32K0y7PjVuxK6z1nMpZOqAFsRUPCkK1YjJ56qJlgw==" + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/@emotion/memoize/-/memoize-0.8.0.tgz", + "integrity": "sha512-G/YwXTkv7Den9mXDO7AhLWkE3q+I92B+VqAE+dYG4NGPaHZGvt3G8Q0p9vmE+sq7rTGphUbAvmQ9YpbfMQGGlA==" }, "@emotion/stylis": { "version": "0.8.5", @@ -51034,6 +51056,16 @@ "@types/unist": "*" } }, + "@types/hoist-non-react-statics": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/@types/hoist-non-react-statics/-/hoist-non-react-statics-3.3.1.tgz", + "integrity": "sha512-iMIqiko6ooLrTh1joXodJK5X9xeEALT1kM5G3ZLhD3hszxBdIEd5C75U834D9mLcINgD4OyZf5uQXjkuYydWvA==", + "dev": true, + "requires": { + "@types/react": "*", + "hoist-non-react-statics": "^3.3.0" + } + }, "@types/html-minifier-terser": { "version": "6.1.0", "resolved": "https://registry.npmjs.org/@types/html-minifier-terser/-/html-minifier-terser-6.1.0.tgz", @@ -51342,6 +51374,17 @@ "@types/stream-chain": "*" } }, + "@types/styled-components": { + "version": "5.1.26", + "resolved": "https://registry.npmjs.org/@types/styled-components/-/styled-components-5.1.26.tgz", + "integrity": "sha512-KuKJ9Z6xb93uJiIyxo/+ksS7yLjS1KzG6iv5i78dhVg/X3u5t1H7juRWqVmodIdz6wGVaIApo1u01kmFRdJHVw==", + "dev": true, + "requires": { + "@types/hoist-non-react-statics": "*", + "@types/react": "*", + "csstype": "^3.0.2" + } + }, "@types/tapable": { "version": "1.0.8", "resolved": "https://registry.npmjs.org/@types/tapable/-/tapable-1.0.8.tgz", @@ -69723,13 +69766,13 @@ } }, "styled-components": { - "version": "5.3.3", - "resolved": "https://registry.npmjs.org/styled-components/-/styled-components-5.3.3.tgz", - "integrity": "sha512-++4iHwBM7ZN+x6DtPPWkCI4vdtwumQ+inA/DdAsqYd4SVgUKJie5vXyzotA00ttcFdQkCng7zc6grwlfIfw+lw==", + "version": "5.3.9", + "resolved": "https://registry.npmjs.org/styled-components/-/styled-components-5.3.9.tgz", + "integrity": "sha512-Aj3kb13B75DQBo2oRwRa/APdB5rSmwUfN5exyarpX+x/tlM/rwZA2vVk2vQgVSP6WKaZJHWwiFrzgHt+CLtB4A==", "requires": { "@babel/helper-module-imports": "^7.0.0", "@babel/traverse": "^7.4.5", - "@emotion/is-prop-valid": "^0.8.8", + "@emotion/is-prop-valid": "^1.1.0", "@emotion/stylis": "^0.8.4", "@emotion/unitless": "^0.7.4", "babel-plugin-styled-components": ">= 1.12.0", diff --git a/extensions/ql-vscode/package.json b/extensions/ql-vscode/package.json index 6285c2cf1..28b66f99c 100644 --- a/extensions/ql-vscode/package.json +++ b/extensions/ql-vscode/package.json @@ -1510,6 +1510,7 @@ "@types/semver": "~7.2.0", "@types/stream-chain": "~2.0.1", "@types/stream-json": "~1.7.1", + "@types/styled-components": "^5.1.11", "@types/tar-stream": "^2.2.2", "@types/through2": "^2.0.36", "@types/tmp": "^0.1.0", From a375afd61baa677172125264201da0e80ac68209 Mon Sep 17 00:00:00 2001 From: Robert Date: Fri, 17 Mar 2023 15:38:08 +0000 Subject: [PATCH 062/156] Remove codeQL.cancelVariantAnalysis command --- extensions/ql-vscode/src/extension.ts | 9 ------- .../query-history/query-history-manager.ts | 3 +-- .../variant-analysis-view-manager.ts | 1 + .../variant-analysis/variant-analysis-view.ts | 5 +--- .../view/variant-analysis/VariantAnalysis.tsx | 1 + .../query-history-manager.test.ts | 26 ++++++++++--------- 6 files changed, 18 insertions(+), 27 deletions(-) diff --git a/extensions/ql-vscode/src/extension.ts b/extensions/ql-vscode/src/extension.ts index b6522377f..d85f05beb 100644 --- a/extensions/ql-vscode/src/extension.ts +++ b/extensions/ql-vscode/src/extension.ts @@ -1145,15 +1145,6 @@ async function activateWithInstalledDistribution( ), ); - ctx.subscriptions.push( - commandRunner( - "codeQL.cancelVariantAnalysis", - async (variantAnalysisId: number) => { - await variantAnalysisManager.cancelVariantAnalysis(variantAnalysisId); - }, - ), - ); - ctx.subscriptions.push( commandRunner("codeQL.exportSelectedVariantAnalysisResults", async () => { await exportSelectedVariantAnalysisResults(qhm); diff --git a/extensions/ql-vscode/src/query-history/query-history-manager.ts b/extensions/ql-vscode/src/query-history/query-history-manager.ts index 44529bdf1..cb702fa05 100644 --- a/extensions/ql-vscode/src/query-history/query-history-manager.ts +++ b/extensions/ql-vscode/src/query-history/query-history-manager.ts @@ -1008,8 +1008,7 @@ export class QueryHistoryManager extends DisposableObject { if (item.t === "local") { item.cancel(); } else if (item.t === "variant-analysis") { - await commands.executeCommand( - "codeQL.cancelVariantAnalysis", + await this.variantAnalysisManager.cancelVariantAnalysis( item.variantAnalysis.id, ); } else { diff --git a/extensions/ql-vscode/src/variant-analysis/variant-analysis-view-manager.ts b/extensions/ql-vscode/src/variant-analysis/variant-analysis-view-manager.ts index 1fa1fe46d..07aa1be33 100644 --- a/extensions/ql-vscode/src/variant-analysis/variant-analysis-view-manager.ts +++ b/extensions/ql-vscode/src/variant-analysis/variant-analysis-view-manager.ts @@ -25,4 +25,5 @@ export interface VariantAnalysisViewManager< variantAnalysisId: number, ): Promise; openQueryFile(variantAnalysisId: number): Promise; + cancelVariantAnalysis(variantAnalysisId: number): Promise; } diff --git a/extensions/ql-vscode/src/variant-analysis/variant-analysis-view.ts b/extensions/ql-vscode/src/variant-analysis/variant-analysis-view.ts index 351e5afbf..858256080 100644 --- a/extensions/ql-vscode/src/variant-analysis/variant-analysis-view.ts +++ b/extensions/ql-vscode/src/variant-analysis/variant-analysis-view.ts @@ -110,10 +110,7 @@ export class VariantAnalysisView break; case "cancelVariantAnalysis": - void commands.executeCommand( - "codeQL.cancelVariantAnalysis", - this.variantAnalysisId, - ); + await this.manager.cancelVariantAnalysis(this.variantAnalysisId); break; case "requestRepositoryResults": void commands.executeCommand( diff --git a/extensions/ql-vscode/src/view/variant-analysis/VariantAnalysis.tsx b/extensions/ql-vscode/src/view/variant-analysis/VariantAnalysis.tsx index 6c2f27051..73aed5974 100644 --- a/extensions/ql-vscode/src/view/variant-analysis/VariantAnalysis.tsx +++ b/extensions/ql-vscode/src/view/variant-analysis/VariantAnalysis.tsx @@ -38,6 +38,7 @@ const stopQuery = () => { vscode.postMessage({ t: "cancelVariantAnalysis", }); + sendTelemetry("variant-analysis-cancel"); }; const openLogs = () => { diff --git a/extensions/ql-vscode/test/vscode-tests/no-workspace/query-history/query-history-manager.test.ts b/extensions/ql-vscode/test/vscode-tests/no-workspace/query-history/query-history-manager.test.ts index b02ba6833..60f0095aa 100644 --- a/extensions/ql-vscode/test/vscode-tests/no-workspace/query-history/query-history-manager.test.ts +++ b/extensions/ql-vscode/test/vscode-tests/no-workspace/query-history/query-history-manager.test.ts @@ -41,6 +41,9 @@ describe("QueryHistoryManager", () => { let executeCommandSpy: jest.SpiedFunction< typeof vscode.commands.executeCommand >; + let cancelVariantAnalysisSpy: jest.SpiedFunction< + typeof variantAnalysisManagerStub.cancelVariantAnalysis + >; const doCompareCallback = jest.fn(); let queryHistoryManager: QueryHistoryManager; @@ -82,9 +85,14 @@ describe("QueryHistoryManager", () => { onVariantAnalysisStatusUpdated: jest.fn(), onVariantAnalysisRemoved: jest.fn(), removeVariantAnalysis: jest.fn(), + cancelVariantAnalysis: jest.fn(), showView: jest.fn(), } as any as VariantAnalysisManager; + cancelVariantAnalysisSpy = jest + .spyOn(variantAnalysisManagerStub, "cancelVariantAnalysis") + .mockResolvedValue(undefined); + localQueryHistory = [ // completed createMockLocalQueryInfo({ @@ -729,8 +737,7 @@ describe("QueryHistoryManager", () => { const inProgress1 = variantAnalysisHistory[1]; await queryHistoryManager.handleCancel(inProgress1, [inProgress1]); - expect(executeCommandSpy).toBeCalledWith( - "codeQL.cancelVariantAnalysis", + expect(cancelVariantAnalysisSpy).toBeCalledWith( inProgress1.variantAnalysis.id, ); }); @@ -746,12 +753,10 @@ describe("QueryHistoryManager", () => { inProgress1, inProgress2, ]); - expect(executeCommandSpy).toBeCalledWith( - "codeQL.cancelVariantAnalysis", + expect(cancelVariantAnalysisSpy).toBeCalledWith( inProgress1.variantAnalysis.id, ); - expect(executeCommandSpy).toBeCalledWith( - "codeQL.cancelVariantAnalysis", + expect(cancelVariantAnalysisSpy).toBeCalledWith( inProgress2.variantAnalysis.id, ); }); @@ -793,8 +798,7 @@ describe("QueryHistoryManager", () => { await queryHistoryManager.handleCancel(completedVariantAnalysis, [ completedVariantAnalysis, ]); - expect(executeCommandSpy).not.toBeCalledWith( - "codeQL.cancelVariantAnalysis", + expect(cancelVariantAnalysisSpy).not.toBeCalledWith( completedVariantAnalysis.variantAnalysis, ); }); @@ -810,12 +814,10 @@ describe("QueryHistoryManager", () => { completedVariantAnalysis, failedVariantAnalysis, ]); - expect(executeCommandSpy).not.toBeCalledWith( - "codeQL.cancelVariantAnalysis", + expect(cancelVariantAnalysisSpy).not.toBeCalledWith( completedVariantAnalysis.variantAnalysis.id, ); - expect(executeCommandSpy).not.toBeCalledWith( - "codeQL.cancelVariantAnalysis", + expect(cancelVariantAnalysisSpy).not.toBeCalledWith( failedVariantAnalysis.variantAnalysis.id, ); }); From a44ecadae52e6513ce2674b5a8dced5d44e82de8 Mon Sep 17 00:00:00 2001 From: Robert Date: Fri, 17 Mar 2023 16:09:00 +0000 Subject: [PATCH 063/156] Add telemetry for exporting variant analysis results --- .../ql-vscode/src/view/variant-analysis/VariantAnalysis.tsx | 1 + 1 file changed, 1 insertion(+) diff --git a/extensions/ql-vscode/src/view/variant-analysis/VariantAnalysis.tsx b/extensions/ql-vscode/src/view/variant-analysis/VariantAnalysis.tsx index 6c2f27051..d88edf468 100644 --- a/extensions/ql-vscode/src/view/variant-analysis/VariantAnalysis.tsx +++ b/extensions/ql-vscode/src/view/variant-analysis/VariantAnalysis.tsx @@ -137,6 +137,7 @@ export function VariantAnalysis({ repositoryIds: selectedRepositoryIds, }, }); + sendTelemetry("variant-analysis-export-results"); }, [filterSortState, selectedRepositoryIds]); if ( From 94db1dff73a21a89c1ec4d6fc3631677833bd706 Mon Sep 17 00:00:00 2001 From: Robert Date: Fri, 17 Mar 2023 15:51:00 +0000 Subject: [PATCH 064/156] Remove codeQL.openVariantAnalysisQueryText command --- extensions/ql-vscode/src/extension.ts | 9 --------- .../src/query-history/query-history-manager.ts | 3 +-- .../variant-analysis-view-manager.ts | 1 + .../src/variant-analysis/variant-analysis-view.ts | 5 +---- .../src/view/variant-analysis/VariantAnalysis.tsx | 1 + .../query-history/variant-analysis-history.test.ts | 14 ++++++++------ 6 files changed, 12 insertions(+), 21 deletions(-) diff --git a/extensions/ql-vscode/src/extension.ts b/extensions/ql-vscode/src/extension.ts index d85f05beb..ba03356a9 100644 --- a/extensions/ql-vscode/src/extension.ts +++ b/extensions/ql-vscode/src/extension.ts @@ -1198,15 +1198,6 @@ async function activateWithInstalledDistribution( ), ); - ctx.subscriptions.push( - commandRunner( - "codeQL.openVariantAnalysisQueryText", - async (variantAnalysisId: number) => { - await variantAnalysisManager.openQueryText(variantAnalysisId); - }, - ), - ); - ctx.subscriptions.push( commandRunner("codeQL.openReferencedFile", async (selectedQuery: Uri) => { await openReferencedFile(qs, cliServer, selectedQuery); diff --git a/extensions/ql-vscode/src/query-history/query-history-manager.ts b/extensions/ql-vscode/src/query-history/query-history-manager.ts index cb702fa05..d5d7ff19a 100644 --- a/extensions/ql-vscode/src/query-history/query-history-manager.ts +++ b/extensions/ql-vscode/src/query-history/query-history-manager.ts @@ -1034,8 +1034,7 @@ export class QueryHistoryManager extends DisposableObject { } if (finalSingleItem.t === "variant-analysis") { - await commands.executeCommand( - "codeQL.openVariantAnalysisQueryText", + await this.variantAnalysisManager.openQueryText( finalSingleItem.variantAnalysis.id, ); return; diff --git a/extensions/ql-vscode/src/variant-analysis/variant-analysis-view-manager.ts b/extensions/ql-vscode/src/variant-analysis/variant-analysis-view-manager.ts index 07aa1be33..c47220455 100644 --- a/extensions/ql-vscode/src/variant-analysis/variant-analysis-view-manager.ts +++ b/extensions/ql-vscode/src/variant-analysis/variant-analysis-view-manager.ts @@ -25,5 +25,6 @@ export interface VariantAnalysisViewManager< variantAnalysisId: number, ): Promise; openQueryFile(variantAnalysisId: number): Promise; + openQueryText(variantAnalysisId: number): Promise; cancelVariantAnalysis(variantAnalysisId: number): Promise; } diff --git a/extensions/ql-vscode/src/variant-analysis/variant-analysis-view.ts b/extensions/ql-vscode/src/variant-analysis/variant-analysis-view.ts index 858256080..f4f6e7280 100644 --- a/extensions/ql-vscode/src/variant-analysis/variant-analysis-view.ts +++ b/extensions/ql-vscode/src/variant-analysis/variant-analysis-view.ts @@ -123,10 +123,7 @@ export class VariantAnalysisView await this.manager.openQueryFile(this.variantAnalysisId); break; case "openQueryText": - void commands.executeCommand( - "codeQL.openVariantAnalysisQueryText", - this.variantAnalysisId, - ); + await this.manager.openQueryText(this.variantAnalysisId); break; case "copyRepositoryList": void commands.executeCommand( diff --git a/extensions/ql-vscode/src/view/variant-analysis/VariantAnalysis.tsx b/extensions/ql-vscode/src/view/variant-analysis/VariantAnalysis.tsx index 73aed5974..4e932accb 100644 --- a/extensions/ql-vscode/src/view/variant-analysis/VariantAnalysis.tsx +++ b/extensions/ql-vscode/src/view/variant-analysis/VariantAnalysis.tsx @@ -32,6 +32,7 @@ const openQueryText = () => { vscode.postMessage({ t: "openQueryText", }); + sendTelemetry("variant-analysis-open-query-text"); }; const stopQuery = () => { diff --git a/extensions/ql-vscode/test/vscode-tests/no-workspace/query-history/variant-analysis-history.test.ts b/extensions/ql-vscode/test/vscode-tests/no-workspace/query-history/variant-analysis-history.test.ts index 6441d2fea..f36267065 100644 --- a/extensions/ql-vscode/test/vscode-tests/no-workspace/query-history/variant-analysis-history.test.ts +++ b/extensions/ql-vscode/test/vscode-tests/no-workspace/query-history/variant-analysis-history.test.ts @@ -8,7 +8,7 @@ import { } from "fs-extra"; import { join } from "path"; -import { commands, ExtensionContext, Uri } from "vscode"; +import { ExtensionContext, Uri } from "vscode"; import { DatabaseManager } from "../../../../src/local-databases"; import { tmpDir, walkDirectory } from "../../../../src/helpers"; import { DisposableBucket } from "../../disposable-bucket"; @@ -54,9 +54,12 @@ describe("Variant Analyses and QueryHistoryManager", () => { rehydrateVariantAnalysis: rehydrateVariantAnalysisStub, onVariantAnalysisStatusUpdated: jest.fn(), showView: showViewStub, + openQueryText: jest.fn(), } as any as VariantAnalysisManager; - let executeCommandSpy: jest.SpiedFunction; + let openQueryTextSpy: jest.SpiedFunction< + typeof variantAnalysisManagerStub.openQueryText + >; beforeEach(async () => { // Since these tests change the state of the query history manager, we need to copy the original @@ -95,8 +98,8 @@ describe("Variant Analyses and QueryHistoryManager", () => { ); disposables.push(qhm); - executeCommandSpy = jest - .spyOn(commands, "executeCommand") + openQueryTextSpy = jest + .spyOn(variantAnalysisManagerStub, "openQueryText") .mockResolvedValue(undefined); }); @@ -180,8 +183,7 @@ describe("Variant Analyses and QueryHistoryManager", () => { await qhm.readQueryHistory(); await qhm.handleShowQueryText(qhm.treeDataProvider.allHistory[0], []); - expect(executeCommandSpy).toHaveBeenCalledWith( - "codeQL.openVariantAnalysisQueryText", + expect(openQueryTextSpy).toHaveBeenCalledWith( rawQueryHistory[0].variantAnalysis.id, ); }); From af63e5094ff20e31bacefe632b0dde5ae89370b2 Mon Sep 17 00:00:00 2001 From: Koen Vlaswinkel Date: Mon, 20 Mar 2023 11:19:26 +0100 Subject: [PATCH 065/156] Convert `commandRunnerWithProgress` invocations to `withProgress` --- extensions/ql-vscode/src/extension.ts | 12 +- .../ql-vscode/src/local-databases-ui.ts | 373 ++++++++++-------- 2 files changed, 210 insertions(+), 175 deletions(-) diff --git a/extensions/ql-vscode/src/extension.ts b/extensions/ql-vscode/src/extension.ts index a3502bb21..67fcb49ee 100644 --- a/extensions/ql-vscode/src/extension.ts +++ b/extensions/ql-vscode/src/extension.ts @@ -1270,7 +1270,7 @@ async function activateWithInstalledDistribution( commandRunnerWithProgress( "codeQL.chooseDatabaseFolder", (progress: ProgressCallback, token: CancellationToken) => - databaseUI.handleChooseDatabaseFolder(progress, token), + databaseUI.chooseDatabaseFolder(progress, token), { title: "Choose a Database from a Folder", }, @@ -1280,7 +1280,7 @@ async function activateWithInstalledDistribution( commandRunnerWithProgress( "codeQL.chooseDatabaseArchive", (progress: ProgressCallback, token: CancellationToken) => - databaseUI.handleChooseDatabaseArchive(progress, token), + databaseUI.chooseDatabaseArchive(progress, token), { title: "Choose a Database from an Archive", }, @@ -1291,11 +1291,7 @@ async function activateWithInstalledDistribution( "codeQL.chooseDatabaseGithub", async (progress: ProgressCallback, token: CancellationToken) => { const credentials = isCanary() ? app.credentials : undefined; - await databaseUI.handleChooseDatabaseGithub( - credentials, - progress, - token, - ); + await databaseUI.chooseDatabaseGithub(credentials, progress, token); }, { title: "Adding database from GitHub", @@ -1306,7 +1302,7 @@ async function activateWithInstalledDistribution( commandRunnerWithProgress( "codeQL.chooseDatabaseInternet", (progress: ProgressCallback, token: CancellationToken) => - databaseUI.handleChooseDatabaseInternet(progress, token), + databaseUI.chooseDatabaseInternet(progress, token), { title: "Adding database from URL", diff --git a/extensions/ql-vscode/src/local-databases-ui.ts b/extensions/ql-vscode/src/local-databases-ui.ts index 5d6d8fcc0..402e6a2d2 100644 --- a/extensions/ql-vscode/src/local-databases-ui.ts +++ b/extensions/ql-vscode/src/local-databases-ui.ts @@ -21,11 +21,7 @@ import { DatabaseItem, DatabaseManager, } from "./local-databases"; -import { - commandRunner, - commandRunnerWithProgress, - ProgressCallback, -} from "./commandRunner"; +import { commandRunner, ProgressCallback, withProgress } from "./commandRunner"; import { isLikelyDatabaseRoot, isLikelyDbLanguageFolder, @@ -213,77 +209,45 @@ export class DatabaseUI extends DisposableObject { init() { void extLogger.log("Registering database panel commands."); this.push( - commandRunnerWithProgress( - "codeQL.setCurrentDatabase", - this.handleSetCurrentDatabase, - { - title: "Importing database from archive", - }, - ), + commandRunner("codeQL.setCurrentDatabase", this.handleSetCurrentDatabase), ); this.push( - commandRunnerWithProgress( + commandRunner( "codeQL.setDefaultTourDatabase", this.handleSetDefaultTourDatabase, - { - title: "Set Default Database for Codespace CodeQL Tour", - }, ), ); this.push( - commandRunnerWithProgress( + commandRunner( "codeQL.upgradeCurrentDatabase", this.handleUpgradeCurrentDatabase, - { - title: "Upgrading current database", - cancellable: true, - }, ), ); - this.push( - commandRunnerWithProgress("codeQL.clearCache", this.handleClearCache, { - title: "Clearing Cache", - }), - ); + this.push(commandRunner("codeQL.clearCache", this.handleClearCache)); this.push( - commandRunnerWithProgress( + commandRunner( "codeQLDatabases.chooseDatabaseFolder", this.handleChooseDatabaseFolder, - { - title: "Adding database from folder", - }, ), ); this.push( - commandRunnerWithProgress( + commandRunner( "codeQLDatabases.chooseDatabaseArchive", this.handleChooseDatabaseArchive, - { - title: "Adding database from archive", - }, ), ); this.push( - commandRunnerWithProgress( + commandRunner( "codeQLDatabases.chooseDatabaseInternet", this.handleChooseDatabaseInternet, - { - title: "Adding database from URL", - }, ), ); this.push( - commandRunnerWithProgress( - "codeQLDatabases.chooseDatabaseGithub", - async (progress: ProgressCallback, token: CancellationToken) => { - const credentials = isCanary() ? this.app.credentials : undefined; - await this.handleChooseDatabaseGithub(credentials, progress, token); - }, - { - title: "Adding database from GitHub", - }, - ), + commandRunner("codeQLDatabases.chooseDatabaseGithub", async () => { + const credentials = isCanary() ? this.app.credentials : undefined; + await this.handleChooseDatabaseGithub(credentials); + }), ); this.push( commandRunner( @@ -301,23 +265,15 @@ export class DatabaseUI extends DisposableObject { ), ); this.push( - commandRunnerWithProgress( + commandRunner( "codeQLDatabases.removeDatabase", this.handleRemoveDatabase, - { - title: "Removing database", - cancellable: false, - }, ), ); this.push( - commandRunnerWithProgress( + commandRunner( "codeQLDatabases.upgradeDatabase", this.handleUpgradeDatabase, - { - title: "Upgrading database", - cancellable: true, - }, ), ); this.push( @@ -349,7 +305,7 @@ export class DatabaseUI extends DisposableObject { await this.databaseManager.setCurrentDatabaseItem(databaseItem); }; - handleChooseDatabaseFolder = async ( + chooseDatabaseFolder = async ( progress: ProgressCallback, token: CancellationToken, ): Promise => { @@ -364,42 +320,57 @@ export class DatabaseUI extends DisposableObject { } }; - private handleSetDefaultTourDatabase = async ( - progress: ProgressCallback, - token: CancellationToken, - ): Promise => { - try { - if (!workspace.workspaceFolders?.length) { - throw new Error("No workspace folder is open."); - } else { - // This specifically refers to the database folder in - // https://github.com/github/codespaces-codeql - const uri = Uri.parse( - `${workspace.workspaceFolders[0].uri}/.tours/codeql-tutorial-database`, - ); + private handleChooseDatabaseFolder = async (): Promise => { + return withProgress( + async (progress, token) => { + await this.chooseDatabaseFolder(progress, token); + }, + { + title: "Adding database from folder", + }, + ); + }; - let databaseItem = this.databaseManager.findDatabaseItem(uri); - const isTutorialDatabase = true; - if (databaseItem === undefined) { - databaseItem = await this.databaseManager.openDatabase( - progress, - token, - uri, - "CodeQL Tutorial Database", - isTutorialDatabase, + private handleSetDefaultTourDatabase = async (): Promise => { + return withProgress( + async (progress, token) => { + try { + if (!workspace.workspaceFolders?.length) { + throw new Error("No workspace folder is open."); + } else { + // This specifically refers to the database folder in + // https://github.com/github/codespaces-codeql + const uri = Uri.parse( + `${workspace.workspaceFolders[0].uri}/.tours/codeql-tutorial-database`, + ); + + let databaseItem = this.databaseManager.findDatabaseItem(uri); + const isTutorialDatabase = true; + if (databaseItem === undefined) { + databaseItem = await this.databaseManager.openDatabase( + progress, + token, + uri, + "CodeQL Tutorial Database", + isTutorialDatabase, + ); + } + await this.databaseManager.setCurrentDatabaseItem(databaseItem); + await this.handleTourDependencies(); + } + } catch (e) { + // rethrow and let this be handled by default error handling. + throw new Error( + `Could not set the database for the Code Tour. Please make sure you are using the default workspace in your codespace: ${getErrorMessage( + e, + )}`, ); } - await this.databaseManager.setCurrentDatabaseItem(databaseItem); - await this.handleTourDependencies(); - } - } catch (e) { - // rethrow and let this be handled by default error handling. - throw new Error( - `Could not set the database for the Code Tour. Please make sure you are using the default workspace in your codespace: ${getErrorMessage( - e, - )}`, - ); - } + }, + { + title: "Set Default Database for Codespace CodeQL Tour", + }, + ); }; private handleTourDependencies = async (): Promise => { @@ -483,7 +454,7 @@ export class DatabaseUI extends DisposableObject { } }; - handleChooseDatabaseArchive = async ( + chooseDatabaseArchive = async ( progress: ProgressCallback, token: CancellationToken, ): Promise => { @@ -498,7 +469,18 @@ export class DatabaseUI extends DisposableObject { } }; - handleChooseDatabaseInternet = async ( + private handleChooseDatabaseArchive = async (): Promise => { + return withProgress( + async (progress, token) => { + await this.chooseDatabaseArchive(progress, token); + }, + { + title: "Adding database from archive", + }, + ); + }; + + chooseDatabaseInternet = async ( progress: ProgressCallback, token: CancellationToken, ): Promise => { @@ -511,7 +493,20 @@ export class DatabaseUI extends DisposableObject { ); }; - handleChooseDatabaseGithub = async ( + private handleChooseDatabaseInternet = async (): Promise< + DatabaseItem | undefined + > => { + return withProgress( + async (progress, token) => { + return await this.chooseDatabaseInternet(progress, token); + }, + { + title: "Adding database from URL", + }, + ); + }; + + chooseDatabaseGithub = async ( credentials: Credentials | undefined, progress: ProgressCallback, token: CancellationToken, @@ -526,12 +521,18 @@ export class DatabaseUI extends DisposableObject { ); }; - async tryUpgradeCurrentDatabase( - progress: ProgressCallback, - token: CancellationToken, - ) { - await this.handleUpgradeCurrentDatabase(progress, token); - } + private handleChooseDatabaseGithub = async ( + credentials: Credentials | undefined, + ): Promise => { + return withProgress( + async (progress, token) => { + return await this.chooseDatabaseGithub(credentials, progress, token); + }, + { + title: "Adding database from GitHub", + }, + ); + }; private handleSortByName = async () => { if (this.treeDataProvider.sortOrder === SortOrder.NameAsc) { @@ -549,19 +550,44 @@ export class DatabaseUI extends DisposableObject { } }; - private handleUpgradeCurrentDatabase = async ( - progress: ProgressCallback, - token: CancellationToken, - ): Promise => { - await this.handleUpgradeDatabase( - progress, - token, - this.databaseManager.currentDatabaseItem, - [], + private handleUpgradeCurrentDatabase = async (): Promise => { + return withProgress( + async (progress, token) => { + await this.handleUpgradeDatabaseInternal( + progress, + token, + this.databaseManager.currentDatabaseItem, + [], + ); + }, + { + title: "Upgrading current database", + cancellable: true, + }, ); }; private handleUpgradeDatabase = async ( + databaseItem: DatabaseItem | undefined, + multiSelect: DatabaseItem[] | undefined, + ): Promise => { + return withProgress( + async (progress, token) => { + return await this.handleUpgradeDatabaseInternal( + progress, + token, + databaseItem, + multiSelect, + ); + }, + { + title: "Upgrading database", + cancellable: true, + }, + ); + }; + + private handleUpgradeDatabaseInternal = async ( progress: ProgressCallback, token: CancellationToken, databaseItem: DatabaseItem | undefined, @@ -570,7 +596,7 @@ export class DatabaseUI extends DisposableObject { if (multiSelect?.length) { await Promise.all( multiSelect.map((dbItem) => - this.handleUpgradeDatabase(progress, token, dbItem, []), + this.handleUpgradeDatabaseInternal(progress, token, dbItem, []), ), ); } @@ -604,70 +630,83 @@ export class DatabaseUI extends DisposableObject { ); }; - private handleClearCache = async ( - progress: ProgressCallback, - token: CancellationToken, - ): Promise => { - if ( - this.queryServer !== undefined && - this.databaseManager.currentDatabaseItem !== undefined - ) { - await this.queryServer.clearCacheInDatabase( - this.databaseManager.currentDatabaseItem, - progress, - token, - ); - } + private handleClearCache = async (): Promise => { + return withProgress( + async (progress, token) => { + if ( + this.queryServer !== undefined && + this.databaseManager.currentDatabaseItem !== undefined + ) { + await this.queryServer.clearCacheInDatabase( + this.databaseManager.currentDatabaseItem, + progress, + token, + ); + } + }, + { + title: "Clearing cache", + }, + ); }; - private handleSetCurrentDatabase = async ( - progress: ProgressCallback, - token: CancellationToken, - uri: Uri, - ): Promise => { - try { - // Assume user has selected an archive if the file has a .zip extension - if (uri.path.endsWith(".zip")) { - await importArchiveDatabase( - uri.toString(true), - this.databaseManager, - this.storagePath, - progress, - token, - this.queryServer?.cliServer, - ); - } else { - await this.setCurrentDatabase(progress, token, uri); - } - } catch (e) { - // rethrow and let this be handled by default error handling. - throw new Error( - `Could not set database to ${basename( - uri.fsPath, - )}. Reason: ${getErrorMessage(e)}`, - ); - } + private handleSetCurrentDatabase = async (uri: Uri): Promise => { + return withProgress( + async (progress, token) => { + try { + // Assume user has selected an archive if the file has a .zip extension + if (uri.path.endsWith(".zip")) { + await importArchiveDatabase( + uri.toString(true), + this.databaseManager, + this.storagePath, + progress, + token, + this.queryServer?.cliServer, + ); + } else { + await this.setCurrentDatabase(progress, token, uri); + } + } catch (e) { + // rethrow and let this be handled by default error handling. + throw new Error( + `Could not set database to ${basename( + uri.fsPath, + )}. Reason: ${getErrorMessage(e)}`, + ); + } + }, + { + title: "Importing database from archive", + }, + ); }; private handleRemoveDatabase = async ( - progress: ProgressCallback, - token: CancellationToken, databaseItem: DatabaseItem, multiSelect: DatabaseItem[] | undefined, ): Promise => { - if (multiSelect?.length) { - await Promise.all( - multiSelect.map((dbItem) => - this.databaseManager.removeDatabaseItem(progress, token, dbItem), - ), - ); - } else { - await this.databaseManager.removeDatabaseItem( - progress, - token, - databaseItem, - ); - } + return withProgress( + async (progress, token) => { + if (multiSelect?.length) { + await Promise.all( + multiSelect.map((dbItem) => + this.databaseManager.removeDatabaseItem(progress, token, dbItem), + ), + ); + } else { + await this.databaseManager.removeDatabaseItem( + progress, + token, + databaseItem, + ); + } + }, + { + title: "Removing database", + cancellable: false, + }, + ); }; private handleRenameDatabase = async ( From dbd832f1a0549a6f6faaeee63a7f131d2dc37f89 Mon Sep 17 00:00:00 2001 From: Koen Vlaswinkel Date: Mon, 20 Mar 2023 11:29:45 +0100 Subject: [PATCH 066/156] Switch local databases to function definitions The local databases UI was essentially the only class which was defining methods using assignment to a class property rather than using function definitions and binding them. This switches it to use function definitions and binding, which is more consistent with the rest of the codebase. --- .../ql-vscode/src/local-databases-ui.ts | 176 ++++++++++-------- 1 file changed, 94 insertions(+), 82 deletions(-) diff --git a/extensions/ql-vscode/src/local-databases-ui.ts b/extensions/ql-vscode/src/local-databases-ui.ts index 402e6a2d2..22fd7e071 100644 --- a/extensions/ql-vscode/src/local-databases-ui.ts +++ b/extensions/ql-vscode/src/local-databases-ui.ts @@ -69,12 +69,12 @@ class DatabaseTreeDataProvider this.push( this.databaseManager.onDidChangeDatabaseItem( - this.handleDidChangeDatabaseItem, + this.handleDidChangeDatabaseItem.bind(this), ), ); this.push( this.databaseManager.onDidChangeCurrentDatabaseItem( - this.handleDidChangeCurrentDatabaseItem, + this.handleDidChangeCurrentDatabaseItem.bind(this), ), ); } @@ -83,18 +83,18 @@ class DatabaseTreeDataProvider return this._onDidChangeTreeData.event; } - private handleDidChangeDatabaseItem = (event: DatabaseChangedEvent): void => { + private handleDidChangeDatabaseItem(event: DatabaseChangedEvent): void { // Note that events from the database manager are instances of DatabaseChangedEvent // and events fired by the UI are instances of DatabaseItem // When event.item is undefined, then the entire tree is refreshed. // When event.item is a db item, then only that item is refreshed. this._onDidChangeTreeData.fire(event.item); - }; + } - private handleDidChangeCurrentDatabaseItem = ( + private handleDidChangeCurrentDatabaseItem( event: DatabaseChangedEvent, - ): void => { + ): void { if (this.currentDatabaseItem) { this._onDidChangeTreeData.fire(this.currentDatabaseItem); } @@ -102,7 +102,7 @@ class DatabaseTreeDataProvider if (this.currentDatabaseItem) { this._onDidChangeTreeData.fire(this.currentDatabaseItem); } - }; + } public getTreeItem(element: DatabaseItem): TreeItem { const item = new TreeItem(element.name); @@ -209,38 +209,43 @@ export class DatabaseUI extends DisposableObject { init() { void extLogger.log("Registering database panel commands."); this.push( - commandRunner("codeQL.setCurrentDatabase", this.handleSetCurrentDatabase), + commandRunner( + "codeQL.setCurrentDatabase", + this.handleSetCurrentDatabase.bind(this), + ), ); this.push( commandRunner( "codeQL.setDefaultTourDatabase", - this.handleSetDefaultTourDatabase, + this.handleSetDefaultTourDatabase.bind(this), ), ); this.push( commandRunner( "codeQL.upgradeCurrentDatabase", - this.handleUpgradeCurrentDatabase, + this.handleUpgradeCurrentDatabase.bind(this), ), ); - this.push(commandRunner("codeQL.clearCache", this.handleClearCache)); + this.push( + commandRunner("codeQL.clearCache", this.handleClearCache.bind(this)), + ); this.push( commandRunner( "codeQLDatabases.chooseDatabaseFolder", - this.handleChooseDatabaseFolder, + this.handleChooseDatabaseFolder.bind(this), ), ); this.push( commandRunner( "codeQLDatabases.chooseDatabaseArchive", - this.handleChooseDatabaseArchive, + this.handleChooseDatabaseArchive.bind(this), ), ); this.push( commandRunner( "codeQLDatabases.chooseDatabaseInternet", - this.handleChooseDatabaseInternet, + this.handleChooseDatabaseInternet.bind(this), ), ); this.push( @@ -252,63 +257,69 @@ export class DatabaseUI extends DisposableObject { this.push( commandRunner( "codeQLDatabases.setCurrentDatabase", - this.handleMakeCurrentDatabase, + this.handleMakeCurrentDatabase.bind(this), ), ); this.push( - commandRunner("codeQLDatabases.sortByName", this.handleSortByName), + commandRunner( + "codeQLDatabases.sortByName", + this.handleSortByName.bind(this), + ), ); this.push( commandRunner( "codeQLDatabases.sortByDateAdded", - this.handleSortByDateAdded, + this.handleSortByDateAdded.bind(this), ), ); this.push( commandRunner( "codeQLDatabases.removeDatabase", - this.handleRemoveDatabase, + this.handleRemoveDatabase.bind(this), ), ); this.push( commandRunner( "codeQLDatabases.upgradeDatabase", - this.handleUpgradeDatabase, + this.handleUpgradeDatabase.bind(this), ), ); this.push( commandRunner( "codeQLDatabases.renameDatabase", - this.handleRenameDatabase, + this.handleRenameDatabase.bind(this), ), ); this.push( commandRunner( "codeQLDatabases.openDatabaseFolder", - this.handleOpenFolder, + this.handleOpenFolder.bind(this), ), ); this.push( - commandRunner("codeQLDatabases.addDatabaseSource", this.handleAddSource), + commandRunner( + "codeQLDatabases.addDatabaseSource", + this.handleAddSource.bind(this), + ), ); this.push( commandRunner( "codeQLDatabases.removeOrphanedDatabases", - this.handleRemoveOrphanedDatabases, + this.handleRemoveOrphanedDatabases.bind(this), ), ); } - private handleMakeCurrentDatabase = async ( + private async handleMakeCurrentDatabase( databaseItem: DatabaseItem, - ): Promise => { + ): Promise { await this.databaseManager.setCurrentDatabaseItem(databaseItem); - }; + } - chooseDatabaseFolder = async ( + public async chooseDatabaseFolder( progress: ProgressCallback, token: CancellationToken, - ): Promise => { + ): Promise { try { await this.chooseAndSetDatabase(true, progress, token); } catch (e) { @@ -318,9 +329,9 @@ export class DatabaseUI extends DisposableObject { )`Failed to choose and set database: ${getErrorMessage(e)}`, ); } - }; + } - private handleChooseDatabaseFolder = async (): Promise => { + private async handleChooseDatabaseFolder(): Promise { return withProgress( async (progress, token) => { await this.chooseDatabaseFolder(progress, token); @@ -329,9 +340,9 @@ export class DatabaseUI extends DisposableObject { title: "Adding database from folder", }, ); - }; + } - private handleSetDefaultTourDatabase = async (): Promise => { + private async handleSetDefaultTourDatabase(): Promise { return withProgress( async (progress, token) => { try { @@ -371,9 +382,9 @@ export class DatabaseUI extends DisposableObject { title: "Set Default Database for Codespace CodeQL Tour", }, ); - }; + } - private handleTourDependencies = async (): Promise => { + private async handleTourDependencies(): Promise { if (!workspace.workspaceFolders?.length) { throw new Error("No workspace folder is open."); } else { @@ -387,9 +398,10 @@ export class DatabaseUI extends DisposableObject { } await cli.packInstall(tutorialQueriesPath); } - }; + } - handleRemoveOrphanedDatabases = async (): Promise => { + // Public because it's used in tests + public async handleRemoveOrphanedDatabases(): Promise { void extLogger.log("Removing orphaned databases from workspace storage."); let dbDirs = undefined; @@ -452,12 +464,12 @@ export class DatabaseUI extends DisposableObject { )}).\nTo delete unused databases, please remove them manually from the storage folder ${dirname}.`, ); } - }; + } - chooseDatabaseArchive = async ( + public async chooseDatabaseArchive( progress: ProgressCallback, token: CancellationToken, - ): Promise => { + ): Promise { try { await this.chooseAndSetDatabase(false, progress, token); } catch (e: unknown) { @@ -467,9 +479,9 @@ export class DatabaseUI extends DisposableObject { )`Failed to choose and set database: ${getErrorMessage(e)}`, ); } - }; + } - private handleChooseDatabaseArchive = async (): Promise => { + private async handleChooseDatabaseArchive(): Promise { return withProgress( async (progress, token) => { await this.chooseDatabaseArchive(progress, token); @@ -478,12 +490,12 @@ export class DatabaseUI extends DisposableObject { title: "Adding database from archive", }, ); - }; + } - chooseDatabaseInternet = async ( + public async chooseDatabaseInternet( progress: ProgressCallback, token: CancellationToken, - ): Promise => { + ): Promise { return await promptImportInternetDatabase( this.databaseManager, this.storagePath, @@ -491,11 +503,11 @@ export class DatabaseUI extends DisposableObject { token, this.queryServer?.cliServer, ); - }; + } - private handleChooseDatabaseInternet = async (): Promise< + private async handleChooseDatabaseInternet(): Promise< DatabaseItem | undefined - > => { + > { return withProgress( async (progress, token) => { return await this.chooseDatabaseInternet(progress, token); @@ -504,13 +516,13 @@ export class DatabaseUI extends DisposableObject { title: "Adding database from URL", }, ); - }; + } - chooseDatabaseGithub = async ( + public async chooseDatabaseGithub( credentials: Credentials | undefined, progress: ProgressCallback, token: CancellationToken, - ): Promise => { + ): Promise { return await promptImportGithubDatabase( this.databaseManager, this.storagePath, @@ -519,11 +531,11 @@ export class DatabaseUI extends DisposableObject { token, this.queryServer?.cliServer, ); - }; + } - private handleChooseDatabaseGithub = async ( + private async handleChooseDatabaseGithub( credentials: Credentials | undefined, - ): Promise => { + ): Promise { return withProgress( async (progress, token) => { return await this.chooseDatabaseGithub(credentials, progress, token); @@ -532,25 +544,25 @@ export class DatabaseUI extends DisposableObject { title: "Adding database from GitHub", }, ); - }; + } - private handleSortByName = async () => { + private async handleSortByName() { if (this.treeDataProvider.sortOrder === SortOrder.NameAsc) { this.treeDataProvider.sortOrder = SortOrder.NameDesc; } else { this.treeDataProvider.sortOrder = SortOrder.NameAsc; } - }; + } - private handleSortByDateAdded = async () => { + private async handleSortByDateAdded() { if (this.treeDataProvider.sortOrder === SortOrder.DateAddedAsc) { this.treeDataProvider.sortOrder = SortOrder.DateAddedDesc; } else { this.treeDataProvider.sortOrder = SortOrder.DateAddedAsc; } - }; + } - private handleUpgradeCurrentDatabase = async (): Promise => { + private async handleUpgradeCurrentDatabase(): Promise { return withProgress( async (progress, token) => { await this.handleUpgradeDatabaseInternal( @@ -565,12 +577,12 @@ export class DatabaseUI extends DisposableObject { cancellable: true, }, ); - }; + } - private handleUpgradeDatabase = async ( + private async handleUpgradeDatabase( databaseItem: DatabaseItem | undefined, multiSelect: DatabaseItem[] | undefined, - ): Promise => { + ): Promise { return withProgress( async (progress, token) => { return await this.handleUpgradeDatabaseInternal( @@ -585,14 +597,14 @@ export class DatabaseUI extends DisposableObject { cancellable: true, }, ); - }; + } - private handleUpgradeDatabaseInternal = async ( + private async handleUpgradeDatabaseInternal( progress: ProgressCallback, token: CancellationToken, databaseItem: DatabaseItem | undefined, multiSelect: DatabaseItem[] | undefined, - ): Promise => { + ): Promise { if (multiSelect?.length) { await Promise.all( multiSelect.map((dbItem) => @@ -628,9 +640,9 @@ export class DatabaseUI extends DisposableObject { progress, token, ); - }; + } - private handleClearCache = async (): Promise => { + private async handleClearCache(): Promise { return withProgress( async (progress, token) => { if ( @@ -648,9 +660,9 @@ export class DatabaseUI extends DisposableObject { title: "Clearing cache", }, ); - }; + } - private handleSetCurrentDatabase = async (uri: Uri): Promise => { + private async handleSetCurrentDatabase(uri: Uri): Promise { return withProgress( async (progress, token) => { try { @@ -680,12 +692,12 @@ export class DatabaseUI extends DisposableObject { title: "Importing database from archive", }, ); - }; + } - private handleRemoveDatabase = async ( + private async handleRemoveDatabase( databaseItem: DatabaseItem, multiSelect: DatabaseItem[] | undefined, - ): Promise => { + ): Promise { return withProgress( async (progress, token) => { if (multiSelect?.length) { @@ -707,12 +719,12 @@ export class DatabaseUI extends DisposableObject { cancellable: false, }, ); - }; + } - private handleRenameDatabase = async ( + private async handleRenameDatabase( databaseItem: DatabaseItem, multiSelect: DatabaseItem[] | undefined, - ): Promise => { + ): Promise { this.assertSingleDatabase(multiSelect); const newName = await window.showInputBox({ @@ -723,12 +735,12 @@ export class DatabaseUI extends DisposableObject { if (newName) { await this.databaseManager.renameDatabaseItem(databaseItem, newName); } - }; + } - private handleOpenFolder = async ( + private async handleOpenFolder( databaseItem: DatabaseItem, multiSelect: DatabaseItem[] | undefined, - ): Promise => { + ): Promise { if (multiSelect?.length) { await Promise.all( multiSelect.map((dbItem) => env.openExternal(dbItem.databaseUri)), @@ -736,17 +748,17 @@ export class DatabaseUI extends DisposableObject { } else { await env.openExternal(databaseItem.databaseUri); } - }; + } /** * Adds the source folder of a CodeQL database to the workspace. * When a database is first added in the "Databases" view, its source folder is added to the workspace. * If the source folder is removed from the workspace for some reason, we want to be able to re-add it if need be. */ - private handleAddSource = async ( + private async handleAddSource( databaseItem: DatabaseItem, multiSelect: DatabaseItem[] | undefined, - ): Promise => { + ): Promise { if (multiSelect?.length) { for (const dbItem of multiSelect) { await this.databaseManager.addDatabaseSourceArchiveFolder(dbItem); @@ -754,7 +766,7 @@ export class DatabaseUI extends DisposableObject { } else { await this.databaseManager.addDatabaseSourceArchiveFolder(databaseItem); } - }; + } /** * Return the current database directory. If we don't already have a From e603de41c1687e25991d3461ae926f035ed899c3 Mon Sep 17 00:00:00 2001 From: Koen Vlaswinkel Date: Mon, 20 Mar 2023 11:39:53 +0100 Subject: [PATCH 067/156] Convert local database commands to typed commands --- extensions/ql-vscode/src/common/commands.ts | 27 ++++ extensions/ql-vscode/src/extension.ts | 6 +- .../ql-vscode/src/local-databases-ui.ts | 135 ++++-------------- 3 files changed, 58 insertions(+), 110 deletions(-) diff --git a/extensions/ql-vscode/src/common/commands.ts b/extensions/ql-vscode/src/common/commands.ts index dcd175df0..5eaa5f733 100644 --- a/extensions/ql-vscode/src/common/commands.ts +++ b/extensions/ql-vscode/src/common/commands.ts @@ -1,5 +1,6 @@ import type { CommandManager } from "../packages/commands"; import type { Uri } from "vscode"; +import type { DatabaseItem } from "../local-databases"; import type { QueryHistoryInfo } from "../query-history/query-history-info"; // A command function matching the signature that VS Code calls when @@ -53,6 +54,31 @@ export type QueryHistoryCommands = { "codeQLQueryHistory.copyRepoList": SelectionCommandFunction; }; +// Commands used for the local databases panel +export type LocalDatabasesCommands = { + "codeQL.setCurrentDatabase": (uri: Uri) => Promise; + "codeQL.setDefaultTourDatabase": () => Promise; + "codeQL.upgradeCurrentDatabase": () => Promise; + "codeQL.clearCache": () => Promise; + + "codeQLDatabases.chooseDatabaseFolder": () => Promise; + "codeQLDatabases.chooseDatabaseArchive": () => Promise; + "codeQLDatabases.chooseDatabaseInternet": () => Promise; + "codeQLDatabases.chooseDatabaseGithub": () => Promise; + "codeQLDatabases.setCurrentDatabase": ( + databaseItem: DatabaseItem, + ) => Promise; + "codeQLDatabases.sortByName": () => Promise; + "codeQLDatabases.sortByDateAdded": () => Promise; + "codeQLDatabases.removeOrphanedDatabases": () => Promise; + + "codeQLDatabases.removeDatabase": SelectionCommandFunction; + "codeQLDatabases.upgradeDatabase": SelectionCommandFunction; + "codeQLDatabases.renameDatabase": SelectionCommandFunction; + "codeQLDatabases.openDatabaseFolder": SelectionCommandFunction; + "codeQLDatabases.addDatabaseSource": SelectionCommandFunction; +}; + // Commands tied to variant analysis export type VariantAnalysisCommands = { "codeQL.openVariantAnalysisLogs": ( @@ -64,6 +90,7 @@ export type VariantAnalysisCommands = { export type AllCommands = BaseCommands & QueryHistoryCommands & + LocalDatabasesCommands & VariantAnalysisCommands; export type AppCommandManager = CommandManager; diff --git a/extensions/ql-vscode/src/extension.ts b/extensions/ql-vscode/src/extension.ts index 67fcb49ee..03c90dceb 100644 --- a/extensions/ql-vscode/src/extension.ts +++ b/extensions/ql-vscode/src/extension.ts @@ -35,7 +35,6 @@ import { CodeQLCliServer } from "./cli"; import { CliConfigListener, DistributionConfigListener, - isCanary, joinOrderWarningThreshold, MAX_QUERIES, QueryHistoryConfigListener, @@ -642,7 +641,6 @@ async function activateWithInstalledDistribution( getContextStoragePath(ctx), ctx.extensionPath, ); - databaseUI.init(); ctx.subscriptions.push(databaseUI); void extLogger.log("Initializing evaluator log viewer."); @@ -1096,6 +1094,7 @@ async function activateWithInstalledDistribution( ...getCommands(), ...qhm.getCommands(), ...variantAnalysisManager.getCommands(), + ...databaseUI.getCommands(), }; for (const [commandName, command] of Object.entries(allCommands)) { @@ -1290,8 +1289,7 @@ async function activateWithInstalledDistribution( commandRunnerWithProgress( "codeQL.chooseDatabaseGithub", async (progress: ProgressCallback, token: CancellationToken) => { - const credentials = isCanary() ? app.credentials : undefined; - await databaseUI.chooseDatabaseGithub(credentials, progress, token); + await databaseUI.chooseDatabaseGithub(progress, token); }, { title: "Adding database from GitHub", diff --git a/extensions/ql-vscode/src/local-databases-ui.ts b/extensions/ql-vscode/src/local-databases-ui.ts index 22fd7e071..95b98d4fe 100644 --- a/extensions/ql-vscode/src/local-databases-ui.ts +++ b/extensions/ql-vscode/src/local-databases-ui.ts @@ -21,7 +21,7 @@ import { DatabaseItem, DatabaseManager, } from "./local-databases"; -import { commandRunner, ProgressCallback, withProgress } from "./commandRunner"; +import { ProgressCallback, withProgress } from "./commandRunner"; import { isLikelyDatabaseRoot, isLikelyDbLanguageFolder, @@ -38,8 +38,8 @@ import { asError, asyncFilter, getErrorMessage } from "./pure/helpers-pure"; import { QueryRunner } from "./queryRunner"; import { isCanary } from "./config"; import { App } from "./common/app"; -import { Credentials } from "./common/authentication"; import { redactableError } from "./pure/errors"; +import { LocalDatabasesCommands } from "./common/commands"; enum SortOrder { NameAsc = "NameAsc", @@ -206,108 +206,34 @@ export class DatabaseUI extends DisposableObject { ); } - init() { - void extLogger.log("Registering database panel commands."); - this.push( - commandRunner( - "codeQL.setCurrentDatabase", - this.handleSetCurrentDatabase.bind(this), - ), - ); - this.push( - commandRunner( - "codeQL.setDefaultTourDatabase", + public getCommands(): LocalDatabasesCommands { + return { + "codeQL.setCurrentDatabase": this.handleSetCurrentDatabase.bind(this), + "codeQL.setDefaultTourDatabase": this.handleSetDefaultTourDatabase.bind(this), - ), - ); - this.push( - commandRunner( - "codeQL.upgradeCurrentDatabase", + "codeQL.upgradeCurrentDatabase": this.handleUpgradeCurrentDatabase.bind(this), - ), - ); - this.push( - commandRunner("codeQL.clearCache", this.handleClearCache.bind(this)), - ); - - this.push( - commandRunner( - "codeQLDatabases.chooseDatabaseFolder", + "codeQL.clearCache": this.handleClearCache.bind(this), + "codeQLDatabases.chooseDatabaseFolder": this.handleChooseDatabaseFolder.bind(this), - ), - ); - this.push( - commandRunner( - "codeQLDatabases.chooseDatabaseArchive", + "codeQLDatabases.chooseDatabaseArchive": this.handleChooseDatabaseArchive.bind(this), - ), - ); - this.push( - commandRunner( - "codeQLDatabases.chooseDatabaseInternet", + "codeQLDatabases.chooseDatabaseInternet": this.handleChooseDatabaseInternet.bind(this), - ), - ); - this.push( - commandRunner("codeQLDatabases.chooseDatabaseGithub", async () => { - const credentials = isCanary() ? this.app.credentials : undefined; - await this.handleChooseDatabaseGithub(credentials); - }), - ); - this.push( - commandRunner( - "codeQLDatabases.setCurrentDatabase", + "codeQLDatabases.chooseDatabaseGithub": + this.handleChooseDatabaseGithub.bind(this), + "codeQLDatabases.setCurrentDatabase": this.handleMakeCurrentDatabase.bind(this), - ), - ); - this.push( - commandRunner( - "codeQLDatabases.sortByName", - this.handleSortByName.bind(this), - ), - ); - this.push( - commandRunner( - "codeQLDatabases.sortByDateAdded", - this.handleSortByDateAdded.bind(this), - ), - ); - this.push( - commandRunner( - "codeQLDatabases.removeDatabase", - this.handleRemoveDatabase.bind(this), - ), - ); - this.push( - commandRunner( - "codeQLDatabases.upgradeDatabase", - this.handleUpgradeDatabase.bind(this), - ), - ); - this.push( - commandRunner( - "codeQLDatabases.renameDatabase", - this.handleRenameDatabase.bind(this), - ), - ); - this.push( - commandRunner( - "codeQLDatabases.openDatabaseFolder", - this.handleOpenFolder.bind(this), - ), - ); - this.push( - commandRunner( - "codeQLDatabases.addDatabaseSource", - this.handleAddSource.bind(this), - ), - ); - this.push( - commandRunner( - "codeQLDatabases.removeOrphanedDatabases", + "codeQLDatabases.sortByName": this.handleSortByName.bind(this), + "codeQLDatabases.sortByDateAdded": this.handleSortByDateAdded.bind(this), + "codeQLDatabases.removeDatabase": this.handleRemoveDatabase.bind(this), + "codeQLDatabases.upgradeDatabase": this.handleUpgradeDatabase.bind(this), + "codeQLDatabases.renameDatabase": this.handleRenameDatabase.bind(this), + "codeQLDatabases.openDatabaseFolder": this.handleOpenFolder.bind(this), + "codeQLDatabases.addDatabaseSource": this.handleAddSource.bind(this), + "codeQLDatabases.removeOrphanedDatabases": this.handleRemoveOrphanedDatabases.bind(this), - ), - ); + }; } private async handleMakeCurrentDatabase( @@ -505,12 +431,10 @@ export class DatabaseUI extends DisposableObject { ); } - private async handleChooseDatabaseInternet(): Promise< - DatabaseItem | undefined - > { + private async handleChooseDatabaseInternet(): Promise { return withProgress( async (progress, token) => { - return await this.chooseDatabaseInternet(progress, token); + await this.chooseDatabaseInternet(progress, token); }, { title: "Adding database from URL", @@ -519,10 +443,11 @@ export class DatabaseUI extends DisposableObject { } public async chooseDatabaseGithub( - credentials: Credentials | undefined, progress: ProgressCallback, token: CancellationToken, ): Promise { + const credentials = isCanary() ? this.app.credentials : undefined; + return await promptImportGithubDatabase( this.databaseManager, this.storagePath, @@ -533,12 +458,10 @@ export class DatabaseUI extends DisposableObject { ); } - private async handleChooseDatabaseGithub( - credentials: Credentials | undefined, - ): Promise { + private async handleChooseDatabaseGithub(): Promise { return withProgress( async (progress, token) => { - return await this.chooseDatabaseGithub(credentials, progress, token); + await this.chooseDatabaseGithub(progress, token); }, { title: "Adding database from GitHub", From b76bef4246a1c5f67e5678dde6048113a8998274 Mon Sep 17 00:00:00 2001 From: Robert Date: Mon, 20 Mar 2023 12:33:51 +0000 Subject: [PATCH 068/156] Remove the codeQL.exportVariantAnalysisResults command --- extensions/ql-vscode/src/extension.ts | 32 +-- .../query-history/query-history-manager.ts | 3 +- .../src/variant-analysis/export-results.ts | 207 ++++++++++-------- .../variant-analysis-manager.ts | 13 ++ .../variant-analysis-view-manager.ts | 5 + .../variant-analysis/variant-analysis-view.ts | 3 +- 6 files changed, 132 insertions(+), 131 deletions(-) diff --git a/extensions/ql-vscode/src/extension.ts b/extensions/ql-vscode/src/extension.ts index b6522377f..212abe0ac 100644 --- a/extensions/ql-vscode/src/extension.ts +++ b/extensions/ql-vscode/src/extension.ts @@ -109,10 +109,7 @@ import { handleInstallPackDependencies, } from "./packaging"; import { HistoryItemLabelProvider } from "./query-history/history-item-label-provider"; -import { - exportSelectedVariantAnalysisResults, - exportVariantAnalysisResults, -} from "./variant-analysis/export-results"; +import { exportSelectedVariantAnalysisResults } from "./variant-analysis/export-results"; import { EvalLogViewer } from "./eval-log-viewer"; import { SummaryLanguageSupport } from "./log-insights/summary-language-support"; import { JoinOrderScannerProvider } from "./log-insights/join-order"; @@ -1156,35 +1153,10 @@ async function activateWithInstalledDistribution( ctx.subscriptions.push( commandRunner("codeQL.exportSelectedVariantAnalysisResults", async () => { - await exportSelectedVariantAnalysisResults(qhm); + await exportSelectedVariantAnalysisResults(variantAnalysisManager, qhm); }), ); - ctx.subscriptions.push( - commandRunnerWithProgress( - "codeQL.exportVariantAnalysisResults", - async ( - progress: ProgressCallback, - token: CancellationToken, - variantAnalysisId: number, - filterSort?: RepositoriesFilterSortStateWithIds, - ) => { - await exportVariantAnalysisResults( - variantAnalysisManager, - variantAnalysisId, - filterSort, - app.credentials, - progress, - token, - ); - }, - { - title: "Exporting variant analysis results", - cancellable: true, - }, - ), - ); - ctx.subscriptions.push( commandRunner( "codeQL.loadVariantAnalysisRepoResults", diff --git a/extensions/ql-vscode/src/query-history/query-history-manager.ts b/extensions/ql-vscode/src/query-history/query-history-manager.ts index 44529bdf1..3b31c4e52 100644 --- a/extensions/ql-vscode/src/query-history/query-history-manager.ts +++ b/extensions/ql-vscode/src/query-history/query-history-manager.ts @@ -1238,8 +1238,7 @@ export class QueryHistoryManager extends DisposableObject { return; } - await commands.executeCommand( - "codeQL.exportVariantAnalysisResults", + await this.variantAnalysisManager.exportResults( finalSingleItem.variantAnalysis.id, ); } diff --git a/extensions/ql-vscode/src/variant-analysis/export-results.ts b/extensions/ql-vscode/src/variant-analysis/export-results.ts index faf3f0ee5..7b5647a00 100644 --- a/extensions/ql-vscode/src/variant-analysis/export-results.ts +++ b/extensions/ql-vscode/src/variant-analysis/export-results.ts @@ -9,7 +9,11 @@ import { window, workspace, } from "vscode"; -import { ProgressCallback, UserCancellationException } from "../commandRunner"; +import { + ProgressCallback, + UserCancellationException, + withProgress, +} from "../commandRunner"; import { showInformationMessageWithAction } from "../helpers"; import { extLogger } from "../common"; import { QueryHistoryManager } from "../query-history/query-history-manager"; @@ -37,6 +41,7 @@ import { Credentials } from "../common/authentication"; * Exports the results of the currently-selected variant analysis. */ export async function exportSelectedVariantAnalysisResults( + variantAnalysisManager: VariantAnalysisManager, queryHistoryManager: QueryHistoryManager, ): Promise { const queryHistoryItem = queryHistoryManager.getCurrentQueryHistoryItem(); @@ -46,8 +51,7 @@ export async function exportSelectedVariantAnalysisResults( ); } - return commands.executeCommand( - "codeQL.exportVariantAnalysisResults", + await variantAnalysisManager.exportResults( queryHistoryItem.variantAnalysis.id, ); } @@ -63,108 +67,117 @@ export async function exportVariantAnalysisResults( variantAnalysisId: number, filterSort: RepositoriesFilterSortStateWithIds | undefined, credentials: Credentials, - progress: ProgressCallback, - token: CancellationToken, ): Promise { - const variantAnalysis = await variantAnalysisManager.getVariantAnalysis( - variantAnalysisId, - ); - if (!variantAnalysis) { - void extLogger.log( - `Could not find variant analysis with id ${variantAnalysisId}`, - ); - throw new Error( - "There was an error when trying to retrieve variant analysis information", - ); - } + await withProgress( + async (progress: ProgressCallback, token: CancellationToken) => { + const variantAnalysis = await variantAnalysisManager.getVariantAnalysis( + variantAnalysisId, + ); + if (!variantAnalysis) { + void extLogger.log( + `Could not find variant analysis with id ${variantAnalysisId}`, + ); + throw new Error( + "There was an error when trying to retrieve variant analysis information", + ); + } - if (token.isCancellationRequested) { - throw new UserCancellationException("Cancelled"); - } + if (token.isCancellationRequested) { + throw new UserCancellationException("Cancelled"); + } - const repoStates = await variantAnalysisManager.getRepoStates( - variantAnalysisId, - ); - - void extLogger.log( - `Exporting variant analysis results for variant analysis with id ${variantAnalysis.id}`, - ); - - progress({ - maxStep: MAX_VARIANT_ANALYSIS_EXPORT_PROGRESS_STEPS, - step: 0, - message: "Determining export format", - }); - - const exportFormat = await determineExportFormat(); - if (!exportFormat) { - return; - } - - if (token.isCancellationRequested) { - throw new UserCancellationException("Cancelled"); - } - - const repositories = filterAndSortRepositoriesWithResults( - variantAnalysis.scannedRepos, - filterSort, - )?.filter( - (repo) => - repo.resultCount && - repoStates.find((r) => r.repositoryId === repo.repository.id) - ?.downloadStatus === - VariantAnalysisScannedRepositoryDownloadStatus.Succeeded, - ); - - async function* getAnalysesResults(): AsyncGenerator< - [VariantAnalysisScannedRepository, VariantAnalysisScannedRepositoryResult] - > { - if (!variantAnalysis) { - return; - } - - if (!repositories) { - return; - } - - for (const repo of repositories) { - const result = await variantAnalysisManager.loadResults( - variantAnalysis.id, - repo.repository.fullName, - { - skipCacheStore: true, - }, + const repoStates = await variantAnalysisManager.getRepoStates( + variantAnalysisId, ); - yield [repo, result]; - } - } + void extLogger.log( + `Exporting variant analysis results for variant analysis with id ${variantAnalysis.id}`, + ); - const exportDirectory = - variantAnalysisManager.getVariantAnalysisStorageLocation( - variantAnalysis.id, - ); + progress({ + maxStep: MAX_VARIANT_ANALYSIS_EXPORT_PROGRESS_STEPS, + step: 0, + message: "Determining export format", + }); - // The date will be formatted like the following: 20221115T123456Z. The time is in UTC. - const formattedDate = new Date() - .toISOString() - .replace(/[-:]/g, "") - .replace(/\.\d+Z$/, "Z"); - const exportedResultsDirectory = join( - exportDirectory, - "exported-results", - `results_${formattedDate}`, - ); + const exportFormat = await determineExportFormat(); + if (!exportFormat) { + return; + } - await exportVariantAnalysisAnalysisResults( - exportedResultsDirectory, - variantAnalysis, - getAnalysesResults(), - repositories?.length ?? 0, - exportFormat, - credentials, - progress, - token, + if (token.isCancellationRequested) { + throw new UserCancellationException("Cancelled"); + } + + const repositories = filterAndSortRepositoriesWithResults( + variantAnalysis.scannedRepos, + filterSort, + )?.filter( + (repo) => + repo.resultCount && + repoStates.find((r) => r.repositoryId === repo.repository.id) + ?.downloadStatus === + VariantAnalysisScannedRepositoryDownloadStatus.Succeeded, + ); + + async function* getAnalysesResults(): AsyncGenerator< + [ + VariantAnalysisScannedRepository, + VariantAnalysisScannedRepositoryResult, + ] + > { + if (!variantAnalysis) { + return; + } + + if (!repositories) { + return; + } + + for (const repo of repositories) { + const result = await variantAnalysisManager.loadResults( + variantAnalysis.id, + repo.repository.fullName, + { + skipCacheStore: true, + }, + ); + + yield [repo, result]; + } + } + + const exportDirectory = + variantAnalysisManager.getVariantAnalysisStorageLocation( + variantAnalysis.id, + ); + + // The date will be formatted like the following: 20221115T123456Z. The time is in UTC. + const formattedDate = new Date() + .toISOString() + .replace(/[-:]/g, "") + .replace(/\.\d+Z$/, "Z"); + const exportedResultsDirectory = join( + exportDirectory, + "exported-results", + `results_${formattedDate}`, + ); + + await exportVariantAnalysisAnalysisResults( + exportedResultsDirectory, + variantAnalysis, + getAnalysesResults(), + repositories?.length ?? 0, + exportFormat, + credentials, + progress, + token, + ); + }, + { + title: "Exporting variant analysis results", + cancellable: true, + }, ); } diff --git a/extensions/ql-vscode/src/variant-analysis/variant-analysis-manager.ts b/extensions/ql-vscode/src/variant-analysis/variant-analysis-manager.ts index 23f43c567..9bd7f201d 100644 --- a/extensions/ql-vscode/src/variant-analysis/variant-analysis-manager.ts +++ b/extensions/ql-vscode/src/variant-analysis/variant-analysis-manager.ts @@ -67,6 +67,7 @@ import { DbManager } from "../databases/db-manager"; import { App } from "../common/app"; import { redactableError } from "../pure/errors"; import { AppCommandManager, VariantAnalysisCommands } from "../common/commands"; +import { exportVariantAnalysisResults } from "./export-results"; export class VariantAnalysisManager extends DisposableObject @@ -690,6 +691,18 @@ export class VariantAnalysisManager await env.clipboard.writeText(text.join(EOL)); } + public async exportResults( + variantAnalysisId: number, + filterSort?: RepositoriesFilterSortStateWithIds, + ) { + await exportVariantAnalysisResults( + this, + variantAnalysisId, + filterSort, + this.app.credentials, + ); + } + private getRepoStatesStoragePath(variantAnalysisId: number): string { return join( this.getVariantAnalysisStorageLocation(variantAnalysisId), diff --git a/extensions/ql-vscode/src/variant-analysis/variant-analysis-view-manager.ts b/extensions/ql-vscode/src/variant-analysis/variant-analysis-view-manager.ts index 1fa1fe46d..88a7c46e2 100644 --- a/extensions/ql-vscode/src/variant-analysis/variant-analysis-view-manager.ts +++ b/extensions/ql-vscode/src/variant-analysis/variant-analysis-view-manager.ts @@ -3,6 +3,7 @@ import { VariantAnalysisScannedRepositoryState, } from "./shared/variant-analysis"; import { AppCommandManager } from "../common/commands"; +import { RepositoriesFilterSortStateWithIds } from "../pure/variant-analysis-filter-sort"; export interface VariantAnalysisViewInterface { variantAnalysisId: number; @@ -25,4 +26,8 @@ export interface VariantAnalysisViewManager< variantAnalysisId: number, ): Promise; openQueryFile(variantAnalysisId: number): Promise; + exportResults( + variantAnalysisId: number, + filterSort?: RepositoriesFilterSortStateWithIds, + ): Promise; } diff --git a/extensions/ql-vscode/src/variant-analysis/variant-analysis-view.ts b/extensions/ql-vscode/src/variant-analysis/variant-analysis-view.ts index 351e5afbf..e21830709 100644 --- a/extensions/ql-vscode/src/variant-analysis/variant-analysis-view.ts +++ b/extensions/ql-vscode/src/variant-analysis/variant-analysis-view.ts @@ -139,8 +139,7 @@ export class VariantAnalysisView ); break; case "exportResults": - void commands.executeCommand( - "codeQL.exportVariantAnalysisResults", + await this.manager.exportResults( this.variantAnalysisId, msg.filterSort, ); From 2e9a22e86de22336ff22102ac7b9a0b645b95f10 Mon Sep 17 00:00:00 2001 From: Koen Vlaswinkel Date: Mon, 20 Mar 2023 13:52:32 +0100 Subject: [PATCH 069/156] Convert new database panel to typed commands This converts the new database panel to use typed commands. There should be no changes in behaviour. --- extensions/ql-vscode/src/common/commands.ts | 23 +++++- .../ql-vscode/src/databases/db-module.ts | 17 +++- .../ql-vscode/src/databases/ui/db-panel.ts | 77 ++++++------------- extensions/ql-vscode/src/extension.ts | 1 + 4 files changed, 61 insertions(+), 57 deletions(-) diff --git a/extensions/ql-vscode/src/common/commands.ts b/extensions/ql-vscode/src/common/commands.ts index dcd175df0..051e59394 100644 --- a/extensions/ql-vscode/src/common/commands.ts +++ b/extensions/ql-vscode/src/common/commands.ts @@ -1,5 +1,6 @@ import type { CommandManager } from "../packages/commands"; import type { Uri } from "vscode"; +import type { DbTreeViewItem } from "../databases/ui/db-tree-view-item"; import type { QueryHistoryInfo } from "../query-history/query-history-info"; // A command function matching the signature that VS Code calls when @@ -9,6 +10,12 @@ export type SelectionCommandFunction = ( multiSelect: Item[], ) => Promise; +// A command function matching the signature that VS Code calls when +// a command on a selection is invoked when canSelectMany is false. +export type SingleSelectionCommandFunction = ( + singleItem: Item, +) => Promise; + /** * Contains type definitions for all commands used by the extension. * @@ -62,8 +69,22 @@ export type VariantAnalysisCommands = { "codeQL.runVariantAnalysisContextEditor": (uri?: Uri) => Promise; }; +export type DatabasePanelCommands = { + "codeQLVariantAnalysisRepositories.openConfigFile": () => Promise; + "codeQLVariantAnalysisRepositories.addNewDatabase": () => Promise; + "codeQLVariantAnalysisRepositories.addNewList": () => Promise; + "codeQLVariantAnalysisRepositories.setupControllerRepository": () => Promise; + + "codeQLVariantAnalysisRepositories.setSelectedItem": SingleSelectionCommandFunction; + "codeQLVariantAnalysisRepositories.setSelectedItemContextMenu": SingleSelectionCommandFunction; + "codeQLVariantAnalysisRepositories.openOnGitHubContextMenu": SingleSelectionCommandFunction; + "codeQLVariantAnalysisRepositories.renameItemContextMenu": SingleSelectionCommandFunction; + "codeQLVariantAnalysisRepositories.removeItemContextMenu": SingleSelectionCommandFunction; +}; + export type AllCommands = BaseCommands & QueryHistoryCommands & - VariantAnalysisCommands; + VariantAnalysisCommands & + DatabasePanelCommands; export type AppCommandManager = CommandManager; diff --git a/extensions/ql-vscode/src/databases/db-module.ts b/extensions/ql-vscode/src/databases/db-module.ts index ceb46779a..8c287cc32 100644 --- a/extensions/ql-vscode/src/databases/db-module.ts +++ b/extensions/ql-vscode/src/databases/db-module.ts @@ -6,10 +6,12 @@ import { DbConfigStore } from "./config/db-config-store"; import { DbManager } from "./db-manager"; import { DbPanel } from "./ui/db-panel"; import { DbSelectionDecorationProvider } from "./ui/db-selection-decoration-provider"; +import { DatabasePanelCommands } from "../common/commands"; export class DbModule extends DisposableObject { public readonly dbManager: DbManager; private readonly dbConfigStore: DbConfigStore; + private dbPanel: DbPanel | undefined; private constructor(app: App) { super(); @@ -26,15 +28,24 @@ export class DbModule extends DisposableObject { return dbModule; } + public getCommands(): DatabasePanelCommands { + if (!this.dbPanel) { + throw new Error("Database panel not initialized"); + } + + return { + ...this.dbPanel.getCommands(), + }; + } + private async initialize(app: App): Promise { void extLogger.log("Initializing database module"); await this.dbConfigStore.initialize(); - const dbPanel = new DbPanel(this.dbManager, app.credentials); - await dbPanel.initialize(); + this.dbPanel = new DbPanel(this.dbManager, app.credentials); - this.push(dbPanel); + this.push(this.dbPanel); this.push(this.dbConfigStore); const dbSelectionDecorationProvider = new DbSelectionDecorationProvider(); diff --git a/extensions/ql-vscode/src/databases/ui/db-panel.ts b/extensions/ql-vscode/src/databases/ui/db-panel.ts index f9eccc5fc..c2dec3897 100644 --- a/extensions/ql-vscode/src/databases/ui/db-panel.ts +++ b/extensions/ql-vscode/src/databases/ui/db-panel.ts @@ -7,7 +7,7 @@ import { window, workspace, } from "vscode"; -import { commandRunner, UserCancellationException } from "../../commandRunner"; +import { UserCancellationException } from "../../commandRunner"; import { getNwoFromGitHubUrl, isValidGitHubNwo, @@ -32,6 +32,7 @@ import { getGitHubUrl } from "./db-tree-view-item-action"; import { getControllerRepo } from "../../variant-analysis/run-remote-query"; import { getErrorMessage } from "../../pure/helpers-pure"; import { Credentials } from "../../common/authentication"; +import { DatabasePanelCommands } from "../../common/commands"; export interface RemoteDatabaseQuickPickItem extends QuickPickItem { kind: string; @@ -72,58 +73,28 @@ export class DbPanel extends DisposableObject { this.push(this.treeView); } - public async initialize(): Promise { - this.push( - commandRunner("codeQLVariantAnalysisRepositories.openConfigFile", () => - this.openConfigFile(), - ), - ); - this.push( - commandRunner("codeQLVariantAnalysisRepositories.addNewDatabase", () => - this.addNewRemoteDatabase(), - ), - ); - this.push( - commandRunner("codeQLVariantAnalysisRepositories.addNewList", () => - this.addNewList(), - ), - ); - this.push( - commandRunner( - "codeQLVariantAnalysisRepositories.setSelectedItem", - (treeViewItem: DbTreeViewItem) => this.setSelectedItem(treeViewItem), - ), - ); - this.push( - commandRunner( - "codeQLVariantAnalysisRepositories.setSelectedItemContextMenu", - (treeViewItem: DbTreeViewItem) => this.setSelectedItem(treeViewItem), - ), - ); - this.push( - commandRunner( - "codeQLVariantAnalysisRepositories.openOnGitHubContextMenu", - (treeViewItem: DbTreeViewItem) => this.openOnGitHub(treeViewItem), - ), - ); - this.push( - commandRunner( - "codeQLVariantAnalysisRepositories.renameItemContextMenu", - (treeViewItem: DbTreeViewItem) => this.renameItem(treeViewItem), - ), - ); - this.push( - commandRunner( - "codeQLVariantAnalysisRepositories.removeItemContextMenu", - (treeViewItem: DbTreeViewItem) => this.removeItem(treeViewItem), - ), - ); - this.push( - commandRunner( - "codeQLVariantAnalysisRepositories.setupControllerRepository", - () => this.setupControllerRepository(), - ), - ); + public getCommands(): DatabasePanelCommands { + return { + "codeQLVariantAnalysisRepositories.openConfigFile": + this.openConfigFile.bind(this), + "codeQLVariantAnalysisRepositories.addNewDatabase": + this.addNewRemoteDatabase.bind(this), + "codeQLVariantAnalysisRepositories.addNewList": + this.addNewList.bind(this), + "codeQLVariantAnalysisRepositories.setupControllerRepository": + this.setupControllerRepository.bind(this), + + "codeQLVariantAnalysisRepositories.setSelectedItem": + this.setSelectedItem.bind(this), + "codeQLVariantAnalysisRepositories.setSelectedItemContextMenu": + this.setSelectedItem.bind(this), + "codeQLVariantAnalysisRepositories.openOnGitHubContextMenu": + this.openOnGitHub.bind(this), + "codeQLVariantAnalysisRepositories.renameItemContextMenu": + this.renameItem.bind(this), + "codeQLVariantAnalysisRepositories.removeItemContextMenu": + this.removeItem.bind(this), + }; } private async openConfigFile(): Promise { diff --git a/extensions/ql-vscode/src/extension.ts b/extensions/ql-vscode/src/extension.ts index c73eb03eb..e15d647c1 100644 --- a/extensions/ql-vscode/src/extension.ts +++ b/extensions/ql-vscode/src/extension.ts @@ -1096,6 +1096,7 @@ async function activateWithInstalledDistribution( ...getCommands(), ...qhm.getCommands(), ...variantAnalysisManager.getCommands(), + ...dbModule.getCommands(), }; for (const [commandName, command] of Object.entries(allCommands)) { From 4fa3c459a1160b21a3bd45539d6e646295c27ba3 Mon Sep 17 00:00:00 2001 From: Elena Tanasoiu Date: Fri, 17 Mar 2023 17:16:17 +0000 Subject: [PATCH 070/156] Open tutorial workspace on extension start When opening https://github.com/github/codespaces-codeql/ in a codespace, it's easy to miss the prompt that tells you to open the tutorial.code-workspace file. In fact people actively dismiss the alert to get it out of the way. If you miss that prompt, you end up with a single-rooted workspace, which causes various other problems. While there is an open issue to allow VS Code to open a default workspace [1], there doesn't seem to have been any progress on it in the last two years. So we're taking matters into our own hands and forcing the extension to open the tutorial workspace, if it detects it. This will only happen if the following three conditions are met: - the .tours folder exists - the tutorial.code-workspace file exists - the CODESPACES_TEMPLATE setting hasn't been set NB: the `CODESPACES_TEMPLATE` setting can only be found if the tutorial.code-workspace has already been opened. So it's a good indicator that we're in the folder, but the user has ignored the prompt. [1]: https://github.com/microsoft/vscode-remote-release/issues/3665 --- extensions/ql-vscode/src/extension.ts | 3 + extensions/ql-vscode/src/helpers.ts | 33 ++++++ .../vscode-tests/no-workspace/helpers.test.ts | 112 +++++++++++++++++- 3 files changed, 147 insertions(+), 1 deletion(-) diff --git a/extensions/ql-vscode/src/extension.ts b/extensions/ql-vscode/src/extension.ts index c73eb03eb..9773ea19d 100644 --- a/extensions/ql-vscode/src/extension.ts +++ b/extensions/ql-vscode/src/extension.ts @@ -70,6 +70,7 @@ import { showInformationMessageWithAction, tmpDir, tmpDirDisposal, + prepareCodeTour, } from "./helpers"; import { asError, @@ -344,6 +345,8 @@ export async function activate( codeQlExtension.variantAnalysisManager, ); + await prepareCodeTour(); + return codeQlExtension; } diff --git a/extensions/ql-vscode/src/helpers.ts b/extensions/ql-vscode/src/helpers.ts index d3245a287..35532cfc3 100644 --- a/extensions/ql-vscode/src/helpers.ts +++ b/extensions/ql-vscode/src/helpers.ts @@ -5,6 +5,7 @@ import { ensureDir, writeFile, opendir, + existsSync, } from "fs-extra"; import { promise as glob } from "glob-promise"; import { load } from "js-yaml"; @@ -16,6 +17,7 @@ import { window as Window, workspace, env, + commands, } from "vscode"; import { CodeQLCliServer, QlpacksInfo } from "./cli"; import { UserCancellationException } from "./commandRunner"; @@ -25,6 +27,7 @@ import { telemetryListener } from "./telemetry"; import { RedactableError } from "./pure/errors"; import { getQlPackPath } from "./pure/ql"; import { dbSchemeToLanguage } from "./common/query-language"; +import { isCodespacesTemplate } from "./config"; // Shared temporary folder for the extension. export const tmpDir = dirSync({ @@ -266,6 +269,36 @@ export function isFolderAlreadyInWorkspace(folderName: string) { ); } +/** Check if the current workspace is the CodeTour and open the workspace folder. + * Without this, we can't run the code tour correctly. + **/ +export async function prepareCodeTour(): Promise { + if (workspace.workspaceFolders?.length) { + const currentFolder = workspace.workspaceFolders[0].uri.fsPath; + + // We need this path to check that the file exists on windows + const tutorialWorkspacePath = join( + currentFolder, + "tutorial.code-workspace", + ); + const toursFolderPath = join(currentFolder, ".tours"); + + if ( + existsSync(tutorialWorkspacePath) && + existsSync(toursFolderPath) && + !isCodespacesTemplate() + ) { + const tutorialWorkspaceUri = Uri.parse( + join( + workspace.workspaceFolders[0].uri.fsPath, + "tutorial.code-workspace", + ), + ); + await commands.executeCommand("vscode.openFolder", tutorialWorkspaceUri); + } + } +} + /** * Provides a utility method to invoke a function only if a minimum time interval has elapsed since * the last invocation of that function. diff --git a/extensions/ql-vscode/test/vscode-tests/no-workspace/helpers.test.ts b/extensions/ql-vscode/test/vscode-tests/no-workspace/helpers.test.ts index cf2a022c2..6b7607e5d 100644 --- a/extensions/ql-vscode/test/vscode-tests/no-workspace/helpers.test.ts +++ b/extensions/ql-vscode/test/vscode-tests/no-workspace/helpers.test.ts @@ -1,4 +1,5 @@ import { + commands, EnvironmentVariableCollection, EnvironmentVariableMutator, Event, @@ -15,7 +16,14 @@ import { import { dump } from "js-yaml"; import * as tmp from "tmp"; import { join } from "path"; -import { writeFileSync, mkdirSync, ensureDirSync, symlinkSync } from "fs-extra"; +import { + writeFileSync, + mkdirSync, + ensureDirSync, + symlinkSync, + writeFile, + mkdir, +} from "fs-extra"; import { DirResult } from "tmp"; import { @@ -24,6 +32,7 @@ import { isFolderAlreadyInWorkspace, isLikelyDatabaseRoot, isLikelyDbLanguageFolder, + prepareCodeTour, showBinaryChoiceDialog, showBinaryChoiceWithUrlDialog, showInformationMessageWithAction, @@ -31,6 +40,7 @@ import { } from "../../../src/helpers"; import { reportStreamProgress } from "../../../src/commandRunner"; import { QueryLanguage } from "../../../src/common/query-language"; +import { Setting } from "../../../src/config"; describe("helpers", () => { describe("Invocation rate limiter", () => { @@ -559,3 +569,103 @@ describe("isFolderAlreadyInWorkspace", () => { expect(isFolderAlreadyInWorkspace("/third/path")).toBe(false); }); }); + +describe("prepareCodeTour", () => { + let dir: tmp.DirResult; + + beforeEach(() => { + dir = tmp.dirSync(); + + const mockWorkspaceFolders = [ + { + uri: Uri.file(dir.name), + name: "test", + index: 0, + }, + ] as WorkspaceFolder[]; + + jest + .spyOn(workspace, "workspaceFolders", "get") + .mockReturnValue(mockWorkspaceFolders); + }); + + afterEach(() => { + dir.removeCallback(); + }); + + describe("if we're in the tour repo", () => { + describe("if the workspace is not already open", () => { + it("should open the tutorial workspace", async () => { + // set up directory to have a 'tutorial.code-workspace' file + const tutorialWorkspacePath = join(dir.name, "tutorial.code-workspace"); + await writeFile(tutorialWorkspacePath, "{}"); + + // set up a .tours directory to indicate we're in the tour codespace + const tourDirPath = join(dir.name, ".tours"); + await mkdir(tourDirPath); + + // spy that we open the workspace file by calling the 'vscode.openFolder' command + const commandSpy = jest.spyOn(commands, "executeCommand"); + commandSpy.mockImplementation(() => Promise.resolve()); + + await prepareCodeTour(); + + expect(commandSpy).toHaveBeenCalledWith( + "vscode.openFolder", + expect.anything(), + ); + }); + }); + + describe("if the workspace is already open", () => { + it("should not open the tutorial workspace", async () => { + // Set isCodespaceTemplate to true to indicate the workspace has already been opened + jest.spyOn(Setting.prototype, "getValue").mockReturnValue(false); + + // set up directory to have a 'tutorial.code-workspace' file + const tutorialWorkspacePath = join(dir.name, "tutorial.code-workspace"); + await writeFile(tutorialWorkspacePath, "{}"); + + // set up a .tours directory to indicate we're in the tour codespace + const tourDirPath = join(dir.name, ".tours"); + await mkdir(tourDirPath); + + // spy that we open the workspace file by calling the 'vscode.openFolder' command + const openFileSpy = jest.spyOn(commands, "executeCommand"); + openFileSpy.mockImplementation(() => Promise.resolve()); + + await prepareCodeTour(); + + expect(openFileSpy).not.toHaveBeenCalledWith("vscode.openFolder"); + }); + }); + }); + + describe("if we're in a different tour repo", () => { + it("should not open the tutorial workspace", async () => { + // set up a .tours directory + const tourDirPath = join(dir.name, ".tours"); + await mkdir(tourDirPath); + + // spy that we open the workspace file by calling the 'vscode.openFolder' command + const openFileSpy = jest.spyOn(commands, "executeCommand"); + openFileSpy.mockImplementation(() => Promise.resolve()); + + await prepareCodeTour(); + + expect(openFileSpy).not.toHaveBeenCalledWith("vscode.openFolder"); + }); + }); + + describe("if we're in a different repo with no tour", () => { + it("should not open the tutorial workspace", async () => { + // spy that we open the workspace file by calling the 'vscode.openFolder' command + const openFileSpy = jest.spyOn(commands, "executeCommand"); + openFileSpy.mockImplementation(() => Promise.resolve()); + + await prepareCodeTour(); + + expect(openFileSpy).not.toHaveBeenCalledWith("vscode.openFolder"); + }); + }); +}); From 5444a9e55e64ce118166d69891bd6f63d95df40a Mon Sep 17 00:00:00 2001 From: Elena Tanasoiu Date: Mon, 20 Mar 2023 15:01:04 +0000 Subject: [PATCH 071/156] Fail gracefully if we can't set up code tour We're running this at the extension start-up. We don't want it to block the extension from completing activation, so let's swallow any errors from the code tour and output them, instead of letting this affect the rest of the extension activation. --- extensions/ql-vscode/src/extension.ts | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/extensions/ql-vscode/src/extension.ts b/extensions/ql-vscode/src/extension.ts index 9773ea19d..920d3018c 100644 --- a/extensions/ql-vscode/src/extension.ts +++ b/extensions/ql-vscode/src/extension.ts @@ -345,7 +345,13 @@ export async function activate( codeQlExtension.variantAnalysisManager, ); - await prepareCodeTour(); + try { + await prepareCodeTour(); + } catch (e: unknown) { + console.log( + `Could not open tutorial workspace automatically: ${getErrorMessage(e)}`, + ); + } return codeQlExtension; } From fb7038292983d2e1396e8c1555a715ec7cb6deee Mon Sep 17 00:00:00 2001 From: Robert Date: Mon, 20 Mar 2023 16:32:12 +0000 Subject: [PATCH 072/156] Fix tests to not reference deleted command --- .../query-history/query-history-manager.test.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/extensions/ql-vscode/test/vscode-tests/no-workspace/query-history/query-history-manager.test.ts b/extensions/ql-vscode/test/vscode-tests/no-workspace/query-history/query-history-manager.test.ts index 60f0095aa..a798fff45 100644 --- a/extensions/ql-vscode/test/vscode-tests/no-workspace/query-history/query-history-manager.test.ts +++ b/extensions/ql-vscode/test/vscode-tests/no-workspace/query-history/query-history-manager.test.ts @@ -86,6 +86,7 @@ describe("QueryHistoryManager", () => { onVariantAnalysisRemoved: jest.fn(), removeVariantAnalysis: jest.fn(), cancelVariantAnalysis: jest.fn(), + exportResults: jest.fn(), showView: jest.fn(), } as any as VariantAnalysisManager; @@ -862,7 +863,7 @@ describe("QueryHistoryManager", () => { const item = localQueryHistory[4]; await queryHistoryManager.handleExportResults(item, [item]); - expect(executeCommandSpy).not.toBeCalled(); + expect(variantAnalysisManagerStub.exportResults).not.toBeCalled(); }); it("should export results for a single variant analysis", async () => { @@ -870,8 +871,7 @@ describe("QueryHistoryManager", () => { const item = variantAnalysisHistory[1]; await queryHistoryManager.handleExportResults(item, [item]); - expect(executeCommandSpy).toBeCalledWith( - "codeQL.exportVariantAnalysisResults", + expect(variantAnalysisManagerStub.exportResults).toBeCalledWith( item.variantAnalysis.id, ); }); @@ -882,7 +882,7 @@ describe("QueryHistoryManager", () => { const item1 = variantAnalysisHistory[1]; const item2 = variantAnalysisHistory[3]; await queryHistoryManager.handleExportResults(item1, [item1, item2]); - expect(executeCommandSpy).not.toBeCalled(); + expect(variantAnalysisManagerStub.exportResults).not.toBeCalled(); }); }); From aa64459353b56630cce6deffcfcf1229cabc4a35 Mon Sep 17 00:00:00 2001 From: Robert Date: Mon, 20 Mar 2023 15:10:29 +0000 Subject: [PATCH 073/156] Convert existing variant analysis commands to bind(this) --- .../src/variant-analysis/variant-analysis-manager.ts | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/extensions/ql-vscode/src/variant-analysis/variant-analysis-manager.ts b/extensions/ql-vscode/src/variant-analysis/variant-analysis-manager.ts index 9bd7f201d..cefb0ef6d 100644 --- a/extensions/ql-vscode/src/variant-analysis/variant-analysis-manager.ts +++ b/extensions/ql-vscode/src/variant-analysis/variant-analysis-manager.ts @@ -131,14 +131,12 @@ export class VariantAnalysisManager getCommands(): VariantAnalysisCommands { return { - "codeQL.openVariantAnalysisLogs": async (variantAnalysisId: number) => { - await this.openVariantAnalysisLogs(variantAnalysisId); - }, - "codeQL.runVariantAnalysis": async (uri?: Uri) => - this.runVariantAnalysisFromCommand(uri), + "codeQL.openVariantAnalysisLogs": this.openVariantAnalysisLogs.bind(this), + "codeQL.runVariantAnalysis": + this.runVariantAnalysisFromCommand.bind(this), // Since we are tracking extension usage through commands, this command mirrors the "codeQL.runVariantAnalysis" command - "codeQL.runVariantAnalysisContextEditor": async (uri?: Uri) => - this.runVariantAnalysisFromCommand(uri), + "codeQL.runVariantAnalysisContextEditor": + this.runVariantAnalysisFromCommand.bind(this), }; } From 08849c1df46f7374de51652228a9bcbd2a7496e0 Mon Sep 17 00:00:00 2001 From: Robert Date: Mon, 20 Mar 2023 15:23:54 +0000 Subject: [PATCH 074/156] Convert codeQL.copyVariantAnalysisRepoList command --- extensions/ql-vscode/src/common/commands.ts | 6 ++++++ extensions/ql-vscode/src/extension.ts | 15 --------------- .../variant-analysis/variant-analysis-manager.ts | 2 ++ 3 files changed, 8 insertions(+), 15 deletions(-) diff --git a/extensions/ql-vscode/src/common/commands.ts b/extensions/ql-vscode/src/common/commands.ts index 051e59394..472d9976d 100644 --- a/extensions/ql-vscode/src/common/commands.ts +++ b/extensions/ql-vscode/src/common/commands.ts @@ -2,6 +2,8 @@ import type { CommandManager } from "../packages/commands"; import type { Uri } from "vscode"; import type { DbTreeViewItem } from "../databases/ui/db-tree-view-item"; import type { QueryHistoryInfo } from "../query-history/query-history-info"; +import { RepositoriesFilterSortStateWithIds } from "../pure/variant-analysis-filter-sort"; +import { VariantAnalysis } from "../variant-analysis/shared/variant-analysis"; // A command function matching the signature that VS Code calls when // a command on a selection is invoked. @@ -62,6 +64,10 @@ export type QueryHistoryCommands = { // Commands tied to variant analysis export type VariantAnalysisCommands = { + "codeQL.copyVariantAnalysisRepoList": ( + variantAnalysisId: number, + filterSort?: RepositoriesFilterSortStateWithIds, + ) => Promise; "codeQL.openVariantAnalysisLogs": ( variantAnalysisId: number, ) => Promise; diff --git a/extensions/ql-vscode/src/extension.ts b/extensions/ql-vscode/src/extension.ts index 00203bd6a..8a833b843 100644 --- a/extensions/ql-vscode/src/extension.ts +++ b/extensions/ql-vscode/src/extension.ts @@ -1100,21 +1100,6 @@ async function activateWithInstalledDistribution( app.commands.register(commandName as keyof AllCommands, command); } - ctx.subscriptions.push( - commandRunner( - "codeQL.copyVariantAnalysisRepoList", - async ( - variantAnalysisId: number, - filterSort?: RepositoriesFilterSortStateWithIds, - ) => { - await variantAnalysisManager.copyRepoListToClipboard( - variantAnalysisId, - filterSort, - ); - }, - ), - ); - ctx.subscriptions.push( commandRunner( "codeQL.monitorVariantAnalysis", diff --git a/extensions/ql-vscode/src/variant-analysis/variant-analysis-manager.ts b/extensions/ql-vscode/src/variant-analysis/variant-analysis-manager.ts index cefb0ef6d..127c71870 100644 --- a/extensions/ql-vscode/src/variant-analysis/variant-analysis-manager.ts +++ b/extensions/ql-vscode/src/variant-analysis/variant-analysis-manager.ts @@ -131,6 +131,8 @@ export class VariantAnalysisManager getCommands(): VariantAnalysisCommands { return { + "codeQL.copyVariantAnalysisRepoList": + this.copyRepoListToClipboard.bind(this), "codeQL.openVariantAnalysisLogs": this.openVariantAnalysisLogs.bind(this), "codeQL.runVariantAnalysis": this.runVariantAnalysisFromCommand.bind(this), From e586f3de53fea138e1b81c210ec52a41cf00d51f Mon Sep 17 00:00:00 2001 From: Robert Date: Mon, 20 Mar 2023 16:59:51 +0000 Subject: [PATCH 075/156] Move codeQL.exportSelectedVariantAnalysisResults to query history manager --- extensions/ql-vscode/src/common/commands.ts | 3 +++ extensions/ql-vscode/src/extension.ts | 7 ------- .../query-history/query-history-manager.ts | 19 ++++++++++++++++++ .../src/variant-analysis/export-results.ts | 20 ------------------- 4 files changed, 22 insertions(+), 27 deletions(-) diff --git a/extensions/ql-vscode/src/common/commands.ts b/extensions/ql-vscode/src/common/commands.ts index 051e59394..8d520d91f 100644 --- a/extensions/ql-vscode/src/common/commands.ts +++ b/extensions/ql-vscode/src/common/commands.ts @@ -58,6 +58,9 @@ export type QueryHistoryCommands = { "codeQLQueryHistory.itemClicked": SelectionCommandFunction; "codeQLQueryHistory.openOnGithub": SelectionCommandFunction; "codeQLQueryHistory.copyRepoList": SelectionCommandFunction; + + // Commands in the command pallete + "codeQL.exportSelectedVariantAnalysisResults": () => Promise; }; // Commands tied to variant analysis diff --git a/extensions/ql-vscode/src/extension.ts b/extensions/ql-vscode/src/extension.ts index 00203bd6a..2edfeb314 100644 --- a/extensions/ql-vscode/src/extension.ts +++ b/extensions/ql-vscode/src/extension.ts @@ -109,7 +109,6 @@ import { handleInstallPackDependencies, } from "./packaging"; import { HistoryItemLabelProvider } from "./query-history/history-item-label-provider"; -import { exportSelectedVariantAnalysisResults } from "./variant-analysis/export-results"; import { EvalLogViewer } from "./eval-log-viewer"; import { SummaryLanguageSupport } from "./log-insights/summary-language-support"; import { JoinOrderScannerProvider } from "./log-insights/join-order"; @@ -1144,12 +1143,6 @@ async function activateWithInstalledDistribution( ), ); - ctx.subscriptions.push( - commandRunner("codeQL.exportSelectedVariantAnalysisResults", async () => { - await exportSelectedVariantAnalysisResults(variantAnalysisManager, qhm); - }), - ); - ctx.subscriptions.push( commandRunner( "codeQL.loadVariantAnalysisRepoResults", diff --git a/extensions/ql-vscode/src/query-history/query-history-manager.ts b/extensions/ql-vscode/src/query-history/query-history-manager.ts index 9647613cd..8eb018843 100644 --- a/extensions/ql-vscode/src/query-history/query-history-manager.ts +++ b/extensions/ql-vscode/src/query-history/query-history-manager.ts @@ -271,6 +271,9 @@ export class QueryHistoryManager extends DisposableObject { "codeQLQueryHistory.itemClicked": this.handleItemClicked.bind(this), "codeQLQueryHistory.openOnGithub": this.handleOpenOnGithub.bind(this), "codeQLQueryHistory.copyRepoList": this.handleCopyRepoList.bind(this), + + "codeQL.exportSelectedVariantAnalysisResults": + this.exportSelectedVariantAnalysisResults.bind(this), }; } @@ -1127,6 +1130,22 @@ export class QueryHistoryManager extends DisposableObject { ); } + /** + * Exports the results of the currently-selected variant analysis. + */ + async exportSelectedVariantAnalysisResults(): Promise { + const queryHistoryItem = this.getCurrentQueryHistoryItem(); + if (!queryHistoryItem || queryHistoryItem.t !== "variant-analysis") { + throw new Error( + "No variant analysis results currently open. To open results, click an item in the query history view.", + ); + } + + await this.variantAnalysisManager.exportResults( + queryHistoryItem.variantAnalysis.id, + ); + } + addQuery(item: QueryHistoryInfo) { this.treeDataProvider.pushQuery(item); this.updateTreeViewSelectionIfVisible(); diff --git a/extensions/ql-vscode/src/variant-analysis/export-results.ts b/extensions/ql-vscode/src/variant-analysis/export-results.ts index 7b5647a00..472b914df 100644 --- a/extensions/ql-vscode/src/variant-analysis/export-results.ts +++ b/extensions/ql-vscode/src/variant-analysis/export-results.ts @@ -16,7 +16,6 @@ import { } from "../commandRunner"; import { showInformationMessageWithAction } from "../helpers"; import { extLogger } from "../common"; -import { QueryHistoryManager } from "../query-history/query-history-manager"; import { createGist } from "./gh-api/gh-api-client"; import { generateVariantAnalysisMarkdown, @@ -37,25 +36,6 @@ import { } from "../pure/variant-analysis-filter-sort"; import { Credentials } from "../common/authentication"; -/** - * Exports the results of the currently-selected variant analysis. - */ -export async function exportSelectedVariantAnalysisResults( - variantAnalysisManager: VariantAnalysisManager, - queryHistoryManager: QueryHistoryManager, -): Promise { - const queryHistoryItem = queryHistoryManager.getCurrentQueryHistoryItem(); - if (!queryHistoryItem || queryHistoryItem.t !== "variant-analysis") { - throw new Error( - "No variant analysis results currently open. To open results, click an item in the query history view.", - ); - } - - await variantAnalysisManager.exportResults( - queryHistoryItem.variantAnalysis.id, - ); -} - const MAX_VARIANT_ANALYSIS_EXPORT_PROGRESS_STEPS = 2; /** From b55910d2b98f105e22178902e24e06b5b2aa8e4e Mon Sep 17 00:00:00 2001 From: Robert Date: Mon, 20 Mar 2023 15:27:19 +0000 Subject: [PATCH 076/156] Convert the codeQL.monitorVariantAnalysis command --- extensions/ql-vscode/src/common/commands.ts | 3 +++ extensions/ql-vscode/src/extension.ts | 12 --------- .../variant-analysis-manager.ts | 3 +-- .../variant-analysis-monitor.ts | 7 +----- .../variant-analysis-monitor.test.ts | 25 +------------------ 5 files changed, 6 insertions(+), 44 deletions(-) diff --git a/extensions/ql-vscode/src/common/commands.ts b/extensions/ql-vscode/src/common/commands.ts index 472d9976d..fd7f47e9b 100644 --- a/extensions/ql-vscode/src/common/commands.ts +++ b/extensions/ql-vscode/src/common/commands.ts @@ -68,6 +68,9 @@ export type VariantAnalysisCommands = { variantAnalysisId: number, filterSort?: RepositoriesFilterSortStateWithIds, ) => Promise; + "codeQL.monitorVariantAnalysis": ( + variantAnalysis: VariantAnalysis, + ) => Promise; "codeQL.openVariantAnalysisLogs": ( variantAnalysisId: number, ) => Promise; diff --git a/extensions/ql-vscode/src/extension.ts b/extensions/ql-vscode/src/extension.ts index 8a833b843..6f590d093 100644 --- a/extensions/ql-vscode/src/extension.ts +++ b/extensions/ql-vscode/src/extension.ts @@ -1100,18 +1100,6 @@ async function activateWithInstalledDistribution( app.commands.register(commandName as keyof AllCommands, command); } - ctx.subscriptions.push( - commandRunner( - "codeQL.monitorVariantAnalysis", - async (variantAnalysis: VariantAnalysis, token: CancellationToken) => { - await variantAnalysisManager.monitorVariantAnalysis( - variantAnalysis, - token, - ); - }, - ), - ); - ctx.subscriptions.push( commandRunner( "codeQL.autoDownloadVariantAnalysisResult", diff --git a/extensions/ql-vscode/src/variant-analysis/variant-analysis-manager.ts b/extensions/ql-vscode/src/variant-analysis/variant-analysis-manager.ts index 127c71870..7256f80a2 100644 --- a/extensions/ql-vscode/src/variant-analysis/variant-analysis-manager.ts +++ b/extensions/ql-vscode/src/variant-analysis/variant-analysis-manager.ts @@ -133,6 +133,7 @@ export class VariantAnalysisManager return { "codeQL.copyVariantAnalysisRepoList": this.copyRepoListToClipboard.bind(this), + "codeQL.monitorVariantAnalysis": this.monitorVariantAnalysis.bind(this), "codeQL.openVariantAnalysisLogs": this.openVariantAnalysisLogs.bind(this), "codeQL.runVariantAnalysis": this.runVariantAnalysisFromCommand.bind(this), @@ -496,12 +497,10 @@ export class VariantAnalysisManager public async monitorVariantAnalysis( variantAnalysis: VariantAnalysis, - cancellationToken: CancellationToken, ): Promise { await this.variantAnalysisMonitor.monitorVariantAnalysis( variantAnalysis, this.app.credentials, - cancellationToken, ); } diff --git a/extensions/ql-vscode/src/variant-analysis/variant-analysis-monitor.ts b/extensions/ql-vscode/src/variant-analysis/variant-analysis-monitor.ts index f7683fb4b..7fa8f3b14 100644 --- a/extensions/ql-vscode/src/variant-analysis/variant-analysis-monitor.ts +++ b/extensions/ql-vscode/src/variant-analysis/variant-analysis-monitor.ts @@ -1,4 +1,4 @@ -import { CancellationToken, commands, EventEmitter } from "vscode"; +import { commands, EventEmitter } from "vscode"; import { getVariantAnalysis } from "./gh-api/gh-api-client"; import { @@ -37,7 +37,6 @@ export class VariantAnalysisMonitor extends DisposableObject { public async monitorVariantAnalysis( variantAnalysis: VariantAnalysis, credentials: Credentials, - cancellationToken: CancellationToken, ): Promise { let attemptCount = 0; const scannedReposDownloaded: number[] = []; @@ -45,10 +44,6 @@ export class VariantAnalysisMonitor extends DisposableObject { while (attemptCount <= VariantAnalysisMonitor.maxAttemptCount) { await sleep(VariantAnalysisMonitor.sleepTime); - if (cancellationToken && cancellationToken.isCancellationRequested) { - return; - } - if (await this.shouldCancelMonitor(variantAnalysis.id)) { return; } diff --git a/extensions/ql-vscode/test/vscode-tests/activated-extension/variant-analysis/variant-analysis-monitor.test.ts b/extensions/ql-vscode/test/vscode-tests/activated-extension/variant-analysis/variant-analysis-monitor.test.ts index 0c9082c91..18cb88f42 100644 --- a/extensions/ql-vscode/test/vscode-tests/activated-extension/variant-analysis/variant-analysis-monitor.test.ts +++ b/extensions/ql-vscode/test/vscode-tests/activated-extension/variant-analysis/variant-analysis-monitor.test.ts @@ -1,4 +1,4 @@ -import { CancellationTokenSource, commands, extensions } from "vscode"; +import { commands, extensions } from "vscode"; import { CodeQLExtensionInterface } from "../../../../src/extension"; import * as ghApiClient from "../../../../src/variant-analysis/gh-api/gh-api-client"; @@ -33,7 +33,6 @@ describe("Variant Analysis Monitor", () => { let mockGetVariantAnalysis: jest.SpiedFunction< typeof ghApiClient.getVariantAnalysis >; - let cancellationTokenSource: CancellationTokenSource; let variantAnalysisMonitor: VariantAnalysisMonitor; let shouldCancelMonitor: jest.Mock, [number]>; let variantAnalysis: VariantAnalysis; @@ -45,8 +44,6 @@ describe("Variant Analysis Monitor", () => { const onVariantAnalysisChangeSpy = jest.fn(); beforeEach(async () => { - cancellationTokenSource = new CancellationTokenSource(); - variantAnalysis = createMockVariantAnalysis({}); shouldCancelMonitor = jest.fn(); @@ -71,25 +68,12 @@ describe("Variant Analysis Monitor", () => { limitNumberOfAttemptsToMonitor(); }); - it("should return early if variant analysis is cancelled", async () => { - cancellationTokenSource.cancel(); - - await variantAnalysisMonitor.monitorVariantAnalysis( - variantAnalysis, - testCredentialsWithStub(), - cancellationTokenSource.token, - ); - - expect(onVariantAnalysisChangeSpy).not.toHaveBeenCalled(); - }); - it("should return early if variant analysis should be cancelled", async () => { shouldCancelMonitor.mockResolvedValue(true); await variantAnalysisMonitor.monitorVariantAnalysis( variantAnalysis, testCredentialsWithStub(), - cancellationTokenSource.token, ); expect(onVariantAnalysisChangeSpy).not.toHaveBeenCalled(); @@ -107,7 +91,6 @@ describe("Variant Analysis Monitor", () => { await variantAnalysisMonitor.monitorVariantAnalysis( variantAnalysis, testCredentialsWithStub(), - cancellationTokenSource.token, ); expect(mockGetVariantAnalysis).toHaveBeenCalledTimes(1); @@ -157,7 +140,6 @@ describe("Variant Analysis Monitor", () => { await variantAnalysisMonitor.monitorVariantAnalysis( variantAnalysis, testCredentialsWithStub(), - cancellationTokenSource.token, ); expect(commandSpy).toBeCalledTimes(succeededRepos.length); @@ -176,7 +158,6 @@ describe("Variant Analysis Monitor", () => { await variantAnalysisMonitor.monitorVariantAnalysis( variantAnalysis, testCredentialsWithStub(), - cancellationTokenSource.token, ); expect(mockGetDownloadResult).toBeCalledTimes(succeededRepos.length); @@ -209,7 +190,6 @@ describe("Variant Analysis Monitor", () => { await variantAnalysisMonitor.monitorVariantAnalysis( variantAnalysis, testCredentialsWithStub(), - cancellationTokenSource.token, ); expect(commandSpy).not.toHaveBeenCalled(); @@ -219,7 +199,6 @@ describe("Variant Analysis Monitor", () => { await variantAnalysisMonitor.monitorVariantAnalysis( variantAnalysis, testCredentialsWithStub(), - cancellationTokenSource.token, ); expect(mockGetDownloadResult).not.toBeCalled(); @@ -278,7 +257,6 @@ describe("Variant Analysis Monitor", () => { await variantAnalysisMonitor.monitorVariantAnalysis( variantAnalysis, testCredentialsWithStub(), - cancellationTokenSource.token, ); expect(mockGetVariantAnalysis).toBeCalledTimes(4); @@ -297,7 +275,6 @@ describe("Variant Analysis Monitor", () => { await variantAnalysisMonitor.monitorVariantAnalysis( variantAnalysis, testCredentialsWithStub(), - cancellationTokenSource.token, ); expect(mockGetDownloadResult).not.toBeCalled(); From 5f2a8fa1d51d91fe8c400301318174b91c369fdb Mon Sep 17 00:00:00 2001 From: Robert Date: Mon, 20 Mar 2023 15:30:19 +0000 Subject: [PATCH 077/156] Convert the codeQL.autoDownloadVariantAnalysisResult command --- extensions/ql-vscode/src/common/commands.ts | 9 +++++- extensions/ql-vscode/src/extension.ts | 21 ------------- .../variant-analysis-manager.ts | 17 ++-------- .../variant-analysis-manager.test.ts | 31 ------------------- .../variant-analysis-monitor.test.ts | 1 - 5 files changed, 11 insertions(+), 68 deletions(-) diff --git a/extensions/ql-vscode/src/common/commands.ts b/extensions/ql-vscode/src/common/commands.ts index fd7f47e9b..24c8b0e98 100644 --- a/extensions/ql-vscode/src/common/commands.ts +++ b/extensions/ql-vscode/src/common/commands.ts @@ -3,7 +3,10 @@ import type { Uri } from "vscode"; import type { DbTreeViewItem } from "../databases/ui/db-tree-view-item"; import type { QueryHistoryInfo } from "../query-history/query-history-info"; import { RepositoriesFilterSortStateWithIds } from "../pure/variant-analysis-filter-sort"; -import { VariantAnalysis } from "../variant-analysis/shared/variant-analysis"; +import { + VariantAnalysis, + VariantAnalysisScannedRepository, +} from "../variant-analysis/shared/variant-analysis"; // A command function matching the signature that VS Code calls when // a command on a selection is invoked. @@ -64,6 +67,10 @@ export type QueryHistoryCommands = { // Commands tied to variant analysis export type VariantAnalysisCommands = { + "codeQL.autoDownloadVariantAnalysisResult": ( + scannedRepo: VariantAnalysisScannedRepository, + variantAnalysisSummary: VariantAnalysis, + ) => Promise; "codeQL.copyVariantAnalysisRepoList": ( variantAnalysisId: number, filterSort?: RepositoriesFilterSortStateWithIds, diff --git a/extensions/ql-vscode/src/extension.ts b/extensions/ql-vscode/src/extension.ts index 6f590d093..cf045bf2d 100644 --- a/extensions/ql-vscode/src/extension.ts +++ b/extensions/ql-vscode/src/extension.ts @@ -120,10 +120,6 @@ import { NewQueryRunner } from "./query-server/query-runner"; import { QueryRunner } from "./queryRunner"; import { VariantAnalysisView } from "./variant-analysis/variant-analysis-view"; import { VariantAnalysisViewSerializer } from "./variant-analysis/variant-analysis-view-serializer"; -import { - VariantAnalysis, - VariantAnalysisScannedRepository, -} from "./variant-analysis/shared/variant-analysis"; import { VariantAnalysisManager } from "./variant-analysis/variant-analysis-manager"; import { createVariantAnalysisContentProvider } from "./variant-analysis/variant-analysis-content-provider"; import { VSCodeMockGitHubApiServer } from "./mocks/vscode-mock-gh-api-server"; @@ -1100,23 +1096,6 @@ async function activateWithInstalledDistribution( app.commands.register(commandName as keyof AllCommands, command); } - ctx.subscriptions.push( - commandRunner( - "codeQL.autoDownloadVariantAnalysisResult", - async ( - scannedRepo: VariantAnalysisScannedRepository, - variantAnalysisSummary: VariantAnalysis, - token: CancellationToken, - ) => { - await variantAnalysisManager.enqueueDownload( - scannedRepo, - variantAnalysisSummary, - token, - ); - }, - ), - ); - ctx.subscriptions.push( commandRunner("codeQL.exportSelectedVariantAnalysisResults", async () => { await exportSelectedVariantAnalysisResults(variantAnalysisManager, qhm); diff --git a/extensions/ql-vscode/src/variant-analysis/variant-analysis-manager.ts b/extensions/ql-vscode/src/variant-analysis/variant-analysis-manager.ts index 7256f80a2..f5fc5fb75 100644 --- a/extensions/ql-vscode/src/variant-analysis/variant-analysis-manager.ts +++ b/extensions/ql-vscode/src/variant-analysis/variant-analysis-manager.ts @@ -131,6 +131,8 @@ export class VariantAnalysisManager getCommands(): VariantAnalysisCommands { return { + "codeQL.autoDownloadVariantAnalysisResult": + this.enqueueDownload.bind(this), "codeQL.copyVariantAnalysisRepoList": this.copyRepoListToClipboard.bind(this), "codeQL.monitorVariantAnalysis": this.monitorVariantAnalysis.bind(this), @@ -507,7 +509,6 @@ export class VariantAnalysisManager public async autoDownloadVariantAnalysisResult( scannedRepo: VariantAnalysisScannedRepository, variantAnalysis: VariantAnalysis, - cancellationToken: CancellationToken, ): Promise { if ( this.repoStates.get(variantAnalysis.id)?.[scannedRepo.repository.id] @@ -524,13 +525,6 @@ export class VariantAnalysisManager await this.onRepoStateUpdated(variantAnalysis.id, repoState); - if (cancellationToken && cancellationToken.isCancellationRequested) { - repoState.downloadStatus = - VariantAnalysisScannedRepositoryDownloadStatus.Failed; - await this.onRepoStateUpdated(variantAnalysis.id, repoState); - return; - } - let repoTask: VariantAnalysisRepositoryTask; try { const repoTaskResponse = await getVariantAnalysisRepo( @@ -605,14 +599,9 @@ export class VariantAnalysisManager public async enqueueDownload( scannedRepo: VariantAnalysisScannedRepository, variantAnalysis: VariantAnalysis, - token: CancellationToken, ): Promise { await this.queue.add(() => - this.autoDownloadVariantAnalysisResult( - scannedRepo, - variantAnalysis, - token, - ), + this.autoDownloadVariantAnalysisResult(scannedRepo, variantAnalysis), ); } diff --git a/extensions/ql-vscode/test/vscode-tests/activated-extension/variant-analysis/variant-analysis-manager.test.ts b/extensions/ql-vscode/test/vscode-tests/activated-extension/variant-analysis/variant-analysis-manager.test.ts index 024a1bc82..05e9b5ed6 100644 --- a/extensions/ql-vscode/test/vscode-tests/activated-extension/variant-analysis/variant-analysis-manager.test.ts +++ b/extensions/ql-vscode/test/vscode-tests/activated-extension/variant-analysis/variant-analysis-manager.test.ts @@ -1,5 +1,4 @@ import { - CancellationTokenSource, commands, env, extensions, @@ -54,7 +53,6 @@ jest.setTimeout(3 * 60 * 1000); describe("Variant Analysis Manager", () => { let app: App; - let cancellationTokenSource: CancellationTokenSource; let variantAnalysisManager: VariantAnalysisManager; let variantAnalysisResultsManager: VariantAnalysisResultsManager; let variantAnalysis: VariantAnalysis; @@ -63,8 +61,6 @@ describe("Variant Analysis Manager", () => { beforeEach(async () => { jest.spyOn(extLogger, "log").mockResolvedValue(undefined); - cancellationTokenSource = new CancellationTokenSource(); - scannedRepos = createMockScannedRepos(); variantAnalysis = createMockVariantAnalysis({ status: VariantAnalysisStatus.InProgress, @@ -203,7 +199,6 @@ describe("Variant Analysis Manager", () => { await variantAnalysisManager.autoDownloadVariantAnalysisResult( scannedRepos[0], variantAnalysis, - cancellationTokenSource.token, ); expect(getVariantAnalysisRepoResultStub).not.toHaveBeenCalled(); @@ -228,23 +223,10 @@ describe("Variant Analysis Manager", () => { getVariantAnalysisRepoResultStub.mockResolvedValue(response); }); - it("should return early if variant analysis is cancelled", async () => { - cancellationTokenSource.cancel(); - - await variantAnalysisManager.autoDownloadVariantAnalysisResult( - scannedRepos[0], - variantAnalysis, - cancellationTokenSource.token, - ); - - expect(getVariantAnalysisRepoStub).not.toHaveBeenCalled(); - }); - it("should fetch a repo task", async () => { await variantAnalysisManager.autoDownloadVariantAnalysisResult( scannedRepos[0], variantAnalysis, - cancellationTokenSource.token, ); expect(getVariantAnalysisRepoStub).toHaveBeenCalled(); @@ -254,7 +236,6 @@ describe("Variant Analysis Manager", () => { await variantAnalysisManager.autoDownloadVariantAnalysisResult( scannedRepos[0], variantAnalysis, - cancellationTokenSource.token, ); expect(getVariantAnalysisRepoResultStub).toHaveBeenCalled(); @@ -265,7 +246,6 @@ describe("Variant Analysis Manager", () => { await variantAnalysisManager.autoDownloadVariantAnalysisResult( scannedRepos[0], variantAnalysis, - cancellationTokenSource.token, ); getVariantAnalysisRepoStub.mockClear(); @@ -273,7 +253,6 @@ describe("Variant Analysis Manager", () => { await variantAnalysisManager.autoDownloadVariantAnalysisResult( scannedRepos[0], variantAnalysis, - cancellationTokenSource.token, ); expect(getVariantAnalysisRepoStub).not.toHaveBeenCalled(); @@ -283,7 +262,6 @@ describe("Variant Analysis Manager", () => { await variantAnalysisManager.autoDownloadVariantAnalysisResult( scannedRepos[0], variantAnalysis, - cancellationTokenSource.token, ); await expect(fs.readJson(repoStatesPath)).resolves.toEqual({ @@ -304,7 +282,6 @@ describe("Variant Analysis Manager", () => { variantAnalysisManager.autoDownloadVariantAnalysisResult( scannedRepos[0], variantAnalysis, - cancellationTokenSource.token, ), ).rejects.toThrow(); @@ -320,7 +297,6 @@ describe("Variant Analysis Manager", () => { variantAnalysisManager.autoDownloadVariantAnalysisResult( scannedRepos[0], variantAnalysis, - cancellationTokenSource.token, ), ).rejects.toThrow(); @@ -329,7 +305,6 @@ describe("Variant Analysis Manager", () => { await variantAnalysisManager.autoDownloadVariantAnalysisResult( scannedRepos[1], variantAnalysis, - cancellationTokenSource.token, ); await expect(fs.readJson(repoStatesPath)).resolves.toEqual({ @@ -355,7 +330,6 @@ describe("Variant Analysis Manager", () => { variantAnalysisManager.autoDownloadVariantAnalysisResult( scannedRepos[0], variantAnalysis, - cancellationTokenSource.token, ), ).rejects.toThrow(); @@ -364,7 +338,6 @@ describe("Variant Analysis Manager", () => { await variantAnalysisManager.autoDownloadVariantAnalysisResult( scannedRepos[1], variantAnalysis, - cancellationTokenSource.token, ); await expect(fs.readJson(repoStatesPath)).resolves.toEqual({ @@ -400,7 +373,6 @@ describe("Variant Analysis Manager", () => { await variantAnalysisManager.autoDownloadVariantAnalysisResult( scannedRepos[0], variantAnalysis, - cancellationTokenSource.token, ); await expect(fs.readJson(repoStatesPath)).resolves.toEqual({ @@ -439,17 +411,14 @@ describe("Variant Analysis Manager", () => { await variantAnalysisManager.enqueueDownload( scannedRepos[0], variantAnalysis, - cancellationTokenSource.token, ); await variantAnalysisManager.enqueueDownload( scannedRepos[1], variantAnalysis, - cancellationTokenSource.token, ); await variantAnalysisManager.enqueueDownload( scannedRepos[2], variantAnalysis, - cancellationTokenSource.token, ); expect(variantAnalysisManager.downloadsQueueSize()).toBe(0); diff --git a/extensions/ql-vscode/test/vscode-tests/activated-extension/variant-analysis/variant-analysis-monitor.test.ts b/extensions/ql-vscode/test/vscode-tests/activated-extension/variant-analysis/variant-analysis-monitor.test.ts index 18cb88f42..329e85685 100644 --- a/extensions/ql-vscode/test/vscode-tests/activated-extension/variant-analysis/variant-analysis-monitor.test.ts +++ b/extensions/ql-vscode/test/vscode-tests/activated-extension/variant-analysis/variant-analysis-monitor.test.ts @@ -167,7 +167,6 @@ describe("Variant Analysis Monitor", () => { index + 1, processScannedRepository(succeededRepo), processUpdatedVariantAnalysis(variantAnalysis, mockApiResponse), - undefined, ); }); }); From ac0d9201569234331e2224d2a384f751fba974da Mon Sep 17 00:00:00 2001 From: Robert Date: Mon, 20 Mar 2023 15:41:28 +0000 Subject: [PATCH 078/156] Convert the codeQL.loadVariantAnalysisRepoResults command --- extensions/ql-vscode/src/common/commands.ts | 5 +++++ extensions/ql-vscode/src/extension.ts | 13 ------------- .../variant-analysis/variant-analysis-manager.ts | 1 + 3 files changed, 6 insertions(+), 13 deletions(-) diff --git a/extensions/ql-vscode/src/common/commands.ts b/extensions/ql-vscode/src/common/commands.ts index 24c8b0e98..930570f05 100644 --- a/extensions/ql-vscode/src/common/commands.ts +++ b/extensions/ql-vscode/src/common/commands.ts @@ -6,6 +6,7 @@ import { RepositoriesFilterSortStateWithIds } from "../pure/variant-analysis-fil import { VariantAnalysis, VariantAnalysisScannedRepository, + VariantAnalysisScannedRepositoryResult, } from "../variant-analysis/shared/variant-analysis"; // A command function matching the signature that VS Code calls when @@ -75,6 +76,10 @@ export type VariantAnalysisCommands = { variantAnalysisId: number, filterSort?: RepositoriesFilterSortStateWithIds, ) => Promise; + "codeQL.loadVariantAnalysisRepoResults": ( + variantAnalysisId: number, + repositoryFullName: string, + ) => Promise; "codeQL.monitorVariantAnalysis": ( variantAnalysis: VariantAnalysis, ) => Promise; diff --git a/extensions/ql-vscode/src/extension.ts b/extensions/ql-vscode/src/extension.ts index cf045bf2d..19fb101a7 100644 --- a/extensions/ql-vscode/src/extension.ts +++ b/extensions/ql-vscode/src/extension.ts @@ -125,7 +125,6 @@ import { createVariantAnalysisContentProvider } from "./variant-analysis/variant import { VSCodeMockGitHubApiServer } from "./mocks/vscode-mock-gh-api-server"; import { VariantAnalysisResultsManager } from "./variant-analysis/variant-analysis-results-manager"; import { ExtensionApp } from "./common/vscode/vscode-app"; -import { RepositoriesFilterSortStateWithIds } from "./pure/variant-analysis-filter-sort"; import { DbModule } from "./databases/db-module"; import { redactableError } from "./pure/errors"; import { QueryHistoryDirs } from "./query-history/query-history-dirs"; @@ -1102,18 +1101,6 @@ async function activateWithInstalledDistribution( }), ); - ctx.subscriptions.push( - commandRunner( - "codeQL.loadVariantAnalysisRepoResults", - async (variantAnalysisId: number, repositoryFullName: string) => { - await variantAnalysisManager.loadResults( - variantAnalysisId, - repositoryFullName, - ); - }, - ), - ); - // The "openVariantAnalysisView" command is internal-only. ctx.subscriptions.push( commandRunner( diff --git a/extensions/ql-vscode/src/variant-analysis/variant-analysis-manager.ts b/extensions/ql-vscode/src/variant-analysis/variant-analysis-manager.ts index f5fc5fb75..859d540ff 100644 --- a/extensions/ql-vscode/src/variant-analysis/variant-analysis-manager.ts +++ b/extensions/ql-vscode/src/variant-analysis/variant-analysis-manager.ts @@ -135,6 +135,7 @@ export class VariantAnalysisManager this.enqueueDownload.bind(this), "codeQL.copyVariantAnalysisRepoList": this.copyRepoListToClipboard.bind(this), + "codeQL.loadVariantAnalysisRepoResults": this.loadResults.bind(this), "codeQL.monitorVariantAnalysis": this.monitorVariantAnalysis.bind(this), "codeQL.openVariantAnalysisLogs": this.openVariantAnalysisLogs.bind(this), "codeQL.runVariantAnalysis": From 0c9df6edba33e16be8d7f5942cc4e0d8726ddd78 Mon Sep 17 00:00:00 2001 From: Robert Date: Mon, 20 Mar 2023 15:43:44 +0000 Subject: [PATCH 079/156] Convert the codeQL.openVariantAnalysisView command --- extensions/ql-vscode/src/common/commands.ts | 3 +++ extensions/ql-vscode/src/extension.ts | 10 ---------- .../src/variant-analysis/variant-analysis-manager.ts | 1 + 3 files changed, 4 insertions(+), 10 deletions(-) diff --git a/extensions/ql-vscode/src/common/commands.ts b/extensions/ql-vscode/src/common/commands.ts index 930570f05..93f9f5b15 100644 --- a/extensions/ql-vscode/src/common/commands.ts +++ b/extensions/ql-vscode/src/common/commands.ts @@ -86,6 +86,9 @@ export type VariantAnalysisCommands = { "codeQL.openVariantAnalysisLogs": ( variantAnalysisId: number, ) => Promise; + "codeQL.openVariantAnalysisView": ( + variantAnalysisId: number, + ) => Promise; "codeQL.runVariantAnalysis": (uri?: Uri) => Promise; "codeQL.runVariantAnalysisContextEditor": (uri?: Uri) => Promise; }; diff --git a/extensions/ql-vscode/src/extension.ts b/extensions/ql-vscode/src/extension.ts index 19fb101a7..169fb9e73 100644 --- a/extensions/ql-vscode/src/extension.ts +++ b/extensions/ql-vscode/src/extension.ts @@ -1101,16 +1101,6 @@ async function activateWithInstalledDistribution( }), ); - // The "openVariantAnalysisView" command is internal-only. - ctx.subscriptions.push( - commandRunner( - "codeQL.openVariantAnalysisView", - async (variantAnalysisId: number) => { - await variantAnalysisManager.showView(variantAnalysisId); - }, - ), - ); - ctx.subscriptions.push( commandRunner("codeQL.openReferencedFile", async (selectedQuery: Uri) => { await openReferencedFile(qs, cliServer, selectedQuery); diff --git a/extensions/ql-vscode/src/variant-analysis/variant-analysis-manager.ts b/extensions/ql-vscode/src/variant-analysis/variant-analysis-manager.ts index 859d540ff..af4eea987 100644 --- a/extensions/ql-vscode/src/variant-analysis/variant-analysis-manager.ts +++ b/extensions/ql-vscode/src/variant-analysis/variant-analysis-manager.ts @@ -138,6 +138,7 @@ export class VariantAnalysisManager "codeQL.loadVariantAnalysisRepoResults": this.loadResults.bind(this), "codeQL.monitorVariantAnalysis": this.monitorVariantAnalysis.bind(this), "codeQL.openVariantAnalysisLogs": this.openVariantAnalysisLogs.bind(this), + "codeQL.openVariantAnalysisView": this.showView.bind(this), "codeQL.runVariantAnalysis": this.runVariantAnalysisFromCommand.bind(this), // Since we are tracking extension usage through commands, this command mirrors the "codeQL.runVariantAnalysis" command From 5cd50a67e7ccb6160741d9cb669dc6662f05ce44 Mon Sep 17 00:00:00 2001 From: Nora Date: Tue, 21 Mar 2023 10:39:02 +0000 Subject: [PATCH 080/156] Move query-serialization --- .../query-history/query-history-manager.ts | 2 +- .../store}/query-serialization.ts | 14 +++++------ .../store}/query-serialization.test.ts | 23 +++++++++++-------- 3 files changed, 21 insertions(+), 18 deletions(-) rename extensions/ql-vscode/src/{ => query-history/store}/query-serialization.ts (91%) rename extensions/ql-vscode/test/vscode-tests/no-workspace/{ => query-history/store}/query-serialization.test.ts (89%) diff --git a/extensions/ql-vscode/src/query-history/query-history-manager.ts b/extensions/ql-vscode/src/query-history/query-history-manager.ts index 9647613cd..ad4adf311 100644 --- a/extensions/ql-vscode/src/query-history/query-history-manager.ts +++ b/extensions/ql-vscode/src/query-history/query-history-manager.ts @@ -48,7 +48,7 @@ import { import { deserializeQueryHistory, serializeQueryHistory, -} from "../query-serialization"; +} from "./store/query-serialization"; import { pathExists } from "fs-extra"; import { CliVersionConstraint } from "../cli"; import { HistoryItemLabelProvider } from "./history-item-label-provider"; diff --git a/extensions/ql-vscode/src/query-serialization.ts b/extensions/ql-vscode/src/query-history/store/query-serialization.ts similarity index 91% rename from extensions/ql-vscode/src/query-serialization.ts rename to extensions/ql-vscode/src/query-history/store/query-serialization.ts index a83d4a1a8..bad4a4677 100644 --- a/extensions/ql-vscode/src/query-serialization.ts +++ b/extensions/ql-vscode/src/query-history/store/query-serialization.ts @@ -1,18 +1,18 @@ import { pathExists, readFile, remove, mkdir, writeFile } from "fs-extra"; import { dirname } from "path"; -import { showAndLogExceptionWithTelemetry } from "./helpers"; +import { showAndLogExceptionWithTelemetry } from "../../helpers"; import { asError, asyncFilter, getErrorMessage, getErrorStack, -} from "./pure/helpers-pure"; -import { CompletedQueryInfo, LocalQueryInfo } from "./query-results"; -import { QueryHistoryInfo } from "./query-history/query-history-info"; -import { QueryEvaluationInfo } from "./run-queries-shared"; -import { QueryResultType } from "./pure/legacy-messages"; -import { redactableError } from "./pure/errors"; +} from "../../pure/helpers-pure"; +import { CompletedQueryInfo, LocalQueryInfo } from "../../query-results"; +import { QueryHistoryInfo } from "../query-history-info"; +import { QueryEvaluationInfo } from "../../run-queries-shared"; +import { QueryResultType } from "../../pure/legacy-messages"; +import { redactableError } from "../../pure/errors"; export async function deserializeQueryHistory( fsPath: string, diff --git a/extensions/ql-vscode/test/vscode-tests/no-workspace/query-serialization.test.ts b/extensions/ql-vscode/test/vscode-tests/no-workspace/query-history/store/query-serialization.test.ts similarity index 89% rename from extensions/ql-vscode/test/vscode-tests/no-workspace/query-serialization.test.ts rename to extensions/ql-vscode/test/vscode-tests/no-workspace/query-history/store/query-serialization.test.ts index 4eea14a61..f09fdfb1b 100644 --- a/extensions/ql-vscode/test/vscode-tests/no-workspace/query-serialization.test.ts +++ b/extensions/ql-vscode/test/vscode-tests/no-workspace/query-history/store/query-serialization.test.ts @@ -1,19 +1,22 @@ import { deserializeQueryHistory, serializeQueryHistory, -} from "../../../src/query-serialization"; +} from "../../../../../src/query-history/store/query-serialization"; import { join } from "path"; import { writeFileSync, mkdirpSync, writeFile } from "fs-extra"; -import { LocalQueryInfo, InitialQueryInfo } from "../../../src/query-results"; -import { QueryWithResults } from "../../../src/run-queries-shared"; -import { DatabaseInfo } from "../../../src/pure/interface-types"; +import { + LocalQueryInfo, + InitialQueryInfo, +} from "../../../../../src/query-results"; +import { QueryWithResults } from "../../../../../src/run-queries-shared"; +import { DatabaseInfo } from "../../../../../src/pure/interface-types"; import { CancellationTokenSource, Uri } from "vscode"; -import { tmpDir } from "../../../src/helpers"; -import { QueryResultType } from "../../../src/pure/legacy-messages"; -import { QueryInProgress } from "../../../src/legacy-query-server/run-queries"; -import { VariantAnalysisHistoryItem } from "../../../src/query-history/variant-analysis-history-item"; -import { QueryHistoryInfo } from "../../../src/query-history/query-history-info"; -import { createMockVariantAnalysisHistoryItem } from "../../factories/query-history/variant-analysis-history-item"; +import { tmpDir } from "../../../../../src/helpers"; +import { QueryResultType } from "../../../../../src/pure/legacy-messages"; +import { QueryInProgress } from "../../../../../src/legacy-query-server/run-queries"; +import { VariantAnalysisHistoryItem } from "../../../../../src/query-history/variant-analysis-history-item"; +import { QueryHistoryInfo } from "../../../../../src/query-history/query-history-info"; +import { createMockVariantAnalysisHistoryItem } from "../../../../factories/query-history/variant-analysis-history-item"; import { nanoid } from "nanoid"; describe("serialize and deserialize", () => { From fa29bcc5fde346e676576f085242c89199dd77a9 Mon Sep 17 00:00:00 2001 From: Nora Date: Tue, 21 Mar 2023 11:03:58 +0000 Subject: [PATCH 081/156] Rename serializer --- extensions/ql-vscode/src/query-history/query-history-manager.ts | 2 +- .../store/{query-serialization.ts => query-history-store.ts} | 0 ...{query-serialization.test.ts => query-history-store.test.ts} | 2 +- 3 files changed, 2 insertions(+), 2 deletions(-) rename extensions/ql-vscode/src/query-history/store/{query-serialization.ts => query-history-store.ts} (100%) rename extensions/ql-vscode/test/vscode-tests/no-workspace/query-history/store/{query-serialization.test.ts => query-history-store.test.ts} (99%) diff --git a/extensions/ql-vscode/src/query-history/query-history-manager.ts b/extensions/ql-vscode/src/query-history/query-history-manager.ts index ad4adf311..605942676 100644 --- a/extensions/ql-vscode/src/query-history/query-history-manager.ts +++ b/extensions/ql-vscode/src/query-history/query-history-manager.ts @@ -48,7 +48,7 @@ import { import { deserializeQueryHistory, serializeQueryHistory, -} from "./store/query-serialization"; +} from "./store/query-history-store"; import { pathExists } from "fs-extra"; import { CliVersionConstraint } from "../cli"; import { HistoryItemLabelProvider } from "./history-item-label-provider"; diff --git a/extensions/ql-vscode/src/query-history/store/query-serialization.ts b/extensions/ql-vscode/src/query-history/store/query-history-store.ts similarity index 100% rename from extensions/ql-vscode/src/query-history/store/query-serialization.ts rename to extensions/ql-vscode/src/query-history/store/query-history-store.ts diff --git a/extensions/ql-vscode/test/vscode-tests/no-workspace/query-history/store/query-serialization.test.ts b/extensions/ql-vscode/test/vscode-tests/no-workspace/query-history/store/query-history-store.test.ts similarity index 99% rename from extensions/ql-vscode/test/vscode-tests/no-workspace/query-history/store/query-serialization.test.ts rename to extensions/ql-vscode/test/vscode-tests/no-workspace/query-history/store/query-history-store.test.ts index f09fdfb1b..9adb3d550 100644 --- a/extensions/ql-vscode/test/vscode-tests/no-workspace/query-history/store/query-serialization.test.ts +++ b/extensions/ql-vscode/test/vscode-tests/no-workspace/query-history/store/query-history-store.test.ts @@ -1,7 +1,7 @@ import { deserializeQueryHistory, serializeQueryHistory, -} from "../../../../../src/query-history/store/query-serialization"; +} from "../../../../../src/query-history/store/query-history-store"; import { join } from "path"; import { writeFileSync, mkdirpSync, writeFile } from "fs-extra"; import { From 8a2630d1b735ade5851b6cd2db6169b21fe8b191 Mon Sep 17 00:00:00 2001 From: Koen Vlaswinkel Date: Mon, 20 Mar 2023 16:51:07 +0100 Subject: [PATCH 082/156] Move local queries commands to separate file --- extensions/ql-vscode/src/extension.ts | 478 +------------------- extensions/ql-vscode/src/local-queries.ts | 512 ++++++++++++++++++++++ 2 files changed, 528 insertions(+), 462 deletions(-) create mode 100644 extensions/ql-vscode/src/local-queries.ts diff --git a/extensions/ql-vscode/src/extension.ts b/extensions/ql-vscode/src/extension.ts index 52e805f86..68331db1f 100644 --- a/extensions/ql-vscode/src/extension.ts +++ b/extensions/ql-vscode/src/extension.ts @@ -1,7 +1,6 @@ import "source-map-support/register"; import { CancellationToken, - CancellationTokenSource, commands, Disposable, env, @@ -9,8 +8,6 @@ import { extensions, languages, ProgressLocation, - QuickPickItem, - Range, Uri, version as vscodeVersion, window as Window, @@ -36,12 +33,11 @@ import { CliConfigListener, DistributionConfigListener, joinOrderWarningThreshold, - MAX_QUERIES, QueryHistoryConfigListener, QueryServerConfigListener, } from "./config"; import { install } from "./languageSupport"; -import { DatabaseItem, DatabaseManager } from "./local-databases"; +import { DatabaseManager } from "./local-databases"; import { DatabaseUI } from "./local-databases-ui"; import { TemplatePrintAstProvider, @@ -60,7 +56,6 @@ import { GithubRateLimitedError, } from "./distribution"; import { - findLanguage, showAndLogErrorMessage, showAndLogExceptionWithTelemetry, showAndLogInformationMessage, @@ -86,20 +81,17 @@ import { queryServerLogger, } from "./common"; import { QueryHistoryManager } from "./query-history/query-history-manager"; -import { CompletedLocalQueryInfo, LocalQueryInfo } from "./query-results"; +import { CompletedLocalQueryInfo } from "./query-results"; import { QueryServerClient as LegacyQueryServerClient } from "./legacy-query-server/queryserver-client"; import { QueryServerClient } from "./query-server/queryserver-client"; -import { displayQuickQuery } from "./quick-query"; import { QLTestAdapterFactory } from "./test-adapter"; import { TestUIService } from "./test-ui"; import { CompareView } from "./compare/compare-view"; -import { gatherQlFiles } from "./pure/files"; import { initializeTelemetry } from "./telemetry"; import { commandRunner, commandRunnerWithProgress, ProgressCallback, - ProgressUpdate, withProgress, } from "./commandRunner"; import { CodeQlStatusBarHandler } from "./status-bar"; @@ -113,7 +105,6 @@ import { EvalLogViewer } from "./eval-log-viewer"; import { SummaryLanguageSupport } from "./log-insights/summary-language-support"; import { JoinOrderScannerProvider } from "./log-insights/join-order"; import { LogScannerService } from "./log-insights/log-scanner-service"; -import { createInitialQueryInfo } from "./run-queries-shared"; import { LegacyQueryRunner } from "./legacy-query-server/legacyRunner"; import { NewQueryRunner } from "./query-server/query-runner"; import { QueryRunner } from "./queryRunner"; @@ -134,6 +125,11 @@ import { redactableError } from "./pure/errors"; import { QueryHistoryDirs } from "./query-history/query-history-dirs"; import { DirResult } from "tmp"; import { AllCommands, BaseCommands } from "./common/commands"; +import { + compileAndRunQuery, + registerLocalQueryCommands, + showResultsForCompletedQuery, +} from "./local-queries"; /** * extension.ts @@ -226,10 +222,6 @@ interface DistributionUpdateConfig { allowAutoUpdating: boolean; } -interface DatabaseQuickPickItem extends QuickPickItem { - databaseItem: DatabaseItem; -} - const shouldUpdateOnNextActivationKey = "shouldUpdateOnNextActivation"; const codeQlVersionRange = DEFAULT_DISTRIBUTION_VERSION_RANGE; @@ -792,300 +784,16 @@ async function activateWithInstalledDistribution( } void extLogger.log("Registering top-level command palette commands."); - ctx.subscriptions.push( - commandRunnerWithProgress( - "codeQL.runQuery", - async ( - progress: ProgressCallback, - token: CancellationToken, - uri: Uri | undefined, - ) => - await compileAndRunQuery( - qs, - qhm, - databaseUI, - localQueryResultsView, - queryStorageDir, - false, - uri, - progress, - token, - undefined, - ), - { - title: "Running query", - cancellable: true, - }, - // Open the query server logger on error since that's usually where the interesting errors appear. - queryServerLogger, - ), - ); - - // Since we are tracking extension usage through commands, this command mirrors the runQuery command - ctx.subscriptions.push( - commandRunnerWithProgress( - "codeQL.runQueryContextEditor", - async ( - progress: ProgressCallback, - token: CancellationToken, - uri: Uri | undefined, - ) => - await compileAndRunQuery( - qs, - qhm, - databaseUI, - localQueryResultsView, - queryStorageDir, - false, - uri, - progress, - token, - undefined, - ), - { - title: "Running query", - cancellable: true, - }, - - // Open the query server logger on error since that's usually where the interesting errors appear. - queryServerLogger, - ), - ); - ctx.subscriptions.push( - commandRunnerWithProgress( - "codeQL.runQueryOnMultipleDatabases", - async ( - progress: ProgressCallback, - token: CancellationToken, - uri: Uri | undefined, - ) => - await compileAndRunQueryOnMultipleDatabases( - cliServer, - qs, - qhm, - dbm, - databaseUI, - localQueryResultsView, - queryStorageDir, - progress, - token, - uri, - ), - { - title: "Running query on selected databases", - cancellable: true, - }, - ), - ); - // Since we are tracking extension usage through commands, this command mirrors the runQueryOnMultipleDatabases command - ctx.subscriptions.push( - commandRunnerWithProgress( - "codeQL.runQueryOnMultipleDatabasesContextEditor", - async ( - progress: ProgressCallback, - token: CancellationToken, - uri: Uri | undefined, - ) => - await compileAndRunQueryOnMultipleDatabases( - cliServer, - qs, - qhm, - dbm, - databaseUI, - localQueryResultsView, - queryStorageDir, - progress, - token, - uri, - ), - { - title: "Running query on selected databases", - cancellable: true, - }, - ), - ); - ctx.subscriptions.push( - commandRunnerWithProgress( - "codeQL.runQueries", - async ( - progress: ProgressCallback, - token: CancellationToken, - _: Uri | undefined, - multi: Uri[], - ) => { - const maxQueryCount = MAX_QUERIES.getValue() as number; - const [files, dirFound] = await gatherQlFiles( - multi.map((uri) => uri.fsPath), - ); - if (files.length > maxQueryCount) { - throw new Error( - `You tried to run ${files.length} queries, but the maximum is ${maxQueryCount}. Try selecting fewer queries or changing the 'codeQL.runningQueries.maxQueries' setting.`, - ); - } - // warn user and display selected files when a directory is selected because some ql - // files may be hidden from the user. - if (dirFound) { - const fileString = files.map((file) => basename(file)).join(", "); - const res = await showBinaryChoiceDialog( - `You are about to run ${files.length} queries: ${fileString} Do you want to continue?`, - ); - if (!res) { - return; - } - } - const queryUris = files.map((path) => Uri.parse(`file:${path}`, true)); - - // Use a wrapped progress so that messages appear with the queries remaining in it. - let queriesRemaining = queryUris.length; - function wrappedProgress(update: ProgressUpdate) { - const message = - queriesRemaining > 1 - ? `${queriesRemaining} remaining. ${update.message}` - : update.message; - progress({ - ...update, - message, - }); - } - - wrappedProgress({ - maxStep: queryUris.length, - step: queryUris.length - queriesRemaining, - message: "", - }); - - await Promise.all( - queryUris.map(async (uri) => - compileAndRunQuery( - qs, - qhm, - databaseUI, - localQueryResultsView, - queryStorageDir, - false, - uri, - wrappedProgress, - token, - undefined, - ).then(() => queriesRemaining--), - ), - ); - }, - { - title: "Running queries", - cancellable: true, - }, - - // Open the query server logger on error since that's usually where the interesting errors appear. - queryServerLogger, - ), - ); - - ctx.subscriptions.push( - commandRunnerWithProgress( - "codeQL.quickEval", - async ( - progress: ProgressCallback, - token: CancellationToken, - uri: Uri | undefined, - ) => - await compileAndRunQuery( - qs, - qhm, - databaseUI, - localQueryResultsView, - queryStorageDir, - true, - uri, - progress, - token, - undefined, - ), - { - title: "Running query", - cancellable: true, - }, - // Open the query server logger on error since that's usually where the interesting errors appear. - queryServerLogger, - ), - ); - - // Since we are tracking extension usage through commands, this command mirrors the "codeQL.quickEval" command - ctx.subscriptions.push( - commandRunnerWithProgress( - "codeQL.quickEvalContextEditor", - async ( - progress: ProgressCallback, - token: CancellationToken, - uri: Uri | undefined, - ) => - await compileAndRunQuery( - qs, - qhm, - databaseUI, - localQueryResultsView, - queryStorageDir, - true, - uri, - progress, - token, - undefined, - ), - { - title: "Running query", - cancellable: true, - }, - // Open the query server logger on error since that's usually where the interesting errors appear. - queryServerLogger, - ), - ); - - ctx.subscriptions.push( - commandRunnerWithProgress( - "codeQL.codeLensQuickEval", - async ( - progress: ProgressCallback, - token: CancellationToken, - uri: Uri, - range: Range, - ) => - await compileAndRunQuery( - qs, - qhm, - databaseUI, - localQueryResultsView, - queryStorageDir, - true, - uri, - progress, - token, - undefined, - range, - ), - { - title: "Running query", - cancellable: true, - }, - - // Open the query server logger on error since that's usually where the interesting errors appear. - queryServerLogger, - ), - ); - - ctx.subscriptions.push( - commandRunnerWithProgress( - "codeQL.quickQuery", - async (progress: ProgressCallback, token: CancellationToken) => - displayQuickQuery(ctx, cliServer, databaseUI, progress, token), - { - title: "Run Quick Query", - }, - - // Open the query server logger on error since that's usually where the interesting errors appear. - queryServerLogger, - ), - ); + registerLocalQueryCommands(ctx, { + queryRunner: qs, + queryHistoryManager: qhm, + databaseManager: dbm, + cliServer, + databaseUI, + localQueryResultsView, + queryStorageDir, + }); const allCommands: AllCommands = { ...getCommands(), @@ -1600,160 +1308,6 @@ async function showResultsForComparison( } } -async function showResultsForCompletedQuery( - localQueryResultsView: ResultsView, - query: CompletedLocalQueryInfo, - forceReveal: WebviewReveal, -): Promise { - await localQueryResultsView.showResults(query, forceReveal, false); -} -async function compileAndRunQuery( - qs: QueryRunner, - qhm: QueryHistoryManager, - databaseUI: DatabaseUI, - localQueryResultsView: ResultsView, - queryStorageDir: string, - quickEval: boolean, - selectedQuery: Uri | undefined, - progress: ProgressCallback, - token: CancellationToken, - databaseItem: DatabaseItem | undefined, - range?: Range, -): Promise { - if (qs !== undefined) { - // If no databaseItem is specified, use the database currently selected in the Databases UI - databaseItem = - databaseItem || (await databaseUI.getDatabaseItem(progress, token)); - if (databaseItem === undefined) { - throw new Error("Can't run query without a selected database"); - } - const databaseInfo = { - name: databaseItem.name, - databaseUri: databaseItem.databaseUri.toString(), - }; - - // handle cancellation from the history view. - const source = new CancellationTokenSource(); - token.onCancellationRequested(() => source.cancel()); - - const initialInfo = await createInitialQueryInfo( - selectedQuery, - databaseInfo, - quickEval, - range, - ); - const item = new LocalQueryInfo(initialInfo, source); - qhm.addQuery(item); - try { - const completedQueryInfo = await qs.compileAndRunQueryAgainstDatabase( - databaseItem, - initialInfo, - queryStorageDir, - progress, - source.token, - undefined, - item, - ); - qhm.completeQuery(item, completedQueryInfo); - await showResultsForCompletedQuery( - localQueryResultsView, - item as CompletedLocalQueryInfo, - WebviewReveal.Forced, - ); - // Note we must update the query history view after showing results as the - // display and sorting might depend on the number of results - } catch (e) { - const err = asError(e); - err.message = `Error running query: ${err.message}`; - item.failureReason = err.message; - throw e; - } finally { - await qhm.refreshTreeView(); - source.dispose(); - } - } -} - -async function compileAndRunQueryOnMultipleDatabases( - cliServer: CodeQLCliServer, - qs: QueryRunner, - qhm: QueryHistoryManager, - dbm: DatabaseManager, - databaseUI: DatabaseUI, - localQueryResultsView: ResultsView, - queryStorageDir: string, - progress: ProgressCallback, - token: CancellationToken, - uri: Uri | undefined, -): Promise { - let filteredDBs = dbm.databaseItems; - if (filteredDBs.length === 0) { - void showAndLogErrorMessage( - "No databases found. Please add a suitable database to your workspace.", - ); - return; - } - // If possible, only show databases with the right language (otherwise show all databases). - const queryLanguage = await findLanguage(cliServer, uri); - if (queryLanguage) { - filteredDBs = dbm.databaseItems.filter( - (db) => db.language === queryLanguage, - ); - if (filteredDBs.length === 0) { - void showAndLogErrorMessage( - `No databases found for language ${queryLanguage}. Please add a suitable database to your workspace.`, - ); - return; - } - } - const quickPickItems = filteredDBs.map((dbItem) => ({ - databaseItem: dbItem, - label: dbItem.name, - description: dbItem.language, - })); - /** - * Databases that were selected in the quick pick menu. - */ - const quickpick = await window.showQuickPick( - quickPickItems, - { canPickMany: true, ignoreFocusOut: true }, - ); - if (quickpick !== undefined) { - // Collect all skipped databases and display them at the end (instead of popping up individual errors) - const skippedDatabases = []; - const errors = []; - for (const item of quickpick) { - try { - await compileAndRunQuery( - qs, - qhm, - databaseUI, - localQueryResultsView, - queryStorageDir, - false, - uri, - progress, - token, - item.databaseItem, - ); - } catch (e) { - skippedDatabases.push(item.label); - errors.push(getErrorMessage(e)); - } - } - if (skippedDatabases.length > 0) { - void extLogger.log(`Errors:\n${errors.join("\n")}`); - void showAndLogWarningMessage( - `The following databases were skipped:\n${skippedDatabases.join( - "\n", - )}.\nFor details about the errors, see the logs.`, - ); - } - } else { - void showAndLogErrorMessage("No databases selected."); - } -} - async function previewQueryHelp( cliServer: CodeQLCliServer, qhelpTmpDir: DirResult, diff --git a/extensions/ql-vscode/src/local-queries.ts b/extensions/ql-vscode/src/local-queries.ts new file mode 100644 index 000000000..761c9a31f --- /dev/null +++ b/extensions/ql-vscode/src/local-queries.ts @@ -0,0 +1,512 @@ +import { + commandRunnerWithProgress, + ProgressCallback, + ProgressUpdate, +} from "./commandRunner"; +import { + CancellationToken, + CancellationTokenSource, + ExtensionContext, + QuickPickItem, + Range, + Uri, + window, +} from "vscode"; +import { extLogger, queryServerLogger } from "./common"; +import { MAX_QUERIES } from "./config"; +import { gatherQlFiles } from "./pure/files"; +import { basename } from "path"; +import { + findLanguage, + showAndLogErrorMessage, + showAndLogWarningMessage, + showBinaryChoiceDialog, +} from "./helpers"; +import { displayQuickQuery } from "./quick-query"; +import { QueryRunner } from "./queryRunner"; +import { QueryHistoryManager } from "./query-history/query-history-manager"; +import { DatabaseUI } from "./local-databases-ui"; +import { ResultsView } from "./interface"; +import { DatabaseItem, DatabaseManager } from "./local-databases"; +import { createInitialQueryInfo } from "./run-queries-shared"; +import { CompletedLocalQueryInfo, LocalQueryInfo } from "./query-results"; +import { WebviewReveal } from "./interface-utils"; +import { asError, getErrorMessage } from "./pure/helpers-pure"; +import { CodeQLCliServer } from "./cli"; + +type LocalQueryOptions = { + queryRunner: QueryRunner; + queryHistoryManager: QueryHistoryManager; + databaseManager: DatabaseManager; + cliServer: CodeQLCliServer; + databaseUI: DatabaseUI; + localQueryResultsView: ResultsView; + queryStorageDir: string; +}; + +export function registerLocalQueryCommands( + ctx: ExtensionContext, + { + queryRunner: qs, + queryHistoryManager: qhm, + databaseManager: dbm, + cliServer, + databaseUI, + localQueryResultsView, + queryStorageDir, + }: LocalQueryOptions, +) { + ctx.subscriptions.push( + commandRunnerWithProgress( + "codeQL.runQuery", + async ( + progress: ProgressCallback, + token: CancellationToken, + uri: Uri | undefined, + ) => + await compileAndRunQuery( + qs, + qhm, + databaseUI, + localQueryResultsView, + queryStorageDir, + false, + uri, + progress, + token, + undefined, + ), + { + title: "Running query", + cancellable: true, + }, + + // Open the query server logger on error since that's usually where the interesting errors appear. + queryServerLogger, + ), + ); + + // Since we are tracking extension usage through commands, this command mirrors the runQuery command + ctx.subscriptions.push( + commandRunnerWithProgress( + "codeQL.runQueryContextEditor", + async ( + progress: ProgressCallback, + token: CancellationToken, + uri: Uri | undefined, + ) => + await compileAndRunQuery( + qs, + qhm, + databaseUI, + localQueryResultsView, + queryStorageDir, + false, + uri, + progress, + token, + undefined, + ), + { + title: "Running query", + cancellable: true, + }, + + // Open the query server logger on error since that's usually where the interesting errors appear. + queryServerLogger, + ), + ); + ctx.subscriptions.push( + commandRunnerWithProgress( + "codeQL.runQueryOnMultipleDatabases", + async ( + progress: ProgressCallback, + token: CancellationToken, + uri: Uri | undefined, + ) => + await compileAndRunQueryOnMultipleDatabases( + cliServer, + qs, + qhm, + dbm, + databaseUI, + localQueryResultsView, + queryStorageDir, + progress, + token, + uri, + ), + { + title: "Running query on selected databases", + cancellable: true, + }, + ), + ); + // Since we are tracking extension usage through commands, this command mirrors the runQueryOnMultipleDatabases command + ctx.subscriptions.push( + commandRunnerWithProgress( + "codeQL.runQueryOnMultipleDatabasesContextEditor", + async ( + progress: ProgressCallback, + token: CancellationToken, + uri: Uri | undefined, + ) => + await compileAndRunQueryOnMultipleDatabases( + cliServer, + qs, + qhm, + dbm, + databaseUI, + localQueryResultsView, + queryStorageDir, + progress, + token, + uri, + ), + { + title: "Running query on selected databases", + cancellable: true, + }, + ), + ); + ctx.subscriptions.push( + commandRunnerWithProgress( + "codeQL.runQueries", + async ( + progress: ProgressCallback, + token: CancellationToken, + _: Uri | undefined, + multi: Uri[], + ) => { + const maxQueryCount = MAX_QUERIES.getValue() as number; + const [files, dirFound] = await gatherQlFiles( + multi.map((uri) => uri.fsPath), + ); + if (files.length > maxQueryCount) { + throw new Error( + `You tried to run ${files.length} queries, but the maximum is ${maxQueryCount}. Try selecting fewer queries or changing the 'codeQL.runningQueries.maxQueries' setting.`, + ); + } + // warn user and display selected files when a directory is selected because some ql + // files may be hidden from the user. + if (dirFound) { + const fileString = files.map((file) => basename(file)).join(", "); + const res = await showBinaryChoiceDialog( + `You are about to run ${files.length} queries: ${fileString} Do you want to continue?`, + ); + if (!res) { + return; + } + } + const queryUris = files.map((path) => Uri.parse(`file:${path}`, true)); + + // Use a wrapped progress so that messages appear with the queries remaining in it. + let queriesRemaining = queryUris.length; + function wrappedProgress(update: ProgressUpdate) { + const message = + queriesRemaining > 1 + ? `${queriesRemaining} remaining. ${update.message}` + : update.message; + progress({ + ...update, + message, + }); + } + + wrappedProgress({ + maxStep: queryUris.length, + step: queryUris.length - queriesRemaining, + message: "", + }); + + await Promise.all( + queryUris.map(async (uri) => + compileAndRunQuery( + qs, + qhm, + databaseUI, + localQueryResultsView, + queryStorageDir, + false, + uri, + wrappedProgress, + token, + undefined, + ).then(() => queriesRemaining--), + ), + ); + }, + { + title: "Running queries", + cancellable: true, + }, + + // Open the query server logger on error since that's usually where the interesting errors appear. + queryServerLogger, + ), + ); + + ctx.subscriptions.push( + commandRunnerWithProgress( + "codeQL.quickEval", + async ( + progress: ProgressCallback, + token: CancellationToken, + uri: Uri | undefined, + ) => + await compileAndRunQuery( + qs, + qhm, + databaseUI, + localQueryResultsView, + queryStorageDir, + true, + uri, + progress, + token, + undefined, + ), + { + title: "Running query", + cancellable: true, + }, + // Open the query server logger on error since that's usually where the interesting errors appear. + queryServerLogger, + ), + ); + + // Since we are tracking extension usage through commands, this command mirrors the "codeQL.quickEval" command + ctx.subscriptions.push( + commandRunnerWithProgress( + "codeQL.quickEvalContextEditor", + async ( + progress: ProgressCallback, + token: CancellationToken, + uri: Uri | undefined, + ) => + await compileAndRunQuery( + qs, + qhm, + databaseUI, + localQueryResultsView, + queryStorageDir, + true, + uri, + progress, + token, + undefined, + ), + { + title: "Running query", + cancellable: true, + }, + // Open the query server logger on error since that's usually where the interesting errors appear. + queryServerLogger, + ), + ); + + ctx.subscriptions.push( + commandRunnerWithProgress( + "codeQL.codeLensQuickEval", + async ( + progress: ProgressCallback, + token: CancellationToken, + uri: Uri, + range: Range, + ) => + await compileAndRunQuery( + qs, + qhm, + databaseUI, + localQueryResultsView, + queryStorageDir, + true, + uri, + progress, + token, + undefined, + range, + ), + { + title: "Running query", + cancellable: true, + }, + + // Open the query server logger on error since that's usually where the interesting errors appear. + queryServerLogger, + ), + ); + + ctx.subscriptions.push( + commandRunnerWithProgress( + "codeQL.quickQuery", + async (progress: ProgressCallback, token: CancellationToken) => + displayQuickQuery(ctx, cliServer, databaseUI, progress, token), + { + title: "Run Quick Query", + }, + + // Open the query server logger on error since that's usually where the interesting errors appear. + queryServerLogger, + ), + ); +} + +export async function compileAndRunQuery( + qs: QueryRunner, + qhm: QueryHistoryManager, + databaseUI: DatabaseUI, + localQueryResultsView: ResultsView, + queryStorageDir: string, + quickEval: boolean, + selectedQuery: Uri | undefined, + progress: ProgressCallback, + token: CancellationToken, + databaseItem: DatabaseItem | undefined, + range?: Range, +): Promise { + if (qs !== undefined) { + // If no databaseItem is specified, use the database currently selected in the Databases UI + databaseItem = + databaseItem || (await databaseUI.getDatabaseItem(progress, token)); + if (databaseItem === undefined) { + throw new Error("Can't run query without a selected database"); + } + const databaseInfo = { + name: databaseItem.name, + databaseUri: databaseItem.databaseUri.toString(), + }; + + // handle cancellation from the history view. + const source = new CancellationTokenSource(); + token.onCancellationRequested(() => source.cancel()); + + const initialInfo = await createInitialQueryInfo( + selectedQuery, + databaseInfo, + quickEval, + range, + ); + const item = new LocalQueryInfo(initialInfo, source); + qhm.addQuery(item); + try { + const completedQueryInfo = await qs.compileAndRunQueryAgainstDatabase( + databaseItem, + initialInfo, + queryStorageDir, + progress, + source.token, + undefined, + item, + ); + qhm.completeQuery(item, completedQueryInfo); + await showResultsForCompletedQuery( + localQueryResultsView, + item as CompletedLocalQueryInfo, + WebviewReveal.Forced, + ); + // Note we must update the query history view after showing results as the + // display and sorting might depend on the number of results + } catch (e) { + const err = asError(e); + err.message = `Error running query: ${err.message}`; + item.failureReason = err.message; + throw e; + } finally { + await qhm.refreshTreeView(); + source.dispose(); + } + } +} + +interface DatabaseQuickPickItem extends QuickPickItem { + databaseItem: DatabaseItem; +} + +async function compileAndRunQueryOnMultipleDatabases( + cliServer: CodeQLCliServer, + qs: QueryRunner, + qhm: QueryHistoryManager, + dbm: DatabaseManager, + databaseUI: DatabaseUI, + localQueryResultsView: ResultsView, + queryStorageDir: string, + progress: ProgressCallback, + token: CancellationToken, + uri: Uri | undefined, +): Promise { + let filteredDBs = dbm.databaseItems; + if (filteredDBs.length === 0) { + void showAndLogErrorMessage( + "No databases found. Please add a suitable database to your workspace.", + ); + return; + } + // If possible, only show databases with the right language (otherwise show all databases). + const queryLanguage = await findLanguage(cliServer, uri); + if (queryLanguage) { + filteredDBs = dbm.databaseItems.filter( + (db) => db.language === queryLanguage, + ); + if (filteredDBs.length === 0) { + void showAndLogErrorMessage( + `No databases found for language ${queryLanguage}. Please add a suitable database to your workspace.`, + ); + return; + } + } + const quickPickItems = filteredDBs.map((dbItem) => ({ + databaseItem: dbItem, + label: dbItem.name, + description: dbItem.language, + })); + /** + * Databases that were selected in the quick pick menu. + */ + const quickpick = await window.showQuickPick( + quickPickItems, + { canPickMany: true, ignoreFocusOut: true }, + ); + if (quickpick !== undefined) { + // Collect all skipped databases and display them at the end (instead of popping up individual errors) + const skippedDatabases = []; + const errors = []; + for (const item of quickpick) { + try { + await compileAndRunQuery( + qs, + qhm, + databaseUI, + localQueryResultsView, + queryStorageDir, + false, + uri, + progress, + token, + item.databaseItem, + ); + } catch (e) { + skippedDatabases.push(item.label); + errors.push(getErrorMessage(e)); + } + } + if (skippedDatabases.length > 0) { + void extLogger.log(`Errors:\n${errors.join("\n")}`); + void showAndLogWarningMessage( + `The following databases were skipped:\n${skippedDatabases.join( + "\n", + )}.\nFor details about the errors, see the logs.`, + ); + } + } else { + void showAndLogErrorMessage("No databases selected."); + } +} + +export async function showResultsForCompletedQuery( + localQueryResultsView: ResultsView, + query: CompletedLocalQueryInfo, + forceReveal: WebviewReveal, +): Promise { + await localQueryResultsView.showResults(query, forceReveal, false); +} From 649179f62e4b5ea486b47630cea7a38747d4bca4 Mon Sep 17 00:00:00 2001 From: Koen Vlaswinkel Date: Mon, 20 Mar 2023 16:52:13 +0100 Subject: [PATCH 083/156] Rename local queries manager variable names --- extensions/ql-vscode/src/local-queries.ts | 42 +++++++++++------------ 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/extensions/ql-vscode/src/local-queries.ts b/extensions/ql-vscode/src/local-queries.ts index 761c9a31f..9bc07f9c8 100644 --- a/extensions/ql-vscode/src/local-queries.ts +++ b/extensions/ql-vscode/src/local-queries.ts @@ -47,9 +47,9 @@ type LocalQueryOptions = { export function registerLocalQueryCommands( ctx: ExtensionContext, { - queryRunner: qs, - queryHistoryManager: qhm, - databaseManager: dbm, + queryRunner, + queryHistoryManager, + databaseManager, cliServer, databaseUI, localQueryResultsView, @@ -65,8 +65,8 @@ export function registerLocalQueryCommands( uri: Uri | undefined, ) => await compileAndRunQuery( - qs, - qhm, + queryRunner, + queryHistoryManager, databaseUI, localQueryResultsView, queryStorageDir, @@ -96,8 +96,8 @@ export function registerLocalQueryCommands( uri: Uri | undefined, ) => await compileAndRunQuery( - qs, - qhm, + queryRunner, + queryHistoryManager, databaseUI, localQueryResultsView, queryStorageDir, @@ -126,9 +126,9 @@ export function registerLocalQueryCommands( ) => await compileAndRunQueryOnMultipleDatabases( cliServer, - qs, - qhm, - dbm, + queryRunner, + queryHistoryManager, + databaseManager, databaseUI, localQueryResultsView, queryStorageDir, @@ -153,9 +153,9 @@ export function registerLocalQueryCommands( ) => await compileAndRunQueryOnMultipleDatabases( cliServer, - qs, - qhm, - dbm, + queryRunner, + queryHistoryManager, + databaseManager, databaseUI, localQueryResultsView, queryStorageDir, @@ -222,8 +222,8 @@ export function registerLocalQueryCommands( await Promise.all( queryUris.map(async (uri) => compileAndRunQuery( - qs, - qhm, + queryRunner, + queryHistoryManager, databaseUI, localQueryResultsView, queryStorageDir, @@ -255,8 +255,8 @@ export function registerLocalQueryCommands( uri: Uri | undefined, ) => await compileAndRunQuery( - qs, - qhm, + queryRunner, + queryHistoryManager, databaseUI, localQueryResultsView, queryStorageDir, @@ -285,8 +285,8 @@ export function registerLocalQueryCommands( uri: Uri | undefined, ) => await compileAndRunQuery( - qs, - qhm, + queryRunner, + queryHistoryManager, databaseUI, localQueryResultsView, queryStorageDir, @@ -315,8 +315,8 @@ export function registerLocalQueryCommands( range: Range, ) => await compileAndRunQuery( - qs, - qhm, + queryRunner, + queryHistoryManager, databaseUI, localQueryResultsView, queryStorageDir, From f37a6c5e9ed59c7f931ed21fba2fe02302dadc56 Mon Sep 17 00:00:00 2001 From: Koen Vlaswinkel Date: Tue, 21 Mar 2023 10:11:36 +0100 Subject: [PATCH 084/156] Convert `commandRunnerWithProgress` to `commandRunner` --- extensions/ql-vscode/src/local-queries.ts | 326 +++++++++------------- 1 file changed, 135 insertions(+), 191 deletions(-) diff --git a/extensions/ql-vscode/src/local-queries.ts b/extensions/ql-vscode/src/local-queries.ts index 9bc07f9c8..3a912c682 100644 --- a/extensions/ql-vscode/src/local-queries.ts +++ b/extensions/ql-vscode/src/local-queries.ts @@ -1,7 +1,8 @@ import { - commandRunnerWithProgress, + commandRunner, ProgressCallback, ProgressUpdate, + withProgress, } from "./commandRunner"; import { CancellationToken, @@ -56,14 +57,9 @@ export function registerLocalQueryCommands( queryStorageDir, }: LocalQueryOptions, ) { - ctx.subscriptions.push( - commandRunnerWithProgress( - "codeQL.runQuery", - async ( - progress: ProgressCallback, - token: CancellationToken, - uri: Uri | undefined, - ) => + const runQuery = async (uri: Uri | undefined) => + withProgress( + async (progress, token) => { await compileAndRunQuery( queryRunner, queryHistoryManager, @@ -75,12 +71,18 @@ export function registerLocalQueryCommands( progress, token, undefined, - ), + ); + }, { title: "Running query", cancellable: true, }, + ); + ctx.subscriptions.push( + commandRunner( + "codeQL.runQuery", + runQuery, // Open the query server logger on error since that's usually where the interesting errors appear. queryServerLogger, ), @@ -88,42 +90,17 @@ export function registerLocalQueryCommands( // Since we are tracking extension usage through commands, this command mirrors the runQuery command ctx.subscriptions.push( - commandRunnerWithProgress( + commandRunner( "codeQL.runQueryContextEditor", - async ( - progress: ProgressCallback, - token: CancellationToken, - uri: Uri | undefined, - ) => - await compileAndRunQuery( - queryRunner, - queryHistoryManager, - databaseUI, - localQueryResultsView, - queryStorageDir, - false, - uri, - progress, - token, - undefined, - ), - { - title: "Running query", - cancellable: true, - }, - + runQuery, // Open the query server logger on error since that's usually where the interesting errors appear. queryServerLogger, ), ); - ctx.subscriptions.push( - commandRunnerWithProgress( - "codeQL.runQueryOnMultipleDatabases", - async ( - progress: ProgressCallback, - token: CancellationToken, - uri: Uri | undefined, - ) => + + const runQueryOnMultipleDatabases = async (uri: Uri | undefined) => + withProgress( + async (progress, token) => await compileAndRunQueryOnMultipleDatabases( cliServer, queryRunner, @@ -140,120 +117,101 @@ export function registerLocalQueryCommands( title: "Running query on selected databases", cancellable: true, }, + ); + + ctx.subscriptions.push( + commandRunner( + "codeQL.runQueryOnMultipleDatabases", + runQueryOnMultipleDatabases, ), ); // Since we are tracking extension usage through commands, this command mirrors the runQueryOnMultipleDatabases command ctx.subscriptions.push( - commandRunnerWithProgress( + commandRunner( "codeQL.runQueryOnMultipleDatabasesContextEditor", - async ( - progress: ProgressCallback, - token: CancellationToken, - uri: Uri | undefined, - ) => - await compileAndRunQueryOnMultipleDatabases( - cliServer, - queryRunner, - queryHistoryManager, - databaseManager, - databaseUI, - localQueryResultsView, - queryStorageDir, - progress, - token, - uri, - ), - { - title: "Running query on selected databases", - cancellable: true, - }, + runQueryOnMultipleDatabases, ), ); ctx.subscriptions.push( - commandRunnerWithProgress( + commandRunner( "codeQL.runQueries", - async ( - progress: ProgressCallback, - token: CancellationToken, - _: Uri | undefined, - multi: Uri[], - ) => { - const maxQueryCount = MAX_QUERIES.getValue() as number; - const [files, dirFound] = await gatherQlFiles( - multi.map((uri) => uri.fsPath), - ); - if (files.length > maxQueryCount) { - throw new Error( - `You tried to run ${files.length} queries, but the maximum is ${maxQueryCount}. Try selecting fewer queries or changing the 'codeQL.runningQueries.maxQueries' setting.`, - ); - } - // warn user and display selected files when a directory is selected because some ql - // files may be hidden from the user. - if (dirFound) { - const fileString = files.map((file) => basename(file)).join(", "); - const res = await showBinaryChoiceDialog( - `You are about to run ${files.length} queries: ${fileString} Do you want to continue?`, - ); - if (!res) { - return; - } - } - const queryUris = files.map((path) => Uri.parse(`file:${path}`, true)); + async (_: Uri | undefined, multi: Uri[]) => + withProgress( + async (progress, token) => { + const maxQueryCount = MAX_QUERIES.getValue() as number; + const [files, dirFound] = await gatherQlFiles( + multi.map((uri) => uri.fsPath), + ); + if (files.length > maxQueryCount) { + throw new Error( + `You tried to run ${files.length} queries, but the maximum is ${maxQueryCount}. Try selecting fewer queries or changing the 'codeQL.runningQueries.maxQueries' setting.`, + ); + } + // warn user and display selected files when a directory is selected because some ql + // files may be hidden from the user. + if (dirFound) { + const fileString = files.map((file) => basename(file)).join(", "); + const res = await showBinaryChoiceDialog( + `You are about to run ${files.length} queries: ${fileString} Do you want to continue?`, + ); + if (!res) { + return; + } + } + const queryUris = files.map((path) => + Uri.parse(`file:${path}`, true), + ); - // Use a wrapped progress so that messages appear with the queries remaining in it. - let queriesRemaining = queryUris.length; - function wrappedProgress(update: ProgressUpdate) { - const message = - queriesRemaining > 1 - ? `${queriesRemaining} remaining. ${update.message}` - : update.message; - progress({ - ...update, - message, - }); - } + // Use a wrapped progress so that messages appear with the queries remaining in it. + let queriesRemaining = queryUris.length; - wrappedProgress({ - maxStep: queryUris.length, - step: queryUris.length - queriesRemaining, - message: "", - }); + function wrappedProgress(update: ProgressUpdate) { + const message = + queriesRemaining > 1 + ? `${queriesRemaining} remaining. ${update.message}` + : update.message; + progress({ + ...update, + message, + }); + } - await Promise.all( - queryUris.map(async (uri) => - compileAndRunQuery( - queryRunner, - queryHistoryManager, - databaseUI, - localQueryResultsView, - queryStorageDir, - false, - uri, - wrappedProgress, - token, - undefined, - ).then(() => queriesRemaining--), - ), - ); - }, - { - title: "Running queries", - cancellable: true, - }, + wrappedProgress({ + maxStep: queryUris.length, + step: queryUris.length - queriesRemaining, + message: "", + }); + await Promise.all( + queryUris.map(async (uri) => + compileAndRunQuery( + queryRunner, + queryHistoryManager, + databaseUI, + localQueryResultsView, + queryStorageDir, + false, + uri, + wrappedProgress, + token, + undefined, + ).then(() => queriesRemaining--), + ), + ); + }, + { + title: "Running queries", + cancellable: true, + }, + ), // Open the query server logger on error since that's usually where the interesting errors appear. queryServerLogger, ), ); - ctx.subscriptions.push( - commandRunnerWithProgress( - "codeQL.quickEval", - async ( - progress: ProgressCallback, - token: CancellationToken, - uri: Uri | undefined, - ) => + const quickEval = async (uri: Uri) => + withProgress( + async (progress, token) => { await compileAndRunQuery( queryRunner, queryHistoryManager, @@ -265,11 +223,18 @@ export function registerLocalQueryCommands( progress, token, undefined, - ), + ); + }, { title: "Running query", cancellable: true, }, + ); + + ctx.subscriptions.push( + commandRunner( + "codeQL.quickEval", + quickEval, // Open the query server logger on error since that's usually where the interesting errors appear. queryServerLogger, ), @@ -277,75 +242,54 @@ export function registerLocalQueryCommands( // Since we are tracking extension usage through commands, this command mirrors the "codeQL.quickEval" command ctx.subscriptions.push( - commandRunnerWithProgress( + commandRunner( "codeQL.quickEvalContextEditor", - async ( - progress: ProgressCallback, - token: CancellationToken, - uri: Uri | undefined, - ) => - await compileAndRunQuery( - queryRunner, - queryHistoryManager, - databaseUI, - localQueryResultsView, - queryStorageDir, - true, - uri, - progress, - token, - undefined, - ), - { - title: "Running query", - cancellable: true, - }, + quickEval, // Open the query server logger on error since that's usually where the interesting errors appear. queryServerLogger, ), ); ctx.subscriptions.push( - commandRunnerWithProgress( + commandRunner( "codeQL.codeLensQuickEval", - async ( - progress: ProgressCallback, - token: CancellationToken, - uri: Uri, - range: Range, - ) => - await compileAndRunQuery( - queryRunner, - queryHistoryManager, - databaseUI, - localQueryResultsView, - queryStorageDir, - true, - uri, - progress, - token, - undefined, - range, + async (uri: Uri, range: Range) => + withProgress( + async (progress, token) => + await compileAndRunQuery( + queryRunner, + queryHistoryManager, + databaseUI, + localQueryResultsView, + queryStorageDir, + true, + uri, + progress, + token, + undefined, + range, + ), + { + title: "Running query", + cancellable: true, + }, ), - { - title: "Running query", - cancellable: true, - }, - // Open the query server logger on error since that's usually where the interesting errors appear. queryServerLogger, ), ); ctx.subscriptions.push( - commandRunnerWithProgress( + commandRunner( "codeQL.quickQuery", - async (progress: ProgressCallback, token: CancellationToken) => - displayQuickQuery(ctx, cliServer, databaseUI, progress, token), - { - title: "Run Quick Query", - }, - + async () => + withProgress( + async (progress, token) => + displayQuickQuery(ctx, cliServer, databaseUI, progress, token), + { + title: "Run Quick Query", + }, + ), // Open the query server logger on error since that's usually where the interesting errors appear. queryServerLogger, ), From 7950c1c98225ca6eaa398e8653333915e3c41cb2 Mon Sep 17 00:00:00 2001 From: Koen Vlaswinkel Date: Tue, 21 Mar 2023 10:25:34 +0100 Subject: [PATCH 085/156] Convert local query commands to typed commands The local query commands are using a separate logger, and this is not supported by the command manager because it is quite specific to this extension. Therefore, we create a separate command manager which uses a different logger to separate the commands. --- extensions/ql-vscode/src/commandRunner.ts | 2 +- extensions/ql-vscode/src/common/commands.ts | 21 +- .../ql-vscode/src/common/vscode/commands.ts | 9 +- .../ql-vscode/src/common/vscode/vscode-app.ts | 6 +- extensions/ql-vscode/src/extension.ts | 38 ++- extensions/ql-vscode/src/local-queries.ts | 298 +++++++----------- extensions/ql-vscode/src/quick-query.ts | 17 +- 7 files changed, 181 insertions(+), 210 deletions(-) diff --git a/extensions/ql-vscode/src/commandRunner.ts b/extensions/ql-vscode/src/commandRunner.ts index 6f316be2b..7079723c1 100644 --- a/extensions/ql-vscode/src/commandRunner.ts +++ b/extensions/ql-vscode/src/commandRunner.ts @@ -89,7 +89,7 @@ export type ProgressTaskWithArgs = ( * @param args arguments passed to this task passed on from * `commands.registerCommand`. */ -type NoProgressTask = (...args: any[]) => Promise; +export type NoProgressTask = (...args: any[]) => Promise; /** * This mediates between the kind of progress callbacks we want to diff --git a/extensions/ql-vscode/src/common/commands.ts b/extensions/ql-vscode/src/common/commands.ts index 00c68c472..bc401234f 100644 --- a/extensions/ql-vscode/src/common/commands.ts +++ b/extensions/ql-vscode/src/common/commands.ts @@ -1,5 +1,5 @@ import type { CommandManager } from "../packages/commands"; -import type { Uri } from "vscode"; +import type { Uri, Range } from "vscode"; import type { DbTreeViewItem } from "../databases/ui/db-tree-view-item"; import type { DatabaseItem } from "../local-databases"; import type { QueryHistoryInfo } from "../query-history/query-history-info"; @@ -29,6 +29,21 @@ export type BaseCommands = { "codeQL.openDocumentation": () => Promise; }; +// Commands used for running local queries +export type LocalQueryCommands = { + "codeQL.runQuery": (uri?: Uri) => Promise; + "codeQL.runQueryContextEditor": (uri?: Uri) => Promise; + "codeQL.runQueryOnMultipleDatabases": (uri?: Uri) => Promise; + "codeQL.runQueryOnMultipleDatabasesContextEditor": ( + uri?: Uri, + ) => Promise; + "codeQL.runQueries": SelectionCommandFunction; + "codeQL.quickEval": (uri: Uri) => Promise; + "codeQL.quickEvalContextEditor": (uri: Uri) => Promise; + "codeQL.codeLensQuickEval": (uri: Uri, range: Range) => Promise; + "codeQL.quickQuery": () => Promise; +}; + // Commands used for the query history panel export type QueryHistoryCommands = { // Commands in the "navigation" group @@ -115,3 +130,7 @@ export type AllCommands = BaseCommands & DatabasePanelCommands; export type AppCommandManager = CommandManager; + +// Separate command manager because it uses a different logger +export type QueryServerCommands = LocalQueryCommands; +export type QueryServerCommandManager = CommandManager; diff --git a/extensions/ql-vscode/src/common/vscode/commands.ts b/extensions/ql-vscode/src/common/vscode/commands.ts index 86e32faa4..fc8db2a78 100644 --- a/extensions/ql-vscode/src/common/vscode/commands.ts +++ b/extensions/ql-vscode/src/common/vscode/commands.ts @@ -1,6 +1,7 @@ import { commands } from "vscode"; -import { commandRunner } from "../../commandRunner"; +import { commandRunner, NoProgressTask } from "../../commandRunner"; import { CommandFunction, CommandManager } from "../../packages/commands"; +import { OutputChannelLogger } from "../logging"; /** * Create a command manager for VSCode, wrapping the commandRunner @@ -8,8 +9,10 @@ import { CommandFunction, CommandManager } from "../../packages/commands"; */ export function createVSCodeCommandManager< Commands extends Record, ->(): CommandManager { - return new CommandManager(commandRunner, wrapExecuteCommand); +>(outputLogger?: OutputChannelLogger): CommandManager { + return new CommandManager((commandId, task: NoProgressTask) => { + return commandRunner(commandId, task, outputLogger); + }, wrapExecuteCommand); } /** diff --git a/extensions/ql-vscode/src/common/vscode/vscode-app.ts b/extensions/ql-vscode/src/common/vscode/vscode-app.ts index 1ae588278..54032a8b1 100644 --- a/extensions/ql-vscode/src/common/vscode/vscode-app.ts +++ b/extensions/ql-vscode/src/common/vscode/vscode-app.ts @@ -3,21 +3,23 @@ import { VSCodeCredentials } from "../../authentication"; import { Disposable } from "../../pure/disposable-object"; import { App, AppMode } from "../app"; import { AppEventEmitter } from "../events"; -import { extLogger, Logger } from "../logging"; +import { extLogger, Logger, queryServerLogger } from "../logging"; import { Memento } from "../memento"; import { VSCodeAppEventEmitter } from "./events"; -import { AppCommandManager } from "../commands"; +import { AppCommandManager, QueryServerCommandManager } from "../commands"; import { createVSCodeCommandManager } from "./commands"; export class ExtensionApp implements App { public readonly credentials: VSCodeCredentials; public readonly commands: AppCommandManager; + public readonly queryServerCommands: QueryServerCommandManager; public constructor( public readonly extensionContext: vscode.ExtensionContext, ) { this.credentials = new VSCodeCredentials(); this.commands = createVSCodeCommandManager(); + this.queryServerCommands = createVSCodeCommandManager(queryServerLogger); extensionContext.subscriptions.push(this.commands); } diff --git a/extensions/ql-vscode/src/extension.ts b/extensions/ql-vscode/src/extension.ts index 68331db1f..1bfcc5df6 100644 --- a/extensions/ql-vscode/src/extension.ts +++ b/extensions/ql-vscode/src/extension.ts @@ -124,10 +124,14 @@ import { DbModule } from "./databases/db-module"; import { redactableError } from "./pure/errors"; import { QueryHistoryDirs } from "./query-history/query-history-dirs"; import { DirResult } from "tmp"; -import { AllCommands, BaseCommands } from "./common/commands"; +import { + AllCommands, + BaseCommands, + QueryServerCommands, +} from "./common/commands"; import { compileAndRunQuery, - registerLocalQueryCommands, + getLocalQueryCommands, showResultsForCompletedQuery, } from "./local-queries"; @@ -785,16 +789,6 @@ async function activateWithInstalledDistribution( void extLogger.log("Registering top-level command palette commands."); - registerLocalQueryCommands(ctx, { - queryRunner: qs, - queryHistoryManager: qhm, - databaseManager: dbm, - cliServer, - databaseUI, - localQueryResultsView, - queryStorageDir, - }); - const allCommands: AllCommands = { ...getCommands(), ...qhm.getCommands(), @@ -807,6 +801,26 @@ async function activateWithInstalledDistribution( app.commands.register(commandName as keyof AllCommands, command); } + const queryServerCommands: QueryServerCommands = { + ...getLocalQueryCommands({ + app, + queryRunner: qs, + queryHistoryManager: qhm, + databaseManager: dbm, + cliServer, + databaseUI, + localQueryResultsView, + queryStorageDir, + }), + }; + + for (const [commandName, command] of Object.entries(queryServerCommands)) { + app.queryServerCommands.register( + commandName as keyof QueryServerCommands, + command, + ); + } + ctx.subscriptions.push( commandRunner( "codeQL.copyVariantAnalysisRepoList", diff --git a/extensions/ql-vscode/src/local-queries.ts b/extensions/ql-vscode/src/local-queries.ts index 3a912c682..3c6b76b03 100644 --- a/extensions/ql-vscode/src/local-queries.ts +++ b/extensions/ql-vscode/src/local-queries.ts @@ -1,5 +1,4 @@ import { - commandRunner, ProgressCallback, ProgressUpdate, withProgress, @@ -7,13 +6,12 @@ import { import { CancellationToken, CancellationTokenSource, - ExtensionContext, QuickPickItem, Range, Uri, window, } from "vscode"; -import { extLogger, queryServerLogger } from "./common"; +import { extLogger } from "./common"; import { MAX_QUERIES } from "./config"; import { gatherQlFiles } from "./pure/files"; import { basename } from "path"; @@ -34,8 +32,11 @@ import { CompletedLocalQueryInfo, LocalQueryInfo } from "./query-results"; import { WebviewReveal } from "./interface-utils"; import { asError, getErrorMessage } from "./pure/helpers-pure"; import { CodeQLCliServer } from "./cli"; +import { LocalQueryCommands } from "./common/commands"; +import { App } from "./common/app"; type LocalQueryOptions = { + app: App; queryRunner: QueryRunner; queryHistoryManager: QueryHistoryManager; databaseManager: DatabaseManager; @@ -45,18 +46,16 @@ type LocalQueryOptions = { queryStorageDir: string; }; -export function registerLocalQueryCommands( - ctx: ExtensionContext, - { - queryRunner, - queryHistoryManager, - databaseManager, - cliServer, - databaseUI, - localQueryResultsView, - queryStorageDir, - }: LocalQueryOptions, -) { +export function getLocalQueryCommands({ + app, + queryRunner, + queryHistoryManager, + databaseManager, + cliServer, + databaseUI, + localQueryResultsView, + queryStorageDir, +}: LocalQueryOptions): LocalQueryCommands { const runQuery = async (uri: Uri | undefined) => withProgress( async (progress, token) => { @@ -79,25 +78,6 @@ export function registerLocalQueryCommands( }, ); - ctx.subscriptions.push( - commandRunner( - "codeQL.runQuery", - runQuery, - // Open the query server logger on error since that's usually where the interesting errors appear. - queryServerLogger, - ), - ); - - // Since we are tracking extension usage through commands, this command mirrors the runQuery command - ctx.subscriptions.push( - commandRunner( - "codeQL.runQueryContextEditor", - runQuery, - // Open the query server logger on error since that's usually where the interesting errors appear. - queryServerLogger, - ), - ); - const runQueryOnMultipleDatabases = async (uri: Uri | undefined) => withProgress( async (progress, token) => @@ -119,95 +99,73 @@ export function registerLocalQueryCommands( }, ); - ctx.subscriptions.push( - commandRunner( - "codeQL.runQueryOnMultipleDatabases", - runQueryOnMultipleDatabases, - ), - ); - // Since we are tracking extension usage through commands, this command mirrors the runQueryOnMultipleDatabases command - ctx.subscriptions.push( - commandRunner( - "codeQL.runQueryOnMultipleDatabasesContextEditor", - runQueryOnMultipleDatabases, - ), - ); - ctx.subscriptions.push( - commandRunner( - "codeQL.runQueries", - async (_: Uri | undefined, multi: Uri[]) => - withProgress( - async (progress, token) => { - const maxQueryCount = MAX_QUERIES.getValue() as number; - const [files, dirFound] = await gatherQlFiles( - multi.map((uri) => uri.fsPath), - ); - if (files.length > maxQueryCount) { - throw new Error( - `You tried to run ${files.length} queries, but the maximum is ${maxQueryCount}. Try selecting fewer queries or changing the 'codeQL.runningQueries.maxQueries' setting.`, - ); - } - // warn user and display selected files when a directory is selected because some ql - // files may be hidden from the user. - if (dirFound) { - const fileString = files.map((file) => basename(file)).join(", "); - const res = await showBinaryChoiceDialog( - `You are about to run ${files.length} queries: ${fileString} Do you want to continue?`, - ); - if (!res) { - return; - } - } - const queryUris = files.map((path) => - Uri.parse(`file:${path}`, true), - ); + const runQueries = async (_: Uri | undefined, multi: Uri[]) => + withProgress( + async (progress, token) => { + const maxQueryCount = MAX_QUERIES.getValue() as number; + const [files, dirFound] = await gatherQlFiles( + multi.map((uri) => uri.fsPath), + ); + if (files.length > maxQueryCount) { + throw new Error( + `You tried to run ${files.length} queries, but the maximum is ${maxQueryCount}. Try selecting fewer queries or changing the 'codeQL.runningQueries.maxQueries' setting.`, + ); + } + // warn user and display selected files when a directory is selected because some ql + // files may be hidden from the user. + if (dirFound) { + const fileString = files.map((file) => basename(file)).join(", "); + const res = await showBinaryChoiceDialog( + `You are about to run ${files.length} queries: ${fileString} Do you want to continue?`, + ); + if (!res) { + return; + } + } + const queryUris = files.map((path) => Uri.parse(`file:${path}`, true)); - // Use a wrapped progress so that messages appear with the queries remaining in it. - let queriesRemaining = queryUris.length; + // Use a wrapped progress so that messages appear with the queries remaining in it. + let queriesRemaining = queryUris.length; - function wrappedProgress(update: ProgressUpdate) { - const message = - queriesRemaining > 1 - ? `${queriesRemaining} remaining. ${update.message}` - : update.message; - progress({ - ...update, - message, - }); - } + function wrappedProgress(update: ProgressUpdate) { + const message = + queriesRemaining > 1 + ? `${queriesRemaining} remaining. ${update.message}` + : update.message; + progress({ + ...update, + message, + }); + } - wrappedProgress({ - maxStep: queryUris.length, - step: queryUris.length - queriesRemaining, - message: "", - }); + wrappedProgress({ + maxStep: queryUris.length, + step: queryUris.length - queriesRemaining, + message: "", + }); - await Promise.all( - queryUris.map(async (uri) => - compileAndRunQuery( - queryRunner, - queryHistoryManager, - databaseUI, - localQueryResultsView, - queryStorageDir, - false, - uri, - wrappedProgress, - token, - undefined, - ).then(() => queriesRemaining--), - ), - ); - }, - { - title: "Running queries", - cancellable: true, - }, - ), - // Open the query server logger on error since that's usually where the interesting errors appear. - queryServerLogger, - ), - ); + await Promise.all( + queryUris.map(async (uri) => + compileAndRunQuery( + queryRunner, + queryHistoryManager, + databaseUI, + localQueryResultsView, + queryStorageDir, + false, + uri, + wrappedProgress, + token, + undefined, + ).then(() => queriesRemaining--), + ), + ); + }, + { + title: "Running queries", + cancellable: true, + }, + ); const quickEval = async (uri: Uri) => withProgress( @@ -231,69 +189,49 @@ export function registerLocalQueryCommands( }, ); - ctx.subscriptions.push( - commandRunner( - "codeQL.quickEval", - quickEval, - // Open the query server logger on error since that's usually where the interesting errors appear. - queryServerLogger, - ), - ); - - // Since we are tracking extension usage through commands, this command mirrors the "codeQL.quickEval" command - ctx.subscriptions.push( - commandRunner( - "codeQL.quickEvalContextEditor", - quickEval, - // Open the query server logger on error since that's usually where the interesting errors appear. - queryServerLogger, - ), - ); - - ctx.subscriptions.push( - commandRunner( - "codeQL.codeLensQuickEval", - async (uri: Uri, range: Range) => - withProgress( - async (progress, token) => - await compileAndRunQuery( - queryRunner, - queryHistoryManager, - databaseUI, - localQueryResultsView, - queryStorageDir, - true, - uri, - progress, - token, - undefined, - range, - ), - { - title: "Running query", - cancellable: true, - }, + const codeLensQuickEval = async (uri: Uri, range: Range) => + withProgress( + async (progress, token) => + await compileAndRunQuery( + queryRunner, + queryHistoryManager, + databaseUI, + localQueryResultsView, + queryStorageDir, + true, + uri, + progress, + token, + undefined, + range, ), - // Open the query server logger on error since that's usually where the interesting errors appear. - queryServerLogger, - ), - ); + { + title: "Running query", + cancellable: true, + }, + ); - ctx.subscriptions.push( - commandRunner( - "codeQL.quickQuery", - async () => - withProgress( - async (progress, token) => - displayQuickQuery(ctx, cliServer, databaseUI, progress, token), - { - title: "Run Quick Query", - }, - ), - // Open the query server logger on error since that's usually where the interesting errors appear. - queryServerLogger, - ), - ); + const quickQuery = async () => + withProgress( + async (progress, token) => + displayQuickQuery(app, cliServer, databaseUI, progress, token), + { + title: "Run Quick Query", + }, + ); + + return { + "codeQL.runQuery": runQuery, + "codeQL.runQueryContextEditor": runQuery, + "codeQL.runQueryOnMultipleDatabases": runQueryOnMultipleDatabases, + "codeQL.runQueryOnMultipleDatabasesContextEditor": + runQueryOnMultipleDatabases, + "codeQL.runQueries": runQueries, + "codeQL.quickEval": quickEval, + "codeQL.quickEvalContextEditor": quickEval, + "codeQL.codeLensQuickEval": codeLensQuickEval, + "codeQL.quickQuery": quickQuery, + }; } export async function compileAndRunQuery( diff --git a/extensions/ql-vscode/src/quick-query.ts b/extensions/ql-vscode/src/quick-query.ts index 4008bdda3..ca0e0ae65 100644 --- a/extensions/ql-vscode/src/quick-query.ts +++ b/extensions/ql-vscode/src/quick-query.ts @@ -1,13 +1,7 @@ import { ensureDir, writeFile, pathExists, readFile } from "fs-extra"; import { dump, load } from "js-yaml"; import { basename, join } from "path"; -import { - CancellationToken, - ExtensionContext, - window as Window, - workspace, - Uri, -} from "vscode"; +import { CancellationToken, window as Window, workspace, Uri } from "vscode"; import { LSPErrorCodes, ResponseError } from "vscode-languageclient"; import { CodeQLCliServer } from "./cli"; import { DatabaseUI } from "./local-databases-ui"; @@ -20,6 +14,7 @@ import { import { ProgressCallback, UserCancellationException } from "./commandRunner"; import { getErrorMessage } from "./pure/helpers-pure"; import { FALLBACK_QLPACK_FILENAME, getQlPackPath } from "./pure/ql"; +import { App } from "./common/app"; const QUICK_QUERIES_DIR_NAME = "quick-queries"; const QUICK_QUERY_QUERY_NAME = "quick-query.ql"; @@ -30,8 +25,8 @@ export function isQuickQueryPath(queryPath: string): boolean { return basename(queryPath) === QUICK_QUERY_QUERY_NAME; } -async function getQuickQueriesDir(ctx: ExtensionContext): Promise { - const storagePath = ctx.storagePath; +async function getQuickQueriesDir(app: App): Promise { + const storagePath = app.workspaceStoragePath; if (storagePath === undefined) { throw new Error("Workspace storage path is undefined"); } @@ -57,7 +52,7 @@ function findExistingQuickQueryEditor() { * Show a buffer the user can enter a simple query into. */ export async function displayQuickQuery( - ctx: ExtensionContext, + app: App, cliServer: CodeQLCliServer, databaseUI: DatabaseUI, progress: ProgressCallback, @@ -73,7 +68,7 @@ export async function displayQuickQuery( } const workspaceFolders = workspace.workspaceFolders || []; - const queriesDir = await getQuickQueriesDir(ctx); + const queriesDir = await getQuickQueriesDir(app); // We need to have a multi-root workspace to make quick query work // at all. Changing the workspace from single-root to multi-root From 737a1f5c370940876357548fdcfd59f966874ce6 Mon Sep 17 00:00:00 2001 From: Elena Tanasoiu Date: Tue, 21 Mar 2023 08:38:23 +0000 Subject: [PATCH 086/156] Use existing file path consistently --- extensions/ql-vscode/src/helpers.ts | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/extensions/ql-vscode/src/helpers.ts b/extensions/ql-vscode/src/helpers.ts index 35532cfc3..32d3bc8f0 100644 --- a/extensions/ql-vscode/src/helpers.ts +++ b/extensions/ql-vscode/src/helpers.ts @@ -288,12 +288,7 @@ export async function prepareCodeTour(): Promise { existsSync(toursFolderPath) && !isCodespacesTemplate() ) { - const tutorialWorkspaceUri = Uri.parse( - join( - workspace.workspaceFolders[0].uri.fsPath, - "tutorial.code-workspace", - ), - ); + const tutorialWorkspaceUri = Uri.parse(tutorialWorkspacePath); await commands.executeCommand("vscode.openFolder", tutorialWorkspaceUri); } } From fade710f95bf71fc1ee847d6efe91bfb8222b5df Mon Sep 17 00:00:00 2001 From: Elena Tanasoiu Date: Tue, 21 Mar 2023 08:50:29 +0000 Subject: [PATCH 087/156] Call it commandSpy everywhere --- .../vscode-tests/no-workspace/helpers.test.ts | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/extensions/ql-vscode/test/vscode-tests/no-workspace/helpers.test.ts b/extensions/ql-vscode/test/vscode-tests/no-workspace/helpers.test.ts index 6b7607e5d..28d545c4d 100644 --- a/extensions/ql-vscode/test/vscode-tests/no-workspace/helpers.test.ts +++ b/extensions/ql-vscode/test/vscode-tests/no-workspace/helpers.test.ts @@ -631,12 +631,12 @@ describe("prepareCodeTour", () => { await mkdir(tourDirPath); // spy that we open the workspace file by calling the 'vscode.openFolder' command - const openFileSpy = jest.spyOn(commands, "executeCommand"); - openFileSpy.mockImplementation(() => Promise.resolve()); + const commandSpy = jest.spyOn(commands, "executeCommand"); + commandSpy.mockImplementation(() => Promise.resolve()); await prepareCodeTour(); - expect(openFileSpy).not.toHaveBeenCalledWith("vscode.openFolder"); + expect(commandSpy).not.toHaveBeenCalledWith("vscode.openFolder"); }); }); }); @@ -648,24 +648,24 @@ describe("prepareCodeTour", () => { await mkdir(tourDirPath); // spy that we open the workspace file by calling the 'vscode.openFolder' command - const openFileSpy = jest.spyOn(commands, "executeCommand"); - openFileSpy.mockImplementation(() => Promise.resolve()); + const commandSpy = jest.spyOn(commands, "executeCommand"); + commandSpy.mockImplementation(() => Promise.resolve()); await prepareCodeTour(); - expect(openFileSpy).not.toHaveBeenCalledWith("vscode.openFolder"); + expect(commandSpy).not.toHaveBeenCalledWith("vscode.openFolder"); }); }); describe("if we're in a different repo with no tour", () => { it("should not open the tutorial workspace", async () => { // spy that we open the workspace file by calling the 'vscode.openFolder' command - const openFileSpy = jest.spyOn(commands, "executeCommand"); - openFileSpy.mockImplementation(() => Promise.resolve()); + const commandSpy = jest.spyOn(commands, "executeCommand"); + commandSpy.mockImplementation(() => Promise.resolve()); await prepareCodeTour(); - expect(openFileSpy).not.toHaveBeenCalledWith("vscode.openFolder"); + expect(commandSpy).not.toHaveBeenCalledWith("vscode.openFolder"); }); }); }); From 782e413c64e8a1d5a79c42a6c22468ee433e2dc8 Mon Sep 17 00:00:00 2001 From: Elena Tanasoiu Date: Tue, 21 Mar 2023 08:52:29 +0000 Subject: [PATCH 088/156] Add workspace filepath to test expectation --- .../ql-vscode/test/vscode-tests/no-workspace/helpers.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/extensions/ql-vscode/test/vscode-tests/no-workspace/helpers.test.ts b/extensions/ql-vscode/test/vscode-tests/no-workspace/helpers.test.ts index 28d545c4d..28a804634 100644 --- a/extensions/ql-vscode/test/vscode-tests/no-workspace/helpers.test.ts +++ b/extensions/ql-vscode/test/vscode-tests/no-workspace/helpers.test.ts @@ -612,7 +612,7 @@ describe("prepareCodeTour", () => { expect(commandSpy).toHaveBeenCalledWith( "vscode.openFolder", - expect.anything(), + Uri.parse(tutorialWorkspacePath), ); }); }); From 8db9f52df3e02fae3e83b46eb3c4884156137f30 Mon Sep 17 00:00:00 2001 From: Elena Tanasoiu Date: Tue, 21 Mar 2023 08:53:25 +0000 Subject: [PATCH 089/156] Adjust the rest of the test expectations Our expectation was quite narrow: we expect to not call an `openFolder` command. We didn't specify any params for it, which might mean this expectation wasn't working like it should. Let's just check that `executeCommand` isn't called at all. --- .../test/vscode-tests/no-workspace/helpers.test.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/extensions/ql-vscode/test/vscode-tests/no-workspace/helpers.test.ts b/extensions/ql-vscode/test/vscode-tests/no-workspace/helpers.test.ts index 28a804634..f46235cc9 100644 --- a/extensions/ql-vscode/test/vscode-tests/no-workspace/helpers.test.ts +++ b/extensions/ql-vscode/test/vscode-tests/no-workspace/helpers.test.ts @@ -636,7 +636,7 @@ describe("prepareCodeTour", () => { await prepareCodeTour(); - expect(commandSpy).not.toHaveBeenCalledWith("vscode.openFolder"); + expect(commandSpy).not.toHaveBeenCalled(); }); }); }); @@ -653,7 +653,7 @@ describe("prepareCodeTour", () => { await prepareCodeTour(); - expect(commandSpy).not.toHaveBeenCalledWith("vscode.openFolder"); + expect(commandSpy).not.toHaveBeenCalled(); }); }); @@ -665,7 +665,7 @@ describe("prepareCodeTour", () => { await prepareCodeTour(); - expect(commandSpy).not.toHaveBeenCalledWith("vscode.openFolder"); + expect(commandSpy).not.toHaveBeenCalled(); }); }); }); From ce413a638558086c53950687a29a998a9ded3110 Mon Sep 17 00:00:00 2001 From: Elena Tanasoiu Date: Tue, 21 Mar 2023 08:56:14 +0000 Subject: [PATCH 090/156] Stub `isCodespaceTemplate` correctly Now that we fixed our expectation in the previous commit, we could see we were stubbing this to false instead of true. So now the test is checking the right scenario. --- .../ql-vscode/test/vscode-tests/no-workspace/helpers.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/extensions/ql-vscode/test/vscode-tests/no-workspace/helpers.test.ts b/extensions/ql-vscode/test/vscode-tests/no-workspace/helpers.test.ts index f46235cc9..ce1ce9783 100644 --- a/extensions/ql-vscode/test/vscode-tests/no-workspace/helpers.test.ts +++ b/extensions/ql-vscode/test/vscode-tests/no-workspace/helpers.test.ts @@ -620,7 +620,7 @@ describe("prepareCodeTour", () => { describe("if the workspace is already open", () => { it("should not open the tutorial workspace", async () => { // Set isCodespaceTemplate to true to indicate the workspace has already been opened - jest.spyOn(Setting.prototype, "getValue").mockReturnValue(false); + jest.spyOn(Setting.prototype, "getValue").mockReturnValue(true); // set up directory to have a 'tutorial.code-workspace' file const tutorialWorkspacePath = join(dir.name, "tutorial.code-workspace"); From 0f4fcdf676883a55797bf6ebdb4b477c9be633e4 Mon Sep 17 00:00:00 2001 From: Elena Tanasoiu Date: Tue, 21 Mar 2023 09:01:33 +0000 Subject: [PATCH 091/156] Add comment with PR description This adds the explanation from the PR description in a comment and removes comment that's no longer helpful. --- extensions/ql-vscode/src/helpers.ts | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/extensions/ql-vscode/src/helpers.ts b/extensions/ql-vscode/src/helpers.ts index 32d3bc8f0..a6fb57ab5 100644 --- a/extensions/ql-vscode/src/helpers.ts +++ b/extensions/ql-vscode/src/helpers.ts @@ -276,13 +276,20 @@ export async function prepareCodeTour(): Promise { if (workspace.workspaceFolders?.length) { const currentFolder = workspace.workspaceFolders[0].uri.fsPath; - // We need this path to check that the file exists on windows const tutorialWorkspacePath = join( currentFolder, "tutorial.code-workspace", ); const toursFolderPath = join(currentFolder, ".tours"); + /** We're opening the tutorial workspace, if we detect it. + * This will only happen if the following three conditions are met: + * - the .tours folder exists + * - the tutorial.code-workspace file exists + * - the CODESPACES_TEMPLATE setting doesn't exist (it's only set if the user has already opened + * the tutorial workspace so it's a good indicator that the user is in the folder but has ignored + * the prompt to open the workspace) + */ if ( existsSync(tutorialWorkspacePath) && existsSync(toursFolderPath) && From 7059802a254b989e11c885a247865119f1da2fc5 Mon Sep 17 00:00:00 2001 From: Elena Tanasoiu Date: Tue, 21 Mar 2023 09:56:23 +0000 Subject: [PATCH 092/156] Add more logging before attempting to open tutorial workspace --- extensions/ql-vscode/src/extension.ts | 2 +- extensions/ql-vscode/src/helpers.ts | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/extensions/ql-vscode/src/extension.ts b/extensions/ql-vscode/src/extension.ts index 920d3018c..103f3491c 100644 --- a/extensions/ql-vscode/src/extension.ts +++ b/extensions/ql-vscode/src/extension.ts @@ -348,7 +348,7 @@ export async function activate( try { await prepareCodeTour(); } catch (e: unknown) { - console.log( + void extLogger.log( `Could not open tutorial workspace automatically: ${getErrorMessage(e)}`, ); } diff --git a/extensions/ql-vscode/src/helpers.ts b/extensions/ql-vscode/src/helpers.ts index a6fb57ab5..b6fb1bcf2 100644 --- a/extensions/ql-vscode/src/helpers.ts +++ b/extensions/ql-vscode/src/helpers.ts @@ -296,6 +296,9 @@ export async function prepareCodeTour(): Promise { !isCodespacesTemplate() ) { const tutorialWorkspaceUri = Uri.parse(tutorialWorkspacePath); + void extLogger.log( + `In prepareCodeTour() method, going to open the tutorial workspace file: ${tutorialWorkspacePath}`, + ); await commands.executeCommand("vscode.openFolder", tutorialWorkspaceUri); } } From 0368d537ade30fdf0c31e5d855bbb773b8a74b04 Mon Sep 17 00:00:00 2001 From: Elena Tanasoiu Date: Tue, 21 Mar 2023 11:01:19 +0000 Subject: [PATCH 093/156] Ask the user for permission to reload workspace To make this a nicer experience for the user, we're adding a prompt to let them know we're about to reload the workspace. --- extensions/ql-vscode/src/helpers.ts | 10 ++++++++++ .../test/vscode-tests/no-workspace/helpers.test.ts | 8 ++++++++ 2 files changed, 18 insertions(+) diff --git a/extensions/ql-vscode/src/helpers.ts b/extensions/ql-vscode/src/helpers.ts index b6fb1bcf2..0d4b16524 100644 --- a/extensions/ql-vscode/src/helpers.ts +++ b/extensions/ql-vscode/src/helpers.ts @@ -295,10 +295,20 @@ export async function prepareCodeTour(): Promise { existsSync(toursFolderPath) && !isCodespacesTemplate() ) { + const answer = await showBinaryChoiceDialog( + "We've detected you're in the CodeQL Tour repo. We will need to open the workspace file to continue. Reload?", + ); + + if (!answer) { + return; + } + const tutorialWorkspaceUri = Uri.parse(tutorialWorkspacePath); + void extLogger.log( `In prepareCodeTour() method, going to open the tutorial workspace file: ${tutorialWorkspacePath}`, ); + await commands.executeCommand("vscode.openFolder", tutorialWorkspaceUri); } } diff --git a/extensions/ql-vscode/test/vscode-tests/no-workspace/helpers.test.ts b/extensions/ql-vscode/test/vscode-tests/no-workspace/helpers.test.ts index ce1ce9783..cea1ba8bc 100644 --- a/extensions/ql-vscode/test/vscode-tests/no-workspace/helpers.test.ts +++ b/extensions/ql-vscode/test/vscode-tests/no-workspace/helpers.test.ts @@ -572,6 +572,9 @@ describe("isFolderAlreadyInWorkspace", () => { describe("prepareCodeTour", () => { let dir: tmp.DirResult; + let showInformationMessageSpy: jest.SpiedFunction< + typeof window.showInformationMessage + >; beforeEach(() => { dir = tmp.dirSync(); @@ -587,6 +590,10 @@ describe("prepareCodeTour", () => { jest .spyOn(workspace, "workspaceFolders", "get") .mockReturnValue(mockWorkspaceFolders); + + showInformationMessageSpy = jest + .spyOn(window, "showInformationMessage") + .mockResolvedValue({ title: "Yes" }); }); afterEach(() => { @@ -610,6 +617,7 @@ describe("prepareCodeTour", () => { await prepareCodeTour(); + expect(showInformationMessageSpy).toHaveBeenCalled(); expect(commandSpy).toHaveBeenCalledWith( "vscode.openFolder", Uri.parse(tutorialWorkspacePath), From c1a515ed82cd218f8fb709e672b59e45708cf241 Mon Sep 17 00:00:00 2001 From: Elena Tanasoiu Date: Tue, 21 Mar 2023 11:07:22 +0000 Subject: [PATCH 094/156] Open tutorial before extension activation To reduce lag when checking for the existence of the tutorial workspace. --- extensions/ql-vscode/src/extension.ts | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/extensions/ql-vscode/src/extension.ts b/extensions/ql-vscode/src/extension.ts index 103f3491c..10295585b 100644 --- a/extensions/ql-vscode/src/extension.ts +++ b/extensions/ql-vscode/src/extension.ts @@ -345,14 +345,6 @@ export async function activate( codeQlExtension.variantAnalysisManager, ); - try { - await prepareCodeTour(); - } catch (e: unknown) { - void extLogger.log( - `Could not open tutorial workspace automatically: ${getErrorMessage(e)}`, - ); - } - return codeQlExtension; } @@ -540,6 +532,14 @@ async function installOrUpdateThenTryActivate( ): Promise> { await installOrUpdateDistribution(ctx, distributionManager, config); + try { + await prepareCodeTour(); + } catch (e: unknown) { + void extLogger.log( + `Could not open tutorial workspace automatically: ${getErrorMessage(e)}`, + ); + } + // Display the warnings even if the extension has already activated. const distributionResult = await getDistributionDisplayingDistributionWarnings(distributionManager); From bb0c53d65d53d04d5e12bd952542d6046b5c8f77 Mon Sep 17 00:00:00 2001 From: Gulshan Singh Date: Tue, 21 Mar 2023 04:59:18 -0700 Subject: [PATCH 095/156] Display EntityValue labels in CSV export (#2170) --- extensions/ql-vscode/CHANGELOG.md | 1 + extensions/ql-vscode/src/run-queries-shared.ts | 18 ++++++++++++------ 2 files changed, 13 insertions(+), 6 deletions(-) diff --git a/extensions/ql-vscode/CHANGELOG.md b/extensions/ql-vscode/CHANGELOG.md index 385bf6f25..53184cdea 100644 --- a/extensions/ql-vscode/CHANGELOG.md +++ b/extensions/ql-vscode/CHANGELOG.md @@ -3,6 +3,7 @@ ## [UNRELEASED] - Show data flow paths of a variant analysis in a new tab +- Show labels of entities in exported CSV results [#2170](https://github.com/github/vscode-codeql/pull/2170) ## 1.8.0 - 9 March 2023 diff --git a/extensions/ql-vscode/src/run-queries-shared.ts b/extensions/ql-vscode/src/run-queries-shared.ts index 41fae0321..4ee8588fb 100644 --- a/extensions/ql-vscode/src/run-queries-shared.ts +++ b/extensions/ql-vscode/src/run-queries-shared.ts @@ -30,7 +30,7 @@ import { nanoid } from "nanoid"; import { CodeQLCliServer } from "./cli"; import { SELECT_QUERY_NAME } from "./contextual/locationFinder"; import { DatabaseManager } from "./local-databases"; -import { DecodedBqrsChunk } from "./pure/bqrs-cli-types"; +import { DecodedBqrsChunk, EntityValue } from "./pure/bqrs-cli-types"; import { extLogger, Logger } from "./common"; import { generateSummarySymbolsFile } from "./log-insights/summary-parser"; import { getErrorMessage } from "./pure/helpers-pure"; @@ -351,11 +351,17 @@ export class QueryEvaluationInfo { chunk.tuples.forEach((tuple) => { out.write( `${tuple - .map((v, i) => - chunk.columns[i].kind === "String" - ? `"${typeof v === "string" ? v.replaceAll('"', '""') : v}"` - : v, - ) + .map((v, i) => { + if (chunk.columns[i].kind === "String") { + return `"${ + typeof v === "string" ? v.replaceAll('"', '""') : v + }"`; + } else if (chunk.columns[i].kind === "Entity") { + return (v as EntityValue).label; + } else { + return v; + } + }) .join(",")}\n`, ); }); From 108943d135024569512fd569126bd2c3b7aad041 Mon Sep 17 00:00:00 2001 From: Elena Tanasoiu Date: Tue, 21 Mar 2023 13:16:39 +0000 Subject: [PATCH 096/156] `existsSync` -> `pathExists` Use async version of file check. --- extensions/ql-vscode/src/helpers.ts | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/extensions/ql-vscode/src/helpers.ts b/extensions/ql-vscode/src/helpers.ts index 0d4b16524..512c77fcf 100644 --- a/extensions/ql-vscode/src/helpers.ts +++ b/extensions/ql-vscode/src/helpers.ts @@ -5,7 +5,6 @@ import { ensureDir, writeFile, opendir, - existsSync, } from "fs-extra"; import { promise as glob } from "glob-promise"; import { load } from "js-yaml"; @@ -291,8 +290,8 @@ export async function prepareCodeTour(): Promise { * the prompt to open the workspace) */ if ( - existsSync(tutorialWorkspacePath) && - existsSync(toursFolderPath) && + (await pathExists(tutorialWorkspacePath)) && + (await pathExists(toursFolderPath)) && !isCodespacesTemplate() ) { const answer = await showBinaryChoiceDialog( From ac2f4475c0470d1fb34a9623a7f9133511221c70 Mon Sep 17 00:00:00 2001 From: Koen Vlaswinkel Date: Tue, 21 Mar 2023 14:40:04 +0100 Subject: [PATCH 097/156] Group local database commands by type --- extensions/ql-vscode/src/common/commands.ts | 21 ++++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/extensions/ql-vscode/src/common/commands.ts b/extensions/ql-vscode/src/common/commands.ts index 00c68c472..4cd660c39 100644 --- a/extensions/ql-vscode/src/common/commands.ts +++ b/extensions/ql-vscode/src/common/commands.ts @@ -63,27 +63,38 @@ export type QueryHistoryCommands = { // Commands used for the local databases panel export type LocalDatabasesCommands = { - "codeQL.setCurrentDatabase": (uri: Uri) => Promise; - "codeQL.setDefaultTourDatabase": () => Promise; + // Command palette commands "codeQL.upgradeCurrentDatabase": () => Promise; "codeQL.clearCache": () => Promise; + // Explorer context menu + "codeQL.setCurrentDatabase": (uri: Uri) => Promise; + + // Database panel view title commands "codeQLDatabases.chooseDatabaseFolder": () => Promise; "codeQLDatabases.chooseDatabaseArchive": () => Promise; "codeQLDatabases.chooseDatabaseInternet": () => Promise; "codeQLDatabases.chooseDatabaseGithub": () => Promise; + "codeQLDatabases.sortByName": () => Promise; + "codeQLDatabases.sortByDateAdded": () => Promise; + + // Database panel context menu "codeQLDatabases.setCurrentDatabase": ( databaseItem: DatabaseItem, ) => Promise; - "codeQLDatabases.sortByName": () => Promise; - "codeQLDatabases.sortByDateAdded": () => Promise; - "codeQLDatabases.removeOrphanedDatabases": () => Promise; + // Database panel selection commands "codeQLDatabases.removeDatabase": SelectionCommandFunction; "codeQLDatabases.upgradeDatabase": SelectionCommandFunction; "codeQLDatabases.renameDatabase": SelectionCommandFunction; "codeQLDatabases.openDatabaseFolder": SelectionCommandFunction; "codeQLDatabases.addDatabaseSource": SelectionCommandFunction; + + // Codespace template commands + "codeQL.setDefaultTourDatabase": () => Promise; + + // Internal commands + "codeQLDatabases.removeOrphanedDatabases": () => Promise; }; // Commands tied to variant analysis From 32b6ad53cf5e7b028e84ba4f4fdc3512231c684a Mon Sep 17 00:00:00 2001 From: Koen Vlaswinkel Date: Tue, 21 Mar 2023 14:44:46 +0100 Subject: [PATCH 098/156] Move codeQL.chooseDatabaseFolder command --- extensions/ql-vscode/src/common/commands.ts | 1 + extensions/ql-vscode/src/extension.ts | 10 ---------- extensions/ql-vscode/src/local-databases-ui.ts | 13 +++++++++++++ 3 files changed, 14 insertions(+), 10 deletions(-) diff --git a/extensions/ql-vscode/src/common/commands.ts b/extensions/ql-vscode/src/common/commands.ts index 4cd660c39..aa2ae016b 100644 --- a/extensions/ql-vscode/src/common/commands.ts +++ b/extensions/ql-vscode/src/common/commands.ts @@ -64,6 +64,7 @@ export type QueryHistoryCommands = { // Commands used for the local databases panel export type LocalDatabasesCommands = { // Command palette commands + "codeQL.chooseDatabaseFolder": () => Promise; "codeQL.upgradeCurrentDatabase": () => Promise; "codeQL.clearCache": () => Promise; diff --git a/extensions/ql-vscode/src/extension.ts b/extensions/ql-vscode/src/extension.ts index 52e805f86..03a5cf061 100644 --- a/extensions/ql-vscode/src/extension.ts +++ b/extensions/ql-vscode/src/extension.ts @@ -1220,16 +1220,6 @@ async function activateWithInstalledDistribution( ), ); - ctx.subscriptions.push( - commandRunnerWithProgress( - "codeQL.chooseDatabaseFolder", - (progress: ProgressCallback, token: CancellationToken) => - databaseUI.chooseDatabaseFolder(progress, token), - { - title: "Choose a Database from a Folder", - }, - ), - ); ctx.subscriptions.push( commandRunnerWithProgress( "codeQL.chooseDatabaseArchive", diff --git a/extensions/ql-vscode/src/local-databases-ui.ts b/extensions/ql-vscode/src/local-databases-ui.ts index 95b98d4fe..5cc11c0d9 100644 --- a/extensions/ql-vscode/src/local-databases-ui.ts +++ b/extensions/ql-vscode/src/local-databases-ui.ts @@ -208,6 +208,8 @@ export class DatabaseUI extends DisposableObject { public getCommands(): LocalDatabasesCommands { return { + "codeQL.chooseDatabaseFolder": + this.handleChooseDatabaseFolderFromPalette.bind(this), "codeQL.setCurrentDatabase": this.handleSetCurrentDatabase.bind(this), "codeQL.setDefaultTourDatabase": this.handleSetDefaultTourDatabase.bind(this), @@ -268,6 +270,17 @@ export class DatabaseUI extends DisposableObject { ); } + private async handleChooseDatabaseFolderFromPalette(): Promise { + return withProgress( + async (progress, token) => { + await this.chooseDatabaseFolder(progress, token); + }, + { + title: "Choose a Database from a Folder", + }, + ); + } + private async handleSetDefaultTourDatabase(): Promise { return withProgress( async (progress, token) => { From 71f22b9a7a699c55e4dee82d55db376584aa2040 Mon Sep 17 00:00:00 2001 From: Koen Vlaswinkel Date: Tue, 21 Mar 2023 14:45:54 +0100 Subject: [PATCH 099/156] Move codeQL.chooseDatabaseArchive command --- extensions/ql-vscode/src/common/commands.ts | 1 + extensions/ql-vscode/src/extension.ts | 10 ---------- extensions/ql-vscode/src/local-databases-ui.ts | 13 +++++++++++++ 3 files changed, 14 insertions(+), 10 deletions(-) diff --git a/extensions/ql-vscode/src/common/commands.ts b/extensions/ql-vscode/src/common/commands.ts index aa2ae016b..97e95be15 100644 --- a/extensions/ql-vscode/src/common/commands.ts +++ b/extensions/ql-vscode/src/common/commands.ts @@ -65,6 +65,7 @@ export type QueryHistoryCommands = { export type LocalDatabasesCommands = { // Command palette commands "codeQL.chooseDatabaseFolder": () => Promise; + "codeQL.chooseDatabaseArchive": () => Promise; "codeQL.upgradeCurrentDatabase": () => Promise; "codeQL.clearCache": () => Promise; diff --git a/extensions/ql-vscode/src/extension.ts b/extensions/ql-vscode/src/extension.ts index 03a5cf061..d17662837 100644 --- a/extensions/ql-vscode/src/extension.ts +++ b/extensions/ql-vscode/src/extension.ts @@ -1220,16 +1220,6 @@ async function activateWithInstalledDistribution( ), ); - ctx.subscriptions.push( - commandRunnerWithProgress( - "codeQL.chooseDatabaseArchive", - (progress: ProgressCallback, token: CancellationToken) => - databaseUI.chooseDatabaseArchive(progress, token), - { - title: "Choose a Database from an Archive", - }, - ), - ); ctx.subscriptions.push( commandRunnerWithProgress( "codeQL.chooseDatabaseGithub", diff --git a/extensions/ql-vscode/src/local-databases-ui.ts b/extensions/ql-vscode/src/local-databases-ui.ts index 5cc11c0d9..e84d6e6df 100644 --- a/extensions/ql-vscode/src/local-databases-ui.ts +++ b/extensions/ql-vscode/src/local-databases-ui.ts @@ -210,6 +210,8 @@ export class DatabaseUI extends DisposableObject { return { "codeQL.chooseDatabaseFolder": this.handleChooseDatabaseFolderFromPalette.bind(this), + "codeQL.chooseDatabaseArchive": + this.handleChooseDatabaseArchiveFromPalette.bind(this), "codeQL.setCurrentDatabase": this.handleSetCurrentDatabase.bind(this), "codeQL.setDefaultTourDatabase": this.handleSetDefaultTourDatabase.bind(this), @@ -431,6 +433,17 @@ export class DatabaseUI extends DisposableObject { ); } + private async handleChooseDatabaseArchiveFromPalette(): Promise { + return withProgress( + async (progress, token) => { + await this.chooseDatabaseArchive(progress, token); + }, + { + title: "Choose a Database from an Archive", + }, + ); + } + public async chooseDatabaseInternet( progress: ProgressCallback, token: CancellationToken, From 15d30d534221a8fe93a2b85b5a3a89a6c51a1145 Mon Sep 17 00:00:00 2001 From: Koen Vlaswinkel Date: Tue, 21 Mar 2023 14:47:26 +0100 Subject: [PATCH 100/156] Move codeQL.chooseDatabaseInternet command --- extensions/ql-vscode/src/common/commands.ts | 1 + extensions/ql-vscode/src/extension.ts | 11 ----------- extensions/ql-vscode/src/local-databases-ui.ts | 2 ++ 3 files changed, 3 insertions(+), 11 deletions(-) diff --git a/extensions/ql-vscode/src/common/commands.ts b/extensions/ql-vscode/src/common/commands.ts index 97e95be15..2aa5adbd4 100644 --- a/extensions/ql-vscode/src/common/commands.ts +++ b/extensions/ql-vscode/src/common/commands.ts @@ -66,6 +66,7 @@ export type LocalDatabasesCommands = { // Command palette commands "codeQL.chooseDatabaseFolder": () => Promise; "codeQL.chooseDatabaseArchive": () => Promise; + "codeQL.chooseDatabaseInternet": () => Promise; "codeQL.upgradeCurrentDatabase": () => Promise; "codeQL.clearCache": () => Promise; diff --git a/extensions/ql-vscode/src/extension.ts b/extensions/ql-vscode/src/extension.ts index d17662837..a57ad17dd 100644 --- a/extensions/ql-vscode/src/extension.ts +++ b/extensions/ql-vscode/src/extension.ts @@ -1231,17 +1231,6 @@ async function activateWithInstalledDistribution( }, ), ); - ctx.subscriptions.push( - commandRunnerWithProgress( - "codeQL.chooseDatabaseInternet", - (progress: ProgressCallback, token: CancellationToken) => - databaseUI.chooseDatabaseInternet(progress, token), - - { - title: "Adding database from URL", - }, - ), - ); ctx.subscriptions.push( commandRunner("codeQL.copyVersion", async () => { diff --git a/extensions/ql-vscode/src/local-databases-ui.ts b/extensions/ql-vscode/src/local-databases-ui.ts index e84d6e6df..befc481b5 100644 --- a/extensions/ql-vscode/src/local-databases-ui.ts +++ b/extensions/ql-vscode/src/local-databases-ui.ts @@ -212,6 +212,8 @@ export class DatabaseUI extends DisposableObject { this.handleChooseDatabaseFolderFromPalette.bind(this), "codeQL.chooseDatabaseArchive": this.handleChooseDatabaseArchiveFromPalette.bind(this), + "codeQL.chooseDatabaseInternet": + this.handleChooseDatabaseInternet.bind(this), "codeQL.setCurrentDatabase": this.handleSetCurrentDatabase.bind(this), "codeQL.setDefaultTourDatabase": this.handleSetDefaultTourDatabase.bind(this), From 7ab986fabe0c9c51f436497262d75c55240f8885 Mon Sep 17 00:00:00 2001 From: Koen Vlaswinkel Date: Tue, 21 Mar 2023 14:48:14 +0100 Subject: [PATCH 101/156] Move codeQL.chooseDatabaseGithub command --- extensions/ql-vscode/src/common/commands.ts | 1 + extensions/ql-vscode/src/extension.ts | 12 ------------ extensions/ql-vscode/src/local-databases-ui.ts | 1 + 3 files changed, 2 insertions(+), 12 deletions(-) diff --git a/extensions/ql-vscode/src/common/commands.ts b/extensions/ql-vscode/src/common/commands.ts index 2aa5adbd4..f7971ccdb 100644 --- a/extensions/ql-vscode/src/common/commands.ts +++ b/extensions/ql-vscode/src/common/commands.ts @@ -67,6 +67,7 @@ export type LocalDatabasesCommands = { "codeQL.chooseDatabaseFolder": () => Promise; "codeQL.chooseDatabaseArchive": () => Promise; "codeQL.chooseDatabaseInternet": () => Promise; + "codeQL.chooseDatabaseGithub": () => Promise; "codeQL.upgradeCurrentDatabase": () => Promise; "codeQL.clearCache": () => Promise; diff --git a/extensions/ql-vscode/src/extension.ts b/extensions/ql-vscode/src/extension.ts index a57ad17dd..52abf5e7a 100644 --- a/extensions/ql-vscode/src/extension.ts +++ b/extensions/ql-vscode/src/extension.ts @@ -1220,18 +1220,6 @@ async function activateWithInstalledDistribution( ), ); - ctx.subscriptions.push( - commandRunnerWithProgress( - "codeQL.chooseDatabaseGithub", - async (progress: ProgressCallback, token: CancellationToken) => { - await databaseUI.chooseDatabaseGithub(progress, token); - }, - { - title: "Adding database from GitHub", - }, - ), - ); - ctx.subscriptions.push( commandRunner("codeQL.copyVersion", async () => { const text = `CodeQL extension version: ${ diff --git a/extensions/ql-vscode/src/local-databases-ui.ts b/extensions/ql-vscode/src/local-databases-ui.ts index befc481b5..fc6b0eff6 100644 --- a/extensions/ql-vscode/src/local-databases-ui.ts +++ b/extensions/ql-vscode/src/local-databases-ui.ts @@ -214,6 +214,7 @@ export class DatabaseUI extends DisposableObject { this.handleChooseDatabaseArchiveFromPalette.bind(this), "codeQL.chooseDatabaseInternet": this.handleChooseDatabaseInternet.bind(this), + "codeQL.chooseDatabaseGithub": this.handleChooseDatabaseGithub.bind(this), "codeQL.setCurrentDatabase": this.handleSetCurrentDatabase.bind(this), "codeQL.setDefaultTourDatabase": this.handleSetDefaultTourDatabase.bind(this), From bed56ef64883cddc533f327e0aedfc1b09ce5b77 Mon Sep 17 00:00:00 2001 From: Koen Vlaswinkel Date: Tue, 21 Mar 2023 14:50:24 +0100 Subject: [PATCH 102/156] Make public methods private in local databases UI Some of the methods in the `DatabaseUI` were public because they were used in the `extension.ts` file. We have moved these method calls into this file, so they do not need to be public anymore. We can also get rid of the separation between some of these methods, so I've moved them into the function that calls them. --- .../ql-vscode/src/local-databases-ui.ts | 52 +++++++------------ 1 file changed, 19 insertions(+), 33 deletions(-) diff --git a/extensions/ql-vscode/src/local-databases-ui.ts b/extensions/ql-vscode/src/local-databases-ui.ts index fc6b0eff6..c12081221 100644 --- a/extensions/ql-vscode/src/local-databases-ui.ts +++ b/extensions/ql-vscode/src/local-databases-ui.ts @@ -249,7 +249,7 @@ export class DatabaseUI extends DisposableObject { await this.databaseManager.setCurrentDatabaseItem(databaseItem); } - public async chooseDatabaseFolder( + private async chooseDatabaseFolder( progress: ProgressCallback, token: CancellationToken, ): Promise { @@ -410,7 +410,7 @@ export class DatabaseUI extends DisposableObject { } } - public async chooseDatabaseArchive( + private async chooseDatabaseArchive( progress: ProgressCallback, token: CancellationToken, ): Promise { @@ -447,23 +447,16 @@ export class DatabaseUI extends DisposableObject { ); } - public async chooseDatabaseInternet( - progress: ProgressCallback, - token: CancellationToken, - ): Promise { - return await promptImportInternetDatabase( - this.databaseManager, - this.storagePath, - progress, - token, - this.queryServer?.cliServer, - ); - } - private async handleChooseDatabaseInternet(): Promise { return withProgress( async (progress, token) => { - await this.chooseDatabaseInternet(progress, token); + await promptImportInternetDatabase( + this.databaseManager, + this.storagePath, + progress, + token, + this.queryServer?.cliServer, + ); }, { title: "Adding database from URL", @@ -471,26 +464,19 @@ export class DatabaseUI extends DisposableObject { ); } - public async chooseDatabaseGithub( - progress: ProgressCallback, - token: CancellationToken, - ): Promise { - const credentials = isCanary() ? this.app.credentials : undefined; - - return await promptImportGithubDatabase( - this.databaseManager, - this.storagePath, - credentials, - progress, - token, - this.queryServer?.cliServer, - ); - } - private async handleChooseDatabaseGithub(): Promise { return withProgress( async (progress, token) => { - await this.chooseDatabaseGithub(progress, token); + const credentials = isCanary() ? this.app.credentials : undefined; + + await promptImportGithubDatabase( + this.databaseManager, + this.storagePath, + credentials, + progress, + token, + this.queryServer?.cliServer, + ); }, { title: "Adding database from GitHub", From 8fd9ebf2d89ce1835040bec24177d3fd39d8edc5 Mon Sep 17 00:00:00 2001 From: Elena Tanasoiu Date: Tue, 21 Mar 2023 13:46:28 +0000 Subject: [PATCH 103/156] Limit comparison to Uri path We attempted to specify exactly which URI we're expecting here. However, `Uri.parse` behaves differently in the test than it does in the code so we've inadvertently created a flakey test [1]. The URI we generate in the test has a `scheme: 'c'` while the one in the code has a `scheme: 'C'` property. This only happens on windows, not ubuntu. Let's narrow the comparison to just the path of the URI. [1]: https://github.com/github/vscode-codeql/actions/runs/4478429334/jobs/7871178529#step:7:231 --- .../ql-vscode/test/vscode-tests/no-workspace/helpers.test.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/extensions/ql-vscode/test/vscode-tests/no-workspace/helpers.test.ts b/extensions/ql-vscode/test/vscode-tests/no-workspace/helpers.test.ts index cea1ba8bc..bd425e0a0 100644 --- a/extensions/ql-vscode/test/vscode-tests/no-workspace/helpers.test.ts +++ b/extensions/ql-vscode/test/vscode-tests/no-workspace/helpers.test.ts @@ -620,7 +620,9 @@ describe("prepareCodeTour", () => { expect(showInformationMessageSpy).toHaveBeenCalled(); expect(commandSpy).toHaveBeenCalledWith( "vscode.openFolder", - Uri.parse(tutorialWorkspacePath), + expect.objectContaining({ + path: Uri.parse(tutorialWorkspacePath).fsPath, + }), ); }); }); From 0379575256f58b80d2f041364e92bde764067335 Mon Sep 17 00:00:00 2001 From: Koen Vlaswinkel Date: Tue, 21 Mar 2023 15:58:12 +0100 Subject: [PATCH 104/156] Move AST and CFG commands to separate file --- extensions/ql-vscode/src/ast-cfg-commands.ts | 212 +++++++++++++++++++ extensions/ql-vscode/src/extension.ts | 187 ++-------------- 2 files changed, 224 insertions(+), 175 deletions(-) create mode 100644 extensions/ql-vscode/src/ast-cfg-commands.ts diff --git a/extensions/ql-vscode/src/ast-cfg-commands.ts b/extensions/ql-vscode/src/ast-cfg-commands.ts new file mode 100644 index 000000000..15941512f --- /dev/null +++ b/extensions/ql-vscode/src/ast-cfg-commands.ts @@ -0,0 +1,212 @@ +import { CancellationToken, ExtensionContext, Uri, window } from "vscode"; +import { commandRunnerWithProgress, ProgressCallback } from "./commandRunner"; +import { AstViewer } from "./astViewer"; +import { + TemplatePrintAstProvider, + TemplatePrintCfgProvider, +} from "./contextual/templateProvider"; +import { compileAndRunQuery } from "./local-queries"; +import { QueryRunner } from "./queryRunner"; +import { QueryHistoryManager } from "./query-history/query-history-manager"; +import { DatabaseUI } from "./local-databases-ui"; +import { ResultsView } from "./interface"; + +type AstCfgOptions = { + queryRunner: QueryRunner; + queryHistoryManager: QueryHistoryManager; + databaseUI: DatabaseUI; + localQueryResultsView: ResultsView; + queryStorageDir: string; + + astViewer: AstViewer; + astTemplateProvider: TemplatePrintAstProvider; + cfgTemplateProvider: TemplatePrintCfgProvider; +}; + +export function registerAstCfgCommands( + ctx: ExtensionContext, + { + queryRunner, + queryHistoryManager, + databaseUI, + localQueryResultsView, + queryStorageDir, + astViewer, + astTemplateProvider, + cfgTemplateProvider, + }: AstCfgOptions, +) { + ctx.subscriptions.push( + commandRunnerWithProgress( + "codeQL.viewAst", + async ( + progress: ProgressCallback, + token: CancellationToken, + selectedFile: Uri, + ) => + await viewAst( + astViewer, + astTemplateProvider, + progress, + token, + selectedFile, + ), + { + cancellable: true, + title: "Calculate AST", + }, + ), + ); + + // Since we are tracking extension usage through commands, this command mirrors the "codeQL.viewAst" command + ctx.subscriptions.push( + commandRunnerWithProgress( + "codeQL.viewAstContextExplorer", + async ( + progress: ProgressCallback, + token: CancellationToken, + selectedFile: Uri, + ) => + await viewAst( + astViewer, + astTemplateProvider, + progress, + token, + selectedFile, + ), + { + cancellable: true, + title: "Calculate AST", + }, + ), + ); + + // Since we are tracking extension usage through commands, this command mirrors the "codeQL.viewAst" command + ctx.subscriptions.push( + commandRunnerWithProgress( + "codeQL.viewAstContextEditor", + async ( + progress: ProgressCallback, + token: CancellationToken, + selectedFile: Uri, + ) => + await viewAst( + astViewer, + astTemplateProvider, + progress, + token, + selectedFile, + ), + { + cancellable: true, + title: "Calculate AST", + }, + ), + ); + + ctx.subscriptions.push( + commandRunnerWithProgress( + "codeQL.viewCfg", + async (progress: ProgressCallback, token: CancellationToken) => { + const res = await cfgTemplateProvider.provideCfgUri( + window.activeTextEditor?.document, + ); + if (res) { + await compileAndRunQuery( + queryRunner, + queryHistoryManager, + databaseUI, + localQueryResultsView, + queryStorageDir, + false, + res[0], + progress, + token, + undefined, + ); + } + }, + { + title: "Calculating Control Flow Graph", + cancellable: true, + }, + ), + ); + + // Since we are tracking extension usage through commands, this command mirrors the "codeQL.viewCfg" command + ctx.subscriptions.push( + commandRunnerWithProgress( + "codeQL.viewCfgContextExplorer", + async (progress: ProgressCallback, token: CancellationToken) => { + const res = await cfgTemplateProvider.provideCfgUri( + window.activeTextEditor?.document, + ); + if (res) { + await compileAndRunQuery( + queryRunner, + queryHistoryManager, + databaseUI, + localQueryResultsView, + queryStorageDir, + false, + res[0], + progress, + token, + undefined, + ); + } + }, + { + title: "Calculating Control Flow Graph", + cancellable: true, + }, + ), + ); + + // Since we are tracking extension usage through commands, this command mirrors the "codeQL.viewCfg" command + ctx.subscriptions.push( + commandRunnerWithProgress( + "codeQL.viewCfgContextEditor", + async (progress: ProgressCallback, token: CancellationToken) => { + const res = await cfgTemplateProvider.provideCfgUri( + window.activeTextEditor?.document, + ); + if (res) { + await compileAndRunQuery( + queryRunner, + queryHistoryManager, + databaseUI, + localQueryResultsView, + queryStorageDir, + false, + res[0], + progress, + token, + undefined, + ); + } + }, + { + title: "Calculating Control Flow Graph", + cancellable: true, + }, + ), + ); +} + +async function viewAst( + astViewer: AstViewer, + printAstTemplateProvider: TemplatePrintAstProvider, + progress: ProgressCallback, + token: CancellationToken, + selectedFile: Uri, +): Promise { + const ast = await printAstTemplateProvider.provideAst( + progress, + token, + selectedFile ?? window.activeTextEditor?.document.uri, + ); + if (ast) { + astViewer.updateRoots(await ast.getRoots(), ast.db, ast.fileName); + } +} diff --git a/extensions/ql-vscode/src/extension.ts b/extensions/ql-vscode/src/extension.ts index 1bfcc5df6..89b70f52c 100644 --- a/extensions/ql-vscode/src/extension.ts +++ b/extensions/ql-vscode/src/extension.ts @@ -130,10 +130,10 @@ import { QueryServerCommands, } from "./common/commands"; import { - compileAndRunQuery, getLocalQueryCommands, showResultsForCompletedQuery, } from "./local-queries"; +import { registerAstCfgCommands } from "./ast-cfg-commands"; /** * extension.ts @@ -1085,7 +1085,7 @@ async function activateWithInstalledDistribution( ); const astViewer = new AstViewer(); - const printAstTemplateProvider = new TemplatePrintAstProvider( + const astTemplateProvider = new TemplatePrintAstProvider( cliServer, qs, dbm, @@ -1095,162 +1095,16 @@ async function activateWithInstalledDistribution( ctx.subscriptions.push(astViewer); - ctx.subscriptions.push( - commandRunnerWithProgress( - "codeQL.viewAst", - async ( - progress: ProgressCallback, - token: CancellationToken, - selectedFile: Uri, - ) => - await viewAst( - astViewer, - printAstTemplateProvider, - progress, - token, - selectedFile, - ), - { - cancellable: true, - title: "Calculate AST", - }, - ), - ); - - // Since we are tracking extension usage through commands, this command mirrors the "codeQL.viewAst" command - ctx.subscriptions.push( - commandRunnerWithProgress( - "codeQL.viewAstContextExplorer", - async ( - progress: ProgressCallback, - token: CancellationToken, - selectedFile: Uri, - ) => - await viewAst( - astViewer, - printAstTemplateProvider, - progress, - token, - selectedFile, - ), - { - cancellable: true, - title: "Calculate AST", - }, - ), - ); - - // Since we are tracking extension usage through commands, this command mirrors the "codeQL.viewAst" command - ctx.subscriptions.push( - commandRunnerWithProgress( - "codeQL.viewAstContextEditor", - async ( - progress: ProgressCallback, - token: CancellationToken, - selectedFile: Uri, - ) => - await viewAst( - astViewer, - printAstTemplateProvider, - progress, - token, - selectedFile, - ), - { - cancellable: true, - title: "Calculate AST", - }, - ), - ); - - ctx.subscriptions.push( - commandRunnerWithProgress( - "codeQL.viewCfg", - async (progress: ProgressCallback, token: CancellationToken) => { - const res = await cfgTemplateProvider.provideCfgUri( - window.activeTextEditor?.document, - ); - if (res) { - await compileAndRunQuery( - qs, - qhm, - databaseUI, - localQueryResultsView, - queryStorageDir, - false, - res[0], - progress, - token, - undefined, - ); - } - }, - { - title: "Calculating Control Flow Graph", - cancellable: true, - }, - ), - ); - - // Since we are tracking extension usage through commands, this command mirrors the "codeQL.viewCfg" command - ctx.subscriptions.push( - commandRunnerWithProgress( - "codeQL.viewCfgContextExplorer", - async (progress: ProgressCallback, token: CancellationToken) => { - const res = await cfgTemplateProvider.provideCfgUri( - window.activeTextEditor?.document, - ); - if (res) { - await compileAndRunQuery( - qs, - qhm, - databaseUI, - localQueryResultsView, - queryStorageDir, - false, - res[0], - progress, - token, - undefined, - ); - } - }, - { - title: "Calculating Control Flow Graph", - cancellable: true, - }, - ), - ); - - // Since we are tracking extension usage through commands, this command mirrors the "codeQL.viewCfg" command - ctx.subscriptions.push( - commandRunnerWithProgress( - "codeQL.viewCfgContextEditor", - async (progress: ProgressCallback, token: CancellationToken) => { - const res = await cfgTemplateProvider.provideCfgUri( - window.activeTextEditor?.document, - ); - if (res) { - await compileAndRunQuery( - qs, - qhm, - databaseUI, - localQueryResultsView, - queryStorageDir, - false, - res[0], - progress, - token, - undefined, - ); - } - }, - { - title: "Calculating Control Flow Graph", - cancellable: true, - }, - ), - ); + registerAstCfgCommands(ctx, { + queryRunner: qs, + queryHistoryManager: qhm, + databaseUI, + localQueryResultsView, + queryStorageDir, + astViewer, + astTemplateProvider, + cfgTemplateProvider, + }); const mockServer = new VSCodeMockGitHubApiServer(ctx); ctx.subscriptions.push(mockServer); @@ -1367,23 +1221,6 @@ async function openReferencedFile( } } -async function viewAst( - astViewer: AstViewer, - printAstTemplateProvider: TemplatePrintAstProvider, - progress: ProgressCallback, - token: CancellationToken, - selectedFile: Uri, -): Promise { - const ast = await printAstTemplateProvider.provideAst( - progress, - token, - selectedFile ?? window.activeTextEditor?.document.uri, - ); - if (ast) { - astViewer.updateRoots(await ast.getRoots(), ast.db, ast.fileName); - } -} - function addUnhandledRejectionListener() { const handler = (error: unknown) => { // This listener will be triggered for errors from other extensions as From 6ff2670ec27fe62971ba7a7a466cd04f8c795449 Mon Sep 17 00:00:00 2001 From: Koen Vlaswinkel Date: Tue, 21 Mar 2023 16:02:05 +0100 Subject: [PATCH 105/156] Remove duplication of AST and CFG command implementations --- extensions/ql-vscode/src/ast-cfg-commands.ts | 195 ++++++------------- 1 file changed, 60 insertions(+), 135 deletions(-) diff --git a/extensions/ql-vscode/src/ast-cfg-commands.ts b/extensions/ql-vscode/src/ast-cfg-commands.ts index 15941512f..75760e6d5 100644 --- a/extensions/ql-vscode/src/ast-cfg-commands.ts +++ b/extensions/ql-vscode/src/ast-cfg-commands.ts @@ -36,161 +36,86 @@ export function registerAstCfgCommands( cfgTemplateProvider, }: AstCfgOptions, ) { + const viewAstCommand = async ( + progress: ProgressCallback, + token: CancellationToken, + selectedFile: Uri, + ) => + await viewAst( + astViewer, + astTemplateProvider, + progress, + token, + selectedFile, + ); + + const viewCfgCommand = async ( + progress: ProgressCallback, + token: CancellationToken, + ) => { + const res = await cfgTemplateProvider.provideCfgUri( + window.activeTextEditor?.document, + ); + if (res) { + await compileAndRunQuery( + queryRunner, + queryHistoryManager, + databaseUI, + localQueryResultsView, + queryStorageDir, + false, + res[0], + progress, + token, + undefined, + ); + } + }; + ctx.subscriptions.push( - commandRunnerWithProgress( - "codeQL.viewAst", - async ( - progress: ProgressCallback, - token: CancellationToken, - selectedFile: Uri, - ) => - await viewAst( - astViewer, - astTemplateProvider, - progress, - token, - selectedFile, - ), - { - cancellable: true, - title: "Calculate AST", - }, - ), + commandRunnerWithProgress("codeQL.viewAst", viewAstCommand, { + cancellable: true, + title: "Calculate AST", + }), ); // Since we are tracking extension usage through commands, this command mirrors the "codeQL.viewAst" command ctx.subscriptions.push( - commandRunnerWithProgress( - "codeQL.viewAstContextExplorer", - async ( - progress: ProgressCallback, - token: CancellationToken, - selectedFile: Uri, - ) => - await viewAst( - astViewer, - astTemplateProvider, - progress, - token, - selectedFile, - ), - { - cancellable: true, - title: "Calculate AST", - }, - ), + commandRunnerWithProgress("codeQL.viewAstContextExplorer", viewAstCommand, { + cancellable: true, + title: "Calculate AST", + }), ); // Since we are tracking extension usage through commands, this command mirrors the "codeQL.viewAst" command ctx.subscriptions.push( - commandRunnerWithProgress( - "codeQL.viewAstContextEditor", - async ( - progress: ProgressCallback, - token: CancellationToken, - selectedFile: Uri, - ) => - await viewAst( - astViewer, - astTemplateProvider, - progress, - token, - selectedFile, - ), - { - cancellable: true, - title: "Calculate AST", - }, - ), + commandRunnerWithProgress("codeQL.viewAstContextEditor", viewAstCommand, { + cancellable: true, + title: "Calculate AST", + }), ); ctx.subscriptions.push( - commandRunnerWithProgress( - "codeQL.viewCfg", - async (progress: ProgressCallback, token: CancellationToken) => { - const res = await cfgTemplateProvider.provideCfgUri( - window.activeTextEditor?.document, - ); - if (res) { - await compileAndRunQuery( - queryRunner, - queryHistoryManager, - databaseUI, - localQueryResultsView, - queryStorageDir, - false, - res[0], - progress, - token, - undefined, - ); - } - }, - { - title: "Calculating Control Flow Graph", - cancellable: true, - }, - ), + commandRunnerWithProgress("codeQL.viewCfg", viewCfgCommand, { + title: "Calculating Control Flow Graph", + cancellable: true, + }), ); // Since we are tracking extension usage through commands, this command mirrors the "codeQL.viewCfg" command ctx.subscriptions.push( - commandRunnerWithProgress( - "codeQL.viewCfgContextExplorer", - async (progress: ProgressCallback, token: CancellationToken) => { - const res = await cfgTemplateProvider.provideCfgUri( - window.activeTextEditor?.document, - ); - if (res) { - await compileAndRunQuery( - queryRunner, - queryHistoryManager, - databaseUI, - localQueryResultsView, - queryStorageDir, - false, - res[0], - progress, - token, - undefined, - ); - } - }, - { - title: "Calculating Control Flow Graph", - cancellable: true, - }, - ), + commandRunnerWithProgress("codeQL.viewCfgContextExplorer", viewCfgCommand, { + title: "Calculating Control Flow Graph", + cancellable: true, + }), ); // Since we are tracking extension usage through commands, this command mirrors the "codeQL.viewCfg" command ctx.subscriptions.push( - commandRunnerWithProgress( - "codeQL.viewCfgContextEditor", - async (progress: ProgressCallback, token: CancellationToken) => { - const res = await cfgTemplateProvider.provideCfgUri( - window.activeTextEditor?.document, - ); - if (res) { - await compileAndRunQuery( - queryRunner, - queryHistoryManager, - databaseUI, - localQueryResultsView, - queryStorageDir, - false, - res[0], - progress, - token, - undefined, - ); - } - }, - { - title: "Calculating Control Flow Graph", - cancellable: true, - }, - ), + commandRunnerWithProgress("codeQL.viewCfgContextEditor", viewCfgCommand, { + title: "Calculating Control Flow Graph", + cancellable: true, + }), ); } From 1909fee91f8b9d13299280ab18eab135ad45d277 Mon Sep 17 00:00:00 2001 From: Koen Vlaswinkel Date: Tue, 21 Mar 2023 16:04:41 +0100 Subject: [PATCH 106/156] Remove use of commandRunnerWithProgress in AST and CFG commands --- extensions/ql-vscode/src/ast-cfg-commands.ts | 113 ++++++++----------- 1 file changed, 49 insertions(+), 64 deletions(-) diff --git a/extensions/ql-vscode/src/ast-cfg-commands.ts b/extensions/ql-vscode/src/ast-cfg-commands.ts index 75760e6d5..c7f463e52 100644 --- a/extensions/ql-vscode/src/ast-cfg-commands.ts +++ b/extensions/ql-vscode/src/ast-cfg-commands.ts @@ -1,5 +1,5 @@ import { CancellationToken, ExtensionContext, Uri, window } from "vscode"; -import { commandRunnerWithProgress, ProgressCallback } from "./commandRunner"; +import { commandRunner, ProgressCallback, withProgress } from "./commandRunner"; import { AstViewer } from "./astViewer"; import { TemplatePrintAstProvider, @@ -36,86 +36,71 @@ export function registerAstCfgCommands( cfgTemplateProvider, }: AstCfgOptions, ) { - const viewAstCommand = async ( - progress: ProgressCallback, - token: CancellationToken, - selectedFile: Uri, - ) => - await viewAst( - astViewer, - astTemplateProvider, - progress, - token, - selectedFile, + const viewAstCommand = async (selectedFile: Uri) => + withProgress( + async (progress, token) => + await viewAst( + astViewer, + astTemplateProvider, + progress, + token, + selectedFile, + ), + { + cancellable: true, + title: "Calculate AST", + }, ); - const viewCfgCommand = async ( - progress: ProgressCallback, - token: CancellationToken, - ) => { - const res = await cfgTemplateProvider.provideCfgUri( - window.activeTextEditor?.document, + const viewCfgCommand = async () => + withProgress( + async (progress, token) => { + const res = await cfgTemplateProvider.provideCfgUri( + window.activeTextEditor?.document, + ); + if (res) { + await compileAndRunQuery( + queryRunner, + queryHistoryManager, + databaseUI, + localQueryResultsView, + queryStorageDir, + false, + res[0], + progress, + token, + undefined, + ); + } + }, + { + title: "Calculating Control Flow Graph", + cancellable: true, + }, ); - if (res) { - await compileAndRunQuery( - queryRunner, - queryHistoryManager, - databaseUI, - localQueryResultsView, - queryStorageDir, - false, - res[0], - progress, - token, - undefined, - ); - } - }; + ctx.subscriptions.push(commandRunner("codeQL.viewAst", viewAstCommand)); + + // Since we are tracking extension usage through commands, this command mirrors the "codeQL.viewAst" command ctx.subscriptions.push( - commandRunnerWithProgress("codeQL.viewAst", viewAstCommand, { - cancellable: true, - title: "Calculate AST", - }), + commandRunner("codeQL.viewAstContextExplorer", viewAstCommand), ); // Since we are tracking extension usage through commands, this command mirrors the "codeQL.viewAst" command ctx.subscriptions.push( - commandRunnerWithProgress("codeQL.viewAstContextExplorer", viewAstCommand, { - cancellable: true, - title: "Calculate AST", - }), + commandRunner("codeQL.viewAstContextEditor", viewAstCommand), ); - // Since we are tracking extension usage through commands, this command mirrors the "codeQL.viewAst" command - ctx.subscriptions.push( - commandRunnerWithProgress("codeQL.viewAstContextEditor", viewAstCommand, { - cancellable: true, - title: "Calculate AST", - }), - ); + ctx.subscriptions.push(commandRunner("codeQL.viewCfg", viewCfgCommand)); + // Since we are tracking extension usage through commands, this command mirrors the "codeQL.viewCfg" command ctx.subscriptions.push( - commandRunnerWithProgress("codeQL.viewCfg", viewCfgCommand, { - title: "Calculating Control Flow Graph", - cancellable: true, - }), + commandRunner("codeQL.viewCfgContextExplorer", viewCfgCommand), ); // Since we are tracking extension usage through commands, this command mirrors the "codeQL.viewCfg" command ctx.subscriptions.push( - commandRunnerWithProgress("codeQL.viewCfgContextExplorer", viewCfgCommand, { - title: "Calculating Control Flow Graph", - cancellable: true, - }), - ); - - // Since we are tracking extension usage through commands, this command mirrors the "codeQL.viewCfg" command - ctx.subscriptions.push( - commandRunnerWithProgress("codeQL.viewCfgContextEditor", viewCfgCommand, { - title: "Calculating Control Flow Graph", - cancellable: true, - }), + commandRunner("codeQL.viewCfgContextEditor", viewCfgCommand), ); } From b3092be5d3e50e35731706996169f97c24e1673e Mon Sep 17 00:00:00 2001 From: Koen Vlaswinkel Date: Tue, 21 Mar 2023 16:09:15 +0100 Subject: [PATCH 107/156] Convert AST and CFG commands to typed commands --- extensions/ql-vscode/src/ast-cfg-commands.ts | 59 +++++++------------ extensions/ql-vscode/src/common/commands.ts | 12 +++- extensions/ql-vscode/src/extension.ts | 61 ++++++++++---------- 3 files changed, 63 insertions(+), 69 deletions(-) diff --git a/extensions/ql-vscode/src/ast-cfg-commands.ts b/extensions/ql-vscode/src/ast-cfg-commands.ts index c7f463e52..2e5343ef4 100644 --- a/extensions/ql-vscode/src/ast-cfg-commands.ts +++ b/extensions/ql-vscode/src/ast-cfg-commands.ts @@ -1,5 +1,5 @@ -import { CancellationToken, ExtensionContext, Uri, window } from "vscode"; -import { commandRunner, ProgressCallback, withProgress } from "./commandRunner"; +import { CancellationToken, Uri, window } from "vscode"; +import { ProgressCallback, withProgress } from "./commandRunner"; import { AstViewer } from "./astViewer"; import { TemplatePrintAstProvider, @@ -10,6 +10,7 @@ import { QueryRunner } from "./queryRunner"; import { QueryHistoryManager } from "./query-history/query-history-manager"; import { DatabaseUI } from "./local-databases-ui"; import { ResultsView } from "./interface"; +import { AstCfgCommands } from "./common/commands"; type AstCfgOptions = { queryRunner: QueryRunner; @@ -23,19 +24,16 @@ type AstCfgOptions = { cfgTemplateProvider: TemplatePrintCfgProvider; }; -export function registerAstCfgCommands( - ctx: ExtensionContext, - { - queryRunner, - queryHistoryManager, - databaseUI, - localQueryResultsView, - queryStorageDir, - astViewer, - astTemplateProvider, - cfgTemplateProvider, - }: AstCfgOptions, -) { +export function getAstCfgCommands({ + queryRunner, + queryHistoryManager, + databaseUI, + localQueryResultsView, + queryStorageDir, + astViewer, + astTemplateProvider, + cfgTemplateProvider, +}: AstCfgOptions): AstCfgCommands { const viewAstCommand = async (selectedFile: Uri) => withProgress( async (progress, token) => @@ -79,29 +77,14 @@ export function registerAstCfgCommands( }, ); - ctx.subscriptions.push(commandRunner("codeQL.viewAst", viewAstCommand)); - - // Since we are tracking extension usage through commands, this command mirrors the "codeQL.viewAst" command - ctx.subscriptions.push( - commandRunner("codeQL.viewAstContextExplorer", viewAstCommand), - ); - - // Since we are tracking extension usage through commands, this command mirrors the "codeQL.viewAst" command - ctx.subscriptions.push( - commandRunner("codeQL.viewAstContextEditor", viewAstCommand), - ); - - ctx.subscriptions.push(commandRunner("codeQL.viewCfg", viewCfgCommand)); - - // Since we are tracking extension usage through commands, this command mirrors the "codeQL.viewCfg" command - ctx.subscriptions.push( - commandRunner("codeQL.viewCfgContextExplorer", viewCfgCommand), - ); - - // Since we are tracking extension usage through commands, this command mirrors the "codeQL.viewCfg" command - ctx.subscriptions.push( - commandRunner("codeQL.viewCfgContextEditor", viewCfgCommand), - ); + return { + "codeQL.viewAst": viewAstCommand, + "codeQL.viewAstContextExplorer": viewAstCommand, + "codeQL.viewAstContextEditor": viewAstCommand, + "codeQL.viewCfg": viewCfgCommand, + "codeQL.viewCfgContextExplorer": viewCfgCommand, + "codeQL.viewCfgContextEditor": viewCfgCommand, + }; } async function viewAst( diff --git a/extensions/ql-vscode/src/common/commands.ts b/extensions/ql-vscode/src/common/commands.ts index bc401234f..7826a21c1 100644 --- a/extensions/ql-vscode/src/common/commands.ts +++ b/extensions/ql-vscode/src/common/commands.ts @@ -123,11 +123,21 @@ export type DatabasePanelCommands = { "codeQLVariantAnalysisRepositories.removeItemContextMenu": SingleSelectionCommandFunction; }; +export type AstCfgCommands = { + "codeQL.viewAst": (selectedFile: Uri) => Promise; + "codeQL.viewAstContextExplorer": (selectedFile: Uri) => Promise; + "codeQL.viewAstContextEditor": (selectedFile: Uri) => Promise; + "codeQL.viewCfg": () => Promise; + "codeQL.viewCfgContextExplorer": () => Promise; + "codeQL.viewCfgContextEditor": () => Promise; +}; + export type AllCommands = BaseCommands & QueryHistoryCommands & LocalDatabasesCommands & VariantAnalysisCommands & - DatabasePanelCommands; + DatabasePanelCommands & + AstCfgCommands; export type AppCommandManager = CommandManager; diff --git a/extensions/ql-vscode/src/extension.ts b/extensions/ql-vscode/src/extension.ts index 89b70f52c..832237421 100644 --- a/extensions/ql-vscode/src/extension.ts +++ b/extensions/ql-vscode/src/extension.ts @@ -133,7 +133,7 @@ import { getLocalQueryCommands, showResultsForCompletedQuery, } from "./local-queries"; -import { registerAstCfgCommands } from "./ast-cfg-commands"; +import { getAstCfgCommands } from "./ast-cfg-commands"; /** * extension.ts @@ -651,6 +651,15 @@ async function activateWithInstalledDistribution( ); const queryStorageDir = join(ctx.globalStorageUri.fsPath, "queries"); await ensureDir(queryStorageDir); + + // Store contextual queries in a temporary folder so that they are removed + // when the application closes. There is no need for the user to interact with them. + const contextualQueryStorageDir = join( + tmpDir.name, + "contextual-query-storage", + ); + await ensureDir(contextualQueryStorageDir); + const labelProvider = new HistoryItemLabelProvider( queryHistoryConfigurationListener, ); @@ -787,6 +796,17 @@ async function activateWithInstalledDistribution( ctx.subscriptions.push(testUIService); } + const astViewer = new AstViewer(); + const astTemplateProvider = new TemplatePrintAstProvider( + cliServer, + qs, + dbm, + contextualQueryStorageDir, + ); + const cfgTemplateProvider = new TemplatePrintCfgProvider(cliServer, dbm); + + ctx.subscriptions.push(astViewer); + void extLogger.log("Registering top-level command palette commands."); const allCommands: AllCommands = { @@ -795,6 +815,16 @@ async function activateWithInstalledDistribution( ...variantAnalysisManager.getCommands(), ...databaseUI.getCommands(), ...dbModule.getCommands(), + ...getAstCfgCommands({ + queryRunner: qs, + queryHistoryManager: qhm, + databaseUI, + localQueryResultsView, + queryStorageDir, + astViewer, + astTemplateProvider, + cfgTemplateProvider, + }), }; for (const [commandName, command] of Object.entries(allCommands)) { @@ -1057,13 +1087,6 @@ async function activateWithInstalledDistribution( // Jump-to-definition and find-references void extLogger.log("Registering jump-to-definition handlers."); - // Store contextual queries in a temporary folder so that they are removed - // when the application closes. There is no need for the user to interact with them. - const contextualQueryStorageDir = join( - tmpDir.name, - "contextual-query-storage", - ); - await ensureDir(contextualQueryStorageDir); languages.registerDefinitionProvider( { scheme: zipArchiveScheme }, new TemplateQueryDefinitionProvider( @@ -1084,28 +1107,6 @@ async function activateWithInstalledDistribution( ), ); - const astViewer = new AstViewer(); - const astTemplateProvider = new TemplatePrintAstProvider( - cliServer, - qs, - dbm, - contextualQueryStorageDir, - ); - const cfgTemplateProvider = new TemplatePrintCfgProvider(cliServer, dbm); - - ctx.subscriptions.push(astViewer); - - registerAstCfgCommands(ctx, { - queryRunner: qs, - queryHistoryManager: qhm, - databaseUI, - localQueryResultsView, - queryStorageDir, - astViewer, - astTemplateProvider, - cfgTemplateProvider, - }); - const mockServer = new VSCodeMockGitHubApiServer(ctx); ctx.subscriptions.push(mockServer); ctx.subscriptions.push( From 17bab1c09cb1a16c7bf0e080c77cd7fc88e8ec8a Mon Sep 17 00:00:00 2001 From: Koen Vlaswinkel Date: Tue, 21 Mar 2023 16:10:05 +0100 Subject: [PATCH 108/156] Remove unnecessary viewAst function --- extensions/ql-vscode/src/ast-cfg-commands.ts | 51 +++++++------------- 1 file changed, 18 insertions(+), 33 deletions(-) diff --git a/extensions/ql-vscode/src/ast-cfg-commands.ts b/extensions/ql-vscode/src/ast-cfg-commands.ts index 2e5343ef4..1b1c8d583 100644 --- a/extensions/ql-vscode/src/ast-cfg-commands.ts +++ b/extensions/ql-vscode/src/ast-cfg-commands.ts @@ -1,5 +1,5 @@ -import { CancellationToken, Uri, window } from "vscode"; -import { ProgressCallback, withProgress } from "./commandRunner"; +import { Uri, window } from "vscode"; +import { withProgress } from "./commandRunner"; import { AstViewer } from "./astViewer"; import { TemplatePrintAstProvider, @@ -34,23 +34,25 @@ export function getAstCfgCommands({ astTemplateProvider, cfgTemplateProvider, }: AstCfgOptions): AstCfgCommands { - const viewAstCommand = async (selectedFile: Uri) => + const viewAst = async (selectedFile: Uri) => withProgress( - async (progress, token) => - await viewAst( - astViewer, - astTemplateProvider, + async (progress, token) => { + const ast = await astTemplateProvider.provideAst( progress, token, - selectedFile, - ), + selectedFile ?? window.activeTextEditor?.document.uri, + ); + if (ast) { + astViewer.updateRoots(await ast.getRoots(), ast.db, ast.fileName); + } + }, { cancellable: true, title: "Calculate AST", }, ); - const viewCfgCommand = async () => + const viewCfg = async () => withProgress( async (progress, token) => { const res = await cfgTemplateProvider.provideCfgUri( @@ -78,28 +80,11 @@ export function getAstCfgCommands({ ); return { - "codeQL.viewAst": viewAstCommand, - "codeQL.viewAstContextExplorer": viewAstCommand, - "codeQL.viewAstContextEditor": viewAstCommand, - "codeQL.viewCfg": viewCfgCommand, - "codeQL.viewCfgContextExplorer": viewCfgCommand, - "codeQL.viewCfgContextEditor": viewCfgCommand, + "codeQL.viewAst": viewAst, + "codeQL.viewAstContextExplorer": viewAst, + "codeQL.viewAstContextEditor": viewAst, + "codeQL.viewCfg": viewCfg, + "codeQL.viewCfgContextExplorer": viewCfg, + "codeQL.viewCfgContextEditor": viewCfg, }; } - -async function viewAst( - astViewer: AstViewer, - printAstTemplateProvider: TemplatePrintAstProvider, - progress: ProgressCallback, - token: CancellationToken, - selectedFile: Uri, -): Promise { - const ast = await printAstTemplateProvider.provideAst( - progress, - token, - selectedFile ?? window.activeTextEditor?.document.uri, - ); - if (ast) { - astViewer.updateRoots(await ast.getRoots(), ast.db, ast.fileName); - } -} From 168af11e009e4f61d2cc57fac5553217655cdd92 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Tue, 21 Mar 2023 16:27:58 +0000 Subject: [PATCH 109/156] Bump CLI version from v2.12.4 to v2.12.5 for integration tests (#2197) Co-authored-by: github-actions[bot] --- extensions/ql-vscode/supported_cli_versions.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/extensions/ql-vscode/supported_cli_versions.json b/extensions/ql-vscode/supported_cli_versions.json index 58b5b931d..124e33c2b 100644 --- a/extensions/ql-vscode/supported_cli_versions.json +++ b/extensions/ql-vscode/supported_cli_versions.json @@ -1,5 +1,5 @@ [ - "v2.12.4", + "v2.12.5", "v2.11.6", "v2.7.6", "v2.8.5", From ef267f87bb5941a8db90ad8d7a60e1b85cdfdba5 Mon Sep 17 00:00:00 2001 From: Koen Vlaswinkel Date: Tue, 21 Mar 2023 16:22:08 +0100 Subject: [PATCH 110/156] Move packaging command registration to separate file --- extensions/ql-vscode/src/extension.ts | 29 +++----------------- extensions/ql-vscode/src/packaging.ts | 39 +++++++++++++++++++++++++-- 2 files changed, 41 insertions(+), 27 deletions(-) diff --git a/extensions/ql-vscode/src/extension.ts b/extensions/ql-vscode/src/extension.ts index 52e805f86..c304d99c2 100644 --- a/extensions/ql-vscode/src/extension.ts +++ b/extensions/ql-vscode/src/extension.ts @@ -103,10 +103,7 @@ import { withProgress, } from "./commandRunner"; import { CodeQlStatusBarHandler } from "./status-bar"; -import { - handleDownloadPacks, - handleInstallPackDependencies, -} from "./packaging"; +import { registerPackagingCommands } from "./packaging"; import { HistoryItemLabelProvider } from "./query-history/history-item-label-provider"; import { exportSelectedVariantAnalysisResults } from "./variant-analysis/export-results"; import { EvalLogViewer } from "./eval-log-viewer"; @@ -1295,27 +1292,9 @@ async function activateWithInstalledDistribution( }), ); - ctx.subscriptions.push( - commandRunnerWithProgress( - "codeQL.installPackDependencies", - async (progress: ProgressCallback) => - await handleInstallPackDependencies(cliServer, progress), - { - title: "Installing pack dependencies", - }, - ), - ); - - ctx.subscriptions.push( - commandRunnerWithProgress( - "codeQL.downloadPacks", - async (progress: ProgressCallback) => - await handleDownloadPacks(cliServer, progress), - { - title: "Downloading packs", - }, - ), - ); + registerPackagingCommands(ctx, { + cliServer, + }); ctx.subscriptions.push( commandRunner("codeQL.showLogs", async () => { diff --git a/extensions/ql-vscode/src/packaging.ts b/extensions/ql-vscode/src/packaging.ts index c17621c09..43d9a99ad 100644 --- a/extensions/ql-vscode/src/packaging.ts +++ b/extensions/ql-vscode/src/packaging.ts @@ -4,13 +4,48 @@ import { showAndLogExceptionWithTelemetry, showAndLogInformationMessage, } from "./helpers"; -import { QuickPickItem, window } from "vscode"; -import { ProgressCallback, UserCancellationException } from "./commandRunner"; +import { ExtensionContext, QuickPickItem, window } from "vscode"; +import { + commandRunnerWithProgress, + ProgressCallback, + UserCancellationException, +} from "./commandRunner"; import { extLogger } from "./common"; import { asError, getErrorStack } from "./pure/helpers-pure"; import { redactableError } from "./pure/errors"; import { PACKS_BY_QUERY_LANGUAGE } from "./common/query-language"; +type PackagingOptions = { + cliServer: CodeQLCliServer; +}; + +export function registerPackagingCommands( + ctx: ExtensionContext, + { cliServer }: PackagingOptions, +) { + ctx.subscriptions.push( + commandRunnerWithProgress( + "codeQL.installPackDependencies", + async (progress: ProgressCallback) => + await handleInstallPackDependencies(cliServer, progress), + { + title: "Installing pack dependencies", + }, + ), + ); + + ctx.subscriptions.push( + commandRunnerWithProgress( + "codeQL.downloadPacks", + async (progress: ProgressCallback) => + await handleDownloadPacks(cliServer, progress), + { + title: "Downloading packs", + }, + ), + ); +} + /** * Prompts user to choose packs to download, and downloads them. * From dfff7ae8de54ef4ee16dae236ca65438b92215ab Mon Sep 17 00:00:00 2001 From: Koen Vlaswinkel Date: Tue, 21 Mar 2023 16:47:00 +0100 Subject: [PATCH 111/156] Move packaging commands to withProgress --- extensions/ql-vscode/src/packaging.ts | 33 +++++++++++++++------------ 1 file changed, 18 insertions(+), 15 deletions(-) diff --git a/extensions/ql-vscode/src/packaging.ts b/extensions/ql-vscode/src/packaging.ts index 43d9a99ad..355b539f8 100644 --- a/extensions/ql-vscode/src/packaging.ts +++ b/extensions/ql-vscode/src/packaging.ts @@ -6,9 +6,10 @@ import { } from "./helpers"; import { ExtensionContext, QuickPickItem, window } from "vscode"; import { - commandRunnerWithProgress, + commandRunner, ProgressCallback, UserCancellationException, + withProgress, } from "./commandRunner"; import { extLogger } from "./common"; import { asError, getErrorStack } from "./pure/helpers-pure"; @@ -24,24 +25,26 @@ export function registerPackagingCommands( { cliServer }: PackagingOptions, ) { ctx.subscriptions.push( - commandRunnerWithProgress( - "codeQL.installPackDependencies", - async (progress: ProgressCallback) => - await handleInstallPackDependencies(cliServer, progress), - { - title: "Installing pack dependencies", - }, + commandRunner("codeQL.installPackDependencies", async () => + withProgress( + async (progress: ProgressCallback) => + await handleInstallPackDependencies(cliServer, progress), + { + title: "Installing pack dependencies", + }, + ), ), ); ctx.subscriptions.push( - commandRunnerWithProgress( - "codeQL.downloadPacks", - async (progress: ProgressCallback) => - await handleDownloadPacks(cliServer, progress), - { - title: "Downloading packs", - }, + commandRunner("codeQL.downloadPacks", async () => + withProgress( + async (progress: ProgressCallback) => + await handleDownloadPacks(cliServer, progress), + { + title: "Downloading packs", + }, + ), ), ); } From 7c7a64ca5b6243aa5f86d3b3ad40c7e5b843d9c3 Mon Sep 17 00:00:00 2001 From: Koen Vlaswinkel Date: Tue, 21 Mar 2023 16:53:33 +0100 Subject: [PATCH 112/156] Convert packaging commands to typed commands --- extensions/ql-vscode/src/common/commands.ts | 8 ++++++- extensions/ql-vscode/src/extension.ts | 9 ++++---- extensions/ql-vscode/src/packaging.ts | 24 ++++++++------------- 3 files changed, 20 insertions(+), 21 deletions(-) diff --git a/extensions/ql-vscode/src/common/commands.ts b/extensions/ql-vscode/src/common/commands.ts index 00c68c472..d9863f43d 100644 --- a/extensions/ql-vscode/src/common/commands.ts +++ b/extensions/ql-vscode/src/common/commands.ts @@ -108,10 +108,16 @@ export type DatabasePanelCommands = { "codeQLVariantAnalysisRepositories.removeItemContextMenu": SingleSelectionCommandFunction; }; +export type PackagingCommands = { + "codeQL.installPackDependencies": () => Promise; + "codeQL.downloadPacks": () => Promise; +}; + export type AllCommands = BaseCommands & QueryHistoryCommands & LocalDatabasesCommands & VariantAnalysisCommands & - DatabasePanelCommands; + DatabasePanelCommands & + PackagingCommands; export type AppCommandManager = CommandManager; diff --git a/extensions/ql-vscode/src/extension.ts b/extensions/ql-vscode/src/extension.ts index c304d99c2..181dd77ab 100644 --- a/extensions/ql-vscode/src/extension.ts +++ b/extensions/ql-vscode/src/extension.ts @@ -103,7 +103,7 @@ import { withProgress, } from "./commandRunner"; import { CodeQlStatusBarHandler } from "./status-bar"; -import { registerPackagingCommands } from "./packaging"; +import { getPackagingCommands } from "./packaging"; import { HistoryItemLabelProvider } from "./query-history/history-item-label-provider"; import { exportSelectedVariantAnalysisResults } from "./variant-analysis/export-results"; import { EvalLogViewer } from "./eval-log-viewer"; @@ -1090,6 +1090,9 @@ async function activateWithInstalledDistribution( ...variantAnalysisManager.getCommands(), ...databaseUI.getCommands(), ...dbModule.getCommands(), + ...getPackagingCommands({ + cliServer, + }), }; for (const [commandName, command] of Object.entries(allCommands)) { @@ -1292,10 +1295,6 @@ async function activateWithInstalledDistribution( }), ); - registerPackagingCommands(ctx, { - cliServer, - }); - ctx.subscriptions.push( commandRunner("codeQL.showLogs", async () => { extLogger.show(); diff --git a/extensions/ql-vscode/src/packaging.ts b/extensions/ql-vscode/src/packaging.ts index 355b539f8..3a543173e 100644 --- a/extensions/ql-vscode/src/packaging.ts +++ b/extensions/ql-vscode/src/packaging.ts @@ -4,9 +4,8 @@ import { showAndLogExceptionWithTelemetry, showAndLogInformationMessage, } from "./helpers"; -import { ExtensionContext, QuickPickItem, window } from "vscode"; +import { QuickPickItem, window } from "vscode"; import { - commandRunner, ProgressCallback, UserCancellationException, withProgress, @@ -15,17 +14,17 @@ import { extLogger } from "./common"; import { asError, getErrorStack } from "./pure/helpers-pure"; import { redactableError } from "./pure/errors"; import { PACKS_BY_QUERY_LANGUAGE } from "./common/query-language"; +import { PackagingCommands } from "./common/commands"; type PackagingOptions = { cliServer: CodeQLCliServer; }; -export function registerPackagingCommands( - ctx: ExtensionContext, - { cliServer }: PackagingOptions, -) { - ctx.subscriptions.push( - commandRunner("codeQL.installPackDependencies", async () => +export function getPackagingCommands({ + cliServer, +}: PackagingOptions): PackagingCommands { + return { + "codeQL.installPackDependencies": async () => withProgress( async (progress: ProgressCallback) => await handleInstallPackDependencies(cliServer, progress), @@ -33,11 +32,7 @@ export function registerPackagingCommands( title: "Installing pack dependencies", }, ), - ), - ); - - ctx.subscriptions.push( - commandRunner("codeQL.downloadPacks", async () => + "codeQL.downloadPacks": async () => withProgress( async (progress: ProgressCallback) => await handleDownloadPacks(cliServer, progress), @@ -45,8 +40,7 @@ export function registerPackagingCommands( title: "Downloading packs", }, ), - ), - ); + }; } /** From 1c6d9f3f22a053108bd0cf06f68a2acee7879eca Mon Sep 17 00:00:00 2001 From: Koen Vlaswinkel Date: Wed, 22 Mar 2023 10:26:29 +0100 Subject: [PATCH 113/156] Use commandRunner for codeQL.restartQueryServer --- extensions/ql-vscode/src/extension.ts | 27 ++++++++++++++------------- 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/extensions/ql-vscode/src/extension.ts b/extensions/ql-vscode/src/extension.ts index 9d056431d..8900dd57c 100644 --- a/extensions/ql-vscode/src/extension.ts +++ b/extensions/ql-vscode/src/extension.ts @@ -1213,19 +1213,20 @@ async function activateWithInstalledDistribution( ); ctx.subscriptions.push( - commandRunnerWithProgress( - "codeQL.restartQueryServer", - async (progress: ProgressCallback, token: CancellationToken) => { - // We restart the CLI server too, to ensure they are the same version - cliServer.restartCliServer(); - await qs.restartQueryServer(progress, token); - void showAndLogInformationMessage("CodeQL Query Server restarted.", { - outputLogger: queryServerLogger, - }); - }, - { - title: "Restarting Query Server", - }, + commandRunner("codeQL.restartQueryServer", async () => + withProgress( + async (progress: ProgressCallback, token: CancellationToken) => { + // We restart the CLI server too, to ensure they are the same version + cliServer.restartCliServer(); + await qs.restartQueryServer(progress, token); + void showAndLogInformationMessage("CodeQL Query Server restarted.", { + outputLogger: queryServerLogger, + }); + }, + { + title: "Restarting Query Server", + }, + ), ), ); From 2c8c7cec8f64f972787ae509e94ce634283b379d Mon Sep 17 00:00:00 2001 From: Koen Vlaswinkel Date: Wed, 22 Mar 2023 10:29:09 +0100 Subject: [PATCH 114/156] Convert codeQL.restartQueryServer to a typed command --- extensions/ql-vscode/src/common/commands.ts | 2 ++ extensions/ql-vscode/src/extension.ts | 39 ++++++++++----------- 2 files changed, 21 insertions(+), 20 deletions(-) diff --git a/extensions/ql-vscode/src/common/commands.ts b/extensions/ql-vscode/src/common/commands.ts index 00c68c472..862b8caac 100644 --- a/extensions/ql-vscode/src/common/commands.ts +++ b/extensions/ql-vscode/src/common/commands.ts @@ -27,6 +27,8 @@ export type SingleSelectionCommandFunction = ( // Base commands not tied directly to a module like e.g. variant analysis. export type BaseCommands = { "codeQL.openDocumentation": () => Promise; + + "codeQL.restartQueryServer": () => Promise; }; // Commands used for the query history panel diff --git a/extensions/ql-vscode/src/extension.ts b/extensions/ql-vscode/src/extension.ts index 8900dd57c..67c52df34 100644 --- a/extensions/ql-vscode/src/extension.ts +++ b/extensions/ql-vscode/src/extension.ts @@ -169,11 +169,28 @@ const extension = extensions.getExtension(extensionId); /** * Return all commands that are not tied to the more specific managers. */ -function getCommands(): BaseCommands { +function getCommands( + cliServer: CodeQLCliServer, + queryRunner: QueryRunner, +): BaseCommands { return { "codeQL.openDocumentation": async () => { await env.openExternal(Uri.parse("https://codeql.github.com/docs/")); }, + "codeQL.restartQueryServer": async () => + withProgress( + async (progress: ProgressCallback, token: CancellationToken) => { + // We restart the CLI server too, to ensure they are the same version + cliServer.restartCliServer(); + await queryRunner.restartQueryServer(progress, token); + void showAndLogInformationMessage("CodeQL Query Server restarted.", { + outputLogger: queryServerLogger, + }); + }, + { + title: "Restarting Query Server", + }, + ), }; } @@ -1097,7 +1114,7 @@ async function activateWithInstalledDistribution( ); const allCommands: AllCommands = { - ...getCommands(), + ...getCommands(cliServer, qs), ...qhm.getCommands(), ...variantAnalysisManager.getCommands(), ...databaseUI.getCommands(), @@ -1212,24 +1229,6 @@ async function activateWithInstalledDistribution( }), ); - ctx.subscriptions.push( - commandRunner("codeQL.restartQueryServer", async () => - withProgress( - async (progress: ProgressCallback, token: CancellationToken) => { - // We restart the CLI server too, to ensure they are the same version - cliServer.restartCliServer(); - await qs.restartQueryServer(progress, token); - void showAndLogInformationMessage("CodeQL Query Server restarted.", { - outputLogger: queryServerLogger, - }); - }, - { - title: "Restarting Query Server", - }, - ), - ), - ); - ctx.subscriptions.push( commandRunnerWithProgress( "codeQL.chooseDatabaseFolder", From aa0d011daa40142d9dce6568bb06a8bd4ded4d4e Mon Sep 17 00:00:00 2001 From: Koen Vlaswinkel Date: Wed, 22 Mar 2023 11:34:39 +0100 Subject: [PATCH 115/156] Convert codeQLEvalLogViewer.clear to a typed command --- extensions/ql-vscode/src/common/commands.ts | 7 ++++++- extensions/ql-vscode/src/eval-log-viewer.ts | 13 +++++++------ extensions/ql-vscode/src/extension.ts | 1 + 3 files changed, 14 insertions(+), 7 deletions(-) diff --git a/extensions/ql-vscode/src/common/commands.ts b/extensions/ql-vscode/src/common/commands.ts index 00c68c472..5975705e5 100644 --- a/extensions/ql-vscode/src/common/commands.ts +++ b/extensions/ql-vscode/src/common/commands.ts @@ -108,10 +108,15 @@ export type DatabasePanelCommands = { "codeQLVariantAnalysisRepositories.removeItemContextMenu": SingleSelectionCommandFunction; }; +export type EvalLogViewerCommands = { + "codeQLEvalLogViewer.clear": () => Promise; +}; + export type AllCommands = BaseCommands & QueryHistoryCommands & LocalDatabasesCommands & VariantAnalysisCommands & - DatabasePanelCommands; + DatabasePanelCommands & + EvalLogViewerCommands; export type AppCommandManager = CommandManager; diff --git a/extensions/ql-vscode/src/eval-log-viewer.ts b/extensions/ql-vscode/src/eval-log-viewer.ts index c2f4b129b..b71d6c22f 100644 --- a/extensions/ql-vscode/src/eval-log-viewer.ts +++ b/extensions/ql-vscode/src/eval-log-viewer.ts @@ -8,11 +8,11 @@ import { EventEmitter, TreeItemCollapsibleState, } from "vscode"; -import { commandRunner } from "./commandRunner"; import { DisposableObject } from "./pure/disposable-object"; import { showAndLogExceptionWithTelemetry } from "./helpers"; import { asError, getErrorMessage } from "./pure/helpers-pure"; import { redactableError } from "./pure/errors"; +import { EvalLogViewerCommands } from "./common/commands"; export interface EvalLogTreeItem { label?: string; @@ -80,11 +80,12 @@ export class EvalLogViewer extends DisposableObject { this.push(this.treeView); this.push(this.treeDataProvider); - this.push( - commandRunner("codeQLEvalLogViewer.clear", async () => { - this.clear(); - }), - ); + } + + public getCommands(): EvalLogViewerCommands { + return { + "codeQLEvalLogViewer.clear": async () => this.clear(), + }; } private clear(): void { diff --git a/extensions/ql-vscode/src/extension.ts b/extensions/ql-vscode/src/extension.ts index 9d056431d..e3091eb39 100644 --- a/extensions/ql-vscode/src/extension.ts +++ b/extensions/ql-vscode/src/extension.ts @@ -1102,6 +1102,7 @@ async function activateWithInstalledDistribution( ...variantAnalysisManager.getCommands(), ...databaseUI.getCommands(), ...dbModule.getCommands(), + ...evalLogViewer.getCommands(), }; for (const [commandName, command] of Object.entries(allCommands)) { From 5af0ebcb2429b35d5b9b80ee07cb85829b62138f Mon Sep 17 00:00:00 2001 From: Robert Date: Wed, 22 Mar 2023 10:49:50 +0000 Subject: [PATCH 116/156] convert to type imports --- extensions/ql-vscode/src/common/commands.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/extensions/ql-vscode/src/common/commands.ts b/extensions/ql-vscode/src/common/commands.ts index 93f9f5b15..fd15cf087 100644 --- a/extensions/ql-vscode/src/common/commands.ts +++ b/extensions/ql-vscode/src/common/commands.ts @@ -2,8 +2,8 @@ import type { CommandManager } from "../packages/commands"; import type { Uri } from "vscode"; import type { DbTreeViewItem } from "../databases/ui/db-tree-view-item"; import type { QueryHistoryInfo } from "../query-history/query-history-info"; -import { RepositoriesFilterSortStateWithIds } from "../pure/variant-analysis-filter-sort"; -import { +import type { RepositoriesFilterSortStateWithIds } from "../pure/variant-analysis-filter-sort"; +import type { VariantAnalysis, VariantAnalysisScannedRepository, VariantAnalysisScannedRepositoryResult, From 0983733a67fca07d50d33248bdf3c340c2b6999f Mon Sep 17 00:00:00 2001 From: Robert Date: Wed, 22 Mar 2023 10:51:03 +0000 Subject: [PATCH 117/156] fix typo --- extensions/ql-vscode/src/common/commands.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/extensions/ql-vscode/src/common/commands.ts b/extensions/ql-vscode/src/common/commands.ts index 8d520d91f..6f2248000 100644 --- a/extensions/ql-vscode/src/common/commands.ts +++ b/extensions/ql-vscode/src/common/commands.ts @@ -59,7 +59,7 @@ export type QueryHistoryCommands = { "codeQLQueryHistory.openOnGithub": SelectionCommandFunction; "codeQLQueryHistory.copyRepoList": SelectionCommandFunction; - // Commands in the command pallete + // Commands in the command palette "codeQL.exportSelectedVariantAnalysisResults": () => Promise; }; From b914b97be79d8c8df7cce2f323f840c0b1c11f3c Mon Sep 17 00:00:00 2001 From: Robert Date: Mon, 20 Mar 2023 10:52:28 +0000 Subject: [PATCH 118/156] Pull progress to separate file --- extensions/ql-vscode/src/commandRunner.ts | 161 ++---------------- .../src/contextual/locationFinder.ts | 2 +- .../ql-vscode/src/contextual/queryResolver.ts | 2 +- .../src/contextual/templateProvider.ts | 2 +- extensions/ql-vscode/src/databaseFetcher.ts | 2 +- .../ql-vscode/src/databases/ui/db-panel.ts | 2 +- extensions/ql-vscode/src/distribution.ts | 2 +- extensions/ql-vscode/src/extension.ts | 8 +- extensions/ql-vscode/src/helpers.ts | 2 +- .../src/legacy-query-server/legacyRunner.ts | 2 +- .../legacy-query-server/queryserver-client.ts | 2 +- .../src/legacy-query-server/run-queries.ts | 2 +- .../src/legacy-query-server/upgrades.ts | 2 +- .../ql-vscode/src/local-databases-ui.ts | 2 +- extensions/ql-vscode/src/local-databases.ts | 2 +- extensions/ql-vscode/src/packaging.ts | 2 +- extensions/ql-vscode/src/progress.ts | 128 ++++++++++++++ .../src/query-server/query-runner.ts | 2 +- .../src/query-server/queryserver-client.ts | 2 +- .../ql-vscode/src/query-server/run-queries.ts | 2 +- extensions/ql-vscode/src/queryRunner.ts | 2 +- extensions/ql-vscode/src/quick-query.ts | 2 +- .../ql-vscode/src/run-queries-shared.ts | 2 +- extensions/ql-vscode/src/telemetry.ts | 2 +- .../src/variant-analysis/export-results.ts | 2 +- .../variant-analysis/repository-selection.ts | 2 +- .../src/variant-analysis/run-remote-query.ts | 2 +- .../variant-analysis-manager.ts | 2 +- 28 files changed, 169 insertions(+), 178 deletions(-) create mode 100644 extensions/ql-vscode/src/progress.ts diff --git a/extensions/ql-vscode/src/commandRunner.ts b/extensions/ql-vscode/src/commandRunner.ts index 7079723c1..ea1a84526 100644 --- a/extensions/ql-vscode/src/commandRunner.ts +++ b/extensions/ql-vscode/src/commandRunner.ts @@ -1,11 +1,4 @@ -import { - CancellationToken, - ProgressOptions as VSCodeProgressOptions, - window as Window, - commands, - Disposable, - ProgressLocation, -} from "vscode"; +import { CancellationToken, commands, Disposable } from "vscode"; import { showAndLogExceptionWithTelemetry, showAndLogWarningMessage, @@ -14,51 +7,22 @@ import { extLogger } from "./common"; import { asError, getErrorMessage, getErrorStack } from "./pure/helpers-pure"; import { telemetryListener } from "./telemetry"; import { redactableError } from "./pure/errors"; - -export class UserCancellationException extends Error { - /** - * @param message The error message - * @param silent If silent is true, then this exception will avoid showing a warning message to the user. - */ - constructor(message?: string, public readonly silent = false) { - super(message); - } -} - -export interface ProgressUpdate { - /** - * The current step - */ - step: number; - /** - * The maximum step. This *should* be constant for a single job. - */ - maxStep: number; - /** - * The current progress message - */ - message: string; -} - -export type ProgressCallback = (p: ProgressUpdate) => void; - -// Make certain properties within a type optional -type Optional = Pick, K> & Omit; - -export type ProgressOptions = Optional; +import { + UserCancellationException, + withProgress, + ProgressOptions, + ProgressCallback, +} from "./progress"; /** - * A task that reports progress. + * A task that handles command invocations from `commandRunner`. + * Arguments passed to the command handler are passed along, + * untouched to this `NoProgressTask` instance. * - * @param progress a progress handler function. Call this - * function with a `ProgressUpdate` instance in order to - * denote some progress being achieved on this task. - * @param token a cancellation token + * @param args arguments passed to this task passed on from + * `commands.registerCommand`. */ -export type ProgressTask = ( - progress: ProgressCallback, - token: CancellationToken, -) => Thenable; +export type NoProgressTask = (...args: any[]) => Promise; /** * A task that handles command invocations from `commandRunner` @@ -75,64 +39,12 @@ export type ProgressTask = ( * @param args arguments passed to this task passed on from * `commands.registerCommand`. */ -export type ProgressTaskWithArgs = ( +type ProgressTaskWithArgs = ( progress: ProgressCallback, token: CancellationToken, ...args: any[] ) => Thenable; -/** - * A task that handles command invocations from `commandRunner`. - * Arguments passed to the command handler are passed along, - * untouched to this `NoProgressTask` instance. - * - * @param args arguments passed to this task passed on from - * `commands.registerCommand`. - */ -export type NoProgressTask = (...args: any[]) => Promise; - -/** - * This mediates between the kind of progress callbacks we want to - * write (where we *set* current progress position and give - * `maxSteps`) and the kind vscode progress api expects us to write - * (which increment progress by a certain amount out of 100%). - * - * Where possible, the `commandRunner` function below should be used - * instead of this function. The commandRunner is meant for wrapping - * top-level commands and provides error handling and other support - * automatically. - * - * Only use this function if you need a progress monitor and the - * control flow does not always come from a command (eg- during - * extension activation, or from an internal language server - * request). - */ -export function withProgress( - task: ProgressTask, - { - location = ProgressLocation.Notification, - title, - cancellable, - }: ProgressOptions = {}, -): Thenable { - let progressAchieved = 0; - return Window.withProgress( - { - location, - title, - cancellable, - }, - (progress, token) => { - return task((p) => { - const { message, step, maxStep } = p; - const increment = (100 * (step - progressAchieved)) / maxStep; - progressAchieved = step; - progress.report({ message, increment }); - }, token); - }, - ); -} - /** * A generic wrapper for command registration. This wrapper adds uniform error handling for commands. * @@ -216,48 +128,3 @@ export function commandRunnerWithProgress( outputLogger, ); } - -/** - * Displays a progress monitor that indicates how much progess has been made - * reading from a stream. - * - * @param readable The stream to read progress from - * @param messagePrefix A prefix for displaying the message - * @param totalNumBytes Total number of bytes in this stream - * @param progress The progress callback used to set messages - */ -export function reportStreamProgress( - readable: NodeJS.ReadableStream, - messagePrefix: string, - totalNumBytes?: number, - progress?: ProgressCallback, -) { - if (progress && totalNumBytes) { - let numBytesDownloaded = 0; - const bytesToDisplayMB = (numBytes: number): string => - `${(numBytes / (1024 * 1024)).toFixed(1)} MB`; - const updateProgress = () => { - progress({ - step: numBytesDownloaded, - maxStep: totalNumBytes, - message: `${messagePrefix} [${bytesToDisplayMB( - numBytesDownloaded, - )} of ${bytesToDisplayMB(totalNumBytes)}]`, - }); - }; - - // Display the progress straight away rather than waiting for the first chunk. - updateProgress(); - - readable.on("data", (data) => { - numBytesDownloaded += data.length; - updateProgress(); - }); - } else if (progress) { - progress({ - step: 1, - maxStep: 2, - message: `${messagePrefix} (Size unknown)`, - }); - } -} diff --git a/extensions/ql-vscode/src/contextual/locationFinder.ts b/extensions/ql-vscode/src/contextual/locationFinder.ts index 86af86211..317861613 100644 --- a/extensions/ql-vscode/src/contextual/locationFinder.ts +++ b/extensions/ql-vscode/src/contextual/locationFinder.ts @@ -11,7 +11,7 @@ import { import { CodeQLCliServer } from "../cli"; import { DatabaseManager, DatabaseItem } from "../local-databases"; import fileRangeFromURI from "./fileRangeFromURI"; -import { ProgressCallback } from "../commandRunner"; +import { ProgressCallback } from "../progress"; import { KeyType } from "./keyType"; import { qlpackOfDatabase, diff --git a/extensions/ql-vscode/src/contextual/queryResolver.ts b/extensions/ql-vscode/src/contextual/queryResolver.ts index 550d1b6b4..40cf87cc6 100644 --- a/extensions/ql-vscode/src/contextual/queryResolver.ts +++ b/extensions/ql-vscode/src/contextual/queryResolver.ts @@ -16,7 +16,7 @@ import { DatabaseItem } from "../local-databases"; import { extLogger } from "../common"; import { createInitialQueryInfo } from "../run-queries-shared"; import { CancellationToken, Uri } from "vscode"; -import { ProgressCallback } from "../commandRunner"; +import { ProgressCallback } from "../progress"; import { QueryRunner } from "../queryRunner"; import { redactableError } from "../pure/errors"; import { QLPACK_FILENAMES } from "../pure/ql"; diff --git a/extensions/ql-vscode/src/contextual/templateProvider.ts b/extensions/ql-vscode/src/contextual/templateProvider.ts index 4b53146d4..ddc23346c 100644 --- a/extensions/ql-vscode/src/contextual/templateProvider.ts +++ b/extensions/ql-vscode/src/contextual/templateProvider.ts @@ -18,7 +18,7 @@ import { import { CodeQLCliServer } from "../cli"; import { DatabaseManager } from "../local-databases"; import { CachedOperation } from "../helpers"; -import { ProgressCallback, withProgress } from "../commandRunner"; +import { ProgressCallback, withProgress } from "../progress"; import AstBuilder from "./astBuilder"; import { KeyType } from "./keyType"; import { diff --git a/extensions/ql-vscode/src/databaseFetcher.ts b/extensions/ql-vscode/src/databaseFetcher.ts index 1e31e7857..ac63fffbb 100644 --- a/extensions/ql-vscode/src/databaseFetcher.ts +++ b/extensions/ql-vscode/src/databaseFetcher.ts @@ -18,7 +18,7 @@ import { retry } from "@octokit/plugin-retry"; import { DatabaseManager, DatabaseItem } from "./local-databases"; import { showAndLogInformationMessage, tmpDir } from "./helpers"; -import { reportStreamProgress, ProgressCallback } from "./commandRunner"; +import { reportStreamProgress, ProgressCallback } from "./progress"; import { extLogger } from "./common"; import { getErrorMessage } from "./pure/helpers-pure"; import { diff --git a/extensions/ql-vscode/src/databases/ui/db-panel.ts b/extensions/ql-vscode/src/databases/ui/db-panel.ts index c2dec3897..7df235347 100644 --- a/extensions/ql-vscode/src/databases/ui/db-panel.ts +++ b/extensions/ql-vscode/src/databases/ui/db-panel.ts @@ -7,7 +7,7 @@ import { window, workspace, } from "vscode"; -import { UserCancellationException } from "../../commandRunner"; +import { UserCancellationException } from "../../progress"; import { getNwoFromGitHubUrl, isValidGitHubNwo, diff --git a/extensions/ql-vscode/src/distribution.ts b/extensions/ql-vscode/src/distribution.ts index 119c82244..017da698d 100644 --- a/extensions/ql-vscode/src/distribution.ts +++ b/extensions/ql-vscode/src/distribution.ts @@ -14,7 +14,7 @@ import { } from "./helpers"; import { extLogger } from "./common"; import { getCodeQlCliVersion } from "./cli-version"; -import { ProgressCallback, reportStreamProgress } from "./commandRunner"; +import { ProgressCallback, reportStreamProgress } from "./progress"; import { codeQlLauncherName, deprecatedCodeQlLauncherName, diff --git a/extensions/ql-vscode/src/extension.ts b/extensions/ql-vscode/src/extension.ts index ba78230be..6f4279fcd 100644 --- a/extensions/ql-vscode/src/extension.ts +++ b/extensions/ql-vscode/src/extension.ts @@ -89,12 +89,8 @@ import { QLTestAdapterFactory } from "./test-adapter"; import { TestUIService } from "./test-ui"; import { CompareView } from "./compare/compare-view"; import { initializeTelemetry } from "./telemetry"; -import { - commandRunner, - commandRunnerWithProgress, - ProgressCallback, - withProgress, -} from "./commandRunner"; +import { commandRunner, commandRunnerWithProgress } from "./commandRunner"; +import { ProgressCallback, withProgress } from "./progress"; import { CodeQlStatusBarHandler } from "./status-bar"; import { getPackagingCommands } from "./packaging"; import { HistoryItemLabelProvider } from "./query-history/history-item-label-provider"; diff --git a/extensions/ql-vscode/src/helpers.ts b/extensions/ql-vscode/src/helpers.ts index 512c77fcf..33f5abd45 100644 --- a/extensions/ql-vscode/src/helpers.ts +++ b/extensions/ql-vscode/src/helpers.ts @@ -19,7 +19,7 @@ import { commands, } from "vscode"; import { CodeQLCliServer, QlpacksInfo } from "./cli"; -import { UserCancellationException } from "./commandRunner"; +import { UserCancellationException } from "./progress"; import { extLogger, OutputChannelLogger } from "./common"; import { QueryMetadata } from "./pure/interface-types"; import { telemetryListener } from "./telemetry"; diff --git a/extensions/ql-vscode/src/legacy-query-server/legacyRunner.ts b/extensions/ql-vscode/src/legacy-query-server/legacyRunner.ts index 44eba17d9..f12434822 100644 --- a/extensions/ql-vscode/src/legacy-query-server/legacyRunner.ts +++ b/extensions/ql-vscode/src/legacy-query-server/legacyRunner.ts @@ -1,5 +1,5 @@ import { CancellationToken } from "vscode"; -import { ProgressCallback } from "../commandRunner"; +import { ProgressCallback } from "../progress"; import { DatabaseItem } from "../local-databases"; import { Dataset, diff --git a/extensions/ql-vscode/src/legacy-query-server/queryserver-client.ts b/extensions/ql-vscode/src/legacy-query-server/queryserver-client.ts index 3cec4d0e7..25e60db23 100644 --- a/extensions/ql-vscode/src/legacy-query-server/queryserver-client.ts +++ b/extensions/ql-vscode/src/legacy-query-server/queryserver-client.ts @@ -13,7 +13,7 @@ import { ProgressMessage, WithProgressId, } from "../pure/legacy-messages"; -import { ProgressCallback, ProgressTask } from "../commandRunner"; +import { ProgressCallback, ProgressTask } from "../progress"; import { ServerProcess } from "../json-rpc-server"; type WithProgressReporting = ( diff --git a/extensions/ql-vscode/src/legacy-query-server/run-queries.ts b/extensions/ql-vscode/src/legacy-query-server/run-queries.ts index a60f8da49..e2f3fb5f5 100644 --- a/extensions/ql-vscode/src/legacy-query-server/run-queries.ts +++ b/extensions/ql-vscode/src/legacy-query-server/run-queries.ts @@ -13,7 +13,7 @@ import { tryGetQueryMetadata, upgradesTmpDir, } from "../helpers"; -import { ProgressCallback } from "../commandRunner"; +import { ProgressCallback } from "../progress"; import { QueryMetadata } from "../pure/interface-types"; import { extLogger, Logger, TeeLogger } from "../common"; import * as messages from "../pure/legacy-messages"; diff --git a/extensions/ql-vscode/src/legacy-query-server/upgrades.ts b/extensions/ql-vscode/src/legacy-query-server/upgrades.ts index 0ec182766..6b70bf58b 100644 --- a/extensions/ql-vscode/src/legacy-query-server/upgrades.ts +++ b/extensions/ql-vscode/src/legacy-query-server/upgrades.ts @@ -4,7 +4,7 @@ import { showAndLogExceptionWithTelemetry, tmpDir, } from "../helpers"; -import { ProgressCallback, UserCancellationException } from "../commandRunner"; +import { ProgressCallback, UserCancellationException } from "../progress"; import { extLogger } from "../common"; import * as messages from "../pure/legacy-messages"; import * as qsClient from "./queryserver-client"; diff --git a/extensions/ql-vscode/src/local-databases-ui.ts b/extensions/ql-vscode/src/local-databases-ui.ts index c12081221..81bf64097 100644 --- a/extensions/ql-vscode/src/local-databases-ui.ts +++ b/extensions/ql-vscode/src/local-databases-ui.ts @@ -21,7 +21,7 @@ import { DatabaseItem, DatabaseManager, } from "./local-databases"; -import { ProgressCallback, withProgress } from "./commandRunner"; +import { ProgressCallback, withProgress } from "./progress"; import { isLikelyDatabaseRoot, isLikelyDbLanguageFolder, diff --git a/extensions/ql-vscode/src/local-databases.ts b/extensions/ql-vscode/src/local-databases.ts index 9542ef767..3d390b472 100644 --- a/extensions/ql-vscode/src/local-databases.ts +++ b/extensions/ql-vscode/src/local-databases.ts @@ -12,7 +12,7 @@ import { isFolderAlreadyInWorkspace, showBinaryChoiceDialog, } from "./helpers"; -import { ProgressCallback, withProgress } from "./commandRunner"; +import { ProgressCallback, withProgress } from "./progress"; import { zipArchiveScheme, encodeArchiveBasePath, diff --git a/extensions/ql-vscode/src/packaging.ts b/extensions/ql-vscode/src/packaging.ts index 3a543173e..64196d48c 100644 --- a/extensions/ql-vscode/src/packaging.ts +++ b/extensions/ql-vscode/src/packaging.ts @@ -9,7 +9,7 @@ import { ProgressCallback, UserCancellationException, withProgress, -} from "./commandRunner"; +} from "./progress"; import { extLogger } from "./common"; import { asError, getErrorStack } from "./pure/helpers-pure"; import { redactableError } from "./pure/errors"; diff --git a/extensions/ql-vscode/src/progress.ts b/extensions/ql-vscode/src/progress.ts new file mode 100644 index 000000000..45758e39f --- /dev/null +++ b/extensions/ql-vscode/src/progress.ts @@ -0,0 +1,128 @@ +import { + CancellationToken, + ProgressLocation, + ProgressOptions as VSCodeProgressOptions, + window as Window, +} from "vscode"; + +export class UserCancellationException extends Error { + /** + * @param message The error message + * @param silent If silent is true, then this exception will avoid showing a warning message to the user. + */ + constructor(message?: string, public readonly silent = false) { + super(message); + } +} + +export interface ProgressUpdate { + /** + * The current step + */ + step: number; + /** + * The maximum step. This *should* be constant for a single job. + */ + maxStep: number; + /** + * The current progress message + */ + message: string; +} + +export type ProgressCallback = (p: ProgressUpdate) => void; + +// Make certain properties within a type optional +type Optional = Pick, K> & Omit; + +export type ProgressOptions = Optional; + +/** + * A task that reports progress. + * + * @param progress a progress handler function. Call this + * function with a `ProgressUpdate` instance in order to + * denote some progress being achieved on this task. + * @param token a cancellation token + */ +export type ProgressTask = ( + progress: ProgressCallback, + token: CancellationToken, +) => Thenable; + +/** + * This mediates between the kind of progress callbacks we want to + * write (where we *set* current progress position and give + * `maxSteps`) and the kind vscode progress api expects us to write + * (which increment progress by a certain amount out of 100%). + */ +export function withProgress( + task: ProgressTask, + { + location = ProgressLocation.Notification, + title, + cancellable, + }: ProgressOptions = {}, +): Thenable { + let progressAchieved = 0; + return Window.withProgress( + { + location, + title, + cancellable, + }, + (progress, token) => { + return task((p) => { + const { message, step, maxStep } = p; + const increment = (100 * (step - progressAchieved)) / maxStep; + progressAchieved = step; + progress.report({ message, increment }); + }, token); + }, + ); +} + +/** + * Displays a progress monitor that indicates how much progess has been made + * reading from a stream. + * + * @param readable The stream to read progress from + * @param messagePrefix A prefix for displaying the message + * @param totalNumBytes Total number of bytes in this stream + * @param progress The progress callback used to set messages + */ +export function reportStreamProgress( + readable: NodeJS.ReadableStream, + messagePrefix: string, + totalNumBytes?: number, + progress?: ProgressCallback, +) { + if (progress && totalNumBytes) { + let numBytesDownloaded = 0; + const bytesToDisplayMB = (numBytes: number): string => + `${(numBytes / (1024 * 1024)).toFixed(1)} MB`; + const updateProgress = () => { + progress({ + step: numBytesDownloaded, + maxStep: totalNumBytes, + message: `${messagePrefix} [${bytesToDisplayMB( + numBytesDownloaded, + )} of ${bytesToDisplayMB(totalNumBytes)}]`, + }); + }; + + // Display the progress straight away rather than waiting for the first chunk. + updateProgress(); + + readable.on("data", (data) => { + numBytesDownloaded += data.length; + updateProgress(); + }); + } else if (progress) { + progress({ + step: 1, + maxStep: 2, + message: `${messagePrefix} (Size unknown)`, + }); + } +} diff --git a/extensions/ql-vscode/src/query-server/query-runner.ts b/extensions/ql-vscode/src/query-server/query-runner.ts index d80a07cbc..ebb90907b 100644 --- a/extensions/ql-vscode/src/query-server/query-runner.ts +++ b/extensions/ql-vscode/src/query-server/query-runner.ts @@ -1,5 +1,5 @@ import { CancellationToken } from "vscode"; -import { ProgressCallback, UserCancellationException } from "../commandRunner"; +import { ProgressCallback, UserCancellationException } from "../progress"; import { DatabaseItem } from "../local-databases"; import { clearCache, diff --git a/extensions/ql-vscode/src/query-server/queryserver-client.ts b/extensions/ql-vscode/src/query-server/queryserver-client.ts index 80bda904c..428526299 100644 --- a/extensions/ql-vscode/src/query-server/queryserver-client.ts +++ b/extensions/ql-vscode/src/query-server/queryserver-client.ts @@ -11,7 +11,7 @@ import { ProgressMessage, WithProgressId, } from "../pure/new-messages"; -import { ProgressCallback, ProgressTask } from "../commandRunner"; +import { ProgressCallback, ProgressTask } from "../progress"; import { ServerProcess } from "../json-rpc-server"; type ServerOpts = { diff --git a/extensions/ql-vscode/src/query-server/run-queries.ts b/extensions/ql-vscode/src/query-server/run-queries.ts index f63203d89..a08680cc4 100644 --- a/extensions/ql-vscode/src/query-server/run-queries.ts +++ b/extensions/ql-vscode/src/query-server/run-queries.ts @@ -1,7 +1,7 @@ import { join } from "path"; import { CancellationToken } from "vscode"; import * as cli from "../cli"; -import { ProgressCallback } from "../commandRunner"; +import { ProgressCallback } from "../progress"; import { DatabaseItem } from "../local-databases"; import { getOnDiskWorkspaceFolders, diff --git a/extensions/ql-vscode/src/queryRunner.ts b/extensions/ql-vscode/src/queryRunner.ts index a2e92ee66..0ef8058e5 100644 --- a/extensions/ql-vscode/src/queryRunner.ts +++ b/extensions/ql-vscode/src/queryRunner.ts @@ -1,6 +1,6 @@ import { CancellationToken } from "vscode"; import { CodeQLCliServer } from "./cli"; -import { ProgressCallback } from "./commandRunner"; +import { ProgressCallback } from "./progress"; import { DatabaseItem } from "./local-databases"; import { InitialQueryInfo, LocalQueryInfo } from "./query-results"; import { QueryWithResults } from "./run-queries-shared"; diff --git a/extensions/ql-vscode/src/quick-query.ts b/extensions/ql-vscode/src/quick-query.ts index ca0e0ae65..47c3ca3a9 100644 --- a/extensions/ql-vscode/src/quick-query.ts +++ b/extensions/ql-vscode/src/quick-query.ts @@ -11,7 +11,7 @@ import { getQlPackForDbscheme, showBinaryChoiceDialog, } from "./helpers"; -import { ProgressCallback, UserCancellationException } from "./commandRunner"; +import { ProgressCallback, UserCancellationException } from "./progress"; import { getErrorMessage } from "./pure/helpers-pure"; import { FALLBACK_QLPACK_FILENAME, getQlPackPath } from "./pure/ql"; import { App } from "./common/app"; diff --git a/extensions/ql-vscode/src/run-queries-shared.ts b/extensions/ql-vscode/src/run-queries-shared.ts index 4ee8588fb..da4b7e86c 100644 --- a/extensions/ql-vscode/src/run-queries-shared.ts +++ b/extensions/ql-vscode/src/run-queries-shared.ts @@ -12,7 +12,7 @@ import { window, } from "vscode"; import { isCanary, AUTOSAVE_SETTING } from "./config"; -import { UserCancellationException } from "./commandRunner"; +import { UserCancellationException } from "./progress"; import { pathExists, readFile, diff --git a/extensions/ql-vscode/src/telemetry.ts b/extensions/ql-vscode/src/telemetry.ts index 4c4cd79d2..6062cb345 100644 --- a/extensions/ql-vscode/src/telemetry.ts +++ b/extensions/ql-vscode/src/telemetry.ts @@ -16,7 +16,7 @@ import { } from "./config"; import * as appInsights from "applicationinsights"; import { extLogger } from "./common"; -import { UserCancellationException } from "./commandRunner"; +import { UserCancellationException } from "./progress"; import { showBinaryChoiceWithUrlDialog } from "./helpers"; import { RedactableError } from "./pure/errors"; diff --git a/extensions/ql-vscode/src/variant-analysis/export-results.ts b/extensions/ql-vscode/src/variant-analysis/export-results.ts index 472b914df..a866436b7 100644 --- a/extensions/ql-vscode/src/variant-analysis/export-results.ts +++ b/extensions/ql-vscode/src/variant-analysis/export-results.ts @@ -13,7 +13,7 @@ import { ProgressCallback, UserCancellationException, withProgress, -} from "../commandRunner"; +} from "../progress"; import { showInformationMessageWithAction } from "../helpers"; import { extLogger } from "../common"; import { createGist } from "./gh-api/gh-api-client"; diff --git a/extensions/ql-vscode/src/variant-analysis/repository-selection.ts b/extensions/ql-vscode/src/variant-analysis/repository-selection.ts index 59f0b7b7b..b8ddcdb51 100644 --- a/extensions/ql-vscode/src/variant-analysis/repository-selection.ts +++ b/extensions/ql-vscode/src/variant-analysis/repository-selection.ts @@ -1,4 +1,4 @@ -import { UserCancellationException } from "../commandRunner"; +import { UserCancellationException } from "../progress"; import { DbManager } from "../databases/db-manager"; import { DbItemKind } from "../databases/db-item"; diff --git a/extensions/ql-vscode/src/variant-analysis/run-remote-query.ts b/extensions/ql-vscode/src/variant-analysis/run-remote-query.ts index 2eb1d8a1b..6b9565a99 100644 --- a/extensions/ql-vscode/src/variant-analysis/run-remote-query.ts +++ b/extensions/ql-vscode/src/variant-analysis/run-remote-query.ts @@ -18,7 +18,7 @@ import { getRemoteControllerRepo, setRemoteControllerRepo, } from "../config"; -import { ProgressCallback, UserCancellationException } from "../commandRunner"; +import { ProgressCallback, UserCancellationException } from "../progress"; import { RequestError } from "@octokit/types/dist-types"; import { QueryMetadata } from "../pure/interface-types"; import { getErrorMessage, REPO_REGEX } from "../pure/helpers-pure"; diff --git a/extensions/ql-vscode/src/variant-analysis/variant-analysis-manager.ts b/extensions/ql-vscode/src/variant-analysis/variant-analysis-manager.ts index af4eea987..276a3af36 100644 --- a/extensions/ql-vscode/src/variant-analysis/variant-analysis-manager.ts +++ b/extensions/ql-vscode/src/variant-analysis/variant-analysis-manager.ts @@ -55,7 +55,7 @@ import { ProgressCallback, UserCancellationException, withProgress, -} from "../commandRunner"; +} from "../progress"; import { CodeQLCliServer } from "../cli"; import { defaultFilterSortState, From bc29231fecef2807dadfd8050fcd2bf6dd81058b Mon Sep 17 00:00:00 2001 From: Koen Vlaswinkel Date: Wed, 22 Mar 2023 14:11:43 +0100 Subject: [PATCH 119/156] Convert AST viewer commands to typed commands --- extensions/ql-vscode/src/astViewer.ts | 25 +++++++++------------ extensions/ql-vscode/src/common/commands.ts | 7 ++++++ extensions/ql-vscode/src/extension.ts | 1 + 3 files changed, 18 insertions(+), 15 deletions(-) diff --git a/extensions/ql-vscode/src/astViewer.ts b/extensions/ql-vscode/src/astViewer.ts index 3c5d2bdf8..5105439f8 100644 --- a/extensions/ql-vscode/src/astViewer.ts +++ b/extensions/ql-vscode/src/astViewer.ts @@ -23,11 +23,11 @@ import { isWholeFileLoc, isLineColumnLoc, } from "./pure/bqrs-utils"; -import { commandRunner } from "./commandRunner"; import { DisposableObject } from "./pure/disposable-object"; import { showAndLogExceptionWithTelemetry } from "./helpers"; import { asError, getErrorMessage } from "./pure/helpers-pure"; import { redactableError } from "./pure/errors"; +import { AstViewerCommands } from "./common/commands"; export interface AstItem { id: BqrsId; @@ -55,15 +55,6 @@ class AstViewerDataProvider readonly onDidChangeTreeData: Event = this._onDidChangeTreeData.event; - constructor() { - super(); - this.push( - commandRunner("codeQLAstViewer.gotoCode", async (item: AstItem) => { - await showLocation(item.fileLocation); - }), - ); - } - refresh(): void { this._onDidChangeTreeData.fire(undefined); } @@ -126,16 +117,20 @@ export class AstViewer extends DisposableObject { this.push(this.treeView); this.push(this.treeDataProvider); - this.push( - commandRunner("codeQLAstViewer.clear", async () => { - this.clear(); - }), - ); this.push( window.onDidChangeTextEditorSelection(this.updateTreeSelection, this), ); } + getCommands(): AstViewerCommands { + return { + "codeQLAstViewer.clear": async () => this.clear(), + "codeQLAstViewer.gotoCode": async (item: AstItem) => { + await showLocation(item.fileLocation); + }, + }; + } + updateRoots(roots: AstItem[], db: DatabaseItem, fileUri: Uri) { this.treeDataProvider.roots = roots; this.treeDataProvider.db = db; diff --git a/extensions/ql-vscode/src/common/commands.ts b/extensions/ql-vscode/src/common/commands.ts index ff52f56a9..0bc97686e 100644 --- a/extensions/ql-vscode/src/common/commands.ts +++ b/extensions/ql-vscode/src/common/commands.ts @@ -1,5 +1,6 @@ import type { CommandManager } from "../packages/commands"; import type { Uri, Range } from "vscode"; +import type { AstItem } from "../astViewer"; import type { DbTreeViewItem } from "../databases/ui/db-tree-view-item"; import type { DatabaseItem } from "../local-databases"; import type { QueryHistoryInfo } from "../query-history/query-history-info"; @@ -176,6 +177,11 @@ export type AstCfgCommands = { "codeQL.viewCfgContextEditor": () => Promise; }; +export type AstViewerCommands = { + "codeQLAstViewer.clear": () => Promise; + "codeQLAstViewer.gotoCode": (item: AstItem) => Promise; +}; + export type PackagingCommands = { "codeQL.installPackDependencies": () => Promise; "codeQL.downloadPacks": () => Promise; @@ -191,6 +197,7 @@ export type AllCommands = BaseCommands & VariantAnalysisCommands & DatabasePanelCommands & AstCfgCommands & + AstViewerCommands & PackagingCommands & EvalLogViewerCommands; diff --git a/extensions/ql-vscode/src/extension.ts b/extensions/ql-vscode/src/extension.ts index 7d3653296..78cb8c765 100644 --- a/extensions/ql-vscode/src/extension.ts +++ b/extensions/ql-vscode/src/extension.ts @@ -837,6 +837,7 @@ async function activateWithInstalledDistribution( astTemplateProvider, cfgTemplateProvider, }), + ...astViewer.getCommands(), ...getPackagingCommands({ cliServer, }), From 1f8070c8b514f1a4221dec3dfc5358cd47291436 Mon Sep 17 00:00:00 2001 From: Koen Vlaswinkel Date: Wed, 22 Mar 2023 14:26:06 +0100 Subject: [PATCH 120/156] Convert summary language commands to typed commands --- extensions/ql-vscode/src/common/commands.ts | 7 ++++++- extensions/ql-vscode/src/extension.ts | 6 ++++-- .../src/log-insights/summary-language-support.ts | 8 ++++++-- 3 files changed, 16 insertions(+), 5 deletions(-) diff --git a/extensions/ql-vscode/src/common/commands.ts b/extensions/ql-vscode/src/common/commands.ts index ff52f56a9..ec85692dc 100644 --- a/extensions/ql-vscode/src/common/commands.ts +++ b/extensions/ql-vscode/src/common/commands.ts @@ -185,6 +185,10 @@ export type EvalLogViewerCommands = { "codeQLEvalLogViewer.clear": () => Promise; }; +export type SummaryLanguageSupportCommands = { + "codeQL.gotoQL": () => Promise; +}; + export type AllCommands = BaseCommands & QueryHistoryCommands & LocalDatabasesCommands & @@ -192,7 +196,8 @@ export type AllCommands = BaseCommands & DatabasePanelCommands & AstCfgCommands & PackagingCommands & - EvalLogViewerCommands; + EvalLogViewerCommands & + SummaryLanguageSupportCommands; export type AppCommandManager = CommandManager; diff --git a/extensions/ql-vscode/src/extension.ts b/extensions/ql-vscode/src/extension.ts index 7d3653296..753f072cd 100644 --- a/extensions/ql-vscode/src/extension.ts +++ b/extensions/ql-vscode/src/extension.ts @@ -819,6 +819,9 @@ async function activateWithInstalledDistribution( ctx.subscriptions.push(astViewer); + const summaryLanguageSupport = new SummaryLanguageSupport(); + ctx.subscriptions.push(summaryLanguageSupport); + void extLogger.log("Registering top-level command palette commands."); const allCommands: AllCommands = { @@ -841,6 +844,7 @@ async function activateWithInstalledDistribution( cliServer, }), ...evalLogViewer.getCommands(), + ...summaryLanguageSupport.getCommands(), }; for (const [commandName, command] of Object.entries(allCommands)) { @@ -937,8 +941,6 @@ async function activateWithInstalledDistribution( }), ); - ctx.subscriptions.push(new SummaryLanguageSupport()); - void extLogger.log("Starting language server."); await client.start(); ctx.subscriptions.push({ diff --git a/extensions/ql-vscode/src/log-insights/summary-language-support.ts b/extensions/ql-vscode/src/log-insights/summary-language-support.ts index c7968ba97..b6920fa30 100644 --- a/extensions/ql-vscode/src/log-insights/summary-language-support.ts +++ b/extensions/ql-vscode/src/log-insights/summary-language-support.ts @@ -13,9 +13,9 @@ import { workspace, } from "vscode"; import { DisposableObject } from "../pure/disposable-object"; -import { commandRunner } from "../commandRunner"; import { extLogger } from "../common"; import { getErrorMessage } from "../pure/helpers-pure"; +import { SummaryLanguageSupportCommands } from "../common/commands"; /** A `Position` within a specified file on disk. */ interface PositionInFile { @@ -73,8 +73,12 @@ export class SummaryLanguageSupport extends DisposableObject { this.handleDidCloseTextDocument.bind(this), ), ); + } - this.push(commandRunner("codeQL.gotoQL", this.handleGotoQL.bind(this))); + public getCommands(): SummaryLanguageSupportCommands { + return { + "codeQL.gotoQL": this.handleGotoQL.bind(this), + }; } /** From ac57f5005d82cf00712ff8e6ffb57f348df1871e Mon Sep 17 00:00:00 2001 From: Koen Vlaswinkel Date: Wed, 22 Mar 2023 15:06:15 +0100 Subject: [PATCH 121/156] Convert results view commands to typed commands --- extensions/ql-vscode/src/common/commands.ts | 10 +++++ extensions/ql-vscode/src/extension.ts | 1 + extensions/ql-vscode/src/interface.ts | 47 ++++++++++++++------- 3 files changed, 42 insertions(+), 16 deletions(-) diff --git a/extensions/ql-vscode/src/common/commands.ts b/extensions/ql-vscode/src/common/commands.ts index 88ed7d44a..03e4d41a1 100644 --- a/extensions/ql-vscode/src/common/commands.ts +++ b/extensions/ql-vscode/src/common/commands.ts @@ -53,6 +53,15 @@ export type LocalQueryCommands = { "codeQL.quickQuery": () => Promise; }; +export type ResultsViewCommands = { + "codeQLQueryResults.up": () => Promise; + "codeQLQueryResults.down": () => Promise; + "codeQLQueryResults.left": () => Promise; + "codeQLQueryResults.right": () => Promise; + "codeQLQueryResults.nextPathStep": () => Promise; + "codeQLQueryResults.previousPathStep": () => Promise; +}; + // Commands used for the query history panel export type QueryHistoryCommands = { // Commands in the "navigation" group @@ -196,6 +205,7 @@ export type SummaryLanguageSupportCommands = { }; export type AllCommands = BaseCommands & + ResultsViewCommands & QueryHistoryCommands & LocalDatabasesCommands & VariantAnalysisCommands & diff --git a/extensions/ql-vscode/src/extension.ts b/extensions/ql-vscode/src/extension.ts index e6a24f47f..812ddc5dc 100644 --- a/extensions/ql-vscode/src/extension.ts +++ b/extensions/ql-vscode/src/extension.ts @@ -826,6 +826,7 @@ async function activateWithInstalledDistribution( const allCommands: AllCommands = { ...getCommands(cliServer, qs), + ...localQueryResultsView.getCommands(), ...qhm.getCommands(), ...variantAnalysisManager.getCommands(), ...databaseUI.getCommands(), diff --git a/extensions/ql-vscode/src/interface.ts b/extensions/ql-vscode/src/interface.ts index 055008e1d..a7d7dcff1 100644 --- a/extensions/ql-vscode/src/interface.ts +++ b/extensions/ql-vscode/src/interface.ts @@ -42,7 +42,6 @@ import { ParsedResultSets, } from "./pure/interface-types"; import { Logger } from "./common"; -import { commandRunner } from "./commandRunner"; import { CompletedQueryInfo, interpretResultsSarif, @@ -72,6 +71,7 @@ import { isCanary, PAGE_SIZE } from "./config"; import { HistoryItemLabelProvider } from "./query-history/history-item-label-provider"; import { telemetryListener } from "./telemetry"; import { redactableError } from "./pure/errors"; +import { ResultsViewCommands } from "./common/commands"; /** * interface.ts @@ -179,21 +179,6 @@ export class ResultsView extends AbstractWebview< this.handleSelectionChange.bind(this), ), ); - const navigationCommands = { - "codeQLQueryResults.up": NavigationDirection.up, - "codeQLQueryResults.down": NavigationDirection.down, - "codeQLQueryResults.left": NavigationDirection.left, - "codeQLQueryResults.right": NavigationDirection.right, - // For backwards compatibility with keybindings set using an earlier version of the extension. - "codeQLQueryResults.nextPathStep": NavigationDirection.down, - "codeQLQueryResults.previousPathStep": NavigationDirection.up, - }; - void logger.log("Registering result view navigation commands."); - for (const [commandId, direction] of Object.entries(navigationCommands)) { - this.push( - commandRunner(commandId, this.navigateResultView.bind(this, direction)), - ); - } this.push( this.databaseManager.onDidChangeDatabaseItem(({ kind }) => { @@ -209,6 +194,36 @@ export class ResultsView extends AbstractWebview< ); } + public getCommands(): ResultsViewCommands { + return { + "codeQLQueryResults.up": this.navigateResultView.bind( + this, + NavigationDirection.up, + ), + "codeQLQueryResults.down": this.navigateResultView.bind( + this, + NavigationDirection.down, + ), + "codeQLQueryResults.left": this.navigateResultView.bind( + this, + NavigationDirection.left, + ), + "codeQLQueryResults.right": this.navigateResultView.bind( + this, + NavigationDirection.right, + ), + // For backwards compatibility with keybindings set using an earlier version of the extension. + "codeQLQueryResults.nextPathStep": this.navigateResultView.bind( + this, + NavigationDirection.down, + ), + "codeQLQueryResults.previousPathStep": this.navigateResultView.bind( + this, + NavigationDirection.up, + ), + }; + } + async navigateResultView(direction: NavigationDirection): Promise { if (!this.panel?.visible) { return; From 9f85f56055ce31d5aa55a8634718264f9d95d1cf Mon Sep 17 00:00:00 2001 From: Koen Vlaswinkel Date: Wed, 22 Mar 2023 15:13:05 +0100 Subject: [PATCH 122/156] Convert test UI commands to typed commands --- extensions/ql-vscode/src/common/commands.ts | 9 ++++++++- extensions/ql-vscode/src/extension.ts | 5 +++++ extensions/ql-vscode/src/test-ui.ts | 17 +++++++++-------- 3 files changed, 22 insertions(+), 9 deletions(-) diff --git a/extensions/ql-vscode/src/common/commands.ts b/extensions/ql-vscode/src/common/commands.ts index 88ed7d44a..499d2c4b7 100644 --- a/extensions/ql-vscode/src/common/commands.ts +++ b/extensions/ql-vscode/src/common/commands.ts @@ -5,6 +5,7 @@ import type { DbTreeViewItem } from "../databases/ui/db-tree-view-item"; import type { DatabaseItem } from "../local-databases"; import type { QueryHistoryInfo } from "../query-history/query-history-info"; import type { RepositoriesFilterSortStateWithIds } from "../pure/variant-analysis-filter-sort"; +import type { TestTreeNode } from "../test-tree-node"; import type { VariantAnalysis, VariantAnalysisScannedRepository, @@ -195,6 +196,11 @@ export type SummaryLanguageSupportCommands = { "codeQL.gotoQL": () => Promise; }; +export type TestUICommands = { + "codeQLTests.showOutputDifferences": (node: TestTreeNode) => Promise; + "codeQLTests.acceptOutput": (node: TestTreeNode) => Promise; +}; + export type AllCommands = BaseCommands & QueryHistoryCommands & LocalDatabasesCommands & @@ -204,7 +210,8 @@ export type AllCommands = BaseCommands & AstViewerCommands & PackagingCommands & EvalLogViewerCommands & - SummaryLanguageSupportCommands; + SummaryLanguageSupportCommands & + Partial; export type AppCommandManager = CommandManager; diff --git a/extensions/ql-vscode/src/extension.ts b/extensions/ql-vscode/src/extension.ts index e6a24f47f..7c1a3937e 100644 --- a/extensions/ql-vscode/src/extension.ts +++ b/extensions/ql-vscode/src/extension.ts @@ -115,6 +115,7 @@ import { AllCommands, BaseCommands, QueryServerCommands, + TestUICommands, } from "./common/commands"; import { getLocalQueryCommands, @@ -795,6 +796,7 @@ async function activateWithInstalledDistribution( const testExplorerExtension = extensions.getExtension( testExplorerExtensionId, ); + let testUiCommands: Partial = {}; if (testExplorerExtension) { const testHub = testExplorerExtension.exports; const testAdapterFactory = new QLTestAdapterFactory( @@ -806,6 +808,8 @@ async function activateWithInstalledDistribution( const testUIService = new TestUIService(testHub); ctx.subscriptions.push(testUIService); + + testUiCommands = testUIService.getCommands(); } const astViewer = new AstViewer(); @@ -846,6 +850,7 @@ async function activateWithInstalledDistribution( }), ...evalLogViewer.getCommands(), ...summaryLanguageSupport.getCommands(), + ...testUiCommands, }; for (const [commandName, command] of Object.entries(allCommands)) { diff --git a/extensions/ql-vscode/src/test-ui.ts b/extensions/ql-vscode/src/test-ui.ts index f0a642576..102053fec 100644 --- a/extensions/ql-vscode/src/test-ui.ts +++ b/extensions/ql-vscode/src/test-ui.ts @@ -16,7 +16,7 @@ import { TestTreeNode } from "./test-tree-node"; import { DisposableObject } from "./pure/disposable-object"; import { UIService } from "./vscode-utils/ui-service"; import { QLTestAdapter, getExpectedFile, getActualFile } from "./test-adapter"; -import { extLogger } from "./common"; +import { TestUICommands } from "./common/commands"; type VSCodeTestEvent = | TestRunStartedEvent @@ -48,16 +48,17 @@ export class TestUIService extends UIService implements TestController { constructor(private readonly testHub: TestHub) { super(); - void extLogger.log("Registering CodeQL test panel commands."); - this.registerCommand( - "codeQLTests.showOutputDifferences", - this.showOutputDifferences, - ); - this.registerCommand("codeQLTests.acceptOutput", this.acceptOutput); - testHub.registerTestController(this); } + public getCommands(): TestUICommands { + return { + "codeQLTests.showOutputDifferences": + this.showOutputDifferences.bind(this), + "codeQLTests.acceptOutput": this.acceptOutput.bind(this), + }; + } + public dispose(): void { this.testHub.unregisterTestController(this); From e74a2e4a159cc49ad57206f342be8a99b46e70f4 Mon Sep 17 00:00:00 2001 From: Koen Vlaswinkel Date: Wed, 22 Mar 2023 15:14:22 +0100 Subject: [PATCH 123/156] Remove `UIService` This class seems to have been introduced at some point to reduce the dependency on VS Code from the test UI service. However, none of its methods are being used anymore, and by using typed commands we have already reduced the dependency on VS Code. Therefore, we can simply remove this class. --- extensions/ql-vscode/src/test-ui.ts | 3 +- .../ql-vscode/src/vscode-utils/ui-service.ts | 32 ------------------- 2 files changed, 1 insertion(+), 34 deletions(-) delete mode 100644 extensions/ql-vscode/src/vscode-utils/ui-service.ts diff --git a/extensions/ql-vscode/src/test-ui.ts b/extensions/ql-vscode/src/test-ui.ts index 102053fec..5739d438f 100644 --- a/extensions/ql-vscode/src/test-ui.ts +++ b/extensions/ql-vscode/src/test-ui.ts @@ -14,7 +14,6 @@ import { import { showAndLogWarningMessage } from "./helpers"; import { TestTreeNode } from "./test-tree-node"; import { DisposableObject } from "./pure/disposable-object"; -import { UIService } from "./vscode-utils/ui-service"; import { QLTestAdapter, getExpectedFile, getActualFile } from "./test-adapter"; import { TestUICommands } from "./common/commands"; @@ -42,7 +41,7 @@ class QLTestListener extends DisposableObject { /** * Service that implements all UI and commands for QL tests. */ -export class TestUIService extends UIService implements TestController { +export class TestUIService extends DisposableObject implements TestController { private readonly listeners: Map = new Map(); constructor(private readonly testHub: TestHub) { diff --git a/extensions/ql-vscode/src/vscode-utils/ui-service.ts b/extensions/ql-vscode/src/vscode-utils/ui-service.ts deleted file mode 100644 index c2ffef0c8..000000000 --- a/extensions/ql-vscode/src/vscode-utils/ui-service.ts +++ /dev/null @@ -1,32 +0,0 @@ -import { TreeDataProvider, window } from "vscode"; -import { DisposableObject } from "../pure/disposable-object"; -import { commandRunner } from "../commandRunner"; - -/** - * A VS Code service that interacts with the UI, including handling commands. - */ -export class UIService extends DisposableObject { - protected constructor() { - super(); - } - - /** - * Registers a command handler with Visual Studio Code. - * @param command The ID of the command to register. - * @param callback Callback function to implement the command. - * @remarks The command handler is automatically unregistered when the service is disposed. - */ - protected registerCommand( - command: string, - callback: (...args: any[]) => any, - ): void { - this.push(commandRunner(command, callback.bind(this))); - } - - protected registerTreeDataProvider( - viewId: string, - treeDataProvider: TreeDataProvider, - ): void { - this.push(window.registerTreeDataProvider(viewId, treeDataProvider)); - } -} From 39d4675b440706dd5bfbe91e7797bc8aec5182af Mon Sep 17 00:00:00 2001 From: Robert Date: Wed, 22 Mar 2023 14:16:55 +0000 Subject: [PATCH 124/156] Start using app.commands.execute for all commands called from extension.ts --- extensions/ql-vscode/src/common/commands.ts | 11 ++++++- extensions/ql-vscode/src/extension.ts | 32 ++++++++++++++------- 2 files changed, 31 insertions(+), 12 deletions(-) diff --git a/extensions/ql-vscode/src/common/commands.ts b/extensions/ql-vscode/src/common/commands.ts index ff52f56a9..8e9c4bb9c 100644 --- a/extensions/ql-vscode/src/common/commands.ts +++ b/extensions/ql-vscode/src/common/commands.ts @@ -30,6 +30,12 @@ export type SingleSelectionCommandFunction = ( * the implementation in the corresponding `getCommands` function. */ +// Builtin commands where the implementation is provided by VS Code and not by this extension. +export type VSCodeCommands = { + "markdown.showPreviewToSide": (uri: Uri) => Promise; + "workbench.action.reloadWindow": () => Promise; +}; + // Base commands not tied directly to a module like e.g. variant analysis. export type BaseCommands = { "codeQL.openDocumentation": () => Promise; @@ -185,7 +191,8 @@ export type EvalLogViewerCommands = { "codeQLEvalLogViewer.clear": () => Promise; }; -export type AllCommands = BaseCommands & +// All commands where the implementation is provided by this extension. +export type AllCodeQLCommands = BaseCommands & QueryHistoryCommands & LocalDatabasesCommands & VariantAnalysisCommands & @@ -194,6 +201,8 @@ export type AllCommands = BaseCommands & PackagingCommands & EvalLogViewerCommands; +export type AllCommands = AllCodeQLCommands & VSCodeCommands; + export type AppCommandManager = CommandManager; // Separate command manager because it uses a different logger diff --git a/extensions/ql-vscode/src/extension.ts b/extensions/ql-vscode/src/extension.ts index 7d3653296..49d5fe674 100644 --- a/extensions/ql-vscode/src/extension.ts +++ b/extensions/ql-vscode/src/extension.ts @@ -1,7 +1,6 @@ import "source-map-support/register"; import { CancellationToken, - commands, Disposable, env, ExtensionContext, @@ -112,7 +111,7 @@ import { redactableError } from "./pure/errors"; import { QueryHistoryDirs } from "./query-history/query-history-dirs"; import { DirResult } from "tmp"; import { - AllCommands, + AllCodeQLCommands, BaseCommands, QueryServerCommands, } from "./common/commands"; @@ -265,6 +264,8 @@ export async function activate( addUnhandledRejectionListener(); install(); + const app = new ExtensionApp(ctx); + const codelensProvider = new QuickEvalCodeLensProvider(); languages.registerCodeLensProvider( { scheme: "file", language: "ql" }, @@ -291,6 +292,7 @@ export async function activate( distributionConfigListener.onDidChangeConfiguration(() => installOrUpdateThenTryActivate( ctx, + app, distributionManager, distributionConfigListener, { @@ -305,6 +307,7 @@ export async function activate( commandRunner(checkForUpdatesCommand, () => installOrUpdateThenTryActivate( ctx, + app, distributionManager, distributionConfigListener, { @@ -324,6 +327,7 @@ export async function activate( const codeQlExtension = await installOrUpdateThenTryActivate( ctx, + app, distributionManager, distributionConfigListener, { @@ -345,6 +349,7 @@ export async function activate( async function installOrUpdateDistributionWithProgressTitle( ctx: ExtensionContext, + app: ExtensionApp, distributionManager: DistributionManager, progressTitle: string, config: DistributionUpdateConfig, @@ -389,7 +394,7 @@ async function installOrUpdateDistributionWithProgressTitle( "Restart and Upgrade", ) ) { - await commands.executeCommand("workbench.action.reloadWindow"); + await app.commands.execute("workbench.action.reloadWindow"); } } else { await withProgress( @@ -416,6 +421,7 @@ async function installOrUpdateDistributionWithProgressTitle( async function installOrUpdateDistribution( ctx: ExtensionContext, + app: ExtensionApp, distributionManager: DistributionManager, config: DistributionUpdateConfig, ): Promise { @@ -436,6 +442,7 @@ async function installOrUpdateDistribution( try { await installOrUpdateDistributionWithProgressTitle( ctx, + app, distributionManager, messageText, config, @@ -521,11 +528,12 @@ async function getDistributionDisplayingDistributionWarnings( async function installOrUpdateThenTryActivate( ctx: ExtensionContext, + app: ExtensionApp, distributionManager: DistributionManager, distributionConfigListener: DistributionConfigListener, config: DistributionUpdateConfig, ): Promise> { - await installOrUpdateDistribution(ctx, distributionManager, config); + await installOrUpdateDistribution(ctx, app, distributionManager, config); try { await prepareCodeTour(); @@ -545,6 +553,7 @@ async function installOrUpdateThenTryActivate( ) { extensionInterface = await activateWithInstalledDistribution( ctx, + app, distributionManager, distributionConfigListener, ); @@ -562,6 +571,7 @@ async function installOrUpdateThenTryActivate( if (chosenAction === installActionName) { await installOrUpdateThenTryActivate( ctx, + app, distributionManager, distributionConfigListener, { @@ -588,6 +598,7 @@ const PACK_GLOBS = [ async function activateWithInstalledDistribution( ctx: ExtensionContext, + app: ExtensionApp, distributionManager: DistributionManager, distributionConfigListener: DistributionConfigListener, ): Promise { @@ -596,8 +607,6 @@ async function activateWithInstalledDistribution( // of activation. errorStubs.forEach((stub) => stub.dispose()); - const app = new ExtensionApp(ctx); - void extLogger.log("Initializing configuration listener..."); const qlConfigurationListener = await QueryServerConfigListener.createQueryServerConfigListener( @@ -821,7 +830,7 @@ async function activateWithInstalledDistribution( void extLogger.log("Registering top-level command palette commands."); - const allCommands: AllCommands = { + const allCommands: AllCodeQLCommands = { ...getCommands(cliServer, qs), ...qhm.getCommands(), ...variantAnalysisManager.getCommands(), @@ -844,7 +853,7 @@ async function activateWithInstalledDistribution( }; for (const [commandName, command] of Object.entries(allCommands)) { - app.commands.register(commandName as keyof AllCommands, command); + app.commands.register(commandName as keyof AllCodeQLCommands, command); } const queryServerCommands: QueryServerCommands = { @@ -895,7 +904,7 @@ async function activateWithInstalledDistribution( ctx.subscriptions.push( commandRunner("codeQL.previewQueryHelp", async (selectedQuery: Uri) => { - await previewQueryHelp(cliServer, qhelpTmpDir, selectedQuery); + await previewQueryHelp(app, cliServer, qhelpTmpDir, selectedQuery); }), ); @@ -1002,7 +1011,7 @@ async function activateWithInstalledDistribution( ), ); - await commands.executeCommand("codeQLDatabases.removeOrphanedDatabases"); + await app.commands.execute("codeQLDatabases.removeOrphanedDatabases"); void extLogger.log("Reading query history"); await qhm.readQueryHistory(); @@ -1040,6 +1049,7 @@ async function showResultsForComparison( } async function previewQueryHelp( + app: ExtensionApp, cliServer: CodeQLCliServer, qhelpTmpDir: DirResult, selectedQuery: Uri, @@ -1055,7 +1065,7 @@ async function previewQueryHelp( const uri = Uri.file(absolutePathToMd); try { await cliServer.generateQueryHelp(pathToQhelp, absolutePathToMd); - await commands.executeCommand("markdown.showPreviewToSide", uri); + await app.commands.execute("markdown.showPreviewToSide", uri); } catch (e) { const errorMessage = getErrorMessage(e).includes( "Generating qhelp in markdown", From c6d8a09f19679fc8f24cd7347a5f7a203b799549 Mon Sep 17 00:00:00 2001 From: Koen Vlaswinkel Date: Wed, 22 Mar 2023 15:27:18 +0100 Subject: [PATCH 125/156] Add support for `Partial` in the command manager The command manager types didn't fully support commands defined with `Partial` because it deduced that the command function was `undefined` when the function was not defined. However, if the command is not present, the command registration will not be called. This fixes the types by specifying that the command definition will never be `undefined`. --- extensions/ql-vscode/src/packages/commands/CommandManager.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/extensions/ql-vscode/src/packages/commands/CommandManager.ts b/extensions/ql-vscode/src/packages/commands/CommandManager.ts index c328d9bed..6583840a7 100644 --- a/extensions/ql-vscode/src/packages/commands/CommandManager.ts +++ b/extensions/ql-vscode/src/packages/commands/CommandManager.ts @@ -30,7 +30,7 @@ export class CommandManager< constructor( private readonly commandRegister: ( commandName: T, - fn: Commands[T], + fn: NonNullable, ) => Disposable, private readonly commandExecute: ( commandName: T, @@ -43,7 +43,7 @@ export class CommandManager< */ register( commandName: T, - definition: Commands[T], + definition: NonNullable, ): void { this.commands.push(this.commandRegister(commandName, definition)); } From 31af28e73b6afa8f5d5d05fbc77cba3e1231f9a7 Mon Sep 17 00:00:00 2001 From: Robert Date: Wed, 22 Mar 2023 14:28:10 +0000 Subject: [PATCH 126/156] Add link to docs --- extensions/ql-vscode/src/common/commands.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/extensions/ql-vscode/src/common/commands.ts b/extensions/ql-vscode/src/common/commands.ts index 8e9c4bb9c..ba5a2210c 100644 --- a/extensions/ql-vscode/src/common/commands.ts +++ b/extensions/ql-vscode/src/common/commands.ts @@ -31,6 +31,7 @@ export type SingleSelectionCommandFunction = ( */ // Builtin commands where the implementation is provided by VS Code and not by this extension. +// See https://code.visualstudio.com/api/references/commands export type VSCodeCommands = { "markdown.showPreviewToSide": (uri: Uri) => Promise; "workbench.action.reloadWindow": () => Promise; From 408c042b3b0b4f097420d409a6f5df4fc377bd52 Mon Sep 17 00:00:00 2001 From: Robert Date: Wed, 22 Mar 2023 14:34:27 +0000 Subject: [PATCH 127/156] Fix remaining imports --- extensions/ql-vscode/src/ast-cfg-commands.ts | 2 +- extensions/ql-vscode/src/local-queries.ts | 6 +----- .../variant-analysis/variant-analysis-manager.test.ts | 2 +- .../vscode-tests/minimal-workspace/local-databases.test.ts | 2 +- .../test/vscode-tests/no-workspace/helpers.test.ts | 2 +- .../test/vscode-tests/no-workspace/telemetry.test.ts | 2 +- 6 files changed, 6 insertions(+), 10 deletions(-) diff --git a/extensions/ql-vscode/src/ast-cfg-commands.ts b/extensions/ql-vscode/src/ast-cfg-commands.ts index 1b1c8d583..49749be22 100644 --- a/extensions/ql-vscode/src/ast-cfg-commands.ts +++ b/extensions/ql-vscode/src/ast-cfg-commands.ts @@ -1,5 +1,5 @@ import { Uri, window } from "vscode"; -import { withProgress } from "./commandRunner"; +import { withProgress } from "./progress"; import { AstViewer } from "./astViewer"; import { TemplatePrintAstProvider, diff --git a/extensions/ql-vscode/src/local-queries.ts b/extensions/ql-vscode/src/local-queries.ts index 3c6b76b03..380c4d21d 100644 --- a/extensions/ql-vscode/src/local-queries.ts +++ b/extensions/ql-vscode/src/local-queries.ts @@ -1,8 +1,4 @@ -import { - ProgressCallback, - ProgressUpdate, - withProgress, -} from "./commandRunner"; +import { ProgressCallback, ProgressUpdate, withProgress } from "./progress"; import { CancellationToken, CancellationTokenSource, diff --git a/extensions/ql-vscode/test/vscode-tests/cli-integration/variant-analysis/variant-analysis-manager.test.ts b/extensions/ql-vscode/test/vscode-tests/cli-integration/variant-analysis/variant-analysis-manager.test.ts index 40a82af4e..dd02364a4 100644 --- a/extensions/ql-vscode/test/vscode-tests/cli-integration/variant-analysis/variant-analysis-manager.test.ts +++ b/extensions/ql-vscode/test/vscode-tests/cli-integration/variant-analysis/variant-analysis-manager.test.ts @@ -25,7 +25,7 @@ import { } from "../../../../src/variant-analysis/shared/variant-analysis"; import { VariantAnalysis as VariantAnalysisApiResponse } from "../../../../src/variant-analysis/gh-api/variant-analysis"; import { createMockApiResponse } from "../../../factories/variant-analysis/gh-api/variant-analysis-api-response"; -import { UserCancellationException } from "../../../../src/commandRunner"; +import { UserCancellationException } from "../../../../src/progress"; import { Repository } from "../../../../src/variant-analysis/gh-api/repository"; import { DbManager } from "../../../../src/databases/db-manager"; import { ExtensionApp } from "../../../../src/common/vscode/vscode-app"; diff --git a/extensions/ql-vscode/test/vscode-tests/minimal-workspace/local-databases.test.ts b/extensions/ql-vscode/test/vscode-tests/minimal-workspace/local-databases.test.ts index 61c68b9c2..6c4167c06 100644 --- a/extensions/ql-vscode/test/vscode-tests/minimal-workspace/local-databases.test.ts +++ b/extensions/ql-vscode/test/vscode-tests/minimal-workspace/local-databases.test.ts @@ -13,7 +13,7 @@ import { FullDatabaseOptions, } from "../../../src/local-databases"; import { Logger } from "../../../src/common"; -import { ProgressCallback } from "../../../src/commandRunner"; +import { ProgressCallback } from "../../../src/progress"; import { CodeQLCliServer, DbInfo } from "../../../src/cli"; import { encodeArchiveBasePath, diff --git a/extensions/ql-vscode/test/vscode-tests/no-workspace/helpers.test.ts b/extensions/ql-vscode/test/vscode-tests/no-workspace/helpers.test.ts index bd425e0a0..8fe7a47bd 100644 --- a/extensions/ql-vscode/test/vscode-tests/no-workspace/helpers.test.ts +++ b/extensions/ql-vscode/test/vscode-tests/no-workspace/helpers.test.ts @@ -38,7 +38,7 @@ import { showInformationMessageWithAction, walkDirectory, } from "../../../src/helpers"; -import { reportStreamProgress } from "../../../src/commandRunner"; +import { reportStreamProgress } from "../../../src/progress"; import { QueryLanguage } from "../../../src/common/query-language"; import { Setting } from "../../../src/config"; diff --git a/extensions/ql-vscode/test/vscode-tests/no-workspace/telemetry.test.ts b/extensions/ql-vscode/test/vscode-tests/no-workspace/telemetry.test.ts index 4517837cf..47738ba85 100644 --- a/extensions/ql-vscode/test/vscode-tests/no-workspace/telemetry.test.ts +++ b/extensions/ql-vscode/test/vscode-tests/no-workspace/telemetry.test.ts @@ -9,7 +9,7 @@ import { TelemetryListener, telemetryListener as globalTelemetryListener, } from "../../../src/telemetry"; -import { UserCancellationException } from "../../../src/commandRunner"; +import { UserCancellationException } from "../../../src/progress"; import { ENABLE_TELEMETRY } from "../../../src/config"; import { createMockExtensionContext } from "./index"; import { vscodeGetConfigurationMock } from "../test-config"; From fd7013f7543d0aa00bd7155696f95a083db603a2 Mon Sep 17 00:00:00 2001 From: Koen Vlaswinkel Date: Wed, 22 Mar 2023 16:04:49 +0100 Subject: [PATCH 128/156] Convert mock API server commands to typed commands --- extensions/ql-vscode/src/common/commands.ts | 11 +++++- extensions/ql-vscode/src/extension.ts | 37 ++----------------- .../src/mocks/vscode-mock-gh-api-server.ts | 14 +++++++ 3 files changed, 28 insertions(+), 34 deletions(-) diff --git a/extensions/ql-vscode/src/common/commands.ts b/extensions/ql-vscode/src/common/commands.ts index 03e4d41a1..e3a610ab1 100644 --- a/extensions/ql-vscode/src/common/commands.ts +++ b/extensions/ql-vscode/src/common/commands.ts @@ -204,6 +204,14 @@ export type SummaryLanguageSupportCommands = { "codeQL.gotoQL": () => Promise; }; +export type MockGitHubApiServerCommands = { + "codeQL.mockGitHubApiServer.startRecording": () => Promise; + "codeQL.mockGitHubApiServer.saveScenario": () => Promise; + "codeQL.mockGitHubApiServer.cancelRecording": () => Promise; + "codeQL.mockGitHubApiServer.loadScenario": () => Promise; + "codeQL.mockGitHubApiServer.unloadScenario": () => Promise; +}; + export type AllCommands = BaseCommands & ResultsViewCommands & QueryHistoryCommands & @@ -214,7 +222,8 @@ export type AllCommands = BaseCommands & AstViewerCommands & PackagingCommands & EvalLogViewerCommands & - SummaryLanguageSupportCommands; + SummaryLanguageSupportCommands & + MockGitHubApiServerCommands; export type AppCommandManager = CommandManager; diff --git a/extensions/ql-vscode/src/extension.ts b/extensions/ql-vscode/src/extension.ts index 812ddc5dc..bc966c99b 100644 --- a/extensions/ql-vscode/src/extension.ts +++ b/extensions/ql-vscode/src/extension.ts @@ -822,6 +822,9 @@ async function activateWithInstalledDistribution( const summaryLanguageSupport = new SummaryLanguageSupport(); ctx.subscriptions.push(summaryLanguageSupport); + const mockServer = new VSCodeMockGitHubApiServer(ctx); + ctx.subscriptions.push(mockServer); + void extLogger.log("Registering top-level command palette commands."); const allCommands: AllCommands = { @@ -847,6 +850,7 @@ async function activateWithInstalledDistribution( }), ...evalLogViewer.getCommands(), ...summaryLanguageSupport.getCommands(), + ...mockServer.getCommands(), }; for (const [commandName, command] of Object.entries(allCommands)) { @@ -973,39 +977,6 @@ async function activateWithInstalledDistribution( ), ); - const mockServer = new VSCodeMockGitHubApiServer(ctx); - ctx.subscriptions.push(mockServer); - ctx.subscriptions.push( - commandRunner( - "codeQL.mockGitHubApiServer.startRecording", - async () => await mockServer.startRecording(), - ), - ); - ctx.subscriptions.push( - commandRunner( - "codeQL.mockGitHubApiServer.saveScenario", - async () => await mockServer.saveScenario(), - ), - ); - ctx.subscriptions.push( - commandRunner( - "codeQL.mockGitHubApiServer.cancelRecording", - async () => await mockServer.cancelRecording(), - ), - ); - ctx.subscriptions.push( - commandRunner( - "codeQL.mockGitHubApiServer.loadScenario", - async () => await mockServer.loadScenario(), - ), - ); - ctx.subscriptions.push( - commandRunner( - "codeQL.mockGitHubApiServer.unloadScenario", - async () => await mockServer.unloadScenario(), - ), - ); - await commands.executeCommand("codeQLDatabases.removeOrphanedDatabases"); void extLogger.log("Reading query history"); diff --git a/extensions/ql-vscode/src/mocks/vscode-mock-gh-api-server.ts b/extensions/ql-vscode/src/mocks/vscode-mock-gh-api-server.ts index fbe43c2c9..50c821b56 100644 --- a/extensions/ql-vscode/src/mocks/vscode-mock-gh-api-server.ts +++ b/extensions/ql-vscode/src/mocks/vscode-mock-gh-api-server.ts @@ -15,6 +15,7 @@ import { } from "../config"; import { DisposableObject } from "../pure/disposable-object"; import { MockGitHubApiServer } from "./mock-gh-api-server"; +import { MockGitHubApiServerCommands } from "../common/commands"; /** * "Interface" to the mock GitHub API server which implements VSCode interactions, such as @@ -34,6 +35,19 @@ export class VSCodeMockGitHubApiServer extends DisposableObject { this.setupConfigListener(); } + public getCommands(): MockGitHubApiServerCommands { + return { + "codeQL.mockGitHubApiServer.startRecording": + this.startRecording.bind(this), + "codeQL.mockGitHubApiServer.saveScenario": this.saveScenario.bind(this), + "codeQL.mockGitHubApiServer.cancelRecording": + this.cancelRecording.bind(this), + "codeQL.mockGitHubApiServer.loadScenario": this.loadScenario.bind(this), + "codeQL.mockGitHubApiServer.unloadScenario": + this.unloadScenario.bind(this), + }; + } + public async startServer(): Promise { this.server.startServer(); } From 5d6a2e6d7fa5a7b47d0cb16be425bd15f632d61b Mon Sep 17 00:00:00 2001 From: Robert Date: Wed, 22 Mar 2023 15:37:39 +0000 Subject: [PATCH 129/156] rename types --- extensions/ql-vscode/src/common/commands.ts | 6 +++--- extensions/ql-vscode/src/extension.ts | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/extensions/ql-vscode/src/common/commands.ts b/extensions/ql-vscode/src/common/commands.ts index 7c93ca427..bda47fb07 100644 --- a/extensions/ql-vscode/src/common/commands.ts +++ b/extensions/ql-vscode/src/common/commands.ts @@ -33,7 +33,7 @@ export type SingleSelectionCommandFunction = ( // Builtin commands where the implementation is provided by VS Code and not by this extension. // See https://code.visualstudio.com/api/references/commands -export type VSCodeCommands = { +export type BuiltInVsCodeCommands = { "markdown.showPreviewToSide": (uri: Uri) => Promise; "workbench.action.reloadWindow": () => Promise; }; @@ -220,7 +220,7 @@ export type MockGitHubApiServerCommands = { }; // All commands where the implementation is provided by this extension. -export type AllCodeQLCommands = BaseCommands & +export type AllExtensionCommands = BaseCommands & QueryHistoryCommands & LocalDatabasesCommands & VariantAnalysisCommands & @@ -232,7 +232,7 @@ export type AllCodeQLCommands = BaseCommands & SummaryLanguageSupportCommands & MockGitHubApiServerCommands; -export type AllCommands = AllCodeQLCommands & VSCodeCommands; +export type AllCommands = AllExtensionCommands & BuiltInVsCodeCommands; export type AppCommandManager = CommandManager; diff --git a/extensions/ql-vscode/src/extension.ts b/extensions/ql-vscode/src/extension.ts index be2cce617..a69270e89 100644 --- a/extensions/ql-vscode/src/extension.ts +++ b/extensions/ql-vscode/src/extension.ts @@ -112,7 +112,7 @@ import { redactableError } from "./pure/errors"; import { QueryHistoryDirs } from "./query-history/query-history-dirs"; import { DirResult } from "tmp"; import { - AllCodeQLCommands, + AllExtensionCommands, BaseCommands, QueryServerCommands, } from "./common/commands"; @@ -837,7 +837,7 @@ async function activateWithInstalledDistribution( void extLogger.log("Registering top-level command palette commands."); - const allCommands: AllCodeQLCommands = { + const allCommands: AllExtensionCommands = { ...getCommands(cliServer, qs), ...localQueryResultsView.getCommands(), ...qhm.getCommands(), @@ -864,7 +864,7 @@ async function activateWithInstalledDistribution( }; for (const [commandName, command] of Object.entries(allCommands)) { - app.commands.register(commandName as keyof AllCodeQLCommands, command); + app.commands.register(commandName as keyof AllExtensionCommands, command); } const queryServerCommands: QueryServerCommands = { From 5ac5de8a5b3038d8e3c38327fa77f01eb84ba1d1 Mon Sep 17 00:00:00 2001 From: Koen Vlaswinkel Date: Wed, 22 Mar 2023 16:50:44 +0100 Subject: [PATCH 130/156] Move query editing commands to separate file --- extensions/ql-vscode/src/extension.ts | 86 ++------------------- extensions/ql-vscode/src/query-editor.ts | 97 ++++++++++++++++++++++++ 2 files changed, 104 insertions(+), 79 deletions(-) create mode 100644 extensions/ql-vscode/src/query-editor.ts diff --git a/extensions/ql-vscode/src/extension.ts b/extensions/ql-vscode/src/extension.ts index 8a8c9570f..3795060b9 100644 --- a/extensions/ql-vscode/src/extension.ts +++ b/extensions/ql-vscode/src/extension.ts @@ -11,13 +11,12 @@ import { Uri, version as vscodeVersion, window as Window, - window, workspace, } from "vscode"; import { LanguageClient } from "vscode-languageclient/node"; import { arch, platform } from "os"; import { ensureDir } from "fs-extra"; -import { basename, join } from "path"; +import { join } from "path"; import { dirSync } from "tmp-promise"; import { testExplorerExtensionId, TestHub } from "vscode-test-adapter-api"; import { lt, parse } from "semver"; @@ -111,7 +110,6 @@ import { ExtensionApp } from "./common/vscode/vscode-app"; import { DbModule } from "./databases/db-module"; import { redactableError } from "./pure/errors"; import { QueryHistoryDirs } from "./query-history/query-history-dirs"; -import { DirResult } from "tmp"; import { AllCommands, BaseCommands, @@ -122,6 +120,7 @@ import { showResultsForCompletedQuery, } from "./local-queries"; import { getAstCfgCommands } from "./ast-cfg-commands"; +import { registerQueryEditorCommands } from "./query-editor"; /** * extension.ts @@ -878,37 +877,11 @@ async function activateWithInstalledDistribution( ); } - ctx.subscriptions.push( - commandRunner("codeQL.openReferencedFile", async (selectedQuery: Uri) => { - await openReferencedFile(qs, cliServer, selectedQuery); - }), - ); - - // Since we are tracking extension usage through commands, this command mirrors the "codeQL.openReferencedFile" command - ctx.subscriptions.push( - commandRunner( - "codeQL.openReferencedFileContextEditor", - async (selectedQuery: Uri) => { - await openReferencedFile(qs, cliServer, selectedQuery); - }, - ), - ); - - // Since we are tracking extension usage through commands, this command mirrors the "codeQL.openReferencedFile" command - ctx.subscriptions.push( - commandRunner( - "codeQL.openReferencedFileContextExplorer", - async (selectedQuery: Uri) => { - await openReferencedFile(qs, cliServer, selectedQuery); - }, - ), - ); - - ctx.subscriptions.push( - commandRunner("codeQL.previewQueryHelp", async (selectedQuery: Uri) => { - await previewQueryHelp(cliServer, qhelpTmpDir, selectedQuery); - }), - ); + registerQueryEditorCommands(ctx, { + queryRunner: qs, + cliServer, + qhelpTmpDir: qhelpTmpDir.name, + }); ctx.subscriptions.push( commandRunner("codeQL.copyVersion", async () => { @@ -1015,51 +988,6 @@ async function showResultsForComparison( } } -async function previewQueryHelp( - cliServer: CodeQLCliServer, - qhelpTmpDir: DirResult, - selectedQuery: Uri, -): Promise { - // selectedQuery is unpopulated when executing through the command palette - const pathToQhelp = selectedQuery - ? selectedQuery.fsPath - : window.activeTextEditor?.document.uri.fsPath; - if (pathToQhelp) { - // Create temporary directory - const relativePathToMd = `${basename(pathToQhelp, ".qhelp")}.md`; - const absolutePathToMd = join(qhelpTmpDir.name, relativePathToMd); - const uri = Uri.file(absolutePathToMd); - try { - await cliServer.generateQueryHelp(pathToQhelp, absolutePathToMd); - await commands.executeCommand("markdown.showPreviewToSide", uri); - } catch (e) { - const errorMessage = getErrorMessage(e).includes( - "Generating qhelp in markdown", - ) - ? redactableError`Could not generate markdown from ${pathToQhelp}: Bad formatting in .qhelp file.` - : redactableError`Could not open a preview of the generated file (${absolutePathToMd}).`; - void showAndLogExceptionWithTelemetry(errorMessage, { - fullMessage: `${errorMessage}\n${getErrorMessage(e)}`, - }); - } - } -} - -async function openReferencedFile( - qs: QueryRunner, - cliServer: CodeQLCliServer, - selectedQuery: Uri, -): Promise { - // If no file is selected, the path of the file in the editor is selected - const path = - selectedQuery?.fsPath || window.activeTextEditor?.document.uri.fsPath; - if (qs !== undefined && path) { - const resolved = await cliServer.resolveQlref(path); - const uri = Uri.file(resolved.resolvedPath); - await window.showTextDocument(uri, { preview: false }); - } -} - function addUnhandledRejectionListener() { const handler = (error: unknown) => { // This listener will be triggered for errors from other extensions as diff --git a/extensions/ql-vscode/src/query-editor.ts b/extensions/ql-vscode/src/query-editor.ts new file mode 100644 index 000000000..6dcfb5dbc --- /dev/null +++ b/extensions/ql-vscode/src/query-editor.ts @@ -0,0 +1,97 @@ +import { commands, ExtensionContext, Uri, window } from "vscode"; +import { CodeQLCliServer } from "./cli"; +import { QueryRunner } from "./queryRunner"; +import { commandRunner } from "./commandRunner"; +import { basename, join } from "path"; +import { getErrorMessage } from "./pure/helpers-pure"; +import { redactableError } from "./pure/errors"; +import { showAndLogExceptionWithTelemetry } from "./helpers"; + +type QueryEditorOptions = { + queryRunner: QueryRunner; + cliServer: CodeQLCliServer; + + qhelpTmpDir: string; +}; + +export function registerQueryEditorCommands( + ctx: ExtensionContext, + { queryRunner, cliServer, qhelpTmpDir }: QueryEditorOptions, +) { + ctx.subscriptions.push( + commandRunner("codeQL.openReferencedFile", async (selectedQuery: Uri) => { + await openReferencedFile(queryRunner, cliServer, selectedQuery); + }), + ); + + // Since we are tracking extension usage through commands, this command mirrors the "codeQL.openReferencedFile" command + ctx.subscriptions.push( + commandRunner( + "codeQL.openReferencedFileContextEditor", + async (selectedQuery: Uri) => { + await openReferencedFile(queryRunner, cliServer, selectedQuery); + }, + ), + ); + + // Since we are tracking extension usage through commands, this command mirrors the "codeQL.openReferencedFile" command + ctx.subscriptions.push( + commandRunner( + "codeQL.openReferencedFileContextExplorer", + async (selectedQuery: Uri) => { + await openReferencedFile(queryRunner, cliServer, selectedQuery); + }, + ), + ); + + ctx.subscriptions.push( + commandRunner("codeQL.previewQueryHelp", async (selectedQuery: Uri) => { + await previewQueryHelp(cliServer, qhelpTmpDir, selectedQuery); + }), + ); +} + +async function previewQueryHelp( + cliServer: CodeQLCliServer, + qhelpTmpDir: string, + selectedQuery: Uri, +): Promise { + // selectedQuery is unpopulated when executing through the command palette + const pathToQhelp = selectedQuery + ? selectedQuery.fsPath + : window.activeTextEditor?.document.uri.fsPath; + if (pathToQhelp) { + // Create temporary directory + const relativePathToMd = `${basename(pathToQhelp, ".qhelp")}.md`; + const absolutePathToMd = join(qhelpTmpDir, relativePathToMd); + const uri = Uri.file(absolutePathToMd); + try { + await cliServer.generateQueryHelp(pathToQhelp, absolutePathToMd); + await commands.executeCommand("markdown.showPreviewToSide", uri); + } catch (e) { + const errorMessage = getErrorMessage(e).includes( + "Generating qhelp in markdown", + ) + ? redactableError`Could not generate markdown from ${pathToQhelp}: Bad formatting in .qhelp file.` + : redactableError`Could not open a preview of the generated file (${absolutePathToMd}).`; + void showAndLogExceptionWithTelemetry(errorMessage, { + fullMessage: `${errorMessage}\n${getErrorMessage(e)}`, + }); + } + } +} + +async function openReferencedFile( + qs: QueryRunner, + cliServer: CodeQLCliServer, + selectedQuery: Uri, +): Promise { + // If no file is selected, the path of the file in the editor is selected + const path = + selectedQuery?.fsPath || window.activeTextEditor?.document.uri.fsPath; + if (qs !== undefined && path) { + const resolved = await cliServer.resolveQlref(path); + const uri = Uri.file(resolved.resolvedPath); + await window.showTextDocument(uri, { preview: false }); + } +} From be3459c1aa91052cb3643397fbb1dadae23e15bd Mon Sep 17 00:00:00 2001 From: Koen Vlaswinkel Date: Wed, 22 Mar 2023 16:52:59 +0100 Subject: [PATCH 131/156] Convert query editing commands to typed commands --- extensions/ql-vscode/src/common/commands.ts | 13 +++++ extensions/ql-vscode/src/extension.ts | 13 +++-- extensions/ql-vscode/src/query-editor.ts | 54 +++++++-------------- 3 files changed, 37 insertions(+), 43 deletions(-) diff --git a/extensions/ql-vscode/src/common/commands.ts b/extensions/ql-vscode/src/common/commands.ts index e3a610ab1..b60f952dc 100644 --- a/extensions/ql-vscode/src/common/commands.ts +++ b/extensions/ql-vscode/src/common/commands.ts @@ -38,6 +38,18 @@ export type BaseCommands = { "codeQL.restartQueryServer": () => Promise; }; +// Commands used when working with queries in the editor +export type QueryEditorCommands = { + "codeQL.openReferencedFile": (selectedQuery: Uri) => Promise; + "codeQL.openReferencedFileContextEditor": ( + selectedQuery: Uri, + ) => Promise; + "codeQL.openReferencedFileContextExplorer": ( + selectedQuery: Uri, + ) => Promise; + "codeQL.previewQueryHelp": (selectedQuery: Uri) => Promise; +}; + // Commands used for running local queries export type LocalQueryCommands = { "codeQL.runQuery": (uri?: Uri) => Promise; @@ -213,6 +225,7 @@ export type MockGitHubApiServerCommands = { }; export type AllCommands = BaseCommands & + QueryEditorCommands & ResultsViewCommands & QueryHistoryCommands & LocalDatabasesCommands & diff --git a/extensions/ql-vscode/src/extension.ts b/extensions/ql-vscode/src/extension.ts index 3795060b9..51a91016f 100644 --- a/extensions/ql-vscode/src/extension.ts +++ b/extensions/ql-vscode/src/extension.ts @@ -120,7 +120,7 @@ import { showResultsForCompletedQuery, } from "./local-queries"; import { getAstCfgCommands } from "./ast-cfg-commands"; -import { registerQueryEditorCommands } from "./query-editor"; +import { getQueryEditorCommands } from "./query-editor"; /** * extension.ts @@ -829,6 +829,11 @@ async function activateWithInstalledDistribution( const allCommands: AllCommands = { ...getCommands(cliServer, qs), + ...getQueryEditorCommands({ + queryRunner: qs, + cliServer, + qhelpTmpDir: qhelpTmpDir.name, + }), ...localQueryResultsView.getCommands(), ...qhm.getCommands(), ...variantAnalysisManager.getCommands(), @@ -877,12 +882,6 @@ async function activateWithInstalledDistribution( ); } - registerQueryEditorCommands(ctx, { - queryRunner: qs, - cliServer, - qhelpTmpDir: qhelpTmpDir.name, - }); - ctx.subscriptions.push( commandRunner("codeQL.copyVersion", async () => { const text = `CodeQL extension version: ${ diff --git a/extensions/ql-vscode/src/query-editor.ts b/extensions/ql-vscode/src/query-editor.ts index 6dcfb5dbc..23b8101c7 100644 --- a/extensions/ql-vscode/src/query-editor.ts +++ b/extensions/ql-vscode/src/query-editor.ts @@ -1,11 +1,11 @@ -import { commands, ExtensionContext, Uri, window } from "vscode"; +import { commands, Uri, window } from "vscode"; import { CodeQLCliServer } from "./cli"; import { QueryRunner } from "./queryRunner"; -import { commandRunner } from "./commandRunner"; import { basename, join } from "path"; import { getErrorMessage } from "./pure/helpers-pure"; import { redactableError } from "./pure/errors"; import { showAndLogExceptionWithTelemetry } from "./helpers"; +import { QueryEditorCommands } from "./common/commands"; type QueryEditorOptions = { queryRunner: QueryRunner; @@ -14,41 +14,23 @@ type QueryEditorOptions = { qhelpTmpDir: string; }; -export function registerQueryEditorCommands( - ctx: ExtensionContext, - { queryRunner, cliServer, qhelpTmpDir }: QueryEditorOptions, -) { - ctx.subscriptions.push( - commandRunner("codeQL.openReferencedFile", async (selectedQuery: Uri) => { - await openReferencedFile(queryRunner, cliServer, selectedQuery); - }), - ); +export function getQueryEditorCommands({ + queryRunner, + cliServer, + qhelpTmpDir, +}: QueryEditorOptions): QueryEditorCommands { + const openReferencedFileCommand = async (selectedQuery: Uri) => + await openReferencedFile(queryRunner, cliServer, selectedQuery); - // Since we are tracking extension usage through commands, this command mirrors the "codeQL.openReferencedFile" command - ctx.subscriptions.push( - commandRunner( - "codeQL.openReferencedFileContextEditor", - async (selectedQuery: Uri) => { - await openReferencedFile(queryRunner, cliServer, selectedQuery); - }, - ), - ); - - // Since we are tracking extension usage through commands, this command mirrors the "codeQL.openReferencedFile" command - ctx.subscriptions.push( - commandRunner( - "codeQL.openReferencedFileContextExplorer", - async (selectedQuery: Uri) => { - await openReferencedFile(queryRunner, cliServer, selectedQuery); - }, - ), - ); - - ctx.subscriptions.push( - commandRunner("codeQL.previewQueryHelp", async (selectedQuery: Uri) => { - await previewQueryHelp(cliServer, qhelpTmpDir, selectedQuery); - }), - ); + return { + "codeQL.openReferencedFile": openReferencedFileCommand, + // Since we are tracking extension usage through commands, this command mirrors the "codeQL.openReferencedFile" command + "codeQL.openReferencedFileContextEditor": openReferencedFileCommand, + // Since we are tracking extension usage through commands, this command mirrors the "codeQL.openReferencedFile" command + "codeQL.openReferencedFileContextExplorer": openReferencedFileCommand, + "codeQL.previewQueryHelp": async (selectedQuery: Uri) => + await previewQueryHelp(cliServer, qhelpTmpDir, selectedQuery), + }; } async function previewQueryHelp( From fe6ff6801a52b5c62bdf80abee1d1db66c7d79dc Mon Sep 17 00:00:00 2001 From: Koen Vlaswinkel Date: Wed, 22 Mar 2023 17:02:16 +0100 Subject: [PATCH 132/156] Convert some base commands to typed commands --- extensions/ql-vscode/src/common/commands.ts | 3 + extensions/ql-vscode/src/extension.ts | 71 ++++++++++----------- 2 files changed, 35 insertions(+), 39 deletions(-) diff --git a/extensions/ql-vscode/src/common/commands.ts b/extensions/ql-vscode/src/common/commands.ts index 07754d509..36ef03576 100644 --- a/extensions/ql-vscode/src/common/commands.ts +++ b/extensions/ql-vscode/src/common/commands.ts @@ -35,7 +35,10 @@ export type SingleSelectionCommandFunction = ( // Base commands not tied directly to a module like e.g. variant analysis. export type BaseCommands = { "codeQL.openDocumentation": () => Promise; + "codeQL.showLogs": () => Promise; + "codeQL.authenticateToGitHub": () => Promise; + "codeQL.copyVersion": () => Promise; "codeQL.restartQueryServer": () => Promise; }; diff --git a/extensions/ql-vscode/src/extension.ts b/extensions/ql-vscode/src/extension.ts index 4d6a2c9f0..514dc8e57 100644 --- a/extensions/ql-vscode/src/extension.ts +++ b/extensions/ql-vscode/src/extension.ts @@ -123,6 +123,7 @@ import { showResultsForCompletedQuery, } from "./local-queries"; import { getAstCfgCommands } from "./ast-cfg-commands"; +import { App } from "./common/app"; /** * extension.ts @@ -158,9 +159,18 @@ const extension = extensions.getExtension(extensionId); * Return all commands that are not tied to the more specific managers. */ function getCommands( + app: App, cliServer: CodeQLCliServer, queryRunner: QueryRunner, ): BaseCommands { + const getCliVersion = async () => { + try { + return await cliServer.getVersion(); + } catch { + return ""; + } + }; + return { "codeQL.openDocumentation": async () => { await env.openExternal(Uri.parse("https://codeql.github.com/docs/")); @@ -179,6 +189,27 @@ function getCommands( title: "Restarting Query Server", }, ), + "codeQL.copyVersion": async () => { + const text = `CodeQL extension version: ${ + extension?.packageJSON.version + } \nCodeQL CLI version: ${await getCliVersion()} \nPlatform: ${platform()} ${arch()}`; + await env.clipboard.writeText(text); + void showAndLogInformationMessage(text); + }, + "codeQL.authenticateToGitHub": async () => { + /** + * Credentials for authenticating to GitHub. + * These are used when making API calls. + */ + const octokit = await app.credentials.getOctokit(); + const userInfo = await octokit.users.getAuthenticated(); + void showAndLogInformationMessage( + `Authenticated to GitHub as user: ${userInfo.data.login}`, + ); + }, + "codeQL.showLogs": async () => { + extLogger.show(); + }, }; } @@ -833,7 +864,7 @@ async function activateWithInstalledDistribution( void extLogger.log("Registering top-level command palette commands."); const allCommands: AllCommands = { - ...getCommands(cliServer, qs), + ...getCommands(app, cliServer, qs), ...localQueryResultsView.getCommands(), ...qhm.getCommands(), ...variantAnalysisManager.getCommands(), @@ -915,44 +946,6 @@ async function activateWithInstalledDistribution( }), ); - ctx.subscriptions.push( - commandRunner("codeQL.copyVersion", async () => { - const text = `CodeQL extension version: ${ - extension?.packageJSON.version - } \nCodeQL CLI version: ${await getCliVersion()} \nPlatform: ${platform()} ${arch()}`; - await env.clipboard.writeText(text); - void showAndLogInformationMessage(text); - }), - ); - - const getCliVersion = async () => { - try { - return await cliServer.getVersion(); - } catch { - return ""; - } - }; - - ctx.subscriptions.push( - commandRunner("codeQL.authenticateToGitHub", async () => { - /** - * Credentials for authenticating to GitHub. - * These are used when making API calls. - */ - const octokit = await app.credentials.getOctokit(); - const userInfo = await octokit.users.getAuthenticated(); - void showAndLogInformationMessage( - `Authenticated to GitHub as user: ${userInfo.data.login}`, - ); - }), - ); - - ctx.subscriptions.push( - commandRunner("codeQL.showLogs", async () => { - extLogger.show(); - }), - ); - void extLogger.log("Starting language server."); await client.start(); ctx.subscriptions.push({ From 844e58a1b116710206feb68b2df39cf767c43c25 Mon Sep 17 00:00:00 2001 From: Shati Patel <42641846+shati-patel@users.noreply.github.com> Date: Wed, 22 Mar 2023 16:54:17 +0000 Subject: [PATCH 133/156] Tidy up recent changelog entries (#2211) --- extensions/ql-vscode/CHANGELOG.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/extensions/ql-vscode/CHANGELOG.md b/extensions/ql-vscode/CHANGELOG.md index 53184cdea..05d03d885 100644 --- a/extensions/ql-vscode/CHANGELOG.md +++ b/extensions/ql-vscode/CHANGELOG.md @@ -2,8 +2,8 @@ ## [UNRELEASED] -- Show data flow paths of a variant analysis in a new tab -- Show labels of entities in exported CSV results [#2170](https://github.com/github/vscode-codeql/pull/2170) +- Show data flow paths of a variant analysis in a new tab. [#2172](https://github.com/github/vscode-codeql/pull/2172) & [#2182](https://github.com/github/vscode-codeql/pull/2182) +- Show labels of entities in exported CSV results. [#2170](https://github.com/github/vscode-codeql/pull/2170) ## 1.8.0 - 9 March 2023 From 3e9c2c85d348f45b64cc3a7a6ab99dc55b48ffcf Mon Sep 17 00:00:00 2001 From: Robert Date: Wed, 22 Mar 2023 14:27:07 +0000 Subject: [PATCH 134/156] Remove app.executeCommand --- extensions/ql-vscode/src/common/app.ts | 1 - extensions/ql-vscode/src/common/commands.ts | 1 + extensions/ql-vscode/src/common/vscode/vscode-app.ts | 4 ---- .../ql-vscode/src/databases/config/db-config-store.ts | 8 ++++---- extensions/ql-vscode/test/__mocks__/appMock.ts | 3 --- .../unit-tests/databases/config/db-config-store.test.ts | 9 +++++++-- 6 files changed, 12 insertions(+), 14 deletions(-) diff --git a/extensions/ql-vscode/src/common/app.ts b/extensions/ql-vscode/src/common/app.ts index 278ea2b9d..2e749c018 100644 --- a/extensions/ql-vscode/src/common/app.ts +++ b/extensions/ql-vscode/src/common/app.ts @@ -7,7 +7,6 @@ import { AppCommandManager } from "./commands"; export interface App { createEventEmitter(): AppEventEmitter; - executeCommand(command: string, ...args: any): Thenable; readonly mode: AppMode; readonly logger: Logger; readonly subscriptions: Disposable[]; diff --git a/extensions/ql-vscode/src/common/commands.ts b/extensions/ql-vscode/src/common/commands.ts index a4ea3fb0f..a0669940d 100644 --- a/extensions/ql-vscode/src/common/commands.ts +++ b/extensions/ql-vscode/src/common/commands.ts @@ -36,6 +36,7 @@ export type SingleSelectionCommandFunction = ( // See https://code.visualstudio.com/api/references/commands export type BuiltInVsCodeCommands = { "markdown.showPreviewToSide": (uri: Uri) => Promise; + setContext: (key: string, value: unknown) => Promise; "workbench.action.reloadWindow": () => Promise; }; diff --git a/extensions/ql-vscode/src/common/vscode/vscode-app.ts b/extensions/ql-vscode/src/common/vscode/vscode-app.ts index 54032a8b1..a8f9da973 100644 --- a/extensions/ql-vscode/src/common/vscode/vscode-app.ts +++ b/extensions/ql-vscode/src/common/vscode/vscode-app.ts @@ -61,8 +61,4 @@ export class ExtensionApp implements App { public createEventEmitter(): AppEventEmitter { return new VSCodeAppEventEmitter(); } - - public executeCommand(command: string, ...args: any): Thenable { - return vscode.commands.executeCommand(command, ...args); - } } diff --git a/extensions/ql-vscode/src/databases/config/db-config-store.ts b/extensions/ql-vscode/src/databases/config/db-config-store.ts index 54a3c549d..3013d164f 100644 --- a/extensions/ql-vscode/src/databases/config/db-config-store.ts +++ b/extensions/ql-vscode/src/databases/config/db-config-store.ts @@ -391,14 +391,14 @@ export class DbConfigStore extends DisposableObject { if (this.configErrors.length === 0) { this.config = newConfig; - await this.app.executeCommand( + await this.app.commands.execute( "setContext", "codeQLVariantAnalysisRepositories.configError", false, ); } else { this.config = undefined; - await this.app.executeCommand( + await this.app.commands.execute( "setContext", "codeQLVariantAnalysisRepositories.configError", true, @@ -426,14 +426,14 @@ export class DbConfigStore extends DisposableObject { if (this.configErrors.length === 0) { this.config = newConfig; - void this.app.executeCommand( + void this.app.commands.execute( "setContext", "codeQLVariantAnalysisRepositories.configError", false, ); } else { this.config = undefined; - void this.app.executeCommand( + void this.app.commands.execute( "setContext", "codeQLVariantAnalysisRepositories.configError", true, diff --git a/extensions/ql-vscode/test/__mocks__/appMock.ts b/extensions/ql-vscode/test/__mocks__/appMock.ts index 6a4b05ba8..1b6d9da9d 100644 --- a/extensions/ql-vscode/test/__mocks__/appMock.ts +++ b/extensions/ql-vscode/test/__mocks__/appMock.ts @@ -14,7 +14,6 @@ export function createMockApp({ workspaceStoragePath = "/mock/workspace/storage/path", globalStoragePath = "/mock/global/storage/path", createEventEmitter = () => new MockAppEventEmitter(), - executeCommand = jest.fn(() => Promise.resolve()), workspaceState = createMockMemento(), credentials = testCredentialsWithStub(), commands = createMockCommandManager(), @@ -23,7 +22,6 @@ export function createMockApp({ workspaceStoragePath?: string; globalStoragePath?: string; createEventEmitter?: () => AppEventEmitter; - executeCommand?: () => Promise; workspaceState?: Memento; credentials?: Credentials; commands?: AppCommandManager; @@ -37,7 +35,6 @@ export function createMockApp({ globalStoragePath, workspaceState, createEventEmitter, - executeCommand, credentials, commands, }; diff --git a/extensions/ql-vscode/test/unit-tests/databases/config/db-config-store.test.ts b/extensions/ql-vscode/test/unit-tests/databases/config/db-config-store.test.ts index 7e0af0d86..ca4b7ead6 100644 --- a/extensions/ql-vscode/test/unit-tests/databases/config/db-config-store.test.ts +++ b/extensions/ql-vscode/test/unit-tests/databases/config/db-config-store.test.ts @@ -19,6 +19,7 @@ import { createRemoteUserDefinedListDbItem, } from "../../../factories/db-item-factories"; import { createMockApp } from "../../../__mocks__/appMock"; +import { createMockCommandManager } from "../../../__mocks__/commandsMock"; describe("db config store", () => { const extensionPath = join(__dirname, "../../../.."); @@ -136,14 +137,16 @@ describe("db config store", () => { it("should set codeQLVariantAnalysisRepositories.configError to true when config has error", async () => { const testDataStoragePathInvalid = join(__dirname, "data", "invalid"); + const executeCommand = jest.fn(); const app = createMockApp({ extensionPath, workspaceStoragePath: testDataStoragePathInvalid, + commands: createMockCommandManager({ executeCommand }), }); const configStore = new DbConfigStore(app, false); await configStore.initialize(); - expect(app.executeCommand).toBeCalledWith( + expect(executeCommand).toBeCalledWith( "setContext", "codeQLVariantAnalysisRepositories.configError", true, @@ -152,14 +155,16 @@ describe("db config store", () => { }); it("should set codeQLVariantAnalysisRepositories.configError to false when config is valid", async () => { + const executeCommand = jest.fn(); const app = createMockApp({ extensionPath, workspaceStoragePath: testDataStoragePath, + commands: createMockCommandManager({ executeCommand }), }); const configStore = new DbConfigStore(app, false); await configStore.initialize(); - expect(app.executeCommand).toBeCalledWith( + expect(executeCommand).toBeCalledWith( "setContext", "codeQLVariantAnalysisRepositories.configError", false, From 81cce9fa8b67324ea18fe4816a998fb01f1af952 Mon Sep 17 00:00:00 2001 From: Koen Vlaswinkel Date: Wed, 22 Mar 2023 17:19:45 +0100 Subject: [PATCH 135/156] Add `codeQL.checkForUpdatesToCLI` type for command The `codeQL.checkForUpdatesToCLI` command is registered pre-activation, and we don't really want to create the command manager before activation, so this will just add the correct type without registering it using the command manager. --- extensions/ql-vscode/src/common/commands.ts | 13 +++++++++++-- extensions/ql-vscode/src/extension.ts | 8 +++++++- 2 files changed, 18 insertions(+), 3 deletions(-) diff --git a/extensions/ql-vscode/src/common/commands.ts b/extensions/ql-vscode/src/common/commands.ts index a4ea3fb0f..a652d74d7 100644 --- a/extensions/ql-vscode/src/common/commands.ts +++ b/extensions/ql-vscode/src/common/commands.ts @@ -39,6 +39,13 @@ export type BuiltInVsCodeCommands = { "workbench.action.reloadWindow": () => Promise; }; +// Commands that are available before the extension is fully activated. +// These commands are *not* registered using the command manager, but can +// be invoked using the command manager. +export type PreActivationCommands = { + "codeQL.checkForUpdatesToCLI": () => Promise; +}; + // Base commands not tied directly to a module like e.g. variant analysis. export type BaseCommands = { "codeQL.openDocumentation": () => Promise; @@ -237,7 +244,7 @@ export type MockGitHubApiServerCommands = { "codeQL.mockGitHubApiServer.unloadScenario": () => Promise; }; -// All commands where the implementation is provided by this extension. +// All commands where the implementation is provided by this activated extension. export type AllExtensionCommands = BaseCommands & QueryEditorCommands & ResultsViewCommands & @@ -253,7 +260,9 @@ export type AllExtensionCommands = BaseCommands & Partial & MockGitHubApiServerCommands; -export type AllCommands = AllExtensionCommands & BuiltInVsCodeCommands; +export type AllCommands = AllExtensionCommands & + PreActivationCommands & + BuiltInVsCodeCommands; export type AppCommandManager = CommandManager; diff --git a/extensions/ql-vscode/src/extension.ts b/extensions/ql-vscode/src/extension.ts index a63ba9b45..3a99ac4ea 100644 --- a/extensions/ql-vscode/src/extension.ts +++ b/extensions/ql-vscode/src/extension.ts @@ -112,6 +112,7 @@ import { QueryHistoryDirs } from "./query-history/query-history-dirs"; import { AllExtensionCommands, BaseCommands, + PreActivationCommands, QueryServerCommands, TestUICommands, } from "./common/commands"; @@ -204,6 +205,8 @@ function registerErrorStubs( stubbedCommands.forEach((command) => { if (excludedCommands.indexOf(command) === -1) { + // This is purposefully using `commandRunner` instead of the command manager because these + // commands are untyped and registered pre-activation. errorStubs.push(commandRunner(command, stubGenerator(command))); } }); @@ -305,6 +308,8 @@ export async function activate( ), ); ctx.subscriptions.push( + // This is purposefully using `commandRunner` directly instead of the command manager + // because this command is registered pre-activation. commandRunner(checkForUpdatesCommand, () => installOrUpdateThenTryActivate( ctx, @@ -1096,7 +1101,8 @@ async function initializeLogging(ctx: ExtensionContext): Promise { ctx.subscriptions.push(ideServerLogger); } -const checkForUpdatesCommand = "codeQL.checkForUpdatesToCLI"; +const checkForUpdatesCommand: keyof PreActivationCommands = + "codeQL.checkForUpdatesToCLI" as const; const avoidVersionCheck = "avoid-version-check-at-startup"; const lastVersionChecked = "last-version-checked"; From aca0489fdcc5541c34064e8ea23fa26ca8d1aae0 Mon Sep 17 00:00:00 2001 From: Koen Vlaswinkel Date: Thu, 23 Mar 2023 11:09:32 +0100 Subject: [PATCH 136/156] Remove `commandRunnerWithProgress` The `commandRunnerWithProgress` is unused because all commands have been converted to using `commandRunner` in combination with `withProgress`. --- extensions/ql-vscode/src/commandRunner.ts | 58 +---------------------- 1 file changed, 2 insertions(+), 56 deletions(-) diff --git a/extensions/ql-vscode/src/commandRunner.ts b/extensions/ql-vscode/src/commandRunner.ts index ea1a84526..86b5cb971 100644 --- a/extensions/ql-vscode/src/commandRunner.ts +++ b/extensions/ql-vscode/src/commandRunner.ts @@ -1,4 +1,4 @@ -import { CancellationToken, commands, Disposable } from "vscode"; +import { commands, Disposable } from "vscode"; import { showAndLogExceptionWithTelemetry, showAndLogWarningMessage, @@ -7,12 +7,7 @@ import { extLogger } from "./common"; import { asError, getErrorMessage, getErrorStack } from "./pure/helpers-pure"; import { telemetryListener } from "./telemetry"; import { redactableError } from "./pure/errors"; -import { - UserCancellationException, - withProgress, - ProgressOptions, - ProgressCallback, -} from "./progress"; +import { UserCancellationException } from "./progress"; /** * A task that handles command invocations from `commandRunner`. @@ -24,27 +19,6 @@ import { */ export type NoProgressTask = (...args: any[]) => Promise; -/** - * A task that handles command invocations from `commandRunner` - * and includes a progress monitor. - * - * - * Arguments passed to the command handler are passed along, - * untouched to this `ProgressTaskWithArgs` instance. - * - * @param progress a progress handler function. Call this - * function with a `ProgressUpdate` instance in order to - * denote some progress being achieved on this task. - * @param token a cancellation token - * @param args arguments passed to this task passed on from - * `commands.registerCommand`. - */ -type ProgressTaskWithArgs = ( - progress: ProgressCallback, - token: CancellationToken, - ...args: any[] -) => Thenable; - /** * A generic wrapper for command registration. This wrapper adds uniform error handling for commands. * @@ -100,31 +74,3 @@ export function commandRunner( } }); } - -/** - * A generic wrapper for command registration. This wrapper adds uniform error handling, - * progress monitoring, and cancellation for commands. - * - * @param commandId The ID of the command to register. - * @param task The task to run. It is passed directly to `commands.registerCommand`. Any - * arguments to the command handler are passed on to the task after the progress callback - * and cancellation token. - * @param progressOptions Progress options to be sent to the progress monitor. - */ -export function commandRunnerWithProgress( - commandId: string, - task: ProgressTaskWithArgs, - progressOptions: ProgressOptions, - outputLogger = extLogger, -): Disposable { - return commandRunner( - commandId, - async (...args: any[]) => { - return withProgress( - (progress, token) => task(progress, token, ...args), - progressOptions, - ); - }, - outputLogger, - ); -} From 8fbde9fba11daad7792fb8b6e6d26c42a9508346 Mon Sep 17 00:00:00 2001 From: Robert Date: Thu, 23 Mar 2023 10:12:20 +0000 Subject: [PATCH 137/156] Limit setContext keys --- extensions/ql-vscode/src/common/commands.ts | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/extensions/ql-vscode/src/common/commands.ts b/extensions/ql-vscode/src/common/commands.ts index a0669940d..d399e8d99 100644 --- a/extensions/ql-vscode/src/common/commands.ts +++ b/extensions/ql-vscode/src/common/commands.ts @@ -36,7 +36,10 @@ export type SingleSelectionCommandFunction = ( // See https://code.visualstudio.com/api/references/commands export type BuiltInVsCodeCommands = { "markdown.showPreviewToSide": (uri: Uri) => Promise; - setContext: (key: string, value: unknown) => Promise; + setContext: ( + key: `${"codeql" | "codeQL"}${string}`, + value: unknown, + ) => Promise; "workbench.action.reloadWindow": () => Promise; }; From aa268cfc5f9039be2936e04f39b73ee55c27d8ac Mon Sep 17 00:00:00 2001 From: Koen Vlaswinkel Date: Thu, 23 Mar 2023 11:13:26 +0100 Subject: [PATCH 138/156] Rename and move `commandRunner` The `commandRunner` name doesn't really make sense since it doesn't "run" a command, but rather registers a command. This renames it to `registerCommandWithErrorHandling` and moves it to the `common/vscode` directory. --- extensions/ql-vscode/src/commandRunner.ts | 76 ------------------- .../ql-vscode/src/common/vscode/commands.ts | 75 ++++++++++++++++-- extensions/ql-vscode/src/extension.ts | 8 +- 3 files changed, 75 insertions(+), 84 deletions(-) delete mode 100644 extensions/ql-vscode/src/commandRunner.ts diff --git a/extensions/ql-vscode/src/commandRunner.ts b/extensions/ql-vscode/src/commandRunner.ts deleted file mode 100644 index 86b5cb971..000000000 --- a/extensions/ql-vscode/src/commandRunner.ts +++ /dev/null @@ -1,76 +0,0 @@ -import { commands, Disposable } from "vscode"; -import { - showAndLogExceptionWithTelemetry, - showAndLogWarningMessage, -} from "./helpers"; -import { extLogger } from "./common"; -import { asError, getErrorMessage, getErrorStack } from "./pure/helpers-pure"; -import { telemetryListener } from "./telemetry"; -import { redactableError } from "./pure/errors"; -import { UserCancellationException } from "./progress"; - -/** - * A task that handles command invocations from `commandRunner`. - * Arguments passed to the command handler are passed along, - * untouched to this `NoProgressTask` instance. - * - * @param args arguments passed to this task passed on from - * `commands.registerCommand`. - */ -export type NoProgressTask = (...args: any[]) => Promise; - -/** - * A generic wrapper for command registration. This wrapper adds uniform error handling for commands. - * - * In this variant of the command runner, no progress monitor is used. - * - * @param commandId The ID of the command to register. - * @param task The task to run. It is passed directly to `commands.registerCommand`. Any - * arguments to the command handler are passed on to the task. - */ -export function commandRunner( - commandId: string, - task: NoProgressTask, - outputLogger = extLogger, -): Disposable { - return commands.registerCommand(commandId, async (...args: any[]) => { - const startTime = Date.now(); - let error: Error | undefined; - - try { - return await task(...args); - } catch (e) { - error = asError(e); - const errorMessage = redactableError(error)`${ - getErrorMessage(e) || e - } (${commandId})`; - const errorStack = getErrorStack(e); - if (e instanceof UserCancellationException) { - // User has cancelled this action manually - if (e.silent) { - void outputLogger.log(errorMessage.fullMessage); - } else { - void showAndLogWarningMessage(errorMessage.fullMessage, { - outputLogger, - }); - } - } else { - // Include the full stack in the error log only. - const fullMessage = errorStack - ? `${errorMessage.fullMessage}\n${errorStack}` - : errorMessage.fullMessage; - void showAndLogExceptionWithTelemetry(errorMessage, { - outputLogger, - fullMessage, - extraTelemetryProperties: { - command: commandId, - }, - }); - } - return undefined; - } finally { - const executionTime = Date.now() - startTime; - telemetryListener?.sendCommandUsage(commandId, executionTime, error); - } - }); -} diff --git a/extensions/ql-vscode/src/common/vscode/commands.ts b/extensions/ql-vscode/src/common/vscode/commands.ts index fc8db2a78..04aa02a5b 100644 --- a/extensions/ql-vscode/src/common/vscode/commands.ts +++ b/extensions/ql-vscode/src/common/vscode/commands.ts @@ -1,7 +1,18 @@ -import { commands } from "vscode"; -import { commandRunner, NoProgressTask } from "../../commandRunner"; +import { commands, Disposable } from "vscode"; import { CommandFunction, CommandManager } from "../../packages/commands"; -import { OutputChannelLogger } from "../logging"; +import { extLogger, OutputChannelLogger } from "../logging"; +import { + asError, + getErrorMessage, + getErrorStack, +} from "../../pure/helpers-pure"; +import { redactableError } from "../../pure/errors"; +import { UserCancellationException } from "../../progress"; +import { + showAndLogExceptionWithTelemetry, + showAndLogWarningMessage, +} from "../../helpers"; +import { telemetryListener } from "../../telemetry"; /** * Create a command manager for VSCode, wrapping the commandRunner @@ -10,11 +21,65 @@ import { OutputChannelLogger } from "../logging"; export function createVSCodeCommandManager< Commands extends Record, >(outputLogger?: OutputChannelLogger): CommandManager { - return new CommandManager((commandId, task: NoProgressTask) => { - return commandRunner(commandId, task, outputLogger); + return new CommandManager((commandId, task) => { + return registerCommandWithErrorHandling(commandId, task, outputLogger); }, wrapExecuteCommand); } +/** + * A wrapper for command registration. This wrapper adds uniform error handling for commands. + * + * @param commandId The ID of the command to register. + * @param task The task to run. It is passed directly to `commands.registerCommand`. Any + * arguments to the command handler are passed on to the task. + */ +export function registerCommandWithErrorHandling( + commandId: string, + task: (...args: any[]) => Promise, + outputLogger = extLogger, +): Disposable { + return commands.registerCommand(commandId, async (...args: any[]) => { + const startTime = Date.now(); + let error: Error | undefined; + + try { + return await task(...args); + } catch (e) { + error = asError(e); + const errorMessage = redactableError(error)`${ + getErrorMessage(e) || e + } (${commandId})`; + const errorStack = getErrorStack(e); + if (e instanceof UserCancellationException) { + // User has cancelled this action manually + if (e.silent) { + void outputLogger.log(errorMessage.fullMessage); + } else { + void showAndLogWarningMessage(errorMessage.fullMessage, { + outputLogger, + }); + } + } else { + // Include the full stack in the error log only. + const fullMessage = errorStack + ? `${errorMessage.fullMessage}\n${errorStack}` + : errorMessage.fullMessage; + void showAndLogExceptionWithTelemetry(errorMessage, { + outputLogger, + fullMessage, + extraTelemetryProperties: { + command: commandId, + }, + }); + } + return undefined; + } finally { + const executionTime = Date.now() - startTime; + telemetryListener?.sendCommandUsage(commandId, executionTime, error); + } + }); +} + /** * wrapExecuteCommand wraps commands.executeCommand to satisfy that the * type is a Promise. Type script does not seem to be smart enough diff --git a/extensions/ql-vscode/src/extension.ts b/extensions/ql-vscode/src/extension.ts index 63ece980d..fb973b9b7 100644 --- a/extensions/ql-vscode/src/extension.ts +++ b/extensions/ql-vscode/src/extension.ts @@ -87,7 +87,6 @@ import { QLTestAdapterFactory } from "./test-adapter"; import { TestUIService } from "./test-ui"; import { CompareView } from "./compare/compare-view"; import { initializeTelemetry } from "./telemetry"; -import { commandRunner } from "./commandRunner"; import { ProgressCallback, withProgress } from "./progress"; import { CodeQlStatusBarHandler } from "./status-bar"; import { getPackagingCommands } from "./packaging"; @@ -123,6 +122,7 @@ import { import { getAstCfgCommands } from "./ast-cfg-commands"; import { getQueryEditorCommands } from "./query-editor"; import { App } from "./common/app"; +import { registerCommandWithErrorHandling } from "./common/vscode/commands"; /** * extension.ts @@ -238,7 +238,9 @@ function registerErrorStubs( if (excludedCommands.indexOf(command) === -1) { // This is purposefully using `commandRunner` instead of the command manager because these // commands are untyped and registered pre-activation. - errorStubs.push(commandRunner(command, stubGenerator(command))); + errorStubs.push( + registerCommandWithErrorHandling(command, stubGenerator(command)), + ); } }); } @@ -341,7 +343,7 @@ export async function activate( ctx.subscriptions.push( // This is purposefully using `commandRunner` directly instead of the command manager // because this command is registered pre-activation. - commandRunner(checkForUpdatesCommand, () => + registerCommandWithErrorHandling(checkForUpdatesCommand, () => installOrUpdateThenTryActivate( ctx, app, From 13c3c8efe4270bd7a8e26f038bc0485bc1c8a155 Mon Sep 17 00:00:00 2001 From: Robert Date: Wed, 22 Mar 2023 15:47:30 +0000 Subject: [PATCH 139/156] Convert extensions/ql-vscode/src/cli.ts to call typed commands --- extensions/ql-vscode/src/cli.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/extensions/ql-vscode/src/cli.ts b/extensions/ql-vscode/src/cli.ts index ae24e905b..45c6a7f6c 100644 --- a/extensions/ql-vscode/src/cli.ts +++ b/extensions/ql-vscode/src/cli.ts @@ -9,7 +9,7 @@ import { Readable } from "stream"; import { StringDecoder } from "string_decoder"; import tk from "tree-kill"; import { promisify } from "util"; -import { CancellationToken, commands, Disposable, Uri } from "vscode"; +import { CancellationToken, Disposable, Uri } from "vscode"; import { BQRSInfo, DecodedBqrsChunk } from "./pure/bqrs-cli-types"; import { allowCanaryQueryServer, CliConfig } from "./config"; @@ -1375,7 +1375,7 @@ export class CodeQLCliServer implements Disposable { if (!this._version) { this._version = this.refreshVersion(); // this._version is only undefined upon config change, so we reset CLI-based context key only when necessary. - await commands.executeCommand( + await this.app.commands.execute( "setContext", "codeql.supportsEvalLog", await this.cliConstraints.supportsPerQueryEvalLog(), From 4c7c1cb0e6e9aa09232451266be1a427fe787a72 Mon Sep 17 00:00:00 2001 From: Shati Patel <42641846+shati-patel@users.noreply.github.com> Date: Thu, 23 Mar 2023 11:00:29 +0000 Subject: [PATCH 140/156] v1.8.1 (#2216) --- extensions/ql-vscode/CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/extensions/ql-vscode/CHANGELOG.md b/extensions/ql-vscode/CHANGELOG.md index 05d03d885..1d2c2139b 100644 --- a/extensions/ql-vscode/CHANGELOG.md +++ b/extensions/ql-vscode/CHANGELOG.md @@ -1,6 +1,6 @@ # CodeQL for Visual Studio Code: Changelog -## [UNRELEASED] +## 1.8.1 - 23 March 2023 - Show data flow paths of a variant analysis in a new tab. [#2172](https://github.com/github/vscode-codeql/pull/2172) & [#2182](https://github.com/github/vscode-codeql/pull/2182) - Show labels of entities in exported CSV results. [#2170](https://github.com/github/vscode-codeql/pull/2170) From 75634b365404f2b9363463aaf37276bfd4dc6944 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Thu, 23 Mar 2023 11:39:09 +0000 Subject: [PATCH 141/156] Bump version to v1.8.2 (#2218) --- extensions/ql-vscode/CHANGELOG.md | 2 ++ extensions/ql-vscode/package-lock.json | 4 ++-- extensions/ql-vscode/package.json | 2 +- 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/extensions/ql-vscode/CHANGELOG.md b/extensions/ql-vscode/CHANGELOG.md index 1d2c2139b..56dcf5fc9 100644 --- a/extensions/ql-vscode/CHANGELOG.md +++ b/extensions/ql-vscode/CHANGELOG.md @@ -1,5 +1,7 @@ # CodeQL for Visual Studio Code: Changelog +## [UNRELEASED] + ## 1.8.1 - 23 March 2023 - Show data flow paths of a variant analysis in a new tab. [#2172](https://github.com/github/vscode-codeql/pull/2172) & [#2182](https://github.com/github/vscode-codeql/pull/2182) diff --git a/extensions/ql-vscode/package-lock.json b/extensions/ql-vscode/package-lock.json index a673eaf66..e4546b988 100644 --- a/extensions/ql-vscode/package-lock.json +++ b/extensions/ql-vscode/package-lock.json @@ -1,12 +1,12 @@ { "name": "vscode-codeql", - "version": "1.8.1", + "version": "1.8.2", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "vscode-codeql", - "version": "1.8.1", + "version": "1.8.2", "hasInstallScript": true, "license": "MIT", "dependencies": { diff --git a/extensions/ql-vscode/package.json b/extensions/ql-vscode/package.json index 28b66f99c..19e0a0eb4 100644 --- a/extensions/ql-vscode/package.json +++ b/extensions/ql-vscode/package.json @@ -4,7 +4,7 @@ "description": "CodeQL for Visual Studio Code", "author": "GitHub", "private": true, - "version": "1.8.1", + "version": "1.8.2", "publisher": "GitHub", "license": "MIT", "icon": "media/VS-marketplace-CodeQL-icon.png", From ddf5b3aac292ddd861245455cea33e9a9b6ce1c4 Mon Sep 17 00:00:00 2001 From: Robert Date: Wed, 22 Mar 2023 15:50:06 +0000 Subject: [PATCH 142/156] Convert extensions/ql-vscode/src/databaseFetcher.ts to call typed commands --- extensions/ql-vscode/src/common/commands.ts | 1 + extensions/ql-vscode/src/databaseFetcher.ts | 12 ++++++++---- extensions/ql-vscode/src/local-databases-ui.ts | 4 ++++ .../cli-integration/databaseFetcher.test.ts | 3 +++ .../vscode-tests/cli-integration/new-query.test.ts | 2 ++ .../vscode-tests/cli-integration/queries.test.ts | 2 ++ 6 files changed, 20 insertions(+), 4 deletions(-) diff --git a/extensions/ql-vscode/src/common/commands.ts b/extensions/ql-vscode/src/common/commands.ts index aa7792624..0a308c1b5 100644 --- a/extensions/ql-vscode/src/common/commands.ts +++ b/extensions/ql-vscode/src/common/commands.ts @@ -35,6 +35,7 @@ export type SingleSelectionCommandFunction = ( // Builtin commands where the implementation is provided by VS Code and not by this extension. // See https://code.visualstudio.com/api/references/commands export type BuiltInVsCodeCommands = { + "codeQLDatabases.focus": () => Promise; "markdown.showPreviewToSide": (uri: Uri) => Promise; setContext: ( key: `${"codeql" | "codeQL"}${string}`, diff --git a/extensions/ql-vscode/src/databaseFetcher.ts b/extensions/ql-vscode/src/databaseFetcher.ts index ac63fffbb..cd6c9acf9 100644 --- a/extensions/ql-vscode/src/databaseFetcher.ts +++ b/extensions/ql-vscode/src/databaseFetcher.ts @@ -1,7 +1,7 @@ import fetch, { Response } from "node-fetch"; import { zip } from "zip-a-folder"; import { Open } from "unzipper"; -import { Uri, CancellationToken, commands, window } from "vscode"; +import { Uri, CancellationToken, window } from "vscode"; import { CodeQLCliServer } from "./cli"; import { ensureDir, @@ -26,6 +26,7 @@ import { isValidGitHubNwo, } from "./common/github-url-identifier-helper"; import { Credentials } from "./common/authentication"; +import { AppCommandManager } from "./common/commands"; /** * Prompts a user to fetch a database from a remote location. Database is assumed to be an archive file. @@ -34,6 +35,7 @@ import { Credentials } from "./common/authentication"; * @param storagePath where to store the unzipped database. */ export async function promptImportInternetDatabase( + commandManager: AppCommandManager, databaseManager: DatabaseManager, storagePath: string, progress: ProgressCallback, @@ -61,7 +63,7 @@ export async function promptImportInternetDatabase( ); if (item) { - await commands.executeCommand("codeQLDatabases.focus"); + await commandManager.execute("codeQLDatabases.focus"); void showAndLogInformationMessage( "Database downloaded and imported successfully.", ); @@ -78,6 +80,7 @@ export async function promptImportInternetDatabase( * @param storagePath where to store the unzipped database. */ export async function promptImportGithubDatabase( + commandManager: AppCommandManager, databaseManager: DatabaseManager, storagePath: string, credentials: Credentials | undefined, @@ -141,7 +144,7 @@ export async function promptImportGithubDatabase( cli, ); if (item) { - await commands.executeCommand("codeQLDatabases.focus"); + await commandManager.execute("codeQLDatabases.focus"); void showAndLogInformationMessage( "Database downloaded and imported successfully.", ); @@ -158,6 +161,7 @@ export async function promptImportGithubDatabase( * @param storagePath where to store the unzipped database. */ export async function importArchiveDatabase( + commandManager: AppCommandManager, databaseUrl: string, databaseManager: DatabaseManager, storagePath: string, @@ -177,7 +181,7 @@ export async function importArchiveDatabase( cli, ); if (item) { - await commands.executeCommand("codeQLDatabases.focus"); + await commandManager.execute("codeQLDatabases.focus"); void showAndLogInformationMessage( "Database unzipped and imported successfully.", ); diff --git a/extensions/ql-vscode/src/local-databases-ui.ts b/extensions/ql-vscode/src/local-databases-ui.ts index 81bf64097..f1d88edb6 100644 --- a/extensions/ql-vscode/src/local-databases-ui.ts +++ b/extensions/ql-vscode/src/local-databases-ui.ts @@ -451,6 +451,7 @@ export class DatabaseUI extends DisposableObject { return withProgress( async (progress, token) => { await promptImportInternetDatabase( + this.app.commands, this.databaseManager, this.storagePath, progress, @@ -470,6 +471,7 @@ export class DatabaseUI extends DisposableObject { const credentials = isCanary() ? this.app.credentials : undefined; await promptImportGithubDatabase( + this.app.commands, this.databaseManager, this.storagePath, credentials, @@ -607,6 +609,7 @@ export class DatabaseUI extends DisposableObject { // Assume user has selected an archive if the file has a .zip extension if (uri.path.endsWith(".zip")) { await importArchiveDatabase( + this.app.commands, uri.toString(true), this.databaseManager, this.storagePath, @@ -762,6 +765,7 @@ export class DatabaseUI extends DisposableObject { // we are selecting a database archive. Must unzip into a workspace-controlled area // before importing. return await importArchiveDatabase( + this.app.commands, uri.toString(true), this.databaseManager, this.storagePath, diff --git a/extensions/ql-vscode/test/vscode-tests/cli-integration/databaseFetcher.test.ts b/extensions/ql-vscode/test/vscode-tests/cli-integration/databaseFetcher.test.ts index 407c22176..3ba6d5806 100644 --- a/extensions/ql-vscode/test/vscode-tests/cli-integration/databaseFetcher.test.ts +++ b/extensions/ql-vscode/test/vscode-tests/cli-integration/databaseFetcher.test.ts @@ -9,6 +9,7 @@ import { promptImportInternetDatabase, } from "../../../src/databaseFetcher"; import { cleanDatabases, dbLoc, DB_URL, storagePath } from "../global.helper"; +import { createMockCommandManager } from "../../__mocks__/commandsMock"; jest.setTimeout(60_000); @@ -53,6 +54,7 @@ describe("DatabaseFetcher", () => { it("should add a database from a folder", async () => { const uri = Uri.file(dbLoc); let dbItem = await importArchiveDatabase( + createMockCommandManager(), uri.toString(true), databaseManager, storagePath, @@ -75,6 +77,7 @@ describe("DatabaseFetcher", () => { inputBoxStub.mockResolvedValue(DB_URL); let dbItem = await promptImportInternetDatabase( + createMockCommandManager(), databaseManager, storagePath, progressCallback, diff --git a/extensions/ql-vscode/test/vscode-tests/cli-integration/new-query.test.ts b/extensions/ql-vscode/test/vscode-tests/cli-integration/new-query.test.ts index a7d8f9d4b..4d47f3b02 100644 --- a/extensions/ql-vscode/test/vscode-tests/cli-integration/new-query.test.ts +++ b/extensions/ql-vscode/test/vscode-tests/cli-integration/new-query.test.ts @@ -13,6 +13,7 @@ import { extLogger, ProgressReporter } from "../../../src/common"; import { QueryResultType } from "../../../src/pure/new-messages"; import { cleanDatabases, dbLoc, storagePath } from "../global.helper"; import { importArchiveDatabase } from "../../../src/databaseFetcher"; +import { createMockCommandManager } from "../../__mocks__/commandsMock"; const baseDir = join(__dirname, "../../../test/data"); @@ -147,6 +148,7 @@ describeWithCodeQL()("using the new query server", () => { await cleanDatabases(extension.databaseManager); const uri = Uri.file(dbLoc); const maybeDbItem = await importArchiveDatabase( + createMockCommandManager(), uri.toString(true), extension.databaseManager, storagePath, diff --git a/extensions/ql-vscode/test/vscode-tests/cli-integration/queries.test.ts b/extensions/ql-vscode/test/vscode-tests/cli-integration/queries.test.ts index 65b304235..b750bbae9 100644 --- a/extensions/ql-vscode/test/vscode-tests/cli-integration/queries.test.ts +++ b/extensions/ql-vscode/test/vscode-tests/cli-integration/queries.test.ts @@ -26,6 +26,7 @@ import { createInitialQueryInfo } from "../../../src/run-queries-shared"; import { QueryRunner } from "../../../src/queryRunner"; import { CompletedQueryInfo } from "../../../src/query-results"; import { SELECT_QUERY_NAME } from "../../../src/contextual/locationFinder"; +import { createMockCommandManager } from "../../__mocks__/commandsMock"; jest.setTimeout(20_000); @@ -78,6 +79,7 @@ describeWithCodeQL()("Queries", () => { await cleanDatabases(databaseManager); const uri = Uri.file(dbLoc); const maybeDbItem = await importArchiveDatabase( + createMockCommandManager(), uri.toString(true), databaseManager, storagePath, From c394b7c4f0f341497a226963e5e7203b4ce5833d Mon Sep 17 00:00:00 2001 From: Robert Date: Wed, 22 Mar 2023 16:19:58 +0000 Subject: [PATCH 143/156] Convert extensions/ql-vscode/src/helpers.ts to call typed commands --- extensions/ql-vscode/src/common/commands.ts | 1 + extensions/ql-vscode/src/extension.ts | 2 +- extensions/ql-vscode/src/helpers.ts | 8 +++-- .../vscode-tests/no-workspace/helpers.test.ts | 34 +++++++------------ 4 files changed, 20 insertions(+), 25 deletions(-) diff --git a/extensions/ql-vscode/src/common/commands.ts b/extensions/ql-vscode/src/common/commands.ts index 0a308c1b5..171ff5be8 100644 --- a/extensions/ql-vscode/src/common/commands.ts +++ b/extensions/ql-vscode/src/common/commands.ts @@ -42,6 +42,7 @@ export type BuiltInVsCodeCommands = { value: unknown, ) => Promise; "workbench.action.reloadWindow": () => Promise; + "vscode.openFolder": (uri: Uri) => Promise; }; // Commands that are available before the extension is fully activated. diff --git a/extensions/ql-vscode/src/extension.ts b/extensions/ql-vscode/src/extension.ts index 63ece980d..b1c6211f2 100644 --- a/extensions/ql-vscode/src/extension.ts +++ b/extensions/ql-vscode/src/extension.ts @@ -573,7 +573,7 @@ async function installOrUpdateThenTryActivate( await installOrUpdateDistribution(ctx, app, distributionManager, config); try { - await prepareCodeTour(); + await prepareCodeTour(app.commands); } catch (e: unknown) { void extLogger.log( `Could not open tutorial workspace automatically: ${getErrorMessage(e)}`, diff --git a/extensions/ql-vscode/src/helpers.ts b/extensions/ql-vscode/src/helpers.ts index 33f5abd45..2576f6b48 100644 --- a/extensions/ql-vscode/src/helpers.ts +++ b/extensions/ql-vscode/src/helpers.ts @@ -16,7 +16,6 @@ import { window as Window, workspace, env, - commands, } from "vscode"; import { CodeQLCliServer, QlpacksInfo } from "./cli"; import { UserCancellationException } from "./progress"; @@ -27,6 +26,7 @@ import { RedactableError } from "./pure/errors"; import { getQlPackPath } from "./pure/ql"; import { dbSchemeToLanguage } from "./common/query-language"; import { isCodespacesTemplate } from "./config"; +import { AppCommandManager } from "./common/commands"; // Shared temporary folder for the extension. export const tmpDir = dirSync({ @@ -271,7 +271,9 @@ export function isFolderAlreadyInWorkspace(folderName: string) { /** Check if the current workspace is the CodeTour and open the workspace folder. * Without this, we can't run the code tour correctly. **/ -export async function prepareCodeTour(): Promise { +export async function prepareCodeTour( + commandManager: AppCommandManager, +): Promise { if (workspace.workspaceFolders?.length) { const currentFolder = workspace.workspaceFolders[0].uri.fsPath; @@ -308,7 +310,7 @@ export async function prepareCodeTour(): Promise { `In prepareCodeTour() method, going to open the tutorial workspace file: ${tutorialWorkspacePath}`, ); - await commands.executeCommand("vscode.openFolder", tutorialWorkspaceUri); + await commandManager.execute("vscode.openFolder", tutorialWorkspaceUri); } } } diff --git a/extensions/ql-vscode/test/vscode-tests/no-workspace/helpers.test.ts b/extensions/ql-vscode/test/vscode-tests/no-workspace/helpers.test.ts index 8fe7a47bd..49bb5117d 100644 --- a/extensions/ql-vscode/test/vscode-tests/no-workspace/helpers.test.ts +++ b/extensions/ql-vscode/test/vscode-tests/no-workspace/helpers.test.ts @@ -1,5 +1,4 @@ import { - commands, EnvironmentVariableCollection, EnvironmentVariableMutator, Event, @@ -41,6 +40,7 @@ import { import { reportStreamProgress } from "../../../src/progress"; import { QueryLanguage } from "../../../src/common/query-language"; import { Setting } from "../../../src/config"; +import { createMockCommandManager } from "../../__mocks__/commandsMock"; describe("helpers", () => { describe("Invocation rate limiter", () => { @@ -612,13 +612,11 @@ describe("prepareCodeTour", () => { await mkdir(tourDirPath); // spy that we open the workspace file by calling the 'vscode.openFolder' command - const commandSpy = jest.spyOn(commands, "executeCommand"); - commandSpy.mockImplementation(() => Promise.resolve()); - - await prepareCodeTour(); + const executeCommand = jest.fn(); + await prepareCodeTour(createMockCommandManager({ executeCommand })); expect(showInformationMessageSpy).toHaveBeenCalled(); - expect(commandSpy).toHaveBeenCalledWith( + expect(executeCommand).toHaveBeenCalledWith( "vscode.openFolder", expect.objectContaining({ path: Uri.parse(tutorialWorkspacePath).fsPath, @@ -641,12 +639,10 @@ describe("prepareCodeTour", () => { await mkdir(tourDirPath); // spy that we open the workspace file by calling the 'vscode.openFolder' command - const commandSpy = jest.spyOn(commands, "executeCommand"); - commandSpy.mockImplementation(() => Promise.resolve()); + const executeCommand = jest.fn(); + await prepareCodeTour(createMockCommandManager({ executeCommand })); - await prepareCodeTour(); - - expect(commandSpy).not.toHaveBeenCalled(); + expect(executeCommand).not.toHaveBeenCalled(); }); }); }); @@ -658,24 +654,20 @@ describe("prepareCodeTour", () => { await mkdir(tourDirPath); // spy that we open the workspace file by calling the 'vscode.openFolder' command - const commandSpy = jest.spyOn(commands, "executeCommand"); - commandSpy.mockImplementation(() => Promise.resolve()); + const executeCommand = jest.fn(); + await prepareCodeTour(createMockCommandManager({ executeCommand })); - await prepareCodeTour(); - - expect(commandSpy).not.toHaveBeenCalled(); + expect(executeCommand).not.toHaveBeenCalled(); }); }); describe("if we're in a different repo with no tour", () => { it("should not open the tutorial workspace", async () => { // spy that we open the workspace file by calling the 'vscode.openFolder' command - const commandSpy = jest.spyOn(commands, "executeCommand"); - commandSpy.mockImplementation(() => Promise.resolve()); + const executeCommand = jest.fn(); + await prepareCodeTour(createMockCommandManager({ executeCommand })); - await prepareCodeTour(); - - expect(commandSpy).not.toHaveBeenCalled(); + expect(executeCommand).not.toHaveBeenCalled(); }); }); }); From 8b9003e84564c2a18aad41abf46008c88fb9a511 Mon Sep 17 00:00:00 2001 From: Robert Date: Wed, 22 Mar 2023 16:42:34 +0000 Subject: [PATCH 144/156] Convert extensions/ql-vscode/src/local-databases.ts to call typed commands --- extensions/ql-vscode/src/extension.ts | 2 +- extensions/ql-vscode/src/local-databases.ts | 4 +++- .../vscode-tests/minimal-workspace/local-databases.test.ts | 2 ++ 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/extensions/ql-vscode/src/extension.ts b/extensions/ql-vscode/src/extension.ts index b1c6211f2..cb0a58771 100644 --- a/extensions/ql-vscode/src/extension.ts +++ b/extensions/ql-vscode/src/extension.ts @@ -678,7 +678,7 @@ async function activateWithInstalledDistribution( } void extLogger.log("Initializing database manager."); - const dbm = new DatabaseManager(ctx, qs, cliServer, extLogger); + const dbm = new DatabaseManager(ctx, app, qs, cliServer, extLogger); // Let this run async. void dbm.loadPersistedState(); diff --git a/extensions/ql-vscode/src/local-databases.ts b/extensions/ql-vscode/src/local-databases.ts index 3d390b472..918ddd5fc 100644 --- a/extensions/ql-vscode/src/local-databases.ts +++ b/extensions/ql-vscode/src/local-databases.ts @@ -28,6 +28,7 @@ import { redactableError } from "./pure/errors"; import { isCodespacesTemplate } from "./config"; import { QlPackGenerator } from "./qlpack-generator"; import { QueryLanguage } from "./common/query-language"; +import { App } from "./common/app"; /** * databases.ts @@ -593,6 +594,7 @@ export class DatabaseManager extends DisposableObject { constructor( private readonly ctx: ExtensionContext, + private readonly app: App, private readonly qs: QueryRunner, private readonly cli: cli.CodeQLCliServer, public logger: Logger, @@ -875,7 +877,7 @@ export class DatabaseManager extends DisposableObject { this._currentDatabaseItem = item; this.updatePersistedCurrentDatabaseItem(); - await vscode.commands.executeCommand( + await this.app.commands.execute( "setContext", "codeQL.currentDatabaseItem", item?.name, diff --git a/extensions/ql-vscode/test/vscode-tests/minimal-workspace/local-databases.test.ts b/extensions/ql-vscode/test/vscode-tests/minimal-workspace/local-databases.test.ts index 6c4167c06..c106110e8 100644 --- a/extensions/ql-vscode/test/vscode-tests/minimal-workspace/local-databases.test.ts +++ b/extensions/ql-vscode/test/vscode-tests/minimal-workspace/local-databases.test.ts @@ -25,6 +25,7 @@ import * as helpers from "../../../src/helpers"; import { Setting } from "../../../src/config"; import { QlPackGenerator } from "../../../src/qlpack-generator"; import { mockedObject } from "../utils/mocking.helpers"; +import { createMockApp } from "../../__mocks__/appMock"; describe("local databases", () => { const MOCK_DB_OPTIONS: FullDatabaseOptions = { @@ -87,6 +88,7 @@ describe("local databases", () => { databaseManager = new DatabaseManager( extensionContext, + createMockApp({}), mockedObject({ registerDatabase: registerSpy, deregisterDatabase: deregisterSpy, From ff418b5487febbc182f797e5a4656a2cce7c9e47 Mon Sep 17 00:00:00 2001 From: Robert Date: Wed, 22 Mar 2023 16:44:41 +0000 Subject: [PATCH 145/156] Convert extensions/ql-vscode/src/query-editor.ts to call typed commands --- extensions/ql-vscode/src/extension.ts | 1 + extensions/ql-vscode/src/query-editor.ts | 17 +++++++++++++---- 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/extensions/ql-vscode/src/extension.ts b/extensions/ql-vscode/src/extension.ts index cb0a58771..7d6b7dfcc 100644 --- a/extensions/ql-vscode/src/extension.ts +++ b/extensions/ql-vscode/src/extension.ts @@ -879,6 +879,7 @@ async function activateWithInstalledDistribution( const allCommands: AllExtensionCommands = { ...getCommands(app, cliServer, qs), ...getQueryEditorCommands({ + commandManager: app.commands, queryRunner: qs, cliServer, qhelpTmpDir: qhelpTmpDir.name, diff --git a/extensions/ql-vscode/src/query-editor.ts b/extensions/ql-vscode/src/query-editor.ts index 23b8101c7..5821dc781 100644 --- a/extensions/ql-vscode/src/query-editor.ts +++ b/extensions/ql-vscode/src/query-editor.ts @@ -1,13 +1,15 @@ -import { commands, Uri, window } from "vscode"; +import { Uri, window } from "vscode"; import { CodeQLCliServer } from "./cli"; import { QueryRunner } from "./queryRunner"; import { basename, join } from "path"; import { getErrorMessage } from "./pure/helpers-pure"; import { redactableError } from "./pure/errors"; import { showAndLogExceptionWithTelemetry } from "./helpers"; -import { QueryEditorCommands } from "./common/commands"; +import { AppCommandManager, QueryEditorCommands } from "./common/commands"; type QueryEditorOptions = { + commandManager: AppCommandManager; + queryRunner: QueryRunner; cliServer: CodeQLCliServer; @@ -15,6 +17,7 @@ type QueryEditorOptions = { }; export function getQueryEditorCommands({ + commandManager, queryRunner, cliServer, qhelpTmpDir, @@ -29,11 +32,17 @@ export function getQueryEditorCommands({ // Since we are tracking extension usage through commands, this command mirrors the "codeQL.openReferencedFile" command "codeQL.openReferencedFileContextExplorer": openReferencedFileCommand, "codeQL.previewQueryHelp": async (selectedQuery: Uri) => - await previewQueryHelp(cliServer, qhelpTmpDir, selectedQuery), + await previewQueryHelp( + commandManager, + cliServer, + qhelpTmpDir, + selectedQuery, + ), }; } async function previewQueryHelp( + commandManager: AppCommandManager, cliServer: CodeQLCliServer, qhelpTmpDir: string, selectedQuery: Uri, @@ -49,7 +58,7 @@ async function previewQueryHelp( const uri = Uri.file(absolutePathToMd); try { await cliServer.generateQueryHelp(pathToQhelp, absolutePathToMd); - await commands.executeCommand("markdown.showPreviewToSide", uri); + await commandManager.execute("markdown.showPreviewToSide", uri); } catch (e) { const errorMessage = getErrorMessage(e).includes( "Generating qhelp in markdown", From 2a2cb2659715bd59913938e0a8898f49f84dae9b Mon Sep 17 00:00:00 2001 From: Robert Date: Wed, 22 Mar 2023 16:49:24 +0000 Subject: [PATCH 146/156] Convert extensions/ql-vscode/src/test-ui.ts to call typed commands --- extensions/ql-vscode/src/common/commands.ts | 8 +++++++- extensions/ql-vscode/src/extension.ts | 2 +- extensions/ql-vscode/src/test-ui.ts | 7 ++++--- 3 files changed, 12 insertions(+), 5 deletions(-) diff --git a/extensions/ql-vscode/src/common/commands.ts b/extensions/ql-vscode/src/common/commands.ts index 171ff5be8..27f303e55 100644 --- a/extensions/ql-vscode/src/common/commands.ts +++ b/extensions/ql-vscode/src/common/commands.ts @@ -1,5 +1,5 @@ import type { CommandManager } from "../packages/commands"; -import type { Uri, Range } from "vscode"; +import type { Uri, Range, TextDocumentShowOptions } from "vscode"; import type { AstItem } from "../astViewer"; import type { DbTreeViewItem } from "../databases/ui/db-tree-view-item"; import type { DatabaseItem } from "../local-databases"; @@ -42,6 +42,12 @@ export type BuiltInVsCodeCommands = { value: unknown, ) => Promise; "workbench.action.reloadWindow": () => Promise; + "vscode.diff": ( + leftSideResource: Uri, + rightSideResource: Uri, + title?: string, + columnOrOptions?: TextDocumentShowOptions, + ) => Promise; "vscode.openFolder": (uri: Uri) => Promise; }; diff --git a/extensions/ql-vscode/src/extension.ts b/extensions/ql-vscode/src/extension.ts index 7d6b7dfcc..c3babbedd 100644 --- a/extensions/ql-vscode/src/extension.ts +++ b/extensions/ql-vscode/src/extension.ts @@ -851,7 +851,7 @@ async function activateWithInstalledDistribution( ); ctx.subscriptions.push(testAdapterFactory); - const testUIService = new TestUIService(testHub); + const testUIService = new TestUIService(app, testHub); ctx.subscriptions.push(testUIService); testUiCommands = testUIService.getCommands(); diff --git a/extensions/ql-vscode/src/test-ui.ts b/extensions/ql-vscode/src/test-ui.ts index 5739d438f..45b8f41a7 100644 --- a/extensions/ql-vscode/src/test-ui.ts +++ b/extensions/ql-vscode/src/test-ui.ts @@ -1,6 +1,6 @@ import { lstat, copy, pathExists, createFile } from "fs-extra"; import { basename } from "path"; -import { Uri, TextDocumentShowOptions, commands, window } from "vscode"; +import { Uri, TextDocumentShowOptions, window } from "vscode"; import { TestHub, TestController, @@ -16,6 +16,7 @@ import { TestTreeNode } from "./test-tree-node"; import { DisposableObject } from "./pure/disposable-object"; import { QLTestAdapter, getExpectedFile, getActualFile } from "./test-adapter"; import { TestUICommands } from "./common/commands"; +import { App } from "./common/app"; type VSCodeTestEvent = | TestRunStartedEvent @@ -44,7 +45,7 @@ class QLTestListener extends DisposableObject { export class TestUIService extends DisposableObject implements TestController { private readonly listeners: Map = new Map(); - constructor(private readonly testHub: TestHub) { + constructor(private readonly app: App, private readonly testHub: TestHub) { super(); testHub.registerTestController(this); @@ -105,7 +106,7 @@ export class TestUIService extends DisposableObject implements TestController { if (await pathExists(actualPath)) { const actualUri = Uri.file(actualPath); - await commands.executeCommand( + await this.app.commands.execute( "vscode.diff", expectedUri, actualUri, From d7e061e1595f957b5b767e9fa27b0902a092f085 Mon Sep 17 00:00:00 2001 From: Robert Date: Wed, 22 Mar 2023 16:55:50 +0000 Subject: [PATCH 147/156] Convert extensions/ql-vscode/src/databases/ui/db-panel.ts to use typed commands --- extensions/ql-vscode/src/common/commands.ts | 1 + extensions/ql-vscode/src/databases/db-module.ts | 2 +- extensions/ql-vscode/src/databases/ui/db-panel.ts | 9 ++++----- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/extensions/ql-vscode/src/common/commands.ts b/extensions/ql-vscode/src/common/commands.ts index 27f303e55..5919ae02c 100644 --- a/extensions/ql-vscode/src/common/commands.ts +++ b/extensions/ql-vscode/src/common/commands.ts @@ -48,6 +48,7 @@ export type BuiltInVsCodeCommands = { title?: string, columnOrOptions?: TextDocumentShowOptions, ) => Promise; + "vscode.open": (uri: Uri) => Promise; "vscode.openFolder": (uri: Uri) => Promise; }; diff --git a/extensions/ql-vscode/src/databases/db-module.ts b/extensions/ql-vscode/src/databases/db-module.ts index 8c287cc32..8d47f75a8 100644 --- a/extensions/ql-vscode/src/databases/db-module.ts +++ b/extensions/ql-vscode/src/databases/db-module.ts @@ -43,7 +43,7 @@ export class DbModule extends DisposableObject { await this.dbConfigStore.initialize(); - this.dbPanel = new DbPanel(this.dbManager, app.credentials); + this.dbPanel = new DbPanel(app, this.dbManager); this.push(this.dbPanel); this.push(this.dbConfigStore); diff --git a/extensions/ql-vscode/src/databases/ui/db-panel.ts b/extensions/ql-vscode/src/databases/ui/db-panel.ts index 7df235347..80a0eec5b 100644 --- a/extensions/ql-vscode/src/databases/ui/db-panel.ts +++ b/extensions/ql-vscode/src/databases/ui/db-panel.ts @@ -1,5 +1,4 @@ import { - commands, QuickPickItem, TreeView, TreeViewExpansionEvent, @@ -31,8 +30,8 @@ import { DbTreeViewItem } from "./db-tree-view-item"; import { getGitHubUrl } from "./db-tree-view-item-action"; import { getControllerRepo } from "../../variant-analysis/run-remote-query"; import { getErrorMessage } from "../../pure/helpers-pure"; -import { Credentials } from "../../common/authentication"; import { DatabasePanelCommands } from "../../common/commands"; +import { App } from "../../common/app"; export interface RemoteDatabaseQuickPickItem extends QuickPickItem { kind: string; @@ -47,8 +46,8 @@ export class DbPanel extends DisposableObject { private readonly treeView: TreeView; public constructor( + private readonly app: App, private readonly dbManager: DbManager, - private readonly credentials: Credentials, ) { super(); @@ -369,13 +368,13 @@ export class DbPanel extends DisposableObject { ); } - await commands.executeCommand("vscode.open", Uri.parse(githubUrl)); + await this.app.commands.execute("vscode.open", Uri.parse(githubUrl)); } private async setupControllerRepository(): Promise { try { // This will also validate that the controller repository is valid - await getControllerRepo(this.credentials); + await getControllerRepo(this.app.credentials); } catch (e: unknown) { if (e instanceof UserCancellationException) { return; From 14dc391229991443106e18a6454868627442debb Mon Sep 17 00:00:00 2001 From: Robert Date: Wed, 22 Mar 2023 17:06:24 +0000 Subject: [PATCH 148/156] Convert extensions/ql-vscode/src/legacy-query-server/queryserver-client.ts to call typed commands --- extensions/ql-vscode/src/extension.ts | 9 ++++++++- .../src/legacy-query-server/queryserver-client.ts | 6 ++++-- .../vscode-tests/cli-integration/legacy-query.test.ts | 2 ++ 3 files changed, 14 insertions(+), 3 deletions(-) diff --git a/extensions/ql-vscode/src/extension.ts b/extensions/ql-vscode/src/extension.ts index c3babbedd..52f1295d6 100644 --- a/extensions/ql-vscode/src/extension.ts +++ b/extensions/ql-vscode/src/extension.ts @@ -667,7 +667,12 @@ async function activateWithInstalledDistribution( ctx.subscriptions.push(statusBar); void extLogger.log("Initializing query server client."); - const qs = await createQueryServer(qlConfigurationListener, cliServer, ctx); + const qs = await createQueryServer( + app, + qlConfigurationListener, + cliServer, + ctx, + ); for (const glob of PACK_GLOBS) { const fsWatcher = workspace.createFileSystemWatcher(glob); @@ -1044,6 +1049,7 @@ function addUnhandledRejectionListener() { } async function createQueryServer( + app: ExtensionApp, qlConfigurationListener: QueryServerConfigListener, cliServer: CodeQLCliServer, ctx: ExtensionContext, @@ -1074,6 +1080,7 @@ async function createQueryServer( return new NewQueryRunner(qs); } else { const qs = new LegacyQueryServerClient( + app, qlConfigurationListener, cliServer, qsOpts, diff --git a/extensions/ql-vscode/src/legacy-query-server/queryserver-client.ts b/extensions/ql-vscode/src/legacy-query-server/queryserver-client.ts index 25e60db23..50c0278db 100644 --- a/extensions/ql-vscode/src/legacy-query-server/queryserver-client.ts +++ b/extensions/ql-vscode/src/legacy-query-server/queryserver-client.ts @@ -1,7 +1,7 @@ import { ensureFile } from "fs-extra"; import { DisposableObject } from "../pure/disposable-object"; -import { CancellationToken, commands } from "vscode"; +import { CancellationToken } from "vscode"; import { createMessageConnection, RequestType } from "vscode-jsonrpc/node"; import * as cli from "../cli"; import { QueryServerConfig } from "../config"; @@ -15,6 +15,7 @@ import { } from "../pure/legacy-messages"; import { ProgressCallback, ProgressTask } from "../progress"; import { ServerProcess } from "../json-rpc-server"; +import { App } from "../common/app"; type WithProgressReporting = ( task: ( @@ -56,6 +57,7 @@ export class QueryServerClient extends DisposableObject { public activeQueryLogger: Logger; constructor( + app: App, readonly config: QueryServerConfig, readonly cliServer: cli.CodeQLCliServer, readonly opts: ServerOpts, @@ -69,7 +71,7 @@ export class QueryServerClient extends DisposableObject { if (config.onDidChangeConfiguration !== undefined) { this.push( config.onDidChangeConfiguration(() => - commands.executeCommand("codeQL.restartQueryServer"), + app.commands.execute("codeQL.restartQueryServer"), ), ); } diff --git a/extensions/ql-vscode/test/vscode-tests/cli-integration/legacy-query.test.ts b/extensions/ql-vscode/test/vscode-tests/cli-integration/legacy-query.test.ts index 6c014b609..faacb6db2 100644 --- a/extensions/ql-vscode/test/vscode-tests/cli-integration/legacy-query.test.ts +++ b/extensions/ql-vscode/test/vscode-tests/cli-integration/legacy-query.test.ts @@ -12,6 +12,7 @@ import { CodeQLExtensionInterface } from "../../../src/extension"; import { describeWithCodeQL } from "../cli"; import { QueryServerClient } from "../../../src/legacy-query-server/queryserver-client"; import { extLogger, ProgressReporter } from "../../../src/common"; +import { createMockApp } from "../../__mocks__/appMock"; const baseDir = join(__dirname, "../../../test/data"); @@ -121,6 +122,7 @@ describeWithCodeQL()("using the legacy query server", () => { cliServer.quiet = true; qs = new QueryServerClient( + createMockApp({}), { codeQlPath: (await extension.distributionManager.getCodeQlPathWithoutVersionCheck()) || From d0c4e5b8c57bec9291ba1ecc05315a8182da11b1 Mon Sep 17 00:00:00 2001 From: Koen Vlaswinkel Date: Thu, 23 Mar 2023 13:30:06 +0100 Subject: [PATCH 149/156] Remove remaining references to `commandRunner` --- extensions/ql-vscode/src/common/vscode/commands.ts | 2 +- extensions/ql-vscode/src/extension.ts | 7 ++++--- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/extensions/ql-vscode/src/common/vscode/commands.ts b/extensions/ql-vscode/src/common/vscode/commands.ts index 04aa02a5b..3d71ae004 100644 --- a/extensions/ql-vscode/src/common/vscode/commands.ts +++ b/extensions/ql-vscode/src/common/vscode/commands.ts @@ -15,7 +15,7 @@ import { import { telemetryListener } from "../../telemetry"; /** - * Create a command manager for VSCode, wrapping the commandRunner + * Create a command manager for VSCode, wrapping registerCommandWithErrorHandling * and vscode.executeCommand. */ export function createVSCodeCommandManager< diff --git a/extensions/ql-vscode/src/extension.ts b/extensions/ql-vscode/src/extension.ts index fb973b9b7..26e301bb9 100644 --- a/extensions/ql-vscode/src/extension.ts +++ b/extensions/ql-vscode/src/extension.ts @@ -236,7 +236,7 @@ function registerErrorStubs( stubbedCommands.forEach((command) => { if (excludedCommands.indexOf(command) === -1) { - // This is purposefully using `commandRunner` instead of the command manager because these + // This is purposefully using `registerCommandWithErrorHandling` instead of the command manager because these // commands are untyped and registered pre-activation. errorStubs.push( registerCommandWithErrorHandling(command, stubGenerator(command)), @@ -341,7 +341,7 @@ export async function activate( ), ); ctx.subscriptions.push( - // This is purposefully using `commandRunner` directly instead of the command manager + // This is purposefully using `registerCommandWithErrorHandling` directly instead of the command manager // because this command is registered pre-activation. registerCommandWithErrorHandling(checkForUpdatesCommand, () => installOrUpdateThenTryActivate( @@ -1035,7 +1035,8 @@ function addUnhandledRejectionListener() { // "uncaughtException" will trigger whenever an exception reaches the top level. // This covers extension initialization and any code within a `setTimeout`. // Notably this does not include exceptions thrown when executing commands, - // because `commandRunner` wraps the command body and handles errors. + // because `registerCommandWithErrorHandling` wraps the command body and + // handles errors. process.addListener("uncaughtException", handler); // "unhandledRejection" will trigger whenever any promise is rejected and it is From f57bfb68755247e785f7bc694e17091973db8787 Mon Sep 17 00:00:00 2001 From: Koen Vlaswinkel Date: Thu, 23 Mar 2023 13:55:52 +0100 Subject: [PATCH 150/156] Add support for typed commands to CodeQL query This adds support for detecting the `CommandManager.execute` method in the unique command use query. This may not be the best way to implement this. There's a method `hasUnderlyingType` on `this.getReceiver().getType()`, but I couldn't really figure out how to get it recognize `CommandManager`. It might be possible if we can construct the type of `CommandManager`, but this will probably include the filepath to the `CommandManager` class, which might not neccessarily be something we want: moving the `CommandManager` class should not require updating the query. I'm very happy to hear other suggestions. --- .github/codeql/queries/unique-command-use.ql | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/.github/codeql/queries/unique-command-use.ql b/.github/codeql/queries/unique-command-use.ql index 9602bf397..7c1d9e196 100644 --- a/.github/codeql/queries/unique-command-use.ql +++ b/.github/codeql/queries/unique-command-use.ql @@ -72,6 +72,20 @@ override string getCommandName() { result = this.getArgument(0).(StringLiteral).getValue() } } + + /** + * A usage of a command from the typescript code, by calling `CommandManager.execute`. + */ + class CommandUsageCommandManagerMethodCallExpr extends CommandUsage, MethodCallExpr { + CommandUsageCommandManagerMethodCallExpr() { + this.getCalleeName() = "execute" and + this.getReceiver().getType().unfold().(TypeReference).getTypeName().getName() = "CommandManager" and + this.getArgument(0).(StringLiteral).getValue().matches("%codeQL%") and + not this.getFile().getRelativePath().matches("extensions/ql-vscode/test/%") + } + + override string getCommandName() { result = this.getArgument(0).(StringLiteral).getValue() } + } /** * A usage of a command from any menu that isn't the command palette. From e0dd8c7392533425226cde6408e2d338a19fc566 Mon Sep 17 00:00:00 2001 From: Robert Date: Thu, 23 Mar 2023 13:04:30 +0000 Subject: [PATCH 151/156] Add comment about codeQLDatabases.focus --- extensions/ql-vscode/src/common/commands.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/extensions/ql-vscode/src/common/commands.ts b/extensions/ql-vscode/src/common/commands.ts index 5919ae02c..74b6c3313 100644 --- a/extensions/ql-vscode/src/common/commands.ts +++ b/extensions/ql-vscode/src/common/commands.ts @@ -35,6 +35,7 @@ export type SingleSelectionCommandFunction = ( // Builtin commands where the implementation is provided by VS Code and not by this extension. // See https://code.visualstudio.com/api/references/commands export type BuiltInVsCodeCommands = { + // The codeQLDatabases.focus command is provided by VS Code because we've registered the custom view "codeQLDatabases.focus": () => Promise; "markdown.showPreviewToSide": (uri: Uri) => Promise; setContext: ( From 2e7952cb3718bc1c4f91b8f106e90c5aa27a958f Mon Sep 17 00:00:00 2001 From: Robert Date: Thu, 23 Mar 2023 13:00:11 +0000 Subject: [PATCH 152/156] Pull tryOpenExternalFile out to a separate file so it can be more easily tested --- .../query-history/query-history-manager.ts | 65 +++------------ .../src/vscode-utils/external-files.ts | 46 ++++++++++ .../query-history-manager.test.ts | 83 ++++--------------- .../vscode-utils/external-files.test.ts | 65 +++++++++++++++ 4 files changed, 135 insertions(+), 124 deletions(-) create mode 100644 extensions/ql-vscode/src/vscode-utils/external-files.ts create mode 100644 extensions/ql-vscode/test/vscode-tests/no-workspace/query-history/vscode-utils/external-files.test.ts diff --git a/extensions/ql-vscode/src/query-history/query-history-manager.ts b/extensions/ql-vscode/src/query-history/query-history-manager.ts index d170d9b55..d7daea4de 100644 --- a/extensions/ql-vscode/src/query-history/query-history-manager.ts +++ b/extensions/ql-vscode/src/query-history/query-history-manager.ts @@ -26,12 +26,7 @@ import { extLogger } from "../common"; import { URLSearchParams } from "url"; import { DisposableObject } from "../pure/disposable-object"; import { ONE_HOUR_IN_MS, TWO_HOURS_IN_MS } from "../pure/time"; -import { - asError, - assertNever, - getErrorMessage, - getErrorStack, -} from "../pure/helpers-pure"; +import { asError, assertNever, getErrorMessage } from "../pure/helpers-pure"; import { CompletedLocalQueryInfo, LocalQueryInfo } from "../query-results"; import { getActionsWorkflowRunUrl, @@ -66,6 +61,7 @@ import { HistoryTreeDataProvider } from "./history-tree-data-provider"; import { redactableError } from "../pure/errors"; import { QueryHistoryDirs } from "./query-history-dirs"; import { QueryHistoryCommands } from "../common/commands"; +import { tryOpenExternalFile } from "../vscode-utils/external-files"; /** * query-history-manager.ts @@ -683,7 +679,7 @@ export class QueryHistoryManager extends DisposableObject { } if (singleItem.completedQuery.logFileLocation) { - await this.tryOpenExternalFile(singleItem.completedQuery.logFileLocation); + await tryOpenExternalFile(singleItem.completedQuery.logFileLocation); } else { void showAndLogWarningMessage("No log file available"); } @@ -800,7 +796,7 @@ export class QueryHistoryManager extends DisposableObject { } if (finalSingleItem.evalLogLocation) { - await this.tryOpenExternalFile(finalSingleItem.evalLogLocation); + await tryOpenExternalFile(finalSingleItem.evalLogLocation); } else { this.warnNoEvalLogs(); } @@ -825,7 +821,7 @@ export class QueryHistoryManager extends DisposableObject { } if (finalSingleItem.evalLogSummaryLocation) { - await this.tryOpenExternalFile(finalSingleItem.evalLogSummaryLocation); + await tryOpenExternalFile(finalSingleItem.evalLogSummaryLocation); return; } @@ -968,7 +964,7 @@ export class QueryHistoryManager extends DisposableObject { const query = finalSingleItem.completedQuery.query; const hasInterpretedResults = query.canHaveInterpretedResults(); if (hasInterpretedResults) { - await this.tryOpenExternalFile(query.resultsPaths.interpretedResultsPath); + await tryOpenExternalFile(query.resultsPaths.interpretedResultsPath); } else { const label = this.labelProvider.getLabel(finalSingleItem); void showAndLogInformationMessage( @@ -997,11 +993,11 @@ export class QueryHistoryManager extends DisposableObject { } const query = finalSingleItem.completedQuery.query; if (await query.hasCsv()) { - void this.tryOpenExternalFile(query.csvPath); + void tryOpenExternalFile(query.csvPath); return; } if (await query.exportCsvResults(this.qs.cliServer, query.csvPath)) { - void this.tryOpenExternalFile(query.csvPath); + void tryOpenExternalFile(query.csvPath); } } @@ -1024,7 +1020,7 @@ export class QueryHistoryManager extends DisposableObject { return; } - await this.tryOpenExternalFile( + await tryOpenExternalFile( await finalSingleItem.completedQuery.query.ensureCsvAlerts( this.qs.cliServer, this.dbm, @@ -1051,7 +1047,7 @@ export class QueryHistoryManager extends DisposableObject { return; } - await this.tryOpenExternalFile( + await tryOpenExternalFile( await finalSingleItem.completedQuery.query.ensureDilPath( this.qs.cliServer, ), @@ -1171,47 +1167,6 @@ export class QueryHistoryManager extends DisposableObject { } } - private async tryOpenExternalFile(fileLocation: string) { - const uri = Uri.file(fileLocation); - try { - await window.showTextDocument(uri, { preview: false }); - } catch (e) { - const msg = getErrorMessage(e); - if ( - msg.includes( - "Files above 50MB cannot be synchronized with extensions", - ) || - msg.includes("too large to open") - ) { - const res = await showBinaryChoiceDialog( - `VS Code does not allow extensions to open files >50MB. This file -exceeds that limit. Do you want to open it outside of VS Code? - -You can also try manually opening it inside VS Code by selecting -the file in the file explorer and dragging it into the workspace.`, - ); - if (res) { - try { - await commands.executeCommand("revealFileInOS", uri); - } catch (e) { - void showAndLogExceptionWithTelemetry( - redactableError( - asError(e), - )`Failed to reveal file in OS: ${getErrorMessage(e)}`, - ); - } - } - } else { - void showAndLogExceptionWithTelemetry( - redactableError(asError(e))`Could not open file ${fileLocation}`, - { - fullMessage: `${getErrorMessage(e)}\n${getErrorStack(e)}`, - }, - ); - } - } - } - private async findOtherQueryToCompare( singleItem: QueryHistoryInfo, multiSelect: QueryHistoryInfo[], diff --git a/extensions/ql-vscode/src/vscode-utils/external-files.ts b/extensions/ql-vscode/src/vscode-utils/external-files.ts new file mode 100644 index 000000000..19e9dca76 --- /dev/null +++ b/extensions/ql-vscode/src/vscode-utils/external-files.ts @@ -0,0 +1,46 @@ +import { commands, Uri, window } from "vscode"; +import { + showAndLogExceptionWithTelemetry, + showBinaryChoiceDialog, +} from "../helpers"; +import { redactableError } from "../pure/errors"; +import { asError, getErrorMessage, getErrorStack } from "../pure/helpers-pure"; + +export async function tryOpenExternalFile(fileLocation: string) { + const uri = Uri.file(fileLocation); + try { + await window.showTextDocument(uri, { preview: false }); + } catch (e) { + const msg = getErrorMessage(e); + if ( + msg.includes("Files above 50MB cannot be synchronized with extensions") || + msg.includes("too large to open") + ) { + const res = await showBinaryChoiceDialog( + `VS Code does not allow extensions to open files >50MB. This file +exceeds that limit. Do you want to open it outside of VS Code? + +You can also try manually opening it inside VS Code by selecting +the file in the file explorer and dragging it into the workspace.`, + ); + if (res) { + try { + await commands.executeCommand("revealFileInOS", uri); + } catch (e) { + void showAndLogExceptionWithTelemetry( + redactableError( + asError(e), + )`Failed to reveal file in OS: ${getErrorMessage(e)}`, + ); + } + } + } else { + void showAndLogExceptionWithTelemetry( + redactableError(asError(e))`Could not open file ${fileLocation}`, + { + fullMessage: `${getErrorMessage(e)}\n${getErrorStack(e)}`, + }, + ); + } + } +} diff --git a/extensions/ql-vscode/test/vscode-tests/no-workspace/query-history/query-history-manager.test.ts b/extensions/ql-vscode/test/vscode-tests/no-workspace/query-history/query-history-manager.test.ts index a798fff45..1e6e323e5 100644 --- a/extensions/ql-vscode/test/vscode-tests/no-workspace/query-history/query-history-manager.test.ts +++ b/extensions/ql-vscode/test/vscode-tests/no-workspace/query-history/query-history-manager.test.ts @@ -22,59 +22,49 @@ import { createMockVariantAnalysisHistoryItem } from "../../../factories/query-h import { VariantAnalysisHistoryItem } from "../../../../src/query-history/variant-analysis-history-item"; import { QueryStatus } from "../../../../src/query-status"; import { VariantAnalysisStatus } from "../../../../src/variant-analysis/shared/variant-analysis"; -import { TextEditor } from "vscode"; import { WebviewReveal } from "../../../../src/interface-utils"; import * as helpers from "../../../../src/helpers"; -import { mockedObject, mockedQuickPickItem } from "../../utils/mocking.helpers"; +import { mockedQuickPickItem } from "../../utils/mocking.helpers"; import { createMockQueryHistoryDirs } from "../../../factories/query-history/query-history-dirs"; +import { createMockApp } from "../../../__mocks__/appMock"; +import { App } from "../../../../src/common/app"; +import { createMockCommandManager } from "../../../__mocks__/commandsMock"; describe("QueryHistoryManager", () => { const mockExtensionLocation = join(tmpDir.name, "mock-extension-location"); let configListener: QueryHistoryConfigListener; - let showTextDocumentSpy: jest.SpiedFunction< - typeof vscode.window.showTextDocument - >; - let showInformationMessageSpy: jest.SpiedFunction< - typeof vscode.window.showInformationMessage - >; let showQuickPickSpy: jest.SpiedFunction; - let executeCommandSpy: jest.SpiedFunction< - typeof vscode.commands.executeCommand - >; let cancelVariantAnalysisSpy: jest.SpiedFunction< typeof variantAnalysisManagerStub.cancelVariantAnalysis >; const doCompareCallback = jest.fn(); + let executeCommand: jest.MockedFn< + (commandName: string, ...args: any[]) => Promise + >; + let mockApp: App; + let queryHistoryManager: QueryHistoryManager; let localQueriesResultsViewStub: ResultsView; let variantAnalysisManagerStub: VariantAnalysisManager; - let tryOpenExternalFile: Function; - let allHistory: QueryHistoryInfo[]; let localQueryHistory: LocalQueryInfo[]; let variantAnalysisHistory: VariantAnalysisHistoryItem[]; beforeEach(() => { - showTextDocumentSpy = jest - .spyOn(vscode.window, "showTextDocument") - .mockResolvedValue(mockedObject({})); - showInformationMessageSpy = jest - .spyOn(vscode.window, "showInformationMessage") - .mockResolvedValue(undefined); showQuickPickSpy = jest .spyOn(vscode.window, "showQuickPick") .mockResolvedValue(undefined); - executeCommandSpy = jest - .spyOn(vscode.commands, "executeCommand") - .mockResolvedValue(undefined); + + executeCommand = jest.fn(); + mockApp = createMockApp({ + commands: createMockCommandManager({ executeCommand }), + }); jest.spyOn(extLogger, "log").mockResolvedValue(undefined); - tryOpenExternalFile = (QueryHistoryManager.prototype as any) - .tryOpenExternalFile; configListener = new QueryHistoryConfigListener(); localQueriesResultsViewStub = { showResults: jest.fn(), @@ -157,51 +147,6 @@ describe("QueryHistoryManager", () => { queryHistoryManager.dispose(); } }); - describe("tryOpenExternalFile", () => { - it("should open an external file", async () => { - await tryOpenExternalFile("xxx"); - expect(showTextDocumentSpy).toHaveBeenCalledTimes(1); - expect(showTextDocumentSpy).toHaveBeenCalledWith( - vscode.Uri.file("xxx"), - expect.anything(), - ); - expect(executeCommandSpy).not.toBeCalled(); - }); - - [ - "too large to open", - "Files above 50MB cannot be synchronized with extensions", - ].forEach((msg) => { - it(`should fail to open a file because "${msg}" and open externally`, async () => { - showTextDocumentSpy.mockRejectedValue(new Error(msg)); - showInformationMessageSpy.mockResolvedValue({ title: "Yes" }); - - await tryOpenExternalFile("xxx"); - const uri = vscode.Uri.file("xxx"); - expect(showTextDocumentSpy).toHaveBeenCalledTimes(1); - expect(showTextDocumentSpy).toHaveBeenCalledWith( - uri, - expect.anything(), - ); - expect(executeCommandSpy).toHaveBeenCalledWith("revealFileInOS", uri); - }); - - it(`should fail to open a file because "${msg}" and NOT open externally`, async () => { - showTextDocumentSpy.mockRejectedValue(new Error(msg)); - showInformationMessageSpy.mockResolvedValue({ title: "No" }); - - await tryOpenExternalFile("xxx"); - const uri = vscode.Uri.file("xxx"); - expect(showTextDocumentSpy).toHaveBeenCalledTimes(1); - expect(showTextDocumentSpy).toHaveBeenCalledWith( - uri, - expect.anything(), - ); - expect(showInformationMessageSpy).toBeCalled(); - expect(executeCommandSpy).not.toBeCalled(); - }); - }); - }); describe("handleItemClicked", () => { describe("single click", () => { diff --git a/extensions/ql-vscode/test/vscode-tests/no-workspace/query-history/vscode-utils/external-files.test.ts b/extensions/ql-vscode/test/vscode-tests/no-workspace/query-history/vscode-utils/external-files.test.ts new file mode 100644 index 000000000..01fdbbc9c --- /dev/null +++ b/extensions/ql-vscode/test/vscode-tests/no-workspace/query-history/vscode-utils/external-files.test.ts @@ -0,0 +1,65 @@ +import * as vscode from "vscode"; +import { tryOpenExternalFile } from "../../../../../src/vscode-utils/external-files"; +import { mockedObject } from "../../../utils/mocking.helpers"; + +describe("tryOpenExternalFile", () => { + let showTextDocumentSpy: jest.SpiedFunction< + typeof vscode.window.showTextDocument + >; + let showInformationMessageSpy: jest.SpiedFunction< + typeof vscode.window.showInformationMessage + >; + let executeCommandSpy: jest.SpiedFunction< + typeof vscode.commands.executeCommand + >; + + beforeEach(() => { + showTextDocumentSpy = jest + .spyOn(vscode.window, "showTextDocument") + .mockResolvedValue(mockedObject({})); + showInformationMessageSpy = jest + .spyOn(vscode.window, "showInformationMessage") + .mockResolvedValue(undefined); + executeCommandSpy = jest + .spyOn(vscode.commands, "executeCommand") + .mockResolvedValue(undefined); + }); + + it("should open an external file", async () => { + await tryOpenExternalFile("xxx"); + expect(showTextDocumentSpy).toHaveBeenCalledTimes(1); + expect(showTextDocumentSpy).toHaveBeenCalledWith( + vscode.Uri.file("xxx"), + expect.anything(), + ); + expect(executeCommandSpy).not.toBeCalled(); + }); + + [ + "too large to open", + "Files above 50MB cannot be synchronized with extensions", + ].forEach((msg) => { + it(`should fail to open a file because "${msg}" and open externally`, async () => { + showTextDocumentSpy.mockRejectedValue(new Error(msg)); + showInformationMessageSpy.mockResolvedValue({ title: "Yes" }); + + await tryOpenExternalFile("xxx"); + const uri = vscode.Uri.file("xxx"); + expect(showTextDocumentSpy).toHaveBeenCalledTimes(1); + expect(showTextDocumentSpy).toHaveBeenCalledWith(uri, expect.anything()); + expect(executeCommandSpy).toHaveBeenCalledWith("revealFileInOS", uri); + }); + + it(`should fail to open a file because "${msg}" and NOT open externally`, async () => { + showTextDocumentSpy.mockRejectedValue(new Error(msg)); + showInformationMessageSpy.mockResolvedValue({ title: "No" }); + + await tryOpenExternalFile("xxx"); + const uri = vscode.Uri.file("xxx"); + expect(showTextDocumentSpy).toHaveBeenCalledTimes(1); + expect(showTextDocumentSpy).toHaveBeenCalledWith(uri, expect.anything()); + expect(showInformationMessageSpy).toBeCalled(); + expect(executeCommandSpy).not.toBeCalled(); + }); + }); +}); From a9e495118c444293dbe8d6c92e20f6fb40320d86 Mon Sep 17 00:00:00 2001 From: Robert Date: Thu, 23 Mar 2023 13:02:09 +0000 Subject: [PATCH 153/156] Convert extensions/ql-vscode/src/query-history/query-history-manager.ts to call typed commands --- extensions/ql-vscode/src/common/commands.ts | 1 + extensions/ql-vscode/src/extension.ts | 1 + .../ql-vscode/src/query-history/query-history-manager.ts | 9 +++++---- .../query-history/history-tree-data-provider.test.ts | 2 ++ .../query-history/query-history-manager.test.ts | 7 ++++--- .../query-history/variant-analysis-history.test.ts | 2 ++ 6 files changed, 15 insertions(+), 7 deletions(-) diff --git a/extensions/ql-vscode/src/common/commands.ts b/extensions/ql-vscode/src/common/commands.ts index 74b6c3313..55e47f22b 100644 --- a/extensions/ql-vscode/src/common/commands.ts +++ b/extensions/ql-vscode/src/common/commands.ts @@ -38,6 +38,7 @@ export type BuiltInVsCodeCommands = { // The codeQLDatabases.focus command is provided by VS Code because we've registered the custom view "codeQLDatabases.focus": () => Promise; "markdown.showPreviewToSide": (uri: Uri) => Promise; + revealFileInOS: (uri: Uri) => Promise; setContext: ( key: `${"codeql" | "codeQL"}${string}`, value: unknown, diff --git a/extensions/ql-vscode/src/extension.ts b/extensions/ql-vscode/src/extension.ts index c6accece0..a3fc19032 100644 --- a/extensions/ql-vscode/src/extension.ts +++ b/extensions/ql-vscode/src/extension.ts @@ -777,6 +777,7 @@ async function activateWithInstalledDistribution( }; const qhm = new QueryHistoryManager( + app, qs, dbm, localQueryResultsView, diff --git a/extensions/ql-vscode/src/query-history/query-history-manager.ts b/extensions/ql-vscode/src/query-history/query-history-manager.ts index d7daea4de..431d4d9db 100644 --- a/extensions/ql-vscode/src/query-history/query-history-manager.ts +++ b/extensions/ql-vscode/src/query-history/query-history-manager.ts @@ -1,6 +1,5 @@ import { join, dirname } from "path"; import { - commands, Disposable, env, EventEmitter, @@ -61,6 +60,7 @@ import { HistoryTreeDataProvider } from "./history-tree-data-provider"; import { redactableError } from "../pure/errors"; import { QueryHistoryDirs } from "./query-history-dirs"; import { QueryHistoryCommands } from "../common/commands"; +import { App } from "../common/app"; import { tryOpenExternalFile } from "../vscode-utils/external-files"; /** @@ -131,6 +131,7 @@ export class QueryHistoryManager extends DisposableObject { readonly onDidCompleteQuery = this._onDidCompleteQuery.event; constructor( + private readonly app: App, private readonly qs: QueryRunner, private readonly dbm: DatabaseManager, private readonly localQueriesResultsView: ResultsView, @@ -747,7 +748,7 @@ export class QueryHistoryManager extends DisposableObject { } } try { - await commands.executeCommand( + await this.app.commands.execute( "revealFileInOS", Uri.file(externalFilePath), ); @@ -1073,7 +1074,7 @@ export class QueryHistoryManager extends DisposableObject { const actionsWorkflowRunUrl = getActionsWorkflowRunUrl(finalSingleItem); - await commands.executeCommand( + await this.app.commands.execute( "vscode.open", Uri.parse(actionsWorkflowRunUrl), ); @@ -1097,7 +1098,7 @@ export class QueryHistoryManager extends DisposableObject { return; } - await commands.executeCommand( + await this.app.commands.execute( "codeQL.copyVariantAnalysisRepoList", finalSingleItem.variantAnalysis.id, ); diff --git a/extensions/ql-vscode/test/vscode-tests/no-workspace/query-history/history-tree-data-provider.test.ts b/extensions/ql-vscode/test/vscode-tests/no-workspace/query-history/history-tree-data-provider.test.ts index b63448a40..ca0b0add8 100644 --- a/extensions/ql-vscode/test/vscode-tests/no-workspace/query-history/history-tree-data-provider.test.ts +++ b/extensions/ql-vscode/test/vscode-tests/no-workspace/query-history/history-tree-data-provider.test.ts @@ -27,6 +27,7 @@ import { } from "../../../../src/query-history/history-tree-data-provider"; import { QueryHistoryManager } from "../../../../src/query-history/query-history-manager"; import { createMockQueryHistoryDirs } from "../../../factories/query-history/query-history-dirs"; +import { createMockApp } from "../../../__mocks__/appMock"; describe("HistoryTreeDataProvider", () => { const mockExtensionLocation = join(tmpDir.name, "mock-extension-location"); @@ -421,6 +422,7 @@ describe("HistoryTreeDataProvider", () => { async function createMockQueryHistory(allHistory: QueryHistoryInfo[]) { const qhm = new QueryHistoryManager( + createMockApp({}), {} as QueryRunner, {} as DatabaseManager, localQueriesResultsViewStub, diff --git a/extensions/ql-vscode/test/vscode-tests/no-workspace/query-history/query-history-manager.test.ts b/extensions/ql-vscode/test/vscode-tests/no-workspace/query-history/query-history-manager.test.ts index 1e6e323e5..2ca728c6b 100644 --- a/extensions/ql-vscode/test/vscode-tests/no-workspace/query-history/query-history-manager.test.ts +++ b/extensions/ql-vscode/test/vscode-tests/no-workspace/query-history/query-history-manager.test.ts @@ -777,7 +777,7 @@ describe("QueryHistoryManager", () => { const item = localQueryHistory[4]; await queryHistoryManager.handleCopyRepoList(item, [item]); - expect(executeCommandSpy).not.toBeCalled(); + expect(executeCommand).not.toBeCalled(); }); it("should copy repo list for a single variant analysis", async () => { @@ -785,7 +785,7 @@ describe("QueryHistoryManager", () => { const item = variantAnalysisHistory[1]; await queryHistoryManager.handleCopyRepoList(item, [item]); - expect(executeCommandSpy).toBeCalledWith( + expect(executeCommand).toBeCalledWith( "codeQL.copyVariantAnalysisRepoList", item.variantAnalysis.id, ); @@ -797,7 +797,7 @@ describe("QueryHistoryManager", () => { const item1 = variantAnalysisHistory[1]; const item2 = variantAnalysisHistory[3]; await queryHistoryManager.handleCopyRepoList(item1, [item1, item2]); - expect(executeCommandSpy).not.toBeCalled(); + expect(executeCommand).not.toBeCalled(); }); }); @@ -1094,6 +1094,7 @@ describe("QueryHistoryManager", () => { async function createMockQueryHistory(allHistory: QueryHistoryInfo[]) { const qhm = new QueryHistoryManager( + mockApp, {} as QueryRunner, {} as DatabaseManager, localQueriesResultsViewStub, diff --git a/extensions/ql-vscode/test/vscode-tests/no-workspace/query-history/variant-analysis-history.test.ts b/extensions/ql-vscode/test/vscode-tests/no-workspace/query-history/variant-analysis-history.test.ts index f36267065..f6115af31 100644 --- a/extensions/ql-vscode/test/vscode-tests/no-workspace/query-history/variant-analysis-history.test.ts +++ b/extensions/ql-vscode/test/vscode-tests/no-workspace/query-history/variant-analysis-history.test.ts @@ -21,6 +21,7 @@ import { VariantAnalysisManager } from "../../../../src/variant-analysis/variant import { QueryHistoryManager } from "../../../../src/query-history/query-history-manager"; import { mockedObject } from "../../utils/mocking.helpers"; import { createMockQueryHistoryDirs } from "../../../factories/query-history/query-history-dirs"; +import { createMockApp } from "../../../__mocks__/appMock"; // set a higher timeout since recursive delete may take a while, expecially on Windows. jest.setTimeout(120000); @@ -73,6 +74,7 @@ describe("Variant Analyses and QueryHistoryManager", () => { ).queries; qhm = new QueryHistoryManager( + createMockApp({}), {} as QueryRunner, {} as DatabaseManager, localQueriesResultsViewStub, From c84c69f52941e886d0551cd34537e234cb2fe050 Mon Sep 17 00:00:00 2001 From: Robert Date: Thu, 23 Mar 2023 13:02:37 +0000 Subject: [PATCH 154/156] Convert extensions/ql-vscode/src/vscode-utils/external-files.ts to call typed commands --- .../query-history/query-history-manager.ts | 26 +++++++++++++---- .../src/vscode-utils/external-files.ts | 10 +++++-- .../vscode-utils/external-files.test.ts | 28 +++++++++++-------- 3 files changed, 43 insertions(+), 21 deletions(-) diff --git a/extensions/ql-vscode/src/query-history/query-history-manager.ts b/extensions/ql-vscode/src/query-history/query-history-manager.ts index 431d4d9db..ca7ab3fd9 100644 --- a/extensions/ql-vscode/src/query-history/query-history-manager.ts +++ b/extensions/ql-vscode/src/query-history/query-history-manager.ts @@ -680,7 +680,10 @@ export class QueryHistoryManager extends DisposableObject { } if (singleItem.completedQuery.logFileLocation) { - await tryOpenExternalFile(singleItem.completedQuery.logFileLocation); + await tryOpenExternalFile( + this.app.commands, + singleItem.completedQuery.logFileLocation, + ); } else { void showAndLogWarningMessage("No log file available"); } @@ -797,7 +800,10 @@ export class QueryHistoryManager extends DisposableObject { } if (finalSingleItem.evalLogLocation) { - await tryOpenExternalFile(finalSingleItem.evalLogLocation); + await tryOpenExternalFile( + this.app.commands, + finalSingleItem.evalLogLocation, + ); } else { this.warnNoEvalLogs(); } @@ -822,7 +828,10 @@ export class QueryHistoryManager extends DisposableObject { } if (finalSingleItem.evalLogSummaryLocation) { - await tryOpenExternalFile(finalSingleItem.evalLogSummaryLocation); + await tryOpenExternalFile( + this.app.commands, + finalSingleItem.evalLogSummaryLocation, + ); return; } @@ -965,7 +974,10 @@ export class QueryHistoryManager extends DisposableObject { const query = finalSingleItem.completedQuery.query; const hasInterpretedResults = query.canHaveInterpretedResults(); if (hasInterpretedResults) { - await tryOpenExternalFile(query.resultsPaths.interpretedResultsPath); + await tryOpenExternalFile( + this.app.commands, + query.resultsPaths.interpretedResultsPath, + ); } else { const label = this.labelProvider.getLabel(finalSingleItem); void showAndLogInformationMessage( @@ -994,11 +1006,11 @@ export class QueryHistoryManager extends DisposableObject { } const query = finalSingleItem.completedQuery.query; if (await query.hasCsv()) { - void tryOpenExternalFile(query.csvPath); + void tryOpenExternalFile(this.app.commands, query.csvPath); return; } if (await query.exportCsvResults(this.qs.cliServer, query.csvPath)) { - void tryOpenExternalFile(query.csvPath); + void tryOpenExternalFile(this.app.commands, query.csvPath); } } @@ -1022,6 +1034,7 @@ export class QueryHistoryManager extends DisposableObject { } await tryOpenExternalFile( + this.app.commands, await finalSingleItem.completedQuery.query.ensureCsvAlerts( this.qs.cliServer, this.dbm, @@ -1049,6 +1062,7 @@ export class QueryHistoryManager extends DisposableObject { } await tryOpenExternalFile( + this.app.commands, await finalSingleItem.completedQuery.query.ensureDilPath( this.qs.cliServer, ), diff --git a/extensions/ql-vscode/src/vscode-utils/external-files.ts b/extensions/ql-vscode/src/vscode-utils/external-files.ts index 19e9dca76..a8e7a2830 100644 --- a/extensions/ql-vscode/src/vscode-utils/external-files.ts +++ b/extensions/ql-vscode/src/vscode-utils/external-files.ts @@ -1,4 +1,5 @@ -import { commands, Uri, window } from "vscode"; +import { Uri, window } from "vscode"; +import { AppCommandManager } from "../common/commands"; import { showAndLogExceptionWithTelemetry, showBinaryChoiceDialog, @@ -6,7 +7,10 @@ import { import { redactableError } from "../pure/errors"; import { asError, getErrorMessage, getErrorStack } from "../pure/helpers-pure"; -export async function tryOpenExternalFile(fileLocation: string) { +export async function tryOpenExternalFile( + CommandManager: AppCommandManager, + fileLocation: string, +) { const uri = Uri.file(fileLocation); try { await window.showTextDocument(uri, { preview: false }); @@ -25,7 +29,7 @@ the file in the file explorer and dragging it into the workspace.`, ); if (res) { try { - await commands.executeCommand("revealFileInOS", uri); + await CommandManager.execute("revealFileInOS", uri); } catch (e) { void showAndLogExceptionWithTelemetry( redactableError( diff --git a/extensions/ql-vscode/test/vscode-tests/no-workspace/query-history/vscode-utils/external-files.test.ts b/extensions/ql-vscode/test/vscode-tests/no-workspace/query-history/vscode-utils/external-files.test.ts index 01fdbbc9c..b87ee3fe6 100644 --- a/extensions/ql-vscode/test/vscode-tests/no-workspace/query-history/vscode-utils/external-files.test.ts +++ b/extensions/ql-vscode/test/vscode-tests/no-workspace/query-history/vscode-utils/external-files.test.ts @@ -1,5 +1,6 @@ import * as vscode from "vscode"; import { tryOpenExternalFile } from "../../../../../src/vscode-utils/external-files"; +import { createMockCommandManager } from "../../../../__mocks__/commandsMock"; import { mockedObject } from "../../../utils/mocking.helpers"; describe("tryOpenExternalFile", () => { @@ -9,9 +10,6 @@ describe("tryOpenExternalFile", () => { let showInformationMessageSpy: jest.SpiedFunction< typeof vscode.window.showInformationMessage >; - let executeCommandSpy: jest.SpiedFunction< - typeof vscode.commands.executeCommand - >; beforeEach(() => { showTextDocumentSpy = jest @@ -20,19 +18,19 @@ describe("tryOpenExternalFile", () => { showInformationMessageSpy = jest .spyOn(vscode.window, "showInformationMessage") .mockResolvedValue(undefined); - executeCommandSpy = jest - .spyOn(vscode.commands, "executeCommand") - .mockResolvedValue(undefined); }); it("should open an external file", async () => { - await tryOpenExternalFile("xxx"); + const executeCommand = jest.fn(); + const commandManager = createMockCommandManager({ executeCommand }); + + await tryOpenExternalFile(commandManager, "xxx"); expect(showTextDocumentSpy).toHaveBeenCalledTimes(1); expect(showTextDocumentSpy).toHaveBeenCalledWith( vscode.Uri.file("xxx"), expect.anything(), ); - expect(executeCommandSpy).not.toBeCalled(); + expect(executeCommand).not.toBeCalled(); }); [ @@ -40,26 +38,32 @@ describe("tryOpenExternalFile", () => { "Files above 50MB cannot be synchronized with extensions", ].forEach((msg) => { it(`should fail to open a file because "${msg}" and open externally`, async () => { + const executeCommand = jest.fn(); + const commandManager = createMockCommandManager({ executeCommand }); + showTextDocumentSpy.mockRejectedValue(new Error(msg)); showInformationMessageSpy.mockResolvedValue({ title: "Yes" }); - await tryOpenExternalFile("xxx"); + await tryOpenExternalFile(commandManager, "xxx"); const uri = vscode.Uri.file("xxx"); expect(showTextDocumentSpy).toHaveBeenCalledTimes(1); expect(showTextDocumentSpy).toHaveBeenCalledWith(uri, expect.anything()); - expect(executeCommandSpy).toHaveBeenCalledWith("revealFileInOS", uri); + expect(executeCommand).toHaveBeenCalledWith("revealFileInOS", uri); }); it(`should fail to open a file because "${msg}" and NOT open externally`, async () => { + const executeCommand = jest.fn(); + const commandManager = createMockCommandManager({ executeCommand }); + showTextDocumentSpy.mockRejectedValue(new Error(msg)); showInformationMessageSpy.mockResolvedValue({ title: "No" }); - await tryOpenExternalFile("xxx"); + await tryOpenExternalFile(commandManager, "xxx"); const uri = vscode.Uri.file("xxx"); expect(showTextDocumentSpy).toHaveBeenCalledTimes(1); expect(showTextDocumentSpy).toHaveBeenCalledWith(uri, expect.anything()); expect(showInformationMessageSpy).toBeCalled(); - expect(executeCommandSpy).not.toBeCalled(); + expect(executeCommand).not.toBeCalled(); }); }); }); From de0a8bf94d6cdf90613347c6f5800d6981d55268 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 23 Mar 2023 13:59:20 +0000 Subject: [PATCH 155/156] Bump @octokit/plugin-throttling in /extensions/ql-vscode Bumps [@octokit/plugin-throttling](https://github.com/octokit/plugin-throttling.js) from 4.3.2 to 5.0.1. - [Release notes](https://github.com/octokit/plugin-throttling.js/releases) - [Commits](https://github.com/octokit/plugin-throttling.js/compare/v4.3.2...v5.0.1) --- updated-dependencies: - dependency-name: "@octokit/plugin-throttling" dependency-type: direct:development update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- extensions/ql-vscode/package-lock.json | 46 +++++++++++++------------- extensions/ql-vscode/package.json | 2 +- 2 files changed, 24 insertions(+), 24 deletions(-) diff --git a/extensions/ql-vscode/package-lock.json b/extensions/ql-vscode/package-lock.json index e4546b988..57c6e6d9b 100644 --- a/extensions/ql-vscode/package-lock.json +++ b/extensions/ql-vscode/package-lock.json @@ -54,7 +54,7 @@ "@babel/core": "^7.18.13", "@babel/plugin-transform-modules-commonjs": "^7.18.6", "@faker-js/faker": "^7.5.0", - "@octokit/plugin-throttling": "^4.3.2", + "@octokit/plugin-throttling": "^5.0.1", "@storybook/addon-actions": "^6.5.10", "@storybook/addon-essentials": "^6.5.10", "@storybook/addon-interactions": "^6.5.10", @@ -5592,12 +5592,12 @@ } }, "node_modules/@octokit/plugin-throttling": { - "version": "4.3.2", - "resolved": "https://registry.npmjs.org/@octokit/plugin-throttling/-/plugin-throttling-4.3.2.tgz", - "integrity": "sha512-ZaCK599h3tzcoy0Jtdab95jgmD7X9iAk59E2E7hYKCAmnURaI4WpzwL9vckImilybUGrjY1JOWJapDs2N2D3vw==", + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/@octokit/plugin-throttling/-/plugin-throttling-5.0.1.tgz", + "integrity": "sha512-I4qxs7wYvYlFuY3PAUGWAVPhFXG3RwnvTiSr5Fu/Auz7bYhDLnzS2MjwV8nGLq/FPrWwYiweeZrI5yjs1YG4tQ==", "dev": true, "dependencies": { - "@octokit/types": "^8.0.0", + "@octokit/types": "^9.0.0", "bottleneck": "^2.15.3" }, "engines": { @@ -5608,18 +5608,18 @@ } }, "node_modules/@octokit/plugin-throttling/node_modules/@octokit/openapi-types": { - "version": "14.0.0", - "resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-14.0.0.tgz", - "integrity": "sha512-HNWisMYlR8VCnNurDU6os2ikx0s0VyEjDYHNS/h4cgb8DeOxQ0n72HyinUtdDVxJhFy3FWLGl0DJhfEWk3P5Iw==", + "version": "16.0.0", + "resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-16.0.0.tgz", + "integrity": "sha512-JbFWOqTJVLHZSUUoF4FzAZKYtqdxWu9Z5m2QQnOyEa04fOFljvyh7D3GYKbfuaSWisqehImiVIMG4eyJeP5VEA==", "dev": true }, "node_modules/@octokit/plugin-throttling/node_modules/@octokit/types": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/@octokit/types/-/types-8.0.0.tgz", - "integrity": "sha512-65/TPpOJP1i3K4lBJMnWqPUJ6zuOtzhtagDvydAWbEXpbFYA0oMKKyLb95NFZZP0lSh/4b6K+DQlzvYQJQQePg==", + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/@octokit/types/-/types-9.0.0.tgz", + "integrity": "sha512-LUewfj94xCMH2rbD5YJ+6AQ4AVjFYTgpp6rboWM5T7N3IsIF65SBEOVcYMGAEzO/kKNiNaW4LoWtoThOhH06gw==", "dev": true, "dependencies": { - "@octokit/openapi-types": "^14.0.0" + "@octokit/openapi-types": "^16.0.0" } }, "node_modules/@octokit/request": { @@ -45277,28 +45277,28 @@ } }, "@octokit/plugin-throttling": { - "version": "4.3.2", - "resolved": "https://registry.npmjs.org/@octokit/plugin-throttling/-/plugin-throttling-4.3.2.tgz", - "integrity": "sha512-ZaCK599h3tzcoy0Jtdab95jgmD7X9iAk59E2E7hYKCAmnURaI4WpzwL9vckImilybUGrjY1JOWJapDs2N2D3vw==", + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/@octokit/plugin-throttling/-/plugin-throttling-5.0.1.tgz", + "integrity": "sha512-I4qxs7wYvYlFuY3PAUGWAVPhFXG3RwnvTiSr5Fu/Auz7bYhDLnzS2MjwV8nGLq/FPrWwYiweeZrI5yjs1YG4tQ==", "dev": true, "requires": { - "@octokit/types": "^8.0.0", + "@octokit/types": "^9.0.0", "bottleneck": "^2.15.3" }, "dependencies": { "@octokit/openapi-types": { - "version": "14.0.0", - "resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-14.0.0.tgz", - "integrity": "sha512-HNWisMYlR8VCnNurDU6os2ikx0s0VyEjDYHNS/h4cgb8DeOxQ0n72HyinUtdDVxJhFy3FWLGl0DJhfEWk3P5Iw==", + "version": "16.0.0", + "resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-16.0.0.tgz", + "integrity": "sha512-JbFWOqTJVLHZSUUoF4FzAZKYtqdxWu9Z5m2QQnOyEa04fOFljvyh7D3GYKbfuaSWisqehImiVIMG4eyJeP5VEA==", "dev": true }, "@octokit/types": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/@octokit/types/-/types-8.0.0.tgz", - "integrity": "sha512-65/TPpOJP1i3K4lBJMnWqPUJ6zuOtzhtagDvydAWbEXpbFYA0oMKKyLb95NFZZP0lSh/4b6K+DQlzvYQJQQePg==", + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/@octokit/types/-/types-9.0.0.tgz", + "integrity": "sha512-LUewfj94xCMH2rbD5YJ+6AQ4AVjFYTgpp6rboWM5T7N3IsIF65SBEOVcYMGAEzO/kKNiNaW4LoWtoThOhH06gw==", "dev": true, "requires": { - "@octokit/openapi-types": "^14.0.0" + "@octokit/openapi-types": "^16.0.0" } } } diff --git a/extensions/ql-vscode/package.json b/extensions/ql-vscode/package.json index 19e0a0eb4..39377ca49 100644 --- a/extensions/ql-vscode/package.json +++ b/extensions/ql-vscode/package.json @@ -1475,7 +1475,7 @@ "@babel/core": "^7.18.13", "@babel/plugin-transform-modules-commonjs": "^7.18.6", "@faker-js/faker": "^7.5.0", - "@octokit/plugin-throttling": "^4.3.2", + "@octokit/plugin-throttling": "^5.0.1", "@storybook/addon-actions": "^6.5.10", "@storybook/addon-essentials": "^6.5.10", "@storybook/addon-interactions": "^6.5.10", From 180b84b3dac3943bd20eb34cf187e1ac4d1b454b Mon Sep 17 00:00:00 2001 From: Robert Date: Thu, 23 Mar 2023 14:25:15 +0000 Subject: [PATCH 156/156] Use correct variable name --- extensions/ql-vscode/src/vscode-utils/external-files.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/extensions/ql-vscode/src/vscode-utils/external-files.ts b/extensions/ql-vscode/src/vscode-utils/external-files.ts index a8e7a2830..b355199ef 100644 --- a/extensions/ql-vscode/src/vscode-utils/external-files.ts +++ b/extensions/ql-vscode/src/vscode-utils/external-files.ts @@ -8,7 +8,7 @@ import { redactableError } from "../pure/errors"; import { asError, getErrorMessage, getErrorStack } from "../pure/helpers-pure"; export async function tryOpenExternalFile( - CommandManager: AppCommandManager, + commandManager: AppCommandManager, fileLocation: string, ) { const uri = Uri.file(fileLocation); @@ -29,7 +29,7 @@ the file in the file explorer and dragging it into the workspace.`, ); if (res) { try { - await CommandManager.execute("revealFileInOS", uri); + await commandManager.execute("revealFileInOS", uri); } catch (e) { void showAndLogExceptionWithTelemetry( redactableError(