diff --git a/Cargo.lock b/Cargo.lock index 74fa50f27..422ff4eb2 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -826,6 +826,7 @@ dependencies = [ "mimalloc", "oxc_allocator", "oxc_ast", + "oxc_diagnostics", "oxc_linter", "oxc_parser", "oxc_semantic", diff --git a/crates/oxc_cli/Cargo.toml b/crates/oxc_cli/Cargo.toml index cec314a49..9fc4f4ec7 100644 --- a/crates/oxc_cli/Cargo.toml +++ b/crates/oxc_cli/Cargo.toml @@ -16,6 +16,7 @@ jemallocator = { workspace = true } mimalloc = { workspace = true } [dependencies] +oxc_diagnostics = { path = "../oxc_diagnostics" } oxc_allocator = { path = "../oxc_allocator" } oxc_ast = { path = "../oxc_ast" } oxc_parser = { path = "../oxc_parser" } diff --git a/crates/oxc_cli/src/lib.rs b/crates/oxc_cli/src/lib.rs index f33b04732..e14580e25 100644 --- a/crates/oxc_cli/src/lib.rs +++ b/crates/oxc_cli/src/lib.rs @@ -1,11 +1,12 @@ mod command; mod walk; -use std::{fs, path::Path, rc::Rc}; +use std::{fs, path::Path, path::PathBuf, rc::Rc}; pub use command::Command; use oxc_allocator::Allocator; use oxc_ast::SourceType; +use oxc_diagnostics::miette::Report; use oxc_linter::Linter; use oxc_parser::Parser; use oxc_semantic::SemanticBuilder; @@ -14,16 +15,31 @@ use walk::Walk; pub struct Cli; +#[derive(Debug)] +pub struct LintResult { + pub path: PathBuf, + pub diagnostics: Vec, +} + impl Cli { - pub fn lint>(path: P) { + pub fn lint>(path: P) -> Option> { let paths = Walk::new(path).iter().collect::>(); - paths.par_iter().for_each(|path| { - Self::lint_path(path); - }); - println!("Checked {} files", paths.len()); + + if paths.is_empty() { + return None; + } + + let result: Vec = paths + .par_iter() + .map(|path| { + let diagnostics = Self::lint_path(path); + LintResult { path: path.to_path_buf(), diagnostics } + }) + .collect(); + Some(result) } - fn lint_path(path: &Path) { + fn lint_path(path: &Path) -> Vec { let source_text = fs::read_to_string(path).expect("{name} not found"); let allocator = Allocator::default(); let source_type = SourceType::from_path(path).expect("incorrect {path:?}"); @@ -36,9 +52,9 @@ impl Cli { ret.errors }; - for diagnostic in diagnostics { - let diagnostic = diagnostic.with_source_code(source_text.clone()); - println!("{diagnostic:?}"); - } + diagnostics + .into_iter() + .map(|diagnostic| diagnostic.with_source_code(source_text.clone())) + .collect() } } diff --git a/crates/oxc_cli/src/main.rs b/crates/oxc_cli/src/main.rs index e49579ab1..c41caf018 100644 --- a/crates/oxc_cli/src/main.rs +++ b/crates/oxc_cli/src/main.rs @@ -9,15 +9,57 @@ static GLOBAL: jemallocator::Jemalloc = jemallocator::Jemalloc; static GLOBAL: mimalloc::MiMalloc = mimalloc::MiMalloc; use std::path::PathBuf; +use std::process::{ExitCode, Termination}; -use oxc_cli::{Cli, Command}; +use oxc_cli::{Cli, Command, LintResult}; -fn main() { +#[derive(Debug)] +pub enum CliRunResult { + None, + PathNotFound { path: PathBuf }, + LintResult(Vec), +} + +impl Termination for CliRunResult { + fn report(self) -> ExitCode { + match self { + Self::None => ExitCode::from(0), + Self::PathNotFound { path } => { + println!("Path {} does not exist.", path.to_string_lossy()); + ExitCode::from(1) + } + Self::LintResult(results) => { + println!("Checked {} files.", results.len()); + + let has_errors = results.iter().any(|result| !result.diagnostics.is_empty()); + + if has_errors { + for LintResult { path, diagnostics } in results { + println!("File: {path:?}"); + for diagnostic in diagnostics { + println!("{diagnostic:?}"); + } + } + return ExitCode::from(1); + } + ExitCode::from(0) + } + } + } +} + +fn main() -> CliRunResult { match Command::new().build().get_matches().subcommand() { Some(("lint", matches)) => { let path = matches.get_one::("path").unwrap(); - Cli::lint(path); + + if path.canonicalize().is_err() { + return CliRunResult::PathNotFound { path: path.clone() }; + } + + let result = Cli::lint(path); + CliRunResult::LintResult(result.unwrap()) } - _ => unreachable!(), + _ => CliRunResult::None, } }