diff --git a/src/com/google/javascript/jscomp/MakeDeclaredNamesUnique.java b/src/com/google/javascript/jscomp/MakeDeclaredNamesUnique.java
index 99bc936865d..57c2be9bbb9 100644
--- a/src/com/google/javascript/jscomp/MakeDeclaredNamesUnique.java
+++ b/src/com/google/javascript/jscomp/MakeDeclaredNamesUnique.java
@@ -108,7 +108,7 @@ public void visit(NodeTraversal t, Node n, Node parent) {
switch (n.getToken()) {
case NAME:
case IMPORT_STAR:
- visitName(t, n, parent);
+ visitNameOrImportStar(t, n, parent);
break;
default:
@@ -116,9 +116,9 @@ public void visit(NodeTraversal t, Node n, Node parent) {
}
}
- private void visitName(NodeTraversal t, Node n, Node parent) {
+ private void visitNameOrImportStar(NodeTraversal t, Node n, Node parent) {
// Don't rename the exported name foo in export {a as foo}; or import {foo as b};
- if (NodeUtil.isNonlocalModuleExportName(n)) {
+ if (n.isName() && NodeUtil.isNonlocalModuleExportName(n)) {
return;
}
String newName = getReplacementName(n.getString());
diff --git a/src/com/google/javascript/jscomp/NodeUtil.java b/src/com/google/javascript/jscomp/NodeUtil.java
index 76ea785763e..1f6a0227f33 100644
--- a/src/com/google/javascript/jscomp/NodeUtil.java
+++ b/src/com/google/javascript/jscomp/NodeUtil.java
@@ -2734,16 +2734,37 @@ static boolean isReferenceName(Node n) {
}
/**
- * @return Whether the name in an import or export spec is not defined within the module, but is
- * an exported name from this or another module. e.g. nonlocal in "export {a as nonlocal}" or
- * "import {nonlocal as a} from './foo.js'"
+ * Returns whether the given name in an import or export spec is not defined within the module,
+ * but is an exported name from this or another module.
+ *
+ *
Examples include `nonlocal` in:
+ *
+ *
+ * - export {a as nonlocal};
+ *
- import {nonlocal} from './foo.js';
+ *
- import {nonlocal as a} from './foo.js';
+ *
- export {nonlocal as a} from './foo.js';
+ *
- export {a as nonlocal} from './foo.js';
+ *
+ *
+ * @param n a NAME node.
*/
static boolean isNonlocalModuleExportName(Node n) {
+ checkArgument(n.isName(), n);
Node parent = n.getParent();
- return (parent != null
- && n.isName()
- && ((parent.isExportSpec() && n != parent.getFirstChild())
- || (parent.isImportSpec() && n != parent.getLastChild())));
+ if (parent.isImportSpec() && n.isFirstChildOf(parent)) {
+ // import {nonlocal as x} from './foo.js'
+ return true;
+ } else if (parent.isExportSpec()) {
+ if (n.isFirstChildOf(parent)) {
+ // export {nonlocal as b} from './foo.js';
+ return isExportFrom(parent.getGrandparent());
+ } else {
+ // export {local as nonlocal};
+ return true;
+ }
+ }
+ return false;
}
/** Whether the child node is the FINALLY block of a try. */
diff --git a/test/com/google/javascript/jscomp/NodeUtilTest.java b/test/com/google/javascript/jscomp/NodeUtilTest.java
index 337066a2e6c..c1c8546c6a7 100644
--- a/test/com/google/javascript/jscomp/NodeUtilTest.java
+++ b/test/com/google/javascript/jscomp/NodeUtilTest.java
@@ -1274,6 +1274,22 @@ public void testIsNonlocalModuleExportNameOnExports2() {
assertThat(NodeUtil.isNonlocalModuleExportName(name)).isFalse();
}
+ @Test
+ public void testIsNonlocalModuleExportNameOnExportFrom() {
+ Node root = parse("export {bar as baz} from './foo.js';");
+ Node moduleBody = root.getFirstChild();
+ Node exportNode = moduleBody.getFirstChild();
+ Node exportSpecs = exportNode.getFirstChild();
+ Node exportSpec = exportSpecs.getFirstChild();
+
+ Node bar = exportSpec.getFirstChild();
+ Node baz = exportSpec.getSecondChild();
+
+ // Neither identifier is defined locally.
+ assertThat(NodeUtil.isNonlocalModuleExportName(bar)).isTrue();
+ assertThat(NodeUtil.isNonlocalModuleExportName(baz)).isTrue();
+ }
+
@Test
public void testIsNonlocalModuleExportNameOnImports1() {
Node root = parse("import {exportName as localName} from './foo.js';");