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

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

Issue 513023002: Step one towards stable error messages with details: (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Created 6 years, 3 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 /// 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
11 import 'package:html5lib/dom.dart' show Document, Element, Text; 11 import 'package:html5lib/dom.dart' show Document, Element, Text;
12 import 'package:html5lib/dom_parsing.dart'; 12 import 'package:html5lib/dom_parsing.dart';
13 import 'package:html5lib/parser.dart' show parseFragment; 13 import 'package:html5lib/parser.dart' show parseFragment;
14 import 'package:analyzer/src/generated/ast.dart'; 14 import 'package:analyzer/src/generated/ast.dart';
15 import 'package:analyzer/src/generated/element.dart' hide Element; 15 import 'package:analyzer/src/generated/element.dart' hide Element;
16 import 'package:analyzer/src/generated/element.dart' as analyzer show Element; 16 import 'package:analyzer/src/generated/element.dart' as analyzer show Element;
17 import 'package:barback/barback.dart'; 17 import 'package:barback/barback.dart';
18 import 'package:code_transformers/messages/build_logger.dart';
18 import 'package:path/path.dart' as path; 19 import 'package:path/path.dart' as path;
19 import 'package:source_span/source_span.dart'; 20 import 'package:source_span/source_span.dart';
20 import 'package:smoke/codegen/generator.dart'; 21 import 'package:smoke/codegen/generator.dart';
21 import 'package:smoke/codegen/recorder.dart'; 22 import 'package:smoke/codegen/recorder.dart';
22 import 'package:code_transformers/resolver.dart'; 23 import 'package:code_transformers/resolver.dart';
23 import 'package:code_transformers/src/dart_sdk.dart'; 24 import 'package:code_transformers/src/dart_sdk.dart';
24 import 'package:template_binding/src/mustache_tokens.dart' show MustacheTokens; 25 import 'package:template_binding/src/mustache_tokens.dart' show MustacheTokens;
25 26
26 import 'package:polymer_expressions/expression.dart' as pe; 27 import 'package:polymer_expressions/expression.dart' as pe;
27 import 'package:polymer_expressions/parser.dart' as pe; 28 import 'package:polymer_expressions/parser.dart' as pe;
28 import 'package:polymer_expressions/visitor.dart' as pe; 29 import 'package:polymer_expressions/visitor.dart' as pe;
29 30
31 import 'common.dart';
30 import 'import_inliner.dart' show ImportInliner; // just for docs. 32 import 'import_inliner.dart' show ImportInliner; // just for docs.
31 import 'common.dart'; 33 import 'messages.dart';
32 import 'wrapped_logger.dart';
33 34
34 /// Combines Dart script tags into a single script tag, and creates a new Dart 35 /// Combines Dart script tags into a single script tag, and creates a new Dart
35 /// file that calls the main function of each of the original script tags. 36 /// file that calls the main function of each of the original script tags.
36 /// 37 ///
37 /// This transformer assumes that all script tags point to external files. To 38 /// This transformer assumes that all script tags point to external files. To
38 /// support script tags with inlined code, use this transformer after running 39 /// support script tags with inlined code, use this transformer after running
39 /// [ImportInliner] on an earlier phase. 40 /// [ImportInliner] on an earlier phase.
40 /// 41 ///
41 /// Internally, this transformer will convert each script tag into an import 42 /// Internally, this transformer will convert each script tag into an import
42 /// statement to a library, and then uses `initPolymer` (see polymer.dart) to 43 /// statement to a library, and then uses `initPolymer` (see polymer.dart) to
(...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after
101 } 102 }
102 103
103 Future apply(Transform transform) => 104 Future apply(Transform transform) =>
104 new _ScriptCompactor(transform, options, resolvers).apply(); 105 new _ScriptCompactor(transform, options, resolvers).apply();
105 } 106 }
106 107
107 /// Helper class mainly use to flatten the async code. 108 /// Helper class mainly use to flatten the async code.
108 class _ScriptCompactor extends PolymerTransformer { 109 class _ScriptCompactor extends PolymerTransformer {
109 final TransformOptions options; 110 final TransformOptions options;
110 final Transform transform; 111 final Transform transform;
111 final TransformLogger logger; 112 final BuildLogger logger;
112 final AssetId docId; 113 final AssetId docId;
113 final AssetId bootstrapId; 114 final AssetId bootstrapId;
114 115
115 /// HTML document parsed from [docId]. 116 /// HTML document parsed from [docId].
116 Document document; 117 Document document;
117 118
118 /// List of ids for each Dart entry script tag (the main tag and any tag 119 /// List of ids for each Dart entry script tag (the main tag and any tag
119 /// included on each custom element definition). 120 /// included on each custom element definition).
120 List<AssetId> entryLibraries; 121 List<AssetId> entryLibraries;
121 122
(...skipping 17 matching lines...) Expand all
139 Resolver resolver; 140 Resolver resolver;
140 141
141 /// Code generator used to create the static initialization for smoke. 142 /// Code generator used to create the static initialization for smoke.
142 final generator = new SmokeCodeGenerator(); 143 final generator = new SmokeCodeGenerator();
143 144
144 _SubExpressionVisitor expressionVisitor; 145 _SubExpressionVisitor expressionVisitor;
145 146
146 _ScriptCompactor(Transform transform, options, this.resolvers) 147 _ScriptCompactor(Transform transform, options, this.resolvers)
147 : transform = transform, 148 : transform = transform,
148 options = options, 149 options = options,
149 logger = options.releaseMode ? transform.logger : 150 logger = new BuildLogger(
150 new WrappedLogger(transform, convertErrorsToWarnings: true), 151 transform, convertErrorsToWarnings: !options.releaseMode),
151 docId = transform.primaryInput.id, 152 docId = transform.primaryInput.id,
152 bootstrapId = transform.primaryInput.id.addExtension('_bootstrap.dart'); 153 bootstrapId = transform.primaryInput.id.addExtension('_bootstrap.dart');
153 154
154 Future apply() => 155 Future apply() =>
155 _loadDocument() 156 _loadDocument()
156 .then(_loadEntryLibraries) 157 .then(_loadEntryLibraries)
157 .then(_processHtml) 158 .then(_processHtml)
158 .then(_emitNewEntrypoint) 159 .then(_emitNewEntrypoint)
159 .then((_) { 160 .then((_) {
160 // Write out the logs collected by our [WrappedLogger]. 161 // Write out the logs collected by our [BuildLogger].
161 if (options.injectBuildLogsInOutput && logger is WrappedLogger) { 162 if (options.injectBuildLogsInOutput) return logger.writeOutput();
162 return (logger as WrappedLogger).writeOutput();
163 }
164 }); 163 });
165 164
166 /// Loads the primary input as an html document. 165 /// Loads the primary input as an html document.
167 Future _loadDocument() => 166 Future _loadDocument() =>
168 readPrimaryAsHtml(transform).then((doc) { document = doc; }); 167 readPrimaryAsHtml(transform, logger).then((doc) { document = doc; });
169 168
170 /// Populates [entryLibraries] as a list containing the asset ids of each 169 /// Populates [entryLibraries] as a list containing the asset ids of each
171 /// library loaded on a script tag. The actual work of computing this is done 170 /// library loaded on a script tag. The actual work of computing this is done
172 /// in an earlier phase and emited in the `entrypoint._data` asset. 171 /// in an earlier phase and emited in the `entrypoint._data` asset.
173 Future _loadEntryLibraries(_) => 172 Future _loadEntryLibraries(_) =>
174 transform.readInputAsString(docId.addExtension('._data')).then((data) { 173 transform.readInputAsString(docId.addExtension('._data')).then((data) {
175 var map = JSON.decode(data); 174 var map = JSON.decode(data);
176 experimentalBootstrap = map['experimental_bootstrap']; 175 experimentalBootstrap = map['experimental_bootstrap'];
177 entryLibraries = map['script_ids'] 176 entryLibraries = map['script_ids']
178 .map((id) => new AssetId.deserialize(id)) 177 .map((id) => new AssetId.deserialize(id))
179 .toList(); 178 .toList();
179 return Future.forEach(entryLibraries, logger.addLogFilesFromAsset);
180 }); 180 });
181 181
182 /// Removes unnecessary script tags, and identifies the main entry point Dart 182 /// Removes unnecessary script tags, and identifies the main entry point Dart
183 /// script tag (if any). 183 /// script tag (if any).
184 void _processHtml(_) { 184 void _processHtml(_) {
185 for (var tag in document.querySelectorAll('script')) { 185 for (var tag in document.querySelectorAll('script')) {
186 var src = tag.attributes['src']; 186 var src = tag.attributes['src'];
187 if (src == 'packages/polymer/boot.js') { 187 if (src == 'packages/polymer/boot.js') {
188 tag.remove(); 188 tag.remove();
189 continue; 189 continue;
190 } 190 }
191 if (tag.attributes['type'] == 'application/dart') { 191 if (tag.attributes['type'] == 'application/dart') {
192 logger.warning('unexpected script. The ' 192 logger.warning(internalErrorUnexpectedScript, span: tag.sourceSpan);
193 'ScriptCompactor transformer should run after running the '
194 'ImportInliner', span: tag.sourceSpan);
195 } 193 }
196 } 194 }
197 } 195 }
198 196
199 /// Emits the main HTML and Dart bootstrap code for the application. If there 197 /// Emits the main HTML and Dart bootstrap code for the application. If there
200 /// were not Dart entry point files, then this simply emits the original HTML. 198 /// were not Dart entry point files, then this simply emits the original HTML.
201 Future _emitNewEntrypoint(_) { 199 Future _emitNewEntrypoint(_) {
202 // If we don't find code, there is nothing to do. 200 // If we don't find code, there is nothing to do.
203 if (entryLibraries.isEmpty) return null; 201 if (entryLibraries.isEmpty) return null;
204 return _initResolver() 202 return _initResolver()
(...skipping 75 matching lines...) Expand 10 before | Expand all | Expand 10 after
280 // Check whether the class has a @CustomTag annotation. Typically we expect 278 // Check whether the class has a @CustomTag annotation. Typically we expect
281 // a single @CustomTag, but it's possible to have several. 279 // a single @CustomTag, but it's possible to have several.
282 var tagNames = []; 280 var tagNames = [];
283 for (var meta in cls.node.metadata) { 281 for (var meta in cls.node.metadata) {
284 var tagName = _extractTagName(meta, cls); 282 var tagName = _extractTagName(meta, cls);
285 if (tagName != null) tagNames.add(tagName); 283 if (tagName != null) tagNames.add(tagName);
286 } 284 }
287 285
288 if (cls.isPrivate && tagNames.isNotEmpty) { 286 if (cls.isPrivate && tagNames.isNotEmpty) {
289 var name = tagNames.first; 287 var name = tagNames.first;
290 logger.error('@CustomTag is not currently supported on private classes:' 288 logger.error(noPrivateCustomTag.create(
291 ' $name. Consider making this class public, or create a ' 289 {'name': name, 'class': cls.name}),
292 'public initialization method marked with `@initMethod` that calls '
293 '`Polymer.register($name, ${cls.name})`.',
294 span: _spanForNode(cls, cls.node.name)); 290 span: _spanForNode(cls, cls.node.name));
295 return; 291 return;
296 } 292 }
297 293
298 // Include #registerCallback if it exists. Note that by default lookupMember 294 // Include #registerCallback if it exists. Note that by default lookupMember
299 // and query will also add the corresponding getters and setters. 295 // and query will also add the corresponding getters and setters.
300 recorder.lookupMember(cls, 'registerCallback'); 296 recorder.lookupMember(cls, 'registerCallback');
301 297
302 // Include methods that end with *Changed. 298 // Include methods that end with *Changed.
303 recorder.runQuery(cls, new QueryOptions( 299 recorder.runQuery(cls, new QueryOptions(
(...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after
365 } 361 }
366 362
367 /// Extract the first argument of an annotation and validate that it's type is 363 /// Extract the first argument of an annotation and validate that it's type is
368 /// String. For instance, return "bar" from `@Foo("bar")`. 364 /// String. For instance, return "bar" from `@Foo("bar")`.
369 String _extractFirstAnnotationArgument(Annotation meta, String name, 365 String _extractFirstAnnotationArgument(Annotation meta, String name,
370 analyzer.Element context) { 366 analyzer.Element context) {
371 367
372 // Read argument from the AST 368 // Read argument from the AST
373 var args = meta.arguments.arguments; 369 var args = meta.arguments.arguments;
374 if (args == null || args.length == 0) { 370 if (args == null || args.length == 0) {
375 logger.warning('Missing argument in @$name annotation', 371 logger.warning(missingArgumentInAnnotation.create({'name': name}),
376 span: _spanForNode(context, meta)); 372 span: _spanForNode(context, meta));
377 return null; 373 return null;
378 } 374 }
379 375
380 var lib = context; 376 var lib = context;
381 while (lib is! LibraryElement) lib = lib.enclosingElement; 377 while (lib is! LibraryElement) lib = lib.enclosingElement;
382 var res = resolver.evaluateConstant(lib, args[0]); 378 var res = resolver.evaluateConstant(lib, args[0]);
383 if (!res.isValid || res.value.type != types.stringType) { 379 if (!res.isValid || res.value.type != types.stringType) {
384 logger.warning('The parameter to @$name seems to be invalid.', 380 logger.warning(invalidArgumentInAnnotation.create({'name': name}),
385 span: _spanForNode(context, args[0])); 381 span: _spanForNode(context, args[0]));
386 return null; 382 return null;
387 } 383 }
388 return res.value.stringValue; 384 return res.value.stringValue;
389 } 385 }
390 386
391 /// Adds the top-level [function] as an initalizer if it's marked with 387 /// Adds the top-level [function] as an initalizer if it's marked with
392 /// `@initMethod`. 388 /// `@initMethod`.
393 _processFunction(FunctionElement function, AssetId id) { 389 _processFunction(FunctionElement function, AssetId id) {
394 bool initMethodFound = false; 390 bool initMethodFound = false;
395 for (var meta in function.metadata) { 391 for (var meta in function.metadata) {
396 var e = meta.element; 392 var e = meta.element;
397 if (e is PropertyAccessorElement && 393 if (e is PropertyAccessorElement &&
398 e.variable == types.initMethodElement) { 394 e.variable == types.initMethodElement) {
399 initMethodFound = true; 395 initMethodFound = true;
400 break; 396 break;
401 } 397 }
402 } 398 }
403 if (!initMethodFound) return; 399 if (!initMethodFound) return;
404 if (function.isPrivate) { 400 if (function.isPrivate) {
405 logger.error('@initMethod is no longer supported on private ' 401 logger.error(noPrivateInitMethod.create({'name': function.displayName}),
406 'functions: ${function.displayName}',
407 span: _spanForNode(function, function.node.name)); 402 span: _spanForNode(function, function.node.name));
408 return; 403 return;
409 } 404 }
410 initializers.add(new _InitMethodInitializer(id, function.displayName)); 405 initializers.add(new _InitMethodInitializer(id, function.displayName));
411 } 406 }
412 407
413 /// Process members that are annotated with `@ComputedProperty` and records 408 /// Process members that are annotated with `@ComputedProperty` and records
414 /// the accessors of their expressions. 409 /// the accessors of their expressions.
415 _processComputedExpressions(List<analyzer.Element> computed) { 410 _processComputedExpressions(List<analyzer.Element> computed) {
416 var constructor = types.computedPropertyElement.constructors.first; 411 var constructor = types.computedPropertyElement.constructors.first;
(...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after
464 459
465 // Include initializers to switch from mirrors_loader to static_loader. 460 // Include initializers to switch from mirrors_loader to static_loader.
466 if (!initializers.isEmpty) { 461 if (!initializers.isEmpty) {
467 code.writeln(); 462 code.writeln();
468 for (var init in initializers) { 463 for (var init in initializers) {
469 var initCode = init.asCode(prefixes[init.assetId]); 464 var initCode = init.asCode(prefixes[init.assetId]);
470 code.write(" $initCode,\n"); 465 code.write(" $initCode,\n");
471 } 466 }
472 code.writeln(' ]);'); 467 code.writeln(' ]);');
473 } else { 468 } else {
474 if (experimentalBootstrap) logger.warning(NO_INITIALIZERS_ERROR); 469 if (experimentalBootstrap) logger.warning(noInitializersError);
475 code.writeln(']);'); 470 code.writeln(']);');
476 } 471 }
477 if (!experimentalBootstrap) { 472 if (!experimentalBootstrap) {
478 code.writeln(' i${entryLibraries.length - 1}.main();'); 473 code.writeln(' i${entryLibraries.length - 1}.main();');
479 } 474 }
480 475
481 // End of main(). 476 // End of main().
482 code.writeln('}'); 477 code.writeln('}');
483 transform.addOutput(new Asset.fromString(bootstrapId, code.toString())); 478 transform.addOutput(new Asset.fromString(bootstrapId, code.toString()));
484 479
(...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after
529 String asCode(String prefix) => 524 String asCode(String prefix) =>
530 "() => Polymer.register('$tagName', $prefix.$typeName)"; 525 "() => Polymer.register('$tagName', $prefix.$typeName)";
531 } 526 }
532 527
533 const MAIN_HEADER = """ 528 const MAIN_HEADER = """
534 library app_bootstrap; 529 library app_bootstrap;
535 530
536 import 'package:polymer/polymer.dart'; 531 import 'package:polymer/polymer.dart';
537 """; 532 """;
538 533
539 const NO_INITIALIZERS_ERROR =
540 'No polymer initializers were found. Make sure to either '
541 'annotate your polymer elements with @CustomTag or include a '
542 'top level method annotated with @initMethod that registers your '
543 'elements. Both annotations are defined in the polymer library ('
544 'package:polymer/polymer.dart).';
545 534
546 /// An html visitor that: 535 /// An html visitor that:
547 /// * finds all polymer expressions and records the getters and setters that 536 /// * finds all polymer expressions and records the getters and setters that
548 /// will be needed to evaluate them at runtime. 537 /// will be needed to evaluate them at runtime.
549 /// * extracts all attributes declared in the `attribute` attributes of 538 /// * extracts all attributes declared in the `attribute` attributes of
550 /// polymer elements. 539 /// polymer elements.
551 class _HtmlExtractor extends TreeVisitor { 540 class _HtmlExtractor extends TreeVisitor {
552 final Map<String, List<String>> publishedAttributes; 541 final Map<String, List<String>> publishedAttributes;
553 final SmokeCodeGenerator generator; 542 final SmokeCodeGenerator generator;
554 final _SubExpressionVisitor expressionVisitor; 543 final _SubExpressionVisitor expressionVisitor;
555 final TransformLogger logger; 544 final BuildLogger logger;
556 bool _inTemplate = false; 545 bool _inTemplate = false;
557 546
558 _HtmlExtractor(this.logger, this.generator, this.publishedAttributes, 547 _HtmlExtractor(this.logger, this.generator, this.publishedAttributes,
559 this.expressionVisitor); 548 this.expressionVisitor);
560 549
561 void visitElement(Element node) { 550 void visitElement(Element node) {
562 if (_inTemplate) _processNormalElement(node); 551 if (_inTemplate) _processNormalElement(node);
563 if (node.localName == 'polymer-element') { 552 if (node.localName == 'polymer-element') {
564 _processPolymerElement(node); 553 _processPolymerElement(node);
565 _processNormalElement(node); 554 _processNormalElement(node);
(...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after
618 _addExpression(exp, isEvent, isTwoWay, node.sourceSpan); 607 _addExpression(exp, isEvent, isTwoWay, node.sourceSpan);
619 } 608 }
620 }); 609 });
621 } 610 }
622 611
623 void _addExpression(String stringExpression, bool inEvent, bool isTwoWay, 612 void _addExpression(String stringExpression, bool inEvent, bool isTwoWay,
624 SourceSpan span) { 613 SourceSpan span) {
625 614
626 if (inEvent) { 615 if (inEvent) {
627 if (stringExpression.startsWith('@')) { 616 if (stringExpression.startsWith('@')) {
628 logger.warning('event bindings with @ are no longer supported', 617 logger.warning(noEventBindingsWithAtExpression, span: span);
629 span: span);
630 return; 618 return;
631 } 619 }
632 620
633 if (stringExpression == '') return; 621 if (stringExpression == '') return;
634 if (stringExpression.startsWith('_')) { 622 if (stringExpression.startsWith('_')) {
635 logger.warning('private symbols cannot be used in event handlers', 623 logger.warning(noPrivateEventHandlers, span: span);
636 span: span);
637 return; 624 return;
638 } 625 }
639 generator.addGetter(stringExpression); 626 generator.addGetter(stringExpression);
640 generator.addSymbol(stringExpression); 627 generator.addSymbol(stringExpression);
641 } 628 }
642 expressionVisitor.run(pe.parse(stringExpression), isTwoWay, span); 629 expressionVisitor.run(pe.parse(stringExpression), isTwoWay, span);
643 } 630 }
644 } 631 }
645 632
646 /// A polymer-expression visitor that records every getter and setter that will 633 /// A polymer-expression visitor that records every getter and setter that will
647 /// be needed to evaluate a single expression at runtime. 634 /// be needed to evaluate a single expression at runtime.
648 class _SubExpressionVisitor extends pe.RecursiveVisitor { 635 class _SubExpressionVisitor extends pe.RecursiveVisitor {
649 final SmokeCodeGenerator generator; 636 final SmokeCodeGenerator generator;
650 final TransformLogger logger; 637 final BuildLogger logger;
651 bool _includeSetter; 638 bool _includeSetter;
652 SourceSpan _currentSpan; 639 SourceSpan _currentSpan;
653 640
654 _SubExpressionVisitor(this.generator, this.logger); 641 _SubExpressionVisitor(this.generator, this.logger);
655 642
656 /// Visit [exp], and record getters and setters that are needed in order to 643 /// Visit [exp], and record getters and setters that are needed in order to
657 /// evaluate it at runtime. [includeSetter] is only true if this expression 644 /// evaluate it at runtime. [includeSetter] is only true if this expression
658 /// occured in a context where it could be updated, for example in two-way 645 /// occured in a context where it could be updated, for example in two-way
659 /// bindings such as `<input value={{exp}}>`. 646 /// bindings such as `<input value={{exp}}>`.
660 void run(pe.Expression exp, bool includeSetter, span) { 647 void run(pe.Expression exp, bool includeSetter, span) {
661 _currentSpan = span; 648 _currentSpan = span;
662 _includeSetter = includeSetter; 649 _includeSetter = includeSetter;
663 visit(exp); 650 visit(exp);
664 } 651 }
665 652
666 /// Adds a getter and symbol for [name], and optionally a setter. 653 /// Adds a getter and symbol for [name], and optionally a setter.
667 _add(String name) { 654 _add(String name) {
668 if (name.startsWith('_')) { 655 if (name.startsWith('_')) {
669 logger.warning('private symbols are not supported', span: _currentSpan); 656 logger.warning(noPrivateSymbolsInBinding, span: _currentSpan);
670 return; 657 return;
671 } 658 }
672 generator.addGetter(name); 659 generator.addGetter(name);
673 generator.addSymbol(name); 660 generator.addSymbol(name);
674 if (_includeSetter) generator.addSetter(name); 661 if (_includeSetter) generator.addSetter(name);
675 } 662 }
676 663
677 void preVisitExpression(e) { 664 void preVisitExpression(e) {
678 // For two-way bindings the outermost expression may be updated, so we need 665 // For two-way bindings the outermost expression may be updated, so we need
679 // both the getter and the setter, but we only need the getter for 666 // both the getter and the setter, but we only need the getter for
(...skipping 171 matching lines...) Expand 10 before | Expand all | Expand 10 after
851 for (var c in combinators) { 838 for (var c in combinators) {
852 if (c is ShowElementCombinator) { 839 if (c is ShowElementCombinator) {
853 var show = c.shownNames.toSet(); 840 var show = c.shownNames.toSet();
854 elements.retainWhere((e) => show.contains(e.displayName)); 841 elements.retainWhere((e) => show.contains(e.displayName));
855 } else if (c is HideElementCombinator) { 842 } else if (c is HideElementCombinator) {
856 var hide = c.hiddenNames.toSet(); 843 var hide = c.hiddenNames.toSet();
857 elements.removeWhere((e) => hide.contains(e.displayName)); 844 elements.removeWhere((e) => hide.contains(e.displayName));
858 } 845 }
859 } 846 }
860 } 847 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698