Skip to content

Latest commit

 

History

History
617 lines (364 loc) · 17.6 KB

CHANGELOG.md

File metadata and controls

617 lines (364 loc) · 17.6 KB

Changelog

main

Fixes

  • rewrite 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

1.0.0-rc.0

At this point, 1.0.0 feels feature complete. Two things remains for a full release:

  1. feedback!
  2. documentation overhaul! monitor progress here

Improvements

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.

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.

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)
  • lhs |> Enum.reverse() |> Kernel.++(enum) => lhs |> Enum.reverse(enum)

Fixes

  • 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 Styler.Style.Configs moduledoc for more

v0.11.9

Improvements

  • pipes: check for Stream.foo equivalents to Enum.foo in a few more cases

Fixes

  • pipes: |> then(&(&1 op y)) rewrites with |> Kernel.op(y) as long as the operator is defined in Kernel; skips the rewrite otherwise (h/t @kerryb for the report & @saveman71 for the fix)

v0.11.8

Two releases in one day!? @koudelka made too good a point about Map.new not being special...

Improvements

  • pipes: treat MapSet.new and Keyword.new the same way we do Map.new (h/t @koudelka)
  • pipes: treat Stream.map the same as Enum.map when piped |> Enum.into

v0.11.7

Improvements

  • deprecations: ~R -> ~r, Date.range/2 -> Date.range/3 with decreasing dates (h/t @milmazz)
  • if: rewrite if not x, do: y => unless x, do: y
  • pipes: |> Enum.map(foo) |> Map.new() => |> Map.new(foo)
  • pipes: remove unnecessary then/2 on named function captures: |> then(&foo/1) => |> foo(), |> then(&foo(&1, ...)) => |> foo(...) (thanks to @tfiedlerdejanze for the idea + impl!)

v0.11.6

Fixes

  • directives: maintain order of module compilation callbacks (@before_compile etc) relative to use statements (Closes #120, h/t @frankdugan3)

v0.11.5

Fixes

  • fix parsing ranges with non-trivial integer bounds like x..y (Closes #119, h/t @maennchen)

v0.11.4

Improvements

Shoutout @milmazz for all the deprecation work below =)

  • Deprecations: Rewrite 1.16 Deprecations (h/t @milmazz for all the work here)
    • add //1 step to Enum.slice/2|String.slice/2 with decreasing ranges
    • File.stream!(file, options, line_or_bytes) => File.stream!(file, line_or_bytes, options)
  • Deprecations Path.safe_relative_to/2 => Path.safe_relative/2

v0.11.3

Fixes

  • directives: fix infinite loop when encountering @spec import(...) :: ... (Closes #115, h/t @kerryb)
  • with: fix deletion of arrow-less with statements within function invocations

v0.11.2

Fixes

  • pipes: fix unpiping do-blocks into variables when the parent expression is a function invocation like a(if x do y end |> z(), b) (Closes #114, h/t @wkirschbaum)

v0.11.1

Fixes

  • with: fix with replacement when it's the only child of a do or -> block (Closes #107, h/t @kerryb -- turns out those edge cases did exist in the wild!)

v0.11.0

Improvements

Comments

Styler will no longer make comments jump around in any situation, and will move comments with the appropriate node in all cases but module directive rearrangement (where they'll just be left behind - sorry! we're still working on it).

  • Keep comments in logical places when rewriting if/unless/cond/with (#79, #97, #101, #103)

With Statements

This release has a slew of improvements for with statements. It's not surprising that there's lots of style rules for with given that just about any case, if, or even cond do could also be expressed as a with. They're very powerful! And with great power...

  • style trivial pattern matches ala lhs <- rhs to lhs = rhs (#86)
  • style _ <- rhs to rhs
  • style keyword , do: to do end rather than wrapping multiple statements in parens
  • style statements all the way to if statements when appropriate (#100)

Other

  • Rewrite {Map|Keyword}.merge(single_key: value) to use put/3 instead (#96)

Fixes

  • with: various edge cases we can only hope no one's encountered and thus never reported

v0.10.5

After being bitten by two of them in a row, Styler's test suite now makes sure that there are no idempotency bugs as part of its tests.

In short, we now have assert style(x) == style(style(x)) as part of every test. Sorry for not thinking to include this before :)

Fixes

  • alias: fix single-module alias deletion newlines bug
  • comments: ensure all generated nodes always include line meta (#101)

v0.10.4

Improvements

  • alias: delete noop single-module aliases (alias Foo, #87, h/t @mgieger)

Fixes

  • pipes: unnest all pipe starts in one pass (f(g(h(x))) |> j() => x |> h() |> g() |> f() |> j(), #94, h/t @tomjschuster)

v0.10.3

Improvements

  • charlists: leave charlist rewriting to elixir's formatter on elixir >= 1.15

Fixes

  • charlists: rewrite empty charlist to use sigil ('' => ~c"")
  • pipes: don't blow up extracting fully-qualified macros (Foo.bar do end |> foo(), #91, h/t @NikitaNaumenko)

v0.10.2

Improvements

  • with: remove identity singleton else clause (eg else {:error, e} -> {:error, e} end, else error -> error end)

v0.10.1

Fixes

  • Fix function head shrink-failures causing comments to jump into blocks (Closes #67, h/t @APB9785)

v0.10.0

Improvements

  • hoist all block-starts to pipes to their own variables (makes styler play better with piped macros)

Fixes

  • fix pipes starting with a macro do-block creating invalid ast (#83, h/t @mhanberg)

v0.9.7

Fixes

  • rewrite pipes starting with quote blocks like we do with case|if|cond|with blocks (#82, h/t @SteffenDE)

v0.9.6

Breaking Change

  • removed mix style task

v0.9.5

Fixes

  • fix mistaking Timex.now/1 in a pipe for Timex.now/0 (#66, h/t @sabiwara)

Removed style

  • stop rewriting Timex.today/0 given that we allow Timex.today/1 -- too inconsistent.

v0.9.4

Improvements

  • if statements: drop else clauses whose body is simply nil

v0.9.3

Fixes

  • fix unless a do b else c end rewrites to if not flopping do/else bodies! (#77, h/t @jcowgar)
  • fix pipes styling ranges with steps (a..b//c) incorrectly (#76, h/t @cschmatzler)

v0.9.2

Fixes

  • fix exception styling module attributes named @def (we confused them with real defs, whoops!) (#75, h/t @randycoulman)

v0.9.1

the boolean blocks edition!

Improvements

  • auto-fix Credo.Check.Refactor.CondStatements (detects any truthy atom, not just true)
  • if/unless rewrites:
    • Credo.Check.Refactor.NegatedConditionsWithElse
    • Credo.Check.Refactor.NegatedConditionsInUnless
    • Credo.Check.Refactor.UnlessWithElse

v0.9.0

the with statement edition!

Improvements

  • Added right-hand-pattern-matching rewrites to for and with left arrow expressions <- (ex: with map = %{} <- foo() => with %{} = map <- foo)
  • with statement rewrites, solving the following credo rules
    • Credo.Check.Readability.WithSingleClause
    • Credo.Check.Refactor.RedundantWithClauseResult
    • Credo.Check.Refactor.WithClauses

v0.8.5

Fixes

  • Fixed exception when encountering non-arrowed case statements ala case foo, do: unquote(quoted) (#69, h/t @brettinternet, nice)

v0.8.4

Fixes

  • Timex related fixes (#66):
    • Rewrite Timex.now/1 to DateTime.now!/1 instead of DateTime.utc_now/1
    • Only rewrite Timex.today/0, don't change Timex.today/1

v0.8.3

Improvements

  • DateTime rewrites (#62, ht @milmazz)
    • DateTime.compare => DateTime.{before/after} (elixir >= 1.15)
    • Timex.now => DateTime.utc_now
    • Timex.today => Date.utc_today

Fixes

  • Pipes: add !=, !==, ===, and, and or to list of valid infix operators (#64)

v0.8.2

Fixes

  • Pipes always de-sugars keyword lists when unpiping them (#60)

v0.8.1

Fixes

  • ModuleDirectives doesn't mistake variables for directives (#57, h/t @leandrocp)

v0.8.0

Improvements (Bug Fix!?)

  • ModuleDirectives no longer throws comments around a file when hoisting directives up (#53)

v0.7.14

Improvements

  • rewrite Logger.warn/1,2 to Logger.warning/1,2 due to Elixir 1.15 deprecation

v0.7.13

Fixes

  • don't unpipe single-piped unquote expressions (h/t @elliottneilclark)

v0.7.12

Fixes

  • fix 0-arity paren removal on metaprogramming creating uncompilable code (h/t @simonprev)

v0.7.11

Fixes

  • fix crash from mix style running plugins as part of formatting (no longer runs formatter plugins)

Improvements

  • single-quote charlists are rewritten to use the ~c sigil ('foo' -> ~c'foo') (h/t @fhunleth)
  • mix style warns the user that Styler is primarily meant to be used as a plugin

v0.7.10

Fixes

  • fix crash when encountering single-quote charlists (h/t @fhunleth)

Improvements

  • single-quote charlists are rewritten to use the ~c sigil ('foo' -> ~c'foo')
  • when encountering _ = bar ->, replace it with bar ->

v0.7.9

Fixes

  • Fix a toggle state resulting from (ahem, nonsense) code like _ = bar -> encountering ParameterPatternMatching style

v0.7.8

Fixes

  • Fix crash trying to remove 0-arity parens from metaprogramming ala def unquote(foo)()

v0.7.7

Improvements

  • Rewrite Enum.into/2,3 into Map.new/1,2 when the collectable is %{} or Map.new/0

v0.7.6

Fixes

v0.7.5

Fixes

  • Fix bug from ParameterPatternMatching implementation that re-ordered pattern matching in cond do -> clauses

v0.7.4

Features

  • Implement Credo.Check.Readability.PreferImplicitTry
  • Implement Credo.Check.Consistency.ParameterPatternMatching for def|defp|fn|case

v0.7.3

Features

  • Remove parens from 0-arity function definitions (Credo.Check.Readability.ParenthesesOnZeroArityDefs)

v0.7.2

Features

  • Rewrite case ... true -> ...; _ -> ... to if statements as well

v0.7.1

Features

  • Rewrite case ... true / else -> to be if statements

v0.7.0

Features

  • Styler.Style.Simple:
    • Optimize Enum.reverse(foo) ++ bar to Enum.reverse(foo, bar)
  • Styler.Style.Pipes:
    • Rewrite |> (& ...).() to |> then(& ...) (Credo.Check.Readability.PipeIntoAnonymousFunctions)
    • Add parens to 1-arity pipe functions (Credo.Check.Readability.OneArityFunctionInPipe)
    • Optimize a |> Enum.reverse() |> Enum.concat(enum) to Enum.reverse(a, enum)

v0.6.1

Improvements

  • Better error handling: mix format will still format files if a style fails

Fixes

  • mix style: only run on .ex and .exs files
  • ModuleDirectives: now expands alias __MODULE__.{A, B} (h/t @adriankumpf)

v0.6.0

Features

  • mix style: brought back to life for folks who want to incrementally introduce Styler

Fixes

  • Styler.Style.Pipes:
    • include x in y and ^foo (for ecto) as a valid pipe starts
    • work even harder to keep rewrites on one line

v0.5.2

Fixes

  • ModuleDirectives: handle dynamic module names
  • Pipes: include Ecto.Query.from and Query.from as valid pipe starts

v0.5.1

Improvements

  • Sped up styling just a little bit

v0.5.0

Improvements

  • Styler now implements Mix.Task.Format, meaning it is now an Elixir formatter plugin. See the README for new installation & usage instructions

Breaking Change! Wooo!

  • the mix style task has been removed

v0.4.1

Improvements

  • Pipes rewrites |> Enum.into(%{}[, mapper]) and Enum.into(Map.new()[, mapper]) to Map.new/1,2 calls

v0.4.0

Improvements

  • Pipes rewrites some two-step processes into one, fixing these credo issues in pipe chains:
    • Credo.Check.Refactor.FilterCount
    • Credo.Check.Refactor.MapJoin
    • Credo.Check.Refactor.MapInto

Fixes

  • ModuleDirectives handles even weirder places to hide your aliases (anonymous functions, in this case)
  • Pipes tries even harder to keep single-pipe rewrites of invocations on one line

v0.3.1

Fixes

  • Pipes
    • fixed omission of == as a valid pipe start operator (h/t @peake100 for the issue)
    • fixed rewrite of a |> b, where b was invoked without parenthesis

v0.3.0

Improvements

  • Enabled Defs style and overhauled it to properly handles comments
  • Optimized and tweaked ModuleDirectives style
    • Now culls newlines between "groups" of the same directive
    • sorts @behaviour directives
    • orders directives within non defmodule contexts (eg, a def do) if there's at least one alias|require|use|import

Fixes

  • Pipes will try to keep single-pipe rewrites on one line

v0.2.0

Improvements

  • Added ModuleDirectives style
    • Note that this is potentially destructive in some rare cases. See moduledoc for more.
    • This supersedes the Aliases style, which has been removed.
  • mix style - reads and writes to stdin/stdout

Fixes

  • Pipes style is now aware of unless blocks

v0.1.1

Improvements

  • Lots of README tweaking =)
  • Optimized some Zipper operations
  • Added Simple style, replacing the following Credo rule:
    • Credo.Check.Readability.LargeNumbers

Fixes

  • Exceptions while parsing code now appropriately render filename rather than nofile:xx
  • Fixed opaque Zipper.path() typespec implementation mismatches (thanks @sega-yarkin)
  • Made ex_doc dev only, removing it as a dependency for users of Styler

v0.1.0

Improvements

  • Initial release of Styler
  • Added Aliases style, replacing the following Credo rules:
    • Credo.Check.Readability.AliasOrder
    • Credo.Check.Readability.MultiAlias
    • Credo.Check.Readability.UnnecessaryAliasExpansion
  • Added Pipes style, replacing the following Credo rules:
    • Credo.Check.Readability.BlockPipe
    • Credo.Check.Readability.SinglePipe
    • Credo.Check.Refactor.PipeChainStart
  • Added Defs style (currently disabled by default)