| Index: pkg/polymer/lib/src/analyzer.dart | 
| diff --git a/pkg/polymer/lib/src/analyzer.dart b/pkg/polymer/lib/src/analyzer.dart | 
| deleted file mode 100644 | 
| index b8011a0f7d7e808f27a67c23c906098a3e14a2fc..0000000000000000000000000000000000000000 | 
| --- a/pkg/polymer/lib/src/analyzer.dart | 
| +++ /dev/null | 
| @@ -1,481 +0,0 @@ | 
| -// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file | 
| -// for details. All rights reserved. Use of this source code is governed by a | 
| -// BSD-style license that can be found in the LICENSE file. | 
| - | 
| -/** | 
| - * Part of the template compilation that concerns with extracting information | 
| - * from the HTML parse tree. | 
| - */ | 
| -library analyzer; | 
| - | 
| -import 'package:html5lib/dom.dart'; | 
| -import 'package:html5lib/dom_parsing.dart'; | 
| - | 
| -import 'custom_tag_name.dart'; | 
| -import 'files.dart'; | 
| -import 'info.dart'; | 
| -import 'messages.dart'; | 
| - | 
| -/** | 
| - * Finds custom elements in this file and the list of referenced files with | 
| - * component declarations. This is the first pass of analysis on a file. | 
| - * | 
| - * Adds emitted error/warning messages to [messages], if [messages] is | 
| - * supplied. | 
| - */ | 
| -FileInfo analyzeDefinitions(GlobalInfo global, UrlInfo inputUrl, | 
| -    Document document, String packageRoot, Messages messages) { | 
| -  var result = new FileInfo(inputUrl); | 
| -  var loader = new _ElementLoader(global, result, packageRoot, messages); | 
| -  loader.visit(document); | 
| -  return result; | 
| -} | 
| - | 
| -/** | 
| - *  Extract relevant information from all files found from the root document. | 
| - * | 
| - *  Adds emitted error/warning messages to [messages], if [messages] is | 
| - *  supplied. | 
| - */ | 
| -void analyzeFile(SourceFile file, Map<String, FileInfo> info, | 
| -                 Iterator<int> uniqueIds, GlobalInfo global, | 
| -                 Messages messages, emulateScopedCss) { | 
| -  var fileInfo = info[file.path]; | 
| -  var analyzer = new _Analyzer(fileInfo, uniqueIds, global, messages, | 
| -      emulateScopedCss); | 
| -  analyzer._normalize(fileInfo, info); | 
| -  analyzer.visit(file.document); | 
| -} | 
| - | 
| - | 
| -/** A visitor that walks the HTML to extract all the relevant information. */ | 
| -class _Analyzer extends TreeVisitor { | 
| -  final FileInfo _fileInfo; | 
| -  LibraryInfo _currentInfo; | 
| -  Iterator<int> _uniqueIds; | 
| -  GlobalInfo _global; | 
| -  Messages _messages; | 
| - | 
| -  int _generatedClassNumber = 0; | 
| - | 
| -  /** | 
| -   * Whether to keep indentation spaces. Break lines and indentation spaces | 
| -   * within templates are preserved in HTML. When users specify the attribute | 
| -   * 'indentation="remove"' on a template tag, we'll trim those indentation | 
| -   * spaces that occur within that tag and its decendants. If any decendant | 
| -   * specifies 'indentation="preserve"', then we'll switch back to the normal | 
| -   * behavior. | 
| -   */ | 
| -  bool _keepIndentationSpaces = true; | 
| - | 
| -  final bool _emulateScopedCss; | 
| - | 
| -  _Analyzer(this._fileInfo, this._uniqueIds, this._global, this._messages, | 
| -      this._emulateScopedCss) { | 
| -    _currentInfo = _fileInfo; | 
| -  } | 
| - | 
| -  void visitElement(Element node) { | 
| -    if (node.tagName == 'script') { | 
| -      // We already extracted script tags in previous phase. | 
| -      return; | 
| -    } | 
| - | 
| -    if (node.tagName == 'style') { | 
| -      // We've already parsed the CSS. | 
| -      // If this is a component remove the style node. | 
| -      if (_currentInfo is ComponentInfo && _emulateScopedCss) node.remove(); | 
| -      return; | 
| -    } | 
| - | 
| -    _bindCustomElement(node); | 
| - | 
| -    var lastInfo = _currentInfo; | 
| -    if (node.tagName == 'polymer-element') { | 
| -      // If element is invalid _ElementLoader already reported an error, but | 
| -      // we skip the body of the element here. | 
| -      var name = node.attributes['name']; | 
| -      if (name == null) return; | 
| - | 
| -      ComponentInfo component = _fileInfo.components[name]; | 
| -      if (component == null) return; | 
| - | 
| -      _analyzeComponent(component); | 
| - | 
| -      _currentInfo = component; | 
| - | 
| -      // Remove the <element> tag from the tree | 
| -      node.remove(); | 
| -    } | 
| - | 
| -    node.attributes.forEach((name, value) { | 
| -      if (name.startsWith('on')) { | 
| -        _validateEventHandler(node, name, value); | 
| -      } else  if (name == 'pseudo' && _currentInfo is ComponentInfo) { | 
| -        // Any component's custom pseudo-element(s) defined? | 
| -        _processPseudoAttribute(node, value.split(' ')); | 
| -      } | 
| -    }); | 
| - | 
| -    var keepSpaces = _keepIndentationSpaces; | 
| -    if (node.tagName == 'template' && | 
| -        node.attributes.containsKey('indentation')) { | 
| -      var value = node.attributes['indentation']; | 
| -      if (value != 'remove' && value != 'preserve') { | 
| -        _messages.warning( | 
| -            "Invalid value for 'indentation' ($value). By default we preserve " | 
| -            "the indentation. Valid values are either 'remove' or 'preserve'.", | 
| -            node.sourceSpan); | 
| -      } | 
| -      _keepIndentationSpaces = value != 'remove'; | 
| -    } | 
| - | 
| -    // Invoke super to visit children. | 
| -    super.visitElement(node); | 
| - | 
| -    _keepIndentationSpaces = keepSpaces; | 
| -    _currentInfo = lastInfo; | 
| -  } | 
| - | 
| -  void _analyzeComponent(ComponentInfo component) { | 
| -    var baseTag = component.extendsTag; | 
| -    component.extendsComponent = baseTag == null ? null | 
| -        : _fileInfo.components[baseTag]; | 
| -    if (component.extendsComponent == null && isCustomTag(baseTag)) { | 
| -      _messages.warning( | 
| -          'custom element with tag name ${component.extendsTag} not found.', | 
| -          component.element.sourceSpan); | 
| -    } | 
| -  } | 
| - | 
| -  void _bindCustomElement(Element node) { | 
| -    // <fancy-button> | 
| -    var component = _fileInfo.components[node.tagName]; | 
| -    if (component == null) { | 
| -      // TODO(jmesserly): warn for unknown element tags? | 
| - | 
| -      // <button is="fancy-button"> | 
| -      var componentName = node.attributes['is']; | 
| -      if (componentName != null) { | 
| -        component = _fileInfo.components[componentName]; | 
| -      } else if (isCustomTag(node.tagName)) { | 
| -        componentName = node.tagName; | 
| -      } | 
| -      if (component == null && componentName != null && | 
| -          componentName != 'polymer-element') { | 
| -        _messages.warning( | 
| -            'custom element with tag name $componentName not found.', | 
| -            node.sourceSpan); | 
| -      } | 
| -    } | 
| - | 
| -    if (component != null) { | 
| -      var baseTag = component.baseExtendsTag; | 
| -      var nodeTag = node.tagName; | 
| -      var hasIsAttribute = node.attributes.containsKey('is'); | 
| - | 
| -      if (baseTag != null && !hasIsAttribute) { | 
| -        _messages.warning( | 
| -            'custom element "${component.tagName}" extends from "$baseTag", but' | 
| -            ' this tag will not include the default properties of "$baseTag". ' | 
| -            'To fix this, either write this tag as <$baseTag ' | 
| -            'is="${component.tagName}"> or remove the "extends" attribute from ' | 
| -            'the custom element declaration.', node.sourceSpan); | 
| -      } else if (hasIsAttribute) { | 
| -        if (baseTag == null) { | 
| -          _messages.warning( | 
| -              'custom element "${component.tagName}" doesn\'t declare any type ' | 
| -              'extensions. To fix this, either rewrite this tag as ' | 
| -              '<${component.tagName}> or add \'extends="$nodeTag"\' to ' | 
| -              'the custom element declaration.', node.sourceSpan); | 
| -        } else if (baseTag != nodeTag) { | 
| -          _messages.warning( | 
| -              'custom element "${component.tagName}" extends from "$baseTag". ' | 
| -              'Did you mean to write <$baseTag is="${component.tagName}">?', | 
| -              node.sourceSpan); | 
| -        } | 
| -      } | 
| -    } | 
| -  } | 
| - | 
| -  void _processPseudoAttribute(Node node, List<String> values) { | 
| -    List mangledValues = []; | 
| -    for (var pseudoElement in values) { | 
| -      if (_global.pseudoElements.containsKey(pseudoElement)) continue; | 
| - | 
| -      _uniqueIds.moveNext(); | 
| -      var newValue = "${pseudoElement}_${_uniqueIds.current}"; | 
| -      _global.pseudoElements[pseudoElement] = newValue; | 
| -      // Mangled name of pseudo-element. | 
| -      mangledValues.add(newValue); | 
| - | 
| -      if (!pseudoElement.startsWith('x-')) { | 
| -        // TODO(terry): The name must start with x- otherwise it's not a custom | 
| -        //              pseudo-element.  May want to relax since components no | 
| -        //              longer need to start with x-.  See isse #509 on | 
| -        //              pseudo-element prefix. | 
| -        _messages.warning("Custom pseudo-element must be prefixed with 'x-'.", | 
| -            node.sourceSpan); | 
| -      } | 
| -    } | 
| - | 
| -    // Update the pseudo attribute with the new mangled names. | 
| -    node.attributes['pseudo'] = mangledValues.join(' '); | 
| -  } | 
| - | 
| -  /** | 
| -   * Support for inline event handlers that take expressions. | 
| -   * For example: `on-double-click=myHandler($event, todo)`. | 
| -   */ | 
| -  void _validateEventHandler(Element node, String name, String value) { | 
| -    if (!name.startsWith('on-')) { | 
| -      // TODO(jmesserly): do we need an option to suppress this warning? | 
| -      _messages.warning('Event handler $name will be interpreted as an inline ' | 
| -          'JavaScript event handler. Use the form ' | 
| -          'on-event-name="handlerName" if you want a Dart handler ' | 
| -          'that will automatically update the UI based on model changes.', | 
| -          node.sourceSpan); | 
| -    } | 
| - | 
| -    if (value.contains('.') || value.contains('(')) { | 
| -      // TODO(sigmund): should we allow more if we use fancy-syntax? | 
| -      _messages.warning('Invalid event handler body "$value". Declare a method ' | 
| -          'in your custom element "void handlerName(event, detail, target)" ' | 
| -          'and use the form on-event-name="handlerName".', | 
| -          node.sourceSpan); | 
| -    } | 
| -  } | 
| - | 
| -  /** | 
| -   * Normalizes references in [info]. On the [analyzeDefinitions] phase, the | 
| -   * analyzer extracted names of files and components. Here we link those names | 
| -   * to actual info classes. In particular: | 
| -   *   * we initialize the [FileInfo.components] map in [info] by importing all | 
| -   *     [declaredComponents], | 
| -   *   * we scan all [info.componentLinks] and import their | 
| -   *     [info.declaredComponents], using [files] to map the href to the file | 
| -   *     info. Names in [info] will shadow names from imported files. | 
| -   */ | 
| -  void _normalize(FileInfo info, Map<String, FileInfo> files) { | 
| -    for (var component in info.declaredComponents) { | 
| -      _addComponent(info, component); | 
| -    } | 
| - | 
| -    for (var link in info.componentLinks) { | 
| -      var file = files[link.resolvedPath]; | 
| -      // We already issued an error for missing files. | 
| -      if (file == null) continue; | 
| -      file.declaredComponents.forEach((c) => _addComponent(info, c)); | 
| -    } | 
| -  } | 
| - | 
| -  /** Adds a component's tag name to the names in scope for [fileInfo]. */ | 
| -  void _addComponent(FileInfo fileInfo, ComponentInfo component) { | 
| -    var existing = fileInfo.components[component.tagName]; | 
| -    if (existing != null) { | 
| -      if (existing == component) { | 
| -        // This is the same exact component as the existing one. | 
| -        return; | 
| -      } | 
| - | 
| -      if (existing is ComponentInfo && component is! ComponentInfo) { | 
| -        // Components declared in [fileInfo] shadow component names declared in | 
| -        // imported files. | 
| -        return; | 
| -      } | 
| - | 
| -      if (existing.hasConflict) { | 
| -        // No need to report a second error for the same name. | 
| -        return; | 
| -      } | 
| - | 
| -      existing.hasConflict = true; | 
| - | 
| -      if (component is ComponentInfo) { | 
| -        _messages.error('duplicate custom element definition for ' | 
| -            '"${component.tagName}".', existing.sourceSpan); | 
| -        _messages.error('duplicate custom element definition for ' | 
| -            '"${component.tagName}" (second location).', component.sourceSpan); | 
| -      } else { | 
| -        _messages.error('imported duplicate custom element definitions ' | 
| -            'for "${component.tagName}".', existing.sourceSpan); | 
| -        _messages.error('imported duplicate custom element definitions ' | 
| -            'for "${component.tagName}" (second location).', | 
| -            component.sourceSpan); | 
| -      } | 
| -    } else { | 
| -      fileInfo.components[component.tagName] = component; | 
| -    } | 
| -  } | 
| -} | 
| - | 
| -/** A visitor that finds `<link rel="import">` and `<element>` tags.  */ | 
| -class _ElementLoader extends TreeVisitor { | 
| -  final GlobalInfo _global; | 
| -  final FileInfo _fileInfo; | 
| -  LibraryInfo _currentInfo; | 
| -  String _packageRoot; | 
| -  bool _inHead = false; | 
| -  Messages _messages; | 
| - | 
| -  /** | 
| -   * Adds emitted warning/error messages to [_messages]. [_messages] | 
| -   * must not be null. | 
| -   */ | 
| -  _ElementLoader(this._global, this._fileInfo, this._packageRoot, | 
| -      this._messages) { | 
| -    _currentInfo = _fileInfo; | 
| -  } | 
| - | 
| -  void visitElement(Element node) { | 
| -    switch (node.tagName) { | 
| -      case 'link': visitLinkElement(node); break; | 
| -      case 'element': | 
| -        _messages.warning('<element> elements are not supported, use' | 
| -            ' <polymer-element> instead', node.sourceSpan); | 
| -        break; | 
| -      case 'polymer-element': | 
| -         visitElementElement(node); | 
| -         break; | 
| -      case 'script': visitScriptElement(node); break; | 
| -      case 'head': | 
| -        var savedInHead = _inHead; | 
| -        _inHead = true; | 
| -        super.visitElement(node); | 
| -        _inHead = savedInHead; | 
| -        break; | 
| -      default: super.visitElement(node); break; | 
| -    } | 
| -  } | 
| - | 
| -  /** | 
| -   * Process `link rel="import"` as specified in: | 
| -   * <https://dvcs.w3.org/hg/webcomponents/raw-file/tip/spec/components/index.html#link-type-component> | 
| -   */ | 
| -  void visitLinkElement(Element node) { | 
| -    var rel = node.attributes['rel']; | 
| -    if (rel != 'component' && rel != 'components' && | 
| -        rel != 'import' && rel != 'stylesheet') return; | 
| - | 
| -    if (!_inHead) { | 
| -      _messages.warning('link rel="$rel" only valid in ' | 
| -          'head.', node.sourceSpan); | 
| -      return; | 
| -    } | 
| - | 
| -    if (rel == 'component' || rel == 'components') { | 
| -      _messages.warning('import syntax is changing, use ' | 
| -          'rel="import" instead of rel="$rel".', node.sourceSpan); | 
| -    } | 
| - | 
| -    var href = node.attributes['href']; | 
| -    if (href == null || href == '') { | 
| -      _messages.warning('link rel="$rel" missing href.', | 
| -          node.sourceSpan); | 
| -      return; | 
| -    } | 
| - | 
| -    bool isStyleSheet = rel == 'stylesheet'; | 
| -    var urlInfo = UrlInfo.resolve(href, _fileInfo.inputUrl, node.sourceSpan, | 
| -        _packageRoot, _messages, ignoreAbsolute: isStyleSheet); | 
| -    if (urlInfo == null) return; | 
| -    if (isStyleSheet) { | 
| -      _fileInfo.styleSheetHrefs.add(urlInfo); | 
| -    } else { | 
| -      _fileInfo.componentLinks.add(urlInfo); | 
| -    } | 
| -  } | 
| - | 
| -  void visitElementElement(Element node) { | 
| -    // TODO(jmesserly): what do we do in this case? It seems like an <element> | 
| -    // inside a Shadow DOM should be scoped to that <template> tag, and not | 
| -    // visible from the outside. | 
| -    if (_currentInfo is ComponentInfo) { | 
| -      _messages.error('Nested component definitions are not yet supported.', | 
| -          node.sourceSpan); | 
| -      return; | 
| -    } | 
| - | 
| -    var tagName = node.attributes['name']; | 
| -    var extendsTag = node.attributes['extends']; | 
| - | 
| -    if (tagName == null) { | 
| -      _messages.error('Missing tag name of the component. Please include an ' | 
| -          'attribute like \'name="your-tag-name"\'.', | 
| -          node.sourceSpan); | 
| -      return; | 
| -    } | 
| - | 
| -    var component = new ComponentInfo(node, tagName, extendsTag); | 
| -    _fileInfo.declaredComponents.add(component); | 
| -    _addComponent(component); | 
| - | 
| -    var lastInfo = _currentInfo; | 
| -    _currentInfo = component; | 
| -    super.visitElement(node); | 
| -    _currentInfo = lastInfo; | 
| -  } | 
| - | 
| -  /** Adds a component's tag name to the global list. */ | 
| -  void _addComponent(ComponentInfo component) { | 
| -    var existing = _global.components[component.tagName]; | 
| -    if (existing != null) { | 
| -      if (existing.hasConflict) { | 
| -        // No need to report a second error for the same name. | 
| -        return; | 
| -      } | 
| - | 
| -      existing.hasConflict = true; | 
| - | 
| -      _messages.error('duplicate custom element definition for ' | 
| -          '"${component.tagName}".', existing.sourceSpan); | 
| -      _messages.error('duplicate custom element definition for ' | 
| -          '"${component.tagName}" (second location).', component.sourceSpan); | 
| -    } else { | 
| -      _global.components[component.tagName] = component; | 
| -    } | 
| -  } | 
| - | 
| -  void visitScriptElement(Element node) { | 
| -    var scriptType = node.attributes['type']; | 
| -    var src = node.attributes["src"]; | 
| - | 
| -    if (scriptType == null) { | 
| -      // Note: in html5 leaving off type= is fine, but it defaults to | 
| -      // text/javascript. Because this might be a common error, we warn about it | 
| -      // in two cases: | 
| -      //   * an inline script tag in a web component | 
| -      //   * a script src= if the src file ends in .dart (component or not) | 
| -      // | 
| -      // The hope is that neither of these cases should break existing valid | 
| -      // code, but that they'll help component authors avoid having their Dart | 
| -      // code accidentally interpreted as JavaScript by the browser. | 
| -      if (src == null && _currentInfo is ComponentInfo) { | 
| -        _messages.warning('script tag in component with no type will ' | 
| -            'be treated as JavaScript. Did you forget type="application/dart"?', | 
| -            node.sourceSpan); | 
| -      } | 
| -      if (src != null && src.endsWith('.dart')) { | 
| -        _messages.warning('script tag with .dart source file but no type will ' | 
| -            'be treated as JavaScript. Did you forget type="application/dart"?', | 
| -            node.sourceSpan); | 
| -      } | 
| -      return; | 
| -    } | 
| - | 
| -    if (scriptType != 'application/dart') return; | 
| - | 
| -    if (src != null) { | 
| -      if (!src.endsWith('.dart')) { | 
| -        _messages.warning('"application/dart" scripts should ' | 
| -            'use the .dart file extension.', | 
| -            node.sourceSpan); | 
| -      } | 
| - | 
| -      if (node.innerHtml.trim() != '') { | 
| -        _messages.error('script tag has "src" attribute and also has script ' | 
| -            'text.', node.sourceSpan); | 
| -      } | 
| -    } | 
| -  } | 
| -} | 
|  |