Skip to content

Commit

Permalink
support pipe versions
Browse files Browse the repository at this point in the history
  • Loading branch information
milmazz authored and novaugust committed Jan 17, 2024
1 parent 3be8083 commit 55389b7
Show file tree
Hide file tree
Showing 3 changed files with 105 additions and 0 deletions.
1 change: 1 addition & 0 deletions lib/style/deprecations.ex
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ defmodule Styler.Style.Deprecations do

defp style(node), do: node

@doc "Extracts the positive or negative integer from the given range block"
def extract_value_from_range({:__block__, _, [value]}), do: value
def extract_value_from_range({:-, _, [{:__block__, _, [value]}]}), do: -value
end
42 changes: 42 additions & 0 deletions lib/style/pipes.ex
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ defmodule Styler.Style.Pipes do
@behaviour Styler.Style

alias Styler.Style
alias Styler.Style.Deprecations

Check warning on line 30 in lib/style/pipes.ex

View workflow job for this annotation

GitHub Actions / Ex1.14.2/OTP25.1.2

unused alias Deprecations

Check warning on line 30 in lib/style/pipes.ex

View workflow job for this annotation

GitHub Actions / Ex1.15.7/OTP25.1.2

unused alias Deprecations

Check warning on line 30 in lib/style/pipes.ex

View workflow job for this annotation

GitHub Actions / Ex1.15.7/OTP25.1.2

unused alias Deprecations
alias Styler.Zipper

def run({{:|>, _, _}, _} = zipper, ctx) do
Expand Down Expand Up @@ -151,6 +152,47 @@ defmodule Styler.Style.Pipes do
defp fix_pipe({:|>, m, [lhs, {{:., dm, [{:__aliases__, am, [:Timex]}, :now]}, funm, []}]}),
do: {:|>, m, [lhs, {{:., dm, [{:__aliases__, am, [:DateTime]}, :now!]}, funm, []}]}

# Path.safe_relative_to/2 => Path.safe_relative/2
# Path.safe_relative/2 is available since v1.14
# TODO: Remove after Elixir v1.19
defp fix_pipe({:|>, m, [lhs, {{:., dm, [{:__aliases__, am, [:Path]}, :safe_relative_to]}, funm, args}]}),
do: {:|>, m, [lhs, {{:., dm, [{:__aliases__, am, [:Path]}, :safe_relative]}, funm, args}]}

if Version.match?(System.version(), ">= 1.16.0-dev") do
# File.stream!(file, options, line_or_bytes) => File.stream!(file, line_or_bytes, options)
defp fix_pipe(
{:|>, m,
[
lhs,
{{:., dm, [{:__aliases__, am, [:File]}, :stream!]}, funm,
[{:__block__, _, [modes]} = options, line_or_bytes]}
]}
)
when is_list(modes),
do: {:|>, m, [lhs, {{:., dm, [{:__aliases__, am, [:File]}, :stream!]}, funm, [line_or_bytes, options]}]}

# For ranges where `start > stop`, you need to explicitly include the step
# Enum.slice(enumerable, 1..-2) => Enum.slice(enumerable, 1..-2//1)
# String.slice("elixir", 2..-1) => String.slice("elixir", 2..-1//1)
defp fix_pipe(
{:|>, m, [lhs, {{:., dm, [{:__aliases__, am, [module]}, :slice]}, funm, [{:.., _, [_, _]}] = args}]} = block
)
when module in [:Enum, :String] do
[{:.., rm, [first, {_, lm, _} = last]}] = args
start = Deprecations.extract_value_from_range(first)
stop = Deprecations.extract_value_from_range(last)

if start > stop do
line = Keyword.fetch!(lm, :line)
step = {:__block__, [token: "1", line: line], [1]}
range_with_step = {:"..//", rm, [first, last, step]}
{:|>, m, [lhs, {{:., dm, [{:__aliases__, am, [module]}, :slice]}, funm, [range_with_step]}]}
else
block
end
end
end

# `lhs |> Enum.reverse() |> Enum.concat(enum)` => `lhs |> Enum.reverse(enum)`
defp fix_pipe(
pipe_chain(
Expand Down
62 changes: 62 additions & 0 deletions test/style/pipes_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -689,5 +689,67 @@ defmodule Styler.Style.PipesTest do
"""
)
end

test "Path.safe_relative_to/2 to Path.safe_relative/2" do
assert_style(
"""
"FOO"
|> String.downcase()
|> Path.safe_relative_to("/")
""",
"""
"FOO"
|> String.downcase()
|> Path.safe_relative("/")
"""
)
end

if Version.match?(System.version(), ">= 1.16.0-dev") do
test "File.stream!(path, modes, line_or_bytes) to File.stream!(path, line_or_bytes, modes)" do
assert_style(
"f |> File.stream!([encoding: :utf8, trim_bom: true], :line) |> Enum.take(2)",
"f |> File.stream!(:line, encoding: :utf8, trim_bom: true) |> Enum.take(2)"
)
end

test "negative steps with Enum.slice/2" do
assert_style(
"enumerable |> Enum.map(& &1) |> Enum.slice(1..-2)",
"enumerable |> Enum.map(& &1) |> Enum.slice(1..-2//1)"
)

assert_style(
"enumerable |> Enum.map(& &1) |> Enum.slice(-1..-2)",
"enumerable |> Enum.map(& &1) |> Enum.slice(-1..-2//1)"
)

assert_style(
"enumerable |> Enum.map(& &1) |> Enum.slice(2..1)",
"enumerable |> Enum.map(& &1) |> Enum.slice(2..1//1)"
)

assert_style(
"enumerable |> Enum.map(& &1) |> Enum.slice(1..3)",
"enumerable |> Enum.map(& &1) |> Enum.slice(1..3)"
)
end

test "negative steps with String.slice/2" do
assert_style(
~s{"ELIXIR" |> String.downcase() |> String.slice(2..-1)},
~s{"ELIXIR" |> String.downcase() |> String.slice(2..-1//1)}
)

assert_style(
~s{"ELIXIR" |> String.downcase() |> String.slice(1..-2)},
~s{"ELIXIR" |> String.downcase() |> String.slice(1..-2//1)}
)

assert_style(~s{"ELIXIR" |> String.downcase() |> String.slice(-4..-1)})
assert_style(~s{"ELIXIR" |> String.downcase() |> String.slice(..)})
assert_style(~s{"ELIXIR" |> String.downcase() |> String.slice(0..-1//2)})
end
end
end
end

0 comments on commit 55389b7

Please sign in to comment.