diff --git a/CHANGELOG.md b/CHANGELOG.md index 9ebaff7..7468937 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,7 +9,8 @@ they can and will change without that change being reflected in Styler's semanti #### Ex1.17+ -Replace `:timer.units(x)` with the new `to_timeout(unit: x)` for `hours|minutes|seconds` +- Replace `:timer.units(x)` with the new `to_timeout(unit: x)` for `hours|minutes|seconds` +- Handle `, else: (_ -> x)` bugs introduced by `(_ -> x)` being termed a literal (#219, h/t @iamhassangm) #### Ex1.18+ @@ -48,6 +49,7 @@ This release taught Styler to try just that little bit harder when doing alias l ### Fixes - `pipes`: handle pipifying when the first arg is itself a pipe: `c(a |> b, d)` => `a |> b() |> c(d)` (#214, h/t @kybishop) +- `with`: correctly handle a stabby `with` `, else: (_ -> :ok)` being rewritten to a case (#219, h/t @iamhassangm) ## 1.3.3 diff --git a/lib/style/blocks.ex b/lib/style/blocks.ex index ac8e7a5..fd51be1 100644 --- a/lib/style/blocks.ex +++ b/lib/style/blocks.ex @@ -53,10 +53,31 @@ defmodule Styler.Style.Blocks do # to `case single_statement do success -> body; ...elses end` def run({{:with, m, [{:<-, am, [success, single_statement]}, [body, elses]]}, zm}, ctx) do {{:__block__, do_meta, [:do]}, body} = body - {{:__block__, _else_meta, [:else]}, elses} = elses + {{:__block__, _, [:else]}, elses} = elses + + elses = + case elses do + # unwrap a stab ala `, else: (_ -> :ok)`. these became literals in 1.17 + {:__block__, _, [[{:->, _, _}] = stab]} -> stab + elses -> elses + end + + # drops keyword formatting etc + do_meta = [line: do_meta[:line]] clauses = [{{:__block__, am, [:do]}, [{:->, do_meta, [[success], body]} | elses]}] + end_line = Style.max_line(elses) + 1 + + # fun fact: i added the detailed meta just because i noticed it was missing while debugging something ... + # ... and it fixed the bug 🤷 + case_meta = [ + end_of_expression: [newlines: 1, line: end_line], + do: do_meta, + end: [line: end_line], + line: m[:line] + ] + # recurse in case this new case should be rewritten to a `if`, etc - run({{:case, m, [single_statement, clauses]}, zm}, ctx) + run({{:case, case_meta, [single_statement, clauses]}, zm}, ctx) end # `with true <- x, do: bar` =>`if x, do: bar` diff --git a/test/style/blocks_test.exs b/test/style/blocks_test.exs index 83cbab4..cf2d164 100644 --- a/test/style/blocks_test.exs +++ b/test/style/blocks_test.exs @@ -239,7 +239,7 @@ defmodule Styler.Style.BlocksTest do end end - describe "with statements" do + describe "with" do test "replacement due to no (or all removed) arrows" do assert_style( """ @@ -787,6 +787,20 @@ defmodule Styler.Style.BlocksTest do end """ end + + test "elixir1.17+ stab regressions" do + assert_style( + """ + with :ok <- foo, do: :bar, else: (_ -> :baz) + """, + """ + case foo do + :ok -> :bar + _ -> :baz + end + """ + ) + end end test "Credo.Check.Refactor.CondStatements" do