cronli5 0.1.7 → 0.2.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 +68 -0
- package/README.md +2 -2
- package/cronli5.min.js +2 -2
- package/dist/cronli5.cjs +451 -144
- package/dist/cronli5.js +451 -144
- package/dist/lang/de.cjs +65 -65
- package/dist/lang/de.js +65 -65
- package/dist/lang/en.cjs +450 -141
- package/dist/lang/en.js +450 -141
- package/dist/lang/es.cjs +71 -72
- package/dist/lang/es.js +71 -72
- package/dist/lang/fi.cjs +71 -66
- package/dist/lang/fi.js +71 -66
- package/dist/lang/zh.cjs +36 -36
- package/dist/lang/zh.js +36 -36
- package/package.json +1 -1
- package/src/core/analyze.ts +14 -13
- package/src/core/ir.ts +13 -8
- package/src/core/shapes.ts +8 -1
- package/src/core/util.ts +86 -3
- package/src/core/validate.ts +1 -1
- package/src/cronli5.ts +3 -3
- package/src/lang/de/index.ts +30 -99
- package/src/lang/en/dialects.ts +6 -2
- package/src/lang/en/index.ts +820 -212
- package/src/lang/es/index.ts +36 -120
- package/src/lang/fi/index.ts +33 -104
- package/src/lang/zh/index.ts +23 -48
- package/src/types.ts +2 -2
- package/types/core/analyze.d.ts +2 -2
- package/types/core/ir.d.ts +8 -7
- package/types/core/shapes.d.ts +2 -1
- package/types/core/util.d.ts +17 -2
- package/types/types.d.ts +1 -1
package/dist/cronli5.js
CHANGED
|
@@ -107,6 +107,43 @@ function orderWeekdaysForDisplay(segments) {
|
|
|
107
107
|
function toFieldNumber(token, numberMap) {
|
|
108
108
|
return isNonNegativeInteger(token) ? +token : numberMap[token.toUpperCase()];
|
|
109
109
|
}
|
|
110
|
+
function segmentsOf(ir, field) {
|
|
111
|
+
return ir.analyses.segments[field] ?? [];
|
|
112
|
+
}
|
|
113
|
+
function stepSegment(ir, field) {
|
|
114
|
+
return segmentsOf(ir, field)[0];
|
|
115
|
+
}
|
|
116
|
+
function singleValues(segments) {
|
|
117
|
+
const values = [];
|
|
118
|
+
for (const segment of segments) {
|
|
119
|
+
if (segment.kind !== "single") {
|
|
120
|
+
return null;
|
|
121
|
+
}
|
|
122
|
+
values.push(+segment.value);
|
|
123
|
+
}
|
|
124
|
+
return values;
|
|
125
|
+
}
|
|
126
|
+
function offsetCleanStride(stride) {
|
|
127
|
+
return stride.start < stride.interval && 24 % stride.interval === 0;
|
|
128
|
+
}
|
|
129
|
+
function hourListStride(values) {
|
|
130
|
+
if (values.length < 2) {
|
|
131
|
+
return null;
|
|
132
|
+
}
|
|
133
|
+
const interval = values[1] - values[0];
|
|
134
|
+
if (interval < 2) {
|
|
135
|
+
return null;
|
|
136
|
+
}
|
|
137
|
+
for (let i = 2; i < values.length; i += 1) {
|
|
138
|
+
if (values[i] - values[i - 1] !== interval) {
|
|
139
|
+
return null;
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
if (values[0] !== 0 && values.length < 5) {
|
|
143
|
+
return null;
|
|
144
|
+
}
|
|
145
|
+
return { interval, last: values[values.length - 1], start: values[0] };
|
|
146
|
+
}
|
|
110
147
|
|
|
111
148
|
// src/core/validate.ts
|
|
112
149
|
function validateCronPattern(cronPattern) {
|
|
@@ -455,6 +492,9 @@ function isDiscreteList(field) {
|
|
|
455
492
|
function isDiscreteHours(hourField) {
|
|
456
493
|
return hourField !== "*" && !isPlainRange(hourField) && !isPlainStep(hourField);
|
|
457
494
|
}
|
|
495
|
+
function isOpenStep(field) {
|
|
496
|
+
return field.indexOf("/") !== -1 && field.indexOf("-") === -1 && field.indexOf(",") === -1;
|
|
497
|
+
}
|
|
458
498
|
|
|
459
499
|
// src/core/analyze.ts
|
|
460
500
|
function getOccurrences(start, interval, max) {
|
|
@@ -591,9 +631,9 @@ function analyze(pattern) {
|
|
|
591
631
|
segments
|
|
592
632
|
};
|
|
593
633
|
const content = { analyses, pattern, shapes };
|
|
594
|
-
return { ...content, plan:
|
|
634
|
+
return { ...content, plan: selectPlan(content) };
|
|
595
635
|
}
|
|
596
|
-
function
|
|
636
|
+
function selectPlan(content) {
|
|
597
637
|
const { analyses, pattern, shapes } = content;
|
|
598
638
|
if (pattern.second !== "0") {
|
|
599
639
|
const seconds = planSeconds(pattern, shapes, analyses);
|
|
@@ -849,7 +889,8 @@ var dialects = {
|
|
|
849
889
|
pm: "p.m.",
|
|
850
890
|
sep: ":",
|
|
851
891
|
serialComma: true,
|
|
852
|
-
through: " through "
|
|
892
|
+
through: " through ",
|
|
893
|
+
untilWindow: true
|
|
853
894
|
},
|
|
854
895
|
house: {
|
|
855
896
|
am: "AM",
|
|
@@ -866,7 +907,7 @@ var dialects = {
|
|
|
866
907
|
};
|
|
867
908
|
function resolveDialect(dialect) {
|
|
868
909
|
if (typeof dialect === "object" && dialect !== null) {
|
|
869
|
-
return { ...dialects.us, ...dialect };
|
|
910
|
+
return { ...dialects.us, untilWindow: false, ...dialect };
|
|
870
911
|
}
|
|
871
912
|
const name = dialect === "uk" ? "gb" : dialect;
|
|
872
913
|
return dialects[name] || dialects.us;
|
|
@@ -938,7 +979,9 @@ function normalizeOptions(options) {
|
|
|
938
979
|
};
|
|
939
980
|
}
|
|
940
981
|
function describe(ir, opts) {
|
|
941
|
-
|
|
982
|
+
const body = confinement(ir, opts) ?? render(ir, ir.plan, opts);
|
|
983
|
+
const lead = isDayUnion(ir, opts) ? dayUnionMonthLead(ir, opts) : "";
|
|
984
|
+
return applyYear(lead + body, ir, opts);
|
|
942
985
|
}
|
|
943
986
|
function render(ir, plan, opts) {
|
|
944
987
|
const renderer = renderers[plan.kind];
|
|
@@ -1023,7 +1066,7 @@ function secondsClause(ir, anchor, opts) {
|
|
|
1023
1066
|
}
|
|
1024
1067
|
if (shape === "step") {
|
|
1025
1068
|
return stepCycle60(
|
|
1026
|
-
ir
|
|
1069
|
+
stepSegment(ir, "second"),
|
|
1027
1070
|
"second",
|
|
1028
1071
|
anchor,
|
|
1029
1072
|
opts
|
|
@@ -1031,19 +1074,19 @@ function secondsClause(ir, anchor, opts) {
|
|
|
1031
1074
|
}
|
|
1032
1075
|
if (shape === "range") {
|
|
1033
1076
|
const bounds = secondField.split("-");
|
|
1034
|
-
const num = seriesNumber(
|
|
1077
|
+
const num = seriesNumber();
|
|
1035
1078
|
return "every second from " + num(bounds[0]) + through(opts) + num(bounds[1]) + " past the " + anchor;
|
|
1036
1079
|
}
|
|
1037
1080
|
if (shape === "single") {
|
|
1038
1081
|
return "at " + getNumber(secondField, opts) + " " + pluralize(secondField, "second") + " past the " + anchor;
|
|
1039
1082
|
}
|
|
1040
1083
|
return strideFromSegments(
|
|
1041
|
-
ir
|
|
1084
|
+
segmentsOf(ir, "second"),
|
|
1042
1085
|
"second",
|
|
1043
1086
|
anchor,
|
|
1044
1087
|
opts
|
|
1045
1088
|
) ?? listPastThe(
|
|
1046
|
-
segmentWords(ir
|
|
1089
|
+
segmentWords(segmentsOf(ir, "second"), opts),
|
|
1047
1090
|
"second",
|
|
1048
1091
|
anchor,
|
|
1049
1092
|
opts
|
|
@@ -1060,15 +1103,15 @@ function renderRangeOfMinutes(ir, plan, opts) {
|
|
|
1060
1103
|
return minuteRangeLead(ir.pattern.minute, opts) + trailingQualifier(ir, opts);
|
|
1061
1104
|
}
|
|
1062
1105
|
function renderMultipleMinutes(ir, plan, opts) {
|
|
1063
|
-
const stride = strideFromSegments(ir
|
|
1106
|
+
const stride = strideFromSegments(segmentsOf(ir, "minute"), "minute", "hour", opts);
|
|
1064
1107
|
return (stride ?? listPastThe(segmentWords(
|
|
1065
|
-
ir
|
|
1108
|
+
segmentsOf(ir, "minute"),
|
|
1066
1109
|
opts
|
|
1067
1110
|
), "minute", "hour", opts)) + trailingQualifier(ir, opts);
|
|
1068
1111
|
}
|
|
1069
1112
|
function renderMinuteFrequency(ir, plan, opts) {
|
|
1070
1113
|
let phrase = stepCycle60(
|
|
1071
|
-
ir
|
|
1114
|
+
stepSegment(ir, "minute"),
|
|
1072
1115
|
"minute",
|
|
1073
1116
|
"hour",
|
|
1074
1117
|
opts
|
|
@@ -1077,9 +1120,14 @@ function renderMinuteFrequency(ir, plan, opts) {
|
|
|
1077
1120
|
const cadence = unevenHourCadence(ir, opts);
|
|
1078
1121
|
phrase += cadence ? ", " + cadence : " during the " + hourTimesFromPlan(ir, plan.hours.times, false, opts) + " hours";
|
|
1079
1122
|
} else if (plan.hours.kind === "window") {
|
|
1080
|
-
phrase += " " +
|
|
1123
|
+
phrase += " " + rangeWindow({
|
|
1124
|
+
continuous: false,
|
|
1125
|
+
from: plan.hours.from,
|
|
1126
|
+
throughMinute: plan.hours.last,
|
|
1127
|
+
to: plan.hours.to
|
|
1128
|
+
}, opts);
|
|
1081
1129
|
} else if (plan.hours.kind === "step") {
|
|
1082
|
-
phrase += " " + everyNthHour(ir
|
|
1130
|
+
phrase += " " + everyNthHour(stepSegment(ir, "hour"), opts);
|
|
1083
1131
|
}
|
|
1084
1132
|
return phrase + trailingQualifier(ir, opts);
|
|
1085
1133
|
}
|
|
@@ -1097,15 +1145,21 @@ function renderMinutesAcrossHours(ir, plan, opts) {
|
|
|
1097
1145
|
}
|
|
1098
1146
|
return "every minute during the " + hourTimesFromPlan(ir, plan.times, false, opts) + " hours" + trailingQualifier(ir, opts);
|
|
1099
1147
|
}
|
|
1100
|
-
|
|
1101
|
-
|
|
1102
|
-
|
|
1103
|
-
|
|
1104
|
-
|
|
1105
|
-
|
|
1106
|
-
"
|
|
1107
|
-
|
|
1108
|
-
)
|
|
1148
|
+
if (plan.form === "range") {
|
|
1149
|
+
const lead2 = minuteRangeLead(ir.pattern.minute, opts);
|
|
1150
|
+
if (cadence !== null) {
|
|
1151
|
+
return lead2 + ", " + cadence + trailingQualifier(ir, opts);
|
|
1152
|
+
}
|
|
1153
|
+
if (singleHourFire(plan.times)) {
|
|
1154
|
+
return lead2 + ", at " + hourTimesFromPlan(ir, plan.times, true, opts) + trailingQualifier(ir, opts);
|
|
1155
|
+
}
|
|
1156
|
+
return lead2 + " during the " + hourTimesFromPlan(ir, plan.times, false, opts) + " hours" + trailingQualifier(ir, opts);
|
|
1157
|
+
}
|
|
1158
|
+
const lead = strideFromSegments(segmentsOf(ir, "minute"), "minute", "hour", opts) ?? listPastThe(
|
|
1159
|
+
segmentWords(segmentsOf(ir, "minute"), opts),
|
|
1160
|
+
"minute",
|
|
1161
|
+
"hour",
|
|
1162
|
+
opts
|
|
1109
1163
|
);
|
|
1110
1164
|
if (cadence !== null) {
|
|
1111
1165
|
return lead + ", " + cadence + trailingQualifier(ir, opts);
|
|
@@ -1127,12 +1181,12 @@ function everyNthHour(segment, opts) {
|
|
|
1127
1181
|
return start === 0 ? base : base + " starting at " + getTime({ hour: start, minute: 0 }, opts);
|
|
1128
1182
|
}
|
|
1129
1183
|
function renderMinuteSpanAcrossHourStep(ir, plan, opts) {
|
|
1130
|
-
const segment = ir
|
|
1184
|
+
const segment = stepSegment(ir, "hour");
|
|
1131
1185
|
if (plan.form === "wildcard") {
|
|
1132
1186
|
return "every minute " + everyNthHour(segment, opts) + trailingQualifier(ir, opts);
|
|
1133
1187
|
}
|
|
1134
|
-
const lead = plan.form === "list" ? strideFromSegments(ir
|
|
1135
|
-
segmentWords(ir
|
|
1188
|
+
const lead = plan.form === "list" ? strideFromSegments(segmentsOf(ir, "minute"), "minute", "hour", opts) ?? listPastThe(
|
|
1189
|
+
segmentWords(segmentsOf(ir, "minute"), opts),
|
|
1136
1190
|
"minute",
|
|
1137
1191
|
"hour",
|
|
1138
1192
|
opts
|
|
@@ -1142,7 +1196,7 @@ function renderMinuteSpanAcrossHourStep(ir, plan, opts) {
|
|
|
1142
1196
|
}
|
|
1143
1197
|
function minuteRangeLead(minuteField, opts) {
|
|
1144
1198
|
const bounds = minuteField.split("-");
|
|
1145
|
-
const num = seriesNumber(
|
|
1199
|
+
const num = seriesNumber();
|
|
1146
1200
|
return "every minute from " + num(bounds[0]) + through(opts) + num(bounds[1]) + " past the hour";
|
|
1147
1201
|
}
|
|
1148
1202
|
function renderEveryHour(ir, plan, opts) {
|
|
@@ -1163,12 +1217,12 @@ function rangeMinuteLead(ir, opts) {
|
|
|
1163
1217
|
return "every hour";
|
|
1164
1218
|
}
|
|
1165
1219
|
return strideFromSegments(
|
|
1166
|
-
ir
|
|
1220
|
+
segmentsOf(ir, "minute"),
|
|
1167
1221
|
"minute",
|
|
1168
1222
|
"hour",
|
|
1169
1223
|
opts
|
|
1170
1224
|
) ?? listPastThe(
|
|
1171
|
-
segmentWords(ir
|
|
1225
|
+
segmentWords(segmentsOf(ir, "minute"), opts),
|
|
1172
1226
|
"minute",
|
|
1173
1227
|
"hour",
|
|
1174
1228
|
opts
|
|
@@ -1179,14 +1233,28 @@ function renderHourStep(ir, plan, opts) {
|
|
|
1179
1233
|
if (cadence !== null) {
|
|
1180
1234
|
return cadence + trailingQualifier(ir, opts);
|
|
1181
1235
|
}
|
|
1182
|
-
return stepHours(ir
|
|
1236
|
+
return stepHours(stepSegment(ir, "hour"), opts) + trailingQualifier(ir, opts);
|
|
1183
1237
|
}
|
|
1184
1238
|
function boundedWindow(plan) {
|
|
1185
|
-
const
|
|
1186
|
-
|
|
1239
|
+
const continuous = plan.minuteForm === "wildcard";
|
|
1240
|
+
const closeMinute = continuous ? plan.boundMinute ?? 0 : 0;
|
|
1241
|
+
return { from: plan.from, closeMinute, to: plan.to, continuous };
|
|
1242
|
+
}
|
|
1243
|
+
function rangeWindow(window, opts) {
|
|
1244
|
+
const { from, to, throughMinute, continuous } = window;
|
|
1245
|
+
const open = "from " + getTime({ hour: from, minute: 0 }, opts);
|
|
1246
|
+
if (opts.style.untilWindow && !opts.short && from !== to) {
|
|
1247
|
+
return continuous ? open + " until " + getTime({ hour: (to + 1) % 24, minute: 0 }, opts) : open + through(opts) + getTime({ hour: to, minute: 0 }, opts);
|
|
1248
|
+
}
|
|
1249
|
+
return open + through(opts) + getTime({ hour: to, minute: throughMinute }, opts);
|
|
1187
1250
|
}
|
|
1188
1251
|
function hourWindow(window, opts) {
|
|
1189
|
-
return
|
|
1252
|
+
return rangeWindow({
|
|
1253
|
+
continuous: window.continuous,
|
|
1254
|
+
from: window.from,
|
|
1255
|
+
throughMinute: window.closeMinute,
|
|
1256
|
+
to: window.to
|
|
1257
|
+
}, opts);
|
|
1190
1258
|
}
|
|
1191
1259
|
function renderClockTimes(ir, plan, opts) {
|
|
1192
1260
|
if (ir.shapes.minute === "single") {
|
|
@@ -1205,7 +1273,10 @@ function renderClockTimes(ir, plan, opts) {
|
|
|
1205
1273
|
plain
|
|
1206
1274
|
}, opts);
|
|
1207
1275
|
});
|
|
1208
|
-
return interpretDayQualifier(ir, opts) + "at " + joinList(times, opts);
|
|
1276
|
+
return interpretDayQualifier(ir, opts) + "at " + joinList(times, opts) + dayUnionTrail(ir, opts);
|
|
1277
|
+
}
|
|
1278
|
+
function dayUnionTrail(ir, opts) {
|
|
1279
|
+
return isDayUnion(ir, opts) ? dayUnionCondition(ir, opts) : "";
|
|
1209
1280
|
}
|
|
1210
1281
|
function renderCompactClockTimes(ir, plan, opts) {
|
|
1211
1282
|
if (plan.fold) {
|
|
@@ -1213,20 +1284,20 @@ function renderCompactClockTimes(ir, plan, opts) {
|
|
|
1213
1284
|
if (cadence2 !== null) {
|
|
1214
1285
|
return cadence2;
|
|
1215
1286
|
}
|
|
1216
|
-
const hasRange = ir
|
|
1287
|
+
const hasRange = segmentsOf(ir, "hour").some(function range(segment) {
|
|
1217
1288
|
return segment.kind === "range";
|
|
1218
1289
|
});
|
|
1219
1290
|
if (hasRange && !ir.analyses.clockSecond) {
|
|
1220
1291
|
return foldedHourWindows(ir, plan, opts) + trailingQualifier(ir, opts);
|
|
1221
1292
|
}
|
|
1222
1293
|
const fold = { minute: plan.minute, second: ir.analyses.clockSecond };
|
|
1223
|
-
return interpretDayQualifier(ir, opts) + "at " + hourSegmentTimes(ir, fold, true, opts);
|
|
1294
|
+
return interpretDayQualifier(ir, opts) + "at " + hourSegmentTimes(ir, fold, true, opts) + dayUnionTrail(ir, opts);
|
|
1224
1295
|
}
|
|
1225
1296
|
const minuteLead = (
|
|
1226
1297
|
// The non-fold branch is a minute list, which has segments. An
|
|
1227
1298
|
// offset/uneven step enumerated to that list reads as a stride.
|
|
1228
|
-
strideFromSegments(ir
|
|
1229
|
-
segmentWords(ir
|
|
1299
|
+
strideFromSegments(segmentsOf(ir, "minute"), "minute", "hour", opts) ?? listPastThe(
|
|
1300
|
+
segmentWords(segmentsOf(ir, "minute"), opts),
|
|
1230
1301
|
"minute",
|
|
1231
1302
|
"hour",
|
|
1232
1303
|
opts
|
|
@@ -1239,26 +1310,162 @@ function renderCompactClockTimes(ir, plan, opts) {
|
|
|
1239
1310
|
function foldedHourWindows(ir, plan, opts) {
|
|
1240
1311
|
const minute = plan.minute;
|
|
1241
1312
|
const windows = [];
|
|
1242
|
-
const
|
|
1243
|
-
|
|
1313
|
+
const times = collectHourOutliers(ir).map(function time(hour) {
|
|
1314
|
+
return getTime({ hour, minute }, opts);
|
|
1315
|
+
});
|
|
1316
|
+
segmentsOf(ir, "hour").forEach(function classify(segment) {
|
|
1244
1317
|
if (segment.kind === "range") {
|
|
1245
|
-
windows.push(
|
|
1246
|
-
|
|
1247
|
-
|
|
1248
|
-
|
|
1249
|
-
|
|
1250
|
-
|
|
1251
|
-
}
|
|
1252
|
-
|
|
1318
|
+
windows.push(rangeWindow({
|
|
1319
|
+
continuous: false,
|
|
1320
|
+
from: +segment.bounds[0],
|
|
1321
|
+
throughMinute: minute,
|
|
1322
|
+
to: +segment.bounds[1]
|
|
1323
|
+
}, opts));
|
|
1324
|
+
}
|
|
1325
|
+
});
|
|
1326
|
+
const phrase = rangeMinuteLead(ir, opts) + " " + joinList(windows, opts);
|
|
1327
|
+
return phrase + outlierTail(times, opts);
|
|
1328
|
+
}
|
|
1329
|
+
function collectHourOutliers(ir) {
|
|
1330
|
+
const hours = [];
|
|
1331
|
+
segmentsOf(ir, "hour").forEach(function classify(segment) {
|
|
1332
|
+
if (segment.kind === "step") {
|
|
1333
|
+
hours.push(...segment.fires);
|
|
1334
|
+
} else if (segment.kind !== "range") {
|
|
1335
|
+
hours.push(+segment.value);
|
|
1253
1336
|
}
|
|
1254
1337
|
});
|
|
1255
|
-
|
|
1256
|
-
|
|
1257
|
-
|
|
1258
|
-
|
|
1259
|
-
|
|
1338
|
+
return hours;
|
|
1339
|
+
}
|
|
1340
|
+
function outlierTail(times, opts) {
|
|
1341
|
+
if (!times.length) {
|
|
1342
|
+
return "";
|
|
1260
1343
|
}
|
|
1261
|
-
return
|
|
1344
|
+
return " and at " + joinList(times, opts);
|
|
1345
|
+
}
|
|
1346
|
+
function isCadenceField(token) {
|
|
1347
|
+
return token === "*" || token.startsWith("*/") && token.indexOf("-") === -1;
|
|
1348
|
+
}
|
|
1349
|
+
function leadingCadence(ir, opts) {
|
|
1350
|
+
const { second, minute } = ir.pattern;
|
|
1351
|
+
if (isCadenceField(second)) {
|
|
1352
|
+
return { secondLead: true, text: secondsClause(ir, "minute", opts) };
|
|
1353
|
+
}
|
|
1354
|
+
if (second === "0" && isCadenceField(minute)) {
|
|
1355
|
+
const text = minute === "*" ? "every minute" : (
|
|
1356
|
+
// A clean minute step's first segment is a step segment.
|
|
1357
|
+
stepCycle60(
|
|
1358
|
+
stepSegment(ir, "minute"),
|
|
1359
|
+
"minute",
|
|
1360
|
+
"hour",
|
|
1361
|
+
opts
|
|
1362
|
+
)
|
|
1363
|
+
);
|
|
1364
|
+
return { secondLead: false, text };
|
|
1365
|
+
}
|
|
1366
|
+
return null;
|
|
1367
|
+
}
|
|
1368
|
+
function minuteConfinement(ir, opts) {
|
|
1369
|
+
const minute = ir.pattern.minute;
|
|
1370
|
+
if (minute === "*") {
|
|
1371
|
+
return "";
|
|
1372
|
+
}
|
|
1373
|
+
if (isCadenceField(minute)) {
|
|
1374
|
+
return " of every other minute";
|
|
1375
|
+
}
|
|
1376
|
+
const segments = segmentsOf(ir, "minute");
|
|
1377
|
+
if (ir.shapes.minute === "single") {
|
|
1378
|
+
return " during minute :" + pad(minute);
|
|
1379
|
+
}
|
|
1380
|
+
if (ir.shapes.minute === "range") {
|
|
1381
|
+
const bounds = minute.split("-");
|
|
1382
|
+
return " during minutes :" + pad(bounds[0]) + through(opts) + ":" + pad(bounds[1]);
|
|
1383
|
+
}
|
|
1384
|
+
const values = segmentWords(segments, opts).map(function colon(word) {
|
|
1385
|
+
return ":" + pad(word);
|
|
1386
|
+
});
|
|
1387
|
+
return " during minutes " + joinList(values, opts);
|
|
1388
|
+
}
|
|
1389
|
+
function hourConfinement(ir, opts) {
|
|
1390
|
+
const hour = ir.pattern.hour;
|
|
1391
|
+
if (hour === "*") {
|
|
1392
|
+
const minutePinned = ir.pattern.minute !== "*" && !isCadenceField(ir.pattern.minute);
|
|
1393
|
+
return minutePinned ? " of every hour" : "";
|
|
1394
|
+
}
|
|
1395
|
+
if (isCadenceField(hour)) {
|
|
1396
|
+
return hour === "*/2" ? " of every other hour" : "";
|
|
1397
|
+
}
|
|
1398
|
+
if (ir.shapes.hour === "single") {
|
|
1399
|
+
const h = +hour;
|
|
1400
|
+
if (ir.shapes.minute === "step") {
|
|
1401
|
+
return " from " + getTime({ hour: h, minute: 0 }, opts) + " until " + getTime({ hour: (h + 1) % 24, minute: 0 }, opts);
|
|
1402
|
+
}
|
|
1403
|
+
if (ir.pattern.minute !== "*" && !isCadenceField(ir.pattern.minute)) {
|
|
1404
|
+
return " at " + getTime({ hour: h, minute: 0 }, opts);
|
|
1405
|
+
}
|
|
1406
|
+
return " of the " + getTime({ hour: h, minute: 0 }, opts) + " hour";
|
|
1407
|
+
}
|
|
1408
|
+
if (ir.shapes.hour === "range") {
|
|
1409
|
+
const bounds = hour.split("-");
|
|
1410
|
+
return " " + rangeWindow({
|
|
1411
|
+
continuous: ir.pattern.minute === "*",
|
|
1412
|
+
from: +bounds[0],
|
|
1413
|
+
throughMinute: 0,
|
|
1414
|
+
to: +bounds[1]
|
|
1415
|
+
}, opts);
|
|
1416
|
+
}
|
|
1417
|
+
return " during the " + hourSegmentTimes(ir, { minute: 0, second: null }, false, opts) + " hours";
|
|
1418
|
+
}
|
|
1419
|
+
function isContiguousHourRange(ir) {
|
|
1420
|
+
return ir.shapes.hour === "range";
|
|
1421
|
+
}
|
|
1422
|
+
function confinableHour(ir) {
|
|
1423
|
+
if (ir.shapes.hour !== "step") {
|
|
1424
|
+
return true;
|
|
1425
|
+
}
|
|
1426
|
+
const segment = stepSegment(ir, "hour");
|
|
1427
|
+
return ir.pattern.hour === "*/2" || segment.startToken.indexOf("-") !== -1;
|
|
1428
|
+
}
|
|
1429
|
+
function isMinuteStride(ir) {
|
|
1430
|
+
if (ir.shapes.minute !== "list") {
|
|
1431
|
+
return false;
|
|
1432
|
+
}
|
|
1433
|
+
const values = singleValues(segmentsOf(ir, "minute"));
|
|
1434
|
+
return values !== null && arithmeticStep(values) !== null;
|
|
1435
|
+
}
|
|
1436
|
+
function confinementEligible(ir, lead) {
|
|
1437
|
+
const { minute, hour } = ir.pattern;
|
|
1438
|
+
const minuteStep = isCadenceField(minute) && minute !== "*";
|
|
1439
|
+
if (!confinableHour(ir)) {
|
|
1440
|
+
return false;
|
|
1441
|
+
}
|
|
1442
|
+
if (lead.secondLead) {
|
|
1443
|
+
if (minuteStep) {
|
|
1444
|
+
return minute === "*/2" && !isContiguousHourRange(ir);
|
|
1445
|
+
}
|
|
1446
|
+
if (isMinuteStride(ir) || ir.shapes.minute === "list" && ir.shapes.hour === "list") {
|
|
1447
|
+
return false;
|
|
1448
|
+
}
|
|
1449
|
+
return true;
|
|
1450
|
+
}
|
|
1451
|
+
if (hour === "*/2") {
|
|
1452
|
+
return true;
|
|
1453
|
+
}
|
|
1454
|
+
return ir.shapes.hour === "single" && minute === "*/2";
|
|
1455
|
+
}
|
|
1456
|
+
function confinement(ir, opts) {
|
|
1457
|
+
if (!opts.style.untilWindow || opts.short) {
|
|
1458
|
+
return null;
|
|
1459
|
+
}
|
|
1460
|
+
if (ir.pattern.minute === "*" && ir.pattern.hour === "*") {
|
|
1461
|
+
return null;
|
|
1462
|
+
}
|
|
1463
|
+
const lead = leadingCadence(ir, opts);
|
|
1464
|
+
if (!lead || !confinementEligible(ir, lead)) {
|
|
1465
|
+
return null;
|
|
1466
|
+
}
|
|
1467
|
+
const minutePart = lead.secondLead ? minuteConfinement(ir, opts) : "";
|
|
1468
|
+
return lead.text + minutePart + hourConfinement(ir, opts) + trailingQualifier(ir, opts);
|
|
1262
1469
|
}
|
|
1263
1470
|
var renderers = {
|
|
1264
1471
|
clockTimes: renderClockTimes,
|
|
@@ -1290,19 +1497,9 @@ function renderStride(stride, opts) {
|
|
|
1290
1497
|
if (start < interval && tiles) {
|
|
1291
1498
|
return cadence + " from " + getNumber(start, opts) + " " + pluralize(start, unit) + " past the " + anchor;
|
|
1292
1499
|
}
|
|
1293
|
-
const num = seriesNumber(
|
|
1500
|
+
const num = seriesNumber();
|
|
1294
1501
|
return cadence + " from " + num(start) + through(opts) + num(last) + " " + pluralize(last, unit) + " past the " + anchor;
|
|
1295
1502
|
}
|
|
1296
|
-
function singleValues(segments) {
|
|
1297
|
-
const values = [];
|
|
1298
|
-
for (const segment of segments) {
|
|
1299
|
-
if (segment.kind !== "single") {
|
|
1300
|
-
return null;
|
|
1301
|
-
}
|
|
1302
|
-
values.push(+segment.value);
|
|
1303
|
-
}
|
|
1304
|
-
return values;
|
|
1305
|
-
}
|
|
1306
1503
|
function strideFromSegments(segments, unit, anchor, opts) {
|
|
1307
1504
|
const values = singleValues(segments);
|
|
1308
1505
|
const step = values && arithmeticStep(values);
|
|
@@ -1351,9 +1548,6 @@ function hourStrideCadence(stride, opts) {
|
|
|
1351
1548
|
}
|
|
1352
1549
|
return cadence + " from " + getTime({ hour: start, minute: 0 }, opts) + through(opts) + getTime({ hour: last, minute: 0 }, opts);
|
|
1353
1550
|
}
|
|
1354
|
-
function offsetCleanStride(stride) {
|
|
1355
|
-
return stride.start < stride.interval && 24 % stride.interval === 0;
|
|
1356
|
-
}
|
|
1357
1551
|
function unevenHourCadence(ir, opts) {
|
|
1358
1552
|
const stride = hourStride(ir);
|
|
1359
1553
|
if (!stride || offsetCleanStride(stride)) {
|
|
@@ -1361,26 +1555,8 @@ function unevenHourCadence(ir, opts) {
|
|
|
1361
1555
|
}
|
|
1362
1556
|
return hourStrideCadence(stride, opts);
|
|
1363
1557
|
}
|
|
1364
|
-
function hourListStride(values) {
|
|
1365
|
-
if (values.length < 2) {
|
|
1366
|
-
return null;
|
|
1367
|
-
}
|
|
1368
|
-
const interval = values[1] - values[0];
|
|
1369
|
-
if (interval < 2) {
|
|
1370
|
-
return null;
|
|
1371
|
-
}
|
|
1372
|
-
for (let i = 2; i < values.length; i += 1) {
|
|
1373
|
-
if (values[i] - values[i - 1] !== interval) {
|
|
1374
|
-
return null;
|
|
1375
|
-
}
|
|
1376
|
-
}
|
|
1377
|
-
if (values[0] !== 0 && values.length < 5) {
|
|
1378
|
-
return null;
|
|
1379
|
-
}
|
|
1380
|
-
return { interval, last: values[values.length - 1], start: values[0] };
|
|
1381
|
-
}
|
|
1382
1558
|
function hourStride(ir) {
|
|
1383
|
-
const segments = ir
|
|
1559
|
+
const segments = segmentsOf(ir, "hour");
|
|
1384
1560
|
if (segments.length === 1 && segments[0].kind === "step") {
|
|
1385
1561
|
const segment = segments[0];
|
|
1386
1562
|
if (segment.fires.length < 2) {
|
|
@@ -1417,9 +1593,9 @@ function hourCadence(ir, minute, opts) {
|
|
|
1417
1593
|
if (ir.pattern.second === "0" && fires <= maxClockTimes && offsetCleanStride(stride)) {
|
|
1418
1594
|
return null;
|
|
1419
1595
|
}
|
|
1420
|
-
const
|
|
1421
|
-
if (
|
|
1422
|
-
return secondsClause(ir, "minute", opts) + " for one minute " + everyNthHour(
|
|
1596
|
+
const minuteZeroStride = minute === 0 && subMinuteSecond(ir) && cleanStrideSegment(ir);
|
|
1597
|
+
if (minuteZeroStride) {
|
|
1598
|
+
return secondsClause(ir, "minute", opts) + " for one minute " + everyNthHour(minuteZeroStride, opts) + trailingQualifier(ir, opts);
|
|
1423
1599
|
}
|
|
1424
1600
|
if (minute === 0 && ir.pattern.second === "0") {
|
|
1425
1601
|
return hourStrideCadence(stride, opts) + trailingQualifier(ir, opts);
|
|
@@ -1427,7 +1603,7 @@ function hourCadence(ir, minute, opts) {
|
|
|
1427
1603
|
return hourCadenceLead(ir, minute, opts) + ", " + hourStrideCadence(stride, opts) + trailingQualifier(ir, opts);
|
|
1428
1604
|
}
|
|
1429
1605
|
function cleanStrideSegment(ir) {
|
|
1430
|
-
const segments = ir
|
|
1606
|
+
const segments = segmentsOf(ir, "hour");
|
|
1431
1607
|
const segment = segments.length === 1 && segments[0];
|
|
1432
1608
|
if (!segment || segment.kind !== "step" || segment.startToken.indexOf("-") !== -1 || !(segment.interval in stepOrdinals)) {
|
|
1433
1609
|
return null;
|
|
@@ -1435,32 +1611,28 @@ function cleanStrideSegment(ir) {
|
|
|
1435
1611
|
return segment;
|
|
1436
1612
|
}
|
|
1437
1613
|
function hasHourWindow(ir) {
|
|
1438
|
-
return ir
|
|
1614
|
+
return segmentsOf(ir, "hour").some(function range(segment) {
|
|
1439
1615
|
return segment.kind === "range";
|
|
1440
1616
|
});
|
|
1441
1617
|
}
|
|
1442
1618
|
function hourRangeWindowTail(ir, opts) {
|
|
1443
1619
|
const windows = [];
|
|
1444
|
-
const
|
|
1445
|
-
ir
|
|
1620
|
+
const outlierHours = collectHourOutliers(ir);
|
|
1621
|
+
segmentsOf(ir, "hour").forEach(function classify(segment) {
|
|
1446
1622
|
if (segment.kind === "range") {
|
|
1447
|
-
windows.push(
|
|
1448
|
-
|
|
1449
|
-
|
|
1450
|
-
|
|
1451
|
-
|
|
1452
|
-
|
|
1453
|
-
} else {
|
|
1454
|
-
singles.push(+segment.value);
|
|
1623
|
+
windows.push(rangeWindow({
|
|
1624
|
+
continuous: false,
|
|
1625
|
+
from: +segment.bounds[0],
|
|
1626
|
+
throughMinute: 0,
|
|
1627
|
+
to: +segment.bounds[1]
|
|
1628
|
+
}, opts));
|
|
1455
1629
|
}
|
|
1456
1630
|
});
|
|
1457
|
-
|
|
1458
|
-
|
|
1459
|
-
|
|
1460
|
-
|
|
1461
|
-
|
|
1462
|
-
}
|
|
1463
|
-
return phrase;
|
|
1631
|
+
const phrase = "every hour " + joinList(windows, opts);
|
|
1632
|
+
const times = outlierHours.map(function time(hour) {
|
|
1633
|
+
return getTime({ hour, minute: 0 }, opts);
|
|
1634
|
+
});
|
|
1635
|
+
return phrase + outlierTail(times, opts);
|
|
1464
1636
|
}
|
|
1465
1637
|
function hourRangeCadence(ir, minute, opts) {
|
|
1466
1638
|
if (minute !== 0 || !hasHourWindow(ir)) {
|
|
@@ -1474,25 +1646,29 @@ function hourRangeCadence(ir, minute, opts) {
|
|
|
1474
1646
|
}
|
|
1475
1647
|
return hourCadenceLead(ir, minute, opts) + ", " + hourRangeWindowTail(ir, opts) + trailingQualifier(ir, opts);
|
|
1476
1648
|
}
|
|
1477
|
-
function seriesNumber(
|
|
1478
|
-
const anyBig = values.some(function big(v) {
|
|
1479
|
-
return +v > 10;
|
|
1480
|
-
});
|
|
1649
|
+
function seriesNumber() {
|
|
1481
1650
|
return function format(n) {
|
|
1482
|
-
return
|
|
1651
|
+
return "" + n;
|
|
1652
|
+
};
|
|
1653
|
+
}
|
|
1654
|
+
function listNumber(count, opts) {
|
|
1655
|
+
return count > 1 ? function asNumeral(n) {
|
|
1656
|
+
return "" + n;
|
|
1657
|
+
} : function spelled(n) {
|
|
1658
|
+
return getNumber(n, opts);
|
|
1483
1659
|
};
|
|
1484
1660
|
}
|
|
1485
1661
|
function numberWords(fires, opts) {
|
|
1486
|
-
return fires.map(
|
|
1662
|
+
return fires.map(listNumber(fires.length, opts));
|
|
1487
1663
|
}
|
|
1488
1664
|
function segmentWords(segments, opts) {
|
|
1489
|
-
const
|
|
1665
|
+
const count = segments.reduce(function tally(sum, segment) {
|
|
1490
1666
|
if (segment.kind === "range") {
|
|
1491
|
-
return
|
|
1667
|
+
return sum + 1;
|
|
1492
1668
|
}
|
|
1493
|
-
return segment.kind === "step" ? segment.fires :
|
|
1494
|
-
});
|
|
1495
|
-
const num =
|
|
1669
|
+
return sum + (segment.kind === "step" ? segment.fires.length : 1);
|
|
1670
|
+
}, 0);
|
|
1671
|
+
const num = listNumber(count, opts);
|
|
1496
1672
|
return segments.flatMap(function word(segment) {
|
|
1497
1673
|
if (segment.kind === "range") {
|
|
1498
1674
|
return [num(segment.bounds[0]) + through(opts) + num(segment.bounds[1])];
|
|
@@ -1524,6 +1700,9 @@ function hourTimes(hours, opts) {
|
|
|
1524
1700
|
});
|
|
1525
1701
|
return joinList(times, opts);
|
|
1526
1702
|
}
|
|
1703
|
+
function singleHourFire(times) {
|
|
1704
|
+
return times.kind === "fires" && times.fires.length === 1;
|
|
1705
|
+
}
|
|
1527
1706
|
function hourTimesFromPlan(ir, times, atContext, opts) {
|
|
1528
1707
|
if (times.kind === "fires") {
|
|
1529
1708
|
return hourTimes(times.fires, opts);
|
|
@@ -1538,7 +1717,7 @@ function segmentHours(segment) {
|
|
|
1538
1717
|
}
|
|
1539
1718
|
function hourSegmentTimes(ir, fold, atContext, opts) {
|
|
1540
1719
|
const { minute, second } = fold;
|
|
1541
|
-
const segments = ir
|
|
1720
|
+
const segments = segmentsOf(ir, "hour");
|
|
1542
1721
|
const plain = mixedTwelve(segments.flatMap(function entries(segment) {
|
|
1543
1722
|
return segmentHours(segment).map(function entry(hour) {
|
|
1544
1723
|
return { hour: +hour, minute, second };
|
|
@@ -1571,28 +1750,47 @@ function disambiguateTimes(pieces, segments, atContext) {
|
|
|
1571
1750
|
return index === 0 ? piece : "at " + piece;
|
|
1572
1751
|
});
|
|
1573
1752
|
}
|
|
1574
|
-
function
|
|
1753
|
+
function joinWith(items, conjunction, opts) {
|
|
1575
1754
|
if (items.length <= 1) {
|
|
1576
1755
|
return items.join("");
|
|
1577
1756
|
}
|
|
1578
1757
|
if (items.length === 2) {
|
|
1579
|
-
return items[0] +
|
|
1758
|
+
return items[0] + conjunction + items[1];
|
|
1580
1759
|
}
|
|
1581
|
-
const
|
|
1582
|
-
return items.slice(0, -1).join(", ") +
|
|
1760
|
+
const tail = opts.style.serialComma ? "," + conjunction : conjunction;
|
|
1761
|
+
return items.slice(0, -1).join(", ") + tail + items[items.length - 1];
|
|
1762
|
+
}
|
|
1763
|
+
function joinList(items, opts) {
|
|
1764
|
+
return joinWith(items, " and ", opts);
|
|
1583
1765
|
}
|
|
1584
|
-
|
|
1766
|
+
function joinOr(items, opts) {
|
|
1767
|
+
return joinWith(items, " or ", opts);
|
|
1768
|
+
}
|
|
1769
|
+
var trailingWords = {
|
|
1770
|
+
all: "",
|
|
1771
|
+
month: "in ",
|
|
1772
|
+
recurringWeekday: true,
|
|
1773
|
+
stepDate: "on ",
|
|
1774
|
+
weekday: "on "
|
|
1775
|
+
};
|
|
1585
1776
|
var leadingWords = {
|
|
1586
1777
|
all: "every day",
|
|
1587
1778
|
month: "every day in ",
|
|
1779
|
+
recurringWeekday: false,
|
|
1588
1780
|
stepDate: "",
|
|
1589
1781
|
weekday: "every "
|
|
1590
1782
|
};
|
|
1591
1783
|
function trailingQualifier(ir, opts) {
|
|
1784
|
+
if (isDayUnion(ir, opts)) {
|
|
1785
|
+
return dayUnionCondition(ir, opts);
|
|
1786
|
+
}
|
|
1592
1787
|
const phrase = dayQualifier(ir, trailingWords, opts);
|
|
1593
1788
|
return phrase && " " + phrase;
|
|
1594
1789
|
}
|
|
1595
1790
|
function interpretDayQualifier(ir, opts) {
|
|
1791
|
+
if (isDayUnion(ir, opts)) {
|
|
1792
|
+
return "";
|
|
1793
|
+
}
|
|
1596
1794
|
return dayQualifier(ir, leadingWords, opts) + " ";
|
|
1597
1795
|
}
|
|
1598
1796
|
function dayQualifier(ir, words, opts) {
|
|
@@ -1604,7 +1802,11 @@ function dayQualifier(ir, words, opts) {
|
|
|
1604
1802
|
return datePhrase(ir, words, opts);
|
|
1605
1803
|
}
|
|
1606
1804
|
if (pattern.weekday !== "*") {
|
|
1607
|
-
const
|
|
1805
|
+
const quartzWeekday = quartzWeekdayPhrase(pattern.weekday, opts);
|
|
1806
|
+
if (quartzWeekday) {
|
|
1807
|
+
return monthScopeForRecurrence(quartzWeekday, ir, opts);
|
|
1808
|
+
}
|
|
1809
|
+
const weekdays = words.weekday + weekdayPhrase(ir, words.recurringWeekday, opts);
|
|
1608
1810
|
return weekdays + monthScope(ir, opts);
|
|
1609
1811
|
}
|
|
1610
1812
|
if (pattern.month !== "*") {
|
|
@@ -1616,10 +1818,14 @@ function datePhrase(ir, words, opts) {
|
|
|
1616
1818
|
const pattern = ir.pattern;
|
|
1617
1819
|
const quartzDate = quartzDatePhrase(pattern.date, opts);
|
|
1618
1820
|
if (quartzDate) {
|
|
1619
|
-
return quartzDate
|
|
1821
|
+
return monthScopeForRecurrence(quartzDate, ir, opts);
|
|
1620
1822
|
}
|
|
1621
1823
|
if (isOpenStep(pattern.date)) {
|
|
1622
|
-
return
|
|
1824
|
+
return monthScopeForRecurrence(
|
|
1825
|
+
words.stepDate + stepDates(pattern.date),
|
|
1826
|
+
ir,
|
|
1827
|
+
opts
|
|
1828
|
+
);
|
|
1623
1829
|
}
|
|
1624
1830
|
if (pattern.month !== "*" && !monthFoldsIntoDate(ir)) {
|
|
1625
1831
|
return "on the " + dateOrdinals(ir, opts) + monthScope(ir, opts);
|
|
@@ -1631,13 +1837,88 @@ function datePhrase(ir, words, opts) {
|
|
|
1631
1837
|
}
|
|
1632
1838
|
function monthFoldsIntoDate(ir) {
|
|
1633
1839
|
return !oddEvenMonth(ir.pattern.month) && // Reached only with a restricted month, which has segments.
|
|
1634
|
-
ir
|
|
1840
|
+
segmentsOf(ir, "month").every(function flat(segment) {
|
|
1635
1841
|
return segment.kind !== "range";
|
|
1636
1842
|
});
|
|
1637
1843
|
}
|
|
1844
|
+
function isDayUnion(ir, opts) {
|
|
1845
|
+
return ir.pattern.date !== "*" && ir.pattern.weekday !== "*" && !!opts.style.untilWindow && !opts.short;
|
|
1846
|
+
}
|
|
1847
|
+
function dayUnionCondition(ir, opts) {
|
|
1848
|
+
const pieces = [
|
|
1849
|
+
...dayUnionDatePieces(ir, opts),
|
|
1850
|
+
...dayUnionWeekdayPieces(ir, opts)
|
|
1851
|
+
];
|
|
1852
|
+
return " whenever the day is " + joinOr(pieces, opts);
|
|
1853
|
+
}
|
|
1854
|
+
function dayUnionMonthLead(ir, opts) {
|
|
1855
|
+
if (ir.pattern.month === "*") {
|
|
1856
|
+
return "";
|
|
1857
|
+
}
|
|
1858
|
+
return "in " + monthName(ir, opts) + " ";
|
|
1859
|
+
}
|
|
1860
|
+
function dayUnionDatePieces(ir, opts) {
|
|
1861
|
+
const dateField = ir.pattern.date;
|
|
1862
|
+
const quartz = quartzDatePhrase(dateField, opts);
|
|
1863
|
+
if (quartz) {
|
|
1864
|
+
return [quartz.replace(/^on /, "")];
|
|
1865
|
+
}
|
|
1866
|
+
const oddEven = oddEvenDay(dateField);
|
|
1867
|
+
if (oddEven) {
|
|
1868
|
+
return [oddEven];
|
|
1869
|
+
}
|
|
1870
|
+
const pieces = [];
|
|
1871
|
+
segmentsOf(ir, "date").forEach(function expand(segment) {
|
|
1872
|
+
if (segment.kind === "range") {
|
|
1873
|
+
pieces.push("from the " + getOrdinal(segment.bounds[0]) + through(opts) + "the " + getOrdinal(segment.bounds[1]));
|
|
1874
|
+
} else if (segment.kind === "step") {
|
|
1875
|
+
segment.fires.forEach(function fire(value) {
|
|
1876
|
+
pieces.push("the " + getOrdinal(value));
|
|
1877
|
+
});
|
|
1878
|
+
} else {
|
|
1879
|
+
pieces.push("the " + getOrdinal(segment.value));
|
|
1880
|
+
}
|
|
1881
|
+
});
|
|
1882
|
+
return pieces;
|
|
1883
|
+
}
|
|
1884
|
+
function dayUnionWeekdayPieces(ir, opts) {
|
|
1885
|
+
const weekdayField = ir.pattern.weekday;
|
|
1886
|
+
const quartz = quartzWeekdayPhrase(weekdayField, opts);
|
|
1887
|
+
if (quartz) {
|
|
1888
|
+
return [quartz.replace(/^on /, "")];
|
|
1889
|
+
}
|
|
1890
|
+
const pieces = [];
|
|
1891
|
+
segmentsOf(ir, "weekday").forEach(function expand(segment) {
|
|
1892
|
+
if (segment.kind === "range" && segment.bounds[0] === "1" && segment.bounds[1] === "5") {
|
|
1893
|
+
pieces.push("a weekday");
|
|
1894
|
+
} else if (segment.kind === "range") {
|
|
1895
|
+
pieces.push("a " + getWeekday(segment.bounds[0], opts) + through(opts) + "a " + getWeekday(segment.bounds[1], opts));
|
|
1896
|
+
} else if (segment.kind === "step") {
|
|
1897
|
+
segment.fires.forEach(function fire(value) {
|
|
1898
|
+
pieces.push("a " + getWeekday(value, opts));
|
|
1899
|
+
});
|
|
1900
|
+
} else {
|
|
1901
|
+
pieces.push("a " + getWeekday(segment.value, opts));
|
|
1902
|
+
}
|
|
1903
|
+
});
|
|
1904
|
+
return pieces;
|
|
1905
|
+
}
|
|
1906
|
+
function oddEvenDay(dateField) {
|
|
1907
|
+
if (!isOpenStep(dateField)) {
|
|
1908
|
+
return null;
|
|
1909
|
+
}
|
|
1910
|
+
const [start, step] = dateField.split("/");
|
|
1911
|
+
if (+step !== 2) {
|
|
1912
|
+
return null;
|
|
1913
|
+
}
|
|
1914
|
+
if (start === "*" || start === "1") {
|
|
1915
|
+
return "an odd-numbered day";
|
|
1916
|
+
}
|
|
1917
|
+
return start === "2" ? "an even-numbered day" : null;
|
|
1918
|
+
}
|
|
1638
1919
|
function dateOrWeekday(ir, opts) {
|
|
1639
1920
|
const pattern = ir.pattern;
|
|
1640
|
-
const weekdayPart = quartzWeekdayPhrase(pattern.weekday, opts) || "on " + weekdayPhrase(ir, opts);
|
|
1921
|
+
const weekdayPart = quartzWeekdayPhrase(pattern.weekday, opts) || "on " + weekdayPhrase(ir, false, opts);
|
|
1641
1922
|
if (pattern.month !== "*" && monthFoldsIntoDate(ir) && !quartzDatePhrase(pattern.date, opts) && !isOpenStep(pattern.date)) {
|
|
1642
1923
|
return "on " + monthDatePhrase(ir, opts) + " or " + weekdayPart + " in " + monthName(ir, opts);
|
|
1643
1924
|
}
|
|
@@ -1688,10 +1969,13 @@ function quartzWeekdayPhrase(weekdayField, opts) {
|
|
|
1688
1969
|
function monthDatePhrase(ir, opts) {
|
|
1689
1970
|
const month = monthName(ir, opts);
|
|
1690
1971
|
const days = renderSegments(
|
|
1691
|
-
ir
|
|
1972
|
+
segmentsOf(ir, "date"),
|
|
1692
1973
|
opts.style.ordinals ? getOrdinal : cardinalDay,
|
|
1693
1974
|
opts
|
|
1694
1975
|
);
|
|
1976
|
+
if (opts.style.dayFirst && ir.shapes.date === "single" && ir.shapes.month !== "single") {
|
|
1977
|
+
return "the " + getOrdinal(ir.pattern.date) + " of " + month;
|
|
1978
|
+
}
|
|
1695
1979
|
return opts.style.dayFirst ? days + " " + month : month + " " + days;
|
|
1696
1980
|
}
|
|
1697
1981
|
function cardinalDay(value) {
|
|
@@ -1703,6 +1987,19 @@ function monthScope(ir, opts) {
|
|
|
1703
1987
|
}
|
|
1704
1988
|
return " in " + monthName(ir, opts);
|
|
1705
1989
|
}
|
|
1990
|
+
function monthScopeForRecurrence(phrase, ir, opts) {
|
|
1991
|
+
if (ir.pattern.month === "*") {
|
|
1992
|
+
return phrase;
|
|
1993
|
+
}
|
|
1994
|
+
const carriesRecurrence = phrase.indexOf(" of the month") !== -1;
|
|
1995
|
+
if (carriesRecurrence && ir.shapes.month === "range") {
|
|
1996
|
+
return phrase.replace(" of the month", " of each month") + " from " + monthName(ir, opts);
|
|
1997
|
+
}
|
|
1998
|
+
if (carriesRecurrence && (ir.shapes.month === "single" || ir.shapes.month === "step")) {
|
|
1999
|
+
return phrase.replace(" of the month", "") + " in " + monthName(ir, opts);
|
|
2000
|
+
}
|
|
2001
|
+
return phrase + " in " + monthName(ir, opts);
|
|
2002
|
+
}
|
|
1706
2003
|
function stepDates(dateField) {
|
|
1707
2004
|
const parts = dateField.split("/");
|
|
1708
2005
|
const interval = +parts[1];
|
|
@@ -1715,14 +2012,14 @@ function stepDates(dateField) {
|
|
|
1715
2012
|
return phrase;
|
|
1716
2013
|
}
|
|
1717
2014
|
function dateOrdinals(ir, opts) {
|
|
1718
|
-
return renderSegments(ir
|
|
2015
|
+
return renderSegments(segmentsOf(ir, "date"), getOrdinal, opts);
|
|
1719
2016
|
}
|
|
1720
2017
|
function monthName(ir, opts) {
|
|
1721
2018
|
const oddEven = oddEvenMonth(ir.pattern.month);
|
|
1722
2019
|
if (oddEven) {
|
|
1723
2020
|
return oddEven;
|
|
1724
2021
|
}
|
|
1725
|
-
return renderSegments(ir
|
|
2022
|
+
return renderSegments(segmentsOf(ir, "month"), function name(value) {
|
|
1726
2023
|
return getMonth(value, opts);
|
|
1727
2024
|
}, opts);
|
|
1728
2025
|
}
|
|
@@ -1739,11 +2036,21 @@ function oddEvenMonth(monthField) {
|
|
|
1739
2036
|
}
|
|
1740
2037
|
return start === "2" ? "every even-numbered month" : null;
|
|
1741
2038
|
}
|
|
1742
|
-
function weekdayPhrase(ir, opts) {
|
|
1743
|
-
const segments = orderWeekdaysForDisplay(ir
|
|
1744
|
-
|
|
2039
|
+
function weekdayPhrase(ir, recurring, opts) {
|
|
2040
|
+
const segments = orderWeekdaysForDisplay(segmentsOf(ir, "weekday"));
|
|
2041
|
+
const hasRange = segments.some(function range(segment) {
|
|
2042
|
+
return segment.kind === "range";
|
|
2043
|
+
});
|
|
2044
|
+
const name = recurring && !hasRange ? function plural(value) {
|
|
2045
|
+
return pluralWeekday(value, opts);
|
|
2046
|
+
} : function singular(value) {
|
|
1745
2047
|
return getWeekday(value, opts);
|
|
1746
|
-
}
|
|
2048
|
+
};
|
|
2049
|
+
return renderSegments(segments, name, opts);
|
|
2050
|
+
}
|
|
2051
|
+
function pluralWeekday(value, opts) {
|
|
2052
|
+
const name = getWeekday(value, opts);
|
|
2053
|
+
return opts.short ? name : name + "s";
|
|
1747
2054
|
}
|
|
1748
2055
|
function renderSegments(segments, word, opts) {
|
|
1749
2056
|
const pieces = [];
|
|
@@ -1758,16 +2065,13 @@ function renderSegments(segments, word, opts) {
|
|
|
1758
2065
|
});
|
|
1759
2066
|
return joinList(pieces, opts);
|
|
1760
2067
|
}
|
|
1761
|
-
function isOpenStep(field) {
|
|
1762
|
-
return field.indexOf("/") !== -1 && field.indexOf("-") === -1 && field.indexOf(",") === -1;
|
|
1763
|
-
}
|
|
1764
2068
|
function applyYear(description, ir, opts) {
|
|
1765
2069
|
const yearField = ir.pattern.year;
|
|
1766
2070
|
if (yearField === "*") {
|
|
1767
2071
|
return description;
|
|
1768
2072
|
}
|
|
1769
2073
|
if (yearField.indexOf("/") !== -1) {
|
|
1770
|
-
return description + " " + stepYears(yearField, opts);
|
|
2074
|
+
return description + ", " + stepYears(yearField, opts);
|
|
1771
2075
|
}
|
|
1772
2076
|
const label = yearLabel(yearField, opts);
|
|
1773
2077
|
if (yearField.indexOf("-") === -1 && yearField.indexOf(",") === -1 && ir.pattern.date !== "*" && description.indexOf(" at ") !== -1) {
|
|
@@ -1780,6 +2084,9 @@ function yearLabel(yearField, opts) {
|
|
|
1780
2084
|
if (yearField.indexOf(",") !== -1) {
|
|
1781
2085
|
return joinList(yearField.split(","), opts);
|
|
1782
2086
|
}
|
|
2087
|
+
if (yearField.indexOf("-") !== -1) {
|
|
2088
|
+
return yearField.split("-").join(through(opts));
|
|
2089
|
+
}
|
|
1783
2090
|
return yearField;
|
|
1784
2091
|
}
|
|
1785
2092
|
function stepYears(yearField, opts) {
|
|
@@ -1789,7 +2096,7 @@ function stepYears(yearField, opts) {
|
|
|
1789
2096
|
if (interval <= 1) {
|
|
1790
2097
|
return "every year";
|
|
1791
2098
|
}
|
|
1792
|
-
let phrase = "every " + getNumber(interval, opts) + " years";
|
|
2099
|
+
let phrase = interval === 2 ? "every other year" : "every " + getNumber(interval, opts) + " years";
|
|
1793
2100
|
if (start !== "*" && start !== "0") {
|
|
1794
2101
|
phrase += " from " + start;
|
|
1795
2102
|
}
|
|
@@ -1891,7 +2198,7 @@ function interpretCronPattern(cronPattern, lang, opts) {
|
|
|
1891
2198
|
return lang.reboot;
|
|
1892
2199
|
}
|
|
1893
2200
|
const ir = analyze(prepare(cronPattern, opts));
|
|
1894
|
-
const plan = lang.
|
|
2201
|
+
const plan = lang.plan ? lang.plan(ir, ir.plan) : ir.plan;
|
|
1895
2202
|
return lang.describe({ ...ir, plan }, opts);
|
|
1896
2203
|
}
|
|
1897
2204
|
var cronli5_default = cronli5;
|