complexity

Enforce a maximum number of branches in a function

Every branch in a function is one more path to keep in mind and to test. This rule counts them and reports any function with more than 20.

The count starts at 1. Each of these adds 1: if, ? :, a loop, a case, a catch, &&, ||, ??, their assignment forms such as ||=, ?., and a default value for a parameter or in destructuring. Nested functions are counted separately. Class field initializers and static blocks are counted too.

Configure#

Off by default. To turn it on:

bunfig.toml
[lint.rules]
"complexity" = "error" # or "warn"

Every option, set to its default. The ones that are commented out are unset by default.

bunfig.toml
[lint.rules]
"complexity" = ["error", {
  max = 20,
  variant = "classic", # "classic" or "modified"
  # maximum = <number>,
}]

Examples#

With a maximum of 3, this function is reported. It has a complexity of 4:

example.jswith 31 problem
function shipping(order) {
  if (order.total > 100) {
    return 0;
  } else if (order.express) {
    return 15;
  } else if (order.country !== "US") {
    return 25;
  }
  return 5;
}
example.jswith 3No problems
function shipping(order) {
  if (order.total > 100) {
    return 0;
  }
  return order.express ? 15 : standardRate(order.country);
}

function standardRate(country) {
  return country === "US" ? 5 : 25;
}

Options#

bunfig.toml
[lint.rules]
complexity = ["error", 10]

The option is either a number (the maximum) or an object:

OptionDefaultWhat it does
max20The highest complexity allowed. maximum is an older name for it.
variant"classic""modified" counts a whole switch as 1, no matter how many cases it has.

Three cases give this function a complexity of 4. default doesn't count:

example.jswith { "max": 3 }1 problem
function label(status) {
  switch (status) {
    case "open":
      return "Open";
    case "merged":
      return "Merged";
    case "closed":
      return "Closed";
    default:
      return "Unknown";
  }
}

With "modified", the same function has a complexity of 2:

example.jswith { "max": 2, "variant": "modified" }No problems
function label(status) {
  switch (status) {
    case "open":
      return "Open";
    case "merged":
      return "Merged";
    case "closed":
      return "Closed";
    default:
      return "Unknown";
  }
}