zf

zenflows testing
git clone https://s.sonu.ch/~srfsh/zf.git
Log | Files | Refs | Submodules | README | LICENSE

priority.ex (3756B)


      1 defmodule Credo.Priority do
      2   @moduledoc false
      3 
      4   # In Credo each Issue is given a priority to differentiate issues by a second
      5   # dimension next to their Category.
      6 
      7   alias Credo.Code.Module
      8   alias Credo.Code.Parameters
      9   alias Credo.Code.Scope
     10   alias Credo.SourceFile
     11 
     12   @def_ops [:def, :defp, :defmacro]
     13   @many_functions_count 5
     14 
     15   @priority_names_map %{
     16     "ignore" => -100,
     17     "low" => -10,
     18     "normal" => 1,
     19     "high" => +10,
     20     "higher" => +20
     21   }
     22 
     23   @doc "Converts a given priority name to a numerical priority"
     24   def to_integer(nil), do: 0
     25 
     26   def to_integer(value) when is_number(value), do: value
     27 
     28   def to_integer(string) when is_binary(string) do
     29     case Integer.parse(string) do
     30       :error -> string |> String.to_atom() |> to_integer()
     31       {value, ""} -> value
     32       {_value, _rest} -> raise "Got an invalid priority: #{inspect(string)}"
     33     end
     34   end
     35 
     36   def to_integer(key) when is_atom(key) do
     37     @priority_names_map[to_string(key)] || raise "Got an invalid priority: #{inspect(key)}"
     38   end
     39 
     40   def to_atom(priority)
     41 
     42   def to_atom(priority) when is_number(priority) do
     43     cond do
     44       priority > 19 -> :higher
     45       priority in 10..19 -> :high
     46       priority in 0..9 -> :normal
     47       priority in -10..-1 -> :low
     48       priority < -10 -> :ignore
     49     end
     50   end
     51 
     52   def to_atom(%{priority: priority}), do: to_atom(priority)
     53 
     54   def to_atom(priority) when is_atom(priority), do: priority
     55 
     56   def to_atom(_), do: nil
     57 
     58   def scope_priorities(%SourceFile{} = source_file) do
     59     line_count =
     60       source_file
     61       |> SourceFile.lines()
     62       |> length()
     63 
     64     empty_priorities = Enum.map(1..line_count, fn _ -> [] end)
     65 
     66     priority_list = Credo.Code.prewalk(source_file, &traverse/2, empty_priorities)
     67 
     68     base_map = make_base_map(priority_list, source_file)
     69 
     70     lookup = Enum.into(base_map, %{})
     71 
     72     Enum.into(base_map, %{}, fn {scope_name, prio} ->
     73       names = String.split(scope_name, ".")
     74 
     75       if names |> List.last() |> String.match?(~r/^[a-z]/) do
     76         mod_name =
     77           names
     78           |> Enum.slice(0..(length(names) - 2))
     79           |> Enum.join(".")
     80 
     81         mod_prio = lookup[mod_name] || 0
     82 
     83         {scope_name, prio + mod_prio}
     84       else
     85         {scope_name, prio}
     86       end
     87     end)
     88   end
     89 
     90   defp make_base_map(priority_list, %SourceFile{} = source_file) do
     91     ast = SourceFile.ast(source_file)
     92     scope_info_list = Scope.scope_info_list(ast)
     93 
     94     priority_list
     95     |> Enum.with_index()
     96     |> Enum.map(fn {list, index} ->
     97       case list do
     98         [] ->
     99           nil
    100 
    101         _ ->
    102           {_, scope_name} = Scope.name_from_scope_info_list(scope_info_list, index + 1)
    103           {scope_name, Enum.sum(list)}
    104       end
    105     end)
    106     |> Enum.reject(&is_nil/1)
    107   end
    108 
    109   defp traverse({:defmodule, meta, _} = ast, acc) do
    110     added_prio = priority_for(ast)
    111 
    112     {ast, List.update_at(acc, meta[:line] - 1, &(&1 ++ [added_prio]))}
    113   end
    114 
    115   for op <- @def_ops do
    116     defp traverse({unquote(op), meta, arguments} = ast, acc)
    117          when is_list(arguments) do
    118       added_prio = priority_for(ast)
    119 
    120       case arguments do
    121         [{_func_name, _meta, _func_arguments}, _do_block] ->
    122           {ast, List.update_at(acc, meta[:line] - 1, &(&1 ++ [added_prio]))}
    123 
    124         _ ->
    125           {ast, acc}
    126       end
    127     end
    128   end
    129 
    130   defp traverse(ast, acc) do
    131     {ast, acc}
    132   end
    133 
    134   defp priority_for({:defmodule, _, _} = ast) do
    135     if Module.def_count(ast) >= @many_functions_count do
    136       2
    137     else
    138       1
    139     end
    140   end
    141 
    142   for op <- @def_ops do
    143     defp priority_for({unquote(op), _, arguments} = ast)
    144          when is_list(arguments) do
    145       count = Parameters.count(ast)
    146 
    147       cond do
    148         count == 0 -> 0
    149         count in 1..2 -> 1
    150         count in 3..4 -> 2
    151         true -> 3
    152       end
    153     end
    154   end
    155 end