diff --git a/crates/oxc_linter/src/generated/rule_runner_impls.rs b/crates/oxc_linter/src/generated/rule_runner_impls.rs index df7113442d05c..d9d943d383bf7 100644 --- a/crates/oxc_linter/src/generated/rule_runner_impls.rs +++ b/crates/oxc_linter/src/generated/rule_runner_impls.rs @@ -3437,6 +3437,12 @@ impl RuleRunner for crate::rules::unicorn::prefer_structured_clone::PreferStruct const RUN_FUNCTIONS: RuleRunFunctionsImplemented = RuleRunFunctionsImplemented::Run; } +impl RuleRunner for crate::rules::unicorn::prefer_ternary::PreferTernary { + const NODE_TYPES: Option<&AstTypesBitset> = + Some(&AstTypesBitset::from_types(&[AstType::IfStatement])); + const RUN_FUNCTIONS: RuleRunFunctionsImplemented = RuleRunFunctionsImplemented::Run; +} + impl RuleRunner for crate::rules::unicorn::prefer_top_level_await::PreferTopLevelAwait { const NODE_TYPES: Option<&AstTypesBitset> = Some(&AstTypesBitset::from_types(&[AstType::CallExpression])); diff --git a/crates/oxc_linter/src/generated/rules_enum.rs b/crates/oxc_linter/src/generated/rules_enum.rs index b7dcbc7519da1..ebb7c3a022897 100644 --- a/crates/oxc_linter/src/generated/rules_enum.rs +++ b/crates/oxc_linter/src/generated/rules_enum.rs @@ -656,6 +656,7 @@ pub use crate::rules::unicorn::prefer_string_slice::PreferStringSlice as Unicorn pub use crate::rules::unicorn::prefer_string_starts_ends_with::PreferStringStartsEndsWith as UnicornPreferStringStartsEndsWith; pub use crate::rules::unicorn::prefer_string_trim_start_end::PreferStringTrimStartEnd as UnicornPreferStringTrimStartEnd; pub use crate::rules::unicorn::prefer_structured_clone::PreferStructuredClone as UnicornPreferStructuredClone; +pub use crate::rules::unicorn::prefer_ternary::PreferTernary as UnicornPreferTernary; pub use crate::rules::unicorn::prefer_top_level_await::PreferTopLevelAwait as UnicornPreferTopLevelAwait; pub use crate::rules::unicorn::prefer_type_error::PreferTypeError as UnicornPreferTypeError; pub use crate::rules::unicorn::relative_url_style::RelativeUrlStyle as UnicornRelativeUrlStyle; @@ -1243,6 +1244,7 @@ pub enum RuleEnum { UnicornPreferStringStartsEndsWith(UnicornPreferStringStartsEndsWith), UnicornPreferStringTrimStartEnd(UnicornPreferStringTrimStartEnd), UnicornPreferStructuredClone(UnicornPreferStructuredClone), + UnicornPreferTernary(UnicornPreferTernary), UnicornPreferTopLevelAwait(UnicornPreferTopLevelAwait), UnicornPreferTypeError(UnicornPreferTypeError), UnicornRelativeUrlStyle(UnicornRelativeUrlStyle), @@ -2008,7 +2010,8 @@ const UNICORN_PREFER_STRING_STARTS_ENDS_WITH_ID: usize = UNICORN_PREFER_STRING_S const UNICORN_PREFER_STRING_TRIM_START_END_ID: usize = UNICORN_PREFER_STRING_STARTS_ENDS_WITH_ID + 1usize; const UNICORN_PREFER_STRUCTURED_CLONE_ID: usize = UNICORN_PREFER_STRING_TRIM_START_END_ID + 1usize; -const UNICORN_PREFER_TOP_LEVEL_AWAIT_ID: usize = UNICORN_PREFER_STRUCTURED_CLONE_ID + 1usize; +const UNICORN_PREFER_TERNARY_ID: usize = UNICORN_PREFER_STRUCTURED_CLONE_ID + 1usize; +const UNICORN_PREFER_TOP_LEVEL_AWAIT_ID: usize = UNICORN_PREFER_TERNARY_ID + 1usize; const UNICORN_PREFER_TYPE_ERROR_ID: usize = UNICORN_PREFER_TOP_LEVEL_AWAIT_ID + 1usize; const UNICORN_RELATIVE_URL_STYLE_ID: usize = UNICORN_PREFER_TYPE_ERROR_ID + 1usize; const UNICORN_REQUIRE_ARRAY_JOIN_SEPARATOR_ID: usize = UNICORN_RELATIVE_URL_STYLE_ID + 1usize; @@ -2812,6 +2815,7 @@ impl RuleEnum { Self::UnicornPreferStringStartsEndsWith(_) => UNICORN_PREFER_STRING_STARTS_ENDS_WITH_ID, Self::UnicornPreferStringTrimStartEnd(_) => UNICORN_PREFER_STRING_TRIM_START_END_ID, Self::UnicornPreferStructuredClone(_) => UNICORN_PREFER_STRUCTURED_CLONE_ID, + Self::UnicornPreferTernary(_) => UNICORN_PREFER_TERNARY_ID, Self::UnicornPreferTopLevelAwait(_) => UNICORN_PREFER_TOP_LEVEL_AWAIT_ID, Self::UnicornPreferTypeError(_) => UNICORN_PREFER_TYPE_ERROR_ID, Self::UnicornRelativeUrlStyle(_) => UNICORN_RELATIVE_URL_STYLE_ID, @@ -3605,6 +3609,7 @@ impl RuleEnum { Self::UnicornPreferStringStartsEndsWith(_) => UnicornPreferStringStartsEndsWith::NAME, Self::UnicornPreferStringTrimStartEnd(_) => UnicornPreferStringTrimStartEnd::NAME, Self::UnicornPreferStructuredClone(_) => UnicornPreferStructuredClone::NAME, + Self::UnicornPreferTernary(_) => UnicornPreferTernary::NAME, Self::UnicornPreferTopLevelAwait(_) => UnicornPreferTopLevelAwait::NAME, Self::UnicornPreferTypeError(_) => UnicornPreferTypeError::NAME, Self::UnicornRelativeUrlStyle(_) => UnicornRelativeUrlStyle::NAME, @@ -4434,6 +4439,7 @@ impl RuleEnum { } Self::UnicornPreferStringTrimStartEnd(_) => UnicornPreferStringTrimStartEnd::CATEGORY, Self::UnicornPreferStructuredClone(_) => UnicornPreferStructuredClone::CATEGORY, + Self::UnicornPreferTernary(_) => UnicornPreferTernary::CATEGORY, Self::UnicornPreferTopLevelAwait(_) => UnicornPreferTopLevelAwait::CATEGORY, Self::UnicornPreferTypeError(_) => UnicornPreferTypeError::CATEGORY, Self::UnicornRelativeUrlStyle(_) => UnicornRelativeUrlStyle::CATEGORY, @@ -5234,6 +5240,7 @@ impl RuleEnum { Self::UnicornPreferStringStartsEndsWith(_) => UnicornPreferStringStartsEndsWith::FIX, Self::UnicornPreferStringTrimStartEnd(_) => UnicornPreferStringTrimStartEnd::FIX, Self::UnicornPreferStructuredClone(_) => UnicornPreferStructuredClone::FIX, + Self::UnicornPreferTernary(_) => UnicornPreferTernary::FIX, Self::UnicornPreferTopLevelAwait(_) => UnicornPreferTopLevelAwait::FIX, Self::UnicornPreferTypeError(_) => UnicornPreferTypeError::FIX, Self::UnicornRelativeUrlStyle(_) => UnicornRelativeUrlStyle::FIX, @@ -6184,6 +6191,7 @@ impl RuleEnum { UnicornPreferStringTrimStartEnd::documentation() } Self::UnicornPreferStructuredClone(_) => UnicornPreferStructuredClone::documentation(), + Self::UnicornPreferTernary(_) => UnicornPreferTernary::documentation(), Self::UnicornPreferTopLevelAwait(_) => UnicornPreferTopLevelAwait::documentation(), Self::UnicornPreferTypeError(_) => UnicornPreferTypeError::documentation(), Self::UnicornRelativeUrlStyle(_) => UnicornRelativeUrlStyle::documentation(), @@ -7928,6 +7936,8 @@ impl RuleEnum { UnicornPreferStructuredClone::config_schema(generator) .or_else(|| UnicornPreferStructuredClone::schema(generator)) } + Self::UnicornPreferTernary(_) => UnicornPreferTernary::config_schema(generator) + .or_else(|| UnicornPreferTernary::schema(generator)), Self::UnicornPreferTopLevelAwait(_) => { UnicornPreferTopLevelAwait::config_schema(generator) .or_else(|| UnicornPreferTopLevelAwait::schema(generator)) @@ -8904,6 +8914,7 @@ impl RuleEnum { Self::UnicornPreferStringStartsEndsWith(_) => "unicorn", Self::UnicornPreferStringTrimStartEnd(_) => "unicorn", Self::UnicornPreferStructuredClone(_) => "unicorn", + Self::UnicornPreferTernary(_) => "unicorn", Self::UnicornPreferTopLevelAwait(_) => "unicorn", Self::UnicornPreferTypeError(_) => "unicorn", Self::UnicornRelativeUrlStyle(_) => "unicorn", @@ -10790,6 +10801,9 @@ impl RuleEnum { Self::UnicornPreferStructuredClone(_) => Ok(Self::UnicornPreferStructuredClone( UnicornPreferStructuredClone::from_configuration(value)?, )), + Self::UnicornPreferTernary(_) => { + Ok(Self::UnicornPreferTernary(UnicornPreferTernary::from_configuration(value)?)) + } Self::UnicornPreferTopLevelAwait(_) => Ok(Self::UnicornPreferTopLevelAwait( UnicornPreferTopLevelAwait::from_configuration(value)?, )), @@ -11831,6 +11845,7 @@ impl RuleEnum { Self::UnicornPreferStringStartsEndsWith(rule) => rule.to_configuration(), Self::UnicornPreferStringTrimStartEnd(rule) => rule.to_configuration(), Self::UnicornPreferStructuredClone(rule) => rule.to_configuration(), + Self::UnicornPreferTernary(rule) => rule.to_configuration(), Self::UnicornPreferTopLevelAwait(rule) => rule.to_configuration(), Self::UnicornPreferTypeError(rule) => rule.to_configuration(), Self::UnicornRelativeUrlStyle(rule) => rule.to_configuration(), @@ -12530,6 +12545,7 @@ impl RuleEnum { Self::UnicornPreferStringStartsEndsWith(rule) => rule.run(node, ctx), Self::UnicornPreferStringTrimStartEnd(rule) => rule.run(node, ctx), Self::UnicornPreferStructuredClone(rule) => rule.run(node, ctx), + Self::UnicornPreferTernary(rule) => rule.run(node, ctx), Self::UnicornPreferTopLevelAwait(rule) => rule.run(node, ctx), Self::UnicornPreferTypeError(rule) => rule.run(node, ctx), Self::UnicornRelativeUrlStyle(rule) => rule.run(node, ctx), @@ -13227,6 +13243,7 @@ impl RuleEnum { Self::UnicornPreferStringStartsEndsWith(rule) => rule.run_once(ctx), Self::UnicornPreferStringTrimStartEnd(rule) => rule.run_once(ctx), Self::UnicornPreferStructuredClone(rule) => rule.run_once(ctx), + Self::UnicornPreferTernary(rule) => rule.run_once(ctx), Self::UnicornPreferTopLevelAwait(rule) => rule.run_once(ctx), Self::UnicornPreferTypeError(rule) => rule.run_once(ctx), Self::UnicornRelativeUrlStyle(rule) => rule.run_once(ctx), @@ -14012,6 +14029,7 @@ impl RuleEnum { Self::UnicornPreferStringStartsEndsWith(rule) => rule.run_on_jest_node(jest_node, ctx), Self::UnicornPreferStringTrimStartEnd(rule) => rule.run_on_jest_node(jest_node, ctx), Self::UnicornPreferStructuredClone(rule) => rule.run_on_jest_node(jest_node, ctx), + Self::UnicornPreferTernary(rule) => rule.run_on_jest_node(jest_node, ctx), Self::UnicornPreferTopLevelAwait(rule) => rule.run_on_jest_node(jest_node, ctx), Self::UnicornPreferTypeError(rule) => rule.run_on_jest_node(jest_node, ctx), Self::UnicornRelativeUrlStyle(rule) => rule.run_on_jest_node(jest_node, ctx), @@ -14719,6 +14737,7 @@ impl RuleEnum { Self::UnicornPreferStringStartsEndsWith(rule) => rule.should_run(ctx), Self::UnicornPreferStringTrimStartEnd(rule) => rule.should_run(ctx), Self::UnicornPreferStructuredClone(rule) => rule.should_run(ctx), + Self::UnicornPreferTernary(rule) => rule.should_run(ctx), Self::UnicornPreferTopLevelAwait(rule) => rule.should_run(ctx), Self::UnicornPreferTypeError(rule) => rule.should_run(ctx), Self::UnicornRelativeUrlStyle(rule) => rule.should_run(ctx), @@ -15658,6 +15677,7 @@ impl RuleEnum { UnicornPreferStringTrimStartEnd::IS_TSGOLINT_RULE } Self::UnicornPreferStructuredClone(_) => UnicornPreferStructuredClone::IS_TSGOLINT_RULE, + Self::UnicornPreferTernary(_) => UnicornPreferTernary::IS_TSGOLINT_RULE, Self::UnicornPreferTopLevelAwait(_) => UnicornPreferTopLevelAwait::IS_TSGOLINT_RULE, Self::UnicornPreferTypeError(_) => UnicornPreferTypeError::IS_TSGOLINT_RULE, Self::UnicornRelativeUrlStyle(_) => UnicornRelativeUrlStyle::IS_TSGOLINT_RULE, @@ -16550,6 +16570,7 @@ impl RuleEnum { } Self::UnicornPreferStringTrimStartEnd(_) => UnicornPreferStringTrimStartEnd::HAS_CONFIG, Self::UnicornPreferStructuredClone(_) => UnicornPreferStructuredClone::HAS_CONFIG, + Self::UnicornPreferTernary(_) => UnicornPreferTernary::HAS_CONFIG, Self::UnicornPreferTopLevelAwait(_) => UnicornPreferTopLevelAwait::HAS_CONFIG, Self::UnicornPreferTypeError(_) => UnicornPreferTypeError::HAS_CONFIG, Self::UnicornRelativeUrlStyle(_) => UnicornRelativeUrlStyle::HAS_CONFIG, @@ -17269,6 +17290,7 @@ impl RuleEnum { Self::UnicornPreferStringStartsEndsWith(rule) => rule.types_info(), Self::UnicornPreferStringTrimStartEnd(rule) => rule.types_info(), Self::UnicornPreferStructuredClone(rule) => rule.types_info(), + Self::UnicornPreferTernary(rule) => rule.types_info(), Self::UnicornPreferTopLevelAwait(rule) => rule.types_info(), Self::UnicornPreferTypeError(rule) => rule.types_info(), Self::UnicornRelativeUrlStyle(rule) => rule.types_info(), @@ -17966,6 +17988,7 @@ impl RuleEnum { Self::UnicornPreferStringStartsEndsWith(rule) => rule.run_info(), Self::UnicornPreferStringTrimStartEnd(rule) => rule.run_info(), Self::UnicornPreferStructuredClone(rule) => rule.run_info(), + Self::UnicornPreferTernary(rule) => rule.run_info(), Self::UnicornPreferTopLevelAwait(rule) => rule.run_info(), Self::UnicornPreferTypeError(rule) => rule.run_info(), Self::UnicornRelativeUrlStyle(rule) => rule.run_info(), @@ -18769,6 +18792,7 @@ pub static RULES: std::sync::LazyLock> = std::sync::LazyLock::new( RuleEnum::UnicornPreferStringStartsEndsWith(UnicornPreferStringStartsEndsWith::default()), RuleEnum::UnicornPreferStringTrimStartEnd(UnicornPreferStringTrimStartEnd::default()), RuleEnum::UnicornPreferStructuredClone(UnicornPreferStructuredClone::default()), + RuleEnum::UnicornPreferTernary(UnicornPreferTernary::default()), RuleEnum::UnicornPreferTopLevelAwait(UnicornPreferTopLevelAwait::default()), RuleEnum::UnicornPreferTypeError(UnicornPreferTypeError::default()), RuleEnum::UnicornRelativeUrlStyle(UnicornRelativeUrlStyle::default()), diff --git a/crates/oxc_linter/src/rules.rs b/crates/oxc_linter/src/rules.rs index af704218b0538..6c8c56a3c863f 100644 --- a/crates/oxc_linter/src/rules.rs +++ b/crates/oxc_linter/src/rules.rs @@ -554,6 +554,7 @@ pub(crate) mod unicorn { pub mod prefer_string_starts_ends_with; pub mod prefer_string_trim_start_end; pub mod prefer_structured_clone; + pub mod prefer_ternary; pub mod prefer_top_level_await; pub mod prefer_type_error; pub mod relative_url_style; diff --git a/crates/oxc_linter/src/rules/unicorn/prefer_ternary.rs b/crates/oxc_linter/src/rules/unicorn/prefer_ternary.rs new file mode 100644 index 0000000000000..76ddeb5c14c2b --- /dev/null +++ b/crates/oxc_linter/src/rules/unicorn/prefer_ternary.rs @@ -0,0 +1,1685 @@ +use std::mem::discriminant; + +use schemars::JsonSchema; +use serde::Deserialize; + +use oxc_ast::{ + AstKind, + ast::{AssignmentTarget, BinaryOperator, Expression, IfStatement, MemberExpression, Statement}, +}; +use oxc_diagnostics::OxcDiagnostic; +use oxc_macros::declare_oxc_lint; +use oxc_span::{GetSpan, Span}; + +use crate::{ + AstNode, + context::LintContext, + rule::{DefaultRuleConfig, Rule}, + utils::{is_same_expression, is_same_member_expression}, +}; + +fn prefer_ternary_diagnostic(span: Span) -> OxcDiagnostic { + OxcDiagnostic::warn("Prefer ternary expressions over simple `if-else` statements.") + .with_help("Rewrite this `if`/`else` as a ternary expression.") + .with_label(span) +} + +#[derive(Debug, Clone, Copy, Default, Deserialize, JsonSchema, PartialEq, Eq)] +#[serde(rename_all = "kebab-case")] +pub enum PreferTernaryOption { + /// Always enforce ternary usage when the branches can be safely merged. + #[default] + Always, + /// Only enforce ternary usage when the condition and both branches are single-line. + OnlySingleLine, +} + +#[derive(Debug, Default, Clone, Deserialize)] +pub struct PreferTernary(PreferTernaryOption); + +declare_oxc_lint!( + /// ### What it does + /// + /// Prefers ternary expressions over simple `if`/`else` statements. + /// + /// ### Why is this bad? + /// + /// Simple `if`/`else` branches for the same operation are often shorter and + /// clearer when expressed as a ternary. + /// + /// ### Examples + /// + /// Examples of **incorrect** code for this rule: + /// ```js + /// if (test) { return a; } else { return b; } + /// ``` + /// + /// Examples of **correct** code for this rule: + /// ```js + /// return test ? a : b; + /// ``` + PreferTernary, + unicorn, + style, + pending, + config = PreferTernaryOption +); + +impl Rule for PreferTernary { + fn from_configuration(value: serde_json::Value) -> Result { + serde_json::from_value::>(value).map(DefaultRuleConfig::into_inner) + } + + fn run<'a>(&self, node: &AstNode<'a>, ctx: &LintContext<'a>) { + let AstKind::IfStatement(if_statement) = node.kind() else { + return; + }; + + if matches!(if_statement.test.get_inner_expression(), Expression::ConditionalExpression(_)) + || is_else_if_branch(node, if_statement, ctx) + { + return; + } + + let Some(if_alternate) = &if_statement.alternate else { + return; + }; + + let consequent = get_node_body_statement(&if_statement.consequent); + let alternate = get_node_body_statement(if_alternate); + + if self.0 == PreferTernaryOption::OnlySingleLine + && (!is_single_line_body(&consequent, ctx) + || !is_single_line_body(&alternate, ctx) + || !is_single_line_expression(&if_statement.test, ctx)) + { + return; + } + + if is_mergeable( + MergeNode::Body(consequent), + MergeNode::Body(alternate), + MergeOptions { check_throw_statement: true, strict: true }, + ctx, + ) { + ctx.diagnostic(prefer_ternary_diagnostic(if_statement.span)); + } + } +} + +#[derive(Debug, Clone, Copy)] +enum BodyNode<'a> { + Statement(&'a Statement<'a>), + Expression(&'a Expression<'a>), +} + +#[derive(Debug, Clone, Copy)] +enum MergeNode<'a> { + Body(BodyNode<'a>), + Expression(&'a Expression<'a>), + Undefined, +} + +#[derive(Debug, Clone, Copy)] +struct MergeOptions { + check_throw_statement: bool, + strict: bool, +} + +fn get_node_body_statement<'a>(statement: &'a Statement<'a>) -> BodyNode<'a> { + match statement { + Statement::ExpressionStatement(expression_statement) => { + BodyNode::Expression(expression_statement.expression.get_inner_expression()) + } + Statement::BlockStatement(block_statement) => { + let mut non_empty = block_statement + .body + .iter() + .filter(|statement| !matches!(statement, Statement::EmptyStatement(_))); + if let Some(single) = non_empty.next() + && non_empty.next().is_none() + { + return get_node_body_statement(single); + } + BodyNode::Statement(statement) + } + _ => BodyNode::Statement(statement), + } +} + +fn is_single_line_expression(expression: &Expression<'_>, ctx: &LintContext<'_>) -> bool { + let span = expression.get_inner_expression().span(); + !ctx.source_range(span).contains('\n') +} + +fn is_single_line_body(body: &BodyNode<'_>, ctx: &LintContext<'_>) -> bool { + let span = match body { + BodyNode::Expression(expression) => expression.get_inner_expression().span(), + BodyNode::Statement(statement) => statement.span(), + }; + !ctx.source_range(span).contains('\n') +} + +fn is_else_if_branch( + node: &AstNode<'_>, + if_statement: &IfStatement<'_>, + ctx: &LintContext<'_>, +) -> bool { + let AstKind::IfStatement(parent_if_statement) = ctx.nodes().parent_kind(node.id()) else { + return false; + }; + + parent_if_statement + .alternate + .as_ref() + .is_some_and(|alternate| alternate.span() == if_statement.span) +} + +fn is_mergeable<'a>( + consequent: MergeNode<'a>, + alternate: MergeNode<'a>, + options: MergeOptions, + ctx: &LintContext<'a>, +) -> bool { + if !same_merge_kind(consequent, alternate) { + return !options.strict; + } + + match (consequent, alternate) { + ( + MergeNode::Body(BodyNode::Statement(Statement::ReturnStatement(consequent))), + MergeNode::Body(BodyNode::Statement(Statement::ReturnStatement(alternate))), + ) if !is_ternary_option_expression(consequent.argument.as_ref()) + && !is_ternary_option_expression(alternate.argument.as_ref()) => + { + is_mergeable( + consequent.argument.as_ref().map_or(MergeNode::Undefined, MergeNode::Expression), + alternate.argument.as_ref().map_or(MergeNode::Undefined, MergeNode::Expression), + MergeOptions { strict: false, ..options }, + ctx, + ) + } + ( + MergeNode::Body(BodyNode::Expression(Expression::YieldExpression(consequent))), + MergeNode::Body(BodyNode::Expression(Expression::YieldExpression(alternate))), + ) if consequent.delegate == alternate.delegate + && !is_ternary_option_expression(consequent.argument.as_ref()) + && !is_ternary_option_expression(alternate.argument.as_ref()) => + { + is_mergeable( + consequent.argument.as_ref().map_or(MergeNode::Undefined, MergeNode::Expression), + alternate.argument.as_ref().map_or(MergeNode::Undefined, MergeNode::Expression), + MergeOptions { strict: false, ..options }, + ctx, + ) + } + ( + MergeNode::Body(BodyNode::Expression(Expression::AwaitExpression(consequent))), + MergeNode::Body(BodyNode::Expression(Expression::AwaitExpression(alternate))), + ) if !is_ternary_expression(&consequent.argument) + && !is_ternary_expression(&alternate.argument) => + { + is_mergeable( + MergeNode::Expression(&consequent.argument), + MergeNode::Expression(&alternate.argument), + MergeOptions { strict: false, ..options }, + ctx, + ) + } + ( + MergeNode::Body(BodyNode::Statement(Statement::ThrowStatement(consequent))), + MergeNode::Body(BodyNode::Statement(Statement::ThrowStatement(alternate))), + ) if options.check_throw_statement + && !is_ternary_expression(&consequent.argument) + && !is_ternary_expression(&alternate.argument) => + { + true + } + ( + MergeNode::Body(BodyNode::Expression(Expression::AssignmentExpression(consequent))), + MergeNode::Body(BodyNode::Expression(Expression::AssignmentExpression(alternate))), + ) if consequent.operator == alternate.operator + && !is_ternary_expression(&consequent.right) + && !is_ternary_expression(&alternate.right) + && is_same_assignment_target(&consequent.left, &alternate.left, ctx) => + { + is_mergeable( + MergeNode::Expression(&consequent.right), + MergeNode::Expression(&alternate.right), + MergeOptions { strict: false, ..options }, + ctx, + ) + } + _ => !options.strict, + } +} + +fn same_merge_kind(consequent: MergeNode<'_>, alternate: MergeNode<'_>) -> bool { + match (consequent, alternate) { + (MergeNode::Undefined, MergeNode::Undefined) => true, + (MergeNode::Expression(consequent), MergeNode::Expression(alternate)) + | ( + MergeNode::Body(BodyNode::Expression(consequent)), + MergeNode::Body(BodyNode::Expression(alternate)), + ) => { + discriminant(consequent.get_inner_expression()) + == discriminant(alternate.get_inner_expression()) + } + ( + MergeNode::Body(BodyNode::Statement(consequent)), + MergeNode::Body(BodyNode::Statement(alternate)), + ) => discriminant(consequent) == discriminant(alternate), + _ => false, + } +} + +fn is_ternary_option_expression(expression: Option<&Expression<'_>>) -> bool { + expression.is_some_and(is_ternary_expression) +} + +fn is_ternary_expression(expression: &Expression<'_>) -> bool { + matches!(expression.get_inner_expression(), Expression::ConditionalExpression(_)) +} + +fn is_same_assignment_target( + left: &AssignmentTarget<'_>, + right: &AssignmentTarget<'_>, + ctx: &LintContext<'_>, +) -> bool { + if let ( + AssignmentTarget::AssignmentTargetIdentifier(left), + AssignmentTarget::AssignmentTargetIdentifier(right), + ) = (left, right) + { + return left.name == right.name; + } + + if let (Some(left_member), Some(right_member)) = + (left.as_member_expression(), right.as_member_expression()) + { + if let (Some(left_name), Some(right_name)) = + (member_static_property_name(left_member), member_static_property_name(right_member)) + { + return left_name == right_name + && is_same_expression( + left_member.object().get_inner_expression(), + right_member.object().get_inner_expression(), + ctx, + ); + } + + return is_same_member_expression(left_member, right_member, ctx); + } + + match (left.get_expression(), right.get_expression()) { + (Some(left), Some(right)) => is_same_expression(left, right, ctx), + _ => false, + } +} + +fn member_static_property_name(member: &MemberExpression<'_>) -> Option { + if let Some(name) = member.static_property_name() { + return Some(name.to_string()); + } + + let MemberExpression::ComputedMemberExpression(computed) = member else { + return None; + }; + + static_string_value(computed.expression.get_inner_expression()) +} + +fn static_string_value(expression: &Expression<'_>) -> Option { + match expression { + Expression::StringLiteral(literal) => Some(literal.value.to_string()), + Expression::TemplateLiteral(literal) => { + literal.single_quasi().map(|quasi| quasi.to_string()) + } + Expression::BinaryExpression(binary) if binary.operator == BinaryOperator::Addition => { + let left = static_string_value(binary.left.get_inner_expression())?; + let right = static_string_value(binary.right.get_inner_expression())?; + Some(format!("{left}{right}")) + } + _ => None, + } +} + +#[test] +fn test() { + use crate::tester::Tester; + let only_single_line_options = vec!["only-single-line"]; + + let pass = vec![ + ( + "function unicorn() { + if(a ? b : c){ + return a; + } else{ + return b; + } + }", + None, + ), + ( + "function unicorn() { + if(test){ + return a ? b : c; + } else{ + return b; + } + }", + None, + ), + ( + "function unicorn() { + if(test){ + return a; + } else{ + return a ? b : c; + } + }", + None, + ), + ( + "function* unicorn() { + if(test){ + yield* a; + } else{ + yield b; + } + }", + None, + ), + ( + "function* unicorn() { + if(a ? b : c){ + yield a; + } else{ + yield b; + } + }", + None, + ), + ( + "function* unicorn() { + if(test){ + yield a ? b : c; + } else{ + yield b; + } + }", + None, + ), + ( + "function* unicorn() { + if(test){ + yield a; + } else{ + yield a ? b : c; + } + }", + None, + ), + ( + "async function unicorn() { + if(a ? b : c){ + await a; + } else{ + await b; + } + }", + None, + ), + ( + "async function unicorn() { + if(test){ + await a ? b : c; + } else{ + await b; + } + }", + None, + ), + ( + "async function unicorn() { + if(test){ + await a; + } else{ + await a ? b : c; + } + }", + None, + ), + ( + "function unicorn() { + if(a ? b : c){ + throw a; + } else{ + throw b; + } + }", + None, + ), + ( + "function unicorn() { + if (test) { + throw a ? b : c; + } else { + throw b; + } + }", + None, + ), + ( + "function unicorn() { + if (test) { + throw a; + } else { + throw a ? b : c; + } + }", + None, + ), + ( + "function unicorn() { + if(test){ + foo = a; + } else{ + bar = b; + } + }", + None, + ), + ( + "function unicorn() { + if(test){ + foo = a; + } else{ + foo *= b; + } + }", + None, + ), + ( + "function unicorn() { + if(test){ + foo().bar = a; + } else{ + foo().bar = b; + } + }", + None, + ), + ( + "function unicorn() { + if(a ? b : c){ + foo = a; + } else{ + foo = b; + } + }", + None, + ), + ( + "function unicorn() { + if(test){ + foo = a ? b : c; + } else{ + foo = b; + } + }", + None, + ), + ( + "function unicorn() { + if(test){ + foo = a; + } else{ + foo = a ? b : c; + } + }", + None, + ), + ( + "if (test) { + a = { + multiline: 'in consequent' + }; + } else{ + a = foo; + }", + Some(serde_json::json!(only_single_line_options)), + ), + ( + "if (test) { + a = foo; + } else{ + a = { + multiline: 'in alternate' + }; + }", + Some(serde_json::json!(only_single_line_options)), + ), + ( + "if ( + test({ + multiline: 'in test' + }) + ) { + a = foo; + } else{ + a = bar; + }", + Some(serde_json::json!(only_single_line_options)), + ), + ( + "if (test) { + a = foo; b = 1; + } else{ + a = bar; + }", + Some(serde_json::json!(only_single_line_options)), + ), + ("if (a) {b}", None), + ("if (a) {} else {b}", None), + ("if (a) {} else {}", None), + ( + "if (test) { + a(); + } else { + b(); + }", + None, + ), + ( + "function foo(){ + if (a) { + return 1; + } else if (b) { + return 2; + } else if (c) { + return 3; + } else { + return 4; + } + }", + None, + ), + ]; + + let fail = vec![ + ( + "function unicorn() { + if(test){ + return a; + } else{ + return b; + } + }", + None, + ), + ( + "async function unicorn() { + if(test){ + return await a; + } else{ + return b; + } + }", + None, + ), + ( + "async function unicorn() { + if(test){ + return await a; + } else{ + return await b; + } + }", + None, + ), + ( + "function unicorn() { + if(test){ + return; + } else{ + return b; + } + }", + None, + ), + ( + "function unicorn() { + if(test){ + return; + } else{ + return; + } + }", + None, + ), + ( + "async function unicorn() { + if(test){ + return; + } else{ + return await b; + } + }", + None, + ), + ( + "async function* unicorn() { + if(test){ + return yield await (foo = a); + } else{ + return yield await (foo = b); + } + }", + None, + ), + ( + "function* unicorn() { + if(test){ + yield a; + } else{ + yield b; + } + }", + None, + ), + ( + "function* unicorn() { + if(test){ + yield; + } else{ + yield b; + } + }", + None, + ), + ( + "function* unicorn() { + if(test){ + yield; + } else{ + yield; + } + }", + None, + ), + ( + "async function* unicorn() { + if(test){ + yield; + } else{ + yield await b; + } + }", + None, + ), + ( + "function* unicorn() { + if(test){ + yield* a; + } else{ + yield* b; + } + }", + None, + ), + ( + "async function* unicorn() { + if(test){ + yield await a; + } else{ + yield b; + } + }", + None, + ), + ( + "async function* unicorn() { + if(test){ + yield await a; + } else{ + yield await b; + } + }", + None, + ), + ( + "async function unicorn() { + if(test){ + await doSomething1(); + } else{ + await doSomething2(); + } + }", + None, + ), + ( + "async function unicorn() { + if(test){ + await a; + } else{ + await b; + } + }", + None, + ), + ( + "function unicorn() { + if (test) { + throw new Error('a'); + } else{ + throw new TypeError('a'); + } + }", + None, + ), + ( + "function unicorn() { + if (test) { + throw a; + } else { + throw b; + } + }", + None, + ), + ( + "function unicorn() { + /* comment cause wrong indention */ if (test) { + throw a; + } else { + throw b; + } + }", + None, + ), + ( + "function unicorn() { + if (test) { + throw a; + } else { + throw b; + } + }", + None, + ), + ( + "async function unicorn() { + if (test) { + throw await a; + } else { + throw b; + } + }", + None, + ), + ( + "async function unicorn() { + if (test) { + throw await a; + } else { + throw await b; + } + }", + None, + ), + ( + "function unicorn() { + const error = new Error(); + if (test) { + throw a; + } else { + throw b; + } + }", + None, + ), + ( + "function unicorn() { + if (test) { + throw a; + } else { + throw b; + } + try {} catch(error) { + const error_ = new TypeError(error); + throw error_; + } + }", + None, + ), + ( + "function unicorn() { + if (test) { + throw a; + } else { + throw b; + } + function foo() { + throw error; + } + }", + None, + ), + ( + "function unicorn() { + if (test) { + throw a; + } else { + throw b; + } + if (test) { + throw a; + } else { + throw b; + } + }", + None, + ), + ( + "function unicorn() { + const error = test ? a : b; + throw error; + if (test) { + throw a; + } else { + throw b; + } + }", + None, + ), + ( + "function outer() { + if (test) { + throw a; + } else { + throw b; + } + function inner() { + if (test) { + throw a; + } else { + throw b; + } + } + }", + None, + ), + ( + "function outer() { + const error = test ? a : b; + throw error; + function inner() { + if (test) { + throw a; + } else { + throw b; + } + } + }", + None, + ), + ("while (foo) if (test) {throw a} else {throw b}", None), + ( + "function unicorn() { + if(test){ + foo = a; + } else{ + foo = b; + } + }", + None, + ), + ( + "function unicorn() { + if(test){ + foo *= a; + } else{ + foo *= b; + } + }", + None, + ), + ( + "async function unicorn() { + if(test){ + foo = await a; + } else{ + foo = b; + } + }", + None, + ), + ( + "async function unicorn() { + if(test){ + foo = await a; + } else{ + foo = await b; + } + }", + None, + ), + ( + "function unicorn() { + if (test) { + foo.bar = a; + } else{ + foo.bar = b; + } + }", + None, + ), + ( + "function unicorn() { + a() + if (test) { + (foo)['b' + 'ar'] = a + } else{ + foo.bar = b + } + }", + None, + ), + ( + "async function* unicorn() { + if(test){ + foo = yield await a; + } else{ + foo = yield await b; + } + }", + None, + ), + ( + "if(test){ + $0 |= $1 ^= $2 &= $3 >>>= $4 >>= $5 <<= $6 %= $7 /= $8 *= $9 **= $10 -= $11 += $12 = + _STOP_ = + $0 |= $1 ^= $2 &= $3 >>>= $4 >>= $5 <<= $6 %= $7 /= $8 *= $9 **= $10 -= $11 += $12 = + 1; + } else{ + $0 |= $1 ^= $2 &= $3 >>>= $4 >>= $5 <<= $6 %= $7 /= $8 *= $9 **= $10 -= $11 += $12 = + _STOP_2_ = + $0 |= $1 ^= $2 &= $3 >>>= $4 >>= $5 <<= $6 %= $7 /= $8 *= $9 **= $10 -= $11 += $12 = + 2; + }", + None, + ), + ( + "if (test) { + a = foo; + } else { + a = bar; + }", + Some(serde_json::json!(only_single_line_options)), + ), + ( + "if ( + ( + test + ) + ) { + a = foo; + } else { + a = bar; + }", + Some(serde_json::json!(only_single_line_options)), + ), + ( + "if (test) { + ( + a = foo + ); + } else { + a = bar; + }", + Some(serde_json::json!(only_single_line_options)), + ), + ( + "if (test) { + a = foo + ; + } else { + a = bar; + }", + Some(serde_json::json!(only_single_line_options)), + ), + ( + "if (test) { + ;;;;;; + a = foo; + ;;;;;; + } else { + a = bar; + }", + Some(serde_json::json!(only_single_line_options)), + ), + ( + "function unicorn() { + // There is an empty block inside consequent + if (test) { + ; + return a; + } else { + return b; + } + }", + None, + ), + ( + "function unicorn() { + if (test) { + foo = a + } else foo = b; + }", + None, + ), + ( + "function unicorn() { + if (test) return a; + else return b; + }", + None, + ), + ( + "if (a = b) { + foo = 1; + } else foo = 2;", + None, + ), + ( + "function* unicorn() { + if (yield a) { + foo = 1; + } else foo = 2; + }", + None, + ), + ( + "function* unicorn() { + if (yield* a) { + foo = 1; + } else foo = 2; + }", + None, + ), + ( + "function foo(){ + if (a) { + return 1; + } else { + if (b) { + return 2; + } else { + return 3; + } + } + }", + None, + ), + ( + "function foo(){ + if (a) { + if (b) { + return 1; + } else { + return 2; + } + } else { + return 3; + } + }", + None, + ), + ("if (test) {foo = /* comment */1;} else {foo = 2;}", None), + ( + "function *foo(bool) { + if (!bool) { + yield call( + setOnTop, + false, + ); + } else { + yield call( + setOnTop, + true, + 'normal', + ); // Keep this comment. + } + }", + None, + ), + ]; + + let _fix = vec![ + ("function unicorn() { + if(test){ + return a; + } else{ + return b; + } + }", "function unicorn() { + return test ? a : b; + }", None), +("async function unicorn() { + if(test){ + return await a; + } else{ + return b; + } + }", "async function unicorn() { + return test ? (await a) : b; + }", None), +("async function unicorn() { + if(test){ + return await a; + } else{ + return await b; + } + }", "async function unicorn() { + return await (test ? a : b); + }", None), +("function unicorn() { + if(test){ + return; + } else{ + return b; + } + }", "function unicorn() { + return test ? undefined : b; + }", None), +("function unicorn() { + if(test){ + return; + } else{ + return; + } + }", "function unicorn() { + return test ? undefined : undefined; + }", None), +("async function unicorn() { + if(test){ + return; + } else{ + return await b; + } + }", "async function unicorn() { + return test ? undefined : (await b); + }", None), +("async function* unicorn() { + if(test){ + return yield await (foo = a); + } else{ + return yield await (foo = b); + } + }", "async function* unicorn() { + return yield (await (foo = test ? a : b)); + }", None), +("function* unicorn() { + if(test){ + yield a; + } else{ + yield b; + } + }", "function* unicorn() { + yield (test ? a : b); + }", None), +("function* unicorn() { + if(test){ + yield; + } else{ + yield b; + } + }", "function* unicorn() { + yield (test ? undefined : b); + }", None), +("function* unicorn() { + if(test){ + yield; + } else{ + yield; + } + }", "function* unicorn() { + yield (test ? undefined : undefined); + }", None), +("async function* unicorn() { + if(test){ + yield; + } else{ + yield await b; + } + }", "async function* unicorn() { + yield (test ? undefined : (await b)); + }", None), +("function* unicorn() { + if(test){ + yield* a; + } else{ + yield* b; + } + }", "function* unicorn() { + yield* (test ? a : b); + }", None), +("async function* unicorn() { + if(test){ + yield await a; + } else{ + yield b; + } + }", "async function* unicorn() { + yield (test ? (await a) : b); + }", None), +("async function* unicorn() { + if(test){ + yield await a; + } else{ + yield await b; + } + }", "async function* unicorn() { + yield (await (test ? a : b)); + }", None), +("async function unicorn() { + if(test){ + await doSomething1(); + } else{ + await doSomething2(); + } + }", "async function unicorn() { + await (test ? doSomething1() : doSomething2()); + }", None), +("async function unicorn() { + if(test){ + await a; + } else{ + await b; + } + }", "async function unicorn() { + await (test ? a : b); + }", None), +("function unicorn() { + if (test) { + throw new Error('a'); + } else{ + throw new TypeError('a'); + } + }", "function unicorn() { + const error = test ? new Error('a') : new TypeError('a'); + throw error; + }", None), +("function unicorn() { + if (test) { + throw a; + } else { + throw b; + } + }", "function unicorn() { + const error = test ? a : b; + throw error; + }", None), +("function unicorn() { + /* comment cause wrong indention */ if (test) { + throw a; + } else { + throw b; + } + }", "function unicorn() { + /* comment cause wrong indention */ const error = test ? a : b; + throw error; + }", None), +("function unicorn() { + if (test) { + throw a; + } else { + throw b; + } + }", "function unicorn() { + const error = test ? a : b; + throw error; + }", None), +("async function unicorn() { + if (test) { + throw await a; + } else { + throw b; + } + }", "async function unicorn() { + const error = test ? (await a) : b; + throw error; + }", None), +("async function unicorn() { + if (test) { + throw await a; + } else { + throw await b; + } + }", "async function unicorn() { + const error = test ? (await a) : (await b); + throw error; + }", None), +("function unicorn() { + const error = new Error(); + if (test) { + throw a; + } else { + throw b; + } + }", "function unicorn() { + const error = new Error(); + const error_ = test ? a : b; + throw error_; + }", None), +("function unicorn() { + if (test) { + throw a; + } else { + throw b; + } + try {} catch(error) { + const error_ = new TypeError(error); + throw error_; + } + }", "function unicorn() { + const error__ = test ? a : b; + throw error__; + try {} catch(error) { + const error_ = new TypeError(error); + throw error_; + } + }", None), +("function unicorn() { + if (test) { + throw a; + } else { + throw b; + } + function foo() { + throw error; + } + }", "function unicorn() { + const error_ = test ? a : b; + throw error_; + function foo() { + throw error; + } + }", None), +("function unicorn() { + if (test) { + throw a; + } else { + throw b; + } + if (test) { + throw a; + } else { + throw b; + } + }", "function unicorn() { + const error = test ? a : b; + throw error; + if (test) { + throw a; + } else { + throw b; + } + }", None), +("function unicorn() { + const error = test ? a : b; + throw error; + if (test) { + throw a; + } else { + throw b; + } + }", "function unicorn() { + const error = test ? a : b; + throw error; + const error_ = test ? a : b; + throw error_; + }", None), +("function outer() { + if (test) { + throw a; + } else { + throw b; + } + function inner() { + if (test) { + throw a; + } else { + throw b; + } + } + }", "function outer() { + const error = test ? a : b; + throw error; + function inner() { + if (test) { + throw a; + } else { + throw b; + } + } + }", None), +("function outer() { + const error = test ? a : b; + throw error; + function inner() { + if (test) { + throw a; + } else { + throw b; + } + } + }", "function outer() { + const error = test ? a : b; + throw error; + function inner() { + const error_ = test ? a : b; + throw error_; + } + }", None), +("while (foo) if (test) {throw a} else {throw b}", "while (foo) { + const error = test ? a : b; + throw error; + }", None), +("function unicorn() { + if(test){ + foo = a; + } else{ + foo = b; + } + }", "function unicorn() { + foo = test ? a : b; + }", None), +("function unicorn() { + if(test){ + foo *= a; + } else{ + foo *= b; + } + }", "function unicorn() { + foo *= test ? a : b; + }", None), +("async function unicorn() { + if(test){ + foo = await a; + } else{ + foo = b; + } + }", "async function unicorn() { + foo = test ? (await a) : b; + }", None), +("async function unicorn() { + if(test){ + foo = await a; + } else{ + foo = await b; + } + }", "async function unicorn() { + foo = await (test ? a : b); + }", None), +("function unicorn() { + if (test) { + foo.bar = a; + } else{ + foo.bar = b; + } + }", "function unicorn() { + foo.bar = test ? a : b; + }", None), +("function unicorn() { + a() + if (test) { + (foo)['b' + 'ar'] = a + } else{ + foo.bar = b + } + }", "function unicorn() { + a() + ;(foo)['b' + 'ar'] = test ? a : b; + }", None), +("async function* unicorn() { + if(test){ + foo = yield await a; + } else{ + foo = yield await b; + } + }", "async function* unicorn() { + foo = yield (await (test ? a : b)); + }", None), +("if(test){ + $0 |= $1 ^= $2 &= $3 >>>= $4 >>= $5 <<= $6 %= $7 /= $8 *= $9 **= $10 -= $11 += $12 = + _STOP_ = + $0 |= $1 ^= $2 &= $3 >>>= $4 >>= $5 <<= $6 %= $7 /= $8 *= $9 **= $10 -= $11 += $12 = + 1; + } else{ + $0 |= $1 ^= $2 &= $3 >>>= $4 >>= $5 <<= $6 %= $7 /= $8 *= $9 **= $10 -= $11 += $12 = + _STOP_2_ = + $0 |= $1 ^= $2 &= $3 >>>= $4 >>= $5 <<= $6 %= $7 /= $8 *= $9 **= $10 -= $11 += $12 = + 2; + }", "$0 |= $1 ^= $2 &= $3 >>>= $4 >>= $5 <<= $6 %= $7 /= $8 *= $9 **= $10 -= $11 += $12 = test ? (_STOP_ = + $0 |= $1 ^= $2 &= $3 >>>= $4 >>= $5 <<= $6 %= $7 /= $8 *= $9 **= $10 -= $11 += $12 = + 1) : (_STOP_2_ = + $0 |= $1 ^= $2 &= $3 >>>= $4 >>= $5 <<= $6 %= $7 /= $8 *= $9 **= $10 -= $11 += $12 = + 2);", None), +("if (test) { + a = foo; + } else { + a = bar; + }", "a = test ? foo : bar;", Some(serde_json::json!(only_single_line_options))), +("if ( + ( + test + ) + ) { + a = foo; + } else { + a = bar; + }", "a = ( + test + ) ? foo : bar;", Some(serde_json::json!(only_single_line_options))), +("if (test) { + ( + a = foo + ); + } else { + a = bar; + }", "a = test ? foo : bar;", Some(serde_json::json!(only_single_line_options))), +("if (test) { + a = foo + ; + } else { + a = bar; + }", "a = test ? foo : bar;", Some(serde_json::json!(only_single_line_options))), +("if (test) { + ;;;;;; + a = foo; + ;;;;;; + } else { + a = bar; + }", "a = test ? foo : bar;", Some(serde_json::json!(only_single_line_options))), +("function unicorn() { + // There is an empty block inside consequent + if (test) { + ; + return a; + } else { + return b; + } + }", "function unicorn() { + // There is an empty block inside consequent + return test ? a : b; + }", None), +("function unicorn() { + if (test) { + foo = a + } else foo = b; + }", "function unicorn() { + foo = test ? a : b; + }", None), +("function unicorn() { + if (test) return a; + else return b; + }", "function unicorn() { + return test ? a : b; + }", None), +("if (a = b) { + foo = 1; + } else foo = 2;", "foo = (a = b) ? 1 : 2;", None), +("function* unicorn() { + if (yield a) { + foo = 1; + } else foo = 2; + }", "function* unicorn() { + foo = (yield a) ? 1 : 2; + }", None), +("function* unicorn() { + if (yield* a) { + foo = 1; + } else foo = 2; + }", "function* unicorn() { + foo = (yield* a) ? 1 : 2; + }", None), +("function foo(){ + if (a) { + return 1; + } else { + if (b) { + return 2; + } else { + return 3; + } + } + }", "function foo(){ + if (a) { + return 1; + } else { + return b ? 2 : 3; + } + }", None), +("function foo(){ + if (a) { + if (b) { + return 1; + } else { + return 2; + } + } else { + return 3; + } + }", "function foo(){ + if (a) { + return b ? 1 : 2; + } else { + return 3; + } + }", None) + ]; + + Tester::new(PreferTernary::NAME, PreferTernary::PLUGIN, pass, fail).test_and_snapshot(); +} diff --git a/crates/oxc_linter/src/snapshots/unicorn_prefer_ternary.snap b/crates/oxc_linter/src/snapshots/unicorn_prefer_ternary.snap new file mode 100644 index 0000000000000..7b48c8148fb02 --- /dev/null +++ b/crates/oxc_linter/src/snapshots/unicorn_prefer_ternary.snap @@ -0,0 +1,651 @@ +--- +source: crates/oxc_linter/src/tester.rs +--- + + ⚠ eslint-plugin-unicorn(prefer-ternary): Prefer ternary expressions over simple `if-else` statements. + ╭─[prefer_ternary.tsx:2:17] + 1 │ function unicorn() { + 2 │ ╭─▶ if(test){ + 3 │ │ return a; + 4 │ │ } else{ + 5 │ │ return b; + 6 │ ╰─▶ } + 7 │ } + ╰──── + help: Rewrite this `if`/`else` as a ternary expression. + + ⚠ eslint-plugin-unicorn(prefer-ternary): Prefer ternary expressions over simple `if-else` statements. + ╭─[prefer_ternary.tsx:2:17] + 1 │ async function unicorn() { + 2 │ ╭─▶ if(test){ + 3 │ │ return await a; + 4 │ │ } else{ + 5 │ │ return b; + 6 │ ╰─▶ } + 7 │ } + ╰──── + help: Rewrite this `if`/`else` as a ternary expression. + + ⚠ eslint-plugin-unicorn(prefer-ternary): Prefer ternary expressions over simple `if-else` statements. + ╭─[prefer_ternary.tsx:2:17] + 1 │ async function unicorn() { + 2 │ ╭─▶ if(test){ + 3 │ │ return await a; + 4 │ │ } else{ + 5 │ │ return await b; + 6 │ ╰─▶ } + 7 │ } + ╰──── + help: Rewrite this `if`/`else` as a ternary expression. + + ⚠ eslint-plugin-unicorn(prefer-ternary): Prefer ternary expressions over simple `if-else` statements. + ╭─[prefer_ternary.tsx:2:17] + 1 │ function unicorn() { + 2 │ ╭─▶ if(test){ + 3 │ │ return; + 4 │ │ } else{ + 5 │ │ return b; + 6 │ ╰─▶ } + 7 │ } + ╰──── + help: Rewrite this `if`/`else` as a ternary expression. + + ⚠ eslint-plugin-unicorn(prefer-ternary): Prefer ternary expressions over simple `if-else` statements. + ╭─[prefer_ternary.tsx:2:17] + 1 │ function unicorn() { + 2 │ ╭─▶ if(test){ + 3 │ │ return; + 4 │ │ } else{ + 5 │ │ return; + 6 │ ╰─▶ } + 7 │ } + ╰──── + help: Rewrite this `if`/`else` as a ternary expression. + + ⚠ eslint-plugin-unicorn(prefer-ternary): Prefer ternary expressions over simple `if-else` statements. + ╭─[prefer_ternary.tsx:2:17] + 1 │ async function unicorn() { + 2 │ ╭─▶ if(test){ + 3 │ │ return; + 4 │ │ } else{ + 5 │ │ return await b; + 6 │ ╰─▶ } + 7 │ } + ╰──── + help: Rewrite this `if`/`else` as a ternary expression. + + ⚠ eslint-plugin-unicorn(prefer-ternary): Prefer ternary expressions over simple `if-else` statements. + ╭─[prefer_ternary.tsx:2:17] + 1 │ async function* unicorn() { + 2 │ ╭─▶ if(test){ + 3 │ │ return yield await (foo = a); + 4 │ │ } else{ + 5 │ │ return yield await (foo = b); + 6 │ ╰─▶ } + 7 │ } + ╰──── + help: Rewrite this `if`/`else` as a ternary expression. + + ⚠ eslint-plugin-unicorn(prefer-ternary): Prefer ternary expressions over simple `if-else` statements. + ╭─[prefer_ternary.tsx:2:17] + 1 │ function* unicorn() { + 2 │ ╭─▶ if(test){ + 3 │ │ yield a; + 4 │ │ } else{ + 5 │ │ yield b; + 6 │ ╰─▶ } + 7 │ } + ╰──── + help: Rewrite this `if`/`else` as a ternary expression. + + ⚠ eslint-plugin-unicorn(prefer-ternary): Prefer ternary expressions over simple `if-else` statements. + ╭─[prefer_ternary.tsx:2:17] + 1 │ function* unicorn() { + 2 │ ╭─▶ if(test){ + 3 │ │ yield; + 4 │ │ } else{ + 5 │ │ yield b; + 6 │ ╰─▶ } + 7 │ } + ╰──── + help: Rewrite this `if`/`else` as a ternary expression. + + ⚠ eslint-plugin-unicorn(prefer-ternary): Prefer ternary expressions over simple `if-else` statements. + ╭─[prefer_ternary.tsx:2:17] + 1 │ function* unicorn() { + 2 │ ╭─▶ if(test){ + 3 │ │ yield; + 4 │ │ } else{ + 5 │ │ yield; + 6 │ ╰─▶ } + 7 │ } + ╰──── + help: Rewrite this `if`/`else` as a ternary expression. + + ⚠ eslint-plugin-unicorn(prefer-ternary): Prefer ternary expressions over simple `if-else` statements. + ╭─[prefer_ternary.tsx:2:17] + 1 │ async function* unicorn() { + 2 │ ╭─▶ if(test){ + 3 │ │ yield; + 4 │ │ } else{ + 5 │ │ yield await b; + 6 │ ╰─▶ } + 7 │ } + ╰──── + help: Rewrite this `if`/`else` as a ternary expression. + + ⚠ eslint-plugin-unicorn(prefer-ternary): Prefer ternary expressions over simple `if-else` statements. + ╭─[prefer_ternary.tsx:2:17] + 1 │ function* unicorn() { + 2 │ ╭─▶ if(test){ + 3 │ │ yield* a; + 4 │ │ } else{ + 5 │ │ yield* b; + 6 │ ╰─▶ } + 7 │ } + ╰──── + help: Rewrite this `if`/`else` as a ternary expression. + + ⚠ eslint-plugin-unicorn(prefer-ternary): Prefer ternary expressions over simple `if-else` statements. + ╭─[prefer_ternary.tsx:2:17] + 1 │ async function* unicorn() { + 2 │ ╭─▶ if(test){ + 3 │ │ yield await a; + 4 │ │ } else{ + 5 │ │ yield b; + 6 │ ╰─▶ } + 7 │ } + ╰──── + help: Rewrite this `if`/`else` as a ternary expression. + + ⚠ eslint-plugin-unicorn(prefer-ternary): Prefer ternary expressions over simple `if-else` statements. + ╭─[prefer_ternary.tsx:2:17] + 1 │ async function* unicorn() { + 2 │ ╭─▶ if(test){ + 3 │ │ yield await a; + 4 │ │ } else{ + 5 │ │ yield await b; + 6 │ ╰─▶ } + 7 │ } + ╰──── + help: Rewrite this `if`/`else` as a ternary expression. + + ⚠ eslint-plugin-unicorn(prefer-ternary): Prefer ternary expressions over simple `if-else` statements. + ╭─[prefer_ternary.tsx:2:17] + 1 │ async function unicorn() { + 2 │ ╭─▶ if(test){ + 3 │ │ await doSomething1(); + 4 │ │ } else{ + 5 │ │ await doSomething2(); + 6 │ ╰─▶ } + 7 │ } + ╰──── + help: Rewrite this `if`/`else` as a ternary expression. + + ⚠ eslint-plugin-unicorn(prefer-ternary): Prefer ternary expressions over simple `if-else` statements. + ╭─[prefer_ternary.tsx:2:17] + 1 │ async function unicorn() { + 2 │ ╭─▶ if(test){ + 3 │ │ await a; + 4 │ │ } else{ + 5 │ │ await b; + 6 │ ╰─▶ } + 7 │ } + ╰──── + help: Rewrite this `if`/`else` as a ternary expression. + + ⚠ eslint-plugin-unicorn(prefer-ternary): Prefer ternary expressions over simple `if-else` statements. + ╭─[prefer_ternary.tsx:2:17] + 1 │ function unicorn() { + 2 │ ╭─▶ if (test) { + 3 │ │ throw new Error('a'); + 4 │ │ } else{ + 5 │ │ throw new TypeError('a'); + 6 │ ╰─▶ } + 7 │ } + ╰──── + help: Rewrite this `if`/`else` as a ternary expression. + + ⚠ eslint-plugin-unicorn(prefer-ternary): Prefer ternary expressions over simple `if-else` statements. + ╭─[prefer_ternary.tsx:2:17] + 1 │ function unicorn() { + 2 │ ╭─▶ if (test) { + 3 │ │ throw a; + 4 │ │ } else { + 5 │ │ throw b; + 6 │ ╰─▶ } + 7 │ } + ╰──── + help: Rewrite this `if`/`else` as a ternary expression. + + ⚠ eslint-plugin-unicorn(prefer-ternary): Prefer ternary expressions over simple `if-else` statements. + ╭─[prefer_ternary.tsx:2:53] + 1 │ function unicorn() { + 2 │ ╭─▶ /* comment cause wrong indention */ if (test) { + 3 │ │ throw a; + 4 │ │ } else { + 5 │ │ throw b; + 6 │ ╰─▶ } + 7 │ } + ╰──── + help: Rewrite this `if`/`else` as a ternary expression. + + ⚠ eslint-plugin-unicorn(prefer-ternary): Prefer ternary expressions over simple `if-else` statements. + ╭─[prefer_ternary.tsx:2:53] + 1 │ function unicorn() { + 2 │ ╭─▶ if (test) { + 3 │ │ throw a; + 4 │ │ } else { + 5 │ │ throw b; + 6 │ ╰─▶ } + 7 │ } + ╰──── + help: Rewrite this `if`/`else` as a ternary expression. + + ⚠ eslint-plugin-unicorn(prefer-ternary): Prefer ternary expressions over simple `if-else` statements. + ╭─[prefer_ternary.tsx:2:17] + 1 │ async function unicorn() { + 2 │ ╭─▶ if (test) { + 3 │ │ throw await a; + 4 │ │ } else { + 5 │ │ throw b; + 6 │ ╰─▶ } + 7 │ } + ╰──── + help: Rewrite this `if`/`else` as a ternary expression. + + ⚠ eslint-plugin-unicorn(prefer-ternary): Prefer ternary expressions over simple `if-else` statements. + ╭─[prefer_ternary.tsx:2:17] + 1 │ async function unicorn() { + 2 │ ╭─▶ if (test) { + 3 │ │ throw await a; + 4 │ │ } else { + 5 │ │ throw await b; + 6 │ ╰─▶ } + 7 │ } + ╰──── + help: Rewrite this `if`/`else` as a ternary expression. + + ⚠ eslint-plugin-unicorn(prefer-ternary): Prefer ternary expressions over simple `if-else` statements. + ╭─[prefer_ternary.tsx:3:17] + 2 │ const error = new Error(); + 3 │ ╭─▶ if (test) { + 4 │ │ throw a; + 5 │ │ } else { + 6 │ │ throw b; + 7 │ ╰─▶ } + 8 │ } + ╰──── + help: Rewrite this `if`/`else` as a ternary expression. + + ⚠ eslint-plugin-unicorn(prefer-ternary): Prefer ternary expressions over simple `if-else` statements. + ╭─[prefer_ternary.tsx:2:17] + 1 │ function unicorn() { + 2 │ ╭─▶ if (test) { + 3 │ │ throw a; + 4 │ │ } else { + 5 │ │ throw b; + 6 │ ╰─▶ } + 7 │ try {} catch(error) { + ╰──── + help: Rewrite this `if`/`else` as a ternary expression. + + ⚠ eslint-plugin-unicorn(prefer-ternary): Prefer ternary expressions over simple `if-else` statements. + ╭─[prefer_ternary.tsx:2:17] + 1 │ function unicorn() { + 2 │ ╭─▶ if (test) { + 3 │ │ throw a; + 4 │ │ } else { + 5 │ │ throw b; + 6 │ ╰─▶ } + 7 │ function foo() { + ╰──── + help: Rewrite this `if`/`else` as a ternary expression. + + ⚠ eslint-plugin-unicorn(prefer-ternary): Prefer ternary expressions over simple `if-else` statements. + ╭─[prefer_ternary.tsx:2:17] + 1 │ function unicorn() { + 2 │ ╭─▶ if (test) { + 3 │ │ throw a; + 4 │ │ } else { + 5 │ │ throw b; + 6 │ ╰─▶ } + 7 │ if (test) { + ╰──── + help: Rewrite this `if`/`else` as a ternary expression. + + ⚠ eslint-plugin-unicorn(prefer-ternary): Prefer ternary expressions over simple `if-else` statements. + ╭─[prefer_ternary.tsx:7:17] + 6 │ } + 7 │ ╭─▶ if (test) { + 8 │ │ throw a; + 9 │ │ } else { + 10 │ │ throw b; + 11 │ ╰─▶ } + 12 │ } + ╰──── + help: Rewrite this `if`/`else` as a ternary expression. + + ⚠ eslint-plugin-unicorn(prefer-ternary): Prefer ternary expressions over simple `if-else` statements. + ╭─[prefer_ternary.tsx:4:17] + 3 │ throw error; + 4 │ ╭─▶ if (test) { + 5 │ │ throw a; + 6 │ │ } else { + 7 │ │ throw b; + 8 │ ╰─▶ } + 9 │ } + ╰──── + help: Rewrite this `if`/`else` as a ternary expression. + + ⚠ eslint-plugin-unicorn(prefer-ternary): Prefer ternary expressions over simple `if-else` statements. + ╭─[prefer_ternary.tsx:2:17] + 1 │ function outer() { + 2 │ ╭─▶ if (test) { + 3 │ │ throw a; + 4 │ │ } else { + 5 │ │ throw b; + 6 │ ╰─▶ } + 7 │ function inner() { + ╰──── + help: Rewrite this `if`/`else` as a ternary expression. + + ⚠ eslint-plugin-unicorn(prefer-ternary): Prefer ternary expressions over simple `if-else` statements. + ╭─[prefer_ternary.tsx:8:21] + 7 │ function inner() { + 8 │ ╭─▶ if (test) { + 9 │ │ throw a; + 10 │ │ } else { + 11 │ │ throw b; + 12 │ ╰─▶ } + 13 │ } + ╰──── + help: Rewrite this `if`/`else` as a ternary expression. + + ⚠ eslint-plugin-unicorn(prefer-ternary): Prefer ternary expressions over simple `if-else` statements. + ╭─[prefer_ternary.tsx:5:21] + 4 │ function inner() { + 5 │ ╭─▶ if (test) { + 6 │ │ throw a; + 7 │ │ } else { + 8 │ │ throw b; + 9 │ ╰─▶ } + 10 │ } + ╰──── + help: Rewrite this `if`/`else` as a ternary expression. + + ⚠ eslint-plugin-unicorn(prefer-ternary): Prefer ternary expressions over simple `if-else` statements. + ╭─[prefer_ternary.tsx:1:13] + 1 │ while (foo) if (test) {throw a} else {throw b} + · ────────────────────────────────── + ╰──── + help: Rewrite this `if`/`else` as a ternary expression. + + ⚠ eslint-plugin-unicorn(prefer-ternary): Prefer ternary expressions over simple `if-else` statements. + ╭─[prefer_ternary.tsx:2:17] + 1 │ function unicorn() { + 2 │ ╭─▶ if(test){ + 3 │ │ foo = a; + 4 │ │ } else{ + 5 │ │ foo = b; + 6 │ ╰─▶ } + 7 │ } + ╰──── + help: Rewrite this `if`/`else` as a ternary expression. + + ⚠ eslint-plugin-unicorn(prefer-ternary): Prefer ternary expressions over simple `if-else` statements. + ╭─[prefer_ternary.tsx:2:17] + 1 │ function unicorn() { + 2 │ ╭─▶ if(test){ + 3 │ │ foo *= a; + 4 │ │ } else{ + 5 │ │ foo *= b; + 6 │ ╰─▶ } + 7 │ } + ╰──── + help: Rewrite this `if`/`else` as a ternary expression. + + ⚠ eslint-plugin-unicorn(prefer-ternary): Prefer ternary expressions over simple `if-else` statements. + ╭─[prefer_ternary.tsx:2:17] + 1 │ async function unicorn() { + 2 │ ╭─▶ if(test){ + 3 │ │ foo = await a; + 4 │ │ } else{ + 5 │ │ foo = b; + 6 │ ╰─▶ } + 7 │ } + ╰──── + help: Rewrite this `if`/`else` as a ternary expression. + + ⚠ eslint-plugin-unicorn(prefer-ternary): Prefer ternary expressions over simple `if-else` statements. + ╭─[prefer_ternary.tsx:2:17] + 1 │ async function unicorn() { + 2 │ ╭─▶ if(test){ + 3 │ │ foo = await a; + 4 │ │ } else{ + 5 │ │ foo = await b; + 6 │ ╰─▶ } + 7 │ } + ╰──── + help: Rewrite this `if`/`else` as a ternary expression. + + ⚠ eslint-plugin-unicorn(prefer-ternary): Prefer ternary expressions over simple `if-else` statements. + ╭─[prefer_ternary.tsx:2:17] + 1 │ function unicorn() { + 2 │ ╭─▶ if (test) { + 3 │ │ foo.bar = a; + 4 │ │ } else{ + 5 │ │ foo.bar = b; + 6 │ ╰─▶ } + 7 │ } + ╰──── + help: Rewrite this `if`/`else` as a ternary expression. + + ⚠ eslint-plugin-unicorn(prefer-ternary): Prefer ternary expressions over simple `if-else` statements. + ╭─[prefer_ternary.tsx:3:17] + 2 │ a() + 3 │ ╭─▶ if (test) { + 4 │ │ (foo)['b' + 'ar'] = a + 5 │ │ } else{ + 6 │ │ foo.bar = b + 7 │ ╰─▶ } + 8 │ } + ╰──── + help: Rewrite this `if`/`else` as a ternary expression. + + ⚠ eslint-plugin-unicorn(prefer-ternary): Prefer ternary expressions over simple `if-else` statements. + ╭─[prefer_ternary.tsx:2:17] + 1 │ async function* unicorn() { + 2 │ ╭─▶ if(test){ + 3 │ │ foo = yield await a; + 4 │ │ } else{ + 5 │ │ foo = yield await b; + 6 │ ╰─▶ } + 7 │ } + ╰──── + help: Rewrite this `if`/`else` as a ternary expression. + + ⚠ eslint-plugin-unicorn(prefer-ternary): Prefer ternary expressions over simple `if-else` statements. + ╭─[prefer_ternary.tsx:1:1] + 1 │ ╭─▶ if(test){ + 2 │ │ $0 |= $1 ^= $2 &= $3 >>>= $4 >>= $5 <<= $6 %= $7 /= $8 *= $9 **= $10 -= $11 += $12 = + 3 │ │ _STOP_ = + 4 │ │ $0 |= $1 ^= $2 &= $3 >>>= $4 >>= $5 <<= $6 %= $7 /= $8 *= $9 **= $10 -= $11 += $12 = + 5 │ │ 1; + 6 │ │ } else{ + 7 │ │ $0 |= $1 ^= $2 &= $3 >>>= $4 >>= $5 <<= $6 %= $7 /= $8 *= $9 **= $10 -= $11 += $12 = + 8 │ │ _STOP_2_ = + 9 │ │ $0 |= $1 ^= $2 &= $3 >>>= $4 >>= $5 <<= $6 %= $7 /= $8 *= $9 **= $10 -= $11 += $12 = + 10 │ │ 2; + 11 │ ╰─▶ } + ╰──── + help: Rewrite this `if`/`else` as a ternary expression. + + ⚠ eslint-plugin-unicorn(prefer-ternary): Prefer ternary expressions over simple `if-else` statements. + ╭─[prefer_ternary.tsx:1:1] + 1 │ ╭─▶ if (test) { + 2 │ │ a = foo; + 3 │ │ } else { + 4 │ │ a = bar; + 5 │ ╰─▶ } + ╰──── + help: Rewrite this `if`/`else` as a ternary expression. + + ⚠ eslint-plugin-unicorn(prefer-ternary): Prefer ternary expressions over simple `if-else` statements. + ╭─[prefer_ternary.tsx:1:1] + 1 │ ╭─▶ if ( + 2 │ │ ( + 3 │ │ test + 4 │ │ ) + 5 │ │ ) { + 6 │ │ a = foo; + 7 │ │ } else { + 8 │ │ a = bar; + 9 │ ╰─▶ } + ╰──── + help: Rewrite this `if`/`else` as a ternary expression. + + ⚠ eslint-plugin-unicorn(prefer-ternary): Prefer ternary expressions over simple `if-else` statements. + ╭─[prefer_ternary.tsx:1:1] + 1 │ ╭─▶ if (test) { + 2 │ │ ( + 3 │ │ a = foo + 4 │ │ ); + 5 │ │ } else { + 6 │ │ a = bar; + 7 │ ╰─▶ } + ╰──── + help: Rewrite this `if`/`else` as a ternary expression. + + ⚠ eslint-plugin-unicorn(prefer-ternary): Prefer ternary expressions over simple `if-else` statements. + ╭─[prefer_ternary.tsx:1:1] + 1 │ ╭─▶ if (test) { + 2 │ │ a = foo + 3 │ │ ; + 4 │ │ } else { + 5 │ │ a = bar; + 6 │ ╰─▶ } + ╰──── + help: Rewrite this `if`/`else` as a ternary expression. + + ⚠ eslint-plugin-unicorn(prefer-ternary): Prefer ternary expressions over simple `if-else` statements. + ╭─[prefer_ternary.tsx:1:1] + 1 │ ╭─▶ if (test) { + 2 │ │ ;;;;;; + 3 │ │ a = foo; + 4 │ │ ;;;;;; + 5 │ │ } else { + 6 │ │ a = bar; + 7 │ ╰─▶ } + ╰──── + help: Rewrite this `if`/`else` as a ternary expression. + + ⚠ eslint-plugin-unicorn(prefer-ternary): Prefer ternary expressions over simple `if-else` statements. + ╭─[prefer_ternary.tsx:3:17] + 2 │ // There is an empty block inside consequent + 3 │ ╭─▶ if (test) { + 4 │ │ ; + 5 │ │ return a; + 6 │ │ } else { + 7 │ │ return b; + 8 │ ╰─▶ } + 9 │ } + ╰──── + help: Rewrite this `if`/`else` as a ternary expression. + + ⚠ eslint-plugin-unicorn(prefer-ternary): Prefer ternary expressions over simple `if-else` statements. + ╭─[prefer_ternary.tsx:2:17] + 1 │ function unicorn() { + 2 │ ╭─▶ if (test) { + 3 │ │ foo = a + 4 │ ╰─▶ } else foo = b; + 5 │ } + ╰──── + help: Rewrite this `if`/`else` as a ternary expression. + + ⚠ eslint-plugin-unicorn(prefer-ternary): Prefer ternary expressions over simple `if-else` statements. + ╭─[prefer_ternary.tsx:2:17] + 1 │ function unicorn() { + 2 │ ╭─▶ if (test) return a; + 3 │ ╰─▶ else return b; + 4 │ } + ╰──── + help: Rewrite this `if`/`else` as a ternary expression. + + ⚠ eslint-plugin-unicorn(prefer-ternary): Prefer ternary expressions over simple `if-else` statements. + ╭─[prefer_ternary.tsx:1:1] + 1 │ ╭─▶ if (a = b) { + 2 │ │ foo = 1; + 3 │ ╰─▶ } else foo = 2; + ╰──── + help: Rewrite this `if`/`else` as a ternary expression. + + ⚠ eslint-plugin-unicorn(prefer-ternary): Prefer ternary expressions over simple `if-else` statements. + ╭─[prefer_ternary.tsx:2:17] + 1 │ function* unicorn() { + 2 │ ╭─▶ if (yield a) { + 3 │ │ foo = 1; + 4 │ ╰─▶ } else foo = 2; + 5 │ } + ╰──── + help: Rewrite this `if`/`else` as a ternary expression. + + ⚠ eslint-plugin-unicorn(prefer-ternary): Prefer ternary expressions over simple `if-else` statements. + ╭─[prefer_ternary.tsx:2:17] + 1 │ function* unicorn() { + 2 │ ╭─▶ if (yield* a) { + 3 │ │ foo = 1; + 4 │ ╰─▶ } else foo = 2; + 5 │ } + ╰──── + help: Rewrite this `if`/`else` as a ternary expression. + + ⚠ eslint-plugin-unicorn(prefer-ternary): Prefer ternary expressions over simple `if-else` statements. + ╭─[prefer_ternary.tsx:5:21] + 4 │ } else { + 5 │ ╭─▶ if (b) { + 6 │ │ return 2; + 7 │ │ } else { + 8 │ │ return 3; + 9 │ ╰─▶ } + 10 │ } + ╰──── + help: Rewrite this `if`/`else` as a ternary expression. + + ⚠ eslint-plugin-unicorn(prefer-ternary): Prefer ternary expressions over simple `if-else` statements. + ╭─[prefer_ternary.tsx:3:21] + 2 │ if (a) { + 3 │ ╭─▶ if (b) { + 4 │ │ return 1; + 5 │ │ } else { + 6 │ │ return 2; + 7 │ ╰─▶ } + 8 │ } else { + ╰──── + help: Rewrite this `if`/`else` as a ternary expression. + + ⚠ eslint-plugin-unicorn(prefer-ternary): Prefer ternary expressions over simple `if-else` statements. + ╭─[prefer_ternary.tsx:1:1] + 1 │ if (test) {foo = /* comment */1;} else {foo = 2;} + · ───────────────────────────────────────────────── + ╰──── + help: Rewrite this `if`/`else` as a ternary expression. + + ⚠ eslint-plugin-unicorn(prefer-ternary): Prefer ternary expressions over simple `if-else` statements. + ╭─[prefer_ternary.tsx:2:17] + 1 │ function *foo(bool) { + 2 │ ╭─▶ if (!bool) { + 3 │ │ yield call( + 4 │ │ setOnTop, + 5 │ │ false, + 6 │ │ ); + 7 │ │ } else { + 8 │ │ yield call( + 9 │ │ setOnTop, + 10 │ │ true, + 11 │ │ 'normal', + 12 │ │ ); // Keep this comment. + 13 │ ╰─▶ } + 14 │ } + ╰──── + help: Rewrite this `if`/`else` as a ternary expression.