@heinlein-video/rrule
Version:
rrule fork. Includes the src/ folder for typescript sourceMaps
181 lines (150 loc) • 4.62 kB
text/typescript
import { notEmpty, repeat, range, isPresent } from '../helpers'
import { ParsedOptions, Frequency } from '../types'
import { YearInfo, rebuildYear } from './yearinfo'
import { rebuildMonth, MonthInfo } from './monthinfo'
import { easter } from './easter'
import { Time } from '../datetime'
import { datetime, sort, toOrdinal } from '../dateutil'
export type DaySet = [(number | null)[], number, number]
export type GetDayset = () => DaySet
// =============================================================================
// Iterinfo
// =============================================================================
export default class Iterinfo {
public yearinfo: YearInfo
public monthinfo: MonthInfo
public eastermask: number[] | null
// eslint-disable-next-line no-empty-function
constructor(private options: ParsedOptions) {}
rebuild(year: number, month: number) {
const options = this.options
if (year !== this.lastyear) {
this.yearinfo = rebuildYear(year, options)
}
if (
notEmpty(options.bynweekday) &&
(month !== this.lastmonth || year !== this.lastyear)
) {
const { yearlen, mrange, wdaymask } = this.yearinfo
this.monthinfo = rebuildMonth(
year,
month,
yearlen,
mrange,
wdaymask,
options
)
}
if (isPresent(options.byeaster)) {
this.eastermask = easter(year, options.byeaster)
}
}
get lastyear() {
return this.monthinfo ? this.monthinfo.lastyear : null
}
get lastmonth() {
return this.monthinfo ? this.monthinfo.lastmonth : null
}
get yearlen() {
return this.yearinfo.yearlen
}
get yearordinal() {
return this.yearinfo.yearordinal
}
get mrange() {
return this.yearinfo.mrange
}
get wdaymask() {
return this.yearinfo.wdaymask
}
get mmask() {
return this.yearinfo.mmask
}
get wnomask() {
return this.yearinfo.wnomask
}
get nwdaymask() {
return this.monthinfo ? this.monthinfo.nwdaymask : []
}
get nextyearlen() {
return this.yearinfo.nextyearlen
}
get mdaymask() {
return this.yearinfo.mdaymask
}
get nmdaymask() {
return this.yearinfo.nmdaymask
}
ydayset() {
return [range(this.yearlen), 0, this.yearlen]
}
mdayset(_: unknown, month: number) {
const start = this.mrange[month - 1]
const end = this.mrange[month]
const set = repeat<number | null>(null, this.yearlen)
for (let i = start; i < end; i++) set[i] = i
return [set, start, end]
}
wdayset(year: number, month: number, day: number) {
// We need to handle cross-year weeks here.
const set = repeat<number | null>(null, this.yearlen + 7)
let i = toOrdinal(datetime(year, month, day)) - this.yearordinal
const start = i
for (let j = 0; j < 7; j++) {
set[i] = i
++i
if (this.wdaymask[i] === this.options.wkst) break
}
return [set, start, i]
}
ddayset(year: number, month: number, day: number) {
const set = repeat(null, this.yearlen) as (number | null)[]
const i = toOrdinal(datetime(year, month, day)) - this.yearordinal
set[i] = i
return [set, i, i + 1]
}
htimeset(hour: number, _: number, second: number, millisecond: number) {
let set: Time[] = []
this.options.byminute.forEach((minute) => {
set = set.concat(this.mtimeset(hour, minute, second, millisecond))
})
sort(set)
return set
}
mtimeset(hour: number, minute: number, _: number, millisecond: number) {
const set = this.options.bysecond.map(
(second) => new Time(hour, minute, second, millisecond)
)
sort(set)
return set
}
stimeset(hour: number, minute: number, second: number, millisecond: number) {
return [new Time(hour, minute, second, millisecond)]
}
getdayset(freq: Frequency): (y: number, m: number, d: number) => DaySet {
switch (freq) {
case Frequency.YEARLY:
return this.ydayset.bind(this)
case Frequency.MONTHLY:
return this.mdayset.bind(this)
case Frequency.WEEKLY:
return this.wdayset.bind(this)
case Frequency.DAILY:
return this.ddayset.bind(this)
default:
return this.ddayset.bind(this)
}
}
gettimeset(
freq: Frequency.HOURLY | Frequency.MINUTELY | Frequency.SECONDLY
): (h: number, m: number, s: number, ms: number) => Time[] {
switch (freq) {
case Frequency.HOURLY:
return this.htimeset.bind(this)
case Frequency.MINUTELY:
return this.mtimeset.bind(this)
case Frequency.SECONDLY:
return this.stimeset.bind(this)
}
}
}