diff --git a/crates/oxc_linter/src/generated/rule_runner_impls.rs b/crates/oxc_linter/src/generated/rule_runner_impls.rs index eb664d94b4c0a..50e5293e2e112 100644 --- a/crates/oxc_linter/src/generated/rule_runner_impls.rs +++ b/crates/oxc_linter/src/generated/rule_runner_impls.rs @@ -51,6 +51,16 @@ impl RuleRunner for crate::rules::eslint::class_methods_use_this::ClassMethodsUs const RUN_FUNCTIONS: RuleRunFunctionsImplemented = RuleRunFunctionsImplemented::Run; } +impl RuleRunner for crate::rules::eslint::complexity::Complexity { + const NODE_TYPES: Option<&AstTypesBitset> = Some(&AstTypesBitset::from_types(&[ + AstType::ArrowFunctionExpression, + AstType::Function, + AstType::PropertyDefinition, + AstType::StaticBlock, + ])); + const RUN_FUNCTIONS: RuleRunFunctionsImplemented = RuleRunFunctionsImplemented::Run; +} + impl RuleRunner for crate::rules::eslint::constructor_super::ConstructorSuper { const NODE_TYPES: Option<&AstTypesBitset> = Some(&AstTypesBitset::from_types(&[AstType::Class])); diff --git a/crates/oxc_linter/src/rules.rs b/crates/oxc_linter/src/rules.rs index ebce9a787c3ee..e668381be19fb 100644 --- a/crates/oxc_linter/src/rules.rs +++ b/crates/oxc_linter/src/rules.rs @@ -46,6 +46,7 @@ pub(crate) mod eslint { pub mod block_scoped_var; pub mod capitalized_comments; pub mod class_methods_use_this; + pub mod complexity; pub mod constructor_super; pub mod curly; pub mod default_case; @@ -708,6 +709,7 @@ oxc_macros::declare_all_lint_rules! { eslint::block_scoped_var, eslint::capitalized_comments, eslint::class_methods_use_this, + eslint::complexity, eslint::constructor_super, eslint::curly, eslint::default_case, diff --git a/crates/oxc_linter/src/rules/eslint/complexity.rs b/crates/oxc_linter/src/rules/eslint/complexity.rs new file mode 100644 index 0000000000000..946e021e7f414 --- /dev/null +++ b/crates/oxc_linter/src/rules/eslint/complexity.rs @@ -0,0 +1,702 @@ +use oxc_ast::AstKind; +use oxc_ast_visit::{Visit, walk}; +use oxc_diagnostics::OxcDiagnostic; +use oxc_macros::declare_oxc_lint; +use oxc_semantic::ScopeFlags; +use oxc_span::{GetSpan, Span}; +use oxc_syntax::operator::AssignmentOperator; +use schemars::JsonSchema; +use serde::{Deserialize, Serialize}; +use serde_json::Value; +use std::ops::Deref; + +use crate::{ + AstNode, + ast_util::get_function_name_with_kind, + context::LintContext, + rule::{DefaultRuleConfig, Rule}, +}; + +fn complexity_diagnostic(span: Span, name: &str, complexity: usize, max: usize) -> OxcDiagnostic { + OxcDiagnostic::warn(format!( + "{name} has a complexity of {complexity}. Maximum allowed is {max}." + )) + .with_label(span) +} + +const THRESHOLD_DEFAULT: usize = 20; + +#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)] +#[serde(rename_all = "camelCase", default)] +#[schemars(rename_all = "camelCase")] +pub struct ComplexityConfig { + /// Maximum amount of cyclomatic complexity + #[serde(alias = "maximum")] + max: usize, + /// The cyclomatic complexity variant to use + variant: Variant, +} + +impl Default for ComplexityConfig { + fn default() -> Self { + Self { max: THRESHOLD_DEFAULT, variant: Variant::Classic } + } +} + +#[derive(Debug, Default, Clone, Copy, Serialize, Deserialize, JsonSchema, PartialEq, Eq)] +#[serde(rename_all = "camelCase")] +#[schemars(untagged, rename_all = "camelCase")] +pub enum Variant { + /// Classic means McCabe cyclomatic complexity + #[default] + Classic, + /// Modified means classic cyclomatic complexity but a switch statement increases + /// complexity by 1 irrespective of the number of `case` statements + Modified, +} + +#[derive(Debug, Default, Clone, Deserialize, Serialize, JsonSchema)] +pub struct Complexity(Box); + +impl Deref for Complexity { + type Target = ComplexityConfig; + + fn deref(&self) -> &Self::Target { + &self.0 + } +} + +declare_oxc_lint!( + /// ### What it does + /// + /// Enforces a maximum cyclomatic complexity in a program, which is the number + /// of linearly independent paths in a program. + /// + /// ### Why is this bad? + /// + /// Having high code complexity reduces code readability. This rule + /// aims to make the code easier to follow by reducing the number of branches + /// in the program. + /// + /// ### Examples + /// + /// Examples of **incorrect** code for this rule with `{ "max": 2 }` + /// ```js + /// function foo() { + /// if (foo1) { + /// return x1; // 1st path + /// } else if (foo2) { + /// return x2; // 2nd path + /// } else { + /// return x3; // 3rd path + /// } + /// } + /// + /// function bar() { + /// // there are 2 paths - when bar1 is falsy, and when bar1 is truthy, in which bar1 = bar1 && bar2; + /// bar1 &&= bar2; + /// // there are 2 paths - when bar3 is truthy, and when bar3 is falsy, in which bar3 = 4; + /// bar3 ||= 4; + /// } + /// + /// // there are 2 paths - when baz1 is defined, and when baz1 is undefined and is assigned 'a' + /// function baz(baz1 = 'a') { + /// const { baz2 = 'b' } = baz3; // there are 2 additional paths - when baz2 is defined and when baz2 is not + /// } + /// + /// function d() { + /// d1 = d2?.d3?.(); // optional chaining creates 2 paths each - when object is defined and when it is not + /// } + /// ``` + /// + /// Examples of **correct** code for this rule with `{ "max": 2 }` + /// ```js + /// // This example is taken directly from ESLint documentation + /// function foo() { // this function has complexity = 1 + /// class C { + /// x = a + b; // this initializer has complexity = 1 + /// y = c || d; // this initializer has complexity = 2 + /// z = e && f; // this initializer has complexity = 2 + /// + /// static p = g || h; // this initializer has complexity = 2 + /// static q = i ? j : k; // this initializer has complexity = 2 + /// + /// static { // this static block has complexity = 2 + /// if (foo) { + /// baz = bar; + /// } + /// } + /// + /// static { // this static block has complexity = 2 + /// qux = baz || quux; + /// } + /// } + /// } + /// ``` + Complexity, + eslint, + restriction, + config = ComplexityConfig, +); + +impl Rule for Complexity { + fn from_configuration(value: serde_json::Value) -> Result { + if let Some(max) = value + .get(0) + .and_then(Value::as_number) + .and_then(serde_json::Number::as_u64) + .and_then(|v| usize::try_from(v).ok()) + { + Ok(Self(Box::new(ComplexityConfig { max, variant: Variant::Classic }))) + } else { + Ok(serde_json::from_value::>(value) + .unwrap_or_default() + .into_inner()) + } + } + + fn run<'a>(&self, node: &AstNode<'a>, ctx: &LintContext<'a>) { + match node.kind() { + AstKind::Function(func) => { + let mut visitor = ComplexityVisitor::new(self.variant); + visitor.visit_function(func, ScopeFlags::Function); + if visitor.complexity > self.max { + let name = { + let parent_node = ctx.nodes().parent_node(node.id()); + &get_function_name_with_kind(node, parent_node) + }; + ctx.diagnostic(complexity_diagnostic( + func.span, + name, + visitor.complexity, + self.max, + )); + } + } + AstKind::ArrowFunctionExpression(func) => { + let mut visitor = ComplexityVisitor::new(self.variant); + visitor.visit_arrow_function_expression(func); + if visitor.complexity > self.max { + let name = { + let parent_node = ctx.nodes().parent_node(node.id()); + &get_function_name_with_kind(node, parent_node) + }; + ctx.diagnostic(complexity_diagnostic( + func.span, + name, + visitor.complexity, + self.max, + )); + } + } + AstKind::StaticBlock(block) => { + let mut visitor = ComplexityVisitor::new(self.variant); + visitor.visit_static_block(block); + if visitor.complexity > self.max { + let name = "class static block"; + ctx.diagnostic(complexity_diagnostic( + block.span, + name, + visitor.complexity, + self.max, + )); + } + } + AstKind::PropertyDefinition(prop_def) => { + let mut visitor = ComplexityVisitor::new(self.variant); + let Some(expr) = &prop_def.value else { + return; + }; + visitor.visit_property_definition(prop_def); + if visitor.complexity > self.max { + let name = "class field initializer"; + ctx.diagnostic(complexity_diagnostic( + expr.span(), + name, + visitor.complexity, + self.max, + )); + } + } + _ => {} + } + } +} + +struct ComplexityVisitor { + variant: Variant, + complexity: usize, + has_entered_complexity_evaluation: bool, +} + +impl ComplexityVisitor { + fn new(variant: Variant) -> Self { + Self { variant, complexity: 1, has_entered_complexity_evaluation: false } + } +} + +impl Visit<'_> for ComplexityVisitor { + fn visit_catch_clause(&mut self, it: &oxc_ast::ast::CatchClause<'_>) { + self.complexity += 1; + walk::walk_catch_clause(self, it); + } + + fn visit_conditional_expression(&mut self, it: &oxc_ast::ast::ConditionalExpression<'_>) { + self.complexity += 1; + walk::walk_conditional_expression(self, it); + } + + fn visit_logical_expression(&mut self, it: &oxc_ast::ast::LogicalExpression<'_>) { + self.complexity += 1; + walk::walk_logical_expression(self, it); + } + + fn visit_for_statement(&mut self, it: &oxc_ast::ast::ForStatement<'_>) { + self.complexity += 1; + walk::walk_for_statement(self, it); + } + + fn visit_for_in_statement(&mut self, it: &oxc_ast::ast::ForInStatement<'_>) { + self.complexity += 1; + walk::walk_for_in_statement(self, it); + } + + fn visit_for_of_statement(&mut self, it: &oxc_ast::ast::ForOfStatement<'_>) { + self.complexity += 1; + walk::walk_for_of_statement(self, it); + } + + fn visit_if_statement(&mut self, it: &oxc_ast::ast::IfStatement<'_>) { + self.complexity += 1; + walk::walk_if_statement(self, it); + } + + fn visit_while_statement(&mut self, it: &oxc_ast::ast::WhileStatement<'_>) { + self.complexity += 1; + walk::walk_while_statement(self, it); + } + + fn visit_do_while_statement(&mut self, it: &oxc_ast::ast::DoWhileStatement<'_>) { + self.complexity += 1; + walk::walk_do_while_statement(self, it); + } + + fn visit_assignment_pattern(&mut self, it: &oxc_ast::ast::AssignmentPattern<'_>) { + self.complexity += 1; + walk::walk_assignment_pattern(self, it); + } + + fn visit_formal_parameter(&mut self, it: &oxc_ast::ast::FormalParameter<'_>) { + if it.initializer.is_some() { + self.complexity += 1; + } + walk::walk_formal_parameter(self, it); + } + + fn visit_switch_case(&mut self, it: &oxc_ast::ast::SwitchCase<'_>) { + if self.variant == Variant::Classic && it.test.is_some() { + self.complexity += 1; + } + walk::walk_switch_case(self, it); + } + + fn visit_switch_statement(&mut self, it: &oxc_ast::ast::SwitchStatement<'_>) { + if self.variant == Variant::Modified { + self.complexity += 1; + } + walk::walk_switch_statement(self, it); + } + + fn visit_assignment_expression(&mut self, it: &oxc_ast::ast::AssignmentExpression<'_>) { + if matches!( + it.operator, + AssignmentOperator::LogicalAnd + | AssignmentOperator::LogicalOr + | AssignmentOperator::LogicalNullish + ) { + self.complexity += 1; + } + walk::walk_assignment_expression(self, it); + } + + fn visit_member_expression(&mut self, it: &oxc_ast::ast::MemberExpression<'_>) { + if it.optional() { + self.complexity += 1; + } + walk::walk_member_expression(self, it); + } + + fn visit_call_expression(&mut self, it: &oxc_ast::ast::CallExpression<'_>) { + if it.optional { + self.complexity += 1; + } + walk::walk_call_expression(self, it); + } + + fn visit_function(&mut self, it: &oxc_ast::ast::Function<'_>, flags: oxc_semantic::ScopeFlags) { + if !self.has_entered_complexity_evaluation { + self.has_entered_complexity_evaluation = true; + walk::walk_function(self, it, flags); + } + // Do not enter function if we already started evaluating complexity + } + + fn visit_arrow_function_expression(&mut self, it: &oxc_ast::ast::ArrowFunctionExpression<'_>) { + if !self.has_entered_complexity_evaluation { + self.has_entered_complexity_evaluation = true; + walk::walk_arrow_function_expression(self, it); + } + // Do not enter function if we already started evaluating complexity + } + + fn visit_static_block(&mut self, it: &oxc_ast::ast::StaticBlock<'_>) { + if !self.has_entered_complexity_evaluation { + self.has_entered_complexity_evaluation = true; + walk::walk_static_block(self, it); + } + // Do not enter static block if we already started evaluating complexity + } + + fn visit_property_definition(&mut self, it: &oxc_ast::ast::PropertyDefinition<'_>) { + if self.has_entered_complexity_evaluation { + // Visit all other nodes except for value expression if part of another + // function / static block's complexity evaluation + let kind = oxc_ast::AstKind::PropertyDefinition(self.alloc(it)); + self.enter_node(kind); + self.visit_span(&it.span); + self.visit_decorators(&it.decorators); + self.visit_property_key(&it.key); + if let Some(type_annotation) = &it.type_annotation { + self.visit_ts_type_annotation(type_annotation); + } + // Intentionally skip `it.value` - do not enter value expression + // if we already started evaluating complexity + self.leave_node(kind); + } else if let Some(value) = &it.value { + self.has_entered_complexity_evaluation = true; + self.visit_expression(value); + } else { + // Do not visit any other node if there is no value expression to + // evaluate - only visit all other nodes if it is part of another + // function / static block evaluation + } + } +} + +#[test] +fn test() { + use crate::tester::Tester; + + let pass = vec![ + ("function a(x) {}", None), + ("function b(x) {}", Some(serde_json::json!([1]))), + ("function a(x) {if (true) {return x;}}", Some(serde_json::json!([2]))), + ("function a(x) {if (true) {return x;} else {return x+1;}}", Some(serde_json::json!([2]))), + ( + "function a(x) {if (true) {return x;} else if (false) {return x+1;} else {return 4;}}", + Some(serde_json::json!([3])), + ), + ( + "function a(x) {for(var i = 0; i < 5; i ++) {x ++;} return x;}", + Some(serde_json::json!([2])), + ), + ("function a(obj) {for(var i in obj) {obj[i] = 3;}}", Some(serde_json::json!([2]))), + ( + "function a(x) {for(var i = 0; i < 5; i ++) {if(i % 2 === 0) {x ++;}} return x;}", + Some(serde_json::json!([3])), + ), + ( + "function a(obj) {if(obj){ for(var x in obj) {try {x.getThis();} catch (e) {x.getThat();}}} else {return false;}}", + Some(serde_json::json!([4])), + ), + ( + "function a(x) {try {x.getThis();} catch (e) {x.getThat();}}", + Some(serde_json::json!([2])), + ), + ("function a(x) {return x === 4 ? 3 : 5;}", Some(serde_json::json!([2]))), + ("function a(x) {return x === 4 ? 3 : (x === 3 ? 2 : 1);}", Some(serde_json::json!([3]))), + ("function a(x) {return x || 4;}", Some(serde_json::json!([2]))), + ("function a(x) {x && 4;}", Some(serde_json::json!([2]))), + ("function a(x) {x ?? 4;}", Some(serde_json::json!([2]))), + ("function a(x) {x ||= 4;}", Some(serde_json::json!([2]))), + ("function a(x) {x &&= 4;}", Some(serde_json::json!([2]))), + ("function a(x) {x ??= 4;}", Some(serde_json::json!([2]))), + ("function a(x) {x = 4;}", Some(serde_json::json!([1]))), + ("function a(x) {x |= 4;}", Some(serde_json::json!([1]))), + ("function a(x) {x &= 4;}", Some(serde_json::json!([1]))), + ("function a(x) {x += 4;}", Some(serde_json::json!([1]))), + ("function a(x) {x >>= 4;}", Some(serde_json::json!([1]))), + ("function a(x) {x >>>= 4;}", Some(serde_json::json!([1]))), + ("function a(x) {x == 4;}", Some(serde_json::json!([1]))), + ("function a(x) {x === 4;}", Some(serde_json::json!([1]))), + ( + "function a(x) {switch(x){case 1: 1; break; case 2: 2; break; default: 3;}}", + Some(serde_json::json!([3])), + ), + ( + "function a(x) {switch(x){case 1: 1; break; case 2: 2; break; default: if(x == 'foo') {5;};}}", + Some(serde_json::json!([4])), + ), + ("function a(x) {while(true) {'foo';}}", Some(serde_json::json!([2]))), + ("function a(x) {do {'foo';} while (true)}", Some(serde_json::json!([2]))), + ("if (foo) { bar(); }", Some(serde_json::json!([3]))), + ("var a = (x) => {do {'foo';} while (true)}", Some(serde_json::json!([2]))), // { "ecmaVersion": 6 }, + ( + "function a(x) {switch(x){case 1: 1; break; case 2: 2; break; default: 3;}}", + Some(serde_json::json!([{ "max": 2, "variant": "modified" }])), + ), + ( + "function a(x) {switch(x){case 1: 1; break; case 2: 2; break; default: if(x == 'foo') {5;};}}", + Some(serde_json::json!([{ "max": 3, "variant": "modified" }])), + ), + ("function foo() { class C { x = a || b; y = c || d; } }", Some(serde_json::json!([2]))), // { "ecmaVersion": 2022 }, + ( + "function foo() { class C { static x = a || b; static y = c || d; } }", + Some(serde_json::json!([2])), + ), // { "ecmaVersion": 2022 }, + ( + "function foo() { class C { x = a || b; y = c || d; } e || f; }", + Some(serde_json::json!([2])), + ), // { "ecmaVersion": 2022 }, + ( + "function foo() { a || b; class C { x = c || d; y = e || f; } }", + Some(serde_json::json!([2])), + ), // { "ecmaVersion": 2022 }, + ("function foo() { class C { [x || y] = a || b; } }", Some(serde_json::json!([2]))), // { "ecmaVersion": 2022 }, + ("class C { x = a || b; y() { c || d; } z = e || f; }", Some(serde_json::json!([2]))), // { "ecmaVersion": 2022 }, + ("class C { x() { a || b; } y = c || d; z() { e || f; } }", Some(serde_json::json!([2]))), // { "ecmaVersion": 2022 }, + ("class C { x = (() => { a || b }) || (() => { c || d }) }", Some(serde_json::json!([2]))), // { "ecmaVersion": 2022 }, + ("class C { x = () => { a || b }; y = () => { c || d } }", Some(serde_json::json!([2]))), // { "ecmaVersion": 2022 }, + ("class C { x = a || (() => { b || c }); }", Some(serde_json::json!([2]))), // { "ecmaVersion": 2022 }, + ("class C { x = class { y = a || b; z = c || d; }; }", Some(serde_json::json!([2]))), // { "ecmaVersion": 2022 }, + ("class C { x = a || class { y = b || c; z = d || e; }; }", Some(serde_json::json!([2]))), // { "ecmaVersion": 2022 }, + ("class C { x; y = a; static z; static q = b; }", Some(serde_json::json!([1]))), // { "ecmaVersion": 2022 }, + ( + "function foo() { class C { static { a || b; } static { c || d; } } }", + Some(serde_json::json!([2])), + ), // { "ecmaVersion": 2022 }, + ("function foo() { a || b; class C { static { c || d; } } }", Some(serde_json::json!([2]))), // { "ecmaVersion": 2022 }, + ("function foo() { class C { static { a || b; } } c || d; }", Some(serde_json::json!([2]))), // { "ecmaVersion": 2022 }, + ( + "function foo() { class C { static { a || b; } } class D { static { c || d; } } }", + Some(serde_json::json!([2])), + ), // { "ecmaVersion": 2022 }, + ("class C { static { a || b; } static { c || d; } }", Some(serde_json::json!([2]))), // { "ecmaVersion": 2022 }, + ( + "class C { static { a || b; } static { c || d; } static { e || f; } }", + Some(serde_json::json!([2])), + ), // { "ecmaVersion": 2022 }, + ("class C { static { () => a || b; c || d; } }", Some(serde_json::json!([2]))), // { "ecmaVersion": 2022 }, + ( + "class C { static { a || b; () => c || d; } static { c || d; } }", + Some(serde_json::json!([2])), + ), // { "ecmaVersion": 2022 }, + ("class C { static { a } }", Some(serde_json::json!([1]))), // { "ecmaVersion": 2022 }, + ("class C { static { a } static { b } }", Some(serde_json::json!([1]))), // { "ecmaVersion": 2022 }, + ( + "class C { static { a || b; } } class D { static { c || d; } }", + Some(serde_json::json!([2])), + ), // { "ecmaVersion": 2022 }, + ("class C { static { a || b; } static c = d || e; }", Some(serde_json::json!([2]))), // { "ecmaVersion": 2022 }, + ("class C { static a = b || c; static { c || d; } }", Some(serde_json::json!([2]))), // { "ecmaVersion": 2022 }, + ("class C { static { a || b; } c = d || e; }", Some(serde_json::json!([2]))), // { "ecmaVersion": 2022 }, + ("class C { a = b || c; static { d || e; } }", Some(serde_json::json!([2]))), // { "ecmaVersion": 2022 }, + ("class C { static { a || b; c || d; } }", Some(serde_json::json!([3]))), // { "ecmaVersion": 2022 }, + ("class C { static { if (a || b) c = d || e; } }", Some(serde_json::json!([4]))), // { "ecmaVersion": 2022 }, + ("function b(x) {}", Some(serde_json::json!([{ "max": 1 }]))), + ("function b(x) {}", Some(serde_json::json!([{ "maximum": 1 }]))), + ("function a(x) {if (true) {return x;}}", Some(serde_json::json!([{ "maximum": 2 }]))), + ("function a(b) { b?.c; }", Some(serde_json::json!([{ "max": 2 }]))), + ("function a(b = '') {}", Some(serde_json::json!([{ "max": 2 }]))), + ("function a(b) { const { c = '' } = b; }", Some(serde_json::json!([{ "max": 2 }]))), + ("function a(b) { const [ c = '' ] = b; }", Some(serde_json::json!([{ "max": 2 }]))), + ]; + + let fail = vec![ + ("function a(x) {}", Some(serde_json::json!([0]))), + ( + "function foo(x) {if (x > 10) {return 'x is greater than 10';} else if (x > 5) {return 'x is greater than 5';} else {return 'x is less than 5';}}", + Some(serde_json::json!([2])), + ), + ("var func = function () {}", Some(serde_json::json!([0]))), + ("var obj = { a(x) {} }", Some(serde_json::json!([0]))), // { "ecmaVersion": 6 }, + ("class Test { a(x) {} }", Some(serde_json::json!([0]))), // { "ecmaVersion": 6 }, + ("var a = (x) => {if (true) {return x;}}", Some(serde_json::json!([1]))), // { "ecmaVersion": 6 }, + ("function a(x) {if (true) {return x;}}", Some(serde_json::json!([1]))), + ("function a(x) {if (true) {return x;} else {return x+1;}}", Some(serde_json::json!([1]))), + ( + "function a(x) {if (true) {return x;} else if (false) {return x+1;} else {return 4;}}", + Some(serde_json::json!([2])), + ), + ( + "function a(x) {for(var i = 0; i < 5; i ++) {x ++;} return x;}", + Some(serde_json::json!([1])), + ), + ("function a(obj) {for(var i in obj) {obj[i] = 3;}}", Some(serde_json::json!([1]))), + ("function a(obj) {for(var i of obj) {obj[i] = 3;}}", Some(serde_json::json!([1]))), // { "ecmaVersion": 6 }, + ( + "function a(x) {for(var i = 0; i < 5; i ++) {if(i % 2 === 0) {x ++;}} return x;}", + Some(serde_json::json!([2])), + ), + ( + "function a(obj) {if(obj){ for(var x in obj) {try {x.getThis();} catch (e) {x.getThat();}}} else {return false;}}", + Some(serde_json::json!([3])), + ), + ( + "function a(x) {try {x.getThis();} catch (e) {x.getThat();}}", + Some(serde_json::json!([1])), + ), + ("function a(x) {return x === 4 ? 3 : 5;}", Some(serde_json::json!([1]))), + ("function a(x) {return x === 4 ? 3 : (x === 3 ? 2 : 1);}", Some(serde_json::json!([2]))), + ("function a(x) {return x || 4;}", Some(serde_json::json!([1]))), + ("function a(x) {x && 4;}", Some(serde_json::json!([1]))), + ("function a(x) {x ?? 4;}", Some(serde_json::json!([1]))), + ("function a(x) {x ||= 4;}", Some(serde_json::json!([1]))), + ("function a(x) {x &&= 4;}", Some(serde_json::json!([1]))), + ("function a(x) {x ??= 4;}", Some(serde_json::json!([1]))), + ( + "function a(x) {switch(x){case 1: 1; break; case 2: 2; break; default: 3;}}", + Some(serde_json::json!([2])), + ), + ( + "function a(x) {switch(x){case 1: 1; break; case 2: 2; break; default: if(x == 'foo') {5;};}}", + Some(serde_json::json!([3])), + ), + ("function a(x) {while(true) {'foo';}}", Some(serde_json::json!([1]))), + ("function a(x) {do {'foo';} while (true)}", Some(serde_json::json!([1]))), + ( + "function a(x) {(function() {while(true){'foo';}})(); (function() {while(true){'bar';}})();}", + Some(serde_json::json!([1])), + ), + ( + "function a(x) {(function() {while(true){'foo';}})(); (function() {'bar';})();}", + Some(serde_json::json!([1])), + ), + ("var obj = { a(x) { return x ? 0 : 1; } };", Some(serde_json::json!([1]))), // { "ecmaVersion": 6 }, + ("var obj = { a: function b(x) { return x ? 0 : 1; } };", Some(serde_json::json!([1]))), + ( + "function a(x) {switch(x){case 1: 1; break; case 2: 2; break; default: 3;}}", + Some(serde_json::json!([{ "max": 1, "variant": "modified" }])), + ), + ( + "function a(x) {switch(x){case 1: 1; break; case 2: 2; break; default: if(x == 'foo') {5;};}}", + Some(serde_json::json!([{ "max": 2, "variant": "modified" }])), + ), + ("function foo () { a || b; class C { x; } c || d; }", Some(serde_json::json!([2]))), // { "ecmaVersion": 2022 }, + ("function foo () { a || b; class C { x = c; } d || e; }", Some(serde_json::json!([2]))), // { "ecmaVersion": 2022 }, + ("function foo () { a || b; class C { [x || y]; } }", Some(serde_json::json!([2]))), // { "ecmaVersion": 2022 }, + ("function foo () { a || b; class C { [x || y] = c; } }", Some(serde_json::json!([2]))), // { "ecmaVersion": 2022 }, + ("function foo () { class C { [x || y]; } a || b; }", Some(serde_json::json!([2]))), // { "ecmaVersion": 2022 }, + ("function foo () { class C { [x || y] = a; } b || c; }", Some(serde_json::json!([2]))), // { "ecmaVersion": 2022 }, + ("function foo () { class C { [x || y]; [z || q]; } }", Some(serde_json::json!([2]))), // { "ecmaVersion": 2022 }, + ( + "function foo () { class C { [x || y] = a; [z || q] = b; } }", + Some(serde_json::json!([2])), + ), // { "ecmaVersion": 2022 }, + ( + "function foo () { a || b; class C { x = c || d; } e || f; }", + Some(serde_json::json!([2])), + ), // { "ecmaVersion": 2022 }, + ( + "class C { x(){ a || b; } y = c || d || e; z() { f || g; } }", + Some(serde_json::json!([2])), + ), // { "ecmaVersion": 2022 }, + ("class C { x = a || b; y() { c || d || e; } z = f || g; }", Some(serde_json::json!([2]))), // { "ecmaVersion": 2022 }, + ("class C { x; y() { c || d || e; } z; }", Some(serde_json::json!([2]))), // { "ecmaVersion": 2022 }, + ("class C { x = a || b; }", Some(serde_json::json!([1]))), // { "ecmaVersion": 2022 }, + ("(class { x = a || b; })", Some(serde_json::json!([1]))), // { "ecmaVersion": 2022 }, + ("class C { static x = a || b; }", Some(serde_json::json!([1]))), // { "ecmaVersion": 2022 }, + ("(class { x = a ? b : c; })", Some(serde_json::json!([1]))), // { "ecmaVersion": 2022 }, + ("class C { x = a || b || c; }", Some(serde_json::json!([2]))), // { "ecmaVersion": 2022 }, + ("class C { x = a || b; y = b || c || d; z = e || f; }", Some(serde_json::json!([2]))), // { "ecmaVersion": 2022 }, + ("class C { x = a || b || c; y = d || e; z = f || g || h; }", Some(serde_json::json!([2]))), // { "ecmaVersion": 2022 }, + ("class C { x = () => a || b || c; }", Some(serde_json::json!([2]))), // { "ecmaVersion": 2022 }, + ("class C { x = (() => a || b || c) || d; }", Some(serde_json::json!([2]))), // { "ecmaVersion": 2022 }, + ("class C { x = () => a || b || c; y = d || e; }", Some(serde_json::json!([2]))), // { "ecmaVersion": 2022 }, + ("class C { x = () => a || b || c; y = d || e || f; }", Some(serde_json::json!([2]))), // { "ecmaVersion": 2022 }, + ( + "class C { x = function () { a || b }; y = function () { c || d }; }", + Some(serde_json::json!([1])), + ), // { "ecmaVersion": 2022 }, + ("class C { x = class { [y || z]; }; }", Some(serde_json::json!([1]))), // { "ecmaVersion": 2022 }, + ("class C { x = class { [y || z] = a; }; }", Some(serde_json::json!([1]))), // { "ecmaVersion": 2022 }, + ("class C { x = class { y = a || b; }; }", Some(serde_json::json!([1]))), // { "ecmaVersion": 2022 }, + ("function foo () { a || b; class C { static {} } c || d; }", Some(serde_json::json!([2]))), // { "ecmaVersion": 2022 }, + ( + "function foo () { a || b; class C { static { c || d; } } e || f; }", + Some(serde_json::json!([2])), + ), // { "ecmaVersion": 2022 }, + ("class C { static { a || b; } }", Some(serde_json::json!([1]))), // { "ecmaVersion": 2022 }, + ("class C { static { a || b || c; } }", Some(serde_json::json!([2]))), // { "ecmaVersion": 2022 }, + ("class C { static { a || b; c || d; } }", Some(serde_json::json!([2]))), // { "ecmaVersion": 2022 }, + ("class C { static { a || b; c || d; e || f; } }", Some(serde_json::json!([3]))), // { "ecmaVersion": 2022 }, + ("class C { static { a || b; c || d; { e || f; } } }", Some(serde_json::json!([3]))), // { "ecmaVersion": 2022 }, + ("class C { static { if (a || b) c = d || e; } }", Some(serde_json::json!([3]))), // { "ecmaVersion": 2022 }, + ( + "class C { static { if (a || b) c = (d => e || f)() || (g => h || i)(); } }", + Some(serde_json::json!([3])), + ), // { "ecmaVersion": 2022 }, + ( + "class C { x(){ a || b; } static { c || d || e; } z() { f || g; } }", + Some(serde_json::json!([2])), + ), // { "ecmaVersion": 2022 }, + ( + "class C { x = a || b; static { c || d || e; } y = f || g; }", + Some(serde_json::json!([2])), + ), // { "ecmaVersion": 2022 }, + ( + "class C { static x = a || b; static { c || d || e; } static y = f || g; }", + Some(serde_json::json!([2])), + ), // { "ecmaVersion": 2022 }, + ( + "class C { static { a || b; } static(){ c || d || e; } static { f || g; } }", + Some(serde_json::json!([2])), + ), // { "ecmaVersion": 2022 }, + ( + "class C { static { a || b; } static static(){ c || d || e; } static { f || g; } }", + Some(serde_json::json!([2])), + ), // { "ecmaVersion": 2022 }, + ( + "class C { static { a || b; } static x = c || d || e; static { f || g; } }", + Some(serde_json::json!([2])), + ), // { "ecmaVersion": 2022 }, + ( + "class C { static { a || b || c || d; } static { e || f || g; } }", + Some(serde_json::json!([3])), + ), // { "ecmaVersion": 2022 }, + ( + "class C { static { a || b || c; } static { d || e || f || g; } }", + Some(serde_json::json!([3])), + ), // { "ecmaVersion": 2022 }, + ( + "class C { static { a || b || c || d; } static { e || f || g || h; } }", + Some(serde_json::json!([3])), + ), // { "ecmaVersion": 2022 }, + ("class C { x = () => a || b || c; y = f || g || h; }", Some(serde_json::json!([2]))), // { "ecmaVersion": 2022 }, + ("function a(x) {}", Some(serde_json::json!([{ "max": 0 }]))), + ("function a(x) {}", Some(serde_json::json!([{ "maximum": 0 }]))), + ("function a(x) {if (true) {return x;}}", Some(serde_json::json!([{ "maximum": 1 }]))), + ( + "const obj = { b: (a) => a?.b?.c, c: function (a) { return a?.b?.c; } };", + Some(serde_json::json!([{ "max": 2 }])), + ), + ("function a(b) { b?.c; }", Some(serde_json::json!([{ "max": 1 }]))), + ("function a(b) { b?.['c']; }", Some(serde_json::json!([{ "max": 1 }]))), + ("function a(b) { b?.c; d || e; }", Some(serde_json::json!([{ "max": 2 }]))), + ("function a(b) { b?.c?.d; }", Some(serde_json::json!([{ "max": 2 }]))), + ("function a(b) { b?.['c']?.['d']; }", Some(serde_json::json!([{ "max": 2 }]))), + ("function a(b) { b?.c?.['d']; }", Some(serde_json::json!([{ "max": 2 }]))), + ("function a(b) { b?.c.d?.e; }", Some(serde_json::json!([{ "max": 2 }]))), + ("function a(b) { b?.c?.(); }", Some(serde_json::json!([{ "max": 2 }]))), + ("function a(b) { b?.c?.()?.(); }", Some(serde_json::json!([{ "max": 3 }]))), + ("function a(b = '') {}", Some(serde_json::json!([{ "max": 1 }]))), + ("function a(b) { const { c = '' } = b; }", Some(serde_json::json!([{ "max": 1 }]))), + ("function a(b) { const [ c = '' ] = b; }", Some(serde_json::json!([{ "max": 1 }]))), + ( + "function a(b) { const [ { c: d = '' } = {} ] = b; }", + Some(serde_json::json!([{ "max": 1 }])), + ), + ]; + + Tester::new(Complexity::NAME, Complexity::PLUGIN, pass, fail).test_and_snapshot(); +} diff --git a/crates/oxc_linter/src/snapshots/eslint_complexity.snap b/crates/oxc_linter/src/snapshots/eslint_complexity.snap new file mode 100644 index 0000000000000..2d45dd64ffe49 --- /dev/null +++ b/crates/oxc_linter/src/snapshots/eslint_complexity.snap @@ -0,0 +1,620 @@ +--- +source: crates/oxc_linter/src/tester.rs +--- + ⚠ eslint(complexity): function `a` has a complexity of 1. Maximum allowed is 0. + ╭─[complexity.tsx:1:1] + 1 │ function a(x) {} + · ──────────────── + ╰──── + + ⚠ eslint(complexity): function `foo` has a complexity of 3. Maximum allowed is 2. + ╭─[complexity.tsx:1:1] + 1 │ function foo(x) {if (x > 10) {return 'x is greater than 10';} else if (x > 5) {return 'x is greater than 5';} else {return 'x is less than 5';}} + · ──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── + ╰──── + + ⚠ eslint(complexity): function has a complexity of 1. Maximum allowed is 0. + ╭─[complexity.tsx:1:12] + 1 │ var func = function () {} + · ────────────── + ╰──── + + ⚠ eslint(complexity): function `a` has a complexity of 1. Maximum allowed is 0. + ╭─[complexity.tsx:1:14] + 1 │ var obj = { a(x) {} } + · ────── + ╰──── + + ⚠ eslint(complexity): method `a` has a complexity of 1. Maximum allowed is 0. + ╭─[complexity.tsx:1:15] + 1 │ class Test { a(x) {} } + · ────── + ╰──── + + ⚠ eslint(complexity): function has a complexity of 2. Maximum allowed is 1. + ╭─[complexity.tsx:1:9] + 1 │ var a = (x) => {if (true) {return x;}} + · ────────────────────────────── + ╰──── + + ⚠ eslint(complexity): function `a` has a complexity of 2. Maximum allowed is 1. + ╭─[complexity.tsx:1:1] + 1 │ function a(x) {if (true) {return x;}} + · ───────────────────────────────────── + ╰──── + + ⚠ eslint(complexity): function `a` has a complexity of 2. Maximum allowed is 1. + ╭─[complexity.tsx:1:1] + 1 │ function a(x) {if (true) {return x;} else {return x+1;}} + · ──────────────────────────────────────────────────────── + ╰──── + + ⚠ eslint(complexity): function `a` has a complexity of 3. Maximum allowed is 2. + ╭─[complexity.tsx:1:1] + 1 │ function a(x) {if (true) {return x;} else if (false) {return x+1;} else {return 4;}} + · ──────────────────────────────────────────────────────────────────────────────────── + ╰──── + + ⚠ eslint(complexity): function `a` has a complexity of 2. Maximum allowed is 1. + ╭─[complexity.tsx:1:1] + 1 │ function a(x) {for(var i = 0; i < 5; i ++) {x ++;} return x;} + · ───────────────────────────────────────────────────────────── + ╰──── + + ⚠ eslint(complexity): function `a` has a complexity of 2. Maximum allowed is 1. + ╭─[complexity.tsx:1:1] + 1 │ function a(obj) {for(var i in obj) {obj[i] = 3;}} + · ───────────────────────────────────────────────── + ╰──── + + ⚠ eslint(complexity): function `a` has a complexity of 2. Maximum allowed is 1. + ╭─[complexity.tsx:1:1] + 1 │ function a(obj) {for(var i of obj) {obj[i] = 3;}} + · ───────────────────────────────────────────────── + ╰──── + + ⚠ eslint(complexity): function `a` has a complexity of 3. Maximum allowed is 2. + ╭─[complexity.tsx:1:1] + 1 │ function a(x) {for(var i = 0; i < 5; i ++) {if(i % 2 === 0) {x ++;}} return x;} + · ─────────────────────────────────────────────────────────────────────────────── + ╰──── + + ⚠ eslint(complexity): function `a` has a complexity of 4. Maximum allowed is 3. + ╭─[complexity.tsx:1:1] + 1 │ function a(obj) {if(obj){ for(var x in obj) {try {x.getThis();} catch (e) {x.getThat();}}} else {return false;}} + · ──────────────────────────────────────────────────────────────────────────────────────────────────────────────── + ╰──── + + ⚠ eslint(complexity): function `a` has a complexity of 2. Maximum allowed is 1. + ╭─[complexity.tsx:1:1] + 1 │ function a(x) {try {x.getThis();} catch (e) {x.getThat();}} + · ─────────────────────────────────────────────────────────── + ╰──── + + ⚠ eslint(complexity): function `a` has a complexity of 2. Maximum allowed is 1. + ╭─[complexity.tsx:1:1] + 1 │ function a(x) {return x === 4 ? 3 : 5;} + · ─────────────────────────────────────── + ╰──── + + ⚠ eslint(complexity): function `a` has a complexity of 3. Maximum allowed is 2. + ╭─[complexity.tsx:1:1] + 1 │ function a(x) {return x === 4 ? 3 : (x === 3 ? 2 : 1);} + · ─────────────────────────────────────────────────────── + ╰──── + + ⚠ eslint(complexity): function `a` has a complexity of 2. Maximum allowed is 1. + ╭─[complexity.tsx:1:1] + 1 │ function a(x) {return x || 4;} + · ────────────────────────────── + ╰──── + + ⚠ eslint(complexity): function `a` has a complexity of 2. Maximum allowed is 1. + ╭─[complexity.tsx:1:1] + 1 │ function a(x) {x && 4;} + · ─────────────────────── + ╰──── + + ⚠ eslint(complexity): function `a` has a complexity of 2. Maximum allowed is 1. + ╭─[complexity.tsx:1:1] + 1 │ function a(x) {x ?? 4;} + · ─────────────────────── + ╰──── + + ⚠ eslint(complexity): function `a` has a complexity of 2. Maximum allowed is 1. + ╭─[complexity.tsx:1:1] + 1 │ function a(x) {x ||= 4;} + · ──────────────────────── + ╰──── + + ⚠ eslint(complexity): function `a` has a complexity of 2. Maximum allowed is 1. + ╭─[complexity.tsx:1:1] + 1 │ function a(x) {x &&= 4;} + · ──────────────────────── + ╰──── + + ⚠ eslint(complexity): function `a` has a complexity of 2. Maximum allowed is 1. + ╭─[complexity.tsx:1:1] + 1 │ function a(x) {x ??= 4;} + · ──────────────────────── + ╰──── + + ⚠ eslint(complexity): function `a` has a complexity of 3. Maximum allowed is 2. + ╭─[complexity.tsx:1:1] + 1 │ function a(x) {switch(x){case 1: 1; break; case 2: 2; break; default: 3;}} + · ────────────────────────────────────────────────────────────────────────── + ╰──── + + ⚠ eslint(complexity): function `a` has a complexity of 4. Maximum allowed is 3. + ╭─[complexity.tsx:1:1] + 1 │ function a(x) {switch(x){case 1: 1; break; case 2: 2; break; default: if(x == 'foo') {5;};}} + · ──────────────────────────────────────────────────────────────────────────────────────────── + ╰──── + + ⚠ eslint(complexity): function `a` has a complexity of 2. Maximum allowed is 1. + ╭─[complexity.tsx:1:1] + 1 │ function a(x) {while(true) {'foo';}} + · ──────────────────────────────────── + ╰──── + + ⚠ eslint(complexity): function `a` has a complexity of 2. Maximum allowed is 1. + ╭─[complexity.tsx:1:1] + 1 │ function a(x) {do {'foo';} while (true)} + · ──────────────────────────────────────── + ╰──── + + ⚠ eslint(complexity): function has a complexity of 2. Maximum allowed is 1. + ╭─[complexity.tsx:1:17] + 1 │ function a(x) {(function() {while(true){'foo';}})(); (function() {while(true){'bar';}})();} + · ──────────────────────────────── + ╰──── + + ⚠ eslint(complexity): function has a complexity of 2. Maximum allowed is 1. + ╭─[complexity.tsx:1:55] + 1 │ function a(x) {(function() {while(true){'foo';}})(); (function() {while(true){'bar';}})();} + · ──────────────────────────────── + ╰──── + + ⚠ eslint(complexity): function has a complexity of 2. Maximum allowed is 1. + ╭─[complexity.tsx:1:17] + 1 │ function a(x) {(function() {while(true){'foo';}})(); (function() {'bar';})();} + · ──────────────────────────────── + ╰──── + + ⚠ eslint(complexity): function `a` has a complexity of 2. Maximum allowed is 1. + ╭─[complexity.tsx:1:14] + 1 │ var obj = { a(x) { return x ? 0 : 1; } }; + · ───────────────────────── + ╰──── + + ⚠ eslint(complexity): function `a` has a complexity of 2. Maximum allowed is 1. + ╭─[complexity.tsx:1:16] + 1 │ var obj = { a: function b(x) { return x ? 0 : 1; } }; + · ─────────────────────────────────── + ╰──── + + ⚠ eslint(complexity): function `a` has a complexity of 2. Maximum allowed is 1. + ╭─[complexity.tsx:1:1] + 1 │ function a(x) {switch(x){case 1: 1; break; case 2: 2; break; default: 3;}} + · ────────────────────────────────────────────────────────────────────────── + ╰──── + + ⚠ eslint(complexity): function `a` has a complexity of 3. Maximum allowed is 2. + ╭─[complexity.tsx:1:1] + 1 │ function a(x) {switch(x){case 1: 1; break; case 2: 2; break; default: if(x == 'foo') {5;};}} + · ──────────────────────────────────────────────────────────────────────────────────────────── + ╰──── + + ⚠ eslint(complexity): function `foo` has a complexity of 3. Maximum allowed is 2. + ╭─[complexity.tsx:1:1] + 1 │ function foo () { a || b; class C { x; } c || d; } + · ────────────────────────────────────────────────── + ╰──── + + ⚠ eslint(complexity): function `foo` has a complexity of 3. Maximum allowed is 2. + ╭─[complexity.tsx:1:1] + 1 │ function foo () { a || b; class C { x = c; } d || e; } + · ────────────────────────────────────────────────────── + ╰──── + + ⚠ eslint(complexity): function `foo` has a complexity of 3. Maximum allowed is 2. + ╭─[complexity.tsx:1:1] + 1 │ function foo () { a || b; class C { [x || y]; } } + · ───────────────────────────────────────────────── + ╰──── + + ⚠ eslint(complexity): function `foo` has a complexity of 3. Maximum allowed is 2. + ╭─[complexity.tsx:1:1] + 1 │ function foo () { a || b; class C { [x || y] = c; } } + · ───────────────────────────────────────────────────── + ╰──── + + ⚠ eslint(complexity): function `foo` has a complexity of 3. Maximum allowed is 2. + ╭─[complexity.tsx:1:1] + 1 │ function foo () { class C { [x || y]; } a || b; } + · ───────────────────────────────────────────────── + ╰──── + + ⚠ eslint(complexity): function `foo` has a complexity of 3. Maximum allowed is 2. + ╭─[complexity.tsx:1:1] + 1 │ function foo () { class C { [x || y] = a; } b || c; } + · ───────────────────────────────────────────────────── + ╰──── + + ⚠ eslint(complexity): function `foo` has a complexity of 3. Maximum allowed is 2. + ╭─[complexity.tsx:1:1] + 1 │ function foo () { class C { [x || y]; [z || q]; } } + · ─────────────────────────────────────────────────── + ╰──── + + ⚠ eslint(complexity): function `foo` has a complexity of 3. Maximum allowed is 2. + ╭─[complexity.tsx:1:1] + 1 │ function foo () { class C { [x || y] = a; [z || q] = b; } } + · ─────────────────────────────────────────────────────────── + ╰──── + + ⚠ eslint(complexity): function `foo` has a complexity of 3. Maximum allowed is 2. + ╭─[complexity.tsx:1:1] + 1 │ function foo () { a || b; class C { x = c || d; } e || f; } + · ─────────────────────────────────────────────────────────── + ╰──── + + ⚠ eslint(complexity): class field initializer has a complexity of 3. Maximum allowed is 2. + ╭─[complexity.tsx:1:30] + 1 │ class C { x(){ a || b; } y = c || d || e; z() { f || g; } } + · ─────────── + ╰──── + + ⚠ eslint(complexity): method `y` has a complexity of 3. Maximum allowed is 2. + ╭─[complexity.tsx:1:24] + 1 │ class C { x = a || b; y() { c || d || e; } z = f || g; } + · ─────────────────── + ╰──── + + ⚠ eslint(complexity): method `y` has a complexity of 3. Maximum allowed is 2. + ╭─[complexity.tsx:1:15] + 1 │ class C { x; y() { c || d || e; } z; } + · ─────────────────── + ╰──── + + ⚠ eslint(complexity): class field initializer has a complexity of 2. Maximum allowed is 1. + ╭─[complexity.tsx:1:15] + 1 │ class C { x = a || b; } + · ────── + ╰──── + + ⚠ eslint(complexity): class field initializer has a complexity of 2. Maximum allowed is 1. + ╭─[complexity.tsx:1:14] + 1 │ (class { x = a || b; }) + · ────── + ╰──── + + ⚠ eslint(complexity): class field initializer has a complexity of 2. Maximum allowed is 1. + ╭─[complexity.tsx:1:22] + 1 │ class C { static x = a || b; } + · ────── + ╰──── + + ⚠ eslint(complexity): class field initializer has a complexity of 2. Maximum allowed is 1. + ╭─[complexity.tsx:1:14] + 1 │ (class { x = a ? b : c; }) + · ───────── + ╰──── + + ⚠ eslint(complexity): class field initializer has a complexity of 3. Maximum allowed is 2. + ╭─[complexity.tsx:1:15] + 1 │ class C { x = a || b || c; } + · ─────────── + ╰──── + + ⚠ eslint(complexity): class field initializer has a complexity of 3. Maximum allowed is 2. + ╭─[complexity.tsx:1:27] + 1 │ class C { x = a || b; y = b || c || d; z = e || f; } + · ─────────── + ╰──── + + ⚠ eslint(complexity): class field initializer has a complexity of 3. Maximum allowed is 2. + ╭─[complexity.tsx:1:15] + 1 │ class C { x = a || b || c; y = d || e; z = f || g || h; } + · ─────────── + ╰──── + + ⚠ eslint(complexity): class field initializer has a complexity of 3. Maximum allowed is 2. + ╭─[complexity.tsx:1:44] + 1 │ class C { x = a || b || c; y = d || e; z = f || g || h; } + · ─────────── + ╰──── + + ⚠ eslint(complexity): method `x` has a complexity of 3. Maximum allowed is 2. + ╭─[complexity.tsx:1:15] + 1 │ class C { x = () => a || b || c; } + · ───────────────── + ╰──── + + ⚠ eslint(complexity): function has a complexity of 3. Maximum allowed is 2. + ╭─[complexity.tsx:1:16] + 1 │ class C { x = (() => a || b || c) || d; } + · ───────────────── + ╰──── + + ⚠ eslint(complexity): method `x` has a complexity of 3. Maximum allowed is 2. + ╭─[complexity.tsx:1:15] + 1 │ class C { x = () => a || b || c; y = d || e; } + · ───────────────── + ╰──── + + ⚠ eslint(complexity): method `x` has a complexity of 3. Maximum allowed is 2. + ╭─[complexity.tsx:1:15] + 1 │ class C { x = () => a || b || c; y = d || e || f; } + · ───────────────── + ╰──── + + ⚠ eslint(complexity): class field initializer has a complexity of 3. Maximum allowed is 2. + ╭─[complexity.tsx:1:38] + 1 │ class C { x = () => a || b || c; y = d || e || f; } + · ─────────── + ╰──── + + ⚠ eslint(complexity): method `x` has a complexity of 2. Maximum allowed is 1. + ╭─[complexity.tsx:1:15] + 1 │ class C { x = function () { a || b }; y = function () { c || d }; } + · ────────────────────── + ╰──── + + ⚠ eslint(complexity): method `y` has a complexity of 2. Maximum allowed is 1. + ╭─[complexity.tsx:1:43] + 1 │ class C { x = function () { a || b }; y = function () { c || d }; } + · ────────────────────── + ╰──── + + ⚠ eslint(complexity): class field initializer has a complexity of 2. Maximum allowed is 1. + ╭─[complexity.tsx:1:15] + 1 │ class C { x = class { [y || z]; }; } + · ─────────────────── + ╰──── + + ⚠ eslint(complexity): class field initializer has a complexity of 2. Maximum allowed is 1. + ╭─[complexity.tsx:1:15] + 1 │ class C { x = class { [y || z] = a; }; } + · ─────────────────────── + ╰──── + + ⚠ eslint(complexity): class field initializer has a complexity of 2. Maximum allowed is 1. + ╭─[complexity.tsx:1:27] + 1 │ class C { x = class { y = a || b; }; } + · ────── + ╰──── + + ⚠ eslint(complexity): function `foo` has a complexity of 3. Maximum allowed is 2. + ╭─[complexity.tsx:1:1] + 1 │ function foo () { a || b; class C { static {} } c || d; } + · ───────────────────────────────────────────────────────── + ╰──── + + ⚠ eslint(complexity): function `foo` has a complexity of 3. Maximum allowed is 2. + ╭─[complexity.tsx:1:1] + 1 │ function foo () { a || b; class C { static { c || d; } } e || f; } + · ────────────────────────────────────────────────────────────────── + ╰──── + + ⚠ eslint(complexity): class static block has a complexity of 2. Maximum allowed is 1. + ╭─[complexity.tsx:1:11] + 1 │ class C { static { a || b; } } + · ────────────────── + ╰──── + + ⚠ eslint(complexity): class static block has a complexity of 3. Maximum allowed is 2. + ╭─[complexity.tsx:1:11] + 1 │ class C { static { a || b || c; } } + · ─────────────────────── + ╰──── + + ⚠ eslint(complexity): class static block has a complexity of 3. Maximum allowed is 2. + ╭─[complexity.tsx:1:11] + 1 │ class C { static { a || b; c || d; } } + · ────────────────────────── + ╰──── + + ⚠ eslint(complexity): class static block has a complexity of 4. Maximum allowed is 3. + ╭─[complexity.tsx:1:11] + 1 │ class C { static { a || b; c || d; e || f; } } + · ────────────────────────────────── + ╰──── + + ⚠ eslint(complexity): class static block has a complexity of 4. Maximum allowed is 3. + ╭─[complexity.tsx:1:11] + 1 │ class C { static { a || b; c || d; { e || f; } } } + · ────────────────────────────────────── + ╰──── + + ⚠ eslint(complexity): class static block has a complexity of 4. Maximum allowed is 3. + ╭─[complexity.tsx:1:11] + 1 │ class C { static { if (a || b) c = d || e; } } + · ────────────────────────────────── + ╰──── + + ⚠ eslint(complexity): class static block has a complexity of 4. Maximum allowed is 3. + ╭─[complexity.tsx:1:11] + 1 │ class C { static { if (a || b) c = (d => e || f)() || (g => h || i)(); } } + · ────────────────────────────────────────────────────────────── + ╰──── + + ⚠ eslint(complexity): class static block has a complexity of 3. Maximum allowed is 2. + ╭─[complexity.tsx:1:26] + 1 │ class C { x(){ a || b; } static { c || d || e; } z() { f || g; } } + · ─────────────────────── + ╰──── + + ⚠ eslint(complexity): class static block has a complexity of 3. Maximum allowed is 2. + ╭─[complexity.tsx:1:23] + 1 │ class C { x = a || b; static { c || d || e; } y = f || g; } + · ─────────────────────── + ╰──── + + ⚠ eslint(complexity): class static block has a complexity of 3. Maximum allowed is 2. + ╭─[complexity.tsx:1:30] + 1 │ class C { static x = a || b; static { c || d || e; } static y = f || g; } + · ─────────────────────── + ╰──── + + ⚠ eslint(complexity): method `static` has a complexity of 3. Maximum allowed is 2. + ╭─[complexity.tsx:1:36] + 1 │ class C { static { a || b; } static(){ c || d || e; } static { f || g; } } + · ────────────────── + ╰──── + + ⚠ eslint(complexity): static method `static` has a complexity of 3. Maximum allowed is 2. + ╭─[complexity.tsx:1:43] + 1 │ class C { static { a || b; } static static(){ c || d || e; } static { f || g; } } + · ────────────────── + ╰──── + + ⚠ eslint(complexity): class field initializer has a complexity of 3. Maximum allowed is 2. + ╭─[complexity.tsx:1:41] + 1 │ class C { static { a || b; } static x = c || d || e; static { f || g; } } + · ─────────── + ╰──── + + ⚠ eslint(complexity): class static block has a complexity of 4. Maximum allowed is 3. + ╭─[complexity.tsx:1:11] + 1 │ class C { static { a || b || c || d; } static { e || f || g; } } + · ──────────────────────────── + ╰──── + + ⚠ eslint(complexity): class static block has a complexity of 4. Maximum allowed is 3. + ╭─[complexity.tsx:1:35] + 1 │ class C { static { a || b || c; } static { d || e || f || g; } } + · ──────────────────────────── + ╰──── + + ⚠ eslint(complexity): class static block has a complexity of 4. Maximum allowed is 3. + ╭─[complexity.tsx:1:11] + 1 │ class C { static { a || b || c || d; } static { e || f || g || h; } } + · ──────────────────────────── + ╰──── + + ⚠ eslint(complexity): class static block has a complexity of 4. Maximum allowed is 3. + ╭─[complexity.tsx:1:40] + 1 │ class C { static { a || b || c || d; } static { e || f || g || h; } } + · ──────────────────────────── + ╰──── + + ⚠ eslint(complexity): method `x` has a complexity of 3. Maximum allowed is 2. + ╭─[complexity.tsx:1:15] + 1 │ class C { x = () => a || b || c; y = f || g || h; } + · ───────────────── + ╰──── + + ⚠ eslint(complexity): class field initializer has a complexity of 3. Maximum allowed is 2. + ╭─[complexity.tsx:1:38] + 1 │ class C { x = () => a || b || c; y = f || g || h; } + · ─────────── + ╰──── + + ⚠ eslint(complexity): function `a` has a complexity of 1. Maximum allowed is 0. + ╭─[complexity.tsx:1:1] + 1 │ function a(x) {} + · ──────────────── + ╰──── + + ⚠ eslint(complexity): function `a` has a complexity of 1. Maximum allowed is 0. + ╭─[complexity.tsx:1:1] + 1 │ function a(x) {} + · ──────────────── + ╰──── + + ⚠ eslint(complexity): function `a` has a complexity of 2. Maximum allowed is 1. + ╭─[complexity.tsx:1:1] + 1 │ function a(x) {if (true) {return x;}} + · ───────────────────────────────────── + ╰──── + + ⚠ eslint(complexity): function `b` has a complexity of 3. Maximum allowed is 2. + ╭─[complexity.tsx:1:18] + 1 │ const obj = { b: (a) => a?.b?.c, c: function (a) { return a?.b?.c; } }; + · ────────────── + ╰──── + + ⚠ eslint(complexity): function `c` has a complexity of 3. Maximum allowed is 2. + ╭─[complexity.tsx:1:37] + 1 │ const obj = { b: (a) => a?.b?.c, c: function (a) { return a?.b?.c; } }; + · ──────────────────────────────── + ╰──── + + ⚠ eslint(complexity): function `a` has a complexity of 2. Maximum allowed is 1. + ╭─[complexity.tsx:1:1] + 1 │ function a(b) { b?.c; } + · ─────────────────────── + ╰──── + + ⚠ eslint(complexity): function `a` has a complexity of 2. Maximum allowed is 1. + ╭─[complexity.tsx:1:1] + 1 │ function a(b) { b?.['c']; } + · ─────────────────────────── + ╰──── + + ⚠ eslint(complexity): function `a` has a complexity of 3. Maximum allowed is 2. + ╭─[complexity.tsx:1:1] + 1 │ function a(b) { b?.c; d || e; } + · ─────────────────────────────── + ╰──── + + ⚠ eslint(complexity): function `a` has a complexity of 3. Maximum allowed is 2. + ╭─[complexity.tsx:1:1] + 1 │ function a(b) { b?.c?.d; } + · ────────────────────────── + ╰──── + + ⚠ eslint(complexity): function `a` has a complexity of 3. Maximum allowed is 2. + ╭─[complexity.tsx:1:1] + 1 │ function a(b) { b?.['c']?.['d']; } + · ────────────────────────────────── + ╰──── + + ⚠ eslint(complexity): function `a` has a complexity of 3. Maximum allowed is 2. + ╭─[complexity.tsx:1:1] + 1 │ function a(b) { b?.c?.['d']; } + · ────────────────────────────── + ╰──── + + ⚠ eslint(complexity): function `a` has a complexity of 3. Maximum allowed is 2. + ╭─[complexity.tsx:1:1] + 1 │ function a(b) { b?.c.d?.e; } + · ──────────────────────────── + ╰──── + + ⚠ eslint(complexity): function `a` has a complexity of 3. Maximum allowed is 2. + ╭─[complexity.tsx:1:1] + 1 │ function a(b) { b?.c?.(); } + · ─────────────────────────── + ╰──── + + ⚠ eslint(complexity): function `a` has a complexity of 4. Maximum allowed is 3. + ╭─[complexity.tsx:1:1] + 1 │ function a(b) { b?.c?.()?.(); } + · ─────────────────────────────── + ╰──── + + ⚠ eslint(complexity): function `a` has a complexity of 2. Maximum allowed is 1. + ╭─[complexity.tsx:1:1] + 1 │ function a(b = '') {} + · ───────────────────── + ╰──── + + ⚠ eslint(complexity): function `a` has a complexity of 2. Maximum allowed is 1. + ╭─[complexity.tsx:1:1] + 1 │ function a(b) { const { c = '' } = b; } + · ─────────────────────────────────────── + ╰──── + + ⚠ eslint(complexity): function `a` has a complexity of 2. Maximum allowed is 1. + ╭─[complexity.tsx:1:1] + 1 │ function a(b) { const [ c = '' ] = b; } + · ─────────────────────────────────────── + ╰──── + + ⚠ eslint(complexity): function `a` has a complexity of 3. Maximum allowed is 1. + ╭─[complexity.tsx:1:1] + 1 │ function a(b) { const [ { c: d = '' } = {} ] = b; } + · ─────────────────────────────────────────────────── + ╰────