src/automata@cron.erl

-module(automata@cron).
-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).
-define(FILEPATH, "src/automata/cron.gleam").
-export([parse/1, validate/1, normalize/1, to_string/1, matches_plan/2, matches/2, iterator_after_plan/2, iterator_after/2, next_after_plan/2, next_after/2, builder/0, any/0, at/1, between/2, every/1, every_from/2, every_between/3, one_of/1, item_exact/1, item_range/2, item_step_any/1, item_step_from/2, item_step_between/3, with_minute/2, with_hour/2, with_day_of_month/2, with_month/2, with_day_of_week/2, build/1]).

-if(?OTP_RELEASE >= 27).
-define(MODULEDOC(Str), -moduledoc(Str)).
-define(DOC(Str), -doc(Str)).
-else.
-define(MODULEDOC(Str), -compile([])).
-define(DOC(Str), -compile([])).
-endif.

?MODULEDOC(
    " UNIX 5-field cron stack: parse a cron string, validate it,\n"
    " normalise it into a fast-evaluation `CronPlan`, and ask whether a\n"
    " given `ValidDateTime` matches or what the next match is. This\n"
    " module is the user-facing facade; the typed phases live in the\n"
    " `automata/cron/{ast,parser,validator,normalize,evaluator,iterator,\n"
    " next,builder}` submodules.\n"
).

-file("src/automata/cron.gleam", 23).
?DOC(
    " Parse a UNIX 5-field cron expression (`minute hour day-of-month\n"
    " month day-of-week`) into a `RawCron` AST. Returns a `ParseError`\n"
    " for syntactic problems such as wrong field count or empty fields.\n"
    " Range and alias validation is done separately by `validate/1`.\n"
).
-spec parse(binary()) -> {ok, automata@cron@ast:raw_cron()} |
    {error, automata@cron@parser:parse_error()}.
parse(Input) ->
    automata@cron@parser:parse(Input).

-file("src/automata/cron.gleam", 30).
?DOC(
    " Validate a `RawCron` and return a `ValidCron` (opaque) when every\n"
    " field is in range and consistent. The returned value is the only\n"
    " shape the rest of the pipeline accepts.\n"
).
-spec validate(automata@cron@ast:raw_cron()) -> {ok,
        automata@cron@validator:valid_cron()} |
    {error, automata@cron@validator:validation_error()}.
validate(Raw) ->
    automata@cron@validator:validate(Raw).

-file("src/automata/cron.gleam", 39).
?DOC(
    " Pre-compute the lookup tables `evaluator`/`iterator`/`next` need.\n"
    " Reuse the resulting `CronPlan` across calls if you evaluate the\n"
    " same spec many times — see the `*_plan` variants.\n"
).
-spec normalize(automata@cron@validator:valid_cron()) -> automata@cron@normalize:cron_plan().
normalize(Spec) ->
    automata@cron@normalize:normalize(Spec).

-file("src/automata/cron.gleam", 44).
?DOC(" Render a `ValidCron` back to its canonical 5-field string form.\n").
-spec to_string(automata@cron@validator:valid_cron()) -> binary().
to_string(Spec) ->
    automata@cron@validator:to_string(Spec).

-file("src/automata/cron.gleam", 75).
?DOC(
    " Same as `matches/2` but takes an already-`normalize`d `CronPlan`,\n"
    " so callers that evaluate the same spec many times can pay the\n"
    " normalisation cost once.\n"
).
-spec matches_plan(
    automata@cron@normalize:cron_plan(),
    automata@schedule@ast:valid_date_time()
) -> boolean().
matches_plan(Plan, At) ->
    automata@cron@evaluator:matches(
        Plan,
        automata@schedule@ast:valid_datetime_value(At)
    ).

-file("src/automata/cron.gleam", 48).
-spec matches(
    automata@cron@validator:valid_cron(),
    automata@schedule@ast:valid_date_time()
) -> boolean().
matches(Spec, At) ->
    _pipe = Spec,
    _pipe@1 = automata@cron@normalize:normalize(_pipe),
    matches_plan(_pipe@1, At).

-file("src/automata/cron.gleam", 83).
?DOC(" Plan-reuse counterpart to `iterator_after/2`.\n").
-spec iterator_after_plan(
    automata@cron@normalize:cron_plan(),
    automata@schedule@ast:boundary()
) -> automata@cron@iterator:cron_iterator().
iterator_after_plan(Plan, Boundary) ->
    automata@cron@iterator:'after'(Plan, Boundary).

-file("src/automata/cron.gleam", 54).
-spec iterator_after(
    automata@cron@validator:valid_cron(),
    automata@schedule@ast:boundary()
) -> automata@cron@iterator:cron_iterator().
iterator_after(Spec, Boundary) ->
    _pipe = Spec,
    _pipe@1 = automata@cron@normalize:normalize(_pipe),
    iterator_after_plan(_pipe@1, Boundary).

-file("src/automata/cron.gleam", 91).
?DOC(" Plan-reuse counterpart to `next_after/2`.\n").
-spec next_after_plan(
    automata@cron@normalize:cron_plan(),
    automata@schedule@ast:valid_date_time()
) -> gleam@option:option(automata@schedule@ast:valid_date_time()).
next_after_plan(Plan, After) ->
    _pipe = automata@cron@next:next_after(
        Plan,
        automata@schedule@ast:valid_datetime_value(After)
    ),
    gleam@option:map(_pipe, fun automata@schedule@ast:unsafe_assume_valid/1).

-file("src/automata/cron.gleam", 63).
-spec next_after(
    automata@cron@validator:valid_cron(),
    automata@schedule@ast:valid_date_time()
) -> gleam@option:option(automata@schedule@ast:valid_date_time()).
next_after(Spec, After) ->
    _pipe = Spec,
    _pipe@1 = automata@cron@normalize:normalize(_pipe),
    next_after_plan(_pipe@1, After).

-file("src/automata/cron.gleam", 99).
-spec builder() -> automata@cron@builder:builder().
builder() ->
    automata@cron@builder:builder().

-file("src/automata/cron.gleam", 103).
-spec any() -> automata@cron@validator:selector().
any() ->
    automata@cron@builder:any().

-file("src/automata/cron.gleam", 107).
-spec at(integer()) -> automata@cron@validator:selector().
at(Value) ->
    automata@cron@builder:at(Value).

-file("src/automata/cron.gleam", 111).
-spec between(integer(), integer()) -> automata@cron@validator:selector().
between(Start, End) ->
    automata@cron@builder:between(Start, End).

-file("src/automata/cron.gleam", 115).
-spec every(integer()) -> automata@cron@validator:selector().
every(Step) ->
    automata@cron@builder:every(Step).

-file("src/automata/cron.gleam", 119).
-spec every_from(integer(), integer()) -> automata@cron@validator:selector().
every_from(Start, Step) ->
    automata@cron@builder:every_from(Start, Step).

-file("src/automata/cron.gleam", 123).
-spec every_between(integer(), integer(), integer()) -> automata@cron@validator:selector().
every_between(Start, End, Step) ->
    automata@cron@builder:every_between(Start, End, Step).

-file("src/automata/cron.gleam", 131).
-spec one_of(list(automata@cron@validator:item())) -> automata@cron@validator:selector().
one_of(Items) ->
    automata@cron@builder:one_of(Items).

-file("src/automata/cron.gleam", 136).
?DOC(" Build an `Item` matching a single value (for use inside `one_of`).\n").
-spec item_exact(integer()) -> automata@cron@validator:item().
item_exact(Value) ->
    {exact, Value}.

-file("src/automata/cron.gleam", 141).
?DOC(" Build an `Item` matching every value in `[from, to]` inclusive.\n").
-spec item_range(integer(), integer()) -> automata@cron@validator:item().
item_range(Start, End) ->
    {range, Start, End}.

-file("src/automata/cron.gleam", 147).
?DOC(
    " Build an `Item` of the form `*/step` (every `step`-th value across\n"
    " the field's full range).\n"
).
-spec item_step_any(integer()) -> automata@cron@validator:item().
item_step_any(Step) ->
    {step, step_any, Step}.

-file("src/automata/cron.gleam", 152).
?DOC(" Build an `Item` of the form `start/step`.\n").
-spec item_step_from(integer(), integer()) -> automata@cron@validator:item().
item_step_from(Start, Step) ->
    {step, {step_exact, Start}, Step}.

-file("src/automata/cron.gleam", 157).
?DOC(" Build an `Item` of the form `from-to/step`.\n").
-spec item_step_between(integer(), integer(), integer()) -> automata@cron@validator:item().
item_step_between(Start, End, Step) ->
    {step, {step_range, Start, End}, Step}.

-file("src/automata/cron.gleam", 165).
-spec with_minute(
    automata@cron@builder:builder(),
    automata@cron@validator:selector()
) -> automata@cron@builder:builder().
with_minute(Builder, Minute) ->
    automata@cron@builder:with_minute(Builder, Minute).

-file("src/automata/cron.gleam", 172).
-spec with_hour(
    automata@cron@builder:builder(),
    automata@cron@validator:selector()
) -> automata@cron@builder:builder().
with_hour(Builder, Hour) ->
    automata@cron@builder:with_hour(Builder, Hour).

-file("src/automata/cron.gleam", 179).
-spec with_day_of_month(
    automata@cron@builder:builder(),
    automata@cron@validator:selector()
) -> automata@cron@builder:builder().
with_day_of_month(Builder, Day_of_month) ->
    automata@cron@builder:with_day_of_month(Builder, Day_of_month).

-file("src/automata/cron.gleam", 186).
-spec with_month(
    automata@cron@builder:builder(),
    automata@cron@validator:selector()
) -> automata@cron@builder:builder().
with_month(Builder, Month) ->
    automata@cron@builder:with_month(Builder, Month).

-file("src/automata/cron.gleam", 193).
-spec with_day_of_week(
    automata@cron@builder:builder(),
    automata@cron@validator:selector()
) -> automata@cron@builder:builder().
with_day_of_week(Builder, Day_of_week) ->
    automata@cron@builder:with_day_of_week(Builder, Day_of_week).

-file("src/automata/cron.gleam", 200).
-spec build(automata@cron@builder:builder()) -> {ok,
        automata@cron@validator:valid_cron()} |
    {error, automata@cron@validator:validation_error()}.
build(Builder) ->
    automata@cron@builder:build(Builder).