Skip to content

Commit

Permalink
JS: fix import/export with empty named imports, see #108
Browse files Browse the repository at this point in the history
  • Loading branch information
tdewolff committed Oct 26, 2023
1 parent 48dbb9f commit 5078a15
Show file tree
Hide file tree
Showing 4 changed files with 39 additions and 24 deletions.
37 changes: 22 additions & 15 deletions js/ast.go
Original file line number Diff line number Diff line change
Expand Up @@ -920,7 +920,7 @@ func (n ImportStmt) String() string {
}
if len(n.List) == 1 && len(n.List[0].Name) == 1 && n.List[0].Name[0] == '*' {
s += " " + n.List[0].String()
} else if 0 < len(n.List) {
} else if n.List != nil {
s += " {"
for i, item := range n.List {
if i != 0 {
Expand All @@ -932,7 +932,7 @@ func (n ImportStmt) String() string {
}
s += " }"
}
if n.Default != nil || len(n.List) != 0 {
if n.Default != nil || n.List != nil {
s += " from"
}
return s + " " + string(n.Module) + ")"
Expand All @@ -945,26 +945,30 @@ func (n ImportStmt) JS(w io.Writer) {
w.Write([]byte(" "))
w.Write(n.Default)
if len(n.List) != 0 {
w.Write([]byte(" ,"))
w.Write([]byte(","))
}
}
if len(n.List) == 1 && len(n.List[0].Name) == 1 && n.List[0].Name[0] == '*' {
w.Write([]byte(" "))
n.List[0].JS(w)
} else if 0 < len(n.List) {
w.Write([]byte(" {"))
for j, item := range n.List {
if j != 0 {
w.Write([]byte(" ,"))
}
if item.Binding != nil {
w.Write([]byte(" "))
item.JS(w)
} else if n.List != nil {
if len(n.List) == 0 {
w.Write([]byte(" {}"))
} else {
w.Write([]byte(" {"))
for j, item := range n.List {
if j != 0 {
w.Write([]byte(","))
}
if item.Binding != nil {
w.Write([]byte(" "))
item.JS(w)
}
}
w.Write([]byte(" }"))
}
w.Write([]byte(" }"))
}
if n.Default != nil || len(n.List) != 0 {
if n.Default != nil || n.List != nil {
w.Write([]byte(" from"))
}
w.Write([]byte(" "))
Expand Down Expand Up @@ -1021,11 +1025,13 @@ func (n ExportStmt) JS(w io.Writer) {
} else if len(n.List) == 1 && (len(n.List[0].Name) == 1 && n.List[0].Name[0] == '*' || n.List[0].Name == nil && len(n.List[0].Binding) == 1 && n.List[0].Binding[0] == '*') {
w.Write([]byte(" "))
n.List[0].JS(w)
} else if len(n.List) == 0 {
w.Write([]byte(" {}"))
} else {
w.Write([]byte(" {"))
for j, item := range n.List {
if j != 0 {
w.Write([]byte(" ,"))
w.Write([]byte(","))
}
if item.Binding != nil {
w.Write([]byte(" "))
Expand All @@ -1038,6 +1044,7 @@ func (n ExportStmt) JS(w io.Writer) {
w.Write([]byte(" from "))
w.Write(n.Module)
}
w.Write([]byte(";"))
}

// DirectivePrologueStmt is a string literal at the beginning of a function or module (usually "use strict").
Expand Down
10 changes: 6 additions & 4 deletions js/ast_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -51,12 +51,12 @@ func TestJS(t *testing.T) {
{"import * as name from 'module-name';", "import * as name from 'module-name';"},
{"import { export1 } from 'module-name';", "import { export1 } from 'module-name';"},
{"import { export1 as alias1 } from 'module-name';", "import { export1 as alias1 } from 'module-name';"},
{"import { export1 , export2 } from 'module-name';", "import { export1 , export2 } from 'module-name';"},
{"import { foo , bar } from 'module-name/path/to/specific/un-exported/file';", "import { foo , bar } from 'module-name/path/to/specific/un-exported/file';"},
{"import defaultExport, * as name from 'module-name';", "import defaultExport , * as name from 'module-name';"},
{"import { export1 , export2 } from 'module-name';", "import { export1, export2 } from 'module-name';"},
{"import { foo , bar } from 'module-name/path/to/specific/un-exported/file';", "import { foo, bar } from 'module-name/path/to/specific/un-exported/file';"},
{"import defaultExport, * as name from 'module-name';", "import defaultExport, * as name from 'module-name';"},
{"import 'module-name';", "import 'module-name';"},
{"var promise = import('module-name');", "var promise = import('module-name');"},
{"export { myFunction as default }", "export { myFunction as default }"},
{"export { myFunction as default }", "export { myFunction as default };"},
{"export default k = 12;", "export default k = 12;"},
{"'use strict';", "'use strict';"},
{"let [name1, name2 = 6] = z;", "let [name1, name2 = 6] = z;"},
Expand Down Expand Up @@ -110,6 +110,8 @@ func TestJS(t *testing.T) {
{"export default await x;", "export default await x;"},
{"export let a = await x;", "export let a = await x;"},
{"if(k00)while((0))", "if (k00) while ((0));"},
{"export{};from", "export {}; from;"},
{"import{} from 'a'", "import {} from 'a';"},
}

re := regexp.MustCompile("\n *")
Expand Down
15 changes: 10 additions & 5 deletions js/parse.go
Original file line number Diff line number Diff line change
Expand Up @@ -620,14 +620,16 @@ func (p *Parser) parseImportStmt() (importStmt ImportStmt) {
importStmt.Module = p.data
p.next()
} else {
expectClause := true
if IsIdentifier(p.tt) || p.tt == YieldToken {
importStmt.Default = p.data
p.next()
if p.tt == CommaToken {
expectClause = p.tt == CommaToken
if expectClause {
p.next()
}
}
if p.tt == MulToken {
if expectClause && p.tt == MulToken {
star := p.data
p.next()
if !p.consume("import statement", AsToken) {
Expand All @@ -639,8 +641,9 @@ func (p *Parser) parseImportStmt() (importStmt ImportStmt) {
}
importStmt.List = []Alias{Alias{star, p.data}}
p.next()
} else if p.tt == OpenBraceToken {
} else if expectClause && p.tt == OpenBraceToken {
p.next()
importStmt.List = []Alias{}
for IsIdentifierName(p.tt) || p.tt == StringToken {
tt := p.tt
var name, binding []byte = nil, p.data
Expand Down Expand Up @@ -670,8 +673,10 @@ func (p *Parser) parseImportStmt() (importStmt ImportStmt) {
if !p.consume("import statement", CloseBraceToken) {
return
}
}
if importStmt.Default == nil && len(importStmt.List) == 0 {
} else if expectClause && importStmt.Default != nil {
p.fail("import statement", MulToken, OpenBraceToken)
return
} else if importStmt.Default == nil {
p.fail("import statement", StringToken, IdentifierToken, MulToken, OpenBraceToken)
return
}
Expand Down
1 change: 1 addition & 0 deletions js/parse_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -545,6 +545,7 @@ func TestParseError(t *testing.T) {
{"import {yield as", "expected Identifier instead of EOF in import statement"},
{"import {yield,", "expected } instead of EOF in import statement"},
{"import yield", "expected from instead of EOF in import statement"},
{"import yield,", "expected * or { instead of EOF in import statement"},
{"import yield from", "expected String instead of EOF in import statement"},
{"export", "expected *, {, var, let, const, function, async, class, or default instead of EOF in export statement"},
{"export *", "expected from instead of EOF in export statement"},
Expand Down

0 comments on commit 5078a15

Please sign in to comment.