defmodule Credo.Check.Readability.SingleFunctionToBlockPipe do
use Credo.Check,
id: "EX3022",
tags: [:controversial],
explanations: [
check: """
A single pipe (`|>`) should not be used to pipe into blocks.
The code in this example ...
list
|> length()
|> case do
0 -> :none
1 -> :one
_ -> :many
end
... should be refactored to look like this:
case length(list) do
0 -> :none
1 -> :one
_ -> :many
end
If you want to disallow piping into blocks altogether, use
`Credo.Check.Readability.BlockPipe`.
Like all `Readability` issues, this one is not a technical concern.
But you can improve the odds of others reading and liking your code by making
it easier to follow.
"""
]
@doc false
@impl true
def run(%SourceFile{} = source_file, params) do
Credo.Code.prewalk(source_file, &traverse(&1, &2, IssueMeta.for(source_file, params)))
end
defp traverse(ast, {false, issues}, _issue_meta) do
{ast, issues}
end
defp traverse(ast, issues, issue_meta) do
case issue(ast, issue_meta) do
nil -> {ast, issues}
false -> {ast, {false, issues}}
issue -> {ast, [issue | issues]}
end
end
defp issue({:|>, _, [{:|>, _, [{:|>, _, _} | _]} | _]}, _), do: false
defp issue({:|>, meta, [arg, {marker, _case_meta, _case_args}]}, issue_meta)
when marker in [:case, :if] do
if issue?(arg), do: issue_for(issue_meta, meta[:line], marker), else: nil
end
defp issue(_, _), do: nil
defp issue?({_, _, nil}), do: true
defp issue?({:%{}, _, _}), do: true
defp issue?(arg) when is_list(arg), do: true
defp issue?({:|>, _, [{_, _, nil}, {_, _, args}]}) when is_list(args), do: true
defp issue?({:|>, _, [{:%{}, _, _}, {_, _, args}]}) when is_list(args), do: true
defp issue?({:|>, _, [arg, {_, _, args}]}) when is_list(arg) and is_list(args), do: true
defp issue?(_), do: false
defp issue_for(issue_meta, line_no, marker) do
format_issue(
issue_meta,
message: "Avoid single pipes to a block",
line_no: line_no,
trigger: marker
)
end
end