Skip to content

Commit aa300f3

Browse files
committed
feat(oxfmt): Collect all files other than JS/TS
1 parent 74e20ff commit aa300f3

File tree

2 files changed

+93
-56
lines changed

2 files changed

+93
-56
lines changed

apps/oxfmt/src/service.rs

Lines changed: 82 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ use oxc_allocator::AllocatorPool;
77
use oxc_diagnostics::{DiagnosticSender, DiagnosticService, OxcDiagnostic};
88
use oxc_formatter::{FormatOptions, Formatter, enable_jsx_source_type, get_parse_options};
99
use oxc_parser::Parser;
10+
use oxc_span::SourceType;
1011

1112
use crate::{command::OutputOptions, walk::WalkEntry};
1213

@@ -62,6 +63,12 @@ impl FormatService {
6263
tx_count: mpsc::Sender<()>,
6364
) {
6465
rx_entry.into_iter().par_bridge().for_each(|entry| {
66+
// TODO: For now, just ignore it
67+
// #[not(feature = "napi")]
68+
if matches!(entry, WalkEntry::Prettier { .. }) {
69+
return;
70+
}
71+
6572
self.process_entry(&entry, tx_error, tx_path);
6673
// Signal that we processed one file (ignore send errors if receiver dropped)
6774
let _ = tx_count.send(());
@@ -72,10 +79,9 @@ impl FormatService {
7279
fn process_entry(&self, entry: &WalkEntry, tx_error: &DiagnosticSender, tx_path: &PathSender) {
7380
let start_time = Instant::now();
7481

75-
let path = &entry.path;
76-
let source_type = enable_jsx_source_type(entry.source_type);
77-
78-
let allocator = self.allocator_pool.get();
82+
let path = match entry {
83+
WalkEntry::OxcFormatter { path, .. } | WalkEntry::Prettier { path } => path,
84+
};
7985
let Ok(source_text) = read_to_string(path) else {
8086
// This happens if `.ts` for MPEG-TS binary is attempted to be formatted
8187
let diagnostics = DiagnosticService::wrap_diagnostics(
@@ -91,63 +97,26 @@ impl FormatService {
9197
return;
9298
};
9399

94-
let ret = Parser::new(&allocator, &source_text, source_type)
95-
.with_options(get_parse_options())
96-
.parse();
97-
if !ret.errors.is_empty() {
98-
let diagnostics = DiagnosticService::wrap_diagnostics(
99-
self.cwd.clone(),
100-
path,
101-
&source_text,
102-
ret.errors,
103-
);
104-
tx_error.send(diagnostics).unwrap();
105-
return;
106-
}
107-
108-
let base_formatter = Formatter::new(&allocator, self.format_options.clone());
109-
110-
#[cfg(feature = "napi")]
111-
let formatted = {
112-
if self.format_options.embedded_language_formatting.is_off() {
113-
base_formatter.format(&ret.program)
114-
} else {
115-
let embedded_formatter = self
116-
.external_formatter
117-
.as_ref()
118-
.expect("`external_formatter` must exist when `napi` feature is enabled")
119-
.to_embedded_formatter();
120-
base_formatter.format_with_embedded(&ret.program, embedded_formatter)
100+
let format_result = match entry {
101+
WalkEntry::OxcFormatter { path, source_type } => {
102+
self.format_by_oxc_formatter(path, &source_text, *source_type)
121103
}
104+
WalkEntry::Prettier { path } => self.format_by_prettier(path, &source_text),
122105
};
123-
#[cfg(not(feature = "napi"))]
124-
let formatted = base_formatter.format(&ret.program);
125-
126-
let code = match formatted.print() {
127-
Ok(printed) => printed.into_code(),
128-
Err(err) => {
106+
let code = match format_result {
107+
Ok(code) => code,
108+
Err(diagnostics) => {
129109
let diagnostics = DiagnosticService::wrap_diagnostics(
130110
self.cwd.clone(),
131111
path,
132112
&source_text,
133-
vec![OxcDiagnostic::error(format!(
134-
"Failed to print formatted code: {}\n{err}",
135-
path.display()
136-
))],
113+
diagnostics,
137114
);
138115
tx_error.send(diagnostics).unwrap();
139116
return;
140117
}
141118
};
142119

143-
#[cfg(feature = "detect_code_removal")]
144-
{
145-
if let Some(diff) = oxc_formatter::detect_code_removal(&source_text, &code, source_type)
146-
{
147-
unreachable!("Code removal detected in `{}`:\n{diff}", path.to_string_lossy());
148-
}
149-
}
150-
151120
let elapsed = start_time.elapsed();
152121
let is_changed = source_text != code;
153122

@@ -182,6 +151,70 @@ impl FormatService {
182151
tx_path.send(output).unwrap();
183152
}
184153
}
154+
155+
fn format_by_oxc_formatter(
156+
&self,
157+
path: &Path,
158+
source_text: &str,
159+
source_type: SourceType,
160+
) -> Result<String, Vec<OxcDiagnostic>> {
161+
let allocator = self.allocator_pool.get();
162+
let source_type = enable_jsx_source_type(source_type);
163+
164+
let ret = Parser::new(&allocator, source_text, source_type)
165+
.with_options(get_parse_options())
166+
.parse();
167+
if !ret.errors.is_empty() {
168+
return Err(ret.errors);
169+
}
170+
171+
let base_formatter = Formatter::new(&allocator, self.format_options.clone());
172+
173+
#[cfg(feature = "napi")]
174+
let formatted = {
175+
if self.format_options.embedded_language_formatting.is_off() {
176+
base_formatter.format(&ret.program)
177+
} else {
178+
let embedded_formatter = self
179+
.external_formatter
180+
.as_ref()
181+
.expect("`external_formatter` must exist when `napi` feature is enabled")
182+
.to_embedded_formatter();
183+
base_formatter.format_with_embedded(&ret.program, embedded_formatter)
184+
}
185+
};
186+
#[cfg(not(feature = "napi"))]
187+
let formatted = base_formatter.format(&ret.program);
188+
189+
let code = match formatted.print() {
190+
Ok(printed) => printed.into_code(),
191+
Err(err) => {
192+
return Err(vec![OxcDiagnostic::error(format!(
193+
"Failed to print formatted code: {}\n{err}",
194+
path.display()
195+
))]);
196+
}
197+
};
198+
199+
#[cfg(feature = "detect_code_removal")]
200+
{
201+
if let Some(diff) = oxc_formatter::detect_code_removal(source_text, &code, source_type)
202+
{
203+
unreachable!("Code removal detected in `{}`:\n{diff}", path.to_string_lossy());
204+
}
205+
}
206+
207+
Ok(code)
208+
}
209+
210+
#[expect(clippy::unused_self)]
211+
fn format_by_prettier(
212+
&self,
213+
_path: &Path,
214+
_source_text: &str,
215+
) -> Result<String, Vec<OxcDiagnostic>> {
216+
unreachable!("Prettier formatting is not implemented yet");
217+
}
185218
}
186219

187220
fn read_to_string(path: &Path) -> io::Result<String> {

apps/oxfmt/src/walk.rs

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -200,9 +200,9 @@ fn load_ignore_paths(cwd: &Path, ignore_paths: &[PathBuf]) -> Vec<PathBuf> {
200200

201201
// ---
202202

203-
pub struct WalkEntry {
204-
pub path: PathBuf,
205-
pub source_type: SourceType,
203+
pub enum WalkEntry {
204+
OxcFormatter { path: PathBuf, source_type: SourceType },
205+
Prettier { path: PathBuf },
206206
}
207207

208208
struct WalkBuilder {
@@ -229,10 +229,14 @@ impl ignore::ParallelVisitor for WalkVisitor {
229229

230230
// Use `is_file()` to detect symlinks to the directory named `.js`
231231
#[expect(clippy::filetype_is_file)]
232-
if file_type.is_file()
233-
&& let Some(source_type) = get_supported_source_type(entry.path())
234-
{
235-
let walk_entry = WalkEntry { path: entry.path().to_path_buf(), source_type };
232+
if file_type.is_file() {
233+
let path = entry.path().to_path_buf();
234+
let walk_entry = if let Some(source_type) = get_supported_source_type(&path) {
235+
WalkEntry::OxcFormatter { path, source_type }
236+
} else {
237+
WalkEntry::Prettier { path }
238+
};
239+
236240
// Send each entry immediately through the channel
237241
// If send fails, the receiver has been dropped, so stop walking
238242
if self.sender.send(walk_entry).is_err() {

0 commit comments

Comments
 (0)