Skip to content

Commit

Permalink
feat(core): add services to component artifacts
Browse files Browse the repository at this point in the history
- add services property to Component interface
- allow to contribute services from a component to
an application
- automatically bind service to application

Signed-off-by: nflaig <nflaig@protonmail.com>
  • Loading branch information
nflaig authored and raymondfeng committed Jun 11, 2020
1 parent 2a30484 commit 5545345
Show file tree
Hide file tree
Showing 3 changed files with 49 additions and 2 deletions.
29 changes: 29 additions & 0 deletions packages/core/src/__tests__/unit/application.unit.ts
Expand Up @@ -171,6 +171,35 @@ describe('Application', () => {
expect(binding.tagNames).to.containEql('foo');
});

it('binds services from a component', () => {
class MyService {}

class MyComponentWithServices implements Component {
services = [MyService];
}

app.component(MyComponentWithServices);

expect(
app.getBinding('services.MyService').valueConstructor,
).to.be.exactly(MyService);
});

it('binds services with @bind from a component', () => {
@bind({scope: BindingScope.TRANSIENT, tags: ['foo']})
class MyService {}

class MyComponentWithServices implements Component {
services = [MyService];
}

app.component(MyComponentWithServices);

const binding = app.getBinding('services.MyService');
expect(binding.scope).to.eql(BindingScope.TRANSIENT);
expect(binding.tagNames).to.containEql('foo');
});

it('honors tags when binding providers from a component', () => {
@bind({tags: ['foo']})
class MyProvider implements Provider<string> {
Expand Down
5 changes: 4 additions & 1 deletion packages/core/src/application.ts
Expand Up @@ -451,7 +451,7 @@ export class Application extends Context implements LifeCycleObserver {
* ```
*/
public service<S>(
cls: Constructor<S | Provider<S>>,
cls: ServiceOrProviderClass<S>,
nameOrOptions?: string | ServiceOptions,
): Binding<S> {
const options = toOptions(nameOrOptions);
Expand Down Expand Up @@ -602,6 +602,9 @@ export interface ApplicationConfig {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
export type ControllerClass<T = any> = Constructor<T>;

// eslint-disable-next-line @typescript-eslint/no-explicit-any
export type ServiceOrProviderClass<T = any> = Constructor<T | Provider<T>>;

/**
* Type description for `package.json`
*/
Expand Down
17 changes: 16 additions & 1 deletion packages/core/src/component.ts
Expand Up @@ -10,7 +10,11 @@ import {
createBindingFromClass,
Provider,
} from '@loopback/context';
import {Application, ControllerClass} from './application';
import {
Application,
ControllerClass,
ServiceOrProviderClass,
} from './application';
import {LifeCycleObserver} from './lifecycle';
import {Server} from './server';

Expand Down Expand Up @@ -71,6 +75,11 @@ export interface Component {

lifeCycleObservers?: Constructor<LifeCycleObserver>[];

/**
* An array of service or provider classes
*/
services?: ServiceOrProviderClass[];

/**
* An array of bindings to be aded to the application context.
*
Expand Down Expand Up @@ -137,4 +146,10 @@ export function mountComponent(app: Application, component: Component) {
app.lifeCycleObserver(observer);
}
}

if (component.services) {
for (const service of component.services) {
app.service(service);
}
}
}

0 comments on commit 5545345

Please sign in to comment.