Skip to content

Commit

Permalink
Use module.export(getters, true) for const ExportNamedDeclaration.
Browse files Browse the repository at this point in the history
These changes let the runtime know that the values returned by the getter
functions for

  export const a = 1, b = 2;

will never change. Unfortunately, it's more difficult to detect that the
same is true for

  const a = 1, b = 2;
  export { a, b };

though that's an area for future improvement.

Part of #134.
  • Loading branch information
benjamn committed May 18, 2017
1 parent b26d9fe commit 0d44e8d
Show file tree
Hide file tree
Showing 3 changed files with 46 additions and 13 deletions.
55 changes: 44 additions & 11 deletions lib/import-export-visitor.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,14 +26,15 @@ class ImportExportVisitor extends Visitor {
codeToInsert += '"use strict";';
}

const namedExports = toModuleExport(
this,
bodyInfo.hoistedExportsMap
);
const addExportsMap = (map, constant) => {
const namedExports = toModuleExport(this, map, constant);
if (namedExports) {
codeToInsert += namedExports;
}
};

if (namedExports) {
codeToInsert += namedExports;
}
addExportsMap(bodyInfo.hoistedExportsMap, false);
addExportsMap(bodyInfo.hoistedConstExportsMap, true);

if (bodyInfo.hoistedExportsString) {
codeToInsert += bodyInfo.hoistedExportsString;
Expand Down Expand Up @@ -303,7 +304,14 @@ class ImportExportVisitor extends Visitor {
}

hoistExports(this, path, specifierMap, "declaration");
addExportedLocalNames(this, specifierMap);

if (! isConstExportDeclaration(decl)) {
// We can skip adding declared names to this.exportedLocalNames if
// the declaration was a const-kinded VariableDeclaration, because
// the assignmentVisitor will not need to worry about changes to
// these variables.
addExportedLocalNames(this, specifierMap);
}

return;
}
Expand Down Expand Up @@ -528,6 +536,7 @@ function getBlockBodyInfo(visitor, path) {
bodyInfo.insertCharIndex = insertCharIndex;
bodyInfo.insertNodeIndex = insertNodeIndex;
bodyInfo.hoistedExportsMap = Object.create(null);
bodyInfo.hoistedConstExportsMap = Object.create(null);
bodyInfo.hoistedExportsString = "";
bodyInfo.hoistedImportsString = "";

Expand Down Expand Up @@ -575,6 +584,7 @@ function hoistExports(visitor, exportDeclPath, mapOrString, childName) {
}

const bodyInfo = getBlockBodyInfo(visitor, exportDeclPath);
const constant = isConstExportDeclaration(exportDeclPath.getValue());

if (typeof mapOrString !== "string") {
const keys = Object.keys(mapOrString);
Expand All @@ -587,7 +597,9 @@ function hoistExports(visitor, exportDeclPath, mapOrString, childName) {

for (let j = 0; j < localCount; ++j) {
addToSpecifierMap(
bodyInfo.hoistedExportsMap,
constant
? bodyInfo.hoistedConstExportsMap
: bodyInfo.hoistedExportsMap,
exported,
locals[j]
);
Expand All @@ -601,6 +613,25 @@ function hoistExports(visitor, exportDeclPath, mapOrString, childName) {
visitor.madeChanges = true;
}

function isConstExportDeclaration(exportDecl) {
if (exportDecl) {
if (exportDecl.type === "ExportDefaultDeclaration") {
const dd = exportDecl.declaration;
return (dd.type !== "FunctionDeclaration" &&
dd.type !== "ClassDeclaration");
}

if (exportDecl.type === "ExportNamedDeclaration") {
const dd = exportDecl.declaration;
return !! dd &&
dd.type === "VariableDeclaration" &&
dd.kind === "const";
}
}

return false;
}

function makeUniqueKey(visitor) {
return visitor.nextKey++;
}
Expand Down Expand Up @@ -802,7 +833,7 @@ function toModuleImport(source, specifierMap, uniqueKey) {
return code;
}

function toModuleExport(visitor, specifierMap) {
function toModuleExport(visitor, specifierMap, constant) {
let code = "";
const exportedKeys = Object.keys(specifierMap);
const keyCount = exportedKeys.length;
Expand Down Expand Up @@ -834,7 +865,9 @@ function toModuleExport(visitor, specifierMap) {
}
}

code += "});";
// The second argument to module.export indicates whether the getter
// functions provided in the first argument are constant or not.
code += constant ? "},true);" : "});";

return code;
}
Expand Down
2 changes: 1 addition & 1 deletion test/output/declarations-basic/expected.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
"use strict";module.export({a:()=>a,b:()=>b,c:()=>c,d:()=>d});const a = 1;
"use strict";module.export({c:()=>c,d:()=>d});module.export({a:()=>a,b:()=>b},true);const a = 1;
const b = function () {
return d;
};
Expand Down
2 changes: 1 addition & 1 deletion test/output/name/expected.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
"use strict";module.export({id:()=>id,name:()=>name});const path = require("path");
"use strict";module.export({id:()=>id,name:()=>name},true);const path = require("path");

const id = module.id,
name = path.basename(__filename);

0 comments on commit 0d44e8d

Please sign in to comment.