hunk.code_window: import { DataTree } from "entities/DataTree/dataTreeFactory";
   import { createImmerReducer } from "utils/AppsmithUtils";
   import * as Sentry from "@sentry/react";
   import log from "loglevel";
   export type EvaluatedTreeState = DataTree;
   const initialState: EvaluatedTreeState = {};
  
hunk.labels: keep keep keep replace keep keep keep keep keep
hunk.file_path: app/client/src/reducers/evaluationReducers/treeReducer.ts
hunk.type: replace
file: import {
    actionChannel,
    call,
    fork,
    put,
    select,
    take,
  } from "redux-saga/effects";
  
  import {
    EvaluationReduxAction,
    ReduxAction,
    ReduxActionTypes,
    ReduxActionWithoutPayload,
  } from "constants/ReduxActionConstants";
  import {
    getDataTree,
    getUnevaluatedDataTree,
  } from "selectors/dataTreeSelectors";
  import WidgetFactory, { WidgetTypeConfigMap } from "../utils/WidgetFactory";
  import { GracefulWorkerService } from "utils/WorkerUtil";
  import Worker from "worker-loader!../workers/evaluation.worker";
  import { EVAL_WORKER_ACTIONS } from "utils/DynamicBindingUtils";
  import log from "loglevel";
  import { WidgetProps } from "widgets/BaseWidget";
  import PerformanceTracker, {
    PerformanceTransactionName,
  } from "../utils/PerformanceTracker";
  import * as Sentry from "@sentry/react";
  import { Action } from "redux";
  import {
    EVALUATE_REDUX_ACTIONS,
    FIRST_EVAL_REDUX_ACTIONS,
    setDependencyMap,
    setEvaluatedTree,
    shouldProcessBatchedAction,
  } from "actions/evaluationActions";
  import {
    evalErrorHandler,
    logSuccessfulBindings,
    postEvalActionDispatcher,
    updateTernDefinitions,
  } from "./PostEvaluationSagas";
  import { getAppMode } from "selectors/applicationSelectors";
  import { APP_MODE } from "entities/App";
  
  let widgetTypeConfigMap: WidgetTypeConfigMap;
  
  const worker = new GracefulWorkerService(Worker);
  
  function* evaluateTreeSaga(
    postEvalActions?: Array<ReduxAction<unknown> | ReduxActionWithoutPayload>,
  ) {
    const unevalTree = yield select(getUnevaluatedDataTree);
    log.debug({ unevalTree });
    PerformanceTracker.startAsyncTracking(
      PerformanceTransactionName.DATA_TREE_EVALUATION,
    );
    const overrideUpdate = localStorage.getItem("shouldOverrideUpdate") || false;
    const workerResponse = yield call(
      worker.request,
      EVAL_WORKER_ACTIONS.EVAL_TREE,
      {
        unevalTree,
        widgetTypeConfigMap,
        overrideUpdate,
      },
    );
    const {
      dataTree,
      dependencies,
      errors,
      evaluationOrder,
      logs,
      unEvalUpdates,
      updates,
    } = workerResponse;
    PerformanceTracker.stopAsyncTracking(
      PerformanceTransactionName.DATA_TREE_EVALUATION,
    );
    PerformanceTracker.startAsyncTracking(
      PerformanceTransactionName.SET_EVALUATED_TREE,
    );
    yield put(setEvaluatedTree(dataTree, updates));
    PerformanceTracker.stopAsyncTracking(
      PerformanceTransactionName.SET_EVALUATED_TREE,
    );
  
    const updatedDataTree = yield select(getDataTree);
  
    log.debug({ dataTree: updatedDataTree });
    logs.forEach((evalLog: any) => log.debug(evalLog));
    yield call(evalErrorHandler, errors, updatedDataTree, evaluationOrder);
    const appMode = yield select(getAppMode);
    if (appMode !== APP_MODE.PUBLISHED) {
      yield fork(
        logSuccessfulBindings,
        unevalTree,
        updatedDataTree,
        evaluationOrder,
      );
  
      yield fork(updateTernDefinitions, updatedDataTree, unEvalUpdates);
    }
  
    yield put(setDependencyMap(dependencies));
    if (postEvalActions && postEvalActions.length) {
      yield call(postEvalActionDispatcher, postEvalActions);
    }
  }
  
  export function* evaluateActionBindings(
    bindings: string[],
    executionParams: Record<string, any> | string = {},
  ) {
    const workerResponse = yield call(
      worker.request,
      EVAL_WORKER_ACTIONS.EVAL_ACTION_BINDINGS,
      {
        bindings,
        executionParams,
      },
    );
  
    const { errors, values } = workerResponse;
  
    yield call(evalErrorHandler, errors);
    return values;
  }
  
  export function* evaluateDynamicTrigger(
    dynamicTrigger: string,
    callbackData?: Array<any>,
  ) {
    const unEvalTree = yield select(getUnevaluatedDataTree);
  
    const workerResponse = yield call(
      worker.request,
      EVAL_WORKER_ACTIONS.EVAL_TRIGGER,
      { dataTree: unEvalTree, dynamicTrigger, callbackData },
    );
  
    const { errors, triggers } = workerResponse;
    yield call(evalErrorHandler, errors);
    return triggers;
  }
  
  export function* clearEvalCache() {
    yield call(worker.request, EVAL_WORKER_ACTIONS.CLEAR_CACHE);
  
    return true;
  }
  
  export function* clearEvalPropertyCache(propertyPath: string) {
    yield call(worker.request, EVAL_WORKER_ACTIONS.CLEAR_PROPERTY_CACHE, {
      propertyPath,
    });
  }
  
  /**
   * clears all cache keys of a widget
   *
   * @param widgetName
   */
  export function* clearEvalPropertyCacheOfWidget(widgetName: string) {
    yield call(
      worker.request,
      EVAL_WORKER_ACTIONS.CLEAR_PROPERTY_CACHE_OF_WIDGET,
      {
        widgetName,
      },
    );
  }
  
  export function* validateProperty(
    property: string,
    value: any,
    props: WidgetProps,
  ) {
    const unevalTree = yield select(getUnevaluatedDataTree);
    const validation = unevalTree[props.widgetName].validationPaths[property];
    return yield call(worker.request, EVAL_WORKER_ACTIONS.VALIDATE_PROPERTY, {
      property,
      value,
      props,
      validation,
    });
  }
  
  function evalQueueBuffer() {
    let canTake = false;
    let postEvalActions: any = [];
    const take = () => {
      if (canTake) {
        const resp = postEvalActions;
        postEvalActions = [];
        canTake = false;
        return { postEvalActions: resp, type: "BUFFERED_ACTION" };
      }
    };
    const flush = () => {
      if (canTake) {
        return [take() as Action];
      }
  
      return [];
    };
  
    const put = (action: EvaluationReduxAction<unknown | unknown[]>) => {
      if (!shouldProcessBatchedAction(action)) {
        return;
      }
      canTake = true;
  
      // TODO: If the action is the same as before, we can send only one and ignore duplicates.
      if (action.postEvalActions) {
        postEvalActions.push(...action.postEvalActions);
      }
    };
  
    return {
      take,
      put,
      isEmpty: () => {
        return !canTake;
      },
      flush,
    };
  }
  
  function* evaluationChangeListenerSaga() {
    // Explicitly shutdown old worker if present
    yield call(worker.shutdown);
    yield call(worker.start);
    widgetTypeConfigMap = WidgetFactory.getWidgetTypeConfigMap();
    const initAction = yield take(FIRST_EVAL_REDUX_ACTIONS);
    yield fork(evaluateTreeSaga, initAction.postEvalActions);
    const evtActionChannel = yield actionChannel(
      EVALUATE_REDUX_ACTIONS,
      evalQueueBuffer(),
    );
    while (true) {
      const action: EvaluationReduxAction<unknown | unknown[]> = yield take(
        evtActionChannel,
      );
      if (shouldProcessBatchedAction(action)) {
        yield call(evaluateTreeSaga, action.postEvalActions);
      }
    }
  }
  
  export default function* evaluationSagaListeners() {
    yield take(ReduxActionTypes.START_EVALUATION);
    while (true) {
      try {
        yield call(evaluationChangeListenerSaga);
      } catch (e) {
        log.error(e);
        Sentry.captureException(e);
      }
    }
  }
  