UNPKG

5.86 kBJavaScriptView Raw
1"use strict";
2// Copyright IBM Corp. and LoopBack contributors 2018,2019. All Rights Reserved.
3// Node module: @loopback/boot
4// This file is licensed under the MIT License.
5// License text available at https://opensource.org/licenses/MIT
6Object.defineProperty(exports, "__esModule", { value: true });
7exports.Bootstrapper = void 0;
8const tslib_1 = require("tslib");
9const core_1 = require("@loopback/core");
10const debug_1 = tslib_1.__importDefault(require("debug"));
11const path_1 = require("path");
12const keys_1 = require("./keys");
13const mixins_1 = require("./mixins");
14const types_1 = require("./types");
15const debug = (0, debug_1.default)('loopback:boot:bootstrapper');
16/**
17 * The Bootstrapper class provides the `boot` function that is responsible for
18 * finding and executing the Booters in an application based on given options.
19 *
20 * NOTE: Bootstrapper should be bound as a SINGLETON so it can be cached as
21 * it does not maintain any state of it's own.
22 *
23 * @param app - Application instance
24 * @param projectRoot - The root directory of the project, relative to which all other paths are resolved
25 * @param bootOptions - The BootOptions describing the conventions to be used by various Booters
26 */
27let Bootstrapper = class Bootstrapper {
28 constructor(app, projectRoot, bootOptions = {}) {
29 this.app = app;
30 this.projectRoot = projectRoot;
31 this.bootOptions = bootOptions;
32 // Resolve path to projectRoot and re-bind
33 this.projectRoot = (0, path_1.resolve)(this.projectRoot);
34 app.bind(keys_1.BootBindings.PROJECT_ROOT).to(this.projectRoot);
35 // This is re-bound for testing reasons where this value may be passed directly
36 // and needs to be propagated to the Booters via DI
37 app.bind(keys_1.BootBindings.BOOT_OPTIONS).to(this.bootOptions);
38 }
39 /**
40 * Function is responsible for calling all registered Booter classes that
41 * are bound to the Application instance. Each phase of an instance must
42 * complete before the next phase is started.
43 *
44 * @param execOptions - Execution options for boot. These
45 * determine the phases and booters that are run.
46 * @param ctx - Optional Context to use to resolve bindings. This is
47 * primarily useful when running app.boot() again but with different settings
48 * (in particular phases) such as 'start' / 'stop'. Using a returned Context from
49 * a previous boot call allows DI to retrieve the same instances of Booters previously
50 * used as they are bound using a CONTEXT scope. This is important as Booter instances
51 * may maintain state.
52 */
53 async boot(execOptions, ctx) {
54 var _a, _b, _c;
55 const bootCtx = ctx !== null && ctx !== void 0 ? ctx : new core_1.Context(this.app);
56 // Bind booters passed in as a part of BootOptions
57 // We use _bindBooter so this Class can be used without the Mixin
58 if (execOptions === null || execOptions === void 0 ? void 0 : execOptions.booters) {
59 execOptions.booters.forEach(booter => (0, mixins_1.bindBooter)(this.app, booter));
60 }
61 // Determine the phases to be run. If a user set a phases filter, those
62 // are selected otherwise we run the default phases (BOOTER_PHASES).
63 const phases = (_b = (_a = execOptions === null || execOptions === void 0 ? void 0 : execOptions.filter) === null || _a === void 0 ? void 0 : _a.phases) !== null && _b !== void 0 ? _b : types_1.BOOTER_PHASES;
64 // Find booters registered to the BOOTERS_TAG by getting the bindings
65 const bindings = bootCtx.findByTag(keys_1.BootTags.BOOTER);
66 // Prefix length. +1 because of `.` => 'booters.'
67 const prefixLength = keys_1.BootBindings.BOOTERS.length + 1;
68 // Names of all registered booters.
69 const defaultBooterNames = bindings.map(binding => binding.key.slice(prefixLength));
70 // Determining the booters to be run. If a user set a booters filter (class
71 // names of booters that should be run), that is the value, otherwise it
72 // is all the registered booters by default.
73 const names = execOptions
74 ? ((_c = execOptions.filter) === null || _c === void 0 ? void 0 : _c.booters)
75 ? execOptions.filter.booters
76 : defaultBooterNames
77 : defaultBooterNames;
78 // Filter bindings by names
79 const filteredBindings = bindings.filter(binding => names.includes(binding.key.slice(prefixLength)));
80 // Resolve Booter Instances
81 const booterInsts = await (0, core_1.resolveList)(filteredBindings, binding =>
82 // We cannot use Booter interface here because "filter.booters"
83 // allows arbitrary string values, not only the phases defined
84 // by Booter interface
85 bootCtx.get(binding.key));
86 // Run phases of booters
87 for (const phase of phases) {
88 for (const inst of booterInsts) {
89 const instName = inst.constructor.name;
90 if (inst[phase]) {
91 debug(`${instName} phase: ${phase} starting.`);
92 await inst[phase]();
93 debug(`${instName} phase: ${phase} complete.`);
94 }
95 else {
96 debug(`${instName} phase: ${phase} not implemented.`);
97 }
98 }
99 }
100 return bootCtx;
101 }
102};
103Bootstrapper = tslib_1.__decorate([
104 tslib_1.__param(0, (0, core_1.inject)(core_1.CoreBindings.APPLICATION_INSTANCE)),
105 tslib_1.__param(1, (0, core_1.inject)(keys_1.BootBindings.PROJECT_ROOT)),
106 tslib_1.__param(2, (0, core_1.inject)(keys_1.BootBindings.BOOT_OPTIONS, { optional: true })),
107 tslib_1.__metadata("design:paramtypes", [Object, String, Object])
108], Bootstrapper);
109exports.Bootstrapper = Bootstrapper;
110//# sourceMappingURL=bootstrapper.js.map
\No newline at end of file