From 96797276e6a8252d648d215b2f7b51ba39d85a8d Mon Sep 17 00:00:00 2001 From: Matt Enlow Date: Wed, 12 Jun 2024 15:02:58 -0700 Subject: [PATCH] gogogo --- CHANGELOG.md | 3 ++ README.md | 69 +++++++++++++++++++++------------- docs/module_directives.md | 68 ++++++++++++++++++++++++++++++++- docs/troubleshooting.md | 34 ----------------- lib/style/module_directives.ex | 46 ----------------------- mix.exs | 3 +- 6 files changed, 113 insertions(+), 110 deletions(-) delete mode 100644 docs/troubleshooting.md diff --git a/CHANGELOG.md b/CHANGELOG.md index 29f7197..2214937 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,8 @@ # Changelog +**Note** Styler's only public API is its usage as a formatter plugin. While you're welcome to play with its internals, +they can and will change without that change being reflected in Styler's semantic version. + ## main ### Fixes diff --git a/README.md b/README.md index 6431660..986dfd7 100644 --- a/README.md +++ b/README.md @@ -5,11 +5,7 @@ you what's wrong, it just rewrites the code for you to fit its style rules. You can learn more about the history, purpose and implementation of Styler from our talk: [Styler: Elixir Style-Guide Enforcer @ GigCity Elixir 2023](https://www.youtube.com/watch?v=6pF8Hl5EuD4) ------------------------ - -Styler's documentation is under work as part of releasing 1.0. - -You can find the much more complete and usable [0.11.9 documentation and readme here.](https://hexdocs.pm/styler/readme.html) +[See our Rewrites documentation on hexdocs for details on what all Styler does](https://hexdocs.pm/styler/) ## Installation @@ -23,51 +19,70 @@ def deps do end ``` -Please excuse the mess below as I find spare time to update our documentation =) Anything with TODOs are, well, notes to myself on documentation that needs rewriting. Happy to accept PRs if one seems doable to others. - -_@TODO put this somewhere more reasonable_ - -**Note** Styler's only public API is its usage as a formatter plugin. While you're welcome to play with its internals, -they can and will change without that change being reflected in Styler's semantic version. - Then add `Styler` as a plugin to your `.formatter.exs` file ```elixir [ plugins: [Styler] - # optionally: include styler configuration - # , styler: [alias_lifting_excludes: []] ] ``` And that's it! Now when you run `mix format` you'll also get the benefits of Styler's Stylish Stylings. +**Speed**: Expect the first run to take some time as `Styler` rewrites violations of styles and bottlenecks on disk I/O. Subsequent formats formats won't take noticeably more time. + ### Configuration -@TODO document: config for lifting, and why we won't add options other configs +Styler can be configured in your `.formatter.exs` file -Styler is @adobe's internal Style Guide Enforcer - allowing exceptions to the styles goes against that ethos. Happily, it's open source and thus yours to do with as you will =) +```elixir +[ + plugins: [Styler], + styler: [ + alias_lifting_exclude: [...] + ] +] +``` -## Features (or as we call them, "Styles") +Styler's only current configuration option is `:alias_lifting_exclude`, which accepts a list of atoms to _not_ lift. See the [Module Directive documentation](docs/module_directives.md#alias-lifting) for more. -@TODO link examples +#### No Credo-Style Enable/Disable -https://hexdocs.pm/styler/1.0.0-rc.0/styles.html +Styler [will not add configuration](https://github.com/adobe/elixir-styler/pull/127#issuecomment-1912242143) for ad-hoc enabling/disabling of rewrites. Sorry! Its implementation simply does not support that approach. There are however many forks out there that have attempted this; please explore the [Github forks tab](https://github.com/adobe/elixir-styler/forks) to see if there's a project that suits your needs or that you can draw inspiration from. -## Styler & Credo +Ultimately Styler is @adobe's internal tool that we're happy to share with the world. We're delighted if you like it as is, and just as excited if it's a starting point for you to make something even better for yourself. -@TODO link credo doc +## !Styler can change the behaviour of your program! -## Your first Styling +The best example of the way in which Styler changes the meaning of your code is the following rewrite: +```elixir +# Before: this case statement... +case foo do + true -> :ok + false -> :error +end -**Speed**: Expect the first run to take some time as `Styler` rewrites violations of styles. +# After: ... is rewritten by Styler to be an if statement!. +if foo do + :ok +else + :error +end +``` -Once styled the first time, future styling formats shouldn't take noticeably more time. +These programs are not semantically equivalent. The former would raise if `foo` returned any value other than `true` or `false`, while the latter blissfully completes. -## Styler can break your code +However, Styler is about _style_, and the `if` statement is (in our opinion) of much better style. If the exception behaviour was intentional on the code author's part, they should have written the program like this: + +```elixir +case foo do + true -> :ok + false -> :error + other -> raise "expected `true` or `false`, got: #{inspect other}" +end +``` -@TODO link troubleshooting -mention our rewrite of case true false to if and how we're OK with this being _Styler_, not _SemanticallyEquivalentRewriter_. +Also good style! But Styler assumes that most of the time people just meant the `if` equivalent of the code, and so makes that change. If issues like this bother you, Styler probably isn't the tool you're looking for. ## Thanks & Inspiration diff --git a/docs/module_directives.md b/docs/module_directives.md index a308cf3..d772504 100644 --- a/docs/module_directives.md +++ b/docs/module_directives.md @@ -1 +1,67 @@ -## Module Directives (`use`, `import`, `alias`, `require`, ...) +## Adds Moduledoc + +Adds `@moduledoc false` to modules without a moduledoc unless the module's name ends with one of the following: + +* `Test` +* `Mixfile` +* `MixProject` +* `Controller` +* `Endpoint` +* `Repo` +* `Router` +* `Socket` +* `View` +* `HTML` +* `JSON` + +## Directive Expansion + +Expands `Module.{SubmoduleA, SubmoduleB}` to their explicit forms for ease of searching. + +```elixir +# Given +import Foo.{Bar, Baz, Bop} +alias Foo.{Bar, Baz.A, Bop} + +# Styled +import Foo.Bar +import Foo.Baz +import Foo.Bop + +alias Foo.Bar +alias Foo.Baz.A +alias Foo.Bop +``` + +## Directive Organization + +Modules directives are sorted into the following order: + +* `@shortdoc` +* `@moduledoc` (adds `@moduledoc false`) +* `@behaviour` +* `use` +* `import` (sorted alphabetically) +* `alias` (sorted alphabetically) +* `require` (sorted alphabetically) +* everything else (order unchanged) + +```elixir +defmodule OrganizeMe do + +end +``` + +If any line previously relied on an alias, the alias is fully expanded when it is moved above the alias: + +```elixir +# Given +alias Foo.Bar +import Bar +# Styled +import Foo.Bar + +alias Foo.Bar +``` + +## Alias Lifting diff --git a/docs/troubleshooting.md b/docs/troubleshooting.md deleted file mode 100644 index 7daa9d3..0000000 --- a/docs/troubleshooting.md +++ /dev/null @@ -1,34 +0,0 @@ -### Troubleshooting: Compilation broke due to Module Directive rearrangement - -Styler naively moves module attributes, which can break compilation. For now, the only fix is some elbow grease. - -#### Module Attribute dependency - -Another common compilation break on the first run is a `@moduledoc` that depended on another module attribute which -was moved below it. - -For example, given the following broken code after an initial `mix format`: - -```elixir -defmodule MyGreatLibrary do - @moduledoc make_pretty_docs(@library_options) - use OptionsMagic, my_opts: @library_options - - @library_options [ ... ] -end -``` - -You can fix the code by moving the static value outside of the module into a naked variable and then reference it in the module. (Note that `use` macros need an `unquote` wrapping the variable!) - -Yes, this is a thing you can do in a `.ex` file =) - -```elixir -library_options = [ ... ] - -defmodule MyGreatLibrary do - @moduledoc make_pretty_docs(library_options) - use OptionsMagic, my_opts: unquote(library_options) - - @library_options library_options -end -``` diff --git a/lib/style/module_directives.ex b/lib/style/module_directives.ex index aeaeb8c..e385eb9 100644 --- a/lib/style/module_directives.ex +++ b/lib/style/module_directives.ex @@ -27,10 +27,6 @@ defmodule Styler.Style.ModuleDirectives do * `Credo.Check.Readability.UnnecessaryAliasExpansion` * `Credo.Check.Design.AliasUsage` - ## Breakages - - **This can break your code.** - ### Strict Layout Modules directives are sorted into the following order: @@ -43,48 +39,6 @@ defmodule Styler.Style.ModuleDirectives do * `alias` * `require` * everything else (unchanged) - - If any of the sorted directives had a dependency on code that is now below it, your code will fail to compile after being styled. - - For instance, the following will be broken because the module attribute definition will - be moved below the `use` clause, meaning `@pi` is undefined when invoked. - - ```elixir - # before - defmodule Approximation do - @pi 3.14 - use Math, pi: @pi - end - - # after - defmodule Approximation do - @moduledoc false - use Math, pi: @pi - @pi 3.14 - end - ``` - - For now, it's up to you to come up with a fix for this issue. Sorry! - - ### Strict Layout: interwoven conflicting aliases - - Ideally no one writes code like this as it's hard for our human brains to notice the context switching! - Still, it's a possible source of breakages in Styler. - - - alias Foo.Bar - Bar.Baz.bop() - - alias Baz.Bar - Bar.Baz.bop() - - # becomes - - alias Baz.Bar - alias Baz.Bar.Baz - alias Foo.Bar - Baz.bop() # was Foo.Bar.Baz, is now Baz.Bar.Baz - Baz.bop() """ @behaviour Styler.Style diff --git a/mix.exs b/mix.exs index 9075a73..81fb9b9 100644 --- a/mix.exs +++ b/mix.exs @@ -69,8 +69,7 @@ defmodule Styler.MixProject do "docs/mix_configs.md": [title: "Mix Config Files (config/config.exs, ...)"], "docs/module_directives.md": [title: "Module Directives (use, alias, ...)"], "docs/credo.md": [title: "Styler & Credo"], - "README.md": [title: "Styler"], - "docs/troubleshooting.md": [title: "Troubleshooting"], + "README.md": [title: "Styler"] ] ] end