feat(transformers): record setters for query fields

Closes #4344
This commit is contained in:
vsavkin 2015-09-25 13:32:58 -07:00 committed by Victor Savkin
parent e7d65ad96f
commit 589ce31dfc
7 changed files with 172 additions and 2 deletions

View File

@ -2,6 +2,7 @@ library angular2.transform.bind_generator.generator;
import 'dart:async';
import 'package:analyzer/analyzer.dart';
import 'package:angular2/src/transform/common/asset_reader.dart';
import 'package:angular2/src/transform/common/ng_deps.dart';
import 'package:angular2/src/transform/common/property_utils.dart' as prop;
@ -9,6 +10,62 @@ import 'package:barback/barback.dart';
import 'visitor.dart';
class _ExtractQueryFieldsFromAnnotation extends Object
with RecursiveAstVisitor<Object> {
final ConstantEvaluator _evaluator = new ConstantEvaluator();
final List<String> queryFields = [];
@override
Object visitNamedExpression(NamedExpression node) {
if ('${node.name.label}' == "queries") {
if (node.expression is! MapLiteral) {
throw new FormatException(
'Expected a map value for "queries", but got ${node.expression}',
node.toSource());
}
MapLiteral queries = node.expression;
queryFields.addAll(queries.entries.map((e) => e.key.accept(_evaluator)));
}
return super.visitNamedExpression(node);
}
Map asMap() {
return new Map.fromIterable(queryFields, value: (_) => 'Object');
}
}
class _ExtractQueryFieldsFromPropMetadata extends Object
with RecursiveAstVisitor<Object> {
final ConstantEvaluator _evaluator = new ConstantEvaluator();
final List<String> queryFields = [];
@override
Object visitMapLiteralEntry(MapLiteralEntry node) {
if (_hasQueryAnnotation(node.value)) {
queryFields.add(node.key.accept(_evaluator));
}
return super.visitMapLiteralEntry(node);
}
bool _hasQueryAnnotation(list) {
var res = false;
list.elements.forEach((item) {
var n = item.constructorName.toString();
if(n == "ContentChild" || n == "ViewChild" || n == "ContentChildren" || n == "ViewChildren") {
res = true;
}
});
return res;
}
asMap() {
return new Map.fromIterable(queryFields, value: (_) => 'Object');
}
}
Future<String> createNgSettersAndGetters(
AssetReader reader, AssetId entryPoint) async {
NgDeps ngDeps = await NgDeps.parse(reader, entryPoint);
@ -17,6 +74,18 @@ Future<String> createNgSettersAndGetters(
var setters = _generateSetters(_createPropertiesMap(ngDeps));
var getters = _generateGetters(_createEventPropertiesList(ngDeps));
ngDeps.registeredTypes.forEach((t) {
final fromAnnotation = new _ExtractQueryFieldsFromAnnotation();
t.annotations.accept(fromAnnotation);
final fromPropMetadata = new _ExtractQueryFieldsFromPropMetadata();
if (t.propMetadata != null) {
t.propMetadata.accept(fromPropMetadata);
}
setters.addAll(_generateSetters(fromAnnotation.asMap()));
setters.addAll(_generateSetters(fromPropMetadata.asMap()));
});
if (setters.isEmpty && getters.isEmpty) return code;
var out = new StringBuffer();
var codeInjectIdx = ngDeps.registeredTypes.last.registerMethod.end;

View File

@ -26,6 +26,9 @@ class RegisteredType {
/// The annotations registered.
final Expression annotations;
/// The property metadata registered.
final Expression propMetadata;
RenderDirectiveMetadata _directiveMetadata = null;
RegisteredType._(
@ -34,7 +37,8 @@ class RegisteredType {
this.reflectionInfoCreate,
this.factoryFn,
this.parameters,
this.annotations);
this.annotations,
this.propMetadata);
/// Creates a {@link RegisteredType} given a {@link MethodInvocation} node representing
/// a call to `registerType`.
@ -42,7 +46,7 @@ class RegisteredType {
var visitor = new _ParseRegisterTypeVisitor();
registerMethod.accept(visitor);
return new RegisteredType._(visitor.typeName, registerMethod, visitor.info,
visitor.factoryFn, visitor.parameters, visitor.annotations);
visitor.factoryFn, visitor.parameters, visitor.annotations, visitor.propMetadata);
}
RenderDirectiveMetadata get directiveMetadata {
@ -68,6 +72,7 @@ class _ParseRegisterTypeVisitor extends Object
Expression factoryFn;
Expression parameters;
Expression annotations;
Expression propMetadata;
@override
Object visitMethodInvocation(MethodInvocation node) {
@ -90,6 +95,8 @@ class _ParseRegisterTypeVisitor extends Object
parameters = arg;
} else if (i == 2) {
factoryFn = arg;
} else if (i == 4) {
propMetadata = arg;
}
}

View File

@ -48,4 +48,26 @@ void allTests() {
await createNgSettersAndGetters(reader, new AssetId('a', inputPath)));
expect(output).toEqual(expected);
});
it('should generate setters for queries defined in the class annotation.',
() async {
var inputPath = 'bind_generator/queries_class_annotation_files/bar.ng_deps.dart';
var expected = formatter.format(
readFile('bind_generator/queries_class_annotation_files/expected/bar.ng_deps.dart'));
var output = formatter.format(
await createNgSettersAndGetters(reader, new AssetId('a', inputPath)));
expect(output).toEqual(expected);
});
it('should generate setters for queries defined via prop annotations.',
() async {
var inputPath = 'bind_generator/queries_prop_annotations_files/bar.ng_deps.dart';
var expected = formatter.format(
readFile('bind_generator/queries_prop_annotations_files/expected/bar.ng_deps.dart'));
var output = formatter.format(
await createNgSettersAndGetters(reader, new AssetId('a', inputPath)));
expect(output).toEqual(expected);
});
}

View File

@ -0,0 +1,18 @@
library bar.ng_deps.dart;
import 'bar.dart';
import 'package:angular2/src/core/metadata.dart';
var _visited = false;
void initReflector(reflector) {
if (_visited) return;
_visited = true;
reflector
..registerType(
ToolTip,
new ReflectionInfo(const [
const Directive(
selector: '[tool-tip]',
queries: const {'queryField': const ContentChild('child')})
], const [], () => new ToolTip()));
}

View File

@ -0,0 +1,19 @@
library bar.ng_deps.dart;
import 'bar.dart';
import 'package:angular2/src/core/metadata.dart';
var _visited = false;
void initReflector(reflector) {
if (_visited) return;
_visited = true;
reflector
..registerType(
ToolTip,
new ReflectionInfo(const [
const Directive(
selector: '[tool-tip]',
queries: const {'queryField': const ContentChild('child')})
], const [], () => new ToolTip()))
..registerSetters({'queryField': (o, v) => o.queryField = v});
}

View File

@ -0,0 +1,17 @@
library bar.ng_deps.dart;
import 'bar.dart';
import 'package:angular2/src/core/metadata.dart';
var _visited = false;
void initReflector(reflector) {
if (_visited) return;
_visited = true;
reflector
..registerType(
ToolTip,
new ReflectionInfo(const [
const Directive(
selector: '[tool-tip]')
], const [], () => new ToolTip(), null, const {'queryField': const [const ContentChild('child')]}));
}

View File

@ -0,0 +1,18 @@
library bar.ng_deps.dart;
import 'bar.dart';
import 'package:angular2/src/core/metadata.dart';
var _visited = false;
void initReflector(reflector) {
if (_visited) return;
_visited = true;
reflector
..registerType(
ToolTip,
new ReflectionInfo(const [
const Directive(
selector: '[tool-tip]')
], const [], () => new ToolTip(), null, const {'queryField': const [const ContentChild('child')]}))
..registerSetters({'queryField': (o, v) => o.queryField = v});
}