Skip to content

Instantly share code, notes, and snippets.

@thiamsantos
Last active April 29, 2022 13:49
Show Gist options
  • Save thiamsantos/55a62a20c9ab064f001a177b41bf5245 to your computer and use it in GitHub Desktop.
Save thiamsantos/55a62a20c9ab064f001a177b41bf5245 to your computer and use it in GitHub Desktop.
Expand multi-alias syntax using credo + sourceror
Mix.install([
:sourceror,
:credo
])
defmodule AliasExpansion do
alias Sourceror.Zipper, as: Z
def expand_aliases(quoted) do
Z.zip(quoted)
|> Z.traverse(&expand_alias/1)
|> Z.root()
end
defp expand_alias(
{{:alias, alias_meta, [{{:., _, [left, :{}]}, call_meta, right}]}, _metadata} = zipper
) do
{_, _, base_segments} = left
leading_comments = alias_meta[:leading_comments] || []
trailing_comments = call_meta[:trailing_comments] || []
right
|> Enum.map(&segments_to_alias(base_segments, &1))
|> put_leading_comments(leading_comments)
|> put_trailing_comments(trailing_comments)
|> Enum.reverse()
|> Enum.reduce(zipper, &Z.insert_right(&2, &1))
|> Z.remove()
end
defp expand_alias(zipper), do: zipper
defp segments_to_alias(base_segments, {_, meta, segments}) do
{:alias, meta, [{:__aliases__, [], base_segments ++ segments}]}
end
defp put_leading_comments([first | rest], comments) do
[Sourceror.prepend_comments(first, comments) | rest]
end
defp put_trailing_comments(list, comments) do
case List.pop_at(list, -1) do
{nil, list} ->
list
{last, list} ->
last =
{:__block__,
[
trailing_comments: comments,
end_of_expression: [newlines: 2]
], [last]}
list ++ [last]
end
end
end
locals_without_parens = [
# Query
from: 2,
# Schema
field: 1,
field: 2,
field: 3,
timestamps: 1,
belongs_to: 2,
belongs_to: 3,
has_one: 2,
has_one: 3,
has_many: 2,
has_many: 3,
many_to_many: 2,
many_to_many: 3,
embeds_one: 2,
embeds_one: 3,
embeds_one: 4,
embeds_many: 2,
embeds_many: 3,
embeds_many: 4
]
Credo.run(["--only", "Credo.Check.Readability.MultiAlias"])
|> Credo.Execution.get_issues()
|> Enum.map(& &1.filename)
|> Enum.map(fn filename ->
filename
|> File.read!()
|> Sourceror.parse_string!()
|> AliasExpansion.expand_aliases()
|> Sourceror.to_string(locals_without_parens: locals_without_parens)
|> tap(&File.write!(filename, &1))
end)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment