(params: {
cronExpression: string
timezone?: string
from?: Date
excludedDates?: string[] | null
endsAt?: Date | null
})
| 63 | * cron-produced occurrence time (not a rounded value) when excluding. |
| 64 | */ |
| 65 | export function computeNextRunAt(params: { |
| 66 | cronExpression: string |
| 67 | timezone?: string |
| 68 | from?: Date |
| 69 | excludedDates?: string[] | null |
| 70 | endsAt?: Date | null |
| 71 | }): Date | null { |
| 72 | const { cronExpression, timezone, from, excludedDates, endsAt } = params |
| 73 | let cron: Cron |
| 74 | try { |
| 75 | cron = new Cron(cronExpression, timezone ? { timezone } : undefined) |
| 76 | } catch { |
| 77 | return null |
| 78 | } |
| 79 | |
| 80 | const excluded = new Set( |
| 81 | (excludedDates ?? []).map((iso) => new Date(iso).getTime()).filter((ms) => !Number.isNaN(ms)) |
| 82 | ) |
| 83 | |
| 84 | let cursor = from ?? new Date() |
| 85 | for (let i = 0; i < MAX_OCCURRENCE_SKIP; i++) { |
| 86 | const next = cron.nextRun(cursor) |
| 87 | if (!next) return null |
| 88 | if (endsAt && next.getTime() > endsAt.getTime()) return null |
| 89 | if (!excluded.has(next.getTime())) return next |
| 90 | cursor = next |
| 91 | } |
| 92 | return null |
| 93 | } |
| 94 | |
| 95 | interface SubBlockValue { |
| 96 | value: string |
no outgoing calls
no test coverage detected