SkillAgentSearch skills...

Recode

A linter with autocorrection and a refactoring tool.

Install / Use

/learn @hrzndhrn/Recode
About this skill

Quality Score

0/100

Supported Platforms

Universal

README

Recode

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

A linter with autocorrection.

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.

recode can correct and check the following things:

> mix recode.help

Design tasks:
TagFIXME            # Checker   - Checks if there are FIXME tags in the sources.
TagTODO             # Checker   - Checks if there are TODO tags in the sources.
Readability tasks:
AliasExpansion      # Corrector - Expands multi aliases to separate aliases.
AliasOrder          # Corrector - Checks if aliases are sorted alphabetically.
EnforceLineLength   # Corrector - Forces expressions to one line.
Format              # Corrector - Does the same as `mix format`.
LocalsWithoutParens # Corrector - Removes parens from locals without parens.
Moduledoc           # Checker   - There should be a @moduledoc in any module.
PipeFunOne          # Corrector - Add parentheses to one-arity functions.
SinglePipe          # Corrector - Pipes should only be used when piping data through multiple calls.
Specs               # Checker   - Checks for specs.
UnnecessaryIfUnless # Corrector - Removes redundant booleans
Refactor tasks:
FilterCount         # Corrector - Checks calls like Enum.filter(...) |> Enum.count().
Nesting             # Checker   - Checks code nesting depth in functions and macros.
Warning tasks:
Dbg                 # Corrector - There should be no calls to dbg.
IOInspect           # Corrector - There should be no calls to IO.inspect.
TestFile         # Corrector - Checks the file extension of test files.
UnusedVariable      # Corrector - Checks if unused variables occur.

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

Installation

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

  def deps do
    [
      {:recode, "~> 0.7", only: :dev, runtime: false}
    ]
  end

Recode requires Elixir 1.13.0 or higher. If you add recode to a project that supports lower Elixir versions you could add recode as following:

  def deps do
    [
      # your deps
    ] ++ recode()
  end

  defp recode() do
    case Version.match?(System.version(), "~> 1.13") do
      true -> [{:recode, "~> 0.7", only: :dev, runtime: false}]
      false -> []
    end
  end

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

Usage

To start with recode a configuration file is needed.

mix recode.gen.config

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

[
  version: "0.7.0",
  # 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,
  # Can be overwritten by calling `mix recode "lib/**/*.ex"`.
  inputs: ["{mix,.formatter}.exs", "{apps,config,lib,test}/**/*.{ex,exs}"],
  formatters: [Recode.CLIFormatter],
  tasks: [
    # Tasks could be added by a tuple of the tasks module name and an options
    # keyword list. A task can be deactivated by `active: false`. The execution of
    # a deactivated task can be forced by calling `mix recode --task ModuleName`.
    {Recode.Task.AliasExpansion, []},
    {Recode.Task.AliasOrder, []},
    {Recode.Task.Dbg, [autocorrect: false]},
    {Recode.Task.EnforceLineLength, [active: true, exclude: "mix.exs"]},
    {Recode.Task.FilterCount, []},
    {Recode.Task.IOInspect, [autocorrect: false]},
    {Recode.Task.Nesting, []},
    {Recode.Task.PipeFunOne, []},
    {Recode.Task.SinglePipe, []},
    {Recode.Task.Specs, [exclude: "test/**/*.{ex,exs}", config: [only: :visible]]},
    {Recode.Task.TagFIXME, [exit_code: 2]},
    {Recode.Task.TagTODO, [exit_code: 4]},
    {Recode.Task.TestFile, []},
    {Recode.Task.UnnecessaryIfUnless, []},
    {Recode.Task.UnusedVariable, [active: false]}
  ]
]

If a configuration file already exists, you can use the mix task

mix recode.update.config

to update the configuration file.

mix recode

This mix task runs the linter with autocorrection. The switch --dry (alias -d) prevents the update of the files and shows all changes in the console.

> cd examples/my_code
> mix recode --dry --no-color --no-manifest
Read 24 files in 0.01s
...................................................!...............!!.........................................................................!....!..!................................!........!...............!..!...!..................!....!.....!................!........!.....!...............!...!!..!.........!...!.!........!!..!..!!!.!....
File: .formatter.exs
Updates: 1
Changed by: Format
     ...|
13 13   |  inputs: ["{mix,.formatter}.exs", "{config,lib,test}/**/*.{ex,exs}", "priv/**/*.json"],
14 14   |  locals_without_parens: [noop: 1],
15    - |  subdirectories: ["priv/*/migrations"],
   15 + |  subdirectories: ["priv/*/migrations"]
16 16   |]
17 17   |

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
1 1   |defmodule MyCode.AliasExpansion do
2   - |  alias MyCode.{PipeFunOne, SinglePipe}
  2 + |  alias MyCode.PipeFunOne
  3 + |  alias MyCode.SinglePipe
3 4   |
4 5   |  def foo(x) do
   ...|
[Moduledoc 1/1] The module Elixir.MyCode.AliasExpansion is missing @moduledoc.
[Specs 5/3] Functions should have a @spec type specification.

File: lib/my_code/alias_order.ex
Updates: 2
Changed by: AliasOrder, AliasExpansion
     ...|
12 12   |
13 13   |defmodule Mycode.AliasOrder do
14    - |  alias MyCode.SinglePipe
   14 + |  alias MyCode.Echo
   15 + |  alias MyCode.Foxtrot
15 16   |  alias MyCode.PipeFunOne
16    - |  alias MyCode.{Foxtrot, Echo}
   17 + |  alias MyCode.SinglePipe
17 18   |
18 19   |  @doc false
     ...|
[Moduledoc 13/1] The module Elixir.Mycode.AliasOrder is missing @moduledoc.

File: lib/my_code/deep.ex
[Moduledoc 1/1] The module Elixir.MyCode.Deep is missing @moduledoc.
[Specs 2/3] Functions should have a @spec type specification.
[Nesting 6/11] The body is nested too deep (max depth: 2).

File: lib/my_code/multi.ex
Updates: 4
Changed by: SinglePipe, PipeFunOne, FilterCount, Format
 1  1   |defmodule MyCode.Multi do
 2    - |
 3  2   |  import MyCode.Fun
 4  3   |
     ...|
 6  5   |
 7  6   |  def pipe(x) do
 8    - |    x |> double |> double() |> dbg()
    7 + |    x |> double() |> double() |> dbg()
 9  8   |  end
10  9   |
11 10   |  def single(x) do
12    - |    x |> double()
   11 + |    double(x)
13 12   |  end
14 13   |
     ...|
19 18   |  def my_count(list) do
20 19   |    list
21    - |    |> Enum.filter(fn x -> rem(x, 2) == 0 end)
22    - |    |> Enum.count()
   20 + |    |> Enum.count(fn x -> rem(x, 2) == 0 end)
23 21   |    |> IO.inspect()
24 22   |  end
     ...|
[Moduledoc 1/1] The module Elixir.MyCode.Multi is missing @moduledoc.
[Specs 4/3] Functions should have a @spec type specification.
[Specs 6/3] Functions should have a @spec type specification.
[Dbg 7/34] There should be no calls to dbg.
[Specs 10/3] Functions should have a @spec type specification.
[Specs 14/3] Functions should have a @spec type specification.
[Specs 18/3] Functions should have a @spec type specification.
[IOInspect 21/8] There should be no calls to IO.inspect.

File: lib/my_code/pipe_fun_one.ex
Updates: 1
Changed by: PipeFunOne
     ...|
 5  5   |
 6  6   |  def pipe(x) do
 7    - |    x |> double |> double()
    7 + |    x |> double() |> double()
 8  8   |  end
 9  9   |end
     ...|

File: lib/my_code/same_line.ex
[Moduledoc 1/1] The module Elixir.MyCode.SameLine is missing @moduledoc.
[Specs 2/3] Functions should have a @spec type specification.

File: lib/my_code/single_pipe.ex
Updates: 1
Changed by: SinglePipe
     ...|
 5  5   |
 6  6   |  def single_pipe(x) do
 7    - |    x |> double()
    7 + |    double(x)
 8  8   |  end
 9  9   |
10    - |  def reverse(a), do: a |> Enum.reverse()
   10 + |  def reverse(a), do: Enum.reverse(a)
11 11   |end
12 12   |

File: lib/my_code/tags.ex
[TagTODO 3/-] Found a tag: TODO: add docs
[TagFIXME 6/-] Found a tag: FIXME: add more functions
[Specs 7/3] Functions should have a @spec type specification.

File: lib/my_code/trailing_comma.ex
Updates: 2
Changed by: SinglePipe, Format
     ...|
 3  3   |
 4  4   |  def list do
 5    - |    [
    5 + |    Enum.reverse([
 6  6   |      100_000,
 7  7   |      200_000,
     ...|
14 14   |      900_000,
15 15   |      1_000_000,
16    - |      2_000_000,
17    - |    ] |> Enum.reverse()
   16 + |      2_000_000
   17 + |    ])
18 18   |  end
19 19   |end
     ...|

File: mix.exs
[Moduledoc 1/1] The module Elixir.MyCode.MixProject is missing @moduledoc.

File: priv/repo/migrations/20190417140000_create_users.exs
Updates: 2
Changed by: LocalsWithoutParens, Format
     ...|
 4  4   |  def up do
 5  5   |    create table("users") do
 6    - |      add :first_name,    :string, size: 40
 7    - |      add(:last_name,    :string, size: 40)
    6 + |      add :first_name, :string, size: 40
    7 + |      add :last_name, :string, size: 40
 8  8   |
 9  9   |      timestamps()
     ...|
[Moduledoc 1/1] The module Elixir.MyRepo.Migrations.CreateUsers is missing @moduledoc.
[Specs 4/3] Functions should have a @spec type specific
View on GitHub
GitHub Stars316
CategoryDevelopment
Updated24d ago
Forks23

Languages

Elixir

Security Score

95/100

Audited on Mar 7, 2026

No findings