mirror of
https://github.com/danbulant/oxc
synced 2026-05-19 20:28:58 +00:00
refactor(formatter,linter,codegen): remove oxc_formatter (#1968)
closes #1941
This commit is contained in:
parent
b5f4f1eb68
commit
a6717db423
28 changed files with 73 additions and 2345 deletions
1
.github/codecov.yml
vendored
1
.github/codecov.yml
vendored
|
|
@ -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
|
||||
|
|
|
|||
2
.github/workflows/conformance.yml
vendored
2
.github/workflows/conformance.yml
vendored
|
|
@ -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/**'
|
||||
|
|
|
|||
15
Cargo.lock
generated
15
Cargo.lock
generated
|
|
@ -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",
|
||||
|
|
|
|||
|
|
@ -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" }
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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"]
|
||||
|
|
|
|||
|
|
@ -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)]
|
||||
|
|
|
|||
|
|
@ -21,6 +21,7 @@ impl Context {
|
|||
}
|
||||
|
||||
#[inline]
|
||||
#[must_use]
|
||||
pub fn and_in(self, include: bool) -> Self {
|
||||
self.and(Self::In, include)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -129,7 +129,7 @@ impl<'a, const MINIFY: bool> Gen<MINIFY> 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<const MINIFY: bool>(
|
|||
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<MINIFY> 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<MINIFY> 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<MINIFY> 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<MINIFY> 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<MINIFY> 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<MINIFY> 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<MINIFY> 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<MINIFY> 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<MINIFY> 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<MINIFY> 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<const MINIFY: bool> Gen<MINIFY> for JSXEmptyExpression {
|
|||
impl<'a, const MINIFY: bool> Gen<MINIFY> 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<MINIFY> for JSXAttributeValue<'a> {
|
|||
impl<'a, const MINIFY: bool> Gen<MINIFY> 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<const MINIFY: bool> Gen<MINIFY> for JSXText {
|
|||
impl<'a, const MINIFY: bool> Gen<MINIFY> 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<MINIFY> 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),
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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<const MINIFY: bool> Codegen<MINIFY> {
|
|||
}
|
||||
|
||||
/// 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<const MINIFY: bool> Codegen<MINIFY> {
|
|||
}
|
||||
}
|
||||
|
||||
fn print_hard_space(&mut self) {
|
||||
pub fn print_hard_space(&mut self) {
|
||||
self.print(b' ');
|
||||
}
|
||||
|
||||
|
|
@ -197,7 +197,7 @@ impl<const MINIFY: bool> Codegen<MINIFY> {
|
|||
self.print_str(b"...");
|
||||
}
|
||||
|
||||
fn print_colon(&mut self) {
|
||||
pub fn print_colon(&mut self) {
|
||||
self.print(b':');
|
||||
}
|
||||
|
||||
|
|
@ -256,6 +256,10 @@ impl<const MINIFY: bool> Codegen<MINIFY> {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn print_expression(&mut self, expr: &Expression<'_>) {
|
||||
expr.gen_expr(self, Precedence::lowest(), Context::default());
|
||||
}
|
||||
|
||||
fn print_expressions<T: GenExpr<MINIFY>>(
|
||||
&mut self,
|
||||
items: &[T],
|
||||
|
|
|
|||
|
|
@ -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 }
|
||||
|
|
@ -1,3 +0,0 @@
|
|||
# Formatter (Prettier)
|
||||
|
||||
TBD
|
||||
|
|
@ -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}");
|
||||
}
|
||||
File diff suppressed because it is too large
Load diff
|
|
@ -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,
|
||||
// <https://prettier.io/docs/en/options#quotes>
|
||||
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<FormatterOptions> 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<u8>,
|
||||
|
||||
/// 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<u8> {
|
||||
&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<T: Gen>(&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<T: Gen>(&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<T: Gen>(&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"));
|
||||
}
|
||||
}
|
||||
|
|
@ -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 }
|
||||
|
|
|
|||
|
|
@ -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" }
|
||||
|
||||
|
|
|
|||
|
|
@ -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<false> {
|
||||
Codegen::<false>::new(0, CodegenOptions)
|
||||
}
|
||||
|
||||
/* JSDoc */
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
};
|
||||
|
|
|
|||
|
|
@ -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());
|
||||
|
|
|
|||
|
|
@ -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),
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
),
|
||||
(
|
||||
|
|
|
|||
|
|
@ -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 }
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
|
|
|
|||
|
|
@ -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
|
||||
);
|
||||
|
|
|
|||
Loading…
Reference in a new issue