Merge pull request #3052 from github/koesie10/argument-self

Extract creation of method argument options to languages
This commit is contained in:
Koen Vlaswinkel
2023-11-06 10:59:20 +01:00
committed by GitHub
9 changed files with 104 additions and 43 deletions

View File

@@ -1,4 +1,4 @@
import { MethodDefinition } from "../method";
import { MethodArgument, MethodDefinition } from "../method";
import {
ModeledMethod,
NeutralModeledMethod,
@@ -45,6 +45,11 @@ export type ModelsAsDataLanguagePredicates = {
neutral?: ModelsAsDataLanguagePredicate<NeutralModeledMethod>;
};
export type MethodArgumentOptions = {
options: MethodArgument[];
defaultArgumentPath: string;
};
export type ModelsAsDataLanguage = {
/**
* The modes that are available for this language. If not specified, all
@@ -54,4 +59,9 @@ export type ModelsAsDataLanguage = {
createMethodSignature: (method: MethodDefinition) => string;
predicates: ModelsAsDataLanguagePredicates;
modelGeneration?: ModelsAsDataLanguageModelGeneration;
/**
* Returns the list of valid arguments that can be selected for the given method.
* @param method The method to get the valid arguments for.
*/
getArgumentOptions: (method: MethodDefinition) => MethodArgumentOptions;
};

View File

@@ -2,6 +2,7 @@ import { ModelsAsDataLanguage } from "../models-as-data";
import { sharedExtensiblePredicates, sharedKinds } from "../shared";
import { Mode } from "../../shared/mode";
import { parseGenerateModelResults } from "./generate";
import { getArgumentsList, MethodArgument } from "../../method";
function parseRubyMethodFromPath(path: string): string {
const match = path.match(/Method\[([^\]]+)].*/);
@@ -157,4 +158,25 @@ export const ruby: ModelsAsDataLanguage = {
},
parseResults: parseGenerateModelResults,
},
getArgumentOptions: (method) => {
const argumentsList = getArgumentsList(method.methodParameters).map(
(argument, index): MethodArgument => ({
path: `Argument[${index}]`,
label: `Argument[${index}]: ${argument}`,
}),
);
return {
options: [
{
path: "Argument[self]",
label: "Argument[self]",
},
...argumentsList,
],
// If there are no arguments, we will default to "Argument[self]"
defaultArgumentPath:
argumentsList.length > 0 ? argumentsList[0].path : "Argument[self]",
};
},
};

View File

@@ -3,6 +3,7 @@ import { Provenance } from "../../modeled-method";
import { DataTuple } from "../../model-extension-file";
import { sharedExtensiblePredicates, sharedKinds } from "../shared";
import { filterFlowModelQueries, parseFlowModelResults } from "./generate";
import { getArgumentsList, MethodArgument } from "../../method";
function readRowToMethod(row: DataTuple[]): string {
return `${row[0]}.${row[1]}#${row[3]}${row[4]}`;
@@ -145,4 +146,25 @@ export const staticLanguage: ModelsAsDataLanguage = {
filterQueries: filterFlowModelQueries,
parseResults: parseFlowModelResults,
},
getArgumentOptions: (method) => {
const argumentsList = getArgumentsList(method.methodParameters).map(
(argument, index): MethodArgument => ({
path: `Argument[${index}]`,
label: `Argument[${index}]: ${argument}`,
}),
);
return {
options: [
{
path: "Argument[this]",
label: "Argument[this]",
},
...argumentsList,
],
// If there are no arguments, we will default to "Argument[this]"
defaultArgumentPath:
argumentsList.length > 0 ? argumentsList[0].path : "Argument[this]",
};
},
};

View File

@@ -61,6 +61,11 @@ export interface Method extends MethodSignature {
readonly usages: readonly Usage[];
}
export interface MethodArgument {
path: string;
label: string;
}
export function getArgumentsList(methodParameters: string): string[] {
if (methodParameters === "()") {
return [];

View File

@@ -39,6 +39,7 @@ export const MethodModelingInputs = ({
onChange,
}: MethodModelingInputsProps): JSX.Element => {
const inputProps = {
language,
method,
modeledMethod,
onChange,
@@ -82,7 +83,7 @@ export const MethodModelingInputs = ({
{isModelingInProgress ? (
<InProgressDropdown />
) : (
<ModelKindDropdown language={language} {...inputProps} />
<ModelKindDropdown {...inputProps} />
)}
</Input>
</Container>

View File

@@ -234,6 +234,7 @@ const ModelableMethodRow = forwardRef<HTMLElement | undefined, MethodRowProps>(
<DataGridRow key={index} focused={focusedIndex === index}>
<DataGridCell>
<ModelTypeDropdown
language={viewState.language}
method={method}
modeledMethod={modeledMethod}
onChange={modeledMethodChangedHandlers[index]}
@@ -241,6 +242,7 @@ const ModelableMethodRow = forwardRef<HTMLElement | undefined, MethodRowProps>(
</DataGridCell>
<DataGridCell>
<ModelInputDropdown
language={viewState.language}
method={method}
modeledMethod={modeledMethod}
onChange={modeledMethodChangedHandlers[index]}
@@ -248,6 +250,7 @@ const ModelableMethodRow = forwardRef<HTMLElement | undefined, MethodRowProps>(
</DataGridCell>
<DataGridCell>
<ModelOutputDropdown
language={viewState.language}
method={method}
modeledMethod={modeledMethod}
onChange={modeledMethodChangedHandlers[index]}

View File

@@ -5,34 +5,33 @@ import {
ModeledMethod,
modeledMethodSupportsInput,
} from "../../model-editor/modeled-method";
import { Method, getArgumentsList } from "../../model-editor/method";
import { Method } from "../../model-editor/method";
import { QueryLanguage } from "../../common/query-language";
import { getModelsAsDataLanguage } from "../../model-editor/languages";
type Props = {
language: QueryLanguage;
method: Method;
modeledMethod: ModeledMethod | undefined;
onChange: (modeledMethod: ModeledMethod) => void;
};
export const ModelInputDropdown = ({
language,
method,
modeledMethod,
onChange,
}: Props): JSX.Element => {
const argumentsList = useMemo(
() => getArgumentsList(method.methodParameters),
[method.methodParameters],
);
const options = useMemo(() => {
const modelsAsDataLanguage = getModelsAsDataLanguage(language);
const options = useMemo(
() => [
{ value: "Argument[this]", label: "Argument[this]" },
...argumentsList.map((argument, index) => ({
value: `Argument[${index}]`,
label: `Argument[${index}]: ${argument}`,
})),
],
[argumentsList],
);
return modelsAsDataLanguage
.getArgumentOptions(method)
.options.map((option) => ({
value: option.path,
label: option.label,
}));
}, [language, method]);
const enabled = useMemo(
() => modeledMethod && modeledMethodSupportsInput(modeledMethod),

View File

@@ -5,35 +5,34 @@ import {
ModeledMethod,
modeledMethodSupportsOutput,
} from "../../model-editor/modeled-method";
import { Method, getArgumentsList } from "../../model-editor/method";
import { Method } from "../../model-editor/method";
import { getModelsAsDataLanguage } from "../../model-editor/languages";
import { QueryLanguage } from "../../common/query-language";
type Props = {
language: QueryLanguage;
method: Method;
modeledMethod: ModeledMethod | undefined;
onChange: (modeledMethod: ModeledMethod) => void;
};
export const ModelOutputDropdown = ({
language,
method,
modeledMethod,
onChange,
}: Props): JSX.Element => {
const argumentsList = useMemo(
() => getArgumentsList(method.methodParameters),
[method.methodParameters],
);
const options = useMemo(() => {
const modelsAsDataLanguage = getModelsAsDataLanguage(language);
const options = useMemo(
() => [
{ value: "ReturnValue", label: "ReturnValue" },
{ value: "Argument[this]", label: "Argument[this]" },
...argumentsList.map((argument, index) => ({
value: `Argument[${index}]`,
label: `Argument[${index}]: ${argument}`,
})),
],
[argumentsList],
);
const options = modelsAsDataLanguage
.getArgumentOptions(method)
.options.map((option) => ({
value: option.path,
label: option.label,
}));
return [{ value: "ReturnValue", label: "ReturnValue" }, ...options];
}, [language, method]);
const enabled = useMemo(
() => modeledMethod && modeledMethodSupportsOutput(modeledMethod),

View File

@@ -1,5 +1,5 @@
import * as React from "react";
import { ChangeEvent, useCallback, useMemo } from "react";
import { ChangeEvent, useCallback } from "react";
import { Dropdown } from "../common/Dropdown";
import {
ModeledMethod,
@@ -7,9 +7,11 @@ import {
ModeledMethodType,
Provenance,
} from "../../model-editor/modeled-method";
import { Method, getArgumentsList } from "../../model-editor/method";
import { Method } from "../../model-editor/method";
import { createEmptyModeledMethod } from "../../model-editor/modeled-method-empty";
import { Mutable } from "../../common/mutable";
import { QueryLanguage } from "../../common/query-language";
import { getModelsAsDataLanguage } from "../../model-editor/languages";
const options: Array<{ value: ModeledMethodType; label: string }> = [
{ value: "none", label: "Unmodeled" },
@@ -20,23 +22,22 @@ const options: Array<{ value: ModeledMethodType; label: string }> = [
];
type Props = {
language: QueryLanguage;
method: Method;
modeledMethod: ModeledMethod | undefined;
onChange: (modeledMethod: ModeledMethod) => void;
};
export const ModelTypeDropdown = ({
language,
method,
modeledMethod,
onChange,
}: Props): JSX.Element => {
const argumentsList = useMemo(
() => getArgumentsList(method.methodParameters),
[method.methodParameters],
);
const handleChange = useCallback(
(e: ChangeEvent<HTMLSelectElement>) => {
const modelsAsDataLanguage = getModelsAsDataLanguage(language);
let newProvenance: Provenance = "manual";
if (modeledMethod && modeledMethodSupportsProvenance(modeledMethod)) {
if (modeledMethod.provenance === "df-generated") {
@@ -54,9 +55,8 @@ export const ModelTypeDropdown = ({
...emptyModeledMethod,
};
if ("input" in updatedModeledMethod) {
// If there are no arguments, we will default to "Argument[this]"
updatedModeledMethod.input =
argumentsList.length === 0 ? "Argument[this]" : "Argument[0]";
modelsAsDataLanguage.getArgumentOptions(method).defaultArgumentPath;
}
if ("output" in updatedModeledMethod) {
updatedModeledMethod.output = "ReturnValue";
@@ -70,7 +70,7 @@ export const ModelTypeDropdown = ({
onChange(updatedModeledMethod);
},
[onChange, method, modeledMethod, argumentsList],
[onChange, method, modeledMethod, language],
);
return (