injection-js
Version:
Dependency Injection library for JavaScript and TypeScript
1,364 lines (1,347 loc) • 65.3 kB
JavaScript
(function (global, factory) {
typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) :
typeof define === 'function' && define.amd ? define(['exports'], factory) :
(global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global["injection-js"] = {}));
})(this, (function (exports) { 'use strict';
let globalScope;
if (typeof window === 'undefined') {
if (typeof WorkerGlobalScope !== 'undefined' && self instanceof WorkerGlobalScope) {
// TODO: Replace any with WorkerGlobalScope from lib.webworker.d.ts #3492
globalScope = self;
}
else {
globalScope = global;
}
}
else {
globalScope = window;
}
// Need to declare a new variable for global here since TypeScript
// exports the original value of the symbol.
const _global = globalScope;
function stringify(token) {
if (typeof token === 'string') {
return token;
}
if (token == null) {
return '' + token;
}
if (token.overriddenName) {
return `${token.overriddenName}`;
}
if (token.name) {
return `${token.name}`;
}
const res = token.toString();
const newLineIndex = res.indexOf('\n');
return newLineIndex === -1 ? res : res.substring(0, newLineIndex);
}
/**
* @license
* Copyright Google Inc. All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/
let _nextClassId = 0;
const Reflect = _global['Reflect'];
function extractAnnotation(annotation) {
if (typeof annotation === 'function' && annotation.hasOwnProperty('annotation')) {
// it is a decorator, extract annotation
annotation = annotation.annotation;
}
return annotation;
}
function applyParams(fnOrArray, key) {
if (fnOrArray === Object || fnOrArray === String || fnOrArray === Function || fnOrArray === Number || fnOrArray === Array) {
throw new Error(`Can not use native ${stringify(fnOrArray)} as constructor`);
}
if (typeof fnOrArray === 'function') {
return fnOrArray;
}
if (Array.isArray(fnOrArray)) {
const annotations = fnOrArray;
const annoLength = annotations.length - 1;
const fn = fnOrArray[annoLength];
if (typeof fn !== 'function') {
throw new Error(`Last position of Class method array must be Function in key ${key} was '${stringify(fn)}'`);
}
if (annoLength !== fn.length) {
throw new Error(`Number of annotations (${annoLength}) does not match number of arguments (${fn.length}) in the function: ${stringify(fn)}`);
}
const paramsAnnotations = [];
for (let i = 0, ii = annotations.length - 1; i < ii; i++) {
const paramAnnotations = [];
paramsAnnotations.push(paramAnnotations);
const annotation = annotations[i];
if (Array.isArray(annotation)) {
for (let j = 0; j < annotation.length; j++) {
paramAnnotations.push(extractAnnotation(annotation[j]));
}
}
else if (typeof annotation === 'function') {
paramAnnotations.push(extractAnnotation(annotation));
}
else {
paramAnnotations.push(annotation);
}
}
Reflect.defineMetadata('parameters', paramsAnnotations, fn);
return fn;
}
throw new Error(`Only Function or Array is supported in Class definition for key '${key}' is '${stringify(fnOrArray)}'`);
}
/**
* Provides a way for expressing ES6 classes with parameter annotations in ES5.
*
* ## Basic Example
*
* ```
* var Greeter = ng.Class({
* constructor: function(name) {
* this.name = name;
* },
*
* greet: function() {
* alert('Hello ' + this.name + '!');
* }
* });
* ```
*
* is equivalent to ES6:
*
* ```
* class Greeter {
* constructor(name) {
* this.name = name;
* }
*
* greet() {
* alert('Hello ' + this.name + '!');
* }
* }
* ```
*
* or equivalent to ES5:
*
* ```
* var Greeter = function (name) {
* this.name = name;
* }
*
* Greeter.prototype.greet = function () {
* alert('Hello ' + this.name + '!');
* }
* ```
*
* ### Example with parameter annotations
*
* ```
* var MyService = ng.Class({
* constructor: [String, [new Optional(), Service], function(name, myService) {
* ...
* }]
* });
* ```
*
* is equivalent to ES6:
*
* ```
* class MyService {
* constructor(name: string, @Optional() myService: Service) {
* ...
* }
* }
* ```
*
* ### Example with inheritance
*
* ```
* var Shape = ng.Class({
* constructor: (color) {
* this.color = color;
* }
* });
*
* var Square = ng.Class({
* extends: Shape,
* constructor: function(color, size) {
* Shape.call(this, color);
* this.size = size;
* }
* });
* ```
* @suppress {globalThis}
* @stable
*/
function Class(clsDef) {
const constructor = applyParams(clsDef.hasOwnProperty('constructor') ? clsDef.constructor : undefined, 'constructor');
let proto = constructor.prototype;
if (clsDef.hasOwnProperty('extends')) {
if (typeof clsDef.extends === 'function') {
constructor.prototype = proto = Object.create(clsDef.extends.prototype);
}
else {
throw new Error(`Class definition 'extends' property must be a constructor function was: ${stringify(clsDef.extends)}`);
}
}
for (const key in clsDef) {
if (key !== 'extends' && key !== 'prototype' && clsDef.hasOwnProperty(key)) {
proto[key] = applyParams(clsDef[key], key);
}
}
if (this && this.annotations instanceof Array) {
Reflect.defineMetadata('annotations', this.annotations, constructor);
}
const constructorName = constructor['name'];
if (!constructorName || constructorName === 'constructor') {
constructor['overriddenName'] = `class${_nextClassId++}`;
}
return constructor;
}
/**
* @suppress {globalThis}
*/
function makeDecorator(name, props, parentClass, chainFn) {
const metaCtor = makeMetadataCtor([props]);
function DecoratorFactory(objOrType) {
if (!(Reflect && Reflect.getOwnMetadata)) {
throw 'reflect-metadata shim is required when using class decorators';
}
if (this instanceof DecoratorFactory) {
metaCtor.call(this, objOrType);
return this;
}
const annotationInstance = new DecoratorFactory(objOrType);
const chainAnnotation = typeof this === 'function' && Array.isArray(this.annotations) ? this.annotations : [];
chainAnnotation.push(annotationInstance);
const TypeDecorator = function TypeDecorator(cls) {
const annotations = Reflect.getOwnMetadata('annotations', cls) || [];
annotations.push(annotationInstance);
Reflect.defineMetadata('annotations', annotations, cls);
return cls;
};
TypeDecorator.annotations = chainAnnotation;
TypeDecorator.Class = Class;
if (chainFn)
chainFn(TypeDecorator);
return TypeDecorator;
}
if (parentClass) {
DecoratorFactory.prototype = Object.create(parentClass.prototype);
}
DecoratorFactory.prototype.toString = () => `@${name}`;
DecoratorFactory.annotationCls = DecoratorFactory;
return DecoratorFactory;
}
function makeMetadataCtor(props) {
return function ctor(...args) {
props.forEach((prop, i) => {
const argVal = args[i];
if (Array.isArray(prop)) {
// plain parameter
this[prop[0]] = argVal === undefined ? prop[1] : argVal;
}
else {
for (const propName in prop) {
this[propName] = argVal && argVal.hasOwnProperty(propName) ? argVal[propName] : prop[propName];
}
}
});
};
}
function makeParamDecorator(name, props, parentClass) {
const metaCtor = makeMetadataCtor(props);
function ParamDecoratorFactory(...args) {
if (this instanceof ParamDecoratorFactory) {
metaCtor.apply(this, args);
return this;
}
const annotationInstance = new ParamDecoratorFactory(...args);
ParamDecorator.annotation = annotationInstance;
return ParamDecorator;
function ParamDecorator(cls, unusedKey, index) {
const parameters = Reflect.getOwnMetadata('parameters', cls) || [];
// there might be gaps if some in between parameters do not have annotations.
// we pad with nulls.
while (parameters.length <= index) {
parameters.push(null);
}
parameters[index] = parameters[index] || [];
parameters[index].push(annotationInstance);
Reflect.defineMetadata('parameters', parameters, cls);
return cls;
}
}
if (parentClass) {
ParamDecoratorFactory.prototype = Object.create(parentClass.prototype);
}
ParamDecoratorFactory.prototype.toString = () => `@${name}`;
ParamDecoratorFactory.annotationCls = ParamDecoratorFactory;
return ParamDecoratorFactory;
}
function makePropDecorator(name, props, parentClass) {
const metaCtor = makeMetadataCtor(props);
function PropDecoratorFactory(...args) {
if (this instanceof PropDecoratorFactory) {
metaCtor.apply(this, args);
return this;
}
const decoratorInstance = new PropDecoratorFactory(...args);
return function PropDecorator(target, name) {
const meta = Reflect.getOwnMetadata('propMetadata', target.constructor) || {};
meta[name] = (meta.hasOwnProperty(name) && meta[name]) || [];
meta[name].unshift(decoratorInstance);
Reflect.defineMetadata('propMetadata', meta, target.constructor);
};
}
if (parentClass) {
PropDecoratorFactory.prototype = Object.create(parentClass.prototype);
}
PropDecoratorFactory.prototype.toString = () => `@${name}`;
PropDecoratorFactory.annotationCls = PropDecoratorFactory;
return PropDecoratorFactory;
}
/**
* @license
* Copyright Google Inc. All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/
/**
* Inject decorator and metadata.
*
* @stable
* @Annotation
*/
const Inject = makeParamDecorator('Inject', [['token', undefined]]);
/**
* Optional decorator and metadata.
*
* @stable
* @Annotation
*/
const Optional = makeParamDecorator('Optional', []);
/**
* Injectable decorator and metadata.
*
* @stable
* @Annotation
*/
const Injectable = makeDecorator('Injectable', []);
/**
* Self decorator and metadata.
*
* @stable
* @Annotation
*/
const Self = makeParamDecorator('Self', []);
/**
* SkipSelf decorator and metadata.
*
* @stable
* @Annotation
*/
const SkipSelf = makeParamDecorator('SkipSelf', []);
/**
* Host decorator and metadata.
*
* @stable
* @Annotation
*/
const Host = makeParamDecorator('Host', []);
/**
* @license
* Copyright Google Inc. All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/
/**
* Allows to refer to references which are not yet defined.
*
* For instance, `forwardRef` is used when the `token` which we need to refer to for the purposes of
* DI is declared,
* but not yet defined. It is also used when the `token` which we use when creating a query is not
* yet defined.
*
* ### Example
* {@example core/di/ts/forward_ref/forward_ref_spec.ts region='forward_ref'}
* @experimental
*/
function forwardRef(forwardRefFn) {
forwardRefFn.__forward_ref__ = forwardRef;
forwardRefFn.toString = function () {
return stringify(this());
};
return forwardRefFn;
}
/**
* Lazily retrieves the reference value from a forwardRef.
*
* Acts as the identity function when given a non-forward-ref value.
*
* ### Example ([live demo](http://plnkr.co/edit/GU72mJrk1fiodChcmiDR?p=preview))
*
* {@example core/di/ts/forward_ref/forward_ref_spec.ts region='resolve_forward_ref'}
*
* See: {@link forwardRef}
* @experimental
*/
function resolveForwardRef(type) {
if (typeof type === 'function' && type.hasOwnProperty('__forward_ref__') && type.__forward_ref__ === forwardRef) {
return type();
}
else {
return type;
}
}
/**
* @license
* Copyright Google Inc. All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/
const _THROW_IF_NOT_FOUND = new Object();
const THROW_IF_NOT_FOUND = _THROW_IF_NOT_FOUND;
// tslint:disable-next-line:class-name no-use-before-declare
class _NullInjector {
get(token, notFoundValue = _THROW_IF_NOT_FOUND) {
if (notFoundValue === _THROW_IF_NOT_FOUND) {
throw new Error(`No provider for ${stringify(token)}!`);
}
return notFoundValue;
}
}
/**
* @whatItDoes Injector interface
* @howToUse
* ```
* const injector: Injector = ...;
* injector.get(...);
* ```
*
* @description
* For more details, see the {@linkDocs guide/dependency-injection "Dependency Injection Guide"}.
*
* ### Example
*
* {@example core/di/ts/injector_spec.ts region='Injector'}
*
* `Injector` returns itself when given `Injector` as a token:
* {@example core/di/ts/injector_spec.ts region='injectInjector'}
*
* @stable
*/
class Injector {
}
Injector.THROW_IF_NOT_FOUND = _THROW_IF_NOT_FOUND;
Injector.NULL = new _NullInjector();
/**
* Current injector value used by `inject`.
* - `undefined`: it is an error to call `inject`
* - Injector instance: Use the injector for resolution.
*/
let _currentInjector = undefined;
function setCurrentInjector(injector) {
const former = _currentInjector;
_currentInjector = injector;
return former;
}
function inject(token) {
if (_currentInjector === undefined) {
throw new Error(`inject() must be called from an injection context such as a constructor, a factory function, or a field initializer`);
}
else {
const value = _currentInjector.get(token);
return value;
}
}
/**
* @license
* Copyright Google Inc. All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/
const ERROR_ORIGINAL_ERROR = 'ngOriginalError';
function getOriginalError(error) {
return error[ERROR_ORIGINAL_ERROR];
}
function wrappedError(message, originalError) {
const msg = `${message} caused by: ${originalError instanceof Error ? originalError.message : originalError}`;
const error = Error(msg);
error[ERROR_ORIGINAL_ERROR] = originalError;
return error;
}
/**
* @license
* Copyright Google Inc. All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/
function findFirstClosedCycle(keys) {
const res = [];
for (let i = 0; i < keys.length; ++i) {
if (res.indexOf(keys[i]) > -1) {
res.push(keys[i]);
return res;
}
res.push(keys[i]);
}
return res;
}
function constructResolvingPath(keys) {
if (keys.length > 1) {
const reversed = findFirstClosedCycle(keys.slice().reverse());
const tokenStrs = reversed.map((k) => stringify(k.token));
return ' (' + tokenStrs.join(' -> ') + ')';
}
return '';
}
function injectionError(injector, key, constructResolvingMessage, originalError) {
const error = (originalError ? wrappedError('', originalError) : Error());
error.addKey = addKey;
error.keys = [key];
error.injectors = [injector];
error.constructResolvingMessage = constructResolvingMessage;
error.message = error.constructResolvingMessage();
error[ERROR_ORIGINAL_ERROR] = originalError;
return error;
}
function addKey(injector, key) {
this.injectors.push(injector);
this.keys.push(key);
this.message = this.constructResolvingMessage();
}
/**
* Thrown when trying to retrieve a dependency by key from {@link Injector}, but the
* {@link Injector} does not have a {@link Provider} for the given key.
*
* ### Example ([live demo](http://plnkr.co/edit/vq8D3FRB9aGbnWJqtEPE?p=preview))
*
* ```typescript
* class A {
* constructor(b:B) {}
* }
*
* expect(() => Injector.resolveAndCreate([A])).toThrowError();
* ```
*/
function noProviderError(injector, key) {
return injectionError(injector, key, function () {
const first = stringify(this.keys[0].token);
return `No provider for ${first}!${constructResolvingPath(this.keys)}`;
});
}
/**
* Thrown when dependencies form a cycle.
*
* ### Example ([live demo](http://plnkr.co/edit/wYQdNos0Tzql3ei1EV9j?p=info))
*
* ```typescript
* var injector = Injector.resolveAndCreate([
* {provide: "one", useFactory: (two) => "two", deps: [[new Inject("two")]]},
* {provide: "two", useFactory: (one) => "one", deps: [[new Inject("one")]]}
* ]);
*
* expect(() => injector.get("one")).toThrowError();
* ```
*
* Retrieving `A` or `B` throws a `CyclicDependencyError` as the graph above cannot be constructed.
*/
function cyclicDependencyError(injector, key) {
return injectionError(injector, key, function () {
return `Cannot instantiate cyclic dependency!${constructResolvingPath(this.keys)}`;
});
}
/**
* Thrown when a constructing type returns with an Error.
*
* The `InstantiationError` class contains the original error plus the dependency graph which caused
* this object to be instantiated.
*
* ### Example ([live demo](http://plnkr.co/edit/7aWYdcqTQsP0eNqEdUAf?p=preview))
*
* ```typescript
* class A {
* constructor() {
* throw new Error('message');
* }
* }
*
* var injector = Injector.resolveAndCreate([A]);
* try {
* injector.get(A);
* } catch (e) {
* expect(e instanceof InstantiationError).toBe(true);
* expect(e.originalException.message).toEqual("message");
* expect(e.originalStack).toBeDefined();
* }
* ```
*/
function instantiationError(injector, originalException, originalStack, key) {
return injectionError(injector, key, function () {
const first = stringify(this.keys[0].token);
return `${getOriginalError(this).message}: Error during instantiation of ${first}!${constructResolvingPath(this.keys)}.`;
}, originalException);
}
/**
* Thrown when an object other then {@link Provider} (or `Type`) is passed to {@link Injector}
* creation.
*
* ### Example ([live demo](http://plnkr.co/edit/YatCFbPAMCL0JSSQ4mvH?p=preview))
*
* ```typescript
* expect(() => Injector.resolveAndCreate(["not a type"])).toThrowError();
* ```
*/
function invalidProviderError(provider) {
return Error(`Invalid provider - only instances of Provider and Type are allowed, got: ${provider}`);
}
/**
* Thrown when the class has no annotation information.
*
* Lack of annotation information prevents the {@link Injector} from determining which dependencies
* need to be injected into the constructor.
*
* ### Example ([live demo](http://plnkr.co/edit/rHnZtlNS7vJOPQ6pcVkm?p=preview))
*
* ```typescript
* class A {
* constructor(b) {}
* }
*
* expect(() => Injector.resolveAndCreate([A])).toThrowError();
* ```
*
* This error is also thrown when the class not marked with {@link Injectable} has parameter types.
*
* ```typescript
* class B {}
*
* class A {
* constructor(b:B) {} // no information about the parameter types of A is available at runtime.
* }
*
* expect(() => Injector.resolveAndCreate([A,B])).toThrowError();
* ```
* @stable
*/
function noAnnotationError(typeOrFunc, params) {
const signature = [];
for (let i = 0, ii = params.length; i < ii; i++) {
const parameter = params[i];
if (!parameter || parameter.length === 0) {
signature.push('?');
}
else {
signature.push(parameter.map(stringify).join(' '));
}
}
return Error("Cannot resolve all parameters for '" +
stringify(typeOrFunc) +
"'(" +
signature.join(', ') +
'). ' +
"Make sure that all the parameters are decorated with Inject or have valid type annotations and that '" +
stringify(typeOrFunc) +
"' is decorated with Injectable.");
}
/**
* Thrown when getting an object by index.
*
* ### Example ([live demo](http://plnkr.co/edit/bRs0SX2OTQiJzqvjgl8P?p=preview))
*
* ```typescript
* class A {}
*
* var injector = Injector.resolveAndCreate([A]);
*
* expect(() => injector.getAt(100)).toThrowError();
* ```
* @stable
*/
function outOfBoundsError(index) {
return Error(`Index ${index} is out-of-bounds.`);
}
// TODO: add a working example after alpha38 is released
/**
* Thrown when a multi provider and a regular provider are bound to the same token.
*
* ### Example
*
* ```typescript
* expect(() => Injector.resolveAndCreate([
* { provide: "Strings", useValue: "string1", multi: true},
* { provide: "Strings", useValue: "string2", multi: false}
* ])).toThrowError();
* ```
*/
function mixingMultiProvidersWithRegularProvidersError(provider1, provider2) {
return Error(`Cannot mix multi providers and regular providers, got: ${provider1} ${provider2}`);
}
/**
* @license
* Copyright Google Inc. All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/
/**
* A unique object used for retrieving items from the {@link ReflectiveInjector}.
*
* Keys have:
* - a system-wide unique `id`.
* - a `token`.
*
* `Key` is used internally by {@link ReflectiveInjector} because its system-wide unique `id` allows
* the
* injector to store created objects in a more efficient way.
*
* `Key` should not be created directly. {@link ReflectiveInjector} creates keys automatically when
* resolving
* providers.
* @experimental
*/
class ReflectiveKey {
/**
* Private
*/
constructor(token, id) {
this.token = token;
this.id = id;
if (!token) {
throw new Error('Token must be defined!');
}
}
/**
* Returns a stringified token.
*/
get displayName() {
return stringify(this.token);
}
/**
* Retrieves a `Key` for a token.
*/
static get(token) {
// tslint:disable-next-line:no-use-before-declare
return _globalKeyRegistry.get(resolveForwardRef(token));
}
/**
* @returns the number of keys registered in the system.
*/
static get numberOfKeys() {
// tslint:disable-next-line:no-use-before-declare
return _globalKeyRegistry.numberOfKeys;
}
}
/**
* @internal
*/
class KeyRegistry {
constructor() {
this._allKeys = new Map();
}
get(token) {
if (token instanceof ReflectiveKey)
return token;
if (this._allKeys.has(token)) {
return this._allKeys.get(token);
}
const newKey = new ReflectiveKey(token, ReflectiveKey.numberOfKeys);
this._allKeys.set(token, newKey);
return newKey;
}
get numberOfKeys() {
return this._allKeys.size;
}
}
const _globalKeyRegistry = new KeyRegistry();
/**
* @license
* Copyright Google Inc. All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/
/**
* @whatItDoes Represents a type that a Component or other object is instances of.
*
* @description
*
* An example of a `Type` is `MyCustomComponent` class, which in JavaScript is be represented by
* the `MyCustomComponent` constructor function.
*
* @stable
*/
const Type = Function;
function isType(v) {
return typeof v === 'function';
}
/**
* @license
* Copyright Google Inc. All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/
/**
* Attention: This regex has to hold even if the code is minified!
*/
const DELEGATE_CTOR = /^function\s+\S+\(\)\s*{[\s\S]+\.apply\(this,\s*arguments\)/;
class ReflectionCapabilities {
constructor(reflect) {
this._reflect = reflect || _global['Reflect'];
}
isReflectionEnabled() {
return true;
}
factory(t) {
return (...args) => new t(...args);
}
/** @internal */
_zipTypesAndAnnotations(paramTypes, paramAnnotations) {
let result;
if (typeof paramTypes === 'undefined') {
result = new Array(paramAnnotations.length);
}
else {
result = new Array(paramTypes.length);
}
for (let i = 0; i < result.length; i++) {
// TS outputs Object for parameters without types, while Traceur omits
// the annotations. For now we preserve the Traceur behavior to aid
// migration, but this can be revisited.
if (typeof paramTypes === 'undefined') {
result[i] = [];
// tslint:disable-next-line:triple-equals
}
else if (paramTypes[i] != Object) {
result[i] = [paramTypes[i]];
}
else {
result[i] = [];
}
if (paramAnnotations && paramAnnotations[i] != null) {
result[i] = result[i].concat(paramAnnotations[i]);
}
}
return result;
}
_ownParameters(type, parentCtor) {
// If we have no decorators, we only have function.length as metadata.
// In that case, to detect whether a child class declared an own constructor or not,
// we need to look inside of that constructor to check whether it is
// just calling the parent.
// This also helps to work around for https://github.com/Microsoft/TypeScript/issues/12439
// that sets 'design:paramtypes' to []
// if a class inherits from another class but has no ctor declared itself.
if (DELEGATE_CTOR.exec(type.toString())) {
return null;
}
// Prefer the direct API.
if (type.parameters && type.parameters !== parentCtor.parameters) {
return type.parameters;
}
// API of tsickle for lowering decorators to properties on the class.
const tsickleCtorParams = type.ctorParameters;
if (tsickleCtorParams && tsickleCtorParams !== parentCtor.ctorParameters) {
// Newer tsickle uses a function closure
// Retain the non-function case for compatibility with older tsickle
const ctorParameters = typeof tsickleCtorParams === 'function' ? tsickleCtorParams() : tsickleCtorParams;
const paramTypes = ctorParameters.map((ctorParam) => ctorParam && ctorParam.type);
const paramAnnotations = ctorParameters.map((ctorParam) => ctorParam && convertTsickleDecoratorIntoMetadata(ctorParam.decorators));
return this._zipTypesAndAnnotations(paramTypes, paramAnnotations);
}
// API for metadata created by invoking the decorators.
if (this._reflect != null && this._reflect.getOwnMetadata != null) {
const paramAnnotations = this._reflect.getOwnMetadata('parameters', type);
const paramTypes = this._reflect.getOwnMetadata('design:paramtypes', type);
if (paramTypes || paramAnnotations) {
return this._zipTypesAndAnnotations(paramTypes, paramAnnotations);
}
}
// If a class has no decorators, at least create metadata
// based on function.length.
// Note: We know that this is a real constructor as we checked
// the content of the constructor above.
return new Array(type.length).fill(undefined);
}
parameters(type) {
// Note: only report metadata if we have at least one class decorator
// to stay in sync with the static reflector.
if (!isType(type)) {
return [];
}
const parentCtor = getParentCtor(type);
let parameters = this._ownParameters(type, parentCtor);
if (!parameters && parentCtor !== Object) {
parameters = this.parameters(parentCtor);
}
return parameters || [];
}
_ownAnnotations(typeOrFunc, parentCtor) {
// Prefer the direct API.
if (typeOrFunc.annotations && typeOrFunc.annotations !== parentCtor.annotations) {
let annotations = typeOrFunc.annotations;
if (typeof annotations === 'function' && annotations.annotations) {
annotations = annotations.annotations;
}
return annotations;
}
// API of tsickle for lowering decorators to properties on the class.
if (typeOrFunc.decorators && typeOrFunc.decorators !== parentCtor.decorators) {
return convertTsickleDecoratorIntoMetadata(typeOrFunc.decorators);
}
// API for metadata created by invoking the decorators.
if (this._reflect && this._reflect.getOwnMetadata) {
return this._reflect.getOwnMetadata('annotations', typeOrFunc);
}
return null;
}
annotations(typeOrFunc) {
if (!isType(typeOrFunc)) {
return [];
}
const parentCtor = getParentCtor(typeOrFunc);
const ownAnnotations = this._ownAnnotations(typeOrFunc, parentCtor) || [];
const parentAnnotations = parentCtor !== Object ? this.annotations(parentCtor) : [];
return parentAnnotations.concat(ownAnnotations);
}
_ownPropMetadata(typeOrFunc, parentCtor) {
// Prefer the direct API.
if (typeOrFunc.propMetadata && typeOrFunc.propMetadata !== parentCtor.propMetadata) {
let propMetadata = typeOrFunc.propMetadata;
if (typeof propMetadata === 'function' && propMetadata.propMetadata) {
propMetadata = propMetadata.propMetadata;
}
return propMetadata;
}
// API of tsickle for lowering decorators to properties on the class.
if (typeOrFunc.propDecorators && typeOrFunc.propDecorators !== parentCtor.propDecorators) {
const propDecorators = typeOrFunc.propDecorators;
const propMetadata = {};
Object.keys(propDecorators).forEach((prop) => {
propMetadata[prop] = convertTsickleDecoratorIntoMetadata(propDecorators[prop]);
});
return propMetadata;
}
// API for metadata created by invoking the decorators.
if (this._reflect && this._reflect.getOwnMetadata) {
return this._reflect.getOwnMetadata('propMetadata', typeOrFunc);
}
return null;
}
propMetadata(typeOrFunc) {
if (!isType(typeOrFunc)) {
return {};
}
const parentCtor = getParentCtor(typeOrFunc);
const propMetadata = {};
if (parentCtor !== Object) {
const parentPropMetadata = this.propMetadata(parentCtor);
Object.keys(parentPropMetadata).forEach((propName) => {
propMetadata[propName] = parentPropMetadata[propName];
});
}
const ownPropMetadata = this._ownPropMetadata(typeOrFunc, parentCtor);
if (ownPropMetadata) {
Object.keys(ownPropMetadata).forEach((propName) => {
const decorators = [];
if (propMetadata.hasOwnProperty(propName)) {
decorators.push(...propMetadata[propName]);
}
decorators.push(...ownPropMetadata[propName]);
propMetadata[propName] = decorators;
});
}
return propMetadata;
}
hasLifecycleHook(type, lcProperty) {
return type instanceof Type && lcProperty in type.prototype;
}
getter(name) {
return new Function('o', 'return o.' + name + ';');
}
setter(name) {
return new Function('o', 'v', 'return o.' + name + ' = v;');
}
method(name) {
const functionBody = `if (!o.${name}) throw new Error('"${name}" is undefined');
return o.${name}.apply(o, args);`;
return new Function('o', 'args', functionBody);
}
// There is not a concept of import uri in Js, but this is useful in developing Dart applications.
importUri(type) {
// StaticSymbol
if (typeof type === 'object' && type['filePath']) {
return type['filePath'];
}
// Runtime type
return `./${stringify(type)}`;
}
resourceUri(type) {
return `./${stringify(type)}`;
}
resolveIdentifier(name, moduleUrl, members, runtime) {
return runtime;
}
resolveEnum(enumIdentifier, name) {
return enumIdentifier[name];
}
}
function convertTsickleDecoratorIntoMetadata(decoratorInvocations) {
if (!decoratorInvocations) {
return [];
}
return decoratorInvocations.map((decoratorInvocation) => {
const decoratorType = decoratorInvocation.type;
const annotationCls = decoratorType.annotationCls;
const annotationArgs = decoratorInvocation.args ? decoratorInvocation.args : [];
return new annotationCls(...annotationArgs);
});
}
function getParentCtor(ctor) {
if (!ctor.prototype) {
return Object;
}
const parentProto = Object.getPrototypeOf(ctor.prototype);
const parentCtor = parentProto ? parentProto.constructor : null;
// Note: We always use `Object` as the null value
// to simplify checking later on.
return parentCtor || Object;
}
/**
* @license
* Copyright Google Inc. All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/
/**
* Provides read-only access to reflection data about symbols. Used internally by Angular
* to power dependency injection and compilation.
*/
class ReflectorReader {
}
/**
* @license
* Copyright Google Inc. All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/
/**
* Provides access to reflection data about symbols. Used internally by Angular
* to power dependency injection and compilation.
*/
class Reflector extends ReflectorReader {
constructor(reflectionCapabilities) {
super();
this.reflectionCapabilities = reflectionCapabilities;
}
updateCapabilities(caps) {
this.reflectionCapabilities = caps;
}
factory(type) {
return this.reflectionCapabilities.factory(type);
}
parameters(typeOrFunc) {
return this.reflectionCapabilities.parameters(typeOrFunc);
}
annotations(typeOrFunc) {
return this.reflectionCapabilities.annotations(typeOrFunc);
}
propMetadata(typeOrFunc) {
return this.reflectionCapabilities.propMetadata(typeOrFunc);
}
hasLifecycleHook(type, lcProperty) {
return this.reflectionCapabilities.hasLifecycleHook(type, lcProperty);
}
getter(name) {
return this.reflectionCapabilities.getter(name);
}
setter(name) {
return this.reflectionCapabilities.setter(name);
}
method(name) {
return this.reflectionCapabilities.method(name);
}
importUri(type) {
return this.reflectionCapabilities.importUri(type);
}
resourceUri(type) {
return this.reflectionCapabilities.resourceUri(type);
}
resolveIdentifier(name, moduleUrl, members, runtime) {
return this.reflectionCapabilities.resolveIdentifier(name, moduleUrl, members, runtime);
}
resolveEnum(identifier, name) {
return this.reflectionCapabilities.resolveEnum(identifier, name);
}
}
/**
* @license
* Copyright Google Inc. All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/
/**
* The {@link Reflector} used internally in Angular to access metadata
* about symbols.
*/
const reflector = new Reflector(new ReflectionCapabilities());
/**
* @license
* Copyright Google Inc. All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/
/**
* Creates a token that can be used in a DI Provider.
*
* ### Example ([live demo](http://plnkr.co/edit/Ys9ezXpj2Mnoy3Uc8KBp?p=preview))
*
* ```typescript
* var t = new OpaqueToken("value");
*
* var injector = Injector.resolveAndCreate([
* {provide: t, useValue: "bindingValue"}
* ]);
*
* expect(injector.get(t)).toEqual("bindingValue");
* ```
*
* Using an `OpaqueToken` is preferable to using strings as tokens because of possible collisions
* caused by multiple providers using the same string as two different tokens.
*
* Using an `OpaqueToken` is preferable to using an `Object` as tokens because it provides better
* error messages.
* @deprecated since v4.0.0 because it does not support type information, use `InjectionToken<?>`
* instead.
*/
class OpaqueToken {
constructor(_desc) {
this._desc = _desc;
}
toString() {
return `Token ${this._desc}`;
}
}
/**
* Creates a token that can be used in a DI Provider.
*
* Use an `InjectionToken` whenever the type you are injecting is not reified (does not have a
* runtime representation) such as when injecting an interface, callable type, array or
* parametrized type.
*
* `InjectionToken` is parameterized on `T` which is the type of object which will be returned by
* the `Injector`. This provides additional level of type safety.
*
* ```
* interface MyInterface {...}
* var myInterface = injector.get(new InjectionToken<MyInterface>('SomeToken'));
* // myInterface is inferred to be MyInterface.
* ```
*
* ### Example
*
* {@example core/di/ts/injector_spec.ts region='InjectionToken'}
*
* @stable
*/
class InjectionToken extends OpaqueToken {
constructor(desc) {
super(desc);
}
toString() {
return `InjectionToken ${this._desc}`;
}
}
/**
* @license
* Copyright Google Inc. All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/
/**
* `Dependency` is used by the framework to extend DI.
* This is internal to Angular and should not be used directly.
*/
class ReflectiveDependency {
constructor(key, optional, visibility) {
this.key = key;
this.optional = optional;
this.visibility = visibility;
}
static fromKey(key) {
return new ReflectiveDependency(key, false, null);
}
}
const _EMPTY_LIST = [];
// tslint:disable-next-line:class-name
class ResolvedReflectiveProvider_ {
constructor(key, resolvedFactories, multiProvider) {
this.key = key;
this.resolvedFactories = resolvedFactories;
this.multiProvider = multiProvider;
}
get resolvedFactory() {
return this.resolvedFactories[0];
}
}
/**
* An internal resolved representation of a factory function created by resolving {@link
* Provider}.
* @experimental
*/
class ResolvedReflectiveFactory {
constructor(
/**
* Factory function which can return an instance of an object represented by a key.
*/
factory,
/**
* Arguments (dependencies) to the `factory` function.
*/
dependencies) {
this.factory = factory;
this.dependencies = dependencies;
}
}
/**
* Resolve a single provider.
*/
function resolveReflectiveFactory(provider) {
let factoryFn;
let resolvedDeps;
if (provider.useClass) {
const useClass = resolveForwardRef(provider.useClass);
factoryFn = reflector.factory(useClass);
resolvedDeps = _dependenciesFor(useClass);
}
else if (provider.useExisting) {
factoryFn = (aliasInstance) => aliasInstance;
resolvedDeps = [ReflectiveDependency.fromKey(ReflectiveKey.get(provider.useExisting))];
}
else if (provider.useFactory) {
factoryFn = provider.useFactory;
resolvedDeps = constructDependencies(provider.useFactory, provider.deps);
}
else {
factoryFn = () => provider.useValue;
resolvedDeps = _EMPTY_LIST;
}
return new ResolvedReflectiveFactory(factoryFn, resolvedDeps);
}
/**
* Converts the {@link Provider} into {@link ResolvedProvider}.
*
* {@link Injector} internally only uses {@link ResolvedProvider}, {@link Provider} contains
* convenience provider syntax.
*/
function resolveReflectiveProvider(provider) {
return new ResolvedReflectiveProvider_(ReflectiveKey.get(provider.provide), [resolveReflectiveFactory(provider)], provider.multi || false);
}
/**
* Resolve a list of Providers.
*/
function resolveReflectiveProviders(providers) {
const normalized = _normalizeProviders(providers, []);
const resolved = normalized.map(resolveReflectiveProvider);
const resolvedProviderMap = mergeResolvedReflectiveProviders(resolved, new Map());
return Array.from(resolvedProviderMap.values());
}
/**
* Merges a list of ResolvedProviders into a list where
* each key is contained exactly once and multi providers
* have been merged.
*/
function mergeResolvedReflectiveProviders(providers, normalizedProvidersMap) {
for (let i = 0; i < providers.length; i++) {
const provider = providers[i];
const existing = normalizedProvidersMap.get(provider.key.id);
if (existing) {
if (provider.multiProvider !== existing.multiProvider) {
throw mixingMultiProvidersWithRegularProvidersError(existing, provider);
}
if (provider.multiProvider) {
for (let j = 0; j < provider.resolvedFactories.length; j++) {
existing.resolvedFactories.push(provider.resolvedFactories[j]);
}
}
else {
normalizedProvidersMap.set(provider.key.id, provider);
}
}
else {
let resolvedProvider;
if (provider.multiProvider) {
resolvedProvider = new ResolvedReflectiveProvider_(provider.key, provider.resolvedFactories.slice(), provider.multiProvider);
}
else {
resolvedProvider = provider;
}
normalizedProvidersMap.set(provider.key.id, resolvedProvider);
}
}
return normalizedProvidersMap;
}
function _normalizeProviders(providers, res) {
providers.forEach((b) => {
if (b instanceof Type) {
res.push({ provide: b, useClass: b });
}
else if (b && typeof b === 'object' && b.provide !== undefined) {
res.push(b);
}
else if (b instanceof Array) {
_normalizeProviders(b, res);
}
else {
throw invalidProviderError(b);
}
});
return res;
}
function constructDependencies(typeOrFunc, dependencies) {
if (!dependencies) {
return _dependenciesFor(typeOrFunc);
}
else {
const params = dependencies.map((t) => [t]);
return dependencies.map((t) => _extractToken(typeOrFunc, t, params));
}
}
function _dependenciesFor(typeOrFunc) {
const params = reflector.parameters(typeOrFunc);
if (!params)
return [];
if (params.some((p) => p == null)) {
throw noAnnotationError(typeOrFunc, params);
}
return params.map((p) => _extractToken(typeOrFunc, p, params));
}
function _extractToken(typeOrFunc, metadata, params) {
let token = null;
let optional = false;
if (!Array.isArray(metadata)) {
if (metadata instanceof Inject) {
return _createDependency(metadata['token'], optional, null);
}
else {
return _createDependency(metadata, optional, null);
}
}
let visibility = null;
for (let i = 0; i < metadata.length; ++i) {
const paramMetadata = metadata[i];
if (paramMetadata instanceof Type) {
token = paramMetadata;