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
25 changes: 23 additions & 2 deletions packages/common/module-utils/configurable-module.builder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { Logger } from '../services/logger.service';
import { randomStringGenerator } from '../utils/random-string-generator.util';
import {
ASYNC_METHOD_SUFFIX,
ASYNC_OPTIONS_METADATA_KEYS,
CONFIGURABLE_MODULE_ID,
DEFAULT_FACTORY_CLASS_METHOD_KEY,
DEFAULT_METHOD_KEY,
Expand Down Expand Up @@ -254,7 +255,7 @@ export class ConfigurableModuleBuilder<
},
{
...self.extras,
...options,
...this.extractExtrasFromAsyncOptions(options, self.extras),
},
);
}
Expand All @@ -277,8 +278,28 @@ export class ConfigurableModuleBuilder<
return moduleOptions as ModuleOptions;
}

private static extractExtrasFromAsyncOptions(
input: ConfigurableModuleAsyncOptions<ModuleOptions> &
ExtraModuleDefinitionOptions,
extras: ExtraModuleDefinitionOptions | undefined,
): Partial<ExtraModuleDefinitionOptions> {
if (!extras) {
return {};
}
const extrasOptions = {};

Object.keys(input as object)
.filter(key => !ASYNC_OPTIONS_METADATA_KEYS.includes(key as any))
.forEach(key => {
extrasOptions[key] = input[key];
});

return extrasOptions;
}

private static createAsyncProviders(
options: ConfigurableModuleAsyncOptions<ModuleOptions>,
options: ConfigurableModuleAsyncOptions<ModuleOptions> &
ExtraModuleDefinitionOptions,
): Provider[] {
if (options.useExisting || options.useFactory) {
if (options.inject && options.provideInjectionTokensFrom) {
Expand Down
13 changes: 13 additions & 0 deletions packages/common/module-utils/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,16 @@ export const DEFAULT_FACTORY_CLASS_METHOD_KEY = 'create';

export const ASYNC_METHOD_SUFFIX = 'Async';
export const CONFIGURABLE_MODULE_ID = 'CONFIGURABLE_MODULE_ID';

/**
* List of keys that are specific to ConfigurableModuleAsyncOptions
* and should be excluded when extracting user-defined extras.
*/
export const ASYNC_OPTIONS_METADATA_KEYS = [
'useFactory',
'useClass',
'useExisting',
'inject',
'imports',
'provideInjectionTokensFrom',
] as const;
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,34 @@ describe('ConfigurableModuleBuilder', () => {
global: true,
});
});

it('should preserve extras in registerAsync transformation', () => {
let capturedExtras: any;

const { ConfigurableModuleClass } = new ConfigurableModuleBuilder()
.setExtras(
{ folder: 'default' },
(definition, extras: { folder: string }) => {
capturedExtras = extras;
return {
...definition,
customProperty: `folder: ${extras.folder}`,
};
},
)
.build();

const asyncResult = ConfigurableModuleClass.registerAsync({
useFactory: () => ({}),
folder: 'forRootAsync',
});

expect(capturedExtras).to.deep.equal({ folder: 'forRootAsync' });
expect(asyncResult).to.have.property(
'customProperty',
'folder: forRootAsync',
);
});
});
describe('setClassMethodName', () => {
it('should set static class method name and return typed builder', () => {
Expand Down
Loading