diff --git a/crates/oxc_ast/src/ast_impl/ts.rs b/crates/oxc_ast/src/ast_impl/ts.rs index 86afae710b411..aaf4820e42e08 100644 --- a/crates/oxc_ast/src/ast_impl/ts.rs +++ b/crates/oxc_ast/src/ast_impl/ts.rs @@ -159,6 +159,16 @@ impl<'a> TSModuleDeclaration<'a> { } } +impl TSModuleDeclarationKind { + pub fn as_str(&self) -> &str { + match self { + Self::Global => "global", + Self::Module => "module", + Self::Namespace => "namespace", + } + } +} + impl<'a> TSModuleDeclarationName<'a> { pub fn is_string_literal(&self) -> bool { matches!(self, Self::StringLiteral(_)) diff --git a/crates/oxc_codegen/src/binary_expr_visitor.rs b/crates/oxc_codegen/src/binary_expr_visitor.rs index 8f48c8ed6f152..87fa282059e9d 100644 --- a/crates/oxc_codegen/src/binary_expr_visitor.rs +++ b/crates/oxc_codegen/src/binary_expr_visitor.rs @@ -9,10 +9,7 @@ use oxc_syntax::{ precedence::{GetPrecedence, Precedence}, }; -use crate::{ - gen::{Gen, GenExpr}, - Codegen, Context, -}; +use crate::{gen::GenExpr, Codegen, Context, Operator}; #[derive(Clone, Copy)] pub enum Binaryish<'a> { @@ -49,11 +46,25 @@ pub enum BinaryishOperator { Logical(LogicalOperator), } -impl Gen for BinaryishOperator { - fn gen(&self, p: &mut Codegen, ctx: Context) { +fn print_binary_operator(op: BinaryOperator, p: &mut Codegen) { + let operator = op.as_str(); + if op.is_keyword() { + p.print_space_before_identifier(); + p.print_str(operator); + } else { + let op: Operator = op.into(); + p.print_space_before_operator(op); + p.print_str(operator); + p.prev_op = Some(op); + p.prev_op_end = p.code().len(); + } +} + +impl BinaryishOperator { + fn gen(self, p: &mut Codegen) { match self { - Self::Binary(op) => op.gen(p, ctx), - Self::Logical(op) => op.gen(p, ctx), + Self::Binary(op) => print_binary_operator(op, p), + Self::Logical(op) => p.print_str(op.as_str()), } } } @@ -185,7 +196,7 @@ impl<'a> BinaryExpressionVisitor<'a> { pub fn visit_right_and_finish(&self, p: &mut Codegen) { p.print_soft_space(); - self.operator.gen(p, Context::empty()); + self.operator.gen(p); p.print_soft_space(); self.e.right().gen_expr(p, self.right_precedence, self.ctx & Context::FORBID_IN); if self.wrap { diff --git a/crates/oxc_codegen/src/gen.rs b/crates/oxc_codegen/src/gen.rs index 4a6ada2ab1765..453ec8f91b15b 100644 --- a/crates/oxc_codegen/src/gen.rs +++ b/crates/oxc_codegen/src/gen.rs @@ -1,14 +1,13 @@ use std::{borrow::Cow, ops::Not}; use cow_utils::CowUtils; -use oxc_allocator::{Box, Vec}; #[allow(clippy::wildcard_imports)] use oxc_ast::ast::*; use oxc_span::GetSpan; use oxc_syntax::{ identifier::{LS, PS}, keyword::is_reserved_keyword_or_global_object, - operator::{BinaryOperator, LogicalOperator, UnaryOperator}, + operator::UnaryOperator, precedence::{GetPrecedence, Precedence}, }; @@ -18,32 +17,12 @@ use crate::{ Codegen, Context, Operator, }; -pub trait Gen { - #[allow(unused_variables)] - fn gen(&self, p: &mut Codegen, ctx: Context) {} +pub trait Gen: GetSpan { + fn gen(&self, p: &mut Codegen, ctx: Context); } -pub trait GenExpr { - #[allow(unused_variables)] - fn gen_expr(&self, p: &mut Codegen, precedence: Precedence, ctx: Context) {} -} - -impl<'a, T> Gen for Box<'a, T> -where - T: Gen, -{ - fn gen(&self, p: &mut Codegen, ctx: Context) { - (**self).gen(p, ctx); - } -} - -impl<'a, T> GenExpr for Box<'a, T> -where - T: GenExpr, -{ - fn gen_expr(&self, p: &mut Codegen, precedence: Precedence, ctx: Context) { - (**self).gen_expr(p, precedence, ctx); - } +pub trait GenExpr: GetSpan { + fn gen_expr(&self, p: &mut Codegen, precedence: Precedence, ctx: Context); } impl<'a> Gen for Program<'a> { @@ -679,9 +658,13 @@ impl<'a> Gen for FunctionBody<'a> { impl<'a> Gen for FormalParameter<'a> { fn gen(&self, p: &mut Codegen, ctx: Context) { - self.decorators.gen(p, ctx); + for decorator in &self.decorators { + decorator.gen(p, ctx); + p.print_hard_space(); + } if let Some(accessibility) = self.accessibility { - accessibility.gen(p, ctx); + p.print_str(accessibility.as_str()); + p.print_hard_space(); } if self.readonly { p.print_str("readonly "); @@ -1716,28 +1699,6 @@ impl<'a> GenExpr for BinaryExpression<'a> { } } -impl Gen for LogicalOperator { - fn gen(&self, p: &mut Codegen, _ctx: Context) { - p.print_str(self.as_str()); - } -} - -impl Gen for BinaryOperator { - fn gen(&self, p: &mut Codegen, _ctx: Context) { - let operator = self.as_str(); - if self.is_keyword() { - p.print_space_before_identifier(); - p.print_str(operator); - } else { - let op: Operator = (*self).into(); - p.print_space_before_operator(op); - p.print_str(operator); - p.prev_op = Some(op); - p.prev_op_end = p.code().len(); - } - } -} - impl<'a> GenExpr for PrivateInExpression<'a> { fn gen_expr(&self, p: &mut Codegen, precedence: Precedence, ctx: Context) { p.wrap(precedence >= Precedence::Compare, |p| { @@ -1868,7 +1829,15 @@ impl<'a> Gen for ArrayAssignmentTarget<'a> { fn gen(&self, p: &mut Codegen, ctx: Context) { p.add_source_mapping(self.span.start); p.print_char(b'['); - p.print_list(&self.elements, ctx); + for (index, item) in self.elements.iter().enumerate() { + if index != 0 { + p.print_comma(); + p.print_soft_space(); + } + if let Some(item) = item { + item.gen(p, ctx); + } + } if let Some(target) = &self.rest { if !self.elements.is_empty() { p.print_comma(); @@ -1884,14 +1853,6 @@ impl<'a> Gen for ArrayAssignmentTarget<'a> { } } -impl<'a> Gen for Option> { - fn gen(&self, p: &mut Codegen, ctx: Context) { - if let Some(arg) = self { - arg.gen(p, ctx); - } - } -} - impl<'a> Gen for ObjectAssignmentTarget<'a> { fn gen(&self, p: &mut Codegen, ctx: Context) { p.add_source_mapping(self.span.start); @@ -2166,7 +2127,10 @@ impl<'a> Gen for Class<'a> { let n = p.code_len(); let wrap = self.is_expression() && (p.start_of_stmt == n || p.start_of_default_export == n); p.wrap(wrap, |p| { - self.decorators.gen(p, ctx); + for decorator in &self.decorators { + decorator.gen(p, ctx); + p.print_hard_space(); + } if self.declare { p.print_str("declare "); } @@ -2469,10 +2433,14 @@ impl<'a> Gen for StaticBlock<'a> { impl<'a> Gen for MethodDefinition<'a> { fn gen(&self, p: &mut Codegen, ctx: Context) { p.add_source_mapping(self.span.start); - self.decorators.gen(p, ctx); + for decorator in &self.decorators { + decorator.gen(p, ctx); + p.print_hard_space(); + } if let Some(accessibility) = &self.accessibility { - accessibility.gen(p, ctx); + p.print_str(accessibility.as_str()); + p.print_hard_space(); } if self.r#type == MethodDefinitionType::TSAbstractMethodDefinition { p.print_str("abstract "); @@ -2532,12 +2500,16 @@ impl<'a> Gen for MethodDefinition<'a> { impl<'a> Gen for PropertyDefinition<'a> { fn gen(&self, p: &mut Codegen, ctx: Context) { p.add_source_mapping(self.span.start); - self.decorators.gen(p, ctx); + for decorator in &self.decorators { + decorator.gen(p, ctx); + p.print_hard_space(); + } if self.declare { p.print_str("declare "); } - if let Some(accessibility) = &self.accessibility { - accessibility.gen(p, ctx); + if let Some(accessibility) = self.accessibility { + p.print_str(accessibility.as_str()); + p.print_hard_space(); } if self.r#type == PropertyDefinitionType::TSAbstractPropertyDefinition { p.print_str("abstract "); @@ -2575,12 +2547,16 @@ impl<'a> Gen for PropertyDefinition<'a> { impl<'a> Gen for AccessorProperty<'a> { fn gen(&self, p: &mut Codegen, ctx: Context) { p.add_source_mapping(self.span.start); - self.decorators.gen(p, ctx); + for decorator in &self.decorators { + decorator.gen(p, ctx); + p.print_hard_space(); + } if self.r#type.is_abstract() { p.print_str("abstract "); } - if let Some(accessibility) = &self.accessibility { - accessibility.gen(p, ctx); + if let Some(accessibility) = self.accessibility { + p.print_str(accessibility.as_str()); + p.print_hard_space(); } if self.r#static { p.print_str("static "); @@ -2740,15 +2716,6 @@ impl<'a> Gen for AssignmentPattern<'a> { } } -impl<'a> Gen for Vec<'a, Decorator<'a>> { - fn gen(&self, p: &mut Codegen, ctx: Context) { - for decorator in self { - decorator.gen(p, ctx); - p.print_hard_space(); - } - } -} - impl<'a> Gen for Decorator<'a> { fn gen(&self, p: &mut Codegen, _ctx: Context) { fn need_wrap(expr: &Expression) -> bool { @@ -3427,7 +3394,7 @@ impl<'a> Gen for TSModuleDeclaration<'a> { if self.declare { p.print_str("declare "); } - self.kind.gen(p, ctx); + p.print_str(self.kind.as_str()); // If the kind is global, then the id is also `global`, so we don't need to print it if !self.kind.is_global() { p.print_space_before_identifier(); @@ -3459,22 +3426,6 @@ impl<'a> Gen for TSModuleDeclaration<'a> { } } -impl Gen for TSModuleDeclarationKind { - fn gen(&self, p: &mut Codegen, _: Context) { - match self { - TSModuleDeclarationKind::Global => { - p.print_str("global"); - } - TSModuleDeclarationKind::Module => { - p.print_str("module"); - } - TSModuleDeclarationKind::Namespace => { - p.print_str("namespace"); - } - } - } -} - impl<'a> Gen for TSModuleDeclarationName<'a> { fn gen(&self, p: &mut Codegen, ctx: Context) { match self { @@ -3639,13 +3590,3 @@ impl<'a> Gen for TSModuleReference<'a> { } } } - -impl Gen for TSAccessibility { - fn gen(&self, p: &mut Codegen, _ctx: Context) { - match self { - Self::Public => p.print_str("public "), - Self::Private => p.print_str("private "), - Self::Protected => p.print_str("protected "), - } - } -} diff --git a/crates/oxc_linter/src/rules/eslint/no_unsafe_negation.rs b/crates/oxc_linter/src/rules/eslint/no_unsafe_negation.rs index 401d5de78a687..d5fb528178eea 100644 --- a/crates/oxc_linter/src/rules/eslint/no_unsafe_negation.rs +++ b/crates/oxc_linter/src/rules/eslint/no_unsafe_negation.rs @@ -76,7 +76,6 @@ impl NoUnsafeNegation { /// Precondition: /// expr.left is `UnaryExpression` whose operator is '!' fn report_with_fix<'a>(expr: &BinaryExpression, ctx: &LintContext<'a>) { - use oxc_codegen::{Context, Gen}; // Diagnostic points at the unexpected negation let diagnostic = no_unsafe_negation_diagnostic(expr.operator.as_str(), expr.left.span()); @@ -88,7 +87,9 @@ impl NoUnsafeNegation { let Expression::UnaryExpression(left) = &expr.left else { unreachable!() }; codegen.print_char(b'('); codegen.print_expression(&left.argument); - expr.operator.gen(&mut codegen, Context::default()); + codegen.print_char(b' '); + codegen.print_str(expr.operator.as_str()); + codegen.print_char(b' '); codegen.print_expression(&expr.right); codegen.print_char(b')'); codegen.into_source_text()