injection-js
Version:
Dependency Injection library for JavaScript and TypeScript
244 lines • 11.3 kB
JavaScript
/**
* @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
*/
import { __spreadArrays } from "tslib";
import { global, stringify } from '../facade/lang';
import { Type, isType } from '../facade/type';
/**
* Attention: This regex has to hold even if the code is minified!
*/
export var DELEGATE_CTOR = /^function\s+\S+\(\)\s*{[\s\S]+\.apply\(this,\s*arguments\)/;
var ReflectionCapabilities = /** @class */ (function () {
function ReflectionCapabilities(reflect) {
this._reflect = reflect || global['Reflect'];
}
ReflectionCapabilities.prototype.isReflectionEnabled = function () {
return true;
};
ReflectionCapabilities.prototype.factory = function (t) {
return function () {
var args = [];
for (var _i = 0; _i < arguments.length; _i++) {
args[_i] = arguments[_i];
}
return new (t.bind.apply(t, __spreadArrays([void 0], args)))();
};
};
/** @internal */
ReflectionCapabilities.prototype._zipTypesAndAnnotations = function (paramTypes, paramAnnotations) {
var result;
if (typeof paramTypes === 'undefined') {
result = new Array(paramAnnotations.length);
}
else {
result = new Array(paramTypes.length);
}
for (var 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;
};
ReflectionCapabilities.prototype._ownParameters = function (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.
var tsickleCtorParams = type.ctorParameters;
if (tsickleCtorParams && tsickleCtorParams !== parentCtor.ctorParameters) {
// Newer tsickle uses a function closure
// Retain the non-function case for compatibility with older tsickle
var ctorParameters = typeof tsickleCtorParams === 'function' ? tsickleCtorParams() : tsickleCtorParams;
var paramTypes = ctorParameters.map(function (ctorParam) { return ctorParam && ctorParam.type; });
var paramAnnotations = ctorParameters.map(function (ctorParam) { return 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) {
var paramAnnotations = this._reflect.getOwnMetadata('parameters', type);
var 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);
};
ReflectionCapabilities.prototype.parameters = function (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 [];
}
var parentCtor = getParentCtor(type);
var parameters = this._ownParameters(type, parentCtor);
if (!parameters && parentCtor !== Object) {
parameters = this.parameters(parentCtor);
}
return parameters || [];
};
ReflectionCapabilities.prototype._ownAnnotations = function (typeOrFunc, parentCtor) {
// Prefer the direct API.
if (typeOrFunc.annotations && typeOrFunc.annotations !== parentCtor.annotations) {
var 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;
};
ReflectionCapabilities.prototype.annotations = function (typeOrFunc) {
if (!isType(typeOrFunc)) {
return [];
}
var parentCtor = getParentCtor(typeOrFunc);
var ownAnnotations = this._ownAnnotations(typeOrFunc, parentCtor) || [];
var parentAnnotations = parentCtor !== Object ? this.annotations(parentCtor) : [];
return parentAnnotations.concat(ownAnnotations);
};
ReflectionCapabilities.prototype._ownPropMetadata = function (typeOrFunc, parentCtor) {
// Prefer the direct API.
if (typeOrFunc.propMetadata && typeOrFunc.propMetadata !== parentCtor.propMetadata) {
var 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) {
var propDecorators_1 = typeOrFunc.propDecorators;
var propMetadata_1 = {};
Object.keys(propDecorators_1).forEach(function (prop) {
propMetadata_1[prop] = convertTsickleDecoratorIntoMetadata(propDecorators_1[prop]);
});
return propMetadata_1;
}
// API for metadata created by invoking the decorators.
if (this._reflect && this._reflect.getOwnMetadata) {
return this._reflect.getOwnMetadata('propMetadata', typeOrFunc);
}
return null;
};
ReflectionCapabilities.prototype.propMetadata = function (typeOrFunc) {
if (!isType(typeOrFunc)) {
return {};
}
var parentCtor = getParentCtor(typeOrFunc);
var propMetadata = {};
if (parentCtor !== Object) {
var parentPropMetadata_1 = this.propMetadata(parentCtor);
Object.keys(parentPropMetadata_1).forEach(function (propName) {
propMetadata[propName] = parentPropMetadata_1[propName];
});
}
var ownPropMetadata = this._ownPropMetadata(typeOrFunc, parentCtor);
if (ownPropMetadata) {
Object.keys(ownPropMetadata).forEach(function (propName) {
var decorators = [];
if (propMetadata.hasOwnProperty(propName)) {
decorators.push.apply(decorators, propMetadata[propName]);
}
decorators.push.apply(decorators, ownPropMetadata[propName]);
propMetadata[propName] = decorators;
});
}
return propMetadata;
};
ReflectionCapabilities.prototype.hasLifecycleHook = function (type, lcProperty) {
return type instanceof Type && lcProperty in type.prototype;
};
ReflectionCapabilities.prototype.getter = function (name) {
return new Function('o', 'return o.' + name + ';');
};
ReflectionCapabilities.prototype.setter = function (name) {
return new Function('o', 'v', 'return o.' + name + ' = v;');
};
ReflectionCapabilities.prototype.method = function (name) {
var functionBody = "if (!o." + name + ") throw new Error('\"" + name + "\" is undefined');\n 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.
ReflectionCapabilities.prototype.importUri = function (type) {
// StaticSymbol
if (typeof type === 'object' && type['filePath']) {
return type['filePath'];
}
// Runtime type
return "./" + stringify(type);
};
ReflectionCapabilities.prototype.resourceUri = function (type) {
return "./" + stringify(type);
};
ReflectionCapabilities.prototype.resolveIdentifier = function (name, moduleUrl, members, runtime) {
return runtime;
};
ReflectionCapabilities.prototype.resolveEnum = function (enumIdentifier, name) {
return enumIdentifier[name];
};
return ReflectionCapabilities;
}());
export { ReflectionCapabilities };
function convertTsickleDecoratorIntoMetadata(decoratorInvocations) {
if (!decoratorInvocations) {
return [];
}
return decoratorInvocations.map(function (decoratorInvocation) {
var decoratorType = decoratorInvocation.type;
var annotationCls = decoratorType.annotationCls;
var annotationArgs = decoratorInvocation.args ? decoratorInvocation.args : [];
return new (annotationCls.bind.apply(annotationCls, __spreadArrays([void 0], annotationArgs)))();
});
}
function getParentCtor(ctor) {
if (!ctor.prototype) {
return Object;
}
var parentProto = Object.getPrototypeOf(ctor.prototype);
var parentCtor = parentProto ? parentProto.constructor : null;
// Note: We always use `Object` as the null value
// to simplify checking later on.
return parentCtor || Object;
}
//# sourceMappingURL=reflection_capabilities.js.map