| 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 /// Logic to validate that developers are correctly using Polymer constructs. | 5 /// Logic to validate that developers are correctly using Polymer constructs. |
| 6 /// This is mainly used to produce warnings for feedback in the editor. | 6 /// This is mainly used to produce warnings for feedback in the editor. |
| 7 library polymer.src.build.linter; | 7 library polymer.src.build.linter; |
| 8 | 8 |
| 9 import 'dart:async'; | 9 import 'dart:async'; |
| 10 import 'dart:convert'; | 10 import 'dart:convert'; |
| (...skipping 151 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 162 | 162 |
| 163 _ElementSummary(this.tagName, this.extendsTag, this.span); | 163 _ElementSummary(this.tagName, this.extendsTag, this.span); |
| 164 | 164 |
| 165 String toString() => "($tagName <: $extendsTag)"; | 165 String toString() => "($tagName <: $extendsTag)"; |
| 166 } | 166 } |
| 167 | 167 |
| 168 class _LinterVisitor extends TreeVisitor { | 168 class _LinterVisitor extends TreeVisitor { |
| 169 BuildLogger _logger; | 169 BuildLogger _logger; |
| 170 AssetId _sourceId; | 170 AssetId _sourceId; |
| 171 bool _inPolymerElement = false; | 171 bool _inPolymerElement = false; |
| 172 bool _inAutoBindingElement = false; |
| 172 bool _dartTagSeen = false; | 173 bool _dartTagSeen = false; |
| 173 bool _polymerHtmlSeen = false; | 174 bool _polymerHtmlSeen = false; |
| 174 bool _polymerExperimentalHtmlSeen = false; | 175 bool _polymerExperimentalHtmlSeen = false; |
| 175 bool _isEntryPoint; | 176 bool _isEntryPoint; |
| 176 Map<String, _ElementSummary> _elements; | 177 Map<String, _ElementSummary> _elements; |
| 177 | 178 |
| 178 _LinterVisitor( | 179 _LinterVisitor( |
| 179 this._sourceId, this._logger, this._elements, this._isEntryPoint) { | 180 this._sourceId, this._logger, this._elements, this._isEntryPoint) { |
| 180 // We normalize the map, so each element has a direct reference to any | 181 // We normalize the map, so each element has a direct reference to any |
| 181 // element it extends from. | 182 // element it extends from. |
| 182 for (var tag in _elements.values) { | 183 for (var tag in _elements.values) { |
| 183 var extendsTag = tag.extendsTag; | 184 var extendsTag = tag.extendsTag; |
| 184 if (extendsTag == null) continue; | 185 if (extendsTag == null) continue; |
| 185 tag.extendsType = _elements[extendsTag]; | 186 tag.extendsType = _elements[extendsTag]; |
| 186 } | 187 } |
| 187 } | 188 } |
| 188 | 189 |
| 189 void visitElement(Element node) { | 190 void visitElement(Element node) { |
| 190 switch (node.localName) { | 191 switch (node.localName) { |
| 191 case 'link': _validateLinkElement(node); break; | 192 case 'link': _validateLinkElement(node); break; |
| 192 case 'element': _validateElementElement(node); break; | 193 case 'element': _validateElementElement(node); break; |
| 193 case 'polymer-element': _validatePolymerElement(node); break; | 194 case 'polymer-element': _validatePolymerElement(node); break; |
| 194 case 'script': _validateScriptElement(node); break; | 195 case 'script': _validateScriptElement(node); break; |
| 196 case 'template': |
| 197 var isTag = node.attributes['is']; |
| 198 if (isTag != null && AUTO_BINDING_ELEMENTS.contains(isTag)) { |
| 199 _inAutoBindingElement = true; |
| 200 } |
| 201 _validateNormalElement(node); |
| 202 super.visitElement(node); |
| 203 _inAutoBindingElement = false; |
| 204 break; |
| 195 default: | 205 default: |
| 196 _validateNormalElement(node); | 206 _validateNormalElement(node); |
| 197 super.visitElement(node); | 207 super.visitElement(node); |
| 198 break; | 208 break; |
| 199 } | 209 } |
| 200 } | 210 } |
| 201 | 211 |
| 202 void run(Document doc) { | 212 void run(Document doc) { |
| 203 visit(doc); | 213 visit(doc); |
| 204 | 214 |
| 205 if (_isEntryPoint && !_dartTagSeen && !_polymerExperimentalHtmlSeen) { | 215 if (_isEntryPoint && !_dartTagSeen && !_polymerExperimentalHtmlSeen) { |
| 206 _logger.warning(MISSING_INIT_POLYMER, span: doc.body.sourceSpan); | 216 _logger.warning(MISSING_INIT_POLYMER, span: doc.body.sourceSpan); |
| 207 } | 217 } |
| 208 } | 218 } |
| (...skipping 193 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 402 {'name': name, 'alternative': alternative}), span: span); | 412 {'name': name, 'alternative': alternative}), span: span); |
| 403 return false; | 413 return false; |
| 404 } | 414 } |
| 405 return true; | 415 return true; |
| 406 } | 416 } |
| 407 | 417 |
| 408 /// Validate event handlers are used correctly. | 418 /// Validate event handlers are used correctly. |
| 409 void _validateEventHandler(Element node, String name, String value) { | 419 void _validateEventHandler(Element node, String name, String value) { |
| 410 if (!name.startsWith('on-')) return; | 420 if (!name.startsWith('on-')) return; |
| 411 | 421 |
| 412 if (!_inPolymerElement) { | 422 if (!_inPolymerElement && !_inAutoBindingElement) { |
| 413 _logger.warning(EVENT_HANDLERS_ONLY_WITHIN_POLYMER, | 423 _logger.warning(EVENT_HANDLERS_ONLY_WITHIN_POLYMER, |
| 414 span: node.attributeSpans[name]); | 424 span: node.attributeSpans[name]); |
| 415 return; | 425 return; |
| 416 } | 426 } |
| 417 | 427 |
| 418 | 428 |
| 419 // Valid bindings have {{ }}, don't look like method calls foo(bar), and are | 429 // Valid bindings have {{ }}, don't look like method calls foo(bar), and are |
| 420 // non empty. | 430 // non empty. |
| 421 if (!value.startsWith("{{") || !value.endsWith("}}") || value.contains('(') | 431 if (!value.startsWith("{{") || !value.endsWith("}}") || value.contains('(') |
| 422 || value.substring(2, value.length - 2).trim() == '') { | 432 || value.substring(2, value.length - 2).trim() == '') { |
| (...skipping 13 matching lines...) Expand all Loading... |
| 436 } else if (segments.length > 2) { | 446 } else if (segments.length > 2) { |
| 437 // web/a/foo.html => ../packages/ | 447 // web/a/foo.html => ../packages/ |
| 438 upDirCount = segments.length - 2; | 448 upDirCount = segments.length - 2; |
| 439 } | 449 } |
| 440 var reachOutPrefix = '../' * upDirCount; | 450 var reachOutPrefix = '../' * upDirCount; |
| 441 return USE_POLYMER_HTML.create({'reachOutPrefix': reachOutPrefix}); | 451 return USE_POLYMER_HTML.create({'reachOutPrefix': reachOutPrefix}); |
| 442 } | 452 } |
| 443 | 453 |
| 444 const List<String> INTERNALLY_DEFINED_ELEMENTS = | 454 const List<String> INTERNALLY_DEFINED_ELEMENTS = |
| 445 const ['auto-binding-dart', 'polymer-element']; | 455 const ['auto-binding-dart', 'polymer-element']; |
| 456 const List<String> AUTO_BINDING_ELEMENTS = |
| 457 const ['auto-binding-dart', 'auto-binding']; |
| OLD | NEW |