| Index: pkg/polymer/lib/src/build/script_compactor.dart
|
| diff --git a/pkg/polymer/lib/src/build/script_compactor.dart b/pkg/polymer/lib/src/build/script_compactor.dart
|
| index 1f76ae9ccbe3ac2ff94fb6521c4426b31d433ad8..1c46f1d1abe1a2aa98ccf684f08e448cd44a413c 100644
|
| --- a/pkg/polymer/lib/src/build/script_compactor.dart
|
| +++ b/pkg/polymer/lib/src/build/script_compactor.dart
|
| @@ -140,6 +140,8 @@ class _ScriptCompactor extends PolymerTransformer {
|
| /// Code generator used to create the static initialization for smoke.
|
| final generator = new SmokeCodeGenerator();
|
|
|
| + _SubExpressionVisitor expressionVisitor;
|
| +
|
| _ScriptCompactor(Transform transform, this.options, this.resolvers)
|
| : transform = transform,
|
| logger = transform.logger,
|
| @@ -228,7 +230,9 @@ class _ScriptCompactor extends PolymerTransformer {
|
| void _extractUsesOfMirrors(_) {
|
| // Generate getters and setters needed to evaluate polymer expressions, and
|
| // extract information about published attributes.
|
| - new _HtmlExtractor(logger, generator, publishedAttributes).visit(document);
|
| + expressionVisitor = new _SubExpressionVisitor(generator, logger);
|
| + new _HtmlExtractor(logger, generator, publishedAttributes,
|
| + expressionVisitor).visit(document);
|
|
|
| // Create a recorder that uses analyzer data to feed data to [generator].
|
| var recorder = new Recorder(generator,
|
| @@ -308,7 +312,16 @@ class _ScriptCompactor extends PolymerTransformer {
|
| // *Changed and @ObserveProperty instead.
|
| recorder.runQuery(cls, new QueryOptions(
|
| includeUpTo: types.htmlElementElement,
|
| - withAnnotations: [types.publishedElement, types.observableElement]));
|
| + withAnnotations: [types.publishedElement, types.observableElement,
|
| + types.computedPropertyElement]));
|
| +
|
| + // Include @ComputedProperty and process their expressions
|
| + var computed = [];
|
| + recorder.runQuery(cls, new QueryOptions(
|
| + includeUpTo: types.htmlElementElement,
|
| + withAnnotations: [types.computedPropertyElement]),
|
| + results: computed);
|
| + _processComputedExpressions(computed);
|
|
|
| for (var tagName in tagNames) {
|
| // Include an initializer that will call Polymer.register
|
| @@ -339,20 +352,28 @@ class _ScriptCompactor extends PolymerTransformer {
|
| /// If [meta] is [CustomTag], extract the name associated with the tag.
|
| String _extractTagName(Annotation meta, ClassElement cls) {
|
| if (meta.element != types.customTagConstructor) return null;
|
| + return _extractFirstAnnotationArgument(meta, 'CustomTag', cls);
|
| + }
|
| +
|
| + /// Extract the first argument of an annotation and validate that it's type is
|
| + /// String. For instance, return "bar" from `@Foo("bar")`.
|
| + String _extractFirstAnnotationArgument(Annotation meta, String name,
|
| + analyzer.Element context) {
|
|
|
| // Read argument from the AST
|
| var args = meta.arguments.arguments;
|
| if (args == null || args.length == 0) {
|
| - logger.warning('Missing argument in @CustomTag annotation',
|
| - span: _spanForNode(cls, meta));
|
| + logger.warning('Missing argument in @$name annotation',
|
| + span: _spanForNode(context, meta));
|
| return null;
|
| }
|
|
|
| - var res = resolver.evaluateConstant(
|
| - cls.enclosingElement.enclosingElement, args[0]);
|
| + var lib = context;
|
| + while (lib is! LibraryElement) lib = lib.enclosingElement;
|
| + var res = resolver.evaluateConstant(lib, args[0]);
|
| if (!res.isValid || res.value.type != types.stringType) {
|
| - logger.warning('The parameter to @CustomTag seems to be invalid.',
|
| - span: _spanForNode(cls, args[0]));
|
| + logger.warning('The parameter to @$name seems to be invalid.',
|
| + span: _spanForNode(context, args[0]));
|
| return null;
|
| }
|
| return res.value.stringValue;
|
| @@ -380,6 +401,22 @@ class _ScriptCompactor extends PolymerTransformer {
|
| initializers.add(new _InitMethodInitializer(id, function.displayName));
|
| }
|
|
|
| + /// Process members that are annotated with `@ComputedProperty` and records
|
| + /// the accessors of their expressions.
|
| + _processComputedExpressions(List<analyzer.Element> computed) {
|
| + var constructor = types.computedPropertyElement.constructors.first;
|
| + for (var member in computed) {
|
| + for (var meta in member.node.metadata) {
|
| + if (meta.element != constructor) continue;
|
| + var expr = _extractFirstAnnotationArgument(
|
| + meta, 'ComputedProperty', member);
|
| + if (expr == null) continue;
|
| + expressionVisitor.run(pe.parse(expr), true,
|
| + _spanForNode(member.enclosingElement, meta.arguments.arguments[0]));
|
| + }
|
| + }
|
| + }
|
| +
|
| /// Writes the final output for the bootstrap Dart file and entrypoint HTML
|
| /// file.
|
| void _emitFiles(_) {
|
| @@ -488,14 +525,12 @@ const NO_INITIALIZERS_ERROR =
|
| class _HtmlExtractor extends TreeVisitor {
|
| final Map<String, List<String>> publishedAttributes;
|
| final SmokeCodeGenerator generator;
|
| - final _SubExpressionVisitor visitor;
|
| + final _SubExpressionVisitor expressionVisitor;
|
| final TransformLogger logger;
|
| bool _inTemplate = false;
|
|
|
| - _HtmlExtractor(TransformLogger logger, SmokeCodeGenerator generator,
|
| - this.publishedAttributes)
|
| - : logger = logger, generator = generator,
|
| - visitor = new _SubExpressionVisitor(generator, logger);
|
| + _HtmlExtractor(this.logger, this.generator, this.publishedAttributes,
|
| + this.expressionVisitor);
|
|
|
| void visitElement(Element node) {
|
| if (_inTemplate) _processNormalElement(node);
|
| @@ -578,7 +613,7 @@ class _HtmlExtractor extends TreeVisitor {
|
| generator.addGetter(stringExpression);
|
| generator.addSymbol(stringExpression);
|
| }
|
| - visitor.run(pe.parse(stringExpression), isTwoWay, span);
|
| + expressionVisitor.run(pe.parse(stringExpression), isTwoWay, span);
|
| }
|
| }
|
|
|
| @@ -690,6 +725,9 @@ class _ResolvedTypes {
|
| /// Element representing the type of `@ObserveProperty`.
|
| final ClassElement observePropertyElement;
|
|
|
| + /// Element representing the type of `@ComputedProperty`.
|
| + final ClassElement computedPropertyElement;
|
| +
|
| /// Element representing the `@initMethod` annotation.
|
| final TopLevelVariableElement initMethodElement;
|
|
|
| @@ -723,6 +761,7 @@ class _ResolvedTypes {
|
| var publishedElement = _lookupType(polymerLib, 'PublishedProperty');
|
| var observableElement = _lookupType(observeLib, 'ObservableProperty');
|
| var observePropertyElement = _lookupType(polymerLib, 'ObserveProperty');
|
| + var computedPropertyElement = _lookupType(polymerLib, 'ComputedProperty');
|
| var polymerClassElement = _lookupType(polymerLib, 'Polymer');
|
| var htmlElementElement = _lookupType(htmlLib, 'HtmlElement');
|
| var stringType = _lookupType(coreLib, 'String').type;
|
| @@ -730,13 +769,15 @@ class _ResolvedTypes {
|
|
|
| return new _ResolvedTypes.internal(htmlElementElement, stringType,
|
| polymerClassElement, customTagConstructor, publishedElement,
|
| - observableElement, observePropertyElement, initMethodElement);
|
| + observableElement, observePropertyElement, computedPropertyElement,
|
| + initMethodElement);
|
| }
|
|
|
| _ResolvedTypes.internal(this.htmlElementElement, this.stringType,
|
| this.polymerClassElement, this.customTagConstructor,
|
| this.publishedElement, this.observableElement,
|
| - this.observePropertyElement, this.initMethodElement);
|
| + this.observePropertyElement, this.computedPropertyElement,
|
| + this.initMethodElement);
|
|
|
| static _lookupType(LibraryElement lib, String typeName) {
|
| var result = lib.getType(typeName);
|
|
|