import type { Moment } from 'moment' ; import { Recurrence } from './parseTasksRecurrence' ; export enum Status { Todo = 'Todo' , Done = 'Done' } export class Task { public readonly status : Status ; public readonly description : string ; public readonly path : string ; /**
     * The original character from within `[]` in the document.
     * Required to be added to the LI the same way obsidian does as a `data-task` attribute.
     */ public readonly originalStatusCharacter : string ; public readonly precedingHeader : string | null ; public readonly startDate : Moment | null ; public readonly scheduledDate : Moment | null ; public readonly dueDate : Moment | null ; public readonly doneDate : Moment | null ; public readonly recurrence : Recurrence | null ; /** The blockLink is a "^" annotation after the dates/recurrence rules. */ public readonly blockLink : string ; public static readonly dateFormat = 'YYYY-MM-DD' ; public static readonly taskRegex = /^([\s\t]*)[-*] +\[(.)\] *(.*)/u ; public static readonly startDateRegex = /🛫 ?(\d{4}-\d{2}-\d{2})$/u ; public static readonly scheduledDateRegex = /[⏳⌛] ?(\d{4}-\d{2}-\d{2})$/u ; public static readonly dueDateRegex = /[📅📆🗓] ?(\d{4}-\d{2}-\d{2})$/u ; public static readonly doneDateRegex = /✅ ?(\d{4}-\d{2}-\d{2})$/u ; public static readonly recurrenceRegex = /🔁([a-zA-Z0-9, !]+)$/u ; constructor ( { status , description , path , originalStatusCharacter , startDate , scheduledDate , dueDate , doneDate , recurrence , } ) { this . status = status ; this . description = description ; this . path = path ; this . originalStatusCharacter = originalStatusCharacter ; this . startDate = startDate ; this . scheduledDate = scheduledDate ; this . dueDate = dueDate ; this . doneDate = doneDate ; this . recurrence = recurrence ; } public static fromLine ( { line , path , } ) { const regexMatch = line . match ( Task . taskRegex ) ; if ( regexMatch === null ) { return null ; } const statusString = regexMatch [ 2 ] . toLowerCase ( ) ; let status ; switch ( statusString ) { case ' ' : status = Status . Todo ; break ; default : status = Status . Done ; } const body = regexMatch [ 3 ] . trim ( ) ; let description = body ; let matched ; let startDate = null ; let scheduledDate = null ; let dueDate = null ; let doneDate = null ; let recurrence = null ; const maxRuns = 7 ; let runs = 0 ; do { matched = false ; const doneDateMatch = description . match ( Task . doneDateRegex ) ; if ( doneDateMatch !== null ) { doneDate = window . moment ( doneDateMatch [ 1 ] , Task . dateFormat ) ; description = description . replace ( Task . doneDateRegex , '' ) . trim ( ) ; matched = true ; } const dueDateMatch = description . match ( Task . dueDateRegex ) ; if ( dueDateMatch !== null ) { dueDate = window . moment ( dueDateMatch [ 1 ] , Task . dateFormat ) ; description = description . replace ( Task . dueDateRegex , '' ) . trim ( ) ; matched = true ; } const scheduledDateMatch = description . match ( Task . scheduledDateRegex ) ; if ( scheduledDateMatch !== null ) { scheduledDate = window . moment ( scheduledDateMatch [ 1 ] , Task . dateFormat ) ; description = description . replace ( Task . scheduledDateRegex , '' ) . trim ( ) ; matched = true ; } const startDateMatch = description . match ( Task . startDateRegex ) ; if ( startDateMatch !== null ) { startDate = window . moment ( startDateMatch [ 1 ] , Task . dateFormat ) ; description = description . replace ( Task . startDateRegex , '' ) . trim ( ) ; matched = true ; } const recurrenceMatch = description . match ( Task . recurrenceRegex ) ; if ( recurrenceMatch !== null ) { recurrence = Recurrence . fromText ( { recurrenceRuleText : recurrenceMatch [ 1 ] . trim ( ) , startDate , scheduledDate , dueDate , } ) ; description = description . replace ( Task . recurrenceRegex , '' ) . trim ( ) ; matched = true ; } runs ++ ; } while ( matched && runs <= maxRuns ) ; const task = new Task ( { status , description , path , originalStatusCharacter : statusString , startDate , scheduledDate , dueDate , doneDate , recurrence , } ) ; return task ; } }