diff --git a/apps/builder/src/page/App/Module/LeftPanel/Components/DebugButton/index.tsx b/apps/builder/src/page/App/Module/LeftPanel/Components/DebugButton/index.tsx index 3af02d2b79..cb194f4e6c 100644 --- a/apps/builder/src/page/App/Module/LeftPanel/Components/DebugButton/index.tsx +++ b/apps/builder/src/page/App/Module/LeftPanel/Components/DebugButton/index.tsx @@ -6,11 +6,11 @@ import { useDispatch, useSelector } from "react-redux" import { Badge, BugIcon, Trigger, getColor } from "@illa-design/react" import { isOpenDebugger } from "@/redux/config/configSelector" import { configActions } from "@/redux/config/configSlice" -import { getExecutionDebuggerData } from "@/redux/currentApp/executionTree/executionSelector" +import { getExecutionError } from "@/redux/currentApp/executionTree/executionSelector" import { trackInEditor } from "@/utils/mixpanelHelper" const DebugButton: FC = () => { - const debuggerData = useSelector(getExecutionDebuggerData) + const debuggerData = useSelector(getExecutionError) const debuggerVisible = useSelector(isOpenDebugger) const debugMessageNumber = debuggerData diff --git a/apps/builder/src/page/App/components/Debugger/index.tsx b/apps/builder/src/page/App/components/Debugger/index.tsx index f1583d9ef2..f95fa7e149 100644 --- a/apps/builder/src/page/App/components/Debugger/index.tsx +++ b/apps/builder/src/page/App/components/Debugger/index.tsx @@ -5,7 +5,7 @@ import { DragBar } from "@/page/App/components/Actions/DragBar" import { ErrorItem } from "@/page/App/components/Debugger/components/ErrorItem" import { isOpenDebugger } from "@/redux/config/configSelector" import { configActions } from "@/redux/config/configSlice" -import { getExecutionDebuggerData } from "@/redux/currentApp/executionTree/executionSelector" +import { getExecutionError } from "@/redux/currentApp/executionTree/executionSelector" import { applyDebuggerStyle, containerStyle, @@ -18,7 +18,7 @@ const DebuggerDefaultHeight = 300 export const Debugger: FC> = (props) => { const dispatch = useDispatch() const panelRef = useRef(null) - const debuggerData = useSelector(getExecutionDebuggerData) + const debuggerData = useSelector(getExecutionError) const debuggerVisible = useSelector(isOpenDebugger) const handleClickDebuggerIcon = useCallback(() => { diff --git a/apps/builder/src/page/App/components/InspectPanel/PanelSetters/ChartSetter/chartKeysDynamicSelectSetter.tsx b/apps/builder/src/page/App/components/InspectPanel/PanelSetters/ChartSetter/chartKeysDynamicSelectSetter.tsx index 8d315a0891..fd72c5b740 100644 --- a/apps/builder/src/page/App/components/InspectPanel/PanelSetters/ChartSetter/chartKeysDynamicSelectSetter.tsx +++ b/apps/builder/src/page/App/components/InspectPanel/PanelSetters/ChartSetter/chartKeysDynamicSelectSetter.tsx @@ -119,11 +119,12 @@ const ChartKeysDynamicSelectSetter: FC = ( [generateNewDatasets, handleUpdateMultiAttrDSL, value], ) - const isError = useSelector((state) => { - const errors = getExecutionError(state) - const thisError = get(errors, `${widgetDisplayName}.${attrName}JS`) - return thisError?.length > 0 - }) + const executionErrors = useSelector(getExecutionError) + const isError = useMemo(() => { + return ( + (executionErrors[`${widgetDisplayName}.${attrName}JS`] ?? [])?.length > 0 + ) + }, [attrName, executionErrors, widgetDisplayName]) const isDynamic = useMemo(() => { const dataSourceMode = get( diff --git a/apps/builder/src/page/App/components/InspectPanel/PanelSetters/DataGridSetter/ColumnMappedSelect/index.tsx b/apps/builder/src/page/App/components/InspectPanel/PanelSetters/DataGridSetter/ColumnMappedSelect/index.tsx index bd9f9243d1..6c26047ded 100644 --- a/apps/builder/src/page/App/components/InspectPanel/PanelSetters/DataGridSetter/ColumnMappedSelect/index.tsx +++ b/apps/builder/src/page/App/components/InspectPanel/PanelSetters/DataGridSetter/ColumnMappedSelect/index.tsx @@ -56,11 +56,13 @@ const ColumnMappedSelect: FC = (props) => { "select", ) === "dynamic" - const isError = useSelector((state) => { - const errors = getExecutionError(state) - const thisError = get(errors, `${widgetDisplayName}.${attrName}JS`) - return thisError?.length > 0 - }) + const executionErrors = useSelector(getExecutionError) + const isError = useMemo(() => { + return ( + (executionErrors[`${widgetDisplayName}.${attrName}JS`] ?? [])?.length > 0 + ) + }, [attrName, executionErrors, widgetDisplayName]) + const handleClickFxButton = useCallback(() => { if (isDynamic) { handleUpdateDsl(`${widgetDisplayName}.${attrName}JS`, "select") diff --git a/apps/builder/src/page/App/components/InspectPanel/PanelSetters/SelectSetter/dataSourceSelectSetter.tsx b/apps/builder/src/page/App/components/InspectPanel/PanelSetters/SelectSetter/dataSourceSelectSetter.tsx index 2da81c18a3..742f16fd1c 100644 --- a/apps/builder/src/page/App/components/InspectPanel/PanelSetters/SelectSetter/dataSourceSelectSetter.tsx +++ b/apps/builder/src/page/App/components/InspectPanel/PanelSetters/SelectSetter/dataSourceSelectSetter.tsx @@ -13,11 +13,13 @@ import { VALIDATION_TYPES } from "@/utils/validationFactory" const DataSourceSetter: FC = (props) => { const { handleUpdateDsl, widgetDisplayName, labelName, labelDesc } = props const actions = useSelector(getActionList) - const isError = useSelector((state) => { - const errors = getExecutionError(state) - const thisError = get(errors, `${widgetDisplayName}.dataSource`) - return thisError?.length > 0 - }) + const executionErrors = useSelector(getExecutionError) + const isError = useMemo(() => { + return ( + (executionErrors[`${widgetDisplayName}.dataSource`] ?? [])?.length > 0 + ) + }, [executionErrors, widgetDisplayName]) + const targetComponentProps = useSelector>( (rootState) => { return searchDSLByDisplayName(widgetDisplayName, rootState)?.props || {} diff --git a/apps/builder/src/page/App/components/InspectPanel/PanelSetters/SelectSetter/dynamicSelectSetter.tsx b/apps/builder/src/page/App/components/InspectPanel/PanelSetters/SelectSetter/dynamicSelectSetter.tsx index be54a73927..30954acb60 100644 --- a/apps/builder/src/page/App/components/InspectPanel/PanelSetters/SelectSetter/dynamicSelectSetter.tsx +++ b/apps/builder/src/page/App/components/InspectPanel/PanelSetters/SelectSetter/dynamicSelectSetter.tsx @@ -1,5 +1,5 @@ import { get } from "lodash-es" -import { FC, useCallback } from "react" +import { FC, useCallback, useMemo } from "react" import { useSelector } from "react-redux" import BaseDynamicSelect from "@/page/App/components/InspectPanel/PanelSetters/SelectSetter/baseDynamicSelect" import { publicPaddingStyle } from "@/page/App/components/InspectPanel/style" @@ -37,11 +37,12 @@ const DynamicSelectSetter: FC = (props) => { [handleUpdateMultiAttrDSL], ) - const isError = useSelector((state) => { - const errors = getExecutionError(state) - const thisError = get(errors, `${widgetDisplayName}.${attrName}JS`) - return thisError?.length > 0 - }) + const executionErrors = useSelector(getExecutionError) + const isError = useMemo(() => { + return ( + (executionErrors[`${widgetDisplayName}.${attrName}JS`] ?? [])?.length > 0 + ) + }, [attrName, executionErrors, widgetDisplayName]) const isDynamic = get( diff --git a/apps/builder/src/page/App/components/InspectPanel/PanelSetters/TableSetter/tableDataSourceSelectSetter.tsx b/apps/builder/src/page/App/components/InspectPanel/PanelSetters/TableSetter/tableDataSourceSelectSetter.tsx index 07217457e1..150a1ceed7 100644 --- a/apps/builder/src/page/App/components/InspectPanel/PanelSetters/TableSetter/tableDataSourceSelectSetter.tsx +++ b/apps/builder/src/page/App/components/InspectPanel/PanelSetters/TableSetter/tableDataSourceSelectSetter.tsx @@ -31,11 +31,14 @@ const TableDataSourceSelectSetter: FC = (props) => { const actions = useSelector(getActionList) const executionResult = useSelector(getExecutionResult) - const isError = useSelector((state) => { - const errors = getExecutionError(state) - const thisError = get(errors, `${widgetDisplayName}.dataSource`) - return thisError?.length > 0 - }) + + const executionErrors = useSelector(getExecutionError) + const isError = useMemo(() => { + return ( + (executionErrors[`${widgetDisplayName}.dataSource`] ?? [])?.length > 0 + ) + }, [executionErrors, widgetDisplayName]) + const targetComponentProps = useSelector>( (rootState) => { return searchDSLByDisplayName(widgetDisplayName, rootState)?.props || {} diff --git a/apps/builder/src/page/App/components/ScaleSquare/components/ResizingAndDragContainer/index.tsx b/apps/builder/src/page/App/components/ScaleSquare/components/ResizingAndDragContainer/index.tsx index ba2603e66b..2df5cba547 100644 --- a/apps/builder/src/page/App/components/ScaleSquare/components/ResizingAndDragContainer/index.tsx +++ b/apps/builder/src/page/App/components/ScaleSquare/components/ResizingAndDragContainer/index.tsx @@ -93,8 +93,13 @@ export const ResizingAndDragContainer: FC = ( const currentUserID = useSelector(getCurrentUserId) const errors = useSelector(getExecutionError) const hasError = useMemo(() => { - const widgetErrors = errors[displayName] ?? {} - return Object.keys(widgetErrors).length > 0 + const keys = Object.keys(errors) + return ( + keys.length > 0 && + keys.some((key) => { + return key.startsWith(displayName) + }) + ) }, [displayName, errors]) const resizingIDs = useSelector(getResizingComponentIDs) const isResizingCurrent = resizingIDs.includes(displayName) diff --git a/apps/builder/src/page/App/components/ScaleSquare/components/WrapperContainer/index.tsx b/apps/builder/src/page/App/components/ScaleSquare/components/WrapperContainer/index.tsx index 99ce38243f..ad4b8c230e 100644 --- a/apps/builder/src/page/App/components/ScaleSquare/components/WrapperContainer/index.tsx +++ b/apps/builder/src/page/App/components/ScaleSquare/components/WrapperContainer/index.tsx @@ -27,11 +27,16 @@ const WrapperContainer: FC = (props) => { }, [displayName, selectedComponents]) const realProps: Record = get(executionResult, displayName, {}) - const hasError = useMemo(() => { - const widgetErrors = errors[displayName] ?? {} - return Object.keys(widgetErrors).length > 0 + const keys = Object.keys(errors) + return ( + keys.length > 0 && + keys.some((key) => { + return key.startsWith(displayName) + }) + ) }, [displayName, errors]) + const isAutoLimitedMode = realProps?.dynamicHeight === "limited" const isOverLap = isAutoLimitedMode && diff --git a/apps/builder/src/page/App/components/ScaleSquare/utils/useScaleStateSelector.ts b/apps/builder/src/page/App/components/ScaleSquare/utils/useScaleStateSelector.ts index 475ce28d8c..fff9ee2c0a 100644 --- a/apps/builder/src/page/App/components/ScaleSquare/utils/useScaleStateSelector.ts +++ b/apps/builder/src/page/App/components/ScaleSquare/utils/useScaleStateSelector.ts @@ -7,8 +7,13 @@ import { getScaleSquareState } from "../components/ResizingAndDragContainer/util export const useScaleStateSelector = (displayName: string) => { const errors = useSelector(getExecutionError) const hasError = useMemo(() => { - const widgetErrors = errors[displayName] ?? {} - return Object.keys(widgetErrors).length > 0 + const keys = Object.keys(errors) + return ( + keys.length > 0 && + keys.some((key) => { + return key.startsWith(displayName) + }) + ) }, [displayName, errors]) const isEditMode = useSelector(getIsILLAEditMode) diff --git a/apps/builder/src/redux/currentApp/executionTree/executionListener.ts b/apps/builder/src/redux/currentApp/executionTree/executionListener.ts index 0a501e5e6d..26aa562aa3 100644 --- a/apps/builder/src/redux/currentApp/executionTree/executionListener.ts +++ b/apps/builder/src/redux/currentApp/executionTree/executionListener.ts @@ -31,7 +31,6 @@ const asyncExecutionDataToRedux = ( const evaluatedTree = executionResult.evaluatedTree const dependencyMap = executionResult.dependencyTree const independencyMap = executionResult.independencyTree - const debuggerData = executionResult.debuggerData const updates = diff(oldExecutionTree, evaluatedTree) || [] listenerApi.dispatch( executionActions.setExecutionResultReducer({ @@ -53,11 +52,6 @@ const asyncExecutionDataToRedux = ( ...errorTree, }), ) - listenerApi.dispatch( - executionActions.setExecutionDebuggerDataReducer({ - ...debuggerData, - }), - ) } async function handleStartExecution( @@ -104,23 +98,19 @@ async function handleStartExecutionOnCanvas( executionTree.updateTreeFromExecution(oldExecutionTree) const evaluatedTree = executionResult.evaluatedTree const errorTree = executionResult.errorTree - const debuggerData = executionResult.debuggerData const updates = diff(oldExecutionTree, evaluatedTree) || [] - listenerApi.dispatch( - executionActions.setExecutionResultReducer({ - updates, - }), - ) - listenerApi.dispatch( - executionActions.setExecutionErrorReducer({ - ...errorTree, - }), - ) - listenerApi.dispatch( - executionActions.setExecutionDebuggerDataReducer({ - ...debuggerData, - }), - ) + if (updates.length > 0) { + listenerApi.dispatch( + executionActions.setExecutionResultReducer({ + updates, + }), + ) + listenerApi.dispatch( + executionActions.setExecutionErrorReducer({ + ...errorTree, + }), + ) + } } } diff --git a/apps/builder/src/redux/currentApp/executionTree/executionReducer.ts b/apps/builder/src/redux/currentApp/executionTree/executionReducer.ts index 5ba7f402d2..4c7039964e 100644 --- a/apps/builder/src/redux/currentApp/executionTree/executionReducer.ts +++ b/apps/builder/src/redux/currentApp/executionTree/executionReducer.ts @@ -55,13 +55,6 @@ export const setExecutionErrorReducer: CaseReducer< state.error = action.payload } -export const setExecutionDebuggerDataReducer: CaseReducer< - ExecutionState, - PayloadAction> -> = (state, action) => { - state.debuggerData = action.payload -} - export const startExecutionReducer: CaseReducer< ExecutionState, PayloadAction diff --git a/apps/builder/src/redux/currentApp/executionTree/executionSelector.ts b/apps/builder/src/redux/currentApp/executionTree/executionSelector.ts index 2586e815c4..43e84f9959 100644 --- a/apps/builder/src/redux/currentApp/executionTree/executionSelector.ts +++ b/apps/builder/src/redux/currentApp/executionTree/executionSelector.ts @@ -56,10 +56,6 @@ export const getExecutionError = createSelector( (execution) => execution.error ?? {}, ) -export const getExecutionDebuggerData = createSelector( - [getExecution], - (execution) => execution.debuggerData ?? {}, -) export const IGNORE_WIDGET_TYPES = new Set([ "PAGE_NODE", "SECTION_NODE", diff --git a/apps/builder/src/redux/currentApp/executionTree/executionSlice.ts b/apps/builder/src/redux/currentApp/executionTree/executionSlice.ts index db8bb56c60..d539338162 100644 --- a/apps/builder/src/redux/currentApp/executionTree/executionSlice.ts +++ b/apps/builder/src/redux/currentApp/executionTree/executionSlice.ts @@ -3,7 +3,6 @@ import { clearLocalStorageInExecutionReducer, resetExecutionResultReducer, setDependenciesReducer, - setExecutionDebuggerDataReducer, setExecutionErrorReducer, setExecutionResultReducer, setGlobalStateInExecutionReducer, @@ -26,7 +25,6 @@ const executionSlice = createSlice({ setIndependenciesReducer, setExecutionResultReducer, setExecutionErrorReducer, - setExecutionDebuggerDataReducer, startExecutionReducer, updateExecutionByDisplayNameReducer, updateExecutionByMultiDisplayNameReducer, diff --git a/apps/builder/src/redux/currentApp/executionTree/executionState.ts b/apps/builder/src/redux/currentApp/executionTree/executionState.ts index 6bd95d61a8..d5aa7040dc 100644 --- a/apps/builder/src/redux/currentApp/executionTree/executionState.ts +++ b/apps/builder/src/redux/currentApp/executionTree/executionState.ts @@ -19,7 +19,6 @@ export interface ExecutionState { dependencies: DependenciesState result: Record error: Record - debuggerData: Record independencies: DependenciesState } @@ -27,7 +26,6 @@ export const executionInitialState: ExecutionState = { dependencies: {}, result: {}, error: {}, - debuggerData: {}, independencies: {}, } diff --git a/apps/builder/src/utils/executionTreeHelper/executionTreeFactory.ts b/apps/builder/src/utils/executionTreeHelper/executionTreeFactory.ts index f510489e93..68fada0144 100644 --- a/apps/builder/src/utils/executionTreeHelper/executionTreeFactory.ts +++ b/apps/builder/src/utils/executionTreeHelper/executionTreeFactory.ts @@ -4,7 +4,7 @@ import { } from "@illa-public/dynamic-string" import { Diff, diff } from "deep-diff" import { klona } from "klona" -import { flatten, get, set, toPath, unset } from "lodash-es" +import { flatten, get, merge, set, toPath, unset } from "lodash-es" import toposort from "toposort" import { createMessage } from "@illa-design/react" import i18n from "@/i18n/config" @@ -68,7 +68,6 @@ export class ExecutionTreeFactory { hasCyclical: boolean = false executedTree: RawTreeShape = {} as RawTreeShape errorTree: Record = {} - debuggerData: Record = {} allKeys: Record = {} runningActionsMap: Map = new Map() @@ -82,7 +81,6 @@ export class ExecutionTreeFactory { this.hasCyclical = false this.executedTree = {} as RawTreeShape this.errorTree = {} - this.debuggerData = {} this.allKeys = {} this.runningActionsMap = new Map() @@ -96,19 +94,23 @@ export class ExecutionTreeFactory { this.dependenciesState = this.generateDependenciesMap(currentRawTree) this.evalOrder = this.sortEvalOrder(this.dependenciesState) this.inDependencyTree = this.generateInDependenciesMap() - const { evaluatedTree, errorTree, debuggerData } = this.executeTree( + const { evaluatedTree, errorTree } = this.executeTree( currentRawTree, this.evalOrder, ) - this.errorTree = errorTree - this.debuggerData = debuggerData - this.executedTree = this.validateTree(evaluatedTree) + + const { validateErrors, validateResultTree } = + this.validateTree(evaluatedTree) + + const mergedError = merge(errorTree, validateErrors) + this.errorTree = mergedError + + this.executedTree = validateResultTree } catch (e) { return { dependencyTree: this.dependenciesState, evaluatedTree: currentRawTree, errorTree: this.errorTree, - debuggerData: this.debuggerData, independencyTree: this.inDependencyTree, } } @@ -117,78 +119,88 @@ export class ExecutionTreeFactory { dependencyTree: this.dependenciesState, evaluatedTree: this.executedTree, errorTree: this.errorTree, - debuggerData: this.debuggerData, independencyTree: this.inDependencyTree, } } validateTree(tree: RawTreeShape) { - return Object.keys(tree).reduce((current: RawTreeShape, displayName) => { - const widgetOrAction = current[displayName] - if (!isWidget(widgetOrAction) && !isAction(widgetOrAction)) { - return current - } - const validationPaths = widgetOrAction.$validationPaths - const listWidgets = - getContainerListDisplayNameMappedChildrenNodeDisplayName( - store.getState(), - ) + const validateErrors: Record = klona(this.errorTree) + const validateResultTree = Object.keys(tree).reduce( + (current: RawTreeShape, displayName) => { + const widgetOrAction = current[displayName] + if (!isWidget(widgetOrAction) && !isAction(widgetOrAction)) { + return current + } + const validationPaths = widgetOrAction.$validationPaths + const listWidgets = + getContainerListDisplayNameMappedChildrenNodeDisplayName( + store.getState(), + ) - const listWidgetDisplayNames = Object.keys(listWidgets) - let currentListDisplayName = "" - for (let i = 0; i < listWidgetDisplayNames.length; i++) { - if (listWidgets[listWidgetDisplayNames[i]].includes(displayName)) { - currentListDisplayName = listWidgetDisplayNames[i] - break + const listWidgetDisplayNames = Object.keys(listWidgets) + let currentListDisplayName = "" + for (let i = 0; i < listWidgetDisplayNames.length; i++) { + if (listWidgets[listWidgetDisplayNames[i]].includes(displayName)) { + currentListDisplayName = listWidgetDisplayNames[i] + break + } } - } - if (isObject(validationPaths)) { - getObjectPaths(validationPaths).forEach((validationPath) => { - const validationType = get( - validationPaths, - validationPath, - ) as VALIDATION_TYPES - const fullPath = `${displayName}.${validationPath}` - const validationFunc = validationFactory[validationType] - const value = get(widgetOrAction, validationPath) - const { isValid, safeValue, errorMessage } = validationFunc( - value, - currentListDisplayName, - ) - set(current, fullPath, safeValue) - if (!isValid) { - let error = get(this.errorTree, fullPath) - if (!Array.isArray(error)) { - error = [] - } - error.push({ - errorType: ExecutionErrorType.VALIDATION, - errorMessage: errorMessage as string, - errorName: "Validation", - }) - set(this.errorTree, fullPath, error) - this.debuggerData[fullPath] = error - } else { - let error = get(this.errorTree, fullPath) - if (Array.isArray(error)) { - const validationIndex = error.findIndex((v) => { - return v.errorType === ExecutionErrorType.VALIDATION - }) - if (validationIndex !== -1) { - error.splice(validationIndex, 1) - if (error.length === 0) { - unset(this.errorTree, fullPath) - delete this.debuggerData[fullPath] + if (isObject(validationPaths)) { + getObjectPaths(validationPaths).forEach((validationPath) => { + const validationType = get( + validationPaths, + validationPath, + ) as VALIDATION_TYPES + const fullPath = `${displayName}.${validationPath}` + const validationFunc = validationFactory[validationType] + const value = get(widgetOrAction, validationPath) + const { isValid, safeValue, errorMessage } = validationFunc( + value, + currentListDisplayName, + ) + set(current, fullPath, safeValue) + let error = validateErrors[fullPath] + if (!isValid) { + if (!Array.isArray(error)) { + error = [] + } + const hasValidateError = error.some( + (v: any) => v.errorType === ExecutionErrorType.VALIDATION, + ) + if (!hasValidateError) { + error.push({ + errorType: ExecutionErrorType.VALIDATION, + errorMessage: errorMessage as string, + errorName: "Validation", + }) + } + + validateErrors[fullPath] = error + } else { + if (Array.isArray(error)) { + const validationIndex = error.findIndex((v) => { + return v.errorType === ExecutionErrorType.VALIDATION + }) + if (validationIndex !== -1) { + error.splice(validationIndex, 1) + if (error.length === 0) { + delete validateErrors[fullPath] + } } } } - } - }) - } + }) + } - return current - }, tree) + return current + }, + tree, + ) + return { + validateResultTree, + validateErrors, + } } calcSubTreeSortOrder( @@ -286,47 +298,25 @@ export class ExecutionTreeFactory { } mergeErrorTree( - newErrorTree: Record, - paths: string[], - isDeletedAction?: boolean, - ) { - const oldErrorTree = klona(this.errorTree) - paths.forEach((path) => { - if (isDeletedAction) { - unset(oldErrorTree, path) - } - const newErrorTreeValue = get(newErrorTree, path) - if (newErrorTreeValue) { - set(oldErrorTree, path, newErrorTreeValue) - } else { - unset(oldErrorTree, path) - } - }) - this.errorTree = oldErrorTree - } - - mergeDebugDataTree( - newDebugDataTree: Record, - paths: string[], - isDeletedAction?: boolean, + newPartErrorTree: Record, + updatePathMapAction: Record, ) { - const oldDebugDataTree = klona(this.debuggerData) - const allOldDebugDataPaths = Object.keys(oldDebugDataTree || {}) - paths.forEach((path) => { - if (isDeletedAction) { - allOldDebugDataPaths.forEach((dp) => { - dp.includes(path) && delete oldDebugDataTree[dp] + const newErrorTree = klona(this.errorTree) + Object.entries(updatePathMapAction).forEach(([path, action]) => { + if (action === "DELETE") { + Object.keys(newErrorTree).forEach((key) => { + key.startsWith(path) && delete newErrorTree[key] }) - return - } - const newDebugData = newDebugDataTree[path] - if (newDebugData) { - oldDebugDataTree[path] = newDebugData } else { - delete oldDebugDataTree[path] + const newErrorTreeValue = get(newPartErrorTree, path) + if (newErrorTreeValue) { + newErrorTree[path] = newErrorTreeValue + } else { + delete newErrorTree[path] + } } }) - this.debuggerData = oldDebugDataTree + return newErrorTree } updateExecutionTreeByUpdatePaths( @@ -360,6 +350,19 @@ export class ExecutionTreeFactory { return currentExecutionTree } + mergeOrderPathAndUpdateMapActions( + orderPaths: string[], + updateMapActions: Record, + ) { + const newUpdateMapActions = klona(updateMapActions) + orderPaths.forEach((path) => { + if (!newUpdateMapActions[path]) { + newUpdateMapActions[path] = "UPDATE" + } + }) + return newUpdateMapActions + } + updateTree( rawTree: RawTreeShape, isDeleteAction?: boolean, @@ -375,7 +378,6 @@ export class ExecutionTreeFactory { dependencyTree: this.dependenciesState, evaluatedTree: currentRawTree, errorTree: this.errorTree, - debuggerData: this.debuggerData, independencyTree: this.inDependencyTree, } } @@ -391,9 +393,7 @@ export class ExecutionTreeFactory { } } this.oldRawTree = klona(currentRawTree) - const updatePaths = this.getUpdatePathFromDifferences(differences) - const updatePathMapAction = - this.getNewUpdatePathFromDifferences(differences) + const updatePathMapAction = this.getUpdatePathFromDifferences(differences) const walkedPath = new Set() let currentExecution = this.updateExecutionTreeByUpdatePaths( @@ -409,26 +409,31 @@ export class ExecutionTreeFactory { !isAddAction, ) - const { evaluatedTree, errorTree, debuggerData } = this.executeTree( + const mergedUpdatePathMapAction = this.mergeOrderPathAndUpdateMapActions( + path, + updatePathMapAction, + ) + const { evaluatedTree, errorTree } = this.executeTree( currentExecution, path, -1, ) + const { validateErrors, validateResultTree } = + this.validateTree(evaluatedTree) - this.mergeErrorTree(errorTree, [...updatePaths, ...path], isDeleteAction) - this.mergeDebugDataTree( - debuggerData, - [...updatePaths, ...path], - isDeleteAction, + const mergedError = merge({}, validateErrors, errorTree) + const errorTreeResult = this.mergeErrorTree( + mergedError, + mergedUpdatePathMapAction, ) + this.errorTree = errorTreeResult - this.executedTree = this.validateTree(evaluatedTree) + this.executedTree = validateResultTree this.executedTree.globalData = evaluatedTree.root.globalData return { dependencyTree: this.dependenciesState, evaluatedTree: this.executedTree, errorTree: this.errorTree, - debuggerData: this.debuggerData, independencyTree: this.inDependencyTree, } } @@ -439,60 +444,6 @@ export class ExecutionTreeFactory { getUpdatePathFromDifferences( differences: Diff, Record>[], - ) { - const updatePaths: string[] = [] - for (const d of differences) { - if (!Array.isArray(d.path) || d.path.length === 0) continue - const subPaths = klona(d.path) - let current = "" - const originalPathLength = subPaths.length - if (subPaths.includes("pageInfos")) { - updatePaths.push("pageInfos") - continue - } - - while (subPaths.length > 1) { - current = convertPathToString(subPaths) - updatePaths.push(current) - subPaths.pop() - } - if (originalPathLength === 1 && d.kind === "N") { - const rhs = d.rhs - if (rhs && typeof rhs === "object") { - const keys = Object.keys(rhs) - keys.forEach((key) => { - updatePaths.push(`${convertPathToString([subPaths[0], key])}`) - }) - } - } - if (originalPathLength === 1 && d.kind === "D") { - updatePaths.push(`${subPaths[0]}`) - } - if (originalPathLength === 1 && d.kind === "E") { - updatePaths.push(`${subPaths[0]}`) - } - if (d.kind === "A") { - const { index, path } = d - - updatePaths.push( - `${convertPathToString([ - ...subPaths, - ...path.filter((p) => !subPaths.includes(p)), - index, - ])}`, - ) - } - } - const hasPath = new Set() - return updatePaths.filter((path) => { - if (hasPath.has(path)) return false - hasPath.add(path) - return true - }) - } - - getNewUpdatePathFromDifferences( - differences: Diff, Record>[], ) { const updatePathMapAction: Record = {} for (const d of differences) { @@ -576,8 +527,8 @@ export class ExecutionTreeFactory { } const walkedPath = new Set() - const updatePaths = this.getUpdatePathFromDifferences(differences) - updatePaths.forEach((path) => { + const updatePathMapAction = this.getUpdatePathFromDifferences(differences) + Object.keys(updatePathMapAction).forEach((path) => { walkedPath.add(path) }) @@ -587,24 +538,34 @@ export class ExecutionTreeFactory { true, ) + const mergedUpdatePathMapAction = this.mergeOrderPathAndUpdateMapActions( + orderPath, + updatePathMapAction, + ) + let currentRawTree = this.updateRawTreeByUpdatePaths( orderPath, currentExecutionTree, walkedPath, ) as RawTreeShape - const { evaluatedTree, errorTree, debuggerData } = this.executeTree( + const { evaluatedTree, errorTree } = this.executeTree( currentRawTree, orderPath, ) - this.mergeErrorTree(errorTree, [...updatePaths, ...orderPath]) - this.mergeDebugDataTree(debuggerData, [...updatePaths, ...orderPath]) - this.executedTree = this.validateTree(evaluatedTree) + const { validateErrors, validateResultTree } = + this.validateTree(evaluatedTree) + const mergedError = merge({}, validateErrors, errorTree) + const errorTreeResult = this.mergeErrorTree( + mergedError, + mergedUpdatePathMapAction, + ) + this.errorTree = errorTreeResult + this.executedTree = validateResultTree return { evaluatedTree: this.executedTree, errorTree: this.errorTree, - debuggerData: this.debuggerData, } } @@ -722,7 +683,6 @@ export class ExecutionTreeFactory { ) { const oldLocalRawTree = klona(oldRawTree) const errorTree: ExecutionState["error"] = {} - const debuggerData: ExecutionState["error"] = {} try { const evaluatedTree = sortedEvalOrder.reduce( (current: RawTreeShape, fullPath: string, currentIndex: number) => { @@ -757,7 +717,7 @@ export class ExecutionTreeFactory { set(current, fullPath, evaluateValue) } } catch (e) { - const oldError = get(errorTree, fullPath, []) as ErrorShape[] + const oldError = errorTree[fullPath] ?? ([] as ErrorShape[]) if (Array.isArray(oldError)) { oldError.push({ errorType: ExecutionErrorType.EVALUATED, @@ -765,9 +725,8 @@ export class ExecutionTreeFactory { errorName: (e as Error).name, }) } - set(errorTree, fullPath, oldError) + errorTree[fullPath] = oldError set(current, fullPath, undefined) - debuggerData[fullPath] = oldError } } if ( @@ -802,9 +761,9 @@ export class ExecutionTreeFactory { }, oldLocalRawTree, ) - return { evaluatedTree, errorTree, debuggerData } + return { evaluatedTree, errorTree } } catch (e) { - return { evaluatedTree: oldLocalRawTree, errorTree, debuggerData } + return { evaluatedTree: oldLocalRawTree, errorTree } } } }