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.
- package/CHANGELOG.md +90 -0
- package/README.md +4 -4
- package/cronli5.min.js +2 -2
- package/dist/cronli5.cjs +514 -407
- package/dist/cronli5.js +514 -407
- package/dist/lang/de.cjs +296 -225
- package/dist/lang/de.js +296 -225
- package/dist/lang/en.cjs +471 -364
- package/dist/lang/en.js +471 -364
- package/dist/lang/es.cjs +318 -281
- package/dist/lang/es.js +318 -281
- package/dist/lang/fi.cjs +326 -276
- package/dist/lang/fi.js +326 -276
- package/dist/lang/zh.cjs +308 -236
- package/dist/lang/zh.js +308 -236
- package/package.json +1 -1
- package/src/core/analyze.ts +22 -21
- package/src/core/cadence.ts +164 -0
- package/src/core/index.ts +3 -1
- package/src/core/normalize.ts +3 -3
- package/src/core/parse.ts +1 -1
- package/src/core/{ir.ts → schedule.ts} +23 -24
- package/src/core/shapes.ts +8 -1
- package/src/core/specs.ts +1 -1
- package/src/core/util.ts +4 -83
- package/src/core/validate.ts +2 -2
- package/src/core/weekday.ts +54 -0
- package/src/cronli5.ts +7 -7
- package/src/lang/de/index.ts +329 -288
- package/src/lang/en/dialects.ts +1 -1
- package/src/lang/en/index.ts +640 -516
- package/src/lang/es/index.ts +342 -374
- package/src/lang/es/notes.md +1 -1
- package/src/lang/fi/dialects.ts +1 -1
- package/src/lang/fi/index.ts +367 -372
- package/src/lang/fi/notes.md +23 -8
- package/src/lang/fi/status.json +1 -1
- package/src/lang/zh/index.ts +344 -262
- package/src/types.ts +6 -6
- package/types/core/analyze.d.ts +4 -4
- package/types/core/cadence.d.ts +33 -0
- package/types/core/index.d.ts +3 -1
- package/types/core/normalize.d.ts +1 -1
- package/types/core/parse.d.ts +1 -1
- package/types/core/{ir.d.ts → schedule.d.ts} +16 -21
- package/types/core/shapes.d.ts +2 -1
- package/types/core/specs.d.ts +1 -1
- package/types/core/util.d.ts +1 -15
- package/types/core/weekday.d.ts +10 -0
- package/types/lang/de/index.d.ts +1 -1
- package/types/lang/en/dialects.d.ts +1 -1
- package/types/lang/en/index.d.ts +1 -1
- package/types/lang/es/index.d.ts +1 -1
- package/types/lang/fi/dialects.d.ts +1 -1
- package/types/lang/fi/index.d.ts +1 -1
- package/types/lang/zh/index.d.ts +1 -1
- package/types/types.d.ts +5 -5
package/dist/cronli5.js
CHANGED
|
@@ -69,41 +69,6 @@ function isNonNegativeInteger(value) {
|
|
|
69
69
|
const digits = /^\d+$/;
|
|
70
70
|
return digits.test(value);
|
|
71
71
|
}
|
|
72
|
-
function arithmeticStep(values) {
|
|
73
|
-
if (values.length < 5) {
|
|
74
|
-
return null;
|
|
75
|
-
}
|
|
76
|
-
const interval = values[1] - values[0];
|
|
77
|
-
if (interval < 2) {
|
|
78
|
-
return null;
|
|
79
|
-
}
|
|
80
|
-
for (let i = 2; i < values.length; i += 1) {
|
|
81
|
-
if (values[i] - values[i - 1] !== interval) {
|
|
82
|
-
return null;
|
|
83
|
-
}
|
|
84
|
-
}
|
|
85
|
-
return { start: values[0], interval, last: values[values.length - 1] };
|
|
86
|
-
}
|
|
87
|
-
function weekdayDisplayKey(value) {
|
|
88
|
-
return value === 0 ? 7 : value;
|
|
89
|
-
}
|
|
90
|
-
function orderWeekdaysForDisplay(segments) {
|
|
91
|
-
const flattened = segments.flatMap(function flat(segment) {
|
|
92
|
-
return segment.kind === "step" ? segment.fires.map(function single(value) {
|
|
93
|
-
return { kind: "single", value: "" + value };
|
|
94
|
-
}) : [segment];
|
|
95
|
-
});
|
|
96
|
-
function key(segment) {
|
|
97
|
-
return segment.kind === "range" ? weekdayDisplayKey(+segment.bounds[0]) : weekdayDisplayKey(+segment.value);
|
|
98
|
-
}
|
|
99
|
-
return flattened.map(function index(segment, position) {
|
|
100
|
-
return [segment, position];
|
|
101
|
-
}).sort(function byDisplayKey(a, b) {
|
|
102
|
-
return key(a[0]) - key(b[0]) || a[1] - b[1];
|
|
103
|
-
}).map(function unwrap(pair) {
|
|
104
|
-
return pair[0];
|
|
105
|
-
});
|
|
106
|
-
}
|
|
107
72
|
function toFieldNumber(token, numberMap) {
|
|
108
73
|
return isNonNegativeInteger(token) ? +token : numberMap[token.toUpperCase()];
|
|
109
74
|
}
|
|
@@ -236,7 +201,7 @@ function normalizeField(value, field, spec) {
|
|
|
236
201
|
const cycle = timeFieldCycle[field];
|
|
237
202
|
const segments = stringValue.split(",").map(function canonical(segment) {
|
|
238
203
|
return canonicalizeTokens(collapseFullSpanRange(
|
|
239
|
-
|
|
204
|
+
enumerateIfNonUniform(
|
|
240
205
|
collapseFullSpanStep(
|
|
241
206
|
collapseDegenerateRange(
|
|
242
207
|
collapseOnceStep(collapseUnitStep(segment, spec), spec),
|
|
@@ -300,7 +265,7 @@ function collapseOnceStep(segment, spec) {
|
|
|
300
265
|
}
|
|
301
266
|
return start === "*" ? "" + spec.min : start;
|
|
302
267
|
}
|
|
303
|
-
function
|
|
268
|
+
function enumerateIfNonUniform(segment, spec, cycle) {
|
|
304
269
|
const parts = segment.split("/");
|
|
305
270
|
if (typeof cycle !== "number" || parts.length !== 2 || includes(parts[0], "-")) {
|
|
306
271
|
return segment;
|
|
@@ -439,6 +404,93 @@ function expandMacro(cronString) {
|
|
|
439
404
|
throw new Error("`cronli5` does not recognize the macro `" + trimmed + "`.");
|
|
440
405
|
}
|
|
441
406
|
|
|
407
|
+
// src/core/weekday.ts
|
|
408
|
+
function weekdayDisplayKey(value) {
|
|
409
|
+
return value === 0 ? 7 : value;
|
|
410
|
+
}
|
|
411
|
+
function orderWeekdaysForDisplay(segments) {
|
|
412
|
+
const flattened = segments.flatMap(function flat(segment) {
|
|
413
|
+
return segment.kind === "step" ? segment.fires.map(function single(value) {
|
|
414
|
+
return { kind: "single", value: "" + value };
|
|
415
|
+
}) : [segment];
|
|
416
|
+
});
|
|
417
|
+
function key(segment) {
|
|
418
|
+
return segment.kind === "range" ? weekdayDisplayKey(+segment.bounds[0]) : weekdayDisplayKey(+segment.value);
|
|
419
|
+
}
|
|
420
|
+
return flattened.map(function index(segment, position) {
|
|
421
|
+
return [segment, position];
|
|
422
|
+
}).sort(function byDisplayKey(a, b) {
|
|
423
|
+
return key(a[0]) - key(b[0]) || a[1] - b[1];
|
|
424
|
+
}).map(function unwrap(pair) {
|
|
425
|
+
return pair[0];
|
|
426
|
+
});
|
|
427
|
+
}
|
|
428
|
+
|
|
429
|
+
// src/core/cadence.ts
|
|
430
|
+
function arithmeticStep(values) {
|
|
431
|
+
if (values.length < 5) {
|
|
432
|
+
return null;
|
|
433
|
+
}
|
|
434
|
+
const interval = values[1] - values[0];
|
|
435
|
+
if (interval < 2) {
|
|
436
|
+
return null;
|
|
437
|
+
}
|
|
438
|
+
for (let i = 2; i < values.length; i += 1) {
|
|
439
|
+
if (values[i] - values[i - 1] !== interval) {
|
|
440
|
+
return null;
|
|
441
|
+
}
|
|
442
|
+
}
|
|
443
|
+
return { start: values[0], interval, last: values[values.length - 1] };
|
|
444
|
+
}
|
|
445
|
+
function segmentsOf(schedule, field) {
|
|
446
|
+
return schedule.analyses.segments[field] ?? [];
|
|
447
|
+
}
|
|
448
|
+
function stepSegment(schedule, field) {
|
|
449
|
+
return segmentsOf(schedule, field)[0];
|
|
450
|
+
}
|
|
451
|
+
function singleValues(segments) {
|
|
452
|
+
const values = [];
|
|
453
|
+
for (const segment of segments) {
|
|
454
|
+
if (segment.kind !== "single") {
|
|
455
|
+
return null;
|
|
456
|
+
}
|
|
457
|
+
values.push(+segment.value);
|
|
458
|
+
}
|
|
459
|
+
return values;
|
|
460
|
+
}
|
|
461
|
+
function offsetCleanStride(stride) {
|
|
462
|
+
return stride.start < stride.interval && 24 % stride.interval === 0;
|
|
463
|
+
}
|
|
464
|
+
function renderStride(spec, parts) {
|
|
465
|
+
const { start, interval, cycle } = spec;
|
|
466
|
+
const tiles = cycle % interval === 0;
|
|
467
|
+
if (start === 0 && tiles) {
|
|
468
|
+
return parts.bare();
|
|
469
|
+
}
|
|
470
|
+
if (start < interval && tiles) {
|
|
471
|
+
return parts.offset();
|
|
472
|
+
}
|
|
473
|
+
return parts.bounded();
|
|
474
|
+
}
|
|
475
|
+
function hourListStride(values) {
|
|
476
|
+
if (values.length < 2) {
|
|
477
|
+
return null;
|
|
478
|
+
}
|
|
479
|
+
const interval = values[1] - values[0];
|
|
480
|
+
if (interval < 2) {
|
|
481
|
+
return null;
|
|
482
|
+
}
|
|
483
|
+
for (let i = 2; i < values.length; i += 1) {
|
|
484
|
+
if (values[i] - values[i - 1] !== interval) {
|
|
485
|
+
return null;
|
|
486
|
+
}
|
|
487
|
+
}
|
|
488
|
+
if (values[0] !== 0 && values.length < 5) {
|
|
489
|
+
return null;
|
|
490
|
+
}
|
|
491
|
+
return { interval, last: values[values.length - 1], start: values[0] };
|
|
492
|
+
}
|
|
493
|
+
|
|
442
494
|
// src/core/shapes.ts
|
|
443
495
|
function isSingleValue(field) {
|
|
444
496
|
return field !== "*" && !includes(field, ",") && !includes(field, "-") && !includes(field, "/");
|
|
@@ -455,6 +507,9 @@ function isDiscreteList(field) {
|
|
|
455
507
|
function isDiscreteHours(hourField) {
|
|
456
508
|
return hourField !== "*" && !isPlainRange(hourField) && !isPlainStep(hourField);
|
|
457
509
|
}
|
|
510
|
+
function isOpenStep(field) {
|
|
511
|
+
return field.indexOf("/") !== -1 && field.indexOf("-") === -1 && field.indexOf(",") === -1;
|
|
512
|
+
}
|
|
458
513
|
|
|
459
514
|
// src/core/analyze.ts
|
|
460
515
|
function getOccurrences(start, interval, max) {
|
|
@@ -590,11 +645,11 @@ function analyze(pattern) {
|
|
|
590
645
|
minuteSpan: minuteSpan(pattern.minute),
|
|
591
646
|
segments
|
|
592
647
|
};
|
|
593
|
-
const
|
|
594
|
-
return { ...
|
|
648
|
+
const facts = { analyses, pattern, shapes };
|
|
649
|
+
return { ...facts, plan: selectPlan(facts) };
|
|
595
650
|
}
|
|
596
|
-
function
|
|
597
|
-
const { analyses, pattern, shapes } =
|
|
651
|
+
function selectPlan(facts) {
|
|
652
|
+
const { analyses, pattern, shapes } = facts;
|
|
598
653
|
if (pattern.second !== "0") {
|
|
599
654
|
const seconds = planSeconds(pattern, shapes, analyses);
|
|
600
655
|
if (seconds) {
|
|
@@ -938,72 +993,134 @@ function normalizeOptions(options) {
|
|
|
938
993
|
years: !!options.years
|
|
939
994
|
};
|
|
940
995
|
}
|
|
941
|
-
function describe(
|
|
942
|
-
const
|
|
943
|
-
|
|
944
|
-
|
|
996
|
+
function describe(schedule, opts) {
|
|
997
|
+
const dense = denseCadence(schedule, opts);
|
|
998
|
+
if (dense !== null) {
|
|
999
|
+
return applyYear(dense, schedule, opts);
|
|
1000
|
+
}
|
|
1001
|
+
const body = confinement(schedule, opts) ?? render(schedule, schedule.plan, opts);
|
|
1002
|
+
const lead = isDayUnion(schedule, opts) ? dayUnionMonthLead(schedule, opts) : "";
|
|
1003
|
+
return applyYear(lead + body, schedule, opts);
|
|
945
1004
|
}
|
|
946
|
-
function render(
|
|
1005
|
+
function render(schedule, plan, opts) {
|
|
947
1006
|
const renderer = renderers[plan.kind];
|
|
948
|
-
return renderer(
|
|
1007
|
+
return renderer(schedule, plan, opts);
|
|
949
1008
|
}
|
|
950
|
-
function
|
|
951
|
-
return "
|
|
1009
|
+
function isCadenceShape(shape) {
|
|
1010
|
+
return shape === "step" || shape === "range" || shape === "list";
|
|
952
1011
|
}
|
|
953
|
-
function
|
|
954
|
-
|
|
1012
|
+
function isDenseCadence(schedule, opts) {
|
|
1013
|
+
if (!opts.style.untilWindow || opts.short || schedule.plan.kind !== "composeSeconds" || schedule.plan.rest.kind === "clockTimes" || isDayUnion(schedule, opts)) {
|
|
1014
|
+
return false;
|
|
1015
|
+
}
|
|
1016
|
+
const { shapes } = schedule;
|
|
1017
|
+
return isCadenceShape(shapes.second) && isCadenceShape(shapes.minute) && isCadenceShape(shapes.hour);
|
|
955
1018
|
}
|
|
956
|
-
function
|
|
957
|
-
const
|
|
958
|
-
|
|
1019
|
+
function denseHourFragment(schedule, opts) {
|
|
1020
|
+
const stride = hourStride(schedule);
|
|
1021
|
+
if (stride) {
|
|
1022
|
+
return hourStrideCadence(stride, opts);
|
|
1023
|
+
}
|
|
1024
|
+
if (schedule.shapes.hour === "range") {
|
|
1025
|
+
const segment = segmentsOf(schedule, "hour").find(function range(part) {
|
|
1026
|
+
return part.kind === "range";
|
|
1027
|
+
});
|
|
1028
|
+
return rangeWindow({
|
|
1029
|
+
continuous: false,
|
|
1030
|
+
from: +segment.bounds[0],
|
|
1031
|
+
throughMinute: 0,
|
|
1032
|
+
to: +segment.bounds[1]
|
|
1033
|
+
}, opts);
|
|
1034
|
+
}
|
|
1035
|
+
return "during the " + hourSegmentTimes(schedule, { minute: 0, second: null }, false, opts) + " hours";
|
|
959
1036
|
}
|
|
960
|
-
function
|
|
961
|
-
|
|
1037
|
+
function denseMinuteFragment(schedule, opts) {
|
|
1038
|
+
if (schedule.shapes.minute === "step") {
|
|
1039
|
+
return stepCycle60(stepSegment(schedule, "minute"), "minute", "hour", opts);
|
|
1040
|
+
}
|
|
1041
|
+
if (schedule.shapes.minute === "range") {
|
|
1042
|
+
return minuteRangeLead(schedule.pattern.minute, opts);
|
|
1043
|
+
}
|
|
1044
|
+
return strideFromSegments(
|
|
1045
|
+
segmentsOf(schedule, "minute"),
|
|
1046
|
+
"minute",
|
|
1047
|
+
"hour",
|
|
1048
|
+
opts
|
|
1049
|
+
) ?? listPastThe(
|
|
1050
|
+
segmentWords(segmentsOf(schedule, "minute"), opts),
|
|
1051
|
+
"minute",
|
|
1052
|
+
"hour",
|
|
1053
|
+
opts
|
|
1054
|
+
);
|
|
1055
|
+
}
|
|
1056
|
+
function denseCadence(schedule, opts) {
|
|
1057
|
+
if (!isDenseCadence(schedule, opts)) {
|
|
1058
|
+
return null;
|
|
1059
|
+
}
|
|
1060
|
+
const hour = denseHourFragment(schedule, opts);
|
|
1061
|
+
const minute = denseMinuteFragment(schedule, opts);
|
|
1062
|
+
const second = secondsClause(schedule, "minute", opts);
|
|
1063
|
+
const nested = hour + ", " + minute + ", and within each of those minutes, " + second;
|
|
1064
|
+
const anchor = trailingQualifier(schedule, opts).trim();
|
|
1065
|
+
return anchor ? anchor + ", " + nested : nested;
|
|
1066
|
+
}
|
|
1067
|
+
function renderEverySecond(schedule, plan, opts) {
|
|
1068
|
+
return "every second" + trailingQualifier(schedule, opts);
|
|
1069
|
+
}
|
|
1070
|
+
function renderStandaloneSeconds(schedule, plan, opts) {
|
|
1071
|
+
return secondsLeadClause(schedule, opts) + trailingQualifier(schedule, opts);
|
|
1072
|
+
}
|
|
1073
|
+
function renderSecondPastMinute(schedule, plan, opts) {
|
|
1074
|
+
const secondField = schedule.pattern.second;
|
|
1075
|
+
return getNumber(secondField, opts) + " " + pluralize(secondField, "second") + " past the minute, every minute" + trailingQualifier(schedule, opts);
|
|
1076
|
+
}
|
|
1077
|
+
function renderSecondsWithinMinute(schedule, plan, opts) {
|
|
1078
|
+
const minuteField = schedule.pattern.minute;
|
|
962
1079
|
const minuteWord = getNumber(minuteField, opts);
|
|
963
1080
|
const minuteUnit = pluralize(minuteField, "minute");
|
|
964
1081
|
if (plan.singleSecond) {
|
|
965
|
-
const secondField =
|
|
966
|
-
return minuteWord + " " + minuteUnit + " and " + getNumber(secondField, opts) + " " + pluralize(secondField, "second") + " past the hour, every hour" + trailingQualifier(
|
|
1082
|
+
const secondField = schedule.pattern.second;
|
|
1083
|
+
return minuteWord + " " + minuteUnit + " and " + getNumber(secondField, opts) + " " + pluralize(secondField, "second") + " past the hour, every hour" + trailingQualifier(schedule, opts);
|
|
967
1084
|
}
|
|
968
|
-
return secondsLeadClause(
|
|
1085
|
+
return secondsLeadClause(schedule, opts) + ", " + minuteWord + " " + minuteUnit + " past the hour, every hour" + trailingQualifier(schedule, opts);
|
|
969
1086
|
}
|
|
970
|
-
function composeHourCadence(
|
|
1087
|
+
function composeHourCadence(schedule, plan, opts) {
|
|
971
1088
|
const clockRest = plan.rest.kind === "clockTimes" || plan.rest.kind === "compactClockTimes";
|
|
972
|
-
if (!clockRest ||
|
|
1089
|
+
if (!clockRest || schedule.shapes.minute !== "single") {
|
|
973
1090
|
return null;
|
|
974
1091
|
}
|
|
975
|
-
const minute = +
|
|
976
|
-
return hourCadence(
|
|
1092
|
+
const minute = +schedule.pattern.minute;
|
|
1093
|
+
return hourCadence(schedule, minute, opts) ?? hourRangeCadence(schedule, minute, opts);
|
|
977
1094
|
}
|
|
978
|
-
function clockTimesConfinement(
|
|
979
|
-
if (+rest.times[0].minute === 0 &&
|
|
980
|
-
return secondsLeadClause(
|
|
1095
|
+
function clockTimesConfinement(schedule, rest, opts) {
|
|
1096
|
+
if (+rest.times[0].minute === 0 && schedule.shapes.minute === "single") {
|
|
1097
|
+
return secondsLeadClause(schedule, opts) + " for one minute at " + durationHours(schedule, rest, opts);
|
|
981
1098
|
}
|
|
982
|
-
return secondsLeadClause(
|
|
1099
|
+
return secondsLeadClause(schedule, opts) + " of " + clockTimesOf(schedule, rest, opts);
|
|
983
1100
|
}
|
|
984
|
-
function renderComposeSeconds(
|
|
985
|
-
const cadence = composeHourCadence(
|
|
1101
|
+
function renderComposeSeconds(schedule, plan, opts) {
|
|
1102
|
+
const cadence = composeHourCadence(schedule, plan, opts);
|
|
986
1103
|
if (cadence !== null) {
|
|
987
1104
|
return cadence;
|
|
988
1105
|
}
|
|
989
|
-
if (plan.rest.kind === "clockTimes" && (
|
|
990
|
-
return clockTimesConfinement(
|
|
1106
|
+
if (plan.rest.kind === "clockTimes" && (schedule.shapes.second === "wildcard" || schedule.shapes.second === "step")) {
|
|
1107
|
+
return clockTimesConfinement(schedule, plan.rest, opts);
|
|
991
1108
|
}
|
|
992
|
-
if (
|
|
993
|
-
return "every second of every other minute" + trailingQualifier(
|
|
1109
|
+
if (schedule.shapes.second === "wildcard" && plan.rest.kind === "minuteFrequency" && plan.rest.hours.kind === "none" && schedule.pattern.minute === "*/2") {
|
|
1110
|
+
return "every second of every other minute" + trailingQualifier(schedule, opts);
|
|
994
1111
|
}
|
|
995
|
-
const restOwnsLead = plan.rest.kind === "compactClockTimes" &&
|
|
996
|
-
const lead = restOwnsLead ? "" : secondsLeadClause(
|
|
997
|
-
return lead + render(
|
|
1112
|
+
const restOwnsLead = plan.rest.kind === "compactClockTimes" && schedule.analyses.clockSecond;
|
|
1113
|
+
const lead = restOwnsLead ? "" : secondsLeadClause(schedule, opts) + ", ";
|
|
1114
|
+
return lead + render(schedule, plan.rest, opts);
|
|
998
1115
|
}
|
|
999
|
-
function durationHours(
|
|
1116
|
+
function durationHours(schedule, plan, opts) {
|
|
1000
1117
|
const hours = plan.times.map(function clock(time) {
|
|
1001
1118
|
return getTime({ hour: time.hour, minute: 0 }, opts);
|
|
1002
1119
|
});
|
|
1003
|
-
const trail = dayQualifier(
|
|
1120
|
+
const trail = dayQualifier(schedule, leadingWords, opts);
|
|
1004
1121
|
return joinList(hours, opts) + (trail && ", " + trail);
|
|
1005
1122
|
}
|
|
1006
|
-
function clockTimesOf(
|
|
1123
|
+
function clockTimesOf(schedule, plan, opts) {
|
|
1007
1124
|
const times = plan.times.map(function clock(time) {
|
|
1008
1125
|
return getTime({
|
|
1009
1126
|
hour: time.hour,
|
|
@@ -1012,21 +1129,21 @@ function clockTimesOf(ir, plan, opts) {
|
|
|
1012
1129
|
explicit: true
|
|
1013
1130
|
}, opts);
|
|
1014
1131
|
});
|
|
1015
|
-
const trail = dayQualifier(
|
|
1132
|
+
const trail = dayQualifier(schedule, leadingWords, opts);
|
|
1016
1133
|
return joinList(times, opts) + (trail && ", " + trail);
|
|
1017
1134
|
}
|
|
1018
|
-
function secondsLeadClause(
|
|
1019
|
-
return secondsClause(
|
|
1135
|
+
function secondsLeadClause(schedule, opts) {
|
|
1136
|
+
return secondsClause(schedule, "minute", opts);
|
|
1020
1137
|
}
|
|
1021
|
-
function secondsClause(
|
|
1022
|
-
const secondField =
|
|
1023
|
-
const shape =
|
|
1138
|
+
function secondsClause(schedule, anchor, opts) {
|
|
1139
|
+
const secondField = schedule.pattern.second;
|
|
1140
|
+
const shape = schedule.shapes.second;
|
|
1024
1141
|
if (secondField === "*") {
|
|
1025
1142
|
return "every second";
|
|
1026
1143
|
}
|
|
1027
1144
|
if (shape === "step") {
|
|
1028
1145
|
return stepCycle60(
|
|
1029
|
-
|
|
1146
|
+
stepSegment(schedule, "second"),
|
|
1030
1147
|
"second",
|
|
1031
1148
|
anchor,
|
|
1032
1149
|
opts
|
|
@@ -1041,86 +1158,96 @@ function secondsClause(ir, anchor, opts) {
|
|
|
1041
1158
|
return "at " + getNumber(secondField, opts) + " " + pluralize(secondField, "second") + " past the " + anchor;
|
|
1042
1159
|
}
|
|
1043
1160
|
return strideFromSegments(
|
|
1044
|
-
|
|
1161
|
+
segmentsOf(schedule, "second"),
|
|
1045
1162
|
"second",
|
|
1046
1163
|
anchor,
|
|
1047
1164
|
opts
|
|
1048
1165
|
) ?? listPastThe(
|
|
1049
|
-
segmentWords(
|
|
1166
|
+
segmentWords(segmentsOf(schedule, "second"), opts),
|
|
1050
1167
|
"second",
|
|
1051
1168
|
anchor,
|
|
1052
1169
|
opts
|
|
1053
1170
|
);
|
|
1054
1171
|
}
|
|
1055
|
-
function renderEveryMinute(
|
|
1056
|
-
return "every minute" + trailingQualifier(
|
|
1172
|
+
function renderEveryMinute(schedule, plan, opts) {
|
|
1173
|
+
return "every minute" + trailingQualifier(schedule, opts);
|
|
1057
1174
|
}
|
|
1058
|
-
function renderSingleMinute(
|
|
1059
|
-
const minuteField =
|
|
1060
|
-
return getNumber(minuteField, opts) + " " + pluralize(minuteField, "minute") + " past the hour, every hour" + trailingQualifier(
|
|
1175
|
+
function renderSingleMinute(schedule, plan, opts) {
|
|
1176
|
+
const minuteField = schedule.pattern.minute;
|
|
1177
|
+
return getNumber(minuteField, opts) + " " + pluralize(minuteField, "minute") + " past the hour, every hour" + trailingQualifier(schedule, opts);
|
|
1061
1178
|
}
|
|
1062
|
-
function renderRangeOfMinutes(
|
|
1063
|
-
return minuteRangeLead(
|
|
1179
|
+
function renderRangeOfMinutes(schedule, plan, opts) {
|
|
1180
|
+
return minuteRangeLead(schedule.pattern.minute, opts) + trailingQualifier(schedule, opts);
|
|
1064
1181
|
}
|
|
1065
|
-
function renderMultipleMinutes(
|
|
1066
|
-
const stride = strideFromSegments(
|
|
1182
|
+
function renderMultipleMinutes(schedule, plan, opts) {
|
|
1183
|
+
const stride = strideFromSegments(segmentsOf(schedule, "minute"), "minute", "hour", opts);
|
|
1067
1184
|
return (stride ?? listPastThe(segmentWords(
|
|
1068
|
-
|
|
1185
|
+
segmentsOf(schedule, "minute"),
|
|
1069
1186
|
opts
|
|
1070
|
-
), "minute", "hour", opts)) + trailingQualifier(
|
|
1187
|
+
), "minute", "hour", opts)) + trailingQualifier(schedule, opts);
|
|
1071
1188
|
}
|
|
1072
|
-
function renderMinuteFrequency(
|
|
1189
|
+
function renderMinuteFrequency(schedule, plan, opts) {
|
|
1073
1190
|
let phrase = stepCycle60(
|
|
1074
|
-
|
|
1191
|
+
stepSegment(schedule, "minute"),
|
|
1075
1192
|
"minute",
|
|
1076
1193
|
"hour",
|
|
1077
1194
|
opts
|
|
1078
1195
|
);
|
|
1079
1196
|
if (plan.hours.kind === "during") {
|
|
1080
|
-
const cadence = unevenHourCadence(
|
|
1081
|
-
phrase += cadence ? ", " + cadence : " during the " + hourTimesFromPlan(
|
|
1197
|
+
const cadence = unevenHourCadence(schedule, opts);
|
|
1198
|
+
phrase += cadence ? ", " + cadence : " during the " + hourTimesFromPlan(schedule, plan.hours.times, false, opts) + " hours";
|
|
1082
1199
|
} else if (plan.hours.kind === "window") {
|
|
1083
|
-
phrase += " " +
|
|
1200
|
+
phrase += " " + rangeWindow({
|
|
1201
|
+
continuous: false,
|
|
1202
|
+
from: plan.hours.from,
|
|
1203
|
+
throughMinute: plan.hours.last,
|
|
1204
|
+
to: plan.hours.to
|
|
1205
|
+
}, opts);
|
|
1084
1206
|
} else if (plan.hours.kind === "step") {
|
|
1085
|
-
phrase += " " + everyNthHour(
|
|
1207
|
+
phrase += " " + everyNthHour(stepSegment(schedule, "hour"), opts);
|
|
1086
1208
|
}
|
|
1087
|
-
return phrase + trailingQualifier(
|
|
1209
|
+
return phrase + trailingQualifier(schedule, opts);
|
|
1088
1210
|
}
|
|
1089
|
-
function renderMinuteSpanInHour(
|
|
1090
|
-
if (
|
|
1091
|
-
return "every minute of the " + getTime({ hour: plan.hour, minute: 0 }, opts) + " hour" + trailingQualifier(
|
|
1211
|
+
function renderMinuteSpanInHour(schedule, plan, opts) {
|
|
1212
|
+
if (schedule.pattern.minute === "*") {
|
|
1213
|
+
return "every minute of the " + getTime({ hour: plan.hour, minute: 0 }, opts) + " hour" + trailingQualifier(schedule, opts);
|
|
1092
1214
|
}
|
|
1093
|
-
return "every minute from " + getTime({ hour: plan.hour, minute: plan.span[0] }, opts) + through(opts) + getTime({ hour: plan.hour, minute: plan.span[1] }, opts) + trailingQualifier(
|
|
1215
|
+
return "every minute from " + getTime({ hour: plan.hour, minute: plan.span[0] }, opts) + through(opts) + getTime({ hour: plan.hour, minute: plan.span[1] }, opts) + trailingQualifier(schedule, opts);
|
|
1094
1216
|
}
|
|
1095
|
-
function renderMinutesAcrossHours(
|
|
1096
|
-
const cadence = unevenHourCadence(
|
|
1217
|
+
function renderMinutesAcrossHours(schedule, plan, opts) {
|
|
1218
|
+
const cadence = unevenHourCadence(schedule, opts);
|
|
1097
1219
|
if (plan.form === "wildcard") {
|
|
1098
1220
|
if (cadence !== null) {
|
|
1099
|
-
return "every minute, " + cadence + trailingQualifier(
|
|
1221
|
+
return "every minute, " + cadence + trailingQualifier(schedule, opts);
|
|
1100
1222
|
}
|
|
1101
|
-
return "every minute during the " + hourTimesFromPlan(
|
|
1223
|
+
return "every minute during the " + hourTimesFromPlan(schedule, plan.times, false, opts) + " hours" + trailingQualifier(schedule, opts);
|
|
1102
1224
|
}
|
|
1103
1225
|
if (plan.form === "range") {
|
|
1104
|
-
const lead2 = minuteRangeLead(
|
|
1226
|
+
const lead2 = minuteRangeLead(schedule.pattern.minute, opts);
|
|
1105
1227
|
if (cadence !== null) {
|
|
1106
|
-
return lead2 + ", " + cadence + trailingQualifier(
|
|
1228
|
+
return lead2 + ", " + cadence + trailingQualifier(schedule, opts);
|
|
1107
1229
|
}
|
|
1108
1230
|
if (singleHourFire(plan.times)) {
|
|
1109
|
-
return lead2 + ", at " + hourTimesFromPlan(
|
|
1231
|
+
return lead2 + ", at " + hourTimesFromPlan(schedule, plan.times, true, opts) + trailingQualifier(schedule, opts);
|
|
1110
1232
|
}
|
|
1111
|
-
return lead2 + " during the " + hourTimesFromPlan(
|
|
1233
|
+
return lead2 + " during the " + hourTimesFromPlan(schedule, plan.times, false, opts) + " hours" + trailingQualifier(schedule, opts);
|
|
1112
1234
|
}
|
|
1113
|
-
const lead = strideFromSegments(
|
|
1114
|
-
|
|
1235
|
+
const lead = strideFromSegments(
|
|
1236
|
+
segmentsOf(schedule, "minute"),
|
|
1237
|
+
"minute",
|
|
1238
|
+
"hour",
|
|
1239
|
+
opts
|
|
1240
|
+
) ?? listPastThe(
|
|
1241
|
+
segmentWords(segmentsOf(schedule, "minute"), opts),
|
|
1115
1242
|
"minute",
|
|
1116
1243
|
"hour",
|
|
1117
1244
|
opts
|
|
1118
1245
|
);
|
|
1119
1246
|
if (cadence !== null) {
|
|
1120
|
-
return lead + ", " + cadence + trailingQualifier(
|
|
1247
|
+
return lead + ", " + cadence + trailingQualifier(schedule, opts);
|
|
1121
1248
|
}
|
|
1122
|
-
const times = hourTimesFromPlan(
|
|
1123
|
-
return lead + ", at " + times + trailingQualifier(
|
|
1249
|
+
const times = hourTimesFromPlan(schedule, plan.times, true, opts);
|
|
1250
|
+
return lead + ", at " + times + trailingQualifier(schedule, opts);
|
|
1124
1251
|
}
|
|
1125
1252
|
var stepOrdinals = {
|
|
1126
1253
|
2: "other",
|
|
@@ -1135,79 +1262,91 @@ function everyNthHour(segment, opts) {
|
|
|
1135
1262
|
const start = segment.startToken === "*" ? 0 : +segment.startToken;
|
|
1136
1263
|
return start === 0 ? base : base + " starting at " + getTime({ hour: start, minute: 0 }, opts);
|
|
1137
1264
|
}
|
|
1138
|
-
function renderMinuteSpanAcrossHourStep(
|
|
1139
|
-
const segment =
|
|
1265
|
+
function renderMinuteSpanAcrossHourStep(schedule, plan, opts) {
|
|
1266
|
+
const segment = stepSegment(schedule, "hour");
|
|
1140
1267
|
if (plan.form === "wildcard") {
|
|
1141
|
-
return "every minute " + everyNthHour(segment, opts) + trailingQualifier(
|
|
1268
|
+
return "every minute " + everyNthHour(segment, opts) + trailingQualifier(schedule, opts);
|
|
1142
1269
|
}
|
|
1143
|
-
const lead = plan.form === "list" ? strideFromSegments(
|
|
1144
|
-
|
|
1270
|
+
const lead = plan.form === "list" ? strideFromSegments(
|
|
1271
|
+
segmentsOf(schedule, "minute"),
|
|
1272
|
+
"minute",
|
|
1273
|
+
"hour",
|
|
1274
|
+
opts
|
|
1275
|
+
) ?? listPastThe(
|
|
1276
|
+
segmentWords(segmentsOf(schedule, "minute"), opts),
|
|
1145
1277
|
"minute",
|
|
1146
1278
|
"hour",
|
|
1147
1279
|
opts
|
|
1148
|
-
) : minuteRangeLead(
|
|
1149
|
-
const cadence = unevenHourCadence(
|
|
1150
|
-
return lead + ", " + (cadence ?? stepHours(segment, opts)) + trailingQualifier(
|
|
1280
|
+
) : minuteRangeLead(schedule.pattern.minute, opts);
|
|
1281
|
+
const cadence = unevenHourCadence(schedule, opts);
|
|
1282
|
+
return lead + ", " + (cadence ?? stepHours(segment, opts)) + trailingQualifier(schedule, opts);
|
|
1151
1283
|
}
|
|
1152
1284
|
function minuteRangeLead(minuteField, opts) {
|
|
1153
1285
|
const bounds = minuteField.split("-");
|
|
1154
1286
|
const num = seriesNumber();
|
|
1155
1287
|
return "every minute from " + num(bounds[0]) + through(opts) + num(bounds[1]) + " past the hour";
|
|
1156
1288
|
}
|
|
1157
|
-
function renderEveryHour(
|
|
1158
|
-
return "every hour" + trailingQualifier(
|
|
1289
|
+
function renderEveryHour(schedule, plan, opts) {
|
|
1290
|
+
return "every hour" + trailingQualifier(schedule, opts);
|
|
1159
1291
|
}
|
|
1160
|
-
function renderHourRange(
|
|
1292
|
+
function renderHourRange(schedule, plan, opts) {
|
|
1161
1293
|
const window = hourWindow(boundedWindow(plan), opts);
|
|
1162
1294
|
if (plan.minuteForm === "wildcard") {
|
|
1163
|
-
return "every minute " + window + trailingQualifier(
|
|
1295
|
+
return "every minute " + window + trailingQualifier(schedule, opts);
|
|
1164
1296
|
}
|
|
1165
1297
|
if (plan.minuteForm === "range") {
|
|
1166
|
-
return minuteRangeLead(
|
|
1298
|
+
return minuteRangeLead(schedule.pattern.minute, opts) + ", " + window + trailingQualifier(schedule, opts);
|
|
1167
1299
|
}
|
|
1168
|
-
return rangeMinuteLead(
|
|
1300
|
+
return rangeMinuteLead(schedule, opts) + " " + window + trailingQualifier(schedule, opts);
|
|
1169
1301
|
}
|
|
1170
|
-
function rangeMinuteLead(
|
|
1171
|
-
if (
|
|
1302
|
+
function rangeMinuteLead(schedule, opts) {
|
|
1303
|
+
if (schedule.pattern.minute === "0") {
|
|
1172
1304
|
return "every hour";
|
|
1173
1305
|
}
|
|
1174
1306
|
return strideFromSegments(
|
|
1175
|
-
|
|
1307
|
+
segmentsOf(schedule, "minute"),
|
|
1176
1308
|
"minute",
|
|
1177
1309
|
"hour",
|
|
1178
1310
|
opts
|
|
1179
1311
|
) ?? listPastThe(
|
|
1180
|
-
segmentWords(
|
|
1312
|
+
segmentWords(segmentsOf(schedule, "minute"), opts),
|
|
1181
1313
|
"minute",
|
|
1182
1314
|
"hour",
|
|
1183
1315
|
opts
|
|
1184
1316
|
);
|
|
1185
1317
|
}
|
|
1186
|
-
function renderHourStep(
|
|
1187
|
-
const cadence = unevenHourCadence(
|
|
1318
|
+
function renderHourStep(schedule, plan, opts) {
|
|
1319
|
+
const cadence = unevenHourCadence(schedule, opts);
|
|
1188
1320
|
if (cadence !== null) {
|
|
1189
|
-
return cadence + trailingQualifier(
|
|
1321
|
+
return cadence + trailingQualifier(schedule, opts);
|
|
1190
1322
|
}
|
|
1191
|
-
return stepHours(
|
|
1323
|
+
return stepHours(stepSegment(schedule, "hour"), opts) + trailingQualifier(schedule, opts);
|
|
1192
1324
|
}
|
|
1193
1325
|
function boundedWindow(plan) {
|
|
1194
|
-
const
|
|
1195
|
-
|
|
1326
|
+
const continuous = plan.minuteForm === "wildcard";
|
|
1327
|
+
const closeMinute = continuous ? plan.boundMinute ?? 0 : 0;
|
|
1328
|
+
return { from: plan.from, closeMinute, to: plan.to, continuous };
|
|
1196
1329
|
}
|
|
1197
|
-
function rangeWindow(
|
|
1330
|
+
function rangeWindow(window, opts) {
|
|
1331
|
+
const { from, to, throughMinute, continuous } = window;
|
|
1198
1332
|
const open = "from " + getTime({ hour: from, minute: 0 }, opts);
|
|
1199
1333
|
if (opts.style.untilWindow && !opts.short && from !== to) {
|
|
1200
|
-
return open + " until " + getTime({ hour: (to + 1) % 24, minute: 0 }, opts);
|
|
1334
|
+
return continuous ? open + " until " + getTime({ hour: (to + 1) % 24, minute: 0 }, opts) : open + through(opts) + getTime({ hour: to, minute: 0 }, opts);
|
|
1201
1335
|
}
|
|
1202
1336
|
return open + through(opts) + getTime({ hour: to, minute: throughMinute }, opts);
|
|
1203
1337
|
}
|
|
1204
1338
|
function hourWindow(window, opts) {
|
|
1205
|
-
return rangeWindow(
|
|
1339
|
+
return rangeWindow({
|
|
1340
|
+
continuous: window.continuous,
|
|
1341
|
+
from: window.from,
|
|
1342
|
+
throughMinute: window.closeMinute,
|
|
1343
|
+
to: window.to
|
|
1344
|
+
}, opts);
|
|
1206
1345
|
}
|
|
1207
|
-
function renderClockTimes(
|
|
1208
|
-
if (
|
|
1209
|
-
const minute = +
|
|
1210
|
-
const cadence = hourCadence(
|
|
1346
|
+
function renderClockTimes(schedule, plan, opts) {
|
|
1347
|
+
if (schedule.shapes.minute === "single") {
|
|
1348
|
+
const minute = +schedule.pattern.minute;
|
|
1349
|
+
const cadence = hourCadence(schedule, minute, opts) ?? hourRangeCadence(schedule, minute, opts);
|
|
1211
1350
|
if (cadence !== null) {
|
|
1212
1351
|
return cadence;
|
|
1213
1352
|
}
|
|
@@ -1221,93 +1360,94 @@ function renderClockTimes(ir, plan, opts) {
|
|
|
1221
1360
|
plain
|
|
1222
1361
|
}, opts);
|
|
1223
1362
|
});
|
|
1224
|
-
return interpretDayQualifier(
|
|
1363
|
+
return interpretDayQualifier(schedule, opts) + "at " + joinList(times, opts) + dayUnionTrail(schedule, opts);
|
|
1225
1364
|
}
|
|
1226
|
-
function dayUnionTrail(
|
|
1227
|
-
return isDayUnion(
|
|
1365
|
+
function dayUnionTrail(schedule, opts) {
|
|
1366
|
+
return isDayUnion(schedule, opts) ? dayUnionCondition(schedule, opts) : "";
|
|
1228
1367
|
}
|
|
1229
|
-
function renderCompactClockTimes(
|
|
1368
|
+
function renderCompactClockTimes(schedule, plan, opts) {
|
|
1230
1369
|
if (plan.fold) {
|
|
1231
|
-
const cadence2 = hourCadence(
|
|
1370
|
+
const cadence2 = hourCadence(schedule, +plan.minute, opts) ?? hourRangeCadence(schedule, +plan.minute, opts);
|
|
1232
1371
|
if (cadence2 !== null) {
|
|
1233
1372
|
return cadence2;
|
|
1234
1373
|
}
|
|
1235
|
-
const hasRange =
|
|
1374
|
+
const hasRange = segmentsOf(schedule, "hour").some(function range(segment) {
|
|
1236
1375
|
return segment.kind === "range";
|
|
1237
1376
|
});
|
|
1238
|
-
if (hasRange && !
|
|
1239
|
-
return foldedHourWindows(
|
|
1377
|
+
if (hasRange && !schedule.analyses.clockSecond) {
|
|
1378
|
+
return foldedHourWindows(schedule, plan, opts) + trailingQualifier(schedule, opts);
|
|
1240
1379
|
}
|
|
1241
|
-
const fold = { minute: plan.minute, second:
|
|
1242
|
-
return interpretDayQualifier(
|
|
1380
|
+
const fold = { minute: plan.minute, second: schedule.analyses.clockSecond };
|
|
1381
|
+
return interpretDayQualifier(schedule, opts) + "at " + hourSegmentTimes(schedule, fold, true, opts) + dayUnionTrail(schedule, opts);
|
|
1243
1382
|
}
|
|
1244
1383
|
const minuteLead = (
|
|
1245
1384
|
// The non-fold branch is a minute list, which has segments. An
|
|
1246
1385
|
// offset/uneven step enumerated to that list reads as a stride.
|
|
1247
|
-
strideFromSegments(
|
|
1248
|
-
|
|
1386
|
+
strideFromSegments(
|
|
1387
|
+
segmentsOf(schedule, "minute"),
|
|
1388
|
+
"minute",
|
|
1389
|
+
"hour",
|
|
1390
|
+
opts
|
|
1391
|
+
) ?? listPastThe(
|
|
1392
|
+
segmentWords(segmentsOf(schedule, "minute"), opts),
|
|
1249
1393
|
"minute",
|
|
1250
1394
|
"hour",
|
|
1251
1395
|
opts
|
|
1252
1396
|
)
|
|
1253
1397
|
);
|
|
1254
|
-
const cadence = unevenHourCadence(
|
|
1255
|
-
const phrase = cadence ? minuteLead + ", " + cadence + trailingQualifier(
|
|
1256
|
-
return
|
|
1398
|
+
const cadence = unevenHourCadence(schedule, opts);
|
|
1399
|
+
const phrase = cadence ? minuteLead + ", " + cadence + trailingQualifier(schedule, opts) : minuteLead + ", at " + hourSegmentTimes(schedule, { minute: 0, second: null }, true, opts) + trailingQualifier(schedule, opts);
|
|
1400
|
+
return schedule.analyses.clockSecond ? secondsLeadClause(schedule, opts) + ", " + phrase : phrase;
|
|
1257
1401
|
}
|
|
1258
|
-
function foldedHourWindows(
|
|
1402
|
+
function foldedHourWindows(schedule, plan, opts) {
|
|
1259
1403
|
const minute = plan.minute;
|
|
1260
1404
|
const windows = [];
|
|
1261
|
-
const
|
|
1262
|
-
const times = outliers.hours.map(function time(hour) {
|
|
1405
|
+
const times = collectHourOutliers(schedule).map(function time(hour) {
|
|
1263
1406
|
return getTime({ hour, minute }, opts);
|
|
1264
1407
|
});
|
|
1265
|
-
|
|
1408
|
+
segmentsOf(schedule, "hour").forEach(function classify(segment) {
|
|
1266
1409
|
if (segment.kind === "range") {
|
|
1267
|
-
windows.push(rangeWindow(
|
|
1268
|
-
|
|
1269
|
-
+segment.bounds[
|
|
1270
|
-
minute,
|
|
1271
|
-
|
|
1272
|
-
));
|
|
1410
|
+
windows.push(rangeWindow({
|
|
1411
|
+
continuous: false,
|
|
1412
|
+
from: +segment.bounds[0],
|
|
1413
|
+
throughMinute: minute,
|
|
1414
|
+
to: +segment.bounds[1]
|
|
1415
|
+
}, opts));
|
|
1273
1416
|
}
|
|
1274
1417
|
});
|
|
1275
|
-
const phrase = rangeMinuteLead(
|
|
1276
|
-
return phrase + outlierTail(times,
|
|
1418
|
+
const phrase = rangeMinuteLead(schedule, opts) + " " + joinList(windows, opts);
|
|
1419
|
+
return phrase + outlierTail(times, opts);
|
|
1277
1420
|
}
|
|
1278
|
-
function collectHourOutliers(
|
|
1421
|
+
function collectHourOutliers(schedule) {
|
|
1279
1422
|
const hours = [];
|
|
1280
|
-
|
|
1281
|
-
ir.analyses.segments.hour.forEach(function classify(segment) {
|
|
1423
|
+
segmentsOf(schedule, "hour").forEach(function classify(segment) {
|
|
1282
1424
|
if (segment.kind === "step") {
|
|
1283
1425
|
hours.push(...segment.fires);
|
|
1284
|
-
pureStrays = false;
|
|
1285
1426
|
} else if (segment.kind !== "range") {
|
|
1286
1427
|
hours.push(+segment.value);
|
|
1287
1428
|
}
|
|
1288
1429
|
});
|
|
1289
|
-
return
|
|
1430
|
+
return hours;
|
|
1290
1431
|
}
|
|
1291
|
-
function outlierTail(times,
|
|
1432
|
+
function outlierTail(times, opts) {
|
|
1292
1433
|
if (!times.length) {
|
|
1293
1434
|
return "";
|
|
1294
1435
|
}
|
|
1295
|
-
|
|
1296
|
-
return connector + joinList(times, opts);
|
|
1436
|
+
return " and at " + joinList(times, opts);
|
|
1297
1437
|
}
|
|
1298
1438
|
function isCadenceField(token) {
|
|
1299
1439
|
return token === "*" || token.startsWith("*/") && token.indexOf("-") === -1;
|
|
1300
1440
|
}
|
|
1301
|
-
function leadingCadence(
|
|
1302
|
-
const { second, minute } =
|
|
1441
|
+
function leadingCadence(schedule, opts) {
|
|
1442
|
+
const { second, minute } = schedule.pattern;
|
|
1303
1443
|
if (isCadenceField(second)) {
|
|
1304
|
-
return { secondLead: true, text: secondsClause(
|
|
1444
|
+
return { secondLead: true, text: secondsClause(schedule, "minute", opts) };
|
|
1305
1445
|
}
|
|
1306
1446
|
if (second === "0" && isCadenceField(minute)) {
|
|
1307
1447
|
const text = minute === "*" ? "every minute" : (
|
|
1308
1448
|
// A clean minute step's first segment is a step segment.
|
|
1309
1449
|
stepCycle60(
|
|
1310
|
-
|
|
1450
|
+
stepSegment(schedule, "minute"),
|
|
1311
1451
|
"minute",
|
|
1312
1452
|
"hour",
|
|
1313
1453
|
opts
|
|
@@ -1317,19 +1457,19 @@ function leadingCadence(ir, opts) {
|
|
|
1317
1457
|
}
|
|
1318
1458
|
return null;
|
|
1319
1459
|
}
|
|
1320
|
-
function minuteConfinement(
|
|
1321
|
-
const minute =
|
|
1460
|
+
function minuteConfinement(schedule, opts) {
|
|
1461
|
+
const minute = schedule.pattern.minute;
|
|
1322
1462
|
if (minute === "*") {
|
|
1323
1463
|
return "";
|
|
1324
1464
|
}
|
|
1325
1465
|
if (isCadenceField(minute)) {
|
|
1326
1466
|
return " of every other minute";
|
|
1327
1467
|
}
|
|
1328
|
-
const segments =
|
|
1329
|
-
if (
|
|
1468
|
+
const segments = segmentsOf(schedule, "minute");
|
|
1469
|
+
if (schedule.shapes.minute === "single") {
|
|
1330
1470
|
return " during minute :" + pad(minute);
|
|
1331
1471
|
}
|
|
1332
|
-
if (
|
|
1472
|
+
if (schedule.shapes.minute === "range") {
|
|
1333
1473
|
const bounds = minute.split("-");
|
|
1334
1474
|
return " during minutes :" + pad(bounds[0]) + through(opts) + ":" + pad(bounds[1]);
|
|
1335
1475
|
}
|
|
@@ -1338,59 +1478,61 @@ function minuteConfinement(ir, opts) {
|
|
|
1338
1478
|
});
|
|
1339
1479
|
return " during minutes " + joinList(values, opts);
|
|
1340
1480
|
}
|
|
1341
|
-
function hourConfinement(
|
|
1342
|
-
const hour =
|
|
1481
|
+
function hourConfinement(schedule, opts) {
|
|
1482
|
+
const hour = schedule.pattern.hour;
|
|
1343
1483
|
if (hour === "*") {
|
|
1344
|
-
const minutePinned =
|
|
1484
|
+
const minutePinned = schedule.pattern.minute !== "*" && !isCadenceField(schedule.pattern.minute);
|
|
1345
1485
|
return minutePinned ? " of every hour" : "";
|
|
1346
1486
|
}
|
|
1347
1487
|
if (isCadenceField(hour)) {
|
|
1348
1488
|
return hour === "*/2" ? " of every other hour" : "";
|
|
1349
1489
|
}
|
|
1350
|
-
if (
|
|
1490
|
+
if (schedule.shapes.hour === "single") {
|
|
1351
1491
|
const h = +hour;
|
|
1352
|
-
if (
|
|
1492
|
+
if (schedule.shapes.minute === "step") {
|
|
1353
1493
|
return " from " + getTime({ hour: h, minute: 0 }, opts) + " until " + getTime({ hour: (h + 1) % 24, minute: 0 }, opts);
|
|
1354
1494
|
}
|
|
1355
|
-
if (
|
|
1495
|
+
if (schedule.pattern.minute !== "*" && !isCadenceField(schedule.pattern.minute)) {
|
|
1356
1496
|
return " at " + getTime({ hour: h, minute: 0 }, opts);
|
|
1357
1497
|
}
|
|
1358
1498
|
return " of the " + getTime({ hour: h, minute: 0 }, opts) + " hour";
|
|
1359
1499
|
}
|
|
1360
|
-
if (
|
|
1500
|
+
if (schedule.shapes.hour === "range") {
|
|
1361
1501
|
const bounds = hour.split("-");
|
|
1362
|
-
return " " + rangeWindow(
|
|
1502
|
+
return " " + rangeWindow({
|
|
1503
|
+
continuous: schedule.pattern.minute === "*",
|
|
1504
|
+
from: +bounds[0],
|
|
1505
|
+
throughMinute: 0,
|
|
1506
|
+
to: +bounds[1]
|
|
1507
|
+
}, opts);
|
|
1363
1508
|
}
|
|
1364
|
-
return " during the " + hourSegmentTimes(
|
|
1509
|
+
return " during the " + hourSegmentTimes(schedule, { minute: 0, second: null }, false, opts) + " hours";
|
|
1365
1510
|
}
|
|
1366
|
-
function
|
|
1367
|
-
|
|
1368
|
-
}
|
|
1369
|
-
function confinableHour(ir) {
|
|
1370
|
-
if (ir.shapes.hour !== "step") {
|
|
1511
|
+
function confinableHour(schedule) {
|
|
1512
|
+
if (schedule.shapes.hour !== "step") {
|
|
1371
1513
|
return true;
|
|
1372
1514
|
}
|
|
1373
|
-
const segment =
|
|
1374
|
-
return
|
|
1515
|
+
const segment = stepSegment(schedule, "hour");
|
|
1516
|
+
return schedule.pattern.hour === "*/2" || segment.startToken.indexOf("-") !== -1;
|
|
1375
1517
|
}
|
|
1376
|
-
function isMinuteStride(
|
|
1377
|
-
if (
|
|
1518
|
+
function isMinuteStride(schedule) {
|
|
1519
|
+
if (schedule.shapes.minute !== "list") {
|
|
1378
1520
|
return false;
|
|
1379
1521
|
}
|
|
1380
|
-
const values = singleValues(
|
|
1522
|
+
const values = singleValues(segmentsOf(schedule, "minute"));
|
|
1381
1523
|
return values !== null && arithmeticStep(values) !== null;
|
|
1382
1524
|
}
|
|
1383
|
-
function confinementEligible(
|
|
1384
|
-
const { minute, hour } =
|
|
1525
|
+
function confinementEligible(schedule, lead) {
|
|
1526
|
+
const { minute, hour } = schedule.pattern;
|
|
1385
1527
|
const minuteStep = isCadenceField(minute) && minute !== "*";
|
|
1386
|
-
if (!confinableHour(
|
|
1528
|
+
if (!confinableHour(schedule)) {
|
|
1387
1529
|
return false;
|
|
1388
1530
|
}
|
|
1389
1531
|
if (lead.secondLead) {
|
|
1390
1532
|
if (minuteStep) {
|
|
1391
|
-
return minute === "*/2" &&
|
|
1533
|
+
return minute === "*/2" && schedule.shapes.hour !== "range";
|
|
1392
1534
|
}
|
|
1393
|
-
if (isMinuteStride(
|
|
1535
|
+
if (isMinuteStride(schedule) || schedule.shapes.minute === "list" && schedule.shapes.hour === "list") {
|
|
1394
1536
|
return false;
|
|
1395
1537
|
}
|
|
1396
1538
|
return true;
|
|
@@ -1398,21 +1540,21 @@ function confinementEligible(ir, lead) {
|
|
|
1398
1540
|
if (hour === "*/2") {
|
|
1399
1541
|
return true;
|
|
1400
1542
|
}
|
|
1401
|
-
return
|
|
1543
|
+
return schedule.shapes.hour === "single" && minute === "*/2";
|
|
1402
1544
|
}
|
|
1403
|
-
function confinement(
|
|
1545
|
+
function confinement(schedule, opts) {
|
|
1404
1546
|
if (!opts.style.untilWindow || opts.short) {
|
|
1405
1547
|
return null;
|
|
1406
1548
|
}
|
|
1407
|
-
if (
|
|
1549
|
+
if (schedule.pattern.minute === "*" && schedule.pattern.hour === "*") {
|
|
1408
1550
|
return null;
|
|
1409
1551
|
}
|
|
1410
|
-
const lead = leadingCadence(
|
|
1411
|
-
if (!lead || !confinementEligible(
|
|
1552
|
+
const lead = leadingCadence(schedule, opts);
|
|
1553
|
+
if (!lead || !confinementEligible(schedule, lead)) {
|
|
1412
1554
|
return null;
|
|
1413
1555
|
}
|
|
1414
|
-
const minutePart = lead.secondLead ? minuteConfinement(
|
|
1415
|
-
return lead.text + minutePart + hourConfinement(
|
|
1556
|
+
const minutePart = lead.secondLead ? minuteConfinement(schedule, opts) : "";
|
|
1557
|
+
return lead.text + minutePart + hourConfinement(schedule, opts) + trailingQualifier(schedule, opts);
|
|
1416
1558
|
}
|
|
1417
1559
|
var renderers = {
|
|
1418
1560
|
clockTimes: renderClockTimes,
|
|
@@ -1434,33 +1576,25 @@ var renderers = {
|
|
|
1434
1576
|
singleMinute: renderSingleMinute,
|
|
1435
1577
|
standaloneSeconds: renderStandaloneSeconds
|
|
1436
1578
|
};
|
|
1437
|
-
function
|
|
1579
|
+
function renderStride2(stride, opts) {
|
|
1438
1580
|
const { interval, start, last, cycle, unit, anchor } = stride;
|
|
1439
1581
|
const cadence = "every " + getNumber(interval, opts) + " " + unit + "s";
|
|
1440
|
-
|
|
1441
|
-
|
|
1442
|
-
|
|
1443
|
-
|
|
1444
|
-
|
|
1445
|
-
|
|
1446
|
-
|
|
1447
|
-
|
|
1448
|
-
|
|
1449
|
-
}
|
|
1450
|
-
function singleValues(segments) {
|
|
1451
|
-
const values = [];
|
|
1452
|
-
for (const segment of segments) {
|
|
1453
|
-
if (segment.kind !== "single") {
|
|
1454
|
-
return null;
|
|
1582
|
+
return renderStride({ start, interval, cycle }, {
|
|
1583
|
+
bare: () => cadence,
|
|
1584
|
+
// A clean wrap from a non-zero offset: name the start, no endpoint.
|
|
1585
|
+
offset: () => cadence + " from " + getNumber(start, opts) + " " + pluralize(start, unit) + " past the " + anchor,
|
|
1586
|
+
// A bounded, non-wrapping set: pin both endpoints. Each bound is a value,
|
|
1587
|
+
// so it reads as a digit, matching the range idiom ("from 0 through 30").
|
|
1588
|
+
bounded: () => {
|
|
1589
|
+
const num = seriesNumber();
|
|
1590
|
+
return cadence + " from " + num(start) + through(opts) + num(last) + " " + pluralize(last, unit) + " past the " + anchor;
|
|
1455
1591
|
}
|
|
1456
|
-
|
|
1457
|
-
}
|
|
1458
|
-
return values;
|
|
1592
|
+
});
|
|
1459
1593
|
}
|
|
1460
1594
|
function strideFromSegments(segments, unit, anchor, opts) {
|
|
1461
1595
|
const values = singleValues(segments);
|
|
1462
1596
|
const step = values && arithmeticStep(values);
|
|
1463
|
-
return step ?
|
|
1597
|
+
return step ? renderStride2({ ...step, cycle: 60, unit, anchor }, opts) : null;
|
|
1464
1598
|
}
|
|
1465
1599
|
function stepCycle60(segment, unit, anchor, opts) {
|
|
1466
1600
|
if (segment.startToken.indexOf("-") !== -1) {
|
|
@@ -1470,7 +1604,7 @@ function stepCycle60(segment, unit, anchor, opts) {
|
|
|
1470
1604
|
if (start !== 0 && segment.fires.length <= 3) {
|
|
1471
1605
|
return listPastThe(numberWords(segment.fires, opts), unit, anchor, opts);
|
|
1472
1606
|
}
|
|
1473
|
-
return
|
|
1607
|
+
return renderStride2({
|
|
1474
1608
|
interval: segment.interval,
|
|
1475
1609
|
start,
|
|
1476
1610
|
last: segment.fires[segment.fires.length - 1],
|
|
@@ -1496,45 +1630,21 @@ function stepHours(segment, opts) {
|
|
|
1496
1630
|
function hourStrideCadence(stride, opts) {
|
|
1497
1631
|
const { start, interval, last } = stride;
|
|
1498
1632
|
const cadence = "every " + getNumber(interval, opts) + " hours";
|
|
1499
|
-
|
|
1500
|
-
|
|
1501
|
-
|
|
1502
|
-
|
|
1503
|
-
|
|
1504
|
-
return cadence + " from " + getTime({ hour: start, minute: 0 }, opts);
|
|
1505
|
-
}
|
|
1506
|
-
return cadence + " from " + getTime({ hour: start, minute: 0 }, opts) + through(opts) + getTime({ hour: last, minute: 0 }, opts);
|
|
1507
|
-
}
|
|
1508
|
-
function offsetCleanStride(stride) {
|
|
1509
|
-
return stride.start < stride.interval && 24 % stride.interval === 0;
|
|
1633
|
+
return renderStride({ start, interval, cycle: 24 }, {
|
|
1634
|
+
bare: () => cadence,
|
|
1635
|
+
offset: () => cadence + " from " + getTime({ hour: start, minute: 0 }, opts),
|
|
1636
|
+
bounded: () => cadence + " from " + getTime({ hour: start, minute: 0 }, opts) + through(opts) + getTime({ hour: last, minute: 0 }, opts)
|
|
1637
|
+
});
|
|
1510
1638
|
}
|
|
1511
|
-
function unevenHourCadence(
|
|
1512
|
-
const stride = hourStride(
|
|
1639
|
+
function unevenHourCadence(schedule, opts) {
|
|
1640
|
+
const stride = hourStride(schedule);
|
|
1513
1641
|
if (!stride || offsetCleanStride(stride)) {
|
|
1514
1642
|
return null;
|
|
1515
1643
|
}
|
|
1516
1644
|
return hourStrideCadence(stride, opts);
|
|
1517
1645
|
}
|
|
1518
|
-
function
|
|
1519
|
-
|
|
1520
|
-
return null;
|
|
1521
|
-
}
|
|
1522
|
-
const interval = values[1] - values[0];
|
|
1523
|
-
if (interval < 2) {
|
|
1524
|
-
return null;
|
|
1525
|
-
}
|
|
1526
|
-
for (let i = 2; i < values.length; i += 1) {
|
|
1527
|
-
if (values[i] - values[i - 1] !== interval) {
|
|
1528
|
-
return null;
|
|
1529
|
-
}
|
|
1530
|
-
}
|
|
1531
|
-
if (values[0] !== 0 && values.length < 5) {
|
|
1532
|
-
return null;
|
|
1533
|
-
}
|
|
1534
|
-
return { interval, last: values[values.length - 1], start: values[0] };
|
|
1535
|
-
}
|
|
1536
|
-
function hourStride(ir) {
|
|
1537
|
-
const segments = ir.analyses.segments.hour;
|
|
1646
|
+
function hourStride(schedule) {
|
|
1647
|
+
const segments = segmentsOf(schedule, "hour");
|
|
1538
1648
|
if (segments.length === 1 && segments[0].kind === "step") {
|
|
1539
1649
|
const segment = segments[0];
|
|
1540
1650
|
if (segment.fires.length < 2) {
|
|
@@ -1546,83 +1656,83 @@ function hourStride(ir) {
|
|
|
1546
1656
|
const values = singleValues(segments);
|
|
1547
1657
|
return values && hourListStride(values);
|
|
1548
1658
|
}
|
|
1549
|
-
function subMinuteSecond(
|
|
1550
|
-
return
|
|
1659
|
+
function subMinuteSecond(schedule) {
|
|
1660
|
+
return schedule.pattern.second === "*" || schedule.shapes.second === "step";
|
|
1551
1661
|
}
|
|
1552
|
-
function hourCadenceLead(
|
|
1662
|
+
function hourCadenceLead(schedule, minute, opts) {
|
|
1553
1663
|
if (minute === 0) {
|
|
1554
|
-
if (subMinuteSecond(
|
|
1555
|
-
return secondsClause(
|
|
1664
|
+
if (subMinuteSecond(schedule)) {
|
|
1665
|
+
return secondsClause(schedule, "minute", opts) + " for one minute";
|
|
1556
1666
|
}
|
|
1557
|
-
return secondsClause(
|
|
1667
|
+
return secondsClause(schedule, "hour", opts);
|
|
1558
1668
|
}
|
|
1559
1669
|
const minutePhrase = getNumber(minute, opts) + " " + pluralize(minute, "minute") + " past the hour";
|
|
1560
|
-
if (
|
|
1670
|
+
if (schedule.pattern.second === "0") {
|
|
1561
1671
|
return minutePhrase;
|
|
1562
1672
|
}
|
|
1563
|
-
return secondsClause(
|
|
1673
|
+
return secondsClause(schedule, "minute", opts) + ", " + minutePhrase;
|
|
1564
1674
|
}
|
|
1565
|
-
function hourCadence(
|
|
1566
|
-
const stride = hourStride(
|
|
1675
|
+
function hourCadence(schedule, minute, opts) {
|
|
1676
|
+
const stride = hourStride(schedule);
|
|
1567
1677
|
if (!stride) {
|
|
1568
1678
|
return null;
|
|
1569
1679
|
}
|
|
1570
1680
|
const fires = (stride.last - stride.start) / stride.interval + 1;
|
|
1571
|
-
if (
|
|
1681
|
+
if (schedule.pattern.second === "0" && fires <= maxClockTimes && offsetCleanStride(stride)) {
|
|
1572
1682
|
return null;
|
|
1573
1683
|
}
|
|
1574
|
-
const minuteZeroStride = minute === 0 && subMinuteSecond(
|
|
1684
|
+
const minuteZeroStride = minute === 0 && subMinuteSecond(schedule) && cleanStrideSegment(schedule);
|
|
1575
1685
|
if (minuteZeroStride) {
|
|
1576
|
-
return secondsClause(
|
|
1686
|
+
return secondsClause(schedule, "minute", opts) + " for one minute " + everyNthHour(minuteZeroStride, opts) + trailingQualifier(schedule, opts);
|
|
1577
1687
|
}
|
|
1578
|
-
if (minute === 0 &&
|
|
1579
|
-
return hourStrideCadence(stride, opts) + trailingQualifier(
|
|
1688
|
+
if (minute === 0 && schedule.pattern.second === "0") {
|
|
1689
|
+
return hourStrideCadence(stride, opts) + trailingQualifier(schedule, opts);
|
|
1580
1690
|
}
|
|
1581
|
-
return hourCadenceLead(
|
|
1691
|
+
return hourCadenceLead(schedule, minute, opts) + ", " + hourStrideCadence(stride, opts) + trailingQualifier(schedule, opts);
|
|
1582
1692
|
}
|
|
1583
|
-
function cleanStrideSegment(
|
|
1584
|
-
const segments =
|
|
1693
|
+
function cleanStrideSegment(schedule) {
|
|
1694
|
+
const segments = segmentsOf(schedule, "hour");
|
|
1585
1695
|
const segment = segments.length === 1 && segments[0];
|
|
1586
1696
|
if (!segment || segment.kind !== "step" || segment.startToken.indexOf("-") !== -1 || !(segment.interval in stepOrdinals)) {
|
|
1587
1697
|
return null;
|
|
1588
1698
|
}
|
|
1589
1699
|
return segment;
|
|
1590
1700
|
}
|
|
1591
|
-
function hasHourWindow(
|
|
1592
|
-
return
|
|
1701
|
+
function hasHourWindow(schedule) {
|
|
1702
|
+
return segmentsOf(schedule, "hour").some(function range(segment) {
|
|
1593
1703
|
return segment.kind === "range";
|
|
1594
1704
|
});
|
|
1595
1705
|
}
|
|
1596
|
-
function hourRangeWindowTail(
|
|
1706
|
+
function hourRangeWindowTail(schedule, opts) {
|
|
1597
1707
|
const windows = [];
|
|
1598
|
-
const
|
|
1599
|
-
|
|
1708
|
+
const outlierHours = collectHourOutliers(schedule);
|
|
1709
|
+
segmentsOf(schedule, "hour").forEach(function classify(segment) {
|
|
1600
1710
|
if (segment.kind === "range") {
|
|
1601
|
-
windows.push(rangeWindow(
|
|
1602
|
-
|
|
1603
|
-
+segment.bounds[
|
|
1604
|
-
0,
|
|
1605
|
-
|
|
1606
|
-
));
|
|
1711
|
+
windows.push(rangeWindow({
|
|
1712
|
+
continuous: false,
|
|
1713
|
+
from: +segment.bounds[0],
|
|
1714
|
+
throughMinute: 0,
|
|
1715
|
+
to: +segment.bounds[1]
|
|
1716
|
+
}, opts));
|
|
1607
1717
|
}
|
|
1608
1718
|
});
|
|
1609
1719
|
const phrase = "every hour " + joinList(windows, opts);
|
|
1610
|
-
const times =
|
|
1720
|
+
const times = outlierHours.map(function time(hour) {
|
|
1611
1721
|
return getTime({ hour, minute: 0 }, opts);
|
|
1612
1722
|
});
|
|
1613
|
-
return phrase + outlierTail(times,
|
|
1723
|
+
return phrase + outlierTail(times, opts);
|
|
1614
1724
|
}
|
|
1615
|
-
function hourRangeCadence(
|
|
1616
|
-
if (minute !== 0 || !hasHourWindow(
|
|
1725
|
+
function hourRangeCadence(schedule, minute, opts) {
|
|
1726
|
+
if (minute !== 0 || !hasHourWindow(schedule)) {
|
|
1617
1727
|
return null;
|
|
1618
1728
|
}
|
|
1619
|
-
if (
|
|
1729
|
+
if (schedule.pattern.second === "0") {
|
|
1620
1730
|
return null;
|
|
1621
1731
|
}
|
|
1622
|
-
if (subMinuteSecond(
|
|
1623
|
-
return secondsClause(
|
|
1732
|
+
if (subMinuteSecond(schedule)) {
|
|
1733
|
+
return secondsClause(schedule, "minute", opts) + " for one minute during the " + hourSegmentTimes(schedule, { minute: 0, second: null }, false, opts) + " hours" + trailingQualifier(schedule, opts);
|
|
1624
1734
|
}
|
|
1625
|
-
return hourCadenceLead(
|
|
1735
|
+
return hourCadenceLead(schedule, minute, opts) + ", " + hourRangeWindowTail(schedule, opts) + trailingQualifier(schedule, opts);
|
|
1626
1736
|
}
|
|
1627
1737
|
function seriesNumber() {
|
|
1628
1738
|
return function format(n) {
|
|
@@ -1681,11 +1791,11 @@ function hourTimes(hours, opts) {
|
|
|
1681
1791
|
function singleHourFire(times) {
|
|
1682
1792
|
return times.kind === "fires" && times.fires.length === 1;
|
|
1683
1793
|
}
|
|
1684
|
-
function hourTimesFromPlan(
|
|
1794
|
+
function hourTimesFromPlan(schedule, times, atContext, opts) {
|
|
1685
1795
|
if (times.kind === "fires") {
|
|
1686
1796
|
return hourTimes(times.fires, opts);
|
|
1687
1797
|
}
|
|
1688
|
-
return hourSegmentTimes(
|
|
1798
|
+
return hourSegmentTimes(schedule, { minute: 0, second: null }, atContext, opts);
|
|
1689
1799
|
}
|
|
1690
1800
|
function segmentHours(segment) {
|
|
1691
1801
|
if (segment.kind === "range") {
|
|
@@ -1693,9 +1803,9 @@ function segmentHours(segment) {
|
|
|
1693
1803
|
}
|
|
1694
1804
|
return segment.kind === "step" ? segment.fires : [segment.value];
|
|
1695
1805
|
}
|
|
1696
|
-
function hourSegmentTimes(
|
|
1806
|
+
function hourSegmentTimes(schedule, fold, atContext, opts) {
|
|
1697
1807
|
const { minute, second } = fold;
|
|
1698
|
-
const segments =
|
|
1808
|
+
const segments = segmentsOf(schedule, "hour");
|
|
1699
1809
|
const plain = mixedTwelve(segments.flatMap(function entries(segment) {
|
|
1700
1810
|
return segmentHours(segment).map(function entry(hour) {
|
|
1701
1811
|
return { hour: +hour, minute, second };
|
|
@@ -1758,85 +1868,85 @@ var leadingWords = {
|
|
|
1758
1868
|
stepDate: "",
|
|
1759
1869
|
weekday: "every "
|
|
1760
1870
|
};
|
|
1761
|
-
function trailingQualifier(
|
|
1762
|
-
if (isDayUnion(
|
|
1763
|
-
return dayUnionCondition(
|
|
1871
|
+
function trailingQualifier(schedule, opts) {
|
|
1872
|
+
if (isDayUnion(schedule, opts)) {
|
|
1873
|
+
return dayUnionCondition(schedule, opts);
|
|
1764
1874
|
}
|
|
1765
|
-
const phrase = dayQualifier(
|
|
1875
|
+
const phrase = dayQualifier(schedule, trailingWords, opts);
|
|
1766
1876
|
return phrase && " " + phrase;
|
|
1767
1877
|
}
|
|
1768
|
-
function interpretDayQualifier(
|
|
1769
|
-
if (isDayUnion(
|
|
1878
|
+
function interpretDayQualifier(schedule, opts) {
|
|
1879
|
+
if (isDayUnion(schedule, opts)) {
|
|
1770
1880
|
return "";
|
|
1771
1881
|
}
|
|
1772
|
-
return dayQualifier(
|
|
1882
|
+
return dayQualifier(schedule, leadingWords, opts) + " ";
|
|
1773
1883
|
}
|
|
1774
|
-
function dayQualifier(
|
|
1775
|
-
const pattern =
|
|
1884
|
+
function dayQualifier(schedule, words, opts) {
|
|
1885
|
+
const pattern = schedule.pattern;
|
|
1776
1886
|
if (pattern.date !== "*" && pattern.weekday !== "*") {
|
|
1777
|
-
return dateOrWeekday(
|
|
1887
|
+
return dateOrWeekday(schedule, opts);
|
|
1778
1888
|
}
|
|
1779
1889
|
if (pattern.date !== "*") {
|
|
1780
|
-
return datePhrase(
|
|
1890
|
+
return datePhrase(schedule, words, opts);
|
|
1781
1891
|
}
|
|
1782
1892
|
if (pattern.weekday !== "*") {
|
|
1783
1893
|
const quartzWeekday = quartzWeekdayPhrase(pattern.weekday, opts);
|
|
1784
1894
|
if (quartzWeekday) {
|
|
1785
|
-
return monthScopeForRecurrence(quartzWeekday,
|
|
1895
|
+
return monthScopeForRecurrence(quartzWeekday, schedule, opts);
|
|
1786
1896
|
}
|
|
1787
|
-
const weekdays = words.weekday + weekdayPhrase(
|
|
1788
|
-
return weekdays + monthScope(
|
|
1897
|
+
const weekdays = words.weekday + weekdayPhrase(schedule, words.recurringWeekday, opts);
|
|
1898
|
+
return weekdays + monthScope(schedule, opts);
|
|
1789
1899
|
}
|
|
1790
1900
|
if (pattern.month !== "*") {
|
|
1791
|
-
return words.month + monthName(
|
|
1901
|
+
return words.month + monthName(schedule, opts);
|
|
1792
1902
|
}
|
|
1793
1903
|
return words.all;
|
|
1794
1904
|
}
|
|
1795
|
-
function datePhrase(
|
|
1796
|
-
const pattern =
|
|
1905
|
+
function datePhrase(schedule, words, opts) {
|
|
1906
|
+
const pattern = schedule.pattern;
|
|
1797
1907
|
const quartzDate = quartzDatePhrase(pattern.date, opts);
|
|
1798
1908
|
if (quartzDate) {
|
|
1799
|
-
return monthScopeForRecurrence(quartzDate,
|
|
1909
|
+
return monthScopeForRecurrence(quartzDate, schedule, opts);
|
|
1800
1910
|
}
|
|
1801
1911
|
if (isOpenStep(pattern.date)) {
|
|
1802
1912
|
return monthScopeForRecurrence(
|
|
1803
1913
|
words.stepDate + stepDates(pattern.date),
|
|
1804
|
-
|
|
1914
|
+
schedule,
|
|
1805
1915
|
opts
|
|
1806
1916
|
);
|
|
1807
1917
|
}
|
|
1808
|
-
if (pattern.month !== "*" && !monthFoldsIntoDate(
|
|
1809
|
-
return "on the " + dateOrdinals(
|
|
1918
|
+
if (pattern.month !== "*" && !monthFoldsIntoDate(schedule)) {
|
|
1919
|
+
return "on the " + dateOrdinals(schedule, opts) + monthScope(schedule, opts);
|
|
1810
1920
|
}
|
|
1811
1921
|
if (pattern.month !== "*") {
|
|
1812
|
-
return "on " + monthDatePhrase(
|
|
1922
|
+
return "on " + monthDatePhrase(schedule, opts);
|
|
1813
1923
|
}
|
|
1814
|
-
return "on the " + dateOrdinals(
|
|
1924
|
+
return "on the " + dateOrdinals(schedule, opts);
|
|
1815
1925
|
}
|
|
1816
|
-
function monthFoldsIntoDate(
|
|
1817
|
-
return !oddEvenMonth(
|
|
1818
|
-
|
|
1926
|
+
function monthFoldsIntoDate(schedule) {
|
|
1927
|
+
return !oddEvenMonth(schedule.pattern.month) && // Reached only with a restricted month, which has segments.
|
|
1928
|
+
segmentsOf(schedule, "month").every(function flat(segment) {
|
|
1819
1929
|
return segment.kind !== "range";
|
|
1820
1930
|
});
|
|
1821
1931
|
}
|
|
1822
|
-
function isDayUnion(
|
|
1823
|
-
return
|
|
1932
|
+
function isDayUnion(schedule, opts) {
|
|
1933
|
+
return schedule.pattern.date !== "*" && schedule.pattern.weekday !== "*" && !!opts.style.untilWindow && !opts.short;
|
|
1824
1934
|
}
|
|
1825
|
-
function dayUnionCondition(
|
|
1935
|
+
function dayUnionCondition(schedule, opts) {
|
|
1826
1936
|
const pieces = [
|
|
1827
|
-
...dayUnionDatePieces(
|
|
1828
|
-
...dayUnionWeekdayPieces(
|
|
1937
|
+
...dayUnionDatePieces(schedule, opts),
|
|
1938
|
+
...dayUnionWeekdayPieces(schedule, opts)
|
|
1829
1939
|
];
|
|
1830
1940
|
return " whenever the day is " + joinOr(pieces, opts);
|
|
1831
1941
|
}
|
|
1832
|
-
function dayUnionMonthLead(
|
|
1833
|
-
if (
|
|
1942
|
+
function dayUnionMonthLead(schedule, opts) {
|
|
1943
|
+
if (schedule.pattern.month === "*") {
|
|
1834
1944
|
return "";
|
|
1835
1945
|
}
|
|
1836
|
-
return "in " + monthName(
|
|
1946
|
+
return "in " + monthName(schedule, opts) + " ";
|
|
1837
1947
|
}
|
|
1838
|
-
function dayUnionDatePieces(
|
|
1839
|
-
const dateField =
|
|
1948
|
+
function dayUnionDatePieces(schedule, opts) {
|
|
1949
|
+
const dateField = schedule.pattern.date;
|
|
1840
1950
|
const quartz = quartzDatePhrase(dateField, opts);
|
|
1841
1951
|
if (quartz) {
|
|
1842
1952
|
return [quartz.replace(/^on /, "")];
|
|
@@ -1846,7 +1956,7 @@ function dayUnionDatePieces(ir, opts) {
|
|
|
1846
1956
|
return [oddEven];
|
|
1847
1957
|
}
|
|
1848
1958
|
const pieces = [];
|
|
1849
|
-
|
|
1959
|
+
segmentsOf(schedule, "date").forEach(function expand(segment) {
|
|
1850
1960
|
if (segment.kind === "range") {
|
|
1851
1961
|
pieces.push("from the " + getOrdinal(segment.bounds[0]) + through(opts) + "the " + getOrdinal(segment.bounds[1]));
|
|
1852
1962
|
} else if (segment.kind === "step") {
|
|
@@ -1859,14 +1969,14 @@ function dayUnionDatePieces(ir, opts) {
|
|
|
1859
1969
|
});
|
|
1860
1970
|
return pieces;
|
|
1861
1971
|
}
|
|
1862
|
-
function dayUnionWeekdayPieces(
|
|
1863
|
-
const weekdayField =
|
|
1972
|
+
function dayUnionWeekdayPieces(schedule, opts) {
|
|
1973
|
+
const weekdayField = schedule.pattern.weekday;
|
|
1864
1974
|
const quartz = quartzWeekdayPhrase(weekdayField, opts);
|
|
1865
1975
|
if (quartz) {
|
|
1866
1976
|
return [quartz.replace(/^on /, "")];
|
|
1867
1977
|
}
|
|
1868
1978
|
const pieces = [];
|
|
1869
|
-
|
|
1979
|
+
segmentsOf(schedule, "weekday").forEach(function expand(segment) {
|
|
1870
1980
|
if (segment.kind === "range" && segment.bounds[0] === "1" && segment.bounds[1] === "5") {
|
|
1871
1981
|
pieces.push("a weekday");
|
|
1872
1982
|
} else if (segment.kind === "range") {
|
|
@@ -1894,16 +2004,16 @@ function oddEvenDay(dateField) {
|
|
|
1894
2004
|
}
|
|
1895
2005
|
return start === "2" ? "an even-numbered day" : null;
|
|
1896
2006
|
}
|
|
1897
|
-
function dateOrWeekday(
|
|
1898
|
-
const pattern =
|
|
1899
|
-
const weekdayPart = quartzWeekdayPhrase(pattern.weekday, opts) || "on " + weekdayPhrase(
|
|
1900
|
-
if (pattern.month !== "*" && monthFoldsIntoDate(
|
|
1901
|
-
return "on " + monthDatePhrase(
|
|
2007
|
+
function dateOrWeekday(schedule, opts) {
|
|
2008
|
+
const pattern = schedule.pattern;
|
|
2009
|
+
const weekdayPart = quartzWeekdayPhrase(pattern.weekday, opts) || "on " + weekdayPhrase(schedule, false, opts);
|
|
2010
|
+
if (pattern.month !== "*" && monthFoldsIntoDate(schedule) && !quartzDatePhrase(pattern.date, opts) && !isOpenStep(pattern.date)) {
|
|
2011
|
+
return "on " + monthDatePhrase(schedule, opts) + " or " + weekdayPart + " in " + monthName(schedule, opts);
|
|
1902
2012
|
}
|
|
1903
|
-
return datePart(
|
|
2013
|
+
return datePart(schedule, opts) + " or " + weekdayPart + orMonthScope(schedule, opts);
|
|
1904
2014
|
}
|
|
1905
|
-
function datePart(
|
|
1906
|
-
const pattern =
|
|
2015
|
+
function datePart(schedule, opts) {
|
|
2016
|
+
const pattern = schedule.pattern;
|
|
1907
2017
|
const quartzDate = quartzDatePhrase(pattern.date, opts);
|
|
1908
2018
|
if (quartzDate) {
|
|
1909
2019
|
return quartzDate;
|
|
@@ -1911,13 +2021,13 @@ function datePart(ir, opts) {
|
|
|
1911
2021
|
if (isOpenStep(pattern.date)) {
|
|
1912
2022
|
return stepDates(pattern.date);
|
|
1913
2023
|
}
|
|
1914
|
-
return "on the " + dateOrdinals(
|
|
2024
|
+
return "on the " + dateOrdinals(schedule, opts);
|
|
1915
2025
|
}
|
|
1916
|
-
function orMonthScope(
|
|
1917
|
-
if (
|
|
2026
|
+
function orMonthScope(schedule, opts) {
|
|
2027
|
+
if (schedule.pattern.month === "*") {
|
|
1918
2028
|
return "";
|
|
1919
2029
|
}
|
|
1920
|
-
return ", in " + monthName(
|
|
2030
|
+
return ", in " + monthName(schedule, opts);
|
|
1921
2031
|
}
|
|
1922
2032
|
function quartzDatePhrase(dateField, opts) {
|
|
1923
2033
|
if (dateField === "L") {
|
|
@@ -1944,39 +2054,39 @@ function quartzWeekdayPhrase(weekdayField, opts) {
|
|
|
1944
2054
|
return "on the last " + getWeekday(weekdayField.slice(0, -1), opts) + " of the month";
|
|
1945
2055
|
}
|
|
1946
2056
|
}
|
|
1947
|
-
function monthDatePhrase(
|
|
1948
|
-
const month = monthName(
|
|
2057
|
+
function monthDatePhrase(schedule, opts) {
|
|
2058
|
+
const month = monthName(schedule, opts);
|
|
1949
2059
|
const days = renderSegments(
|
|
1950
|
-
|
|
2060
|
+
segmentsOf(schedule, "date"),
|
|
1951
2061
|
opts.style.ordinals ? getOrdinal : cardinalDay,
|
|
1952
2062
|
opts
|
|
1953
2063
|
);
|
|
1954
|
-
if (opts.style.dayFirst &&
|
|
1955
|
-
return "the " + getOrdinal(
|
|
2064
|
+
if (opts.style.dayFirst && schedule.shapes.date === "single" && schedule.shapes.month !== "single") {
|
|
2065
|
+
return "the " + getOrdinal(schedule.pattern.date) + " of " + month;
|
|
1956
2066
|
}
|
|
1957
2067
|
return opts.style.dayFirst ? days + " " + month : month + " " + days;
|
|
1958
2068
|
}
|
|
1959
2069
|
function cardinalDay(value) {
|
|
1960
2070
|
return "" + value;
|
|
1961
2071
|
}
|
|
1962
|
-
function monthScope(
|
|
1963
|
-
if (
|
|
2072
|
+
function monthScope(schedule, opts) {
|
|
2073
|
+
if (schedule.pattern.month === "*") {
|
|
1964
2074
|
return "";
|
|
1965
2075
|
}
|
|
1966
|
-
return " in " + monthName(
|
|
2076
|
+
return " in " + monthName(schedule, opts);
|
|
1967
2077
|
}
|
|
1968
|
-
function monthScopeForRecurrence(phrase,
|
|
1969
|
-
if (
|
|
2078
|
+
function monthScopeForRecurrence(phrase, schedule, opts) {
|
|
2079
|
+
if (schedule.pattern.month === "*") {
|
|
1970
2080
|
return phrase;
|
|
1971
2081
|
}
|
|
1972
2082
|
const carriesRecurrence = phrase.indexOf(" of the month") !== -1;
|
|
1973
|
-
if (carriesRecurrence &&
|
|
1974
|
-
return phrase.replace(" of the month", " of each month") + " from " + monthName(
|
|
2083
|
+
if (carriesRecurrence && schedule.shapes.month === "range") {
|
|
2084
|
+
return phrase.replace(" of the month", " of each month") + " from " + monthName(schedule, opts);
|
|
1975
2085
|
}
|
|
1976
|
-
if (carriesRecurrence && (
|
|
1977
|
-
return phrase.replace(" of the month", "") + " in " + monthName(
|
|
2086
|
+
if (carriesRecurrence && (schedule.shapes.month === "single" || schedule.shapes.month === "step")) {
|
|
2087
|
+
return phrase.replace(" of the month", "") + " in " + monthName(schedule, opts);
|
|
1978
2088
|
}
|
|
1979
|
-
return phrase + " in " + monthName(
|
|
2089
|
+
return phrase + " in " + monthName(schedule, opts);
|
|
1980
2090
|
}
|
|
1981
2091
|
function stepDates(dateField) {
|
|
1982
2092
|
const parts = dateField.split("/");
|
|
@@ -1989,15 +2099,15 @@ function stepDates(dateField) {
|
|
|
1989
2099
|
}
|
|
1990
2100
|
return phrase;
|
|
1991
2101
|
}
|
|
1992
|
-
function dateOrdinals(
|
|
1993
|
-
return renderSegments(
|
|
2102
|
+
function dateOrdinals(schedule, opts) {
|
|
2103
|
+
return renderSegments(segmentsOf(schedule, "date"), getOrdinal, opts);
|
|
1994
2104
|
}
|
|
1995
|
-
function monthName(
|
|
1996
|
-
const oddEven = oddEvenMonth(
|
|
2105
|
+
function monthName(schedule, opts) {
|
|
2106
|
+
const oddEven = oddEvenMonth(schedule.pattern.month);
|
|
1997
2107
|
if (oddEven) {
|
|
1998
2108
|
return oddEven;
|
|
1999
2109
|
}
|
|
2000
|
-
return renderSegments(
|
|
2110
|
+
return renderSegments(segmentsOf(schedule, "month"), function name(value) {
|
|
2001
2111
|
return getMonth(value, opts);
|
|
2002
2112
|
}, opts);
|
|
2003
2113
|
}
|
|
@@ -2014,8 +2124,8 @@ function oddEvenMonth(monthField) {
|
|
|
2014
2124
|
}
|
|
2015
2125
|
return start === "2" ? "every even-numbered month" : null;
|
|
2016
2126
|
}
|
|
2017
|
-
function weekdayPhrase(
|
|
2018
|
-
const segments = orderWeekdaysForDisplay(
|
|
2127
|
+
function weekdayPhrase(schedule, recurring, opts) {
|
|
2128
|
+
const segments = orderWeekdaysForDisplay(segmentsOf(schedule, "weekday"));
|
|
2019
2129
|
const hasRange = segments.some(function range(segment) {
|
|
2020
2130
|
return segment.kind === "range";
|
|
2021
2131
|
});
|
|
@@ -2043,11 +2153,8 @@ function renderSegments(segments, word, opts) {
|
|
|
2043
2153
|
});
|
|
2044
2154
|
return joinList(pieces, opts);
|
|
2045
2155
|
}
|
|
2046
|
-
function
|
|
2047
|
-
|
|
2048
|
-
}
|
|
2049
|
-
function applyYear(description, ir, opts) {
|
|
2050
|
-
const yearField = ir.pattern.year;
|
|
2156
|
+
function applyYear(description, schedule, opts) {
|
|
2157
|
+
const yearField = schedule.pattern.year;
|
|
2051
2158
|
if (yearField === "*") {
|
|
2052
2159
|
return description;
|
|
2053
2160
|
}
|
|
@@ -2055,7 +2162,7 @@ function applyYear(description, ir, opts) {
|
|
|
2055
2162
|
return description + ", " + stepYears(yearField, opts);
|
|
2056
2163
|
}
|
|
2057
2164
|
const label = yearLabel(yearField, opts);
|
|
2058
|
-
if (yearField.indexOf("-") === -1 && yearField.indexOf(",") === -1 &&
|
|
2165
|
+
if (yearField.indexOf("-") === -1 && yearField.indexOf(",") === -1 && schedule.pattern.date !== "*" && description.indexOf(" at ") !== -1) {
|
|
2059
2166
|
const yearGlue = opts.style.dayFirst ? " " : ", ";
|
|
2060
2167
|
return description.replace(" at ", yearGlue + label + " at ");
|
|
2061
2168
|
}
|
|
@@ -2178,9 +2285,9 @@ function interpretCronPattern(cronPattern, lang, opts) {
|
|
|
2178
2285
|
if (typeof cronPattern === "string" && cronPattern.trim().toLowerCase() === "@reboot") {
|
|
2179
2286
|
return lang.reboot;
|
|
2180
2287
|
}
|
|
2181
|
-
const
|
|
2182
|
-
const plan = lang.
|
|
2183
|
-
return lang.describe({ ...
|
|
2288
|
+
const schedule = analyze(prepare(cronPattern, opts));
|
|
2289
|
+
const plan = lang.plan ? lang.plan(schedule, schedule.plan) : schedule.plan;
|
|
2290
|
+
return lang.describe({ ...schedule, plan }, opts);
|
|
2184
2291
|
}
|
|
2185
2292
|
var cronli5_default = cronli5;
|
|
2186
2293
|
export {
|