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.cjs
CHANGED
|
@@ -95,41 +95,6 @@ function isNonNegativeInteger(value) {
|
|
|
95
95
|
const digits = /^\d+$/;
|
|
96
96
|
return digits.test(value);
|
|
97
97
|
}
|
|
98
|
-
function arithmeticStep(values) {
|
|
99
|
-
if (values.length < 5) {
|
|
100
|
-
return null;
|
|
101
|
-
}
|
|
102
|
-
const interval = values[1] - values[0];
|
|
103
|
-
if (interval < 2) {
|
|
104
|
-
return null;
|
|
105
|
-
}
|
|
106
|
-
for (let i = 2; i < values.length; i += 1) {
|
|
107
|
-
if (values[i] - values[i - 1] !== interval) {
|
|
108
|
-
return null;
|
|
109
|
-
}
|
|
110
|
-
}
|
|
111
|
-
return { start: values[0], interval, last: values[values.length - 1] };
|
|
112
|
-
}
|
|
113
|
-
function weekdayDisplayKey(value) {
|
|
114
|
-
return value === 0 ? 7 : value;
|
|
115
|
-
}
|
|
116
|
-
function orderWeekdaysForDisplay(segments) {
|
|
117
|
-
const flattened = segments.flatMap(function flat(segment) {
|
|
118
|
-
return segment.kind === "step" ? segment.fires.map(function single(value) {
|
|
119
|
-
return { kind: "single", value: "" + value };
|
|
120
|
-
}) : [segment];
|
|
121
|
-
});
|
|
122
|
-
function key(segment) {
|
|
123
|
-
return segment.kind === "range" ? weekdayDisplayKey(+segment.bounds[0]) : weekdayDisplayKey(+segment.value);
|
|
124
|
-
}
|
|
125
|
-
return flattened.map(function index(segment, position) {
|
|
126
|
-
return [segment, position];
|
|
127
|
-
}).sort(function byDisplayKey(a, b) {
|
|
128
|
-
return key(a[0]) - key(b[0]) || a[1] - b[1];
|
|
129
|
-
}).map(function unwrap(pair) {
|
|
130
|
-
return pair[0];
|
|
131
|
-
});
|
|
132
|
-
}
|
|
133
98
|
function toFieldNumber(token, numberMap) {
|
|
134
99
|
return isNonNegativeInteger(token) ? +token : numberMap[token.toUpperCase()];
|
|
135
100
|
}
|
|
@@ -262,7 +227,7 @@ function normalizeField(value, field, spec) {
|
|
|
262
227
|
const cycle = timeFieldCycle[field];
|
|
263
228
|
const segments = stringValue.split(",").map(function canonical(segment) {
|
|
264
229
|
return canonicalizeTokens(collapseFullSpanRange(
|
|
265
|
-
|
|
230
|
+
enumerateIfNonUniform(
|
|
266
231
|
collapseFullSpanStep(
|
|
267
232
|
collapseDegenerateRange(
|
|
268
233
|
collapseOnceStep(collapseUnitStep(segment, spec), spec),
|
|
@@ -326,7 +291,7 @@ function collapseOnceStep(segment, spec) {
|
|
|
326
291
|
}
|
|
327
292
|
return start === "*" ? "" + spec.min : start;
|
|
328
293
|
}
|
|
329
|
-
function
|
|
294
|
+
function enumerateIfNonUniform(segment, spec, cycle) {
|
|
330
295
|
const parts = segment.split("/");
|
|
331
296
|
if (typeof cycle !== "number" || parts.length !== 2 || includes(parts[0], "-")) {
|
|
332
297
|
return segment;
|
|
@@ -465,6 +430,93 @@ function expandMacro(cronString) {
|
|
|
465
430
|
throw new Error("`cronli5` does not recognize the macro `" + trimmed + "`.");
|
|
466
431
|
}
|
|
467
432
|
|
|
433
|
+
// src/core/weekday.ts
|
|
434
|
+
function weekdayDisplayKey(value) {
|
|
435
|
+
return value === 0 ? 7 : value;
|
|
436
|
+
}
|
|
437
|
+
function orderWeekdaysForDisplay(segments) {
|
|
438
|
+
const flattened = segments.flatMap(function flat(segment) {
|
|
439
|
+
return segment.kind === "step" ? segment.fires.map(function single(value) {
|
|
440
|
+
return { kind: "single", value: "" + value };
|
|
441
|
+
}) : [segment];
|
|
442
|
+
});
|
|
443
|
+
function key(segment) {
|
|
444
|
+
return segment.kind === "range" ? weekdayDisplayKey(+segment.bounds[0]) : weekdayDisplayKey(+segment.value);
|
|
445
|
+
}
|
|
446
|
+
return flattened.map(function index(segment, position) {
|
|
447
|
+
return [segment, position];
|
|
448
|
+
}).sort(function byDisplayKey(a, b) {
|
|
449
|
+
return key(a[0]) - key(b[0]) || a[1] - b[1];
|
|
450
|
+
}).map(function unwrap(pair) {
|
|
451
|
+
return pair[0];
|
|
452
|
+
});
|
|
453
|
+
}
|
|
454
|
+
|
|
455
|
+
// src/core/cadence.ts
|
|
456
|
+
function arithmeticStep(values) {
|
|
457
|
+
if (values.length < 5) {
|
|
458
|
+
return null;
|
|
459
|
+
}
|
|
460
|
+
const interval = values[1] - values[0];
|
|
461
|
+
if (interval < 2) {
|
|
462
|
+
return null;
|
|
463
|
+
}
|
|
464
|
+
for (let i = 2; i < values.length; i += 1) {
|
|
465
|
+
if (values[i] - values[i - 1] !== interval) {
|
|
466
|
+
return null;
|
|
467
|
+
}
|
|
468
|
+
}
|
|
469
|
+
return { start: values[0], interval, last: values[values.length - 1] };
|
|
470
|
+
}
|
|
471
|
+
function segmentsOf(schedule, field) {
|
|
472
|
+
return schedule.analyses.segments[field] ?? [];
|
|
473
|
+
}
|
|
474
|
+
function stepSegment(schedule, field) {
|
|
475
|
+
return segmentsOf(schedule, field)[0];
|
|
476
|
+
}
|
|
477
|
+
function singleValues(segments) {
|
|
478
|
+
const values = [];
|
|
479
|
+
for (const segment of segments) {
|
|
480
|
+
if (segment.kind !== "single") {
|
|
481
|
+
return null;
|
|
482
|
+
}
|
|
483
|
+
values.push(+segment.value);
|
|
484
|
+
}
|
|
485
|
+
return values;
|
|
486
|
+
}
|
|
487
|
+
function offsetCleanStride(stride) {
|
|
488
|
+
return stride.start < stride.interval && 24 % stride.interval === 0;
|
|
489
|
+
}
|
|
490
|
+
function renderStride(spec, parts) {
|
|
491
|
+
const { start, interval, cycle } = spec;
|
|
492
|
+
const tiles = cycle % interval === 0;
|
|
493
|
+
if (start === 0 && tiles) {
|
|
494
|
+
return parts.bare();
|
|
495
|
+
}
|
|
496
|
+
if (start < interval && tiles) {
|
|
497
|
+
return parts.offset();
|
|
498
|
+
}
|
|
499
|
+
return parts.bounded();
|
|
500
|
+
}
|
|
501
|
+
function hourListStride(values) {
|
|
502
|
+
if (values.length < 2) {
|
|
503
|
+
return null;
|
|
504
|
+
}
|
|
505
|
+
const interval = values[1] - values[0];
|
|
506
|
+
if (interval < 2) {
|
|
507
|
+
return null;
|
|
508
|
+
}
|
|
509
|
+
for (let i = 2; i < values.length; i += 1) {
|
|
510
|
+
if (values[i] - values[i - 1] !== interval) {
|
|
511
|
+
return null;
|
|
512
|
+
}
|
|
513
|
+
}
|
|
514
|
+
if (values[0] !== 0 && values.length < 5) {
|
|
515
|
+
return null;
|
|
516
|
+
}
|
|
517
|
+
return { interval, last: values[values.length - 1], start: values[0] };
|
|
518
|
+
}
|
|
519
|
+
|
|
468
520
|
// src/core/shapes.ts
|
|
469
521
|
function isSingleValue(field) {
|
|
470
522
|
return field !== "*" && !includes(field, ",") && !includes(field, "-") && !includes(field, "/");
|
|
@@ -481,6 +533,9 @@ function isDiscreteList(field) {
|
|
|
481
533
|
function isDiscreteHours(hourField) {
|
|
482
534
|
return hourField !== "*" && !isPlainRange(hourField) && !isPlainStep(hourField);
|
|
483
535
|
}
|
|
536
|
+
function isOpenStep(field) {
|
|
537
|
+
return field.indexOf("/") !== -1 && field.indexOf("-") === -1 && field.indexOf(",") === -1;
|
|
538
|
+
}
|
|
484
539
|
|
|
485
540
|
// src/core/analyze.ts
|
|
486
541
|
function getOccurrences(start, interval, max) {
|
|
@@ -616,11 +671,11 @@ function analyze(pattern) {
|
|
|
616
671
|
minuteSpan: minuteSpan(pattern.minute),
|
|
617
672
|
segments
|
|
618
673
|
};
|
|
619
|
-
const
|
|
620
|
-
return { ...
|
|
674
|
+
const facts = { analyses, pattern, shapes };
|
|
675
|
+
return { ...facts, plan: selectPlan(facts) };
|
|
621
676
|
}
|
|
622
|
-
function
|
|
623
|
-
const { analyses, pattern, shapes } =
|
|
677
|
+
function selectPlan(facts) {
|
|
678
|
+
const { analyses, pattern, shapes } = facts;
|
|
624
679
|
if (pattern.second !== "0") {
|
|
625
680
|
const seconds = planSeconds(pattern, shapes, analyses);
|
|
626
681
|
if (seconds) {
|
|
@@ -964,72 +1019,134 @@ function normalizeOptions(options) {
|
|
|
964
1019
|
years: !!options.years
|
|
965
1020
|
};
|
|
966
1021
|
}
|
|
967
|
-
function describe(
|
|
968
|
-
const
|
|
969
|
-
|
|
970
|
-
|
|
1022
|
+
function describe(schedule, opts) {
|
|
1023
|
+
const dense = denseCadence(schedule, opts);
|
|
1024
|
+
if (dense !== null) {
|
|
1025
|
+
return applyYear(dense, schedule, opts);
|
|
1026
|
+
}
|
|
1027
|
+
const body = confinement(schedule, opts) ?? render(schedule, schedule.plan, opts);
|
|
1028
|
+
const lead = isDayUnion(schedule, opts) ? dayUnionMonthLead(schedule, opts) : "";
|
|
1029
|
+
return applyYear(lead + body, schedule, opts);
|
|
971
1030
|
}
|
|
972
|
-
function render(
|
|
1031
|
+
function render(schedule, plan, opts) {
|
|
973
1032
|
const renderer = renderers[plan.kind];
|
|
974
|
-
return renderer(
|
|
1033
|
+
return renderer(schedule, plan, opts);
|
|
975
1034
|
}
|
|
976
|
-
function
|
|
977
|
-
return "
|
|
1035
|
+
function isCadenceShape(shape) {
|
|
1036
|
+
return shape === "step" || shape === "range" || shape === "list";
|
|
978
1037
|
}
|
|
979
|
-
function
|
|
980
|
-
|
|
1038
|
+
function isDenseCadence(schedule, opts) {
|
|
1039
|
+
if (!opts.style.untilWindow || opts.short || schedule.plan.kind !== "composeSeconds" || schedule.plan.rest.kind === "clockTimes" || isDayUnion(schedule, opts)) {
|
|
1040
|
+
return false;
|
|
1041
|
+
}
|
|
1042
|
+
const { shapes } = schedule;
|
|
1043
|
+
return isCadenceShape(shapes.second) && isCadenceShape(shapes.minute) && isCadenceShape(shapes.hour);
|
|
981
1044
|
}
|
|
982
|
-
function
|
|
983
|
-
const
|
|
984
|
-
|
|
1045
|
+
function denseHourFragment(schedule, opts) {
|
|
1046
|
+
const stride = hourStride(schedule);
|
|
1047
|
+
if (stride) {
|
|
1048
|
+
return hourStrideCadence(stride, opts);
|
|
1049
|
+
}
|
|
1050
|
+
if (schedule.shapes.hour === "range") {
|
|
1051
|
+
const segment = segmentsOf(schedule, "hour").find(function range(part) {
|
|
1052
|
+
return part.kind === "range";
|
|
1053
|
+
});
|
|
1054
|
+
return rangeWindow({
|
|
1055
|
+
continuous: false,
|
|
1056
|
+
from: +segment.bounds[0],
|
|
1057
|
+
throughMinute: 0,
|
|
1058
|
+
to: +segment.bounds[1]
|
|
1059
|
+
}, opts);
|
|
1060
|
+
}
|
|
1061
|
+
return "during the " + hourSegmentTimes(schedule, { minute: 0, second: null }, false, opts) + " hours";
|
|
985
1062
|
}
|
|
986
|
-
function
|
|
987
|
-
|
|
1063
|
+
function denseMinuteFragment(schedule, opts) {
|
|
1064
|
+
if (schedule.shapes.minute === "step") {
|
|
1065
|
+
return stepCycle60(stepSegment(schedule, "minute"), "minute", "hour", opts);
|
|
1066
|
+
}
|
|
1067
|
+
if (schedule.shapes.minute === "range") {
|
|
1068
|
+
return minuteRangeLead(schedule.pattern.minute, opts);
|
|
1069
|
+
}
|
|
1070
|
+
return strideFromSegments(
|
|
1071
|
+
segmentsOf(schedule, "minute"),
|
|
1072
|
+
"minute",
|
|
1073
|
+
"hour",
|
|
1074
|
+
opts
|
|
1075
|
+
) ?? listPastThe(
|
|
1076
|
+
segmentWords(segmentsOf(schedule, "minute"), opts),
|
|
1077
|
+
"minute",
|
|
1078
|
+
"hour",
|
|
1079
|
+
opts
|
|
1080
|
+
);
|
|
1081
|
+
}
|
|
1082
|
+
function denseCadence(schedule, opts) {
|
|
1083
|
+
if (!isDenseCadence(schedule, opts)) {
|
|
1084
|
+
return null;
|
|
1085
|
+
}
|
|
1086
|
+
const hour = denseHourFragment(schedule, opts);
|
|
1087
|
+
const minute = denseMinuteFragment(schedule, opts);
|
|
1088
|
+
const second = secondsClause(schedule, "minute", opts);
|
|
1089
|
+
const nested = hour + ", " + minute + ", and within each of those minutes, " + second;
|
|
1090
|
+
const anchor = trailingQualifier(schedule, opts).trim();
|
|
1091
|
+
return anchor ? anchor + ", " + nested : nested;
|
|
1092
|
+
}
|
|
1093
|
+
function renderEverySecond(schedule, plan, opts) {
|
|
1094
|
+
return "every second" + trailingQualifier(schedule, opts);
|
|
1095
|
+
}
|
|
1096
|
+
function renderStandaloneSeconds(schedule, plan, opts) {
|
|
1097
|
+
return secondsLeadClause(schedule, opts) + trailingQualifier(schedule, opts);
|
|
1098
|
+
}
|
|
1099
|
+
function renderSecondPastMinute(schedule, plan, opts) {
|
|
1100
|
+
const secondField = schedule.pattern.second;
|
|
1101
|
+
return getNumber(secondField, opts) + " " + pluralize(secondField, "second") + " past the minute, every minute" + trailingQualifier(schedule, opts);
|
|
1102
|
+
}
|
|
1103
|
+
function renderSecondsWithinMinute(schedule, plan, opts) {
|
|
1104
|
+
const minuteField = schedule.pattern.minute;
|
|
988
1105
|
const minuteWord = getNumber(minuteField, opts);
|
|
989
1106
|
const minuteUnit = pluralize(minuteField, "minute");
|
|
990
1107
|
if (plan.singleSecond) {
|
|
991
|
-
const secondField =
|
|
992
|
-
return minuteWord + " " + minuteUnit + " and " + getNumber(secondField, opts) + " " + pluralize(secondField, "second") + " past the hour, every hour" + trailingQualifier(
|
|
1108
|
+
const secondField = schedule.pattern.second;
|
|
1109
|
+
return minuteWord + " " + minuteUnit + " and " + getNumber(secondField, opts) + " " + pluralize(secondField, "second") + " past the hour, every hour" + trailingQualifier(schedule, opts);
|
|
993
1110
|
}
|
|
994
|
-
return secondsLeadClause(
|
|
1111
|
+
return secondsLeadClause(schedule, opts) + ", " + minuteWord + " " + minuteUnit + " past the hour, every hour" + trailingQualifier(schedule, opts);
|
|
995
1112
|
}
|
|
996
|
-
function composeHourCadence(
|
|
1113
|
+
function composeHourCadence(schedule, plan, opts) {
|
|
997
1114
|
const clockRest = plan.rest.kind === "clockTimes" || plan.rest.kind === "compactClockTimes";
|
|
998
|
-
if (!clockRest ||
|
|
1115
|
+
if (!clockRest || schedule.shapes.minute !== "single") {
|
|
999
1116
|
return null;
|
|
1000
1117
|
}
|
|
1001
|
-
const minute = +
|
|
1002
|
-
return hourCadence(
|
|
1118
|
+
const minute = +schedule.pattern.minute;
|
|
1119
|
+
return hourCadence(schedule, minute, opts) ?? hourRangeCadence(schedule, minute, opts);
|
|
1003
1120
|
}
|
|
1004
|
-
function clockTimesConfinement(
|
|
1005
|
-
if (+rest.times[0].minute === 0 &&
|
|
1006
|
-
return secondsLeadClause(
|
|
1121
|
+
function clockTimesConfinement(schedule, rest, opts) {
|
|
1122
|
+
if (+rest.times[0].minute === 0 && schedule.shapes.minute === "single") {
|
|
1123
|
+
return secondsLeadClause(schedule, opts) + " for one minute at " + durationHours(schedule, rest, opts);
|
|
1007
1124
|
}
|
|
1008
|
-
return secondsLeadClause(
|
|
1125
|
+
return secondsLeadClause(schedule, opts) + " of " + clockTimesOf(schedule, rest, opts);
|
|
1009
1126
|
}
|
|
1010
|
-
function renderComposeSeconds(
|
|
1011
|
-
const cadence = composeHourCadence(
|
|
1127
|
+
function renderComposeSeconds(schedule, plan, opts) {
|
|
1128
|
+
const cadence = composeHourCadence(schedule, plan, opts);
|
|
1012
1129
|
if (cadence !== null) {
|
|
1013
1130
|
return cadence;
|
|
1014
1131
|
}
|
|
1015
|
-
if (plan.rest.kind === "clockTimes" && (
|
|
1016
|
-
return clockTimesConfinement(
|
|
1132
|
+
if (plan.rest.kind === "clockTimes" && (schedule.shapes.second === "wildcard" || schedule.shapes.second === "step")) {
|
|
1133
|
+
return clockTimesConfinement(schedule, plan.rest, opts);
|
|
1017
1134
|
}
|
|
1018
|
-
if (
|
|
1019
|
-
return "every second of every other minute" + trailingQualifier(
|
|
1135
|
+
if (schedule.shapes.second === "wildcard" && plan.rest.kind === "minuteFrequency" && plan.rest.hours.kind === "none" && schedule.pattern.minute === "*/2") {
|
|
1136
|
+
return "every second of every other minute" + trailingQualifier(schedule, opts);
|
|
1020
1137
|
}
|
|
1021
|
-
const restOwnsLead = plan.rest.kind === "compactClockTimes" &&
|
|
1022
|
-
const lead = restOwnsLead ? "" : secondsLeadClause(
|
|
1023
|
-
return lead + render(
|
|
1138
|
+
const restOwnsLead = plan.rest.kind === "compactClockTimes" && schedule.analyses.clockSecond;
|
|
1139
|
+
const lead = restOwnsLead ? "" : secondsLeadClause(schedule, opts) + ", ";
|
|
1140
|
+
return lead + render(schedule, plan.rest, opts);
|
|
1024
1141
|
}
|
|
1025
|
-
function durationHours(
|
|
1142
|
+
function durationHours(schedule, plan, opts) {
|
|
1026
1143
|
const hours = plan.times.map(function clock(time) {
|
|
1027
1144
|
return getTime({ hour: time.hour, minute: 0 }, opts);
|
|
1028
1145
|
});
|
|
1029
|
-
const trail = dayQualifier(
|
|
1146
|
+
const trail = dayQualifier(schedule, leadingWords, opts);
|
|
1030
1147
|
return joinList(hours, opts) + (trail && ", " + trail);
|
|
1031
1148
|
}
|
|
1032
|
-
function clockTimesOf(
|
|
1149
|
+
function clockTimesOf(schedule, plan, opts) {
|
|
1033
1150
|
const times = plan.times.map(function clock(time) {
|
|
1034
1151
|
return getTime({
|
|
1035
1152
|
hour: time.hour,
|
|
@@ -1038,21 +1155,21 @@ function clockTimesOf(ir, plan, opts) {
|
|
|
1038
1155
|
explicit: true
|
|
1039
1156
|
}, opts);
|
|
1040
1157
|
});
|
|
1041
|
-
const trail = dayQualifier(
|
|
1158
|
+
const trail = dayQualifier(schedule, leadingWords, opts);
|
|
1042
1159
|
return joinList(times, opts) + (trail && ", " + trail);
|
|
1043
1160
|
}
|
|
1044
|
-
function secondsLeadClause(
|
|
1045
|
-
return secondsClause(
|
|
1161
|
+
function secondsLeadClause(schedule, opts) {
|
|
1162
|
+
return secondsClause(schedule, "minute", opts);
|
|
1046
1163
|
}
|
|
1047
|
-
function secondsClause(
|
|
1048
|
-
const secondField =
|
|
1049
|
-
const shape =
|
|
1164
|
+
function secondsClause(schedule, anchor, opts) {
|
|
1165
|
+
const secondField = schedule.pattern.second;
|
|
1166
|
+
const shape = schedule.shapes.second;
|
|
1050
1167
|
if (secondField === "*") {
|
|
1051
1168
|
return "every second";
|
|
1052
1169
|
}
|
|
1053
1170
|
if (shape === "step") {
|
|
1054
1171
|
return stepCycle60(
|
|
1055
|
-
|
|
1172
|
+
stepSegment(schedule, "second"),
|
|
1056
1173
|
"second",
|
|
1057
1174
|
anchor,
|
|
1058
1175
|
opts
|
|
@@ -1067,86 +1184,96 @@ function secondsClause(ir, anchor, opts) {
|
|
|
1067
1184
|
return "at " + getNumber(secondField, opts) + " " + pluralize(secondField, "second") + " past the " + anchor;
|
|
1068
1185
|
}
|
|
1069
1186
|
return strideFromSegments(
|
|
1070
|
-
|
|
1187
|
+
segmentsOf(schedule, "second"),
|
|
1071
1188
|
"second",
|
|
1072
1189
|
anchor,
|
|
1073
1190
|
opts
|
|
1074
1191
|
) ?? listPastThe(
|
|
1075
|
-
segmentWords(
|
|
1192
|
+
segmentWords(segmentsOf(schedule, "second"), opts),
|
|
1076
1193
|
"second",
|
|
1077
1194
|
anchor,
|
|
1078
1195
|
opts
|
|
1079
1196
|
);
|
|
1080
1197
|
}
|
|
1081
|
-
function renderEveryMinute(
|
|
1082
|
-
return "every minute" + trailingQualifier(
|
|
1198
|
+
function renderEveryMinute(schedule, plan, opts) {
|
|
1199
|
+
return "every minute" + trailingQualifier(schedule, opts);
|
|
1083
1200
|
}
|
|
1084
|
-
function renderSingleMinute(
|
|
1085
|
-
const minuteField =
|
|
1086
|
-
return getNumber(minuteField, opts) + " " + pluralize(minuteField, "minute") + " past the hour, every hour" + trailingQualifier(
|
|
1201
|
+
function renderSingleMinute(schedule, plan, opts) {
|
|
1202
|
+
const minuteField = schedule.pattern.minute;
|
|
1203
|
+
return getNumber(minuteField, opts) + " " + pluralize(minuteField, "minute") + " past the hour, every hour" + trailingQualifier(schedule, opts);
|
|
1087
1204
|
}
|
|
1088
|
-
function renderRangeOfMinutes(
|
|
1089
|
-
return minuteRangeLead(
|
|
1205
|
+
function renderRangeOfMinutes(schedule, plan, opts) {
|
|
1206
|
+
return minuteRangeLead(schedule.pattern.minute, opts) + trailingQualifier(schedule, opts);
|
|
1090
1207
|
}
|
|
1091
|
-
function renderMultipleMinutes(
|
|
1092
|
-
const stride = strideFromSegments(
|
|
1208
|
+
function renderMultipleMinutes(schedule, plan, opts) {
|
|
1209
|
+
const stride = strideFromSegments(segmentsOf(schedule, "minute"), "minute", "hour", opts);
|
|
1093
1210
|
return (stride ?? listPastThe(segmentWords(
|
|
1094
|
-
|
|
1211
|
+
segmentsOf(schedule, "minute"),
|
|
1095
1212
|
opts
|
|
1096
|
-
), "minute", "hour", opts)) + trailingQualifier(
|
|
1213
|
+
), "minute", "hour", opts)) + trailingQualifier(schedule, opts);
|
|
1097
1214
|
}
|
|
1098
|
-
function renderMinuteFrequency(
|
|
1215
|
+
function renderMinuteFrequency(schedule, plan, opts) {
|
|
1099
1216
|
let phrase = stepCycle60(
|
|
1100
|
-
|
|
1217
|
+
stepSegment(schedule, "minute"),
|
|
1101
1218
|
"minute",
|
|
1102
1219
|
"hour",
|
|
1103
1220
|
opts
|
|
1104
1221
|
);
|
|
1105
1222
|
if (plan.hours.kind === "during") {
|
|
1106
|
-
const cadence = unevenHourCadence(
|
|
1107
|
-
phrase += cadence ? ", " + cadence : " during the " + hourTimesFromPlan(
|
|
1223
|
+
const cadence = unevenHourCadence(schedule, opts);
|
|
1224
|
+
phrase += cadence ? ", " + cadence : " during the " + hourTimesFromPlan(schedule, plan.hours.times, false, opts) + " hours";
|
|
1108
1225
|
} else if (plan.hours.kind === "window") {
|
|
1109
|
-
phrase += " " +
|
|
1226
|
+
phrase += " " + rangeWindow({
|
|
1227
|
+
continuous: false,
|
|
1228
|
+
from: plan.hours.from,
|
|
1229
|
+
throughMinute: plan.hours.last,
|
|
1230
|
+
to: plan.hours.to
|
|
1231
|
+
}, opts);
|
|
1110
1232
|
} else if (plan.hours.kind === "step") {
|
|
1111
|
-
phrase += " " + everyNthHour(
|
|
1233
|
+
phrase += " " + everyNthHour(stepSegment(schedule, "hour"), opts);
|
|
1112
1234
|
}
|
|
1113
|
-
return phrase + trailingQualifier(
|
|
1235
|
+
return phrase + trailingQualifier(schedule, opts);
|
|
1114
1236
|
}
|
|
1115
|
-
function renderMinuteSpanInHour(
|
|
1116
|
-
if (
|
|
1117
|
-
return "every minute of the " + getTime({ hour: plan.hour, minute: 0 }, opts) + " hour" + trailingQualifier(
|
|
1237
|
+
function renderMinuteSpanInHour(schedule, plan, opts) {
|
|
1238
|
+
if (schedule.pattern.minute === "*") {
|
|
1239
|
+
return "every minute of the " + getTime({ hour: plan.hour, minute: 0 }, opts) + " hour" + trailingQualifier(schedule, opts);
|
|
1118
1240
|
}
|
|
1119
|
-
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(
|
|
1241
|
+
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);
|
|
1120
1242
|
}
|
|
1121
|
-
function renderMinutesAcrossHours(
|
|
1122
|
-
const cadence = unevenHourCadence(
|
|
1243
|
+
function renderMinutesAcrossHours(schedule, plan, opts) {
|
|
1244
|
+
const cadence = unevenHourCadence(schedule, opts);
|
|
1123
1245
|
if (plan.form === "wildcard") {
|
|
1124
1246
|
if (cadence !== null) {
|
|
1125
|
-
return "every minute, " + cadence + trailingQualifier(
|
|
1247
|
+
return "every minute, " + cadence + trailingQualifier(schedule, opts);
|
|
1126
1248
|
}
|
|
1127
|
-
return "every minute during the " + hourTimesFromPlan(
|
|
1249
|
+
return "every minute during the " + hourTimesFromPlan(schedule, plan.times, false, opts) + " hours" + trailingQualifier(schedule, opts);
|
|
1128
1250
|
}
|
|
1129
1251
|
if (plan.form === "range") {
|
|
1130
|
-
const lead2 = minuteRangeLead(
|
|
1252
|
+
const lead2 = minuteRangeLead(schedule.pattern.minute, opts);
|
|
1131
1253
|
if (cadence !== null) {
|
|
1132
|
-
return lead2 + ", " + cadence + trailingQualifier(
|
|
1254
|
+
return lead2 + ", " + cadence + trailingQualifier(schedule, opts);
|
|
1133
1255
|
}
|
|
1134
1256
|
if (singleHourFire(plan.times)) {
|
|
1135
|
-
return lead2 + ", at " + hourTimesFromPlan(
|
|
1257
|
+
return lead2 + ", at " + hourTimesFromPlan(schedule, plan.times, true, opts) + trailingQualifier(schedule, opts);
|
|
1136
1258
|
}
|
|
1137
|
-
return lead2 + " during the " + hourTimesFromPlan(
|
|
1259
|
+
return lead2 + " during the " + hourTimesFromPlan(schedule, plan.times, false, opts) + " hours" + trailingQualifier(schedule, opts);
|
|
1138
1260
|
}
|
|
1139
|
-
const lead = strideFromSegments(
|
|
1140
|
-
|
|
1261
|
+
const lead = strideFromSegments(
|
|
1262
|
+
segmentsOf(schedule, "minute"),
|
|
1263
|
+
"minute",
|
|
1264
|
+
"hour",
|
|
1265
|
+
opts
|
|
1266
|
+
) ?? listPastThe(
|
|
1267
|
+
segmentWords(segmentsOf(schedule, "minute"), opts),
|
|
1141
1268
|
"minute",
|
|
1142
1269
|
"hour",
|
|
1143
1270
|
opts
|
|
1144
1271
|
);
|
|
1145
1272
|
if (cadence !== null) {
|
|
1146
|
-
return lead + ", " + cadence + trailingQualifier(
|
|
1273
|
+
return lead + ", " + cadence + trailingQualifier(schedule, opts);
|
|
1147
1274
|
}
|
|
1148
|
-
const times = hourTimesFromPlan(
|
|
1149
|
-
return lead + ", at " + times + trailingQualifier(
|
|
1275
|
+
const times = hourTimesFromPlan(schedule, plan.times, true, opts);
|
|
1276
|
+
return lead + ", at " + times + trailingQualifier(schedule, opts);
|
|
1150
1277
|
}
|
|
1151
1278
|
var stepOrdinals = {
|
|
1152
1279
|
2: "other",
|
|
@@ -1161,79 +1288,91 @@ function everyNthHour(segment, opts) {
|
|
|
1161
1288
|
const start = segment.startToken === "*" ? 0 : +segment.startToken;
|
|
1162
1289
|
return start === 0 ? base : base + " starting at " + getTime({ hour: start, minute: 0 }, opts);
|
|
1163
1290
|
}
|
|
1164
|
-
function renderMinuteSpanAcrossHourStep(
|
|
1165
|
-
const segment =
|
|
1291
|
+
function renderMinuteSpanAcrossHourStep(schedule, plan, opts) {
|
|
1292
|
+
const segment = stepSegment(schedule, "hour");
|
|
1166
1293
|
if (plan.form === "wildcard") {
|
|
1167
|
-
return "every minute " + everyNthHour(segment, opts) + trailingQualifier(
|
|
1294
|
+
return "every minute " + everyNthHour(segment, opts) + trailingQualifier(schedule, opts);
|
|
1168
1295
|
}
|
|
1169
|
-
const lead = plan.form === "list" ? strideFromSegments(
|
|
1170
|
-
|
|
1296
|
+
const lead = plan.form === "list" ? strideFromSegments(
|
|
1297
|
+
segmentsOf(schedule, "minute"),
|
|
1298
|
+
"minute",
|
|
1299
|
+
"hour",
|
|
1300
|
+
opts
|
|
1301
|
+
) ?? listPastThe(
|
|
1302
|
+
segmentWords(segmentsOf(schedule, "minute"), opts),
|
|
1171
1303
|
"minute",
|
|
1172
1304
|
"hour",
|
|
1173
1305
|
opts
|
|
1174
|
-
) : minuteRangeLead(
|
|
1175
|
-
const cadence = unevenHourCadence(
|
|
1176
|
-
return lead + ", " + (cadence ?? stepHours(segment, opts)) + trailingQualifier(
|
|
1306
|
+
) : minuteRangeLead(schedule.pattern.minute, opts);
|
|
1307
|
+
const cadence = unevenHourCadence(schedule, opts);
|
|
1308
|
+
return lead + ", " + (cadence ?? stepHours(segment, opts)) + trailingQualifier(schedule, opts);
|
|
1177
1309
|
}
|
|
1178
1310
|
function minuteRangeLead(minuteField, opts) {
|
|
1179
1311
|
const bounds = minuteField.split("-");
|
|
1180
1312
|
const num = seriesNumber();
|
|
1181
1313
|
return "every minute from " + num(bounds[0]) + through(opts) + num(bounds[1]) + " past the hour";
|
|
1182
1314
|
}
|
|
1183
|
-
function renderEveryHour(
|
|
1184
|
-
return "every hour" + trailingQualifier(
|
|
1315
|
+
function renderEveryHour(schedule, plan, opts) {
|
|
1316
|
+
return "every hour" + trailingQualifier(schedule, opts);
|
|
1185
1317
|
}
|
|
1186
|
-
function renderHourRange(
|
|
1318
|
+
function renderHourRange(schedule, plan, opts) {
|
|
1187
1319
|
const window = hourWindow(boundedWindow(plan), opts);
|
|
1188
1320
|
if (plan.minuteForm === "wildcard") {
|
|
1189
|
-
return "every minute " + window + trailingQualifier(
|
|
1321
|
+
return "every minute " + window + trailingQualifier(schedule, opts);
|
|
1190
1322
|
}
|
|
1191
1323
|
if (plan.minuteForm === "range") {
|
|
1192
|
-
return minuteRangeLead(
|
|
1324
|
+
return minuteRangeLead(schedule.pattern.minute, opts) + ", " + window + trailingQualifier(schedule, opts);
|
|
1193
1325
|
}
|
|
1194
|
-
return rangeMinuteLead(
|
|
1326
|
+
return rangeMinuteLead(schedule, opts) + " " + window + trailingQualifier(schedule, opts);
|
|
1195
1327
|
}
|
|
1196
|
-
function rangeMinuteLead(
|
|
1197
|
-
if (
|
|
1328
|
+
function rangeMinuteLead(schedule, opts) {
|
|
1329
|
+
if (schedule.pattern.minute === "0") {
|
|
1198
1330
|
return "every hour";
|
|
1199
1331
|
}
|
|
1200
1332
|
return strideFromSegments(
|
|
1201
|
-
|
|
1333
|
+
segmentsOf(schedule, "minute"),
|
|
1202
1334
|
"minute",
|
|
1203
1335
|
"hour",
|
|
1204
1336
|
opts
|
|
1205
1337
|
) ?? listPastThe(
|
|
1206
|
-
segmentWords(
|
|
1338
|
+
segmentWords(segmentsOf(schedule, "minute"), opts),
|
|
1207
1339
|
"minute",
|
|
1208
1340
|
"hour",
|
|
1209
1341
|
opts
|
|
1210
1342
|
);
|
|
1211
1343
|
}
|
|
1212
|
-
function renderHourStep(
|
|
1213
|
-
const cadence = unevenHourCadence(
|
|
1344
|
+
function renderHourStep(schedule, plan, opts) {
|
|
1345
|
+
const cadence = unevenHourCadence(schedule, opts);
|
|
1214
1346
|
if (cadence !== null) {
|
|
1215
|
-
return cadence + trailingQualifier(
|
|
1347
|
+
return cadence + trailingQualifier(schedule, opts);
|
|
1216
1348
|
}
|
|
1217
|
-
return stepHours(
|
|
1349
|
+
return stepHours(stepSegment(schedule, "hour"), opts) + trailingQualifier(schedule, opts);
|
|
1218
1350
|
}
|
|
1219
1351
|
function boundedWindow(plan) {
|
|
1220
|
-
const
|
|
1221
|
-
|
|
1352
|
+
const continuous = plan.minuteForm === "wildcard";
|
|
1353
|
+
const closeMinute = continuous ? plan.boundMinute ?? 0 : 0;
|
|
1354
|
+
return { from: plan.from, closeMinute, to: plan.to, continuous };
|
|
1222
1355
|
}
|
|
1223
|
-
function rangeWindow(
|
|
1356
|
+
function rangeWindow(window, opts) {
|
|
1357
|
+
const { from, to, throughMinute, continuous } = window;
|
|
1224
1358
|
const open = "from " + getTime({ hour: from, minute: 0 }, opts);
|
|
1225
1359
|
if (opts.style.untilWindow && !opts.short && from !== to) {
|
|
1226
|
-
return open + " until " + getTime({ hour: (to + 1) % 24, minute: 0 }, opts);
|
|
1360
|
+
return continuous ? open + " until " + getTime({ hour: (to + 1) % 24, minute: 0 }, opts) : open + through(opts) + getTime({ hour: to, minute: 0 }, opts);
|
|
1227
1361
|
}
|
|
1228
1362
|
return open + through(opts) + getTime({ hour: to, minute: throughMinute }, opts);
|
|
1229
1363
|
}
|
|
1230
1364
|
function hourWindow(window, opts) {
|
|
1231
|
-
return rangeWindow(
|
|
1365
|
+
return rangeWindow({
|
|
1366
|
+
continuous: window.continuous,
|
|
1367
|
+
from: window.from,
|
|
1368
|
+
throughMinute: window.closeMinute,
|
|
1369
|
+
to: window.to
|
|
1370
|
+
}, opts);
|
|
1232
1371
|
}
|
|
1233
|
-
function renderClockTimes(
|
|
1234
|
-
if (
|
|
1235
|
-
const minute = +
|
|
1236
|
-
const cadence = hourCadence(
|
|
1372
|
+
function renderClockTimes(schedule, plan, opts) {
|
|
1373
|
+
if (schedule.shapes.minute === "single") {
|
|
1374
|
+
const minute = +schedule.pattern.minute;
|
|
1375
|
+
const cadence = hourCadence(schedule, minute, opts) ?? hourRangeCadence(schedule, minute, opts);
|
|
1237
1376
|
if (cadence !== null) {
|
|
1238
1377
|
return cadence;
|
|
1239
1378
|
}
|
|
@@ -1247,93 +1386,94 @@ function renderClockTimes(ir, plan, opts) {
|
|
|
1247
1386
|
plain
|
|
1248
1387
|
}, opts);
|
|
1249
1388
|
});
|
|
1250
|
-
return interpretDayQualifier(
|
|
1389
|
+
return interpretDayQualifier(schedule, opts) + "at " + joinList(times, opts) + dayUnionTrail(schedule, opts);
|
|
1251
1390
|
}
|
|
1252
|
-
function dayUnionTrail(
|
|
1253
|
-
return isDayUnion(
|
|
1391
|
+
function dayUnionTrail(schedule, opts) {
|
|
1392
|
+
return isDayUnion(schedule, opts) ? dayUnionCondition(schedule, opts) : "";
|
|
1254
1393
|
}
|
|
1255
|
-
function renderCompactClockTimes(
|
|
1394
|
+
function renderCompactClockTimes(schedule, plan, opts) {
|
|
1256
1395
|
if (plan.fold) {
|
|
1257
|
-
const cadence2 = hourCadence(
|
|
1396
|
+
const cadence2 = hourCadence(schedule, +plan.minute, opts) ?? hourRangeCadence(schedule, +plan.minute, opts);
|
|
1258
1397
|
if (cadence2 !== null) {
|
|
1259
1398
|
return cadence2;
|
|
1260
1399
|
}
|
|
1261
|
-
const hasRange =
|
|
1400
|
+
const hasRange = segmentsOf(schedule, "hour").some(function range(segment) {
|
|
1262
1401
|
return segment.kind === "range";
|
|
1263
1402
|
});
|
|
1264
|
-
if (hasRange && !
|
|
1265
|
-
return foldedHourWindows(
|
|
1403
|
+
if (hasRange && !schedule.analyses.clockSecond) {
|
|
1404
|
+
return foldedHourWindows(schedule, plan, opts) + trailingQualifier(schedule, opts);
|
|
1266
1405
|
}
|
|
1267
|
-
const fold = { minute: plan.minute, second:
|
|
1268
|
-
return interpretDayQualifier(
|
|
1406
|
+
const fold = { minute: plan.minute, second: schedule.analyses.clockSecond };
|
|
1407
|
+
return interpretDayQualifier(schedule, opts) + "at " + hourSegmentTimes(schedule, fold, true, opts) + dayUnionTrail(schedule, opts);
|
|
1269
1408
|
}
|
|
1270
1409
|
const minuteLead = (
|
|
1271
1410
|
// The non-fold branch is a minute list, which has segments. An
|
|
1272
1411
|
// offset/uneven step enumerated to that list reads as a stride.
|
|
1273
|
-
strideFromSegments(
|
|
1274
|
-
|
|
1412
|
+
strideFromSegments(
|
|
1413
|
+
segmentsOf(schedule, "minute"),
|
|
1414
|
+
"minute",
|
|
1415
|
+
"hour",
|
|
1416
|
+
opts
|
|
1417
|
+
) ?? listPastThe(
|
|
1418
|
+
segmentWords(segmentsOf(schedule, "minute"), opts),
|
|
1275
1419
|
"minute",
|
|
1276
1420
|
"hour",
|
|
1277
1421
|
opts
|
|
1278
1422
|
)
|
|
1279
1423
|
);
|
|
1280
|
-
const cadence = unevenHourCadence(
|
|
1281
|
-
const phrase = cadence ? minuteLead + ", " + cadence + trailingQualifier(
|
|
1282
|
-
return
|
|
1424
|
+
const cadence = unevenHourCadence(schedule, opts);
|
|
1425
|
+
const phrase = cadence ? minuteLead + ", " + cadence + trailingQualifier(schedule, opts) : minuteLead + ", at " + hourSegmentTimes(schedule, { minute: 0, second: null }, true, opts) + trailingQualifier(schedule, opts);
|
|
1426
|
+
return schedule.analyses.clockSecond ? secondsLeadClause(schedule, opts) + ", " + phrase : phrase;
|
|
1283
1427
|
}
|
|
1284
|
-
function foldedHourWindows(
|
|
1428
|
+
function foldedHourWindows(schedule, plan, opts) {
|
|
1285
1429
|
const minute = plan.minute;
|
|
1286
1430
|
const windows = [];
|
|
1287
|
-
const
|
|
1288
|
-
const times = outliers.hours.map(function time(hour) {
|
|
1431
|
+
const times = collectHourOutliers(schedule).map(function time(hour) {
|
|
1289
1432
|
return getTime({ hour, minute }, opts);
|
|
1290
1433
|
});
|
|
1291
|
-
|
|
1434
|
+
segmentsOf(schedule, "hour").forEach(function classify(segment) {
|
|
1292
1435
|
if (segment.kind === "range") {
|
|
1293
|
-
windows.push(rangeWindow(
|
|
1294
|
-
|
|
1295
|
-
+segment.bounds[
|
|
1296
|
-
minute,
|
|
1297
|
-
|
|
1298
|
-
));
|
|
1436
|
+
windows.push(rangeWindow({
|
|
1437
|
+
continuous: false,
|
|
1438
|
+
from: +segment.bounds[0],
|
|
1439
|
+
throughMinute: minute,
|
|
1440
|
+
to: +segment.bounds[1]
|
|
1441
|
+
}, opts));
|
|
1299
1442
|
}
|
|
1300
1443
|
});
|
|
1301
|
-
const phrase = rangeMinuteLead(
|
|
1302
|
-
return phrase + outlierTail(times,
|
|
1444
|
+
const phrase = rangeMinuteLead(schedule, opts) + " " + joinList(windows, opts);
|
|
1445
|
+
return phrase + outlierTail(times, opts);
|
|
1303
1446
|
}
|
|
1304
|
-
function collectHourOutliers(
|
|
1447
|
+
function collectHourOutliers(schedule) {
|
|
1305
1448
|
const hours = [];
|
|
1306
|
-
|
|
1307
|
-
ir.analyses.segments.hour.forEach(function classify(segment) {
|
|
1449
|
+
segmentsOf(schedule, "hour").forEach(function classify(segment) {
|
|
1308
1450
|
if (segment.kind === "step") {
|
|
1309
1451
|
hours.push(...segment.fires);
|
|
1310
|
-
pureStrays = false;
|
|
1311
1452
|
} else if (segment.kind !== "range") {
|
|
1312
1453
|
hours.push(+segment.value);
|
|
1313
1454
|
}
|
|
1314
1455
|
});
|
|
1315
|
-
return
|
|
1456
|
+
return hours;
|
|
1316
1457
|
}
|
|
1317
|
-
function outlierTail(times,
|
|
1458
|
+
function outlierTail(times, opts) {
|
|
1318
1459
|
if (!times.length) {
|
|
1319
1460
|
return "";
|
|
1320
1461
|
}
|
|
1321
|
-
|
|
1322
|
-
return connector + joinList(times, opts);
|
|
1462
|
+
return " and at " + joinList(times, opts);
|
|
1323
1463
|
}
|
|
1324
1464
|
function isCadenceField(token) {
|
|
1325
1465
|
return token === "*" || token.startsWith("*/") && token.indexOf("-") === -1;
|
|
1326
1466
|
}
|
|
1327
|
-
function leadingCadence(
|
|
1328
|
-
const { second, minute } =
|
|
1467
|
+
function leadingCadence(schedule, opts) {
|
|
1468
|
+
const { second, minute } = schedule.pattern;
|
|
1329
1469
|
if (isCadenceField(second)) {
|
|
1330
|
-
return { secondLead: true, text: secondsClause(
|
|
1470
|
+
return { secondLead: true, text: secondsClause(schedule, "minute", opts) };
|
|
1331
1471
|
}
|
|
1332
1472
|
if (second === "0" && isCadenceField(minute)) {
|
|
1333
1473
|
const text = minute === "*" ? "every minute" : (
|
|
1334
1474
|
// A clean minute step's first segment is a step segment.
|
|
1335
1475
|
stepCycle60(
|
|
1336
|
-
|
|
1476
|
+
stepSegment(schedule, "minute"),
|
|
1337
1477
|
"minute",
|
|
1338
1478
|
"hour",
|
|
1339
1479
|
opts
|
|
@@ -1343,19 +1483,19 @@ function leadingCadence(ir, opts) {
|
|
|
1343
1483
|
}
|
|
1344
1484
|
return null;
|
|
1345
1485
|
}
|
|
1346
|
-
function minuteConfinement(
|
|
1347
|
-
const minute =
|
|
1486
|
+
function minuteConfinement(schedule, opts) {
|
|
1487
|
+
const minute = schedule.pattern.minute;
|
|
1348
1488
|
if (minute === "*") {
|
|
1349
1489
|
return "";
|
|
1350
1490
|
}
|
|
1351
1491
|
if (isCadenceField(minute)) {
|
|
1352
1492
|
return " of every other minute";
|
|
1353
1493
|
}
|
|
1354
|
-
const segments =
|
|
1355
|
-
if (
|
|
1494
|
+
const segments = segmentsOf(schedule, "minute");
|
|
1495
|
+
if (schedule.shapes.minute === "single") {
|
|
1356
1496
|
return " during minute :" + pad(minute);
|
|
1357
1497
|
}
|
|
1358
|
-
if (
|
|
1498
|
+
if (schedule.shapes.minute === "range") {
|
|
1359
1499
|
const bounds = minute.split("-");
|
|
1360
1500
|
return " during minutes :" + pad(bounds[0]) + through(opts) + ":" + pad(bounds[1]);
|
|
1361
1501
|
}
|
|
@@ -1364,59 +1504,61 @@ function minuteConfinement(ir, opts) {
|
|
|
1364
1504
|
});
|
|
1365
1505
|
return " during minutes " + joinList(values, opts);
|
|
1366
1506
|
}
|
|
1367
|
-
function hourConfinement(
|
|
1368
|
-
const hour =
|
|
1507
|
+
function hourConfinement(schedule, opts) {
|
|
1508
|
+
const hour = schedule.pattern.hour;
|
|
1369
1509
|
if (hour === "*") {
|
|
1370
|
-
const minutePinned =
|
|
1510
|
+
const minutePinned = schedule.pattern.minute !== "*" && !isCadenceField(schedule.pattern.minute);
|
|
1371
1511
|
return minutePinned ? " of every hour" : "";
|
|
1372
1512
|
}
|
|
1373
1513
|
if (isCadenceField(hour)) {
|
|
1374
1514
|
return hour === "*/2" ? " of every other hour" : "";
|
|
1375
1515
|
}
|
|
1376
|
-
if (
|
|
1516
|
+
if (schedule.shapes.hour === "single") {
|
|
1377
1517
|
const h = +hour;
|
|
1378
|
-
if (
|
|
1518
|
+
if (schedule.shapes.minute === "step") {
|
|
1379
1519
|
return " from " + getTime({ hour: h, minute: 0 }, opts) + " until " + getTime({ hour: (h + 1) % 24, minute: 0 }, opts);
|
|
1380
1520
|
}
|
|
1381
|
-
if (
|
|
1521
|
+
if (schedule.pattern.minute !== "*" && !isCadenceField(schedule.pattern.minute)) {
|
|
1382
1522
|
return " at " + getTime({ hour: h, minute: 0 }, opts);
|
|
1383
1523
|
}
|
|
1384
1524
|
return " of the " + getTime({ hour: h, minute: 0 }, opts) + " hour";
|
|
1385
1525
|
}
|
|
1386
|
-
if (
|
|
1526
|
+
if (schedule.shapes.hour === "range") {
|
|
1387
1527
|
const bounds = hour.split("-");
|
|
1388
|
-
return " " + rangeWindow(
|
|
1528
|
+
return " " + rangeWindow({
|
|
1529
|
+
continuous: schedule.pattern.minute === "*",
|
|
1530
|
+
from: +bounds[0],
|
|
1531
|
+
throughMinute: 0,
|
|
1532
|
+
to: +bounds[1]
|
|
1533
|
+
}, opts);
|
|
1389
1534
|
}
|
|
1390
|
-
return " during the " + hourSegmentTimes(
|
|
1535
|
+
return " during the " + hourSegmentTimes(schedule, { minute: 0, second: null }, false, opts) + " hours";
|
|
1391
1536
|
}
|
|
1392
|
-
function
|
|
1393
|
-
|
|
1394
|
-
}
|
|
1395
|
-
function confinableHour(ir) {
|
|
1396
|
-
if (ir.shapes.hour !== "step") {
|
|
1537
|
+
function confinableHour(schedule) {
|
|
1538
|
+
if (schedule.shapes.hour !== "step") {
|
|
1397
1539
|
return true;
|
|
1398
1540
|
}
|
|
1399
|
-
const segment =
|
|
1400
|
-
return
|
|
1541
|
+
const segment = stepSegment(schedule, "hour");
|
|
1542
|
+
return schedule.pattern.hour === "*/2" || segment.startToken.indexOf("-") !== -1;
|
|
1401
1543
|
}
|
|
1402
|
-
function isMinuteStride(
|
|
1403
|
-
if (
|
|
1544
|
+
function isMinuteStride(schedule) {
|
|
1545
|
+
if (schedule.shapes.minute !== "list") {
|
|
1404
1546
|
return false;
|
|
1405
1547
|
}
|
|
1406
|
-
const values = singleValues(
|
|
1548
|
+
const values = singleValues(segmentsOf(schedule, "minute"));
|
|
1407
1549
|
return values !== null && arithmeticStep(values) !== null;
|
|
1408
1550
|
}
|
|
1409
|
-
function confinementEligible(
|
|
1410
|
-
const { minute, hour } =
|
|
1551
|
+
function confinementEligible(schedule, lead) {
|
|
1552
|
+
const { minute, hour } = schedule.pattern;
|
|
1411
1553
|
const minuteStep = isCadenceField(minute) && minute !== "*";
|
|
1412
|
-
if (!confinableHour(
|
|
1554
|
+
if (!confinableHour(schedule)) {
|
|
1413
1555
|
return false;
|
|
1414
1556
|
}
|
|
1415
1557
|
if (lead.secondLead) {
|
|
1416
1558
|
if (minuteStep) {
|
|
1417
|
-
return minute === "*/2" &&
|
|
1559
|
+
return minute === "*/2" && schedule.shapes.hour !== "range";
|
|
1418
1560
|
}
|
|
1419
|
-
if (isMinuteStride(
|
|
1561
|
+
if (isMinuteStride(schedule) || schedule.shapes.minute === "list" && schedule.shapes.hour === "list") {
|
|
1420
1562
|
return false;
|
|
1421
1563
|
}
|
|
1422
1564
|
return true;
|
|
@@ -1424,21 +1566,21 @@ function confinementEligible(ir, lead) {
|
|
|
1424
1566
|
if (hour === "*/2") {
|
|
1425
1567
|
return true;
|
|
1426
1568
|
}
|
|
1427
|
-
return
|
|
1569
|
+
return schedule.shapes.hour === "single" && minute === "*/2";
|
|
1428
1570
|
}
|
|
1429
|
-
function confinement(
|
|
1571
|
+
function confinement(schedule, opts) {
|
|
1430
1572
|
if (!opts.style.untilWindow || opts.short) {
|
|
1431
1573
|
return null;
|
|
1432
1574
|
}
|
|
1433
|
-
if (
|
|
1575
|
+
if (schedule.pattern.minute === "*" && schedule.pattern.hour === "*") {
|
|
1434
1576
|
return null;
|
|
1435
1577
|
}
|
|
1436
|
-
const lead = leadingCadence(
|
|
1437
|
-
if (!lead || !confinementEligible(
|
|
1578
|
+
const lead = leadingCadence(schedule, opts);
|
|
1579
|
+
if (!lead || !confinementEligible(schedule, lead)) {
|
|
1438
1580
|
return null;
|
|
1439
1581
|
}
|
|
1440
|
-
const minutePart = lead.secondLead ? minuteConfinement(
|
|
1441
|
-
return lead.text + minutePart + hourConfinement(
|
|
1582
|
+
const minutePart = lead.secondLead ? minuteConfinement(schedule, opts) : "";
|
|
1583
|
+
return lead.text + minutePart + hourConfinement(schedule, opts) + trailingQualifier(schedule, opts);
|
|
1442
1584
|
}
|
|
1443
1585
|
var renderers = {
|
|
1444
1586
|
clockTimes: renderClockTimes,
|
|
@@ -1460,33 +1602,25 @@ var renderers = {
|
|
|
1460
1602
|
singleMinute: renderSingleMinute,
|
|
1461
1603
|
standaloneSeconds: renderStandaloneSeconds
|
|
1462
1604
|
};
|
|
1463
|
-
function
|
|
1605
|
+
function renderStride2(stride, opts) {
|
|
1464
1606
|
const { interval, start, last, cycle, unit, anchor } = stride;
|
|
1465
1607
|
const cadence = "every " + getNumber(interval, opts) + " " + unit + "s";
|
|
1466
|
-
|
|
1467
|
-
|
|
1468
|
-
|
|
1469
|
-
|
|
1470
|
-
|
|
1471
|
-
|
|
1472
|
-
|
|
1473
|
-
|
|
1474
|
-
|
|
1475
|
-
}
|
|
1476
|
-
function singleValues(segments) {
|
|
1477
|
-
const values = [];
|
|
1478
|
-
for (const segment of segments) {
|
|
1479
|
-
if (segment.kind !== "single") {
|
|
1480
|
-
return null;
|
|
1608
|
+
return renderStride({ start, interval, cycle }, {
|
|
1609
|
+
bare: () => cadence,
|
|
1610
|
+
// A clean wrap from a non-zero offset: name the start, no endpoint.
|
|
1611
|
+
offset: () => cadence + " from " + getNumber(start, opts) + " " + pluralize(start, unit) + " past the " + anchor,
|
|
1612
|
+
// A bounded, non-wrapping set: pin both endpoints. Each bound is a value,
|
|
1613
|
+
// so it reads as a digit, matching the range idiom ("from 0 through 30").
|
|
1614
|
+
bounded: () => {
|
|
1615
|
+
const num = seriesNumber();
|
|
1616
|
+
return cadence + " from " + num(start) + through(opts) + num(last) + " " + pluralize(last, unit) + " past the " + anchor;
|
|
1481
1617
|
}
|
|
1482
|
-
|
|
1483
|
-
}
|
|
1484
|
-
return values;
|
|
1618
|
+
});
|
|
1485
1619
|
}
|
|
1486
1620
|
function strideFromSegments(segments, unit, anchor, opts) {
|
|
1487
1621
|
const values = singleValues(segments);
|
|
1488
1622
|
const step = values && arithmeticStep(values);
|
|
1489
|
-
return step ?
|
|
1623
|
+
return step ? renderStride2({ ...step, cycle: 60, unit, anchor }, opts) : null;
|
|
1490
1624
|
}
|
|
1491
1625
|
function stepCycle60(segment, unit, anchor, opts) {
|
|
1492
1626
|
if (segment.startToken.indexOf("-") !== -1) {
|
|
@@ -1496,7 +1630,7 @@ function stepCycle60(segment, unit, anchor, opts) {
|
|
|
1496
1630
|
if (start !== 0 && segment.fires.length <= 3) {
|
|
1497
1631
|
return listPastThe(numberWords(segment.fires, opts), unit, anchor, opts);
|
|
1498
1632
|
}
|
|
1499
|
-
return
|
|
1633
|
+
return renderStride2({
|
|
1500
1634
|
interval: segment.interval,
|
|
1501
1635
|
start,
|
|
1502
1636
|
last: segment.fires[segment.fires.length - 1],
|
|
@@ -1522,45 +1656,21 @@ function stepHours(segment, opts) {
|
|
|
1522
1656
|
function hourStrideCadence(stride, opts) {
|
|
1523
1657
|
const { start, interval, last } = stride;
|
|
1524
1658
|
const cadence = "every " + getNumber(interval, opts) + " hours";
|
|
1525
|
-
|
|
1526
|
-
|
|
1527
|
-
|
|
1528
|
-
|
|
1529
|
-
|
|
1530
|
-
return cadence + " from " + getTime({ hour: start, minute: 0 }, opts);
|
|
1531
|
-
}
|
|
1532
|
-
return cadence + " from " + getTime({ hour: start, minute: 0 }, opts) + through(opts) + getTime({ hour: last, minute: 0 }, opts);
|
|
1533
|
-
}
|
|
1534
|
-
function offsetCleanStride(stride) {
|
|
1535
|
-
return stride.start < stride.interval && 24 % stride.interval === 0;
|
|
1659
|
+
return renderStride({ start, interval, cycle: 24 }, {
|
|
1660
|
+
bare: () => cadence,
|
|
1661
|
+
offset: () => cadence + " from " + getTime({ hour: start, minute: 0 }, opts),
|
|
1662
|
+
bounded: () => cadence + " from " + getTime({ hour: start, minute: 0 }, opts) + through(opts) + getTime({ hour: last, minute: 0 }, opts)
|
|
1663
|
+
});
|
|
1536
1664
|
}
|
|
1537
|
-
function unevenHourCadence(
|
|
1538
|
-
const stride = hourStride(
|
|
1665
|
+
function unevenHourCadence(schedule, opts) {
|
|
1666
|
+
const stride = hourStride(schedule);
|
|
1539
1667
|
if (!stride || offsetCleanStride(stride)) {
|
|
1540
1668
|
return null;
|
|
1541
1669
|
}
|
|
1542
1670
|
return hourStrideCadence(stride, opts);
|
|
1543
1671
|
}
|
|
1544
|
-
function
|
|
1545
|
-
|
|
1546
|
-
return null;
|
|
1547
|
-
}
|
|
1548
|
-
const interval = values[1] - values[0];
|
|
1549
|
-
if (interval < 2) {
|
|
1550
|
-
return null;
|
|
1551
|
-
}
|
|
1552
|
-
for (let i = 2; i < values.length; i += 1) {
|
|
1553
|
-
if (values[i] - values[i - 1] !== interval) {
|
|
1554
|
-
return null;
|
|
1555
|
-
}
|
|
1556
|
-
}
|
|
1557
|
-
if (values[0] !== 0 && values.length < 5) {
|
|
1558
|
-
return null;
|
|
1559
|
-
}
|
|
1560
|
-
return { interval, last: values[values.length - 1], start: values[0] };
|
|
1561
|
-
}
|
|
1562
|
-
function hourStride(ir) {
|
|
1563
|
-
const segments = ir.analyses.segments.hour;
|
|
1672
|
+
function hourStride(schedule) {
|
|
1673
|
+
const segments = segmentsOf(schedule, "hour");
|
|
1564
1674
|
if (segments.length === 1 && segments[0].kind === "step") {
|
|
1565
1675
|
const segment = segments[0];
|
|
1566
1676
|
if (segment.fires.length < 2) {
|
|
@@ -1572,83 +1682,83 @@ function hourStride(ir) {
|
|
|
1572
1682
|
const values = singleValues(segments);
|
|
1573
1683
|
return values && hourListStride(values);
|
|
1574
1684
|
}
|
|
1575
|
-
function subMinuteSecond(
|
|
1576
|
-
return
|
|
1685
|
+
function subMinuteSecond(schedule) {
|
|
1686
|
+
return schedule.pattern.second === "*" || schedule.shapes.second === "step";
|
|
1577
1687
|
}
|
|
1578
|
-
function hourCadenceLead(
|
|
1688
|
+
function hourCadenceLead(schedule, minute, opts) {
|
|
1579
1689
|
if (minute === 0) {
|
|
1580
|
-
if (subMinuteSecond(
|
|
1581
|
-
return secondsClause(
|
|
1690
|
+
if (subMinuteSecond(schedule)) {
|
|
1691
|
+
return secondsClause(schedule, "minute", opts) + " for one minute";
|
|
1582
1692
|
}
|
|
1583
|
-
return secondsClause(
|
|
1693
|
+
return secondsClause(schedule, "hour", opts);
|
|
1584
1694
|
}
|
|
1585
1695
|
const minutePhrase = getNumber(minute, opts) + " " + pluralize(minute, "minute") + " past the hour";
|
|
1586
|
-
if (
|
|
1696
|
+
if (schedule.pattern.second === "0") {
|
|
1587
1697
|
return minutePhrase;
|
|
1588
1698
|
}
|
|
1589
|
-
return secondsClause(
|
|
1699
|
+
return secondsClause(schedule, "minute", opts) + ", " + minutePhrase;
|
|
1590
1700
|
}
|
|
1591
|
-
function hourCadence(
|
|
1592
|
-
const stride = hourStride(
|
|
1701
|
+
function hourCadence(schedule, minute, opts) {
|
|
1702
|
+
const stride = hourStride(schedule);
|
|
1593
1703
|
if (!stride) {
|
|
1594
1704
|
return null;
|
|
1595
1705
|
}
|
|
1596
1706
|
const fires = (stride.last - stride.start) / stride.interval + 1;
|
|
1597
|
-
if (
|
|
1707
|
+
if (schedule.pattern.second === "0" && fires <= maxClockTimes && offsetCleanStride(stride)) {
|
|
1598
1708
|
return null;
|
|
1599
1709
|
}
|
|
1600
|
-
const minuteZeroStride = minute === 0 && subMinuteSecond(
|
|
1710
|
+
const minuteZeroStride = minute === 0 && subMinuteSecond(schedule) && cleanStrideSegment(schedule);
|
|
1601
1711
|
if (minuteZeroStride) {
|
|
1602
|
-
return secondsClause(
|
|
1712
|
+
return secondsClause(schedule, "minute", opts) + " for one minute " + everyNthHour(minuteZeroStride, opts) + trailingQualifier(schedule, opts);
|
|
1603
1713
|
}
|
|
1604
|
-
if (minute === 0 &&
|
|
1605
|
-
return hourStrideCadence(stride, opts) + trailingQualifier(
|
|
1714
|
+
if (minute === 0 && schedule.pattern.second === "0") {
|
|
1715
|
+
return hourStrideCadence(stride, opts) + trailingQualifier(schedule, opts);
|
|
1606
1716
|
}
|
|
1607
|
-
return hourCadenceLead(
|
|
1717
|
+
return hourCadenceLead(schedule, minute, opts) + ", " + hourStrideCadence(stride, opts) + trailingQualifier(schedule, opts);
|
|
1608
1718
|
}
|
|
1609
|
-
function cleanStrideSegment(
|
|
1610
|
-
const segments =
|
|
1719
|
+
function cleanStrideSegment(schedule) {
|
|
1720
|
+
const segments = segmentsOf(schedule, "hour");
|
|
1611
1721
|
const segment = segments.length === 1 && segments[0];
|
|
1612
1722
|
if (!segment || segment.kind !== "step" || segment.startToken.indexOf("-") !== -1 || !(segment.interval in stepOrdinals)) {
|
|
1613
1723
|
return null;
|
|
1614
1724
|
}
|
|
1615
1725
|
return segment;
|
|
1616
1726
|
}
|
|
1617
|
-
function hasHourWindow(
|
|
1618
|
-
return
|
|
1727
|
+
function hasHourWindow(schedule) {
|
|
1728
|
+
return segmentsOf(schedule, "hour").some(function range(segment) {
|
|
1619
1729
|
return segment.kind === "range";
|
|
1620
1730
|
});
|
|
1621
1731
|
}
|
|
1622
|
-
function hourRangeWindowTail(
|
|
1732
|
+
function hourRangeWindowTail(schedule, opts) {
|
|
1623
1733
|
const windows = [];
|
|
1624
|
-
const
|
|
1625
|
-
|
|
1734
|
+
const outlierHours = collectHourOutliers(schedule);
|
|
1735
|
+
segmentsOf(schedule, "hour").forEach(function classify(segment) {
|
|
1626
1736
|
if (segment.kind === "range") {
|
|
1627
|
-
windows.push(rangeWindow(
|
|
1628
|
-
|
|
1629
|
-
+segment.bounds[
|
|
1630
|
-
0,
|
|
1631
|
-
|
|
1632
|
-
));
|
|
1737
|
+
windows.push(rangeWindow({
|
|
1738
|
+
continuous: false,
|
|
1739
|
+
from: +segment.bounds[0],
|
|
1740
|
+
throughMinute: 0,
|
|
1741
|
+
to: +segment.bounds[1]
|
|
1742
|
+
}, opts));
|
|
1633
1743
|
}
|
|
1634
1744
|
});
|
|
1635
1745
|
const phrase = "every hour " + joinList(windows, opts);
|
|
1636
|
-
const times =
|
|
1746
|
+
const times = outlierHours.map(function time(hour) {
|
|
1637
1747
|
return getTime({ hour, minute: 0 }, opts);
|
|
1638
1748
|
});
|
|
1639
|
-
return phrase + outlierTail(times,
|
|
1749
|
+
return phrase + outlierTail(times, opts);
|
|
1640
1750
|
}
|
|
1641
|
-
function hourRangeCadence(
|
|
1642
|
-
if (minute !== 0 || !hasHourWindow(
|
|
1751
|
+
function hourRangeCadence(schedule, minute, opts) {
|
|
1752
|
+
if (minute !== 0 || !hasHourWindow(schedule)) {
|
|
1643
1753
|
return null;
|
|
1644
1754
|
}
|
|
1645
|
-
if (
|
|
1755
|
+
if (schedule.pattern.second === "0") {
|
|
1646
1756
|
return null;
|
|
1647
1757
|
}
|
|
1648
|
-
if (subMinuteSecond(
|
|
1649
|
-
return secondsClause(
|
|
1758
|
+
if (subMinuteSecond(schedule)) {
|
|
1759
|
+
return secondsClause(schedule, "minute", opts) + " for one minute during the " + hourSegmentTimes(schedule, { minute: 0, second: null }, false, opts) + " hours" + trailingQualifier(schedule, opts);
|
|
1650
1760
|
}
|
|
1651
|
-
return hourCadenceLead(
|
|
1761
|
+
return hourCadenceLead(schedule, minute, opts) + ", " + hourRangeWindowTail(schedule, opts) + trailingQualifier(schedule, opts);
|
|
1652
1762
|
}
|
|
1653
1763
|
function seriesNumber() {
|
|
1654
1764
|
return function format(n) {
|
|
@@ -1707,11 +1817,11 @@ function hourTimes(hours, opts) {
|
|
|
1707
1817
|
function singleHourFire(times) {
|
|
1708
1818
|
return times.kind === "fires" && times.fires.length === 1;
|
|
1709
1819
|
}
|
|
1710
|
-
function hourTimesFromPlan(
|
|
1820
|
+
function hourTimesFromPlan(schedule, times, atContext, opts) {
|
|
1711
1821
|
if (times.kind === "fires") {
|
|
1712
1822
|
return hourTimes(times.fires, opts);
|
|
1713
1823
|
}
|
|
1714
|
-
return hourSegmentTimes(
|
|
1824
|
+
return hourSegmentTimes(schedule, { minute: 0, second: null }, atContext, opts);
|
|
1715
1825
|
}
|
|
1716
1826
|
function segmentHours(segment) {
|
|
1717
1827
|
if (segment.kind === "range") {
|
|
@@ -1719,9 +1829,9 @@ function segmentHours(segment) {
|
|
|
1719
1829
|
}
|
|
1720
1830
|
return segment.kind === "step" ? segment.fires : [segment.value];
|
|
1721
1831
|
}
|
|
1722
|
-
function hourSegmentTimes(
|
|
1832
|
+
function hourSegmentTimes(schedule, fold, atContext, opts) {
|
|
1723
1833
|
const { minute, second } = fold;
|
|
1724
|
-
const segments =
|
|
1834
|
+
const segments = segmentsOf(schedule, "hour");
|
|
1725
1835
|
const plain = mixedTwelve(segments.flatMap(function entries(segment) {
|
|
1726
1836
|
return segmentHours(segment).map(function entry(hour) {
|
|
1727
1837
|
return { hour: +hour, minute, second };
|
|
@@ -1784,85 +1894,85 @@ var leadingWords = {
|
|
|
1784
1894
|
stepDate: "",
|
|
1785
1895
|
weekday: "every "
|
|
1786
1896
|
};
|
|
1787
|
-
function trailingQualifier(
|
|
1788
|
-
if (isDayUnion(
|
|
1789
|
-
return dayUnionCondition(
|
|
1897
|
+
function trailingQualifier(schedule, opts) {
|
|
1898
|
+
if (isDayUnion(schedule, opts)) {
|
|
1899
|
+
return dayUnionCondition(schedule, opts);
|
|
1790
1900
|
}
|
|
1791
|
-
const phrase = dayQualifier(
|
|
1901
|
+
const phrase = dayQualifier(schedule, trailingWords, opts);
|
|
1792
1902
|
return phrase && " " + phrase;
|
|
1793
1903
|
}
|
|
1794
|
-
function interpretDayQualifier(
|
|
1795
|
-
if (isDayUnion(
|
|
1904
|
+
function interpretDayQualifier(schedule, opts) {
|
|
1905
|
+
if (isDayUnion(schedule, opts)) {
|
|
1796
1906
|
return "";
|
|
1797
1907
|
}
|
|
1798
|
-
return dayQualifier(
|
|
1908
|
+
return dayQualifier(schedule, leadingWords, opts) + " ";
|
|
1799
1909
|
}
|
|
1800
|
-
function dayQualifier(
|
|
1801
|
-
const pattern =
|
|
1910
|
+
function dayQualifier(schedule, words, opts) {
|
|
1911
|
+
const pattern = schedule.pattern;
|
|
1802
1912
|
if (pattern.date !== "*" && pattern.weekday !== "*") {
|
|
1803
|
-
return dateOrWeekday(
|
|
1913
|
+
return dateOrWeekday(schedule, opts);
|
|
1804
1914
|
}
|
|
1805
1915
|
if (pattern.date !== "*") {
|
|
1806
|
-
return datePhrase(
|
|
1916
|
+
return datePhrase(schedule, words, opts);
|
|
1807
1917
|
}
|
|
1808
1918
|
if (pattern.weekday !== "*") {
|
|
1809
1919
|
const quartzWeekday = quartzWeekdayPhrase(pattern.weekday, opts);
|
|
1810
1920
|
if (quartzWeekday) {
|
|
1811
|
-
return monthScopeForRecurrence(quartzWeekday,
|
|
1921
|
+
return monthScopeForRecurrence(quartzWeekday, schedule, opts);
|
|
1812
1922
|
}
|
|
1813
|
-
const weekdays = words.weekday + weekdayPhrase(
|
|
1814
|
-
return weekdays + monthScope(
|
|
1923
|
+
const weekdays = words.weekday + weekdayPhrase(schedule, words.recurringWeekday, opts);
|
|
1924
|
+
return weekdays + monthScope(schedule, opts);
|
|
1815
1925
|
}
|
|
1816
1926
|
if (pattern.month !== "*") {
|
|
1817
|
-
return words.month + monthName(
|
|
1927
|
+
return words.month + monthName(schedule, opts);
|
|
1818
1928
|
}
|
|
1819
1929
|
return words.all;
|
|
1820
1930
|
}
|
|
1821
|
-
function datePhrase(
|
|
1822
|
-
const pattern =
|
|
1931
|
+
function datePhrase(schedule, words, opts) {
|
|
1932
|
+
const pattern = schedule.pattern;
|
|
1823
1933
|
const quartzDate = quartzDatePhrase(pattern.date, opts);
|
|
1824
1934
|
if (quartzDate) {
|
|
1825
|
-
return monthScopeForRecurrence(quartzDate,
|
|
1935
|
+
return monthScopeForRecurrence(quartzDate, schedule, opts);
|
|
1826
1936
|
}
|
|
1827
1937
|
if (isOpenStep(pattern.date)) {
|
|
1828
1938
|
return monthScopeForRecurrence(
|
|
1829
1939
|
words.stepDate + stepDates(pattern.date),
|
|
1830
|
-
|
|
1940
|
+
schedule,
|
|
1831
1941
|
opts
|
|
1832
1942
|
);
|
|
1833
1943
|
}
|
|
1834
|
-
if (pattern.month !== "*" && !monthFoldsIntoDate(
|
|
1835
|
-
return "on the " + dateOrdinals(
|
|
1944
|
+
if (pattern.month !== "*" && !monthFoldsIntoDate(schedule)) {
|
|
1945
|
+
return "on the " + dateOrdinals(schedule, opts) + monthScope(schedule, opts);
|
|
1836
1946
|
}
|
|
1837
1947
|
if (pattern.month !== "*") {
|
|
1838
|
-
return "on " + monthDatePhrase(
|
|
1948
|
+
return "on " + monthDatePhrase(schedule, opts);
|
|
1839
1949
|
}
|
|
1840
|
-
return "on the " + dateOrdinals(
|
|
1950
|
+
return "on the " + dateOrdinals(schedule, opts);
|
|
1841
1951
|
}
|
|
1842
|
-
function monthFoldsIntoDate(
|
|
1843
|
-
return !oddEvenMonth(
|
|
1844
|
-
|
|
1952
|
+
function monthFoldsIntoDate(schedule) {
|
|
1953
|
+
return !oddEvenMonth(schedule.pattern.month) && // Reached only with a restricted month, which has segments.
|
|
1954
|
+
segmentsOf(schedule, "month").every(function flat(segment) {
|
|
1845
1955
|
return segment.kind !== "range";
|
|
1846
1956
|
});
|
|
1847
1957
|
}
|
|
1848
|
-
function isDayUnion(
|
|
1849
|
-
return
|
|
1958
|
+
function isDayUnion(schedule, opts) {
|
|
1959
|
+
return schedule.pattern.date !== "*" && schedule.pattern.weekday !== "*" && !!opts.style.untilWindow && !opts.short;
|
|
1850
1960
|
}
|
|
1851
|
-
function dayUnionCondition(
|
|
1961
|
+
function dayUnionCondition(schedule, opts) {
|
|
1852
1962
|
const pieces = [
|
|
1853
|
-
...dayUnionDatePieces(
|
|
1854
|
-
...dayUnionWeekdayPieces(
|
|
1963
|
+
...dayUnionDatePieces(schedule, opts),
|
|
1964
|
+
...dayUnionWeekdayPieces(schedule, opts)
|
|
1855
1965
|
];
|
|
1856
1966
|
return " whenever the day is " + joinOr(pieces, opts);
|
|
1857
1967
|
}
|
|
1858
|
-
function dayUnionMonthLead(
|
|
1859
|
-
if (
|
|
1968
|
+
function dayUnionMonthLead(schedule, opts) {
|
|
1969
|
+
if (schedule.pattern.month === "*") {
|
|
1860
1970
|
return "";
|
|
1861
1971
|
}
|
|
1862
|
-
return "in " + monthName(
|
|
1972
|
+
return "in " + monthName(schedule, opts) + " ";
|
|
1863
1973
|
}
|
|
1864
|
-
function dayUnionDatePieces(
|
|
1865
|
-
const dateField =
|
|
1974
|
+
function dayUnionDatePieces(schedule, opts) {
|
|
1975
|
+
const dateField = schedule.pattern.date;
|
|
1866
1976
|
const quartz = quartzDatePhrase(dateField, opts);
|
|
1867
1977
|
if (quartz) {
|
|
1868
1978
|
return [quartz.replace(/^on /, "")];
|
|
@@ -1872,7 +1982,7 @@ function dayUnionDatePieces(ir, opts) {
|
|
|
1872
1982
|
return [oddEven];
|
|
1873
1983
|
}
|
|
1874
1984
|
const pieces = [];
|
|
1875
|
-
|
|
1985
|
+
segmentsOf(schedule, "date").forEach(function expand(segment) {
|
|
1876
1986
|
if (segment.kind === "range") {
|
|
1877
1987
|
pieces.push("from the " + getOrdinal(segment.bounds[0]) + through(opts) + "the " + getOrdinal(segment.bounds[1]));
|
|
1878
1988
|
} else if (segment.kind === "step") {
|
|
@@ -1885,14 +1995,14 @@ function dayUnionDatePieces(ir, opts) {
|
|
|
1885
1995
|
});
|
|
1886
1996
|
return pieces;
|
|
1887
1997
|
}
|
|
1888
|
-
function dayUnionWeekdayPieces(
|
|
1889
|
-
const weekdayField =
|
|
1998
|
+
function dayUnionWeekdayPieces(schedule, opts) {
|
|
1999
|
+
const weekdayField = schedule.pattern.weekday;
|
|
1890
2000
|
const quartz = quartzWeekdayPhrase(weekdayField, opts);
|
|
1891
2001
|
if (quartz) {
|
|
1892
2002
|
return [quartz.replace(/^on /, "")];
|
|
1893
2003
|
}
|
|
1894
2004
|
const pieces = [];
|
|
1895
|
-
|
|
2005
|
+
segmentsOf(schedule, "weekday").forEach(function expand(segment) {
|
|
1896
2006
|
if (segment.kind === "range" && segment.bounds[0] === "1" && segment.bounds[1] === "5") {
|
|
1897
2007
|
pieces.push("a weekday");
|
|
1898
2008
|
} else if (segment.kind === "range") {
|
|
@@ -1920,16 +2030,16 @@ function oddEvenDay(dateField) {
|
|
|
1920
2030
|
}
|
|
1921
2031
|
return start === "2" ? "an even-numbered day" : null;
|
|
1922
2032
|
}
|
|
1923
|
-
function dateOrWeekday(
|
|
1924
|
-
const pattern =
|
|
1925
|
-
const weekdayPart = quartzWeekdayPhrase(pattern.weekday, opts) || "on " + weekdayPhrase(
|
|
1926
|
-
if (pattern.month !== "*" && monthFoldsIntoDate(
|
|
1927
|
-
return "on " + monthDatePhrase(
|
|
2033
|
+
function dateOrWeekday(schedule, opts) {
|
|
2034
|
+
const pattern = schedule.pattern;
|
|
2035
|
+
const weekdayPart = quartzWeekdayPhrase(pattern.weekday, opts) || "on " + weekdayPhrase(schedule, false, opts);
|
|
2036
|
+
if (pattern.month !== "*" && monthFoldsIntoDate(schedule) && !quartzDatePhrase(pattern.date, opts) && !isOpenStep(pattern.date)) {
|
|
2037
|
+
return "on " + monthDatePhrase(schedule, opts) + " or " + weekdayPart + " in " + monthName(schedule, opts);
|
|
1928
2038
|
}
|
|
1929
|
-
return datePart(
|
|
2039
|
+
return datePart(schedule, opts) + " or " + weekdayPart + orMonthScope(schedule, opts);
|
|
1930
2040
|
}
|
|
1931
|
-
function datePart(
|
|
1932
|
-
const pattern =
|
|
2041
|
+
function datePart(schedule, opts) {
|
|
2042
|
+
const pattern = schedule.pattern;
|
|
1933
2043
|
const quartzDate = quartzDatePhrase(pattern.date, opts);
|
|
1934
2044
|
if (quartzDate) {
|
|
1935
2045
|
return quartzDate;
|
|
@@ -1937,13 +2047,13 @@ function datePart(ir, opts) {
|
|
|
1937
2047
|
if (isOpenStep(pattern.date)) {
|
|
1938
2048
|
return stepDates(pattern.date);
|
|
1939
2049
|
}
|
|
1940
|
-
return "on the " + dateOrdinals(
|
|
2050
|
+
return "on the " + dateOrdinals(schedule, opts);
|
|
1941
2051
|
}
|
|
1942
|
-
function orMonthScope(
|
|
1943
|
-
if (
|
|
2052
|
+
function orMonthScope(schedule, opts) {
|
|
2053
|
+
if (schedule.pattern.month === "*") {
|
|
1944
2054
|
return "";
|
|
1945
2055
|
}
|
|
1946
|
-
return ", in " + monthName(
|
|
2056
|
+
return ", in " + monthName(schedule, opts);
|
|
1947
2057
|
}
|
|
1948
2058
|
function quartzDatePhrase(dateField, opts) {
|
|
1949
2059
|
if (dateField === "L") {
|
|
@@ -1970,39 +2080,39 @@ function quartzWeekdayPhrase(weekdayField, opts) {
|
|
|
1970
2080
|
return "on the last " + getWeekday(weekdayField.slice(0, -1), opts) + " of the month";
|
|
1971
2081
|
}
|
|
1972
2082
|
}
|
|
1973
|
-
function monthDatePhrase(
|
|
1974
|
-
const month = monthName(
|
|
2083
|
+
function monthDatePhrase(schedule, opts) {
|
|
2084
|
+
const month = monthName(schedule, opts);
|
|
1975
2085
|
const days = renderSegments(
|
|
1976
|
-
|
|
2086
|
+
segmentsOf(schedule, "date"),
|
|
1977
2087
|
opts.style.ordinals ? getOrdinal : cardinalDay,
|
|
1978
2088
|
opts
|
|
1979
2089
|
);
|
|
1980
|
-
if (opts.style.dayFirst &&
|
|
1981
|
-
return "the " + getOrdinal(
|
|
2090
|
+
if (opts.style.dayFirst && schedule.shapes.date === "single" && schedule.shapes.month !== "single") {
|
|
2091
|
+
return "the " + getOrdinal(schedule.pattern.date) + " of " + month;
|
|
1982
2092
|
}
|
|
1983
2093
|
return opts.style.dayFirst ? days + " " + month : month + " " + days;
|
|
1984
2094
|
}
|
|
1985
2095
|
function cardinalDay(value) {
|
|
1986
2096
|
return "" + value;
|
|
1987
2097
|
}
|
|
1988
|
-
function monthScope(
|
|
1989
|
-
if (
|
|
2098
|
+
function monthScope(schedule, opts) {
|
|
2099
|
+
if (schedule.pattern.month === "*") {
|
|
1990
2100
|
return "";
|
|
1991
2101
|
}
|
|
1992
|
-
return " in " + monthName(
|
|
2102
|
+
return " in " + monthName(schedule, opts);
|
|
1993
2103
|
}
|
|
1994
|
-
function monthScopeForRecurrence(phrase,
|
|
1995
|
-
if (
|
|
2104
|
+
function monthScopeForRecurrence(phrase, schedule, opts) {
|
|
2105
|
+
if (schedule.pattern.month === "*") {
|
|
1996
2106
|
return phrase;
|
|
1997
2107
|
}
|
|
1998
2108
|
const carriesRecurrence = phrase.indexOf(" of the month") !== -1;
|
|
1999
|
-
if (carriesRecurrence &&
|
|
2000
|
-
return phrase.replace(" of the month", " of each month") + " from " + monthName(
|
|
2109
|
+
if (carriesRecurrence && schedule.shapes.month === "range") {
|
|
2110
|
+
return phrase.replace(" of the month", " of each month") + " from " + monthName(schedule, opts);
|
|
2001
2111
|
}
|
|
2002
|
-
if (carriesRecurrence && (
|
|
2003
|
-
return phrase.replace(" of the month", "") + " in " + monthName(
|
|
2112
|
+
if (carriesRecurrence && (schedule.shapes.month === "single" || schedule.shapes.month === "step")) {
|
|
2113
|
+
return phrase.replace(" of the month", "") + " in " + monthName(schedule, opts);
|
|
2004
2114
|
}
|
|
2005
|
-
return phrase + " in " + monthName(
|
|
2115
|
+
return phrase + " in " + monthName(schedule, opts);
|
|
2006
2116
|
}
|
|
2007
2117
|
function stepDates(dateField) {
|
|
2008
2118
|
const parts = dateField.split("/");
|
|
@@ -2015,15 +2125,15 @@ function stepDates(dateField) {
|
|
|
2015
2125
|
}
|
|
2016
2126
|
return phrase;
|
|
2017
2127
|
}
|
|
2018
|
-
function dateOrdinals(
|
|
2019
|
-
return renderSegments(
|
|
2128
|
+
function dateOrdinals(schedule, opts) {
|
|
2129
|
+
return renderSegments(segmentsOf(schedule, "date"), getOrdinal, opts);
|
|
2020
2130
|
}
|
|
2021
|
-
function monthName(
|
|
2022
|
-
const oddEven = oddEvenMonth(
|
|
2131
|
+
function monthName(schedule, opts) {
|
|
2132
|
+
const oddEven = oddEvenMonth(schedule.pattern.month);
|
|
2023
2133
|
if (oddEven) {
|
|
2024
2134
|
return oddEven;
|
|
2025
2135
|
}
|
|
2026
|
-
return renderSegments(
|
|
2136
|
+
return renderSegments(segmentsOf(schedule, "month"), function name(value) {
|
|
2027
2137
|
return getMonth(value, opts);
|
|
2028
2138
|
}, opts);
|
|
2029
2139
|
}
|
|
@@ -2040,8 +2150,8 @@ function oddEvenMonth(monthField) {
|
|
|
2040
2150
|
}
|
|
2041
2151
|
return start === "2" ? "every even-numbered month" : null;
|
|
2042
2152
|
}
|
|
2043
|
-
function weekdayPhrase(
|
|
2044
|
-
const segments = orderWeekdaysForDisplay(
|
|
2153
|
+
function weekdayPhrase(schedule, recurring, opts) {
|
|
2154
|
+
const segments = orderWeekdaysForDisplay(segmentsOf(schedule, "weekday"));
|
|
2045
2155
|
const hasRange = segments.some(function range(segment) {
|
|
2046
2156
|
return segment.kind === "range";
|
|
2047
2157
|
});
|
|
@@ -2069,11 +2179,8 @@ function renderSegments(segments, word, opts) {
|
|
|
2069
2179
|
});
|
|
2070
2180
|
return joinList(pieces, opts);
|
|
2071
2181
|
}
|
|
2072
|
-
function
|
|
2073
|
-
|
|
2074
|
-
}
|
|
2075
|
-
function applyYear(description, ir, opts) {
|
|
2076
|
-
const yearField = ir.pattern.year;
|
|
2182
|
+
function applyYear(description, schedule, opts) {
|
|
2183
|
+
const yearField = schedule.pattern.year;
|
|
2077
2184
|
if (yearField === "*") {
|
|
2078
2185
|
return description;
|
|
2079
2186
|
}
|
|
@@ -2081,7 +2188,7 @@ function applyYear(description, ir, opts) {
|
|
|
2081
2188
|
return description + ", " + stepYears(yearField, opts);
|
|
2082
2189
|
}
|
|
2083
2190
|
const label = yearLabel(yearField, opts);
|
|
2084
|
-
if (yearField.indexOf("-") === -1 && yearField.indexOf(",") === -1 &&
|
|
2191
|
+
if (yearField.indexOf("-") === -1 && yearField.indexOf(",") === -1 && schedule.pattern.date !== "*" && description.indexOf(" at ") !== -1) {
|
|
2085
2192
|
const yearGlue = opts.style.dayFirst ? " " : ", ";
|
|
2086
2193
|
return description.replace(" at ", yearGlue + label + " at ");
|
|
2087
2194
|
}
|
|
@@ -2204,9 +2311,9 @@ function interpretCronPattern(cronPattern, lang, opts) {
|
|
|
2204
2311
|
if (typeof cronPattern === "string" && cronPattern.trim().toLowerCase() === "@reboot") {
|
|
2205
2312
|
return lang.reboot;
|
|
2206
2313
|
}
|
|
2207
|
-
const
|
|
2208
|
-
const plan = lang.
|
|
2209
|
-
return lang.describe({ ...
|
|
2314
|
+
const schedule = analyze(prepare(cronPattern, opts));
|
|
2315
|
+
const plan = lang.plan ? lang.plan(schedule, schedule.plan) : schedule.plan;
|
|
2316
|
+
return lang.describe({ ...schedule, plan }, opts);
|
|
2210
2317
|
}
|
|
2211
2318
|
var cronli5_default = cronli5;
|
|
2212
2319
|
/**
|