diff --git a/Dive-Deeper.md b/Dive-Deeper.md index 30404ce..628949f 100644 --- a/Dive-Deeper.md +++ b/Dive-Deeper.md @@ -1 +1,83 @@ -TODO \ No newline at end of file +_In this page, the deeper understand of decorator will be handled._ + +# How basic decorators works? + +In `nestlogged` package, there are three types of decorator. + +1. Class Decorator (`LoggedInjectable`, `LoggedController`) +2. Method Decorator (`LoggedFunction`, `LoggedRoute`, `ShouldScoped`) +3. Parameter Decorator (`LoggedParam`, `InjectLogger`, `ScopeKey`) + +There is a [good documentation](https://www.typescriptlang.org/docs/handbook/decorators.html) for this in typescriptlang.org. + +# How does the logging decorator actually works? + +In this section, the internal logic of the logging decorators are explained. + +The main logic of this package is placed inside of method decorators. +But before explaining about real logging decorators (method decorators), you have to understand the parameter decorator. + +## Metadata Reflection + +If you open the package.json file and see what is the dependency, there is a package `reflect-meatadata`. +It is used by nestjs, but also nestlogged uses it very actively. +All `LoggedParam`, `InjectLogger`, `ScopeKey` is powered by `reflect-metadata` package. + +It provides **Metadata Reflection API**, which gives functionality to add additional metadatas to a class. +It is pretty useful for saving the metadata in a decorator, and then use it in another decorator. + +## `InjectLogger`, `LoggedParam`, `ScopeKey` Implementation Explained + +If you look at `src/reflected.ts` file, there is implementations for `InjectLogger`, `LoggedParam`, `ScopeKey` decorators. +What these decorators have in common is they store metadatas using metadata reflection api. + +### `InjectLogger` + +Let's look at `InjectLogger` function. + +It's pretty small and simple. + +What it does is putting the information of parameter to it's target. + +When we put the `InjectLogger` to the parameter, the _the prototype of the class for an instance member_ (`target: any`), _The name of the member_ (`propertyKey: string | symbol`), and _The ordinal index of the parameter in the function’s parameter list_ (`parameterIndex: number`) are given to the `InjectLogger` function as the argument. + +And call `Reflect.defineMetadata` to save the `parameterIndex` as `ScopedLogger` injection index. + +The key (`scopedLogger`) when used to define metadata is defined at the almost top of the file, right bottom to the interfaces, as the constant symbol. + +It will be used in both `LoggedFunction` and `LoggedRoute` which will explained later section. + +### `LoggedParam` + +At the right bottom to the `InjectLogger`, there is a function definition for `LoggedParam`. + +It takes parameter name (`name: string`), and options for include or exclude path in object (`options?: {includePath?: ..., excludePath?: ...}`). + +It returns parameter decorator function, which has same parameters with InjectLogger. + +Since the decorator function is **returned after call**, it should be called to be applied. + +```ts +function a( + @InjectLogger logger: ScopedLogger, + @LoggedParam param: string // it's illegal, error + @LoggedParam('param') param: string // Now it returns decorator function to be applied. +) {} +``` + +`LoggedParam` decorator can be used multiple time in one function. + +Because of that, first thing decorator does is getting the existing decorator data. +Right after that, push a new data, then redefine the metadata. + +### `ScopeKey` + +It is simillar to the `LoggedParam` decorator implementation. + +The only different thing is, `ScopeKey` sorts its metadata array by priority. + +### `ShouldScoped` + +Although `ShouldScoped` is a method decorator, it only defined metadata like `InjectLogger`, and it's very simple. +It just set `forceScopeKey` to true in method metadata. +Getting the metadata value which is not defined is same as undefined, so the default value is falsy. \ No newline at end of file