Packages
elvis_core
5.0.1
5.0.4
5.0.3
5.0.2
5.0.1
5.0.0
retired
4.2.3
4.2.2
4.2.1
4.2.0
4.1.1
4.1.0
4.0.0
3.2.5
3.2.4
3.2.3
3.2.2
3.2.1
3.2.0
3.1.0
3.0.1
3.0.0
2.0.1
2.0.0
1.4.0
1.3.2
1.3.1
1.3.0
1.2.0
1.1.2
1.1.1
1.1.0
1.0.0
0.7.0
0.6.1
0.6.0
0.5.0
0.4.3
0.4.2
0.4.1
0.4.0
0.3.9
0.3.8
0.3.7
0.3.6
0.3.5
0.3.4
0.3.3
0.3.2
0.3.1
0.3.0
Core library for the Erlang style reviewer
Current section
Files
Jump to
Current section
Files
src/elvis_result.erl
-module(elvis_result).
-compile({no_auto_import, [error/2]}).
%% API
-export([new_item/1, new_item/2, new_item/3, new/3, status/1, clean/1, print_results/1]).
-export([
get_path/1,
get_rules/1,
get_items/1,
get_message/1,
get_info/1,
get_line_num/1
]).
%% Types
-export_type([item/0, rule/0, file/0, elvis_error/0, elvis_warn/0]).
% API exports, not consumed locally.
-ignore_xref([get_path/1, get_rules/1, get_items/1, get_message/1, get_info/1, get_line_num/1]).
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% Records
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-opaque item() ::
#{
message => string(),
info => [term()],
line_num => -1 | non_neg_integer(),
column_num => -1 | non_neg_integer()
}.
-opaque rule() ::
#{
ns => atom(),
name => atom(),
items => [item()]
}.
-opaque file() :: #{file => string(), rules => [rule()]}.
-opaque elvis_error() :: #{error_msg => string(), info => list()}.
-opaque elvis_warn() :: #{warn_msg => string(), info => list()}.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% Public
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% New
-spec new_item(Format :: string()) -> item().
new_item(Format) ->
new_item(Format, []).
-spec new_item(Format :: string(), Data :: [term()]) -> item().
new_item(Format, Data) ->
new_item(Format, Data, #{}).
-spec new_item(Format :: string(), Data :: [term()], Attrs) -> item() when
Attrs :: #{
node => ktn_code:tree_node(),
zipper => zipper:zipper(ktn_code:tree_node()),
line => -1 | non_neg_integer(),
column => -1 | non_neg_integer(),
limit => -1 | non_neg_integer()
}.
new_item(Format, Data, Attrs) ->
Attrs1 = extend_attrs_with_line_and_column(Attrs),
Line = maps:get(line, Attrs1, -1),
Limit = maps:get(limit, Attrs1, -1),
Column = maps:get(column, Attrs1, -1),
new(item, Format, Data, {Line, Column}, Limit).
extend_attrs_with_line_and_column(#{node := Node} = Attrs) ->
{Line, Column} = ktn_code:attr(location, Node),
Attrs#{line => Line, column => Column};
extend_attrs_with_line_and_column(#{zipper := Zipper} = Attrs) ->
extend_attrs_with_line_and_column(Attrs#{node => zipper:node(Zipper)});
extend_attrs_with_line_and_column(Attrs) ->
Attrs.
-spec new
(item, string(), [term()]) -> item();
(rule, elvis_rule:t(), [item()]) -> rule();
(file, elvis_file:t(), [elvis_error() | rule()]) -> file();
(error, string(), string()) -> elvis_error();
(warn, string(), string()) -> elvis_warn().
% new(item, ...) is kept for backward compatibility, but discouraged
new(item, Msg, Info) ->
new_item(Msg, Info);
new(rule, Rule, Results) ->
#{
ns => elvis_rule:ns(Rule),
name => elvis_rule:name(Rule),
items => Results
};
new(file, #{path := Path}, Rules) ->
#{file => Path, rules => Rules};
new(error, Msg, Info) ->
#{error_msg => Msg, info => Info};
new(warn, Msg, Info) ->
#{warn_msg => Msg, info => Info}.
new(item, Msg0, Info, {Line, Column}, Limit) ->
Prefix0 =
case Line of
-1 ->
"";
_ ->
"At line " ++ integer_to_list(Line) ++ ", "
end,
Prefix1 =
case Column of
-1 ->
Prefix0;
_ when Line =:= -1 ->
"";
_ ->
Prefix0 ++ "column " ++ integer_to_list(Column) ++ ", "
end,
LimitSuffix =
case Limit of
-1 ->
"";
_ ->
" (limit: " ++ integer_to_list(Limit) ++ ")"
end,
#{
message => Prefix1 ++ Msg0 ++ LimitSuffix ++ ".",
info => Info,
line_num => Line,
column_num => Column
}.
%% Getters
-spec get_path(file()) -> string().
get_path(#{file := File}) ->
File.
-spec get_rules(file()) -> [rule()].
get_rules(#{rules := Rules}) ->
Rules.
-spec get_items(rule()) -> [item()].
get_items(#{items := Items}) ->
Items;
get_items(_) ->
[].
-spec get_message(item()) -> string().
get_message(#{message := Message}) ->
Message.
-spec get_info(item()) -> string().
get_info(#{info := Info}) ->
Info.
-spec get_line_num(item()) -> integer().
get_line_num(#{line_num := LineNum}) ->
LineNum.
%% Print
-spec print_results(file() | [elvis_warn()]) -> ok.
print_results(Results) ->
Format = elvis_config:output_format(),
print(Format, Results).
-spec print(plain | colors | parsable, [file() | elvis_warn()] | file()) -> ok.
print(_, []) ->
ok;
print(Format, [Result | Results]) ->
print(Format, Result),
print(Format, Results);
%% File
print(Format, #{file := Path, rules := Rules}) ->
_ =
case Format of
parsable ->
ok;
_ ->
Verbose = elvis_config:verbose(),
case status(Rules) of
ok when Verbose ->
elvis_utils:notice("# ~s [{{green-bold}}OK{{white-bold}}]", [Path]);
ok ->
ok;
fail ->
elvis_utils:notice("# ~s [{{red-bold}}FAIL{{white-bold}}]", [Path])
end
end,
print_rules(Format, Path, Rules);
print(_, Error) ->
print_error(Error).
print_rules(_Format, _File, []) ->
ok;
print_rules(Format, File, [#{items := []} | Items]) ->
print_rules(Format, File, Items);
print_rules(
Format,
File,
[
#{
ns := Scope,
items := Items,
name := Name
}
| EItems
]
) ->
_ =
case Format of
parsable ->
ok;
_ ->
elvis_utils:notice(
" - ~p "
"(https://github.com/inaka/elvis_core/tree/main/doc_rules/~p/~p.md)",
[Name, Scope, Name]
)
end,
print_item(Format, File, Name, Items),
print_rules(Format, File, EItems);
print_rules(Format, File, [Error | Items]) ->
_ = print_error(Error),
print_rules(Format, File, Items).
%% Item
print_item(
Format,
File,
Name,
[
#{
message := Msg,
line_num := Ln,
info := Info
}
| Items
]
) ->
_ =
case Format of
parsable ->
FMsg = io_lib:format(Msg, Info),
io:format("~s:~p:~p:~s~n", [File, Ln, Name, FMsg]);
_ ->
elvis_utils:notice(" - " ++ Msg, Info)
end,
print_item(Format, File, Name, Items);
print_item(Format, File, Name, [Error | Items]) ->
_ = print_error(Error),
print_item(Format, File, Name, Items);
print_item(_Format, _File, _Name, []) ->
ok.
print_error(#{error_msg := Msg, info := Info}) ->
elvis_utils:error(Msg, Info);
print_error(#{warn_msg := Msg, info := Info}) ->
elvis_utils:warn(Msg, Info).
-spec status([file() | rule()]) -> ok | fail.
status([]) ->
ok;
status([#{rules := Rules} | Files]) ->
case status(Rules) of
fail ->
fail;
ok ->
status(Files)
end;
status([#{items := []} | Rules]) ->
status(Rules);
status(_Rules) ->
fail.
%% @doc Removes files that don't have any failures.
-spec clean([file() | rule()]) -> [file() | rule()].
clean(Files) ->
clean(Files, []).
-spec clean([file() | rule()], [file() | rule()]) -> [file() | rule()].
clean([], Result) ->
lists:reverse(Result);
clean([#{rules := []} | Files], Result) ->
clean(Files, Result);
clean([File = #{rules := Rules} | Files], Result) ->
CleanRules = clean(Rules),
NewFile = File#{rules => CleanRules},
clean(Files, [NewFile | Result]);
clean([#{items := []} | Rules], Result) ->
clean(Rules, Result);
clean([Rule | Rules], Result) ->
clean(Rules, [Rule | Result]).