{"action":"created","comment":{"url":"https://api.github.com/repos/dart-lang/angular_analyzer_plugin/pulls/comments/107232540","pull_request_review_id":28192725,"id":107232540,"diff_hunk":"@@ -0,0 +1,663 @@\n+import 'dart:convert';\n+import 'dart:async';\n+import 'dart:collection';\n+import 'package:analysis_server/src/analysis_server.dart';\n+import 'package:analyzer/src/dart/analysis/byte_store.dart';\n+import 'package:analyzer/error/listener.dart';\n+import 'package:analyzer/src/generated/sdk.dart';\n+import 'package:analyzer/src/generated/source.dart';\n+import 'package:analyzer/dart/element/element.dart';\n+import 'package:analysis_server/plugin/protocol/protocol.dart' as protocol;\n+import 'package:analysis_server/src/protocol_server.dart' as protocol;\n+import 'package:analyzer/error/error.dart';\n+import 'package:analyzer/src/dart/analysis/driver.dart';\n+import 'package:analyzer/src/summary/api_signature.dart';\n+import 'package:angular_analyzer_plugin/tasks.dart';\n+import 'package:angular_analyzer_plugin/src/from_file_prefixed_error.dart';\n+import 'package:angular_analyzer_plugin/src/directive_extraction.dart';\n+import 'package:angular_analyzer_plugin/src/view_extraction.dart';\n+import 'package:angular_analyzer_plugin/src/model.dart';\n+import 'package:angular_analyzer_plugin/src/resolver.dart';\n+import 'package:angular_analyzer_plugin/src/converter.dart';\n+import 'package:angular_analyzer_plugin/src/directive_linking.dart';\n+import 'package:angular_analyzer_plugin/src/summary/idl.dart';\n+import 'package:angular_analyzer_plugin/src/summary/format.dart';\n+import 'package:angular_analyzer_plugin/src/standard_components.dart';\n+import 'package:analyzer/src/generated/engine.dart';\n+import 'package:tuple/tuple.dart';\n+import 'package:analyzer/src/dart/analysis/file_state.dart';\n+import 'package:crypto/crypto.dart';\n+\n+class AngularDriver\n+    implements\n+        AnalysisDriverGeneric,\n+        FileDirectiveProvider,\n+        DirectiveLinkerEnablement {\n+  final AnalysisServer server;\n+  final AnalysisDriverScheduler _scheduler;\n+  final AnalysisDriver dartDriver;\n+  final FileContentOverlay _contentOverlay;\n+  StandardHtml standardHtml = null;\n+  SourceFactory _sourceFactory;\n+  final LinkedHashSet<String> _addedFiles = new LinkedHashSet<String>();\n+  final LinkedHashSet<String> _dartFiles = new LinkedHashSet<String>();\n+  final LinkedHashSet<String> _changedFiles = new LinkedHashSet<String>();\n+  final Set<String> _requestedFiles = new HashSet<String>();\n+  final Set<String> _filesToAnalyze = new HashSet<String>();\n+  final Set<Tuple2<String, String>> _htmlViewsToAnalyze =\n+      new HashSet<Tuple2<String, String>>();\n+  final ByteStore byteStore;\n+\n+  AngularDriver(this.server, this.dartDriver, this._scheduler, this.byteStore,\n+      SourceFactory sourceFactory, this._contentOverlay) {\n+    _sourceFactory = sourceFactory.clone();\n+    _scheduler.add(this);\n+  }\n+\n+  bool get hasFilesToAnalyze =>\n+      _filesToAnalyze.isNotEmpty || _htmlViewsToAnalyze.isNotEmpty;\n+\n+  bool _ownsFile(String path) {\n+    return path.endsWith('.dart') || path.endsWith('.html');\n+  }\n+\n+  void addFile(String path) {\n+    if (_ownsFile(path)) {\n+      _addedFiles.add(path);\n+      if (path.endsWith('.dart')) {\n+        _dartFiles.add(path);\n+      }\n+      fileChanged(path);\n+    }\n+  }\n+\n+  void fileChanged(String path) {\n+    if (_ownsFile(path)) {\n+      _changedFiles.add(path);\n+    }\n+    _scheduler.notify(this);\n+  }\n+\n+  AnalysisDriverPriority get workPriority {\n+    if (standardHtml == null) {\n+      return AnalysisDriverPriority.interactive;\n+    }\n+\n+    if (_requestedFiles.isNotEmpty) {\n+      return AnalysisDriverPriority.interactive;\n+    }\n+    // tasks here?\n+    if (_filesToAnalyze.isNotEmpty) {\n+      return AnalysisDriverPriority.general;\n+    }\n+    if (_htmlViewsToAnalyze.isNotEmpty) {\n+      return AnalysisDriverPriority.general;\n+    }\n+    if (_changedFiles.isNotEmpty) {\n+      return AnalysisDriverPriority.general;\n+    }\n+    return AnalysisDriverPriority.nothing;\n+  }\n+\n+  Future<Null> performWork() async {\n+    if (standardHtml == null) {\n+      getStandardHtml();\n+      return;\n+    }\n+\n+    if (_changedFiles.isNotEmpty) {\n+      _changedFiles.clear();\n+      _filesToAnalyze.addAll(_dartFiles);\n+      return;\n+    }\n+\n+    if (_requestedFiles.isNotEmpty) {\n+      final path = _requestedFiles.first;\n+      try {\n+        pushDartErrors(path);\n+        pushDartNavigation(path);\n+        pushDartOccurrences(path);\n+        _requestedFiles.remove(path);\n+      } catch (e) {\n+        e;\n+      }\n+      return;\n+    }\n+\n+    if (_filesToAnalyze.isNotEmpty) {\n+      final path = _filesToAnalyze.first;\n+      pushDartErrors(path);\n+      _filesToAnalyze.remove(path);\n+      return;\n+    }\n+\n+    if (_htmlViewsToAnalyze.isNotEmpty) {\n+      final info = _htmlViewsToAnalyze.first;\n+      pushHtmlErrors(info.item1, info.item2);\n+      _htmlViewsToAnalyze.remove(info);\n+      return;\n+    }\n+\n+    return;\n+  }\n+\n+  Future<StandardHtml> getStandardHtml() async {\n+    if (standardHtml == null) {\n+      final source = _sourceFactory.resolveUri(null, DartSdk.DART_HTML);\n+      final result = await dartDriver.getResult(source.fullName);\n+      final components = <String, Component>{};\n+      final events = <String, OutputElement>{};\n+      final attributes = <String, InputElement>{};\n+      result.unit.accept(new BuildStandardHtmlComponentsVisitor(\n+          components, events, attributes, source));\n+\n+      standardHtml = new StandardHtml(components, events, attributes);\n+    }\n+\n+    return standardHtml;\n+  }\n+\n+  List<AnalysisError> deserializeFromPathErrors(\n+      Source source, List<SummarizedAnalysisErrorFromPath> errors) {\n+    return errors\n+        .map((error) {\n+          final originalError = deserializeError(source, error.originalError);\n+          if (originalError == null) {\n+            return null;\n+          }\n+          return new FromFilePrefixedError.fromPath(error.path, originalError);\n+        })\n+        .where((e) => e != null)\n+        .toList();\n+  }\n+\n+  List<AnalysisError> deserializeErrors(\n+      Source source, List<SummarizedAnalysisError> errors) {\n+    return errors\n+        .map((error) {\n+          return deserializeError(source, error);\n+        })\n+        .where((e) => e != null)\n+        .toList();\n+  }\n+\n+  AnalysisError deserializeError(Source source, SummarizedAnalysisError error) {\n+    final errorName = error.errorCode;\n+    final errorCode = angularWarningCodeByUniqueName(errorName) ??\n+        errorCodeByUniqueName(errorName);\n+    if (errorCode == null) {\n+      return null;\n+    }\n+    return new AnalysisError.forValues(source, error.offset, error.length,\n+        errorCode, error.message, error.correction);\n+  }\n+\n+  Future<String> getHtmlKey(String htmlPath, String dartPath) async {\n+    final key = getContentHash(htmlPath);\n+    key.addBytes(dartDriver.getUnitKeyByPath(dartPath).toByteList());\n+    final directives = (await getDirectives(dartPath)).directives;\n+    final unit = (await dartDriver.getUnitElement(dartPath)).element;\n+    if (unit == null) return null;\n+\n+    final linkErrorListener = new IgnoringErrorListener();\n+    final linkErrorReporter =\n+        new ErrorReporter(linkErrorListener, getSource(dartPath));\n+\n+    final linker = new ChildDirectiveLinker(this, linkErrorReporter);\n+    await linker.linkDirectives(directives, unit.library);\n+\n+    // Trap case: there may be multiple directives that match this!\n+    directives\n+        .where((directive) =>\n+            directive is Component &&\n+            directive.view?.templateUriSource?.fullName == htmlPath)\n+        .forEach((AbstractDirective directive) {\n+      final Component component = directive;\n+      for (final subdirective in component.view.directives) {\n+        if (subdirective is Component &&\n+            subdirective?.view?.templateUriSource != null) {\n+          key.addBytes(\n+              getContentHash(subdirective.view.templateUriSource.fullName)\n+                  .toByteList());\n+        }\n+      }\n+    });\n+\n+    return key.toHex() + '.ngresolved';\n+  }\n+\n+  ApiSignature getContentHash(String path) {\n+    final key = new ApiSignature();\n+    List<int> contentBytes = UTF8.encode(getFileContent(path));\n+    key.addBytes(md5.convert(contentBytes).bytes);\n+    return key;\n+  }\n+\n+  String getFileContent(String path) {\n+    return _contentOverlay[path] ??\n+        ((source) =>\n+            source.exists() ? source.contents.data : \"\")(getSource(path));\n+  }\n+\n+  Future<DirectivesResult> resolveHtml(String htmlPath, String dartPath) async {\n+    final key = await getHtmlKey(htmlPath, dartPath);\n+    final htmlSource = _sourceFactory.forUri(\"file:\" + htmlPath);\n+    final List<int> bytes = byteStore.get(key);\n+    if (bytes != null) {\n+      final summary = new LinkedHtmlSummary.fromBuffer(bytes);\n+      final errors = new List<AnalysisError>.from(\n+          deserializeErrors(htmlSource, summary.errors))\n+        ..addAll(deserializeFromPathErrors(htmlSource, summary.errorsFromPath));\n+      return new DirectivesResult([], errors);\n+    }\n+\n+    final result = await getDirectives(dartPath);\n+    final directives = result.directives;\n+    final unit = (await dartDriver.getUnitElement(dartPath)).element;\n+\n+    if (unit == null) return null;\n+    final context = unit.context;\n+    final dartSource = _sourceFactory.forUri(\"file:\" + dartPath);\n+    final htmlContent = getFileContent(htmlPath);\n+    final standardHtml = await getStandardHtml();\n+\n+    final errors = <AnalysisError>[];\n+    // ignore link errors, they are exposed when resolving dart\n+    final linkErrorListener = new IgnoringErrorListener();\n+    final linkErrorReporter = new ErrorReporter(linkErrorListener, dartSource);\n+\n+    final linker = new ChildDirectiveLinker(this, linkErrorReporter);\n+    await linker.linkDirectives(directives, unit.library);\n+\n+    for (final directive in directives) {\n+      if (directive is Component) {\n+        final view = directive.view;\n+        if (view.templateUriSource?.fullName == htmlPath) {\n+          final tplErrorListener = new RecordingErrorListener();\n+          final errorReporter = new ErrorReporter(tplErrorListener, dartSource);\n+          final template = new Template(view);\n+          view.template = template;\n+          final tplParser = new TemplateParser();\n+\n+          tplParser.parse(htmlContent, htmlSource);\n+          final document = tplParser.document;\n+          final EmbeddedDartParser parser = new EmbeddedDartParser(\n+              htmlSource, tplErrorListener, errorReporter);\n+\n+          template.ast =\n+              new HtmlTreeConverter(parser, htmlSource, tplErrorListener)\n+                  .convert(firstElement(tplParser.document));\n+          template.ast.accept(new NgContentRecorder(directive, errorReporter));\n+          setIgnoredErrors(template, document);\n+          final resolver = new TemplateResolver(\n+              context.typeProvider,\n+              standardHtml.components.values,\n+              standardHtml.events,\n+              standardHtml.attributes,\n+              tplErrorListener);\n+          resolver.resolve(template);\n+\n+          bool rightErrorType(AnalysisError e) =>\n+              !view.template.ignoredErrors.contains(e.errorCode.name);\n+          String shorten(String filename) =>\n+              filename.substring(0, filename.lastIndexOf('.'));\n+\n+          errors.addAll(tplParser.parseErrors.where(rightErrorType));\n+\n+          if (shorten(view.source.fullName) !=\n+              shorten(view.templateSource.fullName)) {\n+            errors.addAll(tplErrorListener.errors\n+                .where(rightErrorType)\n+                .map((e) => new FromFilePrefixedError(view.source, e)));\n+          } else {\n+            errors.addAll(tplErrorListener.errors.where(rightErrorType));\n+          }\n+        }\n+      }\n+    }\n+\n+    final summary = new LinkedHtmlSummaryBuilder()\n+      ..errors = summarizeErrors(\n+          errors.where((error) => error is! FromFilePrefixedError))\n+      ..errorsFromPath = errors\n+          .where((error) => error is FromFilePrefixedError)\n+          .map((error) => new SummarizedAnalysisErrorFromPathBuilder()\n+            ..path = (error as FromFilePrefixedError).fromSourcePath\n+            ..originalError =\n+                summarizeError((error as FromFilePrefixedError).originalError));\n+    final List<int> newBytes = summary.toBuffer();\n+    byteStore.put(key, newBytes);\n+    return new DirectivesResult(directives, errors);\n+  }\n+\n+  Future<List<NgContent>> getHtmlNgContent(String path) async {\n+    final key = getContentHash(path).toHex() + '.ngunlinked';\n+    final List<int> bytes = byteStore.get(key);\n+    final source = getSource(path);\n+    if (bytes != null) {\n+      return new DirectiveLinker(this).deserializeNgContents(\n+          new UnlinkedHtmlSummary.fromBuffer(bytes).ngContents, source);\n+    }\n+\n+    final htmlContent = getFileContent(path);\n+    final tplErrorListener = new RecordingErrorListener();\n+    final errorReporter = new ErrorReporter(tplErrorListener, source);\n+\n+    final tplParser = new TemplateParser();\n+\n+    tplParser.parse(htmlContent, source);\n+    final EmbeddedDartParser parser =\n+        new EmbeddedDartParser(source, tplErrorListener, errorReporter);\n+\n+    final ast = new HtmlTreeConverter(parser, source, tplErrorListener)\n+        .convert(firstElement(tplParser.document));\n+    final contents = <NgContent>[];\n+    ast.accept(new NgContentRecorder.forFile(contents, source, errorReporter));\n+\n+    final summary = new UnlinkedHtmlSummaryBuilder()\n+      ..ngContents = serializeNgContents(contents);\n+    final List<int> newBytes = summary.toBuffer();\n+    byteStore.put(key, newBytes);\n+\n+    return contents;\n+  }\n+\n+  Future pushHtmlErrors(String htmlPath, String dartPath) async {\n+    final errors = (await resolveHtml(htmlPath, dartPath)).errors;\n+    final lineInfo = new LineInfo.fromContent(getFileContent(htmlPath));\n+    final serverErrors = protocol.doAnalysisError_listFromEngine(\n+        dartDriver.analysisOptions, lineInfo, errors);\n+    server.notificationManager\n+        .recordAnalysisErrors(\"angularPlugin\", htmlPath, serverErrors);\n+  }\n+\n+  Future pushDartNavigation(String path) async {}\n+\n+  Future pushDartOccurrences(String path) async {}\n+\n+  Future pushDartErrors(String path) async {\n+    final errors = (await resolveDart(path)).errors;\n+    final lineInfo = new LineInfo.fromContent(getFileContent(path));\n+    final serverErrors = protocol.doAnalysisError_listFromEngine(\n+        dartDriver.analysisOptions, lineInfo, errors);\n+    server.notificationManager\n+        .recordAnalysisErrors(\"angularPlugin\", path, serverErrors);\n+  }\n+\n+  Future<DirectivesResult> resolveDart(String path,\n+      {bool withDirectives: false}) async {\n+    final key =\n+        dartDriver.getResolvedUnitKeyByPath(path).toHex() + '.ngresolved';\n+\n+    if (!withDirectives) {\n+      final List<int> bytes = byteStore.get(key);\n+      if (bytes != null) {\n+        final summary = new LinkedDartSummary.fromBuffer(bytes);\n+\n+        for (final htmlView in summary.referencedHtmlFiles) {\n+          _htmlViewsToAnalyze.add(new Tuple2(htmlView, path));\n+        }\n+\n+        return new DirectivesResult(\n+            [], deserializeErrors(getSource(path), summary.errors));\n+      }\n+    }\n+\n+    final result = await getDirectives(path);\n+    final directives = result.directives;\n+    final unit = (await dartDriver.getUnitElement(path)).element;\n+    if (unit == null) return null;\n+    final context = unit.context;\n+    final source = unit.source;\n+\n+    final errors = new List<AnalysisError>.from(result.errors);\n+    final standardHtml = await getStandardHtml();\n+\n+    final linkErrorListener = new RecordingErrorListener();\n+    final linkErrorReporter = new ErrorReporter(linkErrorListener, source);\n+\n+    final linker = new ChildDirectiveLinker(this, linkErrorReporter);\n+    await linker.linkDirectives(directives, unit.library);\n+    errors.addAll(linkErrorListener.errors);\n+\n+    final List<String> htmlViews = [];\n+\n+    for (final directive in directives) {\n+      if (directive is Component) {\n+        final view = directive.view;\n+        if ((view?.templateText ?? '') != '') {\n+          final tplErrorListener = new RecordingErrorListener();\n+          final errorReporter = new ErrorReporter(tplErrorListener, source);\n+          final template = new Template(view);\n+          view.template = template;\n+          final tplParser = new TemplateParser();\n+\n+          tplParser.parse(view.templateText, source,\n+              offset: view.templateOffset);\n+          final document = tplParser.document;\n+          final EmbeddedDartParser parser =\n+              new EmbeddedDartParser(source, tplErrorListener, errorReporter);\n+\n+          template.ast = new HtmlTreeConverter(parser, source, tplErrorListener)\n+              .convert(firstElement(tplParser.document));\n+          template.ast.accept(new NgContentRecorder(directive, errorReporter));\n+          setIgnoredErrors(template, document);\n+          final resolver = new TemplateResolver(\n+              context.typeProvider,\n+              standardHtml.components.values,\n+              standardHtml.events,\n+              standardHtml.attributes,\n+              tplErrorListener);\n+          resolver.resolve(template);\n+          errors.addAll(tplParser.parseErrors.where(\n+              (e) => !view.template.ignoredErrors.contains(e.errorCode.name)));\n+          errors.addAll(tplErrorListener.errors.where(\n+              (e) => !view.template.ignoredErrors.contains(e.errorCode.name)));\n+        } else if (view?.templateUriSource != null) {\n+          _htmlViewsToAnalyze\n+              .add(new Tuple2(view.templateUriSource.fullName, path));\n+          htmlViews.add(view.templateUriSource.fullName);\n+        }\n+      }\n+    }\n+\n+    final summary = new LinkedDartSummaryBuilder()\n+      ..errors = summarizeErrors(errors)\n+      ..referencedHtmlFiles = htmlViews;\n+    final List<int> newBytes = summary.toBuffer();\n+    byteStore.put(key, newBytes);\n+    return new DirectivesResult(directives, errors);\n+  }\n+\n+  List<SummarizedAnalysisError> summarizeErrors(List<AnalysisError> errors) {\n+    return errors.map((error) => summarizeError(error)).toList();\n+  }\n+\n+  SummarizedAnalysisError summarizeError(AnalysisError error) {\n+    return new SummarizedAnalysisErrorBuilder(\n+        offset: error.offset,\n+        length: error.length,\n+        errorCode: error.errorCode.uniqueName,\n+        message: error.message,\n+        correction: error.correction);\n+  }\n+\n+  Source getSource(String path) {\n+    return _sourceFactory.resolveUri(null, 'file:' + path);\n+  }\n+\n+  Future<CompilationUnitElement> getUnit(String path) async {\n+    return (await dartDriver.getUnitElement(path)).element;\n+  }\n+\n+  Future<List<AbstractDirective>> resynthesizeDirectives(\n+      UnlinkedDartSummary unlinked, String path) async {\n+    return new DirectiveLinker(this).resynthesizeDirectives(unlinked, path);\n+  }\n+\n+  Future<List<AbstractDirective>> getUnlinkedDirectives(path) async {\n+    return (await getDirectives(path)).directives;\n+  }\n+\n+  Future<DirectivesResult> getDirectives(path) async {\n+    final key = getContentHash(path).toHex() + '.ngunlinked';\n+    final List<int> bytes = byteStore.get(key);\n+    if (bytes != null) {\n+      final summary = new UnlinkedDartSummary.fromBuffer(bytes);\n+      return new DirectivesResult(await resynthesizeDirectives(summary, path),\n+          deserializeErrors(getSource(path), summary.errors));\n+    }\n+\n+    final dartResult = await dartDriver.getResult(path);\n+    if (dartResult == null) {\n+      return null;\n+    }\n+\n+    final context = dartResult.unit.element.context;\n+    final ast = dartResult.unit;\n+    final source = dartResult.unit.element.source;\n+    final extractor =\n+        new DirectiveExtractor(ast, context.typeProvider, source, context);\n+    final directives =\n+        new List<AbstractDirective>.from(extractor.getDirectives());\n+\n+    final viewExtractor = new ViewExtractor(ast, directives, context, source);\n+    viewExtractor.getViews();\n+\n+    final tplErrorListener = new RecordingErrorListener();\n+    final errorReporter = new ErrorReporter(tplErrorListener, source);\n+\n+    // collect inline ng-content tags\n+    for (final directive in directives) {\n+      if (directive is Component && directive?.view != null) {\n+        final view = directive.view;\n+        if ((view.templateText ?? \"\") != \"\") {\n+          final template = new Template(view);\n+          view.template = template;\n+          final tplParser = new TemplateParser();\n+\n+          tplParser.parse(view.templateText, source,\n+              offset: view.templateOffset);\n+          final EmbeddedDartParser parser =\n+              new EmbeddedDartParser(source, tplErrorListener, errorReporter);\n+\n+          template.ast = new HtmlTreeConverter(parser, source, tplErrorListener)\n+              .convert(firstElement(tplParser.document));\n+          template.ast.accept(new NgContentRecorder(directive, errorReporter));\n+        }\n+      }\n+    }\n+\n+    final errors = new List<AnalysisError>.from(extractor.errorListener.errors);\n+    errors.addAll(viewExtractor.errorListener.errors);\n+    final result = new DirectivesResult(directives, errors);\n+    final summary = serializeDartResult(result);\n+    final List<int> newBytes = summary.toBuffer();\n+    byteStore.put(key, newBytes);\n+    return result;\n+  }\n+\n+  UnlinkedDartSummaryBuilder serializeDartResult(DirectivesResult result) {\n+    final dirSums = serializeDirectives(result.directives);\n+    final summary = new UnlinkedDartSummaryBuilder()\n+      ..directiveSummaries = dirSums\n+      ..errors = summarizeErrors(result.errors);\n+    return summary;\n+  }\n+\n+  List<SummarizedDirectiveBuilder> serializeDirectives(\n+      List<AbstractDirective> directives) {\n+    final dirSums = <SummarizedDirectiveBuilder>[];\n+    for (final directive in directives) {\n+      final className = directive.classElement.name;\n+      final selector = directive.selector.originalString;\n+      final selectorOffset = directive.selector.offset;\n+      final exportAs = directive?.exportAs?.name;\n+      final exportAsOffset = directive?.exportAs?.nameOffset;\n+      final inputs = <SummarizedBindableBuilder>[];\n+      final outputs = <SummarizedBindableBuilder>[];\n+      for (final input in directive.inputs) {\n+        final name = input.name;\n+        final nameOffset = input.nameOffset;\n+        final propName = input.setter.name.replaceAll('=', '');\n+        final propNameOffset = input.setterRange.offset;\n+        inputs.add(new SummarizedBindableBuilder()\n+          ..name = name\n+          ..nameOffset = nameOffset\n+          ..propName = propName\n+          ..propNameOffset = propNameOffset);\n+      }\n+      for (final output in directive.outputs) {\n+        final name = output.name;\n+        final nameOffset = output.nameOffset;\n+        final propName = output.getter.name.replaceAll('=', '');\n+        final propNameOffset = output.getterRange.offset;\n+        outputs.add(new SummarizedBindableBuilder()\n+          ..name = name\n+          ..nameOffset = nameOffset\n+          ..propName = propName\n+          ..propNameOffset = propNameOffset);\n+      }\n+      final dirUseSums = <SummarizedDirectiveUseBuilder>[];\n+      final ngContents = <SummarizedNgContentBuilder>[];\n+      var templateUrl;\n+      var templateUrlOffset;\n+      var templateUrlLength;\n+      var templateText;\n+      var templateTextOffset;","path":"analyzer_plugin/lib/src/angular_driver.dart","position":609,"original_position":607,"commit_id":"22a86c82ffd82601b5fe2acf606fc673a4fb87c3","original_commit_id":"3e118f538fea7e647a46ac65d9903e5d3b4277ab","user":{"login":"MichaelRFairhurst","id":1627771,"avatar_url":"https://avatars2.githubusercontent.com/u/1627771?v=3","gravatar_id":"","url":"https://api.github.com/users/MichaelRFairhurst","html_url":"https://github.com/MichaelRFairhurst","followers_url":"https://api.github.com/users/MichaelRFairhurst/followers","following_url":"https://api.github.com/users/MichaelRFairhurst/following{/other_user}","gists_url":"https://api.github.com/users/MichaelRFairhurst/gists{/gist_id}","starred_url":"https://api.github.com/users/MichaelRFairhurst/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/MichaelRFairhurst/subscriptions","organizations_url":"https://api.github.com/users/MichaelRFairhurst/orgs","repos_url":"https://api.github.com/users/MichaelRFairhurst/repos","events_url":"https://api.github.com/users/MichaelRFairhurst/events{/privacy}","received_events_url":"https://api.github.com/users/MichaelRFairhurst/received_events","type":"User","site_admin":false},"body":"very right you are...fixed","created_at":"2017-03-21T18:08:08Z","updated_at":"2017-03-21T18:08:09Z","html_url":"https://github.com/dart-lang/angular_analyzer_plugin/pull/250#discussion_r107232540","pull_request_url":"https://api.github.com/repos/dart-lang/angular_analyzer_plugin/pulls/250","_links":{"self":{"href":"https://api.github.com/repos/dart-lang/angular_analyzer_plugin/pulls/comments/107232540"},"html":{"href":"https://github.com/dart-lang/angular_analyzer_plugin/pull/250#discussion_r107232540"},"pull_request":{"href":"https://api.github.com/repos/dart-lang/angular_analyzer_plugin/pulls/250"}}},"pull_request":{"url":"https://api.github.com/repos/dart-lang/angular_analyzer_plugin/pulls/250","id":107297924,"html_url":"https://github.com/dart-lang/angular_analyzer_plugin/pull/250","diff_url":"https://github.com/dart-lang/angular_analyzer_plugin/pull/250.diff","patch_url":"https://github.com/dart-lang/angular_analyzer_plugin/pull/250.patch","issue_url":"https://api.github.com/repos/dart-lang/angular_analyzer_plugin/issues/250","number":250,"state":"open","locked":false,"title":"Most way done with new analysis driver","user":{"login":"MichaelRFairhurst","id":1627771,"avatar_url":"https://avatars2.githubusercontent.com/u/1627771?v=3","gravatar_id":"","url":"https://api.github.com/users/MichaelRFairhurst","html_url":"https://github.com/MichaelRFairhurst","followers_url":"https://api.github.com/users/MichaelRFairhurst/followers","following_url":"https://api.github.com/users/MichaelRFairhurst/following{/other_user}","gists_url":"https://api.github.com/users/MichaelRFairhurst/gists{/gist_id}","starred_url":"https://api.github.com/users/MichaelRFairhurst/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/MichaelRFairhurst/subscriptions","organizations_url":"https://api.github.com/users/MichaelRFairhurst/orgs","repos_url":"https://api.github.com/users/MichaelRFairhurst/repos","events_url":"https://api.github.com/users/MichaelRFairhurst/events{/privacy}","received_events_url":"https://api.github.com/users/MichaelRFairhurst/received_events","type":"User","site_admin":false},"body":"TODO:\r\n- use new plugin model TBC\r\n- eventually still cache StandardHtml in summary\r\n- update a.html when b.html changes and is part of the dependency graph\r\n- run fuzz tester more once DAS is less flaky\r\n- support autocomplete/navigation\r\n- general cleanup of the less-good parts of the changes","created_at":"2017-02-21T22:56:25Z","updated_at":"2017-03-21T18:08:09Z","closed_at":null,"merged_at":null,"merge_commit_sha":"5b17d8825e873d75fecca534d175f2258f8e2ce7","assignee":null,"assignees":[],"milestone":null,"commits_url":"https://api.github.com/repos/dart-lang/angular_analyzer_plugin/pulls/250/commits","review_comments_url":"https://api.github.com/repos/dart-lang/angular_analyzer_plugin/pulls/250/comments","review_comment_url":"https://api.github.com/repos/dart-lang/angular_analyzer_plugin/pulls/comments{/number}","comments_url":"https://api.github.com/repos/dart-lang/angular_analyzer_plugin/issues/250/comments","statuses_url":"https://api.github.com/repos/dart-lang/angular_analyzer_plugin/statuses/22a86c82ffd82601b5fe2acf606fc673a4fb87c3","head":{"label":"MichaelRFairhurst:transition-to-analysis-driver","ref":"transition-to-analysis-driver","sha":"22a86c82ffd82601b5fe2acf606fc673a4fb87c3","user":{"login":"MichaelRFairhurst","id":1627771,"avatar_url":"https://avatars2.githubusercontent.com/u/1627771?v=3","gravatar_id":"","url":"https://api.github.com/users/MichaelRFairhurst","html_url":"https://github.com/MichaelRFairhurst","followers_url":"https://api.github.com/users/MichaelRFairhurst/followers","following_url":"https://api.github.com/users/MichaelRFairhurst/following{/other_user}","gists_url":"https://api.github.com/users/MichaelRFairhurst/gists{/gist_id}","starred_url":"https://api.github.com/users/MichaelRFairhurst/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/MichaelRFairhurst/subscriptions","organizations_url":"https://api.github.com/users/MichaelRFairhurst/orgs","repos_url":"https://api.github.com/users/MichaelRFairhurst/repos","events_url":"https://api.github.com/users/MichaelRFairhurst/events{/privacy}","received_events_url":"https://api.github.com/users/MichaelRFairhurst/received_events","type":"User","site_admin":false},"repo":{"id":72245684,"name":"angular2-dart-analyzer","full_name":"MichaelRFairhurst/angular2-dart-analyzer","owner":{"login":"MichaelRFairhurst","id":1627771,"avatar_url":"https://avatars2.githubusercontent.com/u/1627771?v=3","gravatar_id":"","url":"https://api.github.com/users/MichaelRFairhurst","html_url":"https://github.com/MichaelRFairhurst","followers_url":"https://api.github.com/users/MichaelRFairhurst/followers","following_url":"https://api.github.com/users/MichaelRFairhurst/following{/other_user}","gists_url":"https://api.github.com/users/MichaelRFairhurst/gists{/gist_id}","starred_url":"https://api.github.com/users/MichaelRFairhurst/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/MichaelRFairhurst/subscriptions","organizations_url":"https://api.github.com/users/MichaelRFairhurst/orgs","repos_url":"https://api.github.com/users/MichaelRFairhurst/repos","events_url":"https://api.github.com/users/MichaelRFairhurst/events{/privacy}","received_events_url":"https://api.github.com/users/MichaelRFairhurst/received_events","type":"User","site_admin":false},"private":false,"html_url":"https://github.com/MichaelRFairhurst/angular2-dart-analyzer","description":null,"fork":true,"url":"https://api.github.com/repos/MichaelRFairhurst/angular2-dart-analyzer","forks_url":"https://api.github.com/repos/MichaelRFairhurst/angular2-dart-analyzer/forks","keys_url":"https://api.github.com/repos/MichaelRFairhurst/angular2-dart-analyzer/keys{/key_id}","collaborators_url":"https://api.github.com/repos/MichaelRFairhurst/angular2-dart-analyzer/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/MichaelRFairhurst/angular2-dart-analyzer/teams","hooks_url":"https://api.github.com/repos/MichaelRFairhurst/angular2-dart-analyzer/hooks","issue_events_url":"https://api.github.com/repos/MichaelRFairhurst/angular2-dart-analyzer/issues/events{/number}","events_url":"https://api.github.com/repos/MichaelRFairhurst/angular2-dart-analyzer/events","assignees_url":"https://api.github.com/repos/MichaelRFairhurst/angular2-dart-analyzer/assignees{/user}","branches_url":"https://api.github.com/repos/MichaelRFairhurst/angular2-dart-analyzer/branches{/branch}","tags_url":"https://api.github.com/repos/MichaelRFairhurst/angular2-dart-analyzer/tags","blobs_url":"https://api.github.com/repos/MichaelRFairhurst/angular2-dart-analyzer/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/MichaelRFairhurst/angular2-dart-analyzer/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/MichaelRFairhurst/angular2-dart-analyzer/git/refs{/sha}","trees_url":"https://api.github.com/repos/MichaelRFairhurst/angular2-dart-analyzer/git/trees{/sha}","statuses_url":"https://api.github.com/repos/MichaelRFairhurst/angular2-dart-analyzer/statuses/{sha}","languages_url":"https://api.github.com/repos/MichaelRFairhurst/angular2-dart-analyzer/languages","stargazers_url":"https://api.github.com/repos/MichaelRFairhurst/angular2-dart-analyzer/stargazers","contributors_url":"https://api.github.com/repos/MichaelRFairhurst/angular2-dart-analyzer/contributors","subscribers_url":"https://api.github.com/repos/MichaelRFairhurst/angular2-dart-analyzer/subscribers","subscription_url":"https://api.github.com/repos/MichaelRFairhurst/angular2-dart-analyzer/subscription","commits_url":"https://api.github.com/repos/MichaelRFairhurst/angular2-dart-analyzer/commits{/sha}","git_commits_url":"https://api.github.com/repos/MichaelRFairhurst/angular2-dart-analyzer/git/commits{/sha}","comments_url":"https://api.github.com/repos/MichaelRFairhurst/angular2-dart-analyzer/comments{/number}","issue_comment_url":"https://api.github.com/repos/MichaelRFairhurst/angular2-dart-analyzer/issues/comments{/number}","contents_url":"https://api.github.com/repos/MichaelRFairhurst/angular2-dart-analyzer/contents/{+path}","compare_url":"https://api.github.com/repos/MichaelRFairhurst/angular2-dart-analyzer/compare/{base}...{head}","merges_url":"https://api.github.com/repos/MichaelRFairhurst/angular2-dart-analyzer/merges","archive_url":"https://api.github.com/repos/MichaelRFairhurst/angular2-dart-analyzer/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/MichaelRFairhurst/angular2-dart-analyzer/downloads","issues_url":"https://api.github.com/repos/MichaelRFairhurst/angular2-dart-analyzer/issues{/number}","pulls_url":"https://api.github.com/repos/MichaelRFairhurst/angular2-dart-analyzer/pulls{/number}","milestones_url":"https://api.github.com/repos/MichaelRFairhurst/angular2-dart-analyzer/milestones{/number}","notifications_url":"https://api.github.com/repos/MichaelRFairhurst/angular2-dart-analyzer/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/MichaelRFairhurst/angular2-dart-analyzer/labels{/name}","releases_url":"https://api.github.com/repos/MichaelRFairhurst/angular2-dart-analyzer/releases{/id}","deployments_url":"https://api.github.com/repos/MichaelRFairhurst/angular2-dart-analyzer/deployments","created_at":"2016-10-28T21:58:16Z","updated_at":"2016-10-28T21:58:17Z","pushed_at":"2017-03-21T18:04:02Z","git_url":"git://github.com/MichaelRFairhurst/angular2-dart-analyzer.git","ssh_url":"git@github.com:MichaelRFairhurst/angular2-dart-analyzer.git","clone_url":"https://github.com/MichaelRFairhurst/angular2-dart-analyzer.git","svn_url":"https://github.com/MichaelRFairhurst/angular2-dart-analyzer","homepage":null,"size":2873,"stargazers_count":0,"watchers_count":0,"language":"Dart","has_issues":false,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":0,"mirror_url":null,"open_issues_count":0,"forks":0,"open_issues":0,"watchers":0,"default_branch":"master"}},"base":{"label":"dart-lang:master","ref":"master","sha":"e06e5637441493d51e38cc669f91555188d93fba","user":{"login":"dart-lang","id":1609975,"avatar_url":"https://avatars3.githubusercontent.com/u/1609975?v=3","gravatar_id":"","url":"https://api.github.com/users/dart-lang","html_url":"https://github.com/dart-lang","followers_url":"https://api.github.com/users/dart-lang/followers","following_url":"https://api.github.com/users/dart-lang/following{/other_user}","gists_url":"https://api.github.com/users/dart-lang/gists{/gist_id}","starred_url":"https://api.github.com/users/dart-lang/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/dart-lang/subscriptions","organizations_url":"https://api.github.com/users/dart-lang/orgs","repos_url":"https://api.github.com/users/dart-lang/repos","events_url":"https://api.github.com/users/dart-lang/events{/privacy}","received_events_url":"https://api.github.com/users/dart-lang/received_events","type":"Organization","site_admin":false},"repo":{"id":41174830,"name":"angular_analyzer_plugin","full_name":"dart-lang/angular_analyzer_plugin","owner":{"login":"dart-lang","id":1609975,"avatar_url":"https://avatars3.githubusercontent.com/u/1609975?v=3","gravatar_id":"","url":"https://api.github.com/users/dart-lang","html_url":"https://github.com/dart-lang","followers_url":"https://api.github.com/users/dart-lang/followers","following_url":"https://api.github.com/users/dart-lang/following{/other_user}","gists_url":"https://api.github.com/users/dart-lang/gists{/gist_id}","starred_url":"https://api.github.com/users/dart-lang/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/dart-lang/subscriptions","organizations_url":"https://api.github.com/users/dart-lang/orgs","repos_url":"https://api.github.com/users/dart-lang/repos","events_url":"https://api.github.com/users/dart-lang/events{/privacy}","received_events_url":"https://api.github.com/users/dart-lang/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/dart-lang/angular_analyzer_plugin","description":null,"fork":false,"url":"https://api.github.com/repos/dart-lang/angular_analyzer_plugin","forks_url":"https://api.github.com/repos/dart-lang/angular_analyzer_plugin/forks","keys_url":"https://api.github.com/repos/dart-lang/angular_analyzer_plugin/keys{/key_id}","collaborators_url":"https://api.github.com/repos/dart-lang/angular_analyzer_plugin/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/dart-lang/angular_analyzer_plugin/teams","hooks_url":"https://api.github.com/repos/dart-lang/angular_analyzer_plugin/hooks","issue_events_url":"https://api.github.com/repos/dart-lang/angular_analyzer_plugin/issues/events{/number}","events_url":"https://api.github.com/repos/dart-lang/angular_analyzer_plugin/events","assignees_url":"https://api.github.com/repos/dart-lang/angular_analyzer_plugin/assignees{/user}","branches_url":"https://api.github.com/repos/dart-lang/angular_analyzer_plugin/branches{/branch}","tags_url":"https://api.github.com/repos/dart-lang/angular_analyzer_plugin/tags","blobs_url":"https://api.github.com/repos/dart-lang/angular_analyzer_plugin/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/dart-lang/angular_analyzer_plugin/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/dart-lang/angular_analyzer_plugin/git/refs{/sha}","trees_url":"https://api.github.com/repos/dart-lang/angular_analyzer_plugin/git/trees{/sha}","statuses_url":"https://api.github.com/repos/dart-lang/angular_analyzer_plugin/statuses/{sha}","languages_url":"https://api.github.com/repos/dart-lang/angular_analyzer_plugin/languages","stargazers_url":"https://api.github.com/repos/dart-lang/angular_analyzer_plugin/stargazers","contributors_url":"https://api.github.com/repos/dart-lang/angular_analyzer_plugin/contributors","subscribers_url":"https://api.github.com/repos/dart-lang/angular_analyzer_plugin/subscribers","subscription_url":"https://api.github.com/repos/dart-lang/angular_analyzer_plugin/subscription","commits_url":"https://api.github.com/repos/dart-lang/angular_analyzer_plugin/commits{/sha}","git_commits_url":"https://api.github.com/repos/dart-lang/angular_analyzer_plugin/git/commits{/sha}","comments_url":"https://api.github.com/repos/dart-lang/angular_analyzer_plugin/comments{/number}","issue_comment_url":"https://api.github.com/repos/dart-lang/angular_analyzer_plugin/issues/comments{/number}","contents_url":"https://api.github.com/repos/dart-lang/angular_analyzer_plugin/contents/{+path}","compare_url":"https://api.github.com/repos/dart-lang/angular_analyzer_plugin/compare/{base}...{head}","merges_url":"https://api.github.com/repos/dart-lang/angular_analyzer_plugin/merges","archive_url":"https://api.github.com/repos/dart-lang/angular_analyzer_plugin/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/dart-lang/angular_analyzer_plugin/downloads","issues_url":"https://api.github.com/repos/dart-lang/angular_analyzer_plugin/issues{/number}","pulls_url":"https://api.github.com/repos/dart-lang/angular_analyzer_plugin/pulls{/number}","milestones_url":"https://api.github.com/repos/dart-lang/angular_analyzer_plugin/milestones{/number}","notifications_url":"https://api.github.com/repos/dart-lang/angular_analyzer_plugin/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/dart-lang/angular_analyzer_plugin/labels{/name}","releases_url":"https://api.github.com/repos/dart-lang/angular_analyzer_plugin/releases{/id}","deployments_url":"https://api.github.com/repos/dart-lang/angular_analyzer_plugin/deployments","created_at":"2015-08-21T19:55:44Z","updated_at":"2017-03-14T10:20:24Z","pushed_at":"2017-03-21T18:04:03Z","git_url":"git://github.com/dart-lang/angular_analyzer_plugin.git","ssh_url":"git@github.com:dart-lang/angular_analyzer_plugin.git","clone_url":"https://github.com/dart-lang/angular_analyzer_plugin.git","svn_url":"https://github.com/dart-lang/angular_analyzer_plugin","homepage":null,"size":2592,"stargazers_count":27,"watchers_count":27,"language":"Dart","has_issues":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":9,"mirror_url":null,"open_issues_count":68,"forks":9,"open_issues":68,"watchers":27,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/dart-lang/angular_analyzer_plugin/pulls/250"},"html":{"href":"https://github.com/dart-lang/angular_analyzer_plugin/pull/250"},"issue":{"href":"https://api.github.com/repos/dart-lang/angular_analyzer_plugin/issues/250"},"comments":{"href":"https://api.github.com/repos/dart-lang/angular_analyzer_plugin/issues/250/comments"},"review_comments":{"href":"https://api.github.com/repos/dart-lang/angular_analyzer_plugin/pulls/250/comments"},"review_comment":{"href":"https://api.github.com/repos/dart-lang/angular_analyzer_plugin/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/dart-lang/angular_analyzer_plugin/pulls/250/commits"},"statuses":{"href":"https://api.github.com/repos/dart-lang/angular_analyzer_plugin/statuses/22a86c82ffd82601b5fe2acf606fc673a4fb87c3"}}}}
{"actor":{"display_login":"MichaelRFairhurst"}}