| 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 |
| 11 import 'package:analyzer/analyzer.dart'; |
| 11 import 'package:analyzer/src/generated/ast.dart'; | 12 import 'package:analyzer/src/generated/ast.dart'; |
| 12 import 'package:analyzer/src/generated/error.dart'; | 13 import 'package:analyzer/src/generated/error.dart'; |
| 13 import 'package:analyzer/src/generated/parser.dart'; | 14 import 'package:analyzer/src/generated/parser.dart'; |
| 14 import 'package:analyzer/src/generated/scanner.dart'; | 15 import 'package:analyzer/src/generated/scanner.dart'; |
| 15 import 'package:barback/barback.dart'; | 16 import 'package:barback/barback.dart'; |
| 16 import 'package:source_maps/refactor.dart'; | 17 import 'package:source_maps/refactor.dart'; |
| 17 import 'package:source_maps/span.dart' show SourceFile; | 18 import 'package:source_maps/span.dart' show SourceFile; |
| 18 | 19 |
| 19 /// A [Transformer] that replaces observables based on dirty-checking with an | 20 /// A [Transformer] that replaces observables based on dirty-checking with an |
| 20 /// implementation based on change notifications. | 21 /// implementation based on change notifications. |
| (...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 77 // TODO(sigmund): emit source maps when barback supports it (see | 78 // TODO(sigmund): emit source maps when barback supports it (see |
| 78 // dartbug.com/12340) | 79 // dartbug.com/12340) |
| 79 printer.build(url); | 80 printer.build(url); |
| 80 transform.addOutput(new Asset.fromString(id, printer.text)); | 81 transform.addOutput(new Asset.fromString(id, printer.text)); |
| 81 }); | 82 }); |
| 82 } | 83 } |
| 83 } | 84 } |
| 84 | 85 |
| 85 TextEditTransaction _transformCompilationUnit( | 86 TextEditTransaction _transformCompilationUnit( |
| 86 String inputCode, SourceFile sourceFile, TransformLogger logger) { | 87 String inputCode, SourceFile sourceFile, TransformLogger logger) { |
| 87 var unit = _parseCompilationUnit(inputCode); | 88 var unit = parseCompilationUnit(inputCode, suppressErrors: true); |
| 88 var code = new TextEditTransaction(inputCode, sourceFile); | 89 var code = new TextEditTransaction(inputCode, sourceFile); |
| 89 for (var directive in unit.directives) { | 90 for (var directive in unit.directives) { |
| 90 if (directive is LibraryDirective && _hasObservable(directive)) { | 91 if (directive is LibraryDirective && _hasObservable(directive)) { |
| 91 logger.warning('@observable on a library no longer has any effect. ' | 92 logger.warning('@observable on a library no longer has any effect. ' |
| 92 'It should be placed on individual fields.', | 93 'It should be placed on individual fields.', |
| 93 span: _getSpan(sourceFile, directive)); | 94 span: _getSpan(sourceFile, directive)); |
| 94 break; | 95 break; |
| 95 } | 96 } |
| 96 } | 97 } |
| 97 | 98 |
| 98 for (var declaration in unit.declarations) { | 99 for (var declaration in unit.declarations) { |
| 99 if (declaration is ClassDeclaration) { | 100 if (declaration is ClassDeclaration) { |
| 100 _transformClass(declaration, code, sourceFile, logger); | 101 _transformClass(declaration, code, sourceFile, logger); |
| 101 } else if (declaration is TopLevelVariableDeclaration) { | 102 } else if (declaration is TopLevelVariableDeclaration) { |
| 102 if (_hasObservable(declaration)) { | 103 if (_hasObservable(declaration)) { |
| 103 logger.warning('Top-level fields can no longer be observable. ' | 104 logger.warning('Top-level fields can no longer be observable. ' |
| 104 'Observable fields should be put in an observable objects.', | 105 'Observable fields should be put in an observable objects.', |
| 105 span: _getSpan(sourceFile, declaration)); | 106 span: _getSpan(sourceFile, declaration)); |
| 106 } | 107 } |
| 107 } | 108 } |
| 108 } | 109 } |
| 109 return code; | 110 return code; |
| 110 } | 111 } |
| 111 | 112 |
| 112 /// Parse [code] using analyzer. | |
| 113 CompilationUnit _parseCompilationUnit(String code) { | |
| 114 var errorListener = new _ErrorCollector(); | |
| 115 var reader = new CharSequenceReader(code); | |
| 116 var scanner = new Scanner(null, reader, errorListener); | |
| 117 var token = scanner.tokenize(); | |
| 118 var parser = new Parser(null, errorListener); | |
| 119 return parser.parseCompilationUnit(token); | |
| 120 } | |
| 121 | |
| 122 class _ErrorCollector extends AnalysisErrorListener { | |
| 123 final errors = <AnalysisError>[]; | |
| 124 onError(error) => errors.add(error); | |
| 125 } | |
| 126 | |
| 127 _getSpan(SourceFile file, AstNode node) => file.span(node.offset, node.end); | 113 _getSpan(SourceFile file, AstNode node) => file.span(node.offset, node.end); |
| 128 | 114 |
| 129 /// True if the node has the `@observable` or `@published` annotation. | 115 /// True if the node has the `@observable` or `@published` annotation. |
| 130 // TODO(jmesserly): it is not good to be hard coding Polymer support here. | 116 // TODO(jmesserly): it is not good to be hard coding Polymer support here. |
| 131 bool _hasObservable(AnnotatedNode node) => | 117 bool _hasObservable(AnnotatedNode node) => |
| 132 node.metadata.any(_isObservableAnnotation); | 118 node.metadata.any(_isObservableAnnotation); |
| 133 | 119 |
| 134 // TODO(jmesserly): this isn't correct if the annotation has been imported | 120 // TODO(jmesserly): this isn't correct if the annotation has been imported |
| 135 // with a prefix, or cases like that. We should technically be resolving, but | 121 // with a prefix, or cases like that. We should technically be resolving, but |
| 136 // that is expensive in analyzer, so it isn't feasible yet. | 122 // that is expensive in analyzer, so it isn't feasible yet. |
| (...skipping 290 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 427 | 413 |
| 428 Token _findFieldSeperator(Token token) { | 414 Token _findFieldSeperator(Token token) { |
| 429 while (token != null) { | 415 while (token != null) { |
| 430 if (token.type == TokenType.COMMA || token.type == TokenType.SEMICOLON) { | 416 if (token.type == TokenType.COMMA || token.type == TokenType.SEMICOLON) { |
| 431 break; | 417 break; |
| 432 } | 418 } |
| 433 token = token.next; | 419 token = token.next; |
| 434 } | 420 } |
| 435 return token; | 421 return token; |
| 436 } | 422 } |
| OLD | NEW |