Packages
styler
1.3.0
1.11.0
1.10.1
1.10.0
1.9.1
1.9.0
1.8.0
1.7.0
1.6.0
1.5.1
1.5.0
1.4.2
1.4.1
1.4.0
1.3.3
1.3.2
1.3.1
1.3.0
1.2.1
1.2.0
1.1.2
1.1.1
1.1.0
1.0.0
1.0.0-rc.2
1.0.0-rc.1
1.0.0-rc.0
1.0.0-alpha.0
0.11.9
0.11.8
0.11.7
0.11.6
0.11.5
0.11.4
0.11.3
0.11.2
0.11.1
0.11.0
0.10.5
0.10.4
retired
0.10.3
0.10.2
0.10.1
0.10.0
0.9.7
0.9.6
0.9.5
0.9.4
0.9.3
0.9.2
retired
0.9.1
retired
0.9.0
0.8.5
0.8.4
0.8.3
0.8.2
0.8.1
0.8.0
0.7.14
0.7.13
0.7.12
0.7.11
0.7.10
0.7.9
0.7.8
0.7.7
0.7.6
0.7.5
0.7.4
0.7.3
0.7.2
0.7.1
0.7.0
0.6.1
0.6.0
0.5.2
0.5.1
0.5.0
0.4.1
0.4.0
0.3.1
0.3.0
0.2.0
0.1.1
0.1.0
A code-style enforcer that will just FIFY instead of complaining
Current section
Files
Jump to
Current section
Files
lib/style/configs.ex
# Copyright 2024 Adobe. All rights reserved.
# This file is licensed to you under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License. You may obtain a copy
# of the License at http://www.apache.org/licenses/LICENSE-2.0
# Unless required by applicable law or agreed to in writing, software distributed under
# the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
# OF ANY KIND, either express or implied. See the License for the specific language
# governing permissions and limitations under the License.
defmodule Styler.Style.Configs do
@moduledoc """
Orders `Config.config/2,3` stanzas in configuration files.
- ordering is done only within immediate-sibling config statements
- assignments are moved above the configuration blocks
- any non `config/2,3` or assignment (`=/2`) calls mark the end of a sorting block.
this is support having conditional blocks (`if/case/cond`) and `import_config` stanzas between blocks
### Breakages
If you configure the same values multiple times, Styler may swap their orders
**Before**
line 04: config :foo, bar: :zab
line 40: config :foo, bar: :baz
# Application.fetch_env!(:foo)[:bar] => :baz
**After**
line 04: config :foo, bar: :baz
line 05: config :foo, bar: :zab
# Application.fetch_env!(:foo)[:bar] => :zab
**Fix**
The reason Styler sorts configuration is to help you noticed these duplicated configuration stanzas.
Delete the duplicative/erroneous stanza and life will be good.
"""
alias Styler.Style
def run({{:import, _, [{:__aliases__, _, [:Config]}]}, _} = zipper, %{config?: true} = ctx) do
{:skip, zipper, Map.put(ctx, :mix_config?, true)}
end
def run({{:config, cfm, [_, _ | _]} = config, zm}, %{mix_config?: true, comments: comments} = ctx) do
# all of these list are reversed due to the reduce
{configs, assignments, rest} = accumulate(zm.r, [], [])
# @TODO
# okay so comments between nodes that we moved.......
# lets just push them out of the way (???). so
# 1. figure out first/last possible lines we're talking about here
# 2. only pass comments in that range off
# 3. split those comments into "moved, didn't move"
# 4. for any "didn't move" comments... move them to the top?
#
# also, should i just do a scan of the configs ++ assignments, and see if any of them have lines out of order,
# and decide from there whether or not i want to do set_lines
configs =
[config | configs]
|> Enum.group_by(fn
{:config, _, [{:__block__, _, [app]} | _]} -> app
{:config, _, [arg | _]} -> Style.without_meta(arg)
end)
|> Enum.sort()
|> Enum.flat_map(fn {_app, configs} ->
configs
|> Enum.sort_by(&Style.without_meta/1)
|> Style.reset_newlines()
end)
nodes =
assignments
|> Enum.reverse()
|> Style.reset_newlines()
|> Enum.concat(configs)
{nodes, comments} =
if changed?(nodes) do
# after running, this block should take up the same # of lines that it did before
# the first node of `rest` is greater than the highest line in configs, assignments
# config line is the first line to be used as part of this block
{node_comments, _} = Style.comments_for_node(config, comments)
first_line = min(List.last(node_comments)[:line] || cfm[:line], cfm[:line])
Style.order_line_meta_and_comments(nodes, comments, first_line)
else
{nodes, comments}
end
[config | left_siblings] = Enum.reverse(nodes, zm.l)
{:skip, {config, %{zm | l: left_siblings, r: rest}}, %{ctx | comments: comments}}
end
def run(zipper, %{config?: true} = ctx) do
{:cont, zipper, ctx}
end
def run(zipper, %{file: file} = ctx) do
if file =~ ~r|config/.*\.exs| or file =~ ~r|rel/overlays/.*\.exs| do
# @TODO have this run forward to `import Config`, then run forward from there until we find `config` itself. no need for multi function head
{:cont, zipper, Map.put(ctx, :config?, true)}
else
{:halt, zipper, ctx}
end
end
defp changed?([{_, am, _}, {_, bm, _} = b | tail]) do
if am[:line] > bm[:line], do: true, else: changed?([b | tail])
end
defp changed?(_), do: false
defp accumulate([{:config, _, [_, _ | _]} = c | siblings], cs, as), do: accumulate(siblings, [c | cs], as)
defp accumulate([{:=, _, [_lhs, _rhs]} = a | siblings], cs, as), do: accumulate(siblings, cs, [a | as])
defp accumulate(rest, configs, assignments), do: {configs, assignments, rest}
end