refactor(cli): add WalkOptions for walk logic (#757)

This commit is contained in:
Boshen 2023-08-18 18:09:11 +08:00 committed by GitHub
parent a9c4fddb6d
commit 772f71f191
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 98 additions and 82 deletions

View file

@ -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<PathBuf>,
#[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<String>,
/// Single file, single path or list of paths
#[bpaf(positional("PATH"), many)]
pub paths: Vec<PathBuf>,
}
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<PathBuf>,
#[bpaf(external(walk_options), hide_usage)]
pub walk: WalkOptions,
#[bpaf(external(filter_value), many, group_help(FILTER_HELP))]
pub filter: Vec<FilterValue>,
@ -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::<Vec<String>>();
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")]);
}
}

View file

@ -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<WalkOptions>,
options: Arc<LintOptions>,
linter: Arc<Linter>,
@ -35,8 +37,12 @@ pub struct IsolatedLintHandler {
pub struct MinifiedFileError(pub PathBuf);
impl IsolatedLintHandler {
pub(super) fn new(options: Arc<LintOptions>, linter: Arc<Linter>) -> Self {
Self { options, linter }
pub(super) fn new(
walk_options: Arc<WalkOptions>,
options: Arc<LintOptions>,
linter: Arc<Linter>,
) -> Self {
Self { walk_options, options, linter }
}
/// # Panics
@ -71,7 +77,7 @@ impl IsolatedLintHandler {
) {
let (tx_path, rx_path) = mpsc::channel::<Box<Path>>();
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;

View file

@ -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<WalkOptions>,
options: Arc<LintOptions>,
linter: Arc<Linter>,
}
@ -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::<Vec<String>>();
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);
}
}

View file

@ -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..) {

View file

@ -1,18 +1,12 @@
use std::path::PathBuf;
#[derive(Debug)]
#[allow(clippy::struct_excessive_bools)]
pub struct LintOptions {
pub paths: Vec<PathBuf>,
/// 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<String>,
pub max_warnings: Option<usize>,
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,
}