fix: Parse js actions for view mode changes (#18357)
* added new function inside parse js actions for view moe * fixing test cases * added evaluateSync with isTriggered false * Add types Add switch case for diff.event Add function get back app mode * Change foreach loops to for of * Dont return jsUpdates from view mode save resolved since no operation is happening Change viewModeSaveResolvedFunctionsAndJSUpdates -> viewModeSaveResolvedFunctions to reflect what it's functionality is * Refactor JSObject code * Refactor code for JSobject * remove any * export parsed object's type from ast * create function for deleteResolvedFunctionsAndCurrentJSCollectionState * Code review changes * Fix tests * Change returns in for of loops to continue Remove try for evaluate sync Js updates return * Fix bug * Fix bug Co-authored-by: Rimil Dey <rimil@appsmith.com> Co-authored-by: Aishwarya UR <aishwarya@appsmith.com>
This commit is contained in:
parent
77a225f4dd
commit
efa8b68a47
|
|
@ -139,7 +139,6 @@ describe("generateDataTreeJSAction", () => {
|
|||
ENTITY_TYPE: "JSACTION",
|
||||
body:
|
||||
"export default {\n\tmyVar1: [],\n\tmyVar2: {},\n\tmyFun1: () => {\n\t\t//write code here\n\t},\n\tmyFun2: async () => {\n\t\t//use async-await or promises\n\t}\n}",
|
||||
|
||||
myFun2: {
|
||||
data: {
|
||||
users: [{ id: 1, name: "John" }],
|
||||
|
|
@ -159,11 +158,13 @@ describe("generateDataTreeJSAction", () => {
|
|||
arguments: [],
|
||||
isAsync: true,
|
||||
confirmBeforeExecute: false,
|
||||
body: "async () => {\n\t\t//use async-await or promises\n\t}",
|
||||
},
|
||||
myFun1: {
|
||||
arguments: [],
|
||||
isAsync: false,
|
||||
confirmBeforeExecute: false,
|
||||
body: "() => {\n\t\t//write code here\n\t}",
|
||||
},
|
||||
},
|
||||
bindingPaths: {
|
||||
|
|
@ -350,11 +351,13 @@ describe("generateDataTreeJSAction", () => {
|
|||
arguments: [],
|
||||
isAsync: true,
|
||||
confirmBeforeExecute: false,
|
||||
body: "async () => {\n\t\t//use async-await or promises\n\t}",
|
||||
},
|
||||
myFun1: {
|
||||
arguments: [],
|
||||
isAsync: false,
|
||||
confirmBeforeExecute: false,
|
||||
body: "() => {\n\t\t//write code here\n\t}",
|
||||
},
|
||||
},
|
||||
bindingPaths: {
|
||||
|
|
|
|||
|
|
@ -44,6 +44,7 @@ export const generateDataTreeJSAction = (
|
|||
arguments: action.actionConfiguration.jsArguments,
|
||||
isAsync: action.actionConfiguration.isAsync,
|
||||
confirmBeforeExecute: !!action.confirmBeforeExecute,
|
||||
body: action.actionConfiguration.body,
|
||||
};
|
||||
bindingPaths[action.name] = EvaluationSubstitutionType.SMART_SUBSTITUTE;
|
||||
dynamicBindingPathList.push({ key: action.name });
|
||||
|
|
|
|||
|
|
@ -66,6 +66,7 @@ export interface MetaArgs {
|
|||
arguments: Variable[];
|
||||
isAsync: boolean;
|
||||
confirmBeforeExecute: boolean;
|
||||
body: string;
|
||||
}
|
||||
|
||||
export interface JSActionEntityConfig {
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ import { DataTree, DataTreeJSAction } from "entities/DataTree/dataTreeFactory";
|
|||
import { isEmpty, set } from "lodash";
|
||||
import { EvalErrorTypes } from "utils/DynamicBindingUtils";
|
||||
import { JSUpdate, ParsedJSSubAction } from "utils/JSPaneUtils";
|
||||
import { isTypeOfFunction, parseJSObjectWithAST } from "@shared/ast";
|
||||
import { NodeTypes, parseJSObjectWithAST, JsObjectProperty } from "@shared/ast";
|
||||
import DataTreeEvaluator from "workers/common/DataTreeEvaluator";
|
||||
import evaluateSync, { isFunctionAsync } from "workers/Evaluation/evaluate";
|
||||
import {
|
||||
|
|
@ -16,6 +16,19 @@ import {
|
|||
updateJSCollectionInUnEvalTree,
|
||||
} from "workers/Evaluation/JSObject/utils";
|
||||
|
||||
type Actions = {
|
||||
name: string;
|
||||
body: string;
|
||||
arguments: Array<{ key: string; value: unknown }>;
|
||||
parsedFunction: any;
|
||||
isAsync: boolean;
|
||||
};
|
||||
|
||||
type Variables = {
|
||||
name: string;
|
||||
value: string;
|
||||
};
|
||||
|
||||
/**
|
||||
* Here we update our unEvalTree according to the change in JSObject's body
|
||||
*
|
||||
|
|
@ -33,7 +46,7 @@ export const getUpdatedLocalUnEvalTreeAfterJSUpdates = (
|
|||
const parsedBody = jsUpdates[jsEntity].parsedBody;
|
||||
if (isJSAction(entity)) {
|
||||
if (!!parsedBody) {
|
||||
//add/delete/update functions from dataTree
|
||||
// add/delete/update functions from dataTree
|
||||
localUnEvalTree = updateJSCollectionInUnEvalTree(
|
||||
parsedBody,
|
||||
entity,
|
||||
|
|
@ -54,6 +67,110 @@ export const getUpdatedLocalUnEvalTreeAfterJSUpdates = (
|
|||
|
||||
const regex = new RegExp(/^export default[\s]*?({[\s\S]*?})/);
|
||||
|
||||
function deleteResolvedFunctionsAndCurrentJSCollectionState(
|
||||
dataTreeEvalRef: DataTreeEvaluator,
|
||||
entityName: string,
|
||||
) {
|
||||
delete dataTreeEvalRef.resolvedFunctions[entityName];
|
||||
delete dataTreeEvalRef.currentJSCollectionState[entityName];
|
||||
}
|
||||
|
||||
function parseFunction(
|
||||
parsedElement: JsObjectProperty,
|
||||
unEvalDataTree: DataTree,
|
||||
dataTreeEvalRef: DataTreeEvaluator,
|
||||
entityName: string,
|
||||
actions: Actions[],
|
||||
) {
|
||||
const { result } = evaluateSync(
|
||||
parsedElement.value,
|
||||
unEvalDataTree,
|
||||
{},
|
||||
true,
|
||||
undefined,
|
||||
undefined,
|
||||
true,
|
||||
);
|
||||
if (!!result) {
|
||||
let params: Array<{ key: string; value: unknown }> = [];
|
||||
|
||||
if (parsedElement.arguments) {
|
||||
params = parsedElement.arguments.map(({ defaultValue, paramName }) => ({
|
||||
key: paramName,
|
||||
value: defaultValue,
|
||||
}));
|
||||
}
|
||||
|
||||
const functionString: string = parsedElement.value;
|
||||
set(
|
||||
dataTreeEvalRef.resolvedFunctions,
|
||||
`${entityName}.${parsedElement.key}`,
|
||||
result,
|
||||
);
|
||||
set(
|
||||
dataTreeEvalRef.currentJSCollectionState,
|
||||
`${entityName}.${parsedElement.key}`,
|
||||
functionString,
|
||||
);
|
||||
actions.push({
|
||||
name: parsedElement.key,
|
||||
body: functionString,
|
||||
arguments: params,
|
||||
parsedFunction: result,
|
||||
isAsync: false,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function parseVariables(
|
||||
variables: Variables[],
|
||||
parsedElement: JsObjectProperty,
|
||||
dataTreeEvalRef: DataTreeEvaluator,
|
||||
entityName: string,
|
||||
) {
|
||||
variables.push({
|
||||
name: parsedElement.key,
|
||||
value: parsedElement.value,
|
||||
});
|
||||
set(
|
||||
dataTreeEvalRef.currentJSCollectionState,
|
||||
`${entityName}.${parsedElement.key}`,
|
||||
parsedElement.value,
|
||||
);
|
||||
}
|
||||
|
||||
function getParsedBody(
|
||||
parsedObject: Array<JsObjectProperty>,
|
||||
unEvalDataTree: DataTree,
|
||||
dataTreeEvalRef: DataTreeEvaluator,
|
||||
entityName: string,
|
||||
) {
|
||||
const actions: Actions[] = [];
|
||||
const variables: Variables[] = [];
|
||||
for (const parsedElement of parsedObject) {
|
||||
switch (parsedElement.type) {
|
||||
case "literal":
|
||||
continue;
|
||||
case NodeTypes.ArrowFunctionExpression:
|
||||
case NodeTypes.FunctionExpression:
|
||||
parseFunction(
|
||||
parsedElement,
|
||||
unEvalDataTree,
|
||||
dataTreeEvalRef,
|
||||
entityName,
|
||||
actions,
|
||||
);
|
||||
break;
|
||||
default:
|
||||
parseVariables(variables, parsedElement, dataTreeEvalRef, entityName);
|
||||
}
|
||||
}
|
||||
return {
|
||||
actions,
|
||||
variables,
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Here we parse the JSObject and then determine
|
||||
* 1. it's nature : async or sync
|
||||
|
|
@ -62,24 +179,26 @@ const regex = new RegExp(/^export default[\s]*?({[\s\S]*?})/);
|
|||
*
|
||||
* @param dataTreeEvalRef
|
||||
* @param entity
|
||||
* @param jsUpdates
|
||||
* @param unEvalDataTree
|
||||
* @param entityName
|
||||
* @param jsUpdates
|
||||
* @returns
|
||||
*/
|
||||
export function saveResolvedFunctionsAndJSUpdates(
|
||||
dataTreeEvalRef: DataTreeEvaluator,
|
||||
entity: DataTreeJSAction,
|
||||
jsUpdates: Record<string, JSUpdate>,
|
||||
unEvalDataTree: DataTree,
|
||||
entityName: string,
|
||||
jsUpdates: Record<string, JSUpdate>,
|
||||
) {
|
||||
const correctFormat = regex.test(entity.body);
|
||||
if (correctFormat) {
|
||||
const body = entity.body.replace(/export default/g, "");
|
||||
try {
|
||||
delete dataTreeEvalRef.resolvedFunctions[`${entityName}`];
|
||||
delete dataTreeEvalRef.currentJSCollectionState[`${entityName}`];
|
||||
deleteResolvedFunctionsAndCurrentJSCollectionState(
|
||||
dataTreeEvalRef,
|
||||
entityName,
|
||||
);
|
||||
const parseStartTime = performance.now();
|
||||
const parsedObject = parseJSObjectWithAST(body);
|
||||
const parseEndTime = performance.now();
|
||||
|
|
@ -88,82 +207,23 @@ export function saveResolvedFunctionsAndJSUpdates(
|
|||
JSObjectName: entityName,
|
||||
JSObjectASTParseTime,
|
||||
});
|
||||
const actions: any = [];
|
||||
const variables: any = [];
|
||||
if (!!parsedObject) {
|
||||
parsedObject.forEach((parsedElement) => {
|
||||
if (isTypeOfFunction(parsedElement.type)) {
|
||||
try {
|
||||
const { result } = evaluateSync(
|
||||
parsedElement.value,
|
||||
unEvalDataTree,
|
||||
{},
|
||||
false,
|
||||
undefined,
|
||||
undefined,
|
||||
true,
|
||||
);
|
||||
if (!!result) {
|
||||
let params: Array<{ key: string; value: unknown }> = [];
|
||||
|
||||
if (parsedElement.arguments) {
|
||||
params = parsedElement.arguments.map(
|
||||
({ defaultValue, paramName }) => ({
|
||||
key: paramName,
|
||||
value: defaultValue,
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
const functionString = parsedElement.value;
|
||||
set(
|
||||
dataTreeEvalRef.resolvedFunctions,
|
||||
`${entityName}.${parsedElement.key}`,
|
||||
result,
|
||||
);
|
||||
set(
|
||||
dataTreeEvalRef.currentJSCollectionState,
|
||||
`${entityName}.${parsedElement.key}`,
|
||||
functionString,
|
||||
);
|
||||
actions.push({
|
||||
name: parsedElement.key,
|
||||
body: functionString,
|
||||
arguments: params,
|
||||
parsedFunction: result,
|
||||
isAsync: false,
|
||||
});
|
||||
}
|
||||
} catch {
|
||||
// in case we need to handle error state
|
||||
}
|
||||
} else if (parsedElement.type !== "literal") {
|
||||
variables.push({
|
||||
name: parsedElement.key,
|
||||
value: parsedElement.value,
|
||||
});
|
||||
set(
|
||||
dataTreeEvalRef.currentJSCollectionState,
|
||||
`${entityName}.${parsedElement.key}`,
|
||||
parsedElement.value,
|
||||
);
|
||||
const parsedBody = !!parsedObject
|
||||
? {
|
||||
body: entity.body,
|
||||
...getParsedBody(
|
||||
parsedObject,
|
||||
unEvalDataTree,
|
||||
dataTreeEvalRef,
|
||||
entityName,
|
||||
),
|
||||
}
|
||||
});
|
||||
const parsedBody = {
|
||||
body: entity.body,
|
||||
actions: actions,
|
||||
variables,
|
||||
};
|
||||
set(jsUpdates, `${entityName}`, {
|
||||
parsedBody,
|
||||
id: entity.actionId,
|
||||
});
|
||||
} else {
|
||||
set(jsUpdates, `${entityName}`, {
|
||||
parsedBody: undefined,
|
||||
id: entity.actionId,
|
||||
});
|
||||
}
|
||||
: undefined;
|
||||
|
||||
set(jsUpdates, `${entityName}`, {
|
||||
parsedBody,
|
||||
id: entity.actionId,
|
||||
});
|
||||
} catch (e) {
|
||||
//if we need to push error as popup in case
|
||||
}
|
||||
|
|
@ -181,74 +241,152 @@ export function saveResolvedFunctionsAndJSUpdates(
|
|||
return jsUpdates;
|
||||
}
|
||||
|
||||
export function viewModeSaveResolvedFunctions(
|
||||
dataTreeEvalRef: DataTreeEvaluator,
|
||||
entity: DataTreeJSAction,
|
||||
unEvalDataTree: DataTree,
|
||||
entityName: string,
|
||||
) {
|
||||
try {
|
||||
deleteResolvedFunctionsAndCurrentJSCollectionState(
|
||||
dataTreeEvalRef,
|
||||
entityName,
|
||||
);
|
||||
const jsActions = entity.meta;
|
||||
const jsActionList = Object.keys(jsActions);
|
||||
for (const jsAction of jsActionList) {
|
||||
const { result } = evaluateSync(
|
||||
jsActions[jsAction].body,
|
||||
unEvalDataTree,
|
||||
{},
|
||||
false,
|
||||
undefined,
|
||||
undefined,
|
||||
true,
|
||||
);
|
||||
|
||||
if (!!result) {
|
||||
const functionString = jsActions[jsAction].body;
|
||||
|
||||
set(
|
||||
dataTreeEvalRef.resolvedFunctions,
|
||||
`${entityName}.${jsAction}`,
|
||||
result,
|
||||
);
|
||||
set(
|
||||
dataTreeEvalRef.currentJSCollectionState,
|
||||
`${entityName}.${jsAction}`,
|
||||
functionString,
|
||||
);
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
//if we need to push error as popup in case
|
||||
}
|
||||
}
|
||||
|
||||
export function parseJSActionsWithDifferences(
|
||||
dataTreeEvalRef: DataTreeEvaluator,
|
||||
unEvalDataTree: DataTree,
|
||||
differences: DataTreeDiff[],
|
||||
) {
|
||||
let jsUpdates: Record<string, JSUpdate> = {};
|
||||
for (const diff of differences) {
|
||||
const payLoadPropertyPath = diff.payload.propertyPath;
|
||||
const { entityName, propertyPath } = getEntityNameAndPropertyPath(
|
||||
payLoadPropertyPath,
|
||||
);
|
||||
const entity = unEvalDataTree[entityName];
|
||||
|
||||
if (!isJSAction(entity)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
switch (diff.event) {
|
||||
case DataTreeDiffEvent.DELETE:
|
||||
// when JSObject is deleted, we remove it from currentJSCollectionState & resolvedFunctions
|
||||
deleteResolvedFunctionsAndCurrentJSCollectionState(
|
||||
dataTreeEvalRef,
|
||||
payLoadPropertyPath,
|
||||
);
|
||||
break;
|
||||
case DataTreeDiffEvent.EDIT:
|
||||
if (propertyPath === "body") {
|
||||
jsUpdates = saveResolvedFunctionsAndJSUpdates(
|
||||
dataTreeEvalRef,
|
||||
entity,
|
||||
unEvalDataTree,
|
||||
entityName,
|
||||
jsUpdates,
|
||||
);
|
||||
}
|
||||
break;
|
||||
case DataTreeDiffEvent.NEW:
|
||||
if (propertyPath === "") {
|
||||
jsUpdates = saveResolvedFunctionsAndJSUpdates(
|
||||
dataTreeEvalRef,
|
||||
entity,
|
||||
unEvalDataTree,
|
||||
entityName,
|
||||
jsUpdates,
|
||||
);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
return parseJSUpdates(jsUpdates, unEvalDataTree, dataTreeEvalRef);
|
||||
}
|
||||
|
||||
export function parseJSActionsForViewMode(
|
||||
dataTreeEvalRef: DataTreeEvaluator,
|
||||
unEvalDataTree: DataTree,
|
||||
) {
|
||||
const unEvalDataTreeKeys = Object.keys(unEvalDataTree);
|
||||
for (const entityName of unEvalDataTreeKeys) {
|
||||
const entity = unEvalDataTree[entityName];
|
||||
if (!isJSAction(entity)) {
|
||||
continue;
|
||||
}
|
||||
viewModeSaveResolvedFunctions(
|
||||
dataTreeEvalRef,
|
||||
entity,
|
||||
unEvalDataTree,
|
||||
entityName,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export function parseJSActions(
|
||||
dataTreeEvalRef: DataTreeEvaluator,
|
||||
unEvalDataTree: DataTree,
|
||||
differences?: DataTreeDiff[],
|
||||
oldUnEvalTree?: DataTree,
|
||||
) {
|
||||
let jsUpdates: Record<string, JSUpdate> = {};
|
||||
if (!!differences && !!oldUnEvalTree) {
|
||||
differences.forEach((diff) => {
|
||||
const { entityName, propertyPath } = getEntityNameAndPropertyPath(
|
||||
diff.payload.propertyPath,
|
||||
);
|
||||
const entity = unEvalDataTree[entityName];
|
||||
|
||||
if (!isJSAction(entity)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (diff.event === DataTreeDiffEvent.DELETE) {
|
||||
// when JSObject is deleted, we remove it from currentJSCollectionState & resolvedFunctions
|
||||
if (
|
||||
dataTreeEvalRef.currentJSCollectionState &&
|
||||
dataTreeEvalRef.currentJSCollectionState[diff.payload.propertyPath]
|
||||
) {
|
||||
delete dataTreeEvalRef.currentJSCollectionState[
|
||||
diff.payload.propertyPath
|
||||
];
|
||||
}
|
||||
if (
|
||||
dataTreeEvalRef.resolvedFunctions &&
|
||||
dataTreeEvalRef.resolvedFunctions[diff.payload.propertyPath]
|
||||
) {
|
||||
delete dataTreeEvalRef.resolvedFunctions[diff.payload.propertyPath];
|
||||
}
|
||||
}
|
||||
|
||||
if (
|
||||
(diff.event === DataTreeDiffEvent.EDIT && propertyPath === "body") ||
|
||||
(diff.event === DataTreeDiffEvent.NEW && propertyPath === "")
|
||||
) {
|
||||
jsUpdates = saveResolvedFunctionsAndJSUpdates(
|
||||
dataTreeEvalRef,
|
||||
entity,
|
||||
jsUpdates,
|
||||
unEvalDataTree,
|
||||
entityName,
|
||||
);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
Object.keys(unEvalDataTree).forEach((entityName) => {
|
||||
const entity = unEvalDataTree[entityName];
|
||||
if (!isJSAction(entity)) {
|
||||
return;
|
||||
}
|
||||
jsUpdates = saveResolvedFunctionsAndJSUpdates(
|
||||
dataTreeEvalRef,
|
||||
entity,
|
||||
jsUpdates,
|
||||
unEvalDataTree,
|
||||
entityName,
|
||||
);
|
||||
});
|
||||
const unEvalDataTreeKeys = Object.keys(unEvalDataTree);
|
||||
for (const entityName of unEvalDataTreeKeys) {
|
||||
const entity = unEvalDataTree[entityName];
|
||||
if (!isJSAction(entity)) {
|
||||
continue;
|
||||
}
|
||||
jsUpdates = saveResolvedFunctionsAndJSUpdates(
|
||||
dataTreeEvalRef,
|
||||
entity,
|
||||
unEvalDataTree,
|
||||
entityName,
|
||||
jsUpdates,
|
||||
);
|
||||
}
|
||||
return parseJSUpdates(jsUpdates, unEvalDataTree, dataTreeEvalRef);
|
||||
}
|
||||
|
||||
Object.keys(jsUpdates).forEach((entityName) => {
|
||||
export function parseJSUpdates(
|
||||
jsUpdates: Record<string, JSUpdate>,
|
||||
unEvalDataTree: DataTree,
|
||||
dataTreeEvalRef: DataTreeEvaluator,
|
||||
) {
|
||||
const jsUpdateKeys = Object.keys(jsUpdates);
|
||||
for (const entityName of jsUpdateKeys) {
|
||||
const parsedBody = jsUpdates[entityName].parsedBody;
|
||||
if (!parsedBody) return;
|
||||
if (!parsedBody) continue;
|
||||
parsedBody.actions = parsedBody.actions.map((action) => {
|
||||
return {
|
||||
...action,
|
||||
|
|
@ -262,17 +400,18 @@ export function parseJSActions(
|
|||
parsedFunction: undefined,
|
||||
} as ParsedJSSubAction;
|
||||
});
|
||||
});
|
||||
return { jsUpdates };
|
||||
}
|
||||
return jsUpdates;
|
||||
}
|
||||
|
||||
export function getJSEntities(dataTree: DataTree) {
|
||||
const jsCollections: Record<string, DataTreeJSAction> = {};
|
||||
Object.keys(dataTree).forEach((key: string) => {
|
||||
const dataTreeKeys = Object.keys(dataTree);
|
||||
for (const key of dataTreeKeys) {
|
||||
const entity = dataTree[key];
|
||||
if (isJSAction(entity)) {
|
||||
jsCollections[entity.name] = entity;
|
||||
}
|
||||
});
|
||||
}
|
||||
return jsCollections;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,11 +1,13 @@
|
|||
import {
|
||||
DataTree,
|
||||
DataTreeAppsmith,
|
||||
DataTreeJSAction,
|
||||
EvaluationSubstitutionType,
|
||||
} from "entities/DataTree/dataTreeFactory";
|
||||
import { ParsedBody, ParsedJSSubAction } from "utils/JSPaneUtils";
|
||||
import { unset, set, get } from "lodash";
|
||||
import { isJSAction } from "workers/Evaluation/evaluationUtils";
|
||||
import { APP_MODE } from "../../../entities/App";
|
||||
|
||||
/**
|
||||
* here we add/remove the properties (variables and actions) which got added/removed from the JSObject parsedBody.
|
||||
|
|
@ -72,6 +74,7 @@ export const updateJSCollectionInUnEvalTree = (
|
|||
arguments: action.arguments,
|
||||
isAsync: false,
|
||||
confirmBeforeExecute: false,
|
||||
body: action.body,
|
||||
};
|
||||
|
||||
const data = get(
|
||||
|
|
@ -238,3 +241,8 @@ export function isJSObjectFunction(
|
|||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
export function getAppMode(dataTree: DataTree) {
|
||||
const appsmithObj = dataTree.appsmith as DataTreeAppsmith;
|
||||
return appsmithObj.mode as APP_MODE;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -346,6 +346,14 @@ describe("DataTreeEvaluator", () => {
|
|||
{},
|
||||
);
|
||||
const unEvalTree: UnEvalTree = {
|
||||
appsmith: {
|
||||
mode: "EDIT",
|
||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||
// @ts-ignore
|
||||
ENTITY_TYPE: ENTITY_TYPE.APPSMITH,
|
||||
store: {},
|
||||
theme: {},
|
||||
},
|
||||
Text1: generateDataTreeWidget(
|
||||
{
|
||||
...BASE_WIDGET,
|
||||
|
|
|
|||
|
|
@ -28,6 +28,7 @@ import {
|
|||
convertPathToString,
|
||||
CrashingError,
|
||||
DataTreeDiff,
|
||||
getAllPaths,
|
||||
getEntityNameAndPropertyPath,
|
||||
getImmediateParentsOfPropertyPaths,
|
||||
isAction,
|
||||
|
|
@ -38,7 +39,6 @@ import {
|
|||
translateDiffEventToDataTreeDiffEvent,
|
||||
trimDependantChangePaths,
|
||||
overrideWidgetProperties,
|
||||
getAllPaths,
|
||||
isValidEntity,
|
||||
} from "workers/Evaluation/evaluationUtils";
|
||||
import {
|
||||
|
|
@ -63,14 +63,14 @@ import {
|
|||
import { DATA_BIND_REGEX } from "constants/BindingsConstants";
|
||||
import evaluateSync, {
|
||||
EvalResult,
|
||||
EvaluateContext,
|
||||
evaluateAsync,
|
||||
EvaluateContext,
|
||||
} from "workers/Evaluation/evaluate";
|
||||
import { substituteDynamicBindingWithValues } from "workers/Evaluation/evaluationSubstitution";
|
||||
import {
|
||||
ENTITY_TYPE as CONSOLE_ENTITY_TYPE,
|
||||
Severity,
|
||||
SourceEntity,
|
||||
ENTITY_TYPE as CONSOLE_ENTITY_TYPE,
|
||||
UserLogObject,
|
||||
} from "entities/AppsmithConsole";
|
||||
import { error as logError } from "loglevel";
|
||||
|
|
@ -83,21 +83,27 @@ import {
|
|||
import { klona } from "klona/full";
|
||||
import { EvalMetaUpdates } from "./types";
|
||||
import {
|
||||
updateDependencyMap,
|
||||
createDependencyMap,
|
||||
updateDependencyMap,
|
||||
} from "workers/common/DependencyMap";
|
||||
import {
|
||||
getJSEntities,
|
||||
getUpdatedLocalUnEvalTreeAfterJSUpdates,
|
||||
parseJSActionsForViewMode,
|
||||
parseJSActions,
|
||||
parseJSActionsWithDifferences,
|
||||
} from "workers/Evaluation/JSObject";
|
||||
import { getFixedTimeDifference } from "./utils";
|
||||
import { isJSObjectFunction } from "workers/Evaluation/JSObject/utils";
|
||||
import {
|
||||
getAppMode,
|
||||
isJSObjectFunction,
|
||||
} from "workers/Evaluation/JSObject/utils";
|
||||
import {
|
||||
getValidatedTree,
|
||||
validateActionProperty,
|
||||
validateAndParseWidgetProperty,
|
||||
} from "./validationUtils";
|
||||
import { APP_MODE } from "../../../entities/App";
|
||||
|
||||
type SortedDependencies = Array<string>;
|
||||
|
||||
|
|
@ -142,6 +148,10 @@ export default class DataTreeEvaluator {
|
|||
sortedValidationDependencies: SortedDependencies = [];
|
||||
inverseValidationDependencyMap: DependencyMap = {};
|
||||
public hasCyclicalDependency = false;
|
||||
parseJsActionsConfig = {
|
||||
[APP_MODE.EDIT]: parseJSActions,
|
||||
[APP_MODE.PUBLISHED]: parseJSActionsForViewMode,
|
||||
};
|
||||
constructor(
|
||||
widgetConfigMap: WidgetTypeConfigMap,
|
||||
allActionValidationConfig?: {
|
||||
|
|
@ -190,8 +200,9 @@ export default class DataTreeEvaluator {
|
|||
//save current state of js collection action and variables to be added to uneval tree
|
||||
//save functions in resolveFunctions (as functions) to be executed as functions are not allowed in evalTree
|
||||
//and functions are saved in dataTree as strings
|
||||
const parsedCollections = parseJSActions(this, localUnEvalTree);
|
||||
jsUpdates = parsedCollections.jsUpdates;
|
||||
const currentAppMode: APP_MODE = getAppMode(localUnEvalTree);
|
||||
jsUpdates =
|
||||
this.parseJsActionsConfig[currentAppMode](this, localUnEvalTree) || {};
|
||||
localUnEvalTree = getUpdatedLocalUnEvalTreeAfterJSUpdates(
|
||||
jsUpdates,
|
||||
localUnEvalTree,
|
||||
|
|
@ -363,18 +374,18 @@ export default class DataTreeEvaluator {
|
|||
translateDiffEventToDataTreeDiffEvent(diff, localUnEvalTree),
|
||||
),
|
||||
);
|
||||
//save parsed functions in resolveJSFunctions, update current state of js collection
|
||||
const parsedCollections = parseJSActions(
|
||||
this,
|
||||
localUnEvalTree,
|
||||
jsTranslatedDiffs,
|
||||
this.oldUnEvalTree,
|
||||
);
|
||||
|
||||
jsUpdates = parsedCollections.jsUpdates;
|
||||
//update local data tree if js body has updated (remove/update/add js functions or variables)
|
||||
// save parsed functions in resolveJSFunctions, update current state of js collection
|
||||
jsUpdates =
|
||||
(!!jsTranslatedDiffs && !!this.oldUnEvalTree
|
||||
? parseJSActionsWithDifferences(
|
||||
this,
|
||||
localUnEvalTree,
|
||||
jsTranslatedDiffs,
|
||||
)
|
||||
: parseJSActions(this, localUnEvalTree)) || {};
|
||||
// update local data tree if js body has updated (remove/update/add js functions or variables)
|
||||
localUnEvalTree = getUpdatedLocalUnEvalTreeAfterJSUpdates(
|
||||
jsUpdates,
|
||||
jsUpdates || {},
|
||||
localUnEvalTree,
|
||||
);
|
||||
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ import {
|
|||
DataTreeAction,
|
||||
DataTreeWidget,
|
||||
ENTITY_TYPE,
|
||||
DataTreeAppsmith,
|
||||
} from "entities/DataTree/dataTreeFactory";
|
||||
|
||||
export const arrayAccessorCyclicDependency: Record<string, DataTree> = {
|
||||
|
|
@ -210,6 +211,71 @@ export const arrayAccessorCyclicDependency: Record<string, DataTree> = {
|
|||
privateWidgets: {},
|
||||
meta: {},
|
||||
} as unknown) as DataTreeWidget,
|
||||
appsmith: ({
|
||||
user: {
|
||||
email: "anand@appsmith.com",
|
||||
workspaceIds: [
|
||||
"61431979a67ce2289d3c7c6d",
|
||||
"61431a95a67ce2289d3c7c74",
|
||||
"5f7add8687af934ed846dd6a",
|
||||
"5f9fd13993794869fdbb8dcb",
|
||||
"618b5af5da7cd651ee273112",
|
||||
"604ef1c5c046f668d7bcc051",
|
||||
"61b3389cd3e4214454c26bd1",
|
||||
"61b3389cd3e4214454c26bd2",
|
||||
"620a0d896b4b1e154a3c057a",
|
||||
"620b37296b4b1e154a3c1fd7",
|
||||
"60c1a5273535574772b6377b",
|
||||
"6066e71a034ece74b1481ad2",
|
||||
"623b36e34d9aea1b062b15b3",
|
||||
"623b37de4d9aea1b062b170f",
|
||||
"624fe51b457aa64da9e02ed3",
|
||||
"6176537b515e45415cc7fd15",
|
||||
"6206486d6b4b1e154a3be208",
|
||||
],
|
||||
username: "anand@appsmith.com",
|
||||
name: "Anand Srinivasan",
|
||||
enableTelemetry: true,
|
||||
idToken: {
|
||||
sub: "109879730040206968321",
|
||||
email_verified: true,
|
||||
name: "Anand Srinivasan",
|
||||
given_name: "Anand",
|
||||
locale: "en",
|
||||
hd: "appsmith.com",
|
||||
family_name: "Srinivasan",
|
||||
picture:
|
||||
"https://lh3.googleusercontent.com/a-/AOh14Gi4HfYY0sKhaG93YAHB_E5-dL4BkFxdf8ZfQ2w7=s96-c",
|
||||
email: "anand@appsmith.com",
|
||||
},
|
||||
accountNonExpired: true,
|
||||
accountNonLocked: true,
|
||||
credentialsNonExpired: true,
|
||||
emptyInstance: false,
|
||||
isAnonymous: false,
|
||||
isEnabled: true,
|
||||
isSuperUser: false,
|
||||
isConfigurable: true,
|
||||
},
|
||||
URL: {
|
||||
fullPath:
|
||||
"https://app.appsmith.com/app/untitled-application-25/page1-6272179d8a368d6f1efcd0d2/edit",
|
||||
host: "app.appsmith.com",
|
||||
hostname: "app.appsmith.com",
|
||||
queryParams: {},
|
||||
protocol: "https:",
|
||||
pathname:
|
||||
"/app/untitled-application-25/page1-6272179d8a368d6f1efcd0d2/edit",
|
||||
port: "",
|
||||
hash: "",
|
||||
},
|
||||
store: {},
|
||||
geolocation: {
|
||||
canBeRequested: true,
|
||||
},
|
||||
mode: "EDIT",
|
||||
ENTITY_TYPE: ENTITY_TYPE.APPSMITH,
|
||||
} as unknown) as DataTreeAppsmith,
|
||||
},
|
||||
apiSuccessUnEvalTree: {
|
||||
// success: response -> [{...}, {...}, {...}]
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ import {
|
|||
DataTreeAction,
|
||||
DataTreeWidget,
|
||||
ENTITY_TYPE,
|
||||
DataTreeAppsmith,
|
||||
} from "entities/DataTree/dataTreeFactory";
|
||||
|
||||
export const nestedArrayAccessorCyclicDependency: Record<string, DataTree> = {
|
||||
|
|
@ -210,6 +211,53 @@ export const nestedArrayAccessorCyclicDependency: Record<string, DataTree> = {
|
|||
privateWidgets: {},
|
||||
meta: {},
|
||||
} as unknown) as DataTreeWidget,
|
||||
appsmith: ({
|
||||
user: {
|
||||
email: "rathod@appsmith.com",
|
||||
workspaceIds: [
|
||||
"6218a61972ccd9145ec78c57",
|
||||
"621913df0276eb01d22fec44",
|
||||
"60caf8edb1e47a1315f0c48f",
|
||||
"609114fe05c4d35a9f6cbbf2",
|
||||
],
|
||||
username: "rathod@appsmith.com",
|
||||
name: "Rishabh",
|
||||
commentOnboardingState: "RESOLVED",
|
||||
role: "engineer",
|
||||
useCase: "personal project",
|
||||
enableTelemetry: false,
|
||||
emptyInstance: false,
|
||||
accountNonExpired: true,
|
||||
accountNonLocked: true,
|
||||
credentialsNonExpired: true,
|
||||
isAnonymous: false,
|
||||
isEnabled: true,
|
||||
isSuperUser: false,
|
||||
isConfigurable: true,
|
||||
},
|
||||
URL: {
|
||||
fullPath:
|
||||
"https://dev.appsmith.com/applications/6200d1a2b5bfc0392b959cab/pages/6220c268c48234070f8ac65a/edit?a=b",
|
||||
host: "dev.appsmith.com",
|
||||
hostname: "dev.appsmith.com",
|
||||
queryParams: {
|
||||
a: "b",
|
||||
},
|
||||
protocol: "https:",
|
||||
pathname:
|
||||
"/applications/6200d1a2b5bfc0392b959cab/pages/6220c268c48234070f8ac65a/edit",
|
||||
port: "",
|
||||
hash: "",
|
||||
},
|
||||
store: {
|
||||
textColor: "#DF7E65",
|
||||
},
|
||||
geolocation: {
|
||||
canBeRequested: true,
|
||||
},
|
||||
mode: "EDIT",
|
||||
ENTITY_TYPE: ENTITY_TYPE.APPSMITH,
|
||||
} as unknown) as DataTreeAppsmith,
|
||||
},
|
||||
apiSuccessUnEvalTree: {
|
||||
// success: response -> [ [{...}, {...}, {...}], [{...}, {...}, {...}], [{...}, {...}, {...}] ]
|
||||
|
|
|
|||
|
|
@ -388,6 +388,7 @@ export const asyncTagUnevalTree: DataTree = {
|
|||
arguments: [],
|
||||
isAsync: false,
|
||||
confirmBeforeExecute: false,
|
||||
body: "myFun1: () => {\n\t\treturn JSObject2.callApi();\n\t}",
|
||||
},
|
||||
},
|
||||
bindingPaths: {
|
||||
|
|
@ -426,6 +427,7 @@ export const asyncTagUnevalTree: DataTree = {
|
|||
arguments: [],
|
||||
isAsync: false,
|
||||
confirmBeforeExecute: false,
|
||||
body: "callApi: () => {\n\t\treturn Api1.run()\n\t}",
|
||||
},
|
||||
},
|
||||
bindingPaths: {
|
||||
|
|
@ -1419,3 +1421,71 @@ export const unEvalTreeWidgetSelectWidget = {
|
|||
isDirty: false,
|
||||
},
|
||||
};
|
||||
|
||||
export const emptyTreeWithAppsmithObject = ({
|
||||
appsmith: ({
|
||||
user: {
|
||||
email: "anand@appsmith.com",
|
||||
workspaceIds: [
|
||||
"61431979a67ce2289d3c7c6d",
|
||||
"61431a95a67ce2289d3c7c74",
|
||||
"5f7add8687af934ed846dd6a",
|
||||
"5f9fd13993794869fdbb8dcb",
|
||||
"618b5af5da7cd651ee273112",
|
||||
"604ef1c5c046f668d7bcc051",
|
||||
"61b3389cd3e4214454c26bd1",
|
||||
"61b3389cd3e4214454c26bd2",
|
||||
"620a0d896b4b1e154a3c057a",
|
||||
"620b37296b4b1e154a3c1fd7",
|
||||
"60c1a5273535574772b6377b",
|
||||
"6066e71a034ece74b1481ad2",
|
||||
"623b36e34d9aea1b062b15b3",
|
||||
"623b37de4d9aea1b062b170f",
|
||||
"624fe51b457aa64da9e02ed3",
|
||||
"6176537b515e45415cc7fd15",
|
||||
"6206486d6b4b1e154a3be208",
|
||||
],
|
||||
username: "anand@appsmith.com",
|
||||
name: "Anand Srinivasan",
|
||||
enableTelemetry: true,
|
||||
idToken: {
|
||||
sub: "109879730040206968321",
|
||||
email_verified: true,
|
||||
name: "Anand Srinivasan",
|
||||
given_name: "Anand",
|
||||
locale: "en",
|
||||
hd: "appsmith.com",
|
||||
family_name: "Srinivasan",
|
||||
picture:
|
||||
"https://lh3.googleusercontent.com/a-/AOh14Gi4HfYY0sKhaG93YAHB_E5-dL4BkFxdf8ZfQ2w7=s96-c",
|
||||
email: "anand@appsmith.com",
|
||||
},
|
||||
accountNonExpired: true,
|
||||
accountNonLocked: true,
|
||||
credentialsNonExpired: true,
|
||||
emptyInstance: false,
|
||||
isAnonymous: false,
|
||||
isEnabled: true,
|
||||
isSuperUser: false,
|
||||
isConfigurable: true,
|
||||
},
|
||||
URL: {
|
||||
fullPath:
|
||||
"https://app.appsmith.com/app/untitled-application-25/page1-6272179d8a368d6f1efcd0d2/edit",
|
||||
host: "app.appsmith.com",
|
||||
hostname: "app.appsmith.com",
|
||||
queryParams: {},
|
||||
protocol: "https:",
|
||||
pathname:
|
||||
"/app/untitled-application-25/page1-6272179d8a368d6f1efcd0d2/edit",
|
||||
port: "",
|
||||
hash: "",
|
||||
},
|
||||
store: {},
|
||||
geolocation: {
|
||||
canBeRequested: true,
|
||||
},
|
||||
mode: "EDIT",
|
||||
ENTITY_TYPE: ENTITY_TYPE.APPSMITH,
|
||||
} as unknown) as DataTreeAppsmith,
|
||||
} as unknown) as DataTree;
|
||||
|
|
|
|||
|
|
@ -1,17 +1,22 @@
|
|||
import DataTreeEvaluator from ".";
|
||||
import {
|
||||
asyncTagUnevalTree,
|
||||
emptyTreeWithAppsmithObject,
|
||||
lintingUnEvalTree,
|
||||
unEvalTree,
|
||||
} from "./mockData/mockUnEvalTree";
|
||||
import { DataTree } from "entities/DataTree/dataTreeFactory";
|
||||
import { DataTreeDiff } from "workers/Evaluation/evaluationUtils";
|
||||
import {
|
||||
DataTreeDiff,
|
||||
DataTreeDiffEvent,
|
||||
} from "workers/Evaluation/evaluationUtils";
|
||||
import { ALL_WIDGETS_AND_CONFIG } from "utils/WidgetRegistry";
|
||||
import { arrayAccessorCyclicDependency } from "./mockData/ArrayAccessorTree";
|
||||
import { nestedArrayAccessorCyclicDependency } from "./mockData/NestedArrayAccessorTree";
|
||||
import { updateDependencyMap } from "workers/common/DependencyMap";
|
||||
import { parseJSActions } from "workers/Evaluation/JSObject";
|
||||
import { WidgetConfiguration } from "widgets/constants";
|
||||
import { JSUpdate, ParsedBody } from "../../../utils/JSPaneUtils";
|
||||
|
||||
const widgetConfigMap: Record<
|
||||
string,
|
||||
|
|
@ -21,6 +26,7 @@ const widgetConfigMap: Record<
|
|||
metaProperties: WidgetConfiguration["properties"]["meta"];
|
||||
}
|
||||
> = {};
|
||||
|
||||
ALL_WIDGETS_AND_CONFIG.map(([, config]) => {
|
||||
if (config.type && config.properties) {
|
||||
widgetConfigMap[config.type] = {
|
||||
|
|
@ -209,17 +215,21 @@ describe("DataTreeEvaluator", () => {
|
|||
|
||||
describe("parseJsActions", () => {
|
||||
beforeEach(() => {
|
||||
dataTreeEvaluator.setupFirstTree(({} as unknown) as DataTree);
|
||||
dataTreeEvaluator.setupFirstTree(
|
||||
(emptyTreeWithAppsmithObject as unknown) as DataTree,
|
||||
);
|
||||
dataTreeEvaluator.evalAndValidateFirstTree();
|
||||
});
|
||||
it("set's isAsync tag for cross JsObject references", () => {
|
||||
const result = parseJSActions(dataTreeEvaluator, asyncTagUnevalTree);
|
||||
expect(
|
||||
result.jsUpdates["JSObject1"]?.parsedBody?.actions[0].isAsync,
|
||||
).toBe(true);
|
||||
expect(
|
||||
result.jsUpdates["JSObject2"]?.parsedBody?.actions[0].isAsync,
|
||||
).toBe(true);
|
||||
const jsUpdatesForJsObject1 = (result as Record<string, JSUpdate>)[
|
||||
"JSObject1"
|
||||
].parsedBody as ParsedBody;
|
||||
const jsUpdatesForJsObject2 = (result as Record<string, JSUpdate>)[
|
||||
"JSObject2"
|
||||
].parsedBody as ParsedBody;
|
||||
expect(jsUpdatesForJsObject1.actions[0].isAsync).toBe(true);
|
||||
expect(jsUpdatesForJsObject2.actions[0].isAsync).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -21,14 +21,15 @@ import {
|
|||
import { ECMA_VERSION, SourceType, NodeTypes } from "./src/constants";
|
||||
|
||||
// JSObjects
|
||||
import { parseJSObjectWithAST } from "./src/jsObject";
|
||||
import { parseJSObjectWithAST, JsObjectProperty } from "./src/jsObject";
|
||||
|
||||
// types or intefaces should be exported with type keyword, while enums can be exported like normal functions
|
||||
// types or interfaces should be exported with type keyword, while enums can be exported like normal functions
|
||||
export type {
|
||||
ObjectExpression,
|
||||
PropertyNode,
|
||||
MemberExpressionData,
|
||||
IdentifierInfo,
|
||||
JsObjectProperty,
|
||||
};
|
||||
|
||||
export {
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ import {
|
|||
functionParam,
|
||||
} from "../index";
|
||||
|
||||
type JsObjectProperty = {
|
||||
export type JsObjectProperty = {
|
||||
key: string;
|
||||
value: string;
|
||||
type: string;
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user