UNPKG

queuex-sdk

Version:

A TypeScript-based queue management SDK with Redis support

102 lines (101 loc) 3.66 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.CronParser = void 0; class CronParser { constructor(expression) { this.fields = this.parseExpression(expression); } /** * * @param expression cron expression * @returns cron fields * @throws Error if the expression is invalid * * @example * * * * * * (seconds, minutes, hours, day of month, month, day of week) * @example 0 0 0 * * * (midnight every day) * * */ parseExpression(expression) { const parts = expression.trim().split(/\s+/); if (parts.length !== 6) { throw new Error(`Invalid cron expression: expected 6 fields, got ${parts.length}`); } const ranges = [ { min: 0, max: 59 }, // seconds { min: 0, max: 59 }, // minutes { min: 0, max: 23 }, // hours { min: 1, max: 31 }, // day of month { min: 1, max: 12 }, // month { min: 0, max: 6 }, // day of week ]; return parts.map((part, i) => this.parseField(part, ranges[i].min, ranges[i].max)); } parseField(field, min, max) { if (field === '*') { return { min, max, values: Array.from({ length: max - min + 1 }, (_, i) => min + i), }; } if (field.startsWith('*/')) { const step = parseInt(field.slice(2), 10); if (isNaN(step) || step <= 0) throw new Error(`Invalid step value in ${field}`); const values = []; for (let i = min; i <= max; i += step) { values.push(i); } return { min, max, values }; } const value = parseInt(field, 10); if (isNaN(value) || value < min || value > max) { throw new Error(`Invalid value ${field} for range ${min}-${max}`); } return { min, max, values: [value] }; } next(from = new Date()) { const now = new Date(from); now.setMilliseconds(0); const maxIterations = 1000 * 60 * 60 * 24; // 1 day max let iterations = 0; while (iterations < maxIterations) { now.setSeconds(now.getSeconds() + 1); iterations++; const year = now.getFullYear(); const month = now.getMonth() + 1; const day = now.getDate(); const dow = now.getDay(); const hour = now.getHours(); const min = now.getMinutes(); const sec = now.getSeconds(); if (!this.fields[4].values.includes(month)) { now.setMonth(now.getMonth() + 1, 1); now.setHours(0, 0, 0); continue; } if (!this.fields[3].values.includes(day) || !this.fields[5].values.includes(dow)) { now.setDate(now.getDate() + 1); now.setHours(0, 0, 0); continue; } if (!this.fields[2].values.includes(hour)) { now.setHours(now.getHours() + 1, 0, 0); continue; } if (!this.fields[1].values.includes(min)) { now.setHours(now.getHours() + 1, 0); continue; } if (!this.fields[0].values.includes(sec)) { now.setMinutes(now.getMinutes() + 1); continue; } return new Date(now); } throw new Error('No valid next execution time found within 24 hours'); } } exports.CronParser = CronParser;