anchor.diff:  const String _DIRECTIVE = '-directive';
   String _ATTR_DIRECTIVE = '-attr' + _DIRECTIVE;
   RegExp _ATTR_SELECTOR_REGEXP = new RegExp(r'\[([^\]]+)\]');
  +const List<String> _specs = const ['=>!', '=>', '<=>', '=', '!', '@', '&', '#', '%'];
   
   class SourceMetadataExtractor {
     SourceCrawler sourceCrawler;
  
positive.code:       DirectiveInfo dirInfo = new DirectiveInfo();
        dirInfo.selector = meta.selector;
        meta.attributeMappings.forEach((attrName, mappingSpec) {
          if (mappingSpec.startsWith('=') ||
              mappingSpec.startsWith('&') ||
              mappingSpec.startsWith('@') ||
              mappingSpec.startsWith('!')) {
            dirInfo.expressionAttrs.add(snakecase(attrName));
          }
          if (mappingSpec.length == 1) { // shorthand
            // TODO(pavelgj): Figure out if short-hand LHS should be expanded
            // and added to the expressions list.
            if (attrName != '.') {
              dirInfo.expressions.add(attrName);
            }
          } else {
            mappingSpec = mappingSpec.substring(1);
            if (mappingSpec.startsWith('.')) {
              mappingSpec = mappingSpec.substring(1);
            }
  
negative.code:   }
  }
  
  String _maybeCamelCase(String s) {
    if (s.indexOf('-') > -1) {
      return camelcase(s);
    }
    return s;
  }
  
  class DirectiveMetadataCollectingVisitor {
    List<DirectiveMetadata> metadata = <DirectiveMetadata>[];
  
  