cronli5 0.2.0 → 0.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (57) hide show
  1. package/CHANGELOG.md +90 -0
  2. package/README.md +4 -4
  3. package/cronli5.min.js +2 -2
  4. package/dist/cronli5.cjs +514 -407
  5. package/dist/cronli5.js +514 -407
  6. package/dist/lang/de.cjs +296 -225
  7. package/dist/lang/de.js +296 -225
  8. package/dist/lang/en.cjs +471 -364
  9. package/dist/lang/en.js +471 -364
  10. package/dist/lang/es.cjs +318 -281
  11. package/dist/lang/es.js +318 -281
  12. package/dist/lang/fi.cjs +326 -276
  13. package/dist/lang/fi.js +326 -276
  14. package/dist/lang/zh.cjs +308 -236
  15. package/dist/lang/zh.js +308 -236
  16. package/package.json +1 -1
  17. package/src/core/analyze.ts +22 -21
  18. package/src/core/cadence.ts +164 -0
  19. package/src/core/index.ts +3 -1
  20. package/src/core/normalize.ts +3 -3
  21. package/src/core/parse.ts +1 -1
  22. package/src/core/{ir.ts → schedule.ts} +23 -24
  23. package/src/core/shapes.ts +8 -1
  24. package/src/core/specs.ts +1 -1
  25. package/src/core/util.ts +4 -83
  26. package/src/core/validate.ts +2 -2
  27. package/src/core/weekday.ts +54 -0
  28. package/src/cronli5.ts +7 -7
  29. package/src/lang/de/index.ts +329 -288
  30. package/src/lang/en/dialects.ts +1 -1
  31. package/src/lang/en/index.ts +640 -516
  32. package/src/lang/es/index.ts +342 -374
  33. package/src/lang/es/notes.md +1 -1
  34. package/src/lang/fi/dialects.ts +1 -1
  35. package/src/lang/fi/index.ts +367 -372
  36. package/src/lang/fi/notes.md +23 -8
  37. package/src/lang/fi/status.json +1 -1
  38. package/src/lang/zh/index.ts +344 -262
  39. package/src/types.ts +6 -6
  40. package/types/core/analyze.d.ts +4 -4
  41. package/types/core/cadence.d.ts +33 -0
  42. package/types/core/index.d.ts +3 -1
  43. package/types/core/normalize.d.ts +1 -1
  44. package/types/core/parse.d.ts +1 -1
  45. package/types/core/{ir.d.ts → schedule.d.ts} +16 -21
  46. package/types/core/shapes.d.ts +2 -1
  47. package/types/core/specs.d.ts +1 -1
  48. package/types/core/util.d.ts +1 -15
  49. package/types/core/weekday.d.ts +10 -0
  50. package/types/lang/de/index.d.ts +1 -1
  51. package/types/lang/en/dialects.d.ts +1 -1
  52. package/types/lang/en/index.d.ts +1 -1
  53. package/types/lang/es/index.d.ts +1 -1
  54. package/types/lang/fi/dialects.d.ts +1 -1
  55. package/types/lang/fi/index.d.ts +1 -1
  56. package/types/lang/zh/index.d.ts +1 -1
  57. package/types/types.d.ts +5 -5
package/dist/lang/es.js CHANGED
@@ -31,6 +31,16 @@ function isNonNegativeInteger(value) {
31
31
  const digits = /^\d+$/;
32
32
  return digits.test(value);
33
33
  }
34
+ function toFieldNumber(token, numberMap) {
35
+ return isNonNegativeInteger(token) ? +token : numberMap[token.toUpperCase()];
36
+ }
37
+
38
+ // src/core/shapes.ts
39
+ function isOpenStep(field) {
40
+ return field.indexOf("/") !== -1 && field.indexOf("-") === -1 && field.indexOf(",") === -1;
41
+ }
42
+
43
+ // src/core/cadence.ts
34
44
  function arithmeticStep(values) {
35
45
  if (values.length < 5) {
36
46
  return null;
@@ -46,6 +56,56 @@ function arithmeticStep(values) {
46
56
  }
47
57
  return { start: values[0], interval, last: values[values.length - 1] };
48
58
  }
59
+ function segmentsOf(schedule, field) {
60
+ return schedule.analyses.segments[field] ?? [];
61
+ }
62
+ function stepSegment(schedule, field) {
63
+ return segmentsOf(schedule, field)[0];
64
+ }
65
+ function singleValues(segments) {
66
+ const values = [];
67
+ for (const segment of segments) {
68
+ if (segment.kind !== "single") {
69
+ return null;
70
+ }
71
+ values.push(+segment.value);
72
+ }
73
+ return values;
74
+ }
75
+ function offsetCleanStride(stride) {
76
+ return stride.start < stride.interval && 24 % stride.interval === 0;
77
+ }
78
+ function renderStride(spec, parts) {
79
+ const { start, interval, cycle } = spec;
80
+ const tiles = cycle % interval === 0;
81
+ if (start === 0 && tiles) {
82
+ return parts.bare();
83
+ }
84
+ if (start < interval && tiles) {
85
+ return parts.offset();
86
+ }
87
+ return parts.bounded();
88
+ }
89
+ function hourListStride(values) {
90
+ if (values.length < 2) {
91
+ return null;
92
+ }
93
+ const interval = values[1] - values[0];
94
+ if (interval < 2) {
95
+ return null;
96
+ }
97
+ for (let i = 2; i < values.length; i += 1) {
98
+ if (values[i] - values[i - 1] !== interval) {
99
+ return null;
100
+ }
101
+ }
102
+ if (values[0] !== 0 && values.length < 5) {
103
+ return null;
104
+ }
105
+ return { interval, last: values[values.length - 1], start: values[0] };
106
+ }
107
+
108
+ // src/core/weekday.ts
49
109
  function weekdayDisplayKey(value) {
50
110
  return value === 0 ? 7 : value;
51
111
  }
@@ -66,9 +126,6 @@ function orderWeekdaysForDisplay(segments) {
66
126
  return pair[0];
67
127
  });
68
128
  }
69
- function toFieldNumber(token, numberMap) {
70
- return isNonNegativeInteger(token) ? +token : numberMap[token.toUpperCase()];
71
- }
72
129
 
73
130
  // src/lang/es/dialects.ts
74
131
  var es = {
@@ -95,15 +152,6 @@ function resolveDialect(dialect) {
95
152
  }
96
153
 
97
154
  // src/lang/es/index.ts
98
- function stepSegment(segments) {
99
- return segments[0];
100
- }
101
- function hourSegments(ir) {
102
- return ir.analyses.segments.hour;
103
- }
104
- function fieldSegments(ir, field) {
105
- return ir.analyses.segments[field];
106
- }
107
155
  var numeros = [
108
156
  "cero",
109
157
  "uno",
@@ -156,107 +204,107 @@ function normalizeOptions(options) {
156
204
  years: !!options.years
157
205
  };
158
206
  }
159
- function describe(ir, opts) {
160
- return applyYear(render(ir, ir.plan, opts), ir, opts);
207
+ function describe(schedule, opts) {
208
+ return applyYear(render(schedule, schedule.plan, opts), schedule, opts);
161
209
  }
162
- function render(ir, plan, opts) {
163
- const phrase = renderers[plan.kind](ir, plan, opts);
164
- if (!isDateWeekdayUnion(ir)) {
210
+ function render(schedule, plan, opts) {
211
+ const phrase = renderers[plan.kind](schedule, plan, opts);
212
+ if (!isDateWeekdayUnion(schedule)) {
165
213
  return phrase;
166
214
  }
167
- const lead = unionMonthLeadFull(ir);
168
- return (lead ? lead + " " : "") + phrase + unionYaseaSuffix(ir, opts);
215
+ const lead = unionMonthLeadFull(schedule);
216
+ return (lead ? lead + " " : "") + phrase + unionYaseaSuffix(schedule, opts);
169
217
  }
170
- function renderEverySecond(ir, plan, opts) {
171
- return "cada segundo" + trailingQualifier(ir, opts);
218
+ function renderEverySecond(schedule, plan, opts) {
219
+ return "cada segundo" + trailingQualifier(schedule, opts);
172
220
  }
173
- function renderStandaloneSeconds(ir, plan, opts) {
174
- return secondsLeadClause(ir, opts) + trailingQualifier(ir, opts);
221
+ function renderStandaloneSeconds(schedule, plan, opts) {
222
+ return secondsLeadClause(schedule, opts) + trailingQualifier(schedule, opts);
175
223
  }
176
- function renderSecondPastMinute(ir, plan, opts) {
177
- return "en el segundo " + ir.pattern.second + " de cada minuto" + trailingQualifier(ir, opts);
224
+ function renderSecondPastMinute(schedule, plan, opts) {
225
+ return "en el segundo " + schedule.pattern.second + " de cada minuto" + trailingQualifier(schedule, opts);
178
226
  }
179
- function renderSecondsWithinMinute(ir, plan, opts) {
180
- const minuteField = ir.pattern.minute;
227
+ function renderSecondsWithinMinute(schedule, plan, opts) {
228
+ const minuteField = schedule.pattern.minute;
181
229
  if (plan.singleSecond) {
182
- return "en el minuto " + minuteField + " y el segundo " + ir.pattern.second + " de cada hora" + trailingQualifier(ir, opts);
230
+ return "en el minuto " + minuteField + " y el segundo " + schedule.pattern.second + " de cada hora" + trailingQualifier(schedule, opts);
183
231
  }
184
- return secondsLeadClause(ir, opts) + ", en el minuto " + minuteField + " de cada hora" + trailingQualifier(ir, opts);
232
+ return secondsLeadClause(schedule, opts) + ", en el minuto " + minuteField + " de cada hora" + trailingQualifier(schedule, opts);
185
233
  }
186
- function secondsListAtClock(ir, rest, opts) {
234
+ function secondsListAtClock(schedule, rest, opts) {
187
235
  const clockPhrases = rest.times.map(function clock(time) {
188
236
  return atTime(timePhrase(time.hour, time.minute, null, opts));
189
237
  });
190
238
  const grouped = groupClockTimesByArticle(clockPhrases);
191
239
  const clockList = grouped.startsWith("a ") ? grouped.slice(2) : grouped;
192
- const stride = strideFromSegments(fieldSegments(ir, "second"), "segundo", "", opts);
193
- const secondsPhrase = stride ?? "en los segundos " + joinList(segmentWords(fieldSegments(ir, "second")));
194
- const dayFrame = trailingQualifier(ir, opts);
240
+ const stride = strideFromSegments(segmentsOf(schedule, "second"), "segundo", "", opts);
241
+ const secondsPhrase = stride ?? "en los segundos " + joinList(segmentWords(segmentsOf(schedule, "second")));
242
+ const dayFrame = trailingQualifier(schedule, opts);
195
243
  return (dayFrame ? dayFrame.trimStart() + ", " : "") + secondsPhrase + " de " + clockList;
196
244
  }
197
- function composeHourCadence(ir, plan, opts) {
245
+ function composeHourCadence(schedule, plan, opts) {
198
246
  const clockRest = plan.rest.kind === "clockTimes" || plan.rest.kind === "compactClockTimes";
199
- if (!clockRest || ir.shapes.minute !== "single") {
247
+ if (!clockRest || schedule.shapes.minute !== "single") {
200
248
  return null;
201
249
  }
202
- const minute = +ir.pattern.minute;
203
- return hourCadence(ir, minute, opts) ?? hourRangeCadence(ir, minute, opts);
250
+ const minute = +schedule.pattern.minute;
251
+ return hourCadence(schedule, minute, opts) ?? hourRangeCadence(schedule, minute, opts);
204
252
  }
205
- function isPinnedMinuteSeconds(ir, plan) {
206
- return plan.rest.kind === "clockTimes" && (ir.shapes.second === "wildcard" || ir.shapes.second === "step");
253
+ function isPinnedMinuteSeconds(schedule, plan) {
254
+ return plan.rest.kind === "clockTimes" && (schedule.shapes.second === "wildcard" || schedule.shapes.second === "step");
207
255
  }
208
- function renderComposeSeconds(ir, plan, opts) {
209
- const hourCad = composeHourCadence(ir, plan, opts);
256
+ function renderComposeSeconds(schedule, plan, opts) {
257
+ const hourCad = composeHourCadence(schedule, plan, opts);
210
258
  if (hourCad !== null) {
211
259
  return hourCad;
212
260
  }
213
- if (isPinnedMinuteSeconds(ir, plan)) {
214
- return pinnedMinuteSeconds(ir, plan.rest, opts);
261
+ if (isPinnedMinuteSeconds(schedule, plan)) {
262
+ return pinnedMinuteSeconds(schedule, plan.rest, opts);
215
263
  }
216
- if (plan.rest.kind === "clockTimes" && ir.shapes.second === "list") {
217
- return secondsListAtClock(ir, plan.rest, opts);
264
+ if (plan.rest.kind === "clockTimes" && schedule.shapes.second === "list") {
265
+ return secondsListAtClock(schedule, plan.rest, opts);
218
266
  }
219
- if (plan.rest.kind === "hourRange" && ir.shapes.second === "step" && ir.pattern.weekday !== "*") {
267
+ if (plan.rest.kind === "hourRange" && schedule.shapes.second === "step" && schedule.pattern.weekday !== "*") {
220
268
  const restNode = plan.rest;
221
269
  const window = hourWindow(boundedWindow(restNode), opts);
222
- const dayFrame = weekdayQualifier(ir) + monthScope(ir);
223
- const cadence = "cada " + numero(stepSegment(ir.analyses.segments.second).interval, opts) + " segundos del minuto " + ir.pattern.minute;
270
+ const dayFrame = weekdayQualifier(schedule) + monthScope(schedule);
271
+ const cadence = "cada " + numero(stepSegment(schedule, "second").interval, opts) + " segundos del minuto " + schedule.pattern.minute;
224
272
  return dayFrame + ", " + window + ", " + cadence;
225
273
  }
226
- if (isEveryOtherMinuteSeconds(ir, plan)) {
227
- return secondsLeadClause(ir, opts) + " de " + render(ir, plan.rest, opts);
274
+ if (isEveryOtherMinuteSeconds(schedule, plan)) {
275
+ return secondsLeadClause(schedule, opts) + " de " + render(schedule, plan.rest, opts);
228
276
  }
229
- const restOwnsLead = plan.rest.kind === "compactClockTimes" && ir.analyses.clockSecond;
230
- const lead = restOwnsLead ? "" : secondsLeadClause(ir, opts) + ", ";
231
- return lead + render(ir, plan.rest, opts);
277
+ const restOwnsLead = plan.rest.kind === "compactClockTimes" && schedule.analyses.clockSecond;
278
+ const lead = restOwnsLead ? "" : secondsLeadClause(schedule, opts) + ", ";
279
+ return lead + render(schedule, plan.rest, opts);
232
280
  }
233
- function isEveryOtherMinuteSeconds(ir, plan) {
234
- if (plan.rest.kind !== "minuteFrequency" || ir.shapes.second !== "wildcard" || ir.shapes.hour !== "wildcard") {
281
+ function isEveryOtherMinuteSeconds(schedule, plan) {
282
+ if (plan.rest.kind !== "minuteFrequency" || schedule.shapes.second !== "wildcard" || schedule.shapes.hour !== "wildcard") {
235
283
  return false;
236
284
  }
237
- const minuteStep = stepSegment(ir.analyses.segments.minute);
285
+ const minuteStep = stepSegment(schedule, "minute");
238
286
  return minuteStep.startToken === "*" && minuteStep.interval === 2;
239
287
  }
240
- function pinnedMinuteSeconds(ir, rest, opts) {
241
- const dayTrail = leadingQualifier(ir, opts).trimEnd();
288
+ function pinnedMinuteSeconds(schedule, rest, opts) {
289
+ const dayTrail = leadingQualifier(schedule, opts).trimEnd();
242
290
  const trail = dayTrail ? ", " + dayTrail : "";
243
- if (+rest.times[0].minute === 0 && ir.shapes.minute === "single") {
244
- return secondsLeadClause(ir, opts) + " durante un minuto " + durationHourList(rest.times, opts) + trail;
291
+ if (+rest.times[0].minute === 0 && schedule.shapes.minute === "single") {
292
+ return secondsLeadClause(schedule, opts) + " durante un minuto " + durationHourList(rest.times, opts) + trail;
245
293
  }
246
- return secondsLeadClause(ir, opts) + " de " + explicitClockList(rest.times, opts) + trail;
294
+ return secondsLeadClause(schedule, opts) + " de " + explicitClockList(rest.times, opts) + trail;
247
295
  }
248
- function secondsLeadClause(ir, opts) {
249
- return secondsClause(ir, "minuto", opts);
296
+ function secondsLeadClause(schedule, opts) {
297
+ return secondsClause(schedule, "minuto", opts);
250
298
  }
251
- function secondsClause(ir, anchor, opts) {
252
- const secondField = ir.pattern.second;
253
- const shape = ir.shapes.second;
299
+ function secondsClause(schedule, anchor, opts) {
300
+ const secondField = schedule.pattern.second;
301
+ const shape = schedule.shapes.second;
254
302
  if (secondField === "*") {
255
303
  return "cada segundo";
256
304
  }
257
305
  if (shape === "step") {
258
306
  return stepCycle60(
259
- stepSegment(ir.analyses.segments.second),
307
+ stepSegment(schedule, "second"),
260
308
  "segundo",
261
309
  anchor,
262
310
  opts
@@ -270,31 +318,31 @@ function secondsClause(ir, anchor, opts) {
270
318
  return "en el segundo " + secondField + " de cada " + anchor;
271
319
  }
272
320
  return strideFromSegments(
273
- fieldSegments(ir, "second"),
321
+ segmentsOf(schedule, "second"),
274
322
  "segundo",
275
323
  anchor,
276
324
  opts
277
- ) ?? "en los segundos " + joinList(segmentWords(fieldSegments(ir, "second"))) + " de cada " + anchor;
325
+ ) ?? "en los segundos " + joinList(segmentWords(segmentsOf(schedule, "second"))) + " de cada " + anchor;
278
326
  }
279
- function renderEveryMinute(ir, plan, opts) {
280
- return "cada minuto" + trailingQualifier(ir, opts);
327
+ function renderEveryMinute(schedule, plan, opts) {
328
+ return "cada minuto" + trailingQualifier(schedule, opts);
281
329
  }
282
- function renderSingleMinute(ir, plan, opts) {
283
- return "en el minuto " + ir.pattern.minute + " de cada hora" + trailingQualifier(ir, opts);
330
+ function renderSingleMinute(schedule, plan, opts) {
331
+ return "en el minuto " + schedule.pattern.minute + " de cada hora" + trailingQualifier(schedule, opts);
284
332
  }
285
- function renderRangeOfMinutes(ir, plan, opts) {
286
- return minuteRangeLead(ir.pattern.minute) + " de cada hora" + trailingQualifier(ir, opts);
333
+ function renderRangeOfMinutes(schedule, plan, opts) {
334
+ return minuteRangeLead(schedule.pattern.minute) + " de cada hora" + trailingQualifier(schedule, opts);
287
335
  }
288
- function renderMultipleMinutes(ir, plan, opts) {
289
- return minutesList(ir, opts) + trailingQualifier(ir, opts);
336
+ function renderMultipleMinutes(schedule, plan, opts) {
337
+ return minutesList(schedule, opts) + trailingQualifier(schedule, opts);
290
338
  }
291
- function minutesList(ir, opts) {
339
+ function minutesList(schedule, opts) {
292
340
  return strideFromSegments(
293
- fieldSegments(ir, "minute"),
341
+ segmentsOf(schedule, "minute"),
294
342
  "minuto",
295
343
  "hora",
296
344
  opts
297
- ) ?? "en los minutos " + joinList(segmentWords(fieldSegments(ir, "minute"))) + " de cada hora";
345
+ ) ?? "en los minutos " + joinList(segmentWords(segmentsOf(schedule, "minute"))) + " de cada hora";
298
346
  }
299
347
  function minuteRangeLead(minuteField) {
300
348
  const bounds = minuteField.split("-");
@@ -349,86 +397,86 @@ function spanHours(hours) {
349
397
  return (hour === 1 ? "la " : "las ") + hour;
350
398
  }));
351
399
  }
352
- function renderMinuteFrequency(ir, plan, opts) {
400
+ function renderMinuteFrequency(schedule, plan, opts) {
353
401
  let phrase = stepCycle60(
354
- stepSegment(ir.analyses.segments.minute),
402
+ stepSegment(schedule, "minute"),
355
403
  "minuto",
356
404
  "hora",
357
405
  opts
358
406
  );
359
407
  if (plan.hours.kind === "during") {
360
- const cadence = unevenHourCadence(ir, opts);
408
+ const cadence = unevenHourCadence(schedule, opts);
361
409
  if (cadence) {
362
410
  phrase += ", " + cadence;
363
411
  } else {
364
- phrase += singleHourStep(ir.analyses.segments.hour) ? ", " + stepHourSpan(stepSegment(ir.analyses.segments.hour), opts) : " " + hourSpanFromTimes(ir, plan.hours.times, opts);
412
+ phrase += singleHourStep(schedule.analyses.segments.hour) ? ", " + stepHourSpan(stepSegment(schedule, "hour"), opts) : " " + hourSpanFromTimes(schedule, plan.hours.times, opts);
365
413
  }
366
414
  } else if (plan.hours.kind === "window") {
367
415
  phrase += " " + hourWindow(plan.hours, opts);
368
416
  } else if (plan.hours.kind === "step") {
369
- phrase += ", " + stepHourSpan(stepSegment(ir.analyses.segments.hour), opts);
417
+ phrase += ", " + stepHourSpan(stepSegment(schedule, "hour"), opts);
370
418
  }
371
- return phrase + trailingQualifier(ir, opts);
419
+ return phrase + trailingQualifier(schedule, opts);
372
420
  }
373
- function renderMinuteSpanInHour(ir, plan, opts) {
374
- if (ir.pattern.minute === "*") {
375
- return "cada minuto de la hora " + fromTime(timePhrase(plan.hour, 0, null, opts)) + trailingQualifier(ir, opts);
421
+ function renderMinuteSpanInHour(schedule, plan, opts) {
422
+ if (schedule.pattern.minute === "*") {
423
+ return "cada minuto de la hora " + fromTime(timePhrase(plan.hour, 0, null, opts)) + trailingQualifier(schedule, opts);
376
424
  }
377
425
  return "cada minuto " + timeRange(
378
426
  { hour: plan.hour, minute: plan.span[0] },
379
427
  { hour: plan.hour, minute: plan.span[1] },
380
428
  opts
381
- ) + trailingQualifier(ir, opts);
429
+ ) + trailingQualifier(schedule, opts);
382
430
  }
383
- function renderMinutesAcrossHours(ir, plan, opts) {
384
- const cadence = unevenHourCadence(ir, opts);
431
+ function renderMinutesAcrossHours(schedule, plan, opts) {
432
+ const cadence = unevenHourCadence(schedule, opts);
385
433
  if (plan.form === "wildcard") {
386
434
  if (cadence !== null) {
387
- return "cada minuto, " + cadence + trailingQualifier(ir, opts);
435
+ return "cada minuto, " + cadence + trailingQualifier(schedule, opts);
388
436
  }
389
- if (singleHourStep(ir.analyses.segments.hour)) {
390
- return "cada minuto, " + stepHourSpan(stepSegment(ir.analyses.segments.hour), opts) + trailingQualifier(ir, opts);
437
+ if (singleHourStep(schedule.analyses.segments.hour)) {
438
+ return "cada minuto, " + stepHourSpan(stepSegment(schedule, "hour"), opts) + trailingQualifier(schedule, opts);
391
439
  }
392
- return "cada minuto " + hourSpanFromTimes(ir, plan.times, opts) + trailingQualifier(ir, opts);
440
+ return "cada minuto " + hourSpanFromTimes(schedule, plan.times, opts) + trailingQualifier(schedule, opts);
393
441
  }
394
- const lead = plan.form === "range" ? minuteRangeLead(ir.pattern.minute) : minutesList(ir, opts);
442
+ const lead = plan.form === "range" ? minuteRangeLead(schedule.pattern.minute) : minutesList(schedule, opts);
395
443
  if (cadence !== null) {
396
- return lead + ", " + cadence + trailingQualifier(ir, opts);
444
+ return lead + ", " + cadence + trailingQualifier(schedule, opts);
397
445
  }
398
- return lead + ", " + atHourTimes(ir, plan.times, opts) + trailingQualifier(ir, opts);
446
+ return lead + ", " + atHourTimes(schedule, plan.times, opts) + trailingQualifier(schedule, opts);
399
447
  }
400
- function renderMinuteSpanAcrossHourStep(ir, plan, opts) {
401
- const segment = stepSegment(ir.analyses.segments.hour);
402
- const cadence = unevenHourCadence(ir, opts);
448
+ function renderMinuteSpanAcrossHourStep(schedule, plan, opts) {
449
+ const segment = stepSegment(schedule, "hour");
450
+ const cadence = unevenHourCadence(schedule, opts);
403
451
  if (plan.form === "wildcard") {
404
- return "cada minuto, " + stepHourSpan(segment, opts) + trailingQualifier(ir, opts);
452
+ return "cada minuto, " + stepHourSpan(segment, opts) + trailingQualifier(schedule, opts);
405
453
  }
406
- const lead = plan.form === "list" ? minutesList(ir, opts) : minuteRangeLead(ir.pattern.minute);
407
- return lead + ", " + (cadence ?? stepHours(segment, opts)) + trailingQualifier(ir, opts);
454
+ const lead = plan.form === "list" ? minutesList(schedule, opts) : minuteRangeLead(schedule.pattern.minute);
455
+ return lead + ", " + (cadence ?? stepHours(segment, opts)) + trailingQualifier(schedule, opts);
408
456
  }
409
- function renderEveryHour(ir, plan, opts) {
410
- return "cada hora" + trailingQualifier(ir, opts);
457
+ function renderEveryHour(schedule, plan, opts) {
458
+ return "cada hora" + trailingQualifier(schedule, opts);
411
459
  }
412
- function renderHourRange(ir, plan, opts) {
460
+ function renderHourRange(schedule, plan, opts) {
413
461
  const window = hourWindow(boundedWindow(plan), opts);
414
462
  if (plan.minuteForm === "wildcard") {
415
- return "cada minuto " + window + trailingQualifier(ir, opts);
463
+ return "cada minuto " + window + trailingQualifier(schedule, opts);
416
464
  }
417
465
  if (plan.minuteForm === "range") {
418
- return minuteRangeLead(ir.pattern.minute) + ", " + window + trailingQualifier(ir, opts);
466
+ return minuteRangeLead(schedule.pattern.minute) + ", " + window + trailingQualifier(schedule, opts);
419
467
  }
420
- if (ir.pattern.minute === "0") {
421
- return "cada hora " + window + trailingQualifier(ir, opts);
468
+ if (schedule.pattern.minute === "0") {
469
+ return "cada hora " + window + trailingQualifier(schedule, opts);
422
470
  }
423
- const lead = ir.shapes.minute === "single" ? "en el minuto " + ir.pattern.minute + " de cada hora" : minutesList(ir, opts);
424
- return lead + ", " + window + trailingQualifier(ir, opts);
471
+ const lead = schedule.shapes.minute === "single" ? "en el minuto " + schedule.pattern.minute + " de cada hora" : minutesList(schedule, opts);
472
+ return lead + ", " + window + trailingQualifier(schedule, opts);
425
473
  }
426
- function renderHourStep(ir, plan, opts) {
427
- const cadence = unevenHourCadence(ir, opts);
474
+ function renderHourStep(schedule, plan, opts) {
475
+ const cadence = unevenHourCadence(schedule, opts);
428
476
  if (cadence !== null) {
429
- return cadence + trailingQualifier(ir, opts);
477
+ return cadence + trailingQualifier(schedule, opts);
430
478
  }
431
- return stepHours(stepSegment(ir.analyses.segments.hour), opts) + trailingQualifier(ir, opts);
479
+ return stepHours(stepSegment(schedule, "hour"), opts) + trailingQualifier(schedule, opts);
432
480
  }
433
481
  function boundedWindow(plan) {
434
482
  const last = plan.minuteForm === "wildcard" ? plan.boundMinute ?? 0 : 0;
@@ -441,42 +489,46 @@ function hourWindow(window, opts) {
441
489
  opts
442
490
  );
443
491
  }
444
- function isDateWeekdayUnion(ir) {
445
- return ir.pattern.date !== "*" && ir.pattern.weekday !== "*";
492
+ function isDateWeekdayUnion(schedule) {
493
+ return schedule.pattern.date !== "*" && schedule.pattern.weekday !== "*";
446
494
  }
447
- function unionMonthLeadFull(ir) {
448
- if (ir.pattern.month === "*") {
495
+ function unionMonthLeadFull(schedule) {
496
+ if (schedule.pattern.month === "*") {
449
497
  return "";
450
498
  }
451
- const lead = monthPhrase(ir, monthRanged(ir) ? "de " : "en ");
452
- const segments = flattenSteps(fieldSegments(ir, "month"));
453
- const isEnumeration = !monthRanged(ir) && segments.length >= 2;
499
+ const lead = monthPhrase(schedule, monthRanged(schedule) ? "de " : "en ");
500
+ const segments = flattenSteps(segmentsOf(schedule, "month"));
501
+ const isEnumeration = !monthRanged(schedule) && segments.length >= 2;
454
502
  return isEnumeration ? lead + "," : lead;
455
503
  }
456
- function domArm(ir, opts) {
457
- const date = ir.pattern.date;
504
+ function domArm(schedule, opts) {
505
+ const date = schedule.pattern.date;
458
506
  const quartz = quartzDatePhrase(date);
459
507
  if (quartz) {
460
508
  return quartz;
461
509
  }
510
+ const parity = parityDayPredicate(date);
511
+ if (parity) {
512
+ return parity;
513
+ }
462
514
  if (isOpenStep(date)) {
463
515
  return stepDates(date, opts);
464
516
  }
465
- const segments = fieldSegments(ir, "date");
517
+ const segments = segmentsOf(schedule, "date");
466
518
  if (segments.length === 1 && segments[0].kind === "range") {
467
519
  return "del " + segments[0].bounds[0] + " al " + segments[0].bounds[1] + " del mes";
468
520
  }
469
521
  if (segments.length === 1 && segments[0].kind === "single") {
470
- return ir.pattern.month === "*" ? "el " + segments[0].value + " de cada mes" : "el d\xEDa " + segments[0].value;
522
+ return schedule.pattern.month === "*" ? "el " + segments[0].value + " de cada mes" : "el d\xEDa " + segments[0].value;
471
523
  }
472
524
  return "los d\xEDas " + joinList(segmentWords(segments)) + " del mes";
473
525
  }
474
- function dowArm(ir) {
475
- const quartz = quartzWeekdayPhrase(ir.pattern.weekday);
526
+ function dowArm(schedule) {
527
+ const quartz = quartzWeekdayPhrase(schedule.pattern.weekday);
476
528
  if (quartz) {
477
529
  return quartz;
478
530
  }
479
- const segments = orderWeekdaysForDisplay(fieldSegments(ir, "weekday"));
531
+ const segments = orderWeekdaysForDisplay(segmentsOf(schedule, "weekday"));
480
532
  const allSingles = segments.every(function single(segment) {
481
533
  return segment.kind === "single";
482
534
  });
@@ -489,19 +541,19 @@ function dowArm(ir) {
489
541
  }));
490
542
  }
491
543
  if (segments.length === 1) {
492
- return weekdayRange(segments[0]);
544
+ return "cualquier d\xEDa " + weekdayRange(segments[0]);
493
545
  }
494
546
  return joinList(segments.map(function name(segment) {
495
547
  return segment.kind === "range" ? weekdayRange(segment) : "los " + pluralWeekday(segment.value);
496
548
  }));
497
549
  }
498
- function unionYaseaSuffix(ir, opts) {
499
- return ", ya sea " + domArm(ir, opts) + " o " + dowArm(ir);
550
+ function unionYaseaSuffix(schedule, opts) {
551
+ return ", ya sea " + domArm(schedule, opts) + " o " + dowArm(schedule);
500
552
  }
501
- function renderClockTimes(ir, plan, opts) {
502
- if (ir.shapes.minute === "single") {
503
- const minute = +ir.pattern.minute;
504
- const cadence = hourCadence(ir, minute, opts) ?? hourRangeCadence(ir, minute, opts);
553
+ function renderClockTimes(schedule, plan, opts) {
554
+ if (schedule.shapes.minute === "single") {
555
+ const minute = +schedule.pattern.minute;
556
+ const cadence = hourCadence(schedule, minute, opts) ?? hourRangeCadence(schedule, minute, opts);
505
557
  if (cadence !== null) {
506
558
  return cadence;
507
559
  }
@@ -509,7 +561,7 @@ function renderClockTimes(ir, plan, opts) {
509
561
  const phrases = plan.times.map(function clock(time) {
510
562
  return atTime(timePhrase(time.hour, time.minute, time.second, opts));
511
563
  });
512
- return leadingQualifier(ir, opts) + groupClockTimes(phrases);
564
+ return leadingQualifier(schedule, opts) + groupClockTimes(phrases);
513
565
  }
514
566
  function explicitClockList(times, opts) {
515
567
  const phrases = times.map(function clock(time) {
@@ -685,23 +737,33 @@ function groupClockTimesByArticle(phrases) {
685
737
  const connector = doubleY ? ", " : " y ";
686
738
  return laPart + connector + lasPart;
687
739
  }
688
- function renderCompactClockTimes(ir, plan, opts) {
740
+ function renderCompactClockTimes(schedule, plan, opts) {
689
741
  if (plan.fold) {
690
- const cadence2 = hourCadence(ir, plan.minute, opts) ?? hourRangeCadence(ir, plan.minute, opts);
742
+ const cadence2 = hourCadence(schedule, plan.minute, opts) ?? hourRangeCadence(schedule, plan.minute, opts);
691
743
  if (cadence2 !== null) {
692
744
  return cadence2;
693
745
  }
694
- const ranged = hourSegments(ir).some(function range(segment) {
746
+ const ranged = segmentsOf(schedule, "hour").some(function range(segment) {
695
747
  return segment.kind === "range";
696
748
  });
697
- if (ranged && !ir.analyses.clockSecond) {
698
- return "cada hora " + hourSegmentTimes(ir, plan.minute, ir.analyses.clockSecond, opts) + trailingQualifier(ir, opts);
749
+ if (ranged && !schedule.analyses.clockSecond) {
750
+ return "cada hora " + hourSegmentTimes(
751
+ schedule,
752
+ plan.minute,
753
+ schedule.analyses.clockSecond,
754
+ opts
755
+ ) + trailingQualifier(schedule, opts);
699
756
  }
700
- return leadingQualifier(ir, opts) + hourSegmentTimes(ir, plan.minute, ir.analyses.clockSecond, opts);
757
+ return leadingQualifier(schedule, opts) + hourSegmentTimes(
758
+ schedule,
759
+ plan.minute,
760
+ schedule.analyses.clockSecond,
761
+ opts
762
+ );
701
763
  }
702
- const cadence = unevenHourCadence(ir, opts);
703
- const phrase = cadence ? minutesList(ir, opts) + ", " + cadence + trailingQualifier(ir, opts) : minutesList(ir, opts) + ", " + hourContextTimes(ir, opts) + trailingQualifier(ir, opts);
704
- return ir.analyses.clockSecond ? secondsLeadClause(ir, opts) + ", " + phrase : phrase;
764
+ const cadence = unevenHourCadence(schedule, opts);
765
+ const phrase = cadence ? minutesList(schedule, opts) + ", " + cadence + trailingQualifier(schedule, opts) : minutesList(schedule, opts) + ", " + hourContextTimes(schedule, opts) + trailingQualifier(schedule, opts);
766
+ return schedule.analyses.clockSecond ? secondsLeadClause(schedule, opts) + ", " + phrase : phrase;
705
767
  }
706
768
  var renderers = {
707
769
  clockTimes: renderClockTimes,
@@ -723,18 +785,15 @@ var renderers = {
723
785
  singleMinute: renderSingleMinute,
724
786
  standaloneSeconds: renderStandaloneSeconds
725
787
  };
726
- function renderStride(stride, opts) {
788
+ function renderStride2(stride, opts) {
727
789
  const { interval, start, last, cycle, unit, anchor } = stride;
728
790
  const cadence = "cada " + numero(interval, opts) + " " + unit + "s";
729
- const tiles = cycle % interval === 0;
730
- if (start === 0 && tiles) {
731
- return cadence;
732
- }
733
791
  const tail = anchor ? " de cada " + anchor : "";
734
- if (start < interval && tiles) {
735
- return cadence + " a partir del " + unit + " " + start + tail;
736
- }
737
- return cadence + " del " + unit + " " + start + " al " + last + tail;
792
+ return renderStride({ start, interval, cycle }, {
793
+ bare: () => cadence,
794
+ offset: () => cadence + " a partir del " + unit + " " + start + tail,
795
+ bounded: () => cadence + " del " + unit + " " + start + " al " + last + tail
796
+ });
738
797
  }
739
798
  function stepCycle60(segment, unit, anchor, opts) {
740
799
  if (segment.startToken.indexOf("-") !== -1) {
@@ -744,7 +803,7 @@ function stepCycle60(segment, unit, anchor, opts) {
744
803
  if (start !== 0 && segment.fires.length <= 3) {
745
804
  return "en los " + unit + "s " + joinList(wordList(segment.fires)) + " de cada " + anchor;
746
805
  }
747
- return renderStride({
806
+ return renderStride2({
748
807
  interval: segment.interval,
749
808
  start,
750
809
  last: segment.fires[segment.fires.length - 1],
@@ -756,17 +815,7 @@ function stepCycle60(segment, unit, anchor, opts) {
756
815
  function strideFromSegments(segments, unit, anchor, opts) {
757
816
  const values = singleValues(segments);
758
817
  const step = values && arithmeticStep(values);
759
- return step ? renderStride({ ...step, cycle: 60, unit, anchor }, opts) : null;
760
- }
761
- function singleValues(segments) {
762
- const values = [];
763
- for (const segment of segments) {
764
- if (segment.kind !== "single") {
765
- return null;
766
- }
767
- values.push(+segment.value);
768
- }
769
- return values;
818
+ return step ? renderStride2({ ...step, cycle: 60, unit, anchor }, opts) : null;
770
819
  }
771
820
  function stepHours(segment, opts) {
772
821
  if (segment.startToken.indexOf("-") !== -1) {
@@ -785,45 +834,21 @@ function stepHours(segment, opts) {
785
834
  function hourStrideCadence(stride, opts) {
786
835
  const { start, interval, last } = stride;
787
836
  const cadence = "cada " + numero(interval, opts) + " horas";
788
- const tiles = 24 % interval === 0;
789
- if (start === 0 && tiles) {
790
- return cadence;
791
- }
792
- if (start < interval && tiles) {
793
- return cadence + " a partir de " + timePhrase(start, 0, null, opts);
794
- }
795
- return cadence + " de " + timePhrase(start, 0, null, opts) + " a " + timePhrase(last, 0, null, opts);
796
- }
797
- function offsetCleanStride(stride) {
798
- return stride.start < stride.interval && 24 % stride.interval === 0;
837
+ return renderStride({ start, interval, cycle: 24 }, {
838
+ bare: () => cadence,
839
+ offset: () => cadence + " a partir de " + timePhrase(start, 0, null, opts),
840
+ bounded: () => cadence + " de " + timePhrase(start, 0, null, opts) + " a " + timePhrase(last, 0, null, opts)
841
+ });
799
842
  }
800
- function unevenHourCadence(ir, opts) {
801
- const stride = hourStride(ir);
843
+ function unevenHourCadence(schedule, opts) {
844
+ const stride = hourStride(schedule);
802
845
  if (!stride || offsetCleanStride(stride)) {
803
846
  return null;
804
847
  }
805
848
  return hourStrideCadence(stride, opts);
806
849
  }
807
- function hourListStride(values) {
808
- if (values.length < 2) {
809
- return null;
810
- }
811
- const interval = values[1] - values[0];
812
- if (interval < 2) {
813
- return null;
814
- }
815
- for (let i = 2; i < values.length; i += 1) {
816
- if (values[i] - values[i - 1] !== interval) {
817
- return null;
818
- }
819
- }
820
- if (values[0] !== 0 && values.length < 5) {
821
- return null;
822
- }
823
- return { interval, last: values[values.length - 1], start: values[0] };
824
- }
825
- function hourStride(ir) {
826
- const segments = fieldSegments(ir, "hour");
850
+ function hourStride(schedule) {
851
+ const segments = segmentsOf(schedule, "hour");
827
852
  if (segments.length === 1 && segments[0].kind === "step") {
828
853
  const segment = segments[0];
829
854
  if (segment.fires.length < 2) {
@@ -835,64 +860,64 @@ function hourStride(ir) {
835
860
  const values = singleValues(segments);
836
861
  return values && hourListStride(values);
837
862
  }
838
- function subMinuteSecond(ir) {
839
- return ir.pattern.second === "*" || ir.shapes.second === "step";
863
+ function subMinuteSecond(schedule) {
864
+ return schedule.pattern.second === "*" || schedule.shapes.second === "step";
840
865
  }
841
- function hourCadenceLead(ir, minute, opts) {
866
+ function hourCadenceLead(schedule, minute, opts) {
842
867
  if (minute === 0) {
843
- if (subMinuteSecond(ir)) {
844
- return secondsClause(ir, "minuto", opts) + " durante un minuto";
868
+ if (subMinuteSecond(schedule)) {
869
+ return secondsClause(schedule, "minuto", opts) + " durante un minuto";
845
870
  }
846
- return secondsClause(ir, "hora", opts);
871
+ return secondsClause(schedule, "hora", opts);
847
872
  }
848
873
  const minutePhrase = "en el minuto " + minute;
849
- if (ir.pattern.second === "0") {
874
+ if (schedule.pattern.second === "0") {
850
875
  return minutePhrase;
851
876
  }
852
- return secondsClause(ir, "minuto", opts) + ", " + minutePhrase;
877
+ return secondsClause(schedule, "minuto", opts) + ", " + minutePhrase;
853
878
  }
854
- function hourCadence(ir, minute, opts) {
855
- const stride = hourStride(ir);
879
+ function hourCadence(schedule, minute, opts) {
880
+ const stride = hourStride(schedule);
856
881
  if (!stride) {
857
882
  return null;
858
883
  }
859
884
  const fires = (stride.last - stride.start) / stride.interval + 1;
860
- if (ir.pattern.second === "0" && fires <= maxClockTimes && offsetCleanStride(stride)) {
885
+ if (schedule.pattern.second === "0" && fires <= maxClockTimes && offsetCleanStride(stride)) {
861
886
  return null;
862
887
  }
863
- const confinement = minute === 0 && subMinuteSecond(ir) && cleanStrideSegment(ir);
888
+ const confinement = minute === 0 && subMinuteSecond(schedule) && cleanStrideSegment(schedule);
864
889
  if (confinement) {
865
- return secondsClause(ir, "minuto", opts) + " durante un minuto, " + stepHourSpan(confinement, opts) + trailingQualifier(ir, opts);
890
+ return secondsClause(schedule, "minuto", opts) + " durante un minuto, " + stepHourSpan(confinement, opts) + trailingQualifier(schedule, opts);
866
891
  }
867
- if (minute === 0 && ir.pattern.second === "0") {
868
- return hourStrideCadence(stride, opts) + trailingQualifier(ir, opts);
892
+ if (minute === 0 && schedule.pattern.second === "0") {
893
+ return hourStrideCadence(stride, opts) + trailingQualifier(schedule, opts);
869
894
  }
870
- return hourCadenceLead(ir, minute, opts) + ", " + hourStrideCadence(stride, opts) + trailingQualifier(ir, opts);
895
+ return hourCadenceLead(schedule, minute, opts) + ", " + hourStrideCadence(stride, opts) + trailingQualifier(schedule, opts);
871
896
  }
872
- function cleanStrideSegment(ir) {
873
- const segments = fieldSegments(ir, "hour");
897
+ function cleanStrideSegment(schedule) {
898
+ const segments = segmentsOf(schedule, "hour");
874
899
  const segment = segments.length === 1 && segments[0];
875
900
  if (!segment || segment.kind !== "step" || segment.startToken.indexOf("-") !== -1) {
876
901
  return null;
877
902
  }
878
903
  return segment;
879
904
  }
880
- function hasHourWindow(ir) {
881
- return hourSegments(ir).some(function range(segment) {
905
+ function hasHourWindow(schedule) {
906
+ return segmentsOf(schedule, "hour").some(function range(segment) {
882
907
  return segment.kind === "range";
883
908
  });
884
909
  }
885
- function hourRangeCadence(ir, minute, opts) {
886
- if (minute !== 0 || !hasHourWindow(ir) || ir.pattern.second === "0") {
910
+ function hourRangeCadence(schedule, minute, opts) {
911
+ if (minute !== 0 || !hasHourWindow(schedule) || schedule.pattern.second === "0") {
887
912
  return null;
888
913
  }
889
- if (subMinuteSecond(ir)) {
890
- return secondsClause(ir, "minuto", opts) + " durante un minuto, durante las horas " + hourSegmentTimes(ir, 0, null, opts) + trailingQualifier(ir, opts);
914
+ if (subMinuteSecond(schedule)) {
915
+ return secondsClause(schedule, "minuto", opts) + " durante un minuto, durante las horas " + hourSegmentTimes(schedule, 0, null, opts) + trailingQualifier(schedule, opts);
891
916
  }
892
- return hourCadenceLead(ir, minute, opts) + ", " + hourSegmentTimes(ir, 0, null, opts) + trailingQualifier(ir, opts);
917
+ return hourCadenceLead(schedule, minute, opts) + ", " + hourSegmentTimes(schedule, 0, null, opts) + trailingQualifier(schedule, opts);
893
918
  }
894
- function hourContextTimes(ir, opts) {
895
- const segments = hourSegments(ir);
919
+ function hourContextTimes(schedule, opts) {
920
+ const segments = segmentsOf(schedule, "hour");
896
921
  const points = [];
897
922
  const hasRange = segments.some(function range(segment) {
898
923
  return segment.kind === "range";
@@ -938,25 +963,25 @@ function atTimes(hours, opts) {
938
963
  return atTime(timePhrase(hour, 0, null, opts));
939
964
  });
940
965
  }
941
- function atHourTimes(ir, times, opts) {
966
+ function atHourTimes(schedule, times, opts) {
942
967
  if (times.kind === "fires") {
943
968
  return groupClockTimesByArticle(atTimes(times.fires, opts));
944
969
  }
945
- return hourSegmentTimes(ir, 0, null, opts);
970
+ return hourSegmentTimes(schedule, 0, null, opts);
946
971
  }
947
- function hourSpanFromTimes(ir, times, opts) {
972
+ function hourSpanFromTimes(schedule, times, opts) {
948
973
  if (times.kind === "fires" && times.fires.length > 3) {
949
974
  return "durante las horas " + hourSpanList(times.fires, opts);
950
975
  }
951
- return hourWindowsFromTimes(ir, times, opts);
976
+ return hourWindowsFromTimes(schedule, times, opts);
952
977
  }
953
- function hourWindowsFromTimes(ir, times, opts) {
978
+ function hourWindowsFromTimes(schedule, times, opts) {
954
979
  if (times.kind === "fires") {
955
980
  return joinList(times.fires.map(function window(hour) {
956
981
  return hourAsWindow(hour, opts);
957
982
  }));
958
983
  }
959
- return joinList(hourSegments(ir).map(function window(segment) {
984
+ return joinList(segmentsOf(schedule, "hour").map(function window(segment) {
960
985
  if (segment.kind === "range") {
961
986
  return timeRange(
962
987
  { hour: +segment.bounds[0], minute: 0 },
@@ -972,10 +997,10 @@ function hourWindowsFromTimes(ir, times, opts) {
972
997
  return hourAsWindow(+segment.value, opts);
973
998
  }));
974
999
  }
975
- function hourSegmentTimes(ir, minute, second, opts) {
1000
+ function hourSegmentTimes(schedule, minute, second, opts) {
976
1001
  const pieces = [];
977
1002
  const fromRange = [];
978
- hourSegments(ir).forEach(function clock(segment) {
1003
+ segmentsOf(schedule, "hour").forEach(function clock(segment) {
979
1004
  if (segment.kind === "step") {
980
1005
  segment.fires.forEach(function each(hour) {
981
1006
  pieces.push(atTime(timePhrase(hour, minute, second, opts)));
@@ -1087,47 +1112,47 @@ function dayPeriod(hour, opts) {
1087
1112
  }
1088
1113
  return "de la tarde";
1089
1114
  }
1090
- function leadingQualifier(ir, opts) {
1091
- const pattern = ir.pattern;
1115
+ function leadingQualifier(schedule, opts) {
1116
+ const pattern = schedule.pattern;
1092
1117
  if (pattern.date !== "*" && pattern.weekday !== "*") {
1093
1118
  return "";
1094
1119
  }
1095
1120
  if (pattern.date !== "*") {
1096
- return datePhrase(ir, opts) + " ";
1121
+ return datePhrase(schedule, opts) + " ";
1097
1122
  }
1098
1123
  if (pattern.weekday !== "*") {
1099
- return weekdayQualifier(ir) + monthScope(ir) + " ";
1124
+ return weekdayQualifier(schedule) + monthScope(schedule) + " ";
1100
1125
  }
1101
1126
  if (pattern.month !== "*") {
1102
- return "todos los d\xEDas " + monthPhrase(ir, "de ") + " ";
1127
+ return "todos los d\xEDas " + monthPhrase(schedule, "de ") + " ";
1103
1128
  }
1104
1129
  return "todos los d\xEDas ";
1105
1130
  }
1106
- function trailingQualifier(ir, opts) {
1107
- const pattern = ir.pattern;
1131
+ function trailingQualifier(schedule, opts) {
1132
+ const pattern = schedule.pattern;
1108
1133
  if (pattern.date !== "*" && pattern.weekday !== "*") {
1109
1134
  return "";
1110
1135
  }
1111
1136
  if (pattern.date !== "*") {
1112
- return " " + datePhrase(ir, opts);
1137
+ return " " + datePhrase(schedule, opts);
1113
1138
  }
1114
1139
  if (pattern.weekday !== "*") {
1115
- return " " + weekdayQualifier(ir) + monthScope(ir);
1140
+ return " " + weekdayQualifier(schedule) + monthScope(schedule);
1116
1141
  }
1117
1142
  if (pattern.month !== "*") {
1118
- return " " + monthPhrase(ir, "en ");
1143
+ return " " + monthPhrase(schedule, "en ");
1119
1144
  }
1120
1145
  return "";
1121
1146
  }
1122
- function datePhrase(ir, opts) {
1123
- const pattern = ir.pattern;
1147
+ function datePhrase(schedule, opts) {
1148
+ const pattern = schedule.pattern;
1124
1149
  if (quartzDatePhrase(pattern.date) || isOpenStep(pattern.date)) {
1125
- return dateClause(ir, "", opts) + monthScope(ir);
1150
+ return dateClause(schedule, "", opts) + monthScope(schedule);
1126
1151
  }
1127
- return dateClause(ir, dateMonthPart(ir), opts);
1152
+ return dateClause(schedule, dateMonthPart(schedule), opts);
1128
1153
  }
1129
- function dateClause(ir, monthPart, opts) {
1130
- const pattern = ir.pattern;
1154
+ function dateClause(schedule, monthPart, opts) {
1155
+ const pattern = schedule.pattern;
1131
1156
  const quartz = quartzDatePhrase(pattern.date);
1132
1157
  if (quartz) {
1133
1158
  return quartz;
@@ -1135,31 +1160,31 @@ function dateClause(ir, monthPart, opts) {
1135
1160
  if (isOpenStep(pattern.date)) {
1136
1161
  return stepDates(pattern.date, opts);
1137
1162
  }
1138
- const segments = fieldSegments(ir, "date");
1163
+ const segments = segmentsOf(schedule, "date");
1139
1164
  if (segments.length === 1 && segments[0].kind === "range") {
1140
- return "del " + segments[0].bounds[0] + " al " + segments[0].bounds[1] + monthPart + foldedYear(ir);
1165
+ return "del " + segments[0].bounds[0] + " al " + segments[0].bounds[1] + monthPart + foldedYear(schedule);
1141
1166
  }
1142
1167
  if (segments.length === 1 && segments[0].kind === "single") {
1143
- return "el " + segments[0].value + monthPart + foldedYear(ir);
1168
+ return "el " + segments[0].value + monthPart + foldedYear(schedule);
1144
1169
  }
1145
- return "los d\xEDas " + joinList(segmentWords(segments)) + monthPart + foldedYear(ir);
1170
+ return "los d\xEDas " + joinList(segmentWords(segments)) + monthPart + foldedYear(schedule);
1146
1171
  }
1147
- function monthRanged(ir) {
1148
- return ir.pattern.month !== "*" && fieldSegments(ir, "month").some(function range(segment) {
1172
+ function monthRanged(schedule) {
1173
+ return schedule.pattern.month !== "*" && segmentsOf(schedule, "month").some(function range(segment) {
1149
1174
  return segment.kind === "range";
1150
1175
  });
1151
1176
  }
1152
- function dateMonthPart(ir) {
1153
- if (ir.pattern.month === "*") {
1177
+ function dateMonthPart(schedule) {
1178
+ if (schedule.pattern.month === "*") {
1154
1179
  return " de cada mes";
1155
1180
  }
1156
- if (monthRanged(ir)) {
1157
- return " de cada mes, " + monthPhrase(ir, "de ");
1181
+ if (monthRanged(schedule)) {
1182
+ return " de cada mes, " + monthPhrase(schedule, "de ");
1158
1183
  }
1159
- return " " + monthPhrase(ir, "de ");
1184
+ return " " + monthPhrase(schedule, "de ");
1160
1185
  }
1161
- function foldedYear(ir) {
1162
- const yearField = ir.pattern.year;
1186
+ function foldedYear(schedule) {
1187
+ const yearField = schedule.pattern.year;
1163
1188
  if (yearField === "*" || yearField.indexOf("/") !== -1 || yearField.indexOf("-") !== -1 || yearField.indexOf(",") !== -1) {
1164
1189
  return "";
1165
1190
  }
@@ -1190,12 +1215,12 @@ function quartzWeekdayPhrase(weekdayField) {
1190
1215
  return "el \xFAltimo " + weekdayName(weekdayField.slice(0, -1)) + " del mes";
1191
1216
  }
1192
1217
  }
1193
- function weekdayQualifier(ir) {
1194
- const quartz = quartzWeekdayPhrase(ir.pattern.weekday);
1218
+ function weekdayQualifier(schedule) {
1219
+ const quartz = quartzWeekdayPhrase(schedule.pattern.weekday);
1195
1220
  if (quartz) {
1196
1221
  return quartz;
1197
1222
  }
1198
- const segments = orderWeekdaysForDisplay(fieldSegments(ir, "weekday"));
1223
+ const segments = orderWeekdaysForDisplay(segmentsOf(schedule, "weekday"));
1199
1224
  const allSingles = segments.every(function single(segment) {
1200
1225
  return segment.kind === "single";
1201
1226
  });
@@ -1221,8 +1246,8 @@ function flattenSteps(segments) {
1221
1246
  }) : [segment];
1222
1247
  });
1223
1248
  }
1224
- function monthPhrase(ir, lead) {
1225
- const segments = flattenSteps(fieldSegments(ir, "month"));
1249
+ function monthPhrase(schedule, lead) {
1250
+ const segments = flattenSteps(segmentsOf(schedule, "month"));
1226
1251
  const ranged = segments.some(function range(segment) {
1227
1252
  return segment.kind === "range";
1228
1253
  });
@@ -1238,11 +1263,26 @@ function monthPhrase(ir, lead) {
1238
1263
  return lead + monthName(segment.value);
1239
1264
  }));
1240
1265
  }
1241
- function monthScope(ir) {
1242
- if (ir.pattern.month === "*") {
1266
+ function monthScope(schedule) {
1267
+ if (schedule.pattern.month === "*") {
1243
1268
  return "";
1244
1269
  }
1245
- return (monthRanged(ir) ? ", " : " ") + monthPhrase(ir, "de ");
1270
+ return (monthRanged(schedule) ? ", " : " ") + monthPhrase(schedule, "de ");
1271
+ }
1272
+ function parityDayPredicate(dateField) {
1273
+ if (!isOpenStep(dateField)) {
1274
+ return;
1275
+ }
1276
+ const [start, step] = dateField.split("/");
1277
+ if (+step !== 2) {
1278
+ return;
1279
+ }
1280
+ if (start === "*" || start === "1") {
1281
+ return "un d\xEDa impar del mes";
1282
+ }
1283
+ if (start === "2") {
1284
+ return "un d\xEDa par del mes";
1285
+ }
1246
1286
  }
1247
1287
  function stepDates(dateField, opts) {
1248
1288
  const parts = dateField.split("/");
@@ -1252,15 +1292,15 @@ function stepDates(dateField, opts) {
1252
1292
  }
1253
1293
  return phrase;
1254
1294
  }
1255
- function applyYear(description, ir, opts) {
1256
- const yearField = ir.pattern.year;
1295
+ function applyYear(description, schedule, opts) {
1296
+ const yearField = schedule.pattern.year;
1257
1297
  if (yearField === "*") {
1258
1298
  return description;
1259
1299
  }
1260
1300
  if (yearField.indexOf("/") !== -1) {
1261
1301
  return description + " " + stepYears(yearField, opts);
1262
1302
  }
1263
- if (foldedYear(ir) && ir.pattern.date !== "*") {
1303
+ if (foldedYear(schedule) && schedule.pattern.date !== "*") {
1264
1304
  return description;
1265
1305
  }
1266
1306
  if (yearField.indexOf(",") !== -1) {
@@ -1319,9 +1359,6 @@ function pluralWeekday(token) {
1319
1359
  function monthName(token) {
1320
1360
  return monthNames[+token];
1321
1361
  }
1322
- function isOpenStep(field) {
1323
- return field.indexOf("/") !== -1 && field.indexOf("-") === -1 && field.indexOf(",") === -1;
1324
- }
1325
1362
  var es2 = {
1326
1363
  describe,
1327
1364
  fallback: "un patr\xF3n cron irreconocible",