OLD | NEW |
---|---|
1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file |
2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
4 | 4 |
5 /// Code transform for @observable. The core transformation is relatively | 5 /// Code transform for @observable. The core transformation is relatively |
6 /// straightforward, and essentially like an editor refactoring. | 6 /// straightforward, and essentially like an editor refactoring. |
7 library observe.transformer; | 7 library observe.transformer; |
8 | 8 |
9 import 'dart:async'; | 9 import 'dart:async'; |
10 | 10 |
(...skipping 115 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
126 /// True if the node has the `@observable` or `@published` annotation. | 126 /// True if the node has the `@observable` or `@published` annotation. |
127 // TODO(jmesserly): it is not good to be hard coding Polymer support here. | 127 // TODO(jmesserly): it is not good to be hard coding Polymer support here. |
128 bool _hasObservable(AnnotatedNode node) => | 128 bool _hasObservable(AnnotatedNode node) => |
129 node.metadata.any(_isObservableAnnotation); | 129 node.metadata.any(_isObservableAnnotation); |
130 | 130 |
131 // TODO(jmesserly): this isn't correct if the annotation has been imported | 131 // TODO(jmesserly): this isn't correct if the annotation has been imported |
132 // with a prefix, or cases like that. We should technically be resolving, but | 132 // with a prefix, or cases like that. We should technically be resolving, but |
133 // that is expensive in analyzer, so it isn't feasible yet. | 133 // that is expensive in analyzer, so it isn't feasible yet. |
134 bool _isObservableAnnotation(Annotation node) => | 134 bool _isObservableAnnotation(Annotation node) => |
135 _isAnnotationContant(node, 'observable') || | 135 _isAnnotationContant(node, 'observable') || |
136 _isAnnotationContant(node, 'published') || | 136 _isAnnotationContant(node, 'published') || |
137 _isAnnotationType(node, 'ObservableProperty') || | 137 _isAnnotationType(node, 'ObservableProperty') || |
138 _isAnnotationType(node, 'PublishedProperty'); | 138 _isAnnotationType(node, 'PublishedProperty'); |
139 | 139 |
140 bool _isAnnotationContant(Annotation m, String name) => | 140 bool _isAnnotationContant(Annotation m, String name) => |
141 m.name.name == name && m.constructorName == null && m.arguments == null; | 141 m.name.name == name && m.constructorName == null && m.arguments == null; |
142 | 142 |
143 bool _isAnnotationType(Annotation m, String name) => m.name.name == name; | 143 bool _isAnnotationType(Annotation m, String name) => m.name.name == name; |
144 | 144 |
145 void _transformClass(ClassDeclaration cls, TextEditTransaction code, | 145 void _transformClass(ClassDeclaration cls, TextEditTransaction code, |
146 SourceFile file, BuildLogger logger) { | 146 SourceFile file, BuildLogger logger) { |
147 if (_hasObservable(cls)) { | 147 if (_hasObservable(cls)) { |
148 logger.warning(NO_OBSERVABLE_ON_CLASS, span: _getSpan(file, cls)); | 148 logger.warning(NO_OBSERVABLE_ON_CLASS, span: _getSpan(file, cls)); |
(...skipping 107 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
256 id is PrefixedIdentifier ? id.identifier : id; | 256 id is PrefixedIdentifier ? id.identifier : id; |
257 | 257 |
258 bool _hasKeyword(Token token, Keyword keyword) => | 258 bool _hasKeyword(Token token, Keyword keyword) => |
259 token is KeywordToken && token.keyword == keyword; | 259 token is KeywordToken && token.keyword == keyword; |
260 | 260 |
261 String _getOriginalCode(TextEditTransaction code, AstNode node) => | 261 String _getOriginalCode(TextEditTransaction code, AstNode node) => |
262 code.original.substring(node.offset, node.end); | 262 code.original.substring(node.offset, node.end); |
263 | 263 |
264 void _fixConstructor(ConstructorDeclaration ctor, TextEditTransaction code, | 264 void _fixConstructor(ConstructorDeclaration ctor, TextEditTransaction code, |
265 Set<String> changedFields) { | 265 Set<String> changedFields) { |
266 | |
267 // Fix normal initializers | 266 // Fix normal initializers |
268 for (var initializer in ctor.initializers) { | 267 for (var initializer in ctor.initializers) { |
269 if (initializer is ConstructorFieldInitializer) { | 268 if (initializer is ConstructorFieldInitializer) { |
270 var field = initializer.fieldName; | 269 var field = initializer.fieldName; |
271 if (changedFields.contains(field.name)) { | 270 if (changedFields.contains(field.name)) { |
272 code.edit(field.offset, field.end, '__\$${field.name}'); | 271 code.edit(field.offset, field.end, '__\$${field.name}'); |
273 } | 272 } |
274 } | 273 } |
275 } | 274 } |
276 | 275 |
(...skipping 108 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
385 } else { | 384 } else { |
386 beforeInit = '$metadata $type $beforeInit'; | 385 beforeInit = '$metadata $type $beforeInit'; |
387 } | 386 } |
388 | 387 |
389 code.edit(field.name.offset, field.name.end, beforeInit); | 388 code.edit(field.name.offset, field.name.end, beforeInit); |
390 | 389 |
391 // Replace comma with semicolon | 390 // Replace comma with semicolon |
392 final end = _findFieldSeperator(field.endToken.next); | 391 final end = _findFieldSeperator(field.endToken.next); |
393 if (end.type == TokenType.COMMA) code.edit(end.offset, end.end, ';'); | 392 if (end.type == TokenType.COMMA) code.edit(end.offset, end.end, ';'); |
394 | 393 |
395 code.edit(end.end, end.end, ' @reflectable set $name($type value) { ' | 394 code.edit( |
395 end.end, | |
396 end.end, | |
397 ' @reflectable set $name($type value) { ' | |
396 '__\$$name = notifyPropertyChange(#$name, __\$$name, value); }'); | 398 '__\$$name = notifyPropertyChange(#$name, __\$$name, value); }'); |
Jennifer Messerly
2016/01/22 17:45:00
this is where the generic notifyPropertyChange wou
vsm
2016/01/22 18:49:22
Acknowledged.
| |
397 } | 399 } |
398 } | 400 } |
399 | 401 |
400 Token _findFieldSeperator(Token token) { | 402 Token _findFieldSeperator(Token token) { |
401 while (token != null) { | 403 while (token != null) { |
402 if (token.type == TokenType.COMMA || token.type == TokenType.SEMICOLON) { | 404 if (token.type == TokenType.COMMA || token.type == TokenType.SEMICOLON) { |
403 break; | 405 break; |
404 } | 406 } |
405 token = token.next; | 407 token = token.next; |
406 } | 408 } |
407 return token; | 409 return token; |
408 } | 410 } |
409 | 411 |
410 // TODO(sigmund): remove hard coded Polymer support (@published). The proper way | 412 // TODO(sigmund): remove hard coded Polymer support (@published). The proper way |
411 // to do this would be to switch to use the analyzer to resolve whether | 413 // to do this would be to switch to use the analyzer to resolve whether |
412 // annotations are subtypes of ObservableProperty. | 414 // annotations are subtypes of ObservableProperty. |
413 final observableMatcher = | 415 final observableMatcher = |
414 new RegExp("@(published|observable|PublishedProperty|ObservableProperty)"); | 416 new RegExp("@(published|observable|PublishedProperty|ObservableProperty)"); |
OLD | NEW |