UNPKG

2.92 kBPlain TextView Raw
1// Copyright IBM Corp. and LoopBack contributors 2018,2020. All Rights Reserved.
2// Node module: @loopback/boot
3// This file is licensed under the MIT License.
4// License text available at https://opensource.org/licenses/MIT
5
6import {
7 BINDING_METADATA_KEY,
8 config,
9 Constructor,
10 CoreBindings,
11 hasInjections,
12 inject,
13 isDynamicValueProviderClass,
14 MetadataInspector,
15} from '@loopback/core';
16import {ApplicationWithServices} from '@loopback/service-proxy';
17import debugFactory from 'debug';
18import {BootBindings} from '../keys';
19import {ArtifactOptions, booter} from '../types';
20import {BaseArtifactBooter} from './base-artifact.booter';
21
22const debug = debugFactory('loopback:boot:service-booter');
23
24/**
25 * A class that extends BaseArtifactBooter to boot the 'Service' artifact type.
26 * Discovered services are bound using `app.service()`.
27 *
28 * Supported phases: configure, discover, load
29 *
30 * @param app - Application instance
31 * @param projectRoot - Root of User Project relative to which all paths are resolved
32 * @param bootConfig - Service Artifact Options Object
33 */
34@booter('services')
35export class ServiceBooter extends BaseArtifactBooter {
36 constructor(
37 @inject(CoreBindings.APPLICATION_INSTANCE)
38 public app: ApplicationWithServices,
39 @inject(BootBindings.PROJECT_ROOT) projectRoot: string,
40 @config()
41 public serviceConfig: ArtifactOptions = {},
42 ) {
43 super(
44 projectRoot,
45 // Set Service Booter Options if passed in via bootConfig
46 Object.assign({}, ServiceDefaults, serviceConfig),
47 );
48 }
49
50 /**
51 * Uses super method to get a list of Artifact classes. Boot each file by
52 * creating a DataSourceConstructor and binding it to the application class.
53 */
54 async load() {
55 await super.load();
56
57 for (const cls of this.classes) {
58 if (!isBindableClass(cls)) continue;
59
60 debug('Bind class: %s', cls.name);
61 const binding = this.app.service(cls);
62 debug('Binding created for class: %j', binding);
63 }
64 }
65}
66
67/**
68 * Default ArtifactOptions for DataSourceBooter.
69 */
70export const ServiceDefaults: ArtifactOptions = {
71 dirs: ['services'],
72 extensions: ['.service.js'],
73 nested: true,
74};
75
76function isServiceProvider(cls: Constructor<unknown>) {
77 const hasSupportedName = cls.name.endsWith('Provider');
78 const hasValueMethod = typeof cls.prototype.value === 'function';
79 return hasSupportedName && hasValueMethod;
80}
81
82function isBindableClass(cls: Constructor<unknown>) {
83 if (MetadataInspector.getClassMetadata(BINDING_METADATA_KEY, cls)) {
84 return true;
85 }
86 if (hasInjections(cls)) {
87 return true;
88 }
89 if (isServiceProvider(cls)) {
90 debug('Provider class found: %s', cls.name);
91 return true;
92 }
93 if (isDynamicValueProviderClass(cls)) {
94 debug('Dynamic value provider class found: %s', cls.name);
95 return true;
96 }
97 debug('Skip class not decorated with @injectable: %s', cls.name);
98 return false;
99}