-
Notifications
You must be signed in to change notification settings - Fork 46
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(reflection): create reflector for resolving all metadata on Type
- move private metadata handling logic to reflector
- Loading branch information
Showing
7 changed files
with
253 additions
and
137 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
import {Reflector} from './reflector'; | ||
|
||
/** | ||
* The {@link Reflector} used internally in Angular to access metadata | ||
* about symbols. | ||
*/ | ||
export var reflector = new Reflector(); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,96 @@ | ||
import {Type,isPresent,isFunction} from "../facade/lang"; | ||
|
||
// This will be needed when we will used Reflect APIs | ||
/*const Reflect = global.Reflect; | ||
if (!(Reflect && Reflect.getMetadata)) { | ||
throw 'reflect-metadata shim is required when using class decorators'; | ||
}*/ | ||
|
||
/** | ||
* @internal | ||
* @private | ||
* @type {string} | ||
*/ | ||
export const CLASS_META_KEY = '__mAnnotations'; | ||
/** | ||
* @internal | ||
* @private | ||
* @type {string} | ||
*/ | ||
export const PARAM_META_KEY = '__mParameters'; | ||
/** | ||
* @internal | ||
* @private | ||
* @type {string} | ||
*/ | ||
export const PROP_META_KEY = '__mPropMetadata'; | ||
|
||
|
||
/** | ||
* Provides access to reflection data about symbols. Used internally by Angular | ||
* to power dependency injection and compilation. | ||
*/ | ||
export class Reflector { | ||
|
||
parameters( typeOrFunc: Type ): any[][] { | ||
//return Reflect.getMetadata('parameters', cls); | ||
return extractParameter( typeOrFunc ); | ||
} | ||
|
||
registerParameters( parameters, type: Type ): void { | ||
//Reflect.defineMetadata('parameters', parameters, cls); | ||
type[ PARAM_META_KEY ] = parameters; | ||
} | ||
|
||
annotations( typeOrFunc: Type ): any[] { | ||
//return Reflect.getOwnMetadata('annotations', cls); | ||
return extractAnnotation( typeOrFunc ); | ||
} | ||
|
||
registerAnnotation( annotations, type: Type ): void { | ||
//Reflect.defineMetadata('annotations', annotations, cls); | ||
type[ CLASS_META_KEY ] = annotations; | ||
} | ||
|
||
propMetadata( typeOrFunc: Type ): {[key: string]: any[]} { | ||
//return Reflect.getOwnMetadata('propMetadata', target.constructor); | ||
return extractProperty( typeOrFunc ); | ||
} | ||
|
||
registerPropMetadata( propMetadata, type: Type ): void { | ||
//Reflect.defineMetadata('propMetadata', meta, target.constructor); | ||
type.constructor[ PROP_META_KEY ] = propMetadata; | ||
} | ||
|
||
} | ||
|
||
|
||
function extract( metaKey: string ) { | ||
|
||
return function ( cls: any ): any { | ||
|
||
if ( isFunction( cls ) && cls.hasOwnProperty( metaKey ) ) { | ||
// it is a decorator, extract annotation | ||
return cls[ metaKey ]; | ||
} | ||
|
||
} | ||
|
||
} | ||
|
||
function extractAnnotation( cls: any ): any[] { | ||
|
||
return extract( CLASS_META_KEY )( cls ); | ||
|
||
} | ||
|
||
function extractParameter( cls: any ): any[][] { | ||
|
||
return extract( PARAM_META_KEY )( cls ); | ||
|
||
} | ||
function extractProperty( cls: any ): {[name:string]:any[]} { | ||
|
||
return extract( PROP_META_KEY )( cls ); | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,74 @@ | ||
import {expect} from 'chai'; | ||
import {makePropDecorator} from '../../src/util/decorators'; | ||
import {Injectable} from "../../src/di/decorators"; | ||
import {Inject} from "../../src/di/decorators"; | ||
import {InjectableMetadata} from "../../src/di/metadata"; | ||
import {Host} from "../../src/di/decorators"; | ||
import {HostMetadata} from "../../src/di/metadata"; | ||
import {assign} from "../../src/facade/lang"; | ||
import {InjectMetadata} from "../../src/di/metadata"; | ||
import {reflector} from "../../src/reflection/reflection"; | ||
|
||
|
||
describe( `reflection/reflector`, ()=> { | ||
|
||
it( `should extract class annotation if present`, ()=> { | ||
|
||
@Injectable() | ||
class Test{} | ||
|
||
const actual = reflector.annotations(Test); | ||
const expected = [InjectableMetadata.prototype]; | ||
|
||
expect(actual).to.deep.equal(expected); | ||
|
||
} ); | ||
it( `should extract class property metadata if present`, ()=> { | ||
|
||
class FooMetadata{ | ||
toString(): string { return `@Foo()`; } | ||
} | ||
const Foo = makePropDecorator(FooMetadata); | ||
|
||
class Test{ | ||
@Foo() jedi: string; | ||
|
||
constructor(){ | ||
this.jedi = 'Obi-wan Kenobi'; | ||
} | ||
} | ||
|
||
|
||
|
||
const actual = reflector.propMetadata(Test); | ||
const expected = { jedi: [ FooMetadata.prototype ] }; | ||
|
||
expect(actual).to.deep.equal(expected); | ||
|
||
} ); | ||
it( `should extract constructor params metadata if present`, ()=> { | ||
|
||
function _createProto( Type, props ) { | ||
const instance = Object.create(Type.prototype); | ||
return assign(instance,props); | ||
} | ||
class Test{ | ||
constructor( | ||
@Inject('$http') private $http: ng.IHttpService, | ||
@Inject('$log') private $log: ng.ILogService, | ||
@Host() @Inject('ngModel') ngModel: ng.INgModelController | ||
){} | ||
} | ||
|
||
const actual = reflector.parameters(Test); | ||
const expected = [ | ||
[_createProto(InjectMetadata,{token:'$http'})], | ||
[_createProto(InjectMetadata,{token:'$log'})], | ||
[_createProto(InjectMetadata,{token:'ngModel'}),_createProto(HostMetadata,null)] | ||
]; | ||
|
||
expect(actual).to.deep.equal(expected); | ||
|
||
} ); | ||
|
||
} ); |
Oops, something went wrong.