(block: BlockState)
| 112 | * Returns validation result with error details if invalid |
| 113 | */ |
| 114 | export function validateScheduleBlock(block: BlockState): ScheduleValidationResult { |
| 115 | const scheduleType = getSubBlockValue(block, 'scheduleType') |
| 116 | |
| 117 | if (!scheduleType) { |
| 118 | return { |
| 119 | isValid: false, |
| 120 | error: 'Schedule type is required', |
| 121 | } |
| 122 | } |
| 123 | |
| 124 | const hasValidConfig = hasValidScheduleConfig(scheduleType, block) |
| 125 | |
| 126 | if (!hasValidConfig) { |
| 127 | return { |
| 128 | isValid: false, |
| 129 | error: getMissingConfigError(scheduleType), |
| 130 | scheduleType, |
| 131 | } |
| 132 | } |
| 133 | |
| 134 | const timezone = getSubBlockValue(block, 'timezone') || 'UTC' |
| 135 | |
| 136 | try { |
| 137 | // Get parsed schedule values (safe to use after validation passes) |
| 138 | const scheduleValues = getScheduleTimeValues(block) |
| 139 | const sanitizedScheduleValues = |
| 140 | scheduleType !== 'custom' ? { ...scheduleValues, cronExpression: null } : scheduleValues |
| 141 | |
| 142 | const cronExpression = generateCronExpression(scheduleType, sanitizedScheduleValues) |
| 143 | |
| 144 | const validation = validateCronExpression(cronExpression, timezone) |
| 145 | if (!validation.isValid) { |
| 146 | return { |
| 147 | isValid: false, |
| 148 | error: `Invalid cron expression: ${validation.error}`, |
| 149 | scheduleType, |
| 150 | } |
| 151 | } |
| 152 | |
| 153 | const nextRunAt = calculateNextRunTime(scheduleType, sanitizedScheduleValues) |
| 154 | |
| 155 | return { |
| 156 | isValid: true, |
| 157 | scheduleType, |
| 158 | cronExpression, |
| 159 | nextRunAt, |
| 160 | timezone, |
| 161 | } |
| 162 | } catch (error) { |
| 163 | return { |
| 164 | isValid: false, |
| 165 | error: getErrorMessage(error, 'Failed to generate schedule'), |
| 166 | scheduleType, |
| 167 | } |
| 168 | } |
| 169 | } |
| 170 | |
| 171 | /** |
no test coverage detected