-module(automata@rrule@validator).
-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).
-define(FILEPATH, "src/automata/rrule/validator.gleam").
-export([frequency/1, interval/1, end_condition/1, by_day/1, by_month/1, by_month_day/1, by_hour/1, by_minute/1, validate/1, to_string/1]).
-export_type([frequency/0, weekday_specifier/0, until/0, end_condition/0, rule_part/0, valid_r_rule/0, validation_error/0, partial_rule/0]).
-type frequency() :: daily | weekly | monthly | yearly.
-type weekday_specifier() :: {every_weekday, automata@schedule@ast:weekday()} |
{nth_weekday, integer(), automata@schedule@ast:weekday()}.
-type until() :: {until_date, automata@schedule@ast:date()} |
{until_date_time, automata@schedule@ast:date_time()}.
-type end_condition() :: forever | {count, integer()} | {until, until()}.
-type rule_part() :: freq_part |
interval_part |
count_part |
until_part |
by_day_part |
by_month_part |
by_month_day_part |
by_hour_part |
by_minute_part.
-opaque valid_r_rule() :: {valid_r_rule,
frequency(),
integer(),
end_condition(),
gleam@option:option(list(weekday_specifier())),
gleam@option:option(list(integer())),
gleam@option:option(list(integer())),
gleam@option:option(list(integer())),
gleam@option:option(list(integer()))}.
-type validation_error() :: {missing_part, rule_part()} |
{duplicate_part, rule_part()} |
{unknown_part, binary()} |
{unsupported_part, binary()} |
{invalid_number, rule_part(), binary()} |
{invalid_part_value, rule_part(), binary()} |
{invalid_list, rule_part(), binary()} |
{out_of_range, rule_part(), integer(), integer(), integer()} |
{must_be_positive, rule_part(), integer()} |
{mutually_exclusive_parts, rule_part(), rule_part()} |
{numeric_weekday_requires_monthly_or_yearly, frequency()} |
{impossible_date, binary(), binary()} |
{incompatible_frequency_and_part, frequency(), rule_part()}.
-type partial_rule() :: {partial_rule,
gleam@option:option(frequency()),
gleam@option:option(integer()),
end_condition(),
gleam@option:option(list(weekday_specifier())),
gleam@option:option(list(integer())),
gleam@option:option(list(integer())),
gleam@option:option(list(integer())),
gleam@option:option(list(integer()))}.
-file("src/automata/rrule/validator.gleam", 60).
-spec frequency(valid_r_rule()) -> frequency().
frequency(Spec) ->
erlang:element(2, Spec).
-file("src/automata/rrule/validator.gleam", 64).
-spec interval(valid_r_rule()) -> integer().
interval(Spec) ->
erlang:element(3, Spec).
-file("src/automata/rrule/validator.gleam", 68).
-spec end_condition(valid_r_rule()) -> end_condition().
end_condition(Spec) ->
erlang:element(4, Spec).
-file("src/automata/rrule/validator.gleam", 72).
-spec by_day(valid_r_rule()) -> gleam@option:option(list(weekday_specifier())).
by_day(Spec) ->
erlang:element(5, Spec).
-file("src/automata/rrule/validator.gleam", 76).
-spec by_month(valid_r_rule()) -> gleam@option:option(list(integer())).
by_month(Spec) ->
erlang:element(6, Spec).
-file("src/automata/rrule/validator.gleam", 80).
-spec by_month_day(valid_r_rule()) -> gleam@option:option(list(integer())).
by_month_day(Spec) ->
erlang:element(7, Spec).
-file("src/automata/rrule/validator.gleam", 84).
-spec by_hour(valid_r_rule()) -> gleam@option:option(list(integer())).
by_hour(Spec) ->
erlang:element(8, Spec).
-file("src/automata/rrule/validator.gleam", 88).
-spec by_minute(valid_r_rule()) -> gleam@option:option(list(integer())).
by_minute(Spec) ->
erlang:element(9, Spec).
-file("src/automata/rrule/validator.gleam", 150).
-spec empty_partial_rule() -> partial_rule().
empty_partial_rule() ->
{partial_rule, none, none, forever, none, none, none, none, none}.
-file("src/automata/rrule/validator.gleam", 264).
-spec set_optional(
gleam@option:option(FYP),
{ok, FYP} | {error, validation_error()},
rule_part(),
fun((gleam@option:option(FYP)) -> partial_rule())
) -> {ok, partial_rule()} | {error, validation_error()}.
set_optional(Current, Parsed, Part, Setter) ->
case Parsed of
{error, Error} ->
{error, Error};
{ok, Value} ->
case Current of
none ->
{ok, Setter({some, Value})};
{some, _} ->
{error, {duplicate_part, Part}}
end
end.
-file("src/automata/rrule/validator.gleam", 334).
-spec validate_frequency_compatibility(valid_r_rule()) -> {ok, nil} |
{error, validation_error()}.
validate_frequency_compatibility(Spec) ->
case {erlang:element(2, Spec), erlang:element(7, Spec)} of
{weekly, {some, _}} ->
{error,
{incompatible_frequency_and_part, weekly, by_month_day_part}};
{_, _} ->
{ok, nil}
end.
-file("src/automata/rrule/validator.gleam", 396).
-spec ordinal_within_bound(integer(), integer()) -> boolean().
ordinal_within_bound(Ordinal, Bound) ->
((Ordinal /= 0) andalso (Ordinal >= (0 - Bound))) andalso (Ordinal =< Bound).
-file("src/automata/rrule/validator.gleam", 417).
-spec day_matches_month_day(integer(), integer()) -> boolean().
day_matches_month_day(Day, Maximum) ->
case Day > 0 of
true ->
Day =< Maximum;
false ->
(0 - Day) =< Maximum
end.
-file("src/automata/rrule/validator.gleam", 400).
-spec impossible_month_day(
gleam@option:option(list(integer())),
gleam@option:option(list(integer()))
) -> boolean().
impossible_month_day(By_month, By_month_day) ->
case {By_month, By_month_day} of
{{some, Months}, {some, Days}} ->
not gleam@list:any(
Months,
fun(Month) ->
Maximum = automata@internal@calendar:days_in_month(
2024,
Month
),
gleam@list:any(
Days,
fun(Day) -> day_matches_month_day(Day, Maximum) end
)
orelse gleam@list:any(
Days,
fun(Day@1) ->
day_matches_month_day(
Day@1,
automata@internal@calendar:days_in_month(
2025,
Month
)
)
end
)
end
);
{_, _} ->
false
end.
-file("src/automata/rrule/validator.gleam", 424).
-spec parse_frequency(binary()) -> {ok, frequency()} |
{error, validation_error()}.
parse_frequency(Value) ->
case string:uppercase(Value) of
<<"DAILY"/utf8>> ->
{ok, daily};
<<"WEEKLY"/utf8>> ->
{ok, weekly};
<<"MONTHLY"/utf8>> ->
{ok, monthly};
<<"YEARLY"/utf8>> ->
{ok, yearly};
_ ->
{error, {invalid_part_value, freq_part, Value}}
end.
-file("src/automata/rrule/validator.gleam", 434).
-spec parse_positive_int(rule_part(), binary()) -> {ok, integer()} |
{error, validation_error()}.
parse_positive_int(Part, Value) ->
case gleam_stdlib:parse_int(Value) of
{error, _} ->
{error, {invalid_number, Part, Value}};
{ok, Number} ->
case Number > 0 of
true ->
{ok, Number};
false ->
{error, {must_be_positive, Part, Number}}
end
end.
-file("src/automata/rrule/validator.gleam", 560).
-spec parse_weekday(binary()) -> {ok, automata@schedule@ast:weekday()} |
{error, nil}.
parse_weekday(Value) ->
case Value of
<<"MO"/utf8>> ->
{ok, monday};
<<"TU"/utf8>> ->
{ok, tuesday};
<<"WE"/utf8>> ->
{ok, wednesday};
<<"TH"/utf8>> ->
{ok, thursday};
<<"FR"/utf8>> ->
{ok, friday};
<<"SA"/utf8>> ->
{ok, saturday};
<<"SU"/utf8>> ->
{ok, sunday};
_ ->
{error, nil}
end.
-file("src/automata/rrule/validator.gleam", 529).
-spec parse_weekday_specifier(binary()) -> {ok, weekday_specifier()} |
{error, nil}.
parse_weekday_specifier(Value) ->
Upper = string:uppercase(Value),
Length = string:length(Upper),
case Length < 2 of
true ->
{error, nil};
false ->
Prefix_length = Length - 2,
Prefix = gleam@string:slice(Upper, 0, Prefix_length),
Suffix = gleam@string:slice(Upper, Prefix_length, 2),
case parse_weekday(Suffix) of
{error, nil} ->
{error, nil};
{ok, Weekday} ->
case Prefix of
<<""/utf8>> ->
{ok, {every_weekday, Weekday}};
_ ->
case gleam_stdlib:parse_int(Prefix) of
{ok, Ordinal} ->
case Ordinal =:= 0 of
true ->
{error, nil};
false ->
{ok,
{nth_weekday, Ordinal, Weekday}}
end;
{error, _} ->
{error, nil}
end
end
end
end.
-file("src/automata/rrule/validator.gleam", 514).
-spec collect_weekdays(list(binary()), list(weekday_specifier()), binary()) -> {ok,
list(weekday_specifier())} |
{error, validation_error()}.
collect_weekdays(Values, Acc, Original) ->
case Values of
[] ->
{ok, lists:reverse(Acc)};
[Value | Rest] ->
case parse_weekday_specifier(Value) of
{ok, Item} ->
collect_weekdays(Rest, [Item | Acc], Original);
{error, nil} ->
{error, {invalid_part_value, by_day_part, Original}}
end
end.
-file("src/automata/rrule/validator.gleam", 505).
-spec parse_weekday_specifiers(binary()) -> {ok, list(weekday_specifier())} |
{error, validation_error()}.
parse_weekday_specifiers(Value) ->
case gleam@list:any(
gleam@string:split(Value, <<","/utf8>>),
fun gleam@string:is_empty/1
) of
true ->
{error, {invalid_list, by_day_part, Value}};
false ->
collect_weekdays(gleam@string:split(Value, <<","/utf8>>), [], Value)
end.
-file("src/automata/rrule/validator.gleam", 654).
-spec parse_fixed_int(binary(), integer(), integer()) -> {ok, integer()} |
{error, nil}.
parse_fixed_int(Value, Start, Length) ->
gleam_stdlib:parse_int(gleam@string:slice(Value, Start, Length)).
-file("src/automata/rrule/validator.gleam", 596).
-spec parse_date(binary()) -> {ok, automata@schedule@ast:date()} |
{error, validation_error()}.
parse_date(Value) ->
case parse_fixed_int(Value, 0, 4) of
{error, _} ->
{error, {invalid_part_value, until_part, Value}};
{ok, Year} ->
case parse_fixed_int(Value, 4, 2) of
{error, _} ->
{error, {invalid_part_value, until_part, Value}};
{ok, Month} ->
case parse_fixed_int(Value, 6, 2) of
{error, _} ->
{error, {invalid_part_value, until_part, Value}};
{ok, Day} ->
Date = {date, Year, Month, Day},
case automata@internal@calendar:is_valid_date(Date) of
true ->
{ok, Date};
false ->
{error,
{invalid_part_value, until_part, Value}}
end
end
end
end.
-file("src/automata/rrule/validator.gleam", 617).
-spec parse_datetime(binary()) -> {ok, automata@schedule@ast:date_time()} |
{error, validation_error()}.
parse_datetime(Value) ->
case parse_date(gleam@string:slice(Value, 0, 8)) of
{error, Error} ->
{error, Error};
{ok, Date} ->
case parse_fixed_int(Value, 9, 2) of
{error, _} ->
{error, {invalid_part_value, until_part, Value}};
{ok, Hour} ->
case parse_fixed_int(Value, 11, 2) of
{error, _} ->
{error, {invalid_part_value, until_part, Value}};
{ok, Minute} ->
case parse_fixed_int(Value, 13, 2) of
{error, _} ->
{error,
{invalid_part_value, until_part, Value}};
{ok, Second} ->
Datetime = {date_time,
Date,
{time, Hour, Minute, Second}},
case automata@internal@calendar:is_valid_datetime(
Datetime
) of
true ->
{ok, Datetime};
false ->
{error,
{invalid_part_value,
until_part,
Value}}
end
end
end
end
end.
-file("src/automata/rrule/validator.gleam", 573).
-spec parse_until(binary()) -> {ok, until()} | {error, validation_error()}.
parse_until(Value) ->
case string:length(Value) of
8 ->
case parse_date(Value) of
{ok, Date} ->
{ok, {until_date, Date}};
{error, Error} ->
{error, Error}
end;
16 ->
case (gleam@string:slice(Value, 8, 1) =:= <<"T"/utf8>>) andalso (gleam@string:slice(
Value,
15,
1
)
=:= <<"Z"/utf8>>) of
false ->
{error, {invalid_part_value, until_part, Value}};
true ->
case parse_datetime(Value) of
{ok, Datetime} ->
{ok, {until_date_time, Datetime}};
{error, Error@1} ->
{error, Error@1}
end
end;
_ ->
{error, {invalid_part_value, until_part, Value}}
end.
-file("src/automata/rrule/validator.gleam", 691).
-spec weekday_to_string(automata@schedule@ast:weekday()) -> binary().
weekday_to_string(Day) ->
case Day of
monday ->
<<"MO"/utf8>>;
tuesday ->
<<"TU"/utf8>>;
wednesday ->
<<"WE"/utf8>>;
thursday ->
<<"TH"/utf8>>;
friday ->
<<"FR"/utf8>>;
saturday ->
<<"SA"/utf8>>;
sunday ->
<<"SU"/utf8>>
end.
-file("src/automata/rrule/validator.gleam", 374).
-spec validate_ordinal_range(list(weekday_specifier()), integer()) -> {ok, nil} |
{error, validation_error()}.
validate_ordinal_range(Values, Bound) ->
case Values of
[] ->
{ok, nil};
[Item | Rest] ->
case Item of
{nth_weekday, Ordinal, Day} ->
case ordinal_within_bound(Ordinal, Bound) of
true ->
validate_ordinal_range(Rest, Bound);
false ->
{error,
{invalid_part_value,
by_day_part,
<<(erlang:integer_to_binary(Ordinal))/binary,
(weekday_to_string(Day))/binary>>}}
end;
{every_weekday, _} ->
validate_ordinal_range(Rest, Bound)
end
end.
-file("src/automata/rrule/validator.gleam", 347).
-spec validate_weekday_ordinals(
frequency(),
gleam@option:option(list(weekday_specifier()))
) -> {ok, nil} | {error, validation_error()}.
validate_weekday_ordinals(Frequency, By_day) ->
case By_day of
none ->
{ok, nil};
{some, Values} ->
case gleam@list:any(Values, fun(Item) -> case Item of
{every_weekday, _} ->
false;
{nth_weekday, _, _} ->
true
end end) of
false ->
{ok, nil};
true ->
case Frequency of
monthly ->
validate_ordinal_range(Values, 5);
yearly ->
validate_ordinal_range(Values, 53);
_ ->
{error,
{numeric_weekday_requires_monthly_or_yearly,
Frequency}}
end
end
end.
-file("src/automata/rrule/validator.gleam", 684).
-spec weekday_specifier_to_string(weekday_specifier()) -> binary().
weekday_specifier_to_string(Specifier) ->
case Specifier of
{every_weekday, Day} ->
weekday_to_string(Day);
{nth_weekday, Ordinal, Day@1} ->
<<(erlang:integer_to_binary(Ordinal))/binary,
(weekday_to_string(Day@1))/binary>>
end.
-file("src/automata/rrule/validator.gleam", 670).
-spec append_weekday_part(
list(binary()),
gleam@option:option(list(weekday_specifier()))
) -> list(binary()).
append_weekday_part(Parts, Values) ->
case Values of
none ->
Parts;
{some, Items} ->
lists:append(
Parts,
[<<"BYDAY="/utf8,
(gleam@string:join(
gleam@list:map(
Items,
fun weekday_specifier_to_string/1
),
<<","/utf8>>
))/binary>>]
)
end.
-file("src/automata/rrule/validator.gleam", 703).
-spec frequency_to_string(frequency()) -> binary().
frequency_to_string(Frequency) ->
case Frequency of
daily ->
<<"DAILY"/utf8>>;
weekly ->
<<"WEEKLY"/utf8>>;
monthly ->
<<"MONTHLY"/utf8>>;
yearly ->
<<"YEARLY"/utf8>>
end.
-file("src/automata/rrule/validator.gleam", 732).
-spec int_list_to_string(list(integer())) -> binary().
int_list_to_string(Items) ->
gleam@string:join(
gleam@list:map(Items, fun erlang:integer_to_binary/1),
<<","/utf8>>
).
-file("src/automata/rrule/validator.gleam", 307).
-spec validate_semantics(valid_r_rule()) -> {ok, nil} |
{error, validation_error()}.
validate_semantics(Spec) ->
case validate_frequency_compatibility(Spec) of
{error, Error} ->
{error, Error};
{ok, _} ->
case validate_weekday_ordinals(
erlang:element(2, Spec),
erlang:element(5, Spec)
) of
{error, Error@1} ->
{error, Error@1};
{ok, _} ->
case impossible_month_day(
erlang:element(6, Spec),
erlang:element(7, Spec)
) of
true ->
{error,
{impossible_date,
case erlang:element(6, Spec) of
{some, Values} ->
int_list_to_string(Values);
none ->
<<"*"/utf8>>
end,
case erlang:element(7, Spec) of
{some, Values@1} ->
int_list_to_string(Values@1);
none ->
<<"*"/utf8>>
end}};
false ->
{ok, nil}
end
end
end.
-file("src/automata/rrule/validator.gleam", 280).
-spec finalize(partial_rule()) -> {ok, valid_r_rule()} |
{error, validation_error()}.
finalize(Partial) ->
case erlang:element(2, Partial) of
none ->
{error, {missing_part, freq_part}};
{some, Frequency} ->
Spec = {valid_r_rule, Frequency, case erlang:element(3, Partial) of
none ->
1;
{some, Interval} ->
Interval
end, erlang:element(4, Partial), erlang:element(5, Partial), erlang:element(
6,
Partial
), erlang:element(7, Partial), erlang:element(8, Partial), erlang:element(
9,
Partial
)},
case validate_semantics(Spec) of
{ok, _} ->
{ok, Spec};
{error, Error} ->
{error, Error}
end
end.
-file("src/automata/rrule/validator.gleam", 658).
-spec append_int_part(
list(binary()),
binary(),
gleam@option:option(list(integer()))
) -> list(binary()).
append_int_part(Parts, Name, Values) ->
case Values of
none ->
Parts;
{some, Items} ->
lists:append(
Parts,
[<<<<Name/binary, "="/utf8>>/binary,
(int_list_to_string(Items))/binary>>]
)
end.
-file("src/automata/rrule/validator.gleam", 743).
-spec dedup_sorted(list(integer()), integer(), list(integer())) -> list(integer()).
dedup_sorted(Rest, Previous, Acc) ->
case Rest of
[] ->
lists:reverse(Acc);
[Value | Tail] ->
case Value =:= Previous of
true ->
dedup_sorted(Tail, Previous, Acc);
false ->
dedup_sorted(Tail, Value, [Value | Acc])
end
end.
-file("src/automata/rrule/validator.gleam", 736).
-spec dedup_sort(list(integer()), list(integer())) -> list(integer()).
dedup_sort(Values, Acc) ->
case gleam@list:sort(Values, fun gleam@int:compare/2) of
[] ->
lists:reverse(Acc);
[First | Rest] ->
dedup_sorted(Rest, First, [First | Acc])
end.
-file("src/automata/rrule/validator.gleam", 469).
-spec parse_int_items(
list(binary()),
rule_part(),
integer(),
integer(),
boolean(),
list(integer())
) -> {ok, list(integer())} | {error, validation_error()}.
parse_int_items(Values, Part, Min, Max, Reject_zero, Acc) ->
case Values of
[] ->
{ok, dedup_sort(lists:reverse(Acc), [])};
[Value | Rest] ->
case gleam_stdlib:parse_int(Value) of
{error, _} ->
{error, {invalid_number, Part, Value}};
{ok, Number} ->
case Reject_zero andalso (Number =:= 0) of
true ->
{error, {invalid_part_value, Part, Value}};
false ->
case (Number < Min) orelse (Number > Max) of
true ->
{error,
{out_of_range, Part, Min, Max, Number}};
false ->
parse_int_items(
Rest,
Part,
Min,
Max,
Reject_zero,
[Number | Acc]
)
end
end
end
end.
-file("src/automata/rrule/validator.gleam", 448).
-spec parse_int_list(rule_part(), binary(), integer(), integer(), boolean()) -> {ok,
list(integer())} |
{error, validation_error()}.
parse_int_list(Part, Value, Min, Max, Reject_zero) ->
case gleam@list:any(
gleam@string:split(Value, <<","/utf8>>),
fun gleam@string:is_empty/1
) of
true ->
{error, {invalid_list, Part, Value}};
false ->
parse_int_items(
gleam@string:split(Value, <<","/utf8>>),
Part,
Min,
Max,
Reject_zero,
[]
)
end.
-file("src/automata/rrule/validator.gleam", 177).
-spec apply_part(binary(), binary(), partial_rule()) -> {ok, partial_rule()} |
{error, validation_error()}.
apply_part(Name, Value, Partial) ->
case Name of
<<"FREQ"/utf8>> ->
set_optional(
erlang:element(2, Partial),
parse_frequency(Value),
freq_part,
fun(Updated) ->
{partial_rule,
Updated,
erlang:element(3, Partial),
erlang:element(4, Partial),
erlang:element(5, Partial),
erlang:element(6, Partial),
erlang:element(7, Partial),
erlang:element(8, Partial),
erlang:element(9, Partial)}
end
);
<<"INTERVAL"/utf8>> ->
set_optional(
erlang:element(3, Partial),
parse_positive_int(interval_part, Value),
interval_part,
fun(Updated@1) ->
{partial_rule,
erlang:element(2, Partial),
Updated@1,
erlang:element(4, Partial),
erlang:element(5, Partial),
erlang:element(6, Partial),
erlang:element(7, Partial),
erlang:element(8, Partial),
erlang:element(9, Partial)}
end
);
<<"COUNT"/utf8>> ->
case parse_positive_int(count_part, Value) of
{error, Error} ->
{error, Error};
{ok, Count} ->
case erlang:element(4, Partial) of
forever ->
{ok,
{partial_rule,
erlang:element(2, Partial),
erlang:element(3, Partial),
{count, Count},
erlang:element(5, Partial),
erlang:element(6, Partial),
erlang:element(7, Partial),
erlang:element(8, Partial),
erlang:element(9, Partial)}};
{count, _} ->
{error, {duplicate_part, count_part}};
{until, _} ->
{error,
{mutually_exclusive_parts,
count_part,
until_part}}
end
end;
<<"UNTIL"/utf8>> ->
case parse_until(Value) of
{error, Error@1} ->
{error, Error@1};
{ok, Until} ->
case erlang:element(4, Partial) of
forever ->
{ok,
{partial_rule,
erlang:element(2, Partial),
erlang:element(3, Partial),
{until, Until},
erlang:element(5, Partial),
erlang:element(6, Partial),
erlang:element(7, Partial),
erlang:element(8, Partial),
erlang:element(9, Partial)}};
{count, _} ->
{error,
{mutually_exclusive_parts,
count_part,
until_part}};
{until, _} ->
{error, {duplicate_part, until_part}}
end
end;
<<"BYDAY"/utf8>> ->
set_optional(
erlang:element(5, Partial),
parse_weekday_specifiers(Value),
by_day_part,
fun(Updated@2) ->
{partial_rule,
erlang:element(2, Partial),
erlang:element(3, Partial),
erlang:element(4, Partial),
Updated@2,
erlang:element(6, Partial),
erlang:element(7, Partial),
erlang:element(8, Partial),
erlang:element(9, Partial)}
end
);
<<"BYMONTH"/utf8>> ->
set_optional(
erlang:element(6, Partial),
parse_int_list(by_month_part, Value, 1, 12, false),
by_month_part,
fun(Updated@3) ->
{partial_rule,
erlang:element(2, Partial),
erlang:element(3, Partial),
erlang:element(4, Partial),
erlang:element(5, Partial),
Updated@3,
erlang:element(7, Partial),
erlang:element(8, Partial),
erlang:element(9, Partial)}
end
);
<<"BYMONTHDAY"/utf8>> ->
set_optional(
erlang:element(7, Partial),
parse_int_list(by_month_day_part, Value, -31, 31, true),
by_month_day_part,
fun(Updated@4) ->
{partial_rule,
erlang:element(2, Partial),
erlang:element(3, Partial),
erlang:element(4, Partial),
erlang:element(5, Partial),
erlang:element(6, Partial),
Updated@4,
erlang:element(8, Partial),
erlang:element(9, Partial)}
end
);
<<"BYHOUR"/utf8>> ->
set_optional(
erlang:element(8, Partial),
parse_int_list(by_hour_part, Value, 0, 23, false),
by_hour_part,
fun(Updated@5) ->
{partial_rule,
erlang:element(2, Partial),
erlang:element(3, Partial),
erlang:element(4, Partial),
erlang:element(5, Partial),
erlang:element(6, Partial),
erlang:element(7, Partial),
Updated@5,
erlang:element(9, Partial)}
end
);
<<"BYMINUTE"/utf8>> ->
set_optional(
erlang:element(9, Partial),
parse_int_list(by_minute_part, Value, 0, 59, false),
by_minute_part,
fun(Updated@6) ->
{partial_rule,
erlang:element(2, Partial),
erlang:element(3, Partial),
erlang:element(4, Partial),
erlang:element(5, Partial),
erlang:element(6, Partial),
erlang:element(7, Partial),
erlang:element(8, Partial),
Updated@6}
end
);
<<"BYSECOND"/utf8>> ->
{error, {unsupported_part, <<"BYSECOND"/utf8>>}};
<<"BYYEARDAY"/utf8>> ->
{error, {unsupported_part, <<"BYYEARDAY"/utf8>>}};
<<"BYWEEKNO"/utf8>> ->
{error, {unsupported_part, <<"BYWEEKNO"/utf8>>}};
<<"BYSETPOS"/utf8>> ->
{error, {unsupported_part, <<"BYSETPOS"/utf8>>}};
<<"WKST"/utf8>> ->
{error, {unsupported_part, <<"WKST"/utf8>>}};
<<"BYEASTER"/utf8>> ->
{error, {unsupported_part, <<"BYEASTER"/utf8>>}};
_ ->
{error, {unknown_part, Name}}
end.
-file("src/automata/rrule/validator.gleam", 163).
-spec collect(list(automata@rrule@ast:raw_rule_part()), partial_rule()) -> {ok,
valid_r_rule()} |
{error, validation_error()}.
collect(Parts, Partial) ->
case Parts of
[] ->
finalize(Partial);
[{raw_rule_part, Name, Value} | Rest] ->
case apply_part(Name, Value, Partial) of
{ok, Next} ->
collect(Rest, Next);
{error, Error} ->
{error, Error}
end
end.
-file("src/automata/rrule/validator.gleam", 121).
-spec validate(automata@rrule@ast:raw_r_rule()) -> {ok, valid_r_rule()} |
{error, validation_error()}.
validate(Raw) ->
collect(erlang:element(2, Raw), empty_partial_rule()).
-file("src/automata/rrule/validator.gleam", 754).
-spec pad2(integer()) -> binary().
pad2(Value) ->
case Value < 10 of
true ->
<<"0"/utf8, (erlang:integer_to_binary(Value))/binary>>;
false ->
erlang:integer_to_binary(Value)
end.
-file("src/automata/rrule/validator.gleam", 761).
-spec pad4(integer()) -> binary().
pad4(Value) ->
case Value < 10 of
true ->
<<"000"/utf8, (erlang:integer_to_binary(Value))/binary>>;
false ->
case Value < 100 of
true ->
<<"00"/utf8, (erlang:integer_to_binary(Value))/binary>>;
false ->
case Value < 1000 of
true ->
<<"0"/utf8,
(erlang:integer_to_binary(Value))/binary>>;
false ->
erlang:integer_to_binary(Value)
end
end
end.
-file("src/automata/rrule/validator.gleam", 719).
-spec date_to_string(automata@schedule@ast:date()) -> binary().
date_to_string(Date) ->
<<<<(pad4(erlang:element(2, Date)))/binary,
(pad2(erlang:element(3, Date)))/binary>>/binary,
(pad2(erlang:element(4, Date)))/binary>>.
-file("src/automata/rrule/validator.gleam", 723).
-spec datetime_to_string(automata@schedule@ast:date_time()) -> binary().
datetime_to_string(Datetime) ->
<<<<<<<<<<(date_to_string(erlang:element(2, Datetime)))/binary, "T"/utf8>>/binary,
(pad2(erlang:element(2, erlang:element(3, Datetime))))/binary>>/binary,
(pad2(erlang:element(3, erlang:element(3, Datetime))))/binary>>/binary,
(pad2(erlang:element(4, erlang:element(3, Datetime))))/binary>>/binary,
"Z"/utf8>>.
-file("src/automata/rrule/validator.gleam", 712).
-spec until_to_string(until()) -> binary().
until_to_string(Until) ->
case Until of
{until_date, Date} ->
date_to_string(Date);
{until_date_time, Datetime} ->
datetime_to_string(Datetime)
end.
-file("src/automata/rrule/validator.gleam", 127).
-spec to_string(valid_r_rule()) -> binary().
to_string(Spec) ->
Parts = [<<"FREQ="/utf8,
(frequency_to_string(erlang:element(2, Spec)))/binary>>],
Parts@1 = case erlang:element(4, Spec) of
forever ->
Parts;
{count, Count} ->
lists:append(
Parts,
[<<"COUNT="/utf8, (erlang:integer_to_binary(Count))/binary>>]
);
{until, Until} ->
lists:append(
Parts,
[<<"UNTIL="/utf8, (until_to_string(Until))/binary>>]
)
end,
Parts@2 = case erlang:element(3, Spec) =:= 1 of
true ->
Parts@1;
false ->
lists:append(
Parts@1,
[<<"INTERVAL="/utf8,
(erlang:integer_to_binary(erlang:element(3, Spec)))/binary>>]
)
end,
Parts@3 = append_weekday_part(Parts@2, erlang:element(5, Spec)),
Parts@4 = append_int_part(
Parts@3,
<<"BYMONTH"/utf8>>,
erlang:element(6, Spec)
),
Parts@5 = append_int_part(
Parts@4,
<<"BYMONTHDAY"/utf8>>,
erlang:element(7, Spec)
),
Parts@6 = append_int_part(
Parts@5,
<<"BYHOUR"/utf8>>,
erlang:element(8, Spec)
),
Parts@7 = append_int_part(
Parts@6,
<<"BYMINUTE"/utf8>>,
erlang:element(9, Spec)
),
gleam@string:join(Parts@7, <<";"/utf8>>).