Skip to content

Commit

Permalink
feat: update complexity rule for optional chaining & default values (#…
Browse files Browse the repository at this point in the history
…18152)

Both, optional chaining expressions and default values (in function
parameters or descructuring expressions) increase the branching of the
code and thus the complexity is increased.

Fixes: #18060
  • Loading branch information
lo1tuma committed Mar 1, 2024
1 parent e5ef3cd commit c49ed63
Show file tree
Hide file tree
Showing 3 changed files with 112 additions and 2 deletions.
8 changes: 8 additions & 0 deletions docs/src/rules/complexity.md
Expand Up @@ -57,6 +57,14 @@ function b() {
foo ||= 1;
bar &&= 1;
}

function c(a = {}) { // default parameter -> 2nd path
const { b = 'default' } = a; // default value during destructuring -> 3rd path
}

function d(a) {
return a?.b?.c; // optional chaining with two optional properties creates two additional branches
}
```
:::
Expand Down
13 changes: 13 additions & 0 deletions lib/rules/complexity.js
Expand Up @@ -109,6 +109,7 @@ module.exports = {
IfStatement: increaseComplexity,
WhileStatement: increaseComplexity,
DoWhileStatement: increaseComplexity,
AssignmentPattern: increaseComplexity,

// Avoid `default`
"SwitchCase[test]": increaseComplexity,
Expand All @@ -120,6 +121,18 @@ module.exports = {
}
},

MemberExpression(node) {
if (node.optional === true) {
increaseComplexity();
}
},

CallExpression(node) {
if (node.optional === true) {
increaseComplexity();
}
},

onCodePathEnd(codePath, node) {
const complexity = complexities.pop();

Expand Down
93 changes: 91 additions & 2 deletions tests/lib/rules/complexity.js
Expand Up @@ -124,7 +124,25 @@ ruleTester.run("complexity", rule, {
{ code: "class C { static { if (a || b) c = d || e; } }", options: [4], languageOptions: { ecmaVersion: 2022 } },

// object property options
{ code: "function b(x) {}", options: [{ max: 1 }] }
{ code: "function b(x) {}", options: [{ max: 1 }] },

// optional chaining
{
code: "function a(b) { b?.c; }", options: [{ max: 2 }]
},

// default function parameter values
{
code: "function a(b = '') {}", options: [{ max: 2 }]
},

// default destructuring values
{
code: "function a(b) { const { c = '' } = b; }", options: [{ max: 2 }]
},
{
code: "function a(b) { const [ c = '' ] = b; }", options: [{ max: 2 }]
}
],
invalid: [
{ code: "function a(x) {}", options: [0], errors: [makeError("Function 'a'", 1, 0)] },
Expand Down Expand Up @@ -522,6 +540,77 @@ ruleTester.run("complexity", rule, {
},

// object property options
{ code: "function a(x) {}", options: [{ max: 0 }], errors: [makeError("Function 'a'", 1, 0)] }
{ code: "function a(x) {}", options: [{ max: 0 }], errors: [makeError("Function 'a'", 1, 0)] },

// optional chaining
{
code: "function a(b) { b?.c; }",
options: [{ max: 1 }],
errors: [makeError("Function 'a'", 2, 1)]
},
{
code: "function a(b) { b?.['c']; }",
options: [{ max: 1 }],
errors: [makeError("Function 'a'", 2, 1)]
},
{
code: "function a(b) { b?.c; d || e; }",
options: [{ max: 2 }],
errors: [makeError("Function 'a'", 3, 2)]
},
{
code: "function a(b) { b?.c?.d; }",
options: [{ max: 2 }],
errors: [makeError("Function 'a'", 3, 2)]
},
{
code: "function a(b) { b?.['c']?.['d']; }",
options: [{ max: 2 }],
errors: [makeError("Function 'a'", 3, 2)]
},
{
code: "function a(b) { b?.c?.['d']; }",
options: [{ max: 2 }],
errors: [makeError("Function 'a'", 3, 2)]
},
{
code: "function a(b) { b?.c.d?.e; }",
options: [{ max: 2 }],
errors: [makeError("Function 'a'", 3, 2)]
},
{
code: "function a(b) { b?.c?.(); }",
options: [{ max: 2 }],
errors: [makeError("Function 'a'", 3, 2)]
},
{
code: "function a(b) { b?.c?.()?.(); }",
options: [{ max: 3 }],
errors: [makeError("Function 'a'", 4, 3)]
},

// default function parameter values
{
code: "function a(b = '') {}",
options: [{ max: 1 }],
errors: [makeError("Function 'a'", 2, 1)]
},

// default destructuring values
{
code: "function a(b) { const { c = '' } = b; }",
options: [{ max: 1 }],
errors: [makeError("Function 'a'", 2, 1)]
},
{
code: "function a(b) { const [ c = '' ] = b; }",
options: [{ max: 1 }],
errors: [makeError("Function 'a'", 2, 1)]
},
{
code: "function a(b) { const [ { c: d = '' } = {} ] = b; }",
options: [{ max: 1 }],
errors: [makeError("Function 'a'", 3, 1)]
}
]
});

0 comments on commit c49ed63

Please sign in to comment.