diff --git a/packages/patch-injection/src/index.ts b/packages/patch-injection/src/index.ts index 405790427177d..7bfd782afcd20 100644 --- a/packages/patch-injection/src/index.ts +++ b/packages/patch-injection/src/index.ts @@ -1,2 +1,4 @@ -export * from './definition'; +// export * from './definition'; export * from './makeFunction'; +export * from './midleware'; +// export * from './addPatch'; diff --git a/packages/patch-injection/src/makeFunction.ts b/packages/patch-injection/src/makeFunction.ts index 6bf8e5200a1bf..13cbda272bc0c 100644 --- a/packages/patch-injection/src/makeFunction.ts +++ b/packages/patch-injection/src/makeFunction.ts @@ -1,40 +1,26 @@ -import { addPatch } from './addPatch'; -import { calledFunctions, functions } from './data'; -import type { BaseFunction, PatchData, PatchFunction, PatchedFunction } from './definition'; +import type { BaseFunction, PatchFunction, PatchedFunction } from './definition'; +import { withMiddleware } from './midleware'; export const makeFunction = (fn: T): PatchedFunction => { - const patches = new Set>(); - - patches.add({ - patchFunction: (_next, ...args) => fn(...args), - }); - - const result = ((...args: Parameters): ReturnType => { - let newFn: T = fn; - - for (const patch of patches) { - if (patch.condition && !patch.condition()) { - continue; + const wrapped = withMiddleware(fn); + const patch = (fn: PatchFunction, condition?: () => boolean) => { + return wrapped.use((ctx, next) => { + if (!condition || condition()) { + return fn(next as unknown as T, ...ctx); } - - const nextFn = newFn; - newFn = ((...args: Parameters) => patch.patchFunction(nextFn, ...args)) as T; - } - - calledFunctions.add(result); - return newFn(...args); - }) as PatchedFunction; - - functions.set(result, patches as Set>); - - result.patch = (patch: PatchFunction, condition?: () => boolean) => addPatch(result, patch, condition); - - result.originalSignature = (() => { + return next(...ctx); + }); + }; + const originalSignature = (() => { throw new Error('OriginalSignature of patched functions is not meant to be executed directly.'); }) as unknown as T; - result.patchSignature = (() => { + const patchSignature = (() => { throw new Error('PatchSignature of patched functions is not meant to be executed directly.'); }) as unknown as PatchFunction; - return result; + return Object.assign(wrapped, { + patch, + originalSignature, + patchSignature, + }) as PatchedFunction; }; diff --git a/packages/patch-injection/src/midleware.ts b/packages/patch-injection/src/midleware.ts new file mode 100644 index 0000000000000..2159c8e96773f --- /dev/null +++ b/packages/patch-injection/src/midleware.ts @@ -0,0 +1,36 @@ +type Middleware any> = (ctx: Parameters, next: NextFunction) => ReturnType; +type NextFunction any> = (...args: Parameters | []) => ReturnType; + +export function withMiddleware any>(fn: F) { + const middlewares: Middleware[] = []; + + const buildRunner = (): ((ctx: Parameters) => ReturnType) => { + return middlewares.reduce( + (next, middleware) => { + return (ctx) => middleware(ctx, (...args) => next(args.length ? (args as Parameters) : ctx)); + }, + (ctx: Parameters) => fn(...ctx), + ); + }; + + let runner = buildRunner(); + + const use = (middleware: Middleware) => { + middlewares.push(middleware); + + runner = buildRunner(); + return () => { + const index = middlewares.indexOf(middleware); + if (index > -1) { + middlewares.splice(index, 1); + } + runner = buildRunner(); + }; + }; + + const run = (...args: Parameters): ReturnType => { + return runner(args); + }; + + return Object.assign(run as F, { use, fn }); +}