Commit d85606a1 authored by nanahira's avatar nanahira

add finalHandler to ProtoMiddlewareDispatcher

parent 5fff8688
import { Middleware, MiddlewareNext, MiddlewareResult } from './types';
import {
AnyFunc,
Middleware,
MiddlewareDispatcherOptions,
MiddlewareResult,
} from './types';
import { AnyClass, ClassType } from '../types';
import { DynamicMiddlewareDispatcher } from './dynamic-middleware-dispatcher';
export type ProtoMiddlewareArgs<A extends any[], T = any> = [
...args: A,
type StripLastParam<F extends AnyFunc> = F extends (
...args: [...infer A, any]
) => infer R
? (...args: A) => R
: never;
type ProtoMiddlewareArgs<F extends AnyFunc, T = any> = [
...args: Parameters<StripLastParam<F>>,
inst: T,
];
export type ProtoMiddlewareFunc<A extends any[], T = any> = (
...args: ProtoMiddlewareArgs<A, T>
) => T;
export type ProtoMiddlewareFunc<F extends AnyFunc, T = any> = (
...args: ProtoMiddlewareArgs<F, T>
) => Awaited<ReturnType<F>>;
type LastParam<F extends AnyFunc> = F extends (
...args: [...any, infer L]
) => any
? L
: never;
export class ProtoMiddlewareDispatcher<
A extends any[],
> extends DynamicMiddlewareDispatcher<ProtoMiddlewareFunc<A>> {
F extends AnyFunc,
> extends DynamicMiddlewareDispatcher<ProtoMiddlewareFunc<F>> {
constructor(
private finalHandler: F,
options: MiddlewareDispatcherOptions<ProtoMiddlewareFunc<F>> = {},
) {
super(options);
}
private middlewareProtoMap = new Map<
AnyClass,
Middleware<ProtoMiddlewareFunc<A>>[]
Middleware<ProtoMiddlewareFunc<F>>[]
>();
private middlewareProtoMapPrior = new Map<
AnyClass,
Middleware<ProtoMiddlewareFunc<A>>[]
Middleware<ProtoMiddlewareFunc<F>>[]
>();
middleware<T>(
middleware<T extends LastParam<F>>(
cls: ClassType<T>,
mw: Middleware<ProtoMiddlewareFunc<A, T>>,
mw: Middleware<ProtoMiddlewareFunc<F, T>>,
prior = false,
) {
const map = prior ? this.middlewareProtoMapPrior : this.middlewareProtoMap;
......@@ -34,9 +58,9 @@ export class ProtoMiddlewareDispatcher<
return this;
}
removeMiddleware<T>(
removeMiddleware<T extends LastParam<F>>(
cls: ClassType<T>,
mw: Middleware<ProtoMiddlewareFunc<A, T>>,
mw: Middleware<ProtoMiddlewareFunc<F, T>>,
) {
for (const map of [this.middlewareProtoMap, this.middlewareProtoMapPrior]) {
const mws = map.get(cls);
......@@ -50,13 +74,13 @@ export class ProtoMiddlewareDispatcher<
return this;
}
async dispatch<T>(
...args: ProtoMiddlewareArgs<A, T>
): MiddlewareResult<ProtoMiddlewareFunc<A, T>> {
async dispatch<T extends LastParam<F>>(
...args: ProtoMiddlewareArgs<F, T>
): MiddlewareResult<ProtoMiddlewareFunc<F, T>> {
return super.dispatch(...args);
}
async buildMiddlewares(...args: ProtoMiddlewareArgs<A>) {
async buildMiddlewares(...args: ProtoMiddlewareArgs<F>) {
// buildMiddlewares 只需要知道 inst
if (args.length === 0) return [];
......@@ -74,13 +98,13 @@ export class ProtoMiddlewareDispatcher<
chain.reverse();
const result: Middleware<ProtoMiddlewareFunc<A>>[] = [];
const result: Middleware<ProtoMiddlewareFunc<F>>[] = [];
// 2. prior:Base → Sub
for (const cls of chain) {
const mws = this.middlewareProtoMapPrior.get(cls);
if (mws) {
result.push(...mws);
result.push(...[...mws].reverse());
}
}
......@@ -94,7 +118,7 @@ export class ProtoMiddlewareDispatcher<
}
result.push((...args) => {
return args[args.length - 2]; // inst
return this.finalHandler(...args.slice(0, -1));
});
return result;
......
......@@ -7,13 +7,23 @@ describe('ProtoMiddlewareDispatcher', () => {
class Sub extends Base {}
it('builds middlewares by prototype chain (prior: Base->Sub, normal: Sub->Base)', async () => {
const d = new ProtoMiddlewareDispatcher<[res: number]>();
const d = new ProtoMiddlewareDispatcher(async (x: number, inst: Base) => {
return inst;
});
const order: string[] = [];
d.middleware(
Base,
async (x, inst, next) => {
order.push('base:prior');
order.push('base:prior1');
return next();
},
true,
);
d.middleware(
Base,
async (x, inst, next) => {
order.push('base:prior2');
return next();
},
true,
......@@ -26,6 +36,10 @@ describe('ProtoMiddlewareDispatcher', () => {
},
true,
);
d.middleware(Sub, async (x, inst, next) => {
order.push('sub:normalpre');
return next();
});
d.middleware(Sub, async (x, inst, next) => {
order.push('sub:normal');
expect(inst).toBeInstanceOf(Sub);
......@@ -47,8 +61,10 @@ describe('ProtoMiddlewareDispatcher', () => {
sub.value = 5;
const res = await d.dispatch(3, sub);
expect(order).toEqual([
'base:prior',
'base:prior2',
'base:prior1',
'sub:prior',
'sub:normalpre',
'sub:normal',
'base:normal',
]);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment