Skip to content

Update dependency styler to v1 - #24

Open
renovate[bot] wants to merge 1 commit into
masterfrom
renovate/styler-1.x
Open

renovate[bot] wants to merge 1 commit into
masterfrom
renovate/styler-1.x

Conversation

@renovate

@renovate renovate Bot commented Oct 9, 2026

Copy link
Copy Markdown

This PR contains the following updates:

Package Type Update Change
styler (source) dev major ~> 0.11 → ~> 1.0

Release Notes

adobe/elixir-styler (styler)

v1.12.2

Compare Source

Fixes
  • also leave piped versions of the shift + microsecond bug alone (|> DateTime.add(val, :microsecond) (#​256, h/t @​zvlasic)

v1.12.1

Compare Source

Fixes
  • leave DateTime.add(dt, val, :microsecond) untouched since DateTime.shift with microseconds requires a precision (#​255, h/t @​janpieper)

v1.12.0

Compare Source

Improvements
  • Pipes:
    • don't unpipe |> dbg, to help our friends who format-on-save and like throwing a quick dbg pipe in while debugging (h/t @​mhanberg)
    • optimize two DateTime.shift |> DateTime.shift into a single DateTime.shift when working with literal durations whose keys are disjoint
  • Write "not equal" one way only: not (a == b), !(a == b) => a != b (#​251, h/t @​tomkonidas)
  • Deprecations: DateTime.add(dt, amount, unit) is rewritten to DateTime.shift(dt, unit: amount) for 1.17+ codebases. While not technically deprecated, Elixir docs recommend shift over add (#​253, h/t @​tomkonidas)
  • DateTime.shift(dt, ..duration pairs..) now has its duration pairs shrunk like to_timeout
  • duration pair shrinking improved for precomputed values, for instance second: 86_400 => day: 1
Fixes
  • General improvements to comment handling across Styler (#​254, h/t me and claude)
  • Fixed explicit-keyword-list merges not being rewritten to puts: Map/Keyword.merge([single: :key]) => Map/Keyword.put(:single, :key)

v1.11.0

Compare Source

Improvements
  • mix styler.inline_attrs: Allow multiple file paths to be specified: mix styler.inline_attrs <file1> [<file2> ...]
Module Directive References

Module directives got smarter. Styler will no longer move module attributes below their references in use or @moduledocs.

In other words, Styler will leave the following code untouched:

defmodule MyGreatLibrary do
  @library_options [...]
  @moduledoc make_pretty_docs(@library_options)
  use OptionsMagic, my_opts: @library_options
end

v1.10.1

Compare Source

Improvements

Adds two experimental refactoring features as mix tasks.

mix styler.remove_unused

With Elixir 1.20 on the horizon, many projects are about to discover that they have a lot of unnecessary require Logger lines throughout their codebase.

mix styler.remove_unused will automate the removal of those unused require: statements, alongside any unused import: and unused alias: warnings.

This has long been an internal script useful for running after a bigger refactor that resulted in many superfluous aliases, but with 1.20 coming it seems it might be useful for others as well.

This will never be an integrated part of Styler's format plugin features, as it would not be correct to remove unused nodes whenever running format. It's typical to have unused warnings while in the midst of an implementation, and deleting that code would be obnoxious.

mix styler.inline_attrs <file>

Inlines one-off module attributes that define literal values.

This is something that sometimes is good, and sometimes is bad. In general, defining a module attribute when you could've just written an atom is bad, so inlining is good!

It would probably be most useful as a refactor ability for a language server, but CLIs are a nice second place.

An example of a situation where it results in an improvement:

# Unnecessary indirection with single-use literal-value module attributes
defmodule A do
  @http_client_key :http_key
  @default_client MyHTTPClient

  def http_client, do: Application.get_env(:my_app, @http_client_key, @default_client)
end

# Much better! styler.inline_attrs will perform this refactor
defmodule A do
  def http_client, do: Application.get_env(:my_app, :http_key, MyHTTPClient)
end

It's worthwhile to run this on some suspicious files, then followup with manual intervention when it went too far. This style is not aware of quote boundaries, and so might do some broken things. (Hence "EXPERIMENTAL")

You've been warned =)

v1.10.0

Compare Source

Improvements

Two new standard-library pipe optimizations

  • enum |> Enum.map(fun) |> Enum.intersperse(separator) => Enum.map_intersperse(enum, separator, fun)
  • enum |> Enum.sort() |> Enum.reverse() => Enum.sort(enum, :desc)

And Req (the http client library) pipe optimizations, as detailed below

Req pipe optimizations

Req is a popular HTTP Client. If you aren't using it, you can just ignore this whole section!

Reqs 1-arity "execute the request" functions (delete get head patch post put request run) have a 2-arity version that takes a superset of the arguments Req.new/1 does as its first argument, and the typical options keyword list as its second argument. And so, many places developers are calling a 1-arity function can be replaced with a 2-arity function.

More succinctly, these two statements are equivalent:

  • foo |> Req.new() |> Req.merge(bar) |> Req.post!()
  • Req.post!(foo, bar)

Styler now rewrites the former to the latter, since "less is more" or "code is a liability".

It also rewrites |> Keyword.merge(bar) |> Req.foo() to |> Req.foo(bar). This changes the program's behaviour, since Keyword.merge would overwrite existing values in all cases, whereas Req 2-arity functions intelligently deep-merge values for some keys, like :headers.

v1.9.1

Compare Source

Fix
  • fixes rewrites of single-clause case statement with assignment parent (Closes #​247, h/t @​vasspilka)

v1.9.0

Compare Source

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)

v1.8.0

Compare Source

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

Compare Source

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

Compare Source

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 due to refute passing for both nil and false.

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

Compare Source

Fixes
  • alias lifting: handle comments in snippets with no existing directives (#​239, h/t @​kerryb)

v1.5.0

Compare Source

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

Compare Source

Fixes
  • fix comment misplacement for large comment blocks in config files and # styler:sort (#​230, h/t @​cschmatzler)

v1.4.1

Compare Source

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

Compare Source

  • A very nice change in alias lifting means Styler will make sure that your code is using the aliases that it's specified.
  • Shoutout to the smartrent folks for finding pipifying recursion issues
  • Elixir 1.17 improvements and fixes
  • Elixir 1.19-dev: delete struct updates

Read on for details.

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()
      A.B.C.bar()
      A.B.C.baz()
    

    becomes:

      alias A.B.C
    
      C.foo()
      C.bar()
      C.baz()
    
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 new to_timeout(unit: x) for hours|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 functions d(c(a |> b)) => a |> b |> c() |> d (#​216, h/t @​emkguts)
  • with: fix a stabby with , else: (_ -> :ok) being rewritten to a case (#​219, h/t @​iamhassangm)

v1.3.3

Compare Source

Improvements
  • with do: body and variations with no arrows in the head will be rewritten to just body

  • # styler:sort will sort arbitrary ast nodes within a do end block:

    Given:

styler:sort

    my_macro "some arg" do
      another_macro :q
      another_macro :w
      another_macro :e
      another_macro :r
      another_macro :t
      another_macro :y
    end

We get

styler:sort

    my_macro "some arg" do
      another_macro :e
      another_macro :q
      another_macro :r
      another_macro :t
      another_macro :w
      another_macro :y
    end
Fixes
  • fix a bug in comment-movement when multiple # styler:sort directives are added to a file at the same time

v1.3.2

Compare Source

Improvements
  • # styler:sort can be used to sort values of key-value pairs. eg, sort the value of a single key in a map (Closes #​208, h/t @​ypconstante)

v1.3.1

Compare Source

Improvements
  • # styler:sort now works with maps and the defstruct macro
Fixes
  • # styler:sort no longer blows up on keyword lists :X

v1.3.0

Compare Source

Improvements
# styler:sort Styler's first comment directive

Styler will now keep a user-designated list or wordlist (~w sigil) sorted as part of formatting via the use of comments. Elements of the list are sorted by their string representation.

The intention is to remove comments to humans, like # Please keep this list sorted!, in favor of comments to robots: # styler:sort. Personally speaking, Styler is much better at alphabetical-order than I ever will be.

To use the new directive, put it on the line before a list or wordlist.

This example:

# styler:sort
[:c, :a, :b]

# styler:sort
~w(a list of words)

# styler:sort
@country_codes ~w(
  en_US
  po_PO
  fr_CA
  ja_JP
)

# styler:sort
a_var =
  [
    Modules,
    In,
    A,
    List
  ]

Would yield:

# styler:sort
[:a, :b, :c]

# styler:sort
~w(a list of words)

# styler:sort
@country_codes ~w(
  en_US
  fr_CA
  ja_JP
  po_PO
)

# styler:sort
a_var =
  [
    A,
    In,
    List,
    Modules
  ]

v1.2.1

Compare Source

Fixes
  • |> don't pipify when the call is itself in a pipe (aka don't touch a |> b(c |> d() |>e()) |> f()) (Closes #​204, h/t @​paulswartz)

v1.2.0

Compare Source

Improvements
  • pipes: pipe-ifies when first arg to a function is a pipe. reach out if this happens in unstylish places in your code (Closes #​133)
  • pipes: unpiping assignments will make the assignment one-line when possible (Closes #​181)
  • deprecations: 1.18 deprecations
    • List.zip => Enum.zip
    • first..last = range => first..last//_ = range
Fixes
  • pipes: optimizations are less likely to move comments (Closes #​176)

v1.1.2

Compare Source

Improvements
  • Config Sorting: improve comment handling when only sorting a few nodes (Closes #​187)

v1.1.1

Compare Source

Improvements
  • unless: rewrite unless a |> b |> c as unless !(a |> b() |> c()) rather than unless a |> b() |> c() |> Kernel.!() (h/t @​gregmefford)

v1.1.0

Compare Source

Improvements

The big change here is the rewrite/removal of unless due to unless "eventually" being deprecated. Thanks to @​janpieper and @​ypconstante for bringing this up in #​190.

  • unless: rewrite all unless to if (#​190)
  • pipes: optimize |> Stream.{each|map}(fun) |> Stream.run() to |> Enum.each(fun)
Fixes
  • pipes: optimizations reducing 2 pipes to 1 no longer squeeze all pipes onto one line (#​180)
  • if: fix infinite loop rewriting negated if with empty do body if x != y, do: (), else: :ok (#​196, h/t @​itamm15)

v1.0.0

Compare Source

Styler's two biggest outstanding bugs have been fixed, both related to compilation breaking during module directive organization. One was references to aliases being moved above where the aliases were declared, and the other was similarly module directives being moved after their uses in module directives.

In both cases, Styler is now smart enough to auto-apply the fixes we recommended in the old Readme.

Other than that, a slew of powerful new features have been added, the neatest one (in the author's opinion anyways) being Alias Lifting.

Thanks to everyone who reported bugs that contributed to all the fixes released in 1.0.0 as well.

Improvements
Alias Lifting

Along the lines of Credo.Check.Design.AliasUsage, Styler now "lifts" deeply nested aliases (depth >= 3, ala A.B.C....) that are used more than once.

Put plainly, this code:

defmodule A do
  def lift_me() do
    A.B.C.foo()
    A.B.C.baz()
  end
end

will become

defmodule A do
  @moduledoc false
  alias A.B.C

  def lift_me do
    C.foo()
    C.baz()
  end
end

To exclude modules ending in .Foo from being lifted, add styler: [alias_lifting_exclude: [Foo]] to your .formatter.exs

Module Attribute Lifting

A long outstanding breakage of a first pass with Styler was breaking directives that relied on module attributes which Styler moved after their uses. Styler now detects these potential breakages and automatically applies our suggested fix, which is creating a variable before the module. This usually happened when folks were using a library that autogenerated their moduledocs for them.

In code, this module:

defmodule MyGreatLibrary do
  @library_options [...]
  @moduledoc make_pretty_docs(@library_options)
  use OptionsMagic, my_opts: @library_options

  ...
end

Will now be styled like so:

library_options = [...]

defmodule MyGreatLibrary do
  @moduledoc make_pretty_docs(library_options)
  use OptionsMagic, my_opts: unquote(library_options)

  @library_options library_options

  ...
end
Mix Config File Organization

Styler now organizes Mix.Config.config/2,3 stanzas according to erlang term sorting. This helps manage large configuration files, removing the "where should I put this" burden from developers AND helping find duplicated configuration stanzas.

See the moduledoc for Styler.Style.Configs for more.

Pipe Optimizations
  • Enum.into(x, []) => Enum.to_list(x)
  • Enum.into(x, [], mapper) => Enum.map(x, mapper)
  • a |> Enum.map(m) |> Enum.join() to map_join(a, m). we already did this for join/2, but missed the case for join/1
  • lhs |> Enum.reverse() |> Kernel.++(enum) => lhs |> Enum.reverse(enum)
with styles
  • remove with structure with no left arrows in its head to be normal code (#​174)
  • with true <- x(), do: y => if x(), do: y (#​173)
Everything Else
  • if/unless: invert if and unless with != or !==, like we do for ! and not #​132
  • @derive: move @derive before defstruct|schema|embedded_schema declarations (fixes compiler warning!) #​134
  • strings: rewrite double-quoted strings to use ~s when there's 4+ escaped double-quotes
    ("\"\"\"\"" -> ~s("""")) (Credo.Check.Readability.StringSigils) #​146
  • Map.drop(foo, [single_key]) => Map.delete(foo, single_key) #​161 (also in pipes)
  • Keyword.drop(foo, [single_key]) => Keyword.delete(foo, single_key) #​161 (also in pipes)
Fixes
  • don't blow up on def function_head_with_no_body_nor_parens (#​185, h/t @​ypconstante)
  • fix with arrow replacement + redundant body removal creating invalid statements (#​184, h/t @​JesseHerrick)
  • allow Kernel unary ! and not as valid pipe starts (#​183, h/t @​nherzing)
  • fix Map.drop(x, [a | b]) registering as a chance to refactor to Map.delete
  • alias: expands aliases when moving an alias after another directive that relied on it (#​137)
  • module directives: various fixes for unreported obscure crashes
  • pipes: fix a comment-shifting scenario when unpiping
  • Timex.now/1 will no longer be rewritten to DateTime.now!/1 due to Timex accepting a wider domain of "timezones" than the stdlib (#​145, h/t @​ivymarkwell)
  • with: skip nodes which (unexpectedly) do not contain a do body (#​158, h/t @​DavidB59)
  • then(&fun/1): fix false positives on arithmetic &1 + x / 1 (#​164, h/t @​aenglisc)
Breaking Changes
  • drop support for elixir 1.14
  • ModuleDirectives: group callback attributes (before_compile after_compile after_verify) with nondirectives (previously, were grouped with use, their relative order maintained). to keep the desired behaviour, you can make new use macros that wrap these callbacks. Apologies if this makes using Styler untenable for your codebase, but it's probably not a good tool for macro-heavy libraries.
  • sorting configs for the first time can change your configuration; see Mix Configs docs for more

Configuration

📅 Schedule: (UTC)

  • Branch creation
    • At any time (no schedule defined)
  • Automerge
    • At any time (no schedule defined)

🚦 Automerge: Disabled by config. Please merge this manually once you are satisfied.

♻ Rebasing: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox.

🔕 Ignore: Close this PR and you won't be reminded about this update again.


  • If you want to rebase/retry this PR, check this box

This PR was generated by Mend Renovate. View the repository job log.

@renovate

renovate Bot commented Oct 9, 2026

Copy link
Copy Markdown
Author

⚠️ Artifact update problem

Renovate failed to update an artifact related to this branch. You probably do not want to merge this PR as-is.

♻ Renovate will retry this branch, including artifacts, only when one of the following happens:

  • any of the package files in this branch needs updating, or
  • the branch becomes conflicted, or
  • you click the rebase/retry checkbox if found above, or
  • you rename this PR's title to start with "rebase!" to trigger it manually

The artifact failure details are included below:

File name: mix.lock
/usr/local/bin/mix: line 18: /opt/containerbase/tools/elixir/1.20.4/bin/mix: No such file or directory

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

0 participants