2015-09-04 01:01:36 -04:00
|
|
|
import {resolveForwardRef, Injectable} from 'angular2/src/core/di';
|
2015-11-06 20:34:07 -05:00
|
|
|
import {Type, isPresent, isBlank, stringify} from 'angular2/src/facade/lang';
|
|
|
|
import {BaseException} from 'angular2/src/facade/exceptions';
|
|
|
|
import {ListWrapper, StringMapWrapper} from 'angular2/src/facade/collection';
|
2015-11-04 04:08:51 -05:00
|
|
|
|
2016-04-12 12:40:37 -04:00
|
|
|
import {
|
|
|
|
DirectiveMetadata,
|
|
|
|
ComponentMetadata,
|
|
|
|
InputMetadata,
|
|
|
|
OutputMetadata,
|
|
|
|
HostBindingMetadata,
|
|
|
|
HostListenerMetadata,
|
|
|
|
ContentChildrenMetadata,
|
|
|
|
ViewChildrenMetadata,
|
|
|
|
ContentChildMetadata,
|
|
|
|
ViewChildMetadata
|
|
|
|
} from 'angular2/src/core/metadata';
|
2015-08-20 17:28:25 -04:00
|
|
|
import {reflector} from 'angular2/src/core/reflection/reflection';
|
2016-03-24 16:32:47 -04:00
|
|
|
import {ReflectorReader} from 'angular2/src/core/reflection/reflector_reader';
|
2014-11-11 20:33:47 -05:00
|
|
|
|
2015-10-23 02:35:53 -04:00
|
|
|
function _isDirectiveMetadata(type: any): boolean {
|
|
|
|
return type instanceof DirectiveMetadata;
|
|
|
|
}
|
|
|
|
|
2015-09-19 21:39:35 -04:00
|
|
|
/*
|
2015-08-14 13:03:45 -04:00
|
|
|
* Resolve a `Type` for {@link DirectiveMetadata}.
|
2015-07-07 02:15:58 -04:00
|
|
|
*
|
|
|
|
* This interface can be overridden by the application developer to create custom behavior.
|
|
|
|
*
|
|
|
|
* See {@link Compiler}
|
|
|
|
*/
|
2015-03-16 17:44:14 -04:00
|
|
|
@Injectable()
|
2015-05-11 20:59:39 -04:00
|
|
|
export class DirectiveResolver {
|
2016-03-24 16:32:47 -04:00
|
|
|
private _reflector: ReflectorReader;
|
|
|
|
|
|
|
|
constructor(_reflector?: ReflectorReader) {
|
|
|
|
if (isPresent(_reflector)) {
|
|
|
|
this._reflector = _reflector;
|
|
|
|
} else {
|
|
|
|
this._reflector = reflector;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-07-07 02:15:58 -04:00
|
|
|
/**
|
2015-08-14 13:03:45 -04:00
|
|
|
* Return {@link DirectiveMetadata} for a given `Type`.
|
2015-07-07 02:15:58 -04:00
|
|
|
*/
|
2015-08-14 13:03:45 -04:00
|
|
|
resolve(type: Type): DirectiveMetadata {
|
2016-03-24 16:32:47 -04:00
|
|
|
var typeMetadata = this._reflector.annotations(resolveForwardRef(type));
|
2015-09-03 18:10:48 -04:00
|
|
|
if (isPresent(typeMetadata)) {
|
2015-10-09 12:07:58 -04:00
|
|
|
var metadata = typeMetadata.find(_isDirectiveMetadata);
|
2015-10-23 02:35:53 -04:00
|
|
|
if (isPresent(metadata)) {
|
2016-03-24 16:32:47 -04:00
|
|
|
var propertyMetadata = this._reflector.propMetadata(type);
|
2015-11-04 04:08:51 -05:00
|
|
|
return this._mergeWithPropertyMetadata(metadata, propertyMetadata, type);
|
2014-11-11 20:33:47 -05:00
|
|
|
}
|
|
|
|
}
|
2015-10-23 02:35:53 -04:00
|
|
|
|
2014-11-20 15:07:48 -05:00
|
|
|
throw new BaseException(`No Directive annotation found on ${stringify(type)}`);
|
2014-11-11 20:33:47 -05:00
|
|
|
}
|
2015-09-03 18:10:48 -04:00
|
|
|
|
2016-04-12 12:40:37 -04:00
|
|
|
private _mergeWithPropertyMetadata(dm: DirectiveMetadata,
|
|
|
|
propertyMetadata: {[key: string]: any[]},
|
|
|
|
directiveType: Type): DirectiveMetadata {
|
2015-09-30 23:59:23 -04:00
|
|
|
var inputs = [];
|
|
|
|
var outputs = [];
|
2015-10-02 20:33:21 -04:00
|
|
|
var host: {[key: string]: string} = {};
|
|
|
|
var queries: {[key: string]: any} = {};
|
2015-09-03 18:10:48 -04:00
|
|
|
|
|
|
|
StringMapWrapper.forEach(propertyMetadata, (metadata: any[], propName: string) => {
|
|
|
|
metadata.forEach(a => {
|
2015-09-30 23:59:23 -04:00
|
|
|
if (a instanceof InputMetadata) {
|
2015-09-03 18:10:48 -04:00
|
|
|
if (isPresent(a.bindingPropertyName)) {
|
2015-09-30 23:59:23 -04:00
|
|
|
inputs.push(`${propName}: ${a.bindingPropertyName}`);
|
2015-09-03 18:10:48 -04:00
|
|
|
} else {
|
2015-09-30 23:59:23 -04:00
|
|
|
inputs.push(propName);
|
2015-09-03 18:10:48 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-09-30 23:59:23 -04:00
|
|
|
if (a instanceof OutputMetadata) {
|
2015-09-03 18:10:48 -04:00
|
|
|
if (isPresent(a.bindingPropertyName)) {
|
2015-09-30 23:59:23 -04:00
|
|
|
outputs.push(`${propName}: ${a.bindingPropertyName}`);
|
2015-09-03 18:10:48 -04:00
|
|
|
} else {
|
2015-09-30 23:59:23 -04:00
|
|
|
outputs.push(propName);
|
2015-09-03 18:10:48 -04:00
|
|
|
}
|
|
|
|
}
|
2015-09-04 17:07:16 -04:00
|
|
|
|
|
|
|
if (a instanceof HostBindingMetadata) {
|
|
|
|
if (isPresent(a.hostPropertyName)) {
|
|
|
|
host[`[${a.hostPropertyName}]`] = propName;
|
|
|
|
} else {
|
|
|
|
host[`[${propName}]`] = propName;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (a instanceof HostListenerMetadata) {
|
2015-09-25 15:58:00 -04:00
|
|
|
var args = isPresent(a.args) ? (<any[]>a.args).join(', ') : '';
|
2015-09-04 17:07:16 -04:00
|
|
|
host[`(${a.eventName})`] = `${propName}(${args})`;
|
|
|
|
}
|
2015-09-17 21:45:49 -04:00
|
|
|
|
|
|
|
if (a instanceof ContentChildrenMetadata) {
|
|
|
|
queries[propName] = a;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (a instanceof ViewChildrenMetadata) {
|
|
|
|
queries[propName] = a;
|
|
|
|
}
|
2015-09-19 21:39:35 -04:00
|
|
|
|
|
|
|
if (a instanceof ContentChildMetadata) {
|
|
|
|
queries[propName] = a;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (a instanceof ViewChildMetadata) {
|
|
|
|
queries[propName] = a;
|
|
|
|
}
|
2015-09-03 18:10:48 -04:00
|
|
|
});
|
|
|
|
});
|
2015-11-04 04:08:51 -05:00
|
|
|
return this._merge(dm, inputs, outputs, host, queries, directiveType);
|
2015-09-03 18:10:48 -04:00
|
|
|
}
|
|
|
|
|
2016-04-12 12:40:37 -04:00
|
|
|
private _merge(dm: DirectiveMetadata, inputs: string[], outputs: string[],
|
|
|
|
host: {[key: string]: string}, queries: {[key: string]: any},
|
|
|
|
directiveType: Type): DirectiveMetadata {
|
2015-09-30 23:59:23 -04:00
|
|
|
var mergedInputs = isPresent(dm.inputs) ? ListWrapper.concat(dm.inputs, inputs) : inputs;
|
2015-11-04 04:08:51 -05:00
|
|
|
|
|
|
|
var mergedOutputs;
|
|
|
|
if (isPresent(dm.outputs)) {
|
|
|
|
dm.outputs.forEach((propName: string) => {
|
|
|
|
if (ListWrapper.contains(outputs, propName)) {
|
|
|
|
throw new BaseException(
|
|
|
|
`Output event '${propName}' defined multiple times in '${stringify(directiveType)}'`);
|
|
|
|
}
|
|
|
|
});
|
|
|
|
mergedOutputs = ListWrapper.concat(dm.outputs, outputs);
|
|
|
|
} else {
|
|
|
|
mergedOutputs = outputs;
|
|
|
|
}
|
|
|
|
|
2015-09-04 17:07:16 -04:00
|
|
|
var mergedHost = isPresent(dm.host) ? StringMapWrapper.merge(dm.host, host) : host;
|
2015-09-17 21:45:49 -04:00
|
|
|
var mergedQueries =
|
|
|
|
isPresent(dm.queries) ? StringMapWrapper.merge(dm.queries, queries) : queries;
|
2015-09-03 18:10:48 -04:00
|
|
|
|
|
|
|
if (dm instanceof ComponentMetadata) {
|
|
|
|
return new ComponentMetadata({
|
|
|
|
selector: dm.selector,
|
2015-09-30 23:59:23 -04:00
|
|
|
inputs: mergedInputs,
|
|
|
|
outputs: mergedOutputs,
|
2015-09-04 17:07:16 -04:00
|
|
|
host: mergedHost,
|
2015-09-03 18:10:48 -04:00
|
|
|
exportAs: dm.exportAs,
|
2015-09-14 18:59:09 -04:00
|
|
|
moduleId: dm.moduleId,
|
2015-09-17 21:45:49 -04:00
|
|
|
queries: mergedQueries,
|
2015-09-03 18:10:48 -04:00
|
|
|
changeDetection: dm.changeDetection,
|
2015-10-11 01:11:13 -04:00
|
|
|
providers: dm.providers,
|
|
|
|
viewProviders: dm.viewProviders
|
2015-09-03 18:10:48 -04:00
|
|
|
});
|
|
|
|
|
|
|
|
} else {
|
|
|
|
return new DirectiveMetadata({
|
|
|
|
selector: dm.selector,
|
2015-09-30 23:59:23 -04:00
|
|
|
inputs: mergedInputs,
|
|
|
|
outputs: mergedOutputs,
|
2015-09-04 17:07:16 -04:00
|
|
|
host: mergedHost,
|
2015-09-03 18:10:48 -04:00
|
|
|
exportAs: dm.exportAs,
|
2015-10-11 01:11:13 -04:00
|
|
|
queries: mergedQueries,
|
|
|
|
providers: dm.providers
|
2015-09-03 18:10:48 -04:00
|
|
|
});
|
|
|
|
}
|
|
|
|
}
|
2014-11-11 20:33:47 -05:00
|
|
|
}
|
2015-12-02 13:35:51 -05:00
|
|
|
|
2016-03-24 16:32:47 -04:00
|
|
|
export var CODEGEN_DIRECTIVE_RESOLVER = new DirectiveResolver(reflector);
|