Skip to content

Commit

Permalink
Add JavaScriptSourceNode to represent runtime libraries (fixes #85)
Browse files Browse the repository at this point in the history
R=jmesserly@google.com

Review URL: https://codereview.chromium.org/986723002
  • Loading branch information
sigmundch committed Mar 9, 2015
1 parent 0991bea commit ca80f2c
Show file tree
Hide file tree
Showing 3 changed files with 82 additions and 22 deletions.
29 changes: 15 additions & 14 deletions pkg/dev_compiler/lib/devc.dart
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,6 @@ class Compiler {
List<LibraryInfo> _libraries = <LibraryInfo>[];
final List<CodeGenerator> _generators;
bool _failure = false;
bool _devCompilerRuntimeCopied = false;

factory Compiler(CompilerOptions options,
[TypeResolver resolver, CheckerReporter reporter]) {
Expand Down Expand Up @@ -99,6 +98,8 @@ class Compiler {
_buildHtmlFile(node);
} else if (node is DartSourceNode) {
_buildDartLibrary(node);
} else if (node is JavaScriptSourceNode) {
_buildJavaScriptFile(node);
} else {
assert(false); // should not get a build request on PartSourceNode
}
Expand All @@ -119,19 +120,19 @@ class Compiler {
String outputFile = path.join(_options.outputDir, filename);
new File(outputFile).writeAsStringSync(output);

if (_options.outputDart || _devCompilerRuntimeCopied) return;
// Copy the dev_compiler runtime (implicit dependency for js codegen)
// TODO(sigmund): split this out as a separate node in our dependency graph
// (https://github.com/dart-lang/dev_compiler/issues/85).
var runtimeDir = path.join(
path.dirname(path.dirname(Platform.script.path)), 'lib/runtime/');
var runtimeOutput = path.join(_options.outputDir, 'dev_compiler/runtime/');
new Directory(runtimeOutput).createSync(recursive: true);
new File(path.join(runtimeDir, 'harmony_feature_check.js'))
.copy(path.join(runtimeOutput, 'harmony_feature_check.js'));
new File(path.join(runtimeDir, 'dart_runtime.js'))
.copy(path.join(runtimeOutput, 'dart_runtime.js'));
_devCompilerRuntimeCopied = true;
if (_options.outputDart) return;
}

void _buildJavaScriptFile(JavaScriptSourceNode node) {
// JavaScriptSourceNodes are runtime .js files that just need to be copied
// over to the output location. These can be external dependencies or pieces
// of the dev_compiler runtime.
if (_options.outputDir == null || _options.outputDart) return;
assert(node.uri.scheme == 'package');
var filepath = path.join(_options.outputDir, node.uri.path);
var dir = path.dirname(filepath);
new Directory(dir).createSync(recursive: true);
new File(filepath).writeAsStringSync(node.source.contents.data);
}

bool _isEntry(DartSourceNode node) {
Expand Down
29 changes: 23 additions & 6 deletions pkg/dev_compiler/lib/src/dependency_graph.dart
Original file line number Diff line number Diff line change
Expand Up @@ -50,9 +50,11 @@ class SourceGraph {
var source = _context.sourceFactory.forUri(uriString);
var extension = path.extension(uriString);
if (extension == '.html') {
return new HtmlSourceNode(uri, source);
return new HtmlSourceNode(uri, source, this);
} else if (extension == '.dart' || uriString.startsWith('dart:')) {
return new DartSourceNode(uri, source);
} else if (extension == '.js') {
return new JavaScriptSourceNode(uri, source);
} else {
assert(false); // unreachable
}
Expand Down Expand Up @@ -81,12 +83,12 @@ abstract class SourceNode {

/// Direct dependencies in the [SourceGraph]. These include script tags for
/// [HtmlSourceNode]s; and imports, exports and parts for [DartSourceNode]s.
Iterable<SourceNode> get allDeps;
Iterable<SourceNode> get allDeps => const [];

/// Like [allDeps] but excludes parts for [DartSourceNode]s. For many
/// operations we mainly care about dependencies at the library level, so
/// parts are excluded from this list.
Iterable<SourceNode> get depsWithoutParts;
Iterable<SourceNode> get depsWithoutParts => const [];

SourceNode(this.uri, this.source);

Expand All @@ -108,19 +110,27 @@ abstract class SourceNode {

/// A node representing an entry HTML source file.
class HtmlSourceNode extends SourceNode {
/// Javascript dependencies, included by default on any application.
final runtimeDeps = new Set<JavaScriptSourceNode>();

/// Libraries referred to via script tags.
Set<DartSourceNode> scripts = new Set<DartSourceNode>();

@override
Iterable<SourceNode> get allDeps => scripts;
Iterable<SourceNode> get allDeps => [scripts, runtimeDeps].expand((e) => e);

@override
Iterable<SourceNode> get depsWithoutParts => scripts;
Iterable<SourceNode> get depsWithoutParts => allDeps;

/// Parsed document, updated whenever [update] is invoked.
Document document;

HtmlSourceNode(uri, source) : super(uri, source);
HtmlSourceNode(uri, source, graph) : super(uri, source) {
var prefix = 'package:dev_compiler/runtime';
runtimeDeps
..add(graph.nodeFromUri(Uri.parse('$prefix/dart_runtime.js')))
..add(graph.nodeFromUri(Uri.parse('$prefix/harmony_feature_check.js')));
}

void update(SourceGraph graph) {
super.update(graph);
Expand Down Expand Up @@ -257,6 +267,12 @@ class DartSourceNode extends SourceNode {
}
}

/// Represents a Javascript runtime resource from our compiler that is needed to
/// run an application.
class JavaScriptSourceNode extends SourceNode {
JavaScriptSourceNode(uri, source) : super(uri, source);
}

/// Updates the structure and `needsRebuild` marks in nodes of [graph] reachable
/// from [start].
///
Expand Down Expand Up @@ -320,6 +336,7 @@ rebuild(SourceNode start, SourceGraph graph, bool build(SourceNode node)) {
bool shouldBuildNode(SourceNode n) {
if (n.needsRebuild) return true;
if (n is HtmlSourceNode) return structureHasChanged;
if (n is JavaScriptSourceNode) return false;
return (n as DartSourceNode).imports
.any((i) => apiChangeDetected.contains(i));
}
Expand Down
46 changes: 44 additions & 2 deletions pkg/dev_compiler/test/dependency_graph_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -550,7 +550,11 @@ main() {
group('refresh structure and marks', () {
test('initial marks', () {
var node = nodeOf('/index3.html');
expectGraph(node, 'index3.html');
expectGraph(node, '''
index3.html
|-- dart_runtime.js
|-- harmony_feature_check.js
''');
refreshStructureAndMarks(node, graph);
expectGraph(node, '''
index3.html [needs-rebuild] [structure-changed]
Expand All @@ -560,6 +564,8 @@ main() {
| | |-- a10.dart [needs-rebuild]
| |-- a5.dart [needs-rebuild]
| |-- a6.dart (part) [needs-rebuild]
|-- dart_runtime.js [needs-rebuild]
|-- harmony_feature_check.js [needs-rebuild]
''');
});

Expand All @@ -574,6 +580,8 @@ main() {
| | |-- a10.dart [needs-rebuild]
| |-- a5.dart [needs-rebuild]
| |-- a6.dart (part) [needs-rebuild]
|-- dart_runtime.js [needs-rebuild]
|-- harmony_feature_check.js [needs-rebuild]
''');
clearMarks(node);
expectGraph(node, '''
Expand All @@ -584,6 +592,8 @@ main() {
| | |-- a10.dart
| |-- a5.dart
| |-- a6.dart (part)
|-- dart_runtime.js
|-- harmony_feature_check.js
''');

refreshStructureAndMarks(node, graph);
Expand All @@ -595,6 +605,8 @@ main() {
| | |-- a10.dart
| |-- a5.dart
| |-- a6.dart (part)
|-- dart_runtime.js
|-- harmony_feature_check.js
''');
});

Expand All @@ -614,6 +626,8 @@ main() {
| | |-- a10.dart
| |-- a5.dart
| |-- a6.dart (part)
|-- dart_runtime.js
|-- harmony_feature_check.js
''');
});

Expand All @@ -636,6 +650,8 @@ main() {
| | |-- a8.dart [needs-rebuild] [structure-changed]
| | | |-- a8.dart...
| |-- a6.dart (part)
|-- dart_runtime.js
|-- harmony_feature_check.js
''');
});
});
Expand Down Expand Up @@ -668,7 +684,9 @@ main() {
'a4.dart',
'a5.dart',
'a2.dart',
'index3.html'
'dart_runtime.js',
'harmony_feature_check.js',
'index3.html',
]);

// Marks are removed automatically by rebuild
Expand All @@ -680,6 +698,8 @@ main() {
| | |-- a10.dart
| |-- a5.dart
| |-- a6.dart (part)
|-- dart_runtime.js
|-- harmony_feature_check.js
''');
});

Expand Down Expand Up @@ -830,6 +850,8 @@ main() {
| | |-- a10.dart
| |-- a5.dart
| |-- a6.dart (part)
|-- dart_runtime.js
|-- harmony_feature_check.js
''');

// Modify the file first:
Expand All @@ -850,6 +872,8 @@ main() {
| | |-- a10.dart
| |-- a5.dart
| |-- a6.dart (part)
|-- dart_runtime.js
|-- harmony_feature_check.js
''');

a2.source.contents.modificationTime++;
Expand Down Expand Up @@ -880,6 +904,8 @@ main() {
| |-- a6.dart
| | |-- a5.dart
| |-- a5.dart...
|-- dart_runtime.js
|-- harmony_feature_check.js
''');
});

Expand All @@ -897,6 +923,8 @@ main() {
| | |-- a10.dart
| |-- a5.dart
| |-- a6.dart (part)
|-- dart_runtime.js
|-- harmony_feature_check.js
''');

a2.source.contents.modificationTime++;
Expand All @@ -918,6 +946,8 @@ main() {
| | |-- a10.dart
| |-- a6.dart
| |-- a5.dart
|-- dart_runtime.js
|-- harmony_feature_check.js
''');

a6.source.contents.modificationTime++;
Expand All @@ -934,6 +964,8 @@ main() {
| |-- a6.dart
| | |-- a5.dart
| |-- a5.dart...
|-- dart_runtime.js
|-- harmony_feature_check.js
''');
});

Expand All @@ -951,6 +983,8 @@ main() {
| | |-- a10.dart
| |-- a5.dart
| |-- a6.dart (part)
|-- dart_runtime.js
|-- harmony_feature_check.js
''');

a2.source.contents.modificationTime++;
Expand All @@ -973,6 +1007,8 @@ main() {
| |-- a4.dart
| | |-- a10.dart
| |-- a5.dart
|-- dart_runtime.js
|-- harmony_feature_check.js
''');
});

Expand All @@ -990,6 +1026,8 @@ main() {
| | |-- a10.dart
| |-- a5.dart
| |-- a6.dart (part)
|-- dart_runtime.js
|-- harmony_feature_check.js
''');

a2.source.contents.modificationTime++;
Expand All @@ -1011,6 +1049,8 @@ main() {
| | |-- a10.dart
| |-- a5.dart (part)
| |-- a6.dart (part)
|-- dart_runtime.js
|-- harmony_feature_check.js
''');

a5.source.contents.modificationTime++;
Expand All @@ -1026,6 +1066,8 @@ main() {
| | |-- a10.dart
| |-- a5.dart (part)
| |-- a6.dart (part)
|-- dart_runtime.js
|-- harmony_feature_check.js
''');
});
});
Expand Down

0 comments on commit ca80f2c

Please sign in to comment.