Skip to content

Commit 51b398d

Browse files
committed
clippy fix
1 parent 6edcd5c commit 51b398d

File tree

16 files changed

+294
-81
lines changed

16 files changed

+294
-81
lines changed
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
{
2+
"plugins": ["import"],
3+
"rules": {
4+
"import/no-default-export": "error",
5+
"import/namespace": "allow"
6+
}
7+
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
import * as foo from './foo';
2+
// ^ import/namespace
3+
4+
console.log(foo);
5+
6+
// import/no-default-export
7+
export default function foo() {}
8+
9+

apps/oxlint/fixtures/typescript_eslint/eslintrc.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
{
2+
// NOTE: enabled by default
3+
"plugins": ["@typescript-eslint"],
24
"rules": {
35
"no-loss-of-precision": "off",
46
"@typescript-eslint/no-loss-of-precision": "error",

apps/oxlint/src/command/lint.rs

Lines changed: 144 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
use std::{path::PathBuf, str::FromStr};
22

33
use bpaf::Bpaf;
4-
use oxc_linter::{AllowWarnDeny, FixKind};
4+
use oxc_linter::{AllowWarnDeny, FixKind, LintPlugins};
55

66
use super::{
77
expand_glob,
@@ -211,64 +211,178 @@ impl FromStr for OutputFormat {
211211

212212
/// Enable Plugins
213213
#[allow(clippy::struct_field_names)]
214-
#[derive(Debug, Clone, Bpaf)]
214+
#[derive(Debug, Default, Clone, Bpaf)]
215215
pub struct EnablePlugins {
216216
/// Disable react plugin, which is turned on by default
217-
#[bpaf(long("disable-react-plugin"), flag(false, true), hide_usage)]
218-
pub react_plugin: bool,
217+
#[bpaf(long("disable-react-plugin"), flag(Enable::Disable, Enable::NotSet), hide_usage)]
218+
pub react_plugin: Enable,
219219

220220
/// Disable unicorn plugin, which is turned on by default
221-
#[bpaf(long("disable-unicorn-plugin"), flag(false, true), hide_usage)]
222-
pub unicorn_plugin: bool,
221+
#[bpaf(long("disable-unicorn-plugin"), flag(Enable::Disable, Enable::NotSet), hide_usage)]
222+
pub unicorn_plugin: Enable,
223223

224224
/// Disable oxc unique rules, which is turned on by default
225-
#[bpaf(long("disable-oxc-plugin"), flag(false, true), hide_usage)]
226-
pub oxc_plugin: bool,
225+
#[bpaf(long("disable-oxc-plugin"), flag(Enable::Disable, Enable::NotSet), hide_usage)]
226+
pub oxc_plugin: Enable,
227227

228228
/// Disable TypeScript plugin, which is turned on by default
229-
#[bpaf(long("disable-typescript-plugin"), flag(false, true), hide_usage)]
230-
pub typescript_plugin: bool,
229+
#[bpaf(long("disable-typescript-plugin"), flag(Enable::Disable, Enable::NotSet), hide_usage)]
230+
pub typescript_plugin: Enable,
231231

232232
/// Enable the experimental import plugin and detect ESM problems.
233233
/// It is recommended to use along side with the `--tsconfig` option.
234-
#[bpaf(switch, hide_usage)]
235-
pub import_plugin: bool,
234+
#[bpaf(flag(Enable::Enable, Enable::NotSet), hide_usage)]
235+
pub import_plugin: Enable,
236236

237237
/// Enable the experimental jsdoc plugin and detect JSDoc problems
238-
#[bpaf(switch, hide_usage)]
239-
pub jsdoc_plugin: bool,
238+
#[bpaf(flag(Enable::Enable, Enable::NotSet), hide_usage)]
239+
pub jsdoc_plugin: Enable,
240240

241241
/// Enable the Jest plugin and detect test problems
242-
#[bpaf(switch, hide_usage)]
243-
pub jest_plugin: bool,
242+
#[bpaf(flag(Enable::Enable, Enable::NotSet), hide_usage)]
243+
pub jest_plugin: Enable,
244244

245245
/// Enable the Vitest plugin and detect test problems
246-
#[bpaf(switch, hide_usage)]
247-
pub vitest_plugin: bool,
246+
#[bpaf(flag(Enable::Enable, Enable::NotSet), hide_usage)]
247+
pub vitest_plugin: Enable,
248248

249249
/// Enable the JSX-a11y plugin and detect accessibility problems
250-
#[bpaf(switch, hide_usage)]
251-
pub jsx_a11y_plugin: bool,
250+
#[bpaf(flag(Enable::Enable, Enable::NotSet), hide_usage)]
251+
pub jsx_a11y_plugin: Enable,
252252

253253
/// Enable the Next.js plugin and detect Next.js problems
254-
#[bpaf(switch, hide_usage)]
255-
pub nextjs_plugin: bool,
254+
#[bpaf(flag(Enable::Enable, Enable::NotSet), hide_usage)]
255+
pub nextjs_plugin: Enable,
256256

257257
/// Enable the React performance plugin and detect rendering performance problems
258-
#[bpaf(switch, hide_usage)]
259-
pub react_perf_plugin: bool,
258+
#[bpaf(flag(Enable::Enable, Enable::NotSet), hide_usage)]
259+
pub react_perf_plugin: Enable,
260260

261261
/// Enable the promise plugin and detect promise usage problems
262-
#[bpaf(switch, hide_usage)]
263-
pub promise_plugin: bool,
262+
#[bpaf(flag(Enable::Enable, Enable::NotSet), hide_usage)]
263+
pub promise_plugin: Enable,
264264

265265
/// Enable the node plugin and detect node usage problems
266-
#[bpaf(switch, hide_usage)]
267-
pub node_plugin: bool,
266+
#[bpaf(flag(Enable::Enable, Enable::NotSet), hide_usage)]
267+
pub node_plugin: Enable,
268268

269269
/// Enable the security plugin and detect security problems
270-
#[bpaf(switch, hide_usage)]
271-
pub security_plugin: bool,
270+
#[bpaf(flag(Enable::Enable, Enable::NotSet), hide_usage)]
271+
pub security_plugin: Enable,
272+
}
273+
274+
#[derive(Default, Debug, Clone, Copy, PartialEq, Eq)]
275+
#[allow(clippy::enum_variant_names)]
276+
pub enum Enable {
277+
Enable,
278+
Disable,
279+
#[default]
280+
NotSet,
281+
}
282+
283+
impl From<Option<bool>> for Enable {
284+
fn from(value: Option<bool>) -> Self {
285+
match value {
286+
Some(true) => Self::Enable,
287+
Some(false) => Self::Disable,
288+
None => Self::NotSet,
289+
}
290+
}
291+
}
292+
293+
impl From<Enable> for Option<bool> {
294+
fn from(value: Enable) -> Self {
295+
match value {
296+
Enable::Enable => Some(true),
297+
Enable::Disable => Some(false),
298+
Enable::NotSet => None,
299+
}
300+
}
301+
}
302+
303+
impl Enable {
304+
#[inline]
305+
pub fn is_enabled(self) -> bool {
306+
matches!(self, Self::Enable)
307+
}
308+
309+
#[inline]
310+
pub fn is_not_set(self) -> bool {
311+
matches!(self, Self::NotSet)
312+
}
313+
314+
pub fn inspect<F>(self, f: F)
315+
where
316+
F: FnOnce(bool),
317+
{
318+
if let Some(v) = self.into() {
319+
f(v);
320+
}
321+
}
322+
}
323+
324+
impl EnablePlugins {
325+
pub fn apply_overrides(&self, plugins: &mut LintPlugins) {
326+
self.react_plugin.inspect(|yes| plugins.set(LintPlugins::REACT, yes));
327+
self.unicorn_plugin.inspect(|yes| plugins.set(LintPlugins::UNICORN, yes));
328+
self.oxc_plugin.inspect(|yes| plugins.set(LintPlugins::OXC, yes));
329+
self.typescript_plugin.inspect(|yes| plugins.set(LintPlugins::TYPESCRIPT, yes));
330+
self.import_plugin.inspect(|yes| plugins.set(LintPlugins::IMPORT, yes));
331+
self.jsdoc_plugin.inspect(|yes| plugins.set(LintPlugins::JSDOC, yes));
332+
self.jest_plugin.inspect(|yes| plugins.set(LintPlugins::JEST, yes));
333+
self.vitest_plugin.inspect(|yes| plugins.set(LintPlugins::VITEST, yes));
334+
self.jsx_a11y_plugin.inspect(|yes| plugins.set(LintPlugins::JSX_A11Y, yes));
335+
self.nextjs_plugin.inspect(|yes| plugins.set(LintPlugins::NEXTJS, yes));
336+
self.react_perf_plugin.inspect(|yes| plugins.set(LintPlugins::REACT_PERF, yes));
337+
self.promise_plugin.inspect(|yes| plugins.set(LintPlugins::PROMISE, yes));
338+
self.node_plugin.inspect(|yes| plugins.set(LintPlugins::NODE, yes));
339+
self.security_plugin.inspect(|yes| plugins.set(LintPlugins::SECURITY, yes));
340+
341+
// Without this, jest plugins adapted to vitest will not be enabled.
342+
if self.vitest_plugin.is_enabled() && self.jest_plugin.is_not_set() {
343+
plugins.set(LintPlugins::JEST, true);
344+
}
345+
}
346+
}
347+
348+
#[cfg(test)]
349+
mod plugins {
350+
use super::{Enable, EnablePlugins};
351+
use oxc_linter::LintPlugins;
352+
353+
#[test]
354+
fn test_override_default() {
355+
let mut plugins = LintPlugins::default();
356+
let enable = EnablePlugins::default();
357+
358+
enable.apply_overrides(&mut plugins);
359+
assert_eq!(plugins, LintPlugins::default());
360+
}
361+
362+
#[test]
363+
fn test_overrides() {
364+
let mut plugins = LintPlugins::default();
365+
let enable = EnablePlugins {
366+
react_plugin: Enable::Enable,
367+
unicorn_plugin: Enable::Disable,
368+
..EnablePlugins::default()
369+
};
370+
let expected =
371+
LintPlugins::default().union(LintPlugins::REACT).difference(LintPlugins::UNICORN);
372+
373+
enable.apply_overrides(&mut plugins);
374+
assert_eq!(plugins, expected);
375+
}
376+
377+
#[test]
378+
fn test_override_vitest() {
379+
let mut plugins = LintPlugins::default();
380+
let enable = EnablePlugins { vitest_plugin: Enable::Enable, ..EnablePlugins::default() };
381+
let expected = LintPlugins::default() | LintPlugins::VITEST | LintPlugins::JEST;
382+
383+
enable.apply_overrides(&mut plugins);
384+
assert_eq!(plugins, expected);
385+
}
272386
}
273387

274388
#[cfg(test)]

apps/oxlint/src/lint/mod.rs

Lines changed: 33 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ use ignore::gitignore::Gitignore;
44
use oxc_diagnostics::{DiagnosticService, GraphicalReportHandler};
55
use oxc_linter::{
66
partial_loader::LINT_PARTIAL_LOADER_EXT, AllowWarnDeny, InvalidFilterKind, LintFilter,
7-
LintService, LintServiceOptions, Linter, OxlintOptions,
7+
LintService, LintServiceOptions, Linter, LinterBuilder, Oxlintrc,
88
};
99
use oxc_span::VALID_EXTENSIONS;
1010

@@ -98,39 +98,32 @@ impl Runner for LintRunner {
9898
let number_of_files = paths.len();
9999

100100
let cwd = std::env::current_dir().unwrap();
101-
let mut options =
102-
LintServiceOptions::new(cwd, paths).with_cross_module(enable_plugins.import_plugin);
103-
let lint_options = OxlintOptions::default()
104-
.with_filter(filter)
105-
.with_config_path(basic_options.config)
106-
.with_fix(fix_options.fix_kind())
107-
.with_react_plugin(enable_plugins.react_plugin)
108-
.with_unicorn_plugin(enable_plugins.unicorn_plugin)
109-
.with_typescript_plugin(enable_plugins.typescript_plugin)
110-
.with_oxc_plugin(enable_plugins.oxc_plugin)
111-
.with_import_plugin(enable_plugins.import_plugin)
112-
.with_jsdoc_plugin(enable_plugins.jsdoc_plugin)
113-
.with_jest_plugin(enable_plugins.jest_plugin)
114-
.with_vitest_plugin(enable_plugins.vitest_plugin)
115-
.with_jsx_a11y_plugin(enable_plugins.jsx_a11y_plugin)
116-
.with_nextjs_plugin(enable_plugins.nextjs_plugin)
117-
.with_react_perf_plugin(enable_plugins.react_perf_plugin)
118-
.with_promise_plugin(enable_plugins.promise_plugin)
119-
.with_node_plugin(enable_plugins.node_plugin)
120-
.with_security_plugin(enable_plugins.security_plugin);
121-
122-
let linter = match Linter::from_options(lint_options) {
123-
Ok(lint_service) => lint_service,
124-
Err(diagnostic) => {
125-
let handler = GraphicalReportHandler::new();
126-
let mut err = String::new();
127-
handler.render_report(&mut err, diagnostic.as_ref()).unwrap();
128-
return CliRunResult::InvalidOptions {
129-
message: format!("Failed to parse configuration file.\n{err}"),
130-
};
101+
102+
let mut oxlintrc = if let Some(config_path) = basic_options.config.as_ref() {
103+
match Oxlintrc::from_file(config_path) {
104+
Ok(config) => config,
105+
Err(diagnostic) => {
106+
let handler = GraphicalReportHandler::new();
107+
let mut err = String::new();
108+
handler.render_report(&mut err, &diagnostic).unwrap();
109+
return CliRunResult::InvalidOptions {
110+
message: format!("Failed to parse configuration file.\n{err}"),
111+
};
112+
}
131113
}
114+
} else {
115+
Oxlintrc::default()
132116
};
133117

118+
enable_plugins.apply_overrides(&mut oxlintrc.plugins);
119+
let builder = LinterBuilder::from_oxlintrc(false, oxlintrc)
120+
.with_filters(filter)
121+
.with_fix(fix_options.fix_kind());
122+
123+
let mut options =
124+
LintServiceOptions::new(cwd, paths).with_cross_module(builder.plugins().has_import());
125+
let linter = builder.build();
126+
134127
let tsconfig = basic_options.tsconfig;
135128
if let Some(path) = tsconfig.as_ref() {
136129
if path.is_file() {
@@ -562,4 +555,13 @@ mod test {
562555
assert_eq!(result.number_of_files, 1);
563556
assert_eq!(result.number_of_errors, 1);
564557
}
558+
559+
#[test]
560+
fn test_import_plugin_enabled_in_config() {
561+
let args = &["-c", "fixtures/import/.oxlintrc.json", "fixtures/import/test.js"];
562+
let result = test(args);
563+
assert_eq!(result.number_of_files, 1);
564+
assert_eq!(result.number_of_warnings, 0);
565+
assert_eq!(result.number_of_errors, 1);
566+
}
565567
}

crates/oxc_linter/src/config/env.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ use serde::{Deserialize, Serialize};
1111
/// environments](https://eslint.org/docs/v8.x/use/configure/language-options#specifying-environments)
1212
/// for what environments are available and what each one provides.
1313
#[derive(Debug, Clone, Deserialize, Serialize, JsonSchema)]
14+
#[cfg_attr(test, derive(PartialEq))]
1415
pub struct OxlintEnv(FxHashMap<String, bool>);
1516

1617
impl OxlintEnv {

crates/oxc_linter/src/config/oxlintrc.rs

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,3 +90,49 @@ impl Oxlintrc {
9090
Ok(config)
9191
}
9292
}
93+
94+
#[cfg(test)]
95+
mod test {
96+
use super::*;
97+
use serde_json::json;
98+
99+
#[test]
100+
fn test_oxlintrc_de_empty() {
101+
let config: Oxlintrc = serde_json::from_value(json!({})).unwrap();
102+
assert_eq!(config.plugins, LintPlugins::default());
103+
assert_eq!(config.rules, OxlintRules::default());
104+
assert!(config.rules.is_empty());
105+
assert_eq!(config.settings, OxlintSettings::default());
106+
assert_eq!(config.env, OxlintEnv::default());
107+
}
108+
109+
#[test]
110+
fn test_oxlintrc_de_plugins_empty_array() {
111+
let config: Oxlintrc = serde_json::from_value(json!({ "plugins": [] })).unwrap();
112+
assert_eq!(config.plugins, LintPlugins::default());
113+
}
114+
115+
#[test]
116+
fn test_oxlintrc_de_plugins_enabled_by_default() {
117+
// NOTE(@DonIsaac): creating a Value with `json!` then deserializing it with serde_json::from_value
118+
// Errs with "invalid type: string \"eslint\", expected a borrowed string" and I can't
119+
// figure out why. This seems to work. Why???
120+
let configs = [
121+
r#"{ "plugins": ["eslint"] }"#,
122+
r#"{ "plugins": ["oxc"] }"#,
123+
r#"{ "plugins": ["deepscan"] }"#, // alias for oxc
124+
];
125+
// ^ these plugins are enabled by default already
126+
for oxlintrc in configs {
127+
let config: Oxlintrc = serde_json::from_str(oxlintrc).unwrap();
128+
assert_eq!(config.plugins, LintPlugins::default());
129+
}
130+
}
131+
132+
#[test]
133+
fn test_oxlintrc_de_plugins_new() {
134+
// let config: Oxlintrc = serde_json::from_value(json!({ "plugins": ["import"] })).unwrap();
135+
let config: Oxlintrc = serde_json::from_str(r#"{ "plugins": ["import"] }"#).unwrap();
136+
assert_eq!(config.plugins, LintPlugins::default().union(LintPlugins::IMPORT));
137+
}
138+
}

crates/oxc_linter/src/config/rules.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,9 +23,11 @@ type RuleSet = FxHashSet<RuleWithSeverity>;
2323
// <https://github.com/eslint/eslint/blob/ce838adc3b673e52a151f36da0eedf5876977514/lib/shared/types.js#L12>
2424
// Note: when update document comment, also update `DummyRuleMap`'s description in this file.
2525
#[derive(Debug, Clone, Default)]
26+
#[cfg_attr(test, derive(PartialEq))]
2627
pub struct OxlintRules(Vec<ESLintRule>);
2728

2829
#[derive(Debug, Clone)]
30+
#[cfg_attr(test, derive(PartialEq))]
2931
pub struct ESLintRule {
3032
pub plugin_name: String,
3133
pub rule_name: String,

0 commit comments

Comments
 (0)