Documentation
¶
Overview ¶
Command nestinglint enforces the project's shallow-nesting rule (CODING_STYLE.md: "Keep Indentation Shallow" / "avoids 'arrow code,' where indentation grows with each condition checked"). It flags any function whose control-structure nesting exceeds a threshold, so that "arrow code" is caught mechanically rather than only in review.
What counts as a level ¶
A function body is depth 0. Entering the body of any block-introducing control structure adds one level:
- if / else / else-if (the else-if chain stays at ONE level — see below)
- for / range
- switch / type switch (case bodies live one level below the switch)
- select (comm-clause bodies one level below the select)
- an explicit nested block { }
The reported depth is the deepest such level reached in the function.
else-if is flat ¶
gofmt renders `if a { } else if b { } else { }` as a flat chain at a single indentation level, even though the AST nests each `else if` inside the previous `IfStmt.Else`. This linter mirrors gofmt: an else-if continuation is measured at the SAME level as the `if` it continues, not one deeper. A ten-arm else-if ladder is depth 1, not depth 10.
Function literals are independent scopes ¶
Each closure (a `func(...) { ... }` literal) is measured as its own function, with its body starting fresh at depth 0. The depth walker only descends into statement bodies, never into expressions, so a literal's interior is never counted against its enclosing function; the top-level ast.Inspect visits the literal separately. This keeps the metric per-function and avoids charging a deeply-placed callback for the nesting of its call site.
Depth is a positional/structural property that the gocritic/ruleguard DSL cannot express, so this lives as a standalone go/ast pass, mirroring tools/cmd/singlelinefunclint and tools/cmd/typeswitchlint.
It exits non-zero when any violation is found, so it can gate `make lint`.
Usage:
go run ./tools/cmd/nestinglint [-max N] [dir...]
If no directories are given, it scans the current directory recursively. Test files (_test.go) are skipped, consistent with the other standalone linters and the ruleguard rules that exempt tests from production-only conventions.