fix(transformers): Fix @Input/@Output annotations with setters/getters

Fix @Input annotations to work with setter methods in dart, and fix @Output
annotations to work with getter methods in Dart when using transformers.

Closes #5251

Closes #5259
This commit is contained in:
Ted Sander 2015-11-12 12:34:32 -08:00
parent 7f6289c1bf
commit d9f362a713
3 changed files with 45 additions and 29 deletions

View File

@ -232,21 +232,11 @@ class _DirectiveMetadataVisitor extends Object
for (var variable in node.fields.variables) { for (var variable in node.fields.variables) {
for (var meta in node.metadata) { for (var meta in node.metadata) {
if (_isAnnotation(meta, 'Output')) { if (_isAnnotation(meta, 'Output')) {
final renamed = _getRenamedValue(meta); _addPropertyToType(_outputs, variable.name.toString(), meta);
if (renamed != null) {
_outputs.add('${variable.name}: ${renamed}');
} else {
_outputs.add('${variable.name}');
}
} }
if (_isAnnotation(meta, 'Input')) { if (_isAnnotation(meta, 'Input')) {
final renamed = _getRenamedValue(meta); _addPropertyToType(_inputs, variable.name.toString(), meta);
if (renamed != null) {
_inputs.add('${variable.name}: ${renamed}');
} else {
_inputs.add('${variable.name}');
}
} }
if (_isAnnotation(meta, 'HostBinding')) { if (_isAnnotation(meta, 'HostBinding')) {
@ -265,6 +255,14 @@ class _DirectiveMetadataVisitor extends Object
@override @override
Object visitMethodDeclaration(MethodDeclaration node) { Object visitMethodDeclaration(MethodDeclaration node) {
for (var meta in node.metadata) { for (var meta in node.metadata) {
if (_isAnnotation(meta, 'Output') && node.isGetter) {
_addPropertyToType(_outputs, node.name.toString(), meta);
}
if (_isAnnotation(meta, 'Input') && node.isSetter) {
_addPropertyToType(_inputs, node.name.toString(), meta);
}
if (_isAnnotation(meta, 'HostListener')) { if (_isAnnotation(meta, 'HostListener')) {
if (meta.arguments.arguments.length == 0 || if (meta.arguments.arguments.length == 0 ||
meta.arguments.arguments.length > 2) { meta.arguments.arguments.length > 2) {
@ -280,6 +278,15 @@ class _DirectiveMetadataVisitor extends Object
return null; return null;
} }
void _addPropertyToType(List type, String name, Annotation meta) {
final renamed = _getRenamedValue(meta);
if (renamed != null) {
type.add('${name}: ${renamed}');
} else {
type.add('${name}');
}
}
//TODO Use AnnotationMatcher instead of string matching //TODO Use AnnotationMatcher instead of string matching
bool _isAnnotation(Annotation node, String annotationName) { bool _isAnnotation(Annotation node, String annotationName) {
var id = node.name; var id = node.name;

View File

@ -498,14 +498,14 @@ void allTests() {
it('should merge `outputs` from the annotation and fields.', () async { it('should merge `outputs` from the annotation and fields.', () async {
var model = await _testCreateModel('directives_files/components.dart'); var model = await _testCreateModel('directives_files/components.dart');
expect(model.types['ComponentWithOutputs'].outputs) expect(model.types['ComponentWithOutputs'].outputs).toEqual(
.toEqual({'a': 'a', 'b': 'b', 'c': 'renamed'}); {'a': 'a', 'b': 'b', 'c': 'renamed', 'd': 'd', 'e': 'get-renamed'});
}); });
it('should merge `inputs` from the annotation and fields.', () async { it('should merge `inputs` from the annotation and fields.', () async {
var model = await _testCreateModel('directives_files/components.dart'); var model = await _testCreateModel('directives_files/components.dart');
expect(model.types['ComponentWithInputs'].inputs) expect(model.types['ComponentWithInputs'].inputs).toEqual(
.toEqual({'a': 'a', 'b': 'b', 'c': 'renamed'}); {'a': 'a', 'b': 'b', 'c': 'renamed', 'd': 'd', 'e': 'set-renamed'});
}); });
it('should merge host bindings from the annotation and fields.', () async { it('should merge host bindings from the annotation and fields.', () async {

View File

@ -22,30 +22,41 @@ class ComponentOnly {}
@Component( @Component(
selector: 'component-with-outputs', selector: 'component-with-outputs',
template: '<dep1></dep1><dep2></dep2>', template: '<dep1></dep1><dep2></dep2>',
outputs: ['a'] outputs: ['a'])
)
class ComponentWithOutputs { class ComponentWithOutputs {
@Output() Object b; @Output() Object b;
@Output('renamed') Object c; @Output('renamed') Object c;
Object _d;
@Output() Object get d => _d;
Object _e;
@Output('get-renamed') Object get e => _e;
} }
@Component( @Component(
selector: 'component-with-inputs', selector: 'component-with-inputs',
template: '<dep1></dep1><dep2></dep2>', template: '<dep1></dep1><dep2></dep2>',
inputs: ['a'] inputs: ['a'])
)
class ComponentWithInputs { class ComponentWithInputs {
@Input() Object b; @Input() Object b;
@Input('renamed') Object c; @Input('renamed') Object c;
Object _d;
@Input() void set d(Object value) {
_d = value;
}
Object _e;
@Input('set-renamed') void set e(Object value) {
_e = value;
}
} }
@Component( @Component(
selector: 'component-with-inputs', selector: 'component-with-inputs',
template: '<dep1></dep1><dep2></dep2>', template: '<dep1></dep1><dep2></dep2>',
host: { host: {'[a]': 'a'})
'[a]':'a'
}
)
class ComponentWithHostBindings { class ComponentWithHostBindings {
@HostBinding() Object b; @HostBinding() Object b;
@HostBinding('renamed') Object c; @HostBinding('renamed') Object c;
@ -54,11 +65,9 @@ class ComponentWithHostBindings {
@Component( @Component(
selector: 'component-with-inputs', selector: 'component-with-inputs',
template: '<dep1></dep1><dep2></dep2>', template: '<dep1></dep1><dep2></dep2>',
host: { host: {'(a)': 'onA()'})
'(a)':'onA()'
}
)
class ComponentWithHostListeners { class ComponentWithHostListeners {
@HostListener('b') void onB() {} @HostListener('b') void onB() {}
@HostListener('c', ['\$event.target', '\$event.target.value']) void onC(t,v) {} @HostListener('c', ['\$event.target', '\$event.target.value']) void onC(
t, v) {}
} }