// @flow function monkeyPatch(name: string, parentObj: Object, patches: Object): ()=>void { const injId = Symbol() const before = patches["before"]; const instead = patches["instead"]; const after = patches["after"]; const handler = { apply: (target, thisArg, [ctx, args]) => { if (before !== undefined) before.apply(ctx, args); const res = (patches["instead"] !== undefined) ? instead.apply(ctx, [target.bind(ctx), ...args]) : target.apply(ctx, args) if (after === undefined) return res return after.apply(ctx, [res].concat(args)); } }; const prox = new Proxy(parentObj[name], handler); const orig = parentObj[name]; parentObj[name] = function() { return prox(this, arguments); }; const unpatch = () => { parentObj[name] = orig; } parentObj[injId] = { name: name, orig: orig, unpatch: unpatch }; return unpatch; } function before(name: string, parentObj: Object, func: (...args: mixed[])=>void): ()=>void { return monkeyPatch(name, parentObj, {before: func}) } function instead(name: string, parentObj: Object, func: (orig: (any)=>any, ...args: mixed[])=>any): ()=>void { return monkeyPatch(name, parentObj, {instead: func}) } function after(name: string, parentObj: Object, func: (res: any, ...args: mixed[])=>any): ()=>void { return monkeyPatch(name, parentObj, {after: func}) } module.exports = { monkeyPatch, before, instead, after }