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

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

Issue 26564010: Fixing Polymer linter warnings error on transform changes (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: 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 | « no previous file | no next file » | 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
(...skipping 77 matching lines...) Expand 10 before | Expand all | Expand 10 after
88 for (var tag in document.queryAll('link')) { 88 for (var tag in document.queryAll('link')) {
89 if (tag.attributes['rel'] != 'import') continue; 89 if (tag.attributes['rel'] != 'import') continue;
90 var href = tag.attributes['href']; 90 var href = tag.attributes['href'];
91 var span = tag.sourceSpan; 91 var span = tag.sourceSpan;
92 var id = resolve(sourceId, href, logger, span); 92 var id = resolve(sourceId, href, logger, span);
93 if (id == null) continue; 93 if (id == null) continue;
94 importIds.add(assetExists(id, transform).then((exists) { 94 importIds.add(assetExists(id, transform).then((exists) {
95 if (exists) return id; 95 if (exists) return id;
96 if (sourceId == transform.primaryInput.id) { 96 if (sourceId == transform.primaryInput.id) {
97 logger.error('couldn\'t find imported asset "${id.path}" in package ' 97 logger.error('couldn\'t find imported asset "${id.path}" in package '
98 '"${id.package}".', span); 98 '"${id.package}".', span: span);
99 } 99 }
100 })); 100 }));
101 } 101 }
102 return Future.wait(importIds); 102 return Future.wait(importIds);
103 } 103 }
104 104
105 void _addElements(Document document, TransformLogger logger, 105 void _addElements(Document document, TransformLogger logger,
106 Map<String, _ElementSummary> elements) { 106 Map<String, _ElementSummary> elements) {
107 for (var tag in document.queryAll('polymer-element')) { 107 for (var tag in document.queryAll('polymer-element')) {
108 var name = tag.attributes['name']; 108 var name = tag.attributes['name'];
109 if (name == null) continue; 109 if (name == null) continue;
110 var extendsTag = tag.attributes['extends']; 110 var extendsTag = tag.attributes['extends'];
111 var span = tag.sourceSpan; 111 var span = tag.sourceSpan;
112 var existing = elements[name]; 112 var existing = elements[name];
113 if (existing != null) { 113 if (existing != null) {
114 114
115 // Report warning only once. 115 // Report warning only once.
116 if (existing.hasConflict) continue; 116 if (existing.hasConflict) continue;
117 existing.hasConflict = true; 117 existing.hasConflict = true;
118 logger.warning('duplicate definition for custom tag "$name".', 118 logger.warning('duplicate definition for custom tag "$name".',
119 existing.span); 119 span: existing.span);
120 logger.warning('duplicate definition for custom tag "$name" ' 120 logger.warning('duplicate definition for custom tag "$name" '
121 ' (second definition).', span); 121 ' (second definition).', span: span);
122 continue; 122 continue;
123 } 123 }
124 124
125 elements[name] = new _ElementSummary(name, extendsTag, tag.sourceSpan); 125 elements[name] = new _ElementSummary(name, extendsTag, tag.sourceSpan);
126 } 126 }
127 } 127 }
128 } 128 }
129 129
130 /** A proxy of [Transform] that returns a different logger. */ 130 /** A proxy of [Transform] that returns a different logger. */
131 // TODO(sigmund): get rid of this when barback supports a better way to log 131 // TODO(sigmund): get rid of this when barback supports a better way to log
132 // messages without printing them. 132 // messages without printing them.
133 class _LoggerInterceptor implements Transform, TransformLogger { 133 class _LoggerInterceptor implements Transform, TransformLogger {
134 final Transform _original; 134 final Transform _original;
135 final List<String> _messages = []; 135 final List<String> _messages = [];
136 final MessageFormatter _formatter; 136 final MessageFormatter _formatter;
137 137
138 _LoggerInterceptor(this._original, MessageFormatter formatter) 138 _LoggerInterceptor(this._original, MessageFormatter formatter)
139 : _formatter = formatter == null ? consoleFormatter : formatter; 139 : _formatter = formatter == null ? consoleFormatter : formatter;
140 140
141 TransformLogger get logger => this; 141 TransformLogger get logger => this;
142 142
143 noSuchMethod(Invocation m) => reflect(_original).delegate(m); 143 noSuchMethod(Invocation m) => reflect(_original).delegate(m);
144 144
145 // form TransformLogger: 145 // form TransformLogger:
146 void warning(String message, [Span span]) => _write('warning', message, span); 146 void warning(String message, {AssetId asset, Span span})
147 => _write('warning', message, span);
147 148
148 void error(String message, [Span span]) => _write('error', message, span); 149 void error(String message, {AssetId asset, Span span})
150 => _write('error', message, span);
149 151
150 void _write(String kind, String message, Span span) { 152 void _write(String kind, String message, Span span) {
151 _messages.add(_formatter(kind, message, span)); 153 _messages.add(_formatter(kind, message, span));
152 } 154 }
153 } 155 }
154 156
155 /** 157 /**
156 * Formatter that generates messages using a format that can be parsed 158 * Formatter that generates messages using a format that can be parsed
157 * by tools, such as the Dart Editor, for reporting error messages. 159 * by tools, such as the Dart Editor, for reporting error messages.
158 */ 160 */
(...skipping 84 matching lines...) Expand 10 before | Expand all | Expand 10 after
243 245
244 /** Produce warnings for invalid link-rel tags. */ 246 /** Produce warnings for invalid link-rel tags. */
245 void _validateLinkElement(Element node) { 247 void _validateLinkElement(Element node) {
246 var rel = node.attributes['rel']; 248 var rel = node.attributes['rel'];
247 if (rel != 'import' && rel != 'stylesheet') return; 249 if (rel != 'import' && rel != 'stylesheet') return;
248 250
249 var href = node.attributes['href']; 251 var href = node.attributes['href'];
250 if (href != null && href != '') return; 252 if (href != null && href != '') return;
251 253
252 // TODO(sigmund): warn also if href can't be resolved. 254 // TODO(sigmund): warn also if href can't be resolved.
253 _logger.warning('link rel="$rel" missing href.', node.sourceSpan); 255 _logger.warning('link rel="$rel" missing href.', span: node.sourceSpan);
254 } 256 }
255 257
256 /** Produce warnings if using `<element>` instead of `<polymer-element>`. */ 258 /** Produce warnings if using `<element>` instead of `<polymer-element>`. */
257 void _validateElementElement(Element node) { 259 void _validateElementElement(Element node) {
258 _logger.warning('<element> elements are not supported, use' 260 _logger.warning('<element> elements are not supported, use'
259 ' <polymer-element> instead', node.sourceSpan); 261 ' <polymer-element> instead', span: node.sourceSpan);
260 } 262 }
261 263
262 /** 264 /**
263 * Produce warnings if using `<polymer-element>` in the wrong place or if the 265 * Produce warnings if using `<polymer-element>` in the wrong place or if the
264 * definition is not complete. 266 * definition is not complete.
265 */ 267 */
266 void _validatePolymerElement(Element node) { 268 void _validatePolymerElement(Element node) {
267 if (_inPolymerElement) { 269 if (_inPolymerElement) {
268 _logger.error('Nested polymer element definitions are not allowed.', 270 _logger.error('Nested polymer element definitions are not allowed.',
269 node.sourceSpan); 271 span: node.sourceSpan);
270 return; 272 return;
271 } 273 }
272 274
273 var tagName = node.attributes['name']; 275 var tagName = node.attributes['name'];
274 var extendsTag = node.attributes['extends']; 276 var extendsTag = node.attributes['extends'];
275 277
276 if (tagName == null) { 278 if (tagName == null) {
277 _logger.error('Missing tag name of the custom element. Please include an ' 279 _logger.error('Missing tag name of the custom element. Please include an '
278 'attribute like \'name="your-tag-name"\'.', 280 'attribute like \'name="your-tag-name"\'.',
279 node.sourceSpan); 281 span: node.sourceSpan);
280 } else if (!_isCustomTag(tagName)) { 282 } else if (!_isCustomTag(tagName)) {
281 _logger.error('Invalid name "$tagName". Custom element names must have ' 283 _logger.error('Invalid name "$tagName". Custom element names must have '
282 'at least one dash and can\'t be any of the following names: ' 284 'at least one dash and can\'t be any of the following names: '
283 '${_invalidTagNames.keys.join(", ")}.', 285 '${_invalidTagNames.keys.join(", ")}.',
284 node.sourceSpan); 286 span: node.sourceSpan);
285 } 287 }
286 288
287 if (_elements[extendsTag] == null && _isCustomTag(extendsTag)) { 289 if (_elements[extendsTag] == null && _isCustomTag(extendsTag)) {
288 _logger.warning('custom element with name "$extendsTag" not found.', 290 _logger.warning('custom element with name "$extendsTag" not found.',
289 node.sourceSpan); 291 span: node.sourceSpan);
290 } 292 }
291 293
292 var attrs = node.attributes['attributes']; 294 var attrs = node.attributes['attributes'];
293 if (attrs != null) { 295 if (attrs != null) {
294 var attrsSpan = node.attributeSpans['attributes']; 296 var attrsSpan = node.attributeSpans['attributes'];
295 297
296 // names='a b c' or names='a,b,c' 298 // names='a b c' or names='a,b,c'
297 // record each name for publishing 299 // record each name for publishing
298 for (var attr in attrs.split(attrs.contains(',') ? ',' : ' ')) { 300 for (var attr in attrs.split(attrs.contains(',') ? ',' : ' ')) {
299 // remove excess ws 301 // remove excess ws
(...skipping 24 matching lines...) Expand all
324 var src = node.attributes['src']; 326 var src = node.attributes['src'];
325 327
326 if (scriptType == null) { 328 if (scriptType == null) {
327 if (src == null && _inPolymerElement) { 329 if (src == null && _inPolymerElement) {
328 // TODO(sigmund): revisit this check once we start interop with polymer 330 // TODO(sigmund): revisit this check once we start interop with polymer
329 // elements written in JS. Maybe we need to inspect the contents of the 331 // elements written in JS. Maybe we need to inspect the contents of the
330 // script to find whether there is an import or something that indicates 332 // script to find whether there is an import or something that indicates
331 // that the code is indeed using Dart. 333 // that the code is indeed using Dart.
332 _logger.warning('script tag in polymer element with no type will ' 334 _logger.warning('script tag in polymer element with no type will '
333 'be treated as JavaScript. Did you forget type="application/dart"?', 335 'be treated as JavaScript. Did you forget type="application/dart"?',
334 node.sourceSpan); 336 span: node.sourceSpan);
335 } 337 }
336 if (src != null && src.endsWith('.dart')) { 338 if (src != null && src.endsWith('.dart')) {
337 _logger.warning('script tag with .dart source file but no type will ' 339 _logger.warning('script tag with .dart source file but no type will '
338 'be treated as JavaScript. Did you forget type="application/dart"?', 340 'be treated as JavaScript. Did you forget type="application/dart"?',
339 node.sourceSpan); 341 span: node.sourceSpan);
340 } 342 }
341 return; 343 return;
342 } 344 }
343 345
344 if (scriptType != 'application/dart') return; 346 if (scriptType != 'application/dart') return;
345 347
346 if (src != null) { 348 if (src != null) {
347 if (!src.endsWith('.dart')) { 349 if (!src.endsWith('.dart')) {
348 _logger.warning('"application/dart" scripts should ' 350 _logger.warning('"application/dart" scripts should '
349 'use the .dart file extension.', 351 'use the .dart file extension.',
350 node.sourceSpan); 352 span: node.sourceSpan);
351 } 353 }
352 354
353 if (node.innerHtml.trim() != '') { 355 if (node.innerHtml.trim() != '') {
354 _logger.warning('script tag has "src" attribute and also has script ' 356 _logger.warning('script tag has "src" attribute and also has script '
355 'text.', node.sourceSpan); 357 'text.', span: node.sourceSpan);
356 } 358 }
357 } 359 }
358 } 360 }
359 361
360 /** 362 /**
361 * Produces warnings for misuses of on-foo event handlers, and for instanting 363 * Produces warnings for misuses of on-foo event handlers, and for instanting
362 * custom tags incorrectly. 364 * custom tags incorrectly.
363 */ 365 */
364 void _validateNormalElement(Element node) { 366 void _validateNormalElement(Element node) {
365 // Event handlers only allowed inside polymer-elements 367 // Event handlers only allowed inside polymer-elements
(...skipping 18 matching lines...) Expand all
384 } 386 }
385 387
386 if (customTagName == null || customTagName == 'polymer-element') return; 388 if (customTagName == null || customTagName == 'polymer-element') return;
387 389
388 var info = _elements[customTagName]; 390 var info = _elements[customTagName];
389 if (info == null) { 391 if (info == null) {
390 // TODO(jmesserly): this warning is wrong if someone is using raw custom 392 // 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 393 // elements. Is there another way we can handle this warning that won't
392 // generate false positives? 394 // generate false positives?
393 _logger.warning('definition for Polymer element with tag name ' 395 _logger.warning('definition for Polymer element with tag name '
394 '"$customTagName" not found.', node.sourceSpan); 396 '"$customTagName" not found.', span: node.sourceSpan);
395 return; 397 return;
396 } 398 }
397 399
398 var baseTag = info.baseExtendsTag; 400 var baseTag = info.baseExtendsTag;
399 if (baseTag != null && !hasIsAttribute) { 401 if (baseTag != null && !hasIsAttribute) {
400 _logger.warning( 402 _logger.warning(
401 'custom element "$customTagName" extends from "$baseTag", but ' 403 'custom element "$customTagName" extends from "$baseTag", but '
402 'this tag will not include the default properties of "$baseTag". ' 404 'this tag will not include the default properties of "$baseTag". '
403 'To fix this, either write this tag as <$baseTag ' 405 'To fix this, either write this tag as <$baseTag '
404 'is="$customTagName"> or remove the "extends" attribute from ' 406 'is="$customTagName"> or remove the "extends" attribute from '
405 'the custom element declaration.', node.sourceSpan); 407 'the custom element declaration.', span: node.sourceSpan);
406 return; 408 return;
407 } 409 }
408 410
409 if (hasIsAttribute && baseTag == null) { 411 if (hasIsAttribute && baseTag == null) {
410 _logger.warning( 412 _logger.warning(
411 'custom element "$customTagName" doesn\'t declare any type ' 413 'custom element "$customTagName" doesn\'t declare any type '
412 'extensions. To fix this, either rewrite this tag as ' 414 'extensions. To fix this, either rewrite this tag as '
413 '<$customTagName> or add \'extends="$nodeTag"\' to ' 415 '<$customTagName> or add \'extends="$nodeTag"\' to '
414 'the custom element declaration.', node.sourceSpan); 416 'the custom element declaration.', span: node.sourceSpan);
415 return; 417 return;
416 } 418 }
417 419
418 if (hasIsAttribute && baseTag != nodeTag) { 420 if (hasIsAttribute && baseTag != nodeTag) {
419 _logger.warning( 421 _logger.warning(
420 'custom element "$customTagName" extends from "$baseTag". ' 422 'custom element "$customTagName" extends from "$baseTag". '
421 'Did you mean to write <$baseTag is="$customTagName">?', 423 'Did you mean to write <$baseTag is="$customTagName">?',
422 node.sourceSpan); 424 span: node.sourceSpan);
423 } 425 }
424 } 426 }
425 427
426 /** 428 /**
427 * Validate an attribute on a custom-element. Returns true if valid. 429 * Validate an attribute on a custom-element. Returns true if valid.
428 */ 430 */
429 bool _validateCustomAttributeName(String name, FileSpan span) { 431 bool _validateCustomAttributeName(String name, FileSpan span) {
430 if (name.contains('-')) { 432 if (name.contains('-')) {
431 var newName = toCamelCase(name); 433 var newName = toCamelCase(name);
432 _logger.warning('PolymerElement no longer recognizes attribute names with ' 434 _logger.warning('PolymerElement no longer recognizes attribute names with '
433 'dashes such as "$name". Use "$newName" or "${newName.toLowerCase()}" ' 435 'dashes such as "$name". Use "$newName" or "${newName.toLowerCase()}" '
434 'instead (both forms are equivalent in HTML).', span); 436 'instead (both forms are equivalent in HTML).', span: span);
435 return false; 437 return false;
436 } 438 }
437 return true; 439 return true;
438 } 440 }
439 441
440 /** Validate event handlers are used correctly. */ 442 /** Validate event handlers are used correctly. */
441 void _validateEventHandler(Element node, String name, String value) { 443 void _validateEventHandler(Element node, String name, String value) {
442 if (!name.startsWith('on-')) { 444 if (!name.startsWith('on-')) {
443 _logger.warning('Event handler "$name" will be interpreted as an inline' 445 _logger.warning('Event handler "$name" will be interpreted as an inline'
444 ' JavaScript event handler. Use the form ' 446 ' JavaScript event handler. Use the form '
445 'on-event-name="handlerName" if you want a Dart handler ' 447 'on-event-name="handlerName" if you want a Dart handler '
446 'that will automatically update the UI based on model changes.', 448 'that will automatically update the UI based on model changes.',
447 node.attributeSpans[name]); 449 span: node.attributeSpans[name]);
448 return; 450 return;
449 } 451 }
450 452
451 if (!_inPolymerElement) { 453 if (!_inPolymerElement) {
452 _logger.warning('Inline event handlers are only supported inside ' 454 _logger.warning('Inline event handlers are only supported inside '
453 'declarations of <polymer-element>.', node.attributeSpans[name]); 455 'declarations of <polymer-element>.',
456 span: node.attributeSpans[name]);
454 } 457 }
455 458
456 var eventName = name.substring('on-'.length); 459 var eventName = name.substring('on-'.length);
457 if (eventName.contains('-')) { 460 if (eventName.contains('-')) {
458 var newEvent = toCamelCase(eventName); 461 var newEvent = toCamelCase(eventName);
459 _logger.warning('Invalid event name "$name". After the "on-" the event ' 462 _logger.warning('Invalid event name "$name". After the "on-" the event '
460 'name should not use dashes. For example use "on-$newEvent" or ' 463 'name should not use dashes. For example use "on-$newEvent" or '
461 '"on-${newEvent.toLowerCase()}" (both forms are equivalent in HTML).', 464 '"on-${newEvent.toLowerCase()}" (both forms are equivalent in HTML).',
462 node.attributeSpans[name]); 465 span: node.attributeSpans[name]);
463 } 466 }
464 467
465 if (value.contains('.') || value.contains('(')) { 468 if (value.contains('.') || value.contains('(')) {
466 _logger.warning('Invalid event handler body "$value". Declare a method ' 469 _logger.warning('Invalid event handler body "$value". Declare a method '
467 'in your custom element "void handlerName(event, detail, target)" ' 470 'in your custom element "void handlerName(event, detail, target)" '
468 'and use the form $name="handlerName".', 471 'and use the form $name="handlerName".',
469 node.attributeSpans[name]); 472 span: node.attributeSpans[name]);
470 } 473 }
471 } 474 }
472 } 475 }
473 476
474 477
475 // These names have meaning in SVG or MathML, so they aren't allowed as custom 478 // These names have meaning in SVG or MathML, so they aren't allowed as custom
476 // tags. 479 // tags.
477 var _invalidTagNames = const { 480 var _invalidTagNames = const {
478 'annotation-xml': '', 481 'annotation-xml': '',
479 'color-profile': '', 482 'color-profile': '',
(...skipping 10 matching lines...) Expand all
490 * <https://dvcs.w3.org/hg/webcomponents/raw-file/tip/spec/custom/index.html#dfn -custom-element-name> 493 * <https://dvcs.w3.org/hg/webcomponents/raw-file/tip/spec/custom/index.html#dfn -custom-element-name>
491 */ 494 */
492 bool _isCustomTag(String name) { 495 bool _isCustomTag(String name) {
493 if (name == null || !name.contains('-')) return false; 496 if (name == null || !name.contains('-')) return false;
494 return !_invalidTagNames.containsKey(name); 497 return !_invalidTagNames.containsKey(name);
495 } 498 }
496 499
497 final String _RED_COLOR = '\u001b[31m'; 500 final String _RED_COLOR = '\u001b[31m';
498 final String _MAGENTA_COLOR = '\u001b[35m'; 501 final String _MAGENTA_COLOR = '\u001b[35m';
499 final String _NO_COLOR = '\u001b[0m'; 502 final String _NO_COLOR = '\u001b[0m';
OLDNEW
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698