Skip to content

Commit b348356

Browse files
committed
Extract creation of method argument options to languages
This moves the creation of possible method argument options from the view to the languages. This allows differentiating between the languages, for example by using `Argument[self]` for Ruby instead of `Argument[this]`.
1 parent 146732f commit b348356

File tree

9 files changed

+104
-43
lines changed

9 files changed

+104
-43
lines changed

extensions/ql-vscode/src/model-editor/languages/models-as-data.ts

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { MethodDefinition } from "../method";
1+
import { MethodArgument, MethodDefinition } from "../method";
22
import {
33
ModeledMethod,
44
NeutralModeledMethod,
@@ -45,6 +45,11 @@ export type ModelsAsDataLanguagePredicates = {
4545
neutral?: ModelsAsDataLanguagePredicate<NeutralModeledMethod>;
4646
};
4747

48+
export type MethodArgumentOptions = {
49+
options: MethodArgument[];
50+
defaultArgumentPath: string;
51+
};
52+
4853
export type ModelsAsDataLanguage = {
4954
/**
5055
* The modes that are available for this language. If not specified, all
@@ -54,4 +59,9 @@ export type ModelsAsDataLanguage = {
5459
createMethodSignature: (method: MethodDefinition) => string;
5560
predicates: ModelsAsDataLanguagePredicates;
5661
modelGeneration?: ModelsAsDataLanguageModelGeneration;
62+
/**
63+
* Returns the list of valid arguments that can be selected for the given method.
64+
* @param method The method to get the valid arguments for.
65+
*/
66+
getArgumentOptions: (method: MethodDefinition) => MethodArgumentOptions;
5767
};

extensions/ql-vscode/src/model-editor/languages/ruby/index.ts

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import { ModelsAsDataLanguage } from "../models-as-data";
22
import { sharedExtensiblePredicates, sharedKinds } from "../shared";
33
import { Mode } from "../../shared/mode";
44
import { parseGenerateModelResults } from "./generate";
5+
import { getArgumentsList, MethodArgument } from "../../method";
56

67
function parseRubyMethodFromPath(path: string): string {
78
const match = path.match(/Method\[([^\]]+)].*/);
@@ -157,4 +158,25 @@ export const ruby: ModelsAsDataLanguage = {
157158
},
158159
parseResults: parseGenerateModelResults,
159160
},
161+
getArgumentOptions: (method) => {
162+
const argumentsList = getArgumentsList(method.methodParameters).map(
163+
(argument, index): MethodArgument => ({
164+
path: `Argument[${index}]`,
165+
label: `Argument[${index}]: ${argument}`,
166+
}),
167+
);
168+
169+
return {
170+
options: [
171+
{
172+
path: "Argument[self]",
173+
label: "Argument[self]",
174+
},
175+
...argumentsList,
176+
],
177+
// If there are no arguments, we will default to "Argument[self]"
178+
defaultArgumentPath:
179+
argumentsList.length > 0 ? argumentsList[0].path : "Argument[self]",
180+
};
181+
},
160182
};

extensions/ql-vscode/src/model-editor/languages/static/index.ts

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import { Provenance } from "../../modeled-method";
33
import { DataTuple } from "../../model-extension-file";
44
import { sharedExtensiblePredicates, sharedKinds } from "../shared";
55
import { filterFlowModelQueries, parseFlowModelResults } from "./generate";
6+
import { getArgumentsList, MethodArgument } from "../../method";
67

78
function readRowToMethod(row: DataTuple[]): string {
89
return `${row[0]}.${row[1]}#${row[3]}${row[4]}`;
@@ -145,4 +146,25 @@ export const staticLanguage: ModelsAsDataLanguage = {
145146
filterQueries: filterFlowModelQueries,
146147
parseResults: parseFlowModelResults,
147148
},
149+
getArgumentOptions: (method) => {
150+
const argumentsList = getArgumentsList(method.methodParameters).map(
151+
(argument, index): MethodArgument => ({
152+
path: `Argument[${index}]`,
153+
label: `Argument[${index}]: ${argument}`,
154+
}),
155+
);
156+
157+
return {
158+
options: [
159+
{
160+
path: "Argument[this]",
161+
label: "Argument[this]",
162+
},
163+
...argumentsList,
164+
],
165+
// If there are no arguments, we will default to "Argument[this]"
166+
defaultArgumentPath:
167+
argumentsList.length > 0 ? argumentsList[0].path : "Argument[this]",
168+
};
169+
},
148170
};

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

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,11 @@ export interface Method extends MethodSignature {
6161
readonly usages: readonly Usage[];
6262
}
6363

64+
export interface MethodArgument {
65+
path: string;
66+
label: string;
67+
}
68+
6469
export function getArgumentsList(methodParameters: string): string[] {
6570
if (methodParameters === "()") {
6671
return [];

extensions/ql-vscode/src/view/method-modeling/MethodModelingInputs.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ export const MethodModelingInputs = ({
3939
onChange,
4040
}: MethodModelingInputsProps): JSX.Element => {
4141
const inputProps = {
42+
language,
4243
method,
4344
modeledMethod,
4445
onChange,
@@ -82,7 +83,7 @@ export const MethodModelingInputs = ({
8283
{isModelingInProgress ? (
8384
<InProgressDropdown />
8485
) : (
85-
<ModelKindDropdown language={language} {...inputProps} />
86+
<ModelKindDropdown {...inputProps} />
8687
)}
8788
</Input>
8889
</Container>

extensions/ql-vscode/src/view/model-editor/MethodRow.tsx

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -234,20 +234,23 @@ const ModelableMethodRow = forwardRef<HTMLElement | undefined, MethodRowProps>(
234234
<DataGridRow key={index} focused={focusedIndex === index}>
235235
<DataGridCell>
236236
<ModelTypeDropdown
237+
language={viewState.language}
237238
method={method}
238239
modeledMethod={modeledMethod}
239240
onChange={modeledMethodChangedHandlers[index]}
240241
/>
241242
</DataGridCell>
242243
<DataGridCell>
243244
<ModelInputDropdown
245+
language={viewState.language}
244246
method={method}
245247
modeledMethod={modeledMethod}
246248
onChange={modeledMethodChangedHandlers[index]}
247249
/>
248250
</DataGridCell>
249251
<DataGridCell>
250252
<ModelOutputDropdown
253+
language={viewState.language}
251254
method={method}
252255
modeledMethod={modeledMethod}
253256
onChange={modeledMethodChangedHandlers[index]}

extensions/ql-vscode/src/view/model-editor/ModelInputDropdown.tsx

Lines changed: 14 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -5,34 +5,33 @@ import {
55
ModeledMethod,
66
modeledMethodSupportsInput,
77
} from "../../model-editor/modeled-method";
8-
import { Method, getArgumentsList } from "../../model-editor/method";
8+
import { Method } from "../../model-editor/method";
9+
import { QueryLanguage } from "../../common/query-language";
10+
import { getModelsAsDataLanguage } from "../../model-editor/languages";
911

1012
type Props = {
13+
language: QueryLanguage;
1114
method: Method;
1215
modeledMethod: ModeledMethod | undefined;
1316
onChange: (modeledMethod: ModeledMethod) => void;
1417
};
1518

1619
export const ModelInputDropdown = ({
20+
language,
1721
method,
1822
modeledMethod,
1923
onChange,
2024
}: Props): JSX.Element => {
21-
const argumentsList = useMemo(
22-
() => getArgumentsList(method.methodParameters),
23-
[method.methodParameters],
24-
);
25+
const options = useMemo(() => {
26+
const modelsAsDataLanguage = getModelsAsDataLanguage(language);
2527

26-
const options = useMemo(
27-
() => [
28-
{ value: "Argument[this]", label: "Argument[this]" },
29-
...argumentsList.map((argument, index) => ({
30-
value: `Argument[${index}]`,
31-
label: `Argument[${index}]: ${argument}`,
32-
})),
33-
],
34-
[argumentsList],
35-
);
28+
return modelsAsDataLanguage
29+
.getArgumentOptions(method)
30+
.options.map((option) => ({
31+
value: option.path,
32+
label: option.label,
33+
}));
34+
}, [language, method]);
3635

3736
const enabled = useMemo(
3837
() => modeledMethod && modeledMethodSupportsInput(modeledMethod),

extensions/ql-vscode/src/view/model-editor/ModelOutputDropdown.tsx

Lines changed: 15 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -5,35 +5,34 @@ import {
55
ModeledMethod,
66
modeledMethodSupportsOutput,
77
} from "../../model-editor/modeled-method";
8-
import { Method, getArgumentsList } from "../../model-editor/method";
8+
import { Method } from "../../model-editor/method";
9+
import { getModelsAsDataLanguage } from "../../model-editor/languages";
10+
import { QueryLanguage } from "../../common/query-language";
911

1012
type Props = {
13+
language: QueryLanguage;
1114
method: Method;
1215
modeledMethod: ModeledMethod | undefined;
1316
onChange: (modeledMethod: ModeledMethod) => void;
1417
};
1518

1619
export const ModelOutputDropdown = ({
20+
language,
1721
method,
1822
modeledMethod,
1923
onChange,
2024
}: Props): JSX.Element => {
21-
const argumentsList = useMemo(
22-
() => getArgumentsList(method.methodParameters),
23-
[method.methodParameters],
24-
);
25+
const options = useMemo(() => {
26+
const modelsAsDataLanguage = getModelsAsDataLanguage(language);
2527

26-
const options = useMemo(
27-
() => [
28-
{ value: "ReturnValue", label: "ReturnValue" },
29-
{ value: "Argument[this]", label: "Argument[this]" },
30-
...argumentsList.map((argument, index) => ({
31-
value: `Argument[${index}]`,
32-
label: `Argument[${index}]: ${argument}`,
33-
})),
34-
],
35-
[argumentsList],
36-
);
28+
const options = modelsAsDataLanguage
29+
.getArgumentOptions(method)
30+
.options.map((option) => ({
31+
value: option.path,
32+
label: option.label,
33+
}));
34+
return [{ value: "ReturnValue", label: "ReturnValue" }, ...options];
35+
}, [language, method]);
3736

3837
const enabled = useMemo(
3938
() => modeledMethod && modeledMethodSupportsOutput(modeledMethod),

extensions/ql-vscode/src/view/model-editor/ModelTypeDropdown.tsx

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,17 @@
11
import * as React from "react";
2-
import { ChangeEvent, useCallback, useMemo } from "react";
2+
import { ChangeEvent, useCallback } from "react";
33
import { Dropdown } from "../common/Dropdown";
44
import {
55
ModeledMethod,
66
modeledMethodSupportsProvenance,
77
ModeledMethodType,
88
Provenance,
99
} from "../../model-editor/modeled-method";
10-
import { Method, getArgumentsList } from "../../model-editor/method";
10+
import { Method } from "../../model-editor/method";
1111
import { createEmptyModeledMethod } from "../../model-editor/modeled-method-empty";
1212
import { Mutable } from "../../common/mutable";
13+
import { QueryLanguage } from "../../common/query-language";
14+
import { getModelsAsDataLanguage } from "../../model-editor/languages";
1315

1416
const options: Array<{ value: ModeledMethodType; label: string }> = [
1517
{ value: "none", label: "Unmodeled" },
@@ -20,23 +22,22 @@ const options: Array<{ value: ModeledMethodType; label: string }> = [
2022
];
2123

2224
type Props = {
25+
language: QueryLanguage;
2326
method: Method;
2427
modeledMethod: ModeledMethod | undefined;
2528
onChange: (modeledMethod: ModeledMethod) => void;
2629
};
2730

2831
export const ModelTypeDropdown = ({
32+
language,
2933
method,
3034
modeledMethod,
3135
onChange,
3236
}: Props): JSX.Element => {
33-
const argumentsList = useMemo(
34-
() => getArgumentsList(method.methodParameters),
35-
[method.methodParameters],
36-
);
37-
3837
const handleChange = useCallback(
3938
(e: ChangeEvent<HTMLSelectElement>) => {
39+
const modelsAsDataLanguage = getModelsAsDataLanguage(language);
40+
4041
let newProvenance: Provenance = "manual";
4142
if (modeledMethod && modeledMethodSupportsProvenance(modeledMethod)) {
4243
if (modeledMethod.provenance === "df-generated") {
@@ -54,9 +55,8 @@ export const ModelTypeDropdown = ({
5455
...emptyModeledMethod,
5556
};
5657
if ("input" in updatedModeledMethod) {
57-
// If there are no arguments, we will default to "Argument[this]"
5858
updatedModeledMethod.input =
59-
argumentsList.length === 0 ? "Argument[this]" : "Argument[0]";
59+
modelsAsDataLanguage.getArgumentOptions(method).defaultArgumentPath;
6060
}
6161
if ("output" in updatedModeledMethod) {
6262
updatedModeledMethod.output = "ReturnValue";
@@ -70,7 +70,7 @@ export const ModelTypeDropdown = ({
7070

7171
onChange(updatedModeledMethod);
7272
},
73-
[onChange, method, modeledMethod, argumentsList],
73+
[onChange, method, modeledMethod, language],
7474
);
7575

7676
return (

0 commit comments

Comments
 (0)