angular2
Version:
Angular 2 - a web framework for modern web apps
218 lines (217 loc) • 8.37 kB
JavaScript
import { Type, isBlank, isPresent, CONST_EXPR, isArray } 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, 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(key, optional, lowerBoundVisibility, upperBoundVisibility, properties) {
this.key = key;
this.optional = optional;
this.lowerBoundVisibility = lowerBoundVisibility;
this.upperBoundVisibility = upperBoundVisibility;
this.properties = properties;
}
static fromKey(key) {
return new ReflectiveDependency(key, false, null, null, []);
}
}
const _EMPTY_LIST = CONST_EXPR([]);
export class ResolvedReflectiveProvider_ {
constructor(key, resolvedFactories, multiProvider) {
this.key = key;
this.resolvedFactories = resolvedFactories;
this.multiProvider = multiProvider;
}
get resolvedFactory() { 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.
*/
factory,
/**
* Arguments (dependencies) to the `factory` function.
*/
dependencies) {
this.factory = factory;
this.dependencies = dependencies;
}
}
/**
* Resolve a single provider.
*/
export function resolveReflectiveFactory(provider) {
var factoryFn;
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) {
return new ResolvedReflectiveProvider_(ReflectiveKey.get(provider.token), [resolveReflectiveFactory(provider)], provider.multi);
}
/**
* Resolve a list of Providers.
*/
export function resolveReflectiveProviders(providers) {
var normalized = _normalizeProviders(providers, []);
var resolved = normalized.map(resolveReflectiveProvider);
return MapWrapper.values(mergeResolvedReflectiveProviders(resolved, new Map()));
}
/**
* 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, normalizedProvidersMap) {
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, res) {
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, dependencies) {
if (isBlank(dependencies)) {
return _dependenciesFor(typeOrFunc);
}
else {
var params = dependencies.map(t => [t]);
return dependencies.map(t => _extractToken(typeOrFunc, t, params));
}
}
function _dependenciesFor(typeOrFunc) {
var params = reflector.parameters(typeOrFunc);
if (isBlank(params))
return [];
if (params.some(isBlank)) {
throw new NoAnnotationError(typeOrFunc, params);
}
return params.map((p) => _extractToken(typeOrFunc, p, params));
}
function _extractToken(typeOrFunc, metadata /*any[] | any*/, params) {
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) {
return new ReflectiveDependency(ReflectiveKey.get(token), optional, lowerBoundVisibility, upperBoundVisibility, depProps);
}