| 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 | 
|---|