@alterior/annotations
Version:
Create and interact with Typescript metadata decorators
78 lines • 2.71 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.Mutator = void 0;
const common_1 = require("@alterior/common");
const annotations_1 = require("./annotations");
/**
* Mutators are a way to define "mutation decorators" which in some way change the value
* of the elements they are applied to, as opposed to "annotation decorators", which primarily
* attach metadata.
*
* Create a mutator with Mutator.create().
*/
class Mutator {
/**
* Low-level method to ceate a new mutation decorator (mutator) based on the given function.
* Use `Mutator.define()` instead.
*/
static create(mutator, options) {
return annotations_1.Annotation.decorator(Object.assign({}, options || {}, {
factory: (target, ...args) => {
let paramNames;
let orig = target.propertyDescriptor.value;
if (typeof orig === 'function') {
paramNames = (0, common_1.getParameterNames)(target.propertyDescriptor.value);
}
mutator(target, ...args);
let replacement = target.propertyDescriptor.value;
if (orig !== replacement && paramNames !== undefined && !Object.hasOwn(replacement, '__parameterNames')) {
Object.defineProperty(replacement, '__parameterNames', {
value: paramNames
});
}
}
}));
}
/**
* Define a new mutation decorator (mutator).
* This should be called and returned from a
* function definition. For example:
*
```
function Name() {
return Mutator.define({
invoke(site) {
// ...
}
})
}
```
*
* The `invoke()` function takes a DecoratorSite object which describes the particular
* invocation that is being run, and importantly, access to the property descriptor
* for the property being defined. If you wish to completely replace (or wrap) the
* default value of the property or method you are replacing, set the `value`
* property of the property descriptor with `site.propertyDescriptor.value`
*
* For example:
* ```
export function RunTwice() {
return Mutator.create(
site => {
let prop = site.propertyDescriptor;
let original = prop.value;
let replacement = function(...args) {
original.apply(this, args);
original.apply(this, args);
}
prop.value = replacement;
}
)
* ```
*/
static define(definition) {
return this.create(definition.invoke, definition.options)();
}
}
exports.Mutator = Mutator;
//# sourceMappingURL=mutator.js.map