cronli5 0.2.1 → 0.3.4

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 (55) hide show
  1. package/CHANGELOG.md +109 -0
  2. package/README.md +4 -4
  3. package/cronli5.min.js +2 -2
  4. package/dist/cronli5.cjs +471 -383
  5. package/dist/cronli5.js +471 -383
  6. package/dist/lang/de.cjs +286 -215
  7. package/dist/lang/de.js +286 -215
  8. package/dist/lang/en.cjs +413 -327
  9. package/dist/lang/en.js +413 -327
  10. package/dist/lang/es.cjs +303 -265
  11. package/dist/lang/es.js +303 -265
  12. package/dist/lang/fi.cjs +311 -266
  13. package/dist/lang/fi.js +311 -266
  14. package/dist/lang/zh.cjs +320 -240
  15. package/dist/lang/zh.js +320 -240
  16. package/package.json +6 -6
  17. package/src/core/analyze.ts +12 -12
  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} +17 -18
  23. package/src/core/specs.ts +1 -1
  24. package/src/core/util.ts +3 -165
  25. package/src/core/validate.ts +1 -1
  26. package/src/core/weekday.ts +54 -0
  27. package/src/cronli5.ts +5 -5
  28. package/src/lang/de/index.ts +329 -219
  29. package/src/lang/en/dialects.ts +1 -1
  30. package/src/lang/en/index.ts +521 -372
  31. package/src/lang/es/index.ts +338 -286
  32. package/src/lang/es/notes.md +1 -1
  33. package/src/lang/fi/dialects.ts +1 -1
  34. package/src/lang/fi/index.ts +365 -299
  35. package/src/lang/fi/notes.md +23 -8
  36. package/src/lang/fi/status.json +1 -1
  37. package/src/lang/zh/index.ts +386 -245
  38. package/src/types.ts +6 -6
  39. package/types/core/analyze.d.ts +3 -3
  40. package/types/core/cadence.d.ts +33 -0
  41. package/types/core/index.d.ts +3 -1
  42. package/types/core/normalize.d.ts +1 -1
  43. package/types/core/parse.d.ts +1 -1
  44. package/types/core/{ir.d.ts → schedule.d.ts} +11 -16
  45. package/types/core/specs.d.ts +1 -1
  46. package/types/core/util.d.ts +1 -30
  47. package/types/core/weekday.d.ts +10 -0
  48. package/types/lang/de/index.d.ts +1 -1
  49. package/types/lang/en/dialects.d.ts +1 -1
  50. package/types/lang/en/index.d.ts +1 -1
  51. package/types/lang/es/index.d.ts +1 -1
  52. package/types/lang/fi/dialects.d.ts +1 -1
  53. package/types/lang/fi/index.d.ts +1 -1
  54. package/types/lang/zh/index.d.ts +1 -1
  55. package/types/types.d.ts +5 -5
package/dist/lang/zh.cjs CHANGED
@@ -24,11 +24,7 @@ __export(index_exports, {
24
24
  });
25
25
  module.exports = __toCommonJS(index_exports);
26
26
 
27
- // src/core/util.ts
28
- function isNonNegativeInteger(value) {
29
- const digits = /^\d+$/;
30
- return digits.test(value);
31
- }
27
+ // src/core/cadence.ts
32
28
  function arithmeticStep(values) {
33
29
  if (values.length < 5) {
34
30
  return null;
@@ -44,6 +40,70 @@ function arithmeticStep(values) {
44
40
  }
45
41
  return { start: values[0], interval, last: values[values.length - 1] };
46
42
  }
43
+ function segmentsOf(schedule, field) {
44
+ return schedule.analyses.segments[field] ?? [];
45
+ }
46
+ function stepSegment(schedule, field) {
47
+ return segmentsOf(schedule, field)[0];
48
+ }
49
+ function singleValues(segments) {
50
+ const values = [];
51
+ for (const segment of segments) {
52
+ if (segment.kind !== "single") {
53
+ return null;
54
+ }
55
+ values.push(+segment.value);
56
+ }
57
+ return values;
58
+ }
59
+ function offsetCleanStride(stride) {
60
+ return stride.start < stride.interval && 24 % stride.interval === 0;
61
+ }
62
+ function renderStride(spec, parts) {
63
+ const { start, interval, cycle } = spec;
64
+ const tiles = cycle % interval === 0;
65
+ if (start === 0 && tiles) {
66
+ return parts.bare();
67
+ }
68
+ if (start < interval && tiles) {
69
+ return parts.offset();
70
+ }
71
+ return parts.bounded();
72
+ }
73
+ function hourListStride(values) {
74
+ if (values.length < 2) {
75
+ return null;
76
+ }
77
+ const interval = values[1] - values[0];
78
+ if (interval < 2) {
79
+ return null;
80
+ }
81
+ for (let i = 2; i < values.length; i += 1) {
82
+ if (values[i] - values[i - 1] !== interval) {
83
+ return null;
84
+ }
85
+ }
86
+ if (values[0] !== 0 && values.length < 5) {
87
+ return null;
88
+ }
89
+ return { interval, last: values[values.length - 1], start: values[0] };
90
+ }
91
+
92
+ // src/core/util.ts
93
+ function isNonNegativeInteger(value) {
94
+ const digits = /^\d+$/;
95
+ return digits.test(value);
96
+ }
97
+ function toFieldNumber(token, numberMap) {
98
+ return isNonNegativeInteger(token) ? +token : numberMap[token.toUpperCase()];
99
+ }
100
+
101
+ // src/core/shapes.ts
102
+ function isOpenStep(field) {
103
+ return field.indexOf("/") !== -1 && field.indexOf("-") === -1 && field.indexOf(",") === -1;
104
+ }
105
+
106
+ // src/core/weekday.ts
47
107
  function weekdayDisplayKey(value) {
48
108
  return value === 0 ? 7 : value;
49
109
  }
@@ -64,25 +124,6 @@ function orderWeekdaysForDisplay(segments) {
64
124
  return pair[0];
65
125
  });
66
126
  }
67
- function toFieldNumber(token, numberMap) {
68
- return isNonNegativeInteger(token) ? +token : numberMap[token.toUpperCase()];
69
- }
70
- function segmentsOf(ir, field) {
71
- return ir.analyses.segments[field] ?? [];
72
- }
73
- function stepSegment(ir, field) {
74
- return segmentsOf(ir, field)[0];
75
- }
76
- function singleValues(segments) {
77
- const values = [];
78
- for (const segment of segments) {
79
- if (segment.kind !== "single") {
80
- return null;
81
- }
82
- values.push(+segment.value);
83
- }
84
- return values;
85
- }
86
127
 
87
128
  // src/core/specs.ts
88
129
  var weekdayNumbers = {
@@ -133,19 +174,19 @@ function joinAnd(items) {
133
174
  function cadence(interval, unit) {
134
175
  return interval === 1 ? "\u6BCF" + unit : "\u6BCF" + interval + unit;
135
176
  }
136
- function renderStride(stride) {
177
+ function renderStride2(stride) {
137
178
  const { interval, start, last, cycle, unit, mark, anchor } = stride;
138
- const tiles = cycle % interval === 0;
139
- if (start === 0 && tiles) {
140
- return cadence(interval, unit);
141
- }
142
179
  const lead = anchor + "\u4ECE" + start + mark + "\u8D77" + cadence(interval, unit);
143
- return start < interval && tiles ? lead : lead + "\uFF0C\u81F3" + last + mark;
180
+ return renderStride({ start, interval, cycle }, {
181
+ bare: () => cadence(interval, unit),
182
+ offset: () => lead,
183
+ bounded: () => lead + "\uFF0C\u81F3" + last + mark
184
+ });
144
185
  }
145
186
  function strideFromSegments(segments, unit, mark, anchor) {
146
187
  const values = singleValues(segments);
147
188
  const step = values && arithmeticStep(values);
148
- return step ? renderStride({ ...step, cycle: 60, unit, mark, anchor }) : null;
189
+ return step ? renderStride2({ ...step, cycle: 60, unit, mark, anchor }) : null;
149
190
  }
150
191
  function stepClause(segment, unit, mark, anchor) {
151
192
  const start = segment.startToken === "*" ? 0 : +segment.startToken;
@@ -153,7 +194,7 @@ function stepClause(segment, unit, mark, anchor) {
153
194
  if (segment.startToken.indexOf("-") !== -1 || short) {
154
195
  return anchor + segment.fires.join("\u3001") + mark;
155
196
  }
156
- return renderStride({
197
+ return renderStride2({
157
198
  interval: segment.interval,
158
199
  start,
159
200
  last: segment.fires[segment.fires.length - 1],
@@ -203,9 +244,9 @@ function hourWord(hour) {
203
244
  }
204
245
  return hour === 12 ? "\u6B63\u5348" : hour + "\u70B9";
205
246
  }
206
- function hourFires(ir) {
247
+ function hourFires(schedule) {
207
248
  const fires = [];
208
- segmentsOf(ir, "hour").forEach(function expand(segment) {
249
+ segmentsOf(schedule, "hour").forEach(function expand(segment) {
209
250
  if (segment.kind === "step") {
210
251
  fires.push(...segment.fires);
211
252
  } else if (segment.kind === "range") {
@@ -259,15 +300,15 @@ function renderEveryMinute() {
259
300
  function renderEveryHour() {
260
301
  return "\u6BCF\u5C0F\u65F6";
261
302
  }
262
- function minuteHourClause(ir) {
263
- const segments = segmentsOf(ir, "minute");
264
- if (ir.shapes.minute === "step") {
265
- return stepClause(stepSegment(ir, "minute"), "\u5206\u949F", "\u5206", "\u6BCF\u5C0F\u65F6");
303
+ function minuteHourClause(schedule) {
304
+ const segments = segmentsOf(schedule, "minute");
305
+ if (schedule.shapes.minute === "step") {
306
+ return stepClause(stepSegment(schedule, "minute"), "\u5206\u949F", "\u5206", "\u6BCF\u5C0F\u65F6");
266
307
  }
267
308
  return strideFromSegments(segments, "\u5206\u949F", "\u5206", "\u6BCF\u5C0F\u65F6") ?? "\u6BCF\u5C0F\u65F6" + valueList(segments, "\u5206");
268
309
  }
269
- function renderMinutePast(ir) {
270
- return minuteHourClause(ir);
310
+ function renderMinutePast(schedule) {
311
+ return minuteHourClause(schedule);
271
312
  }
272
313
  function hourSegmentWords(segment) {
273
314
  if (segment.kind === "range") {
@@ -278,62 +319,62 @@ function hourSegmentWords(segment) {
278
319
  }
279
320
  return [hourWord(+segment.value)];
280
321
  }
281
- function hourList(ir) {
282
- const words = segmentsOf(ir, "hour").flatMap(hourSegmentWords);
322
+ function hourList(schedule) {
323
+ const words = segmentsOf(schedule, "hour").flatMap(hourSegmentWords);
283
324
  return joinAnd(words);
284
325
  }
285
- function hourFrame(ir) {
286
- if (ir.shapes.hour === "range") {
287
- const [from, to] = segmentsOf(ir, "hour")[0].bounds;
326
+ function hourFrame(schedule) {
327
+ if (schedule.shapes.hour === "range") {
328
+ const [from, to] = segmentsOf(schedule, "hour")[0].bounds;
288
329
  return "\u5728" + hourWord(+from) + "\u81F3" + hourWord(+to) + "\u4E4B\u95F4\uFF0C";
289
330
  }
290
- return "\u5728" + hourList(ir) + "\uFF0C";
331
+ return "\u5728" + hourList(schedule) + "\uFF0C";
291
332
  }
292
- function renderMinuteFrequency(ir, plan) {
293
- const minuteStep = stepSegment(ir, "minute");
333
+ function renderMinuteFrequency(schedule, plan) {
334
+ const minuteStep = stepSegment(schedule, "minute");
294
335
  const base = stepClause(minuteStep, UNITS.minute, "\u5206", "\u6BCF\u5C0F\u65F6");
295
336
  const { hours } = plan;
296
337
  if (hours.kind === "step" || hours.kind === "during") {
297
- const hourCad = hourCadencePhrase(ir);
338
+ const hourCad = unevenHourCadence(schedule);
298
339
  if (hourCad !== null) {
299
340
  return hourCad + (hourCad.indexOf("\u81F3") === -1 ? "" : "\uFF0C") + base;
300
341
  }
301
342
  }
302
- if (hours.kind === "single" || hours.kind === "window" && hours.from === hours.to) {
343
+ if (hours.kind === "window" && hours.from === hours.to) {
303
344
  return "\u5728" + hourWord(hours.from) + "\u81F3" + hours.from + "\u70B9" + hours.last + "\u5206\u4E4B\u95F4\uFF0C" + base;
304
345
  }
305
346
  if (hours.kind === "window") {
306
347
  return "\u5728" + hourWord(hours.from) + "\u81F3" + hourWord(hours.to) + "\u4E4B\u95F4\uFF0C" + base;
307
348
  }
308
349
  if (hours.kind === "during") {
309
- return "\u5728" + hourList(ir) + "\uFF0C" + base;
350
+ return "\u5728" + hourList(schedule) + "\uFF0C" + base;
310
351
  }
311
352
  return base;
312
353
  }
313
- function renderMinuteSpanInHour(ir, plan) {
354
+ function renderMinuteSpanInHour(schedule, plan) {
314
355
  const span = plan;
315
- if (ir.pattern.minute === "*") {
356
+ if (schedule.pattern.minute === "*") {
316
357
  return hourWord(span.hour) + "\u7684\u6BCF\u4E00\u5206\u949F";
317
358
  }
318
359
  return "\u5728" + hourWord(span.hour) + "\u81F3" + span.hour + "\u70B9" + span.span[1] + "\u5206\u4E4B\u95F4\uFF0C\u6BCF\u5206\u949F";
319
360
  }
320
- function renderMinutesAcrossHours(ir, plan) {
361
+ function renderMinutesAcrossHours(schedule, plan) {
321
362
  const { form } = plan;
322
- const hourCad = hourCadencePhrase(ir);
363
+ const hourCad = unevenHourCadence(schedule);
323
364
  if (form === "wildcard") {
324
- return hourCad === null ? "\u5728" + hourList(ir) + "\uFF0C\u6BCF\u5206\u949F" : hourCad + "\uFF0C\u6BCF\u5206\u949F";
365
+ return hourCad === null ? "\u5728" + hourList(schedule) + "\uFF0C\u6BCF\u5206\u949F" : hourCad + "\uFF0C\u6BCF\u5206\u949F";
325
366
  }
326
- return (hourCad ?? hourList(ir)) + "\uFF0C" + minuteHourClause(ir) + "\uFF0C\u6BCF\u5206\u949F";
367
+ return (hourCad ?? hourList(schedule)) + "\uFF0C" + minuteHourClause(schedule) + "\uFF0C\u6BCF\u5206\u949F";
327
368
  }
328
- function renderMinuteSpanAcrossHourStep(ir, plan) {
329
- const hourStep = stepSegment(ir, "hour");
369
+ function renderMinuteSpanAcrossHourStep(schedule, plan) {
370
+ const hourStep = stepSegment(schedule, "hour");
330
371
  const { form } = plan;
331
372
  if (form === "list") {
332
- return hourCadencePhrase(ir) + "\uFF0C" + renderMinutePast(ir);
373
+ return hourCadencePhrase(schedule) + "\uFF0C" + renderMinutePast(schedule);
333
374
  }
334
- const minuteTail = form === "wildcard" ? "\u6BCF\u5206\u949F" : minuteHourClause(ir) + "\uFF0C\u6BCF\u5206\u949F";
375
+ const minuteTail = form === "wildcard" ? "\u6BCF\u5206\u949F" : minuteHourClause(schedule) + "\uFF0C\u6BCF\u5206\u949F";
335
376
  if (hourStep.startToken !== "*") {
336
- return hourCadencePhrase(ir) + "\uFF0C" + minuteTail;
377
+ return hourCadencePhrase(schedule) + "\uFF0C" + minuteTail;
337
378
  }
338
379
  if (hourStep.interval === 2 && form === "wildcard") {
339
380
  return "\u5728\u5076\u6570\u5C0F\u65F6\uFF0C" + minuteTail;
@@ -341,62 +382,62 @@ function renderMinuteSpanAcrossHourStep(ir, plan) {
341
382
  const cad = cadence(hourStep.interval, UNITS.hour);
342
383
  return form === "wildcard" ? cad + "\u5185\uFF0C" + minuteTail : cad + "\uFF0C" + minuteTail;
343
384
  }
344
- function renderClockTimes(ir, plan, opts) {
345
- const cad = hourCadenceText(ir);
385
+ function renderClockTimes(schedule, plan, opts) {
386
+ const cad = hourCadenceText(schedule);
346
387
  if (cad !== null) {
347
388
  return cad;
348
389
  }
349
390
  const { times } = plan;
350
391
  return joinAnd(times.map((t) => clockTime(t.hour, t.minute, t.second, opts)));
351
392
  }
352
- function renderCompactClockTimes(ir, plan) {
353
- const cad = hourCadenceText(ir);
393
+ function renderCompactClockTimes(schedule, plan) {
394
+ const cad = hourCadenceText(schedule);
354
395
  if (cad !== null) {
355
396
  return cad;
356
397
  }
357
398
  const compact = plan;
358
- const secs = segmentsOf(ir, "second");
359
- const tail = secs.length && ir.pattern.second !== "0" ? "\uFF0C\u7B2C" + valueText(secs) + "\u79D2" : "";
399
+ const secs = segmentsOf(schedule, "second");
400
+ const tail = secs.length && schedule.pattern.second !== "0" ? "\uFF0C\u7B2C" + valueText(secs) + "\u79D2" : "";
360
401
  if (!compact.fold) {
361
- const hourCad = hourCadencePhrase(ir);
362
- return hourCad === null ? minuteHourClause(ir) + "\uFF0C\u5728" + hourList(ir) + tail : hourCad + "\uFF0C" + minuteHourClause(ir) + tail;
402
+ const hourCad = unevenHourCadence(schedule);
403
+ return hourCad === null ? minuteHourClause(schedule) + "\uFF0C\u5728" + hourList(schedule) + tail : hourCad + "\uFF0C" + minuteHourClause(schedule) + tail;
363
404
  }
364
405
  if (compact.minute > 0) {
365
- return minuteHourClause(ir) + "\uFF0C\u5728" + hourList(ir) + tail;
406
+ return minuteHourClause(schedule) + "\uFF0C\u5728" + hourList(schedule) + tail;
366
407
  }
367
- return hourList(ir) + tail;
408
+ return hourList(schedule) + tail;
368
409
  }
369
- function renderHourRange(ir, plan) {
410
+ function renderHourRange(schedule, plan) {
370
411
  const range = plan;
371
412
  if (range.minuteForm === "lead") {
372
- const minuteSegs = segmentsOf(ir, "minute");
373
- const past = minuteSegs.length && ir.pattern.minute !== "0" ? minuteHourClause(ir) : "\u6BCF\u5C0F\u65F6";
413
+ const minuteSegs = segmentsOf(schedule, "minute");
414
+ const past = minuteSegs.length && schedule.pattern.minute !== "0" ? minuteHourClause(schedule) : "\u6BCF\u5C0F\u65F6";
374
415
  return "\u5728" + hourWord(range.from) + "\u81F3" + hourWord(range.to) + "\u4E4B\u95F4\uFF0C" + past;
375
416
  }
376
417
  if (range.minuteForm === "range") {
377
- return "\u5728" + hourWord(range.from) + "\u81F3" + hourWord(range.to) + "\u4E4B\u95F4\uFF0C\u6BCF\u5C0F\u65F6" + valueList(segmentsOf(ir, "minute"), "\u5206") + "\uFF0C\u6BCF\u5206\u949F";
418
+ return "\u5728" + hourWord(range.from) + "\u81F3" + hourWord(range.to) + "\u4E4B\u95F4\uFF0C\u6BCF\u5C0F\u65F6" + valueList(segmentsOf(schedule, "minute"), "\u5206") + "\uFF0C\u6BCF\u5206\u949F";
378
419
  }
379
420
  return "\u5728" + hourWord(range.from) + "\u81F3" + range.to + "\u70B9" + range.last + "\u5206\u4E4B\u95F4\uFF0C\u6BCF\u5206\u949F";
380
421
  }
381
- function renderHourStep(ir) {
382
- const segment = stepSegment(ir, "hour");
422
+ function renderHourStep(schedule) {
423
+ const segment = stepSegment(schedule, "hour");
383
424
  if (segment.fires.length <= 2) {
384
425
  return joinAnd(segment.fires.map(hourWord));
385
426
  }
386
- return hourCadencePhrase(ir);
427
+ return hourCadencePhrase(schedule);
387
428
  }
388
- function hourStride(ir) {
389
- const segments = segmentsOf(ir, "hour");
429
+ function hourStride(schedule) {
430
+ const segments = segmentsOf(schedule, "hour");
390
431
  if (segments.length === 1 && segments[0].kind === "step") {
391
432
  const { fires, interval } = segments[0];
392
433
  return { interval, start: fires[0], last: fires[fires.length - 1] };
393
434
  }
394
435
  const values = singleValues(segments);
395
- return values && arithmeticStep(values);
436
+ return values && hourListStride(values);
396
437
  }
397
- function hourCadencePhrase(ir) {
398
- const stride = hourStride(ir);
399
- return stride && renderStride({
438
+ function hourCadencePhrase(schedule) {
439
+ const stride = hourStride(schedule);
440
+ return stride && renderStride2({
400
441
  ...stride,
401
442
  cycle: 24,
402
443
  unit: UNITS.hour,
@@ -404,76 +445,90 @@ function hourCadencePhrase(ir) {
404
445
  anchor: ""
405
446
  });
406
447
  }
407
- function minuteZeroConfinement(ir, stride, prefix) {
448
+ function unevenHourCadence(schedule) {
449
+ const stride = hourStride(schedule);
450
+ if (!stride) {
451
+ return null;
452
+ }
453
+ if (schedule.shapes.hour !== "step" && offsetCleanStride(stride)) {
454
+ return null;
455
+ }
456
+ return hourCadencePhrase(schedule);
457
+ }
458
+ function shortCleanHourStride(stride) {
459
+ const fires = (stride.last - stride.start) / stride.interval + 1;
460
+ return fires <= maxClockTimes && offsetCleanStride(stride);
461
+ }
462
+ function minuteZeroConfinement(schedule, stride, prefix) {
408
463
  if (stride.interval === 2 && stride.start === 0) {
409
- return "\u5728\u5076\u6570\u5C0F\u65F60\u5206" + secondTail(ir);
464
+ return "\u5728\u5076\u6570\u5C0F\u65F60\u5206" + secondTail(schedule);
410
465
  }
411
466
  if (prefix.indexOf("\u4ECE") !== -1) {
412
- return prefix + "0\u5206" + secondTail(ir);
467
+ return prefix + "0\u5206" + secondTail(schedule);
413
468
  }
414
469
  return null;
415
470
  }
416
- function hourCadence(ir) {
417
- const stride = hourStride(ir);
471
+ function hourCadence(schedule) {
472
+ const stride = hourStride(schedule);
418
473
  if (!stride) {
419
474
  return null;
420
475
  }
421
- const fires = (stride.last - stride.start) / stride.interval + 1;
422
- if (ir.pattern.second === "0" && fires <= maxClockTimes) {
476
+ if (schedule.pattern.second === "0" && shortCleanHourStride(stride)) {
423
477
  return null;
424
478
  }
425
- const prefix = hourCadencePhrase(ir);
479
+ const prefix = hourCadencePhrase(schedule);
426
480
  if (prefix.indexOf("\u81F3") !== -1) {
427
481
  return null;
428
482
  }
429
- const minute = +ir.pattern.minute;
430
- const subMinute = ir.pattern.second === "*" || ir.shapes.second === "step";
483
+ const minute = +schedule.pattern.minute;
484
+ const subMinute = schedule.pattern.second === "*" || schedule.shapes.second === "step";
431
485
  if (minute === 0 && subMinute) {
432
- return minuteZeroConfinement(ir, stride, prefix);
486
+ return minuteZeroConfinement(schedule, stride, prefix);
433
487
  }
434
488
  if (minute === 0) {
435
- return prefix + "0\u5206" + secondTail(ir);
489
+ return prefix + "0\u5206" + secondTail(schedule);
436
490
  }
437
- return ir.pattern.second === "0" ? prefix + minute + "\u5206" : prefix + minute + "\u5206" + secondTail(ir);
491
+ return schedule.pattern.second === "0" ? prefix + minute + "\u5206" : prefix + minute + "\u5206" + secondTail(schedule);
438
492
  }
439
- function hourCadenceText(ir) {
440
- if (ir.shapes.minute !== "single") {
493
+ function hourCadenceText(schedule) {
494
+ if (schedule.shapes.minute !== "single") {
441
495
  return null;
442
496
  }
443
- if (+ir.pattern.minute === 0 && ir.pattern.second === "0") {
444
- return hourCadencePhrase(ir);
497
+ if (+schedule.pattern.minute === 0 && schedule.pattern.second === "0") {
498
+ const stride = hourStride(schedule);
499
+ return stride && !shortCleanHourStride(stride) ? hourCadencePhrase(schedule) : null;
445
500
  }
446
- return hourCadence(ir);
501
+ return hourCadence(schedule);
447
502
  }
448
- function secondTail(ir) {
449
- const sec = secondClause(ir);
503
+ function secondTail(schedule) {
504
+ const sec = secondClause(schedule);
450
505
  return sec === "\u6BCF\u79D2" ? "\u7684\u6BCF\u4E00\u79D2" : "\u7684" + sec;
451
506
  }
452
- function renderRangeOfMinutes(ir) {
453
- return minuteHourClause(ir) + "\uFF0C\u6BCF\u5206\u949F";
507
+ function renderRangeOfMinutes(schedule) {
508
+ return minuteHourClause(schedule) + "\uFF0C\u6BCF\u5206\u949F";
454
509
  }
455
- function renderStandaloneSeconds(ir) {
456
- const segs = segmentsOf(ir, "second");
510
+ function renderStandaloneSeconds(schedule) {
511
+ const segs = segmentsOf(schedule, "second");
457
512
  const first = segs[0];
458
513
  if (segs.length === 1 && first.kind === "step" && first.startToken === "*") {
459
514
  return cadence(first.interval, UNITS.second);
460
515
  }
461
516
  return strideFromSegments(segs, "\u79D2", "\u79D2", "\u6BCF\u5206\u949F") ?? "\u6BCF\u5206\u949F\u7B2C" + valueText(segs) + "\u79D2";
462
517
  }
463
- function renderSecondPastMinute(ir) {
464
- return "\u6BCF\u5206\u949F\u7B2C" + valueText(segmentsOf(ir, "second")) + "\u79D2";
518
+ function renderSecondPastMinute(schedule) {
519
+ return "\u6BCF\u5206\u949F\u7B2C" + valueText(segmentsOf(schedule, "second")) + "\u79D2";
465
520
  }
466
- function renderSecondsWithinMinute(ir) {
467
- const base = "\u6BCF\u5C0F\u65F6" + ir.pattern.minute + "\u5206";
468
- const segs = segmentsOf(ir, "second");
521
+ function renderSecondsWithinMinute(schedule) {
522
+ const base = "\u6BCF\u5C0F\u65F6" + schedule.pattern.minute + "\u5206";
523
+ const segs = segmentsOf(schedule, "second");
469
524
  const first = segs[0];
470
525
  if (segs.length === 1 && first.kind === "step" && first.startToken === "*") {
471
526
  return base + "\uFF0C" + cadence(first.interval, UNITS.second);
472
527
  }
473
528
  return base + "\u7B2C" + valueText(segs) + "\u79D2";
474
529
  }
475
- function secondClause(ir) {
476
- const segs = segmentsOf(ir, "second");
530
+ function secondClause(schedule) {
531
+ const segs = segmentsOf(schedule, "second");
477
532
  if (!segs.length) {
478
533
  return "\u6BCF\u79D2";
479
534
  }
@@ -483,34 +538,34 @@ function secondClause(ir) {
483
538
  }
484
539
  return strideFromSegments(segs, "\u79D2", "\u79D2", "\u6BCF\u5206\u949F") ?? "\u7B2C" + valueText(segs) + "\u79D2";
485
540
  }
486
- function minuteClause(ir) {
487
- if (ir.pattern.minute === "*") {
541
+ function minuteClause(schedule) {
542
+ if (schedule.pattern.minute === "*") {
488
543
  return "\u6BCF\u5206\u949F";
489
544
  }
490
- if (ir.shapes.minute === "step") {
491
- return cadence(stepSegment(ir, "minute").interval, UNITS.minute);
545
+ if (schedule.shapes.minute === "step") {
546
+ return cadence(stepSegment(schedule, "minute").interval, UNITS.minute);
492
547
  }
493
- return valueList(segmentsOf(ir, "minute"), "\u5206");
548
+ return valueList(segmentsOf(schedule, "minute"), "\u5206");
494
549
  }
495
550
  function clockRestCarriesSecond(rest) {
496
551
  return rest.kind === "clockTimes" && rest.times.some((time) => Boolean(time.second));
497
552
  }
498
- function composeSecondsOnHour(ir, plan, opts) {
499
- const sec = secondClause(ir);
553
+ function composeSecondsOnHour(schedule, plan, opts) {
554
+ const sec = secondClause(schedule);
500
555
  const { rest } = plan;
501
556
  const composedClock = rest.kind === "clockTimes" || rest.kind === "compactClockTimes";
502
557
  if (composedClock) {
503
- const hourCad = hourCadence(ir);
558
+ const hourCad = hourCadence(schedule);
504
559
  if (hourCad !== null) {
505
560
  return hourCad;
506
561
  }
507
562
  }
508
- if (composedClock && ir.pattern.minute === "0") {
509
- return composeMinuteZeroClocks(ir, sec);
563
+ if (composedClock && schedule.pattern.minute === "0") {
564
+ return composeMinuteZeroClocks(schedule, sec);
510
565
  }
511
- const restText = render(ir, rest, opts);
566
+ const restText = render(schedule, rest, opts);
512
567
  const secTail = clockRestCarriesSecond(rest) ? "" : sec;
513
- if (composedClock && isDaily(ir)) {
568
+ if (composedClock && isDaily(schedule)) {
514
569
  return "\u6BCF\u5929" + restText + secTail;
515
570
  }
516
571
  if (rest.kind === "singleMinute") {
@@ -518,79 +573,79 @@ function composeSecondsOnHour(ir, plan, opts) {
518
573
  }
519
574
  return restText + secTail;
520
575
  }
521
- function composeMinuteZeroClocks(ir, sec) {
522
- if (hasHourWindow(ir)) {
523
- return isDaily(ir) ? "\u6BCF\u5929" + hourRangeWindow(ir, sec) : hourRangeWindow(ir, sec);
576
+ function composeMinuteZeroClocks(schedule, sec) {
577
+ if (hasHourWindow(schedule)) {
578
+ return isDaily(schedule) ? "\u6BCF\u5929" + hourRangeWindow(schedule, sec) : hourRangeWindow(schedule, sec);
524
579
  }
525
- const clocks = hourFires(ir).map(function clock(hour) {
580
+ const clocks = hourFires(schedule).map(function clock(hour) {
526
581
  return hour === 12 ? "\u6B63\u5348" : hourWord(hour) + "0\u5206";
527
582
  });
528
- const nested = strideFromSegments(segmentsOf(ir, "second"), "\u79D2", "\u79D2", "");
583
+ const nested = strideFromSegments(segmentsOf(schedule, "second"), "\u79D2", "\u79D2", "");
529
584
  const tail = sec === "\u6BCF\u79D2" ? "\u7684\u6BCF\u4E00\u79D2" : "\u7684" + (nested ?? sec);
530
585
  const core = joinAnd(clocks) + tail;
531
- return isDaily(ir) ? "\u6BCF\u5929" + core : core;
586
+ return isDaily(schedule) ? "\u6BCF\u5929" + core : core;
532
587
  }
533
- function hasHourWindow(ir) {
534
- return segmentsOf(ir, "hour").some(function range(segment) {
588
+ function hasHourWindow(schedule) {
589
+ return segmentsOf(schedule, "hour").some(function range(segment) {
535
590
  return segment.kind === "range";
536
591
  });
537
592
  }
538
- function hourRangeWindow(ir, sec) {
539
- const span = hourList(ir);
540
- if (ir.pattern.second === "*" || ir.shapes.second === "step") {
593
+ function hourRangeWindow(schedule, sec) {
594
+ const span = hourList(schedule);
595
+ if (schedule.pattern.second === "*" || schedule.shapes.second === "step") {
541
596
  return span + "0\u5206" + (sec === "\u6BCF\u79D2" ? "\u7684\u6BCF\u4E00\u79D2" : "\u7684" + sec);
542
597
  }
543
598
  return span + "\uFF0C" + sec;
544
599
  }
545
- function composeSecondsCadence(ir) {
546
- const sec = secondClause(ir);
547
- const tail = minuteClause(ir) + sec;
548
- const hourCad = hourCadencePhrase(ir);
600
+ function composeSecondsCadence(schedule) {
601
+ const sec = secondClause(schedule);
602
+ const tail = minuteClause(schedule) + sec;
603
+ const hourCad = unevenHourCadence(schedule);
549
604
  if (hourCad !== null) {
550
605
  return hourCad + (hourCad.indexOf("\u81F3") === -1 ? "\u7684" : "\uFF0C") + tail;
551
606
  }
552
- if (ir.shapes.hour === "single") {
553
- return hourWord(hourFires(ir)[0]) + "\u7684" + tail;
607
+ if (schedule.shapes.hour === "single") {
608
+ return hourWord(hourFires(schedule)[0]) + "\u7684" + tail;
554
609
  }
555
- if (ir.shapes.hour === "wildcard") {
556
- if (ir.shapes.minute === "step" && sec === "\u6BCF\u79D2") {
557
- const minuteStep = stepSegment(ir, "minute");
610
+ if (schedule.shapes.hour === "wildcard") {
611
+ if (schedule.shapes.minute === "step" && sec === "\u6BCF\u79D2") {
612
+ const minuteStep = stepSegment(schedule, "minute");
558
613
  if (minuteStep.startToken === "*" && minuteStep.interval === 2) {
559
614
  return "\u6BCF\u5076\u6570\u5206\u949F\u7684\u6BCF\u4E00\u79D2";
560
615
  }
561
616
  }
562
- return sec + "\uFF0C" + minuteClause(ir);
617
+ return sec + "\uFF0C" + minuteClause(schedule);
563
618
  }
564
- return hourFrame(ir) + tail;
619
+ return hourFrame(schedule) + tail;
565
620
  }
566
- function composeSecondsListed(ir) {
567
- const sec = secondClause(ir);
568
- const minutes = minuteHourClause(ir);
569
- if (ir.shapes.hour === "single" && sec === "\u6BCF\u79D2") {
570
- const minuteSegs = segmentsOf(ir, "minute");
621
+ function composeSecondsListed(schedule) {
622
+ const sec = secondClause(schedule);
623
+ const minutes = minuteHourClause(schedule);
624
+ if (schedule.shapes.hour === "single" && sec === "\u6BCF\u79D2") {
625
+ const minuteSegs = segmentsOf(schedule, "minute");
571
626
  const minuteCad = strideFromSegments(minuteSegs, "\u5206\u949F", "\u5206", "") ?? valueList(minuteSegs, "\u5206");
572
- return hourWord(hourFires(ir)[0]) + minuteCad + "\u7684\u6BCF\u4E00\u79D2";
627
+ return hourWord(hourFires(schedule)[0]) + minuteCad + "\u7684\u6BCF\u4E00\u79D2";
573
628
  }
574
- if (ir.shapes.hour === "wildcard") {
629
+ if (schedule.shapes.hour === "wildcard") {
575
630
  return minutes + "\uFF0C" + sec;
576
631
  }
577
- const hourCad = hourCadencePhrase(ir);
632
+ const hourCad = unevenHourCadence(schedule);
578
633
  if (hourCad !== null) {
579
634
  return hourCad + "\uFF0C" + minutes + "\uFF0C" + sec;
580
635
  }
581
- return hourFrame(ir) + minutes + "\uFF0C" + sec;
636
+ return hourFrame(schedule) + minutes + "\uFF0C" + sec;
582
637
  }
583
- function renderComposeSeconds(ir, plan, opts) {
638
+ function renderComposeSeconds(schedule, plan, opts) {
584
639
  const { rest } = plan;
585
640
  const composedClock = rest.kind === "clockTimes" || rest.kind === "compactClockTimes";
586
- if (ir.pattern.minute === "0" || composedClock && ir.shapes.minute === "single") {
587
- return composeSecondsOnHour(ir, plan, opts);
641
+ if (schedule.pattern.minute === "0" || composedClock && schedule.shapes.minute === "single") {
642
+ return composeSecondsOnHour(schedule, plan, opts);
588
643
  }
589
- const minuteCadence = ir.pattern.minute === "*" || ir.shapes.minute === "step" && stepSegment(ir, "minute").startToken === "*";
644
+ const minuteCadence = schedule.pattern.minute === "*" || schedule.shapes.minute === "step" && stepSegment(schedule, "minute").startToken === "*";
590
645
  if (minuteCadence) {
591
- return composeSecondsCadence(ir);
646
+ return composeSecondsCadence(schedule);
592
647
  }
593
- return composeSecondsListed(ir);
648
+ return composeSecondsListed(schedule);
594
649
  }
595
650
  var renderers = {
596
651
  clockTimes: renderClockTimes,
@@ -612,20 +667,27 @@ var renderers = {
612
667
  singleMinute: renderMinutePast,
613
668
  standaloneSeconds: renderStandaloneSeconds
614
669
  };
615
- function render(ir, plan, opts) {
670
+ function render(schedule, plan, opts) {
616
671
  return renderers[plan.kind](
617
- ir,
672
+ schedule,
618
673
  plan,
619
674
  opts
620
675
  );
621
676
  }
622
- function monthPhrase(ir) {
623
- if (ir.pattern.month === "*") {
677
+ function boundedParityMonth(schedule) {
678
+ if (schedule.shapes.month !== "step" || isOpenStep(schedule.pattern.month)) {
679
+ return false;
680
+ }
681
+ const segs = segmentsOf(schedule, "month");
682
+ return segs.length === 1 && segs[0].kind === "step" && segs[0].interval === 2;
683
+ }
684
+ function monthPhrase(schedule) {
685
+ if (schedule.pattern.month === "*") {
624
686
  return "";
625
687
  }
626
- const segs = segmentsOf(ir, "month");
688
+ const segs = segmentsOf(schedule, "month");
627
689
  const first = segs[0];
628
- if (segs.length === 1 && first.kind === "step" && first.interval === 2) {
690
+ if (segs.length === 1 && first.kind === "step" && first.interval === 2 && isOpenStep(schedule.pattern.month)) {
629
691
  return "\u6BCF\u4E2A" + (first.fires[0] % 2 ? "\u5947" : "\u5076") + "\u6570\u6708";
630
692
  }
631
693
  if (segs.length === 1 && first.kind === "range") {
@@ -641,16 +703,16 @@ function monthPhrase(ir) {
641
703
  });
642
704
  return nums.join("\u3001") + "\u6708";
643
705
  }
644
- function dayList(ir) {
645
- const segs = segmentsOf(ir, "date");
646
- if (segs.every((seg) => seg.kind === "single")) {
647
- return segs.map((seg) => seg.value).join("\u3001") + "\u65E5";
706
+ function dayList(schedule) {
707
+ const segs = segmentsOf(schedule, "date");
708
+ if (segs.every((seg) => seg.kind === "single" || seg.kind === "step")) {
709
+ return fireValues(segs).join("\u3001") + "\u65E5";
648
710
  }
649
711
  return segs.map(function day(seg) {
650
712
  if (seg.kind === "range") {
651
713
  return seg.bounds[0] + "\u65E5\u81F3" + seg.bounds[1] + "\u65E5";
652
714
  }
653
- return seg.value + "\u65E5";
715
+ return seg.kind === "step" ? seg.fires.join("\u3001") + "\u65E5" : seg.value + "\u65E5";
654
716
  }).join("\u3001");
655
717
  }
656
718
  function quartzDate(token, monthPrefix) {
@@ -665,32 +727,46 @@ function quartzDate(token, monthPrefix) {
665
727
  }
666
728
  return monthPrefix + "\u6700\u63A5\u8FD1" + token.slice(0, -1) + "\u65E5\u7684\u5DE5\u4F5C\u65E5";
667
729
  }
668
- function datePhrase(ir) {
669
- const month = monthPhrase(ir);
670
- const date = ir.pattern.date;
730
+ function oddEvenDay(dateField, monthLead) {
731
+ if (!isOpenStep(dateField)) {
732
+ return null;
733
+ }
734
+ const [start, step] = dateField.split("/");
735
+ if (+step !== 2) {
736
+ return null;
737
+ }
738
+ const lead = monthLead ? "\u6BCF\u6708" : "";
739
+ if (start === "*" || start === "1") {
740
+ return lead + "\u5355\u6570\u65E5";
741
+ }
742
+ return start === "2" ? lead + "\u53CC\u6570\u65E5" : null;
743
+ }
744
+ function datePhrase(schedule) {
745
+ const month = monthPhrase(schedule);
746
+ const date = schedule.pattern.date;
671
747
  if (date === "*" || date === "?") {
672
748
  return month;
673
749
  }
674
- if (ir.shapes.date === "quartz") {
750
+ if (schedule.shapes.date === "quartz") {
675
751
  return quartzDate(date, month || "\u672C\u6708");
676
752
  }
677
- if (ir.shapes.date === "step") {
678
- return month + cadence(stepSegment(ir, "date").interval, "\u5929");
753
+ if (schedule.shapes.date === "step" && isOpenStep(date)) {
754
+ return month + cadence(stepSegment(schedule, "date").interval, "\u5929");
679
755
  }
680
756
  if (!month) {
681
- return "\u6BCF\u6708" + dayList(ir);
757
+ return "\u6BCF\u6708" + dayList(schedule);
682
758
  }
683
- const monthMulti = ir.shapes.month === "range" || ir.shapes.month === "list";
684
- return month + (monthMulti ? "\uFF0C" : "") + dayList(ir);
759
+ const monthMulti = schedule.shapes.month === "range" || schedule.shapes.month === "list" || boundedParityMonth(schedule);
760
+ return month + (monthMulti ? "\uFF0C" : "") + dayList(schedule);
685
761
  }
686
- function dateCore(ir, quartzPrefix) {
687
- if (ir.shapes.date === "quartz") {
688
- return quartzDate(ir.pattern.date, quartzPrefix);
762
+ function dateCore(schedule, quartzPrefix) {
763
+ if (schedule.shapes.date === "quartz") {
764
+ return quartzDate(schedule.pattern.date, quartzPrefix);
689
765
  }
690
- if (ir.shapes.date === "step") {
691
- return cadence(stepSegment(ir, "date").interval, "\u5929");
766
+ if (schedule.shapes.date === "step" && isOpenStep(schedule.pattern.date)) {
767
+ return cadence(stepSegment(schedule, "date").interval, "\u5929");
692
768
  }
693
- return dayList(ir);
769
+ return dayList(schedule);
694
770
  }
695
771
  function weekdayName(token) {
696
772
  const number = toFieldNumber(token, weekdayNumbers);
@@ -713,11 +789,11 @@ function quartzWeekday(token, monthPrefix) {
713
789
  const [day, nth] = token.split("#");
714
790
  return "\u7B2C" + nth + "\u4E2A" + weekdayName(day);
715
791
  }
716
- function weekdayPhrase(ir, orContext, monthPrefix) {
717
- if (ir.shapes.weekday === "quartz") {
718
- return quartzWeekday(ir.pattern.weekday, monthPrefix);
792
+ function weekdayPhrase(schedule, orContext, monthPrefix) {
793
+ if (schedule.shapes.weekday === "quartz") {
794
+ return quartzWeekday(schedule.pattern.weekday, monthPrefix);
719
795
  }
720
- const segs = segmentsOf(ir, "weekday");
796
+ const segs = segmentsOf(schedule, "weekday");
721
797
  if (segs.length === 1 && segs[0].kind === "range") {
722
798
  const [from, to] = segs[0].bounds;
723
799
  return "\u6BCF" + weekdayName(from) + "\u81F3" + weekdayName(to);
@@ -734,84 +810,88 @@ function weekdayPhrase(ir, orContext, monthPrefix) {
734
810
  function isSet(token) {
735
811
  return token !== "*" && token !== "?";
736
812
  }
737
- function qualifier(ir) {
738
- const dateSet = isSet(ir.pattern.date);
739
- const weekdaySet = isSet(ir.pattern.weekday);
813
+ function qualifier(schedule) {
814
+ const dateSet = isSet(schedule.pattern.date);
815
+ const weekdaySet = isSet(schedule.pattern.weekday);
740
816
  if (dateSet && weekdaySet) {
741
- const month = monthPhrase(ir);
817
+ const month = monthPhrase(schedule);
742
818
  if (month) {
743
- return month + "\uFF0C" + dateCore(ir, "") + "\u6216" + weekdayPhrase(ir, true, "");
819
+ const date2 = oddEvenDay(schedule.pattern.date, false) || dateCore(schedule, "");
820
+ return month + "\uFF0C" + date2 + "\u6216" + weekdayPhrase(schedule, true, "");
744
821
  }
745
- return datePhrase(ir) + "\u6216" + weekdayPhrase(ir, true, "\u672C\u6708");
822
+ const date = oddEvenDay(schedule.pattern.date, true) || datePhrase(schedule);
823
+ return date + "\u6216" + weekdayPhrase(schedule, true, "\u672C\u6708");
746
824
  }
747
825
  if (dateSet) {
748
- return datePhrase(ir);
826
+ return datePhrase(schedule);
749
827
  }
750
828
  if (weekdaySet) {
751
- const month = monthPhrase(ir);
752
- if (ir.shapes.weekday === "quartz") {
753
- return quartzWeekday(ir.pattern.weekday, month || "\u672C\u6708");
829
+ const month = monthPhrase(schedule);
830
+ if (schedule.shapes.weekday === "quartz") {
831
+ return quartzWeekday(schedule.pattern.weekday, month || "\u672C\u6708");
754
832
  }
755
- return month + weekdayPhrase(ir, false, "\u672C\u6708");
833
+ return month + weekdayPhrase(schedule, false, "\u672C\u6708");
756
834
  }
757
- return monthPhrase(ir);
835
+ return monthPhrase(schedule);
758
836
  }
759
- function isDaily(ir) {
760
- return !isSet(ir.pattern.date) && !isSet(ir.pattern.weekday);
837
+ function isDaily(schedule) {
838
+ return !isSet(schedule.pattern.date) && !isSet(schedule.pattern.weekday);
761
839
  }
762
- function composePoint(ir, core) {
763
- const qual = qualifier(ir);
764
- if (isDaily(ir)) {
840
+ function composePoint(schedule, core) {
841
+ const qual = qualifier(schedule);
842
+ if (isDaily(schedule)) {
765
843
  return qual + "\u6BCF\u5929" + core;
766
844
  }
767
- const dateSet = isSet(ir.pattern.date);
768
- const weekdaySet = isSet(ir.pattern.weekday);
769
- const comma = dateSet && weekdaySet || ir.shapes.date === "step";
845
+ const dateSet = isSet(schedule.pattern.date);
846
+ const weekdaySet = isSet(schedule.pattern.weekday);
847
+ const dateCadence = schedule.shapes.date === "step" && isOpenStep(schedule.pattern.date);
848
+ const comma = dateSet && weekdaySet || dateCadence;
770
849
  return qual + (comma ? "\uFF0C" : "") + core;
771
850
  }
772
- function composeCadence(ir, core) {
773
- const qual = qualifier(ir);
851
+ function composeCadence(schedule, core) {
852
+ const qual = qualifier(schedule);
774
853
  if (!qual) {
775
854
  return core;
776
855
  }
777
- if (ir.plan.kind === "minuteFrequency") {
778
- const lead = ir.plan.hours.kind !== "none";
856
+ if (schedule.plan.kind === "minuteFrequency") {
857
+ const lead = schedule.plan.hours.kind !== "none";
779
858
  return lead ? qual + "\uFF0C" + core : core + "\uFF0C" + qual;
780
859
  }
781
- if (ir.plan.kind === "compactClockTimes") {
860
+ if (schedule.plan.kind === "compactClockTimes") {
782
861
  return qual + "\uFF0C" + core;
783
862
  }
784
- const dateSet = isSet(ir.pattern.date);
785
- const weekdaySet = isSet(ir.pattern.weekday);
786
- const trail = dateSet && (ir.shapes.date !== "step" || weekdaySet);
863
+ const dateSet = isSet(schedule.pattern.date);
864
+ const weekdaySet = isSet(schedule.pattern.weekday);
865
+ const trail = dateSet && (schedule.shapes.date !== "step" || weekdaySet);
787
866
  return trail ? core + "\uFF0C" + qual : qual + "\uFF0C" + core;
788
867
  }
789
- function composeWindow(ir, core) {
790
- return qualifier(ir) + core;
868
+ function composeWindow(schedule, core) {
869
+ const union = isSet(schedule.pattern.date) && isSet(schedule.pattern.weekday);
870
+ return qualifier(schedule) + (union ? "\uFF0C" : "") + core;
791
871
  }
792
- function hourCadenceApplies(ir) {
793
- return hourCadenceText(ir) !== null;
872
+ function hourCadenceApplies(schedule) {
873
+ return hourCadenceText(schedule) !== null;
794
874
  }
795
- function describe(ir, opts) {
796
- const { kind } = ir.plan;
797
- const core = render(ir, ir.plan, opts);
875
+ function describe(schedule, opts) {
876
+ const { kind } = schedule.plan;
877
+ const core = render(schedule, schedule.plan, opts);
798
878
  let composed = core;
799
- if (hourCadenceApplies(ir)) {
800
- composed = composeCadence(ir, core);
801
- } else if (kind === "clockTimes" || kind === "compactClockTimes" && ir.pattern.minute === "0") {
802
- composed = composePoint(ir, core);
879
+ if (hourCadenceApplies(schedule)) {
880
+ composed = composeCadence(schedule, core);
881
+ } else if (kind === "clockTimes" || kind === "compactClockTimes" && schedule.pattern.minute === "0") {
882
+ composed = composePoint(schedule, core);
803
883
  } else if (kind === "hourStep" || kind === "minuteFrequency" || kind === "minuteSpanAcrossHourStep" || kind === "compactClockTimes") {
804
- composed = composeCadence(ir, core);
884
+ composed = composeCadence(schedule, core);
805
885
  } else if (kind === "hourRange") {
806
- composed = composeWindow(ir, core);
886
+ composed = composeWindow(schedule, core);
807
887
  } else {
808
- const qual = qualifier(ir);
809
- composed = qual ? composeCadence(ir, core) : core;
888
+ const qual = qualifier(schedule);
889
+ composed = qual ? composeCadence(schedule, core) : core;
810
890
  }
811
- if (ir.pattern.year === "*") {
891
+ if (schedule.pattern.year === "*") {
812
892
  return composed;
813
893
  }
814
- const year = segmentsOf(ir, "year").map(function part(seg) {
894
+ const year = segmentsOf(schedule, "year").map(function part(seg) {
815
895
  if (seg.kind === "range") {
816
896
  return seg.bounds[0] + "\u5E74\u81F3" + seg.bounds[1] + "\u5E74";
817
897
  }