|
1 | 1 | use std::{path::PathBuf, str::FromStr}; |
2 | 2 |
|
3 | 3 | use bpaf::Bpaf; |
4 | | -use oxc_linter::{AllowWarnDeny, FixKind}; |
| 4 | +use oxc_linter::{AllowWarnDeny, FixKind, LintPlugins}; |
5 | 5 |
|
6 | 6 | use super::{ |
7 | 7 | expand_glob, |
@@ -211,64 +211,178 @@ impl FromStr for OutputFormat { |
211 | 211 |
|
212 | 212 | /// Enable Plugins |
213 | 213 | #[allow(clippy::struct_field_names)] |
214 | | -#[derive(Debug, Clone, Bpaf)] |
| 214 | +#[derive(Debug, Default, Clone, Bpaf)] |
215 | 215 | pub struct EnablePlugins { |
216 | 216 | /// 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, |
219 | 219 |
|
220 | 220 | /// 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, |
223 | 223 |
|
224 | 224 | /// 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, |
227 | 227 |
|
228 | 228 | /// 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, |
231 | 231 |
|
232 | 232 | /// Enable the experimental import plugin and detect ESM problems. |
233 | 233 | /// 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, |
236 | 236 |
|
237 | 237 | /// 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, |
240 | 240 |
|
241 | 241 | /// 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, |
244 | 244 |
|
245 | 245 | /// 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, |
248 | 248 |
|
249 | 249 | /// 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, |
252 | 252 |
|
253 | 253 | /// 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, |
256 | 256 |
|
257 | 257 | /// 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, |
260 | 260 |
|
261 | 261 | /// 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, |
264 | 264 |
|
265 | 265 | /// 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, |
268 | 268 |
|
269 | 269 | /// 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 | + } |
272 | 386 | } |
273 | 387 |
|
274 | 388 | #[cfg(test)] |
|
0 commit comments