Skip to content

Commit

Permalink
fix(linter): make overrides globs relative to config path
Browse files Browse the repository at this point in the history
  • Loading branch information
camchenry committed Nov 21, 2024
1 parent 0918e52 commit 1cae468
Show file tree
Hide file tree
Showing 11 changed files with 89 additions and 4 deletions.
19 changes: 19 additions & 0 deletions apps/oxlint/fixtures/overrides/directories-config.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
{
"rules": {
"no-debugger": "off"
},
"overrides": [
{
"files": ["lib/*.{js,ts}", "src/*"],
"rules": {
"no-debugger": "error"
}
},
{
"files": ["**/tests/*"],
"rules": {
"no-debugger": "warn"
}
}
]
}
1 change: 1 addition & 0 deletions apps/oxlint/fixtures/overrides/lib/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
debugger;
1 change: 1 addition & 0 deletions apps/oxlint/fixtures/overrides/lib/tests/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
debugger;
1 change: 1 addition & 0 deletions apps/oxlint/fixtures/overrides/src/oxlint.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
debugger;
1 change: 1 addition & 0 deletions apps/oxlint/fixtures/overrides/src/tests/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
debugger;
9 changes: 9 additions & 0 deletions apps/oxlint/src/lint.rs
Original file line number Diff line number Diff line change
Expand Up @@ -695,4 +695,13 @@ mod test {
assert_eq!(result.number_of_warnings, 0);
assert_eq!(result.number_of_errors, 1);
}

#[test]
fn test_overrides_directories() {
let result =
test(&["-c", "fixtures/overrides/directories-config.json", "fixtures/overrides"]);
assert_eq!(result.number_of_files, 7);
assert_eq!(result.number_of_warnings, 2);
assert_eq!(result.number_of_errors, 2);
}
}
3 changes: 2 additions & 1 deletion crates/oxc_linter/src/builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -94,9 +94,10 @@ impl LinterBuilder {
categories,
rules: oxlintrc_rules,
overrides,
path,
} = oxlintrc;

let config = LintConfig { plugins, settings, env, globals };
let config = LintConfig { plugins, settings, env, globals, path: Some(path) };
let options = LintOptions::default();
let rules =
if start_empty { FxHashSet::default() } else { Self::warn_correctness(plugins) };
Expand Down
19 changes: 18 additions & 1 deletion crates/oxc_linter/src/config/flat.rs
Original file line number Diff line number Diff line change
Expand Up @@ -92,8 +92,24 @@ impl ConfigStore {
let mut overrides_to_apply: Vec<OverrideId> = Vec::new();
let mut hasher = FxBuildHasher.build_hasher();

// Compute the path of the file relative to the configuration file for glob matching. Globs should match
// relative to the location of the configuration file.
// - path: /some/path/like/this/to/file.js
// - config_path: /some/path/like/.oxlintrc.json
// => relative_path: this/to/file.js
// TODO: Handle nested configuration file paths.
let relative_path = if let Some(config_path) = &self.base.config.path {
if let Some(parent) = config_path.parent() {
path.strip_prefix(parent).unwrap_or(path)
} else {
path
}
} else {
path
};

for (id, override_config) in self.overrides.iter_enumerated() {
if override_config.files.is_match(path) {
if override_config.files.is_match(relative_path) {
overrides_to_apply.push(id);
id.hash(&mut hasher);
}
Expand Down Expand Up @@ -285,6 +301,7 @@ mod test {
env: OxlintEnv::default(),
settings: OxlintSettings::default(),
globals: OxlintGlobals::default(),
path: None,
};
let overrides = from_json!([{
"files": ["*.jsx", "*.tsx"],
Expand Down
6 changes: 6 additions & 0 deletions crates/oxc_linter/src/config/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ mod plugins;
mod rules;
mod settings;

use std::path::PathBuf;

pub(crate) use self::flat::ResolvedLinterState;
pub use self::{
env::OxlintEnv,
Expand All @@ -29,6 +31,8 @@ pub(crate) struct LintConfig {
pub(crate) env: OxlintEnv,
/// Enabled or disabled specific global variables.
pub(crate) globals: OxlintGlobals,
/// Absolute path to the configuration file (may be `None` if there is no file).
pub(crate) path: Option<PathBuf>,
}

impl From<Oxlintrc> for LintConfig {
Expand All @@ -38,6 +42,7 @@ impl From<Oxlintrc> for LintConfig {
settings: config.settings,
env: config.env,
globals: config.globals,
path: Some(config.path),
}
}
}
Expand All @@ -58,6 +63,7 @@ mod test {
let fixture_path = env::current_dir().unwrap().join("fixtures/eslint_config.json");
let config = Oxlintrc::from_file(&fixture_path).unwrap();
assert!(!config.rules.is_empty());
assert!(config.path.ends_with("fixtures/eslint_config.json"));
}

#[test]
Expand Down
20 changes: 20 additions & 0 deletions crates/oxc_linter/src/config/overrides.rs
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,26 @@ impl JsonSchema for GlobSet {
}

mod test {
#[test]
fn test_globset() {
use super::*;
use serde_json::{from_value, json};

let config: OxlintOverride = from_value(json!({
"files": ["*.tsx",],
}))
.unwrap();
assert!(config.files.globs.is_match("/some/path/foo.tsx"));
assert!(!config.files.globs.is_match("/some/path/foo.ts"));

let config: OxlintOverride = from_value(json!({
"files": ["lib/*.ts",],
}))
.unwrap();
assert!(config.files.globs.is_match("lib/foo.ts"));
assert!(!config.files.globs.is_match("src/foo.ts"));
}

#[test]
fn test_parsing_plugins() {
use super::*;
Expand Down
13 changes: 11 additions & 2 deletions crates/oxc_linter/src/config/oxlintrc.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use std::path::Path;
use std::path::{Path, PathBuf};

use oxc_diagnostics::OxcDiagnostic;
use schemars::JsonSchema;
Expand Down Expand Up @@ -85,6 +85,9 @@ pub struct Oxlintrc {
/// Add, remove, or otherwise reconfigure rules for specific files or groups of files.
#[serde(skip_serializing_if = "OxlintOverrides::is_empty")]
pub overrides: OxlintOverrides,
/// Absolute path to the configuration file.
#[serde(skip)]
pub path: PathBuf,
}

impl Oxlintrc {
Expand Down Expand Up @@ -116,10 +119,15 @@ impl Oxlintrc {
OxcDiagnostic::error(format!("Failed to parse eslint config {path:?}.\n{err}"))
})?;

let config = Self::deserialize(&json).map_err(|err| {
let mut config = Self::deserialize(&json).map_err(|err| {
OxcDiagnostic::error(format!("Failed to parse config with error {err:?}"))
})?;

// Get absolute path from `path`
let absolute_path = path.canonicalize().unwrap_or_else(|_| path.to_path_buf());

config.path = absolute_path;

Ok(config)
}
}
Expand All @@ -137,6 +145,7 @@ mod test {
assert!(config.rules.is_empty());
assert_eq!(config.settings, OxlintSettings::default());
assert_eq!(config.env, OxlintEnv::default());
assert_eq!(config.path, PathBuf::default());
}

#[test]
Expand Down

0 comments on commit 1cae468

Please sign in to comment.