-module(pedantic@report). -compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -define(FILEPATH, "src/pedantic/report.gleam"). -export([dynamic_from/1, default_message/1, make_error/3, new/0, add_error/2, add_warning/2, merge/2, prefix_path/2, path_to_string/1, to_dict/1]). -export_type([path_segment/0, error_kind/0, error/0, warning_kind/0, warning/0, report/0, type_graph/0, metadata/0, type_field/0]). -if(?OTP_RELEASE >= 27). -define(MODULEDOC(Str), -moduledoc(Str)). -define(DOC(Str), -doc(Str)). -else. -define(MODULEDOC(Str), -compile([])). -define(DOC(Str), -compile([])). -endif. -type path_segment() :: {field, binary()} | {index, integer()}. -type error_kind() :: {wrong_type, binary(), binary()} | missing_field | {unknown_field, binary()} | {too_small, integer()} | {too_large, integer()} | {too_short, integer()} | {too_long, integer()} | {invalid_enum, list(binary())} | {invalid_format, binary()} | {custom, binary()}. -type error() :: {error, list(path_segment()), binary(), error_kind(), gleam@dynamic:dynamic_()}. -type warning_kind() :: {discarded_unknown_field, binary()}. -type warning() :: {warning, list(path_segment()), warning_kind()}. -type report() :: {report, list(error()), list(warning())}. -type type_graph() :: primitive_int | primitive_string | primitive_bool | primitive_float | {list, type_graph()} | {option, type_graph()} | {object, binary(), list(type_field())} | {dict, type_graph()} | {annotated, type_graph(), metadata()} | {union, list(type_graph())}. -type metadata() :: {metadata, gleam@option:option(binary()), gleam@option:option(binary()), gleam@option:option(gleam@dynamic:dynamic_())}. -type type_field() :: {type_field, binary(), type_graph()}. -file("src/pedantic/report.gleam", 23). -spec dynamic_from(any()) -> gleam@dynamic:dynamic_(). dynamic_from(A) -> gleam_stdlib:identity(A). -file("src/pedantic/report.gleam", 130). ?DOC(" Returns a human-readable default message for any ErrorKind.\n"). -spec default_message(error_kind()) -> binary(). default_message(Kind) -> case Kind of {wrong_type, Expected, Actual} -> <<<<<<"Expected "/utf8, Expected/binary>>/binary, ", got "/utf8>>/binary, Actual/binary>>; missing_field -> <<"Field is required"/utf8>>; {unknown_field, Name} -> <<"Unknown field: "/utf8, Name/binary>>; {too_small, Limit} -> <<"Value must be at least "/utf8, (erlang:integer_to_binary(Limit))/binary>>; {too_large, Limit@1} -> <<"Value must be at most "/utf8, (erlang:integer_to_binary(Limit@1))/binary>>; {too_short, Limit@2} -> <<"Length must be at least "/utf8, (erlang:integer_to_binary(Limit@2))/binary>>; {too_long, Limit@3} -> <<"Length must be at most "/utf8, (erlang:integer_to_binary(Limit@3))/binary>>; {invalid_enum, Options} -> <<"Value must be one of: "/utf8, (gleam@string:join(Options, <<", "/utf8>>))/binary>>; {invalid_format, Expected@1} -> <<"Invalid format: expected "/utf8, Expected@1/binary>>; {custom, Msg} -> Msg end. -file("src/pedantic/report.gleam", 147). ?DOC(" Constructs a ValidationIssue/Error with a default message.\n"). -spec make_error(list(path_segment()), error_kind(), gleam@dynamic:dynamic_()) -> error(). make_error(Path, Kind, Actual) -> {error, Path, default_message(Kind), Kind, Actual}. -file("src/pedantic/report.gleam", 156). ?DOC(" Creates a new, empty report.\n"). -spec new() -> report(). new() -> {report, [], []}. -file("src/pedantic/report.gleam", 161). ?DOC(" Adds an error to a report.\n"). -spec add_error(report(), error()) -> report(). add_error(Report, Error) -> {report, lists:append(erlang:element(2, Report), [Error]), erlang:element(3, Report)}. -file("src/pedantic/report.gleam", 166). ?DOC(" Adds a warning to a report.\n"). -spec add_warning(report(), warning()) -> report(). add_warning(Report, Warning) -> {report, erlang:element(2, Report), lists:append(erlang:element(3, Report), [Warning])}. -file("src/pedantic/report.gleam", 171). ?DOC(" Merges two reports together.\n"). -spec merge(report(), report()) -> report(). merge(A, B) -> {report, lists:append(erlang:element(2, A), erlang:element(2, B)), lists:append(erlang:element(3, A), erlang:element(3, B))}. -file("src/pedantic/report.gleam", 179). ?DOC(" Prefixes the path of all errors and warnings in a report with a segment.\n"). -spec prefix_path(report(), path_segment()) -> report(). prefix_path(Report, Segment) -> Errors = gleam@list:map( erlang:element(2, Report), fun(E) -> {error, [Segment | erlang:element(2, E)], erlang:element(3, E), erlang:element(4, E), erlang:element(5, E)} end ), Warnings = gleam@list:map( erlang:element(3, Report), fun(W) -> {warning, [Segment | erlang:element(2, W)], erlang:element(3, W)} end ), {report, Errors, Warnings}. -file("src/pedantic/report.gleam", 188). ?DOC(" Converts a path to a dotted string representation.\n"). -spec path_to_string(list(path_segment())) -> binary(). path_to_string(Path) -> _pipe = gleam@list:map(Path, fun(Segment) -> case Segment of {field, Name} -> Name; {index, Idx} -> erlang:integer_to_binary(Idx) end end), gleam@string:join(_pipe, <<"."/utf8>>). -file("src/pedantic/report.gleam", 199). ?DOC(" Converts a report into a dictionary mapping dotted paths to lists of human-readable error messages.\n"). -spec to_dict(report()) -> gleam@dict:dict(binary(), list(binary())). to_dict(Report) -> gleam@list:fold( erlang:element(2, Report), maps:new(), fun(Acc, Err) -> Path_str = path_to_string(erlang:element(2, Err)), Existing = begin _pipe = gleam_stdlib:map_get(Acc, Path_str), gleam@result:unwrap(_pipe, []) end, gleam@dict:insert( Acc, Path_str, lists:append(Existing, [erlang:element(3, Err)]) ) end ).