Releases: adobe/elixir-styler
v1.9.1
v1.9.0 - to_timeout with plural units
1.9.0
This was a weird one, but I found myself often writing to_timeout
with plural units and then having to go back and fix the code to be singular units instead. Polling a few colleagues, it seemed I wasn't alone in that mistake. So for the first time, Styler will correct code that would otherwise produce a runtime error, saving you from flow-breaking backtracking.
Improvements
to_timeout
improvements:
- translate plural units to singular
to_timeout(hours: 2)
->to_timeout(hour: 2)
(plurals are valid ast, but invalid arguments to this function) - transform when there are multiple keys:
to_timeout(hours: 24 * 1, seconds: 60 * 4)
->to_timeout(day: 1, minute: 4)
. this can introduce runtime bugs due to duplicate keys, as in the following scenario:to_timeout(minute: 60, hours: 3)
->to_timeout(hour: 1, hour: 3)
styler's LLM edition
Improvements
Rewrite single-clause case statements to be assignments (h/t 🤖)
# before
case foo |> Bar.baz() |> Bop.boop() do
{:ok, widget} ->
x = y
wodget(widget)
end
# after
{:ok, widget} = foo |> Bar.baz() |> Bop.boop()
x = y
wodget(widget)
v1.7.0
1.7.0
Surprising how fast numbers go up when you're following semver.
Two new features, one being a pipe optimization and the other a style-consistency-enforcer in cond
statements.
Improvements
|> Enum.filter(fun) |> List.first([default])
=>|> Enum.find([default], fun)
(#242, h/t @janpieper)
cond
If the last clause's left-hand-side is a truthy atom, map literal, or tuple, rewrite it to be true
# before
cond do
a -> b
c -> d
:else -> e
end
# styled
cond do
a -> b
c -> d
true -> e
end
This also helps Styler identify 2-clause conds that can be rewritten to if/else
more readily, like the following:
# before
cond do
a -> b
:else -> c
end
# styled
if a do
b
else
c
end
v1.6.0: ExUnit assertions edition
That's right, a feature release again so soon!
Improvements
This version of Styler adds many readability improvements around ExUnit assert
and refute
, specifically when working with 1. negations or 2. some Enum
stdlib functions.
Some of these rewrites are not semantically equivalent; for example, refute is_nil(false)
will be rewritten to assert false
, which will fail.
ExUnit assert/refute rewrites
Styler now inverts negated (!, not
) assert/refute (eg assert !x
=> refute x
) statements, and further inverts refute
with boolean comparison operators (refute x < y
=> assert x >= y
) because non-trivial refutes are harder to reason about [ citation needed ]. Asserting something is not nil is the same as just asserting that something, so that's gone too now.
These changes are best summarized by the following table:
before | styled |
---|---|
assert !x |
refute x |
assert not x |
refute x |
assert !!x |
assert x |
assert x != nil |
assert x |
assert x == nil |
no change |
assert is_nil(x) |
no change |
assert !is_nil(x) |
assert x |
assert x not in y |
refute x in y |
refute negated | |
refute x |
no change |
refute !x |
assert x |
refute not x |
assert x |
refute x != y |
assert x == y |
refute x !== y |
assert x === y |
refute x != nil |
assert x == nil |
refute x not in y |
assert x in y |
refute comparison | |
refute x < y |
assert x >= y |
refute x <= y |
assert x > y |
refute x > y |
assert x <= y |
refute x >= y |
assert x < y |
assert Enum.member?(y, x)
->assert x in y
assert Enum.find(x, y)
->assert Enum.any?(x, y)
(nb. not semantically equivalent in theory, but equivalent in practice)assert Enum.any?(y, & &1 == x)
->assert x in y
assert Enum.any?(y, fn var -> var == x end)
->assert x in y
Fixes
- alias lifting: fix bug lifting in snippets with a single ast node at the root level (like a credo config file) (#240, h/t @defndaines)
v1.5.1
v1.5.0
Improvements
- apply aliases to code. if a module is aliased, and then later referenced with its full name, Styler will now shorten it to its alias. (#235, h/t me)
- added
:minimum_supported_elixir_version
configuration to better support libraries using Styler (#231, h/t @maennchen) # styler:sort
will now sort keys for struct/map typespecs (#213, h/t @rojnwa)
Fixes
- apply alias lifting to snippets with no modules or module directives in them. (#189, @h/t @halfdan)
- fix de-sugaring of syntax-sugared keyword lists whose values weren't atoms in map values (#236, h/t @RisPNG)
- fix mix config sorting mangling floating comment blocks in some cases (#230 again, h/t @ryoung786)
v1.4.2
v1.4.1
Improvements
-
to_timeout/1
rewrites to use the next largest unit in some simple instances# before to_timeout(second: 60 * m) to_timeout(day: 7) # after to_timeout(minute: m) to_timeout(week: 1)
Fixes
- fixed styler raising when encountering invalid function definition ast
v1.4.0
Improvements
Alias Lifting
This release taught Styler to try just that little bit harder when doing alias lifting.
-
general improvements around conflict detection, lifting in more correct places and fewer incorrect places (#193, h/t @jsw800)
-
use knowledge of existing aliases to shorten invocations (#201, h/t me)
example:
alias A.B.C A.B.C.foo()
becomes:
alias A.B.C C.foo()
Struct Updates => Map Updates
1.19 deprecates struct update syntax in favor of map update syntax.
# This
%Struct{x | y}
# Styles to this
%{x | y}
WARNING Double check your diffs to make sure your variable is pattern matching against the same struct if you want to harness 1.19's type checking features. Apologies to folks who hoped Styler would do this step for you <3 (#199, h/t @SteffenDE)
Ex1.17+
- Replace
:timer.units(x)
with the newto_timeout(unit: x)
forhours|minutes|seconds
(This style is only applied if you're on 1.17+)
Fixes
pipes
: handle pipifying when the first arg is itself a pipe:c(a |> b, d)
=>a |> b() |> c(d)
(#214, h/t @kybishop)pipes
: handle pipifying nested functionsd(c(a |> b))
=>a |> b |> c() |> d
(#216, h/t @emkguts)with
: fix a stabbywith
, else: (_ -> :ok)
being rewritten to a case (#219, h/t @iamhassangm)