diff --git a/crates/swc_ecma_parser/src/parser/stmt/module_item.rs b/crates/swc_ecma_parser/src/parser/stmt/module_item.rs index 9c500448ed7e..173d9ed095a0 100644 --- a/crates/swc_ecma_parser/src/parser/stmt/module_item.rs +++ b/crates/swc_ecma_parser/src/parser/stmt/module_item.rs @@ -42,15 +42,6 @@ impl Parser { expect!(self, "import"); - if self.input.syntax().typescript() && is!(self, IdentRef) && peeked_is!(self, '=') { - return self - .parse_ts_import_equals_decl( - start, /* is_export */ false, /* is_type_only */ false, - ) - .map(ModuleDecl::from) - .map(ModuleItem::from); - } - // Handle import 'mod.js' let str_start = cur_pos!(self); if let Ok(&Token::Str { .. }) = cur!(self, false) { @@ -84,35 +75,46 @@ impl Parser { }))); } - let type_only = self.input.syntax().typescript() - && is!(self, "type") - && (peeked_is!(self, '{') || !peeked_is!(self, "from") && !peeked_is!(self, ',')); + let mut type_only = false; + let mut specifiers = vec![]; - if type_only { - assert_and_bump!(self, "type"); + 'import_maybe_ident: { + if is!(self, BindingIdent) { + let mut local = self.parse_imported_default_binding()?; - if is!(self, IdentRef) && peeked_is!(self, '=') { - return self - .parse_ts_import_equals_decl( - start, /* is_export */ false, /* is_type_only */ true, - ) - .map(ModuleDecl::from) - .map(ModuleItem::from); - } - } + if self.input.syntax().typescript() && local.sym == "type" { + if is_one_of!(self, '*', '{') { + type_only = true; + break 'import_maybe_ident; + } - let mut specifiers = vec![]; + if is!(self, BindingIdent) { + if !is!(self, "from") || peeked_is!(self, "from") { + type_only = true; + local = self.parse_imported_default_binding()?; + } else if peeked_is!(self, '=') { + type_only = true; + local = self.parse_ident_name()?; + } + } + } - if is!(self, BindingIdent) { - let local = self.parse_imported_default_binding()?; - //TODO: Better error reporting - if !is!(self, "from") { - expect!(self, ','); + if self.input.syntax().typescript() && is!(self, '=') { + return self + .parse_ts_import_equals_decl(start, local, false, type_only) + .map(ModuleDecl::from) + .map(ModuleItem::from); + } + + //TODO: Better error reporting + if !is!(self, "from") { + expect!(self, ','); + } + specifiers.push(ImportSpecifier::Default(ImportDefaultSpecifier { + span: local.span, + local, + })); } - specifiers.push(ImportSpecifier::Default(ImportDefaultSpecifier { - span: local.span, - local, - })); } { @@ -373,9 +375,11 @@ impl Parser { assert_and_bump!(self, "type"); } + let id = self.parse_ident_name()?; + // export import A = B return self - .parse_ts_import_equals_decl(start, /* is_export */ true, is_type_only) + .parse_ts_import_equals_decl(start, id, /* is_export */ true, is_type_only) .map(From::from); } diff --git a/crates/swc_ecma_parser/src/parser/typescript.rs b/crates/swc_ecma_parser/src/parser/typescript.rs index 1c8e8337dae2..808de93c56e2 100644 --- a/crates/swc_ecma_parser/src/parser/typescript.rs +++ b/crates/swc_ecma_parser/src/parser/typescript.rs @@ -1133,12 +1133,12 @@ impl Parser { pub(super) fn parse_ts_import_equals_decl( &mut self, start: BytePos, + id: Ident, is_export: bool, is_type_only: bool, ) -> PResult> { debug_assert!(self.input.syntax().typescript()); - let id = self.parse_ident_name()?; expect!(self, '='); let module_ref = self.parse_ts_module_ref()?; diff --git a/crates/swc_ecma_parser/tests/typescript/issue-8308/1/input.ts b/crates/swc_ecma_parser/tests/typescript/issue-8308/1/input.ts new file mode 100644 index 000000000000..0aad6c7868d6 --- /dev/null +++ b/crates/swc_ecma_parser/tests/typescript/issue-8308/1/input.ts @@ -0,0 +1 @@ +import type from from "foo"; \ No newline at end of file diff --git a/crates/swc_ecma_parser/tests/typescript/issue-8308/1/input.ts.json b/crates/swc_ecma_parser/tests/typescript/issue-8308/1/input.ts.json new file mode 100644 index 000000000000..d2a2f0667091 --- /dev/null +++ b/crates/swc_ecma_parser/tests/typescript/issue-8308/1/input.ts.json @@ -0,0 +1,51 @@ +{ + "type": "Module", + "span": { + "start": 1, + "end": 29, + "ctxt": 0 + }, + "body": [ + { + "type": "ImportDeclaration", + "span": { + "start": 1, + "end": 29, + "ctxt": 0 + }, + "specifiers": [ + { + "type": "ImportDefaultSpecifier", + "span": { + "start": 13, + "end": 17, + "ctxt": 0 + }, + "local": { + "type": "Identifier", + "span": { + "start": 13, + "end": 17, + "ctxt": 0 + }, + "value": "from", + "optional": false + } + } + ], + "source": { + "type": "StringLiteral", + "span": { + "start": 23, + "end": 28, + "ctxt": 0 + }, + "value": "foo", + "raw": "\"foo\"" + }, + "typeOnly": true, + "with": null + } + ], + "interpreter": null +} diff --git a/crates/swc_ecma_parser/tests/typescript/issue-8308/2/input.ts b/crates/swc_ecma_parser/tests/typescript/issue-8308/2/input.ts new file mode 100644 index 000000000000..5f245467b9c7 --- /dev/null +++ b/crates/swc_ecma_parser/tests/typescript/issue-8308/2/input.ts @@ -0,0 +1 @@ +import type from = require("foo"); \ No newline at end of file diff --git a/crates/swc_ecma_parser/tests/typescript/issue-8308/2/input.ts.json b/crates/swc_ecma_parser/tests/typescript/issue-8308/2/input.ts.json new file mode 100644 index 000000000000..a7902a2372e4 --- /dev/null +++ b/crates/swc_ecma_parser/tests/typescript/issue-8308/2/input.ts.json @@ -0,0 +1,49 @@ +{ + "type": "Module", + "span": { + "start": 1, + "end": 35, + "ctxt": 0 + }, + "body": [ + { + "type": "TsImportEqualsDeclaration", + "span": { + "start": 1, + "end": 35, + "ctxt": 0 + }, + "isExport": false, + "isTypeOnly": true, + "id": { + "type": "Identifier", + "span": { + "start": 13, + "end": 17, + "ctxt": 0 + }, + "value": "from", + "optional": false + }, + "moduleRef": { + "type": "TsExternalModuleReference", + "span": { + "start": 20, + "end": 34, + "ctxt": 0 + }, + "expression": { + "type": "StringLiteral", + "span": { + "start": 28, + "end": 33, + "ctxt": 0 + }, + "value": "foo", + "raw": "\"foo\"" + } + } + } + ], + "interpreter": null +} diff --git a/crates/swc_ecma_parser/tests/typescript/issue-8308/3/input.ts b/crates/swc_ecma_parser/tests/typescript/issue-8308/3/input.ts new file mode 100644 index 000000000000..ccfd648b429a --- /dev/null +++ b/crates/swc_ecma_parser/tests/typescript/issue-8308/3/input.ts @@ -0,0 +1 @@ +import type async = require("foo"); \ No newline at end of file diff --git a/crates/swc_ecma_parser/tests/typescript/issue-8308/3/input.ts.json b/crates/swc_ecma_parser/tests/typescript/issue-8308/3/input.ts.json new file mode 100644 index 000000000000..34307549c40c --- /dev/null +++ b/crates/swc_ecma_parser/tests/typescript/issue-8308/3/input.ts.json @@ -0,0 +1,49 @@ +{ + "type": "Module", + "span": { + "start": 1, + "end": 36, + "ctxt": 0 + }, + "body": [ + { + "type": "TsImportEqualsDeclaration", + "span": { + "start": 1, + "end": 36, + "ctxt": 0 + }, + "isExport": false, + "isTypeOnly": true, + "id": { + "type": "Identifier", + "span": { + "start": 13, + "end": 18, + "ctxt": 0 + }, + "value": "async", + "optional": false + }, + "moduleRef": { + "type": "TsExternalModuleReference", + "span": { + "start": 21, + "end": 35, + "ctxt": 0 + }, + "expression": { + "type": "StringLiteral", + "span": { + "start": 29, + "end": 34, + "ctxt": 0 + }, + "value": "foo", + "raw": "\"foo\"" + } + } + } + ], + "interpreter": null +}