157 lines
9.6 KiB
JavaScript
157 lines
9.6 KiB
JavaScript
"use strict";
|
|
/* -------------------------------------------------------------------------
|
|
* aspects.ts
|
|
*
|
|
* A robust “aspect” system supporting:
|
|
* - before: optionally modifies arguments (sync or async)
|
|
* - after: optionally modifies return value (sync or async)
|
|
* - around: complete control over function invocation
|
|
* - error: intercept errors (sync or async)
|
|
*
|
|
* Only supports direct function wrappers (e.g. fn = before(fn, ...)).
|
|
* ------------------------------------------------------------------------ */
|
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
exports.SIGNALS = void 0;
|
|
exports.before = before;
|
|
exports.after = after;
|
|
exports.around = around;
|
|
exports.error = error;
|
|
/* -------------------------------------------------------------------------
|
|
* 1) SIGNALS Enum (string-based to avoid symbol issues)
|
|
* ------------------------------------------------------------------------ */
|
|
var SIGNALS;
|
|
(function (SIGNALS) {
|
|
SIGNALS["BEFORE"] = "BEFORE";
|
|
SIGNALS["AFTER"] = "AFTER";
|
|
SIGNALS["AROUND"] = "AROUND";
|
|
SIGNALS["ERROR"] = "ERROR";
|
|
})(SIGNALS || (exports.SIGNALS = SIGNALS = {}));
|
|
/* -------------------------------------------------------------------------
|
|
* 5) The SignalMap Implementation
|
|
* - This is where the actual "wrapping" logic lives.
|
|
* ------------------------------------------------------------------------ */
|
|
const SignalMap = {
|
|
/**
|
|
* BEFORE:
|
|
* - Possibly modifies arguments
|
|
* - If returns a Promise, we await it before calling original
|
|
* - If returns an array, we use that as new arguments
|
|
*/
|
|
[SIGNALS.BEFORE](original, advice) {
|
|
return function (...args) {
|
|
const maybeNewArgs = advice(this, args);
|
|
if (maybeNewArgs instanceof Promise) {
|
|
return maybeNewArgs.then((resolvedArgs) => {
|
|
const finalArgs = resolvedArgs || args;
|
|
const result = original.apply(this, finalArgs);
|
|
return (result instanceof Promise) ? result : Promise.resolve(result);
|
|
});
|
|
}
|
|
else {
|
|
const finalArgs = Array.isArray(maybeNewArgs) ? maybeNewArgs : args;
|
|
return original.apply(this, finalArgs);
|
|
}
|
|
};
|
|
},
|
|
/**
|
|
* AFTER:
|
|
* - Possibly modifies the return value
|
|
* - If original is async, we chain on its promise
|
|
* - Advice can be sync or async
|
|
*/
|
|
[SIGNALS.AFTER](original, advice) {
|
|
return function (...args) {
|
|
const result = original.apply(this, args);
|
|
if (result instanceof Promise) {
|
|
return result.then((unwrapped) => {
|
|
const maybeNewResult = advice(this, unwrapped, args);
|
|
return (maybeNewResult instanceof Promise) ? maybeNewResult : maybeNewResult;
|
|
});
|
|
}
|
|
else {
|
|
const maybeNewResult = advice(this, result, args);
|
|
if (maybeNewResult instanceof Promise) {
|
|
return maybeNewResult.then(r => r);
|
|
}
|
|
return maybeNewResult;
|
|
}
|
|
};
|
|
},
|
|
/**
|
|
* AROUND:
|
|
* - Full control over invocation
|
|
* - Typically you do: proceed(...args)
|
|
* - If you want to skip or call multiple times, you can
|
|
*/
|
|
[SIGNALS.AROUND](original, advice) {
|
|
return function (...args) {
|
|
const proceed = (...innerArgs) => original.apply(this, innerArgs);
|
|
return advice(proceed, this, args);
|
|
};
|
|
},
|
|
/**
|
|
* ERROR:
|
|
* - Intercepts errors thrown by the original function or a rejected Promise
|
|
* - Optionally returns a fallback or rethrows
|
|
*/
|
|
[SIGNALS.ERROR](original, advice) {
|
|
return function (...args) {
|
|
try {
|
|
const result = original.apply(this, args);
|
|
if (result instanceof Promise) {
|
|
// Handle async rejections
|
|
return result.catch((err) => {
|
|
return advice(err, this, args);
|
|
});
|
|
}
|
|
return result;
|
|
}
|
|
catch (err) {
|
|
// Synchronous error
|
|
return advice(err, this, args);
|
|
}
|
|
};
|
|
},
|
|
};
|
|
/* -------------------------------------------------------------------------
|
|
* 6) Direct Usage Functions (no decorator support)
|
|
* ------------------------------------------------------------------------ */
|
|
/**
|
|
* `before`:
|
|
* Direct usage => myFn = before(myFn, (ctx, args) => ...)
|
|
*/
|
|
function before(fn, advice) {
|
|
return SignalMap[SIGNALS.BEFORE](fn, advice);
|
|
}
|
|
/**
|
|
* `after`:
|
|
* Direct usage => myFn = after(myFn, (ctx, result, args) => ...)
|
|
*/
|
|
function after(fn, advice) {
|
|
return SignalMap[SIGNALS.AFTER](fn, advice);
|
|
}
|
|
/**
|
|
* `around`:
|
|
* Direct usage => myFn = around(myFn, (proceed, ctx, args) => ...)
|
|
*/
|
|
function around(fn, advice) {
|
|
return SignalMap[SIGNALS.AROUND](fn, advice);
|
|
}
|
|
/**
|
|
* `error`:
|
|
* Direct usage => myFn = error(myFn, (err, ctx, args) => ...)
|
|
*/
|
|
function error(fn, advice) {
|
|
return SignalMap[SIGNALS.ERROR](fn, advice);
|
|
}
|
|
/* -------------------------------------------------------------------------
|
|
* 7) Default Export
|
|
* ------------------------------------------------------------------------ */
|
|
exports.default = {
|
|
SIGNALS,
|
|
before,
|
|
after,
|
|
around,
|
|
error,
|
|
};
|
|
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYXNwZWN0c19zaW1wbGUuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi9zcmMvdXRpbHMvYXNwZWN0c19zaW1wbGUudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IjtBQUFBOzs7Ozs7Ozs7OzhFQVU4RTs7O0FBdUw1RSx3QkFFQztBQU1ELHNCQUVDO0FBTUQsd0JBRUM7QUFNRCxzQkFFQztBQS9NSDs7OEVBRThFO0FBQzlFLElBQVksT0FLVDtBQUxILFdBQVksT0FBTztJQUNmLDRCQUFpQixDQUFBO0lBQ2pCLDBCQUFlLENBQUE7SUFDZiw0QkFBaUIsQ0FBQTtJQUNqQiwwQkFBZSxDQUFBO0FBQ2pCLENBQUMsRUFMUyxPQUFPLHVCQUFQLE9BQU8sUUFLaEI7QUEyRUQ7Ozs4RUFHOEU7QUFDOUUsTUFBTSxTQUFTLEdBQWU7SUFDNUI7Ozs7O09BS0c7SUFDSCxDQUFDLE9BQU8sQ0FBQyxNQUFNLENBQUMsQ0FBd0IsUUFBVyxFQUFFLE1BQXVCO1FBQzFFLE9BQU8sVUFBc0MsR0FBRyxJQUFtQjtZQUNqRSxNQUFNLFlBQVksR0FBRyxNQUFNLENBQUMsSUFBSSxFQUFFLElBQUksQ0FBQyxDQUFDO1lBRXhDLElBQUksWUFBWSxZQUFZLE9BQU8sRUFBRSxDQUFDO2dCQUNwQyxPQUFPLFlBQVksQ0FBQyxJQUFJLENBQUMsQ0FBQyxZQUFZLEVBQUUsRUFBRTtvQkFDeEMsTUFBTSxTQUFTLEdBQUcsWUFBWSxJQUFJLElBQUksQ0FBQztvQkFDdkMsTUFBTSxNQUFNLEdBQUcsUUFBUSxDQUFDLEtBQUssQ0FBQyxJQUFJLEVBQUUsU0FBUyxDQUFDLENBQUM7b0JBQy9DLE9BQU8sQ0FBQyxNQUFNLFlBQVksT0FBTyxDQUFDLENBQUMsQ0FBQyxDQUFDLE1BQU0sQ0FBQyxDQUFDLENBQUMsT0FBTyxDQUFDLE9BQU8sQ0FBQyxNQUFNLENBQUMsQ0FBQztnQkFDeEUsQ0FBQyxDQUFrQixDQUFDO1lBQ3RCLENBQUM7aUJBQU0sQ0FBQztnQkFDTixNQUFNLFNBQVMsR0FB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
|