Skip to content

Commit a6c9707

Browse files
authored
Merge pull request #2904 from github/koesie10/convert-yaml-modeled-methods
Convert `yaml.ts` to handle multiple models per method
2 parents 6d7fbfc + ada62ff commit a6c9707

File tree

5 files changed

+299
-212
lines changed

5 files changed

+299
-212
lines changed

extensions/ql-vscode/src/model-editor/auto-modeler.ts

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ import { QueryRunner } from "../query-server";
1616
import { DatabaseItem } from "../databases/local-databases";
1717
import { Mode } from "./shared/mode";
1818
import { CancellationTokenSource } from "vscode";
19+
import { convertToLegacyModeledMethods } from "./modeled-methods-legacy";
1920

2021
// Limit the number of candidates we send to the model in each request
2122
// to avoid long requests.
@@ -192,11 +193,13 @@ export class AutoModeler {
192193
filename: "auto-model.yml",
193194
});
194195

195-
const loadedMethods = loadDataExtensionYaml(models);
196-
if (!loadedMethods) {
196+
const rawLoadedMethods = loadDataExtensionYaml(models);
197+
if (!rawLoadedMethods) {
197198
return;
198199
}
199200

201+
const loadedMethods = convertToLegacyModeledMethods(rawLoadedMethods);
202+
200203
// Any candidate that was part of the response is a negative result
201204
// meaning that the canidate is not a sink for the kinds that the LLM is checking for.
202205
// For now we model this as a sink neutral method, however this is subject

extensions/ql-vscode/src/model-editor/modeled-method-fs.ts

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,11 @@ import { getOnDiskWorkspaceFolders } from "../common/vscode/workspace-folders";
1010
import { load as loadYaml } from "js-yaml";
1111
import { CodeQLCliServer } from "../codeql-cli/cli";
1212
import { pathsEqual } from "../common/files";
13+
import {
14+
convertFromLegacyModeledMethods,
15+
convertFromLegacyModeledMethodsFiles,
16+
convertToLegacyModeledMethods,
17+
} from "./modeled-methods-legacy";
1318

1419
export async function saveModeledMethods(
1520
extensionPack: ExtensionPack,
@@ -29,8 +34,8 @@ export async function saveModeledMethods(
2934
const yamls = createDataExtensionYamls(
3035
language,
3136
methods,
32-
modeledMethods,
33-
existingModeledMethods,
37+
convertFromLegacyModeledMethods(modeledMethods),
38+
convertFromLegacyModeledMethodsFiles(existingModeledMethods),
3439
mode,
3540
);
3641

@@ -68,7 +73,8 @@ async function loadModeledMethodFiles(
6873
);
6974
continue;
7075
}
71-
modeledMethodsByFile[modelFile] = modeledMethods;
76+
modeledMethodsByFile[modelFile] =
77+
convertToLegacyModeledMethods(modeledMethods);
7278
}
7379

7480
return modeledMethodsByFile;
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
import { ModeledMethod } from "./modeled-method";
2+
3+
export function convertFromLegacyModeledMethods(
4+
modeledMethods: Record<string, ModeledMethod>,
5+
): Record<string, ModeledMethod[]> {
6+
// Convert a single ModeledMethod to an array of ModeledMethods
7+
return Object.fromEntries(
8+
Object.entries(modeledMethods).map(([signature, modeledMethod]) => {
9+
return [signature, [modeledMethod]];
10+
}),
11+
);
12+
}
13+
14+
export function convertToLegacyModeledMethods(
15+
modeledMethods: Record<string, ModeledMethod[]>,
16+
): Record<string, ModeledMethod> {
17+
// Always take the first modeled method in the array
18+
return Object.fromEntries(
19+
Object.entries(modeledMethods).map(([signature, modeledMethods]) => {
20+
return [signature, modeledMethods[0]];
21+
}),
22+
);
23+
}
24+
25+
export function convertFromLegacyModeledMethodsFiles(
26+
modeledMethods: Record<string, Record<string, ModeledMethod>>,
27+
): Record<string, Record<string, ModeledMethod[]>> {
28+
return Object.fromEntries(
29+
Object.entries(modeledMethods).map(([filename, modeledMethods]) => {
30+
return [filename, convertFromLegacyModeledMethods(modeledMethods)];
31+
}),
32+
);
33+
}

extensions/ql-vscode/src/model-editor/yaml.ts

Lines changed: 29 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -71,8 +71,8 @@ ${extensions.join("\n")}`;
7171
export function createDataExtensionYamls(
7272
language: string,
7373
methods: Method[],
74-
newModeledMethods: Record<string, ModeledMethod>,
75-
existingModeledMethods: Record<string, Record<string, ModeledMethod>>,
74+
newModeledMethods: Record<string, ModeledMethod[]>,
75+
existingModeledMethods: Record<string, Record<string, ModeledMethod[]>>,
7676
mode: Mode,
7777
) {
7878
switch (mode) {
@@ -98,11 +98,11 @@ export function createDataExtensionYamls(
9898
function createDataExtensionYamlsByGrouping(
9999
language: string,
100100
methods: Method[],
101-
newModeledMethods: Record<string, ModeledMethod>,
102-
existingModeledMethods: Record<string, Record<string, ModeledMethod>>,
101+
newModeledMethods: Record<string, ModeledMethod[]>,
102+
existingModeledMethods: Record<string, Record<string, ModeledMethod[]>>,
103103
createFilename: (method: Method) => string,
104104
): Record<string, string> {
105-
const methodsByFilename: Record<string, Record<string, ModeledMethod>> = {};
105+
const methodsByFilename: Record<string, Record<string, ModeledMethod[]>> = {};
106106

107107
// We only want to generate a yaml file when it's a known external API usage
108108
// and there are new modeled methods for it. This avoids us overwriting other
@@ -114,21 +114,25 @@ function createDataExtensionYamlsByGrouping(
114114
}
115115

116116
// First populate methodsByFilename with any existing modeled methods.
117-
for (const [filename, methods] of Object.entries(existingModeledMethods)) {
117+
for (const [filename, methodsBySignature] of Object.entries(
118+
existingModeledMethods,
119+
)) {
118120
if (filename in methodsByFilename) {
119-
for (const [signature, method] of Object.entries(methods)) {
120-
methodsByFilename[filename][signature] = method;
121+
for (const [signature, methods] of Object.entries(methodsBySignature)) {
122+
methodsByFilename[filename][signature] = methods;
121123
}
122124
}
123125
}
124126

125127
// Add the new modeled methods, potentially overwriting existing modeled methods
126128
// but not removing existing modeled methods that are not in the new set.
127129
for (const method of methods) {
128-
const newMethod = newModeledMethods[method.signature];
129-
if (newMethod) {
130+
const newMethods = newModeledMethods[method.signature];
131+
if (newMethods) {
130132
const filename = createFilename(method);
131-
methodsByFilename[filename][newMethod.signature] = newMethod;
133+
134+
// Override any existing modeled methods with the new ones.
135+
methodsByFilename[filename][method.signature] = newMethods;
132136
}
133137
}
134138

@@ -137,7 +141,7 @@ function createDataExtensionYamlsByGrouping(
137141
for (const [filename, methods] of Object.entries(methodsByFilename)) {
138142
result[filename] = createDataExtensionYaml(
139143
language,
140-
Object.values(methods),
144+
Object.values(methods).flatMap((methods) => methods),
141145
);
142146
}
143147

@@ -147,8 +151,8 @@ function createDataExtensionYamlsByGrouping(
147151
export function createDataExtensionYamlsForApplicationMode(
148152
language: string,
149153
methods: Method[],
150-
newModeledMethods: Record<string, ModeledMethod>,
151-
existingModeledMethods: Record<string, Record<string, ModeledMethod>>,
154+
newModeledMethods: Record<string, ModeledMethod[]>,
155+
existingModeledMethods: Record<string, Record<string, ModeledMethod[]>>,
152156
): Record<string, string> {
153157
return createDataExtensionYamlsByGrouping(
154158
language,
@@ -162,8 +166,8 @@ export function createDataExtensionYamlsForApplicationMode(
162166
export function createDataExtensionYamlsForFrameworkMode(
163167
language: string,
164168
methods: Method[],
165-
newModeledMethods: Record<string, ModeledMethod>,
166-
existingModeledMethods: Record<string, Record<string, ModeledMethod>>,
169+
newModeledMethods: Record<string, ModeledMethod[]>,
170+
existingModeledMethods: Record<string, Record<string, ModeledMethod[]>>,
167171
): Record<string, string> {
168172
return createDataExtensionYamlsByGrouping(
169173
language,
@@ -228,14 +232,14 @@ function validateModelExtensionFile(data: unknown): data is ModelExtensionFile {
228232

229233
export function loadDataExtensionYaml(
230234
data: unknown,
231-
): Record<string, ModeledMethod> | undefined {
235+
): Record<string, ModeledMethod[]> | undefined {
232236
if (!validateModelExtensionFile(data)) {
233237
return undefined;
234238
}
235239

236240
const extensions = data.extensions;
237241

238-
const modeledMethods: Record<string, ModeledMethod> = {};
242+
const modeledMethods: Record<string, ModeledMethod[]> = {};
239243

240244
for (const extension of extensions) {
241245
const addsTo = extension.addsTo;
@@ -250,11 +254,16 @@ export function loadDataExtensionYaml(
250254
}
251255

252256
for (const row of data) {
253-
const modeledMethod = definition.readModeledMethod(row);
257+
const modeledMethod: ModeledMethod = definition.readModeledMethod(row);
254258
if (!modeledMethod) {
255259
continue;
256260
}
257-
modeledMethods[modeledMethod.signature] = modeledMethod;
261+
262+
if (!(modeledMethod.signature in modeledMethods)) {
263+
modeledMethods[modeledMethod.signature] = [];
264+
}
265+
266+
modeledMethods[modeledMethod.signature].push(modeledMethod);
258267
}
259268
}
260269

0 commit comments

Comments
 (0)