diff --git a/crates/oxc_cli/src/command.rs b/crates/oxc_cli/src/command.rs index 0094cab18..5c8d9c2e9 100644 --- a/crates/oxc_cli/src/command.rs +++ b/crates/oxc_cli/src/command.rs @@ -1,5 +1,5 @@ use bpaf::{any, Bpaf, Parser}; -use std::path::PathBuf; +use std::{ffi::OsString, path::PathBuf}; #[derive(Debug, Clone, Bpaf)] #[bpaf(options)] @@ -63,18 +63,22 @@ pub struct CliOptions { } #[derive(Debug, Clone, Bpaf)] -pub struct IgnoreOptions { +pub struct WalkOptions { /// Disables excluding of files from .eslintignore files #[bpaf(switch)] pub no_ignore: bool, /// Specify the file to use as your .eslintignore - #[bpaf(argument("PATH"), optional)] - pub ignore_path: Option, + #[bpaf(argument("PATH"), fallback(".eslintignore".into()))] + pub ignore_path: OsString, /// Specify patterns of files to ignore (in addition to those in .eslintignore) #[bpaf(argument("PATTERN"), many)] pub ignore_pattern: Vec, + + /// Single file, single path or list of paths + #[bpaf(positional("PATH"), many)] + pub paths: Vec, } static FILTER_HELP: &str = r#" @@ -100,9 +104,6 @@ pub struct LintOptions { #[bpaf(switch)] pub fix: bool, - #[bpaf(external(ignore_options), hide_usage)] - pub ignore: IgnoreOptions, - /// Display the execution time of each lint rule #[bpaf(switch, env("TIMING"), hide_usage)] pub timing: bool, @@ -114,9 +115,8 @@ pub struct LintOptions { #[bpaf(external(cli_options), hide_usage)] pub cli: CliOptions, - /// Single file, single path or list of paths - #[bpaf(positional("PATH"), many)] - pub paths: Vec, + #[bpaf(external(walk_options), hide_usage)] + pub walk: WalkOptions, #[bpaf(external(filter_value), many, group_help(FILTER_HELP))] pub filter: Vec, @@ -168,3 +168,56 @@ pub struct CheckOptions { #[bpaf(positional("PATH"))] pub path: PathBuf, } + +#[cfg(test)] +mod walk_options { + use super::{lint_command, WalkOptions}; + use std::{ffi::OsString, path::PathBuf}; + + fn get_walk_options(arg: &str) -> WalkOptions { + let args = arg.split(' ').map(std::string::ToString::to_string).collect::>(); + lint_command().run_inner(args.as_slice()).unwrap().lint_options.walk + } + + #[test] + fn default() { + let options = get_walk_options("."); + assert_eq!(options.paths, vec![PathBuf::from(".")]); + assert_eq!(options.ignore_path, OsString::from(".eslintignore")); + assert!(!options.no_ignore); + assert!(options.ignore_pattern.is_empty()); + } + + #[test] + fn multiple_paths() { + let options = get_walk_options("foo bar baz"); + assert_eq!( + options.paths, + [PathBuf::from("foo"), PathBuf::from("bar"), PathBuf::from("baz")] + ); + } + + #[test] + fn ignore_path() { + let options = get_walk_options("--ignore-path .xxx foo.js"); + assert_eq!(options.ignore_path, PathBuf::from(".xxx")); + } + + #[test] + fn no_ignore() { + let options = get_walk_options("--no-ignore foo.js"); + assert!(options.no_ignore); + } + + #[test] + fn single_ignore_pattern() { + let options = get_walk_options("--ignore-pattern ./test foo.js"); + assert_eq!(options.ignore_pattern, vec![String::from("./test")]); + } + + #[test] + fn multiple_ignore_pattern() { + let options = get_walk_options("--ignore-pattern ./test --ignore-pattern bar.js foo.js"); + assert_eq!(options.ignore_pattern, vec![String::from("./test"), String::from("bar.js")]); + } +} diff --git a/crates/oxc_cli/src/lint/isolated_handler.rs b/crates/oxc_cli/src/lint/isolated_handler.rs index 27f3a67d6..b861f1201 100644 --- a/crates/oxc_cli/src/lint/isolated_handler.rs +++ b/crates/oxc_cli/src/lint/isolated_handler.rs @@ -21,9 +21,11 @@ use oxc_parser::Parser; use oxc_semantic::SemanticBuilder; use oxc_span::SourceType; -use crate::{CliRunResult, Walk}; +use crate::{CliRunResult, Walk, WalkOptions}; pub struct IsolatedLintHandler { + walk_options: Arc, + options: Arc, linter: Arc, @@ -35,8 +37,12 @@ pub struct IsolatedLintHandler { pub struct MinifiedFileError(pub PathBuf); impl IsolatedLintHandler { - pub(super) fn new(options: Arc, linter: Arc) -> Self { - Self { options, linter } + pub(super) fn new( + walk_options: Arc, + options: Arc, + linter: Arc, + ) -> Self { + Self { walk_options, options, linter } } /// # Panics @@ -71,7 +77,7 @@ impl IsolatedLintHandler { ) { let (tx_path, rx_path) = mpsc::channel::>(); - let walk = Walk::new(&self.options); + let walk = Walk::new(&self.walk_options); let number_of_files = Arc::clone(number_of_files); rayon::spawn(move || { let mut count = 0; diff --git a/crates/oxc_cli/src/lint/mod.rs b/crates/oxc_cli/src/lint/mod.rs index ff05c4354..85278a5dd 100644 --- a/crates/oxc_cli/src/lint/mod.rs +++ b/crates/oxc_cli/src/lint/mod.rs @@ -1,7 +1,6 @@ mod error; mod isolated_handler; -use std::path::PathBuf; use std::{io::BufWriter, sync::Arc, time::Duration}; pub use self::{error::Error, isolated_handler::IsolatedLintHandler}; @@ -11,9 +10,13 @@ use oxc_linter::{AllowWarnDeny, LintOptions, Linter, RuleCategory, RuleEnum, RUL use rustc_hash::FxHashSet; use crate::FilterType; -use crate::{command::LintOptions as CliLintOptions, CliRunResult, Runner}; +use crate::{ + command::{LintOptions as CliLintOptions, WalkOptions}, + CliRunResult, Runner, +}; pub struct LintRunner { + walk_options: Arc, options: Arc, linter: Arc, } @@ -23,11 +26,15 @@ impl Runner for LintRunner { type Options = CliLintOptions; fn new(options: Self::Options) -> Self { - let options = parse_cli_options(options); - let linter = Linter::from_rules(Self::derive_rules(&options)) - .with_fix(options.fix) - .with_print_execution_times(options.print_execution_times); - Self { options: Arc::new(options), linter: Arc::new(linter) } + let lint_options = parse_cli_options(&options); + let linter = Linter::from_rules(Self::derive_rules(&lint_options)) + .with_fix(lint_options.fix) + .with_print_execution_times(lint_options.print_execution_times); + Self { + walk_options: Arc::new(options.walk), + options: Arc::new(lint_options), + linter: Arc::new(linter), + } } fn run(&self) -> CliRunResult { @@ -36,8 +43,12 @@ impl Runner for LintRunner { return CliRunResult::None; } - let result = - IsolatedLintHandler::new(Arc::clone(&self.options), Arc::clone(&self.linter)).run(); + let result = IsolatedLintHandler::new( + Arc::clone(&self.walk_options), + Arc::clone(&self.options), + Arc::clone(&self.linter), + ) + .run(); if self.options.print_execution_times { self.print_execution_times(); @@ -121,16 +132,12 @@ impl LintRunner { } } -fn parse_cli_options(options: CliLintOptions) -> LintOptions { - let rules = get_rules(&options); +fn parse_cli_options(options: &CliLintOptions) -> LintOptions { + let rules = get_rules(options); LintOptions { - paths: options.paths, rules, fix: options.fix, quiet: options.cli.quiet, - ignore_path: options.ignore.ignore_path.unwrap_or_else(|| PathBuf::from(".eslintignore")), - no_ignore: options.ignore.no_ignore, - ignore_pattern: options.ignore.ignore_pattern, max_warnings: options.cli.max_warnings, list_rules: options.rules, print_execution_times: options.timing, @@ -157,38 +164,23 @@ fn get_rules(options: &CliLintOptions) -> Vec<(AllowWarnDeny, String)> { #[cfg(test)] mod test { - use std::path::PathBuf; - use super::{parse_cli_options, AllowWarnDeny, LintOptions}; use crate::lint_command; fn get_lint_options(arg: &str) -> LintOptions { let args = arg.split(' ').map(std::string::ToString::to_string).collect::>(); let options = lint_command().run_inner(args.as_slice()).unwrap(); - parse_cli_options(options.lint_options) + parse_cli_options(&options.lint_options) } #[test] fn default() { let options = get_lint_options("."); - assert_eq!(options.paths, vec![PathBuf::from(".")]); assert!(!options.fix); assert!(!options.quiet); - assert_eq!(options.ignore_path, PathBuf::from(".eslintignore")); - assert!(!options.no_ignore); - assert!(options.ignore_pattern.is_empty()); assert_eq!(options.max_warnings, None); } - #[test] - fn multiple_paths() { - let options = get_lint_options("foo bar baz"); - assert_eq!( - options.paths, - [PathBuf::from("foo"), PathBuf::from("bar"), PathBuf::from("baz")] - ); - } - #[test] fn rules_with_deny_and_allow() { let options = @@ -222,34 +214,9 @@ mod test { assert_eq!(options.max_warnings, Some(10)); } - #[test] - fn ignore_path() { - let options = get_lint_options("--ignore-path .xxx foo.js"); - assert_eq!(options.ignore_path, PathBuf::from(".xxx")); - } - - #[test] - fn no_ignore() { - let options = get_lint_options("--no-ignore foo.js"); - assert!(options.no_ignore); - } - - #[test] - fn single_ignore_pattern() { - let options = get_lint_options("--ignore-pattern ./test foo.js"); - assert_eq!(options.ignore_pattern, vec![String::from("./test")]); - } - - #[test] - fn multiple_ignore_pattern() { - let options = get_lint_options("--ignore-pattern ./test --ignore-pattern bar.js foo.js"); - assert_eq!(options.ignore_pattern, vec![String::from("./test"), String::from("bar.js")]); - } - #[test] fn list_rules_true() { let options = get_lint_options("--rules"); - assert!(options.paths.is_empty()); assert!(options.list_rules); } } diff --git a/crates/oxc_cli/src/walk.rs b/crates/oxc_cli/src/walk.rs index 552c05b57..bc9327a62 100644 --- a/crates/oxc_cli/src/walk.rs +++ b/crates/oxc_cli/src/walk.rs @@ -3,7 +3,7 @@ use std::path::Path; use ignore::{overrides::OverrideBuilder, DirEntry, WalkBuilder}; use oxc_span::VALID_EXTENSIONS; -use oxc_linter::LintOptions; +use crate::WalkOptions; pub struct Walk { inner: ignore::Walk, @@ -11,7 +11,7 @@ pub struct Walk { impl Walk { /// # Panics - pub fn new(options: &LintOptions) -> Self { + pub fn new(options: &WalkOptions) -> Self { let mut inner = WalkBuilder::new(&options.paths[0]); if let Some(paths) = options.paths.get(1..) { diff --git a/crates/oxc_linter/src/options.rs b/crates/oxc_linter/src/options.rs index eacc137b8..b876eeb8f 100644 --- a/crates/oxc_linter/src/options.rs +++ b/crates/oxc_linter/src/options.rs @@ -1,18 +1,12 @@ -use std::path::PathBuf; - #[derive(Debug)] #[allow(clippy::struct_excessive_bools)] pub struct LintOptions { - pub paths: Vec, /// Allow / Deny rules in order. [("allow" / "deny", rule name)] /// Defaults to [("deny", "correctness")] pub rules: Vec<(AllowWarnDeny, String)>, pub list_rules: bool, pub fix: bool, pub quiet: bool, - pub ignore_path: PathBuf, - pub no_ignore: bool, - pub ignore_pattern: Vec, pub max_warnings: Option, pub print_execution_times: bool, } @@ -20,14 +14,10 @@ pub struct LintOptions { impl Default for LintOptions { fn default() -> Self { Self { - paths: vec![], rules: vec![(AllowWarnDeny::Deny, String::from("correctness"))], list_rules: false, fix: false, quiet: false, - ignore_path: PathBuf::default(), - no_ignore: false, - ignore_pattern: vec![], max_warnings: None, print_execution_times: false, }