chore: CE changes for module input autocomplete (#28221)
This commit is contained in:
parent
cc01f7b1c9
commit
68df2a18a6
|
|
@ -12,7 +12,7 @@ import moment from "moment";
|
||||||
import type { DerivedPropertiesMap } from "WidgetProvider/factory";
|
import type { DerivedPropertiesMap } from "WidgetProvider/factory";
|
||||||
import type { WidgetFeatures } from "utils/WidgetFeatures";
|
import type { WidgetFeatures } from "utils/WidgetFeatures";
|
||||||
import type { WidgetProps } from "../widgets/BaseWidget";
|
import type { WidgetProps } from "../widgets/BaseWidget";
|
||||||
import type { ExtraDef } from "utils/autocomplete/dataTreeTypeDefCreator";
|
import type { ExtraDef } from "utils/autocomplete/defCreatorUtils";
|
||||||
import type { WidgetEntityConfig } from "@appsmith/entities/DataTree/types";
|
import type { WidgetEntityConfig } from "@appsmith/entities/DataTree/types";
|
||||||
import type {
|
import type {
|
||||||
WidgetQueryConfig,
|
WidgetQueryConfig,
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
import type { ExtraDef } from "utils/autocomplete/dataTreeTypeDefCreator";
|
import type { ExtraDef } from "utils/autocomplete/defCreatorUtils";
|
||||||
import { generateTypeDef } from "utils/autocomplete/dataTreeTypeDefCreator";
|
import { generateTypeDef } from "utils/autocomplete/defCreatorUtils";
|
||||||
import type { AppsmithEntity } from "@appsmith/entities/DataTree/types";
|
import type { AppsmithEntity } from "@appsmith/entities/DataTree/types";
|
||||||
import _ from "lodash";
|
import _ from "lodash";
|
||||||
import { EVALUATION_PATH } from "utils/DynamicBindingUtils";
|
import { EVALUATION_PATH } from "utils/DynamicBindingUtils";
|
||||||
|
|
|
||||||
140
app/client/src/ce/utils/autocomplete/entityDefGeneratorMap.ts
Normal file
140
app/client/src/ce/utils/autocomplete/entityDefGeneratorMap.ts
Normal file
|
|
@ -0,0 +1,140 @@
|
||||||
|
import {
|
||||||
|
type WidgetEntityConfig,
|
||||||
|
type JSActionEntityConfig,
|
||||||
|
type WidgetEntity,
|
||||||
|
type ActionEntity,
|
||||||
|
type AppsmithEntity,
|
||||||
|
type JSActionEntity,
|
||||||
|
ENTITY_TYPE_VALUE,
|
||||||
|
} from "@appsmith/entities/DataTree/types";
|
||||||
|
import type {
|
||||||
|
ConfigTree,
|
||||||
|
DataTreeEntity,
|
||||||
|
} from "entities/DataTree/dataTreeTypes";
|
||||||
|
import { isFunction } from "lodash";
|
||||||
|
import { entityDefinitions } from "@appsmith/utils/autocomplete/EntityDefinitions";
|
||||||
|
import type { Def } from "tern";
|
||||||
|
import type { DataTreeDefEntityInformation } from "utils/autocomplete/CodemirrorTernService";
|
||||||
|
import WidgetFactory from "WidgetProvider/factory";
|
||||||
|
import {
|
||||||
|
addSettersToDefinitions,
|
||||||
|
generateJSFunctionTypeDef,
|
||||||
|
generateTypeDef,
|
||||||
|
flattenDef,
|
||||||
|
} from "utils/autocomplete/defCreatorUtils";
|
||||||
|
|
||||||
|
export type EntityMap = Map<string, DataTreeDefEntityInformation>;
|
||||||
|
|
||||||
|
interface DefGeneratorProps {
|
||||||
|
entity: DataTreeEntity;
|
||||||
|
configTree: ConfigTree;
|
||||||
|
entityName: string;
|
||||||
|
extraDefsToDefine: Def;
|
||||||
|
entityMap: EntityMap;
|
||||||
|
def: Def;
|
||||||
|
jsData: Record<string, unknown>;
|
||||||
|
}
|
||||||
|
|
||||||
|
export type EntityDefGeneratorMap = Record<
|
||||||
|
string,
|
||||||
|
(props: DefGeneratorProps) => void
|
||||||
|
>;
|
||||||
|
|
||||||
|
export const entityDefGeneratorMap: EntityDefGeneratorMap = {
|
||||||
|
[ENTITY_TYPE_VALUE.ACTION]: (props) => {
|
||||||
|
const { def, entity, entityMap, entityName, extraDefsToDefine } = props;
|
||||||
|
def[entityName] = entityDefinitions.ACTION(
|
||||||
|
entity as ActionEntity,
|
||||||
|
extraDefsToDefine,
|
||||||
|
);
|
||||||
|
flattenDef(def, entityName);
|
||||||
|
entityMap.set(entityName, {
|
||||||
|
type: ENTITY_TYPE_VALUE.ACTION,
|
||||||
|
subType: "ACTION",
|
||||||
|
});
|
||||||
|
},
|
||||||
|
[ENTITY_TYPE_VALUE.APPSMITH]: (props) => {
|
||||||
|
const { def, entity, entityMap, extraDefsToDefine } = props;
|
||||||
|
def.appsmith = entityDefinitions.APPSMITH(
|
||||||
|
entity as AppsmithEntity,
|
||||||
|
extraDefsToDefine,
|
||||||
|
);
|
||||||
|
entityMap.set("appsmith", {
|
||||||
|
type: ENTITY_TYPE_VALUE.APPSMITH,
|
||||||
|
subType: ENTITY_TYPE_VALUE.APPSMITH,
|
||||||
|
});
|
||||||
|
},
|
||||||
|
[ENTITY_TYPE_VALUE.JSACTION]: (props) => {
|
||||||
|
const {
|
||||||
|
configTree,
|
||||||
|
def,
|
||||||
|
entity,
|
||||||
|
entityMap,
|
||||||
|
entityName,
|
||||||
|
extraDefsToDefine,
|
||||||
|
jsData,
|
||||||
|
} = props;
|
||||||
|
const entityConfig = configTree[entityName] as JSActionEntityConfig;
|
||||||
|
const metaObj = entityConfig.meta;
|
||||||
|
const jsPropertiesDef: Def = {};
|
||||||
|
|
||||||
|
for (const funcName in metaObj) {
|
||||||
|
const funcTypeDef = generateJSFunctionTypeDef(
|
||||||
|
jsData,
|
||||||
|
`${entityName}.${funcName}`,
|
||||||
|
extraDefsToDefine,
|
||||||
|
);
|
||||||
|
jsPropertiesDef[funcName] = funcTypeDef;
|
||||||
|
// To also show funcName.data in autocompletion hint, we explictly add it here
|
||||||
|
jsPropertiesDef[`${funcName}.data`] = funcTypeDef.data;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (let i = 0; i < entityConfig?.variables?.length; i++) {
|
||||||
|
const varKey = entityConfig?.variables[i];
|
||||||
|
const varValue = (entity as JSActionEntity)[varKey];
|
||||||
|
jsPropertiesDef[varKey] = generateTypeDef(varValue, extraDefsToDefine);
|
||||||
|
}
|
||||||
|
|
||||||
|
def[entityName] = jsPropertiesDef;
|
||||||
|
entityMap.set(entityName, {
|
||||||
|
type: ENTITY_TYPE_VALUE.JSACTION,
|
||||||
|
subType: "JSACTION",
|
||||||
|
});
|
||||||
|
},
|
||||||
|
[ENTITY_TYPE_VALUE.WIDGET]: (props) => {
|
||||||
|
const {
|
||||||
|
configTree,
|
||||||
|
def,
|
||||||
|
entity,
|
||||||
|
entityMap,
|
||||||
|
entityName,
|
||||||
|
extraDefsToDefine,
|
||||||
|
} = props;
|
||||||
|
const widgetType = (entity as WidgetEntity).type;
|
||||||
|
const autocompleteDefinitions =
|
||||||
|
WidgetFactory.getAutocompleteDefinitions(widgetType);
|
||||||
|
|
||||||
|
if (autocompleteDefinitions) {
|
||||||
|
const entityConfig = configTree[entityName] as WidgetEntityConfig;
|
||||||
|
|
||||||
|
if (isFunction(autocompleteDefinitions)) {
|
||||||
|
def[entityName] = autocompleteDefinitions(
|
||||||
|
entity as WidgetEntity,
|
||||||
|
extraDefsToDefine,
|
||||||
|
entityConfig,
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
def[entityName] = autocompleteDefinitions;
|
||||||
|
}
|
||||||
|
|
||||||
|
addSettersToDefinitions(def[entityName] as Def, entity, entityConfig);
|
||||||
|
|
||||||
|
flattenDef(def, entityName);
|
||||||
|
|
||||||
|
entityMap.set(entityName, {
|
||||||
|
type: ENTITY_TYPE_VALUE.WIDGET,
|
||||||
|
subType: widgetType,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
@ -0,0 +1 @@
|
||||||
|
export * from "ce/utils/autocomplete/entityDefGeneratorMap";
|
||||||
|
|
@ -7,7 +7,7 @@ import type { EntityDefinitionsOptions } from "@appsmith/utils/autocomplete/Enti
|
||||||
import { isFunction } from "lodash";
|
import { isFunction } from "lodash";
|
||||||
import type { Def } from "tern";
|
import type { Def } from "tern";
|
||||||
import WidgetFactory from "WidgetProvider/factory";
|
import WidgetFactory from "WidgetProvider/factory";
|
||||||
import { addSettersToDefinitions } from "utils/autocomplete/dataTreeTypeDefCreator";
|
import { addSettersToDefinitions } from "utils/autocomplete/defCreatorUtils";
|
||||||
|
|
||||||
export const getWidgetChildrenPeekData = (
|
export const getWidgetChildrenPeekData = (
|
||||||
widgetName: string,
|
widgetName: string,
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
import type { Def } from "tern";
|
import type { Def } from "tern";
|
||||||
import type { TruthyPrimitiveTypes } from "utils/TypeHelpers";
|
import type { TruthyPrimitiveTypes } from "utils/TypeHelpers";
|
||||||
import { generateTypeDef } from "./dataTreeTypeDefCreator";
|
import { generateTypeDef } from "./defCreatorUtils";
|
||||||
|
|
||||||
export type AdditionalDynamicDataTree = Record<
|
export type AdditionalDynamicDataTree = Record<
|
||||||
string,
|
string,
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,4 @@
|
||||||
import {
|
import { dataTreeTypeDefCreator } from "utils/autocomplete/dataTreeTypeDefCreator";
|
||||||
generateTypeDef,
|
|
||||||
dataTreeTypeDefCreator,
|
|
||||||
flattenDef,
|
|
||||||
getFunctionsArgsType,
|
|
||||||
} from "utils/autocomplete/dataTreeTypeDefCreator";
|
|
||||||
import type {
|
import type {
|
||||||
WidgetEntity,
|
WidgetEntity,
|
||||||
WidgetEntityConfig,
|
WidgetEntityConfig,
|
||||||
|
|
@ -15,6 +10,11 @@ import {
|
||||||
|
|
||||||
import InputWidget from "widgets/InputWidgetV2";
|
import InputWidget from "widgets/InputWidgetV2";
|
||||||
import { registerWidgets } from "WidgetProvider/factory/registrationHelper";
|
import { registerWidgets } from "WidgetProvider/factory/registrationHelper";
|
||||||
|
import {
|
||||||
|
flattenDef,
|
||||||
|
generateTypeDef,
|
||||||
|
getFunctionsArgsType,
|
||||||
|
} from "./defCreatorUtils";
|
||||||
|
|
||||||
describe("dataTreeTypeDefCreator", () => {
|
describe("dataTreeTypeDefCreator", () => {
|
||||||
it("creates the right def for a widget", () => {
|
it("creates the right def for a widget", () => {
|
||||||
|
|
|
||||||
|
|
@ -1,32 +1,8 @@
|
||||||
import type {
|
import type { DataTreeEntityObject } from "@appsmith/entities/DataTree/types";
|
||||||
WidgetEntityConfig,
|
import type { EntityMap } from "@appsmith/utils/autocomplete/entityDefGeneratorMap";
|
||||||
JSActionEntityConfig,
|
import { entityDefGeneratorMap } from "@appsmith/utils/autocomplete/entityDefGeneratorMap";
|
||||||
WidgetEntity,
|
import type { ConfigTree, DataTree } from "entities/DataTree/dataTreeTypes";
|
||||||
} from "@appsmith/entities/DataTree/types";
|
|
||||||
import type {
|
|
||||||
ConfigTree,
|
|
||||||
DataTree,
|
|
||||||
DataTreeEntity,
|
|
||||||
} from "entities/DataTree/dataTreeTypes";
|
|
||||||
import { ENTITY_TYPE_VALUE } from "entities/DataTree/dataTreeFactory";
|
|
||||||
import { uniqueId, isFunction, isObject } from "lodash";
|
|
||||||
import { entityDefinitions } from "@appsmith/utils/autocomplete/EntityDefinitions";
|
|
||||||
import { getType, Types } from "utils/TypeHelpers";
|
|
||||||
import type { Def } from "tern";
|
import type { Def } from "tern";
|
||||||
import {
|
|
||||||
isAction,
|
|
||||||
isAppsmithEntity,
|
|
||||||
isJSAction,
|
|
||||||
isTrueObject,
|
|
||||||
isWidget,
|
|
||||||
} from "@appsmith/workers/Evaluation/evaluationUtils";
|
|
||||||
import type { DataTreeDefEntityInformation } from "utils/autocomplete/CodemirrorTernService";
|
|
||||||
|
|
||||||
export type ExtraDef = Record<string, Def | string>;
|
|
||||||
|
|
||||||
import type { Variable } from "entities/JSCollection";
|
|
||||||
import WidgetFactory from "WidgetProvider/factory";
|
|
||||||
import { shouldAddSetter } from "workers/Evaluation/evaluate";
|
|
||||||
|
|
||||||
// Def names are encoded with information about the entity
|
// Def names are encoded with information about the entity
|
||||||
// This so that we have more info about them
|
// This so that we have more info about them
|
||||||
|
|
@ -38,82 +14,26 @@ export const dataTreeTypeDefCreator = (
|
||||||
dataTree: DataTree,
|
dataTree: DataTree,
|
||||||
jsData: Record<string, unknown> = {},
|
jsData: Record<string, unknown> = {},
|
||||||
configTree: ConfigTree,
|
configTree: ConfigTree,
|
||||||
): { def: Def; entityInfo: Map<string, DataTreeDefEntityInformation> } => {
|
): { def: Def; entityInfo: EntityMap } => {
|
||||||
// When there is a complex data type, we store it in extra def and refer to it in the def
|
// When there is a complex data type, we store it in extra def and refer to it in the def
|
||||||
const extraDefsToDefine: Def = {};
|
const extraDefsToDefine: Def = {};
|
||||||
|
|
||||||
const def: Def = {
|
const def: Def = {
|
||||||
"!name": "DATA_TREE",
|
"!name": "DATA_TREE",
|
||||||
};
|
};
|
||||||
const entityMap: Map<string, DataTreeDefEntityInformation> = new Map();
|
const entityMap: EntityMap = new Map();
|
||||||
|
|
||||||
Object.entries(dataTree).forEach(([entityName, entity]) => {
|
Object.entries(dataTree).forEach(([entityName, entity]) => {
|
||||||
if (isWidget(entity)) {
|
const entityType = (entity as DataTreeEntityObject).ENTITY_TYPE;
|
||||||
const widgetType = entity.type;
|
if (entityType && entityDefGeneratorMap[entityType]) {
|
||||||
const autocompleteDefinitions =
|
entityDefGeneratorMap[entityType]({
|
||||||
WidgetFactory.getAutocompleteDefinitions(widgetType);
|
entity,
|
||||||
|
configTree,
|
||||||
if (autocompleteDefinitions) {
|
entityName,
|
||||||
const entityConfig = configTree[entityName] as WidgetEntityConfig;
|
|
||||||
|
|
||||||
if (isFunction(autocompleteDefinitions)) {
|
|
||||||
def[entityName] = autocompleteDefinitions(
|
|
||||||
entity as WidgetEntity,
|
|
||||||
extraDefsToDefine,
|
extraDefsToDefine,
|
||||||
entityConfig,
|
entityMap,
|
||||||
);
|
def,
|
||||||
} else {
|
|
||||||
def[entityName] = autocompleteDefinitions;
|
|
||||||
}
|
|
||||||
|
|
||||||
addSettersToDefinitions(def[entityName] as Def, entity, entityConfig);
|
|
||||||
|
|
||||||
flattenDef(def, entityName);
|
|
||||||
|
|
||||||
entityMap.set(entityName, {
|
|
||||||
type: ENTITY_TYPE_VALUE.WIDGET,
|
|
||||||
subType: widgetType,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
} else if (isAction(entity)) {
|
|
||||||
def[entityName] = entityDefinitions.ACTION(entity, extraDefsToDefine);
|
|
||||||
flattenDef(def, entityName);
|
|
||||||
entityMap.set(entityName, {
|
|
||||||
type: ENTITY_TYPE_VALUE.ACTION,
|
|
||||||
subType: "ACTION",
|
|
||||||
});
|
|
||||||
} else if (isAppsmithEntity(entity)) {
|
|
||||||
def.appsmith = entityDefinitions.APPSMITH(entity, extraDefsToDefine);
|
|
||||||
entityMap.set("appsmith", {
|
|
||||||
type: ENTITY_TYPE_VALUE.APPSMITH,
|
|
||||||
subType: ENTITY_TYPE_VALUE.APPSMITH,
|
|
||||||
});
|
|
||||||
} else if (isJSAction(entity)) {
|
|
||||||
const entityConfig = configTree[entityName] as JSActionEntityConfig;
|
|
||||||
const metaObj = entityConfig.meta;
|
|
||||||
const jsPropertiesDef: Def = {};
|
|
||||||
|
|
||||||
for (const funcName in metaObj) {
|
|
||||||
const funcTypeDef = generateJSFunctionTypeDef(
|
|
||||||
jsData,
|
jsData,
|
||||||
`${entityName}.${funcName}`,
|
|
||||||
extraDefsToDefine,
|
|
||||||
);
|
|
||||||
jsPropertiesDef[funcName] = funcTypeDef;
|
|
||||||
// To also show funcName.data in autocompletion hint, we explictly add it here
|
|
||||||
jsPropertiesDef[`${funcName}.data`] = funcTypeDef.data;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (let i = 0; i < entityConfig?.variables?.length; i++) {
|
|
||||||
const varKey = entityConfig?.variables[i];
|
|
||||||
const varValue = entity[varKey];
|
|
||||||
jsPropertiesDef[varKey] = generateTypeDef(varValue, extraDefsToDefine);
|
|
||||||
}
|
|
||||||
|
|
||||||
def[entityName] = jsPropertiesDef;
|
|
||||||
entityMap.set(entityName, {
|
|
||||||
type: ENTITY_TYPE_VALUE.JSACTION,
|
|
||||||
subType: "JSACTION",
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
@ -124,137 +44,3 @@ export const dataTreeTypeDefCreator = (
|
||||||
|
|
||||||
return { def, entityInfo: entityMap };
|
return { def, entityInfo: entityMap };
|
||||||
};
|
};
|
||||||
|
|
||||||
export function generateTypeDef(
|
|
||||||
value: unknown,
|
|
||||||
extraDefsToDefine?: ExtraDef,
|
|
||||||
depth = 0,
|
|
||||||
): Def | string {
|
|
||||||
switch (getType(value)) {
|
|
||||||
case Types.ARRAY: {
|
|
||||||
const array = value as [unknown];
|
|
||||||
if (depth > 5) {
|
|
||||||
return `[?]`;
|
|
||||||
}
|
|
||||||
|
|
||||||
const arrayElementType = generateTypeDef(
|
|
||||||
array[0],
|
|
||||||
extraDefsToDefine,
|
|
||||||
depth + 1,
|
|
||||||
);
|
|
||||||
|
|
||||||
if (isObject(arrayElementType)) {
|
|
||||||
if (extraDefsToDefine) {
|
|
||||||
const uniqueDefName = uniqueId("def_");
|
|
||||||
extraDefsToDefine[uniqueDefName] = arrayElementType;
|
|
||||||
return `[${uniqueDefName}]`;
|
|
||||||
}
|
|
||||||
return `[?]`;
|
|
||||||
}
|
|
||||||
return `[${arrayElementType}]`;
|
|
||||||
}
|
|
||||||
case Types.OBJECT: {
|
|
||||||
const objType: Def = {};
|
|
||||||
const object = value as Record<string, unknown>;
|
|
||||||
Object.keys(object).forEach((k) => {
|
|
||||||
objType[k] = generateTypeDef(object[k], extraDefsToDefine, depth);
|
|
||||||
});
|
|
||||||
return objType;
|
|
||||||
}
|
|
||||||
case Types.STRING:
|
|
||||||
return "string";
|
|
||||||
case Types.NUMBER:
|
|
||||||
return "number";
|
|
||||||
case Types.BOOLEAN:
|
|
||||||
return "bool";
|
|
||||||
case Types.NULL:
|
|
||||||
case Types.UNDEFINED:
|
|
||||||
return "?";
|
|
||||||
default:
|
|
||||||
return "?";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export const flattenDef = (def: Def, entityName: string): Def => {
|
|
||||||
const flattenedDef = def;
|
|
||||||
if (!isTrueObject(def[entityName])) return flattenedDef;
|
|
||||||
Object.entries(def[entityName]).forEach(([key, value]) => {
|
|
||||||
if (key.startsWith("!")) return;
|
|
||||||
const keyIsValid = isValidVariableName(key);
|
|
||||||
const parentCompletion = !keyIsValid
|
|
||||||
? `${entityName}["${key}"]`
|
|
||||||
: `${entityName}.${key}`;
|
|
||||||
flattenedDef[parentCompletion] = value;
|
|
||||||
if (!isTrueObject(value)) return;
|
|
||||||
Object.entries(value).forEach(([subKey, subValue]) => {
|
|
||||||
if (subKey.startsWith("!")) return;
|
|
||||||
const childKeyIsValid = isValidVariableName(subKey);
|
|
||||||
const childCompletion = !childKeyIsValid
|
|
||||||
? `${parentCompletion}["${subKey}"]`
|
|
||||||
: `${parentCompletion}.${subKey}`;
|
|
||||||
flattenedDef[childCompletion] = subValue;
|
|
||||||
});
|
|
||||||
});
|
|
||||||
return flattenedDef;
|
|
||||||
};
|
|
||||||
|
|
||||||
const VALID_VARIABLE_NAME_REGEX = /^([a-zA-Z_$][a-zA-Z\d_$]*)$/;
|
|
||||||
|
|
||||||
export const isValidVariableName = (variableName: string) =>
|
|
||||||
VALID_VARIABLE_NAME_REGEX.test(variableName);
|
|
||||||
|
|
||||||
export const getFunctionsArgsType = (args: Variable[]): string => {
|
|
||||||
// skip same name args to avoiding creating invalid type
|
|
||||||
const argNames = new Set<string>();
|
|
||||||
// skip invalid args name
|
|
||||||
args.forEach((arg) => {
|
|
||||||
if (arg.name && isValidVariableName(arg.name)) argNames.add(arg.name);
|
|
||||||
});
|
|
||||||
const argNamesArray = [...argNames];
|
|
||||||
const argsTypeString = argNamesArray.reduce(
|
|
||||||
(accumulatedArgType, argName, currentIndex) => {
|
|
||||||
switch (currentIndex) {
|
|
||||||
case 0:
|
|
||||||
return `${argName}: ?`;
|
|
||||||
case 1:
|
|
||||||
return `${accumulatedArgType}, ${argName}: ?`;
|
|
||||||
default:
|
|
||||||
return `${accumulatedArgType}, ${argName}: ?`;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
argNamesArray[0],
|
|
||||||
);
|
|
||||||
return argsTypeString ? `fn(${argsTypeString})` : `fn()`;
|
|
||||||
};
|
|
||||||
|
|
||||||
export function generateJSFunctionTypeDef(
|
|
||||||
jsData: Record<string, unknown> = {},
|
|
||||||
fullFunctionName: string,
|
|
||||||
extraDefs: ExtraDef,
|
|
||||||
) {
|
|
||||||
return {
|
|
||||||
"!type": getFunctionsArgsType([]),
|
|
||||||
data: generateTypeDef(jsData[fullFunctionName], extraDefs),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function addSettersToDefinitions(
|
|
||||||
definitions: Def,
|
|
||||||
entity: DataTreeEntity,
|
|
||||||
entityConfig?: WidgetEntityConfig,
|
|
||||||
) {
|
|
||||||
if (entityConfig && entityConfig.__setters) {
|
|
||||||
const setters = Object.keys(entityConfig.__setters);
|
|
||||||
|
|
||||||
setters.forEach((setterName: string) => {
|
|
||||||
const setter = entityConfig.__setters?.[setterName];
|
|
||||||
const setterType = entityConfig.__setters?.[setterName].type;
|
|
||||||
|
|
||||||
if (shouldAddSetter(setter, entity)) {
|
|
||||||
definitions[
|
|
||||||
setterName
|
|
||||||
] = `fn(value:${setterType}) -> +Promise[:t=[!0.<i>.:t]]`;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
||||||
144
app/client/src/utils/autocomplete/defCreatorUtils.ts
Normal file
144
app/client/src/utils/autocomplete/defCreatorUtils.ts
Normal file
|
|
@ -0,0 +1,144 @@
|
||||||
|
import { isTrueObject } from "@shared/ast/src/utils";
|
||||||
|
import type { WidgetEntityConfig } from "@appsmith/entities/DataTree/types";
|
||||||
|
import type { DataTreeEntity } from "entities/DataTree/dataTreeTypes";
|
||||||
|
import type { Variable } from "entities/JSCollection";
|
||||||
|
import { isObject, uniqueId } from "lodash";
|
||||||
|
import type { Def } from "tern";
|
||||||
|
import { Types, getType } from "utils/TypeHelpers";
|
||||||
|
import { shouldAddSetter } from "workers/Evaluation/evaluate";
|
||||||
|
|
||||||
|
export type ExtraDef = Record<string, Def | string>;
|
||||||
|
|
||||||
|
export const flattenDef = (def: Def, entityName: string): Def => {
|
||||||
|
const flattenedDef = def;
|
||||||
|
if (!isTrueObject(def[entityName])) return flattenedDef;
|
||||||
|
Object.entries(def[entityName]).forEach(([key, value]) => {
|
||||||
|
if (key.startsWith("!")) return;
|
||||||
|
const keyIsValid = isValidVariableName(key);
|
||||||
|
const parentCompletion = !keyIsValid
|
||||||
|
? `${entityName}["${key}"]`
|
||||||
|
: `${entityName}.${key}`;
|
||||||
|
flattenedDef[parentCompletion] = value;
|
||||||
|
if (!isTrueObject(value)) return;
|
||||||
|
Object.entries(value).forEach(([subKey, subValue]) => {
|
||||||
|
if (subKey.startsWith("!")) return;
|
||||||
|
const childKeyIsValid = isValidVariableName(subKey);
|
||||||
|
const childCompletion = !childKeyIsValid
|
||||||
|
? `${parentCompletion}["${subKey}"]`
|
||||||
|
: `${parentCompletion}.${subKey}`;
|
||||||
|
flattenedDef[childCompletion] = subValue;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
return flattenedDef;
|
||||||
|
};
|
||||||
|
|
||||||
|
export function generateTypeDef(
|
||||||
|
value: unknown,
|
||||||
|
extraDefsToDefine?: ExtraDef,
|
||||||
|
depth = 0,
|
||||||
|
): Def | string {
|
||||||
|
switch (getType(value)) {
|
||||||
|
case Types.ARRAY: {
|
||||||
|
const array = value as [unknown];
|
||||||
|
if (depth > 5) {
|
||||||
|
return `[?]`;
|
||||||
|
}
|
||||||
|
|
||||||
|
const arrayElementType = generateTypeDef(
|
||||||
|
array[0],
|
||||||
|
extraDefsToDefine,
|
||||||
|
depth + 1,
|
||||||
|
);
|
||||||
|
|
||||||
|
if (isObject(arrayElementType)) {
|
||||||
|
if (extraDefsToDefine) {
|
||||||
|
const uniqueDefName = uniqueId("def_");
|
||||||
|
extraDefsToDefine[uniqueDefName] = arrayElementType;
|
||||||
|
return `[${uniqueDefName}]`;
|
||||||
|
}
|
||||||
|
return `[?]`;
|
||||||
|
}
|
||||||
|
return `[${arrayElementType}]`;
|
||||||
|
}
|
||||||
|
case Types.OBJECT: {
|
||||||
|
const objType: Def = {};
|
||||||
|
const object = value as Record<string, unknown>;
|
||||||
|
Object.keys(object).forEach((k) => {
|
||||||
|
objType[k] = generateTypeDef(object[k], extraDefsToDefine, depth);
|
||||||
|
});
|
||||||
|
return objType;
|
||||||
|
}
|
||||||
|
case Types.STRING:
|
||||||
|
return "string";
|
||||||
|
case Types.NUMBER:
|
||||||
|
return "number";
|
||||||
|
case Types.BOOLEAN:
|
||||||
|
return "bool";
|
||||||
|
case Types.NULL:
|
||||||
|
case Types.UNDEFINED:
|
||||||
|
return "?";
|
||||||
|
default:
|
||||||
|
return "?";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const VALID_VARIABLE_NAME_REGEX = /^([a-zA-Z_$][a-zA-Z\d_$]*)$/;
|
||||||
|
|
||||||
|
export const isValidVariableName = (variableName: string) =>
|
||||||
|
VALID_VARIABLE_NAME_REGEX.test(variableName);
|
||||||
|
|
||||||
|
export const getFunctionsArgsType = (args: Variable[]): string => {
|
||||||
|
// skip same name args to avoiding creating invalid type
|
||||||
|
const argNames = new Set<string>();
|
||||||
|
// skip invalid args name
|
||||||
|
args.forEach((arg) => {
|
||||||
|
if (arg.name && isValidVariableName(arg.name)) argNames.add(arg.name);
|
||||||
|
});
|
||||||
|
const argNamesArray = [...argNames];
|
||||||
|
const argsTypeString = argNamesArray.reduce(
|
||||||
|
(accumulatedArgType, argName, currentIndex) => {
|
||||||
|
switch (currentIndex) {
|
||||||
|
case 0:
|
||||||
|
return `${argName}: ?`;
|
||||||
|
case 1:
|
||||||
|
return `${accumulatedArgType}, ${argName}: ?`;
|
||||||
|
default:
|
||||||
|
return `${accumulatedArgType}, ${argName}: ?`;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
argNamesArray[0],
|
||||||
|
);
|
||||||
|
return argsTypeString ? `fn(${argsTypeString})` : `fn()`;
|
||||||
|
};
|
||||||
|
|
||||||
|
export function generateJSFunctionTypeDef(
|
||||||
|
jsData: Record<string, unknown> = {},
|
||||||
|
fullFunctionName: string,
|
||||||
|
extraDefs: ExtraDef,
|
||||||
|
) {
|
||||||
|
return {
|
||||||
|
"!type": getFunctionsArgsType([]),
|
||||||
|
data: generateTypeDef(jsData[fullFunctionName], extraDefs),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export function addSettersToDefinitions(
|
||||||
|
definitions: Def,
|
||||||
|
entity: DataTreeEntity,
|
||||||
|
entityConfig?: WidgetEntityConfig,
|
||||||
|
) {
|
||||||
|
if (entityConfig && entityConfig.__setters) {
|
||||||
|
const setters = Object.keys(entityConfig.__setters);
|
||||||
|
|
||||||
|
setters.forEach((setterName: string) => {
|
||||||
|
const setter = entityConfig.__setters?.[setterName];
|
||||||
|
const setterType = entityConfig.__setters?.[setterName].type;
|
||||||
|
|
||||||
|
if (shouldAddSetter(setter, entity)) {
|
||||||
|
definitions[
|
||||||
|
setterName
|
||||||
|
] = `fn(value:${setterType}) -> +Promise[:t=[!0.<i>.:t]]`;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -12,8 +12,8 @@ import {
|
||||||
ResponsiveBehavior,
|
ResponsiveBehavior,
|
||||||
} from "layoutSystems/common/utils/constants";
|
} from "layoutSystems/common/utils/constants";
|
||||||
import { DefaultAutocompleteDefinitions } from "widgets/WidgetUtils";
|
import { DefaultAutocompleteDefinitions } from "widgets/WidgetUtils";
|
||||||
import type { ExtraDef } from "utils/autocomplete/dataTreeTypeDefCreator";
|
import type { ExtraDef } from "utils/autocomplete/defCreatorUtils";
|
||||||
import { generateTypeDef } from "utils/autocomplete/dataTreeTypeDefCreator";
|
import { generateTypeDef } from "utils/autocomplete/defCreatorUtils";
|
||||||
import type {
|
import type {
|
||||||
AnvilConfig,
|
AnvilConfig,
|
||||||
AutocompletionDefinitions,
|
AutocompletionDefinitions,
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,7 @@ import type { WidgetState } from "widgets/BaseWidget";
|
||||||
import BaseWidget from "widgets/BaseWidget";
|
import BaseWidget from "widgets/BaseWidget";
|
||||||
import IframeComponent from "../component";
|
import IframeComponent from "../component";
|
||||||
import type { IframeWidgetProps } from "../constants";
|
import type { IframeWidgetProps } from "../constants";
|
||||||
import { generateTypeDef } from "utils/autocomplete/dataTreeTypeDefCreator";
|
import { generateTypeDef } from "utils/autocomplete/defCreatorUtils";
|
||||||
import { DefaultAutocompleteDefinitions } from "widgets/WidgetUtils";
|
import { DefaultAutocompleteDefinitions } from "widgets/WidgetUtils";
|
||||||
import type {
|
import type {
|
||||||
AnvilConfig,
|
AnvilConfig,
|
||||||
|
|
|
||||||
|
|
@ -32,7 +32,7 @@ import type {
|
||||||
} from "entities/AppTheming";
|
} from "entities/AppTheming";
|
||||||
import type { BatchPropertyUpdatePayload } from "actions/controlActions";
|
import type { BatchPropertyUpdatePayload } from "actions/controlActions";
|
||||||
import { isAutoHeightEnabledForWidget } from "widgets/WidgetUtils";
|
import { isAutoHeightEnabledForWidget } from "widgets/WidgetUtils";
|
||||||
import { generateTypeDef } from "utils/autocomplete/dataTreeTypeDefCreator";
|
import { generateTypeDef } from "utils/autocomplete/defCreatorUtils";
|
||||||
import type {
|
import type {
|
||||||
AnvilConfig,
|
AnvilConfig,
|
||||||
AutocompletionDefinitions,
|
AutocompletionDefinitions,
|
||||||
|
|
|
||||||
|
|
@ -34,8 +34,8 @@ import {
|
||||||
} from "utils/DynamicBindingUtils";
|
} from "utils/DynamicBindingUtils";
|
||||||
import { removeFalsyEntries } from "utils/helpers";
|
import { removeFalsyEntries } from "utils/helpers";
|
||||||
import { DefaultAutocompleteDefinitions } from "widgets/WidgetUtils";
|
import { DefaultAutocompleteDefinitions } from "widgets/WidgetUtils";
|
||||||
import { generateTypeDef } from "utils/autocomplete/dataTreeTypeDefCreator";
|
import { generateTypeDef } from "utils/autocomplete/defCreatorUtils";
|
||||||
import type { ExtraDef } from "utils/autocomplete/dataTreeTypeDefCreator";
|
import type { ExtraDef } from "utils/autocomplete/defCreatorUtils";
|
||||||
import WidgetFactory from "WidgetProvider/factory";
|
import WidgetFactory from "WidgetProvider/factory";
|
||||||
import type { WidgetProps, WidgetState } from "widgets/BaseWidget";
|
import type { WidgetProps, WidgetState } from "widgets/BaseWidget";
|
||||||
import BaseWidget from "widgets/BaseWidget";
|
import BaseWidget from "widgets/BaseWidget";
|
||||||
|
|
|
||||||
|
|
@ -46,9 +46,9 @@ import type {
|
||||||
} from "widgets/TabsWidget/constants";
|
} from "widgets/TabsWidget/constants";
|
||||||
import { getMetaFlexLayers, isTargetElementClickable } from "./helper";
|
import { getMetaFlexLayers, isTargetElementClickable } from "./helper";
|
||||||
import { DefaultAutocompleteDefinitions } from "widgets/WidgetUtils";
|
import { DefaultAutocompleteDefinitions } from "widgets/WidgetUtils";
|
||||||
import type { ExtraDef } from "utils/autocomplete/dataTreeTypeDefCreator";
|
import type { ExtraDef } from "utils/autocomplete/defCreatorUtils";
|
||||||
import { LayoutSystemTypes } from "layoutSystems/types";
|
import { LayoutSystemTypes } from "layoutSystems/types";
|
||||||
import { generateTypeDef } from "utils/autocomplete/dataTreeTypeDefCreator";
|
import { generateTypeDef } from "utils/autocomplete/defCreatorUtils";
|
||||||
import defaultProps from "./defaultProps";
|
import defaultProps from "./defaultProps";
|
||||||
|
|
||||||
import IconSVG from "../icon.svg";
|
import IconSVG from "../icon.svg";
|
||||||
|
|
|
||||||
|
|
@ -41,8 +41,8 @@ import { OperatorTypes } from "../component/Constants";
|
||||||
import type { TableWidgetProps } from "../constants";
|
import type { TableWidgetProps } from "../constants";
|
||||||
import derivedProperties from "./parseDerivedProperties";
|
import derivedProperties from "./parseDerivedProperties";
|
||||||
import { selectRowIndex, selectRowIndices } from "./utilities";
|
import { selectRowIndex, selectRowIndices } from "./utilities";
|
||||||
import type { ExtraDef } from "utils/autocomplete/dataTreeTypeDefCreator";
|
import type { ExtraDef } from "utils/autocomplete/defCreatorUtils";
|
||||||
import { generateTypeDef } from "utils/autocomplete/dataTreeTypeDefCreator";
|
import { generateTypeDef } from "utils/autocomplete/defCreatorUtils";
|
||||||
|
|
||||||
import type {
|
import type {
|
||||||
ColumnProperties,
|
ColumnProperties,
|
||||||
|
|
|
||||||
|
|
@ -119,8 +119,8 @@ import type {
|
||||||
transformDataWithEditableCell,
|
transformDataWithEditableCell,
|
||||||
} from "./reactTableUtils/transformDataPureFn";
|
} from "./reactTableUtils/transformDataPureFn";
|
||||||
import { getMemoiseTransformDataWithEditableCell } from "./reactTableUtils/transformDataPureFn";
|
import { getMemoiseTransformDataWithEditableCell } from "./reactTableUtils/transformDataPureFn";
|
||||||
import type { ExtraDef } from "utils/autocomplete/dataTreeTypeDefCreator";
|
import type { ExtraDef } from "utils/autocomplete/defCreatorUtils";
|
||||||
import { generateTypeDef } from "utils/autocomplete/dataTreeTypeDefCreator";
|
import { generateTypeDef } from "utils/autocomplete/defCreatorUtils";
|
||||||
import type {
|
import type {
|
||||||
AnvilConfig,
|
AnvilConfig,
|
||||||
AutocompletionDefinitions,
|
AutocompletionDefinitions,
|
||||||
|
|
|
||||||
|
|
@ -119,8 +119,8 @@ import type {
|
||||||
transformDataWithEditableCell,
|
transformDataWithEditableCell,
|
||||||
} from "./reactTableUtils/transformDataPureFn";
|
} from "./reactTableUtils/transformDataPureFn";
|
||||||
import { getMemoiseTransformDataWithEditableCell } from "./reactTableUtils/transformDataPureFn";
|
import { getMemoiseTransformDataWithEditableCell } from "./reactTableUtils/transformDataPureFn";
|
||||||
import type { ExtraDef } from "utils/autocomplete/dataTreeTypeDefCreator";
|
import type { ExtraDef } from "utils/autocomplete/defCreatorUtils";
|
||||||
import { generateTypeDef } from "utils/autocomplete/dataTreeTypeDefCreator";
|
import { generateTypeDef } from "utils/autocomplete/defCreatorUtils";
|
||||||
import type {
|
import type {
|
||||||
AutocompletionDefinitions,
|
AutocompletionDefinitions,
|
||||||
PropertyUpdates,
|
PropertyUpdates,
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user