From f66059e91b2995b3b48def0a61546b1f7cb2d8a9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Barr=C3=A9?= Date: Mon, 4 Mar 2024 05:28:18 +0100 Subject: [PATCH] fix(ast)!: align TSImportType with ESTree (#2578) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Implements https://github.com/typescript-eslint/typescript-eslint/issues/2998 The copy of props feels wrong, but could not get it working otherwise with the box and borrow things 😅 Also I found that TSImportType was missing some entries for visitors and codegen. In the case of codegen I'm not really understand the need as all the types seems to be dismissed? --- crates/oxc_ast/src/ast/ts.rs | 11 +++++++++-- crates/oxc_ast/src/ast_builder.rs | 4 +--- crates/oxc_ast/src/visit.rs | 5 ++++- crates/oxc_ast/src/visit_mut.rs | 5 ++++- crates/oxc_codegen/src/gen_ts.rs | 24 ++++++++++++++++------ crates/oxc_parser/src/ts/types.rs | 33 ++++++++++++++++++------------- 6 files changed, 55 insertions(+), 27 deletions(-) diff --git a/crates/oxc_ast/src/ast/ts.rs b/crates/oxc_ast/src/ast/ts.rs index ab6e2076c..62bf67b86 100644 --- a/crates/oxc_ast/src/ast/ts.rs +++ b/crates/oxc_ast/src/ast/ts.rs @@ -761,17 +761,24 @@ pub struct TSInferType<'a> { pub struct TSTypeQuery<'a> { #[cfg_attr(feature = "serde", serde(flatten))] pub span: Span, - pub expr_name: TSTypeName<'a>, + pub expr_name: TSTypeQueryExprName<'a>, pub type_parameters: Option>>, } +#[derive(Debug, Hash)] +#[cfg_attr(feature = "serde", derive(Serialize), serde(untagged))] +#[cfg_attr(all(feature = "serde", feature = "wasm"), derive(tsify::Tsify))] +pub enum TSTypeQueryExprName<'a> { + TSTypeName(TSTypeName<'a>), + TSImportType(TSImportType<'a>), +} + #[derive(Debug, Hash)] #[cfg_attr(feature = "serde", derive(Serialize), serde(tag = "type", rename_all = "camelCase"))] #[cfg_attr(all(feature = "serde", feature = "wasm"), derive(tsify::Tsify))] pub struct TSImportType<'a> { #[cfg_attr(feature = "serde", serde(flatten))] pub span: Span, - pub is_type_of: bool, pub argument: TSType<'a>, pub qualifier: Option>, pub attributes: Option>, diff --git a/crates/oxc_ast/src/ast_builder.rs b/crates/oxc_ast/src/ast_builder.rs index 37814fa08..af7880a24 100644 --- a/crates/oxc_ast/src/ast_builder.rs +++ b/crates/oxc_ast/src/ast_builder.rs @@ -1642,7 +1642,7 @@ impl<'a> AstBuilder<'a> { pub fn ts_type_query_type( &self, span: Span, - expr_name: TSTypeName<'a>, + expr_name: TSTypeQueryExprName<'a>, type_parameters: Option>>, ) -> TSType<'a> { TSType::TSTypeQuery(self.alloc(TSTypeQuery { span, expr_name, type_parameters })) @@ -1687,7 +1687,6 @@ impl<'a> AstBuilder<'a> { pub fn ts_import_type( &self, span: Span, - is_type_of: bool, argument: TSType<'a>, qualifier: Option>, attributes: Option>, @@ -1695,7 +1694,6 @@ impl<'a> AstBuilder<'a> { ) -> TSType<'a> { TSType::TSImportType(self.alloc(TSImportType { span, - is_type_of, argument, qualifier, attributes, diff --git a/crates/oxc_ast/src/visit.rs b/crates/oxc_ast/src/visit.rs index ccfae6845..d7d5367c5 100644 --- a/crates/oxc_ast/src/visit.rs +++ b/crates/oxc_ast/src/visit.rs @@ -1870,7 +1870,10 @@ pub trait Visit<'a>: Sized { fn visit_ts_type_query(&mut self, ty: &TSTypeQuery<'a>) { let kind = AstKind::TSTypeQuery(self.alloc(ty)); self.enter_node(kind); - self.visit_ts_type_name(&ty.expr_name); + match &ty.expr_name { + TSTypeQueryExprName::TSTypeName(name) => self.visit_ts_type_name(name), + TSTypeQueryExprName::TSImportType(_import) => {} // TODO + } if let Some(type_parameters) = &ty.type_parameters { self.visit_ts_type_parameter_instantiation(type_parameters); } diff --git a/crates/oxc_ast/src/visit_mut.rs b/crates/oxc_ast/src/visit_mut.rs index c1abda805..39ef4cded 100644 --- a/crates/oxc_ast/src/visit_mut.rs +++ b/crates/oxc_ast/src/visit_mut.rs @@ -1872,7 +1872,10 @@ pub trait VisitMut<'a>: Sized { fn visit_ts_type_query(&mut self, ty: &mut TSTypeQuery<'a>) { let kind = AstKind::TSTypeQuery(self.alloc(ty)); self.enter_node(kind); - self.visit_ts_type_name(&mut ty.expr_name); + match &mut ty.expr_name { + TSTypeQueryExprName::TSTypeName(name) => self.visit_ts_type_name(name), + TSTypeQueryExprName::TSImportType(_import) => {} // TODO + } if let Some(type_parameters) = &mut ty.type_parameters { self.visit_ts_type_parameter_instantiation(type_parameters); } diff --git a/crates/oxc_codegen/src/gen_ts.rs b/crates/oxc_codegen/src/gen_ts.rs index 314a6073d..8f73dda8a 100644 --- a/crates/oxc_codegen/src/gen_ts.rs +++ b/crates/oxc_codegen/src/gen_ts.rs @@ -143,12 +143,7 @@ impl<'a, const MINIFY: bool> Gen for TSType<'a> { decl.literal.gen(p, ctx); } Self::TSImportType(decl) => { - if decl.is_type_of { - p.print_str(b"typeof "); - } - p.print_str(b"import("); - decl.argument.gen(p, ctx); - p.print_str(b")"); + decl.gen(p, ctx); } Self::TSQualifiedName(decl) => { decl.left.gen(p, ctx); @@ -450,6 +445,23 @@ impl<'a, const MINIFY: bool> Gen for TSTypeQuery<'a> { } } +impl<'a, const MINIFY: bool> Gen for TSTypeQueryExprName<'a> { + fn gen(&self, p: &mut Codegen<{ MINIFY }>, ctx: Context) { + match self { + Self::TSTypeName(decl) => decl.gen(p, ctx), + Self::TSImportType(decl) => decl.gen(p, ctx), + } + } +} + +impl<'a, const MINIFY: bool> Gen for TSImportType<'a> { + fn gen(&self, p: &mut Codegen<{ MINIFY }>, ctx: Context) { + p.print_str(b"import("); + self.argument.gen(p, ctx); + p.print_str(b")"); + } +} + impl<'a, const MINIFY: bool> Gen for TSTypeParameterInstantiation<'a> { fn gen(&self, p: &mut Codegen<{ MINIFY }>, ctx: Context) { p.print_str(b"<"); diff --git a/crates/oxc_parser/src/ts/types.rs b/crates/oxc_parser/src/ts/types.rs index 8f68b6852..83b263f07 100644 --- a/crates/oxc_parser/src/ts/types.rs +++ b/crates/oxc_parser/src/ts/types.rs @@ -392,14 +392,17 @@ impl<'a> ParserImpl<'a> { Kind::NoSubstitutionTemplate | Kind::TemplateHead => { self.parse_ts_template_literal_type(false) } - Kind::Typeof => { - if self.peek_at(Kind::Import) { - self.parse_ts_import_type() - } else { - self.parse_ts_typeof_type() - } + Kind::Typeof => self.parse_ts_typeof_type(), + Kind::Import => { + let node = self.parse_ts_import_type()?; + Ok(self.ast.ts_import_type( + node.span, + node.argument, + node.qualifier, + node.attributes, + node.type_parameters, + )) } - Kind::Import => self.parse_ts_import_type(), Kind::Minus if self.peek_kind().is_number() => self.parse_ts_literal_type(), Kind::Question => self.parse_js_doc_unknown_or_nullable_type(), // null should not be parsed as a literal type @@ -759,14 +762,17 @@ impl<'a> ParserImpl<'a> { fn parse_ts_typeof_type(&mut self) -> Result> { let span = self.start_span(); self.expect(Kind::Typeof)?; - let expr_name = self.parse_ts_type_name()?; + let expr_name: TSTypeQueryExprName = if self.at(Kind::Import) { + TSTypeQueryExprName::TSImportType(self.parse_ts_import_type()?) + } else { + TSTypeQueryExprName::TSTypeName(self.parse_ts_type_name()?) + }; let type_parameters = self.parse_ts_type_arguments()?; Ok(self.ast.ts_type_query_type(self.end_span(span), expr_name, type_parameters)) } - fn parse_ts_import_type(&mut self) -> Result> { + fn parse_ts_import_type(&mut self) -> Result> { let span = self.start_span(); - let is_type_of = self.eat(Kind::Typeof); self.expect(Kind::Import)?; self.expect(Kind::LParen)?; let argument = self.parse_ts_type()?; @@ -778,14 +784,13 @@ impl<'a> ParserImpl<'a> { let type_parameters = self.parse_ts_type_arguments()?; - Ok(self.ast.ts_import_type( - self.end_span(span), - is_type_of, + Ok(TSImportType { + span: self.end_span(span), argument, qualifier, attributes, type_parameters, - )) + }) } fn parse_ts_import_attributes(&mut self) -> Result> {