Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- import "reflect-metadata";
- type TypeOf<T> = new (...args: any[]) => T;
- type Instantiator = <T>(type: TypeOf<T>) => T;
- const RunArgKeys = {
- run: Symbol(),
- }
- export interface Runnable {
- run(...args: any[]): Promise<any>;
- }
- export function RunArg<T>(factory: TypeOf<RunArgFactory<T>>, ) {
- return (proto: Runnable, method: string, index: number) => {
- const key = RunArgKeys[method];
- if (!key) throw new Error(`${method} not supported`);
- if (!Reflect.hasMetadata(key, proto)) {
- Reflect.defineMetadata(key, [], proto);
- }
- let list = Reflect.getMetadata(key, proto);
- list[index] = factory;
- }
- }
- export interface RunArgFactory<T> {
- produceRunArgFor(r: Runnable): Promise<T>;
- releaseRunArgFor(r: Runnable): Promise<void>;
- aroundRun?<T>(run: () => Promise<T>, r: Runnable): Promise<T>;
- }
- const wraps = {
- runnable: (runnable: Runnable, args: any[]) => () => runnable.run(...args),
- around: (
- arounder: RunArgFactory<any>,
- execution: () => Promise<any>,
- runnable: Runnable,
- ) => () => arounder.aroundRun!(execution, runnable),
- }
- export async function run(
- runnable: Runnable,
- instantiate: Instantiator,
- ) {
- let args: any[] = [];
- let factories: RunArgFactory<any>[] = (
- Reflect.getMetadata(RunArgKeys.run, runnable) as TypeOf<RunArgFactory<any>>[]
- ).map(instantiate);
- let arounders: RunArgFactory<any>[] = [];
- for (let factory of factories) {
- args.push(await factory.produceRunArgFor(runnable));
- if (factory.aroundRun) arounders.push(factory);
- }
- try {
- if (!arounders.length) return await runnable.run(...args);
- let execution = wraps.runnable(runnable, args);
- for (let arounder of arounders) {
- execution = wraps.around(arounder, execution, runnable);
- }
- return await execution();
- } catch (e) {
- throw e;
- } finally {
- for (let factory of factories) {
- await factory.releaseRunArgFor(runnable);
- }
- }
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement