Skip to content

Commit

Permalink
Resolve local paths in es6 modules (+ refactor ModuleBuilder)
Browse files Browse the repository at this point in the history
  • Loading branch information
ochafik committed Jan 26, 2016
1 parent adf6842 commit 4eec9f5
Show file tree
Hide file tree
Showing 3 changed files with 39 additions and 34 deletions.
12 changes: 6 additions & 6 deletions pkg/dev_compiler/lib/src/codegen/js_codegen.dart
Original file line number Diff line number Diff line change
Expand Up @@ -179,11 +179,7 @@ class JSCodegenVisitor extends GeneralizingAstVisitor with ClosureAnnotator {
id.setQualified(!_loader.isLoaded(element));
}

var moduleBuilder = new ModuleBuilder(
compiler.getModuleName(currentLibrary.source.uri),
_jsModuleValue,
_exportsVar,
options.moduleFormat);
var moduleBuilder = new ModuleBuilder(options.moduleFormat);

_exports.forEach(moduleBuilder.addExport);

Expand All @@ -208,7 +204,11 @@ class JSCodegenVisitor extends GeneralizingAstVisitor with ClosureAnnotator {
// var jsBin = compiler.options.runnerOptions.v8Binary;
// String scriptTag = null;
// if (library.library.scriptTag != null) scriptTag = '/usr/bin/env $jsBin';
return moduleBuilder.build(items);
return moduleBuilder.build(
compiler.getModuleName(currentLibrary.source.uri),
_jsModuleValue,
_exportsVar,
items);
}

void _emitModuleItem(AstNode node) {
Expand Down
56 changes: 31 additions & 25 deletions pkg/dev_compiler/lib/src/codegen/module_builder.dart
Original file line number Diff line number Diff line change
Expand Up @@ -4,19 +4,18 @@

library dev_compiler.src.codegen.module_builder;

import 'package:path/path.dart' show relative;

import '../js/js_ast.dart' as JS;
import '../js/js_ast.dart' show js;
import '../options.dart' show ModuleFormat;

/// Helper that builds JS modules in a given [ModuleFormat].
abstract class ModuleBuilder {
final String _jsPath;
final String _jsModuleValue;
final JS.Identifier _exportsVar;
final List<String> _exports = <String>[];
final List<_ModuleImport> _imports = <_ModuleImport>[];

ModuleBuilder._(this._jsPath, this._jsModuleValue, this._exportsVar);
ModuleBuilder._();

/// Returns a [format]-specific [ModuleBuilder].
/// - [jsPath] is the path of the module being built.
Expand All @@ -25,13 +24,12 @@ abstract class ModuleBuilder {
/// library directive). It is null in any other case.
/// - [exportsVar] is the name of the object on which items are exported. Lazy
/// variables and constants are assumed to be declared on this instance.
factory ModuleBuilder(String jsPath, String jsModuleValue,
JS.Identifier exportsVar, ModuleFormat format) {
factory ModuleBuilder(ModuleFormat format) {
switch (format) {
case ModuleFormat.legacy:
return new LegacyModuleBuilder(jsPath, jsModuleValue, exportsVar);
return new LegacyModuleBuilder();
case ModuleFormat.es6:
return new ES6ModuleBuilder(jsPath, jsModuleValue, exportsVar);
return new ES6ModuleBuilder();
}
}

Expand All @@ -48,7 +46,8 @@ abstract class ModuleBuilder {
}

/// Builds a program out of menu items.
JS.Program build(List<JS.ModuleItem> moduleItems);
JS.Program build(String jsPath, String jsModuleValue,
JS.Identifier exportsVar, Iterable<JS.ModuleItem> moduleItems);
}

class _ModuleImport {
Expand All @@ -63,14 +62,14 @@ class _ModuleImport {

/// Generates modules for with DDC's `dart_library.js` loading mechanism.
class LegacyModuleBuilder extends ModuleBuilder {
LegacyModuleBuilder(jsPath, _jsModuleValue, _exportsVar)
: super._(jsPath, _jsModuleValue, _exportsVar);
LegacyModuleBuilder() : super._();

JS.Program build(List<JS.ModuleItem> moduleItems) {
JS.Program build(String jsPath, String jsModuleValue,
JS.Identifier exportsVar, List<JS.ModuleItem> moduleItems) {
// TODO(jmesserly): it would be great to run the renamer on the body,
// then figure out if we really need each of these parameters.
// See ES6 modules: https://github.com/dart-lang/dev_compiler/issues/34
var params = [_exportsVar];
var params = [exportsVar];
var lazyParams = [];

var imports = <JS.Expression>[];
Expand All @@ -90,16 +89,16 @@ class LegacyModuleBuilder extends ModuleBuilder {
// TODO(jmesserly): make these immutable in JS?
for (var name in _exports) {
moduleStatements
.add(js.statement('#.# = #;', [_exportsVar, name, name]));
.add(js.statement('#.# = #;', [exportsVar, name, name]));
}
}

var module =
js.call("function(#) { 'use strict'; #; }", [params, moduleStatements]);

var moduleDef = js.statement("dart_library.library(#, #, #, #, #)", [
js.string(_jsPath, "'"),
_jsModuleValue ?? new JS.LiteralNull(),
js.string(jsPath, "'"),
jsModuleValue ?? new JS.LiteralNull(),
js.commentExpression(
"Imports", new JS.ArrayInitializer(imports, multiline: true)),
js.commentExpression("Lazy imports",
Expand All @@ -110,25 +109,31 @@ class LegacyModuleBuilder extends ModuleBuilder {
}
}

String _relativeModuleName(String moduleName, {String from}) {
var relativeName = relative('/' + moduleName, from: '/' + from + '/..');
return relativeName.startsWith('.') ? relativeName : './$relativeName';
}

/// Generates ES6 modules.
// TODO(ochafik): Break strong dep cycles to accommodate the Closure Compiler.
class ES6ModuleBuilder extends ModuleBuilder {
ES6ModuleBuilder(jsPath, _jsModuleValue, _exportsVar)
: super._(jsPath, _jsModuleValue, _exportsVar);
ES6ModuleBuilder() : super._();

JS.Program build(List<JS.ModuleItem> moduleItems) {
JS.Program build(String jsPath, String jsModuleValue,
JS.Identifier exportsVar, Iterable<JS.ModuleItem> moduleItems) {
var moduleStatements = <JS.ModuleItem>[
// Lazy declarations may reference exports.
js.statement("const # = {};", [_exportsVar])
js.statement("const # = {};", [exportsVar])
];

// TODO(jmesserly): it would be great to run the renamer on the body,
// then figure out if we really need each of these parameters.
// See ES6 modules: https://github.com/dart-lang/dev_compiler/issues/34
for (var i in _imports) {
var moduleName = js.string(_relativeModuleName(i.name, from: jsPath));
// TODO(ochafik): laziness, late binding, etc, to support Closure...
moduleStatements.add(new JS.ImportDeclaration(
defaultBinding: i.libVar, from: js.string(i.name)));
defaultBinding: i.libVar, from: moduleName));
}

moduleStatements.addAll(_flattenBlocks(moduleItems));
Expand All @@ -138,12 +143,12 @@ class ES6ModuleBuilder extends ModuleBuilder {
// TODO(jmesserly): make these immutable in JS?
for (var name in _exports) {
moduleStatements
.add(js.statement('#.# = #;', [_exportsVar, name, name]));
.add(js.statement('#.# = #;', [exportsVar, name, name]));
}
moduleStatements
.add(new JS.ExportDeclaration(_exportsVar, isDefault: true));
.add(new JS.ExportDeclaration(exportsVar, isDefault: true));
}
// TODO(ochafik): What to do of _jsModuleValue?
// TODO(ochafik): What to do of jsModuleValue?
return new JS.Program(moduleStatements);
}
}
Expand All @@ -155,4 +160,5 @@ class ES6ModuleBuilder extends ModuleBuilder {
// are generated from [JSCodegenVisitor], instead of composing them with
// [_statements]).
Iterable<JS.ModuleItem> _flattenBlocks(List<JS.ModuleItem> stats) =>
stats.expand((item) => item is JS.Block ? item.statements : [item]);
stats.expand((item) => item is JS.Block
? _flattenBlocks(item.statements) : [item]);
5 changes: 2 additions & 3 deletions pkg/dev_compiler/test/codegen/expect/es6_modules.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
'use strict';
const exports = {};
import dart from "dart/_runtime";
import core from "dart/core";
import dart from "./dart/_runtime";
import core from "./dart/core";
let dartx = dart.dartx;
const Callback = dart.typedef('Callback', () => dart.functionType(dart.void, [], {i: core.int}));
class A extends core.Object {}
Expand Down

0 comments on commit 4eec9f5

Please sign in to comment.