Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(linter): support env and globals in overrides configuration #8915

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 9 additions & 3 deletions apps/oxlint/fixtures/overrides/.oxlintrc.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,19 +5,25 @@
},
"overrides": [
{
"files": ["*.js"],
"files": [
"*.js"
],
"rules": {
"no-console": "warn"
}
},
{
"files": ["*.{js,jsx}"],
"files": [
"*.{js,jsx}"
],
"rules": {
"no-console": "off"
}
},
{
"files": ["*.ts"],
"files": [
"*.ts"
],
"rules": {
"no-console": "warn"
}
Expand Down
9 changes: 7 additions & 2 deletions apps/oxlint/fixtures/overrides/directories-config.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,18 @@
},
"overrides": [
{
"files": ["lib/*.{js,ts}", "src/*"],
"files": [
"lib/*.{js,ts}",
"src/*"
],
"rules": {
"no-debugger": "error"
}
},
{
"files": ["**/tests/*"],
"files": [
"**/tests/*"
],
"rules": {
"no-debugger": "warn"
}
Expand Down
32 changes: 32 additions & 0 deletions apps/oxlint/fixtures/overrides_env_globals/.oxlintrc.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
{
"env": {
"jquery": true
},
"globals": {
"Foo": "readonly"
},
"overrides": [
{
"files": [
"*.ts"
],
"env": {
"jquery": false
},
"globals": {
"Foo": "writeable"
}
},
{
"files": [
"src/*"
],
"env": {
"jquery": false
},
"globals": {
"Foo": "writeable"
}
}
]
}
6 changes: 6 additions & 0 deletions apps/oxlint/fixtures/overrides_env_globals/src/test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
// for env detection
globalThis = 'abc';
$ = 'abc';

// for globals detection
Foo = 'readable';
6 changes: 6 additions & 0 deletions apps/oxlint/fixtures/overrides_env_globals/test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
// for env detection
globalThis = 'abc';
$ = 'abc';

// for globals detection
Foo = 'readable';
6 changes: 6 additions & 0 deletions apps/oxlint/fixtures/overrides_env_globals/test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
// for env detection
globalThis = 'abc';
$ = 'abc';

// for globals detection
Foo = 'readable';
6 changes: 6 additions & 0 deletions apps/oxlint/src/lint.rs
Original file line number Diff line number Diff line change
Expand Up @@ -755,6 +755,12 @@ mod test {
Tester::new().test_and_snapshot(args);
}

#[test]
fn test_overrides_envs_and_global() {
let args = &["-c", ".oxlintrc.json", "."];
Tester::new().with_cwd("fixtures/overrides_env_globals".into()).test_and_snapshot(args);
}

#[test]
fn test_ignore_patterns() {
let args = &["-c", "./test/eslintrc.json", "--ignore-pattern", "*.ts", "."];
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
---
source: apps/oxlint/src/tester.rs
---
##########
arguments: -c .oxlintrc.json .
working directory: fixtures/overrides_env_globals
----------

! ]8;;https://oxc.rs/docs/guide/usage/linter/rules/eslint/no-global-assign.html\eslint(no-global-assign)]8;;\: Read-only global 'globalThis' should not be modified.
,-[src/test.js:2:1]
1 | // for env detection
2 | globalThis = 'abc';
: ^^^^^|^^^^
: `-- Read-only global 'globalThis' should not be modified.
3 | $ = 'abc';
`----

! ]8;;https://oxc.rs/docs/guide/usage/linter/rules/eslint/no-global-assign.html\eslint(no-global-assign)]8;;\: Read-only global 'globalThis' should not be modified.
,-[test.js:2:1]
1 | // for env detection
2 | globalThis = 'abc';
: ^^^^^|^^^^
: `-- Read-only global 'globalThis' should not be modified.
3 | $ = 'abc';
`----

! ]8;;https://oxc.rs/docs/guide/usage/linter/rules/eslint/no-global-assign.html\eslint(no-global-assign)]8;;\: Read-only global 'globalThis' should not be modified.
,-[test.ts:2:1]
1 | // for env detection
2 | globalThis = 'abc';
: ^^^^^|^^^^
: `-- Read-only global 'globalThis' should not be modified.
3 | $ = 'abc';
`----

! ]8;;https://oxc.rs/docs/guide/usage/linter/rules/eslint/no-global-assign.html\eslint(no-global-assign)]8;;\: Read-only global '$' should not be modified.
,-[test.js:3:1]
2 | globalThis = 'abc';
3 | $ = 'abc';
: |
: `-- Read-only global '$' should not be modified.
4 |
`----

! ]8;;https://oxc.rs/docs/guide/usage/linter/rules/eslint/no-global-assign.html\eslint(no-global-assign)]8;;\: Read-only global 'Foo' should not be modified.
,-[test.js:6:1]
5 | // for globals detection
6 | Foo = 'readable';
: ^|^
: `-- Read-only global 'Foo' should not be modified.
`----

Found 5 warnings and 0 errors.
Finished in <variable>ms on 3 files with 97 rules using 1 threads.
----------
CLI result: LintSucceeded
----------
135 changes: 128 additions & 7 deletions crates/oxc_linter/src/config/config_store.rs
Original file line number Diff line number Diff line change
Expand Up @@ -85,12 +85,9 @@ impl ConfigStore {
return config.base.clone();
}

let mut env = config.base.config.env.clone();
let mut globals = config.base.config.globals.clone();
let mut plugins = config.base.config.plugins;
let all_rules = RULES
.iter()
.filter(|rule| plugins.contains(LintPlugins::from(rule.plugin_name())))
.cloned()
.collect::<Vec<_>>();
let mut rules = config
.base
.rules
Expand All @@ -99,6 +96,12 @@ impl ConfigStore {
.cloned()
.collect::<FxHashSet<_>>();

let all_rules = RULES
.iter()
.filter(|rule| plugins.contains(LintPlugins::from(rule.plugin_name())))
.cloned()
.collect::<Vec<_>>();

for override_config in overrides_to_apply {
if !override_config.rules.is_empty() {
override_config.rules.override_rules(&mut rules, &all_rules);
Expand All @@ -107,18 +110,31 @@ impl ConfigStore {
if let Some(override_plugins) = override_config.plugins {
plugins |= override_plugins;
}

if let Some(override_env) = &override_config.env {
override_env.override_envs(&mut env);
}

if let Some(override_globals) = &override_config.globals {
override_globals.override_globals(&mut globals);
}
}

let rules = rules.into_iter().collect::<Vec<_>>();
let config = if plugins == config.base.config.plugins {
let config = if plugins == config.base.config.plugins
&& env == config.base.config.env
&& globals == config.base.config.globals
{
Arc::clone(&config.base.config)
} else {
let mut config = (*config.base.config).clone();

config.plugins = plugins;
config.env = env;
config.globals = globals;
Arc::new(config)
};

let rules = rules.into_iter().collect::<Vec<_>>();
ResolvedLinterState { rules: Arc::from(rules.into_boxed_slice()), config }
}
}
Expand Down Expand Up @@ -282,4 +298,109 @@ mod test {
let app = store.resolve("App.tsx".as_ref()).config;
assert_eq!(app.plugins, LintPlugins::IMPORT | LintPlugins::REACT | LintPlugins::TYPESCRIPT);
}

#[test]
fn test_add_env() {
let base_config = LintConfig {
env: OxlintEnv::default(),
plugins: LintPlugins::ESLINT,
settings: OxlintSettings::default(),
globals: OxlintGlobals::default(),
path: None,
};

let overrides = from_json!([{
"files": ["*.tsx"],
"env": {
"es2024": true
},
}]);

let store = ConfigStore::new(vec![], base_config, overrides);
assert!(!store.base.base.config.env.contains("React"));

let app = store.resolve("App.tsx".as_ref()).config;
assert!(app.env.contains("es2024"));
}

#[test]
fn test_replace_env() {
let base_config = LintConfig {
env: OxlintEnv::from_iter(["es2024".into()]),
plugins: LintPlugins::ESLINT,
settings: OxlintSettings::default(),
globals: OxlintGlobals::default(),
path: None,
};

let overrides = from_json!([{
"files": ["*.tsx"],
"env": {
"es2024": false
},
}]);

let store = ConfigStore::new(vec![], base_config, overrides);
assert!(store.base.base.config.env.contains("es2024"));

let app = store.resolve("App.tsx".as_ref()).config;
assert!(!app.env.contains("es2024"));
}

#[test]
fn test_add_globals() {
let base_config = LintConfig {
env: OxlintEnv::default(),
plugins: LintPlugins::ESLINT,
settings: OxlintSettings::default(),
globals: OxlintGlobals::default(),
path: None,
};

let overrides = from_json!([{
"files": ["*.tsx"],
"globals": {
"React": "readonly",
"Secret": "writeable"
},
}]);

let store = ConfigStore::new(vec![], base_config, overrides);
assert!(!store.base.base.config.globals.is_enabled("React"));
assert!(!store.base.base.config.globals.is_enabled("Secret"));

let app = store.resolve("App.tsx".as_ref()).config;
assert!(app.globals.is_enabled("React"));
assert!(app.globals.is_enabled("Secret"));
}

#[test]
fn test_replace_globals() {
let base_config = LintConfig {
env: OxlintEnv::default(),
plugins: LintPlugins::ESLINT,
settings: OxlintSettings::default(),
globals: from_json!({
"React": "readonly",
"Secret": "writeable"
}),
path: None,
};

let overrides = from_json!([{
"files": ["*.tsx"],
"globals": {
"React": "off",
"Secret": "off"
},
}]);

let store = ConfigStore::new(vec![], base_config, overrides);
assert!(store.base.base.config.globals.is_enabled("React"));
assert!(store.base.base.config.globals.is_enabled("Secret"));

let app = store.resolve("App.tsx".as_ref()).config;
assert!(!app.globals.is_enabled("React"));
assert!(!app.globals.is_enabled("Secret"));
}
}
Loading
Loading