Packages
metastatic
0.1.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/mix/tasks/metastatic.complexity.ex
defmodule Mix.Tasks.Metastatic.Complexity do
@moduledoc """
Analyzes code complexity for a given file.
## Usage
mix metastatic.complexity FILE [options]
## Options
* `--format` - Output format: text (default), json, or detailed
* `--language` - Source language: python, elixir, or erlang (auto-detected if not specified)
* `--max-cyclomatic` - Cyclomatic complexity threshold (default: 10)
* `--max-cognitive` - Cognitive complexity threshold (default: 15)
* `--max-nesting` - Nesting depth threshold (default: 3)
## Examples
# Basic complexity analysis
mix metastatic.complexity my_file.py
# JSON output
mix metastatic.complexity my_file.py --format json
# Detailed report
mix metastatic.complexity my_file.ex --format detailed
# Custom thresholds
mix metastatic.complexity my_file.erl --max-cyclomatic 15 --max-cognitive 20
## Exit Codes
* 0 - All metrics within thresholds
* 1 - Warnings (exceeded thresholds)
* 2 - Error during analysis
"""
@shortdoc "Analyzes code complexity"
use Mix.Task
alias Metastatic.Analysis.Complexity
alias Metastatic.Analysis.Complexity.Formatter
alias Metastatic.Builder
@impl Mix.Task
def run(args) do
{opts, files, _invalid} =
OptionParser.parse(args,
strict: [
format: :string,
language: :string,
max_cyclomatic: :integer,
max_cognitive: :integer,
max_nesting: :integer
],
aliases: [f: :format, l: :language]
)
format = parse_format(opts[:format])
language = parse_language(opts[:language])
thresholds = build_thresholds(opts)
case files do
[] ->
Mix.shell().error("Error: No file specified")
Mix.shell().info("Usage: mix metastatic.complexity FILE [options]")
exit({:shutdown, 2})
[file | _] ->
analyze_file(file, language, format, thresholds)
end
end
defp analyze_file(file, language, format, thresholds) do
unless File.exists?(file) do
Mix.shell().error("Error: File not found: #{file}")
exit({:shutdown, 2})
end
source = File.read!(file)
lang = language || detect_language(file)
case Builder.from_source(source, lang) do
{:ok, document} ->
case Complexity.analyze(document, thresholds: thresholds) do
{:ok, result} ->
output = Formatter.format(result, format)
Mix.shell().info(output)
# Exit with appropriate code
exit_code = if Enum.empty?(result.warnings), do: 0, else: 1
exit({:shutdown, exit_code})
# {:error, reason} ->
# Mix.shell().error("Analysis error: #{inspect(reason)}")
# exit({:shutdown, 2})
end
{:error, reason} ->
Mix.shell().error("Parse error: #{inspect(reason)}")
exit({:shutdown, 2})
end
end
defp parse_format(nil), do: :text
defp parse_format("text"), do: :text
defp parse_format("json"), do: :json
defp parse_format("detailed"), do: :detailed
defp parse_format(other) do
Mix.shell().error("Unknown format: #{other}")
Mix.shell().info("Valid formats: text, json, detailed")
exit({:shutdown, 2})
end
defp parse_language(nil), do: nil
defp parse_language("python"), do: :python
defp parse_language("elixir"), do: :elixir
defp parse_language("erlang"), do: :erlang
defp parse_language(other) do
Mix.shell().error("Unknown language: #{other}")
Mix.shell().info("Valid languages: python, elixir, erlang")
exit({:shutdown, 2})
end
defp detect_language(file) do
case Path.extname(file) do
".py" ->
:python
".ex" ->
:elixir
".exs" ->
:elixir
".erl" ->
:erlang
".hrl" ->
:erlang
other ->
Mix.shell().error("Cannot detect language from extension: #{other}")
Mix.shell().info("Please specify --language option")
exit({:shutdown, 2})
end
end
defp build_thresholds(opts) do
thresholds = %{}
thresholds =
if max_cyc = opts[:max_cyclomatic] do
Map.put(thresholds, :cyclomatic_warning, max_cyc)
else
thresholds
end
thresholds =
if max_cog = opts[:max_cognitive] do
Map.put(thresholds, :cognitive_warning, max_cog)
else
thresholds
end
thresholds =
if max_nest = opts[:max_nesting] do
Map.put(thresholds, :nesting_warning, max_nest)
else
thresholds
end
thresholds
end
end