diff --git a/javascript/extractor/src/com/semmle/jcorn/Parser.java b/javascript/extractor/src/com/semmle/jcorn/Parser.java index 28b652e5c7f0..9525d5236d5c 100644 --- a/javascript/extractor/src/com/semmle/jcorn/Parser.java +++ b/javascript/extractor/src/com/semmle/jcorn/Parser.java @@ -3547,7 +3547,19 @@ protected List parseExportSpecifiers(Set exports) { SourceLocation loc = new SourceLocation(this.startLoc); Identifier local = this.parseIdent(this.type == TokenType._default); - Identifier exported = this.eatContextual("as") ? this.parseIdent(true) : local; + Identifier exported; + if (!this.eatContextual("as")) { + exported = local; + } else { + if (this.type == TokenType.string) { + // e.g. `export { Foo_new as "Foo::new" }` + Expression string = this.parseExprAtom(null); + String str = ((Literal)string).getStringValue(); + exported = new Identifier(loc, str); + } else { + exported = this.parseIdent(true); + } + } checkExport(exports, exported.getName(), exported.getLoc().getStart()); nodes.add(this.finishNode(new ExportSpecifier(loc, local, exported))); } diff --git a/javascript/ql/test/library-tests/Modules/arbitarySpecifier.js b/javascript/ql/test/library-tests/Modules/arbitarySpecifier.js index 0d3bfd07bbc1..64f88bd1bed6 100644 --- a/javascript/ql/test/library-tests/Modules/arbitarySpecifier.js +++ b/javascript/ql/test/library-tests/Modules/arbitarySpecifier.js @@ -1 +1,5 @@ import { "Foo::new" as Foo_new } from "./foo.wasm" + +const foo = Foo_new() + +export { Foo_new as "Foo::new" } \ No newline at end of file diff --git a/javascript/ql/test/library-tests/Modules/tests.expected b/javascript/ql/test/library-tests/Modules/tests.expected index a3932d29cfb9..a742e604218f 100644 --- a/javascript/ql/test/library-tests/Modules/tests.expected +++ b/javascript/ql/test/library-tests/Modules/tests.expected @@ -3,6 +3,7 @@ test_BulkReExportDeclarations test_ExportDeclarations | a.js:1:1:3:1 | export ... n 23;\\n} | | a.js:5:1:5:32 | export ... } = o; | +| arbitarySpecifier.js:5:1:5:32 | export ... :new" } | | b.js:5:1:5:18 | export { f as g }; | | b.js:7:1:7:21 | export ... './a'; | | d.js:4:1:4:20 | export * from 'm/c'; | @@ -18,6 +19,7 @@ test_ExportDefaultDeclarations | a.js:1:1:3:1 | export ... n 23;\\n} | | es2015_require.js:3:1:3:25 | export ... ss C {} | test_ExportSpecifiers +| arbitarySpecifier.js:5:10:5:30 | Foo_new ... o::new" | arbitarySpecifier.js:5:10:5:16 | Foo_new | arbitarySpecifier.js:5:10:5:30 | Foo_new ... o::new" | | b.js:5:10:5:15 | f as g | b.js:5:10:5:10 | f | b.js:5:15:5:15 | g | | e.js:2:10:2:10 | x | e.js:2:10:2:10 | x | e.js:2:10:2:10 | x | | e.js:2:13:2:13 | y | e.js:2:13:2:13 | y | e.js:2:13:2:13 | y | @@ -74,6 +76,7 @@ test_Module_exports | a.js:1:1:5:32 | | default | a.js:1:16:3:1 | functio ... n 23;\\n} | | a.js:1:1:5:32 | | x | a.js:5:18:5:20 | f() | | a.js:1:1:5:32 | | y | a.js:5:25:5:25 | y | +| arbitarySpecifier.js:1:1:5:32 | | Foo::new | arbitarySpecifier.js:5:10:5:16 | Foo_new | | b.js:1:1:8:0 | | f2 | a.js:1:16:3:1 | functio ... n 23;\\n} | | b.js:1:1:8:0 | | g | b.js:5:10:5:10 | f | | e.js:1:1:4:0 | | g | a.js:1:16:3:1 | functio ... n 23;\\n} | @@ -114,6 +117,7 @@ test_getAnImportedModule | library-tests/Modules/m/c.js | library-tests/Modules/b.js | | library-tests/Modules/reExportNamespaceClient.js | library-tests/Modules/reExportNamespace.js | test_getExportedName +| arbitarySpecifier.js:5:10:5:30 | Foo_new ... o::new" | Foo::new | | b.js:5:10:5:15 | f as g | g | | b.js:7:8:7:9 | f2 | f2 | | e.js:2:10:2:10 | x | x | @@ -135,6 +139,7 @@ test_getImportedName | tst.html:5:10:5:10 | f | default | | unresolved.js:1:8:1:8 | f | default | test_getLocalName +| arbitarySpecifier.js:5:10:5:30 | Foo_new ... o::new" | Foo_new | | b.js:5:10:5:15 | f as g | f | | b.js:7:8:7:9 | f2 | default | | e.js:2:10:2:10 | x | x | @@ -145,6 +150,7 @@ test_getSourceNode | a.js:1:1:3:1 | export ... n 23;\\n} | default | a.js:1:16:3:1 | functio ... n 23;\\n} | | a.js:5:1:5:32 | export ... } = o; | x | a.js:5:18:5:20 | f() | | a.js:5:1:5:32 | export ... } = o; | y | a.js:5:25:5:25 | y | +| arbitarySpecifier.js:5:1:5:32 | export ... :new" } | Foo::new | arbitarySpecifier.js:5:10:5:16 | Foo_new | | b.js:5:1:5:18 | export { f as g }; | g | b.js:5:10:5:10 | f | | b.js:7:1:7:21 | export ... './a'; | f2 | a.js:1:16:3:1 | functio ... n 23;\\n} | | e.js:2:1:2:16 | export { x, y }; | x | e.js:2:10:2:10 | x |