From effe6db8dd7ae7ba2da94a8f12c3d4739df41ae9 Mon Sep 17 00:00:00 2001 From: Don Isaac Date: Fri, 12 Jul 2024 00:39:13 -0400 Subject: [PATCH] feat: add auto-generated help messages to linter diagnostics --- Cargo.lock | 1 + apps/oxlint/src/command/lint.rs | 31 +-- crates/oxc_language_server/src/linter.rs | 2 +- crates/oxc_language_server/src/main.rs | 2 +- crates/oxc_linter/Cargo.toml | 1 + crates/oxc_linter/src/context.rs | 50 +++-- crates/oxc_linter/src/fixer/fix.rs | 176 +++++++++++++++--- crates/oxc_linter/src/fixer/mod.rs | 56 +++++- crates/oxc_linter/src/lib.rs | 15 +- crates/oxc_linter/src/options.rs | 18 +- .../no_useless_promise_resolve_reject.rs | 4 +- .../oxc_linter/src/snapshots/array_type.snap | 89 +++++++++ .../src/snapshots/ban_tslint_comment.snap | 8 + .../snapshots/consistent_type_imports.snap | 11 ++ .../oxc_linter/src/snapshots/escape_case.snap | 8 + .../src/snapshots/explicit_length_check.snap | 2 + .../oxc_linter/src/snapshots/no_debugger.snap | 1 + .../src/snapshots/no_focused_tests.snap | 1 + .../src/snapshots/no_hex_escape.snap | 3 + .../src/snapshots/no_test_prefixes.snap | 24 ++- .../src/snapshots/no_useless_escape.snap | 62 ++++++ .../snapshots/prefer_prototype_methods.snap | 23 +++ .../src/snapshots/prefer_to_be.snap | 49 +++++ .../src/snapshots/prefer_to_have_length.snap | 10 + .../oxc_linter/src/snapshots/prefer_todo.snap | 9 + .../src/snapshots/sort_imports.snap | 15 ++ crates/oxc_linter/src/tester.rs | 2 +- tasks/website/src/linter/snapshots/cli.snap | 6 +- .../src/linter/snapshots/cli_terminal.snap | 6 +- 29 files changed, 610 insertions(+), 75 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 90ddb7251c518d..dcda95719f1f1d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1510,6 +1510,7 @@ dependencies = [ name = "oxc_linter" version = "0.6.0" dependencies = [ + "bitflags 2.6.0", "convert_case", "dashmap 6.0.1", "insta", diff --git a/apps/oxlint/src/command/lint.rs b/apps/oxlint/src/command/lint.rs index a721642ef294d5..1511d069b29072 100644 --- a/apps/oxlint/src/command/lint.rs +++ b/apps/oxlint/src/command/lint.rs @@ -122,26 +122,35 @@ pub struct FixOptions { /// Fix as many issues as possible. Only unfixed issues are reported in the output #[bpaf(switch)] pub fix: bool, - /// Apply all safe fixes and more-risky suggestions. Overrides `--fix`. + /// Apply auto-fixable suggestions. May change program behavior. #[bpaf(switch)] pub fix_suggestions: bool, - /// Apply all fixes and suggestions, including dangerous ones. Overrides - /// `--fix` and `--fix-suggestions`. These fixes may create incorrect code. + /// Apply dangerous fixes and suggestions. #[bpaf(switch)] pub fix_dangerously: bool, } + impl FixOptions { - pub fn fix_kind(&self) -> Option { + pub fn fix_kind(&self) -> FixKind { + let mut kind = FixKind::None; + + if self.fix { + kind.set(FixKind::SafeFix, true); + } + + if self.fix_suggestions { + kind.set(FixKind::Suggestion, true); + } + if self.fix_dangerously { - Some(FixKind::DangerousFix) - } else if self.fix_suggestions { - Some(FixKind::Suggestion) - } else if self.fix { - Some(FixKind::SafeFix) - } else { - None + if kind.is_none() { + kind.set(FixKind::Fix, true); + } + kind.set(FixKind::Dangerous, true); } + + kind } pub fn is_enabled(&self) -> bool { diff --git a/crates/oxc_language_server/src/linter.rs b/crates/oxc_language_server/src/linter.rs index b33746293caac9..be86e2a5d57f76 100644 --- a/crates/oxc_language_server/src/linter.rs +++ b/crates/oxc_language_server/src/linter.rs @@ -388,7 +388,7 @@ pub struct ServerLinter { impl ServerLinter { pub fn new() -> Self { - let linter = Linter::default().with_fix(Some(FixKind::SafeFix)); + let linter = Linter::default().with_fix(FixKind::SafeFix); Self { linter: Arc::new(linter) } } diff --git a/crates/oxc_language_server/src/main.rs b/crates/oxc_language_server/src/main.rs index aa367d23f72d22..4a830be3a9806b 100644 --- a/crates/oxc_language_server/src/main.rs +++ b/crates/oxc_language_server/src/main.rs @@ -346,7 +346,7 @@ impl Backend { *linter = ServerLinter::new_with_linter( Linter::from_options( LintOptions::default() - .with_fix(Some(FixKind::SafeFix)) + .with_fix(FixKind::SafeFix) .with_config_path(Some(config_path)), ) .expect("should have initialized linter with new options"), diff --git a/crates/oxc_linter/Cargo.toml b/crates/oxc_linter/Cargo.toml index f6a412404d3493..64747e8be890fa 100644 --- a/crates/oxc_linter/Cargo.toml +++ b/crates/oxc_linter/Cargo.toml @@ -33,6 +33,7 @@ oxc_codegen = { workspace = true } oxc_resolver = { workspace = true } rayon = { workspace = true } +bitflags = { workspace = true } lazy_static = { workspace = true } serde_json = { workspace = true } serde = { workspace = true, features = ["derive"] } diff --git a/crates/oxc_linter/src/context.rs b/crates/oxc_linter/src/context.rs index 74ecb43bc1b1fc..8aa469a042b52e 100644 --- a/crates/oxc_linter/src/context.rs +++ b/crates/oxc_linter/src/context.rs @@ -26,10 +26,12 @@ pub struct LintContext<'a> { disable_directives: Rc>, - /// Whether or not to apply code fixes during linting. Defaults to `false`. + /// Whether or not to apply code fixes during linting. Defaults to + /// [`FixKind::None`] (no fixing). /// - /// Set via the `--fix` CLI flag. - fix: Option, + /// Set via the `--fix`, `--fix-suggestions`, and `--fix-dangerously` CLI + /// flags. + fix: FixKind, file_path: Rc, @@ -69,7 +71,7 @@ impl<'a> LintContext<'a> { semantic, diagnostics: RefCell::new(Vec::with_capacity(DIAGNOSTICS_INITIAL_CAPACITY)), disable_directives: Rc::new(disable_directives), - fix: None, + fix: FixKind::None, file_path: file_path.into(), eslint_config: Arc::new(OxlintConfig::default()), current_rule_name: "", @@ -79,7 +81,7 @@ impl<'a> LintContext<'a> { /// Enable/disable automatic code fixes. #[must_use] - pub fn with_fix(mut self, fix: Option) -> Self { + pub fn with_fix(mut self, fix: FixKind) -> Self { self.fix = fix; self } @@ -274,19 +276,31 @@ impl<'a> LintContext<'a> { C: Into>, F: FnOnce(RuleFixer<'_, 'a>) -> C, { - if let Some(accepted_fix_kind) = self.fix { - let fixer = RuleFixer::new(fix_kind, self); - let rule_fix: RuleFix<'a> = fix(fixer).into(); - let diagnostic = match (rule_fix.message(), &diagnostic.help) { - (Some(message), None) => diagnostic.with_help(message.to_owned()), - _ => diagnostic, - }; - if rule_fix.kind() <= accepted_fix_kind { - let fix = rule_fix.into_fix(self.source_text()); - self.add_diagnostic(Message::new(diagnostic, Some(fix))); - } else { - self.diagnostic(diagnostic); - } + // if let Some(accepted_fix_kind) = self.fix { + // let fixer = RuleFixer::new(fix_kind, self); + // let rule_fix: RuleFix<'a> = fix(fixer).into(); + // let diagnostic = match (rule_fix.message(), &diagnostic.help) { + // (Some(message), None) => diagnostic.with_help(message.to_owned()), + // _ => diagnostic, + // }; + // if rule_fix.kind() <= accepted_fix_kind { + // let fix = rule_fix.into_fix(self.source_text()); + // self.add_diagnostic(Message::new(diagnostic, Some(fix))); + // } else { + // self.diagnostic(diagnostic); + // } + // } else { + // self.diagnostic(diagnostic); + // } + let fixer = RuleFixer::new(fix_kind, self); + let rule_fix: RuleFix<'a> = fix(fixer).into(); + let diagnostic = match (rule_fix.message(), &diagnostic.help) { + (Some(message), None) => diagnostic.with_help(message.to_owned()), + _ => diagnostic, + }; + if self.fix.can_apply(rule_fix.kind()) { + let fix = rule_fix.into_fix(self.source_text()); + self.add_diagnostic(Message::new(diagnostic, Some(fix))); } else { self.diagnostic(diagnostic); } diff --git a/crates/oxc_linter/src/fixer/fix.rs b/crates/oxc_linter/src/fixer/fix.rs index 552d40e1af5ed0..44ceec7a5c308a 100644 --- a/crates/oxc_linter/src/fixer/fix.rs +++ b/crates/oxc_linter/src/fixer/fix.rs @@ -1,23 +1,87 @@ use std::{borrow::Cow, ops::Deref}; +use bitflags::bitflags; use oxc_span::{GetSpan, Span, SPAN}; -/// Ordered from safest to least safe. -#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] -pub enum FixKind { - /// An automatic code fix that we are confident won't - /// - Cause any parse errors - /// - Change the code's semantics - #[default] - SafeFix, - /// A recommendation about how to fix a rule violation. These are safe to - /// apply, in that they shouldn't cause parse or runtime errors, but may - /// change the meaning of the code. - Suggestion, - /// An automatic code fix that may break the code. This covers fixes that: - /// - Are aggressive - /// - Are under development - DangerousFix, +bitflags! { + /// Flags describing an automatic code fix. + /// + /// These are used by lint rules when they provide a code fix or suggestion. + /// These are also used by the `LintService` to decide which kinds of + /// changes to apply. + /// + /// [`FixKind`] is designed to be interopable with [`bool`]. `true` turns + /// into [`FixKind::Fix`] (applies only safe fixes) and `false` turns into + /// `FixKind::None` (do not apply any fixes or suggestions). + #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] + pub struct FixKind: u8 { + /// An automatic code fix. Most of these are applied with `--fix` + /// + const Fix = 1 << 0; + /// A recommendation about how to fix a rule violation. These are usually + /// safe to apply, in that they shouldn't cause parse or runtime errors, + /// but may change the meaning of the code. + const Suggestion = 1 << 1; + /// Marks a fix or suggestion as dangerous. Dangerous fixes/suggestions + /// may break the code. Covers cases that are + /// - Aggressive (e.g. some code removal) + /// - Are under development. Think of this as similar to the `nursery` + /// rule category. + const Dangerous = 1 << 2; + + /// Used to specify that no fixes should be applied. + const None = 0; + const SafeFix = Self::Fix.bits(); + const DangerousFix = Self::Dangerous.bits() | Self::Fix.bits(); + } +} + +// explicit definition for clarity +impl Default for FixKind { + #[inline] + fn default() -> Self { + Self::None + } +} + +impl FixKind { + #[inline(always)] + pub fn is_none(self) -> bool { + self.is_empty() + } + + #[inline(always)] + pub fn is_some(self) -> bool { + self.bits() > 0 + } + + #[inline] + pub fn is_dangerous(self) -> bool { + self.contains(Self::Dangerous) + } + + /// Check if a [`RuleFix`] produced by a lint rule is allowed to be applied + /// to the source code. + /// + /// Here, `self` is the set of allowed [`FixKinds`], and `rule_fix` is the + /// kind of fixed produced by the rule. + /// + /// # Example + /// ``` + /// use oxc_linter::FixKind; + /// + /// // `none` means no fixes will be applied at all + /// assert!(!FixKind::None.can_apply(FixKind::SafeFix)); + /// + /// // allow safe fixes + /// assert!(FixKind::SafeFix.can_apply(FixKind::SafeFix)); + /// assert!(!FixKind::SafeFix.can_apply(FixKind::DangerousFix)); // not safe + /// assert!(!FixKind::SafeFix.can_apply(FixKind::Suggestion)); // not a fix + /// ``` + #[inline] + pub fn can_apply(self, rule_fix: Self) -> bool { + self.contains(rule_fix) + } } // TODO: rename @@ -52,12 +116,14 @@ macro_rules! impl_from { impl_from!(CompositeFix<'a>, Fix<'a>, Option>, Vec>); impl<'a> From> for CompositeFix<'a> { + #[inline] fn from(val: RuleFix<'a>) -> Self { val.fix } } impl<'a> RuleFix<'a> { + #[inline] pub(super) fn new(kind: FixKind, message: Option>, fix: CompositeFix<'a>) -> Self { Self { kind, message, fix } } @@ -65,7 +131,7 @@ impl<'a> RuleFix<'a> { /// Create a new safe fix. #[inline] pub fn fix(fix: CompositeFix<'a>) -> Self { - Self { kind: FixKind::SafeFix, message: None, fix } + Self { kind: FixKind::Fix, message: None, fix } } /// Create a new suggestion @@ -80,6 +146,41 @@ impl<'a> RuleFix<'a> { Self { kind: FixKind::DangerousFix, message: None, fix } } + /// Mark this [`RuleFix`] as dangerous. + /// + /// This is especially useful for fixer functions that are safe in some + /// cases but not in others. + /// + /// # Example + /// + /// ```ignore + /// use oxc_linter::fixer::{RuleFix, RuleFixer}; + /// use oxc_ast::ast::Expression; + /// + /// fn my_fixer<'a>(fixer: RuleFixer<'a>, bad_node: &Expression<'a>) -> RuleFix<'a> { + /// fixer.delete(bad_node).dangerously() + /// } + /// + /// is_dangerous(bad_node: &Expression<'_>) -> bool { + /// // some check on bad_node + /// # true + /// } + /// + /// fn maybe_dangerous_fixer<'a>(fixer: RuleFixer<'a>, bad_node: &Expression<'a>) -> RuleFix<'a> { + /// let fix = fixer.delete(bad_node); + /// if is_dangerous() { + /// fix.dangerously() + /// } else { + /// fix + /// } + /// } + /// ``` + pub fn dangerously(mut self) -> Self { + self.kind.set(FixKind::Dangerous, true); + self + } + + #[inline] pub fn with_message>>(mut self, message: S) -> Self { self.message = Some(message.into()); self @@ -95,12 +196,12 @@ impl<'a> RuleFix<'a> { self.message.as_deref() } - #[must_use] #[inline] pub fn into_fix(self, source_text: &str) -> Fix<'a> { self.fix.normalize_fixes(source_text) } + #[inline] pub fn extend>>(mut self, fix: F) -> Self { self.fix = self.fix.concat(fix.into()); self @@ -187,11 +288,12 @@ impl<'a> From>> for CompositeFix<'a> { } impl<'a> From>> for CompositeFix<'a> { - fn from(fixes: Vec>) -> Self { - if fixes.is_empty() { - CompositeFix::None - } else { - CompositeFix::Multiple(fixes) + fn from(mut fixes: Vec>) -> Self { + match fixes.len() { + 0 => CompositeFix::None, + // fixes[0] doesn't correctly move the vec's entry + 1 => CompositeFix::Single(fixes.pop().unwrap()), + _ => CompositeFix::Multiple(fixes), } } } @@ -219,6 +321,7 @@ impl<'a> CompositeFix<'a> { } } + #[cold] #[must_use] pub fn concat(self, fix: CompositeFix<'a>) -> Self { match (self, fix) { @@ -333,3 +436,30 @@ impl<'a> CompositeFix<'a> { Fix::new(output, Span::new(start, end)) } } + +#[cfg(test)] +mod test { + use super::*; + + #[test] + fn test_none() { + assert!(FixKind::None.is_none()); + assert!(!FixKind::SafeFix.is_none()); + assert_eq!(FixKind::default(), FixKind::None); + } + + #[test] + fn test_can_apply() { + assert!(FixKind::SafeFix.can_apply(FixKind::SafeFix)); + assert!(!FixKind::SafeFix.can_apply(FixKind::Suggestion)); + assert!(!FixKind::SafeFix.can_apply(FixKind::DangerousFix)); + + assert!(FixKind::DangerousFix.can_apply(FixKind::SafeFix)); + assert!(FixKind::DangerousFix.can_apply(FixKind::DangerousFix)); + assert!(!FixKind::DangerousFix.can_apply(FixKind::Suggestion)); + + assert!(!FixKind::None.can_apply(FixKind::SafeFix)); + assert!(!FixKind::None.can_apply(FixKind::Suggestion)); + assert!(!FixKind::None.can_apply(FixKind::DangerousFix)); + } +} diff --git a/crates/oxc_linter/src/fixer/mod.rs b/crates/oxc_linter/src/fixer/mod.rs index 1e34611e089b73..ab0bbb01ef905c 100644 --- a/crates/oxc_linter/src/fixer/mod.rs +++ b/crates/oxc_linter/src/fixer/mod.rs @@ -1,6 +1,6 @@ mod fix; -use std::borrow::Cow; +use std::borrow::{Borrow, Cow}; use oxc_codegen::{CodeGenerator, CodegenOptions}; use oxc_diagnostics::OxcDiagnostic; @@ -14,6 +14,7 @@ pub use fix::{CompositeFix, Fix, FixKind, RuleFix}; /// /// [`RuleFixer`]: https://github.com/eslint/eslint/blob/main/lib/linter/rule-fixer.js #[derive(Clone, Copy)] +#[must_use] pub struct RuleFixer<'c, 'a: 'c> { /// What kind of fixes will factory methods produce? /// @@ -25,7 +26,7 @@ pub struct RuleFixer<'c, 'a: 'c> { /// Auto-messaging is useful for single fixes, but not so much when we know /// multiple fixes will be applied. Some [`RuleFix`] factory methods /// allocate strings on the heap, which would then just get thrown away. - /// Turning this off prevents uneeded allocations. + /// Turning this off prevents unneeded allocations. /// /// Defaults to `true` auto_message: bool, @@ -33,6 +34,11 @@ pub struct RuleFixer<'c, 'a: 'c> { } impl<'c, 'a: 'c> RuleFixer<'c, 'a> { + /// Maximum length code snippets can be inside auto-created messages before + /// they get truncated. Prevents the terminal from getting flooded when a + /// replacement covers a large span. + const MAX_SNIPPET_LEN: usize = 256; + pub(super) fn new(kind: FixKind, ctx: &'c LintContext<'a>) -> Self { Self { kind, auto_message: true, ctx } } @@ -41,8 +47,7 @@ impl<'c, 'a: 'c> RuleFixer<'c, 'a> { /// containing more than one [`Fix`]. /// /// Calling this method in such cases is _highly recommended_ as it has a - /// sizeable performance impact, but is not _stricly_ necessary. - #[must_use] + /// sizeable performance impact, but is not _strictly_ necessary. pub fn for_multifix(mut self) -> Self { self.auto_message = false; self @@ -87,7 +92,9 @@ impl<'c, 'a: 'c> RuleFixer<'c, 'a> { let replacement_text = self.ctx.source_range(replacement.span()); let fix = Fix::new(replacement_text, target.span()); let message = self.auto_message.then(|| { - let target_text = self.ctx.source_range(target.span()); + let target_text = self.possibly_truncate_range(target.span()); + let borrowed_replacement = Cow::Borrowed(replacement_text); + let replacement_text = self.possibly_truncate_snippet(&borrowed_replacement); Cow::Owned(format!("Replace `{target_text}` with `{replacement_text}`.")) }); @@ -98,10 +105,11 @@ impl<'c, 'a: 'c> RuleFixer<'c, 'a> { #[allow(clippy::unused_self)] pub fn replace>>(&self, target: Span, replacement: S) -> RuleFix<'a> { let fix = Fix::new(replacement, target); - let target_text = self.ctx.source_range(target); + let target_text = self.possibly_truncate_range(target); + let content = self.possibly_truncate_snippet(&fix.content); let message = self .auto_message - .then(|| Cow::Owned(format!("Replace `{target_text}` code with `{}`.", &fix.content))); + .then(|| Cow::Owned(format!("Replace `{target_text}` with `{content}`."))); self.new_fix(CompositeFix::Single(fix), message) } @@ -150,7 +158,8 @@ impl<'c, 'a: 'c> RuleFixer<'c, 'a> { #[allow(clippy::unused_self)] fn insert_text_at>>(&self, index: u32, text: S) -> RuleFix<'a> { let fix = Fix::new(text, Span::new(index, index)); - let message = self.auto_message.then(|| Cow::Owned(format!("Insert `{}`", &fix.content))); + let content = self.possibly_truncate_snippet(&fix.content); + let message = self.auto_message.then(|| Cow::Owned(format!("Insert `{}`", content))); self.new_fix(CompositeFix::Single(fix), message) } @@ -164,6 +173,37 @@ impl<'c, 'a: 'c> RuleFixer<'c, 'a> { pub fn noop(&self) -> RuleFix<'a> { self.new_fix(CompositeFix::None, None) } + + fn possibly_truncate_range(&self, span: Span) -> Cow<'a, str> { + let snippet = self.ctx.source_range(span); + if snippet.len() > Self::MAX_SNIPPET_LEN { + let substring = match snippet.char_indices().nth(Self::MAX_SNIPPET_LEN) { + Some((pos, _)) => Cow::Borrowed(&snippet[..pos]), + // slow path when MAX_SNIPPET_LEN is on a UTF-8 character boundary + None => Cow::Owned(snippet.chars().take(Self::MAX_SNIPPET_LEN).collect()), + }; + substring + "..." + } else { + Cow::Borrowed(snippet) + } + } + + #[allow(clippy::unused_self)] + fn possibly_truncate_snippet<'s>(&self, snippet: &'s Cow<'a, str>) -> Cow<'s, str> + where + 'a: 's, + { + if snippet.len() > Self::MAX_SNIPPET_LEN { + let substring = match snippet.char_indices().nth(Self::MAX_SNIPPET_LEN) { + Some((pos, _)) => Cow::Borrowed(&snippet[..pos]), + // slow path when MAX_SNIPPET_LEN is on a UTF-8 character boundary + None => Cow::Owned(snippet.chars().take(Self::MAX_SNIPPET_LEN).collect()), + }; + substring + "..." + } else { + Cow::Borrowed(snippet.borrow()) + } + } } pub struct FixResult<'a> { diff --git a/crates/oxc_linter/src/lib.rs b/crates/oxc_linter/src/lib.rs index 4b3434a4a272df..372d799ced51b4 100644 --- a/crates/oxc_linter/src/lib.rs +++ b/crates/oxc_linter/src/lib.rs @@ -85,10 +85,19 @@ impl Linter { self } - /// Enable/disable automatic code fixes. + /// Set the kind of auto fixes to apply. + /// + /// # Example + /// + /// ``` + /// use oxc_linter::{Linter, FixKind}; + /// + /// // turn off all auto fixes. This is default behavior. + /// Linter::default().with_fix(FixKind::None); + /// ``` #[must_use] - pub fn with_fix(mut self, yes: Option) -> Self { - self.options.fix = yes; + pub fn with_fix(mut self, kind: FixKind) -> Self { + self.options.fix = kind; self } diff --git a/crates/oxc_linter/src/options.rs b/crates/oxc_linter/src/options.rs index 3d44f14e765dd3..b15f85cb6dca82 100644 --- a/crates/oxc_linter/src/options.rs +++ b/crates/oxc_linter/src/options.rs @@ -19,7 +19,7 @@ pub struct LintOptions { /// Enable automatic code fixes. Set to [`None`] to disable. /// /// The kind represents the riskiest fix that the linter can apply. - pub fix: Option, + pub fix: FixKind, pub react_plugin: bool, pub unicorn_plugin: bool, @@ -39,7 +39,7 @@ impl Default for LintOptions { Self { filter: vec![(AllowWarnDeny::Warn, String::from("correctness"))], config_path: None, - fix: None, + fix: FixKind::None, react_plugin: true, unicorn_plugin: true, typescript_plugin: true, @@ -70,9 +70,19 @@ impl LintOptions { self } + /// Set the kind of auto fixes to apply. + /// + /// # Example + /// + /// ``` + /// use oxc_linter::{LintOptions, FixKind}; + /// + /// // turn off all auto fixes. This is default behavior. + /// LintOptions::default().with_fix(FixKind::None); + /// ``` #[must_use] - pub fn with_fix(mut self, yes: Option) -> Self { - self.fix = yes; + pub fn with_fix(mut self, kind: FixKind) -> Self { + self.fix = kind; self } diff --git a/crates/oxc_linter/src/rules/unicorn/no_useless_promise_resolve_reject.rs b/crates/oxc_linter/src/rules/unicorn/no_useless_promise_resolve_reject.rs index 3f6e5dd2fb3091..fa0ace02fe1b2e 100644 --- a/crates/oxc_linter/src/rules/unicorn/no_useless_promise_resolve_reject.rs +++ b/crates/oxc_linter/src/rules/unicorn/no_useless_promise_resolve_reject.rs @@ -9,7 +9,7 @@ use oxc_span::{GetSpan, Span}; use crate::{ ast_util::outermost_paren_parent, context::LintContext, - fixer::{Fix, RuleFixer}, + fixer::{RuleFix, RuleFixer}, rule::Rule, AstNode, }; @@ -223,7 +223,7 @@ fn generate_fix<'a>( fixer: RuleFixer<'_, 'a>, ctx: &LintContext<'a>, node: &AstNode<'a>, -) -> Fix<'a> { +) -> RuleFix<'a> { if call_expr.arguments.len() > 1 { return fixer.noop(); } diff --git a/crates/oxc_linter/src/snapshots/array_type.snap b/crates/oxc_linter/src/snapshots/array_type.snap index 5e9fea2bc8a204..13be26fb6c1f61 100644 --- a/crates/oxc_linter/src/snapshots/array_type.snap +++ b/crates/oxc_linter/src/snapshots/array_type.snap @@ -6,354 +6,413 @@ source: crates/oxc_linter/src/tester.rs 1 │ let a: Array = []; · ───────────── ╰──── + help: Replace `Array` with `number[]`. ⚠ typescript-eslint(array-type): Array type using 'Array' is forbidden. Use 'T[]' instead. ╭─[array_type.tsx:1:8] 1 │ let a: Array = []; · ────────────────────── ╰──── + help: Replace `Array` with `(string | number)[]`. ⚠ typescript-eslint(array-type): Array type using 'ReadonlyArray' is forbidden. Use 'readonly number[]' instead. ╭─[array_type.tsx:1:8] 1 │ let a: ReadonlyArray = []; · ───────────────────── ╰──── + help: Replace `ReadonlyArray` with `readonly number[]`. ⚠ typescript-eslint(array-type): Array type using 'ReadonlyArray' is forbidden. Use 'readonly T[]' instead. ╭─[array_type.tsx:1:8] 1 │ let a: ReadonlyArray = []; · ────────────────────────────── ╰──── + help: Replace `ReadonlyArray` with `readonly (string | number)[]`. ⚠ typescript-eslint(array-type): Array type using 'Array' is forbidden. Use 'number[]' instead. ╭─[array_type.tsx:1:8] 1 │ let a: Array = []; · ───────────── ╰──── + help: Replace `Array` with `number[]`. ⚠ typescript-eslint(array-type): Array type using 'Array' is forbidden. Use 'T[]' instead. ╭─[array_type.tsx:1:8] 1 │ let a: Array = []; · ────────────────────── ╰──── + help: Replace `Array` with `(string | number)[]`. ⚠ typescript-eslint(array-type): Array type using 'ReadonlyArray' is forbidden. Use 'readonly number[]' instead. ╭─[array_type.tsx:1:8] 1 │ let a: ReadonlyArray = []; · ───────────────────── ╰──── + help: Replace `ReadonlyArray` with `readonly number[]`. ⚠ typescript-eslint(array-type): Array type using 'ReadonlyArray' is forbidden. Use 'readonly T[]' instead. ╭─[array_type.tsx:1:8] 1 │ let a: ReadonlyArray = []; · ────────────────────────────── ╰──── + help: Replace `ReadonlyArray` with `readonly (string | number)[]`. ⚠ typescript-eslint(array-type): Array type using 'Array' is forbidden. Use 'number[]' instead. ╭─[array_type.tsx:1:8] 1 │ let a: Array = []; · ───────────── ╰──── + help: Replace `Array` with `number[]`. ⚠ typescript-eslint(array-type): Array type using 'Array' is forbidden. Use 'T[]' instead. ╭─[array_type.tsx:1:8] 1 │ let a: Array = []; · ────────────────────── ╰──── + help: Replace `Array` with `(string | number)[]`. ⚠ typescript-eslint(array-type): Array type using 'ReadonlyArray' is forbidden for simple types. Use 'readonly number[]' instead. ╭─[array_type.tsx:1:8] 1 │ let a: ReadonlyArray = []; · ───────────────────── ╰──── + help: Replace `ReadonlyArray` with `readonly number[]`. ⚠ typescript-eslint(array-type): Array type using 'readonly T[]' is forbidden for non-simple types. Use 'ReadonlyArray' instead. ╭─[array_type.tsx:1:8] 1 │ let a: readonly (string | number)[] = []; · ──────────────────────────── ╰──── + help: Replace `readonly (string | number)[]` with `ReadonlyArray`. ⚠ typescript-eslint(array-type): Array type using 'Array' is forbidden. Use 'number[]' instead. ╭─[array_type.tsx:1:8] 1 │ let a: Array = []; · ───────────── ╰──── + help: Replace `Array` with `number[]`. ⚠ typescript-eslint(array-type): Array type using 'Array' is forbidden. Use 'T[]' instead. ╭─[array_type.tsx:1:8] 1 │ let a: Array = []; · ────────────────────── ╰──── + help: Replace `Array` with `(string | number)[]`. ⚠ typescript-eslint(array-type): Array type using 'readonly number[]' is forbidden. Use 'ReadonlyArray' instead. ╭─[array_type.tsx:1:8] 1 │ let a: readonly number[] = []; · ───────────────── ╰──── + help: Replace `readonly number[]` with `ReadonlyArray`. ⚠ typescript-eslint(array-type): Array type using 'readonly T[]' is forbidden. Use 'ReadonlyArray' instead. ╭─[array_type.tsx:1:8] 1 │ let a: readonly (string | number)[] = []; · ──────────────────────────── ╰──── + help: Replace `readonly (string | number)[]` with `ReadonlyArray`. ⚠ typescript-eslint(array-type): Array type using 'Array' is forbidden for simple types. Use 'number[]' instead. ╭─[array_type.tsx:1:8] 1 │ let a: Array = []; · ───────────── ╰──── + help: Replace `Array` with `number[]`. ⚠ typescript-eslint(array-type): Array type using 'T[]' is forbidden for non-simple types. Use 'Array' instead. ╭─[array_type.tsx:1:8] 1 │ let a: (string | number)[] = []; · ─────────────────── ╰──── + help: Replace `(string | number)[]` with `Array`. ⚠ typescript-eslint(array-type): Array type using 'ReadonlyArray' is forbidden for simple types. Use 'readonly number[]' instead. ╭─[array_type.tsx:1:8] 1 │ let a: ReadonlyArray = []; · ───────────────────── ╰──── + help: Replace `ReadonlyArray` with `readonly number[]`. ⚠ typescript-eslint(array-type): Array type using 'readonly T[]' is forbidden for non-simple types. Use 'ReadonlyArray' instead. ╭─[array_type.tsx:1:8] 1 │ let a: readonly (string | number)[] = []; · ──────────────────────────── ╰──── + help: Replace `readonly (string | number)[]` with `ReadonlyArray`. ⚠ typescript-eslint(array-type): Array type using 'Array' is forbidden for simple types. Use 'number[]' instead. ╭─[array_type.tsx:1:8] 1 │ let a: Array = []; · ───────────── ╰──── + help: Replace `Array` with `number[]`. ⚠ typescript-eslint(array-type): Array type using 'T[]' is forbidden for non-simple types. Use 'Array' instead. ╭─[array_type.tsx:1:8] 1 │ let a: (string | number)[] = []; · ─────────────────── ╰──── + help: Replace `(string | number)[]` with `Array`. ⚠ typescript-eslint(array-type): Array type using 'ReadonlyArray' is forbidden. Use 'readonly number[]' instead. ╭─[array_type.tsx:1:8] 1 │ let a: ReadonlyArray = []; · ───────────────────── ╰──── + help: Replace `ReadonlyArray` with `readonly number[]`. ⚠ typescript-eslint(array-type): Array type using 'ReadonlyArray' is forbidden. Use 'readonly T[]' instead. ╭─[array_type.tsx:1:8] 1 │ let a: ReadonlyArray = []; · ────────────────────────────── ╰──── + help: Replace `ReadonlyArray` with `readonly (string | number)[]`. ⚠ typescript-eslint(array-type): Array type using 'Array' is forbidden for simple types. Use 'number[]' instead. ╭─[array_type.tsx:1:8] 1 │ let a: Array = []; · ───────────── ╰──── + help: Replace `Array` with `number[]`. ⚠ typescript-eslint(array-type): Array type using 'T[]' is forbidden for non-simple types. Use 'Array' instead. ╭─[array_type.tsx:1:8] 1 │ let a: (string | number)[] = []; · ─────────────────── ╰──── + help: Replace `(string | number)[]` with `Array`. ⚠ typescript-eslint(array-type): Array type using 'ReadonlyArray' is forbidden for simple types. Use 'readonly number[]' instead. ╭─[array_type.tsx:1:8] 1 │ let a: ReadonlyArray = []; · ───────────────────── ╰──── + help: Replace `ReadonlyArray` with `readonly number[]`. ⚠ typescript-eslint(array-type): Array type using 'readonly T[]' is forbidden for non-simple types. Use 'ReadonlyArray' instead. ╭─[array_type.tsx:1:8] 1 │ let a: readonly (string | number)[] = []; · ──────────────────────────── ╰──── + help: Replace `readonly (string | number)[]` with `ReadonlyArray`. ⚠ typescript-eslint(array-type): Array type using 'Array' is forbidden for simple types. Use 'number[]' instead. ╭─[array_type.tsx:1:8] 1 │ let a: Array = []; · ───────────── ╰──── + help: Replace `Array` with `number[]`. ⚠ typescript-eslint(array-type): Array type using 'T[]' is forbidden for non-simple types. Use 'Array' instead. ╭─[array_type.tsx:1:8] 1 │ let a: (string | number)[] = []; · ─────────────────── ╰──── + help: Replace `(string | number)[]` with `Array`. ⚠ typescript-eslint(array-type): Array type using 'readonly number[]' is forbidden. Use 'ReadonlyArray' instead. ╭─[array_type.tsx:1:8] 1 │ let a: readonly number[] = []; · ───────────────── ╰──── + help: Replace `readonly number[]` with `ReadonlyArray`. ⚠ typescript-eslint(array-type): Array type using 'readonly T[]' is forbidden. Use 'ReadonlyArray' instead. ╭─[array_type.tsx:1:8] 1 │ let a: readonly (string | number)[] = []; · ──────────────────────────── ╰──── + help: Replace `readonly (string | number)[]` with `ReadonlyArray`. ⚠ typescript-eslint(array-type): Array type using 'number[]' is forbidden. Use 'Array' instead. ╭─[array_type.tsx:1:8] 1 │ let a: number[] = []; · ──────── ╰──── + help: Replace `number[]` with `Array`. ⚠ typescript-eslint(array-type): Array type using 'T[]' is forbidden. Use 'Array' instead. ╭─[array_type.tsx:1:8] 1 │ let a: (string | number)[] = []; · ─────────────────── ╰──── + help: Replace `(string | number)[]` with `Array`. ⚠ typescript-eslint(array-type): Array type using 'readonly number[]' is forbidden. Use 'ReadonlyArray' instead. ╭─[array_type.tsx:1:8] 1 │ let a: readonly number[] = []; · ───────────────── ╰──── + help: Replace `readonly number[]` with `ReadonlyArray`. ⚠ typescript-eslint(array-type): Array type using 'readonly T[]' is forbidden. Use 'ReadonlyArray' instead. ╭─[array_type.tsx:1:8] 1 │ let a: readonly (string | number)[] = []; · ──────────────────────────── ╰──── + help: Replace `readonly (string | number)[]` with `ReadonlyArray`. ⚠ typescript-eslint(array-type): Array type using 'number[]' is forbidden. Use 'Array' instead. ╭─[array_type.tsx:1:8] 1 │ let a: number[] = []; · ──────── ╰──── + help: Replace `number[]` with `Array`. ⚠ typescript-eslint(array-type): Array type using 'T[]' is forbidden. Use 'Array' instead. ╭─[array_type.tsx:1:8] 1 │ let a: (string | number)[] = []; · ─────────────────── ╰──── + help: Replace `(string | number)[]` with `Array`. ⚠ typescript-eslint(array-type): Array type using 'ReadonlyArray' is forbidden. Use 'readonly number[]' instead. ╭─[array_type.tsx:1:8] 1 │ let a: ReadonlyArray = []; · ───────────────────── ╰──── + help: Replace `ReadonlyArray` with `readonly number[]`. ⚠ typescript-eslint(array-type): Array type using 'ReadonlyArray' is forbidden. Use 'readonly T[]' instead. ╭─[array_type.tsx:1:8] 1 │ let a: ReadonlyArray = []; · ────────────────────────────── ╰──── + help: Replace `ReadonlyArray` with `readonly (string | number)[]`. ⚠ typescript-eslint(array-type): Array type using 'number[]' is forbidden. Use 'Array' instead. ╭─[array_type.tsx:1:8] 1 │ let a: number[] = []; · ──────── ╰──── + help: Replace `number[]` with `Array`. ⚠ typescript-eslint(array-type): Array type using 'T[]' is forbidden. Use 'Array' instead. ╭─[array_type.tsx:1:8] 1 │ let a: (string | number)[] = []; · ─────────────────── ╰──── + help: Replace `(string | number)[]` with `Array`. ⚠ typescript-eslint(array-type): Array type using 'ReadonlyArray' is forbidden for simple types. Use 'readonly number[]' instead. ╭─[array_type.tsx:1:8] 1 │ let a: ReadonlyArray = []; · ───────────────────── ╰──── + help: Replace `ReadonlyArray` with `readonly number[]`. ⚠ typescript-eslint(array-type): Array type using 'readonly T[]' is forbidden for non-simple types. Use 'ReadonlyArray' instead. ╭─[array_type.tsx:1:8] 1 │ let a: readonly (string | number)[] = []; · ──────────────────────────── ╰──── + help: Replace `readonly (string | number)[]` with `ReadonlyArray`. ⚠ typescript-eslint(array-type): Array type using 'number[]' is forbidden. Use 'Array' instead. ╭─[array_type.tsx:1:8] 1 │ let a: number[] = []; · ──────── ╰──── + help: Replace `number[]` with `Array`. ⚠ typescript-eslint(array-type): Array type using 'T[]' is forbidden. Use 'Array' instead. ╭─[array_type.tsx:1:8] 1 │ let a: (string | number)[] = []; · ─────────────────── ╰──── + help: Replace `(string | number)[]` with `Array`. ⚠ typescript-eslint(array-type): Array type using 'readonly number[]' is forbidden. Use 'ReadonlyArray' instead. ╭─[array_type.tsx:1:8] 1 │ let a: readonly number[] = []; · ───────────────── ╰──── + help: Replace `readonly number[]` with `ReadonlyArray`. ⚠ typescript-eslint(array-type): Array type using 'readonly T[]' is forbidden. Use 'ReadonlyArray' instead. ╭─[array_type.tsx:1:8] 1 │ let a: readonly (string | number)[] = []; · ──────────────────────────── ╰──── + help: Replace `readonly (string | number)[]` with `ReadonlyArray`. ⚠ typescript-eslint(array-type): Array type using 'bigint[]' is forbidden. Use 'Array' instead. ╭─[array_type.tsx:1:8] 1 │ let a: bigint[] = []; · ──────── ╰──── + help: Replace `bigint[]` with `Array`. ⚠ typescript-eslint(array-type): Array type using 'T[]' is forbidden. Use 'Array' instead. ╭─[array_type.tsx:1:8] 1 │ let a: (string | bigint)[] = []; · ─────────────────── ╰──── + help: Replace `(string | bigint)[]` with `Array`. ⚠ typescript-eslint(array-type): Array type using 'ReadonlyArray' is forbidden for simple types. Use 'readonly bigint[]' instead. ╭─[array_type.tsx:1:8] 1 │ let a: ReadonlyArray = []; · ───────────────────── ╰──── + help: Replace `ReadonlyArray` with `readonly bigint[]`. ⚠ typescript-eslint(array-type): Array type using 'T[]' is forbidden. Use 'Array' instead. ╭─[array_type.tsx:1:8] 1 │ let a: (string | bigint)[] = []; · ─────────────────── ╰──── + help: Replace `(string | bigint)[]` with `Array`. ⚠ typescript-eslint(array-type): Array type using 'readonly bigint[]' is forbidden. Use 'ReadonlyArray' instead. ╭─[array_type.tsx:1:8] 1 │ let a: readonly bigint[] = []; · ───────────────── ╰──── + help: Replace `readonly bigint[]` with `ReadonlyArray`. ⚠ typescript-eslint(array-type): Array type using 'readonly T[]' is forbidden. Use 'ReadonlyArray' instead. ╭─[array_type.tsx:1:8] 1 │ let a: readonly (string | bigint)[] = []; · ──────────────────────────── ╰──── + help: Replace `readonly (string | bigint)[]` with `ReadonlyArray`. ⚠ typescript-eslint(array-type): Array type using 'Array' is forbidden. Use 'Bar[]' instead. ╭─[array_type.tsx:1:15] 1 │ let a: { foo: Array }[] = []; · ────────── ╰──── + help: Replace `Array` with `Bar[]`. ⚠ typescript-eslint(array-type): Array type using 'Bar[]' is forbidden. Use 'Array' instead. ╭─[array_type.tsx:1:21] 1 │ let a: Array<{ foo: Bar[] }> = []; · ───── ╰──── + help: Replace `Bar[]` with `Array`. ⚠ typescript-eslint(array-type): Array type using 'Array' is forbidden. Use 'Bar[]' instead. ╭─[array_type.tsx:1:17] 1 │ function foo(a: Array): Array {} · ────────── ╰──── + help: Replace `Array` with `Bar[]`. ⚠ typescript-eslint(array-type): Array type using 'Array' is forbidden. Use 'Bar[]' instead. ╭─[array_type.tsx:1:30] 1 │ function foo(a: Array): Array {} · ────────── ╰──── + help: Replace `Array` with `Bar[]`. ⚠ typescript-eslint(array-type): Array type using 'Array' is forbidden for simple types. Use 'undefined[]' instead. ╭─[array_type.tsx:1:8] 1 │ let x: Array = [undefined] as undefined[]; · ──────────────── ╰──── + help: Replace `Array` with `undefined[]`. × Expected `<` but found `EOF` ╭─[array_type.tsx:1:40] @@ -365,18 +424,21 @@ source: crates/oxc_linter/src/tester.rs 1 │ let z: Array = [3, '4']; · ───── ╰──── + help: Replace `Array` with `any[]`. ⚠ typescript-eslint(array-type): Array type using 'T[]' is forbidden for non-simple types. Use 'Array' instead. ╭─[array_type.tsx:1:24] 1 │ let ya = [[1, '2']] as [number, string][]; · ────────────────── ╰──── + help: Replace `[number, string][]` with `Array<[number, string]>`. ⚠ typescript-eslint(array-type): Array type using 'Array' is forbidden for simple types. Use 'T[]' instead. ╭─[array_type.tsx:1:15] 1 │ type Arr = Array; · ──────── ╰──── + help: Replace `Array` with `T[]`. ⚠ typescript-eslint(array-type): Array type using 'Array' is forbidden for simple types. Use 'T[]' instead. ╭─[array_type.tsx:3:14] @@ -385,6 +447,7 @@ source: crates/oxc_linter/src/tester.rs · ──────── 4 │ bar: T[]; ╰──── + help: Replace `Array` with `T[]`. ⚠ typescript-eslint(array-type): Array type using 'T[]' is forbidden for non-simple types. Use 'Array' instead. ╭─[array_type.tsx:2:35] @@ -393,30 +456,35 @@ source: crates/oxc_linter/src/tester.rs · ──────────────────── 3 │ return bar.map(e => e.bar); ╰──── + help: Replace `ArrayClass[]` with `Array>`. ⚠ typescript-eslint(array-type): Array type using 'T[]' is forbidden for non-simple types. Use 'Array' instead. ╭─[array_type.tsx:1:13] 1 │ let barVar: ((c: number) => number)[]; · ───────────────────────── ╰──── + help: Replace `((c: number) => number)[]` with `Array<(c: number) => number>`. ⚠ typescript-eslint(array-type): Array type using 'T[]' is forbidden for non-simple types. Use 'Array' instead. ╭─[array_type.tsx:1:17] 1 │ type barUnion = (string | number | boolean)[]; · ───────────────────────────── ╰──── + help: Replace `(string | number | boolean)[]` with `Array`. ⚠ typescript-eslint(array-type): Array type using 'T[]' is forbidden for non-simple types. Use 'Array' instead. ╭─[array_type.tsx:1:24] 1 │ type barIntersection = (string & number)[]; · ─────────────────── ╰──── + help: Replace `(string & number)[]` with `Array`. ⚠ typescript-eslint(array-type): Array type using 'Array' is forbidden. Use 'undefined[]' instead. ╭─[array_type.tsx:1:8] 1 │ let x: Array = [undefined] as undefined[]; · ──────────────── ╰──── + help: Replace `Array` with `undefined[]`. × Expected `<` but found `EOF` ╭─[array_type.tsx:1:40] @@ -428,12 +496,14 @@ source: crates/oxc_linter/src/tester.rs 1 │ let z: Array = [3, '4']; · ───── ╰──── + help: Replace `Array` with `any[]`. ⚠ typescript-eslint(array-type): Array type using 'Array' is forbidden. Use 'T[]' instead. ╭─[array_type.tsx:1:15] 1 │ type Arr = Array; · ──────── ╰──── + help: Replace `Array` with `T[]`. ⚠ typescript-eslint(array-type): Array type using 'Array' is forbidden. Use 'T[]' instead. ╭─[array_type.tsx:3:14] @@ -442,6 +512,7 @@ source: crates/oxc_linter/src/tester.rs · ──────── 4 │ bar: T[]; ╰──── + help: Replace `Array` with `T[]`. ⚠ typescript-eslint(array-type): Array type using 'Array' is forbidden. Use 'T[]' instead. ╭─[array_type.tsx:2:35] @@ -450,54 +521,63 @@ source: crates/oxc_linter/src/tester.rs · ───────────────────────── 3 │ return foo.map(e => e.foo); ╰──── + help: Replace `Array>` with `ArrayClass[]`. ⚠ typescript-eslint(array-type): Array type using 'Array' is forbidden. Use 'T[]' instead. ╭─[array_type.tsx:1:13] 1 │ let fooVar: Array<(c: number) => number>; · ──────────────────────────── ╰──── + help: Replace `Array<(c: number) => number>` with `((c: number) => number)[]`. ⚠ typescript-eslint(array-type): Array type using 'Array' is forbidden. Use 'T[]' instead. ╭─[array_type.tsx:1:17] 1 │ type fooUnion = Array; · ──────────────────────────────── ╰──── + help: Replace `Array` with `(string | number | boolean)[]`. ⚠ typescript-eslint(array-type): Array type using 'Array' is forbidden. Use 'T[]' instead. ╭─[array_type.tsx:1:24] 1 │ type fooIntersection = Array; · ────────────────────── ╰──── + help: Replace `Array` with `(string & number)[]`. ⚠ typescript-eslint(array-type): Array type using 'Array' is forbidden. Use 'any[]' instead. ╭─[array_type.tsx:1:8] 1 │ let x: Array; · ───── ╰──── + help: Replace `Array` with `any[]`. ⚠ typescript-eslint(array-type): Array type using 'Array' is forbidden. Use 'any[]' instead. ╭─[array_type.tsx:1:8] 1 │ let x: Array<>; · ─────── ╰──── + help: Replace `Array<>` with `any[]`. ⚠ typescript-eslint(array-type): Array type using 'Array' is forbidden for simple types. Use 'any[]' instead. ╭─[array_type.tsx:1:8] 1 │ let x: Array; · ───── ╰──── + help: Replace `Array` with `any[]`. ⚠ typescript-eslint(array-type): Array type using 'Array' is forbidden for simple types. Use 'any[]' instead. ╭─[array_type.tsx:1:8] 1 │ let x: Array<>; · ─────── ╰──── + help: Replace `Array<>` with `any[]`. ⚠ typescript-eslint(array-type): Array type using 'number[]' is forbidden. Use 'Array' instead. ╭─[array_type.tsx:1:31] 1 │ let x: Array = [1] as number[]; · ──────── ╰──── + help: Replace `number[]` with `Array`. × Expected `<` but found `EOF` ╭─[array_type.tsx:1:40] @@ -509,6 +589,7 @@ source: crates/oxc_linter/src/tester.rs 1 │ let ya = [[1, '2']] as [number, string][]; · ────────────────── ╰──── + help: Replace `[number, string][]` with `Array<[number, string]>`. ⚠ typescript-eslint(array-type): Array type using 'T[]' is forbidden. Use 'Array' instead. ╭─[array_type.tsx:4:14] @@ -517,6 +598,7 @@ source: crates/oxc_linter/src/tester.rs · ─── 5 │ baz: Arr; ╰──── + help: Replace `T[]` with `Array`. ⚠ typescript-eslint(array-type): Array type using 'T[]' is forbidden. Use 'Array' instead. ╭─[array_type.tsx:2:35] @@ -525,24 +607,28 @@ source: crates/oxc_linter/src/tester.rs · ──────────────────── 3 │ return bar.map(e => e.bar); ╰──── + help: Replace `ArrayClass[]` with `Array>`. ⚠ typescript-eslint(array-type): Array type using 'T[]' is forbidden. Use 'Array' instead. ╭─[array_type.tsx:1:13] 1 │ let barVar: ((c: number) => number)[]; · ───────────────────────── ╰──── + help: Replace `((c: number) => number)[]` with `Array<(c: number) => number>`. ⚠ typescript-eslint(array-type): Array type using 'T[]' is forbidden. Use 'Array' instead. ╭─[array_type.tsx:1:17] 1 │ type barUnion = (string | number | boolean)[]; · ───────────────────────────── ╰──── + help: Replace `(string | number | boolean)[]` with `Array`. ⚠ typescript-eslint(array-type): Array type using 'T[]' is forbidden. Use 'Array' instead. ╭─[array_type.tsx:1:24] 1 │ type barIntersection = (string & number)[]; · ─────────────────── ╰──── + help: Replace `(string & number)[]` with `Array`. ⚠ typescript-eslint(array-type): Array type using 'string[]' is forbidden. Use 'Array' instead. ╭─[array_type.tsx:3:24] @@ -551,15 +637,18 @@ source: crates/oxc_linter/src/tester.rs · ──────── 4 │ } ╰──── + help: Replace `string[]` with `Array`. ⚠ typescript-eslint(array-type): Array type using 'Array' is forbidden. Use 'T[]' instead. ╭─[array_type.tsx:1:12] 1 │ const foo: Array void> = []; · ─────────────────────────────────── ╰──── + help: Replace `Array void>` with `(new (...args: any[]) => void)[]`. ⚠ typescript-eslint(array-type): Array type using 'ReadonlyArray' is forbidden. Use 'readonly T[]' instead. ╭─[array_type.tsx:1:12] 1 │ const foo: ReadonlyArray void> = []; · ─────────────────────────────────────────── ╰──── + help: Replace `ReadonlyArray void>` with `readonly (new (...args: any[]) => void)[]`. diff --git a/crates/oxc_linter/src/snapshots/ban_tslint_comment.snap b/crates/oxc_linter/src/snapshots/ban_tslint_comment.snap index 15505d38f7056b..a0f87008fe8260 100644 --- a/crates/oxc_linter/src/snapshots/ban_tslint_comment.snap +++ b/crates/oxc_linter/src/snapshots/ban_tslint_comment.snap @@ -6,42 +6,49 @@ source: crates/oxc_linter/src/tester.rs 1 │ /* tslint:disable */ · ──────────────────── ╰──── + help: Delete this code. ⚠ typescript-eslint(ban-tslint-comment): tslint comment detected: "tslint:enable" ╭─[ban_tslint_comment.tsx:1:1] 1 │ /* tslint:enable */ · ─────────────────── ╰──── + help: Delete this code. ⚠ typescript-eslint(ban-tslint-comment): tslint comment detected: "tslint:disable:rule1 rule2 rule3..." ╭─[ban_tslint_comment.tsx:1:1] 1 │ /* tslint:disable:rule1 rule2 rule3... */ · ───────────────────────────────────────── ╰──── + help: Delete this code. ⚠ typescript-eslint(ban-tslint-comment): tslint comment detected: "tslint:enable:rule1 rule2 rule3..." ╭─[ban_tslint_comment.tsx:1:1] 1 │ /* tslint:enable:rule1 rule2 rule3... */ · ──────────────────────────────────────── ╰──── + help: Delete this code. ⚠ typescript-eslint(ban-tslint-comment): tslint comment detected: "tslint:disable-next-line" ╭─[ban_tslint_comment.tsx:1:1] 1 │ // tslint:disable-next-line · ─────────────────────────── ╰──── + help: Delete this code. ⚠ typescript-eslint(ban-tslint-comment): tslint comment detected: "tslint:disable-line" ╭─[ban_tslint_comment.tsx:1:13] 1 │ someCode(); // tslint:disable-line · ────────────────────── ╰──── + help: Delete this code. ⚠ typescript-eslint(ban-tslint-comment): tslint comment detected: "tslint:disable-next-line:rule1 rule2 rule3..." ╭─[ban_tslint_comment.tsx:1:1] 1 │ // tslint:disable-next-line:rule1 rule2 rule3... · ──────────────────────────────────────────────── ╰──── + help: Delete this code. ⚠ typescript-eslint(ban-tslint-comment): tslint comment detected: "tslint:disable-line" ╭─[ban_tslint_comment.tsx:2:9] @@ -51,3 +58,4 @@ source: crates/oxc_linter/src/tester.rs 3 │ console.log(woah); 4 │ ╰──── + help: Delete this code. diff --git a/crates/oxc_linter/src/snapshots/consistent_type_imports.snap b/crates/oxc_linter/src/snapshots/consistent_type_imports.snap index 2712c36d353fab..ce6d107adebb00 100644 --- a/crates/oxc_linter/src/snapshots/consistent_type_imports.snap +++ b/crates/oxc_linter/src/snapshots/consistent_type_imports.snap @@ -296,6 +296,7 @@ source: crates/oxc_linter/src/tester.rs · ─────────────────────────── 3 │ let foo: Foo; ╰──── + help: Replace `import type Foo from 'foo';` with `import Foo from 'foo';`. ⚠ typescript-eslint(consistent-type-imports): Use an `import` instead of an `import type`. ╭─[consistent_type_imports.tsx:2:15] @@ -304,6 +305,7 @@ source: crates/oxc_linter/src/tester.rs · ─────────────────────────────── 3 │ let foo: Foo; ╰──── + help: Replace `import type { Foo } from 'foo';` with `import { Foo } from 'foo';`. ⚠ typescript-eslint(consistent-type-imports): All imports in the declaration are only used as types. Use `import type`. ╭─[consistent_type_imports.tsx:2:15] @@ -336,6 +338,7 @@ source: crates/oxc_linter/src/tester.rs · ──────────────────────────── 3 │ ╰──── + help: Replace `import type Type from 'foo';` with `import Type from 'foo';`. ⚠ typescript-eslint(consistent-type-imports): Use an `import` instead of an `import type`. ╭─[consistent_type_imports.tsx:2:15] @@ -344,6 +347,7 @@ source: crates/oxc_linter/src/tester.rs · ──────────────────────────────── 3 │ ╰──── + help: Replace `import type { Type } from 'foo';` with `import { Type } from 'foo';`. ⚠ typescript-eslint(consistent-type-imports): Use an `import` instead of an `import type`. ╭─[consistent_type_imports.tsx:2:15] @@ -352,6 +356,7 @@ source: crates/oxc_linter/src/tester.rs · ───────────────────────────────── 3 │ ╰──── + help: Replace `import type * as Type from 'foo';` with `import * as Type from 'foo';`. ⚠ typescript-eslint(consistent-type-imports): Use an `import` instead of an `import type`. ╭─[consistent_type_imports.tsx:2:15] @@ -360,6 +365,7 @@ source: crates/oxc_linter/src/tester.rs · ──────────────────────────────────────────────── 3 │ import type // comment ╰──── + help: Replace `import type /*comment*/ * as AllType from 'foo';` with `import /*comment*/ * as AllType from 'foo';`. ⚠ typescript-eslint(consistent-type-imports): Use an `import` instead of an `import type`. ╭─[consistent_type_imports.tsx:3:15] @@ -368,6 +374,9 @@ source: crates/oxc_linter/src/tester.rs 4 │ ╰─▶ DefType from 'foo'; 5 │ import type /*comment*/ { Type } from 'foo'; ╰──── + help: Replace `import type // comment + DefType from 'foo';` with `import // comment + DefType from 'foo';`. ⚠ typescript-eslint(consistent-type-imports): Use an `import` instead of an `import type`. ╭─[consistent_type_imports.tsx:5:15] @@ -376,6 +385,7 @@ source: crates/oxc_linter/src/tester.rs · ──────────────────────────────────────────── 6 │ ╰──── + help: Replace `import type /*comment*/ { Type } from 'foo';` with `import /*comment*/ { Type } from 'foo';`. ⚠ typescript-eslint(consistent-type-imports): Imports Rest are only used as type. ╭─[consistent_type_imports.tsx:2:15] @@ -424,6 +434,7 @@ source: crates/oxc_linter/src/tester.rs · ────── 3 │ type T = A; ╰──── + help: Replace `type A` with `A`. ⚠ typescript-eslint(consistent-type-imports): Imports A are only used as type. ╭─[consistent_type_imports.tsx:2:15] diff --git a/crates/oxc_linter/src/snapshots/escape_case.snap b/crates/oxc_linter/src/snapshots/escape_case.snap index e4d3764de19c5a..2d57ac5467eb42 100644 --- a/crates/oxc_linter/src/snapshots/escape_case.snap +++ b/crates/oxc_linter/src/snapshots/escape_case.snap @@ -6,45 +6,53 @@ source: crates/oxc_linter/src/tester.rs 1 │ const foo = "\xAab\xaab\xAAb\uAaAab\uaaaab\uAAAAb\u{AaAa}b\u{aaaa}b\u{AAAA}"; · ──────────────────────────────────────────────────────────────── ╰──── + help: Replace `"\xAab\xaab\xAAb\uAaAab\uaaaab\uAAAAb\u{AaAa}b\u{aaaa}b\u{AAAA}"` with `"\xAAb\xAAb\xAAb\uAAAAb\uAAAAb\uAAAAb\u{AAAA}b\u{AAAA}b\u{AAAA}"`. ⚠ eslint-plugin-unicorn(escape-case): Use uppercase characters for the value of the escape sequence. ╭─[escape_case.tsx:1:14] 1 │ const foo = `\xAab\xaab\xAA${foo}\uAaAab\uaaaab\uAAAAb\u{AaAa}${foo}\u{aaaa}b\u{AAAA}`; · ────────────── ╰──── + help: Replace `\xAab\xaab\xAA` with `\xAAb\xAAb\xAA`. ⚠ eslint-plugin-unicorn(escape-case): Use uppercase characters for the value of the escape sequence. ╭─[escape_case.tsx:1:34] 1 │ const foo = `\xAab\xaab\xAA${foo}\uAaAab\uaaaab\uAAAAb\u{AaAa}${foo}\u{aaaa}b\u{AAAA}`; · ───────────────────────────── ╰──── + help: Replace `\uAaAab\uaaaab\uAAAAb\u{AaAa}` with `\uAAAAb\uAAAAb\uAAAAb\u{AAAA}`. ⚠ eslint-plugin-unicorn(escape-case): Use uppercase characters for the value of the escape sequence. ╭─[escape_case.tsx:1:69] 1 │ const foo = `\xAab\xaab\xAA${foo}\uAaAab\uaaaab\uAAAAb\u{AaAa}${foo}\u{aaaa}b\u{AAAA}`; · ───────────────── ╰──── + help: Replace `\u{aaaa}b\u{AAAA}` with `\u{AAAA}b\u{AAAA}`. ⚠ eslint-plugin-unicorn(escape-case): Use uppercase characters for the value of the escape sequence. ╭─[escape_case.tsx:1:14] 1 │ const foo = `\ud834${foo}\ud834${foo}\ud834`; · ────── ╰──── + help: Replace `\ud834` with `\uD834`. ⚠ eslint-plugin-unicorn(escape-case): Use uppercase characters for the value of the escape sequence. ╭─[escape_case.tsx:1:26] 1 │ const foo = `\ud834${foo}\ud834${foo}\ud834`; · ────── ╰──── + help: Replace `\ud834` with `\uD834`. ⚠ eslint-plugin-unicorn(escape-case): Use uppercase characters for the value of the escape sequence. ╭─[escape_case.tsx:1:38] 1 │ const foo = `\ud834${foo}\ud834${foo}\ud834`; · ────── ╰──── + help: Replace `\ud834` with `\uD834`. ⚠ eslint-plugin-unicorn(escape-case): Use uppercase characters for the value of the escape sequence. ╭─[escape_case.tsx:1:24] 1 │ const foo = new RegExp("/\u{1d306}/", "u") · ───────────── ╰──── + help: Replace `"/\u{1d306}/"` with `"/\u{1D306}/"`. diff --git a/crates/oxc_linter/src/snapshots/explicit_length_check.snap b/crates/oxc_linter/src/snapshots/explicit_length_check.snap index 308a06cc9450cb..e3fb1306b7791a 100644 --- a/crates/oxc_linter/src/snapshots/explicit_length_check.snap +++ b/crates/oxc_linter/src/snapshots/explicit_length_check.snap @@ -20,6 +20,7 @@ source: crates/oxc_linter/src/tester.rs 1 │ bar(!foo.length || foo.length) · ─────────── ╰──── + help: Replace `!foo.length` with `foo.length === 0`. ⚠ eslint-plugin-unicorn(explicit-length-check): Use `.length > 0` when checking length is not zero. ╭─[explicit_length_check.tsx:1:20] @@ -68,3 +69,4 @@ source: crates/oxc_linter/src/tester.rs 1 │ let foo = arr.length ? 'non-empty' : 'empty' · ────────── ╰──── + help: Replace `arr.length` with `arr.length > 0`. diff --git a/crates/oxc_linter/src/snapshots/no_debugger.snap b/crates/oxc_linter/src/snapshots/no_debugger.snap index 2a2410922a3e66..103c585aa8d056 100644 --- a/crates/oxc_linter/src/snapshots/no_debugger.snap +++ b/crates/oxc_linter/src/snapshots/no_debugger.snap @@ -6,3 +6,4 @@ source: crates/oxc_linter/src/tester.rs 1 │ if (foo) debugger · ──────── ╰──── + help: Replace `debugger` with `{}`. diff --git a/crates/oxc_linter/src/snapshots/no_focused_tests.snap b/crates/oxc_linter/src/snapshots/no_focused_tests.snap index 92a25a26cbfc4a..cad6eace87d0b4 100644 --- a/crates/oxc_linter/src/snapshots/no_focused_tests.snap +++ b/crates/oxc_linter/src/snapshots/no_focused_tests.snap @@ -134,6 +134,7 @@ source: crates/oxc_linter/src/tester.rs · ──── 4 │ ╰──── + help: Delete this code. ⚠ eslint-plugin-jest(no-focused-tests): Unexpected focused test. ╭─[no_focused_tests.tsx:1:10] diff --git a/crates/oxc_linter/src/snapshots/no_hex_escape.snap b/crates/oxc_linter/src/snapshots/no_hex_escape.snap index f2ac87079440fe..e607ab2b13a21d 100644 --- a/crates/oxc_linter/src/snapshots/no_hex_escape.snap +++ b/crates/oxc_linter/src/snapshots/no_hex_escape.snap @@ -6,9 +6,12 @@ source: crates/oxc_linter/src/tester.rs 1 │ const foo = "\xb1" · ────── ╰──── + help: Replace `"\xb1"` with `'\u00b1'`. ⚠ eslint-plugin-unicorn(no-hex-escape): Use Unicode escapes instead of hexadecimal escapes. ╭─[no_hex_escape.tsx:1:8] 1 │ wrapId(/(^|[])(?:алг|арг(?:\x20*рез)?|ввод|ВКЛЮЧИТЬ|вс[её]|выбор|вывод|выход|дано|для|до|дс|если|иначе|исп|использовать|кон(?:(?:\x20+|_)исп)?|кц(?:(?:\x20+|_)при)?|надо|нач|нс|нц|от|пауза|пока|при|раза?|рез|стоп|таб|то|утв|шаг)(?=[]|$)/.source) · ──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── ╰──── + help: Replace `/(^|[])(?:алг|арг(?:\x20*рез)?|ввод|ВКЛЮЧИТЬ|вс[её]|выбор|вывод|выход|дано|для|до|дс|если|иначе|исп|использовать|кон(?:(?:\x20+|_)исп)?|кц(?:(?:\x20+|_)при)?|надо|нач|нс|нц|от|пауза|пока|при|раза?|рез|стоп|таб|то|утв|шаг)(?=[]|$)/...` with `/(^|[])(?:алг|арг(?:\u0020*рез)?|ввод|ВКЛЮЧИТЬ|вс[её]|выбор|вывод|выход|дано|для|до|дс|если|иначе|исп|использовать| + кон(?:(?:\u0020+|_)исп)?|кц(?:(?:\u0020+|_)при)?|надо|нач|нс|нц|от|пауза|пока|при|раза?|рез|стоп|таб|то|утв|шаг)(?=[]|$)/...`. diff --git a/crates/oxc_linter/src/snapshots/no_test_prefixes.snap b/crates/oxc_linter/src/snapshots/no_test_prefixes.snap index f2369626b80780..34ce5497251b06 100644 --- a/crates/oxc_linter/src/snapshots/no_test_prefixes.snap +++ b/crates/oxc_linter/src/snapshots/no_test_prefixes.snap @@ -1,66 +1,75 @@ --- source: crates/oxc_linter/src/tester.rs -assertion_line: 216 --- ⚠ eslint-plugin-jest(no-test-prefixes): Use "describe.only" instead. ╭─[no_test_prefixes.tsx:1:1] 1 │ fdescribe('foo', function () {}) · ───────── ╰──── + help: Replace `fdescribe` with `describe.only`. ⚠ eslint-plugin-jest(no-test-prefixes): Use "describe.skip.each" instead. ╭─[no_test_prefixes.tsx:1:1] 1 │ xdescribe.each([])('foo', function () {}) · ────────────── ╰──── + help: Replace `xdescribe.each` with `describe.skip.each`. ⚠ eslint-plugin-jest(no-test-prefixes): Use "it.only" instead. ╭─[no_test_prefixes.tsx:1:1] 1 │ fit('foo', function () {}) · ─── ╰──── + help: Replace `fit` with `it.only`. ⚠ eslint-plugin-jest(no-test-prefixes): Use "describe.skip" instead. ╭─[no_test_prefixes.tsx:1:1] 1 │ xdescribe('foo', function () {}) · ───────── ╰──── + help: Replace `xdescribe` with `describe.skip`. ⚠ eslint-plugin-jest(no-test-prefixes): Use "it.skip" instead. ╭─[no_test_prefixes.tsx:1:1] 1 │ xit('foo', function () {}) · ─── ╰──── + help: Replace `xit` with `it.skip`. ⚠ eslint-plugin-jest(no-test-prefixes): Use "test.skip" instead. ╭─[no_test_prefixes.tsx:1:1] 1 │ xtest('foo', function () {}) · ───── ╰──── + help: Replace `xtest` with `test.skip`. ⚠ eslint-plugin-jest(no-test-prefixes): Use "it.skip.each" instead. ╭─[no_test_prefixes.tsx:1:1] 1 │ xit.each``('foo', function () {}) · ──────── ╰──── + help: Replace `xit.each` with `it.skip.each`. ⚠ eslint-plugin-jest(no-test-prefixes): Use "test.skip.each" instead. ╭─[no_test_prefixes.tsx:1:1] 1 │ xtest.each``('foo', function () {}) · ────────── ╰──── + help: Replace `xtest.each` with `test.skip.each`. ⚠ eslint-plugin-jest(no-test-prefixes): Use "it.skip.each" instead. ╭─[no_test_prefixes.tsx:1:1] 1 │ xit.each([])('foo', function () {}) · ──────── ╰──── + help: Replace `xit.each` with `it.skip.each`. ⚠ eslint-plugin-jest(no-test-prefixes): Use "test.skip.each" instead. ╭─[no_test_prefixes.tsx:1:1] 1 │ xtest.each([])('foo', function () {}) · ────────── ╰──── + help: Replace `xtest.each` with `test.skip.each`. ⚠ eslint-plugin-jest(no-test-prefixes): Use "it.skip" instead. ╭─[no_test_prefixes.tsx:3:17] @@ -69,6 +78,7 @@ assertion_line: 216 · ─── 4 │ ╰──── + help: Replace `xit` with `it.skip`. ⚠ eslint-plugin-jest(no-test-prefixes): Use "it.skip" instead. ╭─[no_test_prefixes.tsx:3:17] @@ -77,6 +87,7 @@ assertion_line: 216 · ──────── 4 │ ╰──── + help: Replace `skipThis` with `it.skip`. ⚠ eslint-plugin-jest(no-test-prefixes): Use "it.only" instead. ╭─[no_test_prefixes.tsx:3:17] @@ -85,63 +96,74 @@ assertion_line: 216 · ──────── 4 │ ╰──── + help: Replace `onlyThis` with `it.only`. ⚠ eslint-plugin-jest(no-test-prefixes): Use "describe.only" instead. ╭─[no_test_prefixes.tsx:1:1] 1 │ fdescribe("foo", function () {}) · ───────── ╰──── + help: Replace `fdescribe` with `describe.only`. ⚠ eslint-plugin-jest(no-test-prefixes): Use "describe.skip.each" instead. ╭─[no_test_prefixes.tsx:1:1] 1 │ xdescribe.each([])("foo", function () {}) · ────────────── ╰──── + help: Replace `xdescribe.each` with `describe.skip.each`. ⚠ eslint-plugin-jest(no-test-prefixes): Use "it.only" instead. ╭─[no_test_prefixes.tsx:1:1] 1 │ fit("foo", function () {}) · ─── ╰──── + help: Replace `fit` with `it.only`. ⚠ eslint-plugin-jest(no-test-prefixes): Use "describe.skip" instead. ╭─[no_test_prefixes.tsx:1:1] 1 │ xdescribe("foo", function () {}) · ───────── ╰──── + help: Replace `xdescribe` with `describe.skip`. ⚠ eslint-plugin-jest(no-test-prefixes): Use "it.skip" instead. ╭─[no_test_prefixes.tsx:1:1] 1 │ xit("foo", function () {}) · ─── ╰──── + help: Replace `xit` with `it.skip`. ⚠ eslint-plugin-jest(no-test-prefixes): Use "test.skip" instead. ╭─[no_test_prefixes.tsx:1:1] 1 │ xtest("foo", function () {}) · ───── ╰──── + help: Replace `xtest` with `test.skip`. ⚠ eslint-plugin-jest(no-test-prefixes): Use "it.skip.each" instead. ╭─[no_test_prefixes.tsx:1:1] 1 │ xit.each``("foo", function () {}) · ──────── ╰──── + help: Replace `xit.each` with `it.skip.each`. ⚠ eslint-plugin-jest(no-test-prefixes): Use "test.skip.each" instead. ╭─[no_test_prefixes.tsx:1:1] 1 │ xtest.each``("foo", function () {}) · ────────── ╰──── + help: Replace `xtest.each` with `test.skip.each`. ⚠ eslint-plugin-jest(no-test-prefixes): Use "it.skip.each" instead. ╭─[no_test_prefixes.tsx:1:1] 1 │ xit.each([])("foo", function () {}) · ──────── ╰──── + help: Replace `xit.each` with `it.skip.each`. ⚠ eslint-plugin-jest(no-test-prefixes): Use "test.skip.each" instead. ╭─[no_test_prefixes.tsx:1:1] 1 │ xtest.each([])("foo", function () {}) · ────────── ╰──── + help: Replace `xtest.each` with `test.skip.each`. diff --git a/crates/oxc_linter/src/snapshots/no_useless_escape.snap b/crates/oxc_linter/src/snapshots/no_useless_escape.snap index 5bc1093baa3e13..d21f0bd2b9c828 100644 --- a/crates/oxc_linter/src/snapshots/no_useless_escape.snap +++ b/crates/oxc_linter/src/snapshots/no_useless_escape.snap @@ -6,282 +6,329 @@ source: crates/oxc_linter/src/tester.rs 1 │ var foo = /\#/; · ── ╰──── + help: Replace `\#` with `#`. ⚠ eslint(no-useless-escape): Unnecessary escape character ';' ╭─[no_useless_escape.tsx:1:12] 1 │ var foo = /\;/; · ── ╰──── + help: Replace `\;` with `;`. ⚠ eslint(no-useless-escape): Unnecessary escape character '\'' ╭─[no_useless_escape.tsx:1:12] 1 │ var foo = "\'"; · ── ╰──── + help: Replace `\'` with `'`. ⚠ eslint(no-useless-escape): Unnecessary escape character '#' ╭─[no_useless_escape.tsx:1:12] 1 │ var foo = "\#/"; · ── ╰──── + help: Replace `\#` with `#`. ⚠ eslint(no-useless-escape): Unnecessary escape character 'a' ╭─[no_useless_escape.tsx:1:12] 1 │ var foo = "\a" · ── ╰──── + help: Replace `\a` with `a`. ⚠ eslint(no-useless-escape): Unnecessary escape character 'B' ╭─[no_useless_escape.tsx:1:12] 1 │ var foo = "\B"; · ── ╰──── + help: Replace `\B` with `B`. ⚠ eslint(no-useless-escape): Unnecessary escape character '@' ╭─[no_useless_escape.tsx:1:12] 1 │ var foo = "\@"; · ── ╰──── + help: Replace `\@` with `@`. ⚠ eslint(no-useless-escape): Unnecessary escape character 'a' ╭─[no_useless_escape.tsx:1:16] 1 │ var foo = "foo \a bar"; · ── ╰──── + help: Replace `\a` with `a`. ⚠ eslint(no-useless-escape): Unnecessary escape character '"' ╭─[no_useless_escape.tsx:1:12] 1 │ var foo = '\"'; · ── ╰──── + help: Replace `\"` with `"`. ⚠ eslint(no-useless-escape): Unnecessary escape character '#' ╭─[no_useless_escape.tsx:1:12] 1 │ var foo = '\#'; · ── ╰──── + help: Replace `\#` with `#`. ⚠ eslint(no-useless-escape): Unnecessary escape character '$' ╭─[no_useless_escape.tsx:1:12] 1 │ var foo = '\$'; · ── ╰──── + help: Replace `\$` with `$`. ⚠ eslint(no-useless-escape): Unnecessary escape character 'p' ╭─[no_useless_escape.tsx:1:12] 1 │ var foo = '\p'; · ── ╰──── + help: Replace `\p` with `p`. ⚠ eslint(no-useless-escape): Unnecessary escape character 'p' ╭─[no_useless_escape.tsx:1:12] 1 │ var foo = '\p\a\@'; · ── ╰──── + help: Replace `\p` with `p`. ⚠ eslint(no-useless-escape): Unnecessary escape character 'a' ╭─[no_useless_escape.tsx:1:14] 1 │ var foo = '\p\a\@'; · ── ╰──── + help: Replace `\a` with `a`. ⚠ eslint(no-useless-escape): Unnecessary escape character '@' ╭─[no_useless_escape.tsx:1:16] 1 │ var foo = '\p\a\@'; · ── ╰──── + help: Replace `\@` with `@`. ⚠ eslint(no-useless-escape): Unnecessary escape character 'd' ╭─[no_useless_escape.tsx:1:13] 1 │ · ── ╰──── + help: Replace `\d` with `d`. ⚠ eslint(no-useless-escape): Unnecessary escape character '`' ╭─[no_useless_escape.tsx:1:12] 1 │ var foo = '\`'; · ── ╰──── + help: Replace `\`` with ```. ⚠ eslint(no-useless-escape): Unnecessary escape character '"' ╭─[no_useless_escape.tsx:1:12] 1 │ var foo = `\"`; · ── ╰──── + help: Replace `\"` with `"`. ⚠ eslint(no-useless-escape): Unnecessary escape character '\'' ╭─[no_useless_escape.tsx:1:12] 1 │ var foo = `\'`; · ── ╰──── + help: Replace `\'` with `'`. ⚠ eslint(no-useless-escape): Unnecessary escape character '#' ╭─[no_useless_escape.tsx:1:12] 1 │ var foo = `\#`; · ── ╰──── + help: Replace `\#` with `#`. ⚠ eslint(no-useless-escape): Unnecessary escape character '`' ╭─[no_useless_escape.tsx:1:12] 1 │ var foo = '\`foo\`'; · ── ╰──── + help: Replace `\`` with ```. ⚠ eslint(no-useless-escape): Unnecessary escape character '`' ╭─[no_useless_escape.tsx:1:17] 1 │ var foo = '\`foo\`'; · ── ╰──── + help: Replace `\`` with ```. ⚠ eslint(no-useless-escape): Unnecessary escape character '"' ╭─[no_useless_escape.tsx:1:12] 1 │ var foo = `\"${foo}\"`; · ── ╰──── + help: Replace `\"` with `"`. ⚠ eslint(no-useless-escape): Unnecessary escape character '"' ╭─[no_useless_escape.tsx:1:20] 1 │ var foo = `\"${foo}\"`; · ── ╰──── + help: Replace `\"` with `"`. ⚠ eslint(no-useless-escape): Unnecessary escape character '\'' ╭─[no_useless_escape.tsx:1:12] 1 │ var foo = `\'${foo}\'`; · ── ╰──── + help: Replace `\'` with `'`. ⚠ eslint(no-useless-escape): Unnecessary escape character '\'' ╭─[no_useless_escape.tsx:1:20] 1 │ var foo = `\'${foo}\'`; · ── ╰──── + help: Replace `\'` with `'`. ⚠ eslint(no-useless-escape): Unnecessary escape character '#' ╭─[no_useless_escape.tsx:1:12] 1 │ var foo = `\#${foo}`; · ── ╰──── + help: Replace `\#` with `#`. ⚠ eslint(no-useless-escape): Unnecessary escape character ' ' ╭─[no_useless_escape.tsx:1:12] 1 │ let foo = '\ '; · ── ╰──── + help: Replace `\ ` with ` `. ⚠ eslint(no-useless-escape): Unnecessary escape character ' ' ╭─[no_useless_escape.tsx:1:12] 1 │ let foo = /\ /; · ── ╰──── + help: Replace `\ ` with ` `. ⚠ eslint(no-useless-escape): Unnecessary escape character '$' ╭─[no_useless_escape.tsx:1:12] 1 │ var foo = `\$\{{${foo}`; · ── ╰──── + help: Replace `\$` with `$`. ⚠ eslint(no-useless-escape): Unnecessary escape character '$' ╭─[no_useless_escape.tsx:1:12] 1 │ var foo = `\$a${foo}`; · ── ╰──── + help: Replace `\$` with `$`. ⚠ eslint(no-useless-escape): Unnecessary escape character '{' ╭─[no_useless_escape.tsx:1:13] 1 │ var foo = `a\{{${foo}`; · ── ╰──── + help: Replace `\{` with `{`. ⚠ eslint(no-useless-escape): Unnecessary escape character '-' ╭─[no_useless_escape.tsx:1:15] 1 │ var foo = /[ab\-]/ · ── ╰──── + help: Replace `\-` with `-`. ⚠ eslint(no-useless-escape): Unnecessary escape character '-' ╭─[no_useless_escape.tsx:1:13] 1 │ var foo = /[\-ab]/ · ── ╰──── + help: Replace `\-` with `-`. ⚠ eslint(no-useless-escape): Unnecessary escape character '?' ╭─[no_useless_escape.tsx:1:15] 1 │ var foo = /[ab\?]/ · ── ╰──── + help: Replace `\?` with `?`. ⚠ eslint(no-useless-escape): Unnecessary escape character '.' ╭─[no_useless_escape.tsx:1:15] 1 │ var foo = /[ab\.]/ · ── ╰──── + help: Replace `\.` with `.`. ⚠ eslint(no-useless-escape): Unnecessary escape character '|' ╭─[no_useless_escape.tsx:1:14] 1 │ var foo = /[a\|b]/ · ── ╰──── + help: Replace `\|` with `|`. ⚠ eslint(no-useless-escape): Unnecessary escape character '-' ╭─[no_useless_escape.tsx:1:12] 1 │ var foo = /\-/ · ── ╰──── + help: Replace `\-` with `-`. ⚠ eslint(no-useless-escape): Unnecessary escape character '-' ╭─[no_useless_escape.tsx:1:13] 1 │ var foo = /[\-]/ · ── ╰──── + help: Replace `\-` with `-`. ⚠ eslint(no-useless-escape): Unnecessary escape character '$' ╭─[no_useless_escape.tsx:1:15] 1 │ var foo = /[ab\$]/ · ── ╰──── + help: Replace `\$` with `$`. ⚠ eslint(no-useless-escape): Unnecessary escape character '(' ╭─[no_useless_escape.tsx:1:13] 1 │ var foo = /[\(paren]/ · ── ╰──── + help: Replace `\(` with `(`. ⚠ eslint(no-useless-escape): Unnecessary escape character '[' ╭─[no_useless_escape.tsx:1:13] 1 │ var foo = /[\[]/ · ── ╰──── + help: Replace `\[` with `[`. ⚠ eslint(no-useless-escape): Unnecessary escape character '/' ╭─[no_useless_escape.tsx:1:13] 1 │ var foo = /[\/]/ · ── ╰──── + help: Replace `\/` with `/`. ⚠ eslint(no-useless-escape): Unnecessary escape character 'B' ╭─[no_useless_escape.tsx:1:13] 1 │ var foo = /[\B]/ · ── ╰──── + help: Replace `\B` with `B`. ⚠ eslint(no-useless-escape): Unnecessary escape character '-' ╭─[no_useless_escape.tsx:1:16] 1 │ var foo = /[a][\-b]/ · ── ╰──── + help: Replace `\-` with `-`. ⚠ eslint(no-useless-escape): Unnecessary escape character '-' ╭─[no_useless_escape.tsx:1:12] 1 │ var foo = /\-[]/ · ── ╰──── + help: Replace `\-` with `-`. ⚠ eslint(no-useless-escape): Unnecessary escape character '^' ╭─[no_useless_escape.tsx:1:14] 1 │ var foo = /[a\^]/ · ── ╰──── + help: Replace `\^` with `^`. ⚠ eslint(no-useless-escape): Unnecessary escape character 'e' ╭─[no_useless_escape.tsx:2:22] @@ -289,6 +336,7 @@ source: crates/oxc_linter/src/tester.rs 2 │ literal with useless \escape` · ── ╰──── + help: Replace `\e` with `e`. ⚠ eslint(no-useless-escape): Unnecessary escape character 'e' ╭─[no_useless_escape.tsx:2:22] @@ -296,6 +344,7 @@ source: crates/oxc_linter/src/tester.rs 2 │ literal with useless \escape` · ── ╰──── + help: Replace `\e` with `e`. ⚠ eslint(no-useless-escape): Unnecessary escape character 'e' ╭─[no_useless_escape.tsx:2:13] @@ -303,6 +352,7 @@ source: crates/oxc_linter/src/tester.rs 2 │ and useless \escape` · ── ╰──── + help: Replace `\e` with `e`. ⚠ eslint(no-useless-escape): Unnecessary escape character 'e' ╭─[no_useless_escape.tsx:2:13] @@ -310,6 +360,7 @@ source: crates/oxc_linter/src/tester.rs 2 │ and useless \escape` · ── ╰──── + help: Replace `\e` with `e`. ⚠ eslint(no-useless-escape): Unnecessary escape character 'a' ╭─[no_useless_escape.tsx:4:1] @@ -317,6 +368,7 @@ source: crates/oxc_linter/src/tester.rs 4 │ \and useless escape` · ── ╰──── + help: Replace `\a` with `a`. ⚠ eslint(no-useless-escape): Unnecessary escape character 'a' ╭─[no_useless_escape.tsx:4:1] @@ -324,57 +376,67 @@ source: crates/oxc_linter/src/tester.rs 4 │ \and useless escape` · ── ╰──── + help: Replace `\a` with `a`. ⚠ eslint(no-useless-escape): Unnecessary escape character 'a' ╭─[no_useless_escape.tsx:1:2] 1 │ `\a``` · ── ╰──── + help: Replace `\a` with `a`. ⚠ eslint(no-useless-escape): Unnecessary escape character '(' ╭─[no_useless_escape.tsx:1:12] 1 │ var foo = /\(([^\)\(]+)\)$|\(([^\)\)]+)\)$/; · ─── ╰──── + help: Replace `\(` with `(`. ⚠ eslint(no-useless-escape): Unnecessary escape character ')' ╭─[no_useless_escape.tsx:1:19] 1 │ var foo = /\(([^\)\(]+)\)$|\(([^\)\)]+)\)$/; · ─── ╰──── + help: Replace `\)` with `)`. ⚠ eslint(no-useless-escape): Unnecessary escape character '(' ╭─[no_useless_escape.tsx:1:23] 1 │ var foo = /\(([^\)\(]+)\)$|\(([^\)\)]+)\)$/; · ─── ╰──── + help: Replace `\(` with `(`. ⚠ eslint(no-useless-escape): Unnecessary escape character ')' ╭─[no_useless_escape.tsx:1:30] 1 │ var foo = /\(([^\)\(]+)\)$|\(([^\)\)]+)\)$/; · ─── ╰──── + help: Replace `\)` with `)`. ⚠ eslint(no-useless-escape): Unnecessary escape character ')' ╭─[no_useless_escape.tsx:1:41] 1 │ var foo = /\(([^\)\(]+)\)$|\(([^\)\)]+)\)$/; · ── ╰──── + help: Replace `\)` with `)`. ⚠ eslint(no-useless-escape): Unnecessary escape character ')' ╭─[no_useless_escape.tsx:1:43] 1 │ var foo = /\(([^\)\(]+)\)$|\(([^\)\)]+)\)$/; · ── ╰──── + help: Replace `\)` with `)`. ⚠ eslint(no-useless-escape): Unnecessary escape character '\u{85}' ╭─[no_useless_escape.tsx:1:40] 1 │ var stringLiteralWithNextLine = "line 1\…line 2"; · ─ ╰──── + help: Replace `\…` with `…`. ⚠ eslint(no-useless-escape): Unnecessary escape character '\u{85}' ╭─[no_useless_escape.tsx:1:40] 1 │ var stringLiteralWithNextLine = `line 1\…line 2`; · ─ ╰──── + help: Replace `\…` with `…`. diff --git a/crates/oxc_linter/src/snapshots/prefer_prototype_methods.snap b/crates/oxc_linter/src/snapshots/prefer_prototype_methods.snap index b415bff521a23f..acfdc0d70ae841 100644 --- a/crates/oxc_linter/src/snapshots/prefer_prototype_methods.snap +++ b/crates/oxc_linter/src/snapshots/prefer_prototype_methods.snap @@ -6,135 +6,158 @@ source: crates/oxc_linter/src/tester.rs 1 │ const foo = [].push.apply(bar, elements); · ─────── ╰──── + help: Replace `[]` with `Array.prototype`. ⚠ eslint-plugin-unicorn(prefer-prototype-methods): Prefer using `Array.prototype.slice`. ╭─[prefer_prototype_methods.tsx:1:13] 1 │ const foo = [].slice.call(bar); · ──────── ╰──── + help: Replace `[]` with `Array.prototype`. ⚠ eslint-plugin-unicorn(prefer-prototype-methods): Prefer using `Object.prototype.toString`. ╭─[prefer_prototype_methods.tsx:1:13] 1 │ const foo = {}.toString.call(bar); · ─────────── ╰──── + help: Replace `{}` with `Object.prototype`. ⚠ eslint-plugin-unicorn(prefer-prototype-methods): Prefer using `Object.prototype.hasOwnProperty`. ╭─[prefer_prototype_methods.tsx:1:13] 1 │ const foo = {}.hasOwnProperty.call(bar, "property"); · ───────────────── ╰──── + help: Replace `{}` with `Object.prototype`. ⚠ eslint-plugin-unicorn(prefer-prototype-methods): Prefer using `Object.prototype.propertyIsEnumerable`. ╭─[prefer_prototype_methods.tsx:1:13] 1 │ const foo = {}.propertyIsEnumerable.call(bar, "property"); · ─────────────────────── ╰──── + help: Replace `{}` with `Object.prototype`. ⚠ eslint-plugin-unicorn(prefer-prototype-methods): Prefer using `Array.prototype.forEach`. ╭─[prefer_prototype_methods.tsx:1:1] 1 │ [].forEach.call(foo, () => {}) · ────────── ╰──── + help: Replace `[]` with `Array.prototype`. ⚠ eslint-plugin-unicorn(prefer-prototype-methods): Prefer using `Array.prototype.push`. ╭─[prefer_prototype_methods.tsx:1:14] 1 │ const push = [].push.bind(foo) · ─────── ╰──── + help: Replace `[]` with `Array.prototype`. ⚠ eslint-plugin-unicorn(prefer-prototype-methods): Prefer using method from `Array.prototype`. ╭─[prefer_prototype_methods.tsx:1:13] 1 │ const foo = [][method].call(foo) · ────────── ╰──── + help: Replace `[]` with `Array.prototype`. ⚠ eslint-plugin-unicorn(prefer-prototype-methods): Prefer using method from `Array.prototype`. ╭─[prefer_prototype_methods.tsx:1:45] 1 │ const method = "realMethodName";const foo = [][method].call(foo) · ────────── ╰──── + help: Replace `[]` with `Array.prototype`. ⚠ eslint-plugin-unicorn(prefer-prototype-methods): Prefer using `Array.prototype.slice`. ╭─[prefer_prototype_methods.tsx:1:29] 1 │ const array = Reflect.apply([].slice, foo, []) · ──────── ╰──── + help: Replace `[]` with `Array.prototype`. ⚠ eslint-plugin-unicorn(prefer-prototype-methods): Prefer using `Array.prototype.bar`. ╭─[prefer_prototype_methods.tsx:1:15] 1 │ Reflect.apply([].bar, baz, []) · ────── ╰──── + help: Replace `[]` with `Array.prototype`. ⚠ eslint-plugin-unicorn(prefer-prototype-methods): Prefer using `Object.prototype.toString`. ╭─[prefer_prototype_methods.tsx:1:13] 1 │ const foo = ({}).toString.call(bar); · ───────────── ╰──── + help: Replace `{}` with `Object.prototype`. ⚠ eslint-plugin-unicorn(prefer-prototype-methods): Prefer using `Object.prototype.toString`. ╭─[prefer_prototype_methods.tsx:1:14] 1 │ const foo = ({}.toString).call(bar); · ─────────── ╰──── + help: Replace `{}` with `Object.prototype`. ⚠ eslint-plugin-unicorn(prefer-prototype-methods): Prefer using `Object.prototype.toString`. ╭─[prefer_prototype_methods.tsx:1:14] 1 │ const foo = ({}.toString.call)(bar); · ─────────── ╰──── + help: Replace `{}` with `Object.prototype`. ⚠ eslint-plugin-unicorn(prefer-prototype-methods): Prefer using `Array.prototype.slice`. ╭─[prefer_prototype_methods.tsx:1:22] 1 │ function foo(){return[].slice.call(bar);} · ──────── ╰──── + help: Replace `[]` with ` Array.prototype`. ⚠ eslint-plugin-unicorn(prefer-prototype-methods): Prefer using `Object.prototype.toString`. ╭─[prefer_prototype_methods.tsx:1:22] 1 │ function foo(){return{}.toString.call(bar)} · ─────────── ╰──── + help: Replace `{}` with ` Object.prototype`. ⚠ eslint-plugin-unicorn(prefer-prototype-methods): Prefer using method from `Object.prototype`. ╭─[prefer_prototype_methods.tsx:1:15] 1 │ Reflect.apply({}[Symbol()], baz, []) · ──────────── ╰──── + help: Replace `{}` with `Object.prototype`. ⚠ eslint-plugin-unicorn(prefer-prototype-methods): Prefer using method from `Object.prototype`. ╭─[prefer_prototype_methods.tsx:1:15] 1 │ Reflect.apply({}[Symbol("symbol description")], baz, []) · ──────────────────────────────── ╰──── + help: Replace `{}` with `Object.prototype`. ⚠ eslint-plugin-unicorn(prefer-prototype-methods): Prefer using method from `Array.prototype`. ╭─[prefer_prototype_methods.tsx:1:15] 1 │ Reflect.apply([][Symbol()], baz, []) · ──────────── ╰──── + help: Replace `[]` with `Array.prototype`. ⚠ eslint-plugin-unicorn(prefer-prototype-methods): Prefer using method from `Object.prototype`. ╭─[prefer_prototype_methods.tsx:1:15] 1 │ Reflect.apply({}[Symbol("symbol description")], baz, []) · ──────────────────────────────── ╰──── + help: Replace `{}` with `Object.prototype`. ⚠ eslint-plugin-unicorn(prefer-prototype-methods): Prefer using method from `Array.prototype`. ╭─[prefer_prototype_methods.tsx:1:1] 1 │ [][Symbol.iterator].call(foo) · ─────────────────── ╰──── + help: Replace `[]` with `Array.prototype`. ⚠ eslint-plugin-unicorn(prefer-prototype-methods): Prefer using `Array.prototype.at`. ╭─[prefer_prototype_methods.tsx:1:13] 1 │ const foo = [].at.call(bar) · ───── ╰──── + help: Replace `[]` with `Array.prototype`. ⚠ eslint-plugin-unicorn(prefer-prototype-methods): Prefer using `Array.prototype.findLast`. ╭─[prefer_prototype_methods.tsx:1:13] 1 │ const foo = [].findLast.call(bar) · ─────────── ╰──── + help: Replace `[]` with `Array.prototype`. diff --git a/crates/oxc_linter/src/snapshots/prefer_to_be.snap b/crates/oxc_linter/src/snapshots/prefer_to_be.snap index 44d0b76fd228e1..b3034a0dd457a7 100644 --- a/crates/oxc_linter/src/snapshots/prefer_to_be.snap +++ b/crates/oxc_linter/src/snapshots/prefer_to_be.snap @@ -6,291 +6,340 @@ source: crates/oxc_linter/src/tester.rs 1 │ expect(value).toEqual("my string"); · ─────── ╰──── + help: Replace `toEqual` with `toBe`. ⚠ eslint-plugin-jest(prefer-to-be): Use `toBe` when expecting primitive literals. ╭─[prefer_to_be.tsx:1:15] 1 │ expect(value).toStrictEqual("my string"); · ───────────── ╰──── + help: Replace `toStrictEqual` with `toBe`. ⚠ eslint-plugin-jest(prefer-to-be): Use `toBe` when expecting primitive literals. ╭─[prefer_to_be.tsx:1:15] 1 │ expect(value).toStrictEqual(1); · ───────────── ╰──── + help: Replace `toStrictEqual` with `toBe`. ⚠ eslint-plugin-jest(prefer-to-be): Use `toBe` when expecting primitive literals. ╭─[prefer_to_be.tsx:1:15] 1 │ expect(value).toStrictEqual(1,); · ───────────── ╰──── + help: Replace `toStrictEqual` with `toBe`. ⚠ eslint-plugin-jest(prefer-to-be): Use `toBe` when expecting primitive literals. ╭─[prefer_to_be.tsx:1:15] 1 │ expect(value).toStrictEqual(-1); · ───────────── ╰──── + help: Replace `toStrictEqual` with `toBe`. ⚠ eslint-plugin-jest(prefer-to-be): Use `toBe` when expecting primitive literals. ╭─[prefer_to_be.tsx:1:15] 1 │ expect(value).toEqual(`my string`); · ─────── ╰──── + help: Replace `toEqual` with `toBe`. ⚠ eslint-plugin-jest(prefer-to-be): Use `toBe` when expecting primitive literals. ╭─[prefer_to_be.tsx:1:15] 1 │ expect(value)["toEqual"](`my string`); · ───────── ╰──── + help: Replace `"toEqual"` with `"toBe"`. ⚠ eslint-plugin-jest(prefer-to-be): Use `toBe` when expecting primitive literals. ╭─[prefer_to_be.tsx:1:15] 1 │ expect(value).toStrictEqual(`my ${string}`); · ───────────── ╰──── + help: Replace `toStrictEqual` with `toBe`. ⚠ eslint-plugin-jest(prefer-to-be): Use `toBe` when expecting primitive literals. ╭─[prefer_to_be.tsx:1:32] 1 │ expect(loadMessage()).resolves.toStrictEqual("hello world"); · ───────────── ╰──── + help: Replace `toStrictEqual` with `toBe`. ⚠ eslint-plugin-jest(prefer-to-be): Use `toBe` when expecting primitive literals. ╭─[prefer_to_be.tsx:1:32] 1 │ expect(loadMessage()).resolves["toStrictEqual"]("hello world"); · ─────────────── ╰──── + help: Replace `"toStrictEqual"` with `"toBe"`. ⚠ eslint-plugin-jest(prefer-to-be): Use `toBe` when expecting primitive literals. ╭─[prefer_to_be.tsx:1:35] 1 │ expect(loadMessage())["resolves"].toStrictEqual("hello world"); · ───────────── ╰──── + help: Replace `toStrictEqual` with `toBe`. ⚠ eslint-plugin-jest(prefer-to-be): Use `toBe` when expecting primitive literals. ╭─[prefer_to_be.tsx:1:32] 1 │ expect(loadMessage()).resolves.toStrictEqual(false); · ───────────── ╰──── + help: Replace `toStrictEqual` with `toBe`. ⚠ eslint-plugin-jest(prefer-to-be): Use `toBeNull` instead. ╭─[prefer_to_be.tsx:1:14] 1 │ expect(null).toBe(null); · ──── ╰──── + help: Replace `toBe(null)` with `toBeNull()`. ⚠ eslint-plugin-jest(prefer-to-be): Use `toBeNull` instead. ╭─[prefer_to_be.tsx:1:14] 1 │ expect(null).toEqual(null); · ─────── ╰──── + help: Replace `toEqual(null)` with `toBeNull()`. ⚠ eslint-plugin-jest(prefer-to-be): Use `toBeNull` instead. ╭─[prefer_to_be.tsx:1:14] 1 │ expect(null).toEqual(null,); · ─────── ╰──── + help: Replace `toEqual(null,)` with `toBeNull()`. ⚠ eslint-plugin-jest(prefer-to-be): Use `toBeNull` instead. ╭─[prefer_to_be.tsx:1:14] 1 │ expect(null).toStrictEqual(null); · ───────────── ╰──── + help: Replace `toStrictEqual(null)` with `toBeNull()`. ⚠ eslint-plugin-jest(prefer-to-be): Use `toBeNull` instead. ╭─[prefer_to_be.tsx:1:24] 1 │ expect("a string").not.toBe(null); · ──── ╰──── + help: Replace `toBe(null)` with `toBeNull()`. ⚠ eslint-plugin-jest(prefer-to-be): Use `toBeNull` instead. ╭─[prefer_to_be.tsx:1:24] 1 │ expect("a string").not["toBe"](null); · ────── ╰──── + help: Replace `"toBe"](null)` with `"toBeNull"]()`. ⚠ eslint-plugin-jest(prefer-to-be): Use `toBeNull` instead. ╭─[prefer_to_be.tsx:1:27] 1 │ expect("a string")["not"]["toBe"](null); · ────── ╰──── + help: Replace `"toBe"](null)` with `"toBeNull"]()`. ⚠ eslint-plugin-jest(prefer-to-be): Use `toBeNull` instead. ╭─[prefer_to_be.tsx:1:24] 1 │ expect("a string").not.toEqual(null); · ─────── ╰──── + help: Replace `toEqual(null)` with `toBeNull()`. ⚠ eslint-plugin-jest(prefer-to-be): Use `toBeNull` instead. ╭─[prefer_to_be.tsx:1:24] 1 │ expect("a string").not.toStrictEqual(null); · ───────────── ╰──── + help: Replace `toStrictEqual(null)` with `toBeNull()`. ⚠ eslint-plugin-jest(prefer-to-be): Use `toBeUndefined` instead. ╭─[prefer_to_be.tsx:1:19] 1 │ expect(undefined).toBe(undefined); · ──── ╰──── + help: Replace `toBe(undefined)` with `toBeUndefined()`. ⚠ eslint-plugin-jest(prefer-to-be): Use `toBeUndefined` instead. ╭─[prefer_to_be.tsx:1:19] 1 │ expect(undefined).toEqual(undefined); · ─────── ╰──── + help: Replace `toEqual(undefined)` with `toBeUndefined()`. ⚠ eslint-plugin-jest(prefer-to-be): Use `toBeUndefined` instead. ╭─[prefer_to_be.tsx:1:19] 1 │ expect(undefined).toStrictEqual(undefined); · ───────────── ╰──── + help: Replace `toStrictEqual(undefined)` with `toBeUndefined()`. ⚠ eslint-plugin-jest(prefer-to-be): Use `toBeDefined` instead. ╭─[prefer_to_be.tsx:1:24] 1 │ expect("a string").not.toBe(undefined); · ──── ╰──── + help: Replace `not.toBe(undefined)` with `toBeDefined()`. ⚠ eslint-plugin-jest(prefer-to-be): Use `toBeDefined` instead. ╭─[prefer_to_be.tsx:1:32] 1 │ expect("a string").rejects.not.toBe(undefined); · ──── ╰──── + help: Replace `not.toBe(undefined)` with `toBeDefined()`. ⚠ eslint-plugin-jest(prefer-to-be): Use `toBeDefined` instead. ╭─[prefer_to_be.tsx:1:32] 1 │ expect("a string").rejects.not["toBe"](undefined); · ────── ╰──── + help: Replace `.not["toBe"](undefined)` with `["toBeDefined"]()`. ⚠ eslint-plugin-jest(prefer-to-be): Use `toBeDefined` instead. ╭─[prefer_to_be.tsx:1:24] 1 │ expect("a string").not.toEqual(undefined); · ─────── ╰──── + help: Replace `not.toEqual(undefined)` with `toBeDefined()`. ⚠ eslint-plugin-jest(prefer-to-be): Use `toBeDefined` instead. ╭─[prefer_to_be.tsx:1:24] 1 │ expect("a string").not.toStrictEqual(undefined); · ───────────── ╰──── + help: Replace `not.toStrictEqual(undefined)` with `toBeDefined()`. ⚠ eslint-plugin-jest(prefer-to-be): Use `toBeNaN` instead. ╭─[prefer_to_be.tsx:1:13] 1 │ expect(NaN).toBe(NaN); · ──── ╰──── + help: Replace `toBe(NaN)` with `toBeNaN()`. ⚠ eslint-plugin-jest(prefer-to-be): Use `toBeNaN` instead. ╭─[prefer_to_be.tsx:1:13] 1 │ expect(NaN).toEqual(NaN); · ─────── ╰──── + help: Replace `toEqual(NaN)` with `toBeNaN()`. ⚠ eslint-plugin-jest(prefer-to-be): Use `toBeNaN` instead. ╭─[prefer_to_be.tsx:1:13] 1 │ expect(NaN).toStrictEqual(NaN); · ───────────── ╰──── + help: Replace `toStrictEqual(NaN)` with `toBeNaN()`. ⚠ eslint-plugin-jest(prefer-to-be): Use `toBeNaN` instead. ╭─[prefer_to_be.tsx:1:24] 1 │ expect("a string").not.toBe(NaN); · ──── ╰──── + help: Replace `toBe(NaN)` with `toBeNaN()`. ⚠ eslint-plugin-jest(prefer-to-be): Use `toBeNaN` instead. ╭─[prefer_to_be.tsx:1:32] 1 │ expect("a string").rejects.not.toBe(NaN); · ──── ╰──── + help: Replace `toBe(NaN)` with `toBeNaN()`. ⚠ eslint-plugin-jest(prefer-to-be): Use `toBeNaN` instead. ╭─[prefer_to_be.tsx:1:35] 1 │ expect("a string")["rejects"].not.toBe(NaN); · ──── ╰──── + help: Replace `toBe(NaN)` with `toBeNaN()`. ⚠ eslint-plugin-jest(prefer-to-be): Use `toBeNaN` instead. ╭─[prefer_to_be.tsx:1:24] 1 │ expect("a string").not.toEqual(NaN); · ─────── ╰──── + help: Replace `toEqual(NaN)` with `toBeNaN()`. ⚠ eslint-plugin-jest(prefer-to-be): Use `toBeNaN` instead. ╭─[prefer_to_be.tsx:1:24] 1 │ expect("a string").not.toStrictEqual(NaN); · ───────────── ╰──── + help: Replace `toStrictEqual(NaN)` with `toBeNaN()`. ⚠ eslint-plugin-jest(prefer-to-be): Use `toBeUndefined` instead. ╭─[prefer_to_be.tsx:1:23] 1 │ expect(undefined).not.toBeDefined(); · ─────────── ╰──── + help: Replace `not.toBeDefined()` with `toBeUndefined()`. ⚠ eslint-plugin-jest(prefer-to-be): Use `toBeUndefined` instead. ╭─[prefer_to_be.tsx:1:32] 1 │ expect(undefined).resolves.not.toBeDefined(); · ─────────── ╰──── + help: Replace `not.toBeDefined()` with `toBeUndefined()`. ⚠ eslint-plugin-jest(prefer-to-be): Use `toBeUndefined` instead. ╭─[prefer_to_be.tsx:1:28] 1 │ expect(undefined).resolves.toBe(undefined); · ──── ╰──── + help: Replace `toBe(undefined)` with `toBeUndefined()`. ⚠ eslint-plugin-jest(prefer-to-be): Use `toBeDefined` instead. ╭─[prefer_to_be.tsx:1:24] 1 │ expect("a string").not.toBeUndefined(); · ───────────── ╰──── + help: Replace `not.toBeUndefined()` with `toBeDefined()`. ⚠ eslint-plugin-jest(prefer-to-be): Use `toBeDefined` instead. ╭─[prefer_to_be.tsx:1:32] 1 │ expect("a string").rejects.not.toBeUndefined(); · ───────────── ╰──── + help: Replace `not.toBeUndefined()` with `toBeDefined()`. ⚠ eslint-plugin-jest(prefer-to-be): Use `toBe` when expecting primitive literals. ╭─[prefer_to_be.tsx:1:14] 1 │ expect(null).toEqual(1 as unknown as string as unknown as any); · ─────── ╰──── + help: Replace `toEqual` with `toBe`. ⚠ eslint-plugin-jest(prefer-to-be): Use `toBe` when expecting primitive literals. ╭─[prefer_to_be.tsx:1:14] 1 │ expect(null).toEqual(-1 as unknown as string as unknown as any); · ─────── ╰──── + help: Replace `toEqual` with `toBe`. ⚠ eslint-plugin-jest(prefer-to-be): Use `toBe` when expecting primitive literals. ╭─[prefer_to_be.tsx:1:24] 1 │ expect("a string").not.toStrictEqual("string" as number); · ───────────── ╰──── + help: Replace `toStrictEqual` with `toBe`. ⚠ eslint-plugin-jest(prefer-to-be): Use `toBeNull` instead. ╭─[prefer_to_be.tsx:1:14] 1 │ expect(null).toBe(null as unknown as string as unknown as any); · ──── ╰──── + help: Replace `toBe(null as unknown as string as unknown as any)` with `toBeNull()`. ⚠ eslint-plugin-jest(prefer-to-be): Use `toBeNull` instead. ╭─[prefer_to_be.tsx:1:24] 1 │ expect("a string").not.toEqual(null as number); · ─────── ╰──── + help: Replace `toEqual(null as number)` with `toBeNull()`. ⚠ eslint-plugin-jest(prefer-to-be): Use `toBeUndefined` instead. ╭─[prefer_to_be.tsx:1:19] 1 │ expect(undefined).toBe(undefined as unknown as string as any); · ──── ╰──── + help: Replace `toBe(undefined as unknown as string as any)` with `toBeUndefined()`. ⚠ eslint-plugin-jest(prefer-to-be): Use `toBeUndefined` instead. ╭─[prefer_to_be.tsx:1:20] 1 │ expect("a string").toEqual(undefined as number); · ─────── ╰──── + help: Replace `toEqual(undefined as number)` with `toBeUndefined()`. diff --git a/crates/oxc_linter/src/snapshots/prefer_to_have_length.snap b/crates/oxc_linter/src/snapshots/prefer_to_have_length.snap index b34f78c1fe6bd4..f6cb16d8e4a107 100644 --- a/crates/oxc_linter/src/snapshots/prefer_to_have_length.snap +++ b/crates/oxc_linter/src/snapshots/prefer_to_have_length.snap @@ -6,57 +6,67 @@ source: crates/oxc_linter/src/tester.rs 1 │ expect(files["length"]).toBe(1); · ──── ╰──── + help: Replace `expect(files["length"]).toBe` with `expect(files).toHaveLength`. ⚠ eslint-plugin-jest(prefer-to-have-length): Suggest using `toHaveLength()`. ╭─[prefer_to_have_length.tsx:1:25] 1 │ expect(files["length"]).toBe(1,); · ──── ╰──── + help: Replace `expect(files["length"]).toBe` with `expect(files).toHaveLength`. ⚠ eslint-plugin-jest(prefer-to-have-length): Suggest using `toHaveLength()`. ╭─[prefer_to_have_length.tsx:1:32] 1 │ expect(files["length"])["not"].toBe(1); · ──── ╰──── + help: Replace `expect(files["length"])["not"].toBe` with `expect(files)["not"].toHaveLength`. ⚠ eslint-plugin-jest(prefer-to-have-length): Suggest using `toHaveLength()`. ╭─[prefer_to_have_length.tsx:1:25] 1 │ expect(files["length"])["toBe"](1); · ────── ╰──── + help: Replace `expect(files["length"])["toBe"]` with `expect(files).toHaveLength`. ⚠ eslint-plugin-jest(prefer-to-have-length): Suggest using `toHaveLength()`. ╭─[prefer_to_have_length.tsx:1:29] 1 │ expect(files["length"]).not["toBe"](1); · ────── ╰──── + help: Replace `expect(files["length"]).not["toBe"]` with `expect(files).not.toHaveLength`. ⚠ eslint-plugin-jest(prefer-to-have-length): Suggest using `toHaveLength()`. ╭─[prefer_to_have_length.tsx:1:32] 1 │ expect(files["length"])["not"]["toBe"](1); · ────── ╰──── + help: Replace `expect(files["length"])["not"]["toBe"]` with `expect(files)["not"].toHaveLength`. ⚠ eslint-plugin-jest(prefer-to-have-length): Suggest using `toHaveLength()`. ╭─[prefer_to_have_length.tsx:1:22] 1 │ expect(files.length).toBe(1); · ──── ╰──── + help: Replace `expect(files.length).toBe` with `expect(files).toHaveLength`. ⚠ eslint-plugin-jest(prefer-to-have-length): Suggest using `toHaveLength()`. ╭─[prefer_to_have_length.tsx:1:22] 1 │ expect(files.length).toEqual(1); · ─────── ╰──── + help: Replace `expect(files.length).toEqual` with `expect(files).toHaveLength`. ⚠ eslint-plugin-jest(prefer-to-have-length): Suggest using `toHaveLength()`. ╭─[prefer_to_have_length.tsx:1:22] 1 │ expect(files.length).toStrictEqual(1); · ───────────── ╰──── + help: Replace `expect(files.length).toStrictEqual` with `expect(files).toHaveLength`. ⚠ eslint-plugin-jest(prefer-to-have-length): Suggest using `toHaveLength()`. ╭─[prefer_to_have_length.tsx:1:26] 1 │ expect(files.length).not.toStrictEqual(1); · ───────────── ╰──── + help: Replace `expect(files.length).not.toStrictEqual` with `expect(files).not.toHaveLength`. diff --git a/crates/oxc_linter/src/snapshots/prefer_todo.snap b/crates/oxc_linter/src/snapshots/prefer_todo.snap index 5a78c08655324c..c05d1a19f18b0f 100644 --- a/crates/oxc_linter/src/snapshots/prefer_todo.snap +++ b/crates/oxc_linter/src/snapshots/prefer_todo.snap @@ -6,51 +6,60 @@ source: crates/oxc_linter/src/tester.rs 1 │ test('i need to write this test'); · ──── ╰──── + help: Replace `` with `.todo`. ⚠ eslint-plugin-jest(prefer-todo): Suggest using `test.todo`. ╭─[prefer_todo.tsx:1:1] 1 │ test('i need to write this test',); · ──── ╰──── + help: Replace `` with `.todo`. ⚠ eslint-plugin-jest(prefer-todo): Suggest using `test.todo`. ╭─[prefer_todo.tsx:1:1] 1 │ test(`i need to write this test`); · ──── ╰──── + help: Replace `` with `.todo`. ⚠ eslint-plugin-jest(prefer-todo): Suggest using `test.todo`. ╭─[prefer_todo.tsx:1:1] 1 │ it('foo', function () {}) · ───────────────────────── ╰──── + help: Replace `it('foo', function () {})` with `it.todo('foo')`. ⚠ eslint-plugin-jest(prefer-todo): Suggest using `test.todo`. ╭─[prefer_todo.tsx:1:1] 1 │ it('foo', () => {}) · ─────────────────── ╰──── + help: Replace `it('foo', () => {})` with `it.todo('foo')`. ⚠ eslint-plugin-jest(prefer-todo): Suggest using `test.todo`. ╭─[prefer_todo.tsx:1:1] 1 │ test.skip('i need to write this test', () => {}); · ──────────────────────────────────────────────── ╰──── + help: Replace `test.skip('i need to write this test', () => {})` with `test.todo('i need to write this test')`. ⚠ eslint-plugin-jest(prefer-todo): Suggest using `test.todo`. ╭─[prefer_todo.tsx:1:1] 1 │ test.skip('i need to write this test', function() {}); · ───────────────────────────────────────────────────── ╰──── + help: Replace `test.skip('i need to write this test', function() {})` with `test.todo('i need to write this test')`. ⚠ eslint-plugin-jest(prefer-todo): Suggest using `test.todo`. ╭─[prefer_todo.tsx:1:1] 1 │ test[`skip`]('i need to write this test', function() {}); · ──────────────────────────────────────────────────────── ╰──── + help: Replace `test[`skip`]('i need to write this test', function() {})` with `test['todo']('i need to write this test')`. ⚠ eslint-plugin-jest(prefer-todo): Suggest using `test.todo`. ╭─[prefer_todo.tsx:1:1] 1 │ test[`skip`]('i need to write this test', function() {}); · ──────────────────────────────────────────────────────── ╰──── + help: Replace `test[`skip`]('i need to write this test', function() {})` with `test['todo']('i need to write this test')`. diff --git a/crates/oxc_linter/src/snapshots/sort_imports.snap b/crates/oxc_linter/src/snapshots/sort_imports.snap index f60b093834d50e..24dfd53125dc55 100644 --- a/crates/oxc_linter/src/snapshots/sort_imports.snap +++ b/crates/oxc_linter/src/snapshots/sort_imports.snap @@ -62,6 +62,7 @@ source: crates/oxc_linter/src/tester.rs 1 │ import {b, a, d, c} from 'foo.js'; · ─ ╰──── + help: Replace `b, a, d, c` with `a, b, c, d`. ⚠ eslint(sort-imports): Member 'a' of the import declaration should be sorted alphabetically. ╭─[sort_imports.tsx:1:12] @@ -69,12 +70,14 @@ source: crates/oxc_linter/src/tester.rs · ─ 2 │ import {e, f, g, h} from 'bar.js'; ╰──── + help: Replace `b, a, d, c` with `a, b, c, d`. ⚠ eslint(sort-imports): Member 'B' of the import declaration should be sorted alphabetically. ╭─[sort_imports.tsx:1:12] 1 │ import {a, B, c, D} from 'foo.js'; · ─ ╰──── + help: Replace `a, B, c, D` with `B, D, a, c`. ⚠ eslint(sort-imports): Member 'aaaaa' of the import declaration should be sorted alphabetically. ╭─[sort_imports.tsx:1:30] @@ -107,6 +110,17 @@ source: crates/oxc_linter/src/tester.rs · ────────── 7 │ bar, ╰──── + help: Replace `boop, + foo, + zoo, + baz as qux, + bar, + beep` with `bar, + beep, + boop, + foo, + baz as qux, + zoo`. ⚠ eslint(sort-imports): Imports should be sorted alphabetically. ╭─[sort_imports.tsx:2:13] @@ -196,3 +210,4 @@ source: crates/oxc_linter/src/tester.rs 3 │ import { c, a } from 'c'; · ─ ╰──── + help: Replace `c, a` with `a, c`. diff --git a/crates/oxc_linter/src/tester.rs b/crates/oxc_linter/src/tester.rs index 35ac5a87263a5e..1ad9c32e669345 100644 --- a/crates/oxc_linter/src/tester.rs +++ b/crates/oxc_linter/src/tester.rs @@ -259,7 +259,7 @@ impl Tester { let allocator = Allocator::default(); let rule = self.find_rule().read_json(rule_config.unwrap_or_default()); let options = LintOptions::default() - .with_fix(is_fix.then_some(FixKind::DangerousFix)) + .with_fix(is_fix.then_some(FixKind::DangerousFix).unwrap_or_default()) .with_import_plugin(self.import_plugin) .with_jest_plugin(self.jest_plugin) .with_vitest_plugin(self.vitest_plugin) diff --git a/tasks/website/src/linter/snapshots/cli.snap b/tasks/website/src/linter/snapshots/cli.snap index 23397ef38ef75e..2f6f206b25700c 100644 --- a/tasks/website/src/linter/snapshots/cli.snap +++ b/tasks/website/src/linter/snapshots/cli.snap @@ -6,7 +6,7 @@ expression: snapshot ## Usage - **`oxlint`** \[**`-c`**=_`<./oxlintrc.json>`_\] \[**`--fix`**\] \[_`PATH`_\]... + **`oxlint`** \[**`-c`**=_`<./oxlintrc.json>`_\] \[**`--fix`**\] \[**`--fix-suggestions`**\] \[**`--fix-dangerously`**\] \[_`PATH`_\]... ## Basic Configuration - **`-c`**, **`--config`**=_`<./oxlintrc.json>`_ — @@ -72,6 +72,10 @@ Arguments: ## Fix Problems - **` --fix`** — Fix as many issues as possible. Only unfixed issues are reported in the output +- **` --fix-suggestions`** — + Apply all safe fixes and more-risky suggestions. Overrides `--fix`. +- **` --fix-dangerously`** — + Apply all fixes and suggestions, including dangerous ones. Overrides `--fix` and `--fix-suggestions`. These fixes may create incorrect code. diff --git a/tasks/website/src/linter/snapshots/cli_terminal.snap b/tasks/website/src/linter/snapshots/cli_terminal.snap index 42246aa3a568cb..281c068c97045b 100644 --- a/tasks/website/src/linter/snapshots/cli_terminal.snap +++ b/tasks/website/src/linter/snapshots/cli_terminal.snap @@ -2,7 +2,7 @@ source: tasks/website/src/linter/cli.rs expression: snapshot --- -Usage: [-c=<./oxlintrc.json>] [--fix] [PATH]... +Usage: [-c=<./oxlintrc.json>] [--fix] [--fix-suggestions] [--fix-dangerously] [PATH]... Basic Configuration -c, --config=<./oxlintrc.json> Oxlint configuration file (experimental) @@ -44,6 +44,10 @@ Enable Plugins Fix Problems --fix Fix as many issues as possible. Only unfixed issues are reported in the output + --fix-suggestions Apply all safe fixes and more-risky suggestions. Overrides `--fix`. + --fix-dangerously Apply all fixes and suggestions, including dangerous ones. Overrides + `--fix` and `--fix-suggestions`. These fixes may create incorrect + code. Ignore Files --ignore-path=PATH Specify the file to use as your .eslintignore