Skip to content

Commit

Permalink
behave according to precedence rules from spec
Browse files Browse the repository at this point in the history
  • Loading branch information
sokra committed Dec 23, 2015
1 parent b6da0ee commit bde8636
Show file tree
Hide file tree
Showing 8 changed files with 117 additions and 4 deletions.
28 changes: 25 additions & 3 deletions lib/dependencies/HarmonyExportImportedSpecifierDependency.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
Author Tobias Koppers @sokra
*/
var NullDependency = require("./NullDependency");
var HarmonyModulesHelpers = require("./HarmonyModulesHelpers");

function HarmonyExportImportedSpecifierDependency(originModule, importDependency, importedVar, id, name, position) {
NullDependency.call(this);
Expand All @@ -21,10 +22,19 @@ HarmonyExportImportedSpecifierDependency.prototype.type = "harmony export import

HarmonyExportImportedSpecifierDependency.prototype.getReference = function() {
var used = this.originModule.isUsed(this.name);
if(!this.importDependency.module || !used) return null;
var active = HarmonyModulesHelpers.isActive(this.originModule, this);
if(!this.importDependency.module || !used || !active) return null;
return {
module: this.importDependency.module,
importedNames: this.id ? [this.id] : true
importedNames: this.id ? [this.id] : true,
precedence: this.name ? 2 : 3
};
};

HarmonyExportImportedSpecifierDependency.prototype.describeHarmonyExport = function() {
return {
exportedName: this.name,
precedence: this.name ? 2 : 3
};
};

Expand All @@ -33,17 +43,29 @@ HarmonyExportImportedSpecifierDependency.Template = function HarmonyExportImport
HarmonyExportImportedSpecifierDependency.Template.prototype.apply = function(dep, source, outputOptions, requestShortener) {
var name = dep.importedVar;
var used = dep.originModule.isUsed(dep.name);
var active = HarmonyModulesHelpers.isActive(dep.originModule, dep);
var comment = "";
if(outputOptions.pathinfo) comment = "/*! " + requestShortener.shorten(dep.request) + " */ ";
var content;
if(!used) {
content = "/* unused harmony reexport " + (dep.name || "namespace") + " */;";
} else if(!active) {
content = "/* inactive harmony reexport " + (dep.name || "namespace") + " */;";
} else if(dep.name === "default" && !dep.importDependency.module.meta.harmonyModule) {
content = "/* harmony reexport */ Object.defineProperty(exports, " + JSON.stringify(dep.name) + ", {configurable: false, enumerable: true, get: function() { return " + comment + name + "_default.a; }});";
} else if(dep.name) {
content = "/* harmony reexport */ Object.defineProperty(exports, " + JSON.stringify(dep.name) + ", {configurable: false, enumerable: true, get: function() { return " + comment + (name + "[" + JSON.stringify(dep.id) + "]") + "; }});";
} else {
content = "/* harmony namespace reexport */ for(var __WEBPACK_IMPORT_KEY__ in " + comment + name + ") (function(key) { Object.defineProperty(exports, key, {configurable: false, enumerable: true, get: function() { return " + name + "[key]; }}) }(__WEBPACK_IMPORT_KEY__));";
var activeExports = HarmonyModulesHelpers.getActiveExports(dep.originModule);
content = "/* harmony namespace reexport */ for(var __WEBPACK_IMPORT_KEY__ in " + comment + name + ") ";

// Filter out exports which are defined by other exports
// and filter out default export because it cannot be reexported with *
if(activeExports.length > 0)
content += "if(" + JSON.stringify(activeExports.concat("default")) + ".indexOf(__WEBPACK_IMPORT_KEY__) < 0) ";
else
content += "if(__WEBPACK_IMPORT_KEY__ !== 'default') ";
content += "(function(key) { Object.defineProperty(exports, key, {configurable: false, enumerable: true, get: function() { return " + name + "[key]; }}) }(__WEBPACK_IMPORT_KEY__));";
}
source.insert(dep.position, content);

Expand Down
11 changes: 11 additions & 0 deletions lib/dependencies/HarmonyExportSpecifierDependency.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
Author Tobias Koppers @sokra
*/
var NullDependency = require("./NullDependency");
var HarmonyModulesHelpers = require("./HarmonyModulesHelpers");

function HarmonyExportSpecifierDependency(originModule, id, name, position, immutable) {
NullDependency.call(this);
Expand All @@ -18,13 +19,23 @@ HarmonyExportSpecifierDependency.prototype = Object.create(NullDependency.protot
HarmonyExportSpecifierDependency.prototype.constructor = HarmonyExportSpecifierDependency;
HarmonyExportSpecifierDependency.prototype.type = "harmony export specifier";

HarmonyExportSpecifierDependency.prototype.describeHarmonyExport = function() {
return {
exportedName: this.name,
precedence: 1
};
};

HarmonyExportSpecifierDependency.Template = function HarmonyExportSpecifierDependencyTemplate() {};

HarmonyExportSpecifierDependency.Template.prototype.apply = function(dep, source) {
var used = dep.originModule.isUsed(dep.name);
var active = HarmonyModulesHelpers.isActive(dep.originModule, dep);
var content;
if(!used) {
content = "/* unused harmony export " + (dep.name || "namespace") + " */;";
} else if(!active) {
content = "/* inactive harmony export " + (dep.name || "namespace") + " */;";
} else if(dep.immutable) {
content = "/* harmony export */ exports[" + JSON.stringify(dep.name) + "] = " + dep.id + ";";
} else {
Expand Down
44 changes: 43 additions & 1 deletion lib/dependencies/HarmonyModulesHelpers.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,4 +24,46 @@ HarmonyModulesHelpers.checkModuleVar = function(state, request) {
if(!state.harmonyModules || state.harmonyModules.indexOf(request) < 0)
return null;
return HarmonyModulesHelpers.getModuleVar(state, request);
}
};

// checks if an harmory dependency is active in a module according to
// precedence rules.
HarmonyModulesHelpers.isActive = function(module, depInQuestion) {
var desc = depInQuestion.describeHarmonyExport();
if(!desc.exportedName) return true;
var before = true;
for(var i = 0; i < module.dependencies.length; i++) {
var dep = module.dependencies[i];
if(dep === depInQuestion) {
before = false;
continue;
}
if(!dep.describeHarmonyExport) continue;
var d = dep.describeHarmonyExport();
if(!d || !d.exportedName) continue;
if(d.exportedName === desc.exportedName) {
if(d.precedence < desc.precedence) {
return false;
}
if(d.precedence === desc.precedence && !before) {
return false;
}
}
}
return true;
};

// get a list of named exports defined in a module
// doesn't include * reexports.
HarmonyModulesHelpers.getActiveExports = function(module) {
return module.dependencies.reduce(function(arr, dep) {
if(!dep.describeHarmonyExport) return arr;
var d = dep.describeHarmonyExport();
if(!d) return arr;
var name = d.exportedName;
if(!name || arr.indexOf(name) >= 0) return arr;
arr.push(name);
return arr;
}, [])
};

5 changes: 5 additions & 0 deletions test/cases/parsing/harmony-export-precedence/a.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
export function a() { return "a1"; }
export { a, b } from "./b";
export * from "./c";
export { d, e } from "./b";
export var e = "e1";
5 changes: 5 additions & 0 deletions test/cases/parsing/harmony-export-precedence/b.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
export var a = "a2";
export var b = "b2";
export var c = "c2";
export var d = "d2";
export var e = "e2";
6 changes: 6 additions & 0 deletions test/cases/parsing/harmony-export-precedence/c.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
export var a = "a3";
export var b = "b3";
export var c = "c3";
export var e = "e3";
export var f = "f3";
export default "default";
1 change: 1 addition & 0 deletions test/cases/parsing/harmony-export-precedence/d.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export default "default";
21 changes: 21 additions & 0 deletions test/cases/parsing/harmony-export-precedence/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import { a, b, c, d, e } from "./a";

import defaultImport from "./a";

it("should prefer local exports", function() {
a().should.be.eql("a1");
e.should.be.eql("e1");
});

it("should prefer indirect exports over star exports", function() {
b.should.be.eql("b2");
d.should.be.eql("d2");
});

it("should use star exports", function() {
c.should.be.eql("c3");
});

it("should not export default via star export", function() {
(typeof defaultImport).should.be.eql("undefined");
});

0 comments on commit bde8636

Please sign in to comment.