How to Measure and Reduce Frontend Cyclomatic Complexity with ESLint

This article explains cyclomatic complexity concepts, industry standards, calculation methods, and how a custom ESLint rule can be used to assess both single‑function and nested‑function complexity in front‑end projects, including scoring thresholds and practical implementation details.

大转转FE
大转转FE
大转转FE
How to Measure and Reduce Frontend Cyclomatic Complexity with ESLint

Background

At ZhaiZhai, a systematic front‑end quality framework has been built, categorising metrics into monitoring, engineering standards, and technical advancement. Among the engineering standards, code line count, code style, and cyclomatic complexity (CC) are key P2 indicators, and this article focuses on CC.

Cyclomatic Complexity Overview

Cyclomatic complexity (CC) , also known as condition complexity, measures the number of linearly independent paths through a program. Introduced by Thomas J. McCabe in 1976, a higher CC indicates more complex decision logic, lower maintainability, and a higher likelihood of defects.

Industry practice links low CC to better code quality, while high CC almost always signals poor quality.

CC 1‑10: Clear, structured code – low maintenance cost.

CC 10‑20: Moderately complex – medium maintenance cost.

CC 20‑30: Very complex – high maintenance cost.

CC >30: Unreadable – very high maintenance cost.

Calculation Methods

Two typical methods are described.

1) Edge‑Node (M = E − N + 2P)

Where E is the number of edges, N the number of nodes, and P the number of connected components. Since the analysis is performed on a single, connected function, the formula simplifies to M = E − N + 2 .

2) Node Decision (M = P + 1)

Here P is the count of decision nodes such as if, while, for, case, catch, logical operators ( &&, ||), and the ternary operator. Each decision node adds one to the complexity, plus one for the function entry.

Examples:

// Function CC: 3
function test(a) {
  let result = 1;
  if (a > 0 && a < 10) {
    result--;
  }
  return result;
}
// Function CC: 6
function test(a) {
  let result = 1;
  if (a > 0) { result--; }
  for (let i = 0; i < 10; i++) { result += 1; }
  switch (parseInt(result)) {
    case 1: result += 20; break;
    case 2: result += 30; break;
    default: result += 10; break;
  }
  return result > 20 ? result : false;
}

Characteristics of CC

Higher CC correlates strongly with defect density, making it a useful indicator for testing effort and legacy code refactoring. Measuring CC over time helps decide when to refactor and how to allocate testing resources.

ZhaiZhai Front‑End CC Scoring

The company defines a composite score as the average of single‑function CC score and nested‑function CC score.

Single‑function scoring thresholds :

[0, 15] – Pass (no deduction)

(15, 20] – ‑1 point

(20, 30] – ‑2 points

>30 – ‑4 points

Nested‑function scoring depends on total lines of nested functions, with thresholds (e.g., 0‑100 lines → ‑1, 101‑200 lines → ‑1, etc.) and corresponding CC limits.

Detection Approaches

Several tools can compute CC, but ZhaiZhai adopts a function‑level approach using ESLint’s complexity rule as the base and extends it to handle nested functions.

ESLint – complexity

Low integration cost

Fast analysis

Local, easy to modify

Function‑level granularity aligns with refactoring effort

SonarQube

Provides project‑wide metrics and a rich UI, but only offers file‑level CC and is harder to integrate into the existing workflow.

TyphonJS‑ESComplex

Analyzes whole files, but is slower, lacks Vue support, and is no longer maintained.

ESLint Configuration for CC

rules: {
  complexity: ['error', 15]
}

Note: ESLint evaluates each function independently, so nested functions are counted separately.

Nested‑Function CC Implementation

The custom rule traverses the AST to locate all decision nodes and recursively processes any called or defined sub‑functions, summing their complexities to obtain a nested‑function CC value.

Key steps:

Identify decision node types: IfStatement, CatchClause, ConditionalExpression, LogicalExpression, ForStatement, ForInStatement, ForOfStatement, WhileStatement, DoWhileStatement, SwitchCase.

When a function call is encountered, locate its declaration via a recursive AST search ( findFunctionDeclaration) and compute its CC.

Accumulate complexity and line counts for the parent function.

Example of the rule’s entry points:

return {
  "FunctionDeclaration:exit": onCodePathEnd,
  "FunctionExpression:exit": onCodePathEnd,
  "ArrowFunctionExpression:exit": onCodePathEnd
};

AST traversal is performed depth‑first, using a map of node types to their child properties (e.g., { "AssignmentExpression": ["left", "right"] }), ensuring all nested structures are visited.

Usage

After publishing the custom rule as an npm package, developers install it and enable it in their ESLint configuration to receive CC reports for both single and nested functions during local development.

Conclusion

The combined scoring system is integrated into ZhaiZhai’s quality platform, enforcing CC standards across all front‑end projects. Developers can rely on the built‑in ESLint single‑function rule for quick checks and the custom nested‑function rule for deeper analysis, guiding refactoring and improving maintainability.

References

https://baike.baidu.com/item/%E5%9C%88%E5%A4%8D%E6%9D%82%E5%BA%A6/828737 https://juejin.cn/post/6844903965792927751?searchId=2024022216432756DD0DDB3C37A2276D90
frontendASTcode qualitystatic analysiscyclomatic complexityESLint
大转转FE
Written by

大转转FE

Regularly sharing the team's thoughts and insights on frontend development

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.