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: + * + *

+ * + * @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';");