How ESLint Detects Unnecessary Lodash Chaining

Lodash chaining provides a fluent API for sequencing data transformations, but wrapping values in a Lodash wrapper for solitary operations introduces runtime overhead and prevents effective tree-shaking. This article examines how eslint-plugin-lodash parses the Abstract Syntax Tree (AST) to identify redundant chaining, evaluates call depth, and alerts developers to simplify their code into direct method invocations.

Abstract Syntax Tree Traversal

ESLint operates by parsing JavaScript source code into an Abstract Syntax Tree (AST) via parsers like Espree. eslint-plugin-lodash hooks into this process using visitor functions that inspect specific AST node types, primarily CallExpression and MemberExpression.

When code executes a chained operation such as _chain(items).map(fn).value() or _(items).filter(fn).value(), the AST represents this structure as a nested hierarchy of method calls:

  1. The root CallExpression represents .value().
  2. The callee of that call is a MemberExpression pointing to the output of the preceding operation (e.g., .map(fn)).
  3. The chain continues recursively down to the initial wrapper call (_.chain(...) or _(...)).

Scope and Identifier Resolution

Before checking chain length, eslint-plugin-lodash verifies that the invoked object actually originates from the Lodash library. The plugin uses ESLint's built-in Scope manager to trace identifiers. It inspects:

If an identifier does not resolve to the designated Lodash import or variable, the plugin ignores the call, preventing false positives on native method chains or other libraries with similar chaining patterns.

Counting Intermediate Transformations

The core detection logic relies on analyzing the depth of the chain between the initialization and the terminal .value() or unwrapping step. Rules such as lodash/chain-style enforce specific architectural patterns (explicit, implicit, or no chaining).

To catch unnecessary chaining:

  1. Step Identification: When the linter encounters a terminal call (like .value()), it traverses up the AST branch, collecting each intermediate MemberExpression and CallExpression.
  2. Operation Counting: The plugin counts how many transformation steps occur between the creation of the wrapper and the extraction of the value.
  3. Threshold Evaluation: If the chain consists of only zero or one transformation (for example, _.chain(users).map(getName).value()), the chain wrapper provides no functional utility over the direct call _.map(users, getName).

Warning Generation and Autofixing

When the AST walker identifies a chain that violates the configured threshold or rule constraints, eslint-plugin-lodash calls ESLint's context.report() API.

The report contains: