| 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 |