diff --git a/.github/codecov.yml b/.github/codecov.yml index 5e8fdb5a89899..de4391876ed4c 100644 --- a/.github/codecov.yml +++ b/.github/codecov.yml @@ -24,6 +24,5 @@ ignore: - "crates/oxc_type_synthesis" - "crates/oxc_query" # Not aiming for test coverage right now with @u9g - "crates/oxc_linter_plugin" - - "crates/oxc_formatter" # The formatter is not being actively worked on - "crates/oxc_transformer" # not ready - "crates/oxc_js_regex" # not ready diff --git a/.github/workflows/conformance.yml b/.github/workflows/conformance.yml index 0380a79e407ea..ce01f7140d4a2 100644 --- a/.github/workflows/conformance.yml +++ b/.github/workflows/conformance.yml @@ -12,7 +12,6 @@ on: - 'website/**' - 'crates/oxc/**' - 'crates/oxc_cli/**' - - 'crates/oxc_formatter/**' - 'crates/oxc_linter/**' - 'crates/oxc_query/**' - 'crates/oxc_type_synthesis/**' @@ -30,7 +29,6 @@ on: - 'website/**' - 'crates/oxc/**' - 'crates/oxc_cli/**' - - 'crates/oxc_formatter/**' - 'crates/oxc_linter/**' - 'crates/oxc_query/**' - 'crates/oxc_type_synthesis/**' diff --git a/Cargo.lock b/Cargo.lock index a15c7637e7e9f..47048feecfd6f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1530,7 +1530,6 @@ dependencies = [ "oxc_ast", "oxc_codegen", "oxc_diagnostics", - "oxc_formatter", "oxc_index", "oxc_minifier", "oxc_parser", @@ -1665,17 +1664,6 @@ dependencies = [ "unicode-width", ] -[[package]] -name = "oxc_formatter" -version = "0.4.0" -dependencies = [ - "oxc_allocator", - "oxc_ast", - "oxc_parser", - "oxc_span", - "oxc_syntax", -] - [[package]] name = "oxc_index" version = "0.4.0" @@ -1706,7 +1694,6 @@ dependencies = [ "oxc_allocator", "oxc_diagnostics", "oxc_linter", - "oxc_linter_plugin", "oxc_parser", "oxc_semantic", "oxc_span", @@ -1734,8 +1721,8 @@ dependencies = [ "once_cell", "oxc_allocator", "oxc_ast", + "oxc_codegen", "oxc_diagnostics", - "oxc_formatter", "oxc_index", "oxc_macros", "oxc_parser", diff --git a/Cargo.toml b/Cargo.toml index 4618c8fb590f9..e98ce400f18cf 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -66,7 +66,6 @@ oxc_allocator = { version = "0.4.0", path = "crates/oxc_allocator" } oxc_ast = { version = "0.4.0", path = "crates/oxc_ast" } oxc_codegen = { version = "0.4.0", path = "crates/oxc_codegen" } oxc_diagnostics = { version = "0.4.0", path = "crates/oxc_diagnostics" } -oxc_formatter = { version = "0.4.0", path = "crates/oxc_formatter" } oxc_index = { version = "0.4.0", path = "crates/oxc_index" } oxc_minifier = { version = "0.4.0", path = "crates/oxc_minifier" } oxc_parser = { version = "0.4.0", path = "crates/oxc_parser" } diff --git a/MAINTENANCE.md b/MAINTENANCE.md index 13585a3d31277..ca5ef65b1db11 100644 --- a/MAINTENANCE.md +++ b/MAINTENANCE.md @@ -34,7 +34,6 @@ sed -i '' 's/0.3.0/0.4.0/' crates/oxc_allocator/Cargo.toml sed -i '' 's/0.3.0/0.4.0/' crates/oxc_ast/Cargo.toml sed -i '' 's/0.3.0/0.4.0/' crates/oxc_codegen/Cargo.toml sed -i '' 's/0.3.0/0.4.0/' crates/oxc_diagnostics/Cargo.toml -sed -i '' 's/0.3.0/0.4.0/' crates/oxc_formatter/Cargo.toml sed -i '' 's/0.3.0/0.4.0/' crates/oxc_index/Cargo.toml sed -i '' 's/0.3.0/0.4.0/' crates/oxc_minifier/Cargo.toml sed -i '' 's/0.3.0/0.4.0/' crates/oxc_parser/Cargo.toml @@ -60,7 +59,6 @@ cargo publish -p oxc_ast cargo publish -p oxc_diagnostics cargo publish -p oxc_parser cargo publish -p oxc_semantic -cargo publish -p oxc_formatter cargo publish -p oxc_transformer cargo publish -p oxc_codegen cargo publish -p oxc_minifier diff --git a/crates/oxc/Cargo.toml b/crates/oxc/Cargo.toml index 4d76361dd6448..95c3f87ad744c 100644 --- a/crates/oxc/Cargo.toml +++ b/crates/oxc/Cargo.toml @@ -28,7 +28,6 @@ oxc_parser = { workspace = true } oxc_span = { workspace = true } oxc_syntax = { workspace = true } oxc_semantic = { workspace = true, optional = true } -oxc_formatter = { workspace = true, optional = true } oxc_transformer = { workspace = true, optional = true } oxc_minifier = { workspace = true, optional = true } oxc_codegen = { workspace = true, optional = true } @@ -36,7 +35,6 @@ oxc_codegen = { workspace = true, optional = true } [features] serde = ["oxc_ast/serde", "oxc_semantic/serde"] semantic = ["oxc_semantic"] -formatter = ["oxc_formatter"] transformer = ["oxc_transformer"] minifier = ["oxc_minifier"] codegen = ["oxc_codegen"] diff --git a/crates/oxc/src/lib.rs b/crates/oxc/src/lib.rs index 1288987c429dd..6cb4db384da0c 100644 --- a/crates/oxc/src/lib.rs +++ b/crates/oxc/src/lib.rs @@ -43,12 +43,6 @@ pub mod semantic { pub use oxc_semantic::*; } -#[cfg(feature = "formatter")] -pub mod formatter { - #[doc(inline)] - pub use oxc_formatter::*; -} - #[cfg(feature = "transformer")] pub mod transformer { #[doc(inline)] diff --git a/crates/oxc_codegen/src/context.rs b/crates/oxc_codegen/src/context.rs index b8056011d15d0..211bd8c267c78 100644 --- a/crates/oxc_codegen/src/context.rs +++ b/crates/oxc_codegen/src/context.rs @@ -21,6 +21,7 @@ impl Context { } #[inline] + #[must_use] pub fn and_in(self, include: bool) -> Self { self.and(Self::In, include) } diff --git a/crates/oxc_codegen/src/gen.rs b/crates/oxc_codegen/src/gen.rs index ed37a28bb05c8..db7ca36e69374 100644 --- a/crates/oxc_codegen/src/gen.rs +++ b/crates/oxc_codegen/src/gen.rs @@ -129,7 +129,7 @@ impl<'a, const MINIFY: bool> Gen for ExpressionStatement<'a> { fn gen(&self, p: &mut Codegen<{ MINIFY }>, _ctx: Context) { p.print_indent(); p.start_of_stmt = p.code_len(); - self.expression.gen_expr(p, Precedence::lowest(), Context::default()); + p.print_expression(&self.expression); if self.expression.is_specific_id("let") { p.print_semicolon(); } else { @@ -153,7 +153,7 @@ fn print_if( p.print_str(b"if"); p.print_soft_space(); p.print(b'('); - if_stmt.test.gen_expr(p, Precedence::lowest(), Context::default()); + p.print_expression(&if_stmt.test); p.print(b')'); p.print_soft_space(); @@ -251,14 +251,14 @@ impl<'a, const MINIFY: bool> Gen for ForStatement<'a> { p.print_soft_space(); if let Some(test) = self.test.as_ref() { - test.gen_expr(p, Precedence::lowest(), Context::default()); + p.print_expression(test); } p.print_semicolon(); p.print_soft_space(); if let Some(update) = self.update.as_ref() { - update.gen_expr(p, Precedence::lowest(), Context::default()); + p.print_expression(update); } p.print(b')'); @@ -277,7 +277,7 @@ impl<'a, const MINIFY: bool> Gen for ForInStatement<'a> { p.print_space_before_identifier(); p.print_str(b"in"); p.print_hard_space(); - self.right.gen_expr(p, Precedence::lowest(), Context::default()); + p.print_expression(&self.right); p.print(b')'); p.print_soft_space(); self.body.gen(p, ctx); @@ -320,7 +320,7 @@ impl<'a, const MINIFY: bool> Gen for WhileStatement<'a> { p.print_indent(); p.print_str(b"while"); p.print(b'('); - self.test.gen_expr(p, Precedence::lowest(), Context::default()); + p.print_expression(&self.test); p.print(b')'); self.body.gen(p, ctx); } @@ -342,7 +342,7 @@ impl<'a, const MINIFY: bool> Gen for DoWhileStatement<'a> { } p.print_str(b"while"); p.print(b'('); - self.test.gen_expr(p, Precedence::lowest(), Context::default()); + p.print_expression(&self.test); p.print(b')'); p.print_semicolon_after_statement(); } @@ -384,7 +384,7 @@ impl<'a, const MINIFY: bool> Gen for SwitchStatement<'a> { p.print_indent(); p.print_str(b"switch"); p.print(b'('); - self.discriminant.gen_expr(p, Precedence::lowest(), Context::default()); + p.print_expression(&self.discriminant); p.print(b')'); p.print_block_start(); for case in &self.cases { @@ -404,7 +404,7 @@ impl<'a, const MINIFY: bool> Gen for SwitchCase<'a> { Some(test) => { p.print_str(b"case"); p.print_hard_space(); - test.gen_expr(p, Precedence::lowest(), Context::default()); + p.print_expression(test); } None => p.print_str(b"default"), } @@ -425,7 +425,7 @@ impl<'a, const MINIFY: bool> Gen for ReturnStatement<'a> { p.print_str(b"return"); if let Some(arg) = &self.argument { p.print_hard_space(); - arg.gen_expr(p, Precedence::lowest(), Context::default()); + p.print_expression(arg); } p.print_semicolon_after_statement(); } @@ -465,7 +465,7 @@ impl<'a, const MINIFY: bool> Gen for ThrowStatement<'a> { fn gen(&self, p: &mut Codegen<{ MINIFY }>, _ctx: Context) { p.print_indent(); p.print_str(b"throw "); - self.argument.gen_expr(p, Precedence::lowest(), Context::default()); + p.print_expression(&self.argument); p.print_semicolon_after_statement(); } } @@ -475,7 +475,7 @@ impl<'a, const MINIFY: bool> Gen for WithStatement<'a> { p.print_indent(); p.print_str(b"with"); p.print(b'('); - self.object.gen_expr(p, Precedence::lowest(), Context::default()); + p.print_expression(&self.object); p.print(b')'); self.body.gen(p, ctx); } @@ -1645,7 +1645,7 @@ impl<'a, const MINIFY: bool> Gen for TemplateLiteral<'a> { if let Some(expr) = expressions.next() { p.print_str(b"${"); - expr.gen_expr(p, Precedence::lowest(), Context::default()); + p.print_expression(expr); p.print(b'}'); } } @@ -1825,7 +1825,7 @@ impl Gen for JSXEmptyExpression { impl<'a, const MINIFY: bool> Gen for JSXExpression<'a> { fn gen(&self, p: &mut Codegen<{ MINIFY }>, ctx: Context) { match self { - Self::Expression(expr) => expr.gen_expr(p, Precedence::lowest(), Context::default()), + Self::Expression(expr) => p.print_expression(expr), Self::EmptyExpression(expr) => expr.gen(p, ctx), } } @@ -1853,7 +1853,7 @@ impl<'a, const MINIFY: bool> Gen for JSXAttributeValue<'a> { impl<'a, const MINIFY: bool> Gen for JSXSpreadAttribute<'a> { fn gen(&self, p: &mut Codegen<{ MINIFY }>, _ctx: Context) { p.print_str(b"{..."); - self.argument.gen_expr(p, Precedence::lowest(), Context::default()); + p.print_expression(&self.argument); p.print(b'}'); } } @@ -1924,7 +1924,7 @@ impl Gen for JSXText { impl<'a, const MINIFY: bool> Gen for JSXSpreadChild<'a> { fn gen(&self, p: &mut Codegen<{ MINIFY }>, _ctx: Context) { p.print_str(b"..."); - self.expression.gen_expr(p, Precedence::lowest(), Context::default()); + p.print_expression(&self.expression); } } @@ -1933,9 +1933,7 @@ impl<'a, const MINIFY: bool> Gen for JSXChild<'a> { match self { Self::Fragment(fragment) => fragment.gen(p, ctx), Self::Element(el) => el.gen(p, ctx), - Self::Spread(spread) => { - spread.expression.gen_expr(p, Precedence::lowest(), Context::default()); - } + Self::Spread(spread) => p.print_expression(&spread.expression), Self::ExpressionContainer(expr_container) => expr_container.gen(p, ctx), Self::Text(text) => text.gen(p, ctx), } diff --git a/crates/oxc_codegen/src/lib.rs b/crates/oxc_codegen/src/lib.rs index 6d388cb84100b..6775c48cd7907 100644 --- a/crates/oxc_codegen/src/lib.rs +++ b/crates/oxc_codegen/src/lib.rs @@ -24,7 +24,7 @@ use oxc_syntax::{ symbol::SymbolId, }; -use self::{ +pub use crate::{ context::Context, gen::{Gen, GenExpr}, operator::Operator, @@ -111,12 +111,12 @@ impl Codegen { } /// Push a single character into the buffer - fn print(&mut self, ch: u8) { + pub fn print(&mut self, ch: u8) { self.code.push(ch); } /// Push a string into the buffer - fn print_str(&mut self, s: &[u8]) { + pub fn print_str(&mut self, s: &[u8]) { self.code.extend_from_slice(s); } @@ -126,7 +126,7 @@ impl Codegen { } } - fn print_hard_space(&mut self) { + pub fn print_hard_space(&mut self) { self.print(b' '); } @@ -197,7 +197,7 @@ impl Codegen { self.print_str(b"..."); } - fn print_colon(&mut self) { + pub fn print_colon(&mut self) { self.print(b':'); } @@ -256,6 +256,10 @@ impl Codegen { } } + pub fn print_expression(&mut self, expr: &Expression<'_>) { + expr.gen_expr(self, Precedence::lowest(), Context::default()); + } + fn print_expressions>( &mut self, items: &[T], diff --git a/crates/oxc_formatter/Cargo.toml b/crates/oxc_formatter/Cargo.toml deleted file mode 100644 index 85c3f5de44252..0000000000000 --- a/crates/oxc_formatter/Cargo.toml +++ /dev/null @@ -1,27 +0,0 @@ -[package] -name = "oxc_formatter" -version = "0.4.0" -authors.workspace = true -description.workspace = true -edition.workspace = true -homepage.workspace = true -keywords.workspace = true -license.workspace = true -repository.workspace = true -rust-version.workspace = true -categories.workspace = true - -[lints] -workspace = true - -[lib] -doctest = false - -[dependencies] -oxc_allocator = { workspace = true } -oxc_ast = { workspace = true } -oxc_span = { workspace = true } -oxc_syntax = { workspace = true } - -[dev-dependencies] -oxc_parser = { workspace = true } diff --git a/crates/oxc_formatter/README.md b/crates/oxc_formatter/README.md deleted file mode 100644 index 4bf60694b1f1f..0000000000000 --- a/crates/oxc_formatter/README.md +++ /dev/null @@ -1,3 +0,0 @@ -# Formatter (Prettier) - -TBD diff --git a/crates/oxc_formatter/examples/formatter.rs b/crates/oxc_formatter/examples/formatter.rs deleted file mode 100644 index 091d15b0a0c2e..0000000000000 --- a/crates/oxc_formatter/examples/formatter.rs +++ /dev/null @@ -1,32 +0,0 @@ -use std::{env, path::Path}; - -use oxc_allocator::Allocator; -use oxc_formatter::{Formatter, FormatterOptions}; -use oxc_parser::Parser; -use oxc_span::SourceType; - -// Instruction: -// create a `test.js`, -// run `cargo run -p oxc_formatter --example formatter` -// or `cargo watch -x "run -p oxc_formatter --example formatter"` - -fn main() { - let name = env::args().nth(1).unwrap_or_else(|| "test.js".to_string()); - let path = Path::new(&name); - let source_text = std::fs::read_to_string(path).expect("{name} not found"); - let allocator = Allocator::default(); - let source_type = SourceType::from_path(path).unwrap(); - let ret = Parser::new(&allocator, &source_text, source_type).parse(); - - if !ret.errors.is_empty() { - for error in ret.errors { - let error = error.with_source_code(source_text.clone()); - println!("{error:?}"); - } - return; - } - - let formatter_options = FormatterOptions::default(); - let printed = Formatter::new(source_text.len(), formatter_options).build(&ret.program); - println!("{printed}"); -} diff --git a/crates/oxc_formatter/src/gen.rs b/crates/oxc_formatter/src/gen.rs deleted file mode 100644 index b3567284d11de..0000000000000 --- a/crates/oxc_formatter/src/gen.rs +++ /dev/null @@ -1,1852 +0,0 @@ -use oxc_allocator::{Box, Vec}; -#[allow(clippy::wildcard_imports)] -use oxc_ast::ast::*; -use oxc_syntax::operator::BinaryOperator; - -use crate::{Formatter, Separator}; - -pub trait Gen { - fn gen(&self, p: &mut Formatter); -} - -impl<'a, T> Gen for Box<'a, T> -where - T: Gen, -{ - fn gen(&self, p: &mut Formatter) { - (**self).gen(p); - } -} - -impl<'a> Gen for Program<'a> { - fn gen(&self, p: &mut Formatter) { - for directive in &self.directives { - directive.gen(p); - } - for stmt in &self.body { - p.print_semicolon_if_needed(); - stmt.gen(p); - } - } -} - -impl Gen for Directive { - fn gen(&self, p: &mut Formatter) { - p.print_indent(); - p.print(b'"'); - p.print_str(self.directive.as_bytes()); - p.print(b'"'); - p.print_semicolon(); - p.print_newline(); - } -} - -impl<'a> Gen for Statement<'a> { - fn gen(&self, p: &mut Formatter) { - match self { - Self::BlockStatement(stmt) => stmt.gen(p), - Self::BreakStatement(stmt) => stmt.gen(p), - Self::ContinueStatement(stmt) => stmt.gen(p), - Self::DebuggerStatement(stmt) => stmt.gen(p), - Self::DoWhileStatement(stmt) => stmt.gen(p), - Self::EmptyStatement(stmt) => stmt.gen(p), - Self::ExpressionStatement(stmt) => stmt.gen(p), - Self::ForInStatement(stmt) => stmt.gen(p), - Self::ForOfStatement(stmt) => stmt.gen(p), - Self::ForStatement(stmt) => stmt.gen(p), - Self::IfStatement(stmt) => stmt.gen(p), - Self::LabeledStatement(stmt) => stmt.gen(p), - Self::ModuleDeclaration(decl) => decl.gen(p), - Self::ReturnStatement(stmt) => stmt.gen(p), - Self::SwitchStatement(stmt) => stmt.gen(p), - Self::ThrowStatement(stmt) => stmt.gen(p), - Self::TryStatement(stmt) => stmt.gen(p), - Self::WhileStatement(stmt) => stmt.gen(p), - Self::WithStatement(stmt) => stmt.gen(p), - Self::Declaration(decl) => decl.gen(p), - } - } -} - -impl<'a> Gen for ExpressionStatement<'a> { - fn gen(&self, p: &mut Formatter) { - p.print_indent(); - self.expression.gen(p); - if self.expression.is_specific_id("let") { - p.print_semicolon(); - } else { - p.print_semicolon_after_statement(); - } - } -} - -impl Gen for EmptyStatement { - fn gen(&self, p: &mut Formatter) { - p.print_indent(); - p.print_semicolon(); - p.print_newline(); - } -} - -impl<'a> Gen for IfStatement<'a> { - fn gen(&self, p: &mut Formatter) { - p.print_indent(); - print_if(self, p); - } -} - -fn print_if(if_stmt: &IfStatement<'_>, p: &mut Formatter) { - p.print_str(b"if"); - p.print_space(); - p.print(b'('); - if_stmt.test.gen(p); - p.print(b')'); - p.print_space(); - if let Statement::BlockStatement(block) = &if_stmt.consequent { - p.print_block1(block); - } else { - p.print(b'{'); - p.print_newline(); - p.indent(); - if_stmt.consequent.gen(p); - p.needs_semicolon = false; - p.dedent(); - p.print_indent(); - p.print(b'}'); - } - if if_stmt.alternate.is_some() { - p.print_space(); - } else { - p.print_newline(); - } - if let Some(alternate) = if_stmt.alternate.as_ref() { - p.print_semicolon_if_needed(); - p.print_space(); - p.print_str(b"else"); - p.print_space(); - match alternate { - Statement::BlockStatement(block) => { - p.print_block1(block); - p.print_newline(); - } - Statement::IfStatement(if_stmt) => { - print_if(if_stmt, p); - } - _ => { - p.print_newline(); - p.indent(); - alternate.gen(p); - p.dedent(); - } - } - } -} - -impl<'a> Gen for BlockStatement<'a> { - fn gen(&self, p: &mut Formatter) { - p.print_indent(); - p.print_block1(self); - p.print_newline(); - } -} - -impl<'a> Gen for ForStatement<'a> { - fn gen(&self, p: &mut Formatter) { - p.print_indent(); - p.print_str(b"for"); - p.print_space(); - p.print(b'('); - - if let Some(init) = self.init.as_ref() { - match init { - ForStatementInit::Expression(expr) => expr.gen(p), - ForStatementInit::VariableDeclaration(var) => var.gen(p), - ForStatementInit::UsingDeclaration(decl) => decl.gen(p), - } - } - - p.print_semicolon(); - p.print_space(); - - if let Some(test) = self.test.as_ref() { - test.gen(p); - } - - p.print_semicolon(); - p.print_space(); - - if let Some(update) = self.update.as_ref() { - update.gen(p); - } - - p.print(b')'); - p.print_body(&self.body); - } -} - -impl<'a> Gen for ForInStatement<'a> { - fn gen(&self, p: &mut Formatter) { - p.print_indent(); - p.print_str(b"for"); - gen_for_statement_brack_content(&self.left, &self.right, &self.body, b"in", p); - } -} - -impl<'a> Gen for ForOfStatement<'a> { - fn gen(&self, p: &mut Formatter) { - p.print_indent(); - p.print_str(b"for"); - if self.r#await { - p.print_str(b" await"); - } - gen_for_statement_brack_content(&self.left, &self.right, &self.body, b"of", p); - } -} - -fn gen_for_statement_brack_content<'a>( - left: &ForStatementLeft<'a>, - right: &Expression<'a>, - body: &Statement, - key: &[u8], - p: &mut Formatter, -) { - p.print_space(); - p.print(b'('); - left.gen(p); - p.print_space(); - p.print_str(key); - p.print_space(); - right.gen(p); - p.print(b')'); - p.print_body(body); -} - -impl<'a> Gen for ForStatementLeft<'a> { - fn gen(&self, p: &mut Formatter) { - match &self { - ForStatementLeft::VariableDeclaration(var) => var.gen(p), - ForStatementLeft::AssignmentTarget(target) => target.gen(p), - ForStatementLeft::UsingDeclaration(decl) => decl.gen(p), - } - } -} - -impl<'a> Gen for WhileStatement<'a> { - fn gen(&self, p: &mut Formatter) { - p.print_indent(); - p.print_str(b"while"); - p.print_space(); - p.print(b'('); - self.test.gen(p); - p.print(b')'); - p.print_body(&self.body); - } -} - -impl<'a> Gen for DoWhileStatement<'a> { - fn gen(&self, p: &mut Formatter) { - p.print_indent(); - p.print_str(b"do"); - p.print_space(); - if let Statement::BlockStatement(block) = &self.body { - p.print_space(); - p.print_block1(block); - p.print_space(); - } else { - p.print_newline(); - p.indent(); - self.body.gen(p); - p.print_semicolon_if_needed(); - p.dedent(); - p.print_indent(); - } - p.print_str(b"while"); - p.print_space(); - p.print(b'('); - self.test.gen(p); - p.print(b')'); - p.print_semicolon_after_statement(); - } -} - -impl Gen for ContinueStatement { - fn gen(&self, p: &mut Formatter) { - p.print_indent(); - p.print_str(b"continue"); - if let Some(label) = &self.label { - p.print_space(); - label.gen(p); - } - p.print_semicolon_after_statement(); - } -} - -impl Gen for BreakStatement { - fn gen(&self, p: &mut Formatter) { - p.print_indent(); - p.print_str(b"break"); - if let Some(label) = &self.label { - p.print_space(); - label.gen(p); - } - p.print_semicolon_after_statement(); - } -} - -impl<'a> Gen for SwitchStatement<'a> { - fn gen(&self, p: &mut Formatter) { - p.print_indent(); - p.print_str(b"switch"); - p.print_space(); - p.print(b'('); - self.discriminant.gen(p); - p.print(b')'); - p.print_space(); - p.print(b'{'); - p.print_newline(); - p.indent(); - for case in &self.cases { - case.gen(p); - } - p.dedent(); - p.print_indent(); - p.print(b'}'); - p.print_newline(); - p.needs_semicolon = false; - } -} - -impl<'a> Gen for SwitchCase<'a> { - fn gen(&self, p: &mut Formatter) { - p.print_semicolon_if_needed(); - p.print_indent(); - match &self.test { - Some(test) => { - p.print_str(b"case"); - p.print_space(); - test.gen(p); - } - None => p.print_str(b"default"), - } - p.print_colon(); - p.print_newline(); - p.indent(); - for item in &self.consequent { - p.print_semicolon_if_needed(); - item.gen(p); - } - p.dedent(); - } -} - -impl<'a> Gen for ReturnStatement<'a> { - fn gen(&self, p: &mut Formatter) { - p.print_indent(); - p.print_str(b"return"); - if let Some(arg) = &self.argument { - p.print_space(); - arg.gen(p); - } - p.print_semicolon_after_statement(); - } -} - -impl<'a> Gen for LabeledStatement<'a> { - fn gen(&self, p: &mut Formatter) { - p.print_indent(); - self.label.gen(p); - p.print_colon(); - p.print_newline(); - self.body.gen(p); - } -} - -impl<'a> Gen for TryStatement<'a> { - fn gen(&self, p: &mut Formatter) { - p.print_indent(); - p.print_str(b"try"); - p.print_space(); - p.print_block1(&self.block); - if let Some(handler) = &self.handler { - p.print_space(); - p.print_str(b"catch"); - if let Some(param) = &handler.param { - p.print_space(); - p.print_str(b"("); - param.gen(p); - p.print_str(b")"); - } - p.print_space(); - p.print_block1(&handler.body); - } - if let Some(finalizer) = &self.finalizer { - p.print_space(); - p.print_str(b"finally"); - p.print_space(); - p.print_block1(finalizer); - } - p.print_newline(); - } -} - -impl<'a> Gen for ThrowStatement<'a> { - fn gen(&self, p: &mut Formatter) { - p.print_indent(); - p.print_str(b"throw"); - p.print_space(); - self.argument.gen(p); - p.print_semicolon_after_statement(); - } -} - -impl<'a> Gen for WithStatement<'a> { - fn gen(&self, p: &mut Formatter) { - p.print_indent(); - p.print_str(b"with"); - p.print_space(); - p.print(b'('); - self.object.gen(p); - p.print(b')'); - p.print_space(); - self.body.gen(p); - } -} - -impl Gen for DebuggerStatement { - fn gen(&self, p: &mut Formatter) { - p.print_indent(); - p.print_str(b"debugger"); - p.print_semicolon_after_statement(); - } -} - -impl<'a> Gen for ModuleDeclaration<'a> { - fn gen(&self, p: &mut Formatter) { - match self { - Self::ImportDeclaration(decl) => decl.gen(p), - Self::ExportAllDeclaration(decl) => decl.gen(p), - Self::ExportDefaultDeclaration(decl) => decl.gen(p), - Self::ExportNamedDeclaration(decl) => decl.gen(p), - Self::TSExportAssignment(_) | Self::TSNamespaceExportDeclaration(_) => {} - } - } -} - -impl<'a> Gen for Declaration<'a> { - fn gen(&self, p: &mut Formatter) { - match self { - Self::VariableDeclaration(stmt) => { - p.print_indent(); - stmt.gen(p); - p.print_semicolon_after_statement(); - } - Self::FunctionDeclaration(stmt) => { - p.print_indent(); - stmt.gen(p); - p.print_newline(); - } - Self::ClassDeclaration(declaration) => { - declaration.gen(p); - p.print_newline(); - } - Self::UsingDeclaration(declaration) => { - declaration.gen(p); - p.print_newline(); - } - Self::TSTypeAliasDeclaration(_) - | Self::TSInterfaceDeclaration(_) - | Self::TSEnumDeclaration(_) - | Self::TSModuleDeclaration(_) - | Self::TSImportEqualsDeclaration(_) => {} - } - } -} - -impl<'a> Gen for VariableDeclaration<'a> { - fn gen(&self, p: &mut Formatter) { - p.print_str(match self.kind { - VariableDeclarationKind::Const => b"const", - VariableDeclarationKind::Let => b"let", - VariableDeclarationKind::Var => b"var", - }); - p.print_space(); - p.print_list(&self.declarations); - } -} -impl<'a> Gen for UsingDeclaration<'a> { - fn gen(&self, p: &mut Formatter) { - if self.is_await { - p.print_str(b"await"); - p.print_space(); - } - p.print_str(b"using"); - p.print_space(); - p.print_list(&self.declarations); - p.print_semicolon(); - } -} - -impl<'a> Gen for VariableDeclarator<'a> { - fn gen(&self, p: &mut Formatter) { - self.id.gen(p); - if let Some(init) = &self.init { - p.print_space(); - p.print_equal(); - p.print_space(); - init.gen(p); - } - } -} - -impl<'a> Gen for Function<'a> { - fn gen(&self, p: &mut Formatter) { - if self.r#async { - p.print_str(b"async"); - p.print_space(); - } - p.print_str(b"function"); - if self.generator { - p.print(b'*'); - } - if let Some(id) = &self.id { - if !self.generator { - p.print_space(); - } - id.gen(p); - p.print_space(); - } - p.print(b'('); - self.params.gen(p); - p.print(b')'); - p.print_space(); - if let Some(body) = &self.body { - body.gen(p); - } - } -} - -impl<'a> Gen for FunctionBody<'a> { - fn gen(&self, p: &mut Formatter) { - p.print(b'{'); - p.indent(); - p.print_newline(); - for directive in &self.directives { - directive.gen(p); - } - p.needs_semicolon = false; - for stmt in &self.statements { - p.print_semicolon_if_needed(); - stmt.gen(p); - } - p.dedent(); - p.print_indent(); - p.print(b'}'); - p.needs_semicolon = false; - } -} - -impl<'a> Gen for FormalParameter<'a> { - fn gen(&self, p: &mut Formatter) { - self.pattern.gen(p); - } -} - -impl<'a> Gen for FormalParameters<'a> { - fn gen(&self, p: &mut Formatter) { - p.print_list(&self.items); - if let Some(rest) = &self.rest { - if !self.items.is_empty() { - p.print_comma(); - } - rest.gen(p); - } - } -} - -impl<'a> Gen for ImportDeclaration<'a> { - fn gen(&self, p: &mut Formatter) { - p.print_str(b"import "); - if let Some(specifiers) = &self.specifiers { - if specifiers.is_empty() { - p.print(b'\''); - p.print_str(self.source.value.as_bytes()); - p.print(b'\''); - self.with_clause.gen(p); - p.print_semicolon_after_statement(); - return; - } - - let mut in_block = false; - for (index, specifier) in specifiers.iter().enumerate() { - match specifier { - ImportDeclarationSpecifier::ImportDefaultSpecifier(spec) => { - if in_block { - p.print_space(); - p.print_str(b"},"); - p.print_space(); - in_block = false; - } else if index != 0 { - p.print_comma(); - p.print_space(); - } - spec.local.gen(p); - } - ImportDeclarationSpecifier::ImportNamespaceSpecifier(spec) => { - if in_block { - p.print_space(); - p.print_str(b"},"); - p.print_space(); - in_block = false; - } else if index != 0 { - p.print_comma(); - p.print_space(); - } - p.print_str(b"* as "); - spec.local.gen(p); - } - ImportDeclarationSpecifier::ImportSpecifier(spec) => { - if in_block { - p.print_comma(); - } else { - if index != 0 { - p.print_comma(); - p.print_space(); - } - in_block = true; - p.print(b'{'); - } - p.print_space(); - - let imported_name = match &spec.imported { - ModuleExportName::Identifier(identifier) => { - identifier.gen(p); - identifier.name.as_bytes() - } - ModuleExportName::StringLiteral(literal) => { - literal.gen(p); - literal.value.as_bytes() - } - }; - - let local_name = spec.local.name.as_bytes(); - - if imported_name != local_name { - p.print_str(b" as "); - spec.local.gen(p); - } - } - } - } - if in_block { - p.print_space(); - p.print(b'}'); - } - p.print_str(b" from "); - } - self.source.gen(p); - self.with_clause.gen(p); - p.print_semicolon_after_statement(); - } -} - -impl<'a> Gen for Option> { - fn gen(&self, p: &mut Formatter) { - if let Some(with_clause) = self { - p.print_space(); - with_clause.attributes_keyword.gen(p); - p.print_space(); - with_clause.with_entries.gen(p); - } - } -} - -impl<'a> Gen for Vec<'a, ImportAttribute> { - fn gen(&self, p: &mut Formatter) { - p.print_block(self, Separator::Comma); - } -} - -impl Gen for ImportAttribute { - fn gen(&self, p: &mut Formatter) { - match &self.key { - ImportAttributeKey::Identifier(identifier) => { - p.print_str(identifier.name.as_bytes()); - } - ImportAttributeKey::StringLiteral(literal) => literal.gen(p), - }; - p.print_colon(); - p.print_space(); - self.value.gen(p); - } -} - -impl<'a> Gen for ExportNamedDeclaration<'a> { - fn gen(&self, p: &mut Formatter) { - p.print_str(b"export "); - match &self.declaration { - Some(decl) => decl.gen(p), - None => { - p.print(b'{'); - if !self.specifiers.is_empty() { - p.print_space(); - p.print_list(&self.specifiers); - p.print_space(); - } - p.print(b'}'); - if let Some(source) = &self.source { - p.print_space(); - p.print_str(b"from"); - p.print_space(); - source.gen(p); - } - p.print_semicolon_after_statement(); - } - } - } -} - -impl Gen for ExportSpecifier { - fn gen(&self, p: &mut Formatter) { - self.local.gen(p); - if self.local.name() != self.exported.name() { - p.print_str(b" as "); - self.exported.gen(p); - } - } -} - -impl Gen for ModuleExportName { - fn gen(&self, p: &mut Formatter) { - match self { - Self::Identifier(identifier) => { - p.print_str(identifier.name.as_bytes()); - } - Self::StringLiteral(literal) => literal.gen(p), - }; - } -} - -impl<'a> Gen for ExportAllDeclaration<'a> { - fn gen(&self, p: &mut Formatter) { - p.print_str(b"export"); - p.print_space(); - p.print(b'*'); - - if let Some(exported) = &self.exported { - p.print_space(); - p.print_str(b"as "); - exported.gen(p); - } - - p.print_str(b" from"); - p.print_space(); - self.source.gen(p); - self.with_clause.gen(p); - - p.print_semicolon_after_statement(); - } -} - -impl<'a> Gen for ExportDefaultDeclaration<'a> { - fn gen(&self, p: &mut Formatter) { - p.print_str(b"export default "); - self.declaration.gen(p); - } -} -impl<'a> Gen for ExportDefaultDeclarationKind<'a> { - fn gen(&self, p: &mut Formatter) { - match self { - Self::Expression(expr) => { - expr.gen(p); - p.print_semicolon_after_statement(); - } - Self::FunctionDeclaration(fun) => fun.gen(p), - Self::ClassDeclaration(value) => value.gen(p), - Self::TSInterfaceDeclaration(_) | Self::TSEnumDeclaration(_) => {} - } - } -} - -impl<'a> Gen for Expression<'a> { - fn gen(&self, p: &mut Formatter) { - match self { - Self::BooleanLiteral(lit) => lit.gen(p), - Self::NullLiteral(lit) => lit.gen(p), - Self::NumberLiteral(lit) => lit.gen(p), - Self::BigintLiteral(lit) => lit.gen(p), - Self::RegExpLiteral(lit) => lit.gen(p), - Self::StringLiteral(lit) => lit.gen(p), - Self::Identifier(ident) => ident.gen(p), - Self::ThisExpression(expr) => expr.gen(p), - Self::MemberExpression(expr) => expr.gen(p), - Self::CallExpression(expr) => expr.gen(p), - Self::ArrayExpression(expr) => expr.gen(p), - Self::ObjectExpression(expr) => expr.gen(p), - Self::FunctionExpression(expr) => expr.gen(p), - Self::ArrowExpression(expr) => expr.gen(p), - Self::YieldExpression(expr) => expr.gen(p), - Self::UpdateExpression(expr) => expr.gen(p), - Self::UnaryExpression(expr) => expr.gen(p), - Self::BinaryExpression(expr) => expr.gen(p), - Self::PrivateInExpression(expr) => expr.gen(p), - Self::LogicalExpression(expr) => expr.gen(p), - Self::ConditionalExpression(expr) => expr.gen(p), - Self::AssignmentExpression(expr) => expr.gen(p), - Self::SequenceExpression(expr) => expr.gen(p), - Self::ParenthesizedExpression(expr) => expr.gen(p), - Self::ImportExpression(expr) => expr.gen(p), - Self::TemplateLiteral(literal) => literal.gen(p), - Self::TaggedTemplateExpression(expr) => expr.gen(p), - Self::Super(sup) => sup.gen(p), - Self::AwaitExpression(expr) => expr.gen(p), - Self::ChainExpression(expr) => expr.gen(p), - Self::NewExpression(expr) => expr.gen(p), - Self::MetaProperty(expr) => expr.gen(p), - Self::ClassExpression(expr) => expr.gen(p), - Self::JSXElement(el) => el.gen(p), - Self::JSXFragment(fragment) => fragment.gen(p), - Self::TSAsExpression(expr) => expr.expression.gen(p), - Self::TSSatisfiesExpression(expr) => expr.expression.gen(p), - Self::TSTypeAssertion(expr) => expr.expression.gen(p), - Self::TSNonNullExpression(expr) => expr.expression.gen(p), - Self::TSInstantiationExpression(expr) => expr.expression.gen(p), - } - } -} - -impl Gen for IdentifierReference { - fn gen(&self, p: &mut Formatter) { - p.print_str(self.name.as_bytes()); - } -} - -impl Gen for IdentifierName { - fn gen(&self, p: &mut Formatter) { - p.print_str(self.name.as_bytes()); - } -} - -impl Gen for BindingIdentifier { - fn gen(&self, p: &mut Formatter) { - p.print_str(self.name.as_bytes()); - } -} - -impl Gen for LabelIdentifier { - fn gen(&self, p: &mut Formatter) { - p.print_str(self.name.as_bytes()); - } -} - -impl Gen for BooleanLiteral { - fn gen(&self, p: &mut Formatter) { - p.print_str(self.as_str().as_bytes()); - } -} - -impl Gen for NullLiteral { - fn gen(&self, p: &mut Formatter) { - p.print_str(b"null"); - } -} - -impl<'a> Gen for NumberLiteral<'a> { - fn gen(&self, p: &mut Formatter) { - p.print_str(self.raw.as_bytes()); - } -} - -impl Gen for BigintLiteral { - fn gen(&self, p: &mut Formatter) { - p.print_str(self.value.to_string().as_bytes()); - p.print(b'n'); - } -} - -impl Gen for RegExpLiteral { - fn gen(&self, p: &mut Formatter) { - p.print(b'/'); - p.print_str(self.regex.pattern.as_bytes()); - p.print(b'/'); - p.print_str(self.regex.flags.to_string().as_bytes()); - } -} - -impl Gen for StringLiteral { - fn gen(&self, p: &mut Formatter) { - p.print_quote(); - for c in self.value.chars() { - p.print_str(c.escape_default().to_string().as_bytes()); - } - p.print_quote(); - } -} - -impl Gen for ThisExpression { - fn gen(&self, p: &mut Formatter) { - p.print_str(b"this"); - } -} - -impl<'a> Gen for MemberExpression<'a> { - fn gen(&self, p: &mut Formatter) { - match self { - Self::ComputedMemberExpression(expr) => expr.gen(p), - Self::StaticMemberExpression(expr) => expr.gen(p), - Self::PrivateFieldExpression(expr) => expr.gen(p), - } - } -} - -impl<'a> Gen for ComputedMemberExpression<'a> { - fn gen(&self, p: &mut Formatter) { - self.object.gen(p); - if self.optional { - p.print_str(b"?."); - } - p.print(b'['); - self.expression.gen(p); - p.print(b']'); - } -} - -impl<'a> Gen for StaticMemberExpression<'a> { - fn gen(&self, p: &mut Formatter) { - self.object.gen(p); - if self.optional { - p.print(b'?'); - } - p.print(b'.'); - self.property.gen(p); - } -} - -impl<'a> Gen for PrivateFieldExpression<'a> { - fn gen(&self, p: &mut Formatter) { - self.object.gen(p); - if self.optional { - p.print_str(b"?"); - } - p.print(b'.'); - self.field.gen(p); - } -} - -impl<'a> Gen for CallExpression<'a> { - fn gen(&self, p: &mut Formatter) { - self.callee.gen(p); - - if self.optional { - p.print_str(b"?."); - } - p.print(b'('); - p.print_list(&self.arguments); - p.print(b')'); - } -} - -impl<'a> Gen for Argument<'a> { - fn gen(&self, p: &mut Formatter) { - match self { - Self::SpreadElement(elem) => elem.gen(p), - Self::Expression(elem) => elem.gen(p), - } - } -} - -impl<'a> Gen for ArrayExpressionElement<'a> { - fn gen(&self, p: &mut Formatter) { - match self { - Self::Expression(expr) => expr.gen(p), - Self::SpreadElement(elem) => elem.gen(p), - Self::Elision(_span) => {} - } - } -} - -impl<'a> Gen for SpreadElement<'a> { - fn gen(&self, p: &mut Formatter) { - p.print_ellipsis(); - self.argument.gen(p); - } -} - -impl<'a> Gen for ArrayExpression<'a> { - fn gen(&self, p: &mut Formatter) { - p.print(b'['); - p.print_list(&self.elements); - if self.trailing_comma.is_some() { - p.print_comma(); - } - p.print(b']'); - } -} - -impl<'a> Gen for ObjectExpression<'a> { - fn gen(&self, p: &mut Formatter) { - p.print(b'{'); - p.indent(); - for (i, item) in self.properties.iter().enumerate() { - if i != 0 { - p.print_comma(); - } - p.print_newline(); - p.print_indent(); - item.gen(p); - } - p.print_newline(); - p.dedent(); - p.print_indent(); - p.print(b'}'); - } -} - -impl<'a> Gen for ObjectPropertyKind<'a> { - fn gen(&self, p: &mut Formatter) { - match self { - Self::ObjectProperty(prop) => prop.gen(p), - Self::SpreadProperty(elem) => elem.gen(p), - } - } -} - -impl<'a> Gen for ObjectProperty<'a> { - fn gen(&self, p: &mut Formatter) { - if let Expression::FunctionExpression(func) = &self.value { - let is_accessor = match &self.kind { - PropertyKind::Init => false, - PropertyKind::Get => { - p.print_str(b"get "); - true - } - PropertyKind::Set => { - p.print_str(b"set "); - true - } - }; - if self.method || is_accessor { - if func.r#async { - p.print_str(b"async "); - } - if func.generator { - p.print_str(b"*"); - } - if self.computed { - p.print(b'['); - } - self.key.gen(p); - if self.computed { - p.print(b']'); - } - p.print(b'('); - func.params.gen(p); - p.print(b')'); - p.print_space(); - if let Some(body) = &func.body { - body.gen(p); - } - return; - } - } - if self.computed { - p.print(b'['); - } - self.key.gen(p); - if self.computed { - p.print(b']'); - } - p.print_colon(); - p.print_space(); - self.value.gen(p); - } -} - -impl<'a> Gen for PropertyKey<'a> { - fn gen(&self, p: &mut Formatter) { - match self { - Self::Identifier(ident) => { - if p.quote_property_with_double_quotes { - p.print(b'\"'); - } - ident.gen(p); - if p.quote_property_with_double_quotes { - p.print(b'\"'); - } - } - Self::PrivateIdentifier(ident) => ident.gen(p), - Self::Expression(expr) => expr.gen(p), - } - } -} - -impl<'a> Gen for ArrowExpression<'a> { - fn gen(&self, p: &mut Formatter) { - if self.r#async { - p.print_str(b"async"); - p.print_space(); - } - p.print(b'('); - self.params.gen(p); - p.print(b')'); - p.print_space(); - p.print_str(b"=>"); - p.print_space(); - if self.expression { - if let Statement::ExpressionStatement(stmt) = &self.body.statements[0] { - stmt.expression.gen(p); - } - } else { - self.body.gen(p); - } - } -} - -impl<'a> Gen for YieldExpression<'a> { - fn gen(&self, p: &mut Formatter) { - p.print_str(b"yield"); - if self.delegate { - p.print_space(); - p.print(b'*'); - } - - if let Some(argument) = self.argument.as_ref() { - p.print_space(); - argument.gen(p); - } - } -} - -impl<'a> Gen for UpdateExpression<'a> { - fn gen(&self, p: &mut Formatter) { - let operator = self.operator.as_str().as_bytes(); - if self.prefix { - p.print_space(); - p.print_str(operator); - self.argument.gen(p); - } else { - self.argument.gen(p); - p.print_str(operator); - } - } -} - -impl<'a> Gen for UnaryExpression<'a> { - fn gen(&self, p: &mut Formatter) { - let operator = self.operator.as_str().as_bytes(); - if self.operator.is_keyword() { - p.print_str(operator); - p.print_space(); - } else { - p.print_space(); - p.print_str(operator); - } - self.argument.gen(p); - } -} - -impl<'a> Gen for BinaryExpression<'a> { - fn gen(&self, p: &mut Formatter) { - self.left.gen(p); - self.operator.gen(p); - self.right.gen(p); - } -} - -impl Gen for BinaryOperator { - fn gen(&self, p: &mut Formatter) { - let operator = self.as_str().as_bytes(); - p.print_space(); - p.print_str(operator); - p.print_space(); - } -} - -impl<'a> Gen for PrivateInExpression<'a> { - fn gen(&self, p: &mut Formatter) { - self.left.gen(p); - p.print_space(); - p.print_str(self.operator.as_str().as_bytes()); - p.print_space(); - self.right.gen(p); - } -} - -impl<'a> Gen for LogicalExpression<'a> { - fn gen(&self, p: &mut Formatter) { - self.left.gen(p); - p.print_space(); - p.print_str(self.operator.as_str().as_bytes()); - p.print_space(); - self.right.gen(p); - } -} - -impl<'a> Gen for ConditionalExpression<'a> { - fn gen(&self, p: &mut Formatter) { - self.test.gen(p); - p.print_space(); - p.print(b'?'); - p.print_space(); - self.consequent.gen(p); - p.print_space(); - p.print(b':'); - p.print_space(); - self.alternate.gen(p); - } -} - -impl<'a> Gen for AssignmentExpression<'a> { - fn gen(&self, p: &mut Formatter) { - self.left.gen(p); - p.print_space(); - p.print_str(self.operator.as_str().as_bytes()); - p.print_space(); - self.right.gen(p); - } -} - -impl<'a> Gen for AssignmentTarget<'a> { - fn gen(&self, p: &mut Formatter) { - match self { - Self::SimpleAssignmentTarget(target) => target.gen(p), - Self::AssignmentTargetPattern(pat) => pat.gen(p), - } - } -} - -impl<'a> Gen for SimpleAssignmentTarget<'a> { - fn gen(&self, p: &mut Formatter) { - match self { - Self::AssignmentTargetIdentifier(ident) => ident.gen(p), - Self::MemberAssignmentTarget(member_expr) => member_expr.gen(p), - Self::TSAsExpression(expr) => expr.expression.gen(p), - Self::TSSatisfiesExpression(expr) => expr.expression.gen(p), - Self::TSNonNullExpression(expr) => expr.expression.gen(p), - Self::TSTypeAssertion(expr) => expr.expression.gen(p), - } - } -} - -impl<'a> Gen for AssignmentTargetPattern<'a> { - fn gen(&self, p: &mut Formatter) { - match self { - Self::ArrayAssignmentTarget(target) => target.gen(p), - Self::ObjectAssignmentTarget(target) => target.gen(p), - } - } -} - -impl<'a> Gen for ArrayAssignmentTarget<'a> { - fn gen(&self, p: &mut Formatter) { - p.print(b'['); - p.print_list(&self.elements); - if let Some(target) = &self.rest { - p.print_comma(); - p.print_ellipsis(); - target.gen(p); - } - if self.trailing_comma.is_some() { - p.print_comma(); - } - p.print(b']'); - } -} - -impl<'a> Gen for Option> { - fn gen(&self, p: &mut Formatter) { - if let Some(arg) = self { - arg.gen(p); - } - } -} - -impl<'a> Gen for ObjectAssignmentTarget<'a> { - fn gen(&self, p: &mut Formatter) { - p.print(b'{'); - p.print_list(&self.properties); - if let Some(target) = &self.rest { - if !self.properties.is_empty() { - p.print_comma(); - } - p.print_ellipsis(); - target.gen(p); - } - p.print(b'}'); - } -} - -impl<'a> Gen for AssignmentTargetMaybeDefault<'a> { - fn gen(&self, p: &mut Formatter) { - match self { - Self::AssignmentTarget(target) => target.gen(p), - Self::AssignmentTargetWithDefault(target) => target.gen(p), - } - } -} - -impl<'a> Gen for AssignmentTargetWithDefault<'a> { - fn gen(&self, p: &mut Formatter) { - self.binding.gen(p); - p.print_equal(); - self.init.gen(p); - } -} - -impl<'a> Gen for AssignmentTargetProperty<'a> { - fn gen(&self, p: &mut Formatter) { - match self { - Self::AssignmentTargetPropertyIdentifier(ident) => ident.gen(p), - Self::AssignmentTargetPropertyProperty(prop) => prop.gen(p), - } - } -} - -impl<'a> Gen for AssignmentTargetPropertyIdentifier<'a> { - fn gen(&self, p: &mut Formatter) { - self.binding.gen(p); - if let Some(expr) = &self.init { - p.print_space(); - p.print_equal(); - p.print_space(); - expr.gen(p); - } - } -} - -impl<'a> Gen for AssignmentTargetPropertyProperty<'a> { - fn gen(&self, p: &mut Formatter) { - match &self.name { - PropertyKey::Identifier(ident) => { - ident.gen(p); - } - PropertyKey::PrivateIdentifier(ident) => { - ident.gen(p); - } - PropertyKey::Expression(expr) => { - p.print(b'['); - expr.gen(p); - p.print(b']'); - } - } - p.print_colon(); - p.print_space(); - self.binding.gen(p); - } -} - -impl<'a> Gen for SequenceExpression<'a> { - fn gen(&self, p: &mut Formatter) { - p.print_list(&self.expressions); - } -} - -impl<'a> Gen for ParenthesizedExpression<'a> { - fn gen(&self, p: &mut Formatter) { - p.print(b'('); - self.expression.gen(p); - p.print(b')'); - } -} - -impl<'a> Gen for ImportExpression<'a> { - fn gen(&self, p: &mut Formatter) { - p.print_str(b"import("); - self.source.gen(p); - if !self.arguments.is_empty() { - p.print_comma(); - p.print_space(); - p.print_list(&self.arguments); - } - p.print(b')'); - } -} - -impl<'a> Gen for TemplateLiteral<'a> { - fn gen(&self, p: &mut Formatter) { - p.print(b'`'); - let mut expressions = self.expressions.iter(); - - for quasi in &self.quasis { - p.print_str(quasi.value.raw.as_bytes()); - - if let Some(expr) = expressions.next() { - p.print_str(b"${"); - expr.gen(p); - p.print(b'}'); - } - } - - p.print(b'`'); - } -} - -impl<'a> Gen for TaggedTemplateExpression<'a> { - fn gen(&self, p: &mut Formatter) { - self.tag.gen(p); - self.quasi.gen(p); - } -} - -impl Gen for Super { - fn gen(&self, p: &mut Formatter) { - p.print_str(b"super"); - } -} - -impl<'a> Gen for AwaitExpression<'a> { - fn gen(&self, p: &mut Formatter) { - p.print_str(b"await "); - self.argument.gen(p); - } -} - -impl<'a> Gen for ChainExpression<'a> { - fn gen(&self, p: &mut Formatter) { - match &self.expression { - ChainElement::CallExpression(expr) => expr.gen(p), - ChainElement::MemberExpression(expr) => expr.gen(p), - } - } -} - -impl<'a> Gen for NewExpression<'a> { - fn gen(&self, p: &mut Formatter) { - p.print_str(b"new "); - self.callee.gen(p); - p.print(b'('); - p.print_list(&self.arguments); - p.print(b')'); - } -} - -impl Gen for MetaProperty { - fn gen(&self, p: &mut Formatter) { - self.meta.gen(p); - p.print(b'.'); - self.property.gen(p); - } -} - -impl<'a> Gen for Class<'a> { - fn gen(&self, p: &mut Formatter) { - p.print_str(b"class"); - if let Some(id) = &self.id { - p.print_space(); - id.gen(p); - } - if let Some(super_class) = self.super_class.as_ref() { - p.print_str(b" extends "); - super_class.gen(p); - } - p.print_space(); - p.print(b'{'); - p.print_newline(); - p.indent(); - for item in &self.body.body { - p.print_semicolon_if_needed(); - p.print_indent(); - item.gen(p); - if matches!( - item, - ClassElement::PropertyDefinition(_) | ClassElement::AccessorProperty(_) - ) { - p.print_semicolon_after_statement(); - } else { - p.print_newline(); - } - } - p.needs_semicolon = false; - p.dedent(); - p.print_indent(); - p.print(b'}'); - } -} - -impl<'a> Gen for ClassElement<'a> { - fn gen(&self, p: &mut Formatter) { - match self { - Self::StaticBlock(elem) => elem.gen(p), - Self::MethodDefinition(elem) => elem.gen(p), - Self::PropertyDefinition(elem) => elem.gen(p), - Self::AccessorProperty(elem) => elem.gen(p), - Self::TSAbstractMethodDefinition(_) - | Self::TSAbstractPropertyDefinition(_) - | Self::TSIndexSignature(_) => {} - } - } -} - -impl Gen for JSXIdentifier { - fn gen(&self, p: &mut Formatter) { - p.print_str(self.name.as_bytes()); - } -} - -impl<'a> Gen for JSXMemberExpressionObject<'a> { - fn gen(&self, p: &mut Formatter) { - match self { - Self::Identifier(ident) => ident.gen(p), - Self::MemberExpression(member_expr) => member_expr.gen(p), - } - } -} - -impl<'a> Gen for JSXMemberExpression<'a> { - fn gen(&self, p: &mut Formatter) { - self.object.gen(p); - p.print(b'.'); - self.property.gen(p); - } -} - -impl<'a> Gen for JSXElementName<'a> { - fn gen(&self, p: &mut Formatter) { - match self { - Self::Identifier(identifier) => identifier.gen(p), - Self::NamespacedName(namespaced_name) => namespaced_name.gen(p), - Self::MemberExpression(member_expr) => member_expr.gen(p), - } - } -} - -impl Gen for JSXNamespacedName { - fn gen(&self, p: &mut Formatter) { - self.namespace.gen(p); - p.print(b'.'); - self.property.gen(p); - } -} - -impl<'a> Gen for JSXAttributeName<'a> { - fn gen(&self, p: &mut Formatter) { - match self { - Self::Identifier(ident) => ident.gen(p), - Self::NamespacedName(namespaced_name) => namespaced_name.gen(p), - } - } -} - -impl<'a> Gen for JSXAttribute<'a> { - fn gen(&self, p: &mut Formatter) { - self.name.gen(p); - p.print(b'='); - if let Some(value) = &self.value { - value.gen(p); - } - } -} - -impl Gen for JSXEmptyExpression { - fn gen(&self, _: &mut Formatter) {} -} - -impl<'a> Gen for JSXExpression<'a> { - fn gen(&self, p: &mut Formatter) { - match self { - Self::Expression(expr) => expr.gen(p), - Self::EmptyExpression(expr) => expr.gen(p), - } - } -} - -impl<'a> Gen for JSXExpressionContainer<'a> { - fn gen(&self, p: &mut Formatter) { - p.print(b'{'); - self.expression.gen(p); - p.print(b'}'); - } -} - -impl<'a> Gen for JSXAttributeValue<'a> { - fn gen(&self, p: &mut Formatter) { - match self { - Self::Fragment(fragment) => fragment.gen(p), - Self::Element(el) => el.gen(p), - Self::StringLiteral(lit) => lit.gen(p), - Self::ExpressionContainer(expr_container) => expr_container.gen(p), - } - } -} - -impl<'a> Gen for JSXSpreadAttribute<'a> { - fn gen(&self, p: &mut Formatter) { - self.argument.gen(p); - } -} - -impl<'a> Gen for JSXAttributeItem<'a> { - fn gen(&self, p: &mut Formatter) { - match self { - Self::Attribute(attr) => attr.gen(p), - Self::SpreadAttribute(spread_attr) => spread_attr.gen(p), - } - } -} - -impl<'a> Gen for JSXOpeningElement<'a> { - fn gen(&self, p: &mut Formatter) { - p.print_str(b"<"); - self.name.gen(p); - for attr in &self.attributes { - attr.gen(p); - } - if self.self_closing { - p.print_space(); - p.print_str(b"/>"); - } else { - p.print(b'>'); - } - } -} - -impl<'a> Gen for JSXClosingElement<'a> { - fn gen(&self, p: &mut Formatter) { - p.print_str(b"'); - } -} - -impl<'a> Gen for JSXElement<'a> { - fn gen(&self, p: &mut Formatter) { - self.opening_element.gen(p); - for child in &self.children { - child.gen(p); - } - if let Some(closing_element) = &self.closing_element { - closing_element.gen(p); - } - } -} - -impl Gen for JSXOpeningFragment { - fn gen(&self, p: &mut Formatter) { - p.print_str(b"<>"); - } -} - -impl Gen for JSXClosingFragment { - fn gen(&self, p: &mut Formatter) { - p.print_str(b""); - } -} - -impl Gen for JSXText { - fn gen(&self, p: &mut Formatter) { - p.print_str(self.value.as_bytes()); - } -} - -impl<'a> Gen for JSXSpreadChild<'a> { - fn gen(&self, p: &mut Formatter) { - p.print_str(b"..."); - self.expression.gen(p); - } -} - -impl<'a> Gen for JSXChild<'a> { - fn gen(&self, p: &mut Formatter) { - match self { - Self::Fragment(fragment) => fragment.gen(p), - Self::Element(el) => el.gen(p), - Self::Spread(spread) => spread.expression.gen(p), - Self::ExpressionContainer(expr_container) => expr_container.gen(p), - Self::Text(text) => text.gen(p), - } - } -} - -impl<'a> Gen for JSXFragment<'a> { - fn gen(&self, p: &mut Formatter) { - self.opening_fragment.gen(p); - for child in &self.children { - child.gen(p); - } - self.closing_fragment.gen(p); - } -} - -impl<'a> Gen for StaticBlock<'a> { - fn gen(&self, p: &mut Formatter) { - p.print_str(b"static"); - p.print_space(); - p.print(b'{'); - p.print_newline(); - p.indent(); - for stmt in &self.body { - p.print_semicolon_if_needed(); - stmt.gen(p); - } - p.dedent(); - p.needs_semicolon = false; - p.print_indent(); - p.print(b'}'); - } -} - -impl<'a> Gen for MethodDefinition<'a> { - fn gen(&self, p: &mut Formatter) { - if self.r#static { - p.print_str(b"static "); - } - - match &self.kind { - MethodDefinitionKind::Constructor | MethodDefinitionKind::Method => {} - MethodDefinitionKind::Get => p.print_str(b"get "), - MethodDefinitionKind::Set => p.print_str(b"set "), - } - - if self.value.r#async { - p.print_str(b"async "); - } - - if self.value.generator { - p.print_str(b"*"); - } - - if self.computed { - p.print(b'['); - } - self.key.gen(p); - if self.computed { - p.print(b']'); - } - p.print(b'('); - self.value.params.gen(p); - p.print(b')'); - p.print_space(); - if let Some(body) = &self.value.body { - body.gen(p); - } - } -} - -impl<'a> Gen for PropertyDefinition<'a> { - fn gen(&self, p: &mut Formatter) { - if self.r#static { - p.print_str(b"static "); - } - if self.computed { - p.print(b'['); - } - self.key.gen(p); - if self.computed { - p.print(b']'); - } - if let Some(value) = &self.value { - p.print_space(); - p.print_equal(); - p.print_space(); - value.gen(p); - } - } -} - -impl<'a> Gen for AccessorProperty<'a> { - fn gen(&self, p: &mut Formatter) { - if self.r#static { - p.print_str(b"static "); - } - p.print_str(b"accessor "); - if self.computed { - p.print(b'['); - } - self.key.gen(p); - if self.computed { - p.print(b']'); - } - if let Some(value) = &self.value { - p.print_space(); - p.print_equal(); - p.print_space(); - value.gen(p); - } - } -} - -impl Gen for PrivateIdentifier { - fn gen(&self, p: &mut Formatter) { - p.print(b'#'); - p.print_str(self.name.as_bytes()); - } -} - -impl<'a> Gen for BindingPattern<'a> { - fn gen(&self, p: &mut Formatter) { - match &self.kind { - BindingPatternKind::BindingIdentifier(ident) => ident.gen(p), - BindingPatternKind::ObjectPattern(pattern) => pattern.gen(p), - BindingPatternKind::ArrayPattern(pattern) => pattern.gen(p), - BindingPatternKind::AssignmentPattern(pattern) => pattern.gen(p), - } - } -} - -impl<'a> Gen for ObjectPattern<'a> { - fn gen(&self, p: &mut Formatter) { - p.print(b'{'); - p.print_space(); - p.print_list(&self.properties); - if let Some(rest) = &self.rest { - if !self.properties.is_empty() { - p.print_comma(); - } - rest.gen(p); - } - p.print_space(); - p.print(b'}'); - } -} - -impl<'a> Gen for BindingProperty<'a> { - fn gen(&self, p: &mut Formatter) { - if self.computed { - p.print(b'['); - } - self.key.gen(p); - if self.computed { - p.print(b']'); - } - p.print(b':'); - p.print_space(); - self.value.gen(p); - } -} - -impl<'a> Gen for RestElement<'a> { - fn gen(&self, p: &mut Formatter) { - p.print_ellipsis(); - self.argument.gen(p); - } -} - -impl<'a> Gen for ArrayPattern<'a> { - fn gen(&self, p: &mut Formatter) { - p.print(b'['); - for (index, item) in self.elements.iter().enumerate() { - if index != 0 { - p.print_comma(); - } - if let Some(item) = item { - item.gen(p); - } - if index == self.elements.len() - 1 && (item.is_none() || self.rest.is_some()) { - p.print_comma(); - } - } - if let Some(rest) = &self.rest { - rest.gen(p); - } - p.print(b']'); - } -} - -impl<'a> Gen for AssignmentPattern<'a> { - fn gen(&self, p: &mut Formatter) { - self.left.gen(p); - p.print_space(); - p.print_equal(); - p.print_space(); - self.right.gen(p); - } -} diff --git a/crates/oxc_formatter/src/lib.rs b/crates/oxc_formatter/src/lib.rs deleted file mode 100644 index b07a06340e97c..0000000000000 --- a/crates/oxc_formatter/src/lib.rs +++ /dev/null @@ -1,323 +0,0 @@ -//! Prettier -//! -//! This crate is intended to be [prettier](https://prettier.io). -//! Please use the `oxc_codegen ` for code generation. - -mod gen; - -#[allow(clippy::wildcard_imports)] -use oxc_ast::ast::*; - -pub use crate::gen::Gen; - -#[derive(Debug, PartialEq, Eq, Clone)] -/// @see [prettier](https://prettier.io/docs/en/options.html#end-of-line) -pub enum EndOfLine { - /// Line Feed only (`\n`), common on Linux and macOS as well as inside git repos - LF, - /// Carriage Return + Line Feed characters (`\r\n`), common on Windows - CRLF, - /// Carriage Return character only (`\r`), used very rarely - CR, - /// Maintain existing line endings (mixed values within one file are normalised by looking at what’s used after the first line) - Auto(String), -} - -impl EndOfLine { - pub fn get_final_end_of_line(&self) -> FinalEndOfLine { - match self { - Self::Auto(raw_input) => Self::auto_detect_end_of_line(raw_input), - Self::LF => FinalEndOfLine::LF, - Self::CRLF => FinalEndOfLine::CRLF, - Self::CR => FinalEndOfLine::CR, - } - } - - pub fn auto_detect_end_of_line(raw_input_text: &str) -> FinalEndOfLine { - let first_line_feed_pos = raw_input_text.chars().position(|ch| ch == '\n'); - first_line_feed_pos.map_or(FinalEndOfLine::CR, |first_line_feed_pos| { - let char_before_line_feed_pos = first_line_feed_pos.saturating_sub(1); - let char_before_line_feed = raw_input_text.chars().nth(char_before_line_feed_pos); - match char_before_line_feed { - Some('\r') => FinalEndOfLine::CRLF, - _ => FinalEndOfLine::LF, - } - }) - } -} - -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -pub enum FinalEndOfLine { - LF, - CRLF, - CR, -} - -#[derive(Debug, Clone)] -pub struct FormatterOptions { - pub indentation: u8, - // - pub single_quote: bool, - pub end_of_line: EndOfLine, -} - -impl Default for FormatterOptions { - fn default() -> Self { - Self { indentation: 4, single_quote: false, end_of_line: EndOfLine::LF } - } -} - -#[derive(Debug)] -/// processed and reserved for internal use -pub struct InnerOptions { - pub indentation: u8, - pub end_of_line: FinalEndOfLine, - pub single_quote: bool, -} - -impl From for InnerOptions { - fn from(options: FormatterOptions) -> Self { - Self { - indentation: options.indentation, - single_quote: options.single_quote, - end_of_line: options.end_of_line.get_final_end_of_line(), - } - } -} - -pub struct Formatter { - options: InnerOptions, - - /// Output Code - code: Vec, - - /// Current indentation tracking - indentation: u8, - - // states - needs_semicolon: bool, - - // Quote property with double quotes - quote_property_with_double_quotes: bool, -} - -#[derive(Debug, Clone, Copy)] -pub enum Separator { - Comma, - Semicolon, - None, -} - -/// Codegen interface for pretty print or minification -impl Formatter { - pub fn new(source_len: usize, options: FormatterOptions) -> Self { - Self { - options: options.into(), - code: Vec::with_capacity(source_len), - indentation: 0, - needs_semicolon: false, - quote_property_with_double_quotes: false, - } - } - - pub fn build(mut self, program: &Program<'_>) -> String { - program.gen(&mut self); - self.into_code() - } - - #[inline] - pub fn into_code(self) -> String { - // SAFETY: criteria of `from_utf8_unchecked`.are met. - unsafe { String::from_utf8_unchecked(self.code) } - } - - pub fn code(&self) -> &Vec { - &self.code - } - - /// Push a single character into the buffer - #[inline] - pub fn print(&mut self, ch: u8) { - self.code.push(ch); - } - - /// Push a string into the buffer - #[inline] - pub fn print_str(&mut self, s: &[u8]) { - self.code.extend_from_slice(s); - } - - #[inline] - pub fn print_space(&mut self) { - self.code.push(b' '); - } - - #[inline] - pub fn print_newline(&mut self) { - match self.options.end_of_line { - FinalEndOfLine::LF => { - self.code.push(b'\n'); - } - FinalEndOfLine::CRLF => { - self.code.push(b'\r'); - self.code.push(b'\n'); - } - FinalEndOfLine::CR => { - self.code.push(b'\r'); - } - } - } - - #[inline] - pub fn indent(&mut self) { - self.indentation += self.options.indentation; - } - - #[inline] - pub fn dedent(&mut self) { - self.indentation -= self.options.indentation; - } - - #[inline] - pub fn print_semicolon(&mut self) { - self.print(b';'); - } - - #[inline] - pub fn print_comma(&mut self) { - self.print(b','); - } - - fn print_semicolon_after_statement(&mut self) { - self.print_semicolon(); - self.print_newline(); - } - - fn print_semicolon_if_needed(&mut self) { - if self.needs_semicolon { - self.print_semicolon(); - self.needs_semicolon = false; - } - } - - #[inline] - pub fn print_ellipsis(&mut self) { - self.print_str(b"..."); - } - - #[inline] - pub fn print_colon(&mut self) { - self.print(b':'); - } - - #[inline] - pub fn print_equal(&mut self) { - self.print(b'='); - } - - #[inline] - pub fn print_quote(&mut self) { - self.print(if self.options.single_quote { b'\'' } else { b'"' }); - } - - pub fn print_indent(&mut self) { - for _ in 0..self.indentation { - self.print(b' '); - } - } - - #[inline] - pub fn print_sequence(&mut self, items: &[T], separator: Separator) { - let len = items.len(); - for (index, item) in items.iter().enumerate() { - item.gen(self); - match separator { - Separator::Semicolon => self.print_semicolon(), - Separator::Comma => self.print(b','), - Separator::None => {} - } - if index != len - 1 { - self.print_newline(); - } - } - } - - #[inline] - pub fn print_body(&mut self, stmt: &Statement<'_>) { - if let Statement::BlockStatement(block) = stmt { - self.print_space(); - self.print_block1(block); - self.print_newline(); - } else { - self.print_newline(); - self.indent(); - stmt.gen(self); - self.dedent(); - } - } - - #[inline] - pub fn print_block1(&mut self, stmt: &BlockStatement<'_>) { - self.print(b'{'); - self.print_newline(); - self.indent(); - for item in &stmt.body { - self.print_semicolon_if_needed(); - item.gen(self); - } - self.dedent(); - self.needs_semicolon = false; - self.print_indent(); - self.print(b'}'); - } - - #[inline] - pub fn print_block(&mut self, items: &[T], separator: Separator) { - self.print(b'{'); - self.indent(); - if !items.is_empty() { - self.print_newline(); - } - self.print_sequence(items, separator); - self.dedent(); - if !items.is_empty() { - self.print_newline(); - } - self.print(b'}'); - } - - #[inline] - pub fn print_list(&mut self, items: &[T]) { - for (index, item) in items.iter().enumerate() { - if index != 0 { - self.print_comma(); - self.print_space(); - } - item.gen(self); - } - } - - pub fn last_char(&self) -> Option<&u8> { - self.code.last() - } -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn auto_detects_lf() { - assert_eq!(FinalEndOfLine::LF, EndOfLine::auto_detect_end_of_line("One\nTwo\nThree")); - } - - #[test] - fn auto_detects_crlf() { - assert_eq!(FinalEndOfLine::CRLF, EndOfLine::auto_detect_end_of_line("One\r\nTwo\r\nThree")); - } - - #[test] - fn auto_detects_cr() { - assert_eq!(FinalEndOfLine::CR, EndOfLine::auto_detect_end_of_line("One\rTwo\rThree")); - } -} diff --git a/crates/oxc_language_server/Cargo.toml b/crates/oxc_language_server/Cargo.toml index 05653454b7838..c00e25b3df42a 100644 --- a/crates/oxc_language_server/Cargo.toml +++ b/crates/oxc_language_server/Cargo.toml @@ -26,7 +26,6 @@ oxc_linter = { workspace = true } oxc_parser = { workspace = true } oxc_semantic = { workspace = true } oxc_span = { workspace = true } -oxc_linter_plugin = { workspace = true } dashmap = { workspace = true } env_logger = { workspace = true } futures = { workspace = true } diff --git a/crates/oxc_linter/Cargo.toml b/crates/oxc_linter/Cargo.toml index 02333400bb5ff..9b0a31ba97002 100644 --- a/crates/oxc_linter/Cargo.toml +++ b/crates/oxc_linter/Cargo.toml @@ -27,7 +27,7 @@ oxc_diagnostics = { workspace = true } oxc_macros = { workspace = true } oxc_semantic = { workspace = true } oxc_syntax = { workspace = true } -oxc_formatter = { workspace = true } +oxc_codegen = { workspace = true } oxc_index = { workspace = true } oxc_resolver = { version = "1.2.0" } diff --git a/crates/oxc_linter/src/context.rs b/crates/oxc_linter/src/context.rs index 7683d6f09301e..79a3153e8964a 100644 --- a/crates/oxc_linter/src/context.rs +++ b/crates/oxc_linter/src/context.rs @@ -1,7 +1,7 @@ use std::{cell::RefCell, path::Path, rc::Rc}; +use oxc_codegen::{Codegen, CodegenOptions}; use oxc_diagnostics::Error; -use oxc_formatter::{Formatter, FormatterOptions}; use oxc_semantic::{AstNodes, JSDocComment, ScopeTree, Semantic, SymbolTable}; use oxc_span::SourceType; @@ -119,8 +119,8 @@ impl<'a> LintContext<'a> { } #[allow(clippy::unused_self)] - pub fn formatter(&self) -> Formatter { - Formatter::new(0, FormatterOptions::default()) + pub fn codegen(&self) -> Codegen { + Codegen::::new(0, CodegenOptions) } /* JSDoc */ 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 f039b265e0e41..7595737ea3a36 100644 --- a/crates/oxc_linter/src/rules/eslint/no_unsafe_negation.rs +++ b/crates/oxc_linter/src/rules/eslint/no_unsafe_negation.rs @@ -6,7 +6,6 @@ use oxc_diagnostics::{ miette::{self, Diagnostic}, thiserror::{self, Error}, }; -use oxc_formatter::Gen; use oxc_macros::declare_oxc_lint; use oxc_span::{GetSpan, Span}; use oxc_syntax::operator::{BinaryOperator, UnaryOperator}; @@ -83,21 +82,22 @@ impl NoUnsafeNegation { /// Precondition: /// expr.left is `UnaryExpression` whose operator is '!' fn report_with_fix(expr: &BinaryExpression, ctx: &LintContext<'_>) { + use oxc_codegen::{Context, Gen}; // Diagnostic points at the unexpected negation let diagnostic = NoUnsafeNegationDiagnostic(expr.operator.as_str(), expr.left.span()); let fix_producer = || { // modify `!a instance of B` to `!(a instanceof B)` let modified_code = { - let mut formatter = ctx.formatter(); - formatter.print(b'!'); + let mut codegen = ctx.codegen(); + codegen.print(b'!'); let Expression::UnaryExpression(left) = &expr.left else { unreachable!() }; - formatter.print(b'('); - left.argument.gen(&mut formatter); - expr.operator.gen(&mut formatter); - expr.right.gen(&mut formatter); - formatter.print(b')'); - formatter.into_code() + codegen.print(b'('); + codegen.print_expression(&left.argument); + expr.operator.gen(&mut codegen, Context::default()); + codegen.print_expression(&expr.right); + codegen.print(b')'); + codegen.into_code() }; Fix::new(modified_code, expr.span) }; diff --git a/crates/oxc_linter/src/rules/jest/prefer_todo.rs b/crates/oxc_linter/src/rules/jest/prefer_todo.rs index abb92d837c609..721c734d2980a 100644 --- a/crates/oxc_linter/src/rules/jest/prefer_todo.rs +++ b/crates/oxc_linter/src/rules/jest/prefer_todo.rs @@ -147,7 +147,7 @@ fn get_fix_content<'a>(expr: &'a CallExpression<'a>) -> (&'a str, Span) { } fn build_code(expr: &CallExpression, ctx: &LintContext) -> (String, Span) { - let mut formatter = ctx.formatter(); + let mut formatter = ctx.codegen(); if let Expression::Identifier(ident) = &expr.callee { formatter.print_str(ident.name.as_bytes()); diff --git a/crates/oxc_linter/src/rules/unicorn/no_instanceof_array.rs b/crates/oxc_linter/src/rules/unicorn/no_instanceof_array.rs index ca69e8732140c..b13beda79f804 100644 --- a/crates/oxc_linter/src/rules/unicorn/no_instanceof_array.rs +++ b/crates/oxc_linter/src/rules/unicorn/no_instanceof_array.rs @@ -4,9 +4,8 @@ use oxc_diagnostics::{ miette::{self, Diagnostic}, thiserror::Error, }; -use oxc_formatter::Gen; use oxc_macros::declare_oxc_lint; -use oxc_span::Span; +use oxc_span::{GetSpan, Span}; use oxc_syntax::operator::BinaryOperator; use crate::{context::LintContext, fixer::Fix, rule::Rule, AstNode}; @@ -46,11 +45,11 @@ impl Rule for NoInstanceofArray { Expression::Identifier(identifier) if identifier.name == "Array" => { ctx.diagnostic_with_fix(NoInstanceofArrayDiagnostic(expr.span), || { let modified_code = { - let mut formatter = ctx.formatter(); - formatter.print_str(b"Array.isArray("); - expr.left.gen(&mut formatter); - formatter.print(b')'); - formatter.into_code() + let mut codegen = String::new(); + codegen.push_str("Array.isArray("); + codegen.push_str(expr.left.span().source_text(ctx.source_text())); + codegen.push(')'); + codegen }; Fix::new(modified_code, expr.span) }); @@ -90,7 +89,7 @@ fn test() { let fix = vec![ ("arr instanceof Array", "Array.isArray(arr)", None), ("[] instanceof Array", "Array.isArray([])", None), - ("[1,2,3] instanceof Array === true", "Array.isArray([1, 2, 3]) === true", None), + ("[1,2,3] instanceof Array === true", "Array.isArray([1,2,3]) === true", None), ("fun.call(1, 2, 3) instanceof Array", "Array.isArray(fun.call(1, 2, 3))", None), ("obj.arr instanceof Array", "Array.isArray(obj.arr)", None), ("foo.bar[2] instanceof Array", "Array.isArray(foo.bar[2])", None), diff --git a/crates/oxc_linter/src/rules/unicorn/no_unnecessary_await.rs b/crates/oxc_linter/src/rules/unicorn/no_unnecessary_await.rs index 038352ad08f7c..c31051b6bdc8b 100644 --- a/crates/oxc_linter/src/rules/unicorn/no_unnecessary_await.rs +++ b/crates/oxc_linter/src/rules/unicorn/no_unnecessary_await.rs @@ -3,9 +3,8 @@ use oxc_diagnostics::{ miette::{self, Diagnostic}, thiserror::Error, }; -use oxc_formatter::Gen; use oxc_macros::declare_oxc_lint; -use oxc_span::Span; +use oxc_span::{GetSpan, Span}; use crate::{context::LintContext, rule::Rule, AstNode, Fix}; @@ -64,9 +63,9 @@ impl Rule for NoUnnecessaryAwait { ctx.diagnostic_with_fix( NoUnnecessaryAwaitDiagnostic(Span::new(expr.span.start, expr.span.start + 5)), || { - let mut formatter = ctx.formatter(); - expr.argument.gen(&mut formatter); - Fix::new(formatter.into_code(), expr.span) + let mut codegen = String::new(); + codegen.push_str(expr.argument.span().source_text(ctx.source_text())); + Fix::new(codegen, expr.span) }, ); }; @@ -158,8 +157,8 @@ fn test() { let fix = vec![ ("await []", "[]", None), ("await (a == b)", "(a == b)", None), - ("+await -1", "+ -1", None), - ("-await +1", "- +1", None), + ("+await -1", "+-1", None), + ("-await +1", "-+1", None), ("await function() {}", "await function() {}", None), // no autofix ("await class {}", "await class {}", None), // no autofix ("+await +1", "+await +1", None), // no autofix diff --git a/crates/oxc_linter/src/rules/unicorn/require_number_to_fixed_digits_argument.rs b/crates/oxc_linter/src/rules/unicorn/require_number_to_fixed_digits_argument.rs index df28609fd6f7a..2725ca4b47a9c 100644 --- a/crates/oxc_linter/src/rules/unicorn/require_number_to_fixed_digits_argument.rs +++ b/crates/oxc_linter/src/rules/unicorn/require_number_to_fixed_digits_argument.rs @@ -64,7 +64,7 @@ impl Rule for RequireNumberToFixedDigitsArgument { RequireNumberToFixedDigitsArgumentDiagnostic(parenthesis_span), || { let modified_code = { - let mut formatter = ctx.formatter(); + let mut formatter = ctx.codegen(); let mut parenthesis_span_without_right_one = parenthesis_span; parenthesis_span_without_right_one.end -= 1; diff --git a/crates/oxc_linter/src/rules/unicorn/switch_case_braces.rs b/crates/oxc_linter/src/rules/unicorn/switch_case_braces.rs index 287fbc93090ff..1c8765c06c858 100644 --- a/crates/oxc_linter/src/rules/unicorn/switch_case_braces.rs +++ b/crates/oxc_linter/src/rules/unicorn/switch_case_braces.rs @@ -3,7 +3,6 @@ use oxc_diagnostics::{ miette::{self, Diagnostic}, thiserror::Error, }; -use oxc_formatter::Gen; use oxc_macros::declare_oxc_lint; use oxc_span::{GetSpan, Span}; @@ -76,20 +75,23 @@ impl Rule for SwitchCaseBraces { }; ctx.diagnostic_with_fix(SwitchCaseBracesDiagnostic(case_body_span), || { + use oxc_codegen::{Context, Gen}; let modified_code = { - let mut formatter = ctx.formatter(); + let mut formatter = ctx.codegen(); if let Some(case_test) = &case.test { formatter.print_str(b"case "); - case_test.gen(&mut formatter); + formatter.print_expression(case_test); } else { formatter.print_str(b"default"); } formatter.print_colon(); - formatter.print_space(); + formatter.print_hard_space(); formatter.print(b'{'); - case.consequent.iter().for_each(|x| x.gen(&mut formatter)); + case.consequent + .iter() + .for_each(|x| x.gen(&mut formatter, Context::default())); formatter.print(b'}'); formatter.into_code() @@ -140,7 +142,7 @@ fn test() { ), ( "switch(something) { case 1: {} case 2: console.log('something'); break;}", - "switch(something) { case 1: case 2: {console.log(\"something\");\nbreak;\n}}", + "switch(something) { case 1: case 2: {console.log('something');\nbreak;\n}}", None, ), ( diff --git a/crates/oxc_wasm/Cargo.toml b/crates/oxc_wasm/Cargo.toml index 60995f4fde39b..af6ae3529c489 100644 --- a/crates/oxc_wasm/Cargo.toml +++ b/crates/oxc_wasm/Cargo.toml @@ -21,7 +21,7 @@ doctest = false default = ["console_error_panic_hook"] [dependencies] -oxc = { workspace = true, features = ["serde", "semantic", "formatter", "transformer", "minifier", "codegen"] } +oxc = { workspace = true, features = ["serde", "semantic", "transformer", "minifier", "codegen"] } oxc_linter = { workspace = true } oxc_prettier = { workspace = true } diff --git a/crates/oxc_wasm/src/lib.rs b/crates/oxc_wasm/src/lib.rs index a8b6f5ea11fcb..9135e03a0ab8c 100644 --- a/crates/oxc_wasm/src/lib.rs +++ b/crates/oxc_wasm/src/lib.rs @@ -6,7 +6,6 @@ use oxc::{ allocator::Allocator, codegen::{Codegen, CodegenOptions}, diagnostics::Error, - formatter::{Formatter, FormatterOptions}, minifier::{CompressOptions, Minifier, MinifierOptions}, parser::{Parser, ParserReturn}, semantic::{ScopeId, Semantic, SemanticBuilder, SemanticBuilderReturn}, @@ -22,7 +21,7 @@ use trustfall::{execute_query, TransparentValue}; use wasm_bindgen::prelude::*; use crate::options::{ - OxcFormatterOptions, OxcLinterOptions, OxcMinifierOptions, OxcParserOptions, OxcRunOptions, + OxcCodegenOptions, OxcLinterOptions, OxcMinifierOptions, OxcParserOptions, OxcRunOptions, OxcTypeCheckingOptions, }; @@ -182,7 +181,7 @@ impl Oxc { run_options: &OxcRunOptions, parser_options: &OxcParserOptions, _linter_options: &OxcLinterOptions, - formatter_options: &OxcFormatterOptions, + _codegen_options: &OxcCodegenOptions, minifier_options: &OxcMinifierOptions, _type_checking_options: &OxcTypeCheckingOptions, ) -> Result<(), serde_wasm_bindgen::Error> { @@ -226,15 +225,6 @@ impl Oxc { self.save_diagnostics(diagnostics); } - if run_options.format() { - let formatter_options = FormatterOptions { - indentation: formatter_options.indentation, - ..Default::default() - }; - let printed = Formatter::new(source_text.len(), formatter_options).build(program); - self.formatted_text = printed; - } - if run_options.prettier_format() { let ret = Parser::new(&allocator, source_text, source_type) .allow_return_outside_function(parser_options.allow_return_outside_function) diff --git a/crates/oxc_wasm/src/options.rs b/crates/oxc_wasm/src/options.rs index 6eb37ceaafcb2..7d87d7dfdac32 100644 --- a/crates/oxc_wasm/src/options.rs +++ b/crates/oxc_wasm/src/options.rs @@ -141,12 +141,12 @@ impl OxcLinterOptions { #[wasm_bindgen] #[derive(Default, Clone, Copy)] -pub struct OxcFormatterOptions { +pub struct OxcCodegenOptions { pub indentation: u8, } #[wasm_bindgen] -impl OxcFormatterOptions { +impl OxcCodegenOptions { #[wasm_bindgen(constructor)] pub fn new() -> Self { Self::default() diff --git a/website/playground/index.js b/website/playground/index.js index 6d018da70274a..601071fce3433 100644 --- a/website/playground/index.js +++ b/website/playground/index.js @@ -34,7 +34,7 @@ import initWasm, { OxcParserOptions, OxcLinterOptions, OxcMinifierOptions, - OxcFormatterOptions, + OxcCodegenOptions, OxcTypeCheckingOptions, graphql_schema_text, } from "@oxc/wasm-web"; @@ -87,7 +87,7 @@ class Playground { runOptions; parserOptions; - formatterOptions; + codegenOptions; linterOptions; minifierOptions; @@ -118,7 +118,7 @@ class Playground { this.oxc = new Oxc(); this.runOptions = new OxcRunOptions(); this.parserOptions = new OxcParserOptions(); - this.formatterOptions = new OxcFormatterOptions(); + this.codegenOptions = new OxcCodegenOptions(); this.linterOptions = new OxcLinterOptions(); this.minifierOptions = new OxcMinifierOptions(); this.typeCheckOptions = new OxcTypeCheckingOptions(); @@ -466,7 +466,7 @@ class Playground { this.runOptions, this.parserOptions, this.linterOptions, - this.formatterOptions, + this.codegenOptions, this.minifierOptions, this.typeCheckOptions );