Index: pkg/polymer/lib/src/build/linter.dart |
diff --git a/pkg/polymer/lib/src/build/linter.dart b/pkg/polymer/lib/src/build/linter.dart |
index 3ed9c50455da8cae1410b4343960feae49510c05..6542df7b666c2cd5b1800dc324785d8bf6298757 100644 |
--- a/pkg/polymer/lib/src/build/linter.dart |
+++ b/pkg/polymer/lib/src/build/linter.dart |
@@ -16,8 +16,10 @@ import 'dart:convert' show JSON; |
import 'package:barback/barback.dart'; |
import 'package:html5lib/dom.dart'; |
import 'package:html5lib/dom_parsing.dart'; |
+import 'package:source_maps/span.dart'; |
import 'common.dart'; |
+import 'utils.dart'; |
typedef String MessageFormatter(String kind, String message, Span span); |
@@ -191,6 +193,9 @@ String consoleFormatter(String kind, String message, Span span) { |
/** |
* Information needed about other polymer-element tags in order to validate |
* how they are used and extended. |
+ * |
+ * Note: these are only created for polymer-element, because pure custom |
+ * elements don't have a declarative form. |
*/ |
class _ElementSummary { |
final String tagName; |
@@ -284,6 +289,19 @@ class _LinterVisitor extends TreeVisitor { |
node.sourceSpan); |
} |
+ var attrs = node.attributes['attributes']; |
+ if (attrs != null) { |
+ var attrsSpan = node.attributeSpans['attributes']; |
+ |
+ // names='a b c' or names='a,b,c' |
+ // record each name for publishing |
+ for (var attr in attrs.split(attrs.contains(',') ? ',' : ' ')) { |
+ // remove excess ws |
+ attr = attr.trim(); |
+ if (!_validateCustomAttributeName(attr, attrsSpan)) break; |
+ } |
+ } |
+ |
var oldValue = _inPolymerElement; |
_inPolymerElement = true; |
super.visitElement(node); |
@@ -369,10 +387,13 @@ class _LinterVisitor extends TreeVisitor { |
var info = _elements[customTagName]; |
if (info == null) { |
- _logger.warning('definition for custom element with tag name ' |
+ // TODO(jmesserly): this warning is wrong if someone is using raw custom |
+ // elements. Is there another way we can handle this warning that won't |
+ // generate false positives? |
+ _logger.warning('definition for Polymer element with tag name ' |
'"$customTagName" not found.', node.sourceSpan); |
return; |
- } |
+ } |
var baseTag = info.baseExtendsTag; |
if (baseTag != null && !hasIsAttribute) { |
@@ -384,7 +405,7 @@ class _LinterVisitor extends TreeVisitor { |
'the custom element declaration.', node.sourceSpan); |
return; |
} |
- |
+ |
if (hasIsAttribute && baseTag == null) { |
_logger.warning( |
'custom element "$customTagName" doesn\'t declare any type ' |
@@ -393,7 +414,7 @@ class _LinterVisitor extends TreeVisitor { |
'the custom element declaration.', node.sourceSpan); |
return; |
} |
- |
+ |
if (hasIsAttribute && baseTag != nodeTag) { |
_logger.warning( |
'custom element "$customTagName" extends from "$baseTag". ' |
@@ -402,6 +423,20 @@ class _LinterVisitor extends TreeVisitor { |
} |
} |
+ /** |
+ * Validate an attribute on a custom-element. Returns true if valid. |
+ */ |
+ bool _validateCustomAttributeName(String name, FileSpan span) { |
+ if (name.contains('-')) { |
+ var newName = toCamelCase(name); |
+ _logger.warning('PolymerElement no longer recognizes attribute names with ' |
+ 'dashes such as "$name". Use "$newName" or "${newName.toLowerCase()}" ' |
+ 'instead (both forms are equivalent in HTML).', span); |
+ return false; |
+ } |
+ return true; |
+ } |
+ |
/** Validate event handlers are used correctly. */ |
void _validateEventHandler(Element node, String name, String value) { |
if (!name.startsWith('on-')) { |
@@ -409,20 +444,29 @@ class _LinterVisitor extends TreeVisitor { |
' JavaScript event handler. Use the form ' |
'on-event-name="handlerName" if you want a Dart handler ' |
'that will automatically update the UI based on model changes.', |
- node.sourceSpan); |
+ node.attributeSpans[name]); |
return; |
} |
if (!_inPolymerElement) { |
_logger.warning('Inline event handlers are only supported inside ' |
- 'declarations of <polymer-element>.', node.sourceSpan); |
+ 'declarations of <polymer-element>.', node.attributeSpans[name]); |
+ } |
+ |
+ var eventName = name.substring('on-'.length); |
+ if (eventName.contains('-')) { |
+ var newEvent = toCamelCase(eventName); |
+ _logger.warning('Invalid event name "$name". After the "on-" the event ' |
+ 'name should not use dashes. For example use "on-$newEvent" or ' |
+ '"on-${newEvent.toLowerCase()}" (both forms are equivalent in HTML).', |
+ node.attributeSpans[name]); |
} |
if (value.contains('.') || value.contains('(')) { |
_logger.warning('Invalid event handler body "$value". Declare a method ' |
'in your custom element "void handlerName(event, detail, target)" ' |
'and use the form $name="handlerName".', |
- node.sourceSpan); |
+ node.attributeSpans[name]); |
} |
} |
} |