diff --git a/apps/oxlint/src/lib.rs b/apps/oxlint/src/lib.rs index a97587b249644..b764aed31738b 100644 --- a/apps/oxlint/src/lib.rs +++ b/apps/oxlint/src/lib.rs @@ -1,5 +1,4 @@ -use std::io::BufWriter; - +/// Re-exported external linter types for use in `napi/oxlint`. pub use oxc_linter::{ ExternalLinter, ExternalLinterLintFileCb, ExternalLinterLoadPluginCb, LintFileResult, PluginLoadResult, @@ -10,98 +9,20 @@ mod js_plugins; mod lint; mod output_formatter; mod result; +mod run; mod walk; #[cfg(test)] mod tester; -use lint::LintRunner; -use result::CliRunResult; - /// Re-exported CLI-related items for use in `tasks/website`. pub mod cli { pub use super::{command::*, lint::LintRunner, result::CliRunResult}; } +/// Main export for binary +pub use run::lint; + #[cfg(all(feature = "allocator", not(miri), not(target_family = "wasm")))] #[global_allocator] static GLOBAL: mimalloc_safe::MiMalloc = mimalloc_safe::MiMalloc; - -/// Run the linter. -pub fn lint(mut external_linter: Option) -> CliRunResult { - init_tracing(); - init_miette(); - - let mut args = std::env::args_os(); - // If first arg is `node`, also skip script path (`node script.js ...`). - // Otherwise, just skip first arg (`oxlint ...`). - if args.next().is_some_and(|arg| arg == "node") { - args.next(); - } - let args = args.collect::>(); - - let cmd = crate::cli::lint_command(); - let command = match cmd.run_inner(&*args) { - Ok(cmd) => cmd, - Err(e) => { - e.print_message(100); - return if e.exit_code() == 0 { - CliRunResult::LintSucceeded - } else { - CliRunResult::InvalidOptionConfig - }; - } - }; - - command.handle_threads(); - - #[expect(clippy::print_stderr)] - if command.experimental_js_plugins { - // If no `ExternalLinter`, this function was not called by `napi/oxlint` - if external_linter.is_none() { - eprintln!("ERROR: JS plugins are not supported at present"); - return CliRunResult::InvalidOptionConfig; - } - - // Exit early if not 64-bit little-endian, to avoid a panic later on when trying to create - // a fixed-size allocator for raw transfer - if cfg!(not(all(target_pointer_width = "64", target_endian = "little"))) { - eprintln!( - "ERROR: JS plugins are only supported on 64-bit little-endian platforms at present" - ); - return CliRunResult::InvalidOptionConfig; - } - } else { - external_linter = None; - } - - // stdio is blocked by LineWriter, use a BufWriter to reduce syscalls. - // See `https://github.com/rust-lang/rust/issues/60673`. - let mut stdout = BufWriter::new(std::io::stdout()); - - LintRunner::new(command, external_linter).run(&mut stdout) -} - -/// Initialize the data which relies on `is_atty` system calls so they don't block subsequent threads. -fn init_miette() { - miette::set_hook(Box::new(|_| Box::new(miette::MietteHandlerOpts::new().build()))).unwrap(); -} - -/// To debug `oxc_resolver`: -/// `OXC_LOG=oxc_resolver oxlint --import-plugin` -fn init_tracing() { - use tracing_subscriber::{filter::Targets, prelude::*}; - - // Usage without the `regex` feature. - // - tracing_subscriber::registry() - .with(std::env::var("OXC_LOG").map_or_else( - |_| Targets::new(), - |env_var| { - use std::str::FromStr; - Targets::from_str(&env_var).unwrap() - }, - )) - .with(tracing_subscriber::fmt::layer()) - .init(); -} diff --git a/apps/oxlint/src/run.rs b/apps/oxlint/src/run.rs new file mode 100644 index 0000000000000..65cc1592907a6 --- /dev/null +++ b/apps/oxlint/src/run.rs @@ -0,0 +1,84 @@ +use std::io::BufWriter; + +use oxc_linter::ExternalLinter; + +use crate::{lint::LintRunner, result::CliRunResult}; + +/// Run the linter. +pub fn lint(mut external_linter: Option) -> CliRunResult { + init_tracing(); + init_miette(); + + let mut args = std::env::args_os(); + // If first arg is `node`, also skip script path (`node script.js ...`). + // Otherwise, just skip first arg (`oxlint ...`). + if args.next().is_some_and(|arg| arg == "node") { + args.next(); + } + let args = args.collect::>(); + + let cmd = crate::cli::lint_command(); + let command = match cmd.run_inner(&*args) { + Ok(cmd) => cmd, + Err(e) => { + e.print_message(100); + return if e.exit_code() == 0 { + CliRunResult::LintSucceeded + } else { + CliRunResult::InvalidOptionConfig + }; + } + }; + + command.handle_threads(); + + #[expect(clippy::print_stderr)] + if command.experimental_js_plugins { + // If no `ExternalLinter`, this function was not called by `napi/oxlint` + if external_linter.is_none() { + eprintln!("ERROR: JS plugins are not supported at present"); + return CliRunResult::InvalidOptionConfig; + } + + // Exit early if not 64-bit little-endian, to avoid a panic later on when trying to create + // a fixed-size allocator for raw transfer + if cfg!(not(all(target_pointer_width = "64", target_endian = "little"))) { + eprintln!( + "ERROR: JS plugins are only supported on 64-bit little-endian platforms at present" + ); + return CliRunResult::InvalidOptionConfig; + } + } else { + external_linter = None; + } + + // stdio is blocked by LineWriter, use a BufWriter to reduce syscalls. + // See `https://github.com/rust-lang/rust/issues/60673`. + let mut stdout = BufWriter::new(std::io::stdout()); + + LintRunner::new(command, external_linter).run(&mut stdout) +} + +/// Initialize the data which relies on `is_atty` system calls so they don't block subsequent threads. +fn init_miette() { + miette::set_hook(Box::new(|_| Box::new(miette::MietteHandlerOpts::new().build()))).unwrap(); +} + +/// To debug `oxc_resolver`: +/// `OXC_LOG=oxc_resolver oxlint --import-plugin` +fn init_tracing() { + use tracing_subscriber::{filter::Targets, prelude::*}; + + // Usage without the `regex` feature. + // + tracing_subscriber::registry() + .with(std::env::var("OXC_LOG").map_or_else( + |_| Targets::new(), + |env_var| { + use std::str::FromStr; + Targets::from_str(&env_var).unwrap() + }, + )) + .with(tracing_subscriber::fmt::layer()) + .init(); +}