Skip to content

Commit 11c40a0

Browse files
authored
feat(core): adds ClsModule.registerPlugins to inject Plugins from an external module (#192)
1 parent b4b45dc commit 11c40a0

File tree

3 files changed

+90
-5
lines changed

3 files changed

+90
-5
lines changed

docs/docs/06_plugins/index.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,12 @@ ClsModule.forRoot({
1818
});
1919
```
2020

21+
If you need to inject Plugins from an external module, use the `ClsModule.registerPlugins()` registration to import the containing module.
22+
23+
```ts
24+
ClsModule.registerPlugins([new MyPlugin()]);
25+
```
26+
2127
## Available plugins
2228

2329
For a list of plugins managed by the author of `nestjs-cls`, see the [Available Plugins](./01_available-plugins/index.md) page.

packages/core/src/lib/cls.module.ts

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ import { ClsPluginManager } from './plugin/cls-plugin-manager';
4040

4141
import { ProxyProviderManager } from './proxy-provider/proxy-provider-manager';
4242
import { ClsModuleProxyProviderOptions } from './proxy-provider/proxy-provider.interfaces';
43+
import { ClsPlugin } from './plugin/cls-plugin.interface';
4344

4445
const clsServiceProvider: ValueProvider<ClsService> = {
4546
provide: ClsService,
@@ -192,6 +193,18 @@ export class ClsModule implements NestModule {
192193
};
193194
}
194195

196+
/**
197+
* Registers the given Plugins the module along with `ClsService`.
198+
*/
199+
static registerPlugins(plugins: ClsPlugin[]): DynamicModule {
200+
return {
201+
module: ClsModule,
202+
imports: ClsPluginManager.registerPlugins(plugins),
203+
providers: commonProviders,
204+
exports: commonProviders,
205+
};
206+
}
207+
195208
private static createProxyClassProviders(
196209
proxyProviderClasses?: Array<Type>,
197210
) {

packages/core/test/plugin/plugin.spec.ts

Lines changed: 71 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,14 @@ import { NestFactory } from '@nestjs/core';
44
import { Controller, Get, Module } from '@nestjs/common';
55
import supertest from 'supertest';
66

7+
function providerToken(name: string) {
8+
return `${name}ProviderToken`;
9+
}
10+
11+
function pluginInitializedToken(name: string) {
12+
return `${name.toLocaleUpperCase()}_PLUGIN_INITIALIZED`;
13+
}
14+
715
function createDummyPlugin(name: string) {
816
const watchers = {
917
initHasRun: false,
@@ -18,11 +26,11 @@ function createDummyPlugin(name: string) {
1826
watchers.destroyHasRun = true;
1927
},
2028
onClsInit: (cls) => {
21-
cls.set('PLUGIN_INITIALIZED', true);
29+
cls.set(pluginInitializedToken(name), true);
2230
},
2331
providers: [
2432
{
25-
provide: 'providerFromPlugin',
33+
provide: providerToken(name),
2634
useValue: 'valueFromPlugin',
2735
},
2836
],
@@ -51,7 +59,7 @@ describe('Plugins', () => {
5159
await module.init();
5260

5361
expect(watchers.initHasRun).toBe(true);
54-
expect(module.get('providerFromPlugin')).toBe('valueFromPlugin');
62+
expect(module.get(providerToken('forRoot'))).toBe('valueFromPlugin');
5563
expect(watchers.destroyHasRun).toBe(false);
5664

5765
await module.close();
@@ -78,7 +86,9 @@ describe('Plugins', () => {
7886
await module.init();
7987

8088
expect(watchers.initHasRun).toBe(true);
81-
expect(module.get('providerFromPlugin')).toBe('valueFromPlugin');
89+
expect(module.get(providerToken('forRootAsync'))).toBe(
90+
'valueFromPlugin',
91+
);
8292
expect(watchers.destroyHasRun).toBe(false);
8393

8494
await module.close();
@@ -96,7 +106,7 @@ describe('Plugins', () => {
96106
constructor(private readonly cls: ClsService) {}
97107
@Get()
98108
get() {
99-
return this.cls.get('PLUGIN_INITIALIZED');
109+
return this.cls.get(pluginInitializedToken('onClsInit'));
100110
}
101111
}
102112

@@ -123,4 +133,60 @@ describe('Plugins', () => {
123133
await module.close();
124134
},
125135
);
136+
137+
it('should register plugin and run module lifecycle and onClsInit methods (registerPlugins)', async () => {
138+
const root = createDummyPlugin('root');
139+
const feature = createDummyPlugin('feature');
140+
141+
@Controller()
142+
class TestController {
143+
constructor(private readonly cls: ClsService) {}
144+
@Get()
145+
get() {
146+
return (
147+
this.cls.get(pluginInitializedToken('root')) &&
148+
this.cls.get(pluginInitializedToken('feature'))
149+
);
150+
}
151+
}
152+
@Module({
153+
imports: [
154+
ClsModule.forRoot({
155+
middleware: {
156+
mount: true,
157+
},
158+
plugins: [root.plugin],
159+
}),
160+
ClsModule.registerPlugins([feature.plugin]),
161+
],
162+
controllers: [TestController],
163+
})
164+
class TestAppModule {}
165+
166+
const module = await NestFactory.create(TestAppModule);
167+
168+
expect(root.watchers.initHasRun).toBe(false);
169+
expect(feature.watchers.initHasRun).toBe(false);
170+
171+
await module.init();
172+
173+
expect(root.watchers.initHasRun).toBe(true);
174+
expect(feature.watchers.initHasRun).toBe(true);
175+
176+
expect(module.get(providerToken('root'))).toBe('valueFromPlugin');
177+
expect(module.get(providerToken('feature'))).toBe('valueFromPlugin');
178+
179+
expect(root.watchers.destroyHasRun).toBe(false);
180+
expect(feature.watchers.destroyHasRun).toBe(false);
181+
182+
await supertest(module.getHttpServer())
183+
.get('/')
184+
.expect(200)
185+
.expect('true');
186+
187+
await module.close();
188+
189+
expect(root.watchers.destroyHasRun).toBe(true);
190+
expect(feature.watchers.destroyHasRun).toBe(true);
191+
});
126192
});

0 commit comments

Comments
 (0)