Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
56 changes: 56 additions & 0 deletions lib/configurable.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
import { MetadataStorage } from 'class-transformer/types/MetadataStorage';
import configurationHolder from './configuration-holder';
import { applyDecorators } from '@nestjs/common';
import {
ClassConstructor,
Expose,
plainToClass,
Transform,
Type,
} from 'class-transformer';

/* eslint @typescript-eslint/no-var-requires: "off" */
const defaultMetadataStorage: MetadataStorage = require('class-transformer/cjs/storage')
.defaultMetadataStorage;

export function FromConfig(key: string): PropertyDecorator {
const configurationDecorator = (
target: any,
propertyName: string | symbol,
): void => {
configurationHolder.register(
target.constructor,
propertyName as string,
key,
);
defaultMetadataStorage.addTransformMetadata({
target: target.constructor,
propertyName: propertyName as string,
transformFn: () => {
const res = configurationHolder.resolve(
target.constructor,
propertyName as string,
);
return res;
},
options: {},
});
};
return applyDecorators(configurationDecorator, Expose());
}

export function NestedConfig(
type: ClassConstructor<unknown>,
): PropertyDecorator {
const decorator = Transform(({ value, options }) => {
if (value instanceof type) {
return value;
}
return plainToClass(type, value || {}, options);
});
return applyDecorators(
decorator,
Expose(),
Type(() => type),
);
}
34 changes: 34 additions & 0 deletions lib/configuration-holder.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
class ConfigurationHolder {
private readonly metadata: Map<any, Record<string, string>>;
private config: Record<string, unknown>;

constructor() {
this.metadata = new Map<any, Record<string, string>>();
this.config = {};
}

setConfig(config: Record<string, unknown>) {
this.config = config;
}

register(target: any, key: string, value: string) {
if (!this.metadata.has(target)) {
this.metadata.set(target, {});
}
(this.metadata.get(target) as Record<string, string>)[key] = value;
}

resolve(target: any, key: string): any {
if (this.metadata.has(target)) {
const configKey = (this.metadata.get(target) as Record<string, string>)[
key
];
if (configKey) {
return this.config[configKey];
}
}
return undefined;
}
}

export default new ConfigurationHolder();
1 change: 1 addition & 0 deletions lib/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,4 @@ export * from './typed-config.module';
export * from './interfaces';
export * from './loader';
export * from './utils';
export * from './configurable';
2 changes: 2 additions & 0 deletions lib/typed-config.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import {
import { forEachDeep } from './utils/for-each-deep.util';
import { identity } from './utils/identity.util';
import { debug } from './utils/debug.util';
import configurationHolder from './configuration-holder';

@Module({})
export class TypedConfigModule {
Expand Down Expand Up @@ -123,6 +124,7 @@ export class TypedConfigModule {
Config: ClassConstructor<any>,
options?: Partial<ValidatorOptions>,
) {
configurationHolder.setConfig(rawConfig);
const config = plainToClass(Config, rawConfig);
// defaults to strictest validation rules
const schemaErrors = validateSync(config, {
Expand Down