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

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

Issue 180373003: [polymer] switch comment style (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Created 6 years, 10 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
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 /// Logic to validate that developers are correctly using Polymer constructs.
6 * Logic to validate that developers are correctly using Polymer constructs. 6 /// 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 */
9 library polymer.src.build.linter; 7 library polymer.src.build.linter;
10 8
11 import 'dart:async'; 9 import 'dart:async';
12 10
13 import 'package:barback/barback.dart'; 11 import 'package:barback/barback.dart';
14 import 'package:html5lib/dom.dart'; 12 import 'package:html5lib/dom.dart';
15 import 'package:html5lib/dom_parsing.dart'; 13 import 'package:html5lib/dom_parsing.dart';
16 import 'package:source_maps/span.dart'; 14 import 'package:source_maps/span.dart';
17 15
18 import 'common.dart'; 16 import 'common.dart';
19 import 'utils.dart'; 17 import 'utils.dart';
20 18
21 /** 19 /// A linter that checks for common Polymer errors and produces warnings to
22 * A linter that checks for common Polymer errors and produces warnings to 20 /// show on the editor or the command line. Leaves sources unchanged, but
23 * show on the editor or the command line. Leaves sources unchanged, but creates 21 /// creates a new asset containing all the warnings.
24 * a new asset containing all the warnings.
25 */
26 class Linter extends Transformer with PolymerTransformer { 22 class Linter extends Transformer with PolymerTransformer {
27 final TransformOptions options; 23 final TransformOptions options;
28 24
29 /** Only run on .html files. */ 25 /// Only run on .html files.
30 final String allowedExtensions = '.html'; 26 final String allowedExtensions = '.html';
31 27
32 Linter(this.options); 28 Linter(this.options);
33 29
34 Future apply(Transform transform) { 30 Future apply(Transform transform) {
35 var seen = new Set<AssetId>(); 31 var seen = new Set<AssetId>();
36 var primary = transform.primaryInput; 32 var primary = transform.primaryInput;
37 var id = primary.id; 33 var id = primary.id;
38 transform.addOutput(primary); // this phase is analysis only 34 transform.addOutput(primary); // this phase is analysis only
39 seen.add(id); 35 seen.add(id);
40 return readPrimaryAsHtml(transform).then((document) { 36 return readPrimaryAsHtml(transform).then((document) {
41 return _collectElements(document, id, transform, seen).then((elements) { 37 return _collectElements(document, id, transform, seen).then((elements) {
42 bool isEntrypoint = options.isHtmlEntryPoint(id); 38 bool isEntrypoint = options.isHtmlEntryPoint(id);
43 new _LinterVisitor(transform.logger, elements, isEntrypoint) 39 new _LinterVisitor(transform.logger, elements, isEntrypoint)
44 .run(document); 40 .run(document);
45 }); 41 });
46 }); 42 });
47 } 43 }
48 44
49 /** 45 /// Collect into [elements] any data about each polymer-element defined in
50 * Collect into [elements] any data about each polymer-element defined in 46 /// [document] or any of it's imports, unless they have already been [seen].
51 * [document] or any of it's imports, unless they have already been [seen]. 47 /// Elements are added in the order they appear, transitive imports are added
52 * Elements are added in the order they appear, transitive imports are added 48 /// first.
53 * first.
54 */
55 Future<Map<String, _ElementSummary>> _collectElements( 49 Future<Map<String, _ElementSummary>> _collectElements(
56 Document document, AssetId sourceId, Transform transform, 50 Document document, AssetId sourceId, Transform transform,
57 Set<AssetId> seen, [Map<String, _ElementSummary> elements]) { 51 Set<AssetId> seen, [Map<String, _ElementSummary> elements]) {
58 if (elements == null) elements = <String, _ElementSummary>{}; 52 if (elements == null) elements = <String, _ElementSummary>{};
59 return _getImportedIds(document, sourceId, transform) 53 return _getImportedIds(document, sourceId, transform)
60 // Note: the import order is relevant, so we visit in that order. 54 // Note: the import order is relevant, so we visit in that order.
61 .then((ids) => Future.forEach(ids, 55 .then((ids) => Future.forEach(ids,
62 (id) => _readAndCollectElements(id, transform, seen, elements))) 56 (id) => _readAndCollectElements(id, transform, seen, elements)))
63 .then((_) => _addElements(document, transform.logger, elements)) 57 .then((_) => _addElements(document, transform.logger, elements))
64 .then((_) => elements); 58 .then((_) => elements);
(...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after
113 ' (second definition).', span: span); 107 ' (second definition).', span: span);
114 continue; 108 continue;
115 } 109 }
116 110
117 elements[name] = new _ElementSummary(name, extendsTag, tag.sourceSpan); 111 elements[name] = new _ElementSummary(name, extendsTag, tag.sourceSpan);
118 } 112 }
119 } 113 }
120 } 114 }
121 115
122 116
123 /** 117 /// Information needed about other polymer-element tags in order to validate
124 * Information needed about other polymer-element tags in order to validate 118 /// how they are used and extended.
125 * how they are used and extended. 119 ///
126 * 120 /// Note: these are only created for polymer-element, because pure custom
127 * Note: these are only created for polymer-element, because pure custom 121 /// elements don't have a declarative form.
128 * elements don't have a declarative form.
129 */
130 class _ElementSummary { 122 class _ElementSummary {
131 final String tagName; 123 final String tagName;
132 final String extendsTag; 124 final String extendsTag;
133 final Span span; 125 final Span span;
134 126
135 _ElementSummary extendsType; 127 _ElementSummary extendsType;
136 bool hasConflict = false; 128 bool hasConflict = false;
137 129
138 String get baseExtendsTag => extendsType == null 130 String get baseExtendsTag => extendsType == null
139 ? extendsTag : extendsType.baseExtendsTag; 131 ? extendsTag : extendsType.baseExtendsTag;
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after
174 } 166 }
175 167
176 void run(Document doc) { 168 void run(Document doc) {
177 visit(doc); 169 visit(doc);
178 170
179 if (_isEntrypoint && !_dartTagSeen) { 171 if (_isEntrypoint && !_dartTagSeen) {
180 _logger.error(USE_INIT_DART, span: doc.body.sourceSpan); 172 _logger.error(USE_INIT_DART, span: doc.body.sourceSpan);
181 } 173 }
182 } 174 }
183 175
184 /** Produce warnings for invalid link-rel tags. */ 176 /// Produce warnings for invalid link-rel tags.
185 void _validateLinkElement(Element node) { 177 void _validateLinkElement(Element node) {
186 var rel = node.attributes['rel']; 178 var rel = node.attributes['rel'];
187 if (rel != 'import' && rel != 'stylesheet') return; 179 if (rel != 'import' && rel != 'stylesheet') return;
188 180
189 if (rel == 'import' && _dartTagSeen) { 181 if (rel == 'import' && _dartTagSeen) {
190 _logger.warning( 182 _logger.warning(
191 "Move HTML imports above your Dart script tag.", 183 "Move HTML imports above your Dart script tag.",
192 span: node.sourceSpan); 184 span: node.sourceSpan);
193 } 185 }
194 186
195 var href = node.attributes['href']; 187 var href = node.attributes['href'];
196 if (href != null && href != '') return; 188 if (href != null && href != '') return;
197 189
198 // TODO(sigmund): warn also if href can't be resolved. 190 // TODO(sigmund): warn also if href can't be resolved.
199 _logger.warning('link rel="$rel" missing href.', span: node.sourceSpan); 191 _logger.warning('link rel="$rel" missing href.', span: node.sourceSpan);
200 } 192 }
201 193
202 /** Produce warnings if using `<element>` instead of `<polymer-element>`. */ 194 /// Produce warnings if using `<element>` instead of `<polymer-element>`.
203 void _validateElementElement(Element node) { 195 void _validateElementElement(Element node) {
204 _logger.warning('<element> elements are not supported, use' 196 _logger.warning('<element> elements are not supported, use'
205 ' <polymer-element> instead', span: node.sourceSpan); 197 ' <polymer-element> instead', span: node.sourceSpan);
206 } 198 }
207 199
208 /** 200 /// Produce warnings if using `<polymer-element>` in the wrong place or if the
209 * Produce warnings if using `<polymer-element>` in the wrong place or if the 201 /// definition is not complete.
210 * definition is not complete.
211 */
212 void _validatePolymerElement(Element node) { 202 void _validatePolymerElement(Element node) {
213 if (_inPolymerElement) { 203 if (_inPolymerElement) {
214 _logger.error('Nested polymer element definitions are not allowed.', 204 _logger.error('Nested polymer element definitions are not allowed.',
215 span: node.sourceSpan); 205 span: node.sourceSpan);
216 return; 206 return;
217 } 207 }
218 208
219 var tagName = node.attributes['name']; 209 var tagName = node.attributes['name'];
220 var extendsTag = node.attributes['extends']; 210 var extendsTag = node.attributes['extends'];
221 211
(...skipping 25 matching lines...) Expand all
247 if (!_validateCustomAttributeName(attr, attrsSpan)) break; 237 if (!_validateCustomAttributeName(attr, attrsSpan)) break;
248 } 238 }
249 } 239 }
250 240
251 var oldValue = _inPolymerElement; 241 var oldValue = _inPolymerElement;
252 _inPolymerElement = true; 242 _inPolymerElement = true;
253 super.visitElement(node); 243 super.visitElement(node);
254 _inPolymerElement = oldValue; 244 _inPolymerElement = oldValue;
255 } 245 }
256 246
257 /** 247 /// Produces warnings for malformed script tags. In html5 leaving off type= is
258 * Produces warnings for malformed script tags. In html5 leaving off type= is 248 /// fine, but it defaults to text/javascript. Because this might be a common
259 * fine, but it defaults to text/javascript. Because this might be a common 249 /// error, we warn about it when src file ends in .dart, but the type is
260 * error, we warn about it when src file ends in .dart, but the type is 250 /// incorrect, or when users write code in an inline script tag of a custom
261 * incorrect, or when users write code in an inline script tag of a custom 251 /// element.
262 * element. 252 ///
263 * 253 /// The hope is that these cases shouldn't break existing valid code, but that
264 * The hope is that these cases shouldn't break existing valid code, but that 254 /// they'll help Polymer authors avoid having their Dart code accidentally
265 * they'll help Polymer authors avoid having their Dart code accidentally 255 /// interpreted as JavaScript by the browser.
266 * interpreted as JavaScript by the browser.
267 */
268 void _validateScriptElement(Element node) { 256 void _validateScriptElement(Element node) {
269 var scriptType = node.attributes['type']; 257 var scriptType = node.attributes['type'];
270 var isDart = scriptType == 'application/dart'; 258 var isDart = scriptType == 'application/dart';
271 var src = node.attributes['src']; 259 var src = node.attributes['src'];
272 260
273 if (scriptType == null) { 261 if (scriptType == null) {
274 if (src == null && _inPolymerElement) { 262 if (src == null && _inPolymerElement) {
275 // TODO(sigmund): revisit this check once we start interop with polymer 263 // TODO(sigmund): revisit this check once we start interop with polymer
276 // elements written in JS. Maybe we need to inspect the contents of the 264 // elements written in JS. Maybe we need to inspect the contents of the
277 // script to find whether there is an import or something that indicates 265 // script to find whether there is an import or something that indicates
(...skipping 29 matching lines...) Expand all
307 span: node.sourceSpan); 295 span: node.sourceSpan);
308 return; 296 return;
309 } 297 }
310 298
311 if (node.innerHtml.trim() != '') { 299 if (node.innerHtml.trim() != '') {
312 _logger.warning('script tag has "src" attribute and also has script ' 300 _logger.warning('script tag has "src" attribute and also has script '
313 'text.', span: node.sourceSpan); 301 'text.', span: node.sourceSpan);
314 } 302 }
315 } 303 }
316 304
317 /** 305 /// Produces warnings for misuses of on-foo event handlers, and for instanting
318 * Produces warnings for misuses of on-foo event handlers, and for instanting 306 /// custom tags incorrectly.
319 * custom tags incorrectly.
320 */
321 void _validateNormalElement(Element node) { 307 void _validateNormalElement(Element node) {
322 // Event handlers only allowed inside polymer-elements 308 // Event handlers only allowed inside polymer-elements
323 node.attributes.forEach((name, value) { 309 node.attributes.forEach((name, value) {
324 if (name is String && name.startsWith('on')) { 310 if (name is String && name.startsWith('on')) {
325 _validateEventHandler(node, name, value); 311 _validateEventHandler(node, name, value);
326 } 312 }
327 }); 313 });
328 314
329 // Validate uses of custom-tags 315 // Validate uses of custom-tags
330 var nodeTag = node.localName; 316 var nodeTag = node.localName;
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after
373 } 359 }
374 360
375 if (hasIsAttribute && baseTag != nodeTag) { 361 if (hasIsAttribute && baseTag != nodeTag) {
376 _logger.warning( 362 _logger.warning(
377 'custom element "$customTagName" extends from "$baseTag". ' 363 'custom element "$customTagName" extends from "$baseTag". '
378 'Did you mean to write <$baseTag is="$customTagName">?', 364 'Did you mean to write <$baseTag is="$customTagName">?',
379 span: node.sourceSpan); 365 span: node.sourceSpan);
380 } 366 }
381 } 367 }
382 368
383 /** 369 /// Validate an attribute on a custom-element. Returns true if valid.
384 * Validate an attribute on a custom-element. Returns true if valid.
385 */
386 bool _validateCustomAttributeName(String name, FileSpan span) { 370 bool _validateCustomAttributeName(String name, FileSpan span) {
387 if (name.contains('-')) { 371 if (name.contains('-')) {
388 var newName = toCamelCase(name); 372 var newName = toCamelCase(name);
389 _logger.warning('PolymerElement no longer recognizes attribute names with ' 373 _logger.warning('PolymerElement no longer recognizes attribute names with '
390 'dashes such as "$name". Use "$newName" or "${newName.toLowerCase()}" ' 374 'dashes such as "$name". Use "$newName" or "${newName.toLowerCase()}" '
391 'instead (both forms are equivalent in HTML).', span: span); 375 'instead (both forms are equivalent in HTML).', span: span);
392 return false; 376 return false;
393 } 377 }
394 return true; 378 return true;
395 } 379 }
396 380
397 /** Validate event handlers are used correctly. */ 381 /// Validate event handlers are used correctly.
398 void _validateEventHandler(Element node, String name, String value) { 382 void _validateEventHandler(Element node, String name, String value) {
399 if (!name.startsWith('on-')) { 383 if (!name.startsWith('on-')) {
400 _logger.warning('Event handler "$name" will be interpreted as an inline' 384 _logger.warning('Event handler "$name" will be interpreted as an inline'
401 ' JavaScript event handler. Use the form ' 385 ' JavaScript event handler. Use the form '
402 'on-event-name="handlerName" if you want a Dart handler ' 386 'on-event-name="handlerName" if you want a Dart handler '
403 'that will automatically update the UI based on model changes.', 387 'that will automatically update the UI based on model changes.',
404 span: node.attributeSpans[name]); 388 span: node.attributeSpans[name]);
405 return; 389 return;
406 } 390 }
407 391
(...skipping 19 matching lines...) Expand all
427 'annotation-xml': '', 411 'annotation-xml': '',
428 'color-profile': '', 412 'color-profile': '',
429 'font-face': '', 413 'font-face': '',
430 'font-face-src': '', 414 'font-face-src': '',
431 'font-face-uri': '', 415 'font-face-uri': '',
432 'font-face-format': '', 416 'font-face-format': '',
433 'font-face-name': '', 417 'font-face-name': '',
434 'missing-glyph': '', 418 'missing-glyph': '',
435 }; 419 };
436 420
437 /** 421 /// Returns true if this is a valid custom element name. See:
438 * Returns true if this is a valid custom element name. See: 422 /// <https://dvcs.w3.org/hg/webcomponents/raw-file/tip/spec/custom/index.html#df n-custom-element-name>
439 * <https://dvcs.w3.org/hg/webcomponents/raw-file/tip/spec/custom/index.html#dfn -custom-element-name>
440 */
441 bool _isCustomTag(String name) { 423 bool _isCustomTag(String name) {
442 if (name == null || !name.contains('-')) return false; 424 if (name == null || !name.contains('-')) return false;
443 return !_invalidTagNames.containsKey(name); 425 return !_invalidTagNames.containsKey(name);
444 } 426 }
445 427
446 const String USE_INIT_DART = 428 const String USE_INIT_DART =
447 'To run a polymer application, you need to call "initPolymer". You can ' 429 'To run a polymer application, you need to call "initPolymer". You can '
448 'either include a generic script tag that does this for you:' 430 'either include a generic script tag that does this for you:'
449 '\'<script type="application/dart">export "package:polymer/init.dart";' 431 '\'<script type="application/dart">export "package:polymer/init.dart";'
450 '</script>\' or add your own script tag and call that function. ' 432 '</script>\' or add your own script tag and call that function. '
451 'Make sure the script tag is placed after all HTML imports.'; 433 'Make sure the script tag is placed after all HTML imports.';
452 434
453 const String BOOT_JS_DEPRECATED = 435 const String BOOT_JS_DEPRECATED =
454 '"boot.js" is now deprecated. Instead, you can initialize your polymer ' 436 '"boot.js" is now deprecated. Instead, you can initialize your polymer '
455 'application by calling "initPolymer()" in your main. If you don\'t have a ' 437 'application by calling "initPolymer()" in your main. If you don\'t have a '
456 'main, then you can include our generic main by adding the following ' 438 'main, then you can include our generic main by adding the following '
457 'script tag to your page: \'<script type="application/dart">export ' 439 'script tag to your page: \'<script type="application/dart">export '
458 '"package:polymer/init.dart";</script>\'. Additionally you need to ' 440 '"package:polymer/init.dart";</script>\'. Additionally you need to '
459 'include: \'<script src="packages/browser/dart.js"></script>\' in the page ' 441 'include: \'<script src="packages/browser/dart.js"></script>\' in the page '
460 'too. Make sure these script tags come after all HTML imports.'; 442 'too. Make sure these script tags come after all HTML imports.';
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698