Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(19)

Side by Side Diff: lib/src/dependency_graph.dart

Issue 986723002: Add JavaScriptSourceNode to represent runtime libraries (fixes #85) (Closed) Base URL: git@github.com:dart-lang/dev_compiler.git@master
Patch Set: Created 5 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « lib/devc.dart ('k') | test/dependency_graph_test.dart » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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;
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after
43 43
44 SourceGraph(this._context, this._options); 44 SourceGraph(this._context, this._options);
45 45
46 /// Node associated with a resolved [uri]. 46 /// Node associated with a resolved [uri].
47 SourceNode nodeFromUri(Uri uri) { 47 SourceNode nodeFromUri(Uri uri) {
48 var uriString = Uri.encodeFull('$uri'); 48 var uriString = Uri.encodeFull('$uri');
49 return nodes.putIfAbsent(uri, () { 49 return nodes.putIfAbsent(uri, () {
50 var source = _context.sourceFactory.forUri(uriString); 50 var source = _context.sourceFactory.forUri(uriString);
51 var extension = path.extension(uriString); 51 var extension = path.extension(uriString);
52 if (extension == '.html') { 52 if (extension == '.html') {
53 return new HtmlSourceNode(uri, source); 53 return new HtmlSourceNode(uri, source, this);
54 } else if (extension == '.dart' || uriString.startsWith('dart:')) { 54 } else if (extension == '.dart' || uriString.startsWith('dart:')) {
55 return new DartSourceNode(uri, source); 55 return new DartSourceNode(uri, source);
56 } else if (extension == '.js') {
57 return new JavaScriptSourceNode(uri, source);
56 } else { 58 } else {
57 assert(false); // unreachable 59 assert(false); // unreachable
58 } 60 }
59 }); 61 });
60 } 62 }
61 } 63 }
62 64
63 /// A node in the import graph representing a source file. 65 /// A node in the import graph representing a source file.
64 abstract class SourceNode { 66 abstract class SourceNode {
65 /// Resolved URI for this node. 67 /// Resolved URI for this node.
66 final Uri uri; 68 final Uri uri;
67 69
68 /// Resolved source from the analyzer. We let the analyzer internally track 70 /// Resolved source from the analyzer. We let the analyzer internally track
69 /// for modifications to the source files. 71 /// for modifications to the source files.
70 final Source source; 72 final Source source;
71 73
72 /// Last stamp read from `source.modificationStamp`. 74 /// Last stamp read from `source.modificationStamp`.
73 int _lastStamp = 0; 75 int _lastStamp = 0;
74 76
75 /// Whether we need to rebuild this source file. 77 /// Whether we need to rebuild this source file.
76 bool needsRebuild = false; 78 bool needsRebuild = false;
77 79
78 /// Whether the structure of dependencies from this node (scripts, imports, 80 /// Whether the structure of dependencies from this node (scripts, imports,
79 /// exports, or parts) changed after we reparsed its contents. 81 /// exports, or parts) changed after we reparsed its contents.
80 bool structureChanged = false; 82 bool structureChanged = false;
81 83
82 /// Direct dependencies in the [SourceGraph]. These include script tags for 84 /// Direct dependencies in the [SourceGraph]. These include script tags for
83 /// [HtmlSourceNode]s; and imports, exports and parts for [DartSourceNode]s. 85 /// [HtmlSourceNode]s; and imports, exports and parts for [DartSourceNode]s.
84 Iterable<SourceNode> get allDeps; 86 Iterable<SourceNode> get allDeps => const [];
85 87
86 /// Like [allDeps] but excludes parts for [DartSourceNode]s. For many 88 /// Like [allDeps] but excludes parts for [DartSourceNode]s. For many
87 /// operations we mainly care about dependencies at the library level, so 89 /// operations we mainly care about dependencies at the library level, so
88 /// parts are excluded from this list. 90 /// parts are excluded from this list.
89 Iterable<SourceNode> get depsWithoutParts; 91 Iterable<SourceNode> get depsWithoutParts => const [];
90 92
91 SourceNode(this.uri, this.source); 93 SourceNode(this.uri, this.source);
92 94
93 /// Check for whether the file has changed and, if so, mark [needsRebuild] and 95 /// Check for whether the file has changed and, if so, mark [needsRebuild] and
94 /// [structureChanged] as necessary. 96 /// [structureChanged] as necessary.
95 void update(SourceGraph graph) { 97 void update(SourceGraph graph) {
96 int newStamp = source.modificationStamp; 98 int newStamp = source.modificationStamp;
97 if (newStamp > _lastStamp) { 99 if (newStamp > _lastStamp) {
98 _lastStamp = newStamp; 100 _lastStamp = newStamp;
99 needsRebuild = true; 101 needsRebuild = true;
100 } 102 }
101 } 103 }
102 104
103 String toString() { 105 String toString() {
104 var simpleUri = uri.scheme == 'file' ? path.relative(uri.path) : "$uri"; 106 var simpleUri = uri.scheme == 'file' ? path.relative(uri.path) : "$uri";
105 return '[$runtimeType: $simpleUri]'; 107 return '[$runtimeType: $simpleUri]';
106 } 108 }
107 } 109 }
108 110
109 /// A node representing an entry HTML source file. 111 /// A node representing an entry HTML source file.
110 class HtmlSourceNode extends SourceNode { 112 class HtmlSourceNode extends SourceNode {
113 /// Javascript dependencies, included by default on any application.
114 final runtimeDeps = new Set<JavaScriptSourceNode>();
115
111 /// Libraries referred to via script tags. 116 /// Libraries referred to via script tags.
112 Set<DartSourceNode> scripts = new Set<DartSourceNode>(); 117 Set<DartSourceNode> scripts = new Set<DartSourceNode>();
113 118
114 @override 119 @override
115 Iterable<SourceNode> get allDeps => scripts; 120 Iterable<SourceNode> get allDeps => [scripts, runtimeDeps].expand((e) => e);
116 121
117 @override 122 @override
118 Iterable<SourceNode> get depsWithoutParts => scripts; 123 Iterable<SourceNode> get depsWithoutParts => allDeps;
119 124
120 /// Parsed document, updated whenever [update] is invoked. 125 /// Parsed document, updated whenever [update] is invoked.
121 Document document; 126 Document document;
122 127
123 HtmlSourceNode(uri, source) : super(uri, source); 128 HtmlSourceNode(uri, source, graph) : super(uri, source) {
129 var prefix = 'package:dev_compiler/runtime';
130 runtimeDeps
131 ..add(graph.nodeFromUri(Uri.parse('$prefix/dart_runtime.js')))
132 ..add(graph.nodeFromUri(Uri.parse('$prefix/harmony_feature_check.js')));
133 }
124 134
125 void update(SourceGraph graph) { 135 void update(SourceGraph graph) {
126 super.update(graph); 136 super.update(graph);
127 if (needsRebuild) { 137 if (needsRebuild) {
128 document = html.parse(source.contents.data, generateSpans: true); 138 document = html.parse(source.contents.data, generateSpans: true);
129 var newScripts = new Set<DartSourceNode>(); 139 var newScripts = new Set<DartSourceNode>();
130 var tags = document.querySelectorAll('script[type="application/dart"]'); 140 var tags = document.querySelectorAll('script[type="application/dart"]');
131 for (var script in tags) { 141 for (var script in tags) {
132 var src = script.attributes['src']; 142 var src = script.attributes['src'];
133 if (src == null) { 143 if (src == null) {
(...skipping 116 matching lines...) Expand 10 before | Expand all | Expand 10 after
250 // Technically for parts we don't need to look at the contents. If they 260 // Technically for parts we don't need to look at the contents. If they
251 // contain imports, exports, or parts, we'll ignore them in our crawling. 261 // contain imports, exports, or parts, we'll ignore them in our crawling.
252 // However we do a full update to make it easier to adjust when users 262 // However we do a full update to make it easier to adjust when users
253 // switch a file from a part to a library. 263 // switch a file from a part to a library.
254 p.update(graph); 264 p.update(graph);
255 if (p.needsRebuild) needsRebuild = true; 265 if (p.needsRebuild) needsRebuild = true;
256 } 266 }
257 } 267 }
258 } 268 }
259 269
270 /// Represents a Javascript runtime resource from our compiler that is needed to
271 /// run an application.
272 class JavaScriptSourceNode extends SourceNode {
273 JavaScriptSourceNode(uri, source) : super(uri, source);
274 }
275
260 /// Updates the structure and `needsRebuild` marks in nodes of [graph] reachable 276 /// Updates the structure and `needsRebuild` marks in nodes of [graph] reachable
261 /// from [start]. 277 /// from [start].
262 /// 278 ///
263 /// That is, staring from [start], we update the graph by detecting file changes 279 /// That is, staring from [start], we update the graph by detecting file changes
264 /// and rebuilding the structure of the graph wherever it changed (an import was 280 /// and rebuilding the structure of the graph wherever it changed (an import was
265 /// added or removed, etc). 281 /// added or removed, etc).
266 /// 282 ///
267 /// After calling this function a node is marked with `needsRebuild` only if it 283 /// After calling this function a node is marked with `needsRebuild` only if it
268 /// contained local changes. Rebuild decisions that derive from transitive 284 /// contained local changes. Rebuild decisions that derive from transitive
269 /// changes (e.g. when the API of a dependency changed) are handled later in 285 /// changes (e.g. when the API of a dependency changed) are handled later in
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after
313 // cases anways require using summaries to understand what parts of the public 329 // cases anways require using summaries to understand what parts of the public
314 // API may be affected by transitive changes. The re-export case is just one 330 // API may be affected by transitive changes. The re-export case is just one
315 // of those transitive cases, but is not sufficient. See 331 // of those transitive cases, but is not sufficient. See
316 // https://github.com/dart-lang/dev_compiler/issues/76 332 // https://github.com/dart-lang/dev_compiler/issues/76
317 var apiChangeDetected = new HashSet<SourceNode>(); 333 var apiChangeDetected = new HashSet<SourceNode>();
318 bool structureHasChanged = false; 334 bool structureHasChanged = false;
319 335
320 bool shouldBuildNode(SourceNode n) { 336 bool shouldBuildNode(SourceNode n) {
321 if (n.needsRebuild) return true; 337 if (n.needsRebuild) return true;
322 if (n is HtmlSourceNode) return structureHasChanged; 338 if (n is HtmlSourceNode) return structureHasChanged;
339 if (n is JavaScriptSourceNode) return false;
323 return (n as DartSourceNode).imports 340 return (n as DartSourceNode).imports
324 .any((i) => apiChangeDetected.contains(i)); 341 .any((i) => apiChangeDetected.contains(i));
325 } 342 }
326 343
327 visitInPostOrder(start, (n) { 344 visitInPostOrder(start, (n) {
328 if (n.structureChanged) structureHasChanged = true; 345 if (n.structureChanged) structureHasChanged = true;
329 if (shouldBuildNode(n)) { 346 if (shouldBuildNode(n)) {
330 if (build(n)) apiChangeDetected.add(n); 347 if (build(n)) apiChangeDetected.add(n);
331 } else if (n is DartSourceNode && 348 } else if (n is DartSourceNode &&
332 n.exports.any((e) => apiChangeDetected.contains(e))) { 349 n.exports.any((e) => apiChangeDetected.contains(e))) {
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after
367 if (!seen.add(node)) return; 384 if (!seen.add(node)) return;
368 var deps = includeParts ? node.allDeps : node.depsWithoutParts; 385 var deps = includeParts ? node.allDeps : node.depsWithoutParts;
369 deps.forEach(helper); 386 deps.forEach(helper);
370 action(node); 387 action(node);
371 } 388 }
372 helper(start); 389 helper(start);
373 } 390 }
374 391
375 bool _same(Set a, Set b) => a.length == b.length && a.containsAll(b); 392 bool _same(Set a, Set b) => a.length == b.length && a.containsAll(b);
376 final _log = new Logger('dev_compiler.graph'); 393 final _log = new Logger('dev_compiler.graph');
OLDNEW
« no previous file with comments | « lib/devc.dart ('k') | test/dependency_graph_test.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698