diff --git a/apps/oxlint/fixtures/auto_config_detection/.oxlintrc.json b/apps/oxlint/fixtures/auto_config_detection/.oxlintrc.json new file mode 100644 index 0000000000000..a63d73a1442b8 --- /dev/null +++ b/apps/oxlint/fixtures/auto_config_detection/.oxlintrc.json @@ -0,0 +1,5 @@ +{ + "rules": { + "no-debugger": "error" + } +} diff --git a/apps/oxlint/fixtures/auto_config_detection/debugger.js b/apps/oxlint/fixtures/auto_config_detection/debugger.js new file mode 100644 index 0000000000000..eab74692130a6 --- /dev/null +++ b/apps/oxlint/fixtures/auto_config_detection/debugger.js @@ -0,0 +1 @@ +debugger; diff --git a/apps/oxlint/src/command/lint.rs b/apps/oxlint/src/command/lint.rs index f404714428505..e444cb9f623e3 100644 --- a/apps/oxlint/src/command/lint.rs +++ b/apps/oxlint/src/command/lint.rs @@ -62,6 +62,8 @@ pub struct BasicOptions { /// Oxlint configuration file (experimental) /// * only `.json` extension is supported /// * tries to be compatible with the ESLint v8's format + /// + /// If not provided, Oxlint will look for `.oxlintrc.json` in the current working directory. #[bpaf(long, short, argument("./oxlintrc.json"))] pub config: Option, diff --git a/apps/oxlint/src/lint.rs b/apps/oxlint/src/lint.rs index e9524802a8f08..7ced35a4aefdb 100644 --- a/apps/oxlint/src/lint.rs +++ b/apps/oxlint/src/lint.rs @@ -1,4 +1,9 @@ -use std::{env, io::BufWriter, path::PathBuf, time::Instant}; +use std::{ + env, + io::BufWriter, + path::{Path, PathBuf}, + time::Instant, +}; use ignore::gitignore::Gitignore; use oxc_diagnostics::{DiagnosticService, GraphicalReportHandler}; @@ -102,21 +107,13 @@ impl Runner for LintRunner { let number_of_files = paths.len(); - let mut oxlintrc = if let Some(config_path) = basic_options.config.as_ref() { - match Oxlintrc::from_file(config_path) { - Ok(config) => config, - Err(diagnostic) => { - let handler = GraphicalReportHandler::new(); - let mut err = String::new(); - handler.render_report(&mut err, &diagnostic).unwrap(); - return CliRunResult::InvalidOptions { - message: format!("Failed to parse configuration file.\n{err}"), - }; - } - } - } else { - Oxlintrc::default() - }; + let config_search_result = Self::find_oxlint_config(&self.cwd, &basic_options.config); + + if let Err(err) = config_search_result { + return err; + } + + let mut oxlintrc = config_search_result.unwrap(); enable_plugins.apply_overrides(&mut oxlintrc.plugins); @@ -179,6 +176,8 @@ impl Runner for LintRunner { } impl LintRunner { + const DEFAULT_OXLINTRC: &'static str = ".oxlintrc.json"; + #[must_use] pub fn with_cwd(mut self, cwd: PathBuf) -> Self { self.cwd = cwd; @@ -241,6 +240,34 @@ impl LintRunner { Ok(filters) } + + // finds the oxlint config + // when config is provided, but not found, an CliRunResult is returned, else the oxlintrc config file is returned + // when no config is provided, it will search for the default file names in the current working directory + // when no file is found, the default configuration is returned + fn find_oxlint_config(cwd: &Path, config: &Option) -> Result { + if let Some(config_path) = config { + return match Oxlintrc::from_file(config_path) { + Ok(config) => Ok(config), + Err(diagnostic) => { + let handler = GraphicalReportHandler::new(); + let mut err = String::new(); + handler.render_report(&mut err, &diagnostic).unwrap(); + return Err(CliRunResult::InvalidOptions { + message: format!("Failed to parse configuration file.\n{err}"), + }); + } + }; + } + + // no config argument is provided, + // auto detect default config file from current work directory + // or return the default configuration, when no valid file is found + let mut config_path = cwd.to_path_buf(); + config_path.push(Self::DEFAULT_OXLINTRC); + + Oxlintrc::from_file(&config_path).or_else(|_| Ok(Oxlintrc::default())) + } } #[cfg(all(test, not(target_os = "windows")))] @@ -423,6 +450,15 @@ mod test { assert_eq!(result.number_of_errors, 0); } + #[test] + fn oxlint_config_auto_detection() { + let args = &["debugger.js"]; + let result = test_with_cwd("fixtures/auto_config_detection", args); + assert_eq!(result.number_of_files, 1); + assert_eq!(result.number_of_warnings, 0); + assert_eq!(result.number_of_errors, 1); + } + #[test] fn eslintrc_no_undef() { let args = &[ diff --git a/tasks/website/src/linter/snapshots/cli.snap b/tasks/website/src/linter/snapshots/cli.snap index d4184ce620767..e7653edd16d2a 100644 --- a/tasks/website/src/linter/snapshots/cli.snap +++ b/tasks/website/src/linter/snapshots/cli.snap @@ -11,6 +11,8 @@ snapshot_kind: text Oxlint configuration file (experimental) * only `.json` extension is supported * tries to be compatible with the ESLint v8's format + + If not provided, Oxlint will look for `.oxlintrc.json` in the current working directory. - **` --tsconfig`**=_`<./tsconfig.json>`_ — TypeScript `tsconfig.json` path for reading path alias and project references for import plugin