Skip to content

Commit

Permalink
fix #3490, close #3491: import type from from ""
Browse files Browse the repository at this point in the history
  • Loading branch information
evanw committed Nov 18, 2023
1 parent 7cb6e95 commit 08b4607
Show file tree
Hide file tree
Showing 3 changed files with 34 additions and 16 deletions.
12 changes: 12 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,18 @@
document.onkeydown=o=>o.keyCode===65&&console.log("🧀");
```

* Parse an upcoming change to TypeScript type syntax ([#3490](https://github.com/evanw/esbuild/issues/3490), [#3491](https://github.com/evanw/esbuild/pull/3491))

With this release, you can now use `from` as the name of a default type-only import in TypeScript code:

```ts
import type from from 'from'
```

This matches a similar [change in the TypeScript compiler](https://github.com/microsoft/TypeScript/issues/56376) which will start allowing this syntax in an upcoming version of TypeScript.

This change was contributed by [@magic-akari](https://github.com/magic-akari).

## 0.19.5

* Fix a regression in 0.19.0 regarding `paths` in `tsconfig.json` ([#3354](https://github.com/evanw/esbuild/issues/3354))
Expand Down
34 changes: 18 additions & 16 deletions internal/js_parser/js_parser.go
Original file line number Diff line number Diff line change
Expand Up @@ -7491,6 +7491,7 @@ func (p *parser) parseStmt(opts parseStmtOpts) js_ast.Stmt {
p.lexer.Expected(js_lexer.TIdentifier)
}

syntaxBeforePath:
switch p.lexer.Token {
case js_lexer.TOpenParen, js_lexer.TDot:
// "import('path')"
Expand Down Expand Up @@ -7553,22 +7554,23 @@ func (p *parser) parseStmt(opts parseStmtOpts) js_ast.Stmt {
if defaultName.String == "type" {
switch p.lexer.Token {
case js_lexer.TIdentifier:
if p.lexer.Identifier.String != "from" {
defaultName = p.lexer.Identifier
stmt.DefaultName.Loc = p.lexer.Loc()
p.lexer.Next()
if p.lexer.Token == js_lexer.TEquals {
// "import type foo = require('bar');"
// "import type foo = bar.baz;"
opts.isTypeScriptDeclare = true
return p.parseTypeScriptImportEqualsStmt(loc, opts, stmt.DefaultName.Loc, defaultName.String)
} else {
// "import type foo from 'bar';"
p.lexer.ExpectContextualKeyword("from")
p.parsePath()
p.lexer.ExpectOrInsertSemicolon()
return js_ast.Stmt{Loc: loc, Data: js_ast.STypeScriptShared}
}
nameSubstring := p.lexer.Identifier
nameLoc := p.lexer.Loc()
p.lexer.Next()
if p.lexer.Token == js_lexer.TEquals {
// "import type foo = require('bar');"
// "import type foo = bar.baz;"
opts.isTypeScriptDeclare = true
return p.parseTypeScriptImportEqualsStmt(loc, opts, nameLoc, nameSubstring.String)
} else if p.lexer.Token == js_lexer.TStringLiteral && nameSubstring.String == "from" {
// "import type from 'bar';"
break syntaxBeforePath
} else {
// "import type foo from 'bar';"
p.lexer.ExpectContextualKeyword("from")
p.parsePath()
p.lexer.ExpectOrInsertSemicolon()
return js_ast.Stmt{Loc: loc, Data: js_ast.STypeScriptShared}
}

case js_lexer.TAsterisk:
Expand Down
4 changes: 4 additions & 0 deletions internal/js_parser/ts_parser_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2540,12 +2540,14 @@ func TestTSImportEqualsInNamespace(t *testing.T) {
func TestTSTypeOnlyImport(t *testing.T) {
expectPrintedTS(t, "import type foo from 'bar'; x", "x;\n")
expectPrintedTS(t, "import type foo from 'bar'\nx", "x;\n")
expectPrintedTS(t, "import type from from 'bar'; x", "x;\n")
expectPrintedTS(t, "import type * as foo from 'bar'; x", "x;\n")
expectPrintedTS(t, "import type * as foo from 'bar'\nx", "x;\n")
expectPrintedTS(t, "import type {foo, bar as baz} from 'bar'; x", "x;\n")
expectPrintedTS(t, "import type {'foo' as bar} from 'bar'\nx", "x;\n")
expectPrintedTS(t, "import type foo = require('bar'); x", "x;\n")
expectPrintedTS(t, "import type foo = bar.baz; x", "x;\n")
expectPrintedTS(t, "import type from = require('bar'); x", "x;\n")

expectPrintedTS(t, "import type = bar; type", "const type = bar;\ntype;\n")
expectPrintedTS(t, "import type = foo.bar; type", "const type = foo.bar;\ntype;\n")
Expand Down Expand Up @@ -2578,6 +2580,8 @@ func TestTSTypeOnlyImport(t *testing.T) {

expectParseErrorTS(t, "import type foo, * as foo from 'bar'", "<stdin>: ERROR: Expected \"from\" but found \",\"\n")
expectParseErrorTS(t, "import type foo, {foo} from 'bar'", "<stdin>: ERROR: Expected \"from\" but found \",\"\n")
expectParseErrorTS(t, "import type from, * as foo from 'bar'", "<stdin>: ERROR: Expected \"from\" but found \",\"\n")
expectParseErrorTS(t, "import type from, {foo} from 'bar'", "<stdin>: ERROR: Expected \"from\" but found \",\"\n")
expectParseErrorTS(t, "import type * as foo = require('bar')", "<stdin>: ERROR: Expected \"from\" but found \"=\"\n")
expectParseErrorTS(t, "import type {foo} = require('bar')", "<stdin>: ERROR: Expected \"from\" but found \"=\"\n")

Expand Down

0 comments on commit 08b4607

Please sign in to comment.