Skip to content

Commit

Permalink
module directives
Browse files Browse the repository at this point in the history
  • Loading branch information
novaugust committed Jun 12, 2024
1 parent 9679727 commit 1d1542e
Show file tree
Hide file tree
Showing 2 changed files with 137 additions and 4 deletions.
25 changes: 24 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,30 @@ 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)

[See our Rewrites documentation on hexdocs for details on what all Styler does](https://hexdocs.pm/styler/)
## Features

- auto-fixes [many credo rules](docs/credo.md), meaning you can turn them off to speed credo up
- [keeping a strict module layout](docs/module_directives.md#directive-organization)
- alphabetizing module directives
- [extracting repeated aliases](docs/moduledirectives.md#alias-lifting)
- piping and unpiping function calls based on the number of functons
- optimizing standard library calls (`a |> Enum.map(m) |> Enum.into(Map.new)` => `Map.new(a, m)`)
- using sigils for strings with many escaped quotes `\"`
- ... and so many other things.

[See our Rewrites documentation on hexdocs for all the nitty-gritty on what all Styler does](https://hexdocs.pm/styler/)

## Who is Styler for?

Styler was designed for a large team (40+ engineers) working in a single codebase. It helps remove fiddly code review comments and removes failed linter CI slowdowns, helping teams get things done faster. Teams in similar situations might appreciate Styler.

Its automations are also extremely valuable for taming legacy elixir codebases or just refactoring in general. Some of its rewrites have inspired code actions in elixir language servers.

Conversely, Styler probably _isn't_ a good match for:

- libraries
- experimental, macro-heavy codebases
- small teams that don't want to think about code standards

## Installation

Expand Down
116 changes: 113 additions & 3 deletions docs/module_directives.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,11 @@ Adds `@moduledoc false` to modules without a moduledoc unless the module's name
Expands `Module.{SubmoduleA, SubmoduleB}` to their explicit forms for ease of searching.

```elixir
# Given
# Before
import Foo.{Bar, Baz, Bop}
alias Foo.{Bar, Baz.A, Bop}

# Styled
# After
import Foo.Bar
import Foo.Baz
import Foo.Bop
Expand All @@ -46,9 +46,87 @@ Modules directives are sorted into the following order:
* `require` (sorted alphabetically)
* everything else (order unchanged)

### Before

```elixir
defmodule Foo do
@behaviour Lawful
alias A.A
require A

use B

def c(x), do: y

import C
@behaviour Chaotic
@doc "d doc"
def d do
alias X.X
alias H.H

alias Z.Z
import Ecto.Query
X.foo()
end
@shortdoc "it's pretty short"
import A
alias C.C
alias D.D

require C
require B

use A

alias C.C
alias A.A

@moduledoc "README.md"
|> File.read!()
|> String.split("<!-- MDOC !-->")
|> Enum.fetch!(1)
end
```

### After

```elixir
defmodule OrganizeMe do
defmodule Foo do
@shortdoc "it's pretty short"
@moduledoc "README.md"
|> File.read!()
|> String.split("<!-- MDOC !-->")
|> Enum.fetch!(1)
@behaviour Chaotic
@behaviour Lawful

use B
use A.A

import A.A
import C

alias A.A
alias C.C
alias D.D

require A
require B
require C

def c(x), do: y

@doc "d doc"
def d do
import Ecto.Query

alias H.H
alias X.X
alias Z.Z

X.foo()
end
end
```

Expand All @@ -65,3 +143,35 @@ alias Foo.Bar
```

## Alias Lifting

When a module with three parts is referenced two or more times, styler creates a new alias for that module and uses it.

```elixir
# Given
require A.B.C

A.B.C.foo()
A.B.C.bar()

# Styled
alias A.B.C

require C

C.foo()
C.bar()
```

### Collisions

Styler won't lift aliases that will collide with existing aliases, and likewise won't lift any module whose name would collide with a standard library name.

You can specify additional modules to exlude from lifting via the `:alias_lifting_exclude` configuration option. For the example above, the following configuration would keep Styler from creating the `alias A.B.C` node:

```elixir
# .formatter.exs
[
plugins: [Styler],
styler: [alias_lifting_exclude: [:C]],
]
```

0 comments on commit 1d1542e

Please sign in to comment.