-module(pedantic@decode). -compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -define(FILEPATH, "src/pedantic/decode.gleam"). -export([decode_int/1, decode_exact_int/1, decode_float/1, decode_exact_float/1, decode_bool/1, decode_exact_bool/1, decode_string/1, decode_exact_string/1, list/1, optional/1, dict/1, default/2, object/2, field/3, key_optional/3, key_with_default/4, build/1, with_error_formatter/2, with_error_message/2, with_template/2, refine/2, assert_that/3, check/3, min/2, max/2, min_length/2, max_length/2, positive/1, negative/1, non_negative/1, non_positive/1, map/2, trim/1, lowercase/1, uppercase/1, collapse_whitespace/1, replace/3, remove_chars/2, allow_chars/2, strip_control_chars/1, normalize_email/1, normalize_uuid/1, default_if_blank/2, empty_as_none/1, length/2, email/2, uuid/2, any_of/1, min_size/2, max_size/2, int_range/2, float_range/2, string_limit/2, decode_non_empty_string/1, non_empty_list/1, title/2, describe/2, example/2]). -export_type([decoder/1, object_builder/2]). -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 decoder(DPH) :: {decoder, pedantic@report:type_graph(), fun((gleam@dynamic:dynamic_()) -> {ok, DPH} | {error, pedantic@report:report()})}. -opaque object_builder(DPI, DPJ) :: {object_builder, binary(), list(pedantic@report:type_field()), fun((gleam@dynamic:dynamic_()) -> {ok, DPI} | {error, pedantic@report:report()})} | {gleam_phantom, DPJ}. -file("src/pedantic/decode.gleam", 43). -spec decode_int(gleam@dynamic:dynamic_()) -> {ok, integer()} | {error, pedantic@report:report()}. decode_int(Dyn) -> case gleam@dynamic@decode:run( Dyn, {decoder, fun gleam@dynamic@decode:decode_int/1} ) of {ok, I} -> {ok, I}; {error, _} -> case gleam@dynamic@decode:run( Dyn, {decoder, fun gleam@dynamic@decode:decode_string/1} ) of {ok, S} -> case gleam_stdlib:parse_int(S) of {ok, I@1} -> {ok, I@1}; {error, _} -> Err = pedantic@report:make_error( [], {wrong_type, <<"Int"/utf8>>, <<"String"/utf8>>}, Dyn ), {error, {report, [Err], []}} end; {error, _} -> Err@1 = pedantic@report:make_error( [], {wrong_type, <<"Int"/utf8>>, gleam_stdlib:classify_dynamic(Dyn)}, Dyn ), {error, {report, [Err@1], []}} end end. -file("src/pedantic/decode.gleam", 78). -spec decode_exact_int(gleam@dynamic:dynamic_()) -> {ok, integer()} | {error, pedantic@report:report()}. decode_exact_int(Dyn) -> case gleam@dynamic@decode:run( Dyn, {decoder, fun gleam@dynamic@decode:decode_int/1} ) of {ok, I} -> {ok, I}; {error, _} -> Err = pedantic@report:make_error( [], {wrong_type, <<"Int"/utf8>>, gleam_stdlib:classify_dynamic(Dyn)}, Dyn ), {error, {report, [Err], []}} end. -file("src/pedantic/decode.gleam", 99). -spec decode_float(gleam@dynamic:dynamic_()) -> {ok, float()} | {error, pedantic@report:report()}. decode_float(Dyn) -> case gleam@dynamic@decode:run( Dyn, {decoder, fun gleam@dynamic@decode:decode_float/1} ) of {ok, F} -> {ok, F}; {error, _} -> case gleam@dynamic@decode:run( Dyn, {decoder, fun gleam@dynamic@decode:decode_int/1} ) of {ok, I} -> {ok, erlang:float(I)}; {error, _} -> case gleam@dynamic@decode:run( Dyn, {decoder, fun gleam@dynamic@decode:decode_string/1} ) of {ok, S} -> case gleam_stdlib:parse_float(S) of {ok, F@1} -> {ok, F@1}; {error, _} -> Err = pedantic@report:make_error( [], {wrong_type, <<"Float"/utf8>>, <<"String"/utf8>>}, Dyn ), {error, {report, [Err], []}} end; {error, _} -> Err@1 = pedantic@report:make_error( [], {wrong_type, <<"Float"/utf8>>, gleam_stdlib:classify_dynamic(Dyn)}, Dyn ), {error, {report, [Err@1], []}} end end end. -file("src/pedantic/decode.gleam", 143). -spec decode_exact_float(gleam@dynamic:dynamic_()) -> {ok, float()} | {error, pedantic@report:report()}. decode_exact_float(Dyn) -> case gleam@dynamic@decode:run( Dyn, {decoder, fun gleam@dynamic@decode:decode_float/1} ) of {ok, F} -> {ok, F}; {error, _} -> Err = pedantic@report:make_error( [], {wrong_type, <<"Float"/utf8>>, gleam_stdlib:classify_dynamic(Dyn)}, Dyn ), {error, {report, [Err], []}} end. -file("src/pedantic/decode.gleam", 164). -spec decode_bool(gleam@dynamic:dynamic_()) -> {ok, boolean()} | {error, pedantic@report:report()}. decode_bool(Dyn) -> case gleam@dynamic@decode:run( Dyn, {decoder, fun gleam@dynamic@decode:decode_bool/1} ) of {ok, B} -> {ok, B}; {error, _} -> case gleam@dynamic@decode:run( Dyn, {decoder, fun gleam@dynamic@decode:decode_string/1} ) of {ok, S} -> case S of <<"true"/utf8>> -> {ok, true}; <<"1"/utf8>> -> {ok, true}; <<"false"/utf8>> -> {ok, false}; <<"0"/utf8>> -> {ok, false}; _ -> Err = pedantic@report:make_error( [], {wrong_type, <<"Bool"/utf8>>, <<"String"/utf8>>}, Dyn ), {error, {report, [Err], []}} end; {error, _} -> case gleam@dynamic@decode:run( Dyn, {decoder, fun gleam@dynamic@decode:decode_int/1} ) of {ok, 1} -> {ok, true}; {ok, 0} -> {ok, false}; _ -> Err@1 = pedantic@report:make_error( [], {wrong_type, <<"Bool"/utf8>>, gleam_stdlib:classify_dynamic(Dyn)}, Dyn ), {error, {report, [Err@1], []}} end end end. -file("src/pedantic/decode.gleam", 206). -spec decode_exact_bool(gleam@dynamic:dynamic_()) -> {ok, boolean()} | {error, pedantic@report:report()}. decode_exact_bool(Dyn) -> case gleam@dynamic@decode:run( Dyn, {decoder, fun gleam@dynamic@decode:decode_bool/1} ) of {ok, B} -> {ok, B}; {error, _} -> Err = pedantic@report:make_error( [], {wrong_type, <<"Bool"/utf8>>, gleam_stdlib:classify_dynamic(Dyn)}, Dyn ), {error, {report, [Err], []}} end. -file("src/pedantic/decode.gleam", 227). -spec decode_string(gleam@dynamic:dynamic_()) -> {ok, binary()} | {error, pedantic@report:report()}. decode_string(Dyn) -> case gleam@dynamic@decode:run( Dyn, {decoder, fun gleam@dynamic@decode:decode_string/1} ) of {ok, S} -> {ok, S}; {error, _} -> case gleam@dynamic@decode:run( Dyn, {decoder, fun gleam@dynamic@decode:decode_int/1} ) of {ok, I} -> {ok, erlang:integer_to_binary(I)}; {error, _} -> case gleam@dynamic@decode:run( Dyn, {decoder, fun gleam@dynamic@decode:decode_float/1} ) of {ok, F} -> {ok, gleam_stdlib:float_to_string(F)}; {error, _} -> case gleam@dynamic@decode:run( Dyn, {decoder, fun gleam@dynamic@decode:decode_bool/1} ) of {ok, true} -> {ok, <<"true"/utf8>>}; {ok, false} -> {ok, <<"false"/utf8>>}; {error, _} -> Err = pedantic@report:make_error( [], {wrong_type, <<"String"/utf8>>, gleam_stdlib:classify_dynamic(Dyn)}, Dyn ), {error, {report, [Err], []}} end end end end. -file("src/pedantic/decode.gleam", 264). -spec decode_exact_string(gleam@dynamic:dynamic_()) -> {ok, binary()} | {error, pedantic@report:report()}. decode_exact_string(Dyn) -> case gleam@dynamic@decode:run( Dyn, {decoder, fun gleam@dynamic@decode:decode_string/1} ) of {ok, S} -> {ok, S}; {error, _} -> Err = pedantic@report:make_error( [], {wrong_type, <<"String"/utf8>>, gleam_stdlib:classify_dynamic(Dyn)}, Dyn ), {error, {report, [Err], []}} end. -file("src/pedantic/decode.gleam", 293). ?DOC(" List combinator that decodes dynamic arrays into typed Lists, accumulating errors.\n"). -spec list(decoder(DQA)) -> decoder(list(DQA)). list(Element_decoder) -> Function = fun(Dyn) -> case gleam@dynamic@decode:run( Dyn, gleam@dynamic@decode:list( {decoder, fun gleam@dynamic@decode:decode_dynamic/1} ) ) of {ok, Dyn_list} -> {Results, Reports} = begin _pipe = gleam@list:index_map( Dyn_list, fun(Elem_dyn, Idx) -> case (erlang:element(3, Element_decoder))(Elem_dyn) of {ok, V} -> {ok, V}; {error, Rep} -> {error, pedantic@report:prefix_path( Rep, {index, Idx} )} end end ), gleam@list:partition(_pipe, fun(Res) -> case Res of {ok, _} -> true; {error, _} -> false end end) end, case gleam@list:is_empty(Reports) of true -> Values = gleam@list:map( Results, fun(R) -> V@2 = case R of {ok, V@1} -> V@1; _assert_fail -> erlang:error( #{gleam_error => let_assert, message => <<"Pattern match failed, no pattern matched the value."/utf8>>, file => <>, module => <<"pedantic/decode"/utf8>>, function => <<"list"/utf8>>, line => 315, value => _assert_fail, start => 8712, 'end' => 8732, pattern_start => 8723, pattern_end => 8728} ) end, V@2 end ), {ok, Values}; false -> Combined = gleam@list:fold( Reports, pedantic@report:new(), fun(Acc, Next_rep) -> Rep@2 = case Next_rep of {error, Rep@1} -> Rep@1; _assert_fail@1 -> erlang:error( #{gleam_error => let_assert, message => <<"Pattern match failed, no pattern matched the value."/utf8>>, file => <>, module => <<"pedantic/decode"/utf8>>, function => <<"list"/utf8>>, line => 323, value => _assert_fail@1, start => 8934, 'end' => 8966, pattern_start => 8945, pattern_end => 8955} ) end, pedantic@report:merge(Acc, Rep@2) end ), {error, Combined} end; {error, _} -> Err = pedantic@report:make_error( [], {wrong_type, <<"List"/utf8>>, gleam_stdlib:classify_dynamic(Dyn)}, Dyn ), {error, {report, [Err], []}} end end, {decoder, {list, erlang:element(2, Element_decoder)}, Function}. -file("src/pedantic/decode.gleam", 346). ?DOC(" Option/Optional combinator representing absent or nullable values.\n"). -spec optional(decoder(DQE)) -> decoder(gleam@option:option(DQE)). optional(Inner_decoder) -> Function = fun(Dyn) -> case pedantic_ffi:is_null_or_undefined(Dyn) of true -> {ok, none}; false -> case gleam@dynamic@decode:run( Dyn, {decoder, fun gleam@dynamic@decode:decode_string/1} ) of {ok, <<"null"/utf8>>} -> {ok, none}; {ok, <<"undefined"/utf8>>} -> {ok, none}; _ -> case (erlang:element(3, Inner_decoder))(Dyn) of {ok, V} -> {ok, {some, V}}; {error, Rep} -> {error, Rep} end end end end, {decoder, {option, erlang:element(2, Inner_decoder)}, Function}. -file("src/pedantic/decode.gleam", 368). ?DOC(" Dict combinator to decode dynamic objects with string keys, accumulating errors.\n"). -spec dict(decoder(DQI)) -> decoder(gleam@dict:dict(binary(), DQI)). dict(Value_decoder) -> Function = fun(Dyn) -> case gleam@dynamic@decode:run( Dyn, gleam@dynamic@decode:dict( {decoder, fun gleam@dynamic@decode:decode_string/1}, {decoder, fun gleam@dynamic@decode:decode_dynamic/1} ) ) of {ok, Raw_dict} -> {Results, Reports} = begin _pipe = maps:to_list(Raw_dict), _pipe@1 = gleam@list:map( _pipe, fun(Pair) -> {K, V_dyn} = Pair, case (erlang:element(3, Value_decoder))(V_dyn) of {ok, V} -> {ok, {K, V}}; {error, Rep} -> {error, pedantic@report:prefix_path( Rep, {field, K} )} end end ), gleam@list:partition(_pipe@1, fun(Res) -> case Res of {ok, _} -> true; {error, _} -> false end end) end, case gleam@list:is_empty(Reports) of true -> Entries = gleam@list:map( Results, fun(R) -> V@2 = case R of {ok, V@1} -> V@1; _assert_fail -> erlang:error( #{gleam_error => let_assert, message => <<"Pattern match failed, no pattern matched the value."/utf8>>, file => <>, module => <<"pedantic/decode"/utf8>>, function => <<"dict"/utf8>>, line => 392, value => _assert_fail, start => 11000, 'end' => 11020, pattern_start => 11011, pattern_end => 11016} ) end, V@2 end ), {ok, maps:from_list(Entries)}; false -> Combined = gleam@list:fold( Reports, pedantic@report:new(), fun(Acc, Next_rep) -> Rep@2 = case Next_rep of {error, Rep@1} -> Rep@1; _assert_fail@1 -> erlang:error( #{gleam_error => let_assert, message => <<"Pattern match failed, no pattern matched the value."/utf8>>, file => <>, module => <<"pedantic/decode"/utf8>>, function => <<"dict"/utf8>>, line => 400, value => _assert_fail@1, start => 11239, 'end' => 11271, pattern_start => 11250, pattern_end => 11260} ) end, pedantic@report:merge(Acc, Rep@2) end ), {error, Combined} end; {error, _} -> Err = pedantic@report:make_error( [], {wrong_type, <<"Dict"/utf8>>, gleam_stdlib:classify_dynamic(Dyn)}, Dyn ), {error, {report, [Err], []}} end end, {decoder, {dict, erlang:element(2, Value_decoder)}, Function}. -file("src/pedantic/decode.gleam", 423). ?DOC(" Adapts an optional decoder with a default value fallback.\n"). -spec default(decoder(gleam@option:option(DQN)), DQN) -> decoder(DQN). default(Decoder, Default_val) -> Function = fun(Dyn) -> case (erlang:element(3, Decoder))(Dyn) of {ok, {some, V}} -> {ok, V}; {ok, none} -> {ok, Default_val}; {error, R} -> {error, R} end end, {decoder, erlang:element(2, Decoder), Function}. -file("src/pedantic/decode.gleam", 444). ?DOC(" Initializes an ObjectBuilder for a custom record constructor.\n"). -spec object(binary(), DQR) -> object_builder(DQR, any()). object(Name, Constructor) -> {object_builder, Name, [], fun(_) -> {ok, Constructor} end}. -file("src/pedantic/decode.gleam", 452). ?DOC(" Applies a field description and decoder to the object builder.\n"). -spec field(object_builder(fun((DQV) -> DQW), DQX), binary(), decoder(DQV)) -> object_builder(DQW, DQX). field(Builder, Name, Field_decoder) -> Fields = lists:append( erlang:element(3, Builder), [{type_field, Name, erlang:element(2, Field_decoder)}] ), Decoder = fun(Dyn) -> Constructor_res = (erlang:element(4, Builder))(Dyn), Field_dyn_res = gleam@dynamic@decode:run( Dyn, gleam@dynamic@decode:at( [Name], {decoder, fun gleam@dynamic@decode:decode_dynamic/1} ) ), Is_field_optional = case erlang:element(2, Field_decoder) of {option, _} -> true; {annotated, {option, _}, _} -> true; _ -> false end, case {Constructor_res, Field_dyn_res} of {{ok, Constructor_fn}, {ok, Field_dyn}} -> case (erlang:element(3, Field_decoder))(Field_dyn) of {ok, Field_val} -> {ok, Constructor_fn(Field_val)}; {error, Field_report} -> {error, pedantic@report:prefix_path( Field_report, {field, Name} )} end; {{ok, Constructor_fn@1}, {error, _}} -> case Is_field_optional of true -> case (erlang:element(3, Field_decoder))( gleam@dynamic:nil() ) of {ok, Field_val@1} -> {ok, Constructor_fn@1(Field_val@1)}; {error, Field_report@1} -> {error, pedantic@report:prefix_path( Field_report@1, {field, Name} )} end; false -> Err = pedantic@report:make_error( [{field, Name}], missing_field, Dyn ), {error, {report, [Err], []}} end; {{error, Builder_report}, {ok, Field_dyn@1}} -> case (erlang:element(3, Field_decoder))(Field_dyn@1) of {ok, _} -> {error, Builder_report}; {error, Field_report@2} -> Prefixed = pedantic@report:prefix_path( Field_report@2, {field, Name} ), {error, pedantic@report:merge(Builder_report, Prefixed)} end; {{error, Builder_report@1}, {error, _}} -> case Is_field_optional of true -> {error, Builder_report@1}; false -> Err@1 = pedantic@report:make_error( [{field, Name}], missing_field, Dyn ), Field_report@3 = {report, [Err@1], []}, {error, pedantic@report:merge( Builder_report@1, Field_report@3 )} end end end, {object_builder, erlang:element(2, Builder), Fields, Decoder}. -file("src/pedantic/decode.gleam", 526). ?DOC(" Declares an optional key in the object builder, resolving to Option(t).\n"). -spec key_optional( object_builder(fun((gleam@option:option(DRD)) -> DRF), DRG), binary(), decoder(DRD) ) -> object_builder(DRF, DRG). key_optional(Builder, Name, Field_decoder) -> field(Builder, Name, optional(Field_decoder)). -file("src/pedantic/decode.gleam", 535). ?DOC(" Declares an optional key with fallback default value.\n"). -spec key_with_default( object_builder(fun((DRM) -> DRN), DRO), binary(), decoder(DRM), DRM ) -> object_builder(DRN, DRO). key_with_default(Builder, Name, Field_decoder, Default_val) -> field( Builder, Name, begin _pipe = optional(Field_decoder), default(_pipe, Default_val) end ). -file("src/pedantic/decode.gleam", 545). ?DOC(" Finalizes the ObjectBuilder, converting it into a full Decoder.\n"). -spec build(object_builder(DRU, DRU)) -> decoder(DRU). build(Builder) -> Function = fun(Dyn) -> case gleam@dynamic@decode:run( Dyn, gleam@dynamic@decode:dict( {decoder, fun gleam@dynamic@decode:decode_dynamic/1}, {decoder, fun gleam@dynamic@decode:decode_dynamic/1} ) ) of {ok, _} -> (erlang:element(4, Builder))(Dyn); {error, _} -> Err = pedantic@report:make_error( [], {wrong_type, <<"Object"/utf8>>, gleam_stdlib:classify_dynamic(Dyn)}, Dyn ), {error, {report, [Err], []}} end end, {decoder, {object, erlang:element(2, Builder), erlang:element(3, Builder)}, Function}. -file("src/pedantic/decode.gleam", 569). ?DOC(" Custom error formatter decorator.\n"). -spec with_error_formatter( decoder(DRY), fun((gleam@dynamic:dynamic_(), pedantic@report:error_kind()) -> binary()) ) -> decoder(DRY). with_error_formatter(Decoder, Formatter) -> Function = fun(Dyn) -> _pipe = (erlang:element(3, Decoder))(Dyn), gleam@result:map_error( _pipe, fun(Rep) -> Errors = gleam@list:map( erlang:element(2, Rep), fun(Err) -> {error, erlang:element(2, Err), Formatter( erlang:element(5, Err), erlang:element(4, Err) ), erlang:element(4, Err), erlang:element(5, Err)} end ), {report, Errors, erlang:element(3, Rep)} end ) end, {decoder, erlang:element(2, Decoder), Function}. -file("src/pedantic/decode.gleam", 587). ?DOC(" Exposes simple custom validation string messages.\n"). -spec with_error_message(decoder(DSB), binary()) -> decoder(DSB). with_error_message(Decoder, Msg) -> with_error_formatter(Decoder, fun(_, _) -> Msg end). -file("src/pedantic/decode.gleam", 592). ?DOC(" Placeholder template parser replacing {value}, {min}, {max}, {length}.\n"). -spec with_template(decoder(DSE), binary()) -> decoder(DSE). with_template(Decoder, Template) -> Formatter = fun(Actual, Kind) -> Val_str = case gleam@dynamic@decode:run( Actual, {decoder, fun gleam@dynamic@decode:decode_string/1} ) of {ok, S} -> S; {error, _} -> case gleam@dynamic@decode:run( Actual, {decoder, fun gleam@dynamic@decode:decode_int/1} ) of {ok, I} -> erlang:integer_to_binary(I); {error, _} -> case gleam@dynamic@decode:run( Actual, {decoder, fun gleam@dynamic@decode:decode_float/1} ) of {ok, F} -> gleam_stdlib:float_to_string(F); {error, _} -> case gleam@dynamic@decode:run( Actual, {decoder, fun gleam@dynamic@decode:decode_bool/1} ) of {ok, true} -> <<"true"/utf8>>; {ok, false} -> <<"false"/utf8>>; {error, _} -> <<"dynamic"/utf8>> end end end end, Length_str = begin _pipe = string:length(Val_str), erlang:integer_to_binary(_pipe) end, Res = begin _pipe@1 = Template, _pipe@2 = gleam@string:replace(_pipe@1, <<"{value}"/utf8>>, Val_str), gleam@string:replace(_pipe@2, <<"{length}"/utf8>>, Length_str) end, case Kind of {too_small, Lim} -> gleam@string:replace( Res, <<"{min}"/utf8>>, erlang:integer_to_binary(Lim) ); {too_short, Lim} -> gleam@string:replace( Res, <<"{min}"/utf8>>, erlang:integer_to_binary(Lim) ); {too_large, Lim@1} -> gleam@string:replace( Res, <<"{max}"/utf8>>, erlang:integer_to_binary(Lim@1) ); {too_long, Lim@1} -> gleam@string:replace( Res, <<"{max}"/utf8>>, erlang:integer_to_binary(Lim@1) ); _ -> Res end end, with_error_formatter(Decoder, Formatter). -file("src/pedantic/decode.gleam", 638). ?DOC(" Refines a decoder with a custom validation rule.\n"). -spec refine( decoder(DSH), fun((DSH) -> {ok, DSH} | {error, pedantic@report:error_kind()}) ) -> decoder(DSH). refine(Decoder, Rule) -> Function = fun(Dyn) -> case (erlang:element(3, Decoder))(Dyn) of {ok, Val} -> case Rule(Val) of {ok, Refined_val} -> {ok, Refined_val}; {error, Err_kind} -> Err = pedantic@report:make_error([], Err_kind, Dyn), {error, {report, [Err], []}} end; {error, Rep} -> {error, Rep} end end, {decoder, erlang:element(2, Decoder), Function}. -file("src/pedantic/decode.gleam", 660). ?DOC(" Asserts validation constraints using a boolean predicate function.\n"). -spec assert_that( decoder(DSM), fun((DSM) -> boolean()), pedantic@report:error_kind() ) -> decoder(DSM). assert_that(Decoder, Predicate, Error) -> refine(Decoder, fun(Val) -> case Predicate(Val) of true -> {ok, Val}; false -> {error, Error} end end). -file("src/pedantic/decode.gleam", 674). ?DOC(" Standard check validator.\n"). -spec check(decoder(DSP), fun((DSP) -> boolean()), binary()) -> decoder(DSP). check(Decoder, Predicate, Msg) -> assert_that(Decoder, Predicate, {invalid_format, Msg}). -file("src/pedantic/decode.gleam", 683). ?DOC(" Restricts an Int decoder to values greater than or equal to the minimum.\n"). -spec min(decoder(integer()), integer()) -> decoder(integer()). min(Decoder, Minimum) -> refine(Decoder, fun(Val) -> case Val >= Minimum of true -> {ok, Val}; false -> {error, {too_small, Minimum}} end end). -file("src/pedantic/decode.gleam", 693). ?DOC(" Restricts an Int decoder to values less than or equal to the maximum.\n"). -spec max(decoder(integer()), integer()) -> decoder(integer()). max(Decoder, Maximum) -> refine(Decoder, fun(Val) -> case Val =< Maximum of true -> {ok, Val}; false -> {error, {too_large, Maximum}} end end). -file("src/pedantic/decode.gleam", 703). ?DOC(" Restricts a String decoder to a minimum length.\n"). -spec min_length(decoder(binary()), integer()) -> decoder(binary()). min_length(Decoder, Minimum) -> refine(Decoder, fun(Val) -> case string:length(Val) >= Minimum of true -> {ok, Val}; false -> {error, {too_short, Minimum}} end end). -file("src/pedantic/decode.gleam", 713). ?DOC(" Restricts a String decoder to a maximum length.\n"). -spec max_length(decoder(binary()), integer()) -> decoder(binary()). max_length(Decoder, Maximum) -> refine(Decoder, fun(Val) -> case string:length(Val) =< Maximum of true -> {ok, Val}; false -> {error, {too_long, Maximum}} end end). -file("src/pedantic/decode.gleam", 724). -spec positive(decoder(integer())) -> decoder(integer()). positive(Decoder) -> refine(Decoder, fun(Val) -> case Val > 0 of true -> {ok, Val}; false -> {error, {too_small, 1}} end end). -file("src/pedantic/decode.gleam", 733). -spec negative(decoder(integer())) -> decoder(integer()). negative(Decoder) -> refine(Decoder, fun(Val) -> case Val < 0 of true -> {ok, Val}; false -> {error, {too_large, -1}} end end). -file("src/pedantic/decode.gleam", 742). -spec non_negative(decoder(integer())) -> decoder(integer()). non_negative(Decoder) -> refine(Decoder, fun(Val) -> case Val >= 0 of true -> {ok, Val}; false -> {error, {too_small, 0}} end end). -file("src/pedantic/decode.gleam", 751). -spec non_positive(decoder(integer())) -> decoder(integer()). non_positive(Decoder) -> refine(Decoder, fun(Val) -> case Val =< 0 of true -> {ok, Val}; false -> {error, {too_large, 0}} end end). -file("src/pedantic/decode.gleam", 1079). -spec map(decoder(DVT), fun((DVT) -> DVV)) -> decoder(DVV). map(Decoder, Transform_fn) -> Function = fun(Dyn) -> _pipe = (erlang:element(3, Decoder))(Dyn), gleam@result:map(_pipe, Transform_fn) end, {decoder, erlang:element(2, Decoder), Function}. -file("src/pedantic/decode.gleam", 760). -spec trim(decoder(binary())) -> decoder(binary()). trim(Decoder) -> map(Decoder, fun gleam@string:trim/1). -file("src/pedantic/decode.gleam", 764). -spec lowercase(decoder(binary())) -> decoder(binary()). lowercase(Decoder) -> map(Decoder, fun string:lowercase/1). -file("src/pedantic/decode.gleam", 768). -spec uppercase(decoder(binary())) -> decoder(binary()). uppercase(Decoder) -> map(Decoder, fun string:uppercase/1). -file("src/pedantic/decode.gleam", 896). -spec is_whitespace(binary()) -> boolean(). is_whitespace(Grapheme) -> gleam@list:contains( [<<" "/utf8>>, <<"\t"/utf8>>, <<"\n"/utf8>>, <<"\r"/utf8>>, <<"\x{00a0}"/utf8>>], Grapheme ). -file("src/pedantic/decode.gleam", 846). -spec collapse_whitespace_string(binary()) -> binary(). collapse_whitespace_string(Value) -> _pipe = Value, _pipe@1 = gleam@string:to_graphemes(_pipe), _pipe@2 = gleam@list:fold( _pipe@1, {[], false}, fun(Acc, Grapheme) -> {Output, Pending_space} = Acc, case is_whitespace(Grapheme) of true -> {Output, not gleam@list:is_empty(Output)}; false -> Next_output = case Pending_space of true -> [Grapheme, <<" "/utf8>> | Output]; false -> [Grapheme | Output] end, {Next_output, false} end end ), (fun(Result) -> _pipe@3 = erlang:element(1, Result), _pipe@4 = lists:reverse(_pipe@3), gleam@string:join(_pipe@4, <<""/utf8>>) end)(_pipe@2). -file("src/pedantic/decode.gleam", 773). ?DOC(" Replaces each run of whitespace with a single space and trims the result.\n"). -spec collapse_whitespace(decoder(binary())) -> decoder(binary()). collapse_whitespace(Decoder) -> map(Decoder, fun collapse_whitespace_string/1). -file("src/pedantic/decode.gleam", 778). ?DOC(" Replaces every occurrence of `pattern` with `replacement`.\n"). -spec replace(decoder(binary()), binary(), binary()) -> decoder(binary()). replace(Decoder, Pattern, Replacement) -> map( Decoder, fun(Value) -> gleam@string:replace(Value, Pattern, Replacement) end ). -file("src/pedantic/decode.gleam", 865). -spec filter_chars(binary(), binary(), boolean()) -> binary(). filter_chars(Value, Characters, Keep_matching) -> Allowed = gleam@string:to_graphemes(Characters), _pipe = Value, _pipe@1 = gleam@string:to_graphemes(_pipe), _pipe@2 = gleam@list:filter( _pipe@1, fun(Grapheme) -> Matches = gleam@list:contains(Allowed, Grapheme), case Keep_matching of true -> Matches; false -> not Matches end end ), gleam@string:join(_pipe@2, <<""/utf8>>). -file("src/pedantic/decode.gleam", 787). ?DOC(" Removes every grapheme contained in `characters`.\n"). -spec remove_chars(decoder(binary()), binary()) -> decoder(binary()). remove_chars(Decoder, Characters) -> map(Decoder, fun(Value) -> filter_chars(Value, Characters, false) end). -file("src/pedantic/decode.gleam", 795). ?DOC(" Keeps only graphemes contained in `characters`.\n"). -spec allow_chars(decoder(binary()), binary()) -> decoder(binary()). allow_chars(Decoder, Characters) -> map(Decoder, fun(Value) -> filter_chars(Value, Characters, true) end). -file("src/pedantic/decode.gleam", 883). -spec strip_control_chars_string(binary()) -> binary(). strip_control_chars_string(Value) -> _pipe = Value, _pipe@1 = gleam@string:to_utf_codepoints(_pipe), _pipe@2 = gleam@list:filter( _pipe@1, fun(Codepoint) -> Number = gleam_stdlib:identity(Codepoint), case (Number < 32) orelse (Number =:= 127) of true -> false; false -> true end end ), gleam_stdlib:utf_codepoint_list_to_string(_pipe@2). -file("src/pedantic/decode.gleam", 803). ?DOC(" Removes Unicode control code points from the string.\n"). -spec strip_control_chars(decoder(binary())) -> decoder(binary()). strip_control_chars(Decoder) -> map(Decoder, fun strip_control_chars_string/1). -file("src/pedantic/decode.gleam", 808). ?DOC(" Trims and lowercases a string, useful for case-insensitive identifiers.\n"). -spec normalize_email(decoder(binary())) -> decoder(binary()). normalize_email(Decoder) -> map(Decoder, fun(Value) -> _pipe = Value, _pipe@1 = gleam@string:trim(_pipe), string:lowercase(_pipe@1) end). -file("src/pedantic/decode.gleam", 815). ?DOC(" Trims and lowercases a UUID string.\n"). -spec normalize_uuid(decoder(binary())) -> decoder(binary()). normalize_uuid(Decoder) -> map(Decoder, fun(Value) -> _pipe = Value, _pipe@1 = gleam@string:trim(_pipe), string:lowercase(_pipe@1) end). -file("src/pedantic/decode.gleam", 822). ?DOC(" Trims a string and replaces blank values with `default_value`.\n"). -spec default_if_blank(decoder(binary()), binary()) -> decoder(binary()). default_if_blank(Decoder, Default_value) -> map( Decoder, fun(Value) -> Trimmed = gleam@string:trim(Value), case gleam@string:is_empty(Trimmed) of true -> Default_value; false -> Trimmed end end ). -file("src/pedantic/decode.gleam", 836). ?DOC(" Trims a string and turns blank values into `None`.\n"). -spec empty_as_none(decoder(binary())) -> decoder(gleam@option:option(binary())). empty_as_none(Decoder) -> map( Decoder, fun(Value) -> Trimmed = gleam@string:trim(Value), case gleam@string:is_empty(Trimmed) of true -> none; false -> {some, Trimmed} end end ). -file("src/pedantic/decode.gleam", 900). -spec length(decoder(binary()), integer()) -> decoder(binary()). length(Decoder, Len) -> refine( Decoder, fun(Val) -> Actual_len = string:length(Val), case Actual_len =:= Len of true -> {ok, Val}; false -> {error, {invalid_format, <<"Length must be exactly "/utf8, (erlang:integer_to_binary(Len))/binary>>}} end end ). -file("src/pedantic/decode.gleam", 913). -spec is_valid_email(binary()) -> boolean(). is_valid_email(S) -> gleam_stdlib:contains_string(S, <<"@"/utf8>>) andalso gleam_stdlib:contains_string( S, <<"."/utf8>> ). -file("src/pedantic/decode.gleam", 917). -spec email(decoder(binary()), binary()) -> decoder(binary()). email(Decoder, Msg) -> check(Decoder, fun is_valid_email/1, Msg). -file("src/pedantic/decode.gleam", 921). -spec is_valid_uuid(binary()) -> boolean(). is_valid_uuid(S) -> Segments = gleam@string:split(S, <<"-"/utf8>>), case gleam@list:map(Segments, fun string:length/1) of [8, 4, 4, 4, 12] -> true; _ -> false end. -file("src/pedantic/decode.gleam", 929). -spec uuid(decoder(binary()), binary()) -> decoder(binary()). uuid(Decoder, Msg) -> check(Decoder, fun is_valid_uuid/1, Msg). -file("src/pedantic/decode.gleam", 935). -spec any_of(list(decoder(DUN))) -> decoder(DUN). any_of(Decoders) -> Function = fun(Dyn) -> Result = gleam@list:find_map( Decoders, fun(Dec) -> case (erlang:element(3, Dec))(Dyn) of {ok, Val} -> {ok, Val}; {error, _} -> {error, nil} end end ), case Result of {ok, Val@1} -> {ok, Val@1}; {error, _} -> Err = pedantic@report:make_error( [], {wrong_type, <<"Union"/utf8>>, gleam_stdlib:classify_dynamic(Dyn)}, Dyn ), {error, {report, [Err], []}} end end, {decoder, {union, gleam@list:map(Decoders, fun(D) -> erlang:element(2, D) end)}, Function}. -file("src/pedantic/decode.gleam", 966). -spec min_size(decoder(list(DUR)), integer()) -> decoder(list(DUR)). min_size(Decoder, Minimum) -> refine(Decoder, fun(Val) -> case erlang:length(Val) >= Minimum of true -> {ok, Val}; false -> {error, {too_small, Minimum}} end end). -file("src/pedantic/decode.gleam", 975). -spec max_size(decoder(list(DUW)), integer()) -> decoder(list(DUW)). max_size(Decoder, Maximum) -> refine(Decoder, fun(Val) -> case erlang:length(Val) =< Maximum of true -> {ok, Val}; false -> {error, {too_large, Maximum}} end end). -file("src/pedantic/decode.gleam", 986). -spec int_range(integer(), integer()) -> decoder(integer()). int_range(Minimum, Maximum) -> _pipe = {decoder, primitive_int, fun decode_int/1}, _pipe@1 = min(_pipe, Minimum), max(_pipe@1, Maximum). -file("src/pedantic/decode.gleam", 992). -spec float_range(float(), float()) -> decoder(float()). float_range(Minimum, Maximum) -> refine( {decoder, primitive_float, fun decode_float/1}, fun(Val) -> case (Val >= Minimum) andalso (Val =< Maximum) of true -> {ok, Val}; false -> {error, {invalid_format, <<"Value must be within range"/utf8>>}} end end ). -file("src/pedantic/decode.gleam", 1001). -spec string_limit(integer(), integer()) -> decoder(binary()). string_limit(Minimum, Maximum) -> _pipe = {decoder, primitive_string, fun decode_string/1}, _pipe@1 = min_length(_pipe, Minimum), max_length(_pipe@1, Maximum). -file("src/pedantic/decode.gleam", 1012). -spec decode_non_empty_string(gleam@dynamic:dynamic_()) -> {ok, binary()} | {error, pedantic@report:report()}. decode_non_empty_string(Dyn) -> case (erlang:element(3, {decoder, primitive_string, fun decode_string/1}))( Dyn ) of {ok, S} -> case string:length(S) >= 1 of true -> {ok, S}; false -> Err = pedantic@report:make_error([], {too_short, 1}, Dyn), {error, {report, [Err], []}} end; {error, E} -> {error, E} end. -file("src/pedantic/decode.gleam", 1027). -spec non_empty_list(decoder(DVG)) -> decoder(list(DVG)). non_empty_list(Element_decoder) -> _pipe = list(Element_decoder), min_size(_pipe, 1). -file("src/pedantic/decode.gleam", 1037). ?DOC(" Sets the title metadata in the AST graph.\n"). -spec title(decoder(DVK), binary()) -> decoder(DVK). title(Decoder, Name) -> New_graph = case erlang:element(2, Decoder) of {annotated, Inner, Meta} -> {annotated, Inner, {metadata, {some, Name}, erlang:element(3, Meta), erlang:element(4, Meta)}}; Other -> {annotated, Other, {metadata, {some, Name}, none, none}} end, {decoder, New_graph, erlang:element(3, Decoder)}. -file("src/pedantic/decode.gleam", 1051). ?DOC(" Sets the description metadata in the AST graph.\n"). -spec describe(decoder(DVN), binary()) -> decoder(DVN). describe(Decoder, Desc) -> New_graph = case erlang:element(2, Decoder) of {annotated, Inner, Meta} -> {annotated, Inner, {metadata, erlang:element(2, Meta), {some, Desc}, erlang:element(4, Meta)}}; Other -> {annotated, Other, {metadata, none, {some, Desc}, none}} end, {decoder, New_graph, erlang:element(3, Decoder)}. -file("src/pedantic/decode.gleam", 1065). ?DOC(" Sets the example metadata in the AST graph.\n"). -spec example(decoder(DVQ), gleam@dynamic:dynamic_()) -> decoder(DVQ). example(Decoder, Ex) -> New_graph = case erlang:element(2, Decoder) of {annotated, Inner, Meta} -> {annotated, Inner, {metadata, erlang:element(2, Meta), erlang:element(3, Meta), {some, Ex}}}; Other -> {annotated, Other, {metadata, none, none, {some, Ex}}} end, {decoder, New_graph, erlang:element(3, Decoder)}.