diff --git a/app/client/src/workers/Evaluation/JSObject/index.ts b/app/client/src/workers/Evaluation/JSObject/index.ts index 4c9c6b35f785..79dce10b39bb 100644 --- a/app/client/src/workers/Evaluation/JSObject/index.ts +++ b/app/client/src/workers/Evaluation/JSObject/index.ts @@ -114,18 +114,17 @@ export function saveResolvedFunctionsAndJSUpdates( JSObjectName: entityName, JSObjectASTParseTime, }); - // TODO: Fix this the next time the file is edited - // eslint-disable-next-line @typescript-eslint/no-explicit-any - const actions: any = []; - // TODO: Fix this the next time the file is edited - // eslint-disable-next-line @typescript-eslint/no-explicit-any - const variables: any = []; + + const actionsMap: Record = {}; + const variablesMap: Record = {}; if (success) { if (!!parsedObject) { jsPropertiesState.update(entityName, parsedObject); parsedObject.forEach((parsedElement) => { if (isJSFunctionProperty(parsedElement)) { + if (actionsMap[parsedElement.key]) return; + try { ExecutionMetaData.setExecutionMetaData({ enableJSVarUpdateTracking: false, @@ -164,12 +163,11 @@ export function saveResolvedFunctionsAndJSUpdates( `${entityName}.${parsedElement.key}`, functionString, ); - actions.push({ + actionsMap[parsedElement.key] = { name: parsedElement.key, body: functionString, arguments: params, - parsedFunction: result, - }); + }; } } catch { // in case we need to handle error state @@ -184,10 +182,10 @@ export function saveResolvedFunctionsAndJSUpdates( ? parsedElement.key.slice(1, -1) : parsedElement.key; - variables.push({ + variablesMap[parsedKey] = { name: parsedKey, value: parsedElement.value, - }); + }; JSObjectCollection.updateUnEvalState( `${entityName}.${parsedElement.key}`, parsedElement.value, @@ -196,8 +194,8 @@ export function saveResolvedFunctionsAndJSUpdates( }); const parsedBody = { body: entity.body, - actions: actions, - variables, + actions: Object.values(actionsMap), + variables: Object.values(variablesMap), }; set(jsUpdates, `${entityName}`, { @@ -312,8 +310,6 @@ export function parseJSActions( parsedBody.actions = parsedBody.actions.map((action) => { return { ...action, - // parsedFunction - used only to determine if function is async - parsedFunction: undefined, } as ParsedJSSubAction; }); }); diff --git a/app/client/src/workers/Evaluation/JSObject/test.ts b/app/client/src/workers/Evaluation/JSObject/test.ts index 3a4cebe482d0..ccfb1c6c969c 100644 --- a/app/client/src/workers/Evaluation/JSObject/test.ts +++ b/app/client/src/workers/Evaluation/JSObject/test.ts @@ -1,5 +1,14 @@ import type { ConfigTree, UnEvalTree } from "entities/DataTree/dataTreeTypes"; -import { getUpdatedLocalUnEvalTreeAfterJSUpdates } from "."; +import { + getUpdatedLocalUnEvalTreeAfterJSUpdates, + saveResolvedFunctionsAndJSUpdates, +} from "."; +import type { JSUpdate } from "utils/JSPaneUtils"; +import type { + JSActionEntity, + JSActionEntityConfig, +} from "ee/entities/DataTree/types"; +import DataTreeEvaluator from "workers/common/DataTreeEvaluator"; describe("updateJSCollectionInUnEvalTree", function () { it("updates async value of jsAction", () => { @@ -137,3 +146,119 @@ describe("updateJSCollectionInUnEvalTree", function () { expect(expectedResult).toStrictEqual(actualResult); }); }); + +describe("saveResolvedFunctionsAndJSUpdates", function () { + it("parses JSObject with duplicate actions, variables and updates jsUpdates correctly", () => { + const dataTreeEvalRef = new DataTreeEvaluator({}); + const entity: JSActionEntity = { + actionId: "64013546b956c26882acc587", + body: "export default {\n\tmyVar1: [],\n\tmyVar1: [],\n\tmyVar2: {},\n\tmyFun1: () => {\n\t\t//write code here\n\t\t\n\t},\n\tmyFun2: () => {\n\t\t//use async-await or promises\n\t\tyeso\n\t}\n,\n\tmyFun2: () => {\n\t\t//use async-await or promises\n\t\tyeso\n\t}}", + ENTITY_TYPE: "JSACTION", + name: "JSObject1", + pluginType: "JS", + }; + const jsUpdates: Record = {}; + const unEvalDataTree: UnEvalTree = { + JSObject1: { + myVar1: "[]", + myVar2: "{}", + myFun1: new String("() => {}"), + myFun2: new String("async () => {\n yeso;\n}"), + body: "export default {\n\tmyVar1: [],\n\tmyVar1: [],\n\tmyVar2: {},\n\tmyFun1: () => {\n\t\t//write code here\n\t\t\n\t},\n\tmyFun2: () => {\n\t\t//use async-await or promises\n\t\tyeso\n\t}\n,\n\tmyFun2: () => {\n\t\t//use async-await or promises\n\t\tyeso\n\t}}", + ENTITY_TYPE: "JSACTION", + meta: { + myFun1: { + arguments: [], + confirmBeforeExecute: false, + }, + myFun2: { + arguments: [], + confirmBeforeExecute: false, + }, + }, + dependencyMap: { + body: ["myFun1", "myFun2"], + }, + dynamicBindingPathList: [ + { + key: "body", + }, + { + key: "myVar1", + }, + { + key: "myVar2", + }, + { + key: "myFun1", + }, + { + key: "myFun2", + }, + { + key: "myFun2", + }, + ], + bindingPaths: { + body: "SMART_SUBSTITUTE", + myVar1: "SMART_SUBSTITUTE", + myVar2: "SMART_SUBSTITUTE", + myFun1: "SMART_SUBSTITUTE", + myFun2: "SMART_SUBSTITUTE", + }, + reactivePaths: { + body: "SMART_SUBSTITUTE", + myVar1: "SMART_SUBSTITUTE", + myVar2: "SMART_SUBSTITUTE", + myFun1: "SMART_SUBSTITUTE", + myFun2: "SMART_SUBSTITUTE", + }, + pluginType: "JS", + name: "JSObject1", + actionId: "64013546b956c26882acc587", + } as JSActionEntityConfig, + }; + const entityName = "JSObject1"; + + const result = saveResolvedFunctionsAndJSUpdates( + dataTreeEvalRef, + entity, + jsUpdates, + unEvalDataTree, + entityName, + ); + + const expectedJSUpdates = { + JSObject1: { + parsedBody: { + body: "export default {\n\tmyVar1: [],\n\tmyVar1: [],\n\tmyVar2: {},\n\tmyFun1: () => {\n\t\t//write code here\n\t\t\n\t},\n\tmyFun2: () => {\n\t\t//use async-await or promises\n\t\tyeso\n\t}\n,\n\tmyFun2: () => {\n\t\t//use async-await or promises\n\t\tyeso\n\t}}", + actions: [ + { + name: "myFun1", + body: "() => {}", + arguments: [], + }, + { + name: "myFun2", + body: "() => {\n yeso;\n}", + arguments: [], + }, + ], + variables: [ + { + name: "myVar1", + value: "[]", + }, + { + name: "myVar2", + value: "{}", + }, + ], + }, + id: "64013546b956c26882acc587", + }, + }; + + expect(result).toStrictEqual(expectedJSUpdates); + }); +});