-
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(di/provider): create provide function for instances registration…
… to ng container - provider returns string of proper name to register - provider register $inject property on Class if there are any service @Inject-ions
- Loading branch information
Showing
5 changed files
with
372 additions
and
2 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,80 @@ | ||
import {Type,stringify} from '../facade/lang'; | ||
import {isFunction} from "../facade/lang"; | ||
import {reflector} from "../reflection/reflection"; | ||
import {isString} from "../facade/lang"; | ||
import {isArray} from "../facade/lang"; | ||
import {isType} from "../facade/lang"; | ||
import {getTypeName} from "../facade/lang"; | ||
import {PipeMetadata} from "../directives/metadata_directives"; | ||
import {DirectiveMetadata} from "../directives/metadata_directives"; | ||
import {InjectableMetadata} from "./metadata"; | ||
import {resolveDirectiveNameFromSelector} from "../facade/lang"; | ||
import {InjectMetadata} from "./metadata"; | ||
|
||
/** | ||
* should extract the string token from provided Type and add $inject angular 1 annotation to constructor if @Inject | ||
* was used | ||
* @param type | ||
* @returns {string} | ||
*/ | ||
export function provide( type: Type | string, {useClass}:{useClass?:Type} = {} ): string { | ||
|
||
// create $inject annotation if needed | ||
const parameters = isString( type ) | ||
? reflector.parameters( useClass ) | ||
: reflector.parameters( type ); | ||
const injectTo = isString( type ) | ||
? useClass | ||
: type; | ||
|
||
const $inject = _getInjectStringTokens( parameters ); | ||
|
||
if ( isArray( $inject ) ) { | ||
|
||
(injectTo).$inject = $inject; | ||
|
||
} | ||
|
||
return provideResolver( type ); | ||
|
||
} | ||
|
||
export function _getInjectStringTokens( parameters: any[][] = [] ): string[] { | ||
|
||
return parameters | ||
.filter( ( paramMeta )=>paramMeta.length === 1 && paramMeta[ 0 ] instanceof InjectMetadata ) | ||
.map( ( [injectMeta] )=>provideResolver( injectMeta.token ) ); | ||
|
||
} | ||
|
||
export function provideResolver( type: Type | string ): string { | ||
|
||
if ( isString( type ) ) { | ||
return type; | ||
} | ||
if ( isType( type ) ) { | ||
|
||
// only the first class annotations is injectable | ||
const [annotation=null] = reflector.annotations( type as Type ) || []; | ||
|
||
if ( !annotation ) { | ||
|
||
return getTypeName( type ); | ||
|
||
} | ||
|
||
if ( annotation instanceof PipeMetadata ) { | ||
return annotation.name; | ||
} | ||
|
||
if ( annotation instanceof DirectiveMetadata ) { | ||
return resolveDirectiveNameFromSelector( annotation.selector ); | ||
} | ||
|
||
if ( annotation instanceof InjectableMetadata ) { | ||
return getTypeName( type ); | ||
} | ||
|
||
} | ||
|
||
} |
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,229 @@ | ||
import {expect} from 'chai'; | ||
import {provide,provideResolver, _getInjectStringTokens} from "../../src/di/provider"; | ||
import {Inject,Injectable} from "../../src/di/decorators"; | ||
import {InjectMetadata,OptionalMetadata,HostMetadata} from "../../src/di/metadata"; | ||
import {Component,Directive,Pipe} from "../../src/directives/decorators"; | ||
|
||
describe( `di/provider`, ()=> { | ||
|
||
describe( `public #provide`, ()=> { | ||
|
||
it( `should return string name for Angular registry and add $inject prop if needed (string)`, ()=> { | ||
|
||
class Foo{ | ||
constructor(@Inject('$http') private $http){ | ||
|
||
} | ||
} | ||
const actual = provide('fooToken',{useClass:Foo}); | ||
const expected = 'fooToken'; | ||
|
||
expect(actual).to.equal(expected); | ||
expect(Foo.$inject).to.deep.equal(['$http']); | ||
|
||
} ); | ||
it( `should return string name for Angular registry and add $inject prop if needed (Class)`, ()=> { | ||
|
||
class MyService{} | ||
|
||
class Foo{ | ||
constructor(@Inject(MyService) private mySvc){} | ||
} | ||
const actual = provide(Foo); | ||
const expected = 'foo'; | ||
|
||
expect(actual).to.equal(expected); | ||
expect(Foo.$inject).to.deep.equal(['myService']); | ||
|
||
} ); | ||
it( `should return string name for Angular registry and add $inject prop if needed (Pipe)`, ()=> { | ||
|
||
class MyService{} | ||
|
||
@Pipe({ | ||
name: 'fooYo' | ||
}) | ||
class FooPipe{ | ||
constructor(@Inject(MyService) private mySvc){} | ||
} | ||
const actual = provide(FooPipe); | ||
const expected = 'fooYo'; | ||
|
||
expect(actual).to.equal(expected); | ||
expect(FooPipe.$inject).to.deep.equal(['myService']); | ||
|
||
} ); | ||
it( `should return string name for Angular registry and add $inject prop if needed (Directive)`, ()=> { | ||
|
||
class MyService{} | ||
|
||
@Directive({ | ||
selector: '[my-foo]' | ||
}) | ||
class FooDirective{ | ||
constructor(@Inject(MyService) private mySvc){} | ||
} | ||
const actual = provide(FooDirective); | ||
const expected = 'myFoo'; | ||
|
||
expect(actual).to.equal(expected); | ||
expect(FooDirective.$inject).to.deep.equal(['myService']); | ||
|
||
} ); | ||
it( `should return string name for Angular registry and add $inject prop if needed (Component)`, ()=> { | ||
|
||
class MyService{} | ||
|
||
@Component({ | ||
selector: 'my-foo', | ||
template:`hello` | ||
}) | ||
class FooComponent{ | ||
constructor(@Inject(MyService) private mySvc,@Inject('$element') private $element){} | ||
} | ||
const actual = provide(FooComponent); | ||
const expected = 'myFoo'; | ||
|
||
expect(actual).to.equal(expected); | ||
expect(FooComponent.$inject).to.deep.equal(['myService','$element']); | ||
|
||
} ); | ||
|
||
// @TODO | ||
it.skip( `should work as factory with angular.module.*.apply and output array [injectName,typeFunction]`, ()=> { | ||
|
||
/*class MyService{} | ||
class Foo{ | ||
constructor(@Inject(MyService) private mySvc){} | ||
} | ||
let actual = provide(Foo); | ||
let expected = [ 'foo', Foo ]; | ||
expect(actual).to.deep.equal(expected); | ||
expect(Foo.$inject).to.deep.equal(['myService']); | ||
@Directive( { | ||
selector: '[my-attr]' | ||
} ) | ||
class FooDirective{} | ||
let directiveProvider = provide(FooDirective) as [string,Function]; | ||
actual = [ directiveProvider[ 0 ], directiveProvider[ 1 ]() ]; | ||
expected = [ 'myAttr', { | ||
controller: FooDirective, | ||
link: function _postLink(){} | ||
} ]; | ||
expect(actual).to.deep.equal(expected); | ||
expect(FooDirective.$inject).to.deep.equal(['myService']);*/ | ||
|
||
} ); | ||
|
||
} ); | ||
|
||
describe( `#_getInjectStringTokens`, ()=> { | ||
|
||
it( `should create proper $inject string array`, ()=> { | ||
|
||
class MyService{} | ||
|
||
@Injectable() | ||
class AnotherService { | ||
} | ||
|
||
const parameters = [ | ||
[new InjectMetadata('foo')], | ||
[new InjectMetadata(MyService)], | ||
[new InjectMetadata('boo')], | ||
[new InjectMetadata(AnotherService)], | ||
[new InjectMetadata('nope'),new OptionalMetadata(), new HostMetadata()] | ||
]; | ||
|
||
const actual = _getInjectStringTokens(parameters); | ||
const expected = ['foo','myService','boo','anotherService']; | ||
|
||
expect( actual ).to.deep.equal( expected ); | ||
|
||
} ); | ||
|
||
} ); | ||
|
||
describe( `#provideResolver`, ()=> { | ||
|
||
it( `should get DI container string name if string`, ()=> { | ||
|
||
const actual = provideResolver( '$http' ); | ||
const expected = '$http'; | ||
|
||
expect( actual ).to.equal( expected ); | ||
|
||
} ); | ||
|
||
it( `should get DI container string name if service Class`, ()=> { | ||
|
||
class MyService{} | ||
|
||
const actual = provideResolver( MyService ); | ||
const expected = 'myService'; | ||
|
||
expect( actual ).to.equal( expected ); | ||
|
||
} ); | ||
it( `should get DI container string name if Injectable Class`, ()=> { | ||
|
||
@Injectable() | ||
class MyService{} | ||
|
||
const actual = provideResolver( MyService ); | ||
const expected = 'myService'; | ||
|
||
expect( actual ).to.equal( expected ); | ||
|
||
} ); | ||
it( `should get DI container string name if Directive Class`, ()=> { | ||
|
||
@Directive({ | ||
selector:'[my-attr]' | ||
}) | ||
class MyDirective{} | ||
|
||
const actual = provideResolver( MyDirective ); | ||
const expected = 'myAttr'; | ||
|
||
expect( actual ).to.equal( expected ); | ||
|
||
|
||
} ); | ||
it( `should get DI container string name if Component Class`, ()=> { | ||
|
||
@Component({ | ||
selector:'my-cmp' | ||
}) | ||
class MyComponent{} | ||
|
||
const actual = provideResolver( MyComponent ); | ||
const expected = 'myCmp'; | ||
|
||
expect( actual ).to.equal( expected ); | ||
|
||
} ); | ||
it( `should get DI container string name if Pipe Class`, ()=> { | ||
|
||
@Pipe({ | ||
name:'myPipeYo' | ||
}) | ||
class MyPipe{} | ||
|
||
const actual = provideResolver( MyPipe ); | ||
const expected = 'myPipeYo'; | ||
|
||
expect( actual ).to.equal( expected ); | ||
|
||
} ); | ||
|
||
|
||
} ); | ||
|
||
} ); |