import { IElementState, IElementParams, IPartialObserver, EventType, ElementId, InternalType } from "../types"; import { isArgsEqual } from "../util"; import { Processor } from "../Processor"; import { EventsManager } from "../EventsManager"; import { CallbacksManager } from "../CallbacksManager"; import { createStackItem } from "../execute/createStackItem"; export const callHook = ( processor: Processor, eventsManager: EventsManager, callbacksManager: CallbacksManager, elementId: ElementId, state: IElementState, params: IElementParams, observer: IPartialObserver, ): { ___type: InternalType; } => { state.tickState.stack.push({ args: params.args, func: params.func, observer, }); const ret = { ___type: InternalType.Call, }; const currentCallNumber = state.tickState.currentCallNumber; state.tickState.currentCallNumber++; const status = getStatus(currentCallNumber, state.stack, params, state.currentCall); if (status === "restart") { if (state.currentCall) { eventsManager.triggerEvent({ elementId: state.currentCall.elementId, params: {}, type: EventType.Dispose, value: undefined, }); } state.stack.splice(currentCallNumber); createStackItem(callbacksManager, eventsManager, processor, elementId, state, params, observer); // TODO make multiple complete } else if (status === "update") { updateCall(processor, state, observer); } return ret; }; export const updateCall = (processor: Processor, state: IElementState, observer: IPartialObserver) => { if (!state.currentCall) { return; } const { callbacksManager } = processor.locator; const currentCallState = processor.getElementStateById(state.currentCall.elementId); if (currentCallState.observer.next) { callbacksManager.releaseCallback(currentCallState.observer.next); } currentCallState.observer.next = observer.next ? callbacksManager.addCallback(observer.next)[0] : undefined; if (observer.error && currentCallState.observer.error) { callbacksManager.releaseCallback(currentCallState.observer.error); } if (observer.error) { currentCallState.observer.error = callbacksManager.addCallback(observer.error)[0]; } }; export const checkCall = (params1: IElementParams, params2: IElementParams) => { return params1.func === params2.func && isArgsEqual(params1.args, params2.args); }; export const getStatus = ( currentCallNumber: number, stack: IElementState["stack"], params: IElementParams, currentCall: IElementState["currentCall"], ): "none" | "update" | "restart" => { // if not has current call execution if (!currentCall) { const isItCurrentPositionInQueue = (stack.length === 0 && currentCallNumber === 0) || currentCallNumber === stack.length; if (isItCurrentPositionInQueue) { return "restart"; } } // if current hook is greater than current stack execution, do nothing if (currentCallNumber > stack.length - 1) { return "none"; } const oldStack = stack[currentCallNumber]; if (!checkCall(oldStack, params)) { return "restart"; } const isItCurrentCall = currentCallNumber === stack.length - 1; if (!isItCurrentCall) { return "none"; } return "update"; };