Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(87)

Side by Side Diff: pkg/polymer/lib/src/build/linter.dart

Issue 24149003: Port of github.com/polymer/polymer. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: rebase Created 7 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « pkg/polymer/lib/polymer_element.dart ('k') | pkg/polymer/lib/src/build/runner.dart » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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.build.linter; 9 library polymer.src.build.linter;
10 10
11 import 'dart:io'; 11 import 'dart:io';
12 import 'dart:async'; 12 import 'dart:async';
13 import 'dart:mirrors'; 13 import 'dart:mirrors';
14 import 'dart:convert' show JSON; 14 import 'dart:convert' show JSON;
15 15
16 import 'package:barback/barback.dart'; 16 import 'package:barback/barback.dart';
17 import 'package:html5lib/dom.dart'; 17 import 'package:html5lib/dom.dart';
18 import 'package:html5lib/dom_parsing.dart'; 18 import 'package:html5lib/dom_parsing.dart';
19 import 'package:source_maps/span.dart';
19 20
20 import 'common.dart'; 21 import 'common.dart';
22 import 'utils.dart';
21 23
22 typedef String MessageFormatter(String kind, String message, Span span); 24 typedef String MessageFormatter(String kind, String message, Span span);
23 25
24 /** 26 /**
25 * A linter that checks for common Polymer errors and produces warnings to 27 * A linter that checks for common Polymer errors and produces warnings to
26 * show on the editor or the command line. Leaves sources unchanged, but creates 28 * show on the editor or the command line. Leaves sources unchanged, but creates
27 * a new asset containing all the warnings. 29 * a new asset containing all the warnings.
28 */ 30 */
29 class Linter extends Transformer with PolymerTransformer { 31 class Linter extends Transformer with PolymerTransformer {
30 final TransformOptions options; 32 final TransformOptions options;
(...skipping 153 matching lines...) Expand 10 before | Expand all | Expand 10 after
184 output.write(span.getLocationMessage(message, 186 output.write(span.getLocationMessage(message,
185 useColors: useColors, 187 useColors: useColors,
186 color: levelColor)); 188 color: levelColor));
187 } 189 }
188 return output.toString(); 190 return output.toString();
189 } 191 }
190 192
191 /** 193 /**
192 * Information needed about other polymer-element tags in order to validate 194 * Information needed about other polymer-element tags in order to validate
193 * how they are used and extended. 195 * how they are used and extended.
196 *
197 * Note: these are only created for polymer-element, because pure custom
198 * elements don't have a declarative form.
194 */ 199 */
195 class _ElementSummary { 200 class _ElementSummary {
196 final String tagName; 201 final String tagName;
197 final String extendsTag; 202 final String extendsTag;
198 final Span span; 203 final Span span;
199 204
200 _ElementSummary extendsType; 205 _ElementSummary extendsType;
201 bool hasConflict = false; 206 bool hasConflict = false;
202 207
203 String get baseExtendsTag => extendsType == null 208 String get baseExtendsTag => extendsType == null
(...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after
277 'at least one dash and can\'t be any of the following names: ' 282 'at least one dash and can\'t be any of the following names: '
278 '${_invalidTagNames.keys.join(", ")}.', 283 '${_invalidTagNames.keys.join(", ")}.',
279 node.sourceSpan); 284 node.sourceSpan);
280 } 285 }
281 286
282 if (_elements[extendsTag] == null && _isCustomTag(extendsTag)) { 287 if (_elements[extendsTag] == null && _isCustomTag(extendsTag)) {
283 _logger.warning('custom element with name "$extendsTag" not found.', 288 _logger.warning('custom element with name "$extendsTag" not found.',
284 node.sourceSpan); 289 node.sourceSpan);
285 } 290 }
286 291
292 var attrs = node.attributes['attributes'];
293 if (attrs != null) {
294 var attrsSpan = node.attributeSpans['attributes'];
295
296 // names='a b c' or names='a,b,c'
297 // record each name for publishing
298 for (var attr in attrs.split(attrs.contains(',') ? ',' : ' ')) {
299 // remove excess ws
300 attr = attr.trim();
301 if (!_validateCustomAttributeName(attr, attrsSpan)) break;
302 }
303 }
304
287 var oldValue = _inPolymerElement; 305 var oldValue = _inPolymerElement;
288 _inPolymerElement = true; 306 _inPolymerElement = true;
289 super.visitElement(node); 307 super.visitElement(node);
290 _inPolymerElement = oldValue; 308 _inPolymerElement = oldValue;
291 } 309 }
292 310
293 /** 311 /**
294 * Produces warnings for malformed script tags. In html5 leaving off type= is 312 * Produces warnings for malformed script tags. In html5 leaving off type= is
295 * fine, but it defaults to text/javascript. Because this might be a common 313 * fine, but it defaults to text/javascript. Because this might be a common
296 * error, we warn about it when src file ends in .dart, but the type is 314 * error, we warn about it when src file ends in .dart, but the type is
(...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after
362 } else { 380 } else {
363 // <button is="fancy-button"> 381 // <button is="fancy-button">
364 customTagName = node.attributes['is']; 382 customTagName = node.attributes['is'];
365 hasIsAttribute = true; 383 hasIsAttribute = true;
366 } 384 }
367 385
368 if (customTagName == null || customTagName == 'polymer-element') return; 386 if (customTagName == null || customTagName == 'polymer-element') return;
369 387
370 var info = _elements[customTagName]; 388 var info = _elements[customTagName];
371 if (info == null) { 389 if (info == null) {
372 _logger.warning('definition for custom element with tag name ' 390 // TODO(jmesserly): this warning is wrong if someone is using raw custom
391 // elements. Is there another way we can handle this warning that won't
392 // generate false positives?
393 _logger.warning('definition for Polymer element with tag name '
373 '"$customTagName" not found.', node.sourceSpan); 394 '"$customTagName" not found.', node.sourceSpan);
374 return; 395 return;
375 } 396 }
376 397
377 var baseTag = info.baseExtendsTag; 398 var baseTag = info.baseExtendsTag;
378 if (baseTag != null && !hasIsAttribute) { 399 if (baseTag != null && !hasIsAttribute) {
379 _logger.warning( 400 _logger.warning(
380 'custom element "$customTagName" extends from "$baseTag", but ' 401 'custom element "$customTagName" extends from "$baseTag", but '
381 'this tag will not include the default properties of "$baseTag". ' 402 'this tag will not include the default properties of "$baseTag". '
382 'To fix this, either write this tag as <$baseTag ' 403 'To fix this, either write this tag as <$baseTag '
383 'is="$customTagName"> or remove the "extends" attribute from ' 404 'is="$customTagName"> or remove the "extends" attribute from '
384 'the custom element declaration.', node.sourceSpan); 405 'the custom element declaration.', node.sourceSpan);
385 return; 406 return;
386 } 407 }
387 408
388 if (hasIsAttribute && baseTag == null) { 409 if (hasIsAttribute && baseTag == null) {
389 _logger.warning( 410 _logger.warning(
390 'custom element "$customTagName" doesn\'t declare any type ' 411 'custom element "$customTagName" doesn\'t declare any type '
391 'extensions. To fix this, either rewrite this tag as ' 412 'extensions. To fix this, either rewrite this tag as '
392 '<$customTagName> or add \'extends="$nodeTag"\' to ' 413 '<$customTagName> or add \'extends="$nodeTag"\' to '
393 'the custom element declaration.', node.sourceSpan); 414 'the custom element declaration.', node.sourceSpan);
394 return; 415 return;
395 } 416 }
396 417
397 if (hasIsAttribute && baseTag != nodeTag) { 418 if (hasIsAttribute && baseTag != nodeTag) {
398 _logger.warning( 419 _logger.warning(
399 'custom element "$customTagName" extends from "$baseTag". ' 420 'custom element "$customTagName" extends from "$baseTag". '
400 'Did you mean to write <$baseTag is="$customTagName">?', 421 'Did you mean to write <$baseTag is="$customTagName">?',
401 node.sourceSpan); 422 node.sourceSpan);
402 } 423 }
403 } 424 }
404 425
426 /**
427 * Validate an attribute on a custom-element. Returns true if valid.
428 */
429 bool _validateCustomAttributeName(String name, FileSpan span) {
430 if (name.contains('-')) {
431 var newName = toCamelCase(name);
432 _logger.warning('PolymerElement no longer recognizes attribute names with '
433 'dashes such as "$name". Use "$newName" or "${newName.toLowerCase()}" '
434 'instead (both forms are equivalent in HTML).', span);
435 return false;
436 }
437 return true;
438 }
439
405 /** Validate event handlers are used correctly. */ 440 /** Validate event handlers are used correctly. */
406 void _validateEventHandler(Element node, String name, String value) { 441 void _validateEventHandler(Element node, String name, String value) {
407 if (!name.startsWith('on-')) { 442 if (!name.startsWith('on-')) {
408 _logger.warning('Event handler "$name" will be interpreted as an inline' 443 _logger.warning('Event handler "$name" will be interpreted as an inline'
409 ' JavaScript event handler. Use the form ' 444 ' JavaScript event handler. Use the form '
410 'on-event-name="handlerName" if you want a Dart handler ' 445 'on-event-name="handlerName" if you want a Dart handler '
411 'that will automatically update the UI based on model changes.', 446 'that will automatically update the UI based on model changes.',
412 node.sourceSpan); 447 node.attributeSpans[name]);
413 return; 448 return;
414 } 449 }
415 450
416 if (!_inPolymerElement) { 451 if (!_inPolymerElement) {
417 _logger.warning('Inline event handlers are only supported inside ' 452 _logger.warning('Inline event handlers are only supported inside '
418 'declarations of <polymer-element>.', node.sourceSpan); 453 'declarations of <polymer-element>.', node.attributeSpans[name]);
454 }
455
456 var eventName = name.substring('on-'.length);
457 if (eventName.contains('-')) {
458 var newEvent = toCamelCase(eventName);
459 _logger.warning('Invalid event name "$name". After the "on-" the event '
460 'name should not use dashes. For example use "on-$newEvent" or '
461 '"on-${newEvent.toLowerCase()}" (both forms are equivalent in HTML).',
462 node.attributeSpans[name]);
419 } 463 }
420 464
421 if (value.contains('.') || value.contains('(')) { 465 if (value.contains('.') || value.contains('(')) {
422 _logger.warning('Invalid event handler body "$value". Declare a method ' 466 _logger.warning('Invalid event handler body "$value". Declare a method '
423 'in your custom element "void handlerName(event, detail, target)" ' 467 'in your custom element "void handlerName(event, detail, target)" '
424 'and use the form $name="handlerName".', 468 'and use the form $name="handlerName".',
425 node.sourceSpan); 469 node.attributeSpans[name]);
426 } 470 }
427 } 471 }
428 } 472 }
429 473
430 474
431 // These names have meaning in SVG or MathML, so they aren't allowed as custom 475 // These names have meaning in SVG or MathML, so they aren't allowed as custom
432 // tags. 476 // tags.
433 var _invalidTagNames = const { 477 var _invalidTagNames = const {
434 'annotation-xml': '', 478 'annotation-xml': '',
435 'color-profile': '', 479 'color-profile': '',
(...skipping 10 matching lines...) Expand all
446 * <https://dvcs.w3.org/hg/webcomponents/raw-file/tip/spec/custom/index.html#dfn -custom-element-name> 490 * <https://dvcs.w3.org/hg/webcomponents/raw-file/tip/spec/custom/index.html#dfn -custom-element-name>
447 */ 491 */
448 bool _isCustomTag(String name) { 492 bool _isCustomTag(String name) {
449 if (name == null || !name.contains('-')) return false; 493 if (name == null || !name.contains('-')) return false;
450 return !_invalidTagNames.containsKey(name); 494 return !_invalidTagNames.containsKey(name);
451 } 495 }
452 496
453 final String _RED_COLOR = '\u001b[31m'; 497 final String _RED_COLOR = '\u001b[31m';
454 final String _MAGENTA_COLOR = '\u001b[35m'; 498 final String _MAGENTA_COLOR = '\u001b[35m';
455 final String _NO_COLOR = '\u001b[0m'; 499 final String _NO_COLOR = '\u001b[0m';
OLDNEW
« no previous file with comments | « pkg/polymer/lib/polymer_element.dart ('k') | pkg/polymer/lib/src/build/runner.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698