UNPKG

11.7 kBJavaScriptView Raw
1/**
2 * @license
3 * Copyright Google Inc. All Rights Reserved.
4 *
5 * Use of this source code is governed by an MIT-style license that can be
6 * found in the LICENSE file at https://angular.io/license
7 */
8import { Injector, THROW_IF_NOT_FOUND } from './injector';
9import { Self, SkipSelf } from './metadata';
10import { cyclicDependencyError, instantiationError, noProviderError, outOfBoundsError } from './reflective_errors';
11import { ReflectiveKey } from './reflective_key';
12import { resolveReflectiveProviders, } from './reflective_provider';
13// Threshold for the dynamic version
14var UNDEFINED = new Object();
15/**
16 * A ReflectiveDependency injection container used for instantiating objects and resolving
17 * dependencies.
18 *
19 * An `Injector` is a replacement for a `new` operator, which can automatically resolve the
20 * constructor dependencies.
21 *
22 * In typical use, application code asks for the dependencies in the constructor and they are
23 * resolved by the `Injector`.
24 *
25 * ### Example ([live demo](http://plnkr.co/edit/jzjec0?p=preview))
26 *
27 * The following example creates an `Injector` configured to create `Engine` and `Car`.
28 *
29 * ```typescript
30 * @Injectable()
31 * class Engine {
32 * }
33 *
34 * @Injectable()
35 * class Car {
36 * constructor(public engine:Engine) {}
37 * }
38 *
39 * var injector = ReflectiveInjector.resolveAndCreate([Car, Engine]);
40 * var car = injector.get(Car);
41 * expect(car instanceof Car).toBe(true);
42 * expect(car.engine instanceof Engine).toBe(true);
43 * ```
44 *
45 * Notice, we don't use the `new` operator because we explicitly want to have the `Injector`
46 * resolve all of the object's dependencies automatically.
47 *
48 * @stable
49 */
50var ReflectiveInjector = /** @class */ (function () {
51 function ReflectiveInjector() {
52 }
53 /**
54 * Turns an array of provider definitions into an array of resolved providers.
55 *
56 * A resolution is a process of flattening multiple nested arrays and converting individual
57 * providers into an array of {@link ResolvedReflectiveProvider}s.
58 *
59 * ### Example ([live demo](http://plnkr.co/edit/AiXTHi?p=preview))
60 *
61 * ```typescript
62 * @Injectable()
63 * class Engine {
64 * }
65 *
66 * @Injectable()
67 * class Car {
68 * constructor(public engine:Engine) {}
69 * }
70 *
71 * var providers = ReflectiveInjector.resolve([Car, [[Engine]]]);
72 *
73 * expect(providers.length).toEqual(2);
74 *
75 * expect(providers[0] instanceof ResolvedReflectiveProvider).toBe(true);
76 * expect(providers[0].key.displayName).toBe("Car");
77 * expect(providers[0].dependencies.length).toEqual(1);
78 * expect(providers[0].factory).toBeDefined();
79 *
80 * expect(providers[1].key.displayName).toBe("Engine");
81 * });
82 * ```
83 *
84 * See {@link ReflectiveInjector#fromResolvedProviders} for more info.
85 */
86 ReflectiveInjector.resolve = function (providers) {
87 return resolveReflectiveProviders(providers);
88 };
89 /**
90 * Resolves an array of providers and creates an injector from those providers.
91 *
92 * The passed-in providers can be an array of `Type`, {@link Provider},
93 * or a recursive array of more providers.
94 *
95 * ### Example ([live demo](http://plnkr.co/edit/ePOccA?p=preview))
96 *
97 * ```typescript
98 * @Injectable()
99 * class Engine {
100 * }
101 *
102 * @Injectable()
103 * class Car {
104 * constructor(public engine:Engine) {}
105 * }
106 *
107 * var injector = ReflectiveInjector.resolveAndCreate([Car, Engine]);
108 * expect(injector.get(Car) instanceof Car).toBe(true);
109 * ```
110 *
111 * This function is slower than the corresponding `fromResolvedProviders`
112 * because it needs to resolve the passed-in providers first.
113 * See {@link Injector#resolve} and {@link Injector#fromResolvedProviders}.
114 */
115 ReflectiveInjector.resolveAndCreate = function (providers, parent) {
116 var ResolvedReflectiveProviders = ReflectiveInjector.resolve(providers);
117 return ReflectiveInjector.fromResolvedProviders(ResolvedReflectiveProviders, parent);
118 };
119 /**
120 * Creates an injector from previously resolved providers.
121 *
122 * This API is the recommended way to construct injectors in performance-sensitive parts.
123 *
124 * ### Example ([live demo](http://plnkr.co/edit/KrSMci?p=preview))
125 *
126 * ```typescript
127 * @Injectable()
128 * class Engine {
129 * }
130 *
131 * @Injectable()
132 * class Car {
133 * constructor(public engine:Engine) {}
134 * }
135 *
136 * var providers = ReflectiveInjector.resolve([Car, Engine]);
137 * var injector = ReflectiveInjector.fromResolvedProviders(providers);
138 * expect(injector.get(Car) instanceof Car).toBe(true);
139 * ```
140 * @experimental
141 */
142 ReflectiveInjector.fromResolvedProviders = function (providers, parent) {
143 // tslint:disable-next-line:no-use-before-declare
144 return new ReflectiveInjector_(providers, parent);
145 };
146 return ReflectiveInjector;
147}());
148export { ReflectiveInjector };
149// tslint:disable-next-line:class-name
150var ReflectiveInjector_ = /** @class */ (function () {
151 /**
152 * Private
153 */
154 function ReflectiveInjector_(_providers, _parent) {
155 /** @internal */
156 this._constructionCounter = 0;
157 this._providers = _providers;
158 this._parent = _parent || null;
159 var len = _providers.length;
160 this.keyIds = new Array(len);
161 this.objs = new Array(len);
162 for (var i = 0; i < len; i++) {
163 this.keyIds[i] = _providers[i].key.id;
164 this.objs[i] = UNDEFINED;
165 }
166 }
167 ReflectiveInjector_.prototype.get = function (token, notFoundValue) {
168 if (notFoundValue === void 0) { notFoundValue = THROW_IF_NOT_FOUND; }
169 return this._getByKey(ReflectiveKey.get(token), null, notFoundValue);
170 };
171 Object.defineProperty(ReflectiveInjector_.prototype, "parent", {
172 get: function () {
173 return this._parent;
174 },
175 enumerable: false,
176 configurable: true
177 });
178 ReflectiveInjector_.prototype.resolveAndCreateChild = function (providers) {
179 var ResolvedReflectiveProviders = ReflectiveInjector.resolve(providers);
180 return this.createChildFromResolved(ResolvedReflectiveProviders);
181 };
182 ReflectiveInjector_.prototype.createChildFromResolved = function (providers) {
183 var inj = new ReflectiveInjector_(providers);
184 inj._parent = this;
185 return inj;
186 };
187 ReflectiveInjector_.prototype.resolveAndInstantiate = function (provider) {
188 return this.instantiateResolved(ReflectiveInjector.resolve([provider])[0]);
189 };
190 ReflectiveInjector_.prototype.instantiateResolved = function (provider) {
191 return this._instantiateProvider(provider);
192 };
193 ReflectiveInjector_.prototype.getProviderAtIndex = function (index) {
194 if (index < 0 || index >= this._providers.length) {
195 throw outOfBoundsError(index);
196 }
197 return this._providers[index];
198 };
199 /** @internal */
200 ReflectiveInjector_.prototype._new = function (provider) {
201 if (this._constructionCounter++ > this._getMaxNumberOfObjects()) {
202 throw cyclicDependencyError(this, provider.key);
203 }
204 return this._instantiateProvider(provider);
205 };
206 ReflectiveInjector_.prototype._getMaxNumberOfObjects = function () {
207 return this.objs.length;
208 };
209 ReflectiveInjector_.prototype._instantiateProvider = function (provider) {
210 if (provider.multiProvider) {
211 var res = new Array(provider.resolvedFactories.length);
212 for (var i = 0; i < provider.resolvedFactories.length; ++i) {
213 res[i] = this._instantiate(provider, provider.resolvedFactories[i]);
214 }
215 return res;
216 }
217 else {
218 return this._instantiate(provider, provider.resolvedFactories[0]);
219 }
220 };
221 ReflectiveInjector_.prototype._instantiate = function (provider, ResolvedReflectiveFactory) {
222 var _this = this;
223 var factory = ResolvedReflectiveFactory.factory;
224 var deps;
225 try {
226 deps = ResolvedReflectiveFactory.dependencies.map(function (dep) { return _this._getByReflectiveDependency(dep); });
227 }
228 catch (e) {
229 if (e.addKey) {
230 e.addKey(this, provider.key);
231 }
232 throw e;
233 }
234 var obj;
235 try {
236 obj = factory.apply(void 0, deps);
237 }
238 catch (e) {
239 throw instantiationError(this, e, e.stack, provider.key);
240 }
241 return obj;
242 };
243 ReflectiveInjector_.prototype._getByReflectiveDependency = function (dep) {
244 return this._getByKey(dep.key, dep.visibility, dep.optional ? null : THROW_IF_NOT_FOUND);
245 };
246 ReflectiveInjector_.prototype._getByKey = function (key, visibility, notFoundValue) {
247 // tslint:disable-next-line:no-use-before-declare
248 if (key === INJECTOR_KEY) {
249 return this;
250 }
251 if (visibility instanceof Self) {
252 return this._getByKeySelf(key, notFoundValue);
253 }
254 else {
255 return this._getByKeyDefault(key, notFoundValue, visibility);
256 }
257 };
258 ReflectiveInjector_.prototype._getObjByKeyId = function (keyId) {
259 for (var i = 0; i < this.keyIds.length; i++) {
260 if (this.keyIds[i] === keyId) {
261 if (this.objs[i] === UNDEFINED) {
262 this.objs[i] = this._new(this._providers[i]);
263 }
264 return this.objs[i];
265 }
266 }
267 return UNDEFINED;
268 };
269 /** @internal */
270 ReflectiveInjector_.prototype._throwOrNull = function (key, notFoundValue) {
271 if (notFoundValue !== THROW_IF_NOT_FOUND) {
272 return notFoundValue;
273 }
274 else {
275 throw noProviderError(this, key);
276 }
277 };
278 /** @internal */
279 ReflectiveInjector_.prototype._getByKeySelf = function (key, notFoundValue) {
280 var obj = this._getObjByKeyId(key.id);
281 return obj !== UNDEFINED ? obj : this._throwOrNull(key, notFoundValue);
282 };
283 /** @internal */
284 ReflectiveInjector_.prototype._getByKeyDefault = function (key, notFoundValue, visibility) {
285 var inj;
286 if (visibility instanceof SkipSelf) {
287 inj = this._parent;
288 }
289 else {
290 inj = this;
291 }
292 while (inj instanceof ReflectiveInjector_) {
293 var inj_ = inj;
294 var obj = inj_._getObjByKeyId(key.id);
295 if (obj !== UNDEFINED)
296 return obj;
297 inj = inj_._parent;
298 }
299 if (inj !== null) {
300 return inj.get(key.token, notFoundValue);
301 }
302 else {
303 return this._throwOrNull(key, notFoundValue);
304 }
305 };
306 Object.defineProperty(ReflectiveInjector_.prototype, "displayName", {
307 get: function () {
308 var providers = _mapProviders(this, function (b) { return ' "' + b.key.displayName + '" '; }).join(', ');
309 return "ReflectiveInjector(providers: [" + providers + "])";
310 },
311 enumerable: false,
312 configurable: true
313 });
314 ReflectiveInjector_.prototype.toString = function () {
315 return this.displayName;
316 };
317 return ReflectiveInjector_;
318}());
319export { ReflectiveInjector_ };
320var INJECTOR_KEY = ReflectiveKey.get(Injector);
321function _mapProviders(injector, fn) {
322 var res = new Array(injector._providers.length);
323 for (var i = 0; i < injector._providers.length; ++i) {
324 res[i] = fn(injector.getProviderAtIndex(i));
325 }
326 return res;
327}
328//# sourceMappingURL=reflective_injector.js.map
\No newline at end of file