Skip to content

Commit fcf74b3

Browse files
authored
Refactor: extract function for canonicalising modeled methods (#3518)
1 parent c84fa53 commit fcf74b3

File tree

2 files changed

+86
-82
lines changed

2 files changed

+86
-82
lines changed

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

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import { assertNever } from "../common/helpers-pure";
12
import type { MethodSignature } from "./method";
23
import type { ModelingStatus } from "./shared/modeling-status";
34

@@ -169,3 +170,86 @@ export function calculateNewProvenance(
169170
return "manual";
170171
}
171172
}
173+
174+
export function createModeledMethodKey(modeledMethod: ModeledMethod): string {
175+
const canonicalModeledMethod = canonicalizeModeledMethod(modeledMethod);
176+
return JSON.stringify(
177+
canonicalModeledMethod,
178+
// This ensures the keys are always in the same order
179+
Object.keys(canonicalModeledMethod).sort(),
180+
);
181+
}
182+
183+
/**
184+
* This method will reset any properties which are not used for the specific type of modeled method.
185+
*
186+
* It will also set the `provenance` to `manual` since multiple modelings of the same method with a
187+
* different provenance are not actually different.
188+
*
189+
* The returned canonical modeled method should only be used for comparisons. It should not be used
190+
* for display purposes, saving the model, or any other purpose which requires the original modeled
191+
* method to be preserved.
192+
*
193+
* @param modeledMethod The modeled method to canonicalize
194+
*/
195+
function canonicalizeModeledMethod(
196+
modeledMethod: ModeledMethod,
197+
): ModeledMethod {
198+
const methodSignature: MethodSignature = {
199+
endpointType: modeledMethod.endpointType,
200+
signature: modeledMethod.signature,
201+
packageName: modeledMethod.packageName,
202+
typeName: modeledMethod.typeName,
203+
methodName: modeledMethod.methodName,
204+
methodParameters: modeledMethod.methodParameters,
205+
};
206+
207+
switch (modeledMethod.type) {
208+
case "none":
209+
return {
210+
...methodSignature,
211+
type: "none",
212+
};
213+
case "source":
214+
return {
215+
...methodSignature,
216+
type: "source",
217+
output: modeledMethod.output,
218+
kind: modeledMethod.kind,
219+
provenance: "manual",
220+
};
221+
case "sink":
222+
return {
223+
...methodSignature,
224+
type: "sink",
225+
input: modeledMethod.input,
226+
kind: modeledMethod.kind,
227+
provenance: "manual",
228+
};
229+
case "summary":
230+
return {
231+
...methodSignature,
232+
type: "summary",
233+
input: modeledMethod.input,
234+
output: modeledMethod.output,
235+
kind: modeledMethod.kind,
236+
provenance: "manual",
237+
};
238+
case "neutral":
239+
return {
240+
...methodSignature,
241+
type: "neutral",
242+
kind: modeledMethod.kind,
243+
provenance: "manual",
244+
};
245+
case "type":
246+
return {
247+
...methodSignature,
248+
type: "type",
249+
relatedTypeName: modeledMethod.relatedTypeName,
250+
path: modeledMethod.path,
251+
};
252+
default:
253+
assertNever(modeledMethod);
254+
}
255+
}

extensions/ql-vscode/src/model-editor/shared/validation.ts

Lines changed: 2 additions & 82 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
1+
import { createModeledMethodKey } from "../modeled-method";
12
import type { ModeledMethod, NeutralModeledMethod } from "../modeled-method";
2-
import type { MethodSignature } from "../method";
3-
import { assertNever } from "../../common/helpers-pure";
43

54
export type ModeledMethodValidationError = {
65
title: string;
@@ -9,80 +8,6 @@ export type ModeledMethodValidationError = {
98
index: number;
109
};
1110

12-
/**
13-
* This method will reset any properties which are not used for the specific type of modeled method.
14-
*
15-
* It will also set the `provenance` to `manual` since multiple modelings of the same method with a
16-
* different provenance are not actually different.
17-
*
18-
* The returned canonical modeled method should only be used for comparisons. It should not be used
19-
* for display purposes, saving the model, or any other purpose which requires the original modeled
20-
* method to be preserved.
21-
*
22-
* @param modeledMethod The modeled method to canonicalize
23-
*/
24-
function canonicalizeModeledMethod(
25-
modeledMethod: ModeledMethod,
26-
): ModeledMethod {
27-
const methodSignature: MethodSignature = {
28-
endpointType: modeledMethod.endpointType,
29-
signature: modeledMethod.signature,
30-
packageName: modeledMethod.packageName,
31-
typeName: modeledMethod.typeName,
32-
methodName: modeledMethod.methodName,
33-
methodParameters: modeledMethod.methodParameters,
34-
};
35-
36-
switch (modeledMethod.type) {
37-
case "none":
38-
return {
39-
...methodSignature,
40-
type: "none",
41-
};
42-
case "source":
43-
return {
44-
...methodSignature,
45-
type: "source",
46-
output: modeledMethod.output,
47-
kind: modeledMethod.kind,
48-
provenance: "manual",
49-
};
50-
case "sink":
51-
return {
52-
...methodSignature,
53-
type: "sink",
54-
input: modeledMethod.input,
55-
kind: modeledMethod.kind,
56-
provenance: "manual",
57-
};
58-
case "summary":
59-
return {
60-
...methodSignature,
61-
type: "summary",
62-
input: modeledMethod.input,
63-
output: modeledMethod.output,
64-
kind: modeledMethod.kind,
65-
provenance: "manual",
66-
};
67-
case "neutral":
68-
return {
69-
...methodSignature,
70-
type: "neutral",
71-
kind: modeledMethod.kind,
72-
provenance: "manual",
73-
};
74-
case "type":
75-
return {
76-
...methodSignature,
77-
type: "type",
78-
relatedTypeName: modeledMethod.relatedTypeName,
79-
path: modeledMethod.path,
80-
};
81-
default:
82-
assertNever(modeledMethod);
83-
}
84-
}
85-
8611
export function validateModeledMethods(
8712
modeledMethods: ModeledMethod[],
8813
): ModeledMethodValidationError[] {
@@ -97,12 +22,7 @@ export function validateModeledMethods(
9722
// an error for any duplicates.
9823
const seenModeledMethods = new Set<string>();
9924
for (const modeledMethod of consideredModeledMethods) {
100-
const canonicalModeledMethod = canonicalizeModeledMethod(modeledMethod);
101-
const key = JSON.stringify(
102-
canonicalModeledMethod,
103-
// This ensures the keys are always in the same order
104-
Object.keys(canonicalModeledMethod).sort(),
105-
);
25+
const key = createModeledMethodKey(modeledMethod);
10626

10727
if (seenModeledMethods.has(key)) {
10828
result.push({

0 commit comments

Comments
 (0)