Skip to content

Commit 8d33bec

Browse files
committed
fix(core): get rid of array registration
1 parent 0101887 commit 8d33bec

File tree

13 files changed

+65
-112
lines changed

13 files changed

+65
-112
lines changed

packages/authentication/test/acceptance/basic-auth.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,8 @@ describe('Basic Authentication', () => {
9090

9191
async function givenAServer() {
9292
app = new Application();
93-
app.components([AuthenticationComponent, RestComponent]);
93+
app.component(AuthenticationComponent);
94+
app.component(RestComponent);
9495
server = await app.getServer(RestServer);
9596
}
9697

packages/cli/generators/extension/templates/src/mixins/README.md

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -154,7 +154,6 @@ class LoggingComponent implements Component{
154154
loggers: [ColorLogger];
155155
}
156156

157-
const app = new LoggingApplication({
158-
components: [LoggingComponent] // Logger from MyComponent will be bound to loggers.ColorLogger
159-
});
157+
const app = new LoggingApplication();
158+
app.component(LoggingComponent); // Logger from MyComponent will be bound to loggers.ColorLogger
160159
```

packages/cli/generators/extension/templates/src/providers/README.md

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -16,18 +16,18 @@ The logger will log the URL, the parsed request parameters, and the result. The
1616

1717
TimerProvider is automatically bound to your Application's [Context](http://loopback.io/doc/en/lb4/Context.html) using the LogComponent which exports this provider with a binding key of `extension-starter.timer`. You can learn more about components in the [related resources section](#related-resources).
1818

19-
This provider makes availble to your application a timer function which given a start time _(given as an array [seconds, nanoseconds])_ can give you a total time elapsed since the start in milliseconds. The timer can also start timing if no start time is given. This is used by LogComponent to allow a user to time a Sequence.
19+
This provider makes availble to your application a timer function which given a start time _(given as an array [seconds, nanoseconds])_ can give you a total time elapsed since the start in milliseconds. The timer can also start timing if no start time is given. This is used by LogComponent to allow a user to time a Sequence.
2020

2121
*NOTE:* _You can get the start time in the required format by using `this.logger.startTimer()`._
2222

2323
You can provide your own implementation of the elapsed time function by binding it to the binding key (accessible via `ExtensionStarterBindings`) as follows:
2424
```ts
2525
app.bind(ExtensionStarterBindings.TIMER).to(timerFn);
26-
```
26+
```
2727

2828
### LogProvider
2929

30-
LogProvider can automatically be bound to your Application's Context using the LogComponent which exports the provider with a binding key of `extension-starter.actions.log`.
30+
LogProvider can automatically be bound to your Application's Context using the LogComponent which exports the provider with a binding key of `extension-starter.actions.log`.
3131

3232
The key can be accessed by importing `ExtensionStarterBindings` as follows:
3333

@@ -38,7 +38,7 @@ import {ExtensionStarterBindings} from 'HelloExtensions';
3838
const key = ExtensionStarterBindings.LOG_ACTION;
3939
```
4040

41-
LogProvider gives us a seuqence action and a `startTimer` function. In order to use the sequence action, you must define your own sequence as shown below.
41+
LogProvider gives us a seuqence action and a `startTimer` function. In order to use the sequence action, you must define your own sequence as shown below.
4242

4343
**Example: Sequence**
4444
```ts
@@ -85,9 +85,9 @@ Once a sequence has been written, we can just use that in our Application as fol
8585
**Example: Application**
8686
```ts
8787
const app = new Application({
88-
sequence: LogSequence,
89-
components: [LogComponent]
88+
sequence: LogSequence
9089
});
90+
app.component(LogComponent);
9191

9292
// Now all requests handled by our sequence will be logged.
9393
```

packages/core/README.md

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -46,10 +46,8 @@ const app = new Application({
4646
port: 3001,
4747
},
4848
});
49-
app.components([
50-
RestComponent, // REST Server
51-
GrpcComponent, // GRPC Server
52-
]);
49+
app.component(RestComponent) // REST Server
50+
app.component(GrpcComponent) // GRPC Server
5351

5452
(async function start() {
5553
// Let's retrieve the bound instances of our servers.

packages/core/src/application.ts

Lines changed: 0 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -48,30 +48,6 @@ export class Application extends Context {
4848
.tag('controller');
4949
}
5050

51-
/**
52-
* Bind an array of controllers to the Application's master
53-
* context.
54-
* Each controller added in this way will automatically be named based on
55-
* the class constructor name with the "controllers." prefix.
56-
*
57-
* If you wish to control the binding keys for particular controller
58-
* instances, use the app.controller function instead.
59-
* ```ts
60-
* app.controllers([
61-
* FooController,
62-
* BarController,
63-
* ]);
64-
* // Creates a binding for "controllers.FooController" and a binding for
65-
* // "controllers.BarController";
66-
* ```
67-
*
68-
* @param ctors Array of controller classes.
69-
* @returns {Binding[]} An array of bindings for the registered controllers.
70-
*/
71-
controllers(ctors: ControllerClass[]): Binding[] {
72-
return ctors.map(ctor => this.controller(ctor));
73-
}
74-
7551
/**
7652
* Bind a Server constructor to the Application's master context.
7753
* Each server constructor added in this way must provide a unique prefix
@@ -218,29 +194,6 @@ export class Application extends Context {
218194
const instance = this.getSync(componentKey);
219195
mountComponent(this, instance);
220196
}
221-
222-
/**
223-
* Add multiple components to this application and register their
224-
* extensions.
225-
*
226-
* Each component added in this way will automatically be named based on the
227-
* class constructor name with the "components." prefix.
228-
*
229-
* If you wish to control the binding keys for particular instances,
230-
* use the app.component function instead.
231-
* ```ts
232-
* app.components([
233-
* RestComponent,
234-
* GRPCComponent,
235-
* ]);
236-
* // Creates a binding for "components.RestComponent" and a binding for
237-
* // "components.GRPCComponent";
238-
* ```
239-
* @param ctors Array of components to add.
240-
*/
241-
public components(ctors: Constructor<Component>[]) {
242-
ctors.map(ctor => this.component(ctor));
243-
}
244197
}
245198

246199
/**

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

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,8 @@ describe('Bootstrapping the application', () => {
9393
}
9494
}
9595
const app = new Application();
96-
app.components([ConfigComponent, GreetingComponent]);
96+
app.component(ConfigComponent);
97+
app.component(GreetingComponent);
9798

9899
expect(app.getSync('greeting')).to.equal('Hi!');
99100
});

packages/core/test/acceptance/application.feature.md

Lines changed: 7 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2,26 +2,24 @@
22

33
- In order to initialize my application
44
- As an app developer
5-
- I want to register components and sequences when initalizing the application
5+
- I want to register components when initalizing the application
66
- So that I can use them throughout the application lifecycle
77

88
## Scenario: Basic usage (config provided)
99

1010
- Given an importable `Application` class
1111
- When I create an application with user-defined configurations
12-
- Then the application should register the given components and sequences
12+
- Then the application should register the given components
1313

1414
```ts
1515
import {Application} from '@loopback/core';
1616
import {Authentication} from '@loopback/authentication';
1717
import {Authorization} from '@loopback/authorization';
1818
import {Rejection} from '@loopback/rejection';
1919

20-
const app = new Application({
21-
components: [Todo, Authentication, Authorization, Rejection],
22-
sequence: [TodoSequence]
23-
});
24-
25-
// get metadata about the registered components
26-
console.log(app.find('sequence.*')); // [Bindings] should match the 1 sequence registered above
20+
const app = new Application();
21+
app.component(Todo);
22+
app.component(Authentication);
23+
app.component(Authorization);
24+
app.component(Rejection);
2725
```

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

Lines changed: 36 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,12 @@
55

66
import {expect} from '@loopback/testlab';
77
import {Application, Server, Component} from '../../index';
8-
import {Context} from '@loopback/context';
8+
import {Context, Constructor} from '@loopback/context';
99

1010
describe('Application', () => {
1111
describe('controller binding', () => {
1212
let app: Application;
1313
class MyController {}
14-
class MySecondController {}
1514

1615
beforeEach(givenApp);
1716

@@ -29,21 +28,6 @@ describe('Application', () => {
2928
expect(findKeysByTag(app, 'controller')).to.containEql(binding.key);
3029
});
3130

32-
it('binds multiple controllers passed in as an array', () => {
33-
const controllers = [MyController, MySecondController];
34-
const bindings = app.controllers(controllers);
35-
36-
const bindA = bindings[0];
37-
expect(Array.from(bindA.tags)).to.containEql('controller');
38-
expect(bindA.key).to.equal('controllers.MyController');
39-
expect(findKeysByTag(app, 'controller')).to.containEql(bindA.key);
40-
41-
const bindB = bindings[1];
42-
expect(Array.from(bindB.tags)).to.containEql('controller');
43-
expect(bindB.key).to.equal('controllers.MySecondController');
44-
expect(findKeysByTag(app, 'controller')).to.containEql(bindB.key);
45-
});
46-
4731
function givenApp() {
4832
app = new Application();
4933
}
@@ -55,9 +39,6 @@ describe('Application', () => {
5539
class MyComponent implements Component {
5640
controllers = [MyController];
5741
}
58-
class MySecondComponent implements Component {
59-
controllers = [MyController];
60-
}
6142

6243
beforeEach(givenApp);
6344

@@ -75,16 +56,6 @@ describe('Application', () => {
7556
);
7657
});
7758

78-
it('binds multiple components passed in as an array', () => {
79-
app.components([MyComponent, MySecondComponent]);
80-
expect(findKeysByTag(app, 'component')).to.containEql(
81-
'components.MyComponent',
82-
);
83-
expect(findKeysByTag(app, 'component')).to.containEql(
84-
'components.MySecondComponent',
85-
);
86-
});
87-
8859
function givenApp() {
8960
app = new Application();
9061
}
@@ -119,11 +90,46 @@ describe('Application', () => {
11990
});
12091
});
12192

93+
describe('start', () => {
94+
it('starts all injected servers', async () => {
95+
const app = new Application();
96+
app.component(FakeComponent);
97+
98+
await app.start();
99+
const server = await app.getServer(FakeServer);
100+
expect(server).to.not.be.null();
101+
expect(server.running).to.equal(true);
102+
await app.stop();
103+
});
104+
105+
it('does not attempt to start poorly named bindings', async () => {
106+
const app = new Application();
107+
app.component(FakeComponent);
108+
109+
// The app.start should not attempt to start this binding.
110+
app.bind('controllers.servers').to({});
111+
await app.start();
112+
await app.stop();
113+
});
114+
});
115+
122116
function findKeysByTag(ctx: Context, tag: string | RegExp) {
123117
return ctx.findByTag(tag).map(binding => binding.key);
124118
}
125119
});
126120

121+
class FakeComponent implements Component {
122+
servers: {
123+
[name: string]: Constructor<Server>;
124+
};
125+
constructor() {
126+
this.servers = {
127+
FakeServer,
128+
FakeServer2: FakeServer,
129+
};
130+
}
131+
}
132+
127133
class FakeServer extends Context implements Server {
128134
running: boolean = false;
129135
constructor() {

packages/example-log-extension/README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ class LogApp extends LogLevelMixin(RestApplication) {
3737
super({
3838
logLevel: LOG_LEVEL.ERROR,
3939
});
40-
this.components(LogComponent);
40+
this.component(LogComponent);
4141
this.controller(MyController);
4242
};
4343
}

packages/example-log-extension/test/acceptance/log.extension.acceptance.ts

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,8 @@
33
// This file is licensed under the MIT License.
44
// License text available at https://opensource.org/licenses/MIT
55

6-
import {Application} from '@loopback/core';
76
import {
8-
RestComponent,
7+
RestApplication,
98
RestServer,
109
get,
1110
param,
@@ -46,7 +45,7 @@ describe('log extension acceptance test', () => {
4645
let server: RestServer;
4746
let spy: SinonSpy;
4847

49-
class LogApp extends LogLevelMixin(Application) {}
48+
class LogApp extends LogLevelMixin(RestApplication) {}
5049

5150
const debugMatch: string = chalk.white(
5251
'DEBUG: /debug :: MyController.debug() => debug called',
@@ -239,7 +238,7 @@ describe('log extension acceptance test', () => {
239238

240239
async function createApp() {
241240
app = new LogApp();
242-
app.components([RestComponent, LogComponent]);
241+
app.component(LogComponent);
243242

244243
app.bind(EXAMPLE_LOG_BINDINGS.TIMER).to(timer);
245244
server = await app.getServer(RestServer);

0 commit comments

Comments
 (0)