angular2
Version:
Angular 2 - a web framework for modern web apps
293 lines (254 loc) • 9.33 kB
text/typescript
import {
Type,
isBlank,
isPresent,
CONST,
CONST_EXPR,
isArray,
isType
} from 'angular2/src/facade/lang';
import {MapWrapper, ListWrapper} from 'angular2/src/facade/collection';
import {reflector} from 'angular2/src/core/reflection/reflection';
import {ReflectiveKey} from './reflective_key';
import {
InjectMetadata,
InjectableMetadata,
OptionalMetadata,
SelfMetadata,
HostMetadata,
SkipSelfMetadata,
DependencyMetadata
} from './metadata';
import {
NoAnnotationError,
MixingMultiProvidersWithRegularProvidersError,
InvalidProviderError
} from './reflective_exceptions';
import {resolveForwardRef} from './forward_ref';
import {Provider, ProviderBuilder, provide} from './provider';
/**
* `Dependency` is used by the framework to extend DI.
* This is internal to Angular and should not be used directly.
*/
export class ReflectiveDependency {
constructor(public key: ReflectiveKey, public optional: boolean, public lowerBoundVisibility: any,
public upperBoundVisibility: any, public properties: any[]) {}
static fromKey(key: ReflectiveKey): ReflectiveDependency {
return new ReflectiveDependency(key, false, null, null, []);
}
}
const _EMPTY_LIST = CONST_EXPR([]);
/**
* An internal resolved representation of a {@link Provider} used by the {@link Injector}.
*
* It is usually created automatically by `Injector.resolveAndCreate`.
*
* It can be created manually, as follows:
*
* ### Example ([live demo](http://plnkr.co/edit/RfEnhh8kUEI0G3qsnIeT?p%3Dpreview&p=preview))
*
* ```typescript
* var resolvedProviders = Injector.resolve([new Provider('message', {useValue: 'Hello'})]);
* var injector = Injector.fromResolvedProviders(resolvedProviders);
*
* expect(injector.get('message')).toEqual('Hello');
* ```
*/
export interface ResolvedReflectiveProvider {
/**
* A key, usually a `Type`.
*/
key: ReflectiveKey;
/**
* Factory function which can return an instance of an object represented by a key.
*/
resolvedFactories: ResolvedReflectiveFactory[];
/**
* Indicates if the provider is a multi-provider or a regular provider.
*/
multiProvider: boolean;
}
/**
* See {@link ResolvedProvider} instead.
*
* @deprecated
*/
export interface ResolvedReflectiveBinding extends ResolvedReflectiveProvider {}
export class ResolvedReflectiveProvider_ implements ResolvedReflectiveBinding {
constructor(public key: ReflectiveKey, public resolvedFactories: ResolvedReflectiveFactory[],
public multiProvider: boolean) {}
get resolvedFactory(): ResolvedReflectiveFactory { return this.resolvedFactories[0]; }
}
/**
* An internal resolved representation of a factory function created by resolving {@link Provider}.
*/
export class ResolvedReflectiveFactory {
constructor(
/**
* Factory function which can return an instance of an object represented by a key.
*/
public factory: Function,
/**
* Arguments (dependencies) to the `factory` function.
*/
public dependencies: ReflectiveDependency[]) {}
}
/**
* Resolve a single provider.
*/
export function resolveReflectiveFactory(provider: Provider): ResolvedReflectiveFactory {
var factoryFn: Function;
var resolvedDeps;
if (isPresent(provider.useClass)) {
var useClass = resolveForwardRef(provider.useClass);
factoryFn = reflector.factory(useClass);
resolvedDeps = _dependenciesFor(useClass);
} else if (isPresent(provider.useExisting)) {
factoryFn = (aliasInstance) => aliasInstance;
resolvedDeps = [ReflectiveDependency.fromKey(ReflectiveKey.get(provider.useExisting))];
} else if (isPresent(provider.useFactory)) {
factoryFn = provider.useFactory;
resolvedDeps = constructDependencies(provider.useFactory, provider.dependencies);
} 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.
*/
export function resolveReflectiveProvider(provider: Provider): ResolvedReflectiveProvider {
return new ResolvedReflectiveProvider_(ReflectiveKey.get(provider.token),
[resolveReflectiveFactory(provider)], provider.multi);
}
/**
* Resolve a list of Providers.
*/
export function resolveReflectiveProviders(
providers: Array<Type | Provider | any[]>): ResolvedReflectiveProvider[] {
var normalized = _normalizeProviders(providers, []);
var resolved = normalized.map(resolveReflectiveProvider);
return MapWrapper.values(
mergeResolvedReflectiveProviders(resolved, new Map<number, ResolvedReflectiveProvider>()));
}
/**
* Merges a list of ResolvedProviders into a list where
* each key is contained exactly once and multi providers
* have been merged.
*/
export function mergeResolvedReflectiveProviders(
providers: ResolvedReflectiveProvider[],
normalizedProvidersMap: Map<number, ResolvedReflectiveProvider>):
Map<number, ResolvedReflectiveProvider> {
for (var i = 0; i < providers.length; i++) {
var provider = providers[i];
var existing = normalizedProvidersMap.get(provider.key.id);
if (isPresent(existing)) {
if (provider.multiProvider !== existing.multiProvider) {
throw new MixingMultiProvidersWithRegularProvidersError(existing, provider);
}
if (provider.multiProvider) {
for (var j = 0; j < provider.resolvedFactories.length; j++) {
existing.resolvedFactories.push(provider.resolvedFactories[j]);
}
} else {
normalizedProvidersMap.set(provider.key.id, provider);
}
} else {
var resolvedProvider;
if (provider.multiProvider) {
resolvedProvider = new ResolvedReflectiveProvider_(
provider.key, ListWrapper.clone(provider.resolvedFactories), provider.multiProvider);
} else {
resolvedProvider = provider;
}
normalizedProvidersMap.set(provider.key.id, resolvedProvider);
}
}
return normalizedProvidersMap;
}
function _normalizeProviders(providers: Array<Type | Provider | ProviderBuilder | any[]>,
res: Provider[]): Provider[] {
providers.forEach(b => {
if (b instanceof Type) {
res.push(provide(b, {useClass: b}));
} else if (b instanceof Provider) {
res.push(b);
} else if (b instanceof Array) {
_normalizeProviders(b, res);
} else if (b instanceof ProviderBuilder) {
throw new InvalidProviderError(b.token);
} else {
throw new InvalidProviderError(b);
}
});
return res;
}
export function constructDependencies(typeOrFunc: any,
dependencies: any[]): ReflectiveDependency[] {
if (isBlank(dependencies)) {
return _dependenciesFor(typeOrFunc);
} else {
var params: any[][] = dependencies.map(t => [t]);
return dependencies.map(t => _extractToken(typeOrFunc, t, params));
}
}
function _dependenciesFor(typeOrFunc: any): ReflectiveDependency[] {
var params = reflector.parameters(typeOrFunc);
if (isBlank(params)) return [];
if (params.some(isBlank)) {
throw new NoAnnotationError(typeOrFunc, params);
}
return params.map((p: any[]) => _extractToken(typeOrFunc, p, params));
}
function _extractToken(typeOrFunc, metadata /*any[] | any*/,
params: any[][]): ReflectiveDependency {
var depProps = [];
var token = null;
var optional = false;
if (!isArray(metadata)) {
if (metadata instanceof InjectMetadata) {
return _createDependency(metadata.token, optional, null, null, depProps);
} else {
return _createDependency(metadata, optional, null, null, depProps);
}
}
var lowerBoundVisibility = null;
var upperBoundVisibility = null;
for (var i = 0; i < metadata.length; ++i) {
var paramMetadata = metadata[i];
if (paramMetadata instanceof Type) {
token = paramMetadata;
} else if (paramMetadata instanceof InjectMetadata) {
token = paramMetadata.token;
} else if (paramMetadata instanceof OptionalMetadata) {
optional = true;
} else if (paramMetadata instanceof SelfMetadata) {
upperBoundVisibility = paramMetadata;
} else if (paramMetadata instanceof HostMetadata) {
upperBoundVisibility = paramMetadata;
} else if (paramMetadata instanceof SkipSelfMetadata) {
lowerBoundVisibility = paramMetadata;
} else if (paramMetadata instanceof DependencyMetadata) {
if (isPresent(paramMetadata.token)) {
token = paramMetadata.token;
}
depProps.push(paramMetadata);
}
}
token = resolveForwardRef(token);
if (isPresent(token)) {
return _createDependency(token, optional, lowerBoundVisibility, upperBoundVisibility, depProps);
} else {
throw new NoAnnotationError(typeOrFunc, params);
}
}
function _createDependency(token, optional, lowerBoundVisibility, upperBoundVisibility,
depProps): ReflectiveDependency {
return new ReflectiveDependency(ReflectiveKey.get(token), optional, lowerBoundVisibility,
upperBoundVisibility, depProps);
}