diff --git a/crates/oxc_linter/src/rules/eslint/no_return_assign.rs b/crates/oxc_linter/src/rules/eslint/no_return_assign.rs index d3e03fa8b72bd..e20fd3eaa4838 100644 --- a/crates/oxc_linter/src/rules/eslint/no_return_assign.rs +++ b/crates/oxc_linter/src/rules/eslint/no_return_assign.rs @@ -3,9 +3,14 @@ use oxc_diagnostics::OxcDiagnostic; use oxc_macros::declare_oxc_lint; use oxc_span::{GetSpan, Span}; use schemars::JsonSchema; +use serde::Deserialize; use serde_json::Value; -use crate::{AstNode, context::LintContext, rule::Rule}; +use crate::{ + AstNode, + context::LintContext, + rule::{DefaultRuleConfig, Rule}, +}; fn no_return_assign_diagnostic(span: Span, message: &'static str) -> OxcDiagnostic { OxcDiagnostic::warn(message) @@ -13,17 +18,24 @@ fn no_return_assign_diagnostic(span: Span, message: &'static str) -> OxcDiagnost .with_help("Did you mean to use `==` instead of `=`?") } -#[derive(Debug, Default, Clone, JsonSchema)] -#[serde(rename_all = "camelCase", default)] -pub struct NoReturnAssign { - /// Whether to always disallow assignment in return statements. - always_disallow_assignment_in_return: bool, +#[derive(Debug, Default, Clone, Deserialize)] +pub struct NoReturnAssign(NoReturnAssignMode); + +#[derive(Debug, Default, Clone, JsonSchema, Deserialize)] +#[serde(rename_all = "kebab-case")] +pub enum NoReturnAssignMode { + /// Disallow all assignments in return statements. + Always, + /// Allow assignments in return statements only if they are enclosed in parentheses. + /// This is the default mode. + #[default] + ExceptParens, } declare_oxc_lint!( /// ### What it does /// - /// Disallows assignment operators in return statements + /// Disallows assignment operators in return statements. /// /// ### Why is this bad? /// @@ -48,7 +60,7 @@ declare_oxc_lint!( eslint, style, pending, // TODO: add a suggestion - config = NoReturnAssign, + config = NoReturnAssignMode, ); fn is_sentinel_node(ast_kind: AstKind) -> bool { @@ -61,18 +73,18 @@ fn is_sentinel_node(ast_kind: AstKind) -> bool { impl Rule for NoReturnAssign { fn from_configuration(value: Value) -> Self { - let always_disallow_assignment_in_return = value - .get(0) - .and_then(Value::as_str) - .map_or_else(|| false, |value| value != "except-parens"); - Self { always_disallow_assignment_in_return } + serde_json::from_value::>(value) + .unwrap_or_default() + .into_inner() } fn run<'a>(&self, node: &AstNode<'a>, ctx: &LintContext<'a>) { let AstKind::AssignmentExpression(assign) = node.kind() else { return; }; - if !self.always_disallow_assignment_in_return + + // Skip if mode is ExceptParens and the assignment is parenthesized + if matches!(self.0, NoReturnAssignMode::ExceptParens) && ctx.nodes().parent_kind(node.id()).as_parenthesized_expression().is_some() { return; diff --git a/crates/oxc_linter/src/rules/eslint/unicode_bom.rs b/crates/oxc_linter/src/rules/eslint/unicode_bom.rs index db1336e76516a..ef50cc4d5f86a 100644 --- a/crates/oxc_linter/src/rules/eslint/unicode_bom.rs +++ b/crates/oxc_linter/src/rules/eslint/unicode_bom.rs @@ -4,7 +4,10 @@ use oxc_span::{SPAN, Span}; use schemars::JsonSchema; use serde::Deserialize; -use crate::{context::LintContext, rule::Rule}; +use crate::{ + context::LintContext, + rule::{DefaultRuleConfig, Rule}, +}; fn unexpected_unicode_bom_diagnostic(span: Span) -> OxcDiagnostic { OxcDiagnostic::warn("Unexpected Unicode BOM (Byte Order Mark)") @@ -18,11 +21,18 @@ fn expected_unicode_bom_diagnostic(span: Span) -> OxcDiagnostic { .with_label(span) } +#[derive(Debug, Default, Clone, Deserialize)] +pub struct UnicodeBom(BomOptionType); + #[derive(Debug, Default, Clone, Deserialize, JsonSchema)] -#[serde(rename_all = "camelCase", default)] -pub struct UnicodeBom { - /// Configuration option to specify whether to require or disallow Unicode BOM. - bom_option: BomOptionType, +#[serde(rename_all = "kebab-case")] +enum BomOptionType { + /// Always require a Unicode BOM (Byte Order Mark) at the beginning of the file. + Always, + /// Never allow a Unicode BOM (Byte Order Mark) at the beginning of the file. + /// This is the default option. + #[default] + Never, } declare_oxc_lint!( @@ -48,32 +58,27 @@ declare_oxc_lint!( eslint, restriction, fix, - config = UnicodeBom, + config = BomOptionType, ); impl Rule for UnicodeBom { fn from_configuration(value: serde_json::Value) -> Self { - let obj = value.get(0); - - Self { - bom_option: obj - .and_then(serde_json::Value::as_str) - .map(BomOptionType::from) - .unwrap_or_default(), - } + serde_json::from_value::>(value) + .unwrap_or_default() + .into_inner() } fn run_once(&self, ctx: &LintContext) { let source = ctx.source_text(); let has_bomb = source.starts_with(''); - if has_bomb && matches!(self.bom_option, BomOptionType::Never) { + if has_bomb && matches!(self.0, BomOptionType::Never) { ctx.diagnostic_with_fix(unexpected_unicode_bom_diagnostic(SPAN), |fixer| { fixer.delete_range(Span::new(0, 3)) }); } - if !has_bomb && matches!(self.bom_option, BomOptionType::Always) { + if !has_bomb && matches!(self.0, BomOptionType::Always) { ctx.diagnostic_with_fix(expected_unicode_bom_diagnostic(SPAN), |fixer| { fixer.replace(SPAN, "") }); @@ -81,23 +86,6 @@ impl Rule for UnicodeBom { } } -#[derive(Debug, Default, Clone, Deserialize, JsonSchema)] -#[serde(rename_all = "kebab-case")] -enum BomOptionType { - Always, - #[default] - Never, -} - -impl BomOptionType { - pub fn from(raw: &str) -> Self { - match raw { - "always" => Self::Always, - _ => Self::Never, - } - } -} - #[test] fn test() { use crate::tester::Tester; @@ -105,6 +93,8 @@ fn test() { let pass = vec![ (" var a = 123;", Some(serde_json::json!(["always"]))), ("var a = 123;", Some(serde_json::json!(["never"]))), + // Ensure default config works + ("var a = 123;", None), ("var a = 123; ", Some(serde_json::json!(["never"]))), ];