Packages
metastatic
0.8.2
0.26.0
0.25.0
0.24.1
0.24.0
0.23.0
0.22.2
0.22.1
0.22.0
0.21.3
0.21.2
0.21.1
0.21.0
0.20.3
0.20.2
0.20.1
0.20.0
0.19.0
0.18.0
0.17.0
0.16.0
0.15.1
0.15.0
0.14.2
0.14.1
0.14.0
0.13.3
0.13.2
0.13.1
0.13.0
0.12.0
0.11.0
0.10.4
0.10.3
0.10.2
0.10.1
0.10.0
0.9.2
0.9.1
0.9.0
0.8.6
0.8.5
0.8.4
0.8.3
0.8.2
0.8.1
0.8.0
0.7.7
0.7.6
0.7.5
0.7.4
0.7.3
0.7.1
0.7.0
0.6.1
0.6.0
0.5.2
0.5.1
0.5.0
0.4.2
0.4.1
0.4.0
0.3.5
0.3.4
0.3.3
0.3.2
0.3.1
0.3.0
0.2.0
0.1.3
0.1.2
0.1.1
0.1.0
Cross-language code meta-model library using unified MetaAST representation. Parse, transform, and translate code across Python, Elixir, Ruby, Erlang, Haskell, and more via a shared three-tuple AST format.
Current section
Files
Jump to
Current section
Files
lib/metastatic/analysis/business_logic/callback_hell.ex
defmodule Metastatic.Analysis.BusinessLogic.CallbackHell do
@moduledoc """
Detects deeply nested conditional statements (callback hell pattern).
This analyzer identifies code with excessive nesting of conditionals which
creates "callback hell" - code that is hard to read, maintain, and reason about.
## Cross-Language Applicability
This pattern is universal and applies to all languages with conditionals:
- **Python**: Nested if/else chains
- **JavaScript**: Nested if/else or ternary operators
- **Elixir**: Nested case statements
- **Rust**: Nested match expressions
- **Go**: Nested if/else statements
## Examples
### Bad (Elixir)
case get_user(id) do
{:ok, user} ->
case get_account(user) do
{:ok, account} ->
case process(account) do
{:ok, result} -> result
end
end
end
### Good (Elixir)
with {:ok, user} <- get_user(id),
{:ok, account} <- get_account(user),
{:ok, result} <- process(account) do
result
end
### Bad (Python)
if user is not None:
if user.active:
if user.has_permission():
return True
### Good (Python)
return (user is not None and
user.active and
user.has_permission())
## Configuration
- `:max_nesting` - Maximum allowed nesting depth (default: 2)
"""
@behaviour Metastatic.Analysis.Analyzer
alias Metastatic.Analysis.Analyzer
@impl true
def info do
%{
name: :callback_hell,
category: :readability,
description: "Detects deeply nested conditional statements",
severity: :warning,
explanation: """
Deeply nested conditional statements create "callback hell" - code that is
difficult to read, understand, and maintain. Consider refactoring using:
- Early returns / guard clauses
- Flattening logic with boolean operators
- Extracting nested logic into separate functions
- Using language-specific control flow (e.g., with/monad chaining)
""",
configurable: true
}
end
@impl true
def run_before(context) do
# Initialize configuration with default max_nesting
max_nesting = Map.get(context.config, :max_nesting, 2)
context = Map.put(context, :max_nesting, max_nesting)
{:ok, context}
end
@impl true
def analyze({:conditional, _meta, children} = node, context) when is_list(children) do
max_nesting = Map.get(context, :max_nesting, 2)
nesting_level = count_conditional_nesting(node)
if nesting_level > max_nesting do
[
Analyzer.issue(
analyzer: __MODULE__,
category: :readability,
severity: :warning,
message:
"#{nesting_level} levels of nested conditionals - consider refactoring for readability",
node: node,
metadata: %{nesting_level: nesting_level, max_allowed: max_nesting}
)
]
else
[]
end
end
def analyze(_node, _context), do: []
# ----- Private Helpers -----
# Count nesting depth of conditionals - 3-tuple format
defp count_conditional_nesting({:conditional, _meta, [_cond, then_branch, else_branch]}) do
then_depth = count_nested_conditionals(then_branch)
else_depth = count_nested_conditionals(else_branch)
1 + max(then_depth, else_depth)
end
defp count_conditional_nesting(_), do: 0
# Count nested conditionals in a branch - 3-tuple format
defp count_nested_conditionals({:block, _meta, statements}) when is_list(statements) do
statements
|> Enum.map(&count_conditional_nesting/1)
|> Enum.max(fn -> 0 end)
end
defp count_nested_conditionals({:conditional, _meta, _children} = node) do
count_conditional_nesting(node)
end
defp count_nested_conditionals(_), do: 0
end