refactor(core): simplify Reflector code, add types (#12099)

This commit is contained in:
Victor Berchet 2016-10-06 15:11:16 -07:00 committed by Tobias Bosch
parent c9b765f5c0
commit 0254ce1f6c
3 changed files with 61 additions and 87 deletions

View File

@ -16,4 +16,4 @@ export {ReflectionInfo, Reflector} from './reflector';
* The {@link Reflector} used internally in Angular to access metadata * The {@link Reflector} used internally in Angular to access metadata
* about symbols. * about symbols.
*/ */
export var reflector = new Reflector(new ReflectionCapabilities()); export const reflector = new Reflector(new ReflectionCapabilities());

View File

@ -19,19 +19,11 @@ export class ReflectionCapabilities implements PlatformReflectionCapabilities {
isReflectionEnabled(): boolean { return true; } isReflectionEnabled(): boolean { return true; }
factory(t: Type<any>): Function { factory<T>(t: Type<T>): (args: any[]) => T { return (...args: any[]) => new t(...args); }
var prototype = t.prototype;
return function(...args: any[]) {
var instance = Object.create(prototype);
t.apply(instance, args);
return instance;
};
}
/** @internal */ /** @internal */
_zipTypesAndAnnotations( _zipTypesAndAnnotations(paramTypes: any[], paramAnnotations: any[]): any[][] {
paramTypes: any /** TODO #9100 */, paramAnnotations: any /** TODO #9100 */): any[][] { var result: any[][];
var result: any /** TODO #9100 */;
if (typeof paramTypes === 'undefined') { if (typeof paramTypes === 'undefined') {
result = new Array(paramAnnotations.length); result = new Array(paramAnnotations.length);
@ -50,48 +42,45 @@ export class ReflectionCapabilities implements PlatformReflectionCapabilities {
} else { } else {
result[i] = []; result[i] = [];
} }
if (isPresent(paramAnnotations) && isPresent(paramAnnotations[i])) { if (paramAnnotations && isPresent(paramAnnotations[i])) {
result[i] = result[i].concat(paramAnnotations[i]); result[i] = result[i].concat(paramAnnotations[i]);
} }
} }
return result; return result;
} }
parameters(typeOrFunc: Type<any>): any[][] { parameters(type: Type<any>): any[][] {
// Prefer the direct API. // Prefer the direct API.
if (isPresent((<any>typeOrFunc).parameters)) { if ((<any>type).parameters) {
return (<any>typeOrFunc).parameters; return (<any>type).parameters;
} }
// API of tsickle for lowering decorators to properties on the class. // API of tsickle for lowering decorators to properties on the class.
if (isPresent((<any>typeOrFunc).ctorParameters)) { if ((<any>type).ctorParameters) {
let ctorParameters = (<any>typeOrFunc).ctorParameters; const ctorParameters = (<any>type).ctorParameters;
let paramTypes = const paramTypes = ctorParameters.map((ctorParam: any) => ctorParam && ctorParam.type);
ctorParameters.map((ctorParam: any /** TODO #9100 */) => ctorParam && ctorParam.type); const paramAnnotations = ctorParameters.map(
let paramAnnotations = ctorParameters.map( (ctorParam: any) =>
(ctorParam: any /** TODO #9100 */) =>
ctorParam && convertTsickleDecoratorIntoMetadata(ctorParam.decorators)); ctorParam && convertTsickleDecoratorIntoMetadata(ctorParam.decorators));
return this._zipTypesAndAnnotations(paramTypes, paramAnnotations); return this._zipTypesAndAnnotations(paramTypes, paramAnnotations);
} }
// API for metadata created by invoking the decorators. // API for metadata created by invoking the decorators.
if (isPresent(this._reflect) && isPresent(this._reflect.getMetadata)) { if (isPresent(this._reflect) && isPresent(this._reflect.getMetadata)) {
var paramAnnotations = this._reflect.getMetadata('parameters', typeOrFunc); const paramAnnotations = this._reflect.getMetadata('parameters', type);
var paramTypes = this._reflect.getMetadata('design:paramtypes', typeOrFunc); const paramTypes = this._reflect.getMetadata('design:paramtypes', type);
if (isPresent(paramTypes) || isPresent(paramAnnotations)) { if (paramTypes || paramAnnotations) {
return this._zipTypesAndAnnotations(paramTypes, paramAnnotations); return this._zipTypesAndAnnotations(paramTypes, paramAnnotations);
} }
} }
// The array has to be filled with `undefined` because holes would be skipped by `some` // The array has to be filled with `undefined` because holes would be skipped by `some`
let parameters = new Array((<any>typeOrFunc.length)); return new Array((<any>type.length)).fill(undefined);
parameters.fill(undefined);
return parameters;
} }
annotations(typeOrFunc: Type<any>): any[] { annotations(typeOrFunc: Type<any>): any[] {
// Prefer the direct API. // Prefer the direct API.
if (isPresent((<any>typeOrFunc).annotations)) { if ((<any>typeOrFunc).annotations) {
var annotations = (<any>typeOrFunc).annotations; let annotations = (<any>typeOrFunc).annotations;
if (isFunction(annotations) && annotations.annotations) { if (isFunction(annotations) && annotations.annotations) {
annotations = annotations.annotations; annotations = annotations.annotations;
} }
@ -99,22 +88,22 @@ export class ReflectionCapabilities implements PlatformReflectionCapabilities {
} }
// API of tsickle for lowering decorators to properties on the class. // API of tsickle for lowering decorators to properties on the class.
if (isPresent((<any>typeOrFunc).decorators)) { if ((<any>typeOrFunc).decorators) {
return convertTsickleDecoratorIntoMetadata((<any>typeOrFunc).decorators); return convertTsickleDecoratorIntoMetadata((<any>typeOrFunc).decorators);
} }
// API for metadata created by invoking the decorators. // API for metadata created by invoking the decorators.
if (isPresent(this._reflect) && isPresent(this._reflect.getMetadata)) { if (this._reflect && this._reflect.getMetadata) {
var annotations = this._reflect.getMetadata('annotations', typeOrFunc); const annotations = this._reflect.getMetadata('annotations', typeOrFunc);
if (isPresent(annotations)) return annotations; if (annotations) return annotations;
} }
return []; return [];
} }
propMetadata(typeOrFunc: any): {[key: string]: any[]} { propMetadata(typeOrFunc: any): {[key: string]: any[]} {
// Prefer the direct API. // Prefer the direct API.
if (isPresent((<any>typeOrFunc).propMetadata)) { if ((<any>typeOrFunc).propMetadata) {
var propMetadata = (<any>typeOrFunc).propMetadata; let propMetadata = (<any>typeOrFunc).propMetadata;
if (isFunction(propMetadata) && propMetadata.propMetadata) { if (isFunction(propMetadata) && propMetadata.propMetadata) {
propMetadata = propMetadata.propMetadata; propMetadata = propMetadata.propMetadata;
} }
@ -122,9 +111,9 @@ export class ReflectionCapabilities implements PlatformReflectionCapabilities {
} }
// API of tsickle for lowering decorators to properties on the class. // API of tsickle for lowering decorators to properties on the class.
if (isPresent((<any>typeOrFunc).propDecorators)) { if ((<any>typeOrFunc).propDecorators) {
let propDecorators = (<any>typeOrFunc).propDecorators; const propDecorators = (<any>typeOrFunc).propDecorators;
let propMetadata = <{[key: string]: any[]}>{}; const propMetadata = <{[key: string]: any[]}>{};
Object.keys(propDecorators).forEach(prop => { Object.keys(propDecorators).forEach(prop => {
propMetadata[prop] = convertTsickleDecoratorIntoMetadata(propDecorators[prop]); propMetadata[prop] = convertTsickleDecoratorIntoMetadata(propDecorators[prop]);
}); });
@ -132,9 +121,9 @@ export class ReflectionCapabilities implements PlatformReflectionCapabilities {
} }
// API for metadata created by invoking the decorators. // API for metadata created by invoking the decorators.
if (isPresent(this._reflect) && isPresent(this._reflect.getMetadata)) { if (this._reflect && this._reflect.getMetadata) {
var propMetadata = this._reflect.getMetadata('propMetadata', typeOrFunc); const propMetadata = this._reflect.getMetadata('propMetadata', typeOrFunc);
if (isPresent(propMetadata)) return propMetadata; if (propMetadata) return propMetadata;
} }
return {}; return {};
} }
@ -147,7 +136,7 @@ export class ReflectionCapabilities implements PlatformReflectionCapabilities {
hasLifecycleHook(type: any, lcInterface: Type<any>, lcProperty: string): boolean { hasLifecycleHook(type: any, lcInterface: Type<any>, lcProperty: string): boolean {
if (!(type instanceof Type)) return false; if (!(type instanceof Type)) return false;
var proto = (<any>type).prototype; const proto = (<any>type).prototype;
return !!proto[lcProperty]; return !!proto[lcProperty];
} }
@ -158,7 +147,7 @@ export class ReflectionCapabilities implements PlatformReflectionCapabilities {
} }
method(name: string): MethodFn { method(name: string): MethodFn {
let functionBody = `if (!o.${name}) throw new Error('"${name}" is undefined'); const functionBody = `if (!o.${name}) throw new Error('"${name}" is undefined');
return o.${name}.apply(o, args);`; return o.${name}.apply(o, args);`;
return <MethodFn>new Function('o', 'args', functionBody); return <MethodFn>new Function('o', 'args', functionBody);
} }

View File

@ -7,7 +7,6 @@
*/ */
import {MapWrapper} from '../facade/collection'; import {MapWrapper} from '../facade/collection';
import {isPresent} from '../facade/lang';
import {Type} from '../type'; import {Type} from '../type';
import {PlatformReflectionCapabilities} from './platform_reflection_capabilities'; import {PlatformReflectionCapabilities} from './platform_reflection_capabilities';
import {ReflectorReader} from './reflector_reader'; import {ReflectorReader} from './reflector_reader';
@ -60,10 +59,10 @@ export class Reflector extends ReflectorReader {
* potential dead code. * potential dead code.
*/ */
listUnusedKeys(): any[] { listUnusedKeys(): any[] {
if (this._usedKeys == null) { if (!this._usedKeys) {
throw new Error('Usage tracking is disabled'); throw new Error('Usage tracking is disabled');
} }
var allTypes = MapWrapper.keys(this._injectableInfo); const allTypes = MapWrapper.keys(this._injectableInfo);
return allTypes.filter(key => !this._usedKeys.has(key)); return allTypes.filter(key => !this._usedKeys.has(key));
} }
@ -83,87 +82,73 @@ export class Reflector extends ReflectorReader {
factory(type: Type<any>): Function { factory(type: Type<any>): Function {
if (this._containsReflectionInfo(type)) { if (this._containsReflectionInfo(type)) {
var res = this._getReflectionInfo(type).factory; return this._getReflectionInfo(type).factory || null;
return isPresent(res) ? res : null;
} else {
return this.reflectionCapabilities.factory(type);
} }
return this.reflectionCapabilities.factory(type);
} }
parameters(typeOrFunc: Type<any>): any[][] { parameters(typeOrFunc: Type<any>): any[][] {
if (this._injectableInfo.has(typeOrFunc)) { if (this._injectableInfo.has(typeOrFunc)) {
var res = this._getReflectionInfo(typeOrFunc).parameters; return this._getReflectionInfo(typeOrFunc).parameters || [];
return isPresent(res) ? res : [];
} else {
return this.reflectionCapabilities.parameters(typeOrFunc);
} }
return this.reflectionCapabilities.parameters(typeOrFunc);
} }
annotations(typeOrFunc: Type<any>): any[] { annotations(typeOrFunc: Type<any>): any[] {
if (this._injectableInfo.has(typeOrFunc)) { if (this._injectableInfo.has(typeOrFunc)) {
var res = this._getReflectionInfo(typeOrFunc).annotations; return this._getReflectionInfo(typeOrFunc).annotations || [];
return isPresent(res) ? res : [];
} else {
return this.reflectionCapabilities.annotations(typeOrFunc);
} }
return this.reflectionCapabilities.annotations(typeOrFunc);
} }
propMetadata(typeOrFunc: Type<any>): {[key: string]: any[]} { propMetadata(typeOrFunc: Type<any>): {[key: string]: any[]} {
if (this._injectableInfo.has(typeOrFunc)) { if (this._injectableInfo.has(typeOrFunc)) {
var res = this._getReflectionInfo(typeOrFunc).propMetadata; return this._getReflectionInfo(typeOrFunc).propMetadata || {};
return isPresent(res) ? res : {};
} else {
return this.reflectionCapabilities.propMetadata(typeOrFunc);
} }
return this.reflectionCapabilities.propMetadata(typeOrFunc);
} }
interfaces(type: Type<any>): any[] { interfaces(type: Type<any>): any[] {
if (this._injectableInfo.has(type)) { if (this._injectableInfo.has(type)) {
var res = this._getReflectionInfo(type).interfaces; return this._getReflectionInfo(type).interfaces || [];
return isPresent(res) ? res : [];
} else {
return this.reflectionCapabilities.interfaces(type);
} }
return this.reflectionCapabilities.interfaces(type);
} }
hasLifecycleHook(type: any, lcInterface: Type<any>, lcProperty: string): boolean { hasLifecycleHook(type: any, lcInterface: Type<any>, lcProperty: string): boolean {
var interfaces = this.interfaces(type); if (this.interfaces(type).indexOf(lcInterface) !== -1) {
if (interfaces.indexOf(lcInterface) !== -1) {
return true; return true;
} else {
return this.reflectionCapabilities.hasLifecycleHook(type, lcInterface, lcProperty);
} }
return this.reflectionCapabilities.hasLifecycleHook(type, lcInterface, lcProperty);
} }
getter(name: string): GetterFn { getter(name: string): GetterFn {
if (this._getters.has(name)) { return this._getters.has(name) ? this._getters.get(name) :
return this._getters.get(name); this.reflectionCapabilities.getter(name);
} else {
return this.reflectionCapabilities.getter(name);
}
} }
setter(name: string): SetterFn { setter(name: string): SetterFn {
if (this._setters.has(name)) { return this._setters.has(name) ? this._setters.get(name) :
return this._setters.get(name); this.reflectionCapabilities.setter(name);
} else {
return this.reflectionCapabilities.setter(name);
}
} }
method(name: string): MethodFn { method(name: string): MethodFn {
if (this._methods.has(name)) { return this._methods.has(name) ? this._methods.get(name) :
return this._methods.get(name); this.reflectionCapabilities.method(name);
} else {
return this.reflectionCapabilities.method(name);
}
} }
/** @internal */ /** @internal */
_getReflectionInfo(typeOrFunc: any): ReflectionInfo { _getReflectionInfo(typeOrFunc: any): ReflectionInfo {
if (isPresent(this._usedKeys)) { if (this._usedKeys) {
this._usedKeys.add(typeOrFunc); this._usedKeys.add(typeOrFunc);
} }
return this._injectableInfo.get(typeOrFunc); return this._injectableInfo.get(typeOrFunc);
} }