I made one to ban assign/2
. then
is next
defmodule GelaSkins.Credo.NoCallsToAssign2 do
@moduledoc """
Checks that `Phoenix.LiveView.assign/2` can't be called.
"""
# you can configure the basics of your check via the `use Credo.Check` call
use Credo.Check,
base_priority: :high,
category: :custom,
exit_status: 0,
explanations: [
check: """
Always use `assign/3` in favour of `assign/2`.
This forces a pipeline when using multiple assigns. The advantage here is
that assigns may be added, removed, and re-ordered easily (no commas to deal
with) making diffs nicer. It also means you must explicitly name the
parameters accepted by LiveComponents. You cannot simply do
`assign(socket, assigns)`.
"""
]
@doc false
@impl true
def run(%SourceFile{} = source_file, params \\ []) do
# IssueMeta helps us pass down both the source_file and params of a check
# run to the lower levels where issues are created, formatted and returned
issue_meta = IssueMeta.for(source_file, params)
# Finally, we can run our custom made analysis.
# In this example, we look for lines in source code matching our regex:
Credo.Code.prewalk(source_file, &traverse(&1, &2, [], issue_meta))
end
defp traverse({:|>, _, [{:socket, _, _}, {:assign, meta, [_]}]} = ast, issues, [], issue_meta) do
{ast, issues ++ [issue_for(:assign, meta[:line], issue_meta)]}
end
defp traverse({:assign, meta, [{:socket, _, _}, [_]]} = ast, issues, [], issue_meta) do
{ast, issues ++ [issue_for(:assign, meta[:line], issue_meta)]}
end
defp traverse(ast, issues, _, _issue_meta) do
{ast, issues}
end
defp issue_for(trigger, line_no, issue_meta) do
format_issue(
issue_meta,
message: "Only use assign/3",
line_no: line_no,
trigger: trigger
)
end
end
It also checks for a single pipe into assign
. I can’t remember why I did this instead of using the existing credo rule but I assume it’s because sometimes I’m ok with single pipes. This was a while ago.