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