Documentation
¶
Overview ¶
Package schedule parses Todoist-style free-text due dates and recurrence rules into the structured {dueDate, recurrence} form stored on a todo, and formats them back to free text. It is the single source of truth for the schedule grammar: the frontend calls the API to parse instead of keeping a parallel implementation in JavaScript.
Scope is the date-level grammar. Times ("every hour", "at 3pm") are rejected with a clear error rather than guessed, because the app is date-only.
Index ¶
- Variables
- func FirstDue(rc models.Recurrence, now time.Time) (due string, ok bool)
- func Format(rc models.Recurrence) string
- func FormatSchedule(dueDate string, rc *models.Recurrence, now time.Time) string
- func IsNone(raw string) bool
- func NextDue(current string, rc models.Recurrence, now time.Time) (next string, recurring bool, err error)
- func ParseDate(raw string, now time.Time) (string, bool)
- type QuickAdd
- type Schedule
Constants ¶
This section is empty.
Variables ¶
var ErrAdvance = errors.New("recurrence rule cannot be advanced")
ErrAdvance indicates a recurrence rule could not be turned into a date (unknown frequency or no reachable target). It is unreachable for rules that passed parseCore/Valid; the data layer wraps it so it still maps to HTTP 400.
Functions ¶
func FirstDue ¶
FirstDue returns the first due date for rc on or after now. A recurrence created without an explicit starting date uses this so a targeted rule such as "every last friday" or "every month on the 15th" lands on its first real occurrence rather than today. Plain intervals (every day/week/month/year) resolve to now itself. EndDate is not consulted: the first occurrence is the due date even when it already lies past the recurrence window. ok is false only for a malformed rule, which cannot reach here from Parse.
func Format ¶
func Format(rc models.Recurrence) string
Format renders the repeat pattern (without the leading "every" or start/end clauses) for badges and the input seed.
func FormatSchedule ¶
FormatSchedule renders a Schedule back to free text. The output round-trips through Parse, so editing shows what the user would retype. now is the reference "today": a due date equal to today omits the "starting" clause.
func IsNone ¶ added in v0.3.4
IsNone reports whether raw is the explicit "no due date" keyword, with an optional leading "due" qualifier ("due never").
func NextDue ¶
func NextDue(current string, rc models.Recurrence, now time.Time) (next string, recurring bool, err error)
NextDue returns the next due date strictly after current per rc. With FromCompletion set (Todoist's "every!") it advances from now (the completion date) instead of current. recurring is false when the next occurrence would fall past rc.EndDate, signalling the recurrence window has closed.
Types ¶
type QuickAdd ¶
type QuickAdd struct {
Title string
Labels []string
Priority string
Schedule Schedule
NoSchedule bool
}
QuickAdd is the parsed result of a quick-add line: a title, any #label tags, a single @priority, and an optional trailing schedule. NoSchedule is set when the trailing token was the explicit "never" keyword: the todo has no schedule on purpose, which must survive even where a server default due date applies to schedule-less creates.
func Extract ¶
Extract parses a quick-add line into a title, optional #label tags, and an optional trailing schedule. #label tokens (single words, no spaces/commas) are stripped first; the bare name without "#" is kept, de-duplicated case-insensitively in first-seen order. The remaining text is then split into title and schedule by scanning whitespace tokens left to right and taking the first split point at which the trailing suffix parses as a due date / recurrence, so the schedule is the longest trailing run and the title is everything before it.
Because the schedule grammar is anchored at the start (see Parse), a candidate suffix parses only when the schedule phrase begins on its first token — leading title words never produce a false match. parseMonthDayPhrase ignores tokens after a valid month/day, so a candidate is accepted only when removing its last token changes or invalidates the parse; that rejects lenient matches such as "aug 15 milk" where "milk" would otherwise be silently dropped from the title.
ok is false when the title would be empty (blank input, or only labels).
type Schedule ¶
type Schedule struct {
DueDate string
Recurrence *models.Recurrence
}
Schedule is the parsed result of a free-text due/recurrence field. A zero DueDate ("") means no due date; a nil Recurrence means non-recurring.