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 /// Transfomer that combines multiple dart script tags into a single one. | 5 /// Transfomer that combines multiple dart script tags into a single one. |
6 library polymer.src.build.script_compactor; | 6 library polymer.src.build.script_compactor; |
7 | 7 |
8 import 'dart:async'; | 8 import 'dart:async'; |
9 import 'dart:convert'; | 9 import 'dart:convert'; |
10 | 10 |
(...skipping 27 matching lines...) Expand all Loading... |
38 /// [ImportInliner] on an earlier phase. | 38 /// [ImportInliner] on an earlier phase. |
39 /// | 39 /// |
40 /// Internally, this transformer will convert each script tag into an import | 40 /// Internally, this transformer will convert each script tag into an import |
41 /// statement to a library, and then uses `initPolymer` (see polymer.dart) to | 41 /// statement to a library, and then uses `initPolymer` (see polymer.dart) to |
42 /// process `@initMethod` and `@CustomTag` annotations in those libraries. | 42 /// process `@initMethod` and `@CustomTag` annotations in those libraries. |
43 class ScriptCompactor extends Transformer { | 43 class ScriptCompactor extends Transformer { |
44 final Resolvers resolvers; | 44 final Resolvers resolvers; |
45 final TransformOptions options; | 45 final TransformOptions options; |
46 | 46 |
47 ScriptCompactor(this.options, {String sdkDir}) | 47 ScriptCompactor(this.options, {String sdkDir}) |
48 : resolvers = new Resolvers(sdkDir != null ? sdkDir : dartSdkDirectory); | 48 // TODO(sigmund): consider restoring here a resolver that uses the real |
| 49 // SDK once the analyzer is lazy and only an resolves what it needs: |
| 50 //: resolvers = new Resolvers(sdkDir != null ? sdkDir : dartSdkDirectory); |
| 51 : resolvers = new Resolvers.fromMock({ |
| 52 // The list of types below is derived from: |
| 53 // * types we use via our smoke queries, including HtmlElement and |
| 54 // types from `_typeHandlers` (deserialize.dart) |
| 55 // * types that are used internally by the resolver (see |
| 56 // _initializeFrom in resolver.dart). |
| 57 'dart:core': ''' |
| 58 library dart.core; |
| 59 class Object {} |
| 60 class Function {} |
| 61 class StackTrace {} |
| 62 class Symbol {} |
| 63 class Type {} |
| 64 |
| 65 class String extends Object {} |
| 66 class bool extends Object {} |
| 67 class num extends Object {} |
| 68 class int extends num {} |
| 69 class double extends num {} |
| 70 class DateTime extends Object {} |
| 71 class Null extends Object {} |
| 72 |
| 73 class Deprecated extends Object { |
| 74 final String expires; |
| 75 const Deprecated(this.expires); |
| 76 } |
| 77 const Object deprecated = const Deprecated("next release"); |
| 78 |
| 79 class List<V> extends Object {} |
| 80 class Map<K, V> extends Object {} |
| 81 ''', |
| 82 'dart:html': ''' |
| 83 library dart.html; |
| 84 class HtmlElement {} |
| 85 ''', |
| 86 }); |
| 87 |
| 88 |
49 | 89 |
50 /// Only run on entry point .html files. | 90 /// Only run on entry point .html files. |
51 // TODO(nweiz): This should just take an AssetId when barback <0.13.0 support | 91 // TODO(nweiz): This should just take an AssetId when barback <0.13.0 support |
52 // is dropped. | 92 // is dropped. |
53 Future<bool> isPrimary(idOrAsset) { | 93 Future<bool> isPrimary(idOrAsset) { |
54 var id = idOrAsset is AssetId ? idOrAsset : idOrAsset.id; | 94 var id = idOrAsset is AssetId ? idOrAsset : idOrAsset.id; |
55 return new Future.value(options.isHtmlEntryPoint(id)); | 95 return new Future.value(options.isHtmlEntryPoint(id)); |
56 } | 96 } |
57 | 97 |
58 Future apply(Transform transform) => | 98 Future apply(Transform transform) => |
(...skipping 118 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
177 /// package. This includes: | 217 /// package. This includes: |
178 /// | 218 /// |
179 /// * visiting entry-libraries to extract initializers, | 219 /// * visiting entry-libraries to extract initializers, |
180 /// * visiting polymer-expressions to extract getters and setters, | 220 /// * visiting polymer-expressions to extract getters and setters, |
181 /// * looking for published fields of custom elements, and | 221 /// * looking for published fields of custom elements, and |
182 /// * looking for event handlers and callbacks of change notifications. | 222 /// * looking for event handlers and callbacks of change notifications. |
183 /// | 223 /// |
184 void _extractUsesOfMirrors(_) { | 224 void _extractUsesOfMirrors(_) { |
185 // Generate getters and setters needed to evaluate polymer expressions, and | 225 // Generate getters and setters needed to evaluate polymer expressions, and |
186 // extract information about published attributes. | 226 // extract information about published attributes. |
187 new _HtmlExtractor(generator, publishedAttributes).visit(document); | 227 new _HtmlExtractor(logger, generator, publishedAttributes).visit(document); |
188 | 228 |
189 // Create a recorder that uses analyzer data to feed data to [generator]. | 229 // Create a recorder that uses analyzer data to feed data to [generator]. |
190 var recorder = new Recorder(generator, | 230 var recorder = new Recorder(generator, |
191 (lib) => resolver.getImportUri(lib, from: bootstrapId).toString()); | 231 (lib) => resolver.getImportUri(lib, from: bootstrapId).toString()); |
192 | 232 |
193 // Process all classes and top-level functions to include initializers, | 233 // Process all classes and top-level functions to include initializers, |
194 // register custom elements, and include special fields and methods in | 234 // register custom elements, and include special fields and methods in |
195 // custom element classes. | 235 // custom element classes. |
196 for (var id in entryLibraries) { | 236 for (var id in entryLibraries) { |
197 var lib = resolver.getLibrary(id); | 237 var lib = resolver.getLibrary(id); |
(...skipping 238 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
436 | 476 |
437 /// An html visitor that: | 477 /// An html visitor that: |
438 /// * finds all polymer expressions and records the getters and setters that | 478 /// * finds all polymer expressions and records the getters and setters that |
439 /// will be needed to evaluate them at runtime. | 479 /// will be needed to evaluate them at runtime. |
440 /// * extracts all attributes declared in the `attribute` attributes of | 480 /// * extracts all attributes declared in the `attribute` attributes of |
441 /// polymer elements. | 481 /// polymer elements. |
442 class _HtmlExtractor extends TreeVisitor { | 482 class _HtmlExtractor extends TreeVisitor { |
443 final Map<String, List<String>> publishedAttributes; | 483 final Map<String, List<String>> publishedAttributes; |
444 final SmokeCodeGenerator generator; | 484 final SmokeCodeGenerator generator; |
445 final _SubExpressionVisitor visitor; | 485 final _SubExpressionVisitor visitor; |
| 486 final TransformLogger logger; |
446 bool _inTemplate = false; | 487 bool _inTemplate = false; |
447 | 488 |
448 _HtmlExtractor(SmokeCodeGenerator generator, this.publishedAttributes) | 489 _HtmlExtractor(this.logger, SmokeCodeGenerator generator, |
| 490 this.publishedAttributes) |
449 : generator = generator, | 491 : generator = generator, |
450 visitor = new _SubExpressionVisitor(generator); | 492 visitor = new _SubExpressionVisitor(generator); |
451 | 493 |
452 void visitElement(Element node) { | 494 void visitElement(Element node) { |
453 if (_inTemplate) _processNormalElement(node); | 495 if (_inTemplate) _processNormalElement(node); |
454 if (node.localName == 'polymer-element') { | 496 if (node.localName == 'polymer-element') { |
455 _processPolymerElement(node); | 497 _processPolymerElement(node); |
456 _processNormalElement(node); | 498 _processNormalElement(node); |
457 } | 499 } |
458 | 500 |
459 if (node.localName == 'template') { | 501 if (node.localName == 'template') { |
460 var last = _inTemplate; | 502 var last = _inTemplate; |
461 _inTemplate = true; | 503 _inTemplate = true; |
462 super.visitElement(node); | 504 super.visitElement(node); |
463 _inTemplate = last; | 505 _inTemplate = last; |
464 } else { | 506 } else { |
465 super.visitElement(node); | 507 super.visitElement(node); |
466 } | 508 } |
467 } | 509 } |
468 | 510 |
469 void visitText(Text node) { | 511 void visitText(Text node) { |
470 if (!_inTemplate) return; | 512 if (!_inTemplate) return; |
471 var bindings = _Mustaches.parse(node.data); | 513 var bindings = _Mustaches.parse(node.data); |
472 if (bindings == null) return; | 514 if (bindings == null) return; |
473 for (var e in bindings.expressions) { | 515 for (var e in bindings.expressions) { |
474 _addExpression(e, false, false); | 516 _addExpression(e, false, false, node.sourceSpan); |
475 } | 517 } |
476 } | 518 } |
477 | 519 |
478 /// Registers getters and setters for all published attributes. | 520 /// Registers getters and setters for all published attributes. |
479 void _processPolymerElement(Element node) { | 521 void _processPolymerElement(Element node) { |
480 var tagName = node.attributes['name']; | 522 var tagName = node.attributes['name']; |
481 var value = node.attributes['attributes']; | 523 var value = node.attributes['attributes']; |
482 if (value != null) { | 524 if (value != null) { |
483 publishedAttributes[tagName] = | 525 publishedAttributes[tagName] = |
484 value.split(ATTRIBUTES_REGEX).map((a) => a.trim()).toList(); | 526 value.split(ATTRIBUTES_REGEX).map((a) => a.trim()).toList(); |
(...skipping 14 matching lines...) Expand all Loading... |
499 var isTwoWay = false; | 541 var isTwoWay = false; |
500 if (name is String) { | 542 if (name is String) { |
501 name = name.toLowerCase(); | 543 name = name.toLowerCase(); |
502 isEvent = name.startsWith('on-'); | 544 isEvent = name.startsWith('on-'); |
503 isTwoWay = !isEvent && bindings.isWhole && (isCustomTag || | 545 isTwoWay = !isEvent && bindings.isWhole && (isCustomTag || |
504 tag == 'input' && (name == 'value' || name =='checked') || | 546 tag == 'input' && (name == 'value' || name =='checked') || |
505 tag == 'select' && (name == 'selectedindex' || name == 'value') || | 547 tag == 'select' && (name == 'selectedindex' || name == 'value') || |
506 tag == 'textarea' && name == 'value'); | 548 tag == 'textarea' && name == 'value'); |
507 } | 549 } |
508 for (var exp in bindings.expressions) { | 550 for (var exp in bindings.expressions) { |
509 _addExpression(exp, isEvent, isTwoWay); | 551 _addExpression(exp, isEvent, isTwoWay, node.sourceSpan); |
510 } | 552 } |
511 }); | 553 }); |
512 } | 554 } |
513 | 555 |
514 void _addExpression(String stringExpression, bool inEvent, bool isTwoWay) { | 556 void _addExpression(String stringExpression, bool inEvent, bool isTwoWay, |
| 557 span) { |
| 558 |
515 if (inEvent) { | 559 if (inEvent) { |
516 if (!stringExpression.startsWith("@")) { | 560 if (stringExpression.startsWith('@')) { |
517 if (stringExpression == '') return; | 561 logger.warning('event bindings with @ are no longer supported', |
518 generator.addGetter(stringExpression); | 562 span: span); |
519 generator.addSymbol(stringExpression); | |
520 return; | 563 return; |
521 } | 564 } |
522 stringExpression = stringExpression.substring(1); | 565 |
| 566 if (stringExpression == '') return; |
| 567 generator.addGetter(stringExpression); |
| 568 generator.addSymbol(stringExpression); |
523 } | 569 } |
524 visitor.run(pe.parse(stringExpression), isTwoWay); | 570 visitor.run(pe.parse(stringExpression), isTwoWay); |
525 } | 571 } |
526 } | 572 } |
527 | 573 |
528 /// A polymer-expression visitor that records every getter and setter that will | 574 /// A polymer-expression visitor that records every getter and setter that will |
529 /// be needed to evaluate a single expression at runtime. | 575 /// be needed to evaluate a single expression at runtime. |
530 class _SubExpressionVisitor extends pe.RecursiveVisitor { | 576 class _SubExpressionVisitor extends pe.RecursiveVisitor { |
531 final SmokeCodeGenerator generator; | 577 final SmokeCodeGenerator generator; |
532 bool _includeSetter; | 578 bool _includeSetter; |
(...skipping 161 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
694 for (var e in lib.exports) { | 740 for (var e in lib.exports) { |
695 var exported = e.exportedLibrary.units.expand((u) => u.types).toList(); | 741 var exported = e.exportedLibrary.units.expand((u) => u.types).toList(); |
696 _filter(exported, e.combinators); | 742 _filter(exported, e.combinators); |
697 result.addAll(exported); | 743 result.addAll(exported); |
698 } | 744 } |
699 return result; | 745 return result; |
700 } | 746 } |
701 | 747 |
702 /// Retrieves all top-level methods that are visible if you were to import | 748 /// Retrieves all top-level methods that are visible if you were to import |
703 /// [lib]. This includes exported methods from other libraries too. | 749 /// [lib]. This includes exported methods from other libraries too. |
704 List<ClassElement> _visibleTopLevelMethodsOf(LibraryElement lib) { | 750 List<FunctionElement> _visibleTopLevelMethodsOf(LibraryElement lib) { |
705 var result = []; | 751 var result = []; |
706 result.addAll(lib.units.expand((u) => u.functions)); | 752 result.addAll(lib.units.expand((u) => u.functions)); |
707 for (var e in lib.exports) { | 753 for (var e in lib.exports) { |
708 var exported = e.exportedLibrary.units | 754 var exported = e.exportedLibrary.units |
709 .expand((u) => u.functions).toList(); | 755 .expand((u) => u.functions).toList(); |
710 _filter(exported, e.combinators); | 756 _filter(exported, e.combinators); |
711 result.addAll(exported); | 757 result.addAll(exported); |
712 } | 758 } |
713 return result; | 759 return result; |
714 } | 760 } |
715 | 761 |
716 /// Filters [elements] that come from an export, according to its show/hide | 762 /// Filters [elements] that come from an export, according to its show/hide |
717 /// combinators. This modifies [elements] in place. | 763 /// combinators. This modifies [elements] in place. |
718 void _filter(List<analyzer.Element> elements, | 764 void _filter(List<analyzer.Element> elements, |
719 List<NamespaceCombinator> combinators) { | 765 List<NamespaceCombinator> combinators) { |
720 for (var c in combinators) { | 766 for (var c in combinators) { |
721 if (c is ShowElementCombinator) { | 767 if (c is ShowElementCombinator) { |
722 var show = c.shownNames.toSet(); | 768 var show = c.shownNames.toSet(); |
723 elements.retainWhere((e) => show.contains(e.displayName)); | 769 elements.retainWhere((e) => show.contains(e.displayName)); |
724 } else if (c is HideElementCombinator) { | 770 } else if (c is HideElementCombinator) { |
725 var hide = c.hiddenNames.toSet(); | 771 var hide = c.hiddenNames.toSet(); |
726 elements.removeWhere((e) => hide.contains(e.displayName)); | 772 elements.removeWhere((e) => hide.contains(e.displayName)); |
727 } | 773 } |
728 } | 774 } |
729 } | 775 } |
OLD | NEW |