Rename ExternalApiUsage to Method (#2776)
This commit is contained in:
@@ -12,7 +12,7 @@ import type {
|
|||||||
} from "../variant-analysis/shared/variant-analysis";
|
} from "../variant-analysis/shared/variant-analysis";
|
||||||
import type { QLDebugConfiguration } from "../debugger/debug-configuration";
|
import type { QLDebugConfiguration } from "../debugger/debug-configuration";
|
||||||
import type { QueryTreeViewItem } from "../queries-panel/query-tree-view-item";
|
import type { QueryTreeViewItem } from "../queries-panel/query-tree-view-item";
|
||||||
import type { Usage } from "../model-editor/external-api-usage";
|
import type { Usage } from "../model-editor/method";
|
||||||
|
|
||||||
// A command function matching the signature that VS Code calls when
|
// A command function matching the signature that VS Code calls when
|
||||||
// a command is invoked from a context menu on a TreeView with
|
// a command is invoked from a context menu on a TreeView with
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ import {
|
|||||||
} from "../variant-analysis/shared/variant-analysis-filter-sort";
|
} from "../variant-analysis/shared/variant-analysis-filter-sort";
|
||||||
import { ErrorLike } from "../common/errors";
|
import { ErrorLike } from "../common/errors";
|
||||||
import { DataFlowPaths } from "../variant-analysis/shared/data-flow-paths";
|
import { DataFlowPaths } from "../variant-analysis/shared/data-flow-paths";
|
||||||
import { ExternalApiUsage, Usage } from "../model-editor/external-api-usage";
|
import { Method, Usage } from "../model-editor/method";
|
||||||
import { ModeledMethod } from "../model-editor/modeled-method";
|
import { ModeledMethod } from "../model-editor/modeled-method";
|
||||||
import { ModelEditorViewState } from "../model-editor/shared/view-state";
|
import { ModelEditorViewState } from "../model-editor/shared/view-state";
|
||||||
import { Mode } from "../model-editor/shared/mode";
|
import { Mode } from "../model-editor/shared/mode";
|
||||||
@@ -495,9 +495,9 @@ interface SetExtensionPackStateMessage {
|
|||||||
viewState: ModelEditorViewState;
|
viewState: ModelEditorViewState;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface SetExternalApiUsagesMessage {
|
interface SetMethodsMessage {
|
||||||
t: "setExternalApiUsages";
|
t: "setMethods";
|
||||||
externalApiUsages: ExternalApiUsage[];
|
methods: Method[];
|
||||||
}
|
}
|
||||||
|
|
||||||
interface LoadModeledMethodsMessage {
|
interface LoadModeledMethodsMessage {
|
||||||
@@ -523,7 +523,7 @@ interface SwitchModeMessage {
|
|||||||
|
|
||||||
interface JumpToUsageMessage {
|
interface JumpToUsageMessage {
|
||||||
t: "jumpToUsage";
|
t: "jumpToUsage";
|
||||||
method: ExternalApiUsage;
|
method: Method;
|
||||||
usage: Usage;
|
usage: Usage;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -535,29 +535,29 @@ interface OpenExtensionPackMessage {
|
|||||||
t: "openExtensionPack";
|
t: "openExtensionPack";
|
||||||
}
|
}
|
||||||
|
|
||||||
interface RefreshExternalApiUsages {
|
interface RefreshMethods {
|
||||||
t: "refreshExternalApiUsages";
|
t: "refreshMethods";
|
||||||
}
|
}
|
||||||
|
|
||||||
interface SaveModeledMethods {
|
interface SaveModeledMethods {
|
||||||
t: "saveModeledMethods";
|
t: "saveModeledMethods";
|
||||||
externalApiUsages: ExternalApiUsage[];
|
methods: Method[];
|
||||||
modeledMethods: Record<string, ModeledMethod>;
|
modeledMethods: Record<string, ModeledMethod>;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface GenerateExternalApiMessage {
|
interface GenerateMethodMessage {
|
||||||
t: "generateExternalApi";
|
t: "generateMethod";
|
||||||
}
|
}
|
||||||
|
|
||||||
interface GenerateExternalApiFromLlmMessage {
|
interface GenerateMethodsFromLlmMessage {
|
||||||
t: "generateExternalApiFromLlm";
|
t: "generateMethodsFromLlm";
|
||||||
packageName: string;
|
packageName: string;
|
||||||
externalApiUsages: ExternalApiUsage[];
|
methods: Method[];
|
||||||
modeledMethods: Record<string, ModeledMethod>;
|
modeledMethods: Record<string, ModeledMethod>;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface StopGeneratingExternalApiFromLlmMessage {
|
interface StopGeneratingMethodsFromLlmMessage {
|
||||||
t: "stopGeneratingExternalApiFromLlm";
|
t: "stopGeneratingMethodsFromLlm";
|
||||||
packageName: string;
|
packageName: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -572,7 +572,7 @@ interface HideModeledApisMessage {
|
|||||||
|
|
||||||
export type ToModelEditorMessage =
|
export type ToModelEditorMessage =
|
||||||
| SetExtensionPackStateMessage
|
| SetExtensionPackStateMessage
|
||||||
| SetExternalApiUsagesMessage
|
| SetMethodsMessage
|
||||||
| LoadModeledMethodsMessage
|
| LoadModeledMethodsMessage
|
||||||
| AddModeledMethodsMessage
|
| AddModeledMethodsMessage
|
||||||
| SetInProgressMethodsMessage;
|
| SetInProgressMethodsMessage;
|
||||||
@@ -580,14 +580,14 @@ export type ToModelEditorMessage =
|
|||||||
export type FromModelEditorMessage =
|
export type FromModelEditorMessage =
|
||||||
| ViewLoadedMsg
|
| ViewLoadedMsg
|
||||||
| SwitchModeMessage
|
| SwitchModeMessage
|
||||||
| RefreshExternalApiUsages
|
| RefreshMethods
|
||||||
| OpenDatabaseMessage
|
| OpenDatabaseMessage
|
||||||
| OpenExtensionPackMessage
|
| OpenExtensionPackMessage
|
||||||
| JumpToUsageMessage
|
| JumpToUsageMessage
|
||||||
| SaveModeledMethods
|
| SaveModeledMethods
|
||||||
| GenerateExternalApiMessage
|
| GenerateMethodMessage
|
||||||
| GenerateExternalApiFromLlmMessage
|
| GenerateMethodsFromLlmMessage
|
||||||
| StopGeneratingExternalApiFromLlmMessage
|
| StopGeneratingMethodsFromLlmMessage
|
||||||
| ModelDependencyMessage
|
| ModelDependencyMessage
|
||||||
| HideModeledApisMessage;
|
| HideModeledApisMessage;
|
||||||
|
|
||||||
@@ -597,7 +597,7 @@ export type FromMethodModelingMessage =
|
|||||||
|
|
||||||
interface SetMethodMessage {
|
interface SetMethodMessage {
|
||||||
t: "setMethod";
|
t: "setMethod";
|
||||||
method: ExternalApiUsage;
|
method: Method;
|
||||||
}
|
}
|
||||||
|
|
||||||
export type ToMethodModelingMessage = SetMethodMessage;
|
export type ToMethodModelingMessage = SetMethodMessage;
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ import { assertNever } from "../common/helpers-pure";
|
|||||||
import { dir } from "tmp-promise";
|
import { dir } from "tmp-promise";
|
||||||
import { writeFile, outputFile } from "fs-extra";
|
import { writeFile, outputFile } from "fs-extra";
|
||||||
import { dump as dumpYaml } from "js-yaml";
|
import { dump as dumpYaml } from "js-yaml";
|
||||||
import { MethodSignature } from "./external-api-usage";
|
import { MethodSignature } from "./method";
|
||||||
import { runQuery } from "../local-queries/run-query";
|
import { runQuery } from "../local-queries/run-query";
|
||||||
import { QueryMetadata } from "../common/interface-types";
|
import { QueryMetadata } from "../common/interface-types";
|
||||||
import { CancellationTokenSource } from "vscode";
|
import { CancellationTokenSource } from "vscode";
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import { AutoModelQueriesResult } from "./auto-model-codeml-queries";
|
|||||||
import { assertNever } from "../common/helpers-pure";
|
import { assertNever } from "../common/helpers-pure";
|
||||||
import * as Sarif from "sarif";
|
import * as Sarif from "sarif";
|
||||||
import { gzipEncode } from "../common/zlib";
|
import { gzipEncode } from "../common/zlib";
|
||||||
import { ExternalApiUsage, MethodSignature } from "./external-api-usage";
|
import { Method, MethodSignature } from "./method";
|
||||||
import { ModeledMethod } from "./modeled-method";
|
import { ModeledMethod } from "./modeled-method";
|
||||||
import { groupMethods, sortGroupNames, sortMethods } from "./shared/sorting";
|
import { groupMethods, sortGroupNames, sortMethods } from "./shared/sorting";
|
||||||
|
|
||||||
@@ -13,28 +13,26 @@ import { groupMethods, sortGroupNames, sortMethods } from "./shared/sorting";
|
|||||||
* candidates to the candidate limit and filtering out anything that is already modeled and respecting
|
* candidates to the candidate limit and filtering out anything that is already modeled and respecting
|
||||||
* the order in the UI.
|
* the order in the UI.
|
||||||
* @param mode Whether it is application or framework mode.
|
* @param mode Whether it is application or framework mode.
|
||||||
* @param externalApiUsages all external API usages.
|
* @param methods all methods.
|
||||||
* @param modeledMethods the currently modeled methods.
|
* @param modeledMethods the currently modeled methods.
|
||||||
* @returns list of modeled methods that are candidates for modeling.
|
* @returns list of modeled methods that are candidates for modeling.
|
||||||
*/
|
*/
|
||||||
export function getCandidates(
|
export function getCandidates(
|
||||||
mode: Mode,
|
mode: Mode,
|
||||||
externalApiUsages: ExternalApiUsage[],
|
methods: Method[],
|
||||||
modeledMethods: Record<string, ModeledMethod>,
|
modeledMethods: Record<string, ModeledMethod>,
|
||||||
): MethodSignature[] {
|
): MethodSignature[] {
|
||||||
// Sort the same way as the UI so we send the first ones listed in the UI first
|
// Sort the same way as the UI so we send the first ones listed in the UI first
|
||||||
const grouped = groupMethods(externalApiUsages, mode);
|
const grouped = groupMethods(methods, mode);
|
||||||
const sortedGroupNames = sortGroupNames(grouped);
|
const sortedGroupNames = sortGroupNames(grouped);
|
||||||
const sortedExternalApiUsages = sortedGroupNames.flatMap((name) =>
|
const sortedMethods = sortedGroupNames.flatMap((name) =>
|
||||||
sortMethods(grouped[name]),
|
sortMethods(grouped[name]),
|
||||||
);
|
);
|
||||||
|
|
||||||
const candidates: MethodSignature[] = [];
|
const candidates: MethodSignature[] = [];
|
||||||
|
|
||||||
for (const externalApiUsage of sortedExternalApiUsages) {
|
for (const method of sortedMethods) {
|
||||||
const modeledMethod: ModeledMethod = modeledMethods[
|
const modeledMethod: ModeledMethod = modeledMethods[method.signature] ?? {
|
||||||
externalApiUsage.signature
|
|
||||||
] ?? {
|
|
||||||
type: "none",
|
type: "none",
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -44,12 +42,12 @@ export function getCandidates(
|
|||||||
}
|
}
|
||||||
|
|
||||||
// A method that is supported is modeled outside of the model file, so it is not a candidate.
|
// A method that is supported is modeled outside of the model file, so it is not a candidate.
|
||||||
if (externalApiUsage.supported) {
|
if (method.supported) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// The rest are candidates
|
// The rest are candidates
|
||||||
candidates.push(externalApiUsage);
|
candidates.push(method);
|
||||||
}
|
}
|
||||||
return candidates;
|
return candidates;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { ExternalApiUsage, MethodSignature } from "./external-api-usage";
|
import { Method, MethodSignature } from "./method";
|
||||||
import { ModeledMethod } from "./modeled-method";
|
import { ModeledMethod } from "./modeled-method";
|
||||||
import { extLogger } from "../common/logging/vscode";
|
import { extLogger } from "../common/logging/vscode";
|
||||||
import { load as loadYaml } from "js-yaml";
|
import { load as loadYaml } from "js-yaml";
|
||||||
@@ -52,13 +52,13 @@ export class AutoModeler {
|
|||||||
* Models the given package's external API usages, except
|
* Models the given package's external API usages, except
|
||||||
* the ones that are already modeled.
|
* the ones that are already modeled.
|
||||||
* @param packageName The name of the package to model.
|
* @param packageName The name of the package to model.
|
||||||
* @param externalApiUsages The external API usages.
|
* @param methods The methods.
|
||||||
* @param modeledMethods The currently modeled methods.
|
* @param modeledMethods The currently modeled methods.
|
||||||
* @param mode The mode we are modeling in.
|
* @param mode The mode we are modeling in.
|
||||||
*/
|
*/
|
||||||
public async startModeling(
|
public async startModeling(
|
||||||
packageName: string,
|
packageName: string,
|
||||||
externalApiUsages: ExternalApiUsage[],
|
methods: Method[],
|
||||||
modeledMethods: Record<string, ModeledMethod>,
|
modeledMethods: Record<string, ModeledMethod>,
|
||||||
mode: Mode,
|
mode: Mode,
|
||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
@@ -72,7 +72,7 @@ export class AutoModeler {
|
|||||||
try {
|
try {
|
||||||
await this.modelPackage(
|
await this.modelPackage(
|
||||||
packageName,
|
packageName,
|
||||||
externalApiUsages,
|
methods,
|
||||||
modeledMethods,
|
modeledMethods,
|
||||||
mode,
|
mode,
|
||||||
cancellationTokenSource,
|
cancellationTokenSource,
|
||||||
@@ -105,7 +105,7 @@ export class AutoModeler {
|
|||||||
|
|
||||||
private async modelPackage(
|
private async modelPackage(
|
||||||
packageName: string,
|
packageName: string,
|
||||||
externalApiUsages: ExternalApiUsage[],
|
methods: Method[],
|
||||||
modeledMethods: Record<string, ModeledMethod>,
|
modeledMethods: Record<string, ModeledMethod>,
|
||||||
mode: Mode,
|
mode: Mode,
|
||||||
cancellationTokenSource: CancellationTokenSource,
|
cancellationTokenSource: CancellationTokenSource,
|
||||||
@@ -113,11 +113,7 @@ export class AutoModeler {
|
|||||||
void extLogger.log(`Modeling package ${packageName}`);
|
void extLogger.log(`Modeling package ${packageName}`);
|
||||||
await withProgress(async (progress) => {
|
await withProgress(async (progress) => {
|
||||||
// Fetch the candidates to send to the model
|
// Fetch the candidates to send to the model
|
||||||
const allCandidateMethods = getCandidates(
|
const allCandidateMethods = getCandidates(mode, methods, modeledMethods);
|
||||||
mode,
|
|
||||||
externalApiUsages,
|
|
||||||
modeledMethods,
|
|
||||||
);
|
|
||||||
|
|
||||||
// If there are no candidates, there is nothing to model and we just return
|
// If there are no candidates, there is nothing to model and we just return
|
||||||
if (allCandidateMethods.length === 0) {
|
if (allCandidateMethods.length === 0) {
|
||||||
|
|||||||
@@ -1,16 +1,12 @@
|
|||||||
import { DecodedBqrsChunk } from "../common/bqrs-cli-types";
|
import { DecodedBqrsChunk } from "../common/bqrs-cli-types";
|
||||||
import {
|
import { Call, CallClassification, Method } from "./method";
|
||||||
Call,
|
|
||||||
CallClassification,
|
|
||||||
ExternalApiUsage,
|
|
||||||
} from "./external-api-usage";
|
|
||||||
import { ModeledMethodType } from "./modeled-method";
|
import { ModeledMethodType } from "./modeled-method";
|
||||||
import { parseLibraryFilename } from "./library";
|
import { parseLibraryFilename } from "./library";
|
||||||
|
|
||||||
export function decodeBqrsToExternalApiUsages(
|
export function decodeBqrsToExternalApiUsages(
|
||||||
chunk: DecodedBqrsChunk,
|
chunk: DecodedBqrsChunk,
|
||||||
): ExternalApiUsage[] {
|
): Method[] {
|
||||||
const methodsByApiName = new Map<string, ExternalApiUsage>();
|
const methodsByApiName = new Map<string, Method>();
|
||||||
|
|
||||||
chunk?.tuples.forEach((tuple) => {
|
chunk?.tuples.forEach((tuple) => {
|
||||||
const usage = tuple[0] as Call;
|
const usage = tuple[0] as Call;
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ import { Mode } from "./shared/mode";
|
|||||||
import { writeFile } from "fs-extra";
|
import { writeFile } from "fs-extra";
|
||||||
import { QueryLanguage } from "../common/query-language";
|
import { QueryLanguage } from "../common/query-language";
|
||||||
import { fetchExternalApiQueries } from "./queries";
|
import { fetchExternalApiQueries } from "./queries";
|
||||||
import { ExternalApiUsage } from "./external-api-usage";
|
import { Method } from "./method";
|
||||||
import { runQuery } from "../local-queries/run-query";
|
import { runQuery } from "../local-queries/run-query";
|
||||||
import { decodeBqrsToExternalApiUsages } from "./bqrs";
|
import { decodeBqrsToExternalApiUsages } from "./bqrs";
|
||||||
|
|
||||||
@@ -69,7 +69,7 @@ export async function runExternalApiQueries(
|
|||||||
progress,
|
progress,
|
||||||
token,
|
token,
|
||||||
}: RunQueryOptions,
|
}: RunQueryOptions,
|
||||||
): Promise<ExternalApiUsage[] | undefined> {
|
): Promise<Method[] | undefined> {
|
||||||
// The below code is temporary to allow for rapid prototyping of the queries. Once the queries are stabilized, we will
|
// The below code is temporary to allow for rapid prototyping of the queries. Once the queries are stabilized, we will
|
||||||
// move these queries into the `github/codeql` repository and use them like any other contextual (e.g. AST) queries.
|
// move these queries into the `github/codeql` repository and use them like any other contextual (e.g. AST) queries.
|
||||||
// This is intentionally not pretty code, as it will be removed soon.
|
// This is intentionally not pretty code, as it will be removed soon.
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import { ExtensionContext, window } from "vscode";
|
import { ExtensionContext, window } from "vscode";
|
||||||
import { DisposableObject } from "../../common/disposable-object";
|
import { DisposableObject } from "../../common/disposable-object";
|
||||||
import { MethodModelingViewProvider } from "./method-modeling-view-provider";
|
import { MethodModelingViewProvider } from "./method-modeling-view-provider";
|
||||||
import { ExternalApiUsage } from "../external-api-usage";
|
import { Method } from "../method";
|
||||||
|
|
||||||
export class MethodModelingPanel extends DisposableObject {
|
export class MethodModelingPanel extends DisposableObject {
|
||||||
private readonly provider: MethodModelingViewProvider;
|
private readonly provider: MethodModelingViewProvider;
|
||||||
@@ -18,7 +18,7 @@ export class MethodModelingPanel extends DisposableObject {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
public async setMethod(method: ExternalApiUsage): Promise<void> {
|
public async setMethod(method: Method): Promise<void> {
|
||||||
await this.provider.setMethod(method);
|
await this.provider.setMethod(method);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ import { telemetryListener } from "../../common/vscode/telemetry";
|
|||||||
import { showAndLogExceptionWithTelemetry } from "../../common/logging/notifications";
|
import { showAndLogExceptionWithTelemetry } from "../../common/logging/notifications";
|
||||||
import { extLogger } from "../../common/logging/vscode/loggers";
|
import { extLogger } from "../../common/logging/vscode/loggers";
|
||||||
import { redactableError } from "../../common/errors";
|
import { redactableError } from "../../common/errors";
|
||||||
import { ExternalApiUsage } from "../external-api-usage";
|
import { Method } from "../method";
|
||||||
|
|
||||||
export class MethodModelingViewProvider implements WebviewViewProvider {
|
export class MethodModelingViewProvider implements WebviewViewProvider {
|
||||||
public static readonly viewType = "codeQLMethodModeling";
|
public static readonly viewType = "codeQLMethodModeling";
|
||||||
@@ -46,7 +46,7 @@ export class MethodModelingViewProvider implements WebviewViewProvider {
|
|||||||
this.webviewView = webviewView;
|
this.webviewView = webviewView;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async setMethod(method: ExternalApiUsage): Promise<void> {
|
public async setMethod(method: Method): Promise<void> {
|
||||||
if (this.webviewView) {
|
if (this.webviewView) {
|
||||||
await this.webviewView.webview.postMessage({
|
await this.webviewView.webview.postMessage({
|
||||||
t: "setMethod",
|
t: "setMethod",
|
||||||
|
|||||||
@@ -39,7 +39,7 @@ export interface MethodSignature {
|
|||||||
methodParameters: string;
|
methodParameters: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ExternalApiUsage extends MethodSignature {
|
export interface Method extends MethodSignature {
|
||||||
/**
|
/**
|
||||||
* Contains the name of the library containing the method declaration, e.g. `sql2o-1.6.0.jar` or `System.Runtime.dll`
|
* Contains the name of the library containing the method declaration, e.g. `sql2o-1.6.0.jar` or `System.Runtime.dll`
|
||||||
*/
|
*/
|
||||||
@@ -9,7 +9,7 @@ import {
|
|||||||
Uri,
|
Uri,
|
||||||
} from "vscode";
|
} from "vscode";
|
||||||
import { DisposableObject } from "../../common/disposable-object";
|
import { DisposableObject } from "../../common/disposable-object";
|
||||||
import { ExternalApiUsage, Usage } from "../external-api-usage";
|
import { Method, Usage } from "../method";
|
||||||
import { DatabaseItem } from "../../databases/local-databases";
|
import { DatabaseItem } from "../../databases/local-databases";
|
||||||
import { relative } from "path";
|
import { relative } from "path";
|
||||||
import { CodeQLCliServer } from "../../codeql-cli/cli";
|
import { CodeQLCliServer } from "../../codeql-cli/cli";
|
||||||
@@ -19,7 +19,7 @@ export class MethodsUsageDataProvider
|
|||||||
extends DisposableObject
|
extends DisposableObject
|
||||||
implements TreeDataProvider<MethodsUsageTreeViewItem>
|
implements TreeDataProvider<MethodsUsageTreeViewItem>
|
||||||
{
|
{
|
||||||
private externalApiUsages: ExternalApiUsage[] = [];
|
private methods: Method[] = [];
|
||||||
private databaseItem: DatabaseItem | undefined = undefined;
|
private databaseItem: DatabaseItem | undefined = undefined;
|
||||||
private sourceLocationPrefix: string | undefined = undefined;
|
private sourceLocationPrefix: string | undefined = undefined;
|
||||||
private hideModeledApis: boolean = INITIAL_HIDE_MODELED_APIS_VALUE;
|
private hideModeledApis: boolean = INITIAL_HIDE_MODELED_APIS_VALUE;
|
||||||
@@ -44,16 +44,16 @@ export class MethodsUsageDataProvider
|
|||||||
* method and instead always pass new objects/arrays.
|
* method and instead always pass new objects/arrays.
|
||||||
*/
|
*/
|
||||||
public async setState(
|
public async setState(
|
||||||
externalApiUsages: ExternalApiUsage[],
|
methods: Method[],
|
||||||
databaseItem: DatabaseItem,
|
databaseItem: DatabaseItem,
|
||||||
hideModeledApis: boolean,
|
hideModeledApis: boolean,
|
||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
if (
|
if (
|
||||||
this.externalApiUsages !== externalApiUsages ||
|
this.methods !== methods ||
|
||||||
this.databaseItem !== databaseItem ||
|
this.databaseItem !== databaseItem ||
|
||||||
this.hideModeledApis !== hideModeledApis
|
this.hideModeledApis !== hideModeledApis
|
||||||
) {
|
) {
|
||||||
this.externalApiUsages = externalApiUsages;
|
this.methods = methods;
|
||||||
this.databaseItem = databaseItem;
|
this.databaseItem = databaseItem;
|
||||||
this.sourceLocationPrefix =
|
this.sourceLocationPrefix =
|
||||||
await this.databaseItem.getSourceLocationPrefix(this.cliServer);
|
await this.databaseItem.getSourceLocationPrefix(this.cliServer);
|
||||||
@@ -100,9 +100,9 @@ export class MethodsUsageDataProvider
|
|||||||
getChildren(item?: MethodsUsageTreeViewItem): MethodsUsageTreeViewItem[] {
|
getChildren(item?: MethodsUsageTreeViewItem): MethodsUsageTreeViewItem[] {
|
||||||
if (item === undefined) {
|
if (item === undefined) {
|
||||||
if (this.hideModeledApis) {
|
if (this.hideModeledApis) {
|
||||||
return this.externalApiUsages.filter((api) => !api.supported);
|
return this.methods.filter((api) => !api.supported);
|
||||||
} else {
|
} else {
|
||||||
return this.externalApiUsages;
|
return this.methods;
|
||||||
}
|
}
|
||||||
} else if (isExternalApiUsage(item)) {
|
} else if (isExternalApiUsage(item)) {
|
||||||
return item.usages;
|
return item.usages;
|
||||||
@@ -117,13 +117,13 @@ export class MethodsUsageDataProvider
|
|||||||
if (isExternalApiUsage(item)) {
|
if (isExternalApiUsage(item)) {
|
||||||
return undefined;
|
return undefined;
|
||||||
} else {
|
} else {
|
||||||
return this.externalApiUsages.find((e) => e.usages.includes(item));
|
return this.methods.find((e) => e.usages.includes(item));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public resolveCanonicalUsage(usage: Usage): Usage | undefined {
|
public resolveCanonicalUsage(usage: Usage): Usage | undefined {
|
||||||
for (const externalApiUsage of this.externalApiUsages) {
|
for (const method of this.methods) {
|
||||||
for (const u of externalApiUsage.usages) {
|
for (const u of method.usages) {
|
||||||
if (usagesAreEqual(u, usage)) {
|
if (usagesAreEqual(u, usage)) {
|
||||||
return u;
|
return u;
|
||||||
}
|
}
|
||||||
@@ -133,11 +133,9 @@ export class MethodsUsageDataProvider
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export type MethodsUsageTreeViewItem = ExternalApiUsage | Usage;
|
export type MethodsUsageTreeViewItem = Method | Usage;
|
||||||
|
|
||||||
function isExternalApiUsage(
|
function isExternalApiUsage(item: MethodsUsageTreeViewItem): item is Method {
|
||||||
item: MethodsUsageTreeViewItem,
|
|
||||||
): item is ExternalApiUsage {
|
|
||||||
return (item as any).usages !== undefined;
|
return (item as any).usages !== undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import {
|
|||||||
MethodsUsageDataProvider,
|
MethodsUsageDataProvider,
|
||||||
MethodsUsageTreeViewItem,
|
MethodsUsageTreeViewItem,
|
||||||
} from "./methods-usage-data-provider";
|
} from "./methods-usage-data-provider";
|
||||||
import { ExternalApiUsage, Usage } from "../external-api-usage";
|
import { Method, Usage } from "../method";
|
||||||
import { DatabaseItem } from "../../databases/local-databases";
|
import { DatabaseItem } from "../../databases/local-databases";
|
||||||
import { CodeQLCliServer } from "../../codeql-cli/cli";
|
import { CodeQLCliServer } from "../../codeql-cli/cli";
|
||||||
|
|
||||||
@@ -24,18 +24,14 @@ export class MethodsUsagePanel extends DisposableObject {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public async setState(
|
public async setState(
|
||||||
externalApiUsages: ExternalApiUsage[],
|
methods: Method[],
|
||||||
databaseItem: DatabaseItem,
|
databaseItem: DatabaseItem,
|
||||||
hideModeledApis: boolean,
|
hideModeledApis: boolean,
|
||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
await this.dataProvider.setState(
|
await this.dataProvider.setState(methods, databaseItem, hideModeledApis);
|
||||||
externalApiUsages,
|
|
||||||
databaseItem,
|
|
||||||
hideModeledApis,
|
|
||||||
);
|
|
||||||
const numOfApis = hideModeledApis
|
const numOfApis = hideModeledApis
|
||||||
? externalApiUsages.filter((api) => !api.supported).length
|
? methods.filter((api) => !api.supported).length
|
||||||
: externalApiUsages.length;
|
: methods.length;
|
||||||
this.treeView.badge = {
|
this.treeView.badge = {
|
||||||
value: numOfApis,
|
value: numOfApis,
|
||||||
tooltip: "Number of external APIs",
|
tooltip: "Number of external APIs",
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ import { DisposableObject } from "../common/disposable-object";
|
|||||||
import { MethodsUsagePanel } from "./methods-usage/methods-usage-panel";
|
import { MethodsUsagePanel } from "./methods-usage/methods-usage-panel";
|
||||||
import { Mode } from "./shared/mode";
|
import { Mode } from "./shared/mode";
|
||||||
import { showResolvableLocation } from "../databases/local-databases/locations";
|
import { showResolvableLocation } from "../databases/local-databases/locations";
|
||||||
import { ExternalApiUsage, Usage } from "./external-api-usage";
|
import { Method, Usage } from "./method";
|
||||||
import { setUpPack } from "./model-editor-queries";
|
import { setUpPack } from "./model-editor-queries";
|
||||||
import { MethodModelingPanel } from "./method-modeling/method-modeling-panel";
|
import { MethodModelingPanel } from "./method-modeling/method-modeling-panel";
|
||||||
|
|
||||||
@@ -175,10 +175,7 @@ export class ModelEditorModule extends DisposableObject {
|
|||||||
await ensureDir(this.queryStorageDir);
|
await ensureDir(this.queryStorageDir);
|
||||||
}
|
}
|
||||||
|
|
||||||
private async showMethod(
|
private async showMethod(method: Method, usage: Usage): Promise<void> {
|
||||||
method: ExternalApiUsage,
|
|
||||||
usage: Usage,
|
|
||||||
): Promise<void> {
|
|
||||||
await this.methodsUsagePanel.revealItem(usage);
|
await this.methodsUsagePanel.revealItem(usage);
|
||||||
await this.methodModelingPanel.setMethod(method);
|
await this.methodModelingPanel.setMethod(method);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ import { App } from "../common/app";
|
|||||||
import { showResolvableLocation } from "../databases/local-databases/locations";
|
import { showResolvableLocation } from "../databases/local-databases/locations";
|
||||||
import { redactableError } from "../common/errors";
|
import { redactableError } from "../common/errors";
|
||||||
import { runExternalApiQueries } from "./external-api-usage-queries";
|
import { runExternalApiQueries } from "./external-api-usage-queries";
|
||||||
import { ExternalApiUsage, Usage } from "./external-api-usage";
|
import { Method, Usage } from "./method";
|
||||||
import { ModeledMethod } from "./modeled-method";
|
import { ModeledMethod } from "./modeled-method";
|
||||||
import { ExtensionPack } from "./shared/extension-pack";
|
import { ExtensionPack } from "./shared/extension-pack";
|
||||||
import { showLlmGeneration } from "../config";
|
import { showLlmGeneration } from "../config";
|
||||||
@@ -46,7 +46,7 @@ export class ModelEditorView extends AbstractWebview<
|
|||||||
> {
|
> {
|
||||||
private readonly autoModeler: AutoModeler;
|
private readonly autoModeler: AutoModeler;
|
||||||
|
|
||||||
private externalApiUsages: ExternalApiUsage[];
|
private methods: Method[];
|
||||||
private hideModeledApis: boolean;
|
private hideModeledApis: boolean;
|
||||||
|
|
||||||
public constructor(
|
public constructor(
|
||||||
@@ -61,12 +61,12 @@ export class ModelEditorView extends AbstractWebview<
|
|||||||
private readonly extensionPack: ExtensionPack,
|
private readonly extensionPack: ExtensionPack,
|
||||||
private mode: Mode,
|
private mode: Mode,
|
||||||
private readonly updateMethodsUsagePanelState: (
|
private readonly updateMethodsUsagePanelState: (
|
||||||
externalApiUsages: ExternalApiUsage[],
|
methods: Method[],
|
||||||
databaseItem: DatabaseItem,
|
databaseItem: DatabaseItem,
|
||||||
hideModeledApis: boolean,
|
hideModeledApis: boolean,
|
||||||
) => Promise<void>,
|
) => Promise<void>,
|
||||||
private readonly showMethod: (
|
private readonly showMethod: (
|
||||||
method: ExternalApiUsage,
|
method: Method,
|
||||||
usage: Usage,
|
usage: Usage,
|
||||||
) => Promise<void>,
|
) => Promise<void>,
|
||||||
private readonly handleViewBecameActive: (view: ModelEditorView) => void,
|
private readonly handleViewBecameActive: (view: ModelEditorView) => void,
|
||||||
@@ -94,7 +94,7 @@ export class ModelEditorView extends AbstractWebview<
|
|||||||
await this.postMessage({ t: "addModeledMethods", modeledMethods });
|
await this.postMessage({ t: "addModeledMethods", modeledMethods });
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
this.externalApiUsages = [];
|
this.methods = [];
|
||||||
this.hideModeledApis = INITIAL_HIDE_MODELED_APIS_VALUE;
|
this.hideModeledApis = INITIAL_HIDE_MODELED_APIS_VALUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -106,7 +106,7 @@ export class ModelEditorView extends AbstractWebview<
|
|||||||
if (panel.active) {
|
if (panel.active) {
|
||||||
this.handleViewBecameActive(this);
|
this.handleViewBecameActive(this);
|
||||||
await this.updateMethodsUsagePanelState(
|
await this.updateMethodsUsagePanelState(
|
||||||
this.externalApiUsages,
|
this.methods,
|
||||||
this.databaseItem,
|
this.databaseItem,
|
||||||
this.hideModeledApis,
|
this.hideModeledApis,
|
||||||
);
|
);
|
||||||
@@ -188,7 +188,7 @@ export class ModelEditorView extends AbstractWebview<
|
|||||||
);
|
);
|
||||||
|
|
||||||
break;
|
break;
|
||||||
case "refreshExternalApiUsages":
|
case "refreshMethods":
|
||||||
await this.loadExternalApiUsages();
|
await this.loadExternalApiUsages();
|
||||||
|
|
||||||
break;
|
break;
|
||||||
@@ -201,7 +201,7 @@ export class ModelEditorView extends AbstractWebview<
|
|||||||
this.extensionPack,
|
this.extensionPack,
|
||||||
this.databaseItem.name,
|
this.databaseItem.name,
|
||||||
this.databaseItem.language,
|
this.databaseItem.language,
|
||||||
msg.externalApiUsages,
|
msg.methods,
|
||||||
msg.modeledMethods,
|
msg.modeledMethods,
|
||||||
this.mode,
|
this.mode,
|
||||||
this.cliServer,
|
this.cliServer,
|
||||||
@@ -210,18 +210,18 @@ export class ModelEditorView extends AbstractWebview<
|
|||||||
await Promise.all([this.setViewState(), this.loadExternalApiUsages()]);
|
await Promise.all([this.setViewState(), this.loadExternalApiUsages()]);
|
||||||
|
|
||||||
break;
|
break;
|
||||||
case "generateExternalApi":
|
case "generateMethod":
|
||||||
await this.generateModeledMethods();
|
await this.generateModeledMethods();
|
||||||
|
|
||||||
break;
|
break;
|
||||||
case "generateExternalApiFromLlm":
|
case "generateMethodsFromLlm":
|
||||||
await this.generateModeledMethodsFromLlm(
|
await this.generateModeledMethodsFromLlm(
|
||||||
msg.packageName,
|
msg.packageName,
|
||||||
msg.externalApiUsages,
|
msg.methods,
|
||||||
msg.modeledMethods,
|
msg.modeledMethods,
|
||||||
);
|
);
|
||||||
break;
|
break;
|
||||||
case "stopGeneratingExternalApiFromLlm":
|
case "stopGeneratingMethodsFromLlm":
|
||||||
await this.autoModeler.stopModeling(msg.packageName);
|
await this.autoModeler.stopModeling(msg.packageName);
|
||||||
break;
|
break;
|
||||||
case "modelDependency":
|
case "modelDependency":
|
||||||
@@ -236,7 +236,7 @@ export class ModelEditorView extends AbstractWebview<
|
|||||||
case "hideModeledApis":
|
case "hideModeledApis":
|
||||||
this.hideModeledApis = msg.hideModeledApis;
|
this.hideModeledApis = msg.hideModeledApis;
|
||||||
await this.updateMethodsUsagePanelState(
|
await this.updateMethodsUsagePanelState(
|
||||||
this.externalApiUsages,
|
this.methods,
|
||||||
this.databaseItem,
|
this.databaseItem,
|
||||||
this.hideModeledApis,
|
this.hideModeledApis,
|
||||||
);
|
);
|
||||||
@@ -270,7 +270,7 @@ export class ModelEditorView extends AbstractWebview<
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
protected async handleJumpToUsage(method: ExternalApiUsage, usage: Usage) {
|
protected async handleJumpToUsage(method: Method, usage: Usage) {
|
||||||
await this.showMethod(method, usage);
|
await this.showMethod(method, usage);
|
||||||
await showResolvableLocation(usage.url, this.databaseItem, this.app.logger);
|
await showResolvableLocation(usage.url, this.databaseItem, this.app.logger);
|
||||||
}
|
}
|
||||||
@@ -311,15 +311,15 @@ export class ModelEditorView extends AbstractWebview<
|
|||||||
if (!queryResult) {
|
if (!queryResult) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
this.externalApiUsages = queryResult;
|
this.methods = queryResult;
|
||||||
|
|
||||||
await this.postMessage({
|
await this.postMessage({
|
||||||
t: "setExternalApiUsages",
|
t: "setMethods",
|
||||||
externalApiUsages: this.externalApiUsages,
|
methods: this.methods,
|
||||||
});
|
});
|
||||||
if (this.isMostRecentlyActiveView(this)) {
|
if (this.isMostRecentlyActiveView(this)) {
|
||||||
await this.updateMethodsUsagePanelState(
|
await this.updateMethodsUsagePanelState(
|
||||||
this.externalApiUsages,
|
this.methods,
|
||||||
this.databaseItem,
|
this.databaseItem,
|
||||||
this.hideModeledApis,
|
this.hideModeledApis,
|
||||||
);
|
);
|
||||||
@@ -399,12 +399,12 @@ export class ModelEditorView extends AbstractWebview<
|
|||||||
|
|
||||||
private async generateModeledMethodsFromLlm(
|
private async generateModeledMethodsFromLlm(
|
||||||
packageName: string,
|
packageName: string,
|
||||||
externalApiUsages: ExternalApiUsage[],
|
methods: Method[],
|
||||||
modeledMethods: Record<string, ModeledMethod>,
|
modeledMethods: Record<string, ModeledMethod>,
|
||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
await this.autoModeler.startModeling(
|
await this.autoModeler.startModeling(
|
||||||
packageName,
|
packageName,
|
||||||
externalApiUsages,
|
methods,
|
||||||
modeledMethods,
|
modeledMethods,
|
||||||
this.mode,
|
this.mode,
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { outputFile, readFile } from "fs-extra";
|
import { outputFile, readFile } from "fs-extra";
|
||||||
import { ExternalApiUsage } from "./external-api-usage";
|
import { Method } from "./method";
|
||||||
import { ModeledMethod } from "./modeled-method";
|
import { ModeledMethod } from "./modeled-method";
|
||||||
import { Mode } from "./shared/mode";
|
import { Mode } from "./shared/mode";
|
||||||
import { createDataExtensionYamls, loadDataExtensionYaml } from "./yaml";
|
import { createDataExtensionYamls, loadDataExtensionYaml } from "./yaml";
|
||||||
@@ -15,7 +15,7 @@ export async function saveModeledMethods(
|
|||||||
extensionPack: ExtensionPack,
|
extensionPack: ExtensionPack,
|
||||||
databaseName: string,
|
databaseName: string,
|
||||||
language: string,
|
language: string,
|
||||||
externalApiUsages: ExternalApiUsage[],
|
methods: Method[],
|
||||||
modeledMethods: Record<string, ModeledMethod>,
|
modeledMethods: Record<string, ModeledMethod>,
|
||||||
mode: Mode,
|
mode: Mode,
|
||||||
cliServer: CodeQLCliServer,
|
cliServer: CodeQLCliServer,
|
||||||
@@ -30,7 +30,7 @@ export async function saveModeledMethods(
|
|||||||
const yamls = createDataExtensionYamls(
|
const yamls = createDataExtensionYamls(
|
||||||
databaseName,
|
databaseName,
|
||||||
language,
|
language,
|
||||||
externalApiUsages,
|
methods,
|
||||||
modeledMethods,
|
modeledMethods,
|
||||||
existingModeledMethods,
|
existingModeledMethods,
|
||||||
mode,
|
mode,
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { MethodSignature } from "./external-api-usage";
|
import { MethodSignature } from "./method";
|
||||||
|
|
||||||
export type ModeledMethodType =
|
export type ModeledMethodType =
|
||||||
| "none"
|
| "none"
|
||||||
|
|||||||
@@ -1,15 +1,14 @@
|
|||||||
import { ExternalApiUsage } from "../external-api-usage";
|
import { Method } from "../method";
|
||||||
|
|
||||||
export function calculateModeledPercentage(
|
export function calculateModeledPercentage(
|
||||||
externalApiUsages: Array<Pick<ExternalApiUsage, "supported">>,
|
methods: Array<Pick<Method, "supported">>,
|
||||||
): number {
|
): number {
|
||||||
if (externalApiUsages.length === 0) {
|
if (methods.length === 0) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
const modeledExternalApiUsages = externalApiUsages.filter((m) => m.supported);
|
const modeledMethods = methods.filter((m) => m.supported);
|
||||||
|
|
||||||
const modeledRatio =
|
const modeledRatio = modeledMethods.length / methods.length;
|
||||||
modeledExternalApiUsages.length / externalApiUsages.length;
|
|
||||||
return modeledRatio * 100;
|
return modeledRatio * 100;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,47 +1,40 @@
|
|||||||
import { ExternalApiUsage } from "../external-api-usage";
|
import { Method } from "../method";
|
||||||
import { Mode } from "./mode";
|
import { Mode } from "./mode";
|
||||||
import { calculateModeledPercentage } from "./modeled-percentage";
|
import { calculateModeledPercentage } from "./modeled-percentage";
|
||||||
|
|
||||||
export function groupMethods(
|
export function groupMethods(
|
||||||
externalApiUsages: ExternalApiUsage[],
|
methods: Method[],
|
||||||
mode: Mode,
|
mode: Mode,
|
||||||
): Record<string, ExternalApiUsage[]> {
|
): Record<string, Method[]> {
|
||||||
const groupedByLibrary: Record<string, ExternalApiUsage[]> = {};
|
const groupedByLibrary: Record<string, Method[]> = {};
|
||||||
|
|
||||||
for (const externalApiUsage of externalApiUsages) {
|
for (const method of methods) {
|
||||||
// Group by package if using framework mode
|
// Group by package if using framework mode
|
||||||
const key =
|
const key = mode === Mode.Framework ? method.packageName : method.library;
|
||||||
mode === Mode.Framework
|
|
||||||
? externalApiUsage.packageName
|
|
||||||
: externalApiUsage.library;
|
|
||||||
|
|
||||||
groupedByLibrary[key] ??= [];
|
groupedByLibrary[key] ??= [];
|
||||||
groupedByLibrary[key].push(externalApiUsage);
|
groupedByLibrary[key].push(method);
|
||||||
}
|
}
|
||||||
|
|
||||||
return groupedByLibrary;
|
return groupedByLibrary;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function sortGroupNames(
|
export function sortGroupNames(methods: Record<string, Method[]>): string[] {
|
||||||
methods: Record<string, ExternalApiUsage[]>,
|
|
||||||
): string[] {
|
|
||||||
return Object.keys(methods).sort((a, b) =>
|
return Object.keys(methods).sort((a, b) =>
|
||||||
compareGroups(methods[a], a, methods[b], b),
|
compareGroups(methods[a], a, methods[b], b),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function sortMethods(
|
export function sortMethods(methods: Method[]): Method[] {
|
||||||
externalApiUsages: ExternalApiUsage[],
|
const sortedMethods = [...methods];
|
||||||
): ExternalApiUsage[] {
|
sortedMethods.sort((a, b) => compareMethod(a, b));
|
||||||
const sortedExternalApiUsages = [...externalApiUsages];
|
return sortedMethods;
|
||||||
sortedExternalApiUsages.sort((a, b) => compareMethod(a, b));
|
|
||||||
return sortedExternalApiUsages;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function compareGroups(
|
function compareGroups(
|
||||||
a: ExternalApiUsage[],
|
a: Method[],
|
||||||
aName: string,
|
aName: string,
|
||||||
b: ExternalApiUsage[],
|
b: Method[],
|
||||||
bName: string,
|
bName: string,
|
||||||
): number {
|
): number {
|
||||||
const supportedPercentageA = calculateModeledPercentage(a);
|
const supportedPercentageA = calculateModeledPercentage(a);
|
||||||
@@ -75,7 +68,7 @@ function compareGroups(
|
|||||||
return numberOfUsagesB - numberOfUsagesA;
|
return numberOfUsagesB - numberOfUsagesA;
|
||||||
}
|
}
|
||||||
|
|
||||||
function compareMethod(a: ExternalApiUsage, b: ExternalApiUsage): number {
|
function compareMethod(a: Method, b: Method): number {
|
||||||
// Sort first by supported, putting unmodeled methods first.
|
// Sort first by supported, putting unmodeled methods first.
|
||||||
if (a.supported && !b.supported) {
|
if (a.supported && !b.supported) {
|
||||||
return 1;
|
return 1;
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import Ajv from "ajv";
|
import Ajv from "ajv";
|
||||||
|
|
||||||
import { ExternalApiUsage } from "./external-api-usage";
|
import { Method } from "./method";
|
||||||
import { ModeledMethod, ModeledMethodType } from "./modeled-method";
|
import { ModeledMethod, ModeledMethodType } from "./modeled-method";
|
||||||
import {
|
import {
|
||||||
ExtensiblePredicateDefinition,
|
ExtensiblePredicateDefinition,
|
||||||
@@ -71,7 +71,7 @@ ${extensions.join("\n")}`;
|
|||||||
export function createDataExtensionYamls(
|
export function createDataExtensionYamls(
|
||||||
databaseName: string,
|
databaseName: string,
|
||||||
language: string,
|
language: string,
|
||||||
externalApiUsages: ExternalApiUsage[],
|
methods: Method[],
|
||||||
newModeledMethods: Record<string, ModeledMethod>,
|
newModeledMethods: Record<string, ModeledMethod>,
|
||||||
existingModeledMethods: Record<string, Record<string, ModeledMethod>>,
|
existingModeledMethods: Record<string, Record<string, ModeledMethod>>,
|
||||||
mode: Mode,
|
mode: Mode,
|
||||||
@@ -80,7 +80,7 @@ export function createDataExtensionYamls(
|
|||||||
case Mode.Application:
|
case Mode.Application:
|
||||||
return createDataExtensionYamlsForApplicationMode(
|
return createDataExtensionYamlsForApplicationMode(
|
||||||
language,
|
language,
|
||||||
externalApiUsages,
|
methods,
|
||||||
newModeledMethods,
|
newModeledMethods,
|
||||||
existingModeledMethods,
|
existingModeledMethods,
|
||||||
);
|
);
|
||||||
@@ -88,7 +88,7 @@ export function createDataExtensionYamls(
|
|||||||
return createDataExtensionYamlsForFrameworkMode(
|
return createDataExtensionYamlsForFrameworkMode(
|
||||||
databaseName,
|
databaseName,
|
||||||
language,
|
language,
|
||||||
externalApiUsages,
|
methods,
|
||||||
newModeledMethods,
|
newModeledMethods,
|
||||||
existingModeledMethods,
|
existingModeledMethods,
|
||||||
);
|
);
|
||||||
@@ -99,7 +99,7 @@ export function createDataExtensionYamls(
|
|||||||
|
|
||||||
export function createDataExtensionYamlsForApplicationMode(
|
export function createDataExtensionYamlsForApplicationMode(
|
||||||
language: string,
|
language: string,
|
||||||
externalApiUsages: ExternalApiUsage[],
|
methods: Method[],
|
||||||
newModeledMethods: Record<string, ModeledMethod>,
|
newModeledMethods: Record<string, ModeledMethod>,
|
||||||
existingModeledMethods: Record<string, Record<string, ModeledMethod>>,
|
existingModeledMethods: Record<string, Record<string, ModeledMethod>>,
|
||||||
): Record<string, string> {
|
): Record<string, string> {
|
||||||
@@ -111,11 +111,9 @@ export function createDataExtensionYamlsForApplicationMode(
|
|||||||
// We only want to generate a yaml file when it's a known external API usage
|
// We only want to generate a yaml file when it's a known external API usage
|
||||||
// and there are new modeled methods for it. This avoids us overwriting other
|
// and there are new modeled methods for it. This avoids us overwriting other
|
||||||
// files that may contain data we don't know about.
|
// files that may contain data we don't know about.
|
||||||
for (const externalApiUsage of externalApiUsages) {
|
for (const method of methods) {
|
||||||
if (externalApiUsage.signature in newModeledMethods) {
|
if (method.signature in newModeledMethods) {
|
||||||
methodsByLibraryFilename[
|
methodsByLibraryFilename[createFilenameForLibrary(method.library)] = {};
|
||||||
createFilenameForLibrary(externalApiUsage.library)
|
|
||||||
] = {};
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -130,11 +128,11 @@ export function createDataExtensionYamlsForApplicationMode(
|
|||||||
|
|
||||||
// Add the new modeled methods, potentially overwriting existing modeled methods
|
// Add the new modeled methods, potentially overwriting existing modeled methods
|
||||||
// but not removing existing modeled methods that are not in the new set.
|
// but not removing existing modeled methods that are not in the new set.
|
||||||
for (const externalApiUsage of externalApiUsages) {
|
for (const method of methods) {
|
||||||
const method = newModeledMethods[externalApiUsage.signature];
|
const newMethod = newModeledMethods[method.signature];
|
||||||
if (method) {
|
if (newMethod) {
|
||||||
const filename = createFilenameForLibrary(externalApiUsage.library);
|
const filename = createFilenameForLibrary(method.library);
|
||||||
methodsByLibraryFilename[filename][method.signature] = method;
|
methodsByLibraryFilename[filename][newMethod.signature] = newMethod;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -153,7 +151,7 @@ export function createDataExtensionYamlsForApplicationMode(
|
|||||||
export function createDataExtensionYamlsForFrameworkMode(
|
export function createDataExtensionYamlsForFrameworkMode(
|
||||||
databaseName: string,
|
databaseName: string,
|
||||||
language: string,
|
language: string,
|
||||||
externalApiUsages: ExternalApiUsage[],
|
unmodeledMethods: Method[],
|
||||||
newModeledMethods: Record<string, ModeledMethod>,
|
newModeledMethods: Record<string, ModeledMethod>,
|
||||||
existingModeledMethods: Record<string, Record<string, ModeledMethod>>,
|
existingModeledMethods: Record<string, Record<string, ModeledMethod>>,
|
||||||
prefix = "models/",
|
prefix = "models/",
|
||||||
@@ -177,8 +175,8 @@ export function createDataExtensionYamlsForFrameworkMode(
|
|||||||
|
|
||||||
// Add the new modeled methods, potentially overwriting existing modeled methods
|
// Add the new modeled methods, potentially overwriting existing modeled methods
|
||||||
// but not removing existing modeled methods that are not in the new set.
|
// but not removing existing modeled methods that are not in the new set.
|
||||||
for (const externalApiUsage of externalApiUsages) {
|
for (const method of unmodeledMethods) {
|
||||||
const modeledMethod = newModeledMethods[externalApiUsage.signature];
|
const modeledMethod = newModeledMethods[method.signature];
|
||||||
if (modeledMethod) {
|
if (modeledMethod) {
|
||||||
methods[modeledMethod.signature] = modeledMethod;
|
methods[modeledMethod.signature] = modeledMethod;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,18 +0,0 @@
|
|||||||
import * as React from "react";
|
|
||||||
|
|
||||||
import { Meta, StoryFn } from "@storybook/react";
|
|
||||||
|
|
||||||
import { ExternalApiUsageName as ExternalApiUsageNameComponent } from "../../view/model-editor/ExternalApiUsageName";
|
|
||||||
import { createExternalApiUsage } from "../../../test/factories/data-extension/external-api-factories";
|
|
||||||
|
|
||||||
export default {
|
|
||||||
title: "CodeQL Model Editor/External API Usage Name",
|
|
||||||
component: ExternalApiUsageNameComponent,
|
|
||||||
} as Meta<typeof ExternalApiUsageNameComponent>;
|
|
||||||
|
|
||||||
const Template: StoryFn<typeof ExternalApiUsageNameComponent> = (args) => (
|
|
||||||
<ExternalApiUsageNameComponent {...args} />
|
|
||||||
);
|
|
||||||
|
|
||||||
export const ExternalApiUsageName = Template.bind({});
|
|
||||||
ExternalApiUsageName.args = createExternalApiUsage();
|
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
import * as React from "react";
|
||||||
|
|
||||||
|
import { Meta, StoryFn } from "@storybook/react";
|
||||||
|
|
||||||
|
import { MethodName as MethodNameComponent } from "../../view/model-editor/MethodName";
|
||||||
|
import { createMethod } from "../../../test/factories/data-extension/method-factories";
|
||||||
|
|
||||||
|
export default {
|
||||||
|
title: "CodeQL Model Editor/Method Name",
|
||||||
|
component: MethodNameComponent,
|
||||||
|
} as Meta<typeof MethodNameComponent>;
|
||||||
|
|
||||||
|
const Template: StoryFn<typeof MethodNameComponent> = (args) => (
|
||||||
|
<MethodNameComponent {...args} />
|
||||||
|
);
|
||||||
|
|
||||||
|
export const MethodName = Template.bind({});
|
||||||
|
MethodName.args = createMethod();
|
||||||
@@ -3,7 +3,7 @@ import * as React from "react";
|
|||||||
import { Meta, StoryFn } from "@storybook/react";
|
import { Meta, StoryFn } from "@storybook/react";
|
||||||
|
|
||||||
import { MethodRow as MethodRowComponent } from "../../view/model-editor/MethodRow";
|
import { MethodRow as MethodRowComponent } from "../../view/model-editor/MethodRow";
|
||||||
import { CallClassification } from "../../model-editor/external-api-usage";
|
import { CallClassification } from "../../model-editor/method";
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
title: "CodeQL Model Editor/Method Row",
|
title: "CodeQL Model Editor/Method Row",
|
||||||
@@ -16,7 +16,7 @@ const Template: StoryFn<typeof MethodRowComponent> = (args) => (
|
|||||||
|
|
||||||
export const MethodRow = Template.bind({});
|
export const MethodRow = Template.bind({});
|
||||||
MethodRow.args = {
|
MethodRow.args = {
|
||||||
externalApiUsage: {
|
method: {
|
||||||
library: "sql2o-1.6.0.jar",
|
library: "sql2o-1.6.0.jar",
|
||||||
signature: "org.sql2o.Sql2o#open()",
|
signature: "org.sql2o.Sql2o#open()",
|
||||||
packageName: "org.sql2o",
|
packageName: "org.sql2o",
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import { Meta, StoryFn } from "@storybook/react";
|
|||||||
|
|
||||||
import { Mode } from "../../model-editor/shared/mode";
|
import { Mode } from "../../model-editor/shared/mode";
|
||||||
import { ModelEditor as ModelEditorComponent } from "../../view/model-editor/ModelEditor";
|
import { ModelEditor as ModelEditorComponent } from "../../view/model-editor/ModelEditor";
|
||||||
import { CallClassification } from "../../model-editor/external-api-usage";
|
import { CallClassification } from "../../model-editor/method";
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
title: "CodeQL Model Editor/CodeQL Model Editor",
|
title: "CodeQL Model Editor/CodeQL Model Editor",
|
||||||
@@ -31,7 +31,7 @@ ModelEditor.args = {
|
|||||||
showLlmButton: true,
|
showLlmButton: true,
|
||||||
mode: Mode.Application,
|
mode: Mode.Application,
|
||||||
},
|
},
|
||||||
initialExternalApiUsages: [
|
initialMethods: [
|
||||||
{
|
{
|
||||||
library: "sql2o",
|
library: "sql2o",
|
||||||
libraryVersion: "1.6.0",
|
libraryVersion: "1.6.0",
|
||||||
|
|||||||
@@ -4,8 +4,8 @@ import {
|
|||||||
ModelingStatus,
|
ModelingStatus,
|
||||||
ModelingStatusIndicator,
|
ModelingStatusIndicator,
|
||||||
} from "../model-editor/ModelingStatusIndicator";
|
} from "../model-editor/ModelingStatusIndicator";
|
||||||
import { ExternalApiUsage } from "../../model-editor/external-api-usage";
|
import { Method } from "../../model-editor/method";
|
||||||
import { ExternalApiUsageName } from "../model-editor/ExternalApiUsageName";
|
import { MethodName } from "../model-editor/MethodName";
|
||||||
|
|
||||||
const Container = styled.div`
|
const Container = styled.div`
|
||||||
background-color: var(--vscode-peekViewResult-background);
|
background-color: var(--vscode-peekViewResult-background);
|
||||||
@@ -25,18 +25,18 @@ const DependencyContainer = styled.div`
|
|||||||
|
|
||||||
export type MethodModelingProps = {
|
export type MethodModelingProps = {
|
||||||
modelingStatus: ModelingStatus;
|
modelingStatus: ModelingStatus;
|
||||||
externalApiUsage: ExternalApiUsage;
|
method: Method;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const MethodModeling = ({
|
export const MethodModeling = ({
|
||||||
modelingStatus,
|
modelingStatus,
|
||||||
externalApiUsage,
|
method,
|
||||||
}: MethodModelingProps): JSX.Element => {
|
}: MethodModelingProps): JSX.Element => {
|
||||||
return (
|
return (
|
||||||
<Container>
|
<Container>
|
||||||
<Title>API or Method</Title>
|
<Title>API or Method</Title>
|
||||||
<DependencyContainer>
|
<DependencyContainer>
|
||||||
<ExternalApiUsageName {...externalApiUsage} />
|
<MethodName {...method} />
|
||||||
<ModelingStatusIndicator status={modelingStatus} />
|
<ModelingStatusIndicator status={modelingStatus} />
|
||||||
</DependencyContainer>
|
</DependencyContainer>
|
||||||
</Container>
|
</Container>
|
||||||
|
|||||||
@@ -2,12 +2,12 @@ import * as React from "react";
|
|||||||
import { useEffect, useState } from "react";
|
import { useEffect, useState } from "react";
|
||||||
import { MethodModeling } from "./MethodModeling";
|
import { MethodModeling } from "./MethodModeling";
|
||||||
import { ModelingStatus } from "../model-editor/ModelingStatusIndicator";
|
import { ModelingStatus } from "../model-editor/ModelingStatusIndicator";
|
||||||
import { ExternalApiUsage } from "../../model-editor/external-api-usage";
|
import { Method } from "../../model-editor/method";
|
||||||
import { ToMethodModelingMessage } from "../../common/interface-types";
|
import { ToMethodModelingMessage } from "../../common/interface-types";
|
||||||
import { assertNever } from "../../common/helpers-pure";
|
import { assertNever } from "../../common/helpers-pure";
|
||||||
|
|
||||||
export function MethodModelingView(): JSX.Element {
|
export function MethodModelingView(): JSX.Element {
|
||||||
const [method, setMethod] = useState<ExternalApiUsage | undefined>(undefined);
|
const [method, setMethod] = useState<Method | undefined>(undefined);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const listener = (evt: MessageEvent) => {
|
const listener = (evt: MessageEvent) => {
|
||||||
@@ -36,7 +36,5 @@ export function MethodModelingView(): JSX.Element {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const modelingStatus: ModelingStatus = "saved";
|
const modelingStatus: ModelingStatus = "saved";
|
||||||
return (
|
return <MethodModeling modelingStatus={modelingStatus} method={method} />;
|
||||||
<MethodModeling modelingStatus={modelingStatus} externalApiUsage={method} />
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import * as React from "react";
|
import * as React from "react";
|
||||||
import { render as reactRender, screen } from "@testing-library/react";
|
import { render as reactRender, screen } from "@testing-library/react";
|
||||||
import { MethodModeling, MethodModelingProps } from "../MethodModeling";
|
import { MethodModeling, MethodModelingProps } from "../MethodModeling";
|
||||||
import { createExternalApiUsage } from "../../../../test/factories/data-extension/external-api-factories";
|
import { createMethod } from "../../../../test/factories/data-extension/method-factories";
|
||||||
|
|
||||||
describe(MethodModeling.name, () => {
|
describe(MethodModeling.name, () => {
|
||||||
const render = (props: MethodModelingProps) =>
|
const render = (props: MethodModelingProps) =>
|
||||||
@@ -10,7 +10,7 @@ describe(MethodModeling.name, () => {
|
|||||||
it("renders method modeling panel", () => {
|
it("renders method modeling panel", () => {
|
||||||
render({
|
render({
|
||||||
modelingStatus: "saved",
|
modelingStatus: "saved",
|
||||||
externalApiUsage: createExternalApiUsage(),
|
method: createMethod(),
|
||||||
});
|
});
|
||||||
|
|
||||||
expect(screen.getByText("API or Method")).toBeInTheDocument();
|
expect(screen.getByText("API or Method")).toBeInTheDocument();
|
||||||
|
|||||||
@@ -1,19 +0,0 @@
|
|||||||
import * as React from "react";
|
|
||||||
import { styled } from "styled-components";
|
|
||||||
import { ExternalApiUsage } from "../../model-editor/external-api-usage";
|
|
||||||
|
|
||||||
const Name = styled.span`
|
|
||||||
font-family: var(--vscode-editor-font-family);
|
|
||||||
`;
|
|
||||||
|
|
||||||
export const ExternalApiUsageName = (
|
|
||||||
externalApiUsage: ExternalApiUsage,
|
|
||||||
): JSX.Element => {
|
|
||||||
return (
|
|
||||||
<Name>
|
|
||||||
{externalApiUsage.packageName && <>{externalApiUsage.packageName}.</>}
|
|
||||||
{externalApiUsage.typeName}.{externalApiUsage.methodName}
|
|
||||||
{externalApiUsage.methodParameters}
|
|
||||||
</Name>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
import * as React from "react";
|
import * as React from "react";
|
||||||
import { useCallback, useMemo, useState } from "react";
|
import { useCallback, useMemo, useState } from "react";
|
||||||
import { styled } from "styled-components";
|
import { styled } from "styled-components";
|
||||||
import { ExternalApiUsage } from "../../model-editor/external-api-usage";
|
import { Method } from "../../model-editor/method";
|
||||||
import { ModeledMethod } from "../../model-editor/modeled-method";
|
import { ModeledMethod } from "../../model-editor/modeled-method";
|
||||||
import { ModeledMethodDataGrid } from "./ModeledMethodDataGrid";
|
import { ModeledMethodDataGrid } from "./ModeledMethodDataGrid";
|
||||||
import { calculateModeledPercentage } from "../../model-editor/shared/modeled-percentage";
|
import { calculateModeledPercentage } from "../../model-editor/shared/modeled-percentage";
|
||||||
@@ -70,7 +70,7 @@ const ButtonsContainer = styled.div`
|
|||||||
type Props = {
|
type Props = {
|
||||||
title: string;
|
title: string;
|
||||||
libraryVersion?: string;
|
libraryVersion?: string;
|
||||||
externalApiUsages: ExternalApiUsage[];
|
methods: Method[];
|
||||||
modeledMethods: Record<string, ModeledMethod>;
|
modeledMethods: Record<string, ModeledMethod>;
|
||||||
modifiedSignatures: Set<string>;
|
modifiedSignatures: Set<string>;
|
||||||
inProgressMethods: InProgressMethods;
|
inProgressMethods: InProgressMethods;
|
||||||
@@ -78,16 +78,16 @@ type Props = {
|
|||||||
hideModeledApis: boolean;
|
hideModeledApis: boolean;
|
||||||
onChange: (
|
onChange: (
|
||||||
modelName: string,
|
modelName: string,
|
||||||
externalApiUsage: ExternalApiUsage,
|
method: Method,
|
||||||
modeledMethod: ModeledMethod,
|
modeledMethod: ModeledMethod,
|
||||||
) => void;
|
) => void;
|
||||||
onSaveModelClick: (
|
onSaveModelClick: (
|
||||||
externalApiUsages: ExternalApiUsage[],
|
methods: Method[],
|
||||||
modeledMethods: Record<string, ModeledMethod>,
|
modeledMethods: Record<string, ModeledMethod>,
|
||||||
) => void;
|
) => void;
|
||||||
onGenerateFromLlmClick: (
|
onGenerateFromLlmClick: (
|
||||||
dependencyName: string,
|
dependencyName: string,
|
||||||
externalApiUsages: ExternalApiUsage[],
|
methods: Method[],
|
||||||
modeledMethods: Record<string, ModeledMethod>,
|
modeledMethods: Record<string, ModeledMethod>,
|
||||||
) => void;
|
) => void;
|
||||||
onStopGenerateFromLlmClick: (dependencyName: string) => void;
|
onStopGenerateFromLlmClick: (dependencyName: string) => void;
|
||||||
@@ -98,7 +98,7 @@ type Props = {
|
|||||||
export const LibraryRow = ({
|
export const LibraryRow = ({
|
||||||
title,
|
title,
|
||||||
libraryVersion,
|
libraryVersion,
|
||||||
externalApiUsages,
|
methods,
|
||||||
modeledMethods,
|
modeledMethods,
|
||||||
modifiedSignatures,
|
modifiedSignatures,
|
||||||
inProgressMethods,
|
inProgressMethods,
|
||||||
@@ -112,8 +112,8 @@ export const LibraryRow = ({
|
|||||||
onModelDependencyClick,
|
onModelDependencyClick,
|
||||||
}: Props) => {
|
}: Props) => {
|
||||||
const modeledPercentage = useMemo(() => {
|
const modeledPercentage = useMemo(() => {
|
||||||
return calculateModeledPercentage(externalApiUsages);
|
return calculateModeledPercentage(methods);
|
||||||
}, [externalApiUsages]);
|
}, [methods]);
|
||||||
|
|
||||||
const [isExpanded, setExpanded] = useState(false);
|
const [isExpanded, setExpanded] = useState(false);
|
||||||
|
|
||||||
@@ -123,11 +123,11 @@ export const LibraryRow = ({
|
|||||||
|
|
||||||
const handleModelWithAI = useCallback(
|
const handleModelWithAI = useCallback(
|
||||||
async (e: React.MouseEvent) => {
|
async (e: React.MouseEvent) => {
|
||||||
onGenerateFromLlmClick(title, externalApiUsages, modeledMethods);
|
onGenerateFromLlmClick(title, methods, modeledMethods);
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
},
|
},
|
||||||
[title, externalApiUsages, modeledMethods, onGenerateFromLlmClick],
|
[title, methods, modeledMethods, onGenerateFromLlmClick],
|
||||||
);
|
);
|
||||||
|
|
||||||
const handleStopModelWithAI = useCallback(
|
const handleStopModelWithAI = useCallback(
|
||||||
@@ -159,31 +159,29 @@ export const LibraryRow = ({
|
|||||||
|
|
||||||
const handleSave = useCallback(
|
const handleSave = useCallback(
|
||||||
async (e: React.MouseEvent) => {
|
async (e: React.MouseEvent) => {
|
||||||
onSaveModelClick(externalApiUsages, modeledMethods);
|
onSaveModelClick(methods, modeledMethods);
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
},
|
},
|
||||||
[externalApiUsages, modeledMethods, onSaveModelClick],
|
[methods, modeledMethods, onSaveModelClick],
|
||||||
);
|
);
|
||||||
|
|
||||||
const onChangeWithModelName = useCallback(
|
const onChangeWithModelName = useCallback(
|
||||||
(externalApiUsage: ExternalApiUsage, modeledMethod: ModeledMethod) => {
|
(method: Method, modeledMethod: ModeledMethod) => {
|
||||||
onChange(title, externalApiUsage, modeledMethod);
|
onChange(title, method, modeledMethod);
|
||||||
},
|
},
|
||||||
[onChange, title],
|
[onChange, title],
|
||||||
);
|
);
|
||||||
|
|
||||||
const hasUnsavedChanges = useMemo(() => {
|
const hasUnsavedChanges = useMemo(() => {
|
||||||
return externalApiUsages.some((externalApiUsage) =>
|
return methods.some((method) => modifiedSignatures.has(method.signature));
|
||||||
modifiedSignatures.has(externalApiUsage.signature),
|
}, [methods, modifiedSignatures]);
|
||||||
);
|
|
||||||
}, [externalApiUsages, modifiedSignatures]);
|
|
||||||
|
|
||||||
const canStopAutoModeling = useMemo(() => {
|
const canStopAutoModeling = useMemo(() => {
|
||||||
return externalApiUsages.some((externalApiUsage) =>
|
return methods.some((method) =>
|
||||||
inProgressMethods.hasMethod(title, externalApiUsage.signature),
|
inProgressMethods.hasMethod(title, method.signature),
|
||||||
);
|
);
|
||||||
}, [externalApiUsages, title, inProgressMethods]);
|
}, [methods, title, inProgressMethods]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<LibraryContainer>
|
<LibraryContainer>
|
||||||
@@ -233,7 +231,7 @@ export const LibraryRow = ({
|
|||||||
<SectionDivider />
|
<SectionDivider />
|
||||||
<ModeledMethodDataGrid
|
<ModeledMethodDataGrid
|
||||||
packageName={title}
|
packageName={title}
|
||||||
externalApiUsages={externalApiUsages}
|
methods={methods}
|
||||||
modeledMethods={modeledMethods}
|
modeledMethods={modeledMethods}
|
||||||
modifiedSignatures={modifiedSignatures}
|
modifiedSignatures={modifiedSignatures}
|
||||||
inProgressMethods={inProgressMethods}
|
inProgressMethods={inProgressMethods}
|
||||||
|
|||||||
@@ -1,9 +1,6 @@
|
|||||||
import * as React from "react";
|
import * as React from "react";
|
||||||
import { useMemo } from "react";
|
import { useMemo } from "react";
|
||||||
import {
|
import { CallClassification, Method } from "../../model-editor/method";
|
||||||
CallClassification,
|
|
||||||
ExternalApiUsage,
|
|
||||||
} from "../../model-editor/external-api-usage";
|
|
||||||
import { VSCodeTag } from "@vscode/webview-ui-toolkit/react";
|
import { VSCodeTag } from "@vscode/webview-ui-toolkit/react";
|
||||||
import { styled } from "styled-components";
|
import { styled } from "styled-components";
|
||||||
|
|
||||||
@@ -19,18 +16,18 @@ const ClassificationTag = styled(VSCodeTag)`
|
|||||||
`;
|
`;
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
externalApiUsage: ExternalApiUsage;
|
method: Method;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const MethodClassifications = ({ externalApiUsage }: Props) => {
|
export const MethodClassifications = ({ method }: Props) => {
|
||||||
const allUsageClassifications = useMemo(
|
const allUsageClassifications = useMemo(
|
||||||
() =>
|
() =>
|
||||||
new Set(
|
new Set(
|
||||||
externalApiUsage.usages.map((usage) => {
|
method.usages.map((usage) => {
|
||||||
return usage.classification;
|
return usage.classification;
|
||||||
}),
|
}),
|
||||||
),
|
),
|
||||||
[externalApiUsage.usages],
|
[method.usages],
|
||||||
);
|
);
|
||||||
|
|
||||||
const inSource = allUsageClassifications.has(CallClassification.Source);
|
const inSource = allUsageClassifications.has(CallClassification.Source);
|
||||||
|
|||||||
17
extensions/ql-vscode/src/view/model-editor/MethodName.tsx
Normal file
17
extensions/ql-vscode/src/view/model-editor/MethodName.tsx
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
import * as React from "react";
|
||||||
|
import { styled } from "styled-components";
|
||||||
|
import { Method } from "../../model-editor/method";
|
||||||
|
|
||||||
|
const Name = styled.span`
|
||||||
|
font-family: var(--vscode-editor-font-family);
|
||||||
|
`;
|
||||||
|
|
||||||
|
export const MethodName = (method: Method): JSX.Element => {
|
||||||
|
return (
|
||||||
|
<Name>
|
||||||
|
{method.packageName && <>{method.packageName}.</>}
|
||||||
|
{method.typeName}.{method.methodName}
|
||||||
|
{method.methodParameters}
|
||||||
|
</Name>
|
||||||
|
);
|
||||||
|
};
|
||||||
@@ -9,7 +9,7 @@ import { ChangeEvent, useCallback, useMemo } from "react";
|
|||||||
import { styled } from "styled-components";
|
import { styled } from "styled-components";
|
||||||
import { vscode } from "../vscode-api";
|
import { vscode } from "../vscode-api";
|
||||||
|
|
||||||
import { ExternalApiUsage } from "../../model-editor/external-api-usage";
|
import { Method } from "../../model-editor/method";
|
||||||
import {
|
import {
|
||||||
ModeledMethod,
|
ModeledMethod,
|
||||||
ModeledMethodType,
|
ModeledMethodType,
|
||||||
@@ -25,7 +25,7 @@ import {
|
|||||||
ModelingStatusIndicator,
|
ModelingStatusIndicator,
|
||||||
} from "./ModelingStatusIndicator";
|
} from "./ModelingStatusIndicator";
|
||||||
import { InProgressDropdown } from "./InProgressDropdown";
|
import { InProgressDropdown } from "./InProgressDropdown";
|
||||||
import { ExternalApiUsageName } from "./ExternalApiUsageName";
|
import { MethodName } from "./MethodName";
|
||||||
|
|
||||||
const ApiOrMethodCell = styled(VSCodeDataGridCell)`
|
const ApiOrMethodCell = styled(VSCodeDataGridCell)`
|
||||||
display: flex;
|
display: flex;
|
||||||
@@ -61,24 +61,20 @@ const modelTypeOptions: Array<{ value: ModeledMethodType; label: string }> = [
|
|||||||
];
|
];
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
externalApiUsage: ExternalApiUsage;
|
method: Method;
|
||||||
modeledMethod: ModeledMethod | undefined;
|
modeledMethod: ModeledMethod | undefined;
|
||||||
methodIsUnsaved: boolean;
|
methodIsUnsaved: boolean;
|
||||||
modelingInProgress: boolean;
|
modelingInProgress: boolean;
|
||||||
mode: Mode;
|
mode: Mode;
|
||||||
hideModeledApis: boolean;
|
hideModeledApis: boolean;
|
||||||
onChange: (
|
onChange: (method: Method, modeledMethod: ModeledMethod) => void;
|
||||||
externalApiUsage: ExternalApiUsage,
|
|
||||||
modeledMethod: ModeledMethod,
|
|
||||||
) => void;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export const MethodRow = (props: Props) => {
|
export const MethodRow = (props: Props) => {
|
||||||
const { externalApiUsage, modeledMethod, methodIsUnsaved, hideModeledApis } =
|
const { method, modeledMethod, methodIsUnsaved, hideModeledApis } = props;
|
||||||
props;
|
|
||||||
|
|
||||||
const methodCanBeModeled =
|
const methodCanBeModeled =
|
||||||
!externalApiUsage.supported ||
|
!method.supported ||
|
||||||
(modeledMethod && modeledMethod?.type !== "none") ||
|
(modeledMethod && modeledMethod?.type !== "none") ||
|
||||||
methodIsUnsaved;
|
methodIsUnsaved;
|
||||||
|
|
||||||
@@ -92,17 +88,16 @@ export const MethodRow = (props: Props) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
function ModelableMethodRow(props: Props) {
|
function ModelableMethodRow(props: Props) {
|
||||||
const { externalApiUsage, modeledMethod, methodIsUnsaved, mode, onChange } =
|
const { method, modeledMethod, methodIsUnsaved, mode, onChange } = props;
|
||||||
props;
|
|
||||||
|
|
||||||
const argumentsList = useMemo(() => {
|
const argumentsList = useMemo(() => {
|
||||||
if (externalApiUsage.methodParameters === "()") {
|
if (method.methodParameters === "()") {
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
return externalApiUsage.methodParameters
|
return method.methodParameters
|
||||||
.substring(1, externalApiUsage.methodParameters.length - 1)
|
.substring(1, method.methodParameters.length - 1)
|
||||||
.split(",");
|
.split(",");
|
||||||
}, [externalApiUsage.methodParameters]);
|
}, [method.methodParameters]);
|
||||||
|
|
||||||
const handleTypeInput = useCallback(
|
const handleTypeInput = useCallback(
|
||||||
(e: ChangeEvent<HTMLSelectElement>) => {
|
(e: ChangeEvent<HTMLSelectElement>) => {
|
||||||
@@ -113,7 +108,7 @@ function ModelableMethodRow(props: Props) {
|
|||||||
newProvenance = "ai-manual";
|
newProvenance = "ai-manual";
|
||||||
}
|
}
|
||||||
|
|
||||||
onChange(externalApiUsage, {
|
onChange(method, {
|
||||||
// If there are no arguments, we will default to "Argument[this]"
|
// If there are no arguments, we will default to "Argument[this]"
|
||||||
input: argumentsList.length === 0 ? "Argument[this]" : "Argument[0]",
|
input: argumentsList.length === 0 ? "Argument[this]" : "Argument[0]",
|
||||||
output: "ReturnType",
|
output: "ReturnType",
|
||||||
@@ -121,14 +116,14 @@ function ModelableMethodRow(props: Props) {
|
|||||||
...modeledMethod,
|
...modeledMethod,
|
||||||
type: e.target.value as ModeledMethodType,
|
type: e.target.value as ModeledMethodType,
|
||||||
provenance: newProvenance,
|
provenance: newProvenance,
|
||||||
signature: externalApiUsage.signature,
|
signature: method.signature,
|
||||||
packageName: externalApiUsage.packageName,
|
packageName: method.packageName,
|
||||||
typeName: externalApiUsage.typeName,
|
typeName: method.typeName,
|
||||||
methodName: externalApiUsage.methodName,
|
methodName: method.methodName,
|
||||||
methodParameters: externalApiUsage.methodParameters,
|
methodParameters: method.methodParameters,
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
[onChange, externalApiUsage, modeledMethod, argumentsList],
|
[onChange, method, modeledMethod, argumentsList],
|
||||||
);
|
);
|
||||||
const handleInputInput = useCallback(
|
const handleInputInput = useCallback(
|
||||||
(e: ChangeEvent<HTMLSelectElement>) => {
|
(e: ChangeEvent<HTMLSelectElement>) => {
|
||||||
@@ -138,12 +133,12 @@ function ModelableMethodRow(props: Props) {
|
|||||||
|
|
||||||
const target = e.target as HTMLSelectElement;
|
const target = e.target as HTMLSelectElement;
|
||||||
|
|
||||||
onChange(externalApiUsage, {
|
onChange(method, {
|
||||||
...modeledMethod,
|
...modeledMethod,
|
||||||
input: target.value as ModeledMethod["input"],
|
input: target.value as ModeledMethod["input"],
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
[onChange, externalApiUsage, modeledMethod],
|
[onChange, method, modeledMethod],
|
||||||
);
|
);
|
||||||
const handleOutputInput = useCallback(
|
const handleOutputInput = useCallback(
|
||||||
(e: ChangeEvent<HTMLSelectElement>) => {
|
(e: ChangeEvent<HTMLSelectElement>) => {
|
||||||
@@ -153,12 +148,12 @@ function ModelableMethodRow(props: Props) {
|
|||||||
|
|
||||||
const target = e.target as HTMLSelectElement;
|
const target = e.target as HTMLSelectElement;
|
||||||
|
|
||||||
onChange(externalApiUsage, {
|
onChange(method, {
|
||||||
...modeledMethod,
|
...modeledMethod,
|
||||||
output: target.value as ModeledMethod["output"],
|
output: target.value as ModeledMethod["output"],
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
[onChange, externalApiUsage, modeledMethod],
|
[onChange, method, modeledMethod],
|
||||||
);
|
);
|
||||||
const handleKindChange = useCallback(
|
const handleKindChange = useCallback(
|
||||||
(kind: string) => {
|
(kind: string) => {
|
||||||
@@ -166,17 +161,17 @@ function ModelableMethodRow(props: Props) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
onChange(externalApiUsage, {
|
onChange(method, {
|
||||||
...modeledMethod,
|
...modeledMethod,
|
||||||
kind,
|
kind,
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
[onChange, externalApiUsage, modeledMethod],
|
[onChange, method, modeledMethod],
|
||||||
);
|
);
|
||||||
|
|
||||||
const jumpToUsage = useCallback(
|
const jumpToUsage = useCallback(
|
||||||
() => sendJumpToUsageMessage(externalApiUsage),
|
() => sendJumpToUsageMessage(method),
|
||||||
[externalApiUsage],
|
[method],
|
||||||
);
|
);
|
||||||
|
|
||||||
const inputOptions = useMemo(
|
const inputOptions = useMemo(
|
||||||
@@ -218,11 +213,11 @@ function ModelableMethodRow(props: Props) {
|
|||||||
<VSCodeDataGridRow>
|
<VSCodeDataGridRow>
|
||||||
<ApiOrMethodCell gridColumn={1}>
|
<ApiOrMethodCell gridColumn={1}>
|
||||||
<ModelingStatusIndicator status={modelingStatus} />
|
<ModelingStatusIndicator status={modelingStatus} />
|
||||||
<MethodClassifications externalApiUsage={externalApiUsage} />
|
<MethodClassifications method={method} />
|
||||||
<ExternalApiUsageName {...props.externalApiUsage} />
|
<MethodName {...props.method} />
|
||||||
{mode === Mode.Application && (
|
{mode === Mode.Application && (
|
||||||
<UsagesButton onClick={jumpToUsage}>
|
<UsagesButton onClick={jumpToUsage}>
|
||||||
{externalApiUsage.usages.length}
|
{method.usages.length}
|
||||||
</UsagesButton>
|
</UsagesButton>
|
||||||
)}
|
)}
|
||||||
<ViewLink onClick={jumpToUsage}>View</ViewLink>
|
<ViewLink onClick={jumpToUsage}>View</ViewLink>
|
||||||
@@ -284,25 +279,25 @@ function ModelableMethodRow(props: Props) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function UnmodelableMethodRow(props: Props) {
|
function UnmodelableMethodRow(props: Props) {
|
||||||
const { externalApiUsage, mode } = props;
|
const { method, mode } = props;
|
||||||
|
|
||||||
const jumpToUsage = useCallback(
|
const jumpToUsage = useCallback(
|
||||||
() => sendJumpToUsageMessage(externalApiUsage),
|
() => sendJumpToUsageMessage(method),
|
||||||
[externalApiUsage],
|
[method],
|
||||||
);
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<VSCodeDataGridRow>
|
<VSCodeDataGridRow>
|
||||||
<ApiOrMethodCell gridColumn={1}>
|
<ApiOrMethodCell gridColumn={1}>
|
||||||
<ModelingStatusIndicator status="saved" />
|
<ModelingStatusIndicator status="saved" />
|
||||||
<ExternalApiUsageName {...props.externalApiUsage} />
|
<MethodName {...props.method} />
|
||||||
{mode === Mode.Application && (
|
{mode === Mode.Application && (
|
||||||
<UsagesButton onClick={jumpToUsage}>
|
<UsagesButton onClick={jumpToUsage}>
|
||||||
{externalApiUsage.usages.length}
|
{method.usages.length}
|
||||||
</UsagesButton>
|
</UsagesButton>
|
||||||
)}
|
)}
|
||||||
<ViewLink onClick={jumpToUsage}>View</ViewLink>
|
<ViewLink onClick={jumpToUsage}>View</ViewLink>
|
||||||
<MethodClassifications externalApiUsage={externalApiUsage} />
|
<MethodClassifications method={method} />
|
||||||
</ApiOrMethodCell>
|
</ApiOrMethodCell>
|
||||||
<VSCodeDataGridCell gridColumn="span 4">
|
<VSCodeDataGridCell gridColumn="span 4">
|
||||||
Method already modeled
|
Method already modeled
|
||||||
@@ -311,12 +306,12 @@ function UnmodelableMethodRow(props: Props) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function sendJumpToUsageMessage(externalApiUsage: ExternalApiUsage) {
|
function sendJumpToUsageMessage(method: Method) {
|
||||||
vscode.postMessage({
|
vscode.postMessage({
|
||||||
t: "jumpToUsage",
|
t: "jumpToUsage",
|
||||||
method: externalApiUsage,
|
method,
|
||||||
// In framework mode, the first and only usage is the definition of the method
|
// In framework mode, the first and only usage is the definition of the method
|
||||||
usage: externalApiUsage.usages[0],
|
usage: method.usages[0],
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ import {
|
|||||||
VSCodeTag,
|
VSCodeTag,
|
||||||
} from "@vscode/webview-ui-toolkit/react";
|
} from "@vscode/webview-ui-toolkit/react";
|
||||||
import { styled } from "styled-components";
|
import { styled } from "styled-components";
|
||||||
import { ExternalApiUsage } from "../../model-editor/external-api-usage";
|
import { Method } from "../../model-editor/method";
|
||||||
import { ModeledMethod } from "../../model-editor/modeled-method";
|
import { ModeledMethod } from "../../model-editor/modeled-method";
|
||||||
import { assertNever } from "../../common/helpers-pure";
|
import { assertNever } from "../../common/helpers-pure";
|
||||||
import { vscode } from "../vscode-api";
|
import { vscode } from "../vscode-api";
|
||||||
@@ -73,14 +73,14 @@ const ButtonsContainer = styled.div`
|
|||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
initialViewState?: ModelEditorViewState;
|
initialViewState?: ModelEditorViewState;
|
||||||
initialExternalApiUsages?: ExternalApiUsage[];
|
initialMethods?: Method[];
|
||||||
initialModeledMethods?: Record<string, ModeledMethod>;
|
initialModeledMethods?: Record<string, ModeledMethod>;
|
||||||
initialHideModeledApis?: boolean;
|
initialHideModeledApis?: boolean;
|
||||||
};
|
};
|
||||||
|
|
||||||
export function ModelEditor({
|
export function ModelEditor({
|
||||||
initialViewState,
|
initialViewState,
|
||||||
initialExternalApiUsages = [],
|
initialMethods = [],
|
||||||
initialModeledMethods = {},
|
initialModeledMethods = {},
|
||||||
initialHideModeledApis = INITIAL_HIDE_MODELED_APIS_VALUE,
|
initialHideModeledApis = INITIAL_HIDE_MODELED_APIS_VALUE,
|
||||||
}: Props): JSX.Element {
|
}: Props): JSX.Element {
|
||||||
@@ -88,9 +88,7 @@ export function ModelEditor({
|
|||||||
initialViewState,
|
initialViewState,
|
||||||
);
|
);
|
||||||
|
|
||||||
const [externalApiUsages, setExternalApiUsages] = useState<
|
const [methods, setMethods] = useState<Method[]>(initialMethods);
|
||||||
ExternalApiUsage[]
|
|
||||||
>(initialExternalApiUsages);
|
|
||||||
const [modifiedSignatures, setModifiedSignatures] = useState<Set<string>>(
|
const [modifiedSignatures, setModifiedSignatures] = useState<Set<string>>(
|
||||||
new Set(),
|
new Set(),
|
||||||
);
|
);
|
||||||
@@ -122,8 +120,8 @@ export function ModelEditor({
|
|||||||
case "setModelEditorViewState":
|
case "setModelEditorViewState":
|
||||||
setViewState(msg.viewState);
|
setViewState(msg.viewState);
|
||||||
break;
|
break;
|
||||||
case "setExternalApiUsages":
|
case "setMethods":
|
||||||
setExternalApiUsages(msg.externalApiUsages);
|
setMethods(msg.methods);
|
||||||
break;
|
break;
|
||||||
case "loadModeledMethods":
|
case "loadModeledMethods":
|
||||||
setModeledMethods((oldModeledMethods) => {
|
setModeledMethods((oldModeledMethods) => {
|
||||||
@@ -177,12 +175,12 @@ export function ModelEditor({
|
|||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
const modeledPercentage = useMemo(
|
const modeledPercentage = useMemo(
|
||||||
() => calculateModeledPercentage(externalApiUsages),
|
() => calculateModeledPercentage(methods),
|
||||||
[externalApiUsages],
|
[methods],
|
||||||
);
|
);
|
||||||
|
|
||||||
const onChange = useCallback(
|
const onChange = useCallback(
|
||||||
(modelName: string, method: ExternalApiUsage, model: ModeledMethod) => {
|
(modelName: string, method: Method, model: ModeledMethod) => {
|
||||||
setModeledMethods((oldModeledMethods) => ({
|
setModeledMethods((oldModeledMethods) => ({
|
||||||
...oldModeledMethods,
|
...oldModeledMethods,
|
||||||
[method.signature]: model,
|
[method.signature]: model,
|
||||||
@@ -197,33 +195,30 @@ export function ModelEditor({
|
|||||||
|
|
||||||
const onRefreshClick = useCallback(() => {
|
const onRefreshClick = useCallback(() => {
|
||||||
vscode.postMessage({
|
vscode.postMessage({
|
||||||
t: "refreshExternalApiUsages",
|
t: "refreshMethods",
|
||||||
});
|
});
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
const onSaveAllClick = useCallback(() => {
|
const onSaveAllClick = useCallback(() => {
|
||||||
vscode.postMessage({
|
vscode.postMessage({
|
||||||
t: "saveModeledMethods",
|
t: "saveModeledMethods",
|
||||||
externalApiUsages,
|
methods,
|
||||||
modeledMethods,
|
modeledMethods,
|
||||||
});
|
});
|
||||||
setModifiedSignatures(new Set());
|
setModifiedSignatures(new Set());
|
||||||
}, [externalApiUsages, modeledMethods]);
|
}, [methods, modeledMethods]);
|
||||||
|
|
||||||
const onSaveModelClick = useCallback(
|
const onSaveModelClick = useCallback(
|
||||||
(
|
(methods: Method[], modeledMethods: Record<string, ModeledMethod>) => {
|
||||||
externalApiUsages: ExternalApiUsage[],
|
|
||||||
modeledMethods: Record<string, ModeledMethod>,
|
|
||||||
) => {
|
|
||||||
vscode.postMessage({
|
vscode.postMessage({
|
||||||
t: "saveModeledMethods",
|
t: "saveModeledMethods",
|
||||||
externalApiUsages,
|
methods,
|
||||||
modeledMethods,
|
modeledMethods,
|
||||||
});
|
});
|
||||||
setModifiedSignatures((oldModifiedSignatures) => {
|
setModifiedSignatures((oldModifiedSignatures) => {
|
||||||
const newModifiedSignatures = new Set([...oldModifiedSignatures]);
|
const newModifiedSignatures = new Set([...oldModifiedSignatures]);
|
||||||
for (const externalApiUsage of externalApiUsages) {
|
for (const method of methods) {
|
||||||
newModifiedSignatures.delete(externalApiUsage.signature);
|
newModifiedSignatures.delete(method.signature);
|
||||||
}
|
}
|
||||||
return newModifiedSignatures;
|
return newModifiedSignatures;
|
||||||
});
|
});
|
||||||
@@ -233,7 +228,7 @@ export function ModelEditor({
|
|||||||
|
|
||||||
const onGenerateFromSourceClick = useCallback(() => {
|
const onGenerateFromSourceClick = useCallback(() => {
|
||||||
vscode.postMessage({
|
vscode.postMessage({
|
||||||
t: "generateExternalApi",
|
t: "generateMethod",
|
||||||
});
|
});
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
@@ -246,13 +241,13 @@ export function ModelEditor({
|
|||||||
const onGenerateFromLlmClick = useCallback(
|
const onGenerateFromLlmClick = useCallback(
|
||||||
(
|
(
|
||||||
packageName: string,
|
packageName: string,
|
||||||
externalApiUsages: ExternalApiUsage[],
|
methods: Method[],
|
||||||
modeledMethods: Record<string, ModeledMethod>,
|
modeledMethods: Record<string, ModeledMethod>,
|
||||||
) => {
|
) => {
|
||||||
vscode.postMessage({
|
vscode.postMessage({
|
||||||
t: "generateExternalApiFromLlm",
|
t: "generateMethodsFromLlm",
|
||||||
packageName,
|
packageName,
|
||||||
externalApiUsages,
|
methods,
|
||||||
modeledMethods,
|
modeledMethods,
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
@@ -261,7 +256,7 @@ export function ModelEditor({
|
|||||||
|
|
||||||
const onStopGenerateFromLlmClick = useCallback((packageName: string) => {
|
const onStopGenerateFromLlmClick = useCallback((packageName: string) => {
|
||||||
vscode.postMessage({
|
vscode.postMessage({
|
||||||
t: "stopGeneratingExternalApiFromLlm",
|
t: "stopGeneratingMethodsFromLlm",
|
||||||
packageName,
|
packageName,
|
||||||
});
|
});
|
||||||
}, []);
|
}, []);
|
||||||
@@ -292,7 +287,7 @@ export function ModelEditor({
|
|||||||
setHideModeledApis((oldHideModeledApis) => !oldHideModeledApis);
|
setHideModeledApis((oldHideModeledApis) => !oldHideModeledApis);
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
if (viewState === undefined || externalApiUsages.length === 0) {
|
if (viewState === undefined || methods.length === 0) {
|
||||||
return <LoadingContainer>Loading...</LoadingContainer>;
|
return <LoadingContainer>Loading...</LoadingContainer>;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -357,7 +352,7 @@ export function ModelEditor({
|
|||||||
)}
|
)}
|
||||||
</ButtonsContainer>
|
</ButtonsContainer>
|
||||||
<ModeledMethodsList
|
<ModeledMethodsList
|
||||||
externalApiUsages={externalApiUsages}
|
methods={methods}
|
||||||
modeledMethods={modeledMethods}
|
modeledMethods={modeledMethods}
|
||||||
modifiedSignatures={modifiedSignatures}
|
modifiedSignatures={modifiedSignatures}
|
||||||
inProgressMethods={inProgressMethods}
|
inProgressMethods={inProgressMethods}
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import {
|
|||||||
VSCodeDataGridRow,
|
VSCodeDataGridRow,
|
||||||
} from "@vscode/webview-ui-toolkit/react";
|
} from "@vscode/webview-ui-toolkit/react";
|
||||||
import { MethodRow } from "./MethodRow";
|
import { MethodRow } from "./MethodRow";
|
||||||
import { ExternalApiUsage } from "../../model-editor/external-api-usage";
|
import { Method } from "../../model-editor/method";
|
||||||
import { ModeledMethod } from "../../model-editor/modeled-method";
|
import { ModeledMethod } from "../../model-editor/modeled-method";
|
||||||
import { useMemo } from "react";
|
import { useMemo } from "react";
|
||||||
import { Mode } from "../../model-editor/shared/mode";
|
import { Mode } from "../../model-editor/shared/mode";
|
||||||
@@ -14,21 +14,18 @@ import { InProgressMethods } from "../../model-editor/shared/in-progress-methods
|
|||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
packageName: string;
|
packageName: string;
|
||||||
externalApiUsages: ExternalApiUsage[];
|
methods: Method[];
|
||||||
modeledMethods: Record<string, ModeledMethod>;
|
modeledMethods: Record<string, ModeledMethod>;
|
||||||
modifiedSignatures: Set<string>;
|
modifiedSignatures: Set<string>;
|
||||||
inProgressMethods: InProgressMethods;
|
inProgressMethods: InProgressMethods;
|
||||||
mode: Mode;
|
mode: Mode;
|
||||||
hideModeledApis: boolean;
|
hideModeledApis: boolean;
|
||||||
onChange: (
|
onChange: (method: Method, modeledMethod: ModeledMethod) => void;
|
||||||
externalApiUsage: ExternalApiUsage,
|
|
||||||
modeledMethod: ModeledMethod,
|
|
||||||
) => void;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export const ModeledMethodDataGrid = ({
|
export const ModeledMethodDataGrid = ({
|
||||||
packageName,
|
packageName,
|
||||||
externalApiUsages,
|
methods,
|
||||||
modeledMethods,
|
modeledMethods,
|
||||||
modifiedSignatures,
|
modifiedSignatures,
|
||||||
inProgressMethods,
|
inProgressMethods,
|
||||||
@@ -36,10 +33,7 @@ export const ModeledMethodDataGrid = ({
|
|||||||
hideModeledApis,
|
hideModeledApis,
|
||||||
onChange,
|
onChange,
|
||||||
}: Props) => {
|
}: Props) => {
|
||||||
const sortedExternalApiUsages = useMemo(
|
const sortedMethods = useMemo(() => sortMethods(methods), [methods]);
|
||||||
() => sortMethods(externalApiUsages),
|
|
||||||
[externalApiUsages],
|
|
||||||
);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<VSCodeDataGrid gridTemplateColumns="0.5fr 0.125fr 0.125fr 0.125fr 0.125fr">
|
<VSCodeDataGrid gridTemplateColumns="0.5fr 0.125fr 0.125fr 0.125fr 0.125fr">
|
||||||
@@ -60,15 +54,15 @@ export const ModeledMethodDataGrid = ({
|
|||||||
Kind
|
Kind
|
||||||
</VSCodeDataGridCell>
|
</VSCodeDataGridCell>
|
||||||
</VSCodeDataGridRow>
|
</VSCodeDataGridRow>
|
||||||
{sortedExternalApiUsages.map((externalApiUsage) => (
|
{sortedMethods.map((method) => (
|
||||||
<MethodRow
|
<MethodRow
|
||||||
key={externalApiUsage.signature}
|
key={method.signature}
|
||||||
externalApiUsage={externalApiUsage}
|
method={method}
|
||||||
modeledMethod={modeledMethods[externalApiUsage.signature]}
|
modeledMethod={modeledMethods[method.signature]}
|
||||||
methodIsUnsaved={modifiedSignatures.has(externalApiUsage.signature)}
|
methodIsUnsaved={modifiedSignatures.has(method.signature)}
|
||||||
modelingInProgress={inProgressMethods.hasMethod(
|
modelingInProgress={inProgressMethods.hasMethod(
|
||||||
packageName,
|
packageName,
|
||||||
externalApiUsage.signature,
|
method.signature,
|
||||||
)}
|
)}
|
||||||
mode={mode}
|
mode={mode}
|
||||||
hideModeledApis={hideModeledApis}
|
hideModeledApis={hideModeledApis}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import * as React from "react";
|
import * as React from "react";
|
||||||
import { useMemo } from "react";
|
import { useMemo } from "react";
|
||||||
import { ExternalApiUsage } from "../../model-editor/external-api-usage";
|
import { Method } from "../../model-editor/method";
|
||||||
import { ModeledMethod } from "../../model-editor/modeled-method";
|
import { ModeledMethod } from "../../model-editor/modeled-method";
|
||||||
import { LibraryRow } from "./LibraryRow";
|
import { LibraryRow } from "./LibraryRow";
|
||||||
import { Mode } from "../../model-editor/shared/mode";
|
import { Mode } from "../../model-editor/shared/mode";
|
||||||
@@ -12,7 +12,7 @@ import { ModelEditorViewState } from "../../model-editor/shared/view-state";
|
|||||||
import { InProgressMethods } from "../../model-editor/shared/in-progress-methods";
|
import { InProgressMethods } from "../../model-editor/shared/in-progress-methods";
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
externalApiUsages: ExternalApiUsage[];
|
methods: Method[];
|
||||||
modeledMethods: Record<string, ModeledMethod>;
|
modeledMethods: Record<string, ModeledMethod>;
|
||||||
modifiedSignatures: Set<string>;
|
modifiedSignatures: Set<string>;
|
||||||
inProgressMethods: InProgressMethods;
|
inProgressMethods: InProgressMethods;
|
||||||
@@ -20,16 +20,16 @@ type Props = {
|
|||||||
hideModeledApis: boolean;
|
hideModeledApis: boolean;
|
||||||
onChange: (
|
onChange: (
|
||||||
modelName: string,
|
modelName: string,
|
||||||
externalApiUsage: ExternalApiUsage,
|
method: Method,
|
||||||
modeledMethod: ModeledMethod,
|
modeledMethod: ModeledMethod,
|
||||||
) => void;
|
) => void;
|
||||||
onSaveModelClick: (
|
onSaveModelClick: (
|
||||||
externalApiUsages: ExternalApiUsage[],
|
methods: Method[],
|
||||||
modeledMethods: Record<string, ModeledMethod>,
|
modeledMethods: Record<string, ModeledMethod>,
|
||||||
) => void;
|
) => void;
|
||||||
onGenerateFromLlmClick: (
|
onGenerateFromLlmClick: (
|
||||||
packageName: string,
|
packageName: string,
|
||||||
externalApiUsages: ExternalApiUsage[],
|
methods: Method[],
|
||||||
modeledMethods: Record<string, ModeledMethod>,
|
modeledMethods: Record<string, ModeledMethod>,
|
||||||
) => void;
|
) => void;
|
||||||
onStopGenerateFromLlmClick: (packageName: string) => void;
|
onStopGenerateFromLlmClick: (packageName: string) => void;
|
||||||
@@ -42,7 +42,7 @@ const libraryNameOverrides: Record<string, string> = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export const ModeledMethodsList = ({
|
export const ModeledMethodsList = ({
|
||||||
externalApiUsages,
|
methods,
|
||||||
modeledMethods,
|
modeledMethods,
|
||||||
modifiedSignatures,
|
modifiedSignatures,
|
||||||
inProgressMethods,
|
inProgressMethods,
|
||||||
@@ -56,8 +56,8 @@ export const ModeledMethodsList = ({
|
|||||||
onModelDependencyClick,
|
onModelDependencyClick,
|
||||||
}: Props) => {
|
}: Props) => {
|
||||||
const grouped = useMemo(
|
const grouped = useMemo(
|
||||||
() => groupMethods(externalApiUsages, viewState.mode),
|
() => groupMethods(methods, viewState.mode),
|
||||||
[externalApiUsages, viewState.mode],
|
[methods, viewState.mode],
|
||||||
);
|
);
|
||||||
|
|
||||||
const libraryVersions = useMemo(() => {
|
const libraryVersions = useMemo(() => {
|
||||||
@@ -67,8 +67,8 @@ export const ModeledMethodsList = ({
|
|||||||
|
|
||||||
const libraryVersions: Record<string, string> = {};
|
const libraryVersions: Record<string, string> = {};
|
||||||
|
|
||||||
for (const externalApiUsage of externalApiUsages) {
|
for (const method of methods) {
|
||||||
const { library, libraryVersion } = externalApiUsage;
|
const { library, libraryVersion } = method;
|
||||||
|
|
||||||
if (library && libraryVersion) {
|
if (library && libraryVersion) {
|
||||||
libraryVersions[library] = libraryVersion;
|
libraryVersions[library] = libraryVersion;
|
||||||
@@ -76,7 +76,7 @@ export const ModeledMethodsList = ({
|
|||||||
}
|
}
|
||||||
|
|
||||||
return libraryVersions;
|
return libraryVersions;
|
||||||
}, [externalApiUsages, viewState.mode]);
|
}, [methods, viewState.mode]);
|
||||||
|
|
||||||
const sortedGroupNames = useMemo(() => sortGroupNames(grouped), [grouped]);
|
const sortedGroupNames = useMemo(() => sortGroupNames(grouped), [grouped]);
|
||||||
|
|
||||||
@@ -87,7 +87,7 @@ export const ModeledMethodsList = ({
|
|||||||
key={libraryName}
|
key={libraryName}
|
||||||
title={libraryNameOverrides[libraryName] ?? libraryName}
|
title={libraryNameOverrides[libraryName] ?? libraryName}
|
||||||
libraryVersion={libraryVersions[libraryName]}
|
libraryVersion={libraryVersions[libraryName]}
|
||||||
externalApiUsages={grouped[libraryName]}
|
methods={grouped[libraryName]}
|
||||||
modeledMethods={modeledMethods}
|
modeledMethods={modeledMethods}
|
||||||
modifiedSignatures={modifiedSignatures}
|
modifiedSignatures={modifiedSignatures}
|
||||||
inProgressMethods={inProgressMethods}
|
inProgressMethods={inProgressMethods}
|
||||||
|
|||||||
@@ -1,18 +0,0 @@
|
|||||||
import * as React from "react";
|
|
||||||
import { render as reactRender, screen } from "@testing-library/react";
|
|
||||||
import { ExternalApiUsageName } from "../ExternalApiUsageName";
|
|
||||||
import { ExternalApiUsage } from "../../../model-editor/external-api-usage";
|
|
||||||
import { createExternalApiUsage } from "../../../../test/factories/data-extension/external-api-factories";
|
|
||||||
|
|
||||||
describe(ExternalApiUsageName.name, () => {
|
|
||||||
const render = (props: ExternalApiUsage) =>
|
|
||||||
reactRender(<ExternalApiUsageName {...props} />);
|
|
||||||
|
|
||||||
it("renders method name", () => {
|
|
||||||
const apiUsage = createExternalApiUsage();
|
|
||||||
render(apiUsage);
|
|
||||||
|
|
||||||
const name = `${apiUsage.packageName}.${apiUsage.typeName}.${apiUsage.methodName}${apiUsage.methodParameters}`;
|
|
||||||
expect(screen.getByText(name)).toBeInTheDocument();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
import * as React from "react";
|
||||||
|
import { render as reactRender, screen } from "@testing-library/react";
|
||||||
|
import { MethodName } from "../MethodName";
|
||||||
|
import { Method } from "../../../model-editor/method";
|
||||||
|
import { createMethod } from "../../../../test/factories/data-extension/method-factories";
|
||||||
|
|
||||||
|
describe(MethodName.name, () => {
|
||||||
|
const render = (props: Method) => reactRender(<MethodName {...props} />);
|
||||||
|
|
||||||
|
it("renders method name", () => {
|
||||||
|
const method = createMethod();
|
||||||
|
render(method);
|
||||||
|
|
||||||
|
const name = `${method.packageName}.${method.typeName}.${method.methodName}${method.methodParameters}`;
|
||||||
|
expect(screen.getByText(name)).toBeInTheDocument();
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -1,12 +1,12 @@
|
|||||||
import {
|
import {
|
||||||
Usage,
|
Usage,
|
||||||
ExternalApiUsage,
|
Method,
|
||||||
CallClassification,
|
CallClassification,
|
||||||
} from "../../../src/model-editor/external-api-usage";
|
} from "../../../src/model-editor/method";
|
||||||
import { ModeledMethodType } from "../../../src/model-editor/modeled-method";
|
import { ModeledMethodType } from "../../../src/model-editor/modeled-method";
|
||||||
import { ResolvableLocationValue } from "../../../src/common/bqrs-cli-types";
|
import { ResolvableLocationValue } from "../../../src/common/bqrs-cli-types";
|
||||||
|
|
||||||
export function createExternalApiUsage({
|
export function createMethod({
|
||||||
library = "sql2o-1.6.0.jar",
|
library = "sql2o-1.6.0.jar",
|
||||||
supported = true,
|
supported = true,
|
||||||
supportedType = "summary" as ModeledMethodType,
|
supportedType = "summary" as ModeledMethodType,
|
||||||
@@ -26,7 +26,7 @@ export function createExternalApiUsage({
|
|||||||
typeName?: string;
|
typeName?: string;
|
||||||
methodName?: string;
|
methodName?: string;
|
||||||
methodParameters?: string;
|
methodParameters?: string;
|
||||||
} = {}): ExternalApiUsage {
|
} = {}): Method {
|
||||||
return {
|
return {
|
||||||
library,
|
library,
|
||||||
supported,
|
supported,
|
||||||
@@ -8,7 +8,7 @@ import { AutomodelMode } from "../../../src/model-editor/auto-model-api";
|
|||||||
import { AutoModelQueriesResult } from "../../../src/model-editor/auto-model-codeml-queries";
|
import { AutoModelQueriesResult } from "../../../src/model-editor/auto-model-codeml-queries";
|
||||||
import * as sarif from "sarif";
|
import * as sarif from "sarif";
|
||||||
import { gzipDecode } from "../../../src/common/zlib";
|
import { gzipDecode } from "../../../src/common/zlib";
|
||||||
import { ExternalApiUsage } from "../../../src/model-editor/external-api-usage";
|
import { Method } from "../../../src/model-editor/method";
|
||||||
import { ModeledMethod } from "../../../src/model-editor/modeled-method";
|
import { ModeledMethod } from "../../../src/model-editor/modeled-method";
|
||||||
|
|
||||||
describe("createAutoModelRequest", () => {
|
describe("createAutoModelRequest", () => {
|
||||||
@@ -86,7 +86,7 @@ describe("createAutoModelRequest", () => {
|
|||||||
|
|
||||||
describe("getCandidates", () => {
|
describe("getCandidates", () => {
|
||||||
it("doesn't return methods that are already modelled", () => {
|
it("doesn't return methods that are already modelled", () => {
|
||||||
const externalApiUsages: ExternalApiUsage[] = [
|
const methods: Method[] = [
|
||||||
{
|
{
|
||||||
library: "my.jar",
|
library: "my.jar",
|
||||||
signature: "org.my.A#x()",
|
signature: "org.my.A#x()",
|
||||||
@@ -113,16 +113,12 @@ describe("getCandidates", () => {
|
|||||||
methodParameters: "()",
|
methodParameters: "()",
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
const candidates = getCandidates(
|
const candidates = getCandidates(Mode.Application, methods, modeledMethods);
|
||||||
Mode.Application,
|
|
||||||
externalApiUsages,
|
|
||||||
modeledMethods,
|
|
||||||
);
|
|
||||||
expect(candidates.length).toEqual(0);
|
expect(candidates.length).toEqual(0);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("doesn't return methods that are supported from other sources", () => {
|
it("doesn't return methods that are supported from other sources", () => {
|
||||||
const externalApiUsages: ExternalApiUsage[] = [
|
const methods: Method[] = [
|
||||||
{
|
{
|
||||||
library: "my.jar",
|
library: "my.jar",
|
||||||
signature: "org.my.A#x()",
|
signature: "org.my.A#x()",
|
||||||
@@ -136,17 +132,13 @@ describe("getCandidates", () => {
|
|||||||
},
|
},
|
||||||
];
|
];
|
||||||
const modeledMethods = {};
|
const modeledMethods = {};
|
||||||
const candidates = getCandidates(
|
const candidates = getCandidates(Mode.Application, methods, modeledMethods);
|
||||||
Mode.Application,
|
|
||||||
externalApiUsages,
|
|
||||||
modeledMethods,
|
|
||||||
);
|
|
||||||
expect(candidates.length).toEqual(0);
|
expect(candidates.length).toEqual(0);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("returns methods that are neither modeled nor supported from other sources", () => {
|
it("returns methods that are neither modeled nor supported from other sources", () => {
|
||||||
const externalApiUsages: ExternalApiUsage[] = [];
|
const methods: Method[] = [];
|
||||||
externalApiUsages.push({
|
methods.push({
|
||||||
library: "my.jar",
|
library: "my.jar",
|
||||||
signature: "org.my.A#x()",
|
signature: "org.my.A#x()",
|
||||||
packageName: "org.my",
|
packageName: "org.my",
|
||||||
@@ -158,11 +150,7 @@ describe("getCandidates", () => {
|
|||||||
usages: [],
|
usages: [],
|
||||||
});
|
});
|
||||||
const modeledMethods = {};
|
const modeledMethods = {};
|
||||||
const candidates = getCandidates(
|
const candidates = getCandidates(Mode.Application, methods, modeledMethods);
|
||||||
Mode.Application,
|
|
||||||
externalApiUsages,
|
|
||||||
modeledMethods,
|
|
||||||
);
|
|
||||||
expect(candidates.length).toEqual(1);
|
expect(candidates.length).toEqual(1);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { decodeBqrsToExternalApiUsages } from "../../../src/model-editor/bqrs";
|
import { decodeBqrsToExternalApiUsages } from "../../../src/model-editor/bqrs";
|
||||||
import { DecodedBqrsChunk } from "../../../src/common/bqrs-cli-types";
|
import { DecodedBqrsChunk } from "../../../src/common/bqrs-cli-types";
|
||||||
import { CallClassification } from "../../../src/model-editor/external-api-usage";
|
import { CallClassification } from "../../../src/model-editor/method";
|
||||||
|
|
||||||
describe("decodeBqrsToExternalApiUsages", () => {
|
describe("decodeBqrsToExternalApiUsages", () => {
|
||||||
const chunk: DecodedBqrsChunk = {
|
const chunk: DecodedBqrsChunk = {
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import {
|
|||||||
createFilenameForLibrary,
|
createFilenameForLibrary,
|
||||||
loadDataExtensionYaml,
|
loadDataExtensionYaml,
|
||||||
} from "../../../src/model-editor/yaml";
|
} from "../../../src/model-editor/yaml";
|
||||||
import { CallClassification } from "../../../src/model-editor/external-api-usage";
|
import { CallClassification } from "../../../src/model-editor/method";
|
||||||
|
|
||||||
describe("createDataExtensionYaml", () => {
|
describe("createDataExtensionYaml", () => {
|
||||||
it("creates the correct YAML file", () => {
|
it("creates the correct YAML file", () => {
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ import { mockedObject, mockedUri } from "../../utils/mocking.helpers";
|
|||||||
import { CodeQLCliServer } from "../../../../src/codeql-cli/cli";
|
import { CodeQLCliServer } from "../../../../src/codeql-cli/cli";
|
||||||
import { QueryRunner } from "../../../../src/query-server";
|
import { QueryRunner } from "../../../../src/query-server";
|
||||||
import * as queryResolver from "../../../../src/local-queries/query-resolver";
|
import * as queryResolver from "../../../../src/local-queries/query-resolver";
|
||||||
import { MethodSignature } from "../../../../src/model-editor/external-api-usage";
|
import { MethodSignature } from "../../../../src/model-editor/method";
|
||||||
import { join } from "path";
|
import { join } from "path";
|
||||||
import { exists, readFile } from "fs-extra";
|
import { exists, readFile } from "fs-extra";
|
||||||
import { load as loadYaml } from "js-yaml";
|
import { load as loadYaml } from "js-yaml";
|
||||||
|
|||||||
@@ -1,11 +1,11 @@
|
|||||||
import { CodeQLCliServer } from "../../../../../src/codeql-cli/cli";
|
import { CodeQLCliServer } from "../../../../../src/codeql-cli/cli";
|
||||||
import { ExternalApiUsage } from "../../../../../src/model-editor/external-api-usage";
|
import { Method } from "../../../../../src/model-editor/method";
|
||||||
import { MethodsUsageDataProvider } from "../../../../../src/model-editor/methods-usage/methods-usage-data-provider";
|
import { MethodsUsageDataProvider } from "../../../../../src/model-editor/methods-usage/methods-usage-data-provider";
|
||||||
import { DatabaseItem } from "../../../../../src/databases/local-databases";
|
import { DatabaseItem } from "../../../../../src/databases/local-databases";
|
||||||
import {
|
import {
|
||||||
createExternalApiUsage,
|
createMethod,
|
||||||
createUsage,
|
createUsage,
|
||||||
} from "../../../../factories/data-extension/external-api-factories";
|
} from "../../../../factories/data-extension/method-factories";
|
||||||
import { mockedObject } from "../../../utils/mocking.helpers";
|
import { mockedObject } from "../../../utils/mocking.helpers";
|
||||||
|
|
||||||
describe("MethodsUsageDataProvider", () => {
|
describe("MethodsUsageDataProvider", () => {
|
||||||
@@ -18,31 +18,31 @@ describe("MethodsUsageDataProvider", () => {
|
|||||||
|
|
||||||
describe("setState", () => {
|
describe("setState", () => {
|
||||||
const hideModeledApis = false;
|
const hideModeledApis = false;
|
||||||
const externalApiUsages: ExternalApiUsage[] = [];
|
const methods: Method[] = [];
|
||||||
const dbItem = mockedObject<DatabaseItem>({
|
const dbItem = mockedObject<DatabaseItem>({
|
||||||
getSourceLocationPrefix: () => "test",
|
getSourceLocationPrefix: () => "test",
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should not emit onDidChangeTreeData event when state has not changed", async () => {
|
it("should not emit onDidChangeTreeData event when state has not changed", async () => {
|
||||||
await dataProvider.setState(externalApiUsages, dbItem, hideModeledApis);
|
await dataProvider.setState(methods, dbItem, hideModeledApis);
|
||||||
|
|
||||||
const onDidChangeTreeDataListener = jest.fn();
|
const onDidChangeTreeDataListener = jest.fn();
|
||||||
dataProvider.onDidChangeTreeData(onDidChangeTreeDataListener);
|
dataProvider.onDidChangeTreeData(onDidChangeTreeDataListener);
|
||||||
|
|
||||||
await dataProvider.setState(externalApiUsages, dbItem, hideModeledApis);
|
await dataProvider.setState(methods, dbItem, hideModeledApis);
|
||||||
|
|
||||||
expect(onDidChangeTreeDataListener).not.toHaveBeenCalled();
|
expect(onDidChangeTreeDataListener).not.toHaveBeenCalled();
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should emit onDidChangeTreeData event when externalApiUsages has changed", async () => {
|
it("should emit onDidChangeTreeData event when methods has changed", async () => {
|
||||||
const externalApiUsages2: ExternalApiUsage[] = [];
|
const methods2: Method[] = [];
|
||||||
|
|
||||||
await dataProvider.setState(externalApiUsages, dbItem, hideModeledApis);
|
await dataProvider.setState(methods, dbItem, hideModeledApis);
|
||||||
|
|
||||||
const onDidChangeTreeDataListener = jest.fn();
|
const onDidChangeTreeDataListener = jest.fn();
|
||||||
dataProvider.onDidChangeTreeData(onDidChangeTreeDataListener);
|
dataProvider.onDidChangeTreeData(onDidChangeTreeDataListener);
|
||||||
|
|
||||||
await dataProvider.setState(externalApiUsages2, dbItem, hideModeledApis);
|
await dataProvider.setState(methods2, dbItem, hideModeledApis);
|
||||||
|
|
||||||
expect(onDidChangeTreeDataListener).toHaveBeenCalledTimes(1);
|
expect(onDidChangeTreeDataListener).toHaveBeenCalledTimes(1);
|
||||||
});
|
});
|
||||||
@@ -52,23 +52,23 @@ describe("MethodsUsageDataProvider", () => {
|
|||||||
getSourceLocationPrefix: () => "test",
|
getSourceLocationPrefix: () => "test",
|
||||||
});
|
});
|
||||||
|
|
||||||
await dataProvider.setState(externalApiUsages, dbItem, hideModeledApis);
|
await dataProvider.setState(methods, dbItem, hideModeledApis);
|
||||||
|
|
||||||
const onDidChangeTreeDataListener = jest.fn();
|
const onDidChangeTreeDataListener = jest.fn();
|
||||||
dataProvider.onDidChangeTreeData(onDidChangeTreeDataListener);
|
dataProvider.onDidChangeTreeData(onDidChangeTreeDataListener);
|
||||||
|
|
||||||
await dataProvider.setState(externalApiUsages, dbItem2, hideModeledApis);
|
await dataProvider.setState(methods, dbItem2, hideModeledApis);
|
||||||
|
|
||||||
expect(onDidChangeTreeDataListener).toHaveBeenCalledTimes(1);
|
expect(onDidChangeTreeDataListener).toHaveBeenCalledTimes(1);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should emit onDidChangeTreeData event when hideModeledApis has changed", async () => {
|
it("should emit onDidChangeTreeData event when hideModeledApis has changed", async () => {
|
||||||
await dataProvider.setState(externalApiUsages, dbItem, hideModeledApis);
|
await dataProvider.setState(methods, dbItem, hideModeledApis);
|
||||||
|
|
||||||
const onDidChangeTreeDataListener = jest.fn();
|
const onDidChangeTreeDataListener = jest.fn();
|
||||||
dataProvider.onDidChangeTreeData(onDidChangeTreeDataListener);
|
dataProvider.onDidChangeTreeData(onDidChangeTreeDataListener);
|
||||||
|
|
||||||
await dataProvider.setState(externalApiUsages, dbItem, !hideModeledApis);
|
await dataProvider.setState(methods, dbItem, !hideModeledApis);
|
||||||
|
|
||||||
expect(onDidChangeTreeDataListener).toHaveBeenCalledTimes(1);
|
expect(onDidChangeTreeDataListener).toHaveBeenCalledTimes(1);
|
||||||
});
|
});
|
||||||
@@ -77,36 +77,29 @@ describe("MethodsUsageDataProvider", () => {
|
|||||||
const dbItem2 = mockedObject<DatabaseItem>({
|
const dbItem2 = mockedObject<DatabaseItem>({
|
||||||
getSourceLocationPrefix: () => "test",
|
getSourceLocationPrefix: () => "test",
|
||||||
});
|
});
|
||||||
const externalApiUsages2: ExternalApiUsage[] = [];
|
const methods2: Method[] = [];
|
||||||
|
|
||||||
await dataProvider.setState(externalApiUsages, dbItem, hideModeledApis);
|
await dataProvider.setState(methods, dbItem, hideModeledApis);
|
||||||
|
|
||||||
const onDidChangeTreeDataListener = jest.fn();
|
const onDidChangeTreeDataListener = jest.fn();
|
||||||
dataProvider.onDidChangeTreeData(onDidChangeTreeDataListener);
|
dataProvider.onDidChangeTreeData(onDidChangeTreeDataListener);
|
||||||
|
|
||||||
await dataProvider.setState(
|
await dataProvider.setState(methods2, dbItem2, !hideModeledApis);
|
||||||
externalApiUsages2,
|
|
||||||
dbItem2,
|
|
||||||
!hideModeledApis,
|
|
||||||
);
|
|
||||||
|
|
||||||
expect(onDidChangeTreeDataListener).toHaveBeenCalledTimes(1);
|
expect(onDidChangeTreeDataListener).toHaveBeenCalledTimes(1);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("getChildren", () => {
|
describe("getChildren", () => {
|
||||||
const supportedExternalApiUsage = createExternalApiUsage({
|
const supportedMethod = createMethod({
|
||||||
supported: true,
|
supported: true,
|
||||||
});
|
});
|
||||||
|
|
||||||
const unsupportedExternalApiUsage = createExternalApiUsage({
|
const unsupportedMethod = createMethod({
|
||||||
supported: false,
|
supported: false,
|
||||||
});
|
});
|
||||||
|
|
||||||
const externalApiUsages: ExternalApiUsage[] = [
|
const methods: Method[] = [supportedMethod, unsupportedMethod];
|
||||||
supportedExternalApiUsage,
|
|
||||||
unsupportedExternalApiUsage,
|
|
||||||
];
|
|
||||||
const dbItem = mockedObject<DatabaseItem>({
|
const dbItem = mockedObject<DatabaseItem>({
|
||||||
getSourceLocationPrefix: () => "test",
|
getSourceLocationPrefix: () => "test",
|
||||||
});
|
});
|
||||||
@@ -118,19 +111,19 @@ describe("MethodsUsageDataProvider", () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it("should return usages if item is external api usage", async () => {
|
it("should return usages if item is external api usage", async () => {
|
||||||
const externalApiUsage = createExternalApiUsage({ usages: [usage] });
|
const method = createMethod({ usages: [usage] });
|
||||||
expect(dataProvider.getChildren(externalApiUsage)).toEqual([usage]);
|
expect(dataProvider.getChildren(method)).toEqual([usage]);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should show all externalApiUsages if hideModeledApis is false and looking at the root", async () => {
|
it("should show all methods if hideModeledApis is false and looking at the root", async () => {
|
||||||
const hideModeledApis = false;
|
const hideModeledApis = false;
|
||||||
await dataProvider.setState(externalApiUsages, dbItem, hideModeledApis);
|
await dataProvider.setState(methods, dbItem, hideModeledApis);
|
||||||
expect(dataProvider.getChildren().length).toEqual(2);
|
expect(dataProvider.getChildren().length).toEqual(2);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should filter externalApiUsages if hideModeledApis is true and looking at the root", async () => {
|
it("should filter methods if hideModeledApis is true and looking at the root", async () => {
|
||||||
const hideModeledApis = true;
|
const hideModeledApis = true;
|
||||||
await dataProvider.setState(externalApiUsages, dbItem, hideModeledApis);
|
await dataProvider.setState(methods, dbItem, hideModeledApis);
|
||||||
expect(dataProvider.getChildren().length).toEqual(1);
|
expect(dataProvider.getChildren().length).toEqual(1);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,13 +1,13 @@
|
|||||||
import { window, TreeView } from "vscode";
|
import { window, TreeView } from "vscode";
|
||||||
import { CodeQLCliServer } from "../../../../../src/codeql-cli/cli";
|
import { CodeQLCliServer } from "../../../../../src/codeql-cli/cli";
|
||||||
import { ExternalApiUsage } from "../../../../../src/model-editor/external-api-usage";
|
import { Method } from "../../../../../src/model-editor/method";
|
||||||
import { MethodsUsagePanel } from "../../../../../src/model-editor/methods-usage/methods-usage-panel";
|
import { MethodsUsagePanel } from "../../../../../src/model-editor/methods-usage/methods-usage-panel";
|
||||||
import { DatabaseItem } from "../../../../../src/databases/local-databases";
|
import { DatabaseItem } from "../../../../../src/databases/local-databases";
|
||||||
import { mockedObject } from "../../../utils/mocking.helpers";
|
import { mockedObject } from "../../../utils/mocking.helpers";
|
||||||
import {
|
import {
|
||||||
createExternalApiUsage,
|
createMethod,
|
||||||
createUsage,
|
createUsage,
|
||||||
} from "../../../../factories/data-extension/external-api-factories";
|
} from "../../../../factories/data-extension/method-factories";
|
||||||
|
|
||||||
describe("MethodsUsagePanel", () => {
|
describe("MethodsUsagePanel", () => {
|
||||||
const mockCliServer = mockedObject<CodeQLCliServer>({});
|
const mockCliServer = mockedObject<CodeQLCliServer>({});
|
||||||
@@ -17,7 +17,7 @@ describe("MethodsUsagePanel", () => {
|
|||||||
|
|
||||||
describe("setState", () => {
|
describe("setState", () => {
|
||||||
const hideModeledApis = false;
|
const hideModeledApis = false;
|
||||||
const externalApiUsages: ExternalApiUsage[] = [createExternalApiUsage()];
|
const methods: Method[] = [createMethod()];
|
||||||
|
|
||||||
it("should update the tree view with the correct batch number", async () => {
|
it("should update the tree view with the correct batch number", async () => {
|
||||||
const mockTreeView = {
|
const mockTreeView = {
|
||||||
@@ -26,7 +26,7 @@ describe("MethodsUsagePanel", () => {
|
|||||||
jest.spyOn(window, "createTreeView").mockReturnValue(mockTreeView);
|
jest.spyOn(window, "createTreeView").mockReturnValue(mockTreeView);
|
||||||
|
|
||||||
const panel = new MethodsUsagePanel(mockCliServer);
|
const panel = new MethodsUsagePanel(mockCliServer);
|
||||||
await panel.setState(externalApiUsages, dbItem, hideModeledApis);
|
await panel.setState(methods, dbItem, hideModeledApis);
|
||||||
|
|
||||||
expect(mockTreeView.badge?.value).toBe(1);
|
expect(mockTreeView.badge?.value).toBe(1);
|
||||||
});
|
});
|
||||||
@@ -46,14 +46,14 @@ describe("MethodsUsagePanel", () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it("should reveal the correct item in the tree view", async () => {
|
it("should reveal the correct item in the tree view", async () => {
|
||||||
const externalApiUsages = [
|
const methods = [
|
||||||
createExternalApiUsage({
|
createMethod({
|
||||||
usages: [usage],
|
usages: [usage],
|
||||||
}),
|
}),
|
||||||
];
|
];
|
||||||
|
|
||||||
const panel = new MethodsUsagePanel(mockCliServer);
|
const panel = new MethodsUsagePanel(mockCliServer);
|
||||||
await panel.setState(externalApiUsages, dbItem, hideModeledApis);
|
await panel.setState(methods, dbItem, hideModeledApis);
|
||||||
|
|
||||||
await panel.revealItem(usage);
|
await panel.revealItem(usage);
|
||||||
|
|
||||||
@@ -61,9 +61,9 @@ describe("MethodsUsagePanel", () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it("should do nothing if usage cannot be found", async () => {
|
it("should do nothing if usage cannot be found", async () => {
|
||||||
const externalApiUsages = [createExternalApiUsage({})];
|
const methods = [createMethod({})];
|
||||||
const panel = new MethodsUsagePanel(mockCliServer);
|
const panel = new MethodsUsagePanel(mockCliServer);
|
||||||
await panel.setState(externalApiUsages, dbItem, hideModeledApis);
|
await panel.setState(methods, dbItem, hideModeledApis);
|
||||||
|
|
||||||
await panel.revealItem(usage);
|
await panel.revealItem(usage);
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user