fix(transformer): Add getters for events.

closes https://github.com/angular/angular/issues/2725
This commit is contained in:
Jacob MacDonald
2015-06-25 07:29:20 -07:00
parent d037c082fb
commit 5a21dc5340
6 changed files with 118 additions and 18 deletions

View File

@ -9,22 +9,32 @@ import 'package:barback/barback.dart';
import 'visitor.dart';
Future<String> createNgSetters(AssetReader reader, AssetId entryPoint) async {
Future<String> createNgSettersAndGetters(
AssetReader reader, AssetId entryPoint) async {
NgDeps ngDeps = await NgDeps.parse(reader, entryPoint);
String code = ngDeps.code;
var setters = _generateSetters(_createBindMap(ngDeps));
var setters = _generateSetters(_createPropertiesMap(ngDeps));
var getters = _generateGetters(_createEventsMap(ngDeps));
if (setters.length == 0) return code;
if (setters.isEmpty && getters.isEmpty) return code;
var out = new StringBuffer();
var codeInjectIdx = ngDeps.registeredTypes.last.registerMethod.end;
return '${code.substring(0, codeInjectIdx)}'
'..registerSetters({${setters.join(', ')}})'
'${code.substring(codeInjectIdx)}';
out.write(code.substring(0, codeInjectIdx));
if (setters.isNotEmpty) {
out.write('..registerSetters({${setters.join(', ')}})');
}
if (getters.isNotEmpty) {
out.write('..registerGetters({${getters.join(', ')}})');
}
out.write(code.substring(codeInjectIdx));
return '$out';
}
// TODO(kegluneq): De-dupe from template_compiler/generator.dart.
/// Consumes the map generated by {@link _createBindMap} to codegen setters.
/// Consumes the map generated by {@link _createPropertiesMap} to codegen
/// setters.
List<String> _generateSetters(Map<String, String> bindMap) {
var setters = [];
// TODO(kegluneq): Include types for receivers. See #886.
@ -43,8 +53,8 @@ List<String> _generateSetters(Map<String, String> bindMap) {
/// Collapses all `properties` in {@link ngDeps} into a map where the keys are
/// the bind properties and the values are either the one and only type
/// binding to that property or the empty string.
Map<String, String> _createBindMap(NgDeps ngDeps) {
var visitor = new ExtractSettersVisitor();
Map<String, String> _createPropertiesMap(NgDeps ngDeps) {
var visitor = new ExtractNamedExpressionVisitor('properties');
var bindMap = {};
ngDeps.registeredTypes.forEach((RegisteredType t) {
visitor.bindConfig.clear();
@ -68,3 +78,37 @@ Map<String, String> _createBindMap(NgDeps ngDeps) {
});
return bindMap;
}
/// Consumes the map generated by {@link _createEventsMap} to codegen getters.
List<String> _generateGetters(Map<String, String> bindMap) {
var getters = [];
// TODO(kegluneq): Include types for receivers. See #886.
bindMap.forEach((getterName, eventName) {
if (!prop.isValid(eventName)) {
// TODO(kegluenq): Eagerly throw here once #1295 is addressed.
getters.add(prop.lazyInvalidGetter(eventName));
} else {
getters.add(''' '${prop.sanitize(eventName)}': (o) => o.$getterName''');
}
});
return getters;
}
/// Collapses all `events` in {@link ngDeps} into a map where the keys are
/// the property names for the event emitters and the values are the event name.
Map<String, String> _createEventsMap(NgDeps ngDeps) {
var visitor = new ExtractNamedExpressionVisitor('events');
var bindMap = {};
ngDeps.registeredTypes.forEach((RegisteredType t) {
visitor.bindConfig.clear();
t.annotations.accept(visitor);
visitor.bindConfig.forEach((String config) {
// See comments for `Directive` in annotations_impl/annotations.ts for
// details on how `events` is specified.
var parts = config.split(':').map((p) => p.trim()).toList();
bindMap[parts[0]] = parts.length > 1 ? parts[1] : parts[0];
});
});
return bindMap;
}

View File

@ -31,11 +31,11 @@ class BindGenerator extends Transformer {
try {
var id = transform.primaryInput.id;
var reader = new AssetReader.fromTransform(transform);
var transformedCode = await createNgSetters(reader, id);
var transformedCode = await createNgSettersAndGetters(reader, id);
transform.addOutput(new Asset.fromString(
id, formatter.format(transformedCode, uri: id.path)));
} catch (ex, stackTrace) {
log.logger.error('Creating ng setters failed.\n'
log.logger.error('Creating ng setters/getters failed.\n'
'Exception: $ex\n'
'Stack Trace: $stackTrace');
}

View File

@ -6,18 +6,22 @@ import 'package:angular2/src/transform/common/logging.dart';
/// Visitor responsible for crawling the "annotations" value in a
/// `registerType` call and pulling out the properties of any "bind"
/// values found.
class ExtractSettersVisitor extends Object with RecursiveAstVisitor<Object> {
class ExtractNamedExpressionVisitor extends Object with
RecursiveAstVisitor<Object> {
final ConstantEvaluator _evaluator = new ConstantEvaluator();
final List<String> bindConfig = [];
final String nameToExtract;
ExtractNamedExpressionVisitor(this.nameToExtract);
@override
Object visitNamedExpression(NamedExpression node) {
if ('${node.name.label}' == 'properties') {
if ('${node.name.label}' == nameToExtract) {
var evaluated = node.expression.accept(_evaluator);
if (evaluated is List) {
bindConfig.addAll(evaluated);
} else {
logger.error('`properties` currently only supports List values');
logger.error('`$nameToExtract` currently only supports List values');
}
return null;
}