OLD | NEW |
1 // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2015, 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 /// Tracks the shape of the import/export graph and dependencies between files. | 5 /// Tracks the shape of the import/export graph and dependencies between files. |
6 library dev_compiler.src.dependency_graph; | 6 library dev_compiler.src.dependency_graph; |
7 | 7 |
8 import 'dart:collection' show HashSet; | 8 import 'dart:collection' show HashSet; |
9 | 9 |
10 import 'package:analyzer/analyzer.dart' show parseDirectives; | 10 import 'package:analyzer/analyzer.dart' show parseDirectives; |
11 import 'package:analyzer/src/generated/ast.dart' | 11 import 'package:analyzer/src/generated/ast.dart' |
12 show | 12 show |
13 AstNode, | 13 AstNode, |
14 CompilationUnit, | 14 CompilationUnit, |
15 ExportDirective, | 15 ExportDirective, |
16 Identifier, | 16 Identifier, |
17 ImportDirective, | 17 ImportDirective, |
18 LibraryDirective, | 18 LibraryDirective, |
19 PartDirective, | 19 PartDirective, |
20 PartOfDirective; | 20 PartOfDirective; |
21 import 'package:analyzer/src/generated/engine.dart' | 21 import 'package:analyzer/src/generated/engine.dart' |
22 show ParseDartTask, AnalysisContext; | 22 show ParseDartTask, AnalysisContext; |
23 import 'package:analyzer/src/generated/source.dart' show Source, SourceKind; | 23 import 'package:analyzer/src/generated/source.dart' show Source, SourceKind; |
24 import 'package:html5lib/dom.dart' show Document, Node; | 24 import 'package:html5lib/dom.dart' show Document, Node; |
25 import 'package:html5lib/parser.dart' as html; | 25 import 'package:html5lib/parser.dart' as html; |
26 import 'package:logging/logging.dart' show Level; | 26 import 'package:logging/logging.dart' show Logger, Level; |
27 import 'package:path/path.dart' as path; | 27 import 'package:path/path.dart' as path; |
28 import 'package:source_span/source_span.dart' show SourceSpan; | 28 import 'package:source_span/source_span.dart' show SourceSpan; |
29 | 29 |
30 import 'info.dart'; | 30 import 'info.dart'; |
31 import 'options.dart'; | 31 import 'options.dart'; |
32 import 'report.dart'; | 32 import 'report.dart'; |
33 import 'utils.dart'; | 33 import 'utils.dart'; |
34 | 34 |
35 /// Holds references to all source nodes in the import graph. This is mainly | 35 /// Holds references to all source nodes in the import graph. This is mainly |
36 /// used as a level of indirection to ensure that each source has a canonical | 36 /// used as a level of indirection to ensure that each source has a canonical |
37 /// representation. | 37 /// representation. |
38 class SourceGraph { | 38 class SourceGraph { |
39 /// All nodes in the source graph. Used to get a canonical representation for | 39 /// All nodes in the source graph. Used to get a canonical representation for |
40 /// any node. | 40 /// any node. |
41 final Map<Uri, SourceNode> nodes = {}; | 41 final Map<Uri, SourceNode> nodes = {}; |
42 | 42 |
| 43 /// Resources included by default on any application. |
| 44 final runtimeDeps = new Set<ResourceSourceNode>(); |
| 45 |
43 /// Analyzer used to resolve source files. | 46 /// Analyzer used to resolve source files. |
44 final AnalysisContext _context; | 47 final AnalysisContext _context; |
45 final CheckerReporter _reporter; | 48 final CheckerReporter _reporter; |
46 final CompilerOptions _options; | 49 final CompilerOptions _options; |
47 | 50 |
48 SourceGraph(this._context, this._reporter, this._options); | 51 SourceGraph(this._context, this._reporter, this._options) { |
| 52 var dir = _options.runtimeDir; |
| 53 if (dir == null) { |
| 54 _log.severe('Runtime dir could not be determined automatically, ' |
| 55 'please specify the --runtime-dir flag on the command line.'); |
| 56 return; |
| 57 } |
| 58 var prefix = path.absolute(dir); |
| 59 var files = |
| 60 _options.serverMode ? runtimeFilesForServerMode : defaultRuntimeFiles; |
| 61 for (var file in files) { |
| 62 runtimeDeps.add(nodeFromUri(path.toUri(path.join(prefix, file)))); |
| 63 } |
| 64 } |
49 | 65 |
50 /// Node associated with a resolved [uri]. | 66 /// Node associated with a resolved [uri]. |
51 SourceNode nodeFromUri(Uri uri) { | 67 SourceNode nodeFromUri(Uri uri) { |
52 var uriString = Uri.encodeFull('$uri'); | 68 var uriString = Uri.encodeFull('$uri'); |
53 return nodes.putIfAbsent(uri, () { | 69 return nodes.putIfAbsent(uri, () { |
54 var source = _context.sourceFactory.forUri(uriString); | 70 var source = _context.sourceFactory.forUri(uriString); |
55 var extension = path.extension(uriString); | 71 var extension = path.extension(uriString); |
56 if (extension == '.html') { | 72 if (extension == '.html') { |
57 return new HtmlSourceNode(uri, source, this); | 73 return new HtmlSourceNode(uri, source, this); |
58 } else if (extension == '.dart' || uriString.startsWith('dart:')) { | 74 } else if (extension == '.dart' || uriString.startsWith('dart:')) { |
(...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
117 | 133 |
118 String toString() { | 134 String toString() { |
119 var simpleUri = uri.scheme == 'file' ? path.relative(uri.path) : "$uri"; | 135 var simpleUri = uri.scheme == 'file' ? path.relative(uri.path) : "$uri"; |
120 return '[$runtimeType: $simpleUri]'; | 136 return '[$runtimeType: $simpleUri]'; |
121 } | 137 } |
122 } | 138 } |
123 | 139 |
124 /// A node representing an entry HTML source file. | 140 /// A node representing an entry HTML source file. |
125 class HtmlSourceNode extends SourceNode { | 141 class HtmlSourceNode extends SourceNode { |
126 /// Resources included by default on any application. | 142 /// Resources included by default on any application. |
127 final runtimeDeps = new Set<ResourceSourceNode>(); | 143 final runtimeDeps; |
128 | 144 |
129 /// Libraries referred to via script tags. | 145 /// Libraries referred to via script tags. |
130 Set<DartSourceNode> scripts = new Set<DartSourceNode>(); | 146 Set<DartSourceNode> scripts = new Set<DartSourceNode>(); |
131 | 147 |
132 @override | 148 @override |
133 Iterable<SourceNode> get allDeps => [scripts, runtimeDeps].expand((e) => e); | 149 Iterable<SourceNode> get allDeps => [scripts, runtimeDeps].expand((e) => e); |
134 | 150 |
135 @override | 151 @override |
136 Iterable<SourceNode> get depsWithoutParts => allDeps; | 152 Iterable<SourceNode> get depsWithoutParts => allDeps; |
137 | 153 |
138 /// Parsed document, updated whenever [update] is invoked. | 154 /// Parsed document, updated whenever [update] is invoked. |
139 Document document; | 155 Document document; |
140 | 156 |
141 HtmlSourceNode(uri, source, graph) : super(uri, source) { | 157 HtmlSourceNode(Uri uri, Source source, SourceGraph graph) |
142 var prefix = 'package:dev_compiler/runtime'; | 158 : runtimeDeps = graph.runtimeDeps, |
143 var files = ['harmony_feature_check.js', 'dart_runtime.js', 'dart_core.js']; | 159 super(uri, source); |
144 if (graph._options.serverMode) { | |
145 files.addAll(const ['messages_widget.js', 'messages.css']); | |
146 } | |
147 files.forEach((file) { | |
148 runtimeDeps.add(graph.nodeFromUri(Uri.parse('$prefix/$file'))); | |
149 }); | |
150 } | |
151 | 160 |
152 void update(SourceGraph graph) { | 161 void update(SourceGraph graph) { |
153 super.update(graph); | 162 super.update(graph); |
154 if (needsRebuild) { | 163 if (needsRebuild) { |
155 graph._reporter.clearHtml(uri); | 164 graph._reporter.clearHtml(uri); |
156 document = html.parse(source.contents.data, generateSpans: true); | 165 document = html.parse(source.contents.data, generateSpans: true); |
157 var newScripts = new Set<DartSourceNode>(); | 166 var newScripts = new Set<DartSourceNode>(); |
158 var tags = document.querySelectorAll('script[type="application/dart"]'); | 167 var tags = document.querySelectorAll('script[type="application/dart"]'); |
159 for (var script in tags) { | 168 for (var script in tags) { |
160 var src = script.attributes['src']; | 169 var src = script.attributes['src']; |
(...skipping 267 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
428 helper(start); | 437 helper(start); |
429 } | 438 } |
430 | 439 |
431 bool _same(Set a, Set b) => a.length == b.length && a.containsAll(b); | 440 bool _same(Set a, Set b) => a.length == b.length && a.containsAll(b); |
432 | 441 |
433 /// An error message discovered while parsing the dependencies between files. | 442 /// An error message discovered while parsing the dependencies between files. |
434 class DependencyGraphError extends MessageWithSpan { | 443 class DependencyGraphError extends MessageWithSpan { |
435 const DependencyGraphError(String message, SourceSpan span) | 444 const DependencyGraphError(String message, SourceSpan span) |
436 : super(message, Level.SEVERE, span); | 445 : super(message, Level.SEVERE, span); |
437 } | 446 } |
| 447 |
| 448 /// Runtime files added to all applications when running the compiler in the |
| 449 /// command line. |
| 450 const defaultRuntimeFiles = const [ |
| 451 'harmony_feature_check.js', |
| 452 'dart_runtime.js', |
| 453 'dart_core.js' |
| 454 ]; |
| 455 |
| 456 /// Runtime files added to applications when running in server mode. |
| 457 final runtimeFilesForServerMode = new List<String>.from(defaultRuntimeFiles) |
| 458 ..addAll(const ['messages_widget.js', 'messages.css']); |
| 459 |
| 460 final _log = new Logger('dev_compiler.dependency_graph'); |
OLD | NEW |