Skip to content

Commit 2fc1e32

Browse files
committed
fix(linter): support nested extending
1 parent 4cfdc59 commit 2fc1e32

5 files changed

Lines changed: 46 additions & 9 deletions

File tree

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
{
2+
"extends": ["../extends_rules_config.json"]
3+
}

apps/oxlint/src/lint.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1022,4 +1022,11 @@ mod test {
10221022
let args = &["--config", "extends_rules_config.json", "console.js"];
10231023
Tester::new().with_cwd("fixtures/extends_config".into()).test_and_snapshot(args);
10241024
}
1025+
1026+
#[test]
1027+
fn test_extends_extends_config() {
1028+
// Check that using a config that extends a config which extends a config works
1029+
let args = &["--config", "relative_paths/extends_extends_config.json", "console.js"];
1030+
Tester::new().with_cwd("fixtures/extends_config".into()).test_and_snapshot(args);
1031+
}
10251032
}

apps/oxlint/src/snapshots/fixtures__extends_config_--config extends_rules_config.json [email protected]

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ working directory: fixtures/extends_config
1414
help: Delete this console statement.
1515
1616
Found 0 warnings and 1 error.
17-
Finished in <variable>ms on 1 file with 100 rules using 1 threads.
17+
Finished in <variable>ms on 1 file with 101 rules using 1 threads.
1818
----------
1919
CLI result: LintFoundErrors
2020
----------
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
---
2+
source: apps/oxlint/src/tester.rs
3+
---
4+
##########
5+
arguments: --config relative_paths/extends_extends_config.json console.js
6+
working directory: fixtures/extends_config
7+
----------
8+
9+
x ]8;;https://oxc.rs/docs/guide/usage/linter/rules/eslint/no-console.html\eslint(no-console)]8;;\: eslint(no-console): Unexpected console statement.
10+
,-[console.js:1:1]
11+
1 | console.log("test");
12+
: ^^^^^^^^^^^
13+
`----
14+
help: Delete this console statement.
15+
16+
Found 0 warnings and 1 error.
17+
Finished in <variable>ms on 1 file with 102 rules using 1 threads.
18+
----------
19+
CLI result: LintFoundErrors
20+
----------

crates/oxc_linter/src/config/config_builder.rs

Lines changed: 15 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -109,23 +109,29 @@ impl ConfigStoreBuilder {
109109
}
110110

111111
{
112-
let all_rules = builder.cache.borrow();
113-
114112
if !extends.is_empty() {
115-
let config_file_path = builder.config.path.as_ref().and_then(|p| p.parent());
113+
let config_path = builder.config.path.clone();
114+
let config_path_parent = config_path.as_ref().and_then(|p| p.parent());
116115
for path in &extends {
117116
// resolve path relative to config path
118-
let path = match config_file_path {
117+
let path = match config_path_parent {
119118
Some(config_file_path) => &config_file_path.join(path),
120119
None => path,
121120
};
122121
// TODO: throw an error if this is a self-referential extend
123122
// TODO(perf): use a global config cache to avoid re-parsing the same file multiple times
124123
match Oxlintrc::from_file(path) {
125124
Ok(extended_config) => {
126-
extended_config
127-
.rules
128-
.override_rules(&mut builder.rules, all_rules.as_slice());
125+
// TODO(refactor): can we merge this together? seems redundant to use `override_rules` and then
126+
// use `ConfigStoreBuilder`, but we don't have a better way of loading rules from config files other than that.
127+
// Use `override_rules` to apply rule configurations and add/remove rules as needed
128+
extended_config.rules.override_rules(&mut builder.rules, &RULES);
129+
// Use `ConfigStoreBuilder` to load extended config files and then apply rules from those
130+
let extended_config_store =
131+
ConfigStoreBuilder::from_oxlintrc(true, extended_config)?;
132+
for rule in extended_config_store.rules {
133+
builder = builder.with_rule(rule);
134+
}
129135
}
130136
Err(err) => {
131137
return Err(ConfigBuilderError::InvalidConfigFile {
@@ -137,6 +143,8 @@ impl ConfigStoreBuilder {
137143
}
138144
}
139145

146+
let all_rules = builder.cache.borrow();
147+
140148
oxlintrc_rules.override_rules(&mut builder.rules, all_rules.as_slice());
141149
}
142150

@@ -179,7 +187,6 @@ impl ConfigStoreBuilder {
179187
self.config.plugins
180188
}
181189

182-
#[cfg(test)]
183190
pub(crate) fn with_rule(mut self, rule: RuleWithSeverity) -> Self {
184191
self.rules.insert(rule);
185192
self

0 commit comments

Comments
 (0)