UNPKG

6.92 kBJavaScriptView Raw
1"use strict";
2// Copyright IBM Corp. and LoopBack contributors 2019. All Rights Reserved.
3// Node module: @loopback/context
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.config = void 0;
8const binding_key_1 = require("./binding-key");
9const context_view_1 = require("./context-view");
10const inject_1 = require("./inject");
11const value_promise_1 = require("./value-promise");
12/**
13 * Inject a property from `config` of the current binding. If no corresponding
14 * config value is present, `undefined` will be injected as the configuration
15 * binding is resolved with `optional: true` by default.
16 *
17 * @example
18 * ```ts
19 * class Store {
20 * constructor(
21 * @config('x') public optionX: number,
22 * @config('y') public optionY: string,
23 * ) { }
24 * }
25 *
26 * ctx.configure('store1', { x: 1, y: 'a' });
27 * ctx.configure('store2', { x: 2, y: 'b' });
28 *
29 * ctx.bind('store1').toClass(Store);
30 * ctx.bind('store2').toClass(Store);
31 *
32 * const store1 = ctx.getSync('store1');
33 * expect(store1.optionX).to.eql(1);
34 * expect(store1.optionY).to.eql('a');
35 *
36 * const store2 = ctx.getSync('store2');
37 * expect(store2.optionX).to.eql(2);
38 * expect(store2.optionY).to.eql('b');
39 * ```
40 *
41 * @param propertyPath - Optional property path of the config. If is `''` or not
42 * present, the `config` object will be returned.
43 * @param metadata - Optional metadata to help the injection
44 */
45function config(propertyPath, metadata) {
46 propertyPath = propertyPath !== null && propertyPath !== void 0 ? propertyPath : '';
47 if (typeof propertyPath === 'object') {
48 metadata = propertyPath;
49 propertyPath = '';
50 }
51 metadata = Object.assign({ propertyPath, decorator: '@config', optional: true }, metadata);
52 return (0, inject_1.inject)('', metadata, resolveFromConfig);
53}
54exports.config = config;
55(function (config) {
56 /**
57 * `@inject.getter` decorator to inject a config getter function
58 * @param propertyPath - Optional property path of the config object
59 * @param metadata - Injection metadata
60 */
61 config.getter = function injectConfigGetter(propertyPath, metadata) {
62 propertyPath = propertyPath !== null && propertyPath !== void 0 ? propertyPath : '';
63 if (typeof propertyPath === 'object') {
64 metadata = propertyPath;
65 propertyPath = '';
66 }
67 metadata = Object.assign({ propertyPath, decorator: '@config.getter', optional: true }, metadata);
68 return (0, inject_1.inject)('', metadata, resolveAsGetterFromConfig);
69 };
70 /**
71 * `@inject.view` decorator to inject a config context view to allow dynamic
72 * changes in configuration
73 * @param propertyPath - Optional property path of the config object
74 * @param metadata - Injection metadata
75 */
76 config.view = function injectConfigView(propertyPath, metadata) {
77 propertyPath = propertyPath !== null && propertyPath !== void 0 ? propertyPath : '';
78 if (typeof propertyPath === 'object') {
79 metadata = propertyPath;
80 propertyPath = '';
81 }
82 metadata = Object.assign({ propertyPath, decorator: '@config.view', optional: true }, metadata);
83 return (0, inject_1.inject)('', metadata, resolveAsViewFromConfig);
84 };
85})(config || (exports.config = config = {}));
86/**
87 * Get the key for the current binding on which dependency injection is
88 * performed
89 * @param session - Resolution session
90 */
91function getCurrentBindingKey(session) {
92 var _a;
93 // The current binding is not set if `instantiateClass` is invoked directly
94 return (_a = session.currentBinding) === null || _a === void 0 ? void 0 : _a.key;
95}
96/**
97 * Get the target binding key from which the configuration should be resolved
98 * @param injection - Injection
99 * @param session - Resolution session
100 */
101function getTargetBindingKey(injection, session) {
102 return injection.metadata.fromBinding || getCurrentBindingKey(session);
103}
104/**
105 * Resolver for `@config`
106 * @param ctx - Context object
107 * @param injection - Injection metadata
108 * @param session - Resolution session
109 */
110function resolveFromConfig(ctx, injection, session) {
111 const bindingKey = getTargetBindingKey(injection, session);
112 // Return `undefined` if no current binding is present
113 if (!bindingKey)
114 return undefined;
115 const meta = injection.metadata;
116 return ctx.getConfigAsValueOrPromise(bindingKey, meta.propertyPath, {
117 session,
118 optional: meta.optional,
119 });
120}
121/**
122 * Resolver from `@config.getter`
123 * @param ctx - Context object
124 * @param injection - Injection metadata
125 * @param session - Resolution session
126 */
127function resolveAsGetterFromConfig(ctx, injection, session) {
128 (0, inject_1.assertTargetType)(injection, Function, 'Getter function');
129 const bindingKey = getTargetBindingKey(injection, session);
130 const meta = injection.metadata;
131 return async function getter() {
132 // Return `undefined` if no current binding is present
133 if (!bindingKey)
134 return undefined;
135 return ctx.getConfigAsValueOrPromise(bindingKey, meta.propertyPath, {
136 // https://github.com/loopbackio/loopback-next/issues/9041
137 // We should start with a new session for `getter` resolution to avoid
138 // possible circular dependencies
139 session: undefined,
140 optional: meta.optional,
141 });
142 };
143}
144/**
145 * Resolver for `@config.view`
146 * @param ctx - Context object
147 * @param injection - Injection metadata
148 * @param session - Resolution session
149 */
150function resolveAsViewFromConfig(ctx, injection, session) {
151 (0, inject_1.assertTargetType)(injection, context_view_1.ContextView);
152 const bindingKey = getTargetBindingKey(injection, session);
153 // Return `undefined` if no current binding is present
154 if (!bindingKey)
155 return undefined;
156 const view = new ConfigView(ctx, binding => binding.key === binding_key_1.BindingKey.buildKeyForConfig(bindingKey).toString(), injection.metadata.propertyPath);
157 view.open();
158 return view;
159}
160/**
161 * A subclass of `ContextView` to handle dynamic configuration as its
162 * `values()` honors the `propertyPath`.
163 */
164class ConfigView extends context_view_1.ContextView {
165 constructor(ctx, filter, propertyPath) {
166 super(ctx, filter);
167 this.propertyPath = propertyPath;
168 }
169 /**
170 * Get values for the configuration with a property path
171 * @param session - Resolution session
172 */
173 async values(session) {
174 const configValues = await super.values(session);
175 const propertyPath = this.propertyPath;
176 if (!propertyPath)
177 return configValues;
178 return configValues.map(v => (0, value_promise_1.getDeepProperty)(v, propertyPath));
179 }
180}
181//# sourceMappingURL=inject-config.js.map
\No newline at end of file