Skip to content

Make it configurable (:grimacing:) #127

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 24 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,10 +29,33 @@ And that's it! Now when you run `mix format` you'll also get the benefits of Sty

### Configuration

There isn't any! This is intentional.
There isn't much! This is intentional.

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 =)

However, it's possible to gradually implement Styler via minimal config in `.formatter.exs` file:

```
[
plugins: [Styler],
styler: [
# List of rules to enable

# Can have a keyword list of options
{Styler.Style.ModuleDirectives, []},

# Or just a module name
Styler.Style.Pipes
]
]
```

By default, if the `styler` key is not present, all rules are enabled.

#### Supported options

* `ignore_prefixes` - a list of file prefixes to skip when applying the rule. Example: `ignore_prefixes: ["test/"]`

## Features (or as we call them, "Styles")

At this point, Styler does a lot. We've catalogued a list of Credo rules that it automatically fixes, but it does some things -
Expand Down
36 changes: 35 additions & 1 deletion lib/styler.ex
Original file line number Diff line number Diff line change
Expand Up @@ -29,11 +29,28 @@ defmodule Styler do
@doc false
def style({ast, comments}, file, opts) do
on_error = opts[:on_error] || :log
enabled_styles = opts[:config] || @styles
zipper = Zipper.zip(ast)
context = %{comments: comments, file: file}

{{ast, _}, %{comments: comments}} =
Enum.reduce(@styles, {zipper, context}, fn style, {zipper, context} ->
enabled_styles
|> Enum.filter(fn
{_style, opts} ->
if Keyword.has_key?(opts, :ignore_prefixes) do
!Enum.any?(opts[:ignore_prefixes], &String.starts_with?(file, Path.join(File.cwd!(), &1)))
else
true
end

_style ->
true
end)
|> Enum.map(fn
{style, _opts} -> style
style -> style
end)
|> Enum.reduce({zipper, context}, fn style, {zipper, context} ->
try do
Zipper.traverse_while(zipper, context, &style.run/2)
rescue
Expand All @@ -56,9 +73,26 @@ defmodule Styler do
@impl Mix.Tasks.Format
def features(_opts), do: [sigils: [], extensions: [".ex", ".exs"]]

@doc """
Options is a list of styles, that can have options, à la credo:

Example `.formatter.exs`:

[
plugins: [Styler],
styler: [
{Styler.Style.ModuleDirectives, ignore_prefixes: ["lib/"]},
{Styler.Style.Pipes, ignore_prefixes: ["test/"]},
]
]

For now, the only config is `ignore_prefixes`, which is a list of file
prefixes to ignore when styling.
"""
@impl Mix.Tasks.Format
def format(input, formatter_opts, opts \\ []) do
file = formatter_opts[:file]
opts = Keyword.put(opts, :config, formatter_opts[:styler])

{ast, comments} =
input
Expand Down
30 changes: 30 additions & 0 deletions test/style/pipes_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -672,4 +672,34 @@ defmodule Styler.Style.PipesTest do
end
end
end

describe "configurable" do
test "filename prefix is ignored" do
assert_style("f(g(h(x))) |> j()", "f(g(h(x))) |> j()", "lib/test.exs",
config: [
{Styler.Style.Pipes, ignore_prefixes: ["lib/"]}
]
)
end

test "filename not in prefix is styled" do
assert_style("f(g(h(x))) |> j()", "x |> h() |> g() |> f() |> j()", "test/test.exs",
config: [
{Styler.Style.Pipes, ignore_prefixes: ["lib/"]}
]
)
end

test "filename prefix is ignored with multiple prefixes" do
assert_style("f(g(h(x))) |> j()", "f(g(h(x))) |> j()", "lib/test.exs",
config: [
{Styler.Style.Pipes, ignore_prefixes: ["lib/", "test/"]}
]
)
end

test "if style is not present, no changes are made" do
assert_style("f(g(h(x))) |> j()", "f(g(h(x))) |> j()", "lib/test.exs", config: [])
end
end
end
17 changes: 10 additions & 7 deletions test/support/style_case.ex
Original file line number Diff line number Diff line change
Expand Up @@ -16,18 +16,18 @@ defmodule Styler.StyleCase do

using do
quote do
import unquote(__MODULE__), only: [assert_style: 1, assert_style: 2, style: 1]
import unquote(__MODULE__), only: [assert_style: 1, assert_style: 2, assert_style: 3, assert_style: 4, style: 3]
end
end

defmacro assert_style(before, expected \\ nil) do
defmacro assert_style(before, expected \\ nil, filename \\ "testfile", opts \\ []) do
expected = expected || before

quote bind_quoted: [before: before, expected: expected] do
quote bind_quoted: [before: before, expected: expected, filename: filename, opts: opts] do
alias Styler.Zipper

expected = String.trim(expected)
{styled_ast, styled, styled_comments} = style(before)
{styled_ast, styled, styled_comments} = style(before, filename, opts)

if styled != expected and ExUnit.configuration()[:trace] do
IO.puts("\n======Given=============\n")
Expand Down Expand Up @@ -89,7 +89,7 @@ defmodule Styler.StyleCase do
end)

assert expected == styled
{_, restyled, _} = style(styled)
{_, restyled, _} = style(styled, filename, opts)

assert restyled == styled, """
expected styling to be idempotent, but a second pass resulted in more changes.
Expand All @@ -107,9 +107,12 @@ defmodule Styler.StyleCase do
end
end

def style(code) do
def style(code, filename, opts) do
{ast, comments} = Styler.string_to_quoted_with_comments(code)
{styled_ast, comments} = Styler.style({ast, comments}, "testfile", on_error: :raise)

opts = Keyword.put(opts, :on_error, :raise)

{styled_ast, comments} = Styler.style({ast, comments}, Path.join(File.cwd!(), filename), opts)

try do
styled_code = styled_ast |> Styler.quoted_to_string(comments) |> String.trim_trailing("\n")
Expand Down