1 |
|
2 |
|
3 |
|
4 |
|
5 |
|
6 | import {
|
7 | BINDING_METADATA_KEY,
|
8 | config,
|
9 | Constructor,
|
10 | CoreBindings,
|
11 | hasInjections,
|
12 | inject,
|
13 | isDynamicValueProviderClass,
|
14 | MetadataInspector,
|
15 | } from '@loopback/core';
|
16 | import {ApplicationWithServices} from '@loopback/service-proxy';
|
17 | import debugFactory from 'debug';
|
18 | import {BootBindings} from '../keys';
|
19 | import {ArtifactOptions, booter} from '../types';
|
20 | import {BaseArtifactBooter} from './base-artifact.booter';
|
21 |
|
22 | const debug = debugFactory('loopback:boot:service-booter');
|
23 |
|
24 |
|
25 |
|
26 |
|
27 |
|
28 |
|
29 |
|
30 |
|
31 |
|
32 |
|
33 |
|
34 | @booter('services')
|
35 | export 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 |
|
46 | Object.assign({}, ServiceDefaults, serviceConfig),
|
47 | );
|
48 | }
|
49 |
|
50 | |
51 |
|
52 |
|
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 |
|
69 |
|
70 | export const ServiceDefaults: ArtifactOptions = {
|
71 | dirs: ['services'],
|
72 | extensions: ['.service.js'],
|
73 | nested: true,
|
74 | };
|
75 |
|
76 | function 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 |
|
82 | function 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 | }
|