defmodule Mix.Tasks.Metacredo.Gen.Config do
@shortdoc "Generate a default .metacredo.exs configuration file"
@moduledoc """
Generates a `.metacredo.exs` configuration file in the current directory.
The generated file lists every available MetaCredo check grouped by category.
To disable a check, move its entry to the `disabled` list or set its second
element to `false`:
{MetaCredo.Check.Security.SQLInjection, false}
## Usage
$ mix metacredo.gen.config
## Options
* `--force` - Overwrite an existing `.metacredo.exs`
"""
use Mix.Task
@impl Mix.Task
def run(argv) do
force? = "--force" in argv
path = MetaCredo.Config.default_config_path()
if File.exists?(path) and not force? do
Mix.shell().info("#{path} already exists. Use --force to overwrite.")
else
Mix.Task.run("app.start", [])
File.write!(path, build_config())
Mix.shell().info("Created #{path}")
end
end
# -- Private --
defp build_config do
checks_section = build_checks_section()
"""
# Generated by `mix metacredo.gen.config`.
# Move any check to the `disabled` list or set its second element to `false`
# to turn it off. Add `{ModuleName, [param: value]}` to customise params.
%{
configs: [
%{
name: "default",
files: %{
included: ["lib/", "src/", "web/"],
excluded: [
~r"/_build/",
~r"/deps/",
~r"/node_modules/"
]
},
checks: %{
enabled: [
#{checks_section}
],
disabled: []
}
}
]
}
"""
end
defp build_checks_section do
discover_checks()
|> Enum.group_by(& &1.category())
|> Enum.sort_by(fn {cat, _} -> to_string(cat) end)
|> Enum.map_join("\n", fn {category, checks} ->
header = " # -- #{format_category(category)} --"
lines =
checks
|> Enum.sort_by(&inspect/1)
|> Enum.map_join(",\n", fn mod ->
" {#{inspect(mod)}, []}"
end)
header <> "\n" <> lines
end)
end
defp discover_checks do
case :application.get_key(:metacredo, :modules) do
{:ok, modules} ->
Enum.filter(modules, fn mod ->
String.starts_with?(to_string(mod), "Elixir.MetaCredo.Check.") and
function_exported?(mod, :run, 2) and
function_exported?(mod, :category, 0)
end)
:undefined ->
[]
end
end
defp format_category(category) do
category
|> to_string()
|> String.replace("_", " ")
|> String.split()
|> Enum.map_join(" ", &String.capitalize/1)
end
end