Skip to content

Commit aa9812f

Browse files
committed
feat(core): Set tags to group bound artifacts
1 parent 991cf38 commit aa9812f

File tree

3 files changed

+79
-9
lines changed

3 files changed

+79
-9
lines changed

packages/core/src/application.ts

Lines changed: 16 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ export class Application extends Context {
4848
*
4949
* @param controllerCtor {Function} The controller class
5050
* (constructor function).
51+
* @param {string=} name Optional controller name, default to the class name
5152
* @return {Binding} The newly created binding, you can use the reference to
5253
* further modify the binding, e.g. lock the value to prevent further
5354
* modifications.
@@ -58,10 +59,11 @@ export class Application extends Context {
5859
* app.controller(MyController).lock();
5960
* ```
6061
*/
61-
controller(controllerCtor: ControllerClass): Binding {
62-
return this.bind('controllers.' + controllerCtor.name).toClass(
63-
controllerCtor,
64-
);
62+
controller(controllerCtor: ControllerClass, name?: string): Binding {
63+
name = name || controllerCtor.name;
64+
return this.bind(`controllers.${name}`)
65+
.toClass(controllerCtor)
66+
.tag('controller');
6567
}
6668

6769
/**
@@ -89,6 +91,7 @@ export class Application extends Context {
8991
const key = `${CoreBindings.SERVERS}.${suffix}`;
9092
return this.bind(key)
9193
.toClass(ctor)
94+
.tag('server')
9295
.inScope(BindingScope.SINGLETON);
9396
}
9497

@@ -181,7 +184,8 @@ export class Application extends Context {
181184
* Add a component to this application and register extensions such as
182185
* controllers, providers, and servers from the component.
183186
*
184-
* @param component The component class to add.
187+
* @param componentCtor The component class to add.
188+
* @param {string=} name Optional component name, default to the class name
185189
*
186190
* ```ts
187191
*
@@ -197,9 +201,13 @@ export class Application extends Context {
197201
* app.component(ProductComponent);
198202
* ```
199203
*/
200-
public component(component: Constructor<Component>) {
201-
const componentKey = `components.${component.name}`;
202-
this.bind(componentKey).toClass(component);
204+
public component(componentCtor: Constructor<Component>, name?: string) {
205+
name = name || componentCtor.name;
206+
const componentKey = `components.${name}`;
207+
this.bind(componentKey)
208+
.toClass(componentCtor)
209+
.inScope(BindingScope.SINGLETON)
210+
.tag('component');
203211
// Assuming components can be synchronously instantiated
204212
const instance = this.getSync(componentKey);
205213
mountComponent(this, instance);

packages/core/test/acceptance/application.acceptance.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,10 @@ describe('Bootstrapping the application', () => {
4949
expect(app.find('controllers.*').map(b => b.key)).to.eql([
5050
'controllers.ProductController',
5151
]);
52+
53+
expect(app.findByTag('controller').map(b => b.key)).to.eql([
54+
'controllers.ProductController',
55+
]);
5256
});
5357

5458
it('registers all controllers from components', async () => {

packages/core/test/unit/application.test.ts

Lines changed: 59 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,64 @@ import {Application, Server, Component} from '../../index';
88
import {Context, Constructor} from '@loopback/context';
99

1010
describe('Application', () => {
11+
describe('controller binding', () => {
12+
let app: Application;
13+
class MyController {}
14+
15+
beforeEach(givenApp);
16+
17+
it('binds a controller', () => {
18+
const binding = app.controller(MyController);
19+
expect(Array.from(binding.tags)).to.containEql('controller');
20+
expect(binding.key).to.equal('controllers.MyController');
21+
expect(findKeysByTag(app, 'controller')).to.containEql(binding.key);
22+
});
23+
24+
it('binds a controller with custom name', () => {
25+
const binding = app.controller(MyController, 'my-controller');
26+
expect(Array.from(binding.tags)).to.containEql('controller');
27+
expect(binding.key).to.equal('controllers.my-controller');
28+
expect(findKeysByTag(app, 'controller')).to.containEql(binding.key);
29+
});
30+
31+
function givenApp() {
32+
app = new Application();
33+
}
34+
});
35+
36+
describe('component binding', () => {
37+
let app: Application;
38+
class MyController {}
39+
class MyComponent implements Component {
40+
controllers = [MyController];
41+
}
42+
43+
beforeEach(givenApp);
44+
45+
it('binds a component', () => {
46+
app.component(MyComponent);
47+
expect(findKeysByTag(app, 'component')).to.containEql(
48+
'components.MyComponent',
49+
);
50+
});
51+
52+
it('binds a component', () => {
53+
app.component(MyComponent, 'my-component');
54+
expect(findKeysByTag(app, 'component')).to.containEql(
55+
'components.my-component',
56+
);
57+
});
58+
59+
function givenApp() {
60+
app = new Application();
61+
}
62+
});
63+
1164
describe('server binding', () => {
1265
it('defaults to constructor name', async () => {
1366
const app = new Application();
14-
app.server(FakeServer);
67+
const binding = app.server(FakeServer);
68+
expect(Array.from(binding.tags)).to.containEql('server');
1569
const result = await app.getServer(FakeServer.name);
1670
expect(result.constructor.name).to.equal(FakeServer.name);
1771
});
@@ -62,6 +116,10 @@ describe('Application', () => {
62116
});
63117
});
64118
});
119+
120+
function findKeysByTag(ctx: Context, tag: string | RegExp) {
121+
return ctx.findByTag(tag).map(binding => binding.key);
122+
}
65123
});
66124

67125
class FakeComponent implements Component {

0 commit comments

Comments
 (0)