Skip to content

Commit 0508f24

Browse files
committed
some parsing fixes for source phase imports
1 parent 6e4be2f commit 0508f24

File tree

4 files changed

+52
-2
lines changed

4 files changed

+52
-2
lines changed

CHANGELOG.md

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,18 @@
1515
}
1616
```
1717

18+
* Fix a regression with the parsing of source phase imports
19+
20+
The change in the previous release to parse [source phase imports](https://github.com/tc39/proposal-source-phase-imports) failed to properly handle the following cases:
21+
22+
```ts
23+
import source from 'bar'
24+
import source from from 'bar'
25+
import source type foo from 'bar'
26+
```
27+
28+
Parsing for these cases should now be fixed. The first case was incorrectly treated as a syntax error because esbuild was expecting the second case. And the last case was previously allowed but is now forbidden. TypeScript hasn't added this feature yet so it remains to be seen whether the last case will be allowed, but it's safer to disallow it for now. At least Babel doesn't allow the last case when parsing TypeScript, and Babel was involved with the source phase import specification.
29+
1830
## 0.25.7
1931

2032
* Parse and print JavaScript imports with an explicit phase ([#4238](https://github.com/evanw/esbuild/issues/4238))

internal/js_parser/js_parser.go

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7935,12 +7935,30 @@ func (p *parser) parseStmt(opts parseStmtOpts) js_ast.Stmt {
79357935
}
79367936

79377937
if isSourceName && p.lexer.Token == js_lexer.TIdentifier {
7938+
if p.lexer.Raw() == "from" {
7939+
nameSubstring := p.lexer.Identifier
7940+
nameLoc := p.lexer.Loc()
7941+
p.lexer.Next()
7942+
if p.lexer.IsContextualKeyword("from") {
7943+
// "import source from from 'foo';"
7944+
p.markSyntaxFeature(compat.ImportSource, js_lexer.RangeOfIdentifier(p.source, defaultLoc))
7945+
phase = ast.SourcePhase
7946+
stmt.DefaultName = &ast.LocRef{Loc: nameLoc, Ref: p.storeNameInRef(nameSubstring)}
7947+
p.lexer.Next()
7948+
} else {
7949+
// "import source from 'foo';"
7950+
stmt.DefaultName = &ast.LocRef{Loc: defaultLoc, Ref: p.storeNameInRef(defaultName)}
7951+
}
7952+
break
7953+
}
7954+
79387955
// "import source foo from 'bar';"
79397956
p.markSyntaxFeature(compat.ImportSource, js_lexer.RangeOfIdentifier(p.source, defaultLoc))
79407957
phase = ast.SourcePhase
7941-
defaultName = p.lexer.Identifier
7942-
defaultLoc = p.lexer.Loc()
7958+
stmt.DefaultName = &ast.LocRef{Loc: p.lexer.Loc(), Ref: p.storeNameInRef(p.lexer.Identifier)}
79437959
p.lexer.Next()
7960+
p.lexer.ExpectContextualKeyword("from")
7961+
break
79447962
}
79457963

79467964
stmt.DefaultName = &ast.LocRef{Loc: defaultLoc, Ref: p.storeNameInRef(defaultName)}

internal/js_parser/js_parser_test.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3115,6 +3115,7 @@ func TestImport(t *testing.T) {
31153115
expectParseError(t, "import * as '' from 'foo'", "<stdin>: ERROR: Expected identifier but found \"''\"\n")
31163116

31173117
// See: https://github.com/tc39/proposal-defer-import-eval
3118+
expectPrinted(t, "import defer from 'bar'", "import defer from \"bar\";\n")
31183119
expectPrinted(t, "import defer, { foo } from 'bar'", "import defer, { foo } from \"bar\";\n")
31193120
expectPrinted(t, "import defer * as foo from 'bar'", "import defer * as foo from \"bar\";\n")
31203121
expectPrinted(t, "import.defer('foo')", "import.defer(\"foo\");\n")
@@ -3125,8 +3126,11 @@ func TestImport(t *testing.T) {
31253126
expectParseErrorTarget(t, 6, "import.defer('foo')", "<stdin>: ERROR: Deferred imports are not available in the configured target environment\n")
31263127

31273128
// See: https://github.com/tc39/proposal-source-phase-imports
3129+
expectPrinted(t, "import source from 'bar'", "import source from \"bar\";\n")
31283130
expectPrinted(t, "import source, { foo } from 'bar'", "import source, { foo } from \"bar\";\n")
31293131
expectPrinted(t, "import source foo from 'bar'", "import source foo from \"bar\";\n")
3132+
expectPrinted(t, "import source from from 'bar'", "import source from from \"bar\";\n")
3133+
expectPrinted(t, "import source source from 'bar'", "import source source from \"bar\";\n")
31303134
expectPrinted(t, "import.source('foo')", "import.source(\"foo\");\n")
31313135
expectParseError(t, "import source 'bar'", "<stdin>: ERROR: Expected \"from\" but found \"'bar'\"\n")
31323136
expectParseError(t, "import source * as foo from 'bar'", "<stdin>: ERROR: Expected \"from\" but found \"*\"\n")

internal/js_parser/ts_parser_test.go

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2966,6 +2966,22 @@ func TestTSTypeOnlyImport(t *testing.T) {
29662966
expectParseErrorTS(t, "import { x, type 'y' as 'z' } from 'mod'", "<stdin>: ERROR: Expected identifier but found \"'z'\"\n")
29672967
expectParseErrorTS(t, "import { x, type as 'y' } from 'mod'", "<stdin>: ERROR: Expected \"}\" but found \"'y'\"\n")
29682968
expectParseErrorTS(t, "import { x, type y as 'z' } from 'mod'", "<stdin>: ERROR: Expected identifier but found \"'z'\"\n")
2969+
2970+
// See: https://github.com/tc39/proposal-defer-import-eval
2971+
expectPrintedTS(t, "import defer * as foo from 'bar'", "")
2972+
expectPrintedTS(t, "import defer * as foo from 'bar'; let x: foo.Type", "let x;\n")
2973+
expectPrintedTS(t, "import defer * as foo from 'bar'; let x = foo.value", "import defer * as foo from \"bar\";\nlet x = foo.value;\n")
2974+
expectPrintedTS(t, "import type defer from 'bar'", "")
2975+
expectParseErrorTS(t, "import type defer * as foo from 'bar'", "<stdin>: ERROR: Expected \"from\" but found \"*\"\n")
2976+
2977+
// See: https://github.com/tc39/proposal-source-phase-imports
2978+
expectPrintedTS(t, "import type source from 'bar'", "")
2979+
expectPrintedTS(t, "import source foo from 'bar'", "")
2980+
expectPrintedTS(t, "import source foo from 'bar'; let x: foo", "let x;\n")
2981+
expectPrintedTS(t, "import source foo from 'bar'; let x = foo", "import source foo from \"bar\";\nlet x = foo;\n")
2982+
expectPrintedTS(t, "import source type from 'bar'", "")
2983+
expectParseErrorTS(t, "import source type foo from 'bar'", "<stdin>: ERROR: Expected \"from\" but found \"foo\"\n")
2984+
expectParseErrorTS(t, "import type source foo from 'bar'", "<stdin>: ERROR: Expected \"from\" but found \"foo\"\n")
29692985
}
29702986

29712987
func TestTSTypeOnlyExport(t *testing.T) {

0 commit comments

Comments
 (0)