@toss/nestjs-aop
Version:
<!-- PROJECT LOGO --> <br /> <div align="center"> <a href="https://github.com/toss/nestjs-aop"> <img src="https://toss.tech/wp-content/uploads/2022/11/tech-article-nest-js-02.png" alt="Logo" height="200"> </a>
51 lines (47 loc) • 1.8 kB
text/typescript
import { applyDecorators } from '@nestjs/common';
import { AopMetadata } from './core/types';
import { AddMetadata } from './utils';
/**
* @param metadataKey equal to 1st argument of Aspect Decorator
* @param metadata The value corresponding to the metadata of WrapParams. It can be obtained from LazyDecorator's warp method and used.
*/
export const createDecorator = (
metadataKey: symbol | string,
metadata?: unknown,
): MethodDecorator => {
const aopSymbol = Symbol('AOP_DECORATOR');
return applyDecorators(
// 1. Add metadata to the method
(target: object, propertyKey: string | symbol, descriptor: PropertyDescriptor) => {
return AddMetadata<symbol | string, AopMetadata>(metadataKey, {
originalFn: descriptor.value,
metadata,
aopSymbol,
})(target, propertyKey, descriptor);
},
// 2. Wrap the method before the lazy decorator is executed
(_: object, propertyKey: string | symbol, descriptor: PropertyDescriptor) => {
const originalFn = descriptor.value;
descriptor.value = function (this: any, ...args: unknown[]) {
const wrappedFn = this[aopSymbol]?.[propertyKey];
if (wrappedFn) {
// If there is a wrapper stored in the method, use it
return wrappedFn.apply(this, args);
}
// if there is no wrapper that comes out of method, call originalFn
return originalFn.apply(this, args);
};
/**
* There are codes that using `function.name`.
* Therefore the codes below are necessary.
*
* ex) @nestjs/swagger
*/
Object.defineProperty(descriptor.value, 'name', {
value: propertyKey.toString(),
writable: false,
});
Object.setPrototypeOf(descriptor.value, originalFn);
},
);
};