Packages
ex_check_ng
1.0.0-rc.2
One task to efficiently run all code analysis & testing tools in an Elixir project. Community-maintained fork of ex_check.
Current section
Files
Jump to
Current section
Files
lib/ex_check/diagnostics.ex
defmodule ExCheck.Diagnostics do
@moduledoc false
# Best-effort extraction of structured `{file, line, message}` findings from the raw
# (ANSI-containing) output of failed tools. Result tuples stay untouched — the Manifest
# and Pipeline pattern-match them — so parsing happens on demand in the reporters that
# want it (json, agent, github). The pretty reporter never calls this and pays nothing.
alias ExCheck.Reporter
defmodule Diagnostic do
@moduledoc false
defstruct [:file, :line, :column, :message, severity: :error]
@type t :: %__MODULE__{
file: String.t() | nil,
line: pos_integer | nil,
column: pos_integer | nil,
message: String.t(),
severity: :error | :warning
}
end
@callback parse(String.t()) :: [Diagnostic.t()]
# Keyed by base tool atom; umbrella instances `{name, app}` collapse to `name`.
@parsers %{
compiler: ExCheck.Diagnostics.Compiler,
credo: ExCheck.Diagnostics.Credo,
ex_unit: ExCheck.Diagnostics.ExUnit
}
@doc """
Structured diagnostics for a single result tuple. Only `:error` results are parsed
(the default compiler command runs with `--warnings-as-errors`, so warnings already
surface as failures — extend the guard here to parse `:ok` results too if needed).
Anything without a registered parser, or that fails to parse, yields `[]`.
"""
@spec extract(tuple) :: [Diagnostic.t()]
def extract({:error, {name, _cmd, _opts}, {_code, output, _duration}}) do
case Map.get(@parsers, base_name(name)) do
nil -> []
parser -> output |> Reporter.strip_ansi() |> parser.parse()
end
rescue
_ -> []
end
def extract(_), do: []
defp base_name({name, _app}), do: name
defp base_name(name), do: name
end