| 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 /** | 5 /** |
| 6 * Logic to validate that developers are correctly using Polymer constructs. | 6 * Logic to validate that developers are correctly using Polymer constructs. |
| 7 * This is mainly used to produce warnings for feedback in the editor. | 7 * This is mainly used to produce warnings for feedback in the editor. |
| 8 */ | 8 */ |
| 9 library polymer.src.linter; | 9 library polymer.src.linter; |
| 10 | 10 |
| 11 import 'dart:io'; |
| 11 import 'dart:async'; | 12 import 'dart:async'; |
| 12 import 'dart:mirrors'; | 13 import 'dart:mirrors'; |
| 13 import 'dart:convert' show JSON; | 14 import 'dart:convert' show JSON; |
| 14 | 15 |
| 15 import 'package:barback/barback.dart'; | 16 import 'package:barback/barback.dart'; |
| 16 import 'package:html5lib/dom.dart'; | 17 import 'package:html5lib/dom.dart'; |
| 17 import 'package:html5lib/dom_parsing.dart'; | 18 import 'package:html5lib/dom_parsing.dart'; |
| 18 | 19 |
| 19 import 'transform/common.dart'; | 20 import 'transform/common.dart'; |
| 20 | 21 |
| 21 typedef String MessageFormatter(String kind, String message, Span span); | 22 typedef String MessageFormatter(String kind, String message, Span span); |
| 22 | 23 |
| 23 /** | 24 /** |
| 24 * A linter that checks for common Polymer errors and produces warnings to | 25 * A linter that checks for common Polymer errors and produces warnings to |
| 25 * show on the editor or the command line. Leaves sources unchanged, but creates | 26 * show on the editor or the command line. Leaves sources unchanged, but creates |
| 26 * a new asset containing all the warnings. | 27 * a new asset containing all the warnings. |
| 27 */ | 28 */ |
| 28 class Linter extends Transformer { | 29 class Linter extends Transformer with PolymerTransformer { |
| 30 final TransformOptions options; |
| 31 |
| 29 /** Only run on .html files. */ | 32 /** Only run on .html files. */ |
| 30 final String allowedExtensions = '.html'; | 33 final String allowedExtensions = '.html'; |
| 31 | 34 |
| 32 final MessageFormatter _formatter; | 35 final MessageFormatter _formatter; |
| 33 | 36 |
| 34 Linter([this._formatter]); | 37 Linter(this.options, [this._formatter]); |
| 35 | 38 |
| 36 Future apply(Transform transform) { | 39 Future apply(Transform transform) { |
| 37 var wrapper = new _LoggerInterceptor(transform, _formatter); | 40 var wrapper = new _LoggerInterceptor(transform, _formatter); |
| 38 var seen = new Set<AssetId>(); | 41 var seen = new Set<AssetId>(); |
| 39 var primary = transform.primaryInput; | 42 var primary = transform.primaryInput; |
| 40 var id = primary.id; | 43 var id = primary.id; |
| 41 wrapper.addOutput(primary); // this phase is analysis only | 44 wrapper.addOutput(primary); // this phase is analysis only |
| 42 seen.add(id); | 45 seen.add(id); |
| 43 return readPrimaryAsHtml(wrapper).then((document) { | 46 return readPrimaryAsHtml(wrapper).then((document) { |
| 44 return _collectElements(document, id, wrapper, seen).then((elements) { | 47 return _collectElements(document, id, wrapper, seen).then((elements) { |
| (...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 113 | 116 |
| 114 /** A proxy of [Transform] that returns a different logger. */ | 117 /** A proxy of [Transform] that returns a different logger. */ |
| 115 // TODO(sigmund): get rid of this when barback supports a better way to log | 118 // TODO(sigmund): get rid of this when barback supports a better way to log |
| 116 // messages without printing them. | 119 // messages without printing them. |
| 117 class _LoggerInterceptor implements Transform, TransformLogger { | 120 class _LoggerInterceptor implements Transform, TransformLogger { |
| 118 final Transform _original; | 121 final Transform _original; |
| 119 final List<String> _messages = []; | 122 final List<String> _messages = []; |
| 120 final MessageFormatter _formatter; | 123 final MessageFormatter _formatter; |
| 121 | 124 |
| 122 _LoggerInterceptor(this._original, MessageFormatter formatter) | 125 _LoggerInterceptor(this._original, MessageFormatter formatter) |
| 123 : _formatter = formatter == null ? _defaultFormatter : formatter; | 126 : _formatter = formatter == null ? consoleFormatter : formatter; |
| 124 | 127 |
| 125 TransformLogger get logger => this; | 128 TransformLogger get logger => this; |
| 126 | 129 |
| 127 noSuchMethod(Invocation m) => reflect(_original).delegate(m); | 130 noSuchMethod(Invocation m) => reflect(_original).delegate(m); |
| 128 | 131 |
| 129 // form TransformLogger: | 132 // form TransformLogger: |
| 130 void warning(String message, [Span span]) => _write('warning', message, span); | 133 void warning(String message, [Span span]) => _write('warning', message, span); |
| 131 | 134 |
| 132 void error(String message, [Span span]) => _write('error', message, span); | 135 void error(String message, [Span span]) => _write('error', message, span); |
| 133 | 136 |
| 134 void _write(String kind, String message, Span span) { | 137 void _write(String kind, String message, Span span) { |
| 135 _messages.add(_formatter(kind, message, span)); | 138 _messages.add(_formatter(kind, message, span)); |
| 136 } | 139 } |
| 137 } | 140 } |
| 138 | 141 |
| 139 /** | 142 /** |
| 140 * Default formatter that generates messages using a format that can be parsed | 143 * Formatter that generates messages using a format that can be parsed |
| 141 * by tools, such as the Dart Editor, for reporting error messages. | 144 * by tools, such as the Dart Editor, for reporting error messages. |
| 142 */ | 145 */ |
| 143 String _defaultFormatter(String kind, String message, Span span) { | 146 String jsonFormatter(String kind, String message, Span span) { |
| 144 return JSON.encode((span == null) | 147 return JSON.encode((span == null) |
| 145 ? [{'method': 'warning', 'params': {'message': message}}] | 148 ? [{'method': 'warning', 'params': {'message': message}}] |
| 146 : [{'method': kind, | 149 : [{'method': kind, |
| 147 'params': { | 150 'params': { |
| 148 'file': span.sourceUrl, | 151 'file': span.sourceUrl, |
| 149 'message': message, | 152 'message': message, |
| 150 'line': span.start.line + 1, | 153 'line': span.start.line + 1, |
| 151 'charStart': span.start.offset, | 154 'charStart': span.start.offset, |
| 152 'charEnd': span.end.offset, | 155 'charEnd': span.end.offset, |
| 153 }}]); | 156 }}]); |
| 154 } | 157 } |
| 155 | 158 |
| 159 /** |
| 160 * Formatter that generates messages that are easy to read on the console (used |
| 161 * by default). |
| 162 */ |
| 163 String consoleFormatter(String kind, String message, Span span) { |
| 164 var useColors = stdioType(stdout) == StdioType.TERMINAL; |
| 165 var levelColor = (kind == 'error') ? _RED_COLOR : _MAGENTA_COLOR; |
| 166 var output = new StringBuffer(); |
| 167 if (useColors) output.write(levelColor); |
| 168 output..write(kind)..write(' '); |
| 169 if (useColors) output.write(_NO_COLOR); |
| 170 if (span == null) { |
| 171 output.write(message); |
| 172 } else { |
| 173 output.write(span.getLocationMessage(message, |
| 174 useColors: useColors, |
| 175 color: levelColor)); |
| 176 } |
| 177 return output.toString(); |
| 178 } |
| 156 | 179 |
| 157 /** | 180 /** |
| 158 * Information needed about other polymer-element tags in order to validate | 181 * Information needed about other polymer-element tags in order to validate |
| 159 * how they are used and extended. | 182 * how they are used and extended. |
| 160 */ | 183 */ |
| 161 class _ElementSummary { | 184 class _ElementSummary { |
| 162 final String tagName; | 185 final String tagName; |
| 163 final String extendsTag; | 186 final String extendsTag; |
| 164 final Span span; | 187 final Span span; |
| 165 | 188 |
| (...skipping 242 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 408 }; | 431 }; |
| 409 | 432 |
| 410 /** | 433 /** |
| 411 * Returns true if this is a valid custom element name. See: | 434 * Returns true if this is a valid custom element name. See: |
| 412 * <https://dvcs.w3.org/hg/webcomponents/raw-file/tip/spec/custom/index.html#dfn
-custom-element-name> | 435 * <https://dvcs.w3.org/hg/webcomponents/raw-file/tip/spec/custom/index.html#dfn
-custom-element-name> |
| 413 */ | 436 */ |
| 414 bool _isCustomTag(String name) { | 437 bool _isCustomTag(String name) { |
| 415 if (name == null || !name.contains('-')) return false; | 438 if (name == null || !name.contains('-')) return false; |
| 416 return !_invalidTagNames.containsKey(name); | 439 return !_invalidTagNames.containsKey(name); |
| 417 } | 440 } |
| 441 |
| 442 final String _RED_COLOR = '\u001b[31m'; |
| 443 final String _MAGENTA_COLOR = '\u001b[35m'; |
| 444 final String _NO_COLOR = '\u001b[0m'; |
| OLD | NEW |