lucacervello / recode

A linter with autocorrection and a refactoring tool.

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Recode

Hex.pm: version GitHub: CI status License: MIT

A linter with autocorrection and a refactoring tool.

recode is an experimental project to play around with the great sourceror package by @doorgan.

This library is still under development, breaking changes are expected. The same is true for sourceror and most of recode's functionality is based on sourceror.

For now, recode corrects only a few things:

  • AliasExpansion expands multi aliases
  • AliasOrder orders aliases alphabetically
  • Format runs the Elixir formatter
  • PipeFunOne adds () to one arity functions in pipes
  • SinglePipe corrects single pipes
  • TestFileExt renames test file extensions to *.exs

It is also possible to run recode in a none-autocorect mode to just lint your code.

There is also one mix task for code refactoring. The task mix recode.rename renames a function and all their function calls.

Installation

The package can be installed by adding recode to your list of dependencies in mix.exs:

def deps do
  [
    {:recode, "~> 0.1"}
  ]
end

Documentation can be found at https://hexdocs.pm/recode.

Usage

To start with Foo a configuration file is needed.

mix recode.gen.config

This mix task generates the config file .recode.exs.

alias Recode.Task

[
  # Can also be set/reset with "--autocorrect"/"--no-autocorrect".
  autocorrect: true,
  # With "--dry" no changes will be written to the files.
  # Can also be set/reset with "--dry"/"--no-dry".
  # If dry is true then verbose is also active.
  dry: false,
  # Can also be set/reset with "--verbose"/"--no-verbose".
  verbose: false,
  inputs: ["{config,lib,test}/**/*.{ex,exs}"],
  formatter: {Recode.Formatter, []},
  tasks: [
    {Task.AliasExpansion, []},
    {Task.AliasOrder, []},
    {Task.PipeFunOne, []},
    {Task.SinglePipe, []},
    {Task.Specs, exclude: "test/**/*.{ex,exs}", config: [only: :visible]},
    {Task.TestFileExt, []},
    {Task.SameLine, active: false}
  ]
]

mix recode

This mix tasks runs the linter with autocorrection. The switch --dry prevents the update of the files and shows all changes in the console.

> cd examples/my_code
> mix recode --dry
Found 11 files, including 2 scripts.
.............................................................................
 File: lib/my_code.ex
[Specs 15/3] Functions should have a @spec type specification.

 File: lib/my_code/alias_expansion.ex
Updates: 1
Changed by: AliasExpansion
001   |defmodule MyCode.AliasExpansion do
002 - |  alias MyCode.{PipeFunOne, SinglePipe}
002 + |  alias MyCode.PipeFunOne
003 + |  alias MyCode.SinglePipe
004   |
005   |  def foo(x) do
[Specs 5/3] Functions should have a @spec type specification.

 File: lib/my_code/alias_order.ex
Updates: 2
Changed by: AliasOrder, AliasExpansion
012   |
013   |defmodule Mycode.AliasOrder do
014 - |  alias MyCode.SinglePipe
014 + |  alias MyCode.Echo
015 + |  alias MyCode.Foxtrot
016   |  alias MyCode.PipeFunOne
017 - |  alias MyCode.{Foxtrot, Echo}
017 + |  alias MyCode.SinglePipe
018   |
019   |  @doc false

 File: lib/my_code/fun.ex
Updates: 1
Changed by: Format
002   |  @moduledoc false
003   |
004 - |
005 - |
006 - |
007 - |
008 - |
004   |  def noop(x), do: x
005   |end

 File: lib/my_code/multi.ex
Updates: 2
Changed by: SinglePipe, PipeFunOne
007   |
008   |  def pipe(x) do
009 - |    x |> double |> double()
009 + |    x |> double() |> double()
010   |  end
011   |
012   |  def single(x) do
013 - |    x |> double()
013 + |    double(x)
014   |  end
015   |

 File: lib/my_code/pipe_fun_one.ex
Updates: 1
Changed by: PipeFunOne
005   |
006   |  def pipe(x) do
007 - |    x |> double |> double()
007 + |    x |> double() |> double()
008   |  end
009   |end

 File: lib/my_code/singel_pipe.ex
Updates: 1
Changed by: SinglePipe
005   |
006   |  def single_pipe(x) do
007 - |    x |> double()
007 + |    double(x)
008   |  end
009   |
010 - |  def reverse(a), do: a |> Enum.reverse()
010 + |  def reverse(a), do: Enum.reverse(a)
011   |end
012   |

 File: test/my_code_test.exs
Updates: 1
Changed by: TestFileExt
Moved from: test/my_code_test.ex

The switch --no-autocorrect runs the linter without any file changes.

> cd examples/my_code
> mix recode --no-autocorrect
Found 11 files, including 2 scripts.
.............................................................................
 File: lib/my_code.ex
[Specs 15/3] Functions should have a @spec type specification.

 File: lib/my_code/alias_expansion.ex
[AliasExpansion 2/3] Avoid multi aliases.
[Specs 4/3] Functions should have a @spec type specification.

 File: lib/my_code/alias_order.ex
[AliasOrder 15/3] The alias `MyCode.PipeFunOne` is not alphabetically ordered among its group
[AliasOrder 16/3] The alias `MyCode` is not alphabetically ordered among its group
[AliasOrder 16/26] The alias `Echo` is not alphabetically ordered among its multi group
[AliasExpansion 16/3] Avoid multi aliases.

 File: lib/my_code/fun.ex
[Format -/-] The file is not formatted.

 File: lib/my_code/multi.ex
[PipeFunOne 9/7] Use parentheses for one-arity functions in pipes.
[SinglePipe 13/7] Use a function call when a pipeline is only one function long.

 File: lib/my_code/pipe_fun_one.ex
[PipeFunOne 7/7] Use parentheses for one-arity functions in pipes.

 File: lib/my_code/singel_pipe.ex
[SinglePipe 7/7] Use a function call when a pipeline is only one function long.
[SinglePipe 10/25] Use a function call when a pipeline is only one function long.

 File: test/my_code_test.ex
[TestFileExt -/-] The file must be renamed to test/my_code_test.exs so that ExUnit can find it.

mix recode.rename

A mix task to rename a function and all their function calls.

> cd examples/my_code
> mix recode.rename --dry MyCode.SinglePipe.double dbl
Found 11 files, including 2 scripts.
...........
 File: lib/my_code/alias_expansion.ex
Updates: 1
Changed by: Rename
003   |
004   |  def foo(x) do
005 - |    SinglePipe.double(x) + PipeFunOne.double(x)
005 + |    SinglePipe.dbl(x) + PipeFunOne.double(x)
006   |  end
007   |end

 File: lib/my_code/alias_order.ex
Updates: 1
Changed by: Rename
018   |  @doc false
019   |  def foo do
020 - |    {SinglePipe.double(2), PipeFunOne.double(3)}
020 + |    {SinglePipe.dbl(2), PipeFunOne.double(3)}
021   |  end
022   |

 File: lib/my_code/singel_pipe.ex
Updates: 1
Changed by: Rename
002   |  @moduledoc false
003   |
004 - |  def double(x), do: x + x
004 + |  def dbl(x), do: x + x
005   |
006   |  def single_pipe(x) do
007 - |    x |> double()
007 + |    x |> dbl()
008   |  end
009   |

Refactored code should be compellable, but it is not guaranteed.

Differences to Credo

recode was started as a plugin for credo. Unfortunately it was not possible to implement autocorrection as a plugin because the traversation of the code does not support changing the code.

Maybe some code lines from recode could be used as inspiration for credo to bring the autocorrect feature to credo.

Other differences:

  • recode requiers Elixir 1.12, credo requiers Elixir 1.7
  • recode has autocorrection
  • credo has much more checkers
  • credo is faster
  • credo has more features

About

A linter with autocorrection and a refactoring tool.

License:MIT License


Languages

Language:Elixir 100.0%