fix: Improve error message on missing dependency
This commit is contained in:
parent
7501ad11ca
commit
2ccc65d7fd
|
@ -1,4 +1,4 @@
|
||||||
import {CONST} from 'angular2/src/facade/lang';
|
import {CONST, stringify} from 'angular2/src/facade/lang';
|
||||||
import {DependencyAnnotation} from 'angular2/src/di/annotations_impl';
|
import {DependencyAnnotation} from 'angular2/src/di/annotations_impl';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -41,6 +41,7 @@ export class Attribute extends DependencyAnnotation {
|
||||||
// account.
|
// account.
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
toString() { return `@Attribute(${stringify(this.attributeName)})`; }
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -53,4 +54,5 @@ export class Attribute extends DependencyAnnotation {
|
||||||
@CONST()
|
@CONST()
|
||||||
export class Query extends DependencyAnnotation {
|
export class Query extends DependencyAnnotation {
|
||||||
constructor(public directive: any) { super(); }
|
constructor(public directive: any) { super(); }
|
||||||
|
toString() { return `@Query(${stringify(this.directive)})`; }
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,6 +9,9 @@ export class Visibility extends DependencyAnnotation {
|
||||||
}
|
}
|
||||||
|
|
||||||
get includeSelf(): boolean { return isBlank(this._includeSelf) ? false : this._includeSelf; }
|
get includeSelf(): boolean { return isBlank(this._includeSelf) ? false : this._includeSelf; }
|
||||||
|
toString() {
|
||||||
|
return `@Visibility(depth: ${this.depth}, crossComponentBoundaries: ${this.crossComponentBoundaries}, includeSelf: ${this.includeSelf}})`;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -51,6 +54,7 @@ export class Visibility extends DependencyAnnotation {
|
||||||
@CONST()
|
@CONST()
|
||||||
export class Self extends Visibility {
|
export class Self extends Visibility {
|
||||||
constructor() { super(0, false, true); }
|
constructor() { super(0, false, true); }
|
||||||
|
toString() { return `@Self()`; }
|
||||||
}
|
}
|
||||||
|
|
||||||
// make constants after switching to ts2dart
|
// make constants after switching to ts2dart
|
||||||
|
@ -102,6 +106,7 @@ export var self = new Self();
|
||||||
@CONST()
|
@CONST()
|
||||||
export class Parent extends Visibility {
|
export class Parent extends Visibility {
|
||||||
constructor({self}: {self?: boolean} = {}) { super(1, false, self); }
|
constructor({self}: {self?: boolean} = {}) { super(1, false, self); }
|
||||||
|
toString() { return `@Parent(self: ${this.includeSelf}})`; }
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -164,6 +169,7 @@ export class Parent extends Visibility {
|
||||||
@CONST()
|
@CONST()
|
||||||
export class Ancestor extends Visibility {
|
export class Ancestor extends Visibility {
|
||||||
constructor({self}: {self?: boolean} = {}) { super(999999, false, self); }
|
constructor({self}: {self?: boolean} = {}) { super(999999, false, self); }
|
||||||
|
toString() { return `@Ancestor(self: ${this.includeSelf}})`; }
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -203,4 +209,5 @@ export class Ancestor extends Visibility {
|
||||||
@CONST()
|
@CONST()
|
||||||
export class Unbounded extends Visibility {
|
export class Unbounded extends Visibility {
|
||||||
constructor({self}: {self?: boolean} = {}) { super(999999, true, self); }
|
constructor({self}: {self?: boolean} = {}) { super(999999, true, self); }
|
||||||
|
toString() { return `@Unbounded(self: ${this.includeSelf}})`; }
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import {CONST} from "angular2/src/facade/lang";
|
import {CONST, stringify} from "angular2/src/facade/lang";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A parameter annotation that specifies a dependency.
|
* A parameter annotation that specifies a dependency.
|
||||||
|
@ -15,6 +15,7 @@ import {CONST} from "angular2/src/facade/lang";
|
||||||
@CONST()
|
@CONST()
|
||||||
export class Inject {
|
export class Inject {
|
||||||
constructor(public token) {}
|
constructor(public token) {}
|
||||||
|
toString() { return `@Inject(${stringify(this.token)})`; }
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -33,6 +34,7 @@ export class Inject {
|
||||||
@CONST()
|
@CONST()
|
||||||
export class InjectPromise {
|
export class InjectPromise {
|
||||||
constructor(public token) {}
|
constructor(public token) {}
|
||||||
|
toString() { return `@InjectPromise(${stringify(this.token)})`; }
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -51,6 +53,7 @@ export class InjectPromise {
|
||||||
@CONST()
|
@CONST()
|
||||||
export class InjectLazy {
|
export class InjectLazy {
|
||||||
constructor(public token) {}
|
constructor(public token) {}
|
||||||
|
toString() { return `@InjectLazy(${stringify(this.token)})`; }
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -69,6 +72,7 @@ export class InjectLazy {
|
||||||
*/
|
*/
|
||||||
@CONST()
|
@CONST()
|
||||||
export class Optional {
|
export class Optional {
|
||||||
|
toString() { return `@Optional()`; }
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -437,22 +437,27 @@ export class BindingBuilder {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function _constructDependencies(factoryFunction: Function, dependencies: List<any>) {
|
function _constructDependencies(factoryFunction: Function,
|
||||||
return isBlank(dependencies) ?
|
dependencies: List<any>): List<Dependency> {
|
||||||
_dependenciesFor(factoryFunction) :
|
if (isBlank(dependencies)) {
|
||||||
ListWrapper.map(dependencies, (t) => _extractToken(factoryFunction, t));
|
return _dependenciesFor(factoryFunction);
|
||||||
|
} else {
|
||||||
|
var params: List<List<any>> = ListWrapper.map(dependencies, (t) => [t]);
|
||||||
|
return ListWrapper.map(dependencies, (t) => _extractToken(factoryFunction, t, params));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function _dependenciesFor(typeOrFunc): List<any> {
|
function _dependenciesFor(typeOrFunc): List<Dependency> {
|
||||||
var params = reflector.parameters(typeOrFunc);
|
var params = reflector.parameters(typeOrFunc);
|
||||||
if (isBlank(params)) return [];
|
if (isBlank(params)) return [];
|
||||||
if (ListWrapper.any(params, (p) => isBlank(p))) {
|
if (ListWrapper.any(params, (p) => isBlank(p))) {
|
||||||
throw new NoAnnotationError(typeOrFunc);
|
throw new NoAnnotationError(typeOrFunc, params);
|
||||||
}
|
}
|
||||||
return ListWrapper.map(params, (p) => _extractToken(typeOrFunc, p));
|
return ListWrapper.map(params, (p: List<any>) => _extractToken(typeOrFunc, p, params));
|
||||||
}
|
}
|
||||||
|
|
||||||
function _extractToken(typeOrFunc, annotations) {
|
function _extractToken(typeOrFunc, annotations /*List<any> | any*/,
|
||||||
|
params: List<List<any>>): Dependency {
|
||||||
var depProps = [];
|
var depProps = [];
|
||||||
var token = null;
|
var token = null;
|
||||||
var optional = false;
|
var optional = false;
|
||||||
|
@ -496,7 +501,7 @@ function _extractToken(typeOrFunc, annotations) {
|
||||||
if (isPresent(token)) {
|
if (isPresent(token)) {
|
||||||
return _createDependency(token, asPromise, lazy, optional, depProps);
|
return _createDependency(token, asPromise, lazy, optional, depProps);
|
||||||
} else {
|
} else {
|
||||||
throw new NoAnnotationError(typeOrFunc);
|
throw new NoAnnotationError(typeOrFunc, params);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import {ListWrapper, List} from 'angular2/src/facade/collection';
|
import {ListWrapper, List} from 'angular2/src/facade/collection';
|
||||||
import {stringify, BaseException} from 'angular2/src/facade/lang';
|
import {stringify, BaseException, isBlank} from 'angular2/src/facade/lang';
|
||||||
|
|
||||||
function findFirstClosedCycle(keys: List<any>): List<any> {
|
function findFirstClosedCycle(keys: List<any>): List<any> {
|
||||||
var res = [];
|
var res = [];
|
||||||
|
@ -179,9 +179,19 @@ export class InvalidBindingError extends BaseException {
|
||||||
export class NoAnnotationError extends BaseException {
|
export class NoAnnotationError extends BaseException {
|
||||||
name: string;
|
name: string;
|
||||||
message: string;
|
message: string;
|
||||||
constructor(typeOrFunc) {
|
constructor(typeOrFunc, params: List<List<any>>) {
|
||||||
super();
|
super();
|
||||||
this.message = "Cannot resolve all parameters for " + stringify(typeOrFunc) + ". " +
|
var signature = ListWrapper.create();
|
||||||
|
for (var i = 0, ii = params.length; i < ii; i++) {
|
||||||
|
var parameter = params[i];
|
||||||
|
if (isBlank(parameter) || parameter.length == 0) {
|
||||||
|
ListWrapper.push(signature, '?');
|
||||||
|
} else {
|
||||||
|
ListWrapper.push(signature, ListWrapper.map(parameter, stringify).join(' '));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.message = "Cannot resolve all parameters for " + stringify(typeOrFunc) + "(" +
|
||||||
|
signature.join(', ') + "). " +
|
||||||
'Make sure they all have valid type or annotations.';
|
'Make sure they all have valid type or annotations.';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import {Type} from 'angular2/src/facade/lang';
|
import {Type, stringify} from 'angular2/src/facade/lang';
|
||||||
|
|
||||||
export interface ForwardRefFn { (): any; }
|
export interface ForwardRefFn { (): any; }
|
||||||
|
|
||||||
|
@ -30,6 +30,7 @@ export interface ForwardRefFn { (): any; }
|
||||||
*/
|
*/
|
||||||
export function forwardRef(forwardRefFn: ForwardRefFn): Type {
|
export function forwardRef(forwardRefFn: ForwardRefFn): Type {
|
||||||
(<any>forwardRefFn).__forward_ref__ = forwardRef;
|
(<any>forwardRefFn).__forward_ref__ = forwardRef;
|
||||||
|
(<any>forwardRefFn).toString = function() { return stringify(this()); };
|
||||||
return (<Type><any>forwardRefFn);
|
return (<Type><any>forwardRefFn);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,4 @@
|
||||||
|
library angular2.di.type_info;
|
||||||
|
|
||||||
|
// In dart always return empty, as we can get the co
|
||||||
|
argsLength(Type type) => 0;
|
|
@ -0,0 +1,13 @@
|
||||||
|
import {Type} from 'angular2/src/facade/lang';
|
||||||
|
import {GetterFn, SetterFn, MethodFn} from './types';
|
||||||
|
import {List} from 'angular2/src/facade/collection';
|
||||||
|
|
||||||
|
export interface PlatformReflectionCapabilities {
|
||||||
|
factory(type: Type): Function;
|
||||||
|
interfaces(type: Type): List<any>;
|
||||||
|
parameters(type: Type): List<List<any>>;
|
||||||
|
annotations(type: Type): List<any>;
|
||||||
|
getter(name: string): GetterFn;
|
||||||
|
setter(name: string): SetterFn;
|
||||||
|
method(name: string): MethodFn;
|
||||||
|
}
|
|
@ -3,13 +3,18 @@ library reflection.reflection;
|
||||||
import 'reflector.dart';
|
import 'reflector.dart';
|
||||||
import 'types.dart';
|
import 'types.dart';
|
||||||
export 'reflector.dart';
|
export 'reflector.dart';
|
||||||
|
import 'platform_reflection_capabilities.dart';
|
||||||
import 'package:angular2/src/facade/lang.dart';
|
import 'package:angular2/src/facade/lang.dart';
|
||||||
|
|
||||||
class NoReflectionCapabilities implements IReflectionCapabilities {
|
class NoReflectionCapabilities implements PlatformReflectionCapabilities {
|
||||||
Function factory(Type type) {
|
Function factory(Type type) {
|
||||||
throw "Cannot find reflection information on ${stringify(type)}";
|
throw "Cannot find reflection information on ${stringify(type)}";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
List interfaces(Type type) {
|
||||||
|
throw "Cannot find reflection information on ${stringify(type)}";
|
||||||
|
}
|
||||||
|
|
||||||
List parameters(Type type) {
|
List parameters(Type type) {
|
||||||
throw "Cannot find reflection information on ${stringify(type)}";
|
throw "Cannot find reflection information on ${stringify(type)}";
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,8 +3,9 @@ library reflection.reflection_capabilities;
|
||||||
import 'package:angular2/src/facade/lang.dart';
|
import 'package:angular2/src/facade/lang.dart';
|
||||||
import 'types.dart';
|
import 'types.dart';
|
||||||
import 'dart:mirrors';
|
import 'dart:mirrors';
|
||||||
|
import 'platform_reflection_capabilities.dart';
|
||||||
|
|
||||||
class ReflectionCapabilities implements IReflectionCapabilities {
|
class ReflectionCapabilities implements PlatformReflectionCapabilities {
|
||||||
ReflectionCapabilities([metadataReader]) {}
|
ReflectionCapabilities([metadataReader]) {}
|
||||||
|
|
||||||
Function factory(Type type) {
|
Function factory(Type type) {
|
||||||
|
|
|
@ -1,8 +1,9 @@
|
||||||
import {Type, isPresent, global, stringify, BaseException} from 'angular2/src/facade/lang';
|
import {Type, isPresent, global, stringify, BaseException} from 'angular2/src/facade/lang';
|
||||||
import {List, ListWrapper} from 'angular2/src/facade/collection';
|
import {List, ListWrapper} from 'angular2/src/facade/collection';
|
||||||
import {GetterFn, SetterFn, MethodFn, IReflectionCapabilities} from './types';
|
import {GetterFn, SetterFn, MethodFn} from './types';
|
||||||
|
import {PlatformReflectionCapabilities} from 'platform_reflection_capabilities';
|
||||||
|
|
||||||
export class ReflectionCapabilities implements IReflectionCapabilities {
|
export class ReflectionCapabilities implements PlatformReflectionCapabilities {
|
||||||
private _reflect: any;
|
private _reflect: any;
|
||||||
|
|
||||||
constructor(reflect?: any) { this._reflect = isPresent(reflect) ? reflect : global.Reflect; }
|
constructor(reflect?: any) { this._reflect = isPresent(reflect) ? reflect : global.Reflect; }
|
||||||
|
|
|
@ -7,17 +7,19 @@ import {
|
||||||
StringMap,
|
StringMap,
|
||||||
StringMapWrapper
|
StringMapWrapper
|
||||||
} from 'angular2/src/facade/collection';
|
} from 'angular2/src/facade/collection';
|
||||||
import {SetterFn, GetterFn, MethodFn, IReflectionCapabilities} from './types';
|
import {SetterFn, GetterFn, MethodFn} from './types';
|
||||||
export {SetterFn, GetterFn, MethodFn, IReflectionCapabilities} from './types';
|
import {PlatformReflectionCapabilities} from './platform_reflection_capabilities';
|
||||||
|
export {SetterFn, GetterFn, MethodFn} from './types';
|
||||||
|
export {PlatformReflectionCapabilities} from './platform_reflection_capabilities';
|
||||||
|
|
||||||
export class Reflector {
|
export class Reflector {
|
||||||
_typeInfo: Map<Type, any>;
|
_typeInfo: Map<Type, any>;
|
||||||
_getters: Map<string, GetterFn>;
|
_getters: Map<string, GetterFn>;
|
||||||
_setters: Map<string, SetterFn>;
|
_setters: Map<string, SetterFn>;
|
||||||
_methods: Map<string, MethodFn>;
|
_methods: Map<string, MethodFn>;
|
||||||
reflectionCapabilities: IReflectionCapabilities;
|
reflectionCapabilities: PlatformReflectionCapabilities;
|
||||||
|
|
||||||
constructor(reflectionCapabilities: IReflectionCapabilities) {
|
constructor(reflectionCapabilities: PlatformReflectionCapabilities) {
|
||||||
this._typeInfo = MapWrapper.create();
|
this._typeInfo = MapWrapper.create();
|
||||||
this._getters = MapWrapper.create();
|
this._getters = MapWrapper.create();
|
||||||
this._setters = MapWrapper.create();
|
this._setters = MapWrapper.create();
|
||||||
|
|
|
@ -3,13 +3,3 @@ library reflection.types;
|
||||||
typedef SetterFn(Object obj, value);
|
typedef SetterFn(Object obj, value);
|
||||||
typedef GetterFn(Object obj);
|
typedef GetterFn(Object obj);
|
||||||
typedef MethodFn(Object obj, List args);
|
typedef MethodFn(Object obj, List args);
|
||||||
|
|
||||||
abstract class IReflectionCapabilities {
|
|
||||||
Function factory(Type type);
|
|
||||||
List<List<Type>> parameters(Type type);
|
|
||||||
List<Type> interfaces(Type type);
|
|
||||||
List annotations(Type type);
|
|
||||||
GetterFn getter(String name);
|
|
||||||
SetterFn setter(String name);
|
|
||||||
MethodFn method(String name);
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,21 +1,13 @@
|
||||||
import {Type} from 'angular2/src/facade/lang';
|
import {Type} from 'angular2/src/facade/lang';
|
||||||
import {List} from 'angular2/src/facade/collection';
|
import {List} from 'angular2/src/facade/collection';
|
||||||
|
|
||||||
// HACK: workaround for Traceur behavior.
|
export {Function as GetterFn};
|
||||||
// It expects all transpiled modules to contain this marker.
|
export {Function as SetterFn};
|
||||||
// TODO: remove this when we no longer use traceur
|
export {Function as MethodFn};
|
||||||
export var __esModule = true;
|
|
||||||
|
|
||||||
|
// TODO replace once dgeni is fixed
|
||||||
|
/**
|
||||||
export type SetterFn = (obj: any, value: any) => void;
|
export type SetterFn = (obj: any, value: any) => void;
|
||||||
export type GetterFn = (obj: any) => any;
|
export type GetterFn = (obj: any) => any;
|
||||||
export type MethodFn = (obj: any, args: List<any>) => any;
|
export type MethodFn = (obj: any, args: List<any>) => any;
|
||||||
|
**/
|
||||||
export interface IReflectionCapabilities {
|
|
||||||
factory(type: Type): Function;
|
|
||||||
parameters(type: Type): List<List<any>>;
|
|
||||||
interfaces(type: Type): List<any>;
|
|
||||||
annotations(type: Type): List<any>;
|
|
||||||
getter(name: string): GetterFn;
|
|
||||||
setter(name: string): SetterFn;
|
|
||||||
method(name: string): MethodFn;
|
|
||||||
}
|
|
||||||
|
|
|
@ -106,7 +106,7 @@ export function main() {
|
||||||
|
|
||||||
it('should throw when no type and not @Inject', () => {
|
it('should throw when no type and not @Inject', () => {
|
||||||
expect(() => Injector.resolveAndCreate([NoAnnotations]))
|
expect(() => Injector.resolveAndCreate([NoAnnotations]))
|
||||||
.toThrowError('Cannot resolve all parameters for NoAnnotations. ' +
|
.toThrowError('Cannot resolve all parameters for NoAnnotations(?). ' +
|
||||||
'Make sure they all have valid type or annotations.');
|
'Make sure they all have valid type or annotations.');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue