chore(packaging): move files to match target file structure
This commit is contained in:
92
modules/angular2/src/di/annotations.js
vendored
Normal file
92
modules/angular2/src/di/annotations.js
vendored
Normal file
@ -0,0 +1,92 @@
|
||||
import {CONST} from "facade/src/lang";
|
||||
|
||||
/**
|
||||
* A parameter annotation that creates a synchronous eager dependency.
|
||||
*
|
||||
* ```
|
||||
* class AComponent {
|
||||
* constructor(@Inject('aServiceToken') aService) {}
|
||||
* }
|
||||
* ```
|
||||
*
|
||||
*/
|
||||
export class Inject {
|
||||
token;
|
||||
@CONST()
|
||||
constructor(token) {
|
||||
this.token = token;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A parameter annotation that creates an asynchronous eager dependency.
|
||||
*
|
||||
* ```
|
||||
* class AComponent {
|
||||
* constructor(@InjectPromise('aServiceToken') aServicePromise) {
|
||||
* aServicePromise.then(aService => ...);
|
||||
* }
|
||||
* }
|
||||
* ```
|
||||
*
|
||||
*/
|
||||
export class InjectPromise {
|
||||
token;
|
||||
@CONST()
|
||||
constructor(token) {
|
||||
this.token = token;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A parameter annotation that creates a synchronous lazy dependency.
|
||||
*
|
||||
* ```
|
||||
* class AComponent {
|
||||
* constructor(@InjectLazy('aServiceToken') aServiceFn) {
|
||||
* aService = aServiceFn();
|
||||
* }
|
||||
* }
|
||||
* ```
|
||||
*
|
||||
*/
|
||||
export class InjectLazy {
|
||||
token;
|
||||
@CONST()
|
||||
constructor(token) {
|
||||
this.token = token;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* `DependencyAnnotation` is used by the framework to extend DI.
|
||||
*
|
||||
* Only annotations implementing `DependencyAnnotation` will be added
|
||||
* to the list of dependency properties.
|
||||
*
|
||||
* For example:
|
||||
*
|
||||
* ```
|
||||
* class Parent extends DependencyAnnotation {}
|
||||
* class NotDependencyProperty {}
|
||||
*
|
||||
* class AComponent {
|
||||
* constructor(@Parent @NotDependencyProperty aService:AService) {}
|
||||
* }
|
||||
* ```
|
||||
*
|
||||
* will create the following dependency:
|
||||
*
|
||||
* ```
|
||||
* new Dependency(Key.get(AService), [new Parent()])
|
||||
* ```
|
||||
*
|
||||
* The framework can use `new Parent()` to handle the `aService` dependency
|
||||
* in a specific way.
|
||||
*
|
||||
*/
|
||||
export class DependencyAnnotation {
|
||||
@CONST()
|
||||
constructor() {
|
||||
}
|
||||
}
|
128
modules/angular2/src/di/binding.js
vendored
Normal file
128
modules/angular2/src/di/binding.js
vendored
Normal file
@ -0,0 +1,128 @@
|
||||
import {FIELD, Type, isBlank, isPresent} from 'facade/src/lang';
|
||||
import {List, MapWrapper, ListWrapper} from 'facade/src/collection';
|
||||
import {reflector} from 'reflection/src/reflection';
|
||||
import {Key} from './key';
|
||||
import {Inject, InjectLazy, InjectPromise, DependencyAnnotation} from './annotations';
|
||||
import {NoAnnotationError} from './exceptions';
|
||||
|
||||
export class Dependency {
|
||||
key:Key;
|
||||
asPromise:boolean;
|
||||
lazy:boolean;
|
||||
properties:List;
|
||||
constructor(key:Key, asPromise:boolean, lazy:boolean, properties:List) {
|
||||
this.key = key;
|
||||
this.asPromise = asPromise;
|
||||
this.lazy = lazy;
|
||||
this.properties = properties;
|
||||
}
|
||||
}
|
||||
|
||||
export class Binding {
|
||||
key:Key;
|
||||
factory:Function;
|
||||
dependencies:List;
|
||||
providedAsPromise:boolean;
|
||||
|
||||
constructor(key:Key, factory:Function, dependencies:List, providedAsPromise:boolean) {
|
||||
this.key = key;
|
||||
this.factory = factory;
|
||||
this.dependencies = dependencies;
|
||||
this.providedAsPromise = providedAsPromise;
|
||||
}
|
||||
}
|
||||
|
||||
export function bind(token):BindingBuilder {
|
||||
return new BindingBuilder(token);
|
||||
}
|
||||
|
||||
export class BindingBuilder {
|
||||
token;
|
||||
constructor(token) {
|
||||
this.token = token;
|
||||
}
|
||||
|
||||
toClass(type:Type):Binding {
|
||||
return new Binding(
|
||||
Key.get(this.token),
|
||||
reflector.factory(type),
|
||||
_dependenciesFor(type),
|
||||
false
|
||||
);
|
||||
}
|
||||
|
||||
toValue(value):Binding {
|
||||
return new Binding(
|
||||
Key.get(this.token),
|
||||
() => value,
|
||||
[],
|
||||
false
|
||||
);
|
||||
}
|
||||
|
||||
toFactory(factoryFunction:Function, dependencies:List = null):Binding {
|
||||
return new Binding(
|
||||
Key.get(this.token),
|
||||
factoryFunction,
|
||||
this._constructDependencies(factoryFunction, dependencies),
|
||||
false
|
||||
);
|
||||
}
|
||||
|
||||
toAsyncFactory(factoryFunction:Function, dependencies:List = null):Binding {
|
||||
return new Binding(
|
||||
Key.get(this.token),
|
||||
factoryFunction,
|
||||
this._constructDependencies(factoryFunction, dependencies),
|
||||
true
|
||||
);
|
||||
}
|
||||
|
||||
_constructDependencies(factoryFunction:Function, dependencies:List) {
|
||||
return isBlank(dependencies) ?
|
||||
_dependenciesFor(factoryFunction) :
|
||||
ListWrapper.map(dependencies, (t) => new Dependency(Key.get(t), false, false, []));
|
||||
}
|
||||
}
|
||||
|
||||
function _dependenciesFor(typeOrFunc):List {
|
||||
var params = reflector.parameters(typeOrFunc);
|
||||
if (isBlank(params)) return [];
|
||||
if (ListWrapper.any(params, (p) => isBlank(p))) throw new NoAnnotationError(typeOrFunc);
|
||||
return ListWrapper.map(params, (p) => _extractToken(typeOrFunc, p));
|
||||
}
|
||||
|
||||
function _extractToken(typeOrFunc, annotations) {
|
||||
var type;
|
||||
var depProps = [];
|
||||
|
||||
for (var i = 0; i < annotations.length; ++i) {
|
||||
var paramAnnotation = annotations[i];
|
||||
|
||||
if (paramAnnotation instanceof Type) {
|
||||
type = paramAnnotation;
|
||||
|
||||
} else if (paramAnnotation instanceof Inject) {
|
||||
return _createDependency(paramAnnotation.token, false, false, []);
|
||||
|
||||
} else if (paramAnnotation instanceof InjectPromise) {
|
||||
return _createDependency(paramAnnotation.token, true, false, []);
|
||||
|
||||
} else if (paramAnnotation instanceof InjectLazy) {
|
||||
return _createDependency(paramAnnotation.token, false, true, []);
|
||||
|
||||
} else if (paramAnnotation instanceof DependencyAnnotation) {
|
||||
ListWrapper.push(depProps, paramAnnotation);
|
||||
}
|
||||
}
|
||||
|
||||
if (isPresent(type)) {
|
||||
return _createDependency(type, false, false, depProps);
|
||||
} else {
|
||||
throw new NoAnnotationError(typeOrFunc);
|
||||
}
|
||||
}
|
||||
|
||||
function _createDependency(token, asPromise, lazy, depProps):Dependency {
|
||||
return new Dependency(Key.get(token), asPromise, lazy, depProps);
|
||||
}
|
107
modules/angular2/src/di/exceptions.js
vendored
Normal file
107
modules/angular2/src/di/exceptions.js
vendored
Normal file
@ -0,0 +1,107 @@
|
||||
import {ListWrapper, List} from 'facade/src/collection';
|
||||
import {stringify} from 'facade/src/lang';
|
||||
import {Key} from './key';
|
||||
|
||||
function findFirstClosedCycle(keys:List) {
|
||||
var res = [];
|
||||
for(var i = 0; i < keys.length; ++i) {
|
||||
if (ListWrapper.contains(res, keys[i])) {
|
||||
ListWrapper.push(res, keys[i]);
|
||||
return res;
|
||||
} else {
|
||||
ListWrapper.push(res, keys[i]);
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
function constructResolvingPath(keys:List) {
|
||||
if (keys.length > 1) {
|
||||
var reversed = findFirstClosedCycle(ListWrapper.reversed(keys));
|
||||
var tokenStrs = ListWrapper.map(reversed, (k) => stringify(k.token));
|
||||
return " (" + tokenStrs.join(' -> ') + ")";
|
||||
} else {
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
export class KeyMetadataError extends Error {}
|
||||
|
||||
export class ProviderError extends Error {
|
||||
keys:List;
|
||||
constructResolvingMessage:Function;
|
||||
message;
|
||||
constructor(key:Key, constructResolvingMessage:Function) {
|
||||
this.keys = [key];
|
||||
this.constructResolvingMessage = constructResolvingMessage;
|
||||
this.message = this.constructResolvingMessage(this.keys);
|
||||
}
|
||||
|
||||
addKey(key:Key) {
|
||||
ListWrapper.push(this.keys, key);
|
||||
this.message = this.constructResolvingMessage(this.keys);
|
||||
}
|
||||
|
||||
toString() {
|
||||
return this.message;
|
||||
}
|
||||
}
|
||||
|
||||
export class NoProviderError extends ProviderError {
|
||||
constructor(key:Key) {
|
||||
super(key, function (keys:List) {
|
||||
var first = stringify(ListWrapper.first(keys).token);
|
||||
return `No provider for ${first}!${constructResolvingPath(keys)}`;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export class AsyncBindingError extends ProviderError {
|
||||
constructor(key:Key) {
|
||||
super(key, function (keys:List) {
|
||||
var first = stringify(ListWrapper.first(keys).token);
|
||||
return `Cannot instantiate ${first} synchronously. ` +
|
||||
`It is provided as a promise!${constructResolvingPath(keys)}`;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export class CyclicDependencyError extends ProviderError {
|
||||
constructor(key:Key) {
|
||||
super(key, function (keys:List) {
|
||||
return `Cannot instantiate cyclic dependency!${constructResolvingPath(keys)}`;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export class InstantiationError extends ProviderError {
|
||||
constructor(originalException, key:Key) {
|
||||
super(key, function (keys:List) {
|
||||
var first = stringify(ListWrapper.first(keys).token);
|
||||
return `Error during instantiation of ${first}!${constructResolvingPath(keys)}.` +
|
||||
` ORIGINAL ERROR: ${originalException}`;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export class InvalidBindingError extends Error {
|
||||
message:string;
|
||||
constructor(binding) {
|
||||
this.message = `Invalid binding ${binding}`;
|
||||
}
|
||||
|
||||
toString() {
|
||||
return this.message;
|
||||
}
|
||||
}
|
||||
|
||||
export class NoAnnotationError extends Error {
|
||||
message:string;
|
||||
constructor(typeOrFunc) {
|
||||
this.message = `Cannot resolve all parameters for ${stringify(typeOrFunc)}`;
|
||||
}
|
||||
|
||||
toString() {
|
||||
return this.message;
|
||||
}
|
||||
}
|
258
modules/angular2/src/di/injector.js
vendored
Normal file
258
modules/angular2/src/di/injector.js
vendored
Normal file
@ -0,0 +1,258 @@
|
||||
import {Map, List, MapWrapper, ListWrapper} from 'facade/src/collection';
|
||||
import {Binding, BindingBuilder, bind} from './binding';
|
||||
import {ProviderError, NoProviderError, InvalidBindingError,
|
||||
AsyncBindingError, CyclicDependencyError, InstantiationError} from './exceptions';
|
||||
import {FunctionWrapper, Type, isPresent, isBlank} from 'facade/src/lang';
|
||||
import {Promise, PromiseWrapper} from 'facade/src/async';
|
||||
import {Key} from './key';
|
||||
|
||||
var _constructing = new Object();
|
||||
|
||||
class _Waiting {
|
||||
promise:Promise;
|
||||
constructor(promise:Promise) {
|
||||
this.promise = promise;
|
||||
}
|
||||
}
|
||||
function _isWaiting(obj):boolean {
|
||||
return obj instanceof _Waiting;
|
||||
}
|
||||
|
||||
|
||||
export class Injector {
|
||||
_bindings:List;
|
||||
_instances:List;
|
||||
_parent:Injector;
|
||||
_defaultBindings:boolean;
|
||||
_asyncStrategy: _AsyncInjectorStrategy;
|
||||
_syncStrategy:_SyncInjectorStrategy;
|
||||
constructor(bindings:List, {parent=null, defaultBindings=false}={}) {
|
||||
var flatten = _flattenBindings(bindings, MapWrapper.create());
|
||||
this._bindings = this._createListOfBindings(flatten);
|
||||
this._instances = this._createInstances();
|
||||
this._parent = parent;
|
||||
this._defaultBindings = defaultBindings;
|
||||
|
||||
this._asyncStrategy = new _AsyncInjectorStrategy(this);
|
||||
this._syncStrategy = new _SyncInjectorStrategy(this);
|
||||
}
|
||||
|
||||
get(token) {
|
||||
return this._getByKey(Key.get(token), false, false);
|
||||
}
|
||||
|
||||
asyncGet(token) {
|
||||
return this._getByKey(Key.get(token), true, false);
|
||||
}
|
||||
|
||||
createChild(bindings:List):Injector {
|
||||
return new Injector(bindings, {parent: this});
|
||||
}
|
||||
|
||||
|
||||
_createListOfBindings(flattenBindings):List {
|
||||
var bindings = ListWrapper.createFixedSize(Key.numberOfKeys + 1);
|
||||
MapWrapper.forEach(flattenBindings, (v, keyId) => bindings[keyId] = v);
|
||||
return bindings;
|
||||
}
|
||||
|
||||
_createInstances():List {
|
||||
return ListWrapper.createFixedSize(Key.numberOfKeys + 1);
|
||||
}
|
||||
|
||||
_getByKey(key:Key, returnPromise:boolean, returnLazy:boolean) {
|
||||
if (returnLazy) {
|
||||
return () => this._getByKey(key, returnPromise, false);
|
||||
}
|
||||
|
||||
var strategy = returnPromise ? this._asyncStrategy : this._syncStrategy;
|
||||
|
||||
var instance = strategy.readFromCache(key);
|
||||
if (isPresent(instance)) return instance;
|
||||
|
||||
instance = strategy.instantiate(key);
|
||||
if (isPresent(instance)) return instance;
|
||||
|
||||
if (isPresent(this._parent)) {
|
||||
return this._parent._getByKey(key, returnPromise, returnLazy);
|
||||
}
|
||||
throw new NoProviderError(key);
|
||||
}
|
||||
|
||||
_resolveDependencies(key:Key, binding:Binding, forceAsync:boolean):List {
|
||||
try {
|
||||
var getDependency = d => this._getByKey(d.key, forceAsync || d.asPromise, d.lazy);
|
||||
return ListWrapper.map(binding.dependencies, getDependency);
|
||||
} catch (e) {
|
||||
this._clear(key);
|
||||
if (e instanceof ProviderError) e.addKey(key);
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
_getInstance(key:Key) {
|
||||
if (this._instances.length <= key.id) return null;
|
||||
return ListWrapper.get(this._instances, key.id);
|
||||
}
|
||||
|
||||
_setInstance(key:Key, obj) {
|
||||
ListWrapper.set(this._instances, key.id, obj);
|
||||
}
|
||||
|
||||
_getBinding(key:Key) {
|
||||
var binding = this._bindings.length <= key.id ?
|
||||
null :
|
||||
ListWrapper.get(this._bindings, key.id);
|
||||
|
||||
if (isBlank(binding) && this._defaultBindings) {
|
||||
return bind(key.token).toClass(key.token);
|
||||
} else {
|
||||
return binding;
|
||||
}
|
||||
}
|
||||
|
||||
_markAsConstructing(key:Key) {
|
||||
this._setInstance(key, _constructing);
|
||||
}
|
||||
|
||||
_clear(key:Key) {
|
||||
this._setInstance(key, null);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class _SyncInjectorStrategy {
|
||||
injector:Injector;
|
||||
constructor(injector:Injector) {
|
||||
this.injector = injector;
|
||||
}
|
||||
|
||||
readFromCache(key:Key) {
|
||||
if (key.token === Injector) {
|
||||
return this.injector;
|
||||
}
|
||||
|
||||
var instance = this.injector._getInstance(key);
|
||||
|
||||
if (instance === _constructing) {
|
||||
throw new CyclicDependencyError(key);
|
||||
} else if (isPresent(instance) && !_isWaiting(instance)) {
|
||||
return instance;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
instantiate(key:Key) {
|
||||
var binding = this.injector._getBinding(key);
|
||||
if (isBlank(binding)) return null;
|
||||
|
||||
if (binding.providedAsPromise) throw new AsyncBindingError(key);
|
||||
|
||||
//add a marker so we can detect cyclic dependencies
|
||||
this.injector._markAsConstructing(key);
|
||||
|
||||
var deps = this.injector._resolveDependencies(key, binding, false);
|
||||
return this._createInstance(key, binding, deps);
|
||||
}
|
||||
|
||||
_createInstance(key:Key, binding:Binding, deps:List) {
|
||||
try {
|
||||
var instance = FunctionWrapper.apply(binding.factory, deps);
|
||||
this.injector._setInstance(key, instance);
|
||||
return instance;
|
||||
} catch (e) {
|
||||
this.injector._clear(key);
|
||||
throw new InstantiationError(e, key);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class _AsyncInjectorStrategy {
|
||||
injector:Injector;
|
||||
constructor(injector:Injector) {
|
||||
this.injector = injector;
|
||||
}
|
||||
|
||||
readFromCache(key:Key) {
|
||||
if (key.token === Injector) {
|
||||
return PromiseWrapper.resolve(this.injector);
|
||||
}
|
||||
|
||||
var instance = this.injector._getInstance(key);
|
||||
|
||||
if (instance === _constructing) {
|
||||
throw new CyclicDependencyError(key);
|
||||
} else if (_isWaiting(instance)) {
|
||||
return instance.promise;
|
||||
} else if (isPresent(instance)) {
|
||||
return PromiseWrapper.resolve(instance);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
instantiate(key:Key) {
|
||||
var binding = this.injector._getBinding(key);
|
||||
if (isBlank(binding)) return null;
|
||||
|
||||
//add a marker so we can detect cyclic dependencies
|
||||
this.injector._markAsConstructing(key);
|
||||
|
||||
var deps = this.injector._resolveDependencies(key, binding, true);
|
||||
var depsPromise = PromiseWrapper.all(deps);
|
||||
|
||||
var promise = PromiseWrapper
|
||||
.then(depsPromise, null, (e) => this._errorHandler(key, e))
|
||||
.then(deps => this._findOrCreate(key, binding, deps))
|
||||
.then(instance => this._cacheInstance(key, instance));
|
||||
|
||||
this.injector._setInstance(key, new _Waiting(promise));
|
||||
return promise;
|
||||
}
|
||||
|
||||
_errorHandler(key:Key, e):Promise {
|
||||
if (e instanceof ProviderError) e.addKey(key);
|
||||
return PromiseWrapper.reject(e);
|
||||
}
|
||||
|
||||
_findOrCreate(key:Key, binding:Binding, deps:List) {
|
||||
try {
|
||||
var instance = this.injector._getInstance(key);
|
||||
if (!_isWaiting(instance)) return instance;
|
||||
return FunctionWrapper.apply(binding.factory, deps);
|
||||
} catch (e) {
|
||||
this.injector._clear(key);
|
||||
throw new InstantiationError(e, key);
|
||||
}
|
||||
}
|
||||
|
||||
_cacheInstance(key, instance) {
|
||||
this.injector._setInstance(key, instance);
|
||||
return instance
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function _flattenBindings(bindings:List, res:Map) {
|
||||
ListWrapper.forEach(bindings, function (b) {
|
||||
if (b instanceof Binding) {
|
||||
MapWrapper.set(res, b.key.id, b);
|
||||
|
||||
} else if (b instanceof Type) {
|
||||
var s = bind(b).toClass(b);
|
||||
MapWrapper.set(res, s.key.id, s);
|
||||
|
||||
} else if (b instanceof List) {
|
||||
_flattenBindings(b, res);
|
||||
|
||||
} else if (b instanceof BindingBuilder) {
|
||||
throw new InvalidBindingError(b.token);
|
||||
|
||||
} else {
|
||||
throw new InvalidBindingError(b);
|
||||
}
|
||||
});
|
||||
return res;
|
||||
}
|
55
modules/angular2/src/di/key.js
vendored
Normal file
55
modules/angular2/src/di/key.js
vendored
Normal file
@ -0,0 +1,55 @@
|
||||
import {KeyMetadataError} from './exceptions';
|
||||
import {MapWrapper, Map} from 'facade/src/collection';
|
||||
import {FIELD, int, isPresent} from 'facade/src/lang';
|
||||
|
||||
export class Key {
|
||||
token;
|
||||
id:int;
|
||||
metadata:any;
|
||||
constructor(token, id:int) {
|
||||
this.token = token;
|
||||
this.id = id;
|
||||
this.metadata = null;
|
||||
}
|
||||
|
||||
static setMetadata(key:Key, metadata):Key {
|
||||
if (isPresent(key.metadata) && key.metadata !== metadata) {
|
||||
throw new KeyMetadataError();
|
||||
}
|
||||
key.metadata = metadata;
|
||||
return key;
|
||||
}
|
||||
|
||||
static get(token):Key {
|
||||
return _globalKeyRegistry.get(token);
|
||||
}
|
||||
|
||||
static get numberOfKeys():int {
|
||||
return _globalKeyRegistry.numberOfKeys;
|
||||
}
|
||||
}
|
||||
|
||||
export class KeyRegistry {
|
||||
_allKeys:Map;
|
||||
constructor() {
|
||||
this._allKeys = MapWrapper.create();
|
||||
}
|
||||
|
||||
get(token):Key {
|
||||
if (token instanceof Key) return token;
|
||||
|
||||
if (MapWrapper.contains(this._allKeys, token)) {
|
||||
return MapWrapper.get(this._allKeys, token);
|
||||
}
|
||||
|
||||
var newKey = new Key(token, Key.numberOfKeys);
|
||||
MapWrapper.set(this._allKeys, token, newKey);
|
||||
return newKey;
|
||||
}
|
||||
|
||||
get numberOfKeys():int {
|
||||
return MapWrapper.size(this._allKeys);
|
||||
}
|
||||
}
|
||||
|
||||
var _globalKeyRegistry = new KeyRegistry();
|
11
modules/angular2/src/di/opaque_token.js
vendored
Normal file
11
modules/angular2/src/di/opaque_token.js
vendored
Normal file
@ -0,0 +1,11 @@
|
||||
export class OpaqueToken {
|
||||
_desc:string;
|
||||
|
||||
constructor(desc:string){
|
||||
this._desc = `Token(${desc})`;
|
||||
}
|
||||
|
||||
toString() {
|
||||
return this._desc;
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user