Merge pull request #3020 from github/koesie10/refactor-predicates

Refactor model editor predicates
This commit is contained in:
Koen Vlaswinkel
2023-10-27 10:39:52 +02:00
committed by GitHub
37 changed files with 326 additions and 172 deletions

View File

@@ -18,6 +18,7 @@ import { Mode } from "./shared/mode";
import { CancellationTokenSource } from "vscode"; import { CancellationTokenSource } from "vscode";
import { ModelingStore } from "./modeling-store"; import { ModelingStore } from "./modeling-store";
import { ModelConfigListener } from "../config"; import { ModelConfigListener } from "../config";
import { QueryLanguage } from "../common/query-language";
/** /**
* The auto-modeler holds state around auto-modeling jobs and allows * The auto-modeler holds state around auto-modeling jobs and allows
@@ -36,6 +37,7 @@ export class AutoModeler {
private readonly modelingStore: ModelingStore, private readonly modelingStore: ModelingStore,
private readonly queryStorageDir: string, private readonly queryStorageDir: string,
private readonly databaseItem: DatabaseItem, private readonly databaseItem: DatabaseItem,
private readonly language: QueryLanguage,
private readonly addModeledMethods: ( private readonly addModeledMethods: (
modeledMethods: Record<string, ModeledMethod[]>, modeledMethods: Record<string, ModeledMethod[]>,
) => Promise<void>, ) => Promise<void>,
@@ -202,7 +204,7 @@ export class AutoModeler {
filename: "auto-model.yml", filename: "auto-model.yml",
}); });
const loadedMethods = loadDataExtensionYaml(models); const loadedMethods = loadDataExtensionYaml(models, this.language);
if (!loadedMethods) { if (!loadedMethods) {
return; return;
} }

View File

@@ -5,7 +5,7 @@ import { QueryRunner } from "../query-server";
import { CodeQLCliServer } from "../codeql-cli/cli"; import { CodeQLCliServer } from "../codeql-cli/cli";
import { showAndLogExceptionWithTelemetry } from "../common/logging"; import { showAndLogExceptionWithTelemetry } from "../common/logging";
import { extLogger } from "../common/logging/vscode"; import { extLogger } from "../common/logging/vscode";
import { extensiblePredicateDefinitions } from "./predicates"; import { getModelsAsDataLanguage } from "./languages";
import { ProgressCallback } from "../common/vscode/progress"; import { ProgressCallback } from "../common/vscode/progress";
import { getOnDiskWorkspaceFolders } from "../common/vscode/workspace-folders"; import { getOnDiskWorkspaceFolders } from "../common/vscode/workspace-folders";
import { ModeledMethod, ModeledMethodType } from "./modeled-method"; import { ModeledMethod, ModeledMethodType } from "./modeled-method";
@@ -13,12 +13,14 @@ import { redactableError } from "../common/errors";
import { telemetryListener } from "../common/vscode/telemetry"; import { telemetryListener } from "../common/vscode/telemetry";
import { runQuery } from "../local-queries/run-query"; import { runQuery } from "../local-queries/run-query";
import { resolveQueries } from "../local-queries"; import { resolveQueries } from "../local-queries";
import { QueryLanguage } from "../common/query-language";
type FlowModelOptions = { type FlowModelOptions = {
cliServer: CodeQLCliServer; cliServer: CodeQLCliServer;
queryRunner: QueryRunner; queryRunner: QueryRunner;
queryStorageDir: string; queryStorageDir: string;
databaseItem: DatabaseItem; databaseItem: DatabaseItem;
language: QueryLanguage;
progress: ProgressCallback; progress: ProgressCallback;
token: CancellationToken; token: CancellationToken;
onResults: (results: ModeledMethod[]) => void | Promise<void>; onResults: (results: ModeledMethod[]) => void | Promise<void>;
@@ -104,6 +106,7 @@ async function runSingleFlowQuery(
queryRunner, queryRunner,
queryStorageDir, queryStorageDir,
databaseItem, databaseItem,
language,
progress, progress,
token, token,
}: Omit<FlowModelOptions, "onResults">, }: Omit<FlowModelOptions, "onResults">,
@@ -140,7 +143,9 @@ async function runSingleFlowQuery(
} }
// Interpret the results // Interpret the results
const definition = extensiblePredicateDefinitions[type]; const modelsAsDataLanguage = getModelsAsDataLanguage(language);
const definition = modelsAsDataLanguage[type];
const bqrsPath = completedQuery.outputDir.bqrsPath; const bqrsPath = completedQuery.outputDir.bqrsPath;

View File

@@ -0,0 +1,2 @@
export * from "./languages";
export * from "./models-as-data";

View File

@@ -0,0 +1,18 @@
import { QueryLanguage } from "../../common/query-language";
import { ModelsAsDataLanguage } from "./models-as-data";
import { staticLanguage } from "./static";
const languages: Partial<Record<QueryLanguage, ModelsAsDataLanguage>> = {
[QueryLanguage.CSharp]: staticLanguage,
[QueryLanguage.Java]: staticLanguage,
};
export function getModelsAsDataLanguage(
language: QueryLanguage,
): ModelsAsDataLanguage {
const definition = languages[language];
if (!definition) {
throw new Error(`No models-as-data definition for ${language}`);
}
return definition;
}

View File

@@ -0,0 +1,19 @@
import { ModeledMethod, ModeledMethodType } from "../modeled-method";
import { DataTuple } from "../model-extension-file";
type GenerateMethodDefinition = (method: ModeledMethod) => DataTuple[];
type ReadModeledMethod = (row: DataTuple[]) => ModeledMethod;
export type ModelsAsDataLanguageModelType = Exclude<ModeledMethodType, "none">;
export type ModelsAsDataLanguageModel = {
extensiblePredicate: string;
supportedKinds: string[];
generateMethodDefinition: GenerateMethodDefinition;
readModeledMethod: ReadModeledMethod;
};
export type ModelsAsDataLanguage = Record<
ModelsAsDataLanguageModelType,
ModelsAsDataLanguageModel
>;

View File

@@ -0,0 +1,25 @@
export const sharedExtensiblePredicates = {
source: "sourceModel",
sink: "sinkModel",
summary: "summaryModel",
neutral: "neutralModel",
};
export const sharedKinds = {
source: ["local", "remote"],
sink: [
"code-injection",
"command-injection",
"file-content-store",
"html-injection",
"js-injection",
"ldap-injection",
"log-injection",
"path-injection",
"request-forgery",
"sql-injection",
"url-redirection",
],
summary: ["taint", "value"],
neutral: ["summary", "source", "sink"],
};

View File

@@ -1,24 +1,16 @@
import { ModeledMethod, ModeledMethodType, Provenance } from "./modeled-method"; import { ModelsAsDataLanguage } from "./models-as-data";
import { DataTuple } from "./model-extension-file"; import { ModeledMethodType, Provenance } from "../modeled-method";
import { DataTuple } from "../model-extension-file";
export type ExtensiblePredicateDefinition = { import { sharedExtensiblePredicates, sharedKinds } from "./shared";
extensiblePredicate: string;
generateMethodDefinition: (method: ModeledMethod) => DataTuple[];
readModeledMethod: (row: DataTuple[]) => ModeledMethod;
supportedKinds?: string[];
};
function readRowToMethod(row: DataTuple[]): string { function readRowToMethod(row: DataTuple[]): string {
return `${row[0]}.${row[1]}#${row[3]}${row[4]}`; return `${row[0]}.${row[1]}#${row[3]}${row[4]}`;
} }
export const extensiblePredicateDefinitions: Record< export const staticLanguage: ModelsAsDataLanguage = {
Exclude<ModeledMethodType, "none">,
ExtensiblePredicateDefinition
> = {
source: { source: {
extensiblePredicate: "sourceModel", extensiblePredicate: sharedExtensiblePredicates.source,
supportedKinds: sharedKinds.source,
// extensible predicate sourceModel( // extensible predicate sourceModel(
// string package, string type, boolean subtypes, string name, string signature, string ext, // string package, string type, boolean subtypes, string name, string signature, string ext,
// string output, string kind, string provenance // string output, string kind, string provenance
@@ -35,7 +27,7 @@ export const extensiblePredicateDefinitions: Record<
method.provenance, method.provenance,
], ],
readModeledMethod: (row) => ({ readModeledMethod: (row) => ({
type: "source", type: "source" as ModeledMethodType,
input: "", input: "",
output: row[6] as string, output: row[6] as string,
kind: row[7] as string, kind: row[7] as string,
@@ -46,10 +38,10 @@ export const extensiblePredicateDefinitions: Record<
methodName: row[3] as string, methodName: row[3] as string,
methodParameters: row[4] as string, methodParameters: row[4] as string,
}), }),
supportedKinds: ["local", "remote"],
}, },
sink: { sink: {
extensiblePredicate: "sinkModel", extensiblePredicate: sharedExtensiblePredicates.sink,
supportedKinds: sharedKinds.sink,
// extensible predicate sinkModel( // extensible predicate sinkModel(
// string package, string type, boolean subtypes, string name, string signature, string ext, // string package, string type, boolean subtypes, string name, string signature, string ext,
// string input, string kind, string provenance // string input, string kind, string provenance
@@ -77,22 +69,10 @@ export const extensiblePredicateDefinitions: Record<
methodName: row[3] as string, methodName: row[3] as string,
methodParameters: row[4] as string, methodParameters: row[4] as string,
}), }),
supportedKinds: [
"code-injection",
"command-injection",
"file-content-store",
"html-injection",
"js-injection",
"ldap-injection",
"log-injection",
"path-injection",
"request-forgery",
"sql-injection",
"url-redirection",
],
}, },
summary: { summary: {
extensiblePredicate: "summaryModel", extensiblePredicate: sharedExtensiblePredicates.summary,
supportedKinds: sharedKinds.summary,
// extensible predicate summaryModel( // extensible predicate summaryModel(
// string package, string type, boolean subtypes, string name, string signature, string ext, // string package, string type, boolean subtypes, string name, string signature, string ext,
// string input, string output, string kind, string provenance // string input, string output, string kind, string provenance
@@ -121,10 +101,10 @@ export const extensiblePredicateDefinitions: Record<
methodName: row[3] as string, methodName: row[3] as string,
methodParameters: row[4] as string, methodParameters: row[4] as string,
}), }),
supportedKinds: ["taint", "value"],
}, },
neutral: { neutral: {
extensiblePredicate: "neutralModel", extensiblePredicate: sharedExtensiblePredicates.neutral,
supportedKinds: sharedKinds.neutral,
// extensible predicate neutralModel( // extensible predicate neutralModel(
// string package, string type, string name, string signature, string kind, string provenance // string package, string type, string name, string signature, string kind, string provenance
// ); // );
@@ -148,6 +128,5 @@ export const extensiblePredicateDefinitions: Record<
methodName: row[2] as string, methodName: row[2] as string,
methodParameters: row[3] as string, methodParameters: row[3] as string,
}), }),
supportedKinds: ["summary", "source", "sink"],
}, },
}; };

View File

@@ -15,6 +15,10 @@ import { ModelEditorViewTracker } from "../model-editor-view-tracker";
import { ModelConfigListener } from "../../config"; import { ModelConfigListener } from "../../config";
import { DatabaseItem } from "../../databases/local-databases"; import { DatabaseItem } from "../../databases/local-databases";
import { ModelingEvents } from "../modeling-events"; import { ModelingEvents } from "../modeling-events";
import {
QueryLanguage,
tryGetQueryLanguage,
} from "../../common/query-language";
export class MethodModelingViewProvider extends AbstractWebviewViewProvider< export class MethodModelingViewProvider extends AbstractWebviewViewProvider<
ToMethodModelingMessage, ToMethodModelingMessage,
@@ -24,6 +28,7 @@ export class MethodModelingViewProvider extends AbstractWebviewViewProvider<
private method: Method | undefined = undefined; private method: Method | undefined = undefined;
private databaseItem: DatabaseItem | undefined = undefined; private databaseItem: DatabaseItem | undefined = undefined;
private language: QueryLanguage | undefined = undefined;
constructor( constructor(
app: App, app: App,
@@ -45,6 +50,7 @@ export class MethodModelingViewProvider extends AbstractWebviewViewProvider<
await this.postMessage({ await this.postMessage({
t: "setMethodModelingPanelViewState", t: "setMethodModelingPanelViewState",
viewState: { viewState: {
language: this.language,
showMultipleModels: this.modelConfig.showMultipleModels, showMultipleModels: this.modelConfig.showMultipleModels,
}, },
}); });
@@ -56,6 +62,7 @@ export class MethodModelingViewProvider extends AbstractWebviewViewProvider<
): Promise<void> { ): Promise<void> {
this.method = method; this.method = method;
this.databaseItem = databaseItem; this.databaseItem = databaseItem;
this.language = databaseItem && tryGetQueryLanguage(databaseItem.language);
if (this.isShowingView) { if (this.isShowingView) {
await this.postMessage({ await this.postMessage({
@@ -70,6 +77,9 @@ export class MethodModelingViewProvider extends AbstractWebviewViewProvider<
const selectedMethod = this.modelingStore.getSelectedMethodDetails(); const selectedMethod = this.modelingStore.getSelectedMethodDetails();
if (selectedMethod) { if (selectedMethod) {
this.databaseItem = selectedMethod.databaseItem; this.databaseItem = selectedMethod.databaseItem;
this.language = tryGetQueryLanguage(
selectedMethod.databaseItem.language,
);
this.method = selectedMethod.method; this.method = selectedMethod.method;
await this.postMessage({ await this.postMessage({
@@ -185,6 +195,7 @@ export class MethodModelingViewProvider extends AbstractWebviewViewProvider<
if (this.webviewView) { if (this.webviewView) {
this.method = e.method; this.method = e.method;
this.databaseItem = e.databaseItem; this.databaseItem = e.databaseItem;
this.language = tryGetQueryLanguage(e.databaseItem.language);
await this.postMessage({ await this.postMessage({
t: "setSelectedMethod", t: "setSelectedMethod",

View File

@@ -233,6 +233,7 @@ export class ModelEditorModule extends DisposableObject {
queryDir, queryDir,
db, db,
modelFile, modelFile,
language,
); );
this.modelingEvents.onDbClosed(async (dbUri) => { this.modelingEvents.onDbClosed(async (dbUri) => {

View File

@@ -38,7 +38,10 @@ import { ModelConfigListener } from "../config";
import { INITIAL_MODE, Mode } from "./shared/mode"; import { INITIAL_MODE, Mode } from "./shared/mode";
import { loadModeledMethods, saveModeledMethods } from "./modeled-method-fs"; import { loadModeledMethods, saveModeledMethods } from "./modeled-method-fs";
import { pickExtensionPack } from "./extension-pack-picker"; import { pickExtensionPack } from "./extension-pack-picker";
import { getLanguageDisplayName } from "../common/query-language"; import {
getLanguageDisplayName,
QueryLanguage,
} from "../common/query-language";
import { AutoModeler } from "./auto-modeler"; import { AutoModeler } from "./auto-modeler";
import { telemetryListener } from "../common/vscode/telemetry"; import { telemetryListener } from "../common/vscode/telemetry";
import { ModelingStore } from "./modeling-store"; import { ModelingStore } from "./modeling-store";
@@ -64,6 +67,8 @@ export class ModelEditorView extends AbstractWebview<
private readonly queryDir: string, private readonly queryDir: string,
private readonly databaseItem: DatabaseItem, private readonly databaseItem: DatabaseItem,
private readonly extensionPack: ExtensionPack, private readonly extensionPack: ExtensionPack,
// The language is equal to databaseItem.language but is properly typed as QueryLanguage
private readonly language: QueryLanguage,
initialMode: Mode = INITIAL_MODE, initialMode: Mode = INITIAL_MODE,
) { ) {
super(app); super(app);
@@ -82,6 +87,7 @@ export class ModelEditorView extends AbstractWebview<
modelingStore, modelingStore,
queryStorageDir, queryStorageDir,
databaseItem, databaseItem,
language,
async (modeledMethods) => { async (modeledMethods) => {
this.addModeledMethods(modeledMethods); this.addModeledMethods(modeledMethods);
}, },
@@ -218,7 +224,7 @@ export class ModelEditorView extends AbstractWebview<
}); });
await saveModeledMethods( await saveModeledMethods(
this.extensionPack, this.extensionPack,
this.databaseItem.language, this.language,
methods, methods,
modeledMethods, modeledMethods,
mode, mode,
@@ -367,6 +373,7 @@ export class ModelEditorView extends AbstractWebview<
t: "setModelEditorViewState", t: "setModelEditorViewState",
viewState: { viewState: {
extensionPack: this.extensionPack, extensionPack: this.extensionPack,
language: this.language,
showFlowGeneration: this.modelConfig.flowGeneration, showFlowGeneration: this.modelConfig.flowGeneration,
showLlmButton, showLlmButton,
showMultipleModels: this.modelConfig.showMultipleModels, showMultipleModels: this.modelConfig.showMultipleModels,
@@ -394,6 +401,7 @@ export class ModelEditorView extends AbstractWebview<
try { try {
const modeledMethods = await loadModeledMethods( const modeledMethods = await loadModeledMethods(
this.extensionPack, this.extensionPack,
this.language,
this.cliServer, this.cliServer,
this.app.logger, this.app.logger,
); );
@@ -458,6 +466,14 @@ export class ModelEditorView extends AbstractWebview<
if (!addedDatabase) { if (!addedDatabase) {
return; return;
} }
if (addedDatabase.language !== this.language) {
void showAndLogErrorMessage(
this.app.logger,
`The selected database is for ${addedDatabase.language}, but the current database is for ${this.language}.`,
);
return;
}
} }
progress({ progress({
@@ -472,6 +488,7 @@ export class ModelEditorView extends AbstractWebview<
queryRunner: this.queryRunner, queryRunner: this.queryRunner,
queryStorageDir: this.queryStorageDir, queryStorageDir: this.queryStorageDir,
databaseItem: addedDatabase ?? this.databaseItem, databaseItem: addedDatabase ?? this.databaseItem,
language: this.language,
onResults: async (modeledMethods) => { onResults: async (modeledMethods) => {
const modeledMethodsByName: Record<string, ModeledMethod[]> = {}; const modeledMethodsByName: Record<string, ModeledMethod[]> = {};
@@ -579,6 +596,7 @@ export class ModelEditorView extends AbstractWebview<
this.queryDir, this.queryDir,
addedDatabase, addedDatabase,
modelFile, modelFile,
this.language,
Mode.Framework, Mode.Framework,
); );
await view.openView(); await view.openView();

View File

@@ -10,10 +10,11 @@ import { getOnDiskWorkspaceFolders } from "../common/vscode/workspace-folders";
import { load as loadYaml } from "js-yaml"; import { load as loadYaml } from "js-yaml";
import { CodeQLCliServer } from "../codeql-cli/cli"; import { CodeQLCliServer } from "../codeql-cli/cli";
import { pathsEqual } from "../common/files"; import { pathsEqual } from "../common/files";
import { QueryLanguage } from "../common/query-language";
export async function saveModeledMethods( export async function saveModeledMethods(
extensionPack: ExtensionPack, extensionPack: ExtensionPack,
language: string, language: QueryLanguage,
methods: readonly Method[], methods: readonly Method[],
modeledMethods: Readonly<Record<string, readonly ModeledMethod[]>>, modeledMethods: Readonly<Record<string, readonly ModeledMethod[]>>,
mode: Mode, mode: Mode,
@@ -22,6 +23,7 @@ export async function saveModeledMethods(
): Promise<void> { ): Promise<void> {
const existingModeledMethods = await loadModeledMethodFiles( const existingModeledMethods = await loadModeledMethodFiles(
extensionPack, extensionPack,
language,
cliServer, cliServer,
logger, logger,
); );
@@ -43,6 +45,7 @@ export async function saveModeledMethods(
async function loadModeledMethodFiles( async function loadModeledMethodFiles(
extensionPack: ExtensionPack, extensionPack: ExtensionPack,
language: QueryLanguage,
cliServer: CodeQLCliServer, cliServer: CodeQLCliServer,
logger: NotificationLogger, logger: NotificationLogger,
): Promise<Record<string, Record<string, ModeledMethod[]>>> { ): Promise<Record<string, Record<string, ModeledMethod[]>>> {
@@ -60,7 +63,7 @@ async function loadModeledMethodFiles(
filename: modelFile, filename: modelFile,
}); });
const modeledMethods = loadDataExtensionYaml(data); const modeledMethods = loadDataExtensionYaml(data, language);
if (!modeledMethods) { if (!modeledMethods) {
void showAndLogErrorMessage( void showAndLogErrorMessage(
logger, logger,
@@ -76,6 +79,7 @@ async function loadModeledMethodFiles(
export async function loadModeledMethods( export async function loadModeledMethods(
extensionPack: ExtensionPack, extensionPack: ExtensionPack,
language: QueryLanguage,
cliServer: CodeQLCliServer, cliServer: CodeQLCliServer,
logger: NotificationLogger, logger: NotificationLogger,
): Promise<Record<string, ModeledMethod[]>> { ): Promise<Record<string, ModeledMethod[]>> {
@@ -83,6 +87,7 @@ export async function loadModeledMethods(
const modeledMethodsByFile = await loadModeledMethodFiles( const modeledMethodsByFile = await loadModeledMethodFiles(
extensionPack, extensionPack,
language,
cliServer, cliServer,
logger, logger,
); );

View File

@@ -1,8 +1,10 @@
import { ExtensionPack } from "./extension-pack"; import { ExtensionPack } from "./extension-pack";
import { Mode } from "./mode"; import { Mode } from "./mode";
import { QueryLanguage } from "../../common/query-language";
export interface ModelEditorViewState { export interface ModelEditorViewState {
extensionPack: ExtensionPack; extensionPack: ExtensionPack;
language: QueryLanguage;
showFlowGeneration: boolean; showFlowGeneration: boolean;
showLlmButton: boolean; showLlmButton: boolean;
showMultipleModels: boolean; showMultipleModels: boolean;
@@ -11,5 +13,6 @@ export interface ModelEditorViewState {
} }
export interface MethodModelingPanelViewState { export interface MethodModelingPanelViewState {
language: QueryLanguage | undefined;
showMultipleModels: boolean; showMultipleModels: boolean;
} }

View File

@@ -3,21 +3,22 @@ import Ajv from "ajv";
import { Method } from "./method"; import { Method } from "./method";
import { ModeledMethod, ModeledMethodType } from "./modeled-method"; import { ModeledMethod, ModeledMethodType } from "./modeled-method";
import { import {
ExtensiblePredicateDefinition, getModelsAsDataLanguage,
extensiblePredicateDefinitions, ModelsAsDataLanguageModel,
} from "./predicates"; } from "./languages";
import * as modelExtensionFileSchema from "./model-extension-file.schema.json"; import * as modelExtensionFileSchema from "./model-extension-file.schema.json";
import { Mode } from "./shared/mode"; import { Mode } from "./shared/mode";
import { assertNever } from "../common/helpers-pure"; import { assertNever } from "../common/helpers-pure";
import { ModelExtensionFile } from "./model-extension-file"; import { ModelExtensionFile } from "./model-extension-file";
import { QueryLanguage } from "../common/query-language";
const ajv = new Ajv({ allErrors: true, allowUnionTypes: true }); const ajv = new Ajv({ allErrors: true, allowUnionTypes: true });
const modelExtensionFileSchemaValidate = ajv.compile(modelExtensionFileSchema); const modelExtensionFileSchemaValidate = ajv.compile(modelExtensionFileSchema);
function createDataProperty( function createDataProperty(
methods: readonly ModeledMethod[], methods: readonly ModeledMethod[],
definition: ExtensiblePredicateDefinition, definition: ModelsAsDataLanguageModel,
) { ) {
if (methods.length === 0) { if (methods.length === 0) {
return " []"; return " []";
@@ -34,9 +35,11 @@ function createDataProperty(
} }
export function createDataExtensionYaml( export function createDataExtensionYaml(
language: string, language: QueryLanguage,
modeledMethods: readonly ModeledMethod[], modeledMethods: readonly ModeledMethod[],
) { ) {
const modelsAsDataLanguage = getModelsAsDataLanguage(language);
const methodsByType: Record< const methodsByType: Record<
Exclude<ModeledMethodType, "none">, Exclude<ModeledMethodType, "none">,
ModeledMethod[] ModeledMethod[]
@@ -53,7 +56,7 @@ export function createDataExtensionYaml(
} }
} }
const extensions = Object.entries(extensiblePredicateDefinitions).map( const extensions = Object.entries(modelsAsDataLanguage).map(
([type, definition]) => ` - addsTo: ([type, definition]) => ` - addsTo:
pack: codeql/${language}-all pack: codeql/${language}-all
extensible: ${definition.extensiblePredicate} extensible: ${definition.extensiblePredicate}
@@ -69,7 +72,7 @@ ${extensions.join("\n")}`;
} }
export function createDataExtensionYamls( export function createDataExtensionYamls(
language: string, language: QueryLanguage,
methods: readonly Method[], methods: readonly Method[],
newModeledMethods: Readonly<Record<string, readonly ModeledMethod[]>>, newModeledMethods: Readonly<Record<string, readonly ModeledMethod[]>>,
existingModeledMethods: Readonly< existingModeledMethods: Readonly<
@@ -98,7 +101,7 @@ export function createDataExtensionYamls(
} }
function createDataExtensionYamlsByGrouping( function createDataExtensionYamlsByGrouping(
language: string, language: QueryLanguage,
methods: readonly Method[], methods: readonly Method[],
newModeledMethods: Readonly<Record<string, readonly ModeledMethod[]>>, newModeledMethods: Readonly<Record<string, readonly ModeledMethod[]>>,
existingModeledMethods: Readonly< existingModeledMethods: Readonly<
@@ -153,7 +156,7 @@ function createDataExtensionYamlsByGrouping(
} }
export function createDataExtensionYamlsForApplicationMode( export function createDataExtensionYamlsForApplicationMode(
language: string, language: QueryLanguage,
methods: readonly Method[], methods: readonly Method[],
newModeledMethods: Readonly<Record<string, readonly ModeledMethod[]>>, newModeledMethods: Readonly<Record<string, readonly ModeledMethod[]>>,
existingModeledMethods: Readonly< existingModeledMethods: Readonly<
@@ -170,7 +173,7 @@ export function createDataExtensionYamlsForApplicationMode(
} }
export function createDataExtensionYamlsForFrameworkMode( export function createDataExtensionYamlsForFrameworkMode(
language: string, language: QueryLanguage,
methods: readonly Method[], methods: readonly Method[],
newModeledMethods: Readonly<Record<string, readonly ModeledMethod[]>>, newModeledMethods: Readonly<Record<string, readonly ModeledMethod[]>>,
existingModeledMethods: Readonly< existingModeledMethods: Readonly<
@@ -240,11 +243,14 @@ function validateModelExtensionFile(data: unknown): data is ModelExtensionFile {
export function loadDataExtensionYaml( export function loadDataExtensionYaml(
data: unknown, data: unknown,
language: QueryLanguage,
): Record<string, ModeledMethod[]> | undefined { ): Record<string, ModeledMethod[]> | undefined {
if (!validateModelExtensionFile(data)) { if (!validateModelExtensionFile(data)) {
return undefined; return undefined;
} }
const modelsAsDataLanguage = getModelsAsDataLanguage(language);
const extensions = data.extensions; const extensions = data.extensions;
const modeledMethods: Record<string, ModeledMethod[]> = {}; const modeledMethods: Record<string, ModeledMethod[]> = {};
@@ -254,7 +260,7 @@ export function loadDataExtensionYaml(
const extensible = addsTo.extensible; const extensible = addsTo.extensible;
const data = extension.data; const data = extension.data;
const definition = Object.values(extensiblePredicateDefinitions).find( const definition = Object.values(modelsAsDataLanguage).find(
(definition) => definition.extensiblePredicate === extensible, (definition) => definition.extensiblePredicate === extensible,
); );
if (!definition) { if (!definition) {

View File

@@ -2,10 +2,9 @@ import * as React from "react";
import { Meta, StoryFn } from "@storybook/react"; import { Meta, StoryFn } from "@storybook/react";
import { Mode } from "../../model-editor/shared/mode";
import { LibraryRow as LibraryRowComponent } from "../../view/model-editor/LibraryRow"; import { LibraryRow as LibraryRowComponent } from "../../view/model-editor/LibraryRow";
import { CallClassification } from "../../model-editor/method"; import { CallClassification } from "../../model-editor/method";
import { createMockExtensionPack } from "../../../test/factories/model-editor/extension-pack"; import { createMockModelEditorViewState } from "../../../test/factories/model-editor/view-state";
export default { export default {
title: "CodeQL Model Editor/Library Row", title: "CodeQL Model Editor/Library Row",
@@ -219,13 +218,10 @@ LibraryRow.args = {
}, },
modifiedSignatures: new Set(["org.sql2o.Sql2o#Sql2o(String)"]), modifiedSignatures: new Set(["org.sql2o.Sql2o#Sql2o(String)"]),
inProgressMethods: new Set(), inProgressMethods: new Set(),
viewState: { viewState: createMockModelEditorViewState({
extensionPack: createMockExtensionPack(),
showFlowGeneration: true, showFlowGeneration: true,
showLlmButton: true, showLlmButton: true,
showMultipleModels: true, showMultipleModels: true,
mode: Mode.Application, }),
sourceArchiveAvailable: true,
},
hideModeledMethods: false, hideModeledMethods: false,
}; };

View File

@@ -10,10 +10,8 @@ import {
MULTIPLE_MODELS_GRID_TEMPLATE_COLUMNS, MULTIPLE_MODELS_GRID_TEMPLATE_COLUMNS,
SINGLE_MODEL_GRID_TEMPLATE_COLUMNS, SINGLE_MODEL_GRID_TEMPLATE_COLUMNS,
} from "../../view/model-editor/ModeledMethodDataGrid"; } from "../../view/model-editor/ModeledMethodDataGrid";
import { ModelEditorViewState } from "../../model-editor/shared/view-state";
import { createMockExtensionPack } from "../../../test/factories/model-editor/extension-pack";
import { Mode } from "../../model-editor/shared/mode";
import { DataGrid } from "../../view/common/DataGrid"; import { DataGrid } from "../../view/common/DataGrid";
import { createMockModelEditorViewState } from "../../../test/factories/model-editor/view-state";
export default { export default {
title: "CodeQL Model Editor/Method Row", title: "CodeQL Model Editor/Method Row",
@@ -99,14 +97,11 @@ const modeledMethod: ModeledMethod = {
methodParameters: "()", methodParameters: "()",
}; };
const viewState: ModelEditorViewState = { const viewState = createMockModelEditorViewState({
extensionPack: createMockExtensionPack(),
showFlowGeneration: true, showFlowGeneration: true,
showLlmButton: true, showLlmButton: true,
showMultipleModels: true, showMultipleModels: true,
mode: Mode.Application, });
sourceArchiveAvailable: true,
};
export const Unmodeled = Template.bind({}); export const Unmodeled = Template.bind({});
Unmodeled.args = { Unmodeled.args = {

View File

@@ -2,9 +2,9 @@ import * as React from "react";
import { Meta, StoryFn } from "@storybook/react"; import { Meta, StoryFn } from "@storybook/react";
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/method"; import { CallClassification } from "../../model-editor/method";
import { createMockModelEditorViewState } from "../../../test/factories/model-editor/view-state";
export default { export default {
title: "CodeQL Model Editor/CodeQL Model Editor", title: "CodeQL Model Editor/CodeQL Model Editor",
@@ -17,7 +17,7 @@ const Template: StoryFn<typeof ModelEditorComponent> = (args) => (
export const ModelEditor = Template.bind({}); export const ModelEditor = Template.bind({});
ModelEditor.args = { ModelEditor.args = {
initialViewState: { initialViewState: createMockModelEditorViewState({
extensionPack: { extensionPack: {
path: "/home/user/vscode-codeql-starter/codeql-custom-queries-java/sql2o", path: "/home/user/vscode-codeql-starter/codeql-custom-queries-java/sql2o",
yamlPath: yamlPath:
@@ -31,9 +31,7 @@ ModelEditor.args = {
showFlowGeneration: true, showFlowGeneration: true,
showLlmButton: true, showLlmButton: true,
showMultipleModels: true, showMultipleModels: true,
mode: Mode.Application, }),
sourceArchiveAvailable: true,
},
initialMethods: [ initialMethods: [
{ {
library: "sql2o", library: "sql2o",

View File

@@ -8,6 +8,7 @@ import { ModeledMethod } from "../../model-editor/modeled-method";
import { VSCodeTag } from "@vscode/webview-ui-toolkit/react"; import { VSCodeTag } from "@vscode/webview-ui-toolkit/react";
import { ReviewInEditorButton } from "./ReviewInEditorButton"; import { ReviewInEditorButton } from "./ReviewInEditorButton";
import { ModeledMethodsPanel } from "./ModeledMethodsPanel"; import { ModeledMethodsPanel } from "./ModeledMethodsPanel";
import { QueryLanguage } from "../../common/query-language";
const Container = styled.div` const Container = styled.div`
padding-top: 0.5rem; padding-top: 0.5rem;
@@ -49,6 +50,7 @@ const UnsavedTag = ({ modelingStatus }: { modelingStatus: ModelingStatus }) => (
); );
export type MethodModelingProps = { export type MethodModelingProps = {
language: QueryLanguage;
modelingStatus: ModelingStatus; modelingStatus: ModelingStatus;
method: Method; method: Method;
modeledMethods: ModeledMethod[]; modeledMethods: ModeledMethod[];
@@ -58,6 +60,7 @@ export type MethodModelingProps = {
}; };
export const MethodModeling = ({ export const MethodModeling = ({
language,
modelingStatus, modelingStatus,
modeledMethods, modeledMethods,
method, method,
@@ -77,6 +80,7 @@ export const MethodModeling = ({
<MethodName {...method} /> <MethodName {...method} />
</DependencyContainer> </DependencyContainer>
<ModeledMethodsPanel <ModeledMethodsPanel
language={language}
method={method} method={method}
modeledMethods={modeledMethods} modeledMethods={modeledMethods}
showMultipleModels={showMultipleModels} showMultipleModels={showMultipleModels}

View File

@@ -7,6 +7,7 @@ import { ModelInputDropdown } from "../model-editor/ModelInputDropdown";
import { ModelOutputDropdown } from "../model-editor/ModelOutputDropdown"; import { ModelOutputDropdown } from "../model-editor/ModelOutputDropdown";
import { ModelKindDropdown } from "../model-editor/ModelKindDropdown"; import { ModelKindDropdown } from "../model-editor/ModelKindDropdown";
import { InProgressDropdown } from "../model-editor/InProgressDropdown"; import { InProgressDropdown } from "../model-editor/InProgressDropdown";
import { QueryLanguage } from "../../common/query-language";
const Container = styled.div` const Container = styled.div`
padding-top: 0.5rem; padding-top: 0.5rem;
@@ -23,6 +24,7 @@ const Name = styled.span`
`; `;
export type MethodModelingInputsProps = { export type MethodModelingInputsProps = {
language: QueryLanguage;
method: Method; method: Method;
modeledMethod: ModeledMethod | undefined; modeledMethod: ModeledMethod | undefined;
isModelingInProgress: boolean; isModelingInProgress: boolean;
@@ -30,6 +32,7 @@ export type MethodModelingInputsProps = {
}; };
export const MethodModelingInputs = ({ export const MethodModelingInputs = ({
language,
method, method,
modeledMethod, modeledMethod,
isModelingInProgress, isModelingInProgress,
@@ -79,7 +82,7 @@ export const MethodModelingInputs = ({
{isModelingInProgress ? ( {isModelingInProgress ? (
<InProgressDropdown /> <InProgressDropdown />
) : ( ) : (
<ModelKindDropdown {...inputProps} /> <ModelKindDropdown language={language} {...inputProps} />
)} )}
</Input> </Input>
</Container> </Container>

View File

@@ -80,7 +80,7 @@ export function MethodModelingView({ initialViewState }: Props): JSX.Element {
}; };
}, []); }, []);
if (!inModelingMode) { if (!inModelingMode || !viewState?.language) {
return <NotInModelingMode />; return <NotInModelingMode />;
} }
@@ -105,6 +105,7 @@ export function MethodModelingView({ initialViewState }: Props): JSX.Element {
return ( return (
<MethodModeling <MethodModeling
language={viewState?.language}
modelingStatus={modelingStatus} modelingStatus={modelingStatus}
method={method} method={method}
modeledMethods={modeledMethods} modeledMethods={modeledMethods}

View File

@@ -6,8 +6,10 @@ import { Method } from "../../model-editor/method";
import { styled } from "styled-components"; import { styled } from "styled-components";
import { MultipleModeledMethodsPanel } from "./MultipleModeledMethodsPanel"; import { MultipleModeledMethodsPanel } from "./MultipleModeledMethodsPanel";
import { convertToLegacyModeledMethod } from "../../model-editor/shared/modeled-methods-legacy"; import { convertToLegacyModeledMethod } from "../../model-editor/shared/modeled-methods-legacy";
import { QueryLanguage } from "../../common/query-language";
export type ModeledMethodsPanelProps = { export type ModeledMethodsPanelProps = {
language: QueryLanguage;
method: Method; method: Method;
modeledMethods: ModeledMethod[]; modeledMethods: ModeledMethod[];
isModelingInProgress: boolean; isModelingInProgress: boolean;
@@ -20,6 +22,7 @@ const SingleMethodModelingInputs = styled(MethodModelingInputs)`
`; `;
export const ModeledMethodsPanel = ({ export const ModeledMethodsPanel = ({
language,
method, method,
modeledMethods, modeledMethods,
isModelingInProgress, isModelingInProgress,
@@ -36,6 +39,7 @@ export const ModeledMethodsPanel = ({
if (!showMultipleModels) { if (!showMultipleModels) {
return ( return (
<SingleMethodModelingInputs <SingleMethodModelingInputs
language={language}
method={method} method={method}
modeledMethod={convertToLegacyModeledMethod(modeledMethods)} modeledMethod={convertToLegacyModeledMethod(modeledMethods)}
isModelingInProgress={isModelingInProgress} isModelingInProgress={isModelingInProgress}
@@ -46,6 +50,7 @@ export const ModeledMethodsPanel = ({
return ( return (
<MultipleModeledMethodsPanel <MultipleModeledMethodsPanel
language={language}
method={method} method={method}
modeledMethods={modeledMethods} modeledMethods={modeledMethods}
isModelingInProgress={isModelingInProgress} isModelingInProgress={isModelingInProgress}

View File

@@ -12,8 +12,10 @@ import { VSCodeButton } from "@vscode/webview-ui-toolkit/react";
import { Codicon } from "../common"; import { Codicon } from "../common";
import { validateModeledMethods } from "../../model-editor/shared/validation"; import { validateModeledMethods } from "../../model-editor/shared/validation";
import { ModeledMethodAlert } from "./ModeledMethodAlert"; import { ModeledMethodAlert } from "./ModeledMethodAlert";
import { QueryLanguage } from "../../common/query-language";
export type MultipleModeledMethodsPanelProps = { export type MultipleModeledMethodsPanelProps = {
language: QueryLanguage;
method: Method; method: Method;
modeledMethods: ModeledMethod[]; modeledMethods: ModeledMethod[];
isModelingInProgress: boolean; isModelingInProgress: boolean;
@@ -53,6 +55,7 @@ const ModificationActions = styled.div`
`; `;
export const MultipleModeledMethodsPanel = ({ export const MultipleModeledMethodsPanel = ({
language,
method, method,
modeledMethods, modeledMethods,
isModelingInProgress, isModelingInProgress,
@@ -150,6 +153,7 @@ export const MultipleModeledMethodsPanel = ({
)} )}
{modeledMethods.length > 0 ? ( {modeledMethods.length > 0 ? (
<MethodModelingInputs <MethodModelingInputs
language={language}
method={method} method={method}
modeledMethod={modeledMethods[selectedIndex]} modeledMethod={modeledMethods[selectedIndex]}
isModelingInProgress={isModelingInProgress} isModelingInProgress={isModelingInProgress}
@@ -157,6 +161,7 @@ export const MultipleModeledMethodsPanel = ({
/> />
) : ( ) : (
<MethodModelingInputs <MethodModelingInputs
language={language}
method={method} method={method}
modeledMethod={undefined} modeledMethod={undefined}
isModelingInProgress={isModelingInProgress} isModelingInProgress={isModelingInProgress}

View File

@@ -3,6 +3,7 @@ import { render as reactRender, screen } from "@testing-library/react";
import { MethodModeling, MethodModelingProps } from "../MethodModeling"; import { MethodModeling, MethodModelingProps } from "../MethodModeling";
import { createMethod } from "../../../../test/factories/model-editor/method-factories"; import { createMethod } from "../../../../test/factories/model-editor/method-factories";
import { createModeledMethod } from "../../../../test/factories/model-editor/modeled-method-factories"; import { createModeledMethod } from "../../../../test/factories/model-editor/modeled-method-factories";
import { QueryLanguage } from "../../../common/query-language";
describe(MethodModeling.name, () => { describe(MethodModeling.name, () => {
const render = (props: MethodModelingProps) => const render = (props: MethodModelingProps) =>
@@ -15,6 +16,7 @@ describe(MethodModeling.name, () => {
const onChange = jest.fn(); const onChange = jest.fn();
render({ render({
language: QueryLanguage.Java,
modelingStatus: "saved", modelingStatus: "saved",
method, method,
modeledMethods: [modeledMethod], modeledMethods: [modeledMethod],

View File

@@ -7,11 +7,13 @@ import {
} from "../MethodModelingInputs"; } from "../MethodModelingInputs";
import { createMethod } from "../../../../test/factories/model-editor/method-factories"; import { createMethod } from "../../../../test/factories/model-editor/method-factories";
import { createModeledMethod } from "../../../../test/factories/model-editor/modeled-method-factories"; import { createModeledMethod } from "../../../../test/factories/model-editor/modeled-method-factories";
import { QueryLanguage } from "../../../common/query-language";
describe(MethodModelingInputs.name, () => { describe(MethodModelingInputs.name, () => {
const render = (props: MethodModelingInputsProps) => const render = (props: MethodModelingInputsProps) =>
reactRender(<MethodModelingInputs {...props} />); reactRender(<MethodModelingInputs {...props} />);
const language = QueryLanguage.Java;
const method = createMethod(); const method = createMethod();
const modeledMethod = createModeledMethod(); const modeledMethod = createModeledMethod();
const isModelingInProgress = false; const isModelingInProgress = false;
@@ -19,6 +21,7 @@ describe(MethodModelingInputs.name, () => {
it("renders the method modeling inputs", () => { it("renders the method modeling inputs", () => {
render({ render({
language,
method, method,
modeledMethod, modeledMethod,
isModelingInProgress, isModelingInProgress,
@@ -44,6 +47,7 @@ describe(MethodModelingInputs.name, () => {
it("allows changing the type", async () => { it("allows changing the type", async () => {
render({ render({
language,
method, method,
modeledMethod, modeledMethod,
isModelingInProgress, isModelingInProgress,
@@ -65,6 +69,7 @@ describe(MethodModelingInputs.name, () => {
it("sets other dropdowns when model type is changed", () => { it("sets other dropdowns when model type is changed", () => {
const { rerender } = render({ const { rerender } = render({
language,
method, method,
modeledMethod, modeledMethod,
isModelingInProgress, isModelingInProgress,
@@ -77,6 +82,7 @@ describe(MethodModelingInputs.name, () => {
rerender( rerender(
<MethodModelingInputs <MethodModelingInputs
language={language}
method={method} method={method}
modeledMethod={updatedModeledMethod} modeledMethod={updatedModeledMethod}
isModelingInProgress={isModelingInProgress} isModelingInProgress={isModelingInProgress}
@@ -105,6 +111,7 @@ describe(MethodModelingInputs.name, () => {
it("sets in progress dropdowns when modeling is in progress", () => { it("sets in progress dropdowns when modeling is in progress", () => {
render({ render({
language,
method, method,
modeledMethod, modeledMethod,
isModelingInProgress: true, isModelingInProgress: true,

View File

@@ -6,11 +6,13 @@ import {
ModeledMethodsPanel, ModeledMethodsPanel,
ModeledMethodsPanelProps, ModeledMethodsPanelProps,
} from "../ModeledMethodsPanel"; } from "../ModeledMethodsPanel";
import { QueryLanguage } from "../../../common/query-language";
describe(ModeledMethodsPanel.name, () => { describe(ModeledMethodsPanel.name, () => {
const render = (props: ModeledMethodsPanelProps) => const render = (props: ModeledMethodsPanelProps) =>
reactRender(<ModeledMethodsPanel {...props} />); reactRender(<ModeledMethodsPanel {...props} />);
const language = QueryLanguage.Java;
const method = createMethod(); const method = createMethod();
const modeledMethods = [createModeledMethod(), createModeledMethod()]; const modeledMethods = [createModeledMethod(), createModeledMethod()];
const isModelingInProgress = false; const isModelingInProgress = false;
@@ -21,6 +23,7 @@ describe(ModeledMethodsPanel.name, () => {
it("renders the method modeling inputs", () => { it("renders the method modeling inputs", () => {
render({ render({
language,
method, method,
modeledMethods, modeledMethods,
isModelingInProgress, isModelingInProgress,
@@ -33,6 +36,7 @@ describe(ModeledMethodsPanel.name, () => {
it("does not render the pagination", () => { it("does not render the pagination", () => {
render({ render({
language,
method, method,
modeledMethods, modeledMethods,
isModelingInProgress, isModelingInProgress,
@@ -52,6 +56,7 @@ describe(ModeledMethodsPanel.name, () => {
it("renders the method modeling inputs once", () => { it("renders the method modeling inputs once", () => {
render({ render({
language,
method, method,
modeledMethods, modeledMethods,
isModelingInProgress, isModelingInProgress,
@@ -64,6 +69,7 @@ describe(ModeledMethodsPanel.name, () => {
it("renders the pagination", () => { it("renders the pagination", () => {
render({ render({
language,
method, method,
modeledMethods, modeledMethods,
isModelingInProgress, isModelingInProgress,

View File

@@ -8,11 +8,13 @@ import {
} from "../MultipleModeledMethodsPanel"; } from "../MultipleModeledMethodsPanel";
import userEvent from "@testing-library/user-event"; import userEvent from "@testing-library/user-event";
import { ModeledMethod } from "../../../model-editor/modeled-method"; import { ModeledMethod } from "../../../model-editor/modeled-method";
import { QueryLanguage } from "../../../common/query-language";
describe(MultipleModeledMethodsPanel.name, () => { describe(MultipleModeledMethodsPanel.name, () => {
const render = (props: MultipleModeledMethodsPanelProps) => const render = (props: MultipleModeledMethodsPanelProps) =>
reactRender(<MultipleModeledMethodsPanel {...props} />); reactRender(<MultipleModeledMethodsPanel {...props} />);
const language = QueryLanguage.Java;
const method = createMethod(); const method = createMethod();
const isModelingInProgress = false; const isModelingInProgress = false;
const onChange = jest.fn<void, [string, ModeledMethod[]]>(); const onChange = jest.fn<void, [string, ModeledMethod[]]>();
@@ -22,6 +24,7 @@ describe(MultipleModeledMethodsPanel.name, () => {
it("renders the method modeling inputs once", () => { it("renders the method modeling inputs once", () => {
render({ render({
language,
method, method,
modeledMethods, modeledMethods,
isModelingInProgress, isModelingInProgress,
@@ -38,6 +41,7 @@ describe(MultipleModeledMethodsPanel.name, () => {
it("disables all pagination", () => { it("disables all pagination", () => {
render({ render({
language,
method, method,
modeledMethods, modeledMethods,
isModelingInProgress, isModelingInProgress,
@@ -58,6 +62,7 @@ describe(MultipleModeledMethodsPanel.name, () => {
it("cannot add or delete modeling", () => { it("cannot add or delete modeling", () => {
render({ render({
language,
method, method,
modeledMethods, modeledMethods,
isModelingInProgress, isModelingInProgress,
@@ -88,6 +93,7 @@ describe(MultipleModeledMethodsPanel.name, () => {
it("renders the method modeling inputs once", () => { it("renders the method modeling inputs once", () => {
render({ render({
language,
method, method,
modeledMethods, modeledMethods,
isModelingInProgress, isModelingInProgress,
@@ -104,6 +110,7 @@ describe(MultipleModeledMethodsPanel.name, () => {
it("disables all pagination", () => { it("disables all pagination", () => {
render({ render({
language,
method, method,
modeledMethods, modeledMethods,
isModelingInProgress, isModelingInProgress,
@@ -123,6 +130,7 @@ describe(MultipleModeledMethodsPanel.name, () => {
it("cannot delete modeling", () => { it("cannot delete modeling", () => {
render({ render({
language,
method, method,
modeledMethods, modeledMethods,
isModelingInProgress, isModelingInProgress,
@@ -138,6 +146,7 @@ describe(MultipleModeledMethodsPanel.name, () => {
it("can add modeling", async () => { it("can add modeling", async () => {
render({ render({
language,
method, method,
modeledMethods, modeledMethods,
isModelingInProgress, isModelingInProgress,
@@ -165,6 +174,7 @@ describe(MultipleModeledMethodsPanel.name, () => {
it("changes selection to the newly added modeling", async () => { it("changes selection to the newly added modeling", async () => {
const { rerender } = render({ const { rerender } = render({
language,
method, method,
modeledMethods, modeledMethods,
isModelingInProgress, isModelingInProgress,
@@ -175,6 +185,7 @@ describe(MultipleModeledMethodsPanel.name, () => {
rerender( rerender(
<MultipleModeledMethodsPanel <MultipleModeledMethodsPanel
language={language}
method={method} method={method}
modeledMethods={ modeledMethods={
onChange.mock.calls[onChange.mock.calls.length - 1][1] onChange.mock.calls[onChange.mock.calls.length - 1][1]
@@ -208,6 +219,7 @@ describe(MultipleModeledMethodsPanel.name, () => {
it("renders the method modeling inputs once", () => { it("renders the method modeling inputs once", () => {
render({ render({
language,
method, method,
modeledMethods, modeledMethods,
isModelingInProgress, isModelingInProgress,
@@ -224,6 +236,7 @@ describe(MultipleModeledMethodsPanel.name, () => {
it("renders the pagination", () => { it("renders the pagination", () => {
render({ render({
language,
method, method,
modeledMethods, modeledMethods,
isModelingInProgress, isModelingInProgress,
@@ -237,6 +250,7 @@ describe(MultipleModeledMethodsPanel.name, () => {
it("disables the correct pagination", async () => { it("disables the correct pagination", async () => {
render({ render({
language,
method, method,
modeledMethods, modeledMethods,
isModelingInProgress, isModelingInProgress,
@@ -255,6 +269,7 @@ describe(MultipleModeledMethodsPanel.name, () => {
it("can use the pagination", async () => { it("can use the pagination", async () => {
render({ render({
language,
method, method,
modeledMethods, modeledMethods,
isModelingInProgress, isModelingInProgress,
@@ -290,6 +305,7 @@ describe(MultipleModeledMethodsPanel.name, () => {
it("correctly updates selected pagination index when the number of models decreases", async () => { it("correctly updates selected pagination index when the number of models decreases", async () => {
const { rerender } = render({ const { rerender } = render({
language,
method, method,
modeledMethods, modeledMethods,
isModelingInProgress, isModelingInProgress,
@@ -300,6 +316,7 @@ describe(MultipleModeledMethodsPanel.name, () => {
rerender( rerender(
<MultipleModeledMethodsPanel <MultipleModeledMethodsPanel
language={language}
method={method} method={method}
modeledMethods={[modeledMethods[1]]} modeledMethods={[modeledMethods[1]]}
isModelingInProgress={isModelingInProgress} isModelingInProgress={isModelingInProgress}
@@ -317,6 +334,7 @@ describe(MultipleModeledMethodsPanel.name, () => {
it("does not show errors", () => { it("does not show errors", () => {
render({ render({
language,
method, method,
modeledMethods, modeledMethods,
isModelingInProgress, isModelingInProgress,
@@ -328,6 +346,7 @@ describe(MultipleModeledMethodsPanel.name, () => {
it("can update the first modeling", async () => { it("can update the first modeling", async () => {
render({ render({
language,
method, method,
modeledMethods, modeledMethods,
isModelingInProgress, isModelingInProgress,
@@ -359,6 +378,7 @@ describe(MultipleModeledMethodsPanel.name, () => {
it("can update the second modeling", async () => { it("can update the second modeling", async () => {
render({ render({
language,
method, method,
modeledMethods, modeledMethods,
isModelingInProgress, isModelingInProgress,
@@ -392,6 +412,7 @@ describe(MultipleModeledMethodsPanel.name, () => {
it("can delete modeling", async () => { it("can delete modeling", async () => {
render({ render({
language,
method, method,
modeledMethods, modeledMethods,
isModelingInProgress, isModelingInProgress,
@@ -408,6 +429,7 @@ describe(MultipleModeledMethodsPanel.name, () => {
it("can add modeling", async () => { it("can add modeling", async () => {
render({ render({
language,
method, method,
modeledMethods, modeledMethods,
isModelingInProgress, isModelingInProgress,
@@ -435,6 +457,7 @@ describe(MultipleModeledMethodsPanel.name, () => {
it("shows an error when adding a neutral modeling", async () => { it("shows an error when adding a neutral modeling", async () => {
const { rerender } = render({ const { rerender } = render({
language,
method, method,
modeledMethods, modeledMethods,
isModelingInProgress, isModelingInProgress,
@@ -445,6 +468,7 @@ describe(MultipleModeledMethodsPanel.name, () => {
rerender( rerender(
<MultipleModeledMethodsPanel <MultipleModeledMethodsPanel
language={language}
method={method} method={method}
modeledMethods={ modeledMethods={
onChange.mock.calls[onChange.mock.calls.length - 1][1] onChange.mock.calls[onChange.mock.calls.length - 1][1]
@@ -464,6 +488,7 @@ describe(MultipleModeledMethodsPanel.name, () => {
rerender( rerender(
<MultipleModeledMethodsPanel <MultipleModeledMethodsPanel
language={language}
method={method} method={method}
modeledMethods={ modeledMethods={
onChange.mock.calls[onChange.mock.calls.length - 1][1] onChange.mock.calls[onChange.mock.calls.length - 1][1]
@@ -481,6 +506,7 @@ describe(MultipleModeledMethodsPanel.name, () => {
rerender( rerender(
<MultipleModeledMethodsPanel <MultipleModeledMethodsPanel
language={language}
method={method} method={method}
modeledMethods={ modeledMethods={
onChange.mock.calls[onChange.mock.calls.length - 1][1] onChange.mock.calls[onChange.mock.calls.length - 1][1]
@@ -498,6 +524,7 @@ describe(MultipleModeledMethodsPanel.name, () => {
it("changes selection to the newly added modeling", async () => { it("changes selection to the newly added modeling", async () => {
const { rerender } = render({ const { rerender } = render({
language,
method, method,
modeledMethods, modeledMethods,
isModelingInProgress, isModelingInProgress,
@@ -510,6 +537,7 @@ describe(MultipleModeledMethodsPanel.name, () => {
rerender( rerender(
<MultipleModeledMethodsPanel <MultipleModeledMethodsPanel
language={language}
method={method} method={method}
modeledMethods={ modeledMethods={
onChange.mock.calls[onChange.mock.calls.length - 1][1] onChange.mock.calls[onChange.mock.calls.length - 1][1]
@@ -550,6 +578,7 @@ describe(MultipleModeledMethodsPanel.name, () => {
it("can use the pagination", async () => { it("can use the pagination", async () => {
render({ render({
language,
method, method,
modeledMethods, modeledMethods,
isModelingInProgress, isModelingInProgress,
@@ -639,6 +668,7 @@ describe(MultipleModeledMethodsPanel.name, () => {
it("preserves selection when a modeling other than the selected modeling is removed", async () => { it("preserves selection when a modeling other than the selected modeling is removed", async () => {
const { rerender } = render({ const { rerender } = render({
language,
method, method,
modeledMethods, modeledMethods,
isModelingInProgress, isModelingInProgress,
@@ -649,6 +679,7 @@ describe(MultipleModeledMethodsPanel.name, () => {
rerender( rerender(
<MultipleModeledMethodsPanel <MultipleModeledMethodsPanel
language={language}
method={method} method={method}
modeledMethods={modeledMethods.slice(0, 2)} modeledMethods={modeledMethods.slice(0, 2)}
isModelingInProgress={isModelingInProgress} isModelingInProgress={isModelingInProgress}
@@ -661,6 +692,7 @@ describe(MultipleModeledMethodsPanel.name, () => {
it("reduces selection when the selected modeling is removed", async () => { it("reduces selection when the selected modeling is removed", async () => {
const { rerender } = render({ const { rerender } = render({
language,
method, method,
modeledMethods, modeledMethods,
isModelingInProgress, isModelingInProgress,
@@ -673,6 +705,7 @@ describe(MultipleModeledMethodsPanel.name, () => {
rerender( rerender(
<MultipleModeledMethodsPanel <MultipleModeledMethodsPanel
language={language}
method={method} method={method}
modeledMethods={modeledMethods.slice(0, 2)} modeledMethods={modeledMethods.slice(0, 2)}
isModelingInProgress={isModelingInProgress} isModelingInProgress={isModelingInProgress}
@@ -704,6 +737,7 @@ describe(MultipleModeledMethodsPanel.name, () => {
it("can add modeling", () => { it("can add modeling", () => {
render({ render({
language,
method, method,
modeledMethods, modeledMethods,
isModelingInProgress, isModelingInProgress,
@@ -717,6 +751,7 @@ describe(MultipleModeledMethodsPanel.name, () => {
it("can delete first modeling", async () => { it("can delete first modeling", async () => {
render({ render({
language,
method, method,
modeledMethods, modeledMethods,
isModelingInProgress, isModelingInProgress,
@@ -733,6 +768,7 @@ describe(MultipleModeledMethodsPanel.name, () => {
it("can delete second modeling", async () => { it("can delete second modeling", async () => {
render({ render({
language,
method, method,
modeledMethods, modeledMethods,
isModelingInProgress, isModelingInProgress,
@@ -750,6 +786,7 @@ describe(MultipleModeledMethodsPanel.name, () => {
it("can add modeling after deleting second modeling", async () => { it("can add modeling after deleting second modeling", async () => {
const { rerender } = render({ const { rerender } = render({
language,
method, method,
modeledMethods, modeledMethods,
isModelingInProgress, isModelingInProgress,
@@ -766,6 +803,7 @@ describe(MultipleModeledMethodsPanel.name, () => {
rerender( rerender(
<MultipleModeledMethodsPanel <MultipleModeledMethodsPanel
language={language}
method={method} method={method}
modeledMethods={modeledMethods.slice(0, 1)} modeledMethods={modeledMethods.slice(0, 1)}
isModelingInProgress={isModelingInProgress} isModelingInProgress={isModelingInProgress}
@@ -806,6 +844,7 @@ describe(MultipleModeledMethodsPanel.name, () => {
it("shows errors", () => { it("shows errors", () => {
render({ render({
language,
method, method,
modeledMethods, modeledMethods,
isModelingInProgress, isModelingInProgress,
@@ -817,6 +856,7 @@ describe(MultipleModeledMethodsPanel.name, () => {
it("shows the correct error message", async () => { it("shows the correct error message", async () => {
render({ render({
language,
method, method,
modeledMethods, modeledMethods,
isModelingInProgress, isModelingInProgress,

View File

@@ -262,6 +262,7 @@ const ModelableMethodRow = forwardRef<HTMLElement | undefined, MethodRowProps>(
</DataGridCell> </DataGridCell>
<DataGridCell> <DataGridCell>
<ModelKindDropdown <ModelKindDropdown
language={viewState.language}
method={method} method={method}
modeledMethod={modeledMethod} modeledMethod={modeledMethod}
onChange={modeledMethodChangedHandlers[index]} onChange={modeledMethodChangedHandlers[index]}

View File

@@ -6,24 +6,29 @@ import type {
} from "../../model-editor/modeled-method"; } from "../../model-editor/modeled-method";
import { Dropdown } from "../common/Dropdown"; import { Dropdown } from "../common/Dropdown";
import { Method } from "../../model-editor/method"; import { Method } from "../../model-editor/method";
import { extensiblePredicateDefinitions } from "../../model-editor/predicates"; import { getModelsAsDataLanguage } from "../../model-editor/languages";
import { QueryLanguage } from "../../common/query-language";
type Props = { type Props = {
language: QueryLanguage;
method: Method; method: Method;
modeledMethod: ModeledMethod | undefined; modeledMethod: ModeledMethod | undefined;
onChange: (modeledMethod: ModeledMethod) => void; onChange: (modeledMethod: ModeledMethod) => void;
}; };
export const ModelKindDropdown = ({ export const ModelKindDropdown = ({
language,
method, method,
modeledMethod, modeledMethod,
onChange, onChange,
}: Props) => { }: Props) => {
const predicate = useMemo(() => { const predicate = useMemo(() => {
const modelsAsDataLanguage = getModelsAsDataLanguage(language);
return modeledMethod?.type && modeledMethod.type !== "none" return modeledMethod?.type && modeledMethod.type !== "none"
? extensiblePredicateDefinitions[modeledMethod.type] ? modelsAsDataLanguage[modeledMethod.type]
: undefined; : undefined;
}, [modeledMethod?.type]); }, [language, modeledMethod?.type]);
const kinds = useMemo(() => predicate?.supportedKinds || [], [predicate]); const kinds = useMemo(() => predicate?.supportedKinds || [], [predicate]);

View File

@@ -1,19 +1,10 @@
import * as React from "react"; import * as React from "react";
import { render, screen } from "@testing-library/react"; import { render, screen } from "@testing-library/react";
import { HiddenMethodsRow } from "../HiddenMethodsRow"; import { HiddenMethodsRow } from "../HiddenMethodsRow";
import { createMockExtensionPack } from "../../../../test/factories/model-editor/extension-pack"; import { createMockModelEditorViewState } from "../../../../test/factories/model-editor/view-state";
import { ModelEditorViewState } from "../../../model-editor/shared/view-state";
import { Mode } from "../../../model-editor/shared/mode";
describe(HiddenMethodsRow.name, () => { describe(HiddenMethodsRow.name, () => {
const viewState: ModelEditorViewState = { const viewState = createMockModelEditorViewState();
mode: Mode.Application,
showFlowGeneration: false,
showLlmButton: false,
showMultipleModels: false,
extensionPack: createMockExtensionPack(),
sourceArchiveAvailable: true,
};
it("does not render with 0 hidden methods", () => { it("does not render with 0 hidden methods", () => {
const { container } = render( const { container } = render(

View File

@@ -2,10 +2,8 @@ import * as React from "react";
import { render as reactRender, screen } from "@testing-library/react"; import { render as reactRender, screen } from "@testing-library/react";
import { createMethod } from "../../../../test/factories/model-editor/method-factories"; import { createMethod } from "../../../../test/factories/model-editor/method-factories";
import { LibraryRow, LibraryRowProps } from "../LibraryRow"; import { LibraryRow, LibraryRowProps } from "../LibraryRow";
import { createMockExtensionPack } from "../../../../test/factories/model-editor/extension-pack";
import { Mode } from "../../../model-editor/shared/mode";
import { ModelEditorViewState } from "../../../model-editor/shared/view-state";
import userEvent from "@testing-library/user-event"; import userEvent from "@testing-library/user-event";
import { createMockModelEditorViewState } from "../../../../test/factories/model-editor/view-state";
describe(LibraryRow.name, () => { describe(LibraryRow.name, () => {
const method = createMethod(); const method = createMethod();
@@ -15,14 +13,7 @@ describe(LibraryRow.name, () => {
const onStopGenerateFromLlmClick = jest.fn(); const onStopGenerateFromLlmClick = jest.fn();
const onModelDependencyClick = jest.fn(); const onModelDependencyClick = jest.fn();
const viewState: ModelEditorViewState = { const viewState = createMockModelEditorViewState();
mode: Mode.Application,
showFlowGeneration: false,
showLlmButton: false,
showMultipleModels: false,
extensionPack: createMockExtensionPack(),
sourceArchiveAvailable: true,
};
const render = (props: Partial<LibraryRowProps> = {}) => const render = (props: Partial<LibraryRowProps> = {}) =>
reactRender( reactRender(

View File

@@ -5,12 +5,10 @@ import {
screen, screen,
} from "@testing-library/react"; } from "@testing-library/react";
import { createMethod } from "../../../../test/factories/model-editor/method-factories"; import { createMethod } from "../../../../test/factories/model-editor/method-factories";
import { Mode } from "../../../model-editor/shared/mode";
import { MethodRow, MethodRowProps } from "../MethodRow"; import { MethodRow, MethodRowProps } from "../MethodRow";
import { ModeledMethod } from "../../../model-editor/modeled-method"; import { ModeledMethod } from "../../../model-editor/modeled-method";
import userEvent from "@testing-library/user-event"; import userEvent from "@testing-library/user-event";
import { ModelEditorViewState } from "../../../model-editor/shared/view-state"; import { createMockModelEditorViewState } from "../../../../test/factories/model-editor/view-state";
import { createMockExtensionPack } from "../../../../test/factories/model-editor/extension-pack";
describe(MethodRow.name, () => { describe(MethodRow.name, () => {
const method = createMethod({ const method = createMethod({
@@ -33,14 +31,7 @@ describe(MethodRow.name, () => {
}; };
const onChange = jest.fn(); const onChange = jest.fn();
const viewState: ModelEditorViewState = { const viewState = createMockModelEditorViewState();
mode: Mode.Application,
showFlowGeneration: false,
showLlmButton: false,
showMultipleModels: false,
extensionPack: createMockExtensionPack(),
sourceArchiveAvailable: true,
};
const render = (props: Partial<MethodRowProps> = {}) => const render = (props: Partial<MethodRowProps> = {}) =>
reactRender( reactRender(

View File

@@ -4,6 +4,7 @@ import { ModelKindDropdown } from "../ModelKindDropdown";
import userEvent from "@testing-library/user-event"; import userEvent from "@testing-library/user-event";
import { createMethod } from "../../../../test/factories/model-editor/method-factories"; import { createMethod } from "../../../../test/factories/model-editor/method-factories";
import { createModeledMethod } from "../../../../test/factories/model-editor/modeled-method-factories"; import { createModeledMethod } from "../../../../test/factories/model-editor/modeled-method-factories";
import { QueryLanguage } from "../../../common/query-language";
describe(ModelKindDropdown.name, () => { describe(ModelKindDropdown.name, () => {
const onChange = jest.fn(); const onChange = jest.fn();
@@ -21,6 +22,7 @@ describe(ModelKindDropdown.name, () => {
render( render(
<ModelKindDropdown <ModelKindDropdown
language={QueryLanguage.Java}
method={method} method={method}
modeledMethod={modeledMethod} modeledMethod={modeledMethod}
onChange={onChange} onChange={onChange}
@@ -45,6 +47,7 @@ describe(ModelKindDropdown.name, () => {
const { rerender } = render( const { rerender } = render(
<ModelKindDropdown <ModelKindDropdown
language={QueryLanguage.Java}
method={method} method={method}
modeledMethod={modeledMethod} modeledMethod={modeledMethod}
onChange={onChange} onChange={onChange}
@@ -62,6 +65,7 @@ describe(ModelKindDropdown.name, () => {
rerender( rerender(
<ModelKindDropdown <ModelKindDropdown
language={QueryLanguage.Java}
method={method} method={method}
modeledMethod={updatedModeledMethod} modeledMethod={updatedModeledMethod}
onChange={onChange} onChange={onChange}
@@ -79,6 +83,7 @@ describe(ModelKindDropdown.name, () => {
render( render(
<ModelKindDropdown <ModelKindDropdown
language={QueryLanguage.Java}
method={method} method={method}
modeledMethod={modeledMethod} modeledMethod={modeledMethod}
onChange={onChange} onChange={onChange}
@@ -102,6 +107,7 @@ describe(ModelKindDropdown.name, () => {
render( render(
<ModelKindDropdown <ModelKindDropdown
language={QueryLanguage.Java}
method={method} method={method}
modeledMethod={modeledMethod} modeledMethod={modeledMethod}
onChange={onChange} onChange={onChange}
@@ -120,6 +126,7 @@ describe(ModelKindDropdown.name, () => {
render( render(
<ModelKindDropdown <ModelKindDropdown
language={QueryLanguage.Java}
method={method} method={method}
modeledMethod={modeledMethod} modeledMethod={modeledMethod}
onChange={onChange} onChange={onChange}

View File

@@ -1,13 +1,11 @@
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 { createMethod } from "../../../../test/factories/model-editor/method-factories"; import { createMethod } from "../../../../test/factories/model-editor/method-factories";
import { Mode } from "../../../model-editor/shared/mode";
import { import {
ModeledMethodDataGrid, ModeledMethodDataGrid,
ModeledMethodDataGridProps, ModeledMethodDataGridProps,
} from "../ModeledMethodDataGrid"; } from "../ModeledMethodDataGrid";
import { ModelEditorViewState } from "../../../model-editor/shared/view-state"; import { createMockModelEditorViewState } from "../../../../test/factories/model-editor/view-state";
import { createMockExtensionPack } from "../../../../test/factories/model-editor/extension-pack";
describe(ModeledMethodDataGrid.name, () => { describe(ModeledMethodDataGrid.name, () => {
const method1 = createMethod({ const method1 = createMethod({
@@ -42,14 +40,7 @@ describe(ModeledMethodDataGrid.name, () => {
}); });
const onChange = jest.fn(); const onChange = jest.fn();
const viewState: ModelEditorViewState = { const viewState = createMockModelEditorViewState();
mode: Mode.Application,
showFlowGeneration: false,
showLlmButton: false,
showMultipleModels: false,
extensionPack: createMockExtensionPack(),
sourceArchiveAvailable: true,
};
const render = (props: Partial<ModeledMethodDataGridProps> = {}) => const render = (props: Partial<ModeledMethodDataGridProps> = {}) =>
reactRender( reactRender(

View File

@@ -1,13 +1,11 @@
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 { createMethod } from "../../../../test/factories/model-editor/method-factories"; import { createMethod } from "../../../../test/factories/model-editor/method-factories";
import { createMockExtensionPack } from "../../../../test/factories/model-editor/extension-pack";
import { Mode } from "../../../model-editor/shared/mode";
import { ModelEditorViewState } from "../../../model-editor/shared/view-state";
import { import {
ModeledMethodsList, ModeledMethodsList,
ModeledMethodsListProps, ModeledMethodsListProps,
} from "../ModeledMethodsList"; } from "../ModeledMethodsList";
import { createMockModelEditorViewState } from "../../../../test/factories/model-editor/view-state";
describe(ModeledMethodsList.name, () => { describe(ModeledMethodsList.name, () => {
const method1 = createMethod({ const method1 = createMethod({
@@ -43,14 +41,7 @@ describe(ModeledMethodsList.name, () => {
const onStopGenerateFromLlmClick = jest.fn(); const onStopGenerateFromLlmClick = jest.fn();
const onModelDependencyClick = jest.fn(); const onModelDependencyClick = jest.fn();
const viewState: ModelEditorViewState = { const viewState = createMockModelEditorViewState();
mode: Mode.Application,
showFlowGeneration: false,
showLlmButton: false,
showMultipleModels: false,
extensionPack: createMockExtensionPack(),
sourceArchiveAvailable: true,
};
const render = (props: Partial<ModeledMethodsListProps> = {}) => const render = (props: Partial<ModeledMethodsListProps> = {}) =>
reactRender( reactRender(

View File

@@ -0,0 +1,19 @@
import { ModelEditorViewState } from "../../../src/model-editor/shared/view-state";
import { Mode } from "../../../src/model-editor/shared/mode";
import { createMockExtensionPack } from "./extension-pack";
import { QueryLanguage } from "../../../src/common/query-language";
export function createMockModelEditorViewState(
data: Partial<ModelEditorViewState> = {},
): ModelEditorViewState {
return {
language: QueryLanguage.Java,
mode: Mode.Application,
showFlowGeneration: false,
showLlmButton: false,
showMultipleModels: false,
extensionPack: createMockExtensionPack(),
sourceArchiveAvailable: true,
...data,
};
}

View File

@@ -7,10 +7,11 @@ import {
loadDataExtensionYaml, loadDataExtensionYaml,
} from "../../../src/model-editor/yaml"; } from "../../../src/model-editor/yaml";
import { CallClassification } from "../../../src/model-editor/method"; import { CallClassification } from "../../../src/model-editor/method";
import { QueryLanguage } from "../../../src/common/query-language";
describe("createDataExtensionYaml", () => { describe("createDataExtensionYaml", () => {
it("creates the correct YAML file", () => { it("creates the correct YAML file", () => {
const yaml = createDataExtensionYaml("java", [ const yaml = createDataExtensionYaml(QueryLanguage.Java, [
{ {
type: "sink", type: "sink",
input: "Argument[0]", input: "Argument[0]",
@@ -50,7 +51,7 @@ describe("createDataExtensionYaml", () => {
}); });
it("includes the correct language", () => { it("includes the correct language", () => {
const yaml = createDataExtensionYaml("csharp", []); const yaml = createDataExtensionYaml(QueryLanguage.CSharp, []);
expect(yaml).toEqual(`extensions: expect(yaml).toEqual(`extensions:
- addsTo: - addsTo:
@@ -79,7 +80,7 @@ describe("createDataExtensionYaml", () => {
describe("createDataExtensionYamlsForApplicationMode", () => { describe("createDataExtensionYamlsForApplicationMode", () => {
it("creates the correct YAML files when there are no existing modeled methods", () => { it("creates the correct YAML files when there are no existing modeled methods", () => {
const yaml = createDataExtensionYamlsForApplicationMode( const yaml = createDataExtensionYamlsForApplicationMode(
"java", QueryLanguage.Java,
[ [
{ {
library: "sql2o", library: "sql2o",
@@ -323,7 +324,7 @@ describe("createDataExtensionYamlsForApplicationMode", () => {
it("creates the correct YAML files when there are existing modeled methods", () => { it("creates the correct YAML files when there are existing modeled methods", () => {
const yaml = createDataExtensionYamlsForApplicationMode( const yaml = createDataExtensionYamlsForApplicationMode(
"java", QueryLanguage.Java,
[ [
{ {
library: "sql2o", library: "sql2o",
@@ -618,7 +619,7 @@ describe("createDataExtensionYamlsForApplicationMode", () => {
describe("createDataExtensionYamlsForFrameworkMode", () => { describe("createDataExtensionYamlsForFrameworkMode", () => {
it("creates the correct YAML files when there are no existing modeled methods", () => { it("creates the correct YAML files when there are no existing modeled methods", () => {
const yaml = createDataExtensionYamlsForFrameworkMode( const yaml = createDataExtensionYamlsForFrameworkMode(
"java", QueryLanguage.Java,
[ [
{ {
library: "sql2o", library: "sql2o",
@@ -774,7 +775,7 @@ describe("createDataExtensionYamlsForFrameworkMode", () => {
it("creates the correct YAML files when there are existing modeled methods", () => { it("creates the correct YAML files when there are existing modeled methods", () => {
const yaml = createDataExtensionYamlsForFrameworkMode( const yaml = createDataExtensionYamlsForFrameworkMode(
"java", QueryLanguage.Java,
[ [
{ {
library: "sql2o", library: "sql2o",
@@ -980,38 +981,41 @@ describe("createDataExtensionYamlsForFrameworkMode", () => {
describe("loadDataExtensionYaml", () => { describe("loadDataExtensionYaml", () => {
it("loads the YAML file", () => { it("loads the YAML file", () => {
const data = loadDataExtensionYaml({ const data = loadDataExtensionYaml(
extensions: [ {
{ extensions: [
addsTo: { pack: "codeql/java-all", extensible: "sourceModel" }, {
data: [], addsTo: { pack: "codeql/java-all", extensible: "sourceModel" },
}, data: [],
{ },
addsTo: { pack: "codeql/java-all", extensible: "sinkModel" }, {
data: [ addsTo: { pack: "codeql/java-all", extensible: "sinkModel" },
[ data: [
"org.sql2o", [
"Connection", "org.sql2o",
true, "Connection",
"createQuery", true,
"(String)", "createQuery",
"", "(String)",
"Argument[0]", "",
"sql", "Argument[0]",
"manual", "sql",
"manual",
],
], ],
], },
}, {
{ addsTo: { pack: "codeql/java-all", extensible: "summaryModel" },
addsTo: { pack: "codeql/java-all", extensible: "summaryModel" }, data: [],
data: [], },
}, {
{ addsTo: { pack: "codeql/java-all", extensible: "neutralModel" },
addsTo: { pack: "codeql/java-all", extensible: "neutralModel" }, data: [],
data: [], },
}, ],
], },
}); QueryLanguage.Java,
);
expect(data).toEqual({ expect(data).toEqual({
"org.sql2o.Connection#createQuery(String)": [ "org.sql2o.Connection#createQuery(String)": [
@@ -1033,13 +1037,16 @@ describe("loadDataExtensionYaml", () => {
it("returns undefined if given a string", () => { it("returns undefined if given a string", () => {
expect(() => expect(() =>
loadDataExtensionYaml(`extensions: loadDataExtensionYaml(
`extensions:
- addsTo: - addsTo:
pack: codeql/java-all pack: codeql/java-all
extensible: sinkModel extensible: sinkModel
data: data:
- ["org.sql2o","Connection",true,"createQuery","(String)","","Argument[0]","sql","manual"] - ["org.sql2o","Connection",true,"createQuery","(String)","","Argument[0]","sql","manual"]
`), `,
QueryLanguage.Java,
),
).toThrow("Invalid data extension YAML: must be object"); ).toThrow("Invalid data extension YAML: must be object");
}); });
}); });

View File

@@ -11,6 +11,7 @@ import { ExtensionPack } from "../../../../src/model-editor/shared/extension-pac
import { join } from "path"; import { join } from "path";
import { extLogger } from "../../../../src/common/logging/vscode"; import { extLogger } from "../../../../src/common/logging/vscode";
import { homedir } from "os"; import { homedir } from "os";
import { QueryLanguage } from "../../../../src/common/query-language";
const dummyExtensionPackContents = ` const dummyExtensionPackContents = `
name: dummy/pack name: dummy/pack
@@ -192,6 +193,7 @@ describe("modeled-method-fs", () => {
const modeledMethods = await loadModeledMethods( const modeledMethods = await loadModeledMethods(
makeExtensionPack(extensionPackPath), makeExtensionPack(extensionPackPath),
QueryLanguage.Java,
cli, cli,
extLogger, extLogger,
); );

View File

@@ -12,6 +12,7 @@ import { createMockModelingStore } from "../../../__mocks__/model-editor/modelin
import { createMockModelEditorViewTracker } from "../../../__mocks__/model-editor/modelEditorViewTrackerMock"; import { createMockModelEditorViewTracker } from "../../../__mocks__/model-editor/modelEditorViewTrackerMock";
import { ModelConfigListener } from "../../../../src/config"; import { ModelConfigListener } from "../../../../src/config";
import { createMockModelingEvents } from "../../../__mocks__/model-editor/modelingEventsMock"; import { createMockModelingEvents } from "../../../__mocks__/model-editor/modelingEventsMock";
import { QueryLanguage } from "../../../../src/common/query-language";
describe("ModelEditorView", () => { describe("ModelEditorView", () => {
const app = createMockApp({}); const app = createMockApp({});
@@ -56,6 +57,7 @@ describe("ModelEditorView", () => {
queryDir, queryDir,
databaseItem, databaseItem,
extensionPack, extensionPack,
QueryLanguage.Java,
mode, mode,
); );
}); });