defmodule Mix.Tasks.Recode do
@shortdoc "Runs the linter"
@moduledoc """
#{@shortdoc}.
```shell
> mix recode [options] [inputs]
```
Without a `inputs` argument the `inputs` value from the config is used. The
`inputs` argument accepts a wildcard.
If `inputs` value is `-`, then the input is read from stdin.
Without the option `--config file` the config file `.recode.exs` is used. A
default `.recode.exs` can be generated with `mix recode.gen.config`.
## Command line Option
* `--autocorrect`, `--no-autocorrect` - Activates/deactivates autocrrection.
Overwrites the corresponding value in the configuration.
* `--config` - specifies an alternative config file.
* `--dry`, `--no-dry` - Activates/deactivates the dry mode. No file is
overwritten in dry mode. Overwrites the corresponding value in the
configuration.
* `--verbose`, `--no-verbose` - Activate/deactivates the verbose mode.
Overwrites the corresponding value in the configuration.
* `--task`, specifies the task to use. With this option, the task is used
even if it is specified as `active: false` in the configuration.
"""
use Mix.Task
alias Recode.Config
alias Recode.Runner
alias Rewrite.DotFormatter
alias Rewrite.Project
# The minimum version of the config to run recode. This version marks the last
# breaking change for handle the config.
@config_min_version "0.3.0"
@opts strict: [
autocorrect: :boolean,
dry: :boolean,
verbose: :boolean,
config: :string,
task: :string
]
@impl Mix.Task
@spec run(list()) :: no_return()
def run(opts) do
opts = opts!(opts)
Mix.Task.run("compile")
opts
|> config!()
|> validate_config!()
|> Keyword.merge(opts)
|> update(:verbose)
|> update(:locals_without_parens)
|> Runner.run()
|> output()
end
@spec output(Project.t()) :: no_return()
defp output(%Project{sources: sources}) when map_size(sources) == 0 do
Mix.raise("No sources found")
end
defp output(%Project{} = project) do
case Project.issues?(project) do
true -> exit({:shutdown, 1})
false -> exit(:normal)
end
end
defp opts!(opts) do
case OptionParser.parse!(opts, @opts) do
{opts, []} -> opts
{opts, [inputs]} -> Keyword.put(opts, :inputs, inputs)
{_opts, args} -> Mix.raise("#{inspect(args)} : Unknown")
end
end
defp config!(opts) do
case Config.read(opts) do
{:ok, config} -> config
{:error, :not_found} -> Mix.raise("Config file not found")
end
end
defp validate_config!(config) do
cmp =
config
|> Keyword.get(:version, "0.1.0")
|> Version.compare(@config_min_version)
if cmp == :lt do
Mix.raise("The config is out of date. Run `mix recode.gen.config` to update.")
end
config
end
defp update(opts, :verbose) do
case opts[:dry] do
true -> Keyword.put(opts, :verbose, true)
false -> opts
end
end
defp update(opts, :locals_without_parens) do
Keyword.put(opts, :locals_without_parens, DotFormatter.locals_without_parens())
end
end