import { Day , DayProperty } from './Day' ; import { FrequencyValue , FrequencyValueEvery } from './Frequency' ; import { Functions as fn } from './Functions' ; import { Locales } from './Locale' ; import { Schedule , ScheduleInput } from './Schedule' ; import { Weekday } from './Weekday' ; param day returns export type DescribePattern = ( day : Day ) => string ; /**
 * A rule helps parse [[ScheduleInput]] and determines whether it matches the
 * given pattern.
 *
 * - When a number is given, the input MUST be an array of the same length and contain any values.
 * - When an array of numbers is given, the input MUST be an array containing the same values.
 * - When a TRUE is given the input MUST contain that property and can be any value.
 * - When a FALSE is given the input MAY contain that property (optional).
 * - When a property is NOT specified, the input MUST NOT contain that property.
 * - When an object with every is given, the input must match the every and offset values (have the same frequency).
 */ export type PatternRule = number | number [ ] | boolean | FrequencyValueEvery ; /**
 * The set of rules you can specify for determining if a [[ScheduleInput]]
 * matches a pattern.
 */ export interface PatternRules { dayOfWeek ? : PatternRule ; dayOfMonth ? : PatternRule ; lastDayOfMonth ? : PatternRule ; dayOfYear ? : PatternRule ; month ? : PatternRule ; week ? : PatternRule ; year ? : PatternRule ; weekOfYear ? : PatternRule ; weekspanOfYear ? : PatternRule ; fullWeekOfYear ? : PatternRule ; lastWeekspanOfYear ? : PatternRule ; lastFullWeekOfYear ? : PatternRule ; weekOfMonth ? : PatternRule ; weekspanOfMonth ? : PatternRule ; fullWeekOfMonth ? : PatternRule ; lastWeekspanOfMonth ? : PatternRule ; lastFullWeekOfMonth ? : PatternRule ; } /**
 * A class which helps describe [[ScheduleInput]] if it matches a pattern.
 */ export class Pattern { /**
     * The properties in the [[ScheduleInput]] which are compared against the
     * rules of a pattern.
     */ public static PROPS : DayProperty [ ] = [ 'dayOfWeek' , 'dayOfMonth' , 'lastDayOfMonth' , 'dayOfYear' , 'month' , 'week' , 'year' , 'weekOfYear' , 'weekspanOfYear' , 'fullWeekOfYear' , 'lastWeekspanOfYear' , 'lastFullWeekOfYear' , 'weekOfMonth' , 'weekspanOfMonth' , 'fullWeekOfMonth' , 'lastWeekspanOfMonth' , 'lastFullWeekOfMonth' ] ; /**
     * Whether this pattern should be "listed" or not. Visual schedulers may
     * provide a shortcut to describing and changing a [[Schedule]] through
     * patterns and any pattern where listed is `true` could be an option in a
     * list. The default patterns are all listed.
     */ public listed : boolean ; /**
     * The function which describes this pattern given a [[Day]] to base it on.
     */ public describe : DescribePattern ; /**
     * The name of this pattern. This is not typically displayed to a user, just
     * to uniquely identify a pattern.
     */ public name : string ; /**
     * The rules for matching a pattern to a [[Schedule]] or applying a pattern to
     * a schedule.
     */ public rules : PatternRules ; param name param listed param describe param rules public constructor ( name , listed , describe , rules ) { this . name = name ; this . listed = listed ; this . describe = describe ; this . rules = rules ; } param schedule param day returns public apply < M , I extends ScheduleInput < M > | Schedule < M > > ( schedule , day ) { if ( schedule instanceof Schedule ) { this . applyGeneric ( day , ( prop , frequency ) => schedule . setFrequency ( prop , frequency ) , ( prop ) => schedule . setFrequency ( prop ) ) ; schedule . updateChecks ( ) ; } else { this . applyGeneric ( day , ( prop , frequency ) => schedule [ prop ] = frequency , ( prop ) => delete schedule [ prop ] ) ; } return schedule ; } param day param setFrequency param removeFrequency public applyGeneric ( day , setFrequency , removeFrequency ) { for ( const prop of Pattern . PROPS ) { const rule = this . rules [ prop ] ; if ( rule === 1 ) { setFrequency ( prop , [ day [ prop ] ] ) ; } if ( fn . isArray ( rule ) ) { setFrequency ( prop , rule ) ; } if ( ! fn . isDefined ( rule ) ) { removeFrequency ( prop ) ; } } } param schedule param exactlyWith returns public isMatch < M , I extends ScheduleInput < M > | Schedule < M > > ( schedule , exactlyWith ? ) { if ( schedule instanceof Schedule ) { return this . isMatchGeneric ( ( prop ) => schedule [ prop ] . input , exactlyWith ) ; } else { return this . isMatchGeneric ( ( prop ) => schedule [ prop ] , exactlyWith ) ; } } param input param exactlyWith returns public isMatchGeneric ( getFrequency , exactlyWith ? ) { const exactly = fn . isDefined ( exactlyWith ) ; for ( const prop of Pattern . PROPS ) { const rule = this . rules [ prop ] ; const curr = getFrequency ( prop ) ; if ( rule === false ) { continue ; } if ( rule === true && ! curr ) { return false ; } if ( ! fn . isDefined ( rule ) && curr ) { return false ; } if ( fn . isNumber ( rule ) ) { if ( fn . isArray ( curr ) && curr . length === rule ) { if ( exactly && curr . indexOf ( exactlyWith [ prop ] ) === - 1 ) { return false ; } } else { return false ; } } if ( fn . isArray ( rule ) ) { if ( ! fn . isArray ( curr ) ) { return false ; } if ( rule . length !== curr . length ) { return false ; } for ( let i = 0 ; i < rule . length ; i ++ ) { if ( rule [ i ] !== curr [ i ] ) { return false ; } } if ( exactly && rule . indexOf ( exactlyWith [ prop ] ) === - 1 ) { return false ; } } if ( fn . isFrequencyValueEvery ( rule ) ) { if ( ! fn . isFrequencyValueEvery ( curr ) ) { return false ; } const ruleOffset = rule . offset || 0 ; const currOffset = curr . offset || 0 ; if ( currOffset !== ruleOffset || curr . every !== rule . every ) { return false ; } if ( exactly && ( exactlyWith [ prop ] % rule . every ) !== ruleOffset ) { return false ; } } } return true ; } param name return public static withName ( name ) { return PatternMap [ name ] ; } param input param listedOnly param exactlyWith see public static findMatch < M , I extends ScheduleInput < M > | Schedule < M > > ( input , listedOnly = true , exactlyWith ? ) { for ( const pattern of Patterns ) { if ( ( pattern . listed || ! listedOnly ) && pattern . isMatch < M , I > ( input , exactlyWith ) ) { return pattern ; } } return null ; } } see export let Patterns = [ new Pattern ( 'none' , true , ( day ) => Locales . current . patternNone ( day ) , { year : 1 , month : 1 , dayOfMonth : 1 } ) , new Pattern ( 'daily' , true , ( day ) => Locales . current . patternDaily ( day ) , { } ) , new Pattern ( 'weekly' , true , ( day ) => Locales . current . patternWeekly ( day ) , { dayOfWeek : 1 } ) , new Pattern ( 'monthlyWeek' , true , ( day ) => Locales . current . patternMonthlyWeek ( day ) , { dayOfWeek : 1 , weekspanOfMonth : 1 } ) , new Pattern ( 'annually' , true , ( day ) => Locales . current . patternAnnually ( day ) , { month : 1 , dayOfMonth : 1 } ) , new Pattern ( 'annuallyMonthWeek' , true , ( day ) => Locales . current . patternAnnuallyMonthWeek ( day ) , { month : 1 , dayOfWeek : 1 , weekspanOfMonth : 1 } ) , new Pattern ( 'weekday' , true , ( day ) => Locales . current . patternWeekday ( day ) , { dayOfWeek : [ Weekday . MONDAY , Weekday . TUESDAY , Weekday . WEDNESDAY , Weekday . THURSDAY , Weekday . FRIDAY ] } ) , new Pattern ( 'monthly' , true , ( day ) => Locales . current . patternMonthly ( day ) , { dayOfMonth : 1 } ) , new Pattern ( 'lastDay' , true , ( day ) => Locales . current . patternLastDay ( day ) , { lastDayOfMonth : [ 1 ] } ) , new Pattern ( 'lastDayOfMonth' , true , ( day ) => Locales . current . patternLastDayOfMonth ( day ) , { month : 1 , lastDayOfMonth : [ 1 ] } ) , new Pattern ( 'lastWeekday' , true , ( day ) => Locales . current . patternLastWeekday ( day ) , { lastWeekspanOfMonth : [ 0 ] , dayOfWeek : 1 , month : 1 } ) , new Pattern ( 'custom' , true , ( day ) => Locales . current . patternCustom ( day ) , { dayOfWeek : false , dayOfMonth : false , lastDayOfMonth : false , dayOfYear : false , year : false , month : false , week : false , weekOfYear : false , weekspanOfYear : false , fullWeekOfYear : false , lastWeekspanOfYear : false , lastFullWeekOfYear : false , weekOfMonth : false , weekspanOfMonth : false , fullWeekOfMonth : false , lastWeekspanOfMonth : false , lastFullWeekOfMonth : false } ) ] ; see export let PatternMap = { } ; for ( const pattern of Patterns ) { PatternMap [ pattern . name ] = pattern ; }