Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 | 1x 1x 36x 36x 36x 36x 36x 36x 36x 36x 36x 36x 36x 36x 36x 36x 36x 36x 20x 33x 33x 20x 24x 24x 20x 20x 36x 26x 25x 25x 25x 25x 25x 1x 26x 36x 4x 3x 3x 3x 3x 3x 1x 4x 36x 40x 5x 5x 35x 35x 33x 2x 1x 1x 1x 1x 1x 1x 1x 1x 1x 2x 31x 33x 1x 1x 1x 1x 30x 33x 35x 17x 17x 35x 40x 1x 1x 1x 1x 31x 40x 36x | import { FlowfulError } from './error';
import { ActionHandler } from './action-handler';
import { ActionMapExtended, ActionMapInternal } from './action-map';
export type ChainedActionHandlerMiddlewareCallback<AM extends ActionMapExtended = ActionMapExtended> = (
actionMap: AM,
handler: ActionHandler
) => any;
export type ActionHandlerMiddlewareCallback<AM extends ActionMapExtended = ActionMapExtended> = (
next: ChainedActionHandlerMiddlewareCallback<AM>
) => ChainedActionHandlerMiddlewareCallback<AM>;
export interface IActionHandlerMiddlewareRunner {
run(actionMap: ActionMapExtended, handler: ActionHandler): any;
}
export interface IActionHandlerMiddleware<AM extends ActionMapExtended = ActionMapExtended>
extends IActionHandlerMiddlewareRunner {
add(callback: ActionHandlerMiddlewareCallback<AM>): boolean;
remove(callback: ActionHandlerMiddlewareCallback<AM>): boolean;
compose(): void;
}
export interface ActionHandlerMiddlewareOptions {
cancellable?: boolean;
}
export class ActionHandlerMiddleware<AM extends ActionMapExtended = ActionMapExtended>
implements IActionHandlerMiddlewareRunner
{
protected _middlewareCallbacks: Set<ActionHandlerMiddlewareCallback<AM>>;
protected _middlewareCallbacksArray: ActionHandlerMiddlewareCallback<AM>[];
protected _composed?: ChainedActionHandlerMiddlewareCallback<AM>;
protected _last?: ChainedActionHandlerMiddlewareCallback<AM>;
protected _className = 'ActionHandlerMiddleware';
protected _errorPrefix = `[Flowful][${this._className}]`;
public options: Required<ActionHandlerMiddlewareOptions>;
constructor(options?: ActionHandlerMiddlewareOptions) {
this.options = {
cancellable: options?.cancellable ?? true,
};
this._middlewareCallbacks = new Set();
this._middlewareCallbacksArray = [];
}
compose() {
let next = (actionMap: AM, handler: ActionHandler) => {
return this._last!(actionMap, handler);
};
for (const middleware of this._middlewareCallbacksArray) {
next = middleware(next);
}
this._composed = next;
}
add(callback: ActionHandlerMiddlewareCallback<AM>) {
if (!this._middlewareCallbacks.has(callback)) {
this._middlewareCallbacks.add(callback);
this._middlewareCallbacksArray.unshift(callback);
this._composed = undefined;
return true;
}
return false;
}
remove(callback: ActionHandlerMiddlewareCallback<AM>) {
if (this._middlewareCallbacks.has(callback)) {
this._middlewareCallbacks.delete(callback);
this._middlewareCallbacksArray = [...this._middlewareCallbacks];
this._composed = undefined;
return true;
}
return false;
}
run(actionMap: ActionMapExtended, handler: ActionHandler) {
if (!this._middlewareCallbacks.size) {
// size is slightly faster than array.length
return handler.invoke(actionMap as ActionMapInternal);
}
let calledTimes = 0;
this._last = (actionMapFromMiddlewares: ActionMapExtended, handlerFromMiddlewares: ActionHandler) => {
if (!this.options.cancellable) {
if (actionMapFromMiddlewares !== actionMap) {
throw new FlowfulError(
`${this._errorPrefix} The next function in the action handler middleware was called with a different ActionMap, which is not possible when cancellable option is set to false.`
);
}
if (handlerFromMiddlewares !== handler) {
throw new FlowfulError(
`${this._errorPrefix} The next function in the action handler middleware was called with a different ActionHandler, which is not possible when cancellable option is set to false.`
);
}
}
calledTimes++;
if (calledTimes > 1) {
// We have to check it here, otherwise it will throw an error that the action was emitted several times
throw new FlowfulError(
`${this._errorPrefix} The next function in the action handler middleware was called more than once.`
);
}
return handlerFromMiddlewares.invoke(actionMapFromMiddlewares as ActionMapInternal);
};
if (!this._composed) {
this.compose();
}
const middlewareOutput = this._composed!(actionMap as unknown as AM, handler);
if (!this.options.cancellable && calledTimes === 0) {
// the middleware should not be able to cancel the action
throw new FlowfulError(
`${this._errorPrefix} The next function in the action handler middleware was not called, which is not possible when cancellable option is set to false.`
);
}
return middlewareOutput;
}
}
|