diff --git a/crates/oxc_ast/src/ast_impl/ts.rs b/crates/oxc_ast/src/ast_impl/ts.rs index 17973c988..975e2e9a9 100644 --- a/crates/oxc_ast/src/ast_impl/ts.rs +++ b/crates/oxc_ast/src/ast_impl/ts.rs @@ -194,6 +194,13 @@ impl<'a> TSModuleBlock<'a> { } } +impl<'a> TSModuleReference<'a> { + /// Returns `true` if this is an [`TSModuleReference::ExternalModuleReference`]. + pub fn is_external(&self) -> bool { + matches!(self, Self::ExternalModuleReference(_)) + } +} + impl<'a> Decorator<'a> { /// Get the name of the decorator /// ```ts diff --git a/crates/oxc_semantic/src/checker/mod.rs b/crates/oxc_semantic/src/checker/mod.rs index eb36d98dd..35ed35fb2 100644 --- a/crates/oxc_semantic/src/checker/mod.rs +++ b/crates/oxc_semantic/src/checker/mod.rs @@ -99,6 +99,9 @@ pub fn check<'a>(node: &AstNode<'a>, ctx: &SemanticBuilder<'a>) { } AstKind::TSModuleDeclaration(decl) => ts::check_ts_module_declaration(decl, ctx), AstKind::TSEnumDeclaration(decl) => ts::check_ts_enum_declaration(decl, ctx), + AstKind::TSImportEqualsDeclaration(decl) => { + ts::check_ts_import_equals_declaration(decl, ctx); + } _ => {} } } diff --git a/crates/oxc_semantic/src/checker/typescript.rs b/crates/oxc_semantic/src/checker/typescript.rs index 263b043aa..689c40fd0 100644 --- a/crates/oxc_semantic/src/checker/typescript.rs +++ b/crates/oxc_semantic/src/checker/typescript.rs @@ -168,3 +168,19 @@ pub fn check_ts_enum_declaration<'a>(decl: &TSEnumDeclaration<'a>, ctx: &Semanti } }); } + +/// TS(1392) +fn import_alias_cannot_use_import_type(span: Span) -> OxcDiagnostic { + OxcDiagnostic::error("TS(1392): An import alias cannot use 'import type'").with_label(span) +} + +pub fn check_ts_import_equals_declaration<'a>( + decl: &TSImportEqualsDeclaration<'a>, + ctx: &SemanticBuilder<'a>, +) { + // `import type Foo = require('./foo')` is allowed + // `import { Foo } from './foo'; import type Bar = Foo.Bar` is not allowed + if decl.import_kind.is_type() && !decl.module_reference.is_external() { + ctx.error(import_alias_cannot_use_import_type(decl.span)); + } +} diff --git a/tasks/coverage/parser_babel.snap b/tasks/coverage/parser_babel.snap index bcc3d0ab8..985fa153d 100644 --- a/tasks/coverage/parser_babel.snap +++ b/tasks/coverage/parser_babel.snap @@ -3,7 +3,7 @@ commit: 12619ffe parser_babel Summary: AST Parsed : 2093/2101 (99.62%) Positive Passed: 2083/2101 (99.14%) -Negative Passed: 1371/1501 (91.34%) +Negative Passed: 1373/1501 (91.47%) Expect Syntax Error: "annex-b/disabled/1.1-html-comments-close/input.js" Expect Syntax Error: "annex-b/disabled/3.1-sloppy-labeled-functions/input.js" Expect Syntax Error: "annex-b/disabled/3.1-sloppy-labeled-functions-if-body/input.js" @@ -86,8 +86,6 @@ Expect Syntax Error: "typescript/expect-plugin/export-type-named/input.js" Expect Syntax Error: "typescript/export/equals-in-script/input.ts" Expect Syntax Error: "typescript/import/equals-in-script/input.ts" Expect Syntax Error: "typescript/import/equals-require-in-script/input.ts" -Expect Syntax Error: "typescript/import/export-import-type/input.ts" -Expect Syntax Error: "typescript/import/type-equals/input.ts" Expect Syntax Error: "typescript/interface/get-set-invalid-optional-parameter/input.ts" Expect Syntax Error: "typescript/interface/get-set-invalid-optional-parameter-babel-7/input.ts" Expect Syntax Error: "typescript/interface/get-set-invalid-parameters/input.ts" @@ -10270,6 +10268,26 @@ Expect to Parse: "typescript/types/const-type-parameters-babel-7/input.ts" · ── ╰──── + × TS(1392): An import alias cannot use 'import type' + ╭─[typescript/import/export-import-type/input.ts:1:8] + 1 │ export import type A = B.C; + · ──────────────────── + ╰──── + + × TS(1392): An import alias cannot use 'import type' + ╭─[typescript/import/type-equals/input.ts:1:1] + 1 │ import type A = B.C; + · ──────────────────── + 2 │ import type B = C; + ╰──── + + × TS(1392): An import alias cannot use 'import type' + ╭─[typescript/import/type-equals/input.ts:2:1] + 1 │ import type A = B.C; + 2 │ import type B = C; + · ────────────────── + ╰──── + × 'abstract' modifier cannot be used here. ╭─[typescript/interface/abstract/input.ts:1:1] 1 │ abstract interface Foo {