| 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); }'); |
| 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 |