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.cjs
CHANGED
|
@@ -133,6 +133,43 @@ function orderWeekdaysForDisplay(segments) {
|
|
|
133
133
|
function toFieldNumber(token, numberMap) {
|
|
134
134
|
return isNonNegativeInteger(token) ? +token : numberMap[token.toUpperCase()];
|
|
135
135
|
}
|
|
136
|
+
function segmentsOf(ir, field) {
|
|
137
|
+
return ir.analyses.segments[field] ?? [];
|
|
138
|
+
}
|
|
139
|
+
function stepSegment(ir, field) {
|
|
140
|
+
return segmentsOf(ir, field)[0];
|
|
141
|
+
}
|
|
142
|
+
function singleValues(segments) {
|
|
143
|
+
const values = [];
|
|
144
|
+
for (const segment of segments) {
|
|
145
|
+
if (segment.kind !== "single") {
|
|
146
|
+
return null;
|
|
147
|
+
}
|
|
148
|
+
values.push(+segment.value);
|
|
149
|
+
}
|
|
150
|
+
return values;
|
|
151
|
+
}
|
|
152
|
+
function offsetCleanStride(stride) {
|
|
153
|
+
return stride.start < stride.interval && 24 % stride.interval === 0;
|
|
154
|
+
}
|
|
155
|
+
function hourListStride(values) {
|
|
156
|
+
if (values.length < 2) {
|
|
157
|
+
return null;
|
|
158
|
+
}
|
|
159
|
+
const interval = values[1] - values[0];
|
|
160
|
+
if (interval < 2) {
|
|
161
|
+
return null;
|
|
162
|
+
}
|
|
163
|
+
for (let i = 2; i < values.length; i += 1) {
|
|
164
|
+
if (values[i] - values[i - 1] !== interval) {
|
|
165
|
+
return null;
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
if (values[0] !== 0 && values.length < 5) {
|
|
169
|
+
return null;
|
|
170
|
+
}
|
|
171
|
+
return { interval, last: values[values.length - 1], start: values[0] };
|
|
172
|
+
}
|
|
136
173
|
|
|
137
174
|
// src/core/validate.ts
|
|
138
175
|
function validateCronPattern(cronPattern) {
|
|
@@ -481,6 +518,9 @@ function isDiscreteList(field) {
|
|
|
481
518
|
function isDiscreteHours(hourField) {
|
|
482
519
|
return hourField !== "*" && !isPlainRange(hourField) && !isPlainStep(hourField);
|
|
483
520
|
}
|
|
521
|
+
function isOpenStep(field) {
|
|
522
|
+
return field.indexOf("/") !== -1 && field.indexOf("-") === -1 && field.indexOf(",") === -1;
|
|
523
|
+
}
|
|
484
524
|
|
|
485
525
|
// src/core/analyze.ts
|
|
486
526
|
function getOccurrences(start, interval, max) {
|
|
@@ -617,9 +657,9 @@ function analyze(pattern) {
|
|
|
617
657
|
segments
|
|
618
658
|
};
|
|
619
659
|
const content = { analyses, pattern, shapes };
|
|
620
|
-
return { ...content, plan:
|
|
660
|
+
return { ...content, plan: selectPlan(content) };
|
|
621
661
|
}
|
|
622
|
-
function
|
|
662
|
+
function selectPlan(content) {
|
|
623
663
|
const { analyses, pattern, shapes } = content;
|
|
624
664
|
if (pattern.second !== "0") {
|
|
625
665
|
const seconds = planSeconds(pattern, shapes, analyses);
|
|
@@ -875,7 +915,8 @@ var dialects = {
|
|
|
875
915
|
pm: "p.m.",
|
|
876
916
|
sep: ":",
|
|
877
917
|
serialComma: true,
|
|
878
|
-
through: " through "
|
|
918
|
+
through: " through ",
|
|
919
|
+
untilWindow: true
|
|
879
920
|
},
|
|
880
921
|
house: {
|
|
881
922
|
am: "AM",
|
|
@@ -892,7 +933,7 @@ var dialects = {
|
|
|
892
933
|
};
|
|
893
934
|
function resolveDialect(dialect) {
|
|
894
935
|
if (typeof dialect === "object" && dialect !== null) {
|
|
895
|
-
return { ...dialects.us, ...dialect };
|
|
936
|
+
return { ...dialects.us, untilWindow: false, ...dialect };
|
|
896
937
|
}
|
|
897
938
|
const name = dialect === "uk" ? "gb" : dialect;
|
|
898
939
|
return dialects[name] || dialects.us;
|
|
@@ -964,7 +1005,9 @@ function normalizeOptions(options) {
|
|
|
964
1005
|
};
|
|
965
1006
|
}
|
|
966
1007
|
function describe(ir, opts) {
|
|
967
|
-
|
|
1008
|
+
const body = confinement(ir, opts) ?? render(ir, ir.plan, opts);
|
|
1009
|
+
const lead = isDayUnion(ir, opts) ? dayUnionMonthLead(ir, opts) : "";
|
|
1010
|
+
return applyYear(lead + body, ir, opts);
|
|
968
1011
|
}
|
|
969
1012
|
function render(ir, plan, opts) {
|
|
970
1013
|
const renderer = renderers[plan.kind];
|
|
@@ -1049,7 +1092,7 @@ function secondsClause(ir, anchor, opts) {
|
|
|
1049
1092
|
}
|
|
1050
1093
|
if (shape === "step") {
|
|
1051
1094
|
return stepCycle60(
|
|
1052
|
-
ir
|
|
1095
|
+
stepSegment(ir, "second"),
|
|
1053
1096
|
"second",
|
|
1054
1097
|
anchor,
|
|
1055
1098
|
opts
|
|
@@ -1057,19 +1100,19 @@ function secondsClause(ir, anchor, opts) {
|
|
|
1057
1100
|
}
|
|
1058
1101
|
if (shape === "range") {
|
|
1059
1102
|
const bounds = secondField.split("-");
|
|
1060
|
-
const num = seriesNumber(
|
|
1103
|
+
const num = seriesNumber();
|
|
1061
1104
|
return "every second from " + num(bounds[0]) + through(opts) + num(bounds[1]) + " past the " + anchor;
|
|
1062
1105
|
}
|
|
1063
1106
|
if (shape === "single") {
|
|
1064
1107
|
return "at " + getNumber(secondField, opts) + " " + pluralize(secondField, "second") + " past the " + anchor;
|
|
1065
1108
|
}
|
|
1066
1109
|
return strideFromSegments(
|
|
1067
|
-
ir
|
|
1110
|
+
segmentsOf(ir, "second"),
|
|
1068
1111
|
"second",
|
|
1069
1112
|
anchor,
|
|
1070
1113
|
opts
|
|
1071
1114
|
) ?? listPastThe(
|
|
1072
|
-
segmentWords(ir
|
|
1115
|
+
segmentWords(segmentsOf(ir, "second"), opts),
|
|
1073
1116
|
"second",
|
|
1074
1117
|
anchor,
|
|
1075
1118
|
opts
|
|
@@ -1086,15 +1129,15 @@ function renderRangeOfMinutes(ir, plan, opts) {
|
|
|
1086
1129
|
return minuteRangeLead(ir.pattern.minute, opts) + trailingQualifier(ir, opts);
|
|
1087
1130
|
}
|
|
1088
1131
|
function renderMultipleMinutes(ir, plan, opts) {
|
|
1089
|
-
const stride = strideFromSegments(ir
|
|
1132
|
+
const stride = strideFromSegments(segmentsOf(ir, "minute"), "minute", "hour", opts);
|
|
1090
1133
|
return (stride ?? listPastThe(segmentWords(
|
|
1091
|
-
ir
|
|
1134
|
+
segmentsOf(ir, "minute"),
|
|
1092
1135
|
opts
|
|
1093
1136
|
), "minute", "hour", opts)) + trailingQualifier(ir, opts);
|
|
1094
1137
|
}
|
|
1095
1138
|
function renderMinuteFrequency(ir, plan, opts) {
|
|
1096
1139
|
let phrase = stepCycle60(
|
|
1097
|
-
ir
|
|
1140
|
+
stepSegment(ir, "minute"),
|
|
1098
1141
|
"minute",
|
|
1099
1142
|
"hour",
|
|
1100
1143
|
opts
|
|
@@ -1103,9 +1146,14 @@ function renderMinuteFrequency(ir, plan, opts) {
|
|
|
1103
1146
|
const cadence = unevenHourCadence(ir, opts);
|
|
1104
1147
|
phrase += cadence ? ", " + cadence : " during the " + hourTimesFromPlan(ir, plan.hours.times, false, opts) + " hours";
|
|
1105
1148
|
} else if (plan.hours.kind === "window") {
|
|
1106
|
-
phrase += " " +
|
|
1149
|
+
phrase += " " + rangeWindow({
|
|
1150
|
+
continuous: false,
|
|
1151
|
+
from: plan.hours.from,
|
|
1152
|
+
throughMinute: plan.hours.last,
|
|
1153
|
+
to: plan.hours.to
|
|
1154
|
+
}, opts);
|
|
1107
1155
|
} else if (plan.hours.kind === "step") {
|
|
1108
|
-
phrase += " " + everyNthHour(ir
|
|
1156
|
+
phrase += " " + everyNthHour(stepSegment(ir, "hour"), opts);
|
|
1109
1157
|
}
|
|
1110
1158
|
return phrase + trailingQualifier(ir, opts);
|
|
1111
1159
|
}
|
|
@@ -1123,15 +1171,21 @@ function renderMinutesAcrossHours(ir, plan, opts) {
|
|
|
1123
1171
|
}
|
|
1124
1172
|
return "every minute during the " + hourTimesFromPlan(ir, plan.times, false, opts) + " hours" + trailingQualifier(ir, opts);
|
|
1125
1173
|
}
|
|
1126
|
-
|
|
1127
|
-
|
|
1128
|
-
|
|
1129
|
-
|
|
1130
|
-
|
|
1131
|
-
|
|
1132
|
-
"
|
|
1133
|
-
|
|
1134
|
-
)
|
|
1174
|
+
if (plan.form === "range") {
|
|
1175
|
+
const lead2 = minuteRangeLead(ir.pattern.minute, opts);
|
|
1176
|
+
if (cadence !== null) {
|
|
1177
|
+
return lead2 + ", " + cadence + trailingQualifier(ir, opts);
|
|
1178
|
+
}
|
|
1179
|
+
if (singleHourFire(plan.times)) {
|
|
1180
|
+
return lead2 + ", at " + hourTimesFromPlan(ir, plan.times, true, opts) + trailingQualifier(ir, opts);
|
|
1181
|
+
}
|
|
1182
|
+
return lead2 + " during the " + hourTimesFromPlan(ir, plan.times, false, opts) + " hours" + trailingQualifier(ir, opts);
|
|
1183
|
+
}
|
|
1184
|
+
const lead = strideFromSegments(segmentsOf(ir, "minute"), "minute", "hour", opts) ?? listPastThe(
|
|
1185
|
+
segmentWords(segmentsOf(ir, "minute"), opts),
|
|
1186
|
+
"minute",
|
|
1187
|
+
"hour",
|
|
1188
|
+
opts
|
|
1135
1189
|
);
|
|
1136
1190
|
if (cadence !== null) {
|
|
1137
1191
|
return lead + ", " + cadence + trailingQualifier(ir, opts);
|
|
@@ -1153,12 +1207,12 @@ function everyNthHour(segment, opts) {
|
|
|
1153
1207
|
return start === 0 ? base : base + " starting at " + getTime({ hour: start, minute: 0 }, opts);
|
|
1154
1208
|
}
|
|
1155
1209
|
function renderMinuteSpanAcrossHourStep(ir, plan, opts) {
|
|
1156
|
-
const segment = ir
|
|
1210
|
+
const segment = stepSegment(ir, "hour");
|
|
1157
1211
|
if (plan.form === "wildcard") {
|
|
1158
1212
|
return "every minute " + everyNthHour(segment, opts) + trailingQualifier(ir, opts);
|
|
1159
1213
|
}
|
|
1160
|
-
const lead = plan.form === "list" ? strideFromSegments(ir
|
|
1161
|
-
segmentWords(ir
|
|
1214
|
+
const lead = plan.form === "list" ? strideFromSegments(segmentsOf(ir, "minute"), "minute", "hour", opts) ?? listPastThe(
|
|
1215
|
+
segmentWords(segmentsOf(ir, "minute"), opts),
|
|
1162
1216
|
"minute",
|
|
1163
1217
|
"hour",
|
|
1164
1218
|
opts
|
|
@@ -1168,7 +1222,7 @@ function renderMinuteSpanAcrossHourStep(ir, plan, opts) {
|
|
|
1168
1222
|
}
|
|
1169
1223
|
function minuteRangeLead(minuteField, opts) {
|
|
1170
1224
|
const bounds = minuteField.split("-");
|
|
1171
|
-
const num = seriesNumber(
|
|
1225
|
+
const num = seriesNumber();
|
|
1172
1226
|
return "every minute from " + num(bounds[0]) + through(opts) + num(bounds[1]) + " past the hour";
|
|
1173
1227
|
}
|
|
1174
1228
|
function renderEveryHour(ir, plan, opts) {
|
|
@@ -1189,12 +1243,12 @@ function rangeMinuteLead(ir, opts) {
|
|
|
1189
1243
|
return "every hour";
|
|
1190
1244
|
}
|
|
1191
1245
|
return strideFromSegments(
|
|
1192
|
-
ir
|
|
1246
|
+
segmentsOf(ir, "minute"),
|
|
1193
1247
|
"minute",
|
|
1194
1248
|
"hour",
|
|
1195
1249
|
opts
|
|
1196
1250
|
) ?? listPastThe(
|
|
1197
|
-
segmentWords(ir
|
|
1251
|
+
segmentWords(segmentsOf(ir, "minute"), opts),
|
|
1198
1252
|
"minute",
|
|
1199
1253
|
"hour",
|
|
1200
1254
|
opts
|
|
@@ -1205,14 +1259,28 @@ function renderHourStep(ir, plan, opts) {
|
|
|
1205
1259
|
if (cadence !== null) {
|
|
1206
1260
|
return cadence + trailingQualifier(ir, opts);
|
|
1207
1261
|
}
|
|
1208
|
-
return stepHours(ir
|
|
1262
|
+
return stepHours(stepSegment(ir, "hour"), opts) + trailingQualifier(ir, opts);
|
|
1209
1263
|
}
|
|
1210
1264
|
function boundedWindow(plan) {
|
|
1211
|
-
const
|
|
1212
|
-
|
|
1265
|
+
const continuous = plan.minuteForm === "wildcard";
|
|
1266
|
+
const closeMinute = continuous ? plan.boundMinute ?? 0 : 0;
|
|
1267
|
+
return { from: plan.from, closeMinute, to: plan.to, continuous };
|
|
1268
|
+
}
|
|
1269
|
+
function rangeWindow(window, opts) {
|
|
1270
|
+
const { from, to, throughMinute, continuous } = window;
|
|
1271
|
+
const open = "from " + getTime({ hour: from, minute: 0 }, opts);
|
|
1272
|
+
if (opts.style.untilWindow && !opts.short && from !== to) {
|
|
1273
|
+
return continuous ? open + " until " + getTime({ hour: (to + 1) % 24, minute: 0 }, opts) : open + through(opts) + getTime({ hour: to, minute: 0 }, opts);
|
|
1274
|
+
}
|
|
1275
|
+
return open + through(opts) + getTime({ hour: to, minute: throughMinute }, opts);
|
|
1213
1276
|
}
|
|
1214
1277
|
function hourWindow(window, opts) {
|
|
1215
|
-
return
|
|
1278
|
+
return rangeWindow({
|
|
1279
|
+
continuous: window.continuous,
|
|
1280
|
+
from: window.from,
|
|
1281
|
+
throughMinute: window.closeMinute,
|
|
1282
|
+
to: window.to
|
|
1283
|
+
}, opts);
|
|
1216
1284
|
}
|
|
1217
1285
|
function renderClockTimes(ir, plan, opts) {
|
|
1218
1286
|
if (ir.shapes.minute === "single") {
|
|
@@ -1231,7 +1299,10 @@ function renderClockTimes(ir, plan, opts) {
|
|
|
1231
1299
|
plain
|
|
1232
1300
|
}, opts);
|
|
1233
1301
|
});
|
|
1234
|
-
return interpretDayQualifier(ir, opts) + "at " + joinList(times, opts);
|
|
1302
|
+
return interpretDayQualifier(ir, opts) + "at " + joinList(times, opts) + dayUnionTrail(ir, opts);
|
|
1303
|
+
}
|
|
1304
|
+
function dayUnionTrail(ir, opts) {
|
|
1305
|
+
return isDayUnion(ir, opts) ? dayUnionCondition(ir, opts) : "";
|
|
1235
1306
|
}
|
|
1236
1307
|
function renderCompactClockTimes(ir, plan, opts) {
|
|
1237
1308
|
if (plan.fold) {
|
|
@@ -1239,20 +1310,20 @@ function renderCompactClockTimes(ir, plan, opts) {
|
|
|
1239
1310
|
if (cadence2 !== null) {
|
|
1240
1311
|
return cadence2;
|
|
1241
1312
|
}
|
|
1242
|
-
const hasRange = ir
|
|
1313
|
+
const hasRange = segmentsOf(ir, "hour").some(function range(segment) {
|
|
1243
1314
|
return segment.kind === "range";
|
|
1244
1315
|
});
|
|
1245
1316
|
if (hasRange && !ir.analyses.clockSecond) {
|
|
1246
1317
|
return foldedHourWindows(ir, plan, opts) + trailingQualifier(ir, opts);
|
|
1247
1318
|
}
|
|
1248
1319
|
const fold = { minute: plan.minute, second: ir.analyses.clockSecond };
|
|
1249
|
-
return interpretDayQualifier(ir, opts) + "at " + hourSegmentTimes(ir, fold, true, opts);
|
|
1320
|
+
return interpretDayQualifier(ir, opts) + "at " + hourSegmentTimes(ir, fold, true, opts) + dayUnionTrail(ir, opts);
|
|
1250
1321
|
}
|
|
1251
1322
|
const minuteLead = (
|
|
1252
1323
|
// The non-fold branch is a minute list, which has segments. An
|
|
1253
1324
|
// offset/uneven step enumerated to that list reads as a stride.
|
|
1254
|
-
strideFromSegments(ir
|
|
1255
|
-
segmentWords(ir
|
|
1325
|
+
strideFromSegments(segmentsOf(ir, "minute"), "minute", "hour", opts) ?? listPastThe(
|
|
1326
|
+
segmentWords(segmentsOf(ir, "minute"), opts),
|
|
1256
1327
|
"minute",
|
|
1257
1328
|
"hour",
|
|
1258
1329
|
opts
|
|
@@ -1265,26 +1336,162 @@ function renderCompactClockTimes(ir, plan, opts) {
|
|
|
1265
1336
|
function foldedHourWindows(ir, plan, opts) {
|
|
1266
1337
|
const minute = plan.minute;
|
|
1267
1338
|
const windows = [];
|
|
1268
|
-
const
|
|
1269
|
-
|
|
1339
|
+
const times = collectHourOutliers(ir).map(function time(hour) {
|
|
1340
|
+
return getTime({ hour, minute }, opts);
|
|
1341
|
+
});
|
|
1342
|
+
segmentsOf(ir, "hour").forEach(function classify(segment) {
|
|
1270
1343
|
if (segment.kind === "range") {
|
|
1271
|
-
windows.push(
|
|
1272
|
-
|
|
1273
|
-
|
|
1274
|
-
|
|
1275
|
-
|
|
1276
|
-
|
|
1277
|
-
}
|
|
1278
|
-
|
|
1344
|
+
windows.push(rangeWindow({
|
|
1345
|
+
continuous: false,
|
|
1346
|
+
from: +segment.bounds[0],
|
|
1347
|
+
throughMinute: minute,
|
|
1348
|
+
to: +segment.bounds[1]
|
|
1349
|
+
}, opts));
|
|
1350
|
+
}
|
|
1351
|
+
});
|
|
1352
|
+
const phrase = rangeMinuteLead(ir, opts) + " " + joinList(windows, opts);
|
|
1353
|
+
return phrase + outlierTail(times, opts);
|
|
1354
|
+
}
|
|
1355
|
+
function collectHourOutliers(ir) {
|
|
1356
|
+
const hours = [];
|
|
1357
|
+
segmentsOf(ir, "hour").forEach(function classify(segment) {
|
|
1358
|
+
if (segment.kind === "step") {
|
|
1359
|
+
hours.push(...segment.fires);
|
|
1360
|
+
} else if (segment.kind !== "range") {
|
|
1361
|
+
hours.push(+segment.value);
|
|
1279
1362
|
}
|
|
1280
1363
|
});
|
|
1281
|
-
|
|
1282
|
-
|
|
1283
|
-
|
|
1284
|
-
|
|
1285
|
-
|
|
1364
|
+
return hours;
|
|
1365
|
+
}
|
|
1366
|
+
function outlierTail(times, opts) {
|
|
1367
|
+
if (!times.length) {
|
|
1368
|
+
return "";
|
|
1286
1369
|
}
|
|
1287
|
-
return
|
|
1370
|
+
return " and at " + joinList(times, opts);
|
|
1371
|
+
}
|
|
1372
|
+
function isCadenceField(token) {
|
|
1373
|
+
return token === "*" || token.startsWith("*/") && token.indexOf("-") === -1;
|
|
1374
|
+
}
|
|
1375
|
+
function leadingCadence(ir, opts) {
|
|
1376
|
+
const { second, minute } = ir.pattern;
|
|
1377
|
+
if (isCadenceField(second)) {
|
|
1378
|
+
return { secondLead: true, text: secondsClause(ir, "minute", opts) };
|
|
1379
|
+
}
|
|
1380
|
+
if (second === "0" && isCadenceField(minute)) {
|
|
1381
|
+
const text = minute === "*" ? "every minute" : (
|
|
1382
|
+
// A clean minute step's first segment is a step segment.
|
|
1383
|
+
stepCycle60(
|
|
1384
|
+
stepSegment(ir, "minute"),
|
|
1385
|
+
"minute",
|
|
1386
|
+
"hour",
|
|
1387
|
+
opts
|
|
1388
|
+
)
|
|
1389
|
+
);
|
|
1390
|
+
return { secondLead: false, text };
|
|
1391
|
+
}
|
|
1392
|
+
return null;
|
|
1393
|
+
}
|
|
1394
|
+
function minuteConfinement(ir, opts) {
|
|
1395
|
+
const minute = ir.pattern.minute;
|
|
1396
|
+
if (minute === "*") {
|
|
1397
|
+
return "";
|
|
1398
|
+
}
|
|
1399
|
+
if (isCadenceField(minute)) {
|
|
1400
|
+
return " of every other minute";
|
|
1401
|
+
}
|
|
1402
|
+
const segments = segmentsOf(ir, "minute");
|
|
1403
|
+
if (ir.shapes.minute === "single") {
|
|
1404
|
+
return " during minute :" + pad(minute);
|
|
1405
|
+
}
|
|
1406
|
+
if (ir.shapes.minute === "range") {
|
|
1407
|
+
const bounds = minute.split("-");
|
|
1408
|
+
return " during minutes :" + pad(bounds[0]) + through(opts) + ":" + pad(bounds[1]);
|
|
1409
|
+
}
|
|
1410
|
+
const values = segmentWords(segments, opts).map(function colon(word) {
|
|
1411
|
+
return ":" + pad(word);
|
|
1412
|
+
});
|
|
1413
|
+
return " during minutes " + joinList(values, opts);
|
|
1414
|
+
}
|
|
1415
|
+
function hourConfinement(ir, opts) {
|
|
1416
|
+
const hour = ir.pattern.hour;
|
|
1417
|
+
if (hour === "*") {
|
|
1418
|
+
const minutePinned = ir.pattern.minute !== "*" && !isCadenceField(ir.pattern.minute);
|
|
1419
|
+
return minutePinned ? " of every hour" : "";
|
|
1420
|
+
}
|
|
1421
|
+
if (isCadenceField(hour)) {
|
|
1422
|
+
return hour === "*/2" ? " of every other hour" : "";
|
|
1423
|
+
}
|
|
1424
|
+
if (ir.shapes.hour === "single") {
|
|
1425
|
+
const h = +hour;
|
|
1426
|
+
if (ir.shapes.minute === "step") {
|
|
1427
|
+
return " from " + getTime({ hour: h, minute: 0 }, opts) + " until " + getTime({ hour: (h + 1) % 24, minute: 0 }, opts);
|
|
1428
|
+
}
|
|
1429
|
+
if (ir.pattern.minute !== "*" && !isCadenceField(ir.pattern.minute)) {
|
|
1430
|
+
return " at " + getTime({ hour: h, minute: 0 }, opts);
|
|
1431
|
+
}
|
|
1432
|
+
return " of the " + getTime({ hour: h, minute: 0 }, opts) + " hour";
|
|
1433
|
+
}
|
|
1434
|
+
if (ir.shapes.hour === "range") {
|
|
1435
|
+
const bounds = hour.split("-");
|
|
1436
|
+
return " " + rangeWindow({
|
|
1437
|
+
continuous: ir.pattern.minute === "*",
|
|
1438
|
+
from: +bounds[0],
|
|
1439
|
+
throughMinute: 0,
|
|
1440
|
+
to: +bounds[1]
|
|
1441
|
+
}, opts);
|
|
1442
|
+
}
|
|
1443
|
+
return " during the " + hourSegmentTimes(ir, { minute: 0, second: null }, false, opts) + " hours";
|
|
1444
|
+
}
|
|
1445
|
+
function isContiguousHourRange(ir) {
|
|
1446
|
+
return ir.shapes.hour === "range";
|
|
1447
|
+
}
|
|
1448
|
+
function confinableHour(ir) {
|
|
1449
|
+
if (ir.shapes.hour !== "step") {
|
|
1450
|
+
return true;
|
|
1451
|
+
}
|
|
1452
|
+
const segment = stepSegment(ir, "hour");
|
|
1453
|
+
return ir.pattern.hour === "*/2" || segment.startToken.indexOf("-") !== -1;
|
|
1454
|
+
}
|
|
1455
|
+
function isMinuteStride(ir) {
|
|
1456
|
+
if (ir.shapes.minute !== "list") {
|
|
1457
|
+
return false;
|
|
1458
|
+
}
|
|
1459
|
+
const values = singleValues(segmentsOf(ir, "minute"));
|
|
1460
|
+
return values !== null && arithmeticStep(values) !== null;
|
|
1461
|
+
}
|
|
1462
|
+
function confinementEligible(ir, lead) {
|
|
1463
|
+
const { minute, hour } = ir.pattern;
|
|
1464
|
+
const minuteStep = isCadenceField(minute) && minute !== "*";
|
|
1465
|
+
if (!confinableHour(ir)) {
|
|
1466
|
+
return false;
|
|
1467
|
+
}
|
|
1468
|
+
if (lead.secondLead) {
|
|
1469
|
+
if (minuteStep) {
|
|
1470
|
+
return minute === "*/2" && !isContiguousHourRange(ir);
|
|
1471
|
+
}
|
|
1472
|
+
if (isMinuteStride(ir) || ir.shapes.minute === "list" && ir.shapes.hour === "list") {
|
|
1473
|
+
return false;
|
|
1474
|
+
}
|
|
1475
|
+
return true;
|
|
1476
|
+
}
|
|
1477
|
+
if (hour === "*/2") {
|
|
1478
|
+
return true;
|
|
1479
|
+
}
|
|
1480
|
+
return ir.shapes.hour === "single" && minute === "*/2";
|
|
1481
|
+
}
|
|
1482
|
+
function confinement(ir, opts) {
|
|
1483
|
+
if (!opts.style.untilWindow || opts.short) {
|
|
1484
|
+
return null;
|
|
1485
|
+
}
|
|
1486
|
+
if (ir.pattern.minute === "*" && ir.pattern.hour === "*") {
|
|
1487
|
+
return null;
|
|
1488
|
+
}
|
|
1489
|
+
const lead = leadingCadence(ir, opts);
|
|
1490
|
+
if (!lead || !confinementEligible(ir, lead)) {
|
|
1491
|
+
return null;
|
|
1492
|
+
}
|
|
1493
|
+
const minutePart = lead.secondLead ? minuteConfinement(ir, opts) : "";
|
|
1494
|
+
return lead.text + minutePart + hourConfinement(ir, opts) + trailingQualifier(ir, opts);
|
|
1288
1495
|
}
|
|
1289
1496
|
var renderers = {
|
|
1290
1497
|
clockTimes: renderClockTimes,
|
|
@@ -1316,19 +1523,9 @@ function renderStride(stride, opts) {
|
|
|
1316
1523
|
if (start < interval && tiles) {
|
|
1317
1524
|
return cadence + " from " + getNumber(start, opts) + " " + pluralize(start, unit) + " past the " + anchor;
|
|
1318
1525
|
}
|
|
1319
|
-
const num = seriesNumber(
|
|
1526
|
+
const num = seriesNumber();
|
|
1320
1527
|
return cadence + " from " + num(start) + through(opts) + num(last) + " " + pluralize(last, unit) + " past the " + anchor;
|
|
1321
1528
|
}
|
|
1322
|
-
function singleValues(segments) {
|
|
1323
|
-
const values = [];
|
|
1324
|
-
for (const segment of segments) {
|
|
1325
|
-
if (segment.kind !== "single") {
|
|
1326
|
-
return null;
|
|
1327
|
-
}
|
|
1328
|
-
values.push(+segment.value);
|
|
1329
|
-
}
|
|
1330
|
-
return values;
|
|
1331
|
-
}
|
|
1332
1529
|
function strideFromSegments(segments, unit, anchor, opts) {
|
|
1333
1530
|
const values = singleValues(segments);
|
|
1334
1531
|
const step = values && arithmeticStep(values);
|
|
@@ -1377,9 +1574,6 @@ function hourStrideCadence(stride, opts) {
|
|
|
1377
1574
|
}
|
|
1378
1575
|
return cadence + " from " + getTime({ hour: start, minute: 0 }, opts) + through(opts) + getTime({ hour: last, minute: 0 }, opts);
|
|
1379
1576
|
}
|
|
1380
|
-
function offsetCleanStride(stride) {
|
|
1381
|
-
return stride.start < stride.interval && 24 % stride.interval === 0;
|
|
1382
|
-
}
|
|
1383
1577
|
function unevenHourCadence(ir, opts) {
|
|
1384
1578
|
const stride = hourStride(ir);
|
|
1385
1579
|
if (!stride || offsetCleanStride(stride)) {
|
|
@@ -1387,26 +1581,8 @@ function unevenHourCadence(ir, opts) {
|
|
|
1387
1581
|
}
|
|
1388
1582
|
return hourStrideCadence(stride, opts);
|
|
1389
1583
|
}
|
|
1390
|
-
function hourListStride(values) {
|
|
1391
|
-
if (values.length < 2) {
|
|
1392
|
-
return null;
|
|
1393
|
-
}
|
|
1394
|
-
const interval = values[1] - values[0];
|
|
1395
|
-
if (interval < 2) {
|
|
1396
|
-
return null;
|
|
1397
|
-
}
|
|
1398
|
-
for (let i = 2; i < values.length; i += 1) {
|
|
1399
|
-
if (values[i] - values[i - 1] !== interval) {
|
|
1400
|
-
return null;
|
|
1401
|
-
}
|
|
1402
|
-
}
|
|
1403
|
-
if (values[0] !== 0 && values.length < 5) {
|
|
1404
|
-
return null;
|
|
1405
|
-
}
|
|
1406
|
-
return { interval, last: values[values.length - 1], start: values[0] };
|
|
1407
|
-
}
|
|
1408
1584
|
function hourStride(ir) {
|
|
1409
|
-
const segments = ir
|
|
1585
|
+
const segments = segmentsOf(ir, "hour");
|
|
1410
1586
|
if (segments.length === 1 && segments[0].kind === "step") {
|
|
1411
1587
|
const segment = segments[0];
|
|
1412
1588
|
if (segment.fires.length < 2) {
|
|
@@ -1443,9 +1619,9 @@ function hourCadence(ir, minute, opts) {
|
|
|
1443
1619
|
if (ir.pattern.second === "0" && fires <= maxClockTimes && offsetCleanStride(stride)) {
|
|
1444
1620
|
return null;
|
|
1445
1621
|
}
|
|
1446
|
-
const
|
|
1447
|
-
if (
|
|
1448
|
-
return secondsClause(ir, "minute", opts) + " for one minute " + everyNthHour(
|
|
1622
|
+
const minuteZeroStride = minute === 0 && subMinuteSecond(ir) && cleanStrideSegment(ir);
|
|
1623
|
+
if (minuteZeroStride) {
|
|
1624
|
+
return secondsClause(ir, "minute", opts) + " for one minute " + everyNthHour(minuteZeroStride, opts) + trailingQualifier(ir, opts);
|
|
1449
1625
|
}
|
|
1450
1626
|
if (minute === 0 && ir.pattern.second === "0") {
|
|
1451
1627
|
return hourStrideCadence(stride, opts) + trailingQualifier(ir, opts);
|
|
@@ -1453,7 +1629,7 @@ function hourCadence(ir, minute, opts) {
|
|
|
1453
1629
|
return hourCadenceLead(ir, minute, opts) + ", " + hourStrideCadence(stride, opts) + trailingQualifier(ir, opts);
|
|
1454
1630
|
}
|
|
1455
1631
|
function cleanStrideSegment(ir) {
|
|
1456
|
-
const segments = ir
|
|
1632
|
+
const segments = segmentsOf(ir, "hour");
|
|
1457
1633
|
const segment = segments.length === 1 && segments[0];
|
|
1458
1634
|
if (!segment || segment.kind !== "step" || segment.startToken.indexOf("-") !== -1 || !(segment.interval in stepOrdinals)) {
|
|
1459
1635
|
return null;
|
|
@@ -1461,32 +1637,28 @@ function cleanStrideSegment(ir) {
|
|
|
1461
1637
|
return segment;
|
|
1462
1638
|
}
|
|
1463
1639
|
function hasHourWindow(ir) {
|
|
1464
|
-
return ir
|
|
1640
|
+
return segmentsOf(ir, "hour").some(function range(segment) {
|
|
1465
1641
|
return segment.kind === "range";
|
|
1466
1642
|
});
|
|
1467
1643
|
}
|
|
1468
1644
|
function hourRangeWindowTail(ir, opts) {
|
|
1469
1645
|
const windows = [];
|
|
1470
|
-
const
|
|
1471
|
-
ir
|
|
1646
|
+
const outlierHours = collectHourOutliers(ir);
|
|
1647
|
+
segmentsOf(ir, "hour").forEach(function classify(segment) {
|
|
1472
1648
|
if (segment.kind === "range") {
|
|
1473
|
-
windows.push(
|
|
1474
|
-
|
|
1475
|
-
|
|
1476
|
-
|
|
1477
|
-
|
|
1478
|
-
|
|
1479
|
-
} else {
|
|
1480
|
-
singles.push(+segment.value);
|
|
1649
|
+
windows.push(rangeWindow({
|
|
1650
|
+
continuous: false,
|
|
1651
|
+
from: +segment.bounds[0],
|
|
1652
|
+
throughMinute: 0,
|
|
1653
|
+
to: +segment.bounds[1]
|
|
1654
|
+
}, opts));
|
|
1481
1655
|
}
|
|
1482
1656
|
});
|
|
1483
|
-
|
|
1484
|
-
|
|
1485
|
-
|
|
1486
|
-
|
|
1487
|
-
|
|
1488
|
-
}
|
|
1489
|
-
return phrase;
|
|
1657
|
+
const phrase = "every hour " + joinList(windows, opts);
|
|
1658
|
+
const times = outlierHours.map(function time(hour) {
|
|
1659
|
+
return getTime({ hour, minute: 0 }, opts);
|
|
1660
|
+
});
|
|
1661
|
+
return phrase + outlierTail(times, opts);
|
|
1490
1662
|
}
|
|
1491
1663
|
function hourRangeCadence(ir, minute, opts) {
|
|
1492
1664
|
if (minute !== 0 || !hasHourWindow(ir)) {
|
|
@@ -1500,25 +1672,29 @@ function hourRangeCadence(ir, minute, opts) {
|
|
|
1500
1672
|
}
|
|
1501
1673
|
return hourCadenceLead(ir, minute, opts) + ", " + hourRangeWindowTail(ir, opts) + trailingQualifier(ir, opts);
|
|
1502
1674
|
}
|
|
1503
|
-
function seriesNumber(
|
|
1504
|
-
const anyBig = values.some(function big(v) {
|
|
1505
|
-
return +v > 10;
|
|
1506
|
-
});
|
|
1675
|
+
function seriesNumber() {
|
|
1507
1676
|
return function format(n) {
|
|
1508
|
-
return
|
|
1677
|
+
return "" + n;
|
|
1678
|
+
};
|
|
1679
|
+
}
|
|
1680
|
+
function listNumber(count, opts) {
|
|
1681
|
+
return count > 1 ? function asNumeral(n) {
|
|
1682
|
+
return "" + n;
|
|
1683
|
+
} : function spelled(n) {
|
|
1684
|
+
return getNumber(n, opts);
|
|
1509
1685
|
};
|
|
1510
1686
|
}
|
|
1511
1687
|
function numberWords(fires, opts) {
|
|
1512
|
-
return fires.map(
|
|
1688
|
+
return fires.map(listNumber(fires.length, opts));
|
|
1513
1689
|
}
|
|
1514
1690
|
function segmentWords(segments, opts) {
|
|
1515
|
-
const
|
|
1691
|
+
const count = segments.reduce(function tally(sum, segment) {
|
|
1516
1692
|
if (segment.kind === "range") {
|
|
1517
|
-
return
|
|
1693
|
+
return sum + 1;
|
|
1518
1694
|
}
|
|
1519
|
-
return segment.kind === "step" ? segment.fires :
|
|
1520
|
-
});
|
|
1521
|
-
const num =
|
|
1695
|
+
return sum + (segment.kind === "step" ? segment.fires.length : 1);
|
|
1696
|
+
}, 0);
|
|
1697
|
+
const num = listNumber(count, opts);
|
|
1522
1698
|
return segments.flatMap(function word(segment) {
|
|
1523
1699
|
if (segment.kind === "range") {
|
|
1524
1700
|
return [num(segment.bounds[0]) + through(opts) + num(segment.bounds[1])];
|
|
@@ -1550,6 +1726,9 @@ function hourTimes(hours, opts) {
|
|
|
1550
1726
|
});
|
|
1551
1727
|
return joinList(times, opts);
|
|
1552
1728
|
}
|
|
1729
|
+
function singleHourFire(times) {
|
|
1730
|
+
return times.kind === "fires" && times.fires.length === 1;
|
|
1731
|
+
}
|
|
1553
1732
|
function hourTimesFromPlan(ir, times, atContext, opts) {
|
|
1554
1733
|
if (times.kind === "fires") {
|
|
1555
1734
|
return hourTimes(times.fires, opts);
|
|
@@ -1564,7 +1743,7 @@ function segmentHours(segment) {
|
|
|
1564
1743
|
}
|
|
1565
1744
|
function hourSegmentTimes(ir, fold, atContext, opts) {
|
|
1566
1745
|
const { minute, second } = fold;
|
|
1567
|
-
const segments = ir
|
|
1746
|
+
const segments = segmentsOf(ir, "hour");
|
|
1568
1747
|
const plain = mixedTwelve(segments.flatMap(function entries(segment) {
|
|
1569
1748
|
return segmentHours(segment).map(function entry(hour) {
|
|
1570
1749
|
return { hour: +hour, minute, second };
|
|
@@ -1597,28 +1776,47 @@ function disambiguateTimes(pieces, segments, atContext) {
|
|
|
1597
1776
|
return index === 0 ? piece : "at " + piece;
|
|
1598
1777
|
});
|
|
1599
1778
|
}
|
|
1600
|
-
function
|
|
1779
|
+
function joinWith(items, conjunction, opts) {
|
|
1601
1780
|
if (items.length <= 1) {
|
|
1602
1781
|
return items.join("");
|
|
1603
1782
|
}
|
|
1604
1783
|
if (items.length === 2) {
|
|
1605
|
-
return items[0] +
|
|
1784
|
+
return items[0] + conjunction + items[1];
|
|
1606
1785
|
}
|
|
1607
|
-
const
|
|
1608
|
-
return items.slice(0, -1).join(", ") +
|
|
1786
|
+
const tail = opts.style.serialComma ? "," + conjunction : conjunction;
|
|
1787
|
+
return items.slice(0, -1).join(", ") + tail + items[items.length - 1];
|
|
1788
|
+
}
|
|
1789
|
+
function joinList(items, opts) {
|
|
1790
|
+
return joinWith(items, " and ", opts);
|
|
1609
1791
|
}
|
|
1610
|
-
|
|
1792
|
+
function joinOr(items, opts) {
|
|
1793
|
+
return joinWith(items, " or ", opts);
|
|
1794
|
+
}
|
|
1795
|
+
var trailingWords = {
|
|
1796
|
+
all: "",
|
|
1797
|
+
month: "in ",
|
|
1798
|
+
recurringWeekday: true,
|
|
1799
|
+
stepDate: "on ",
|
|
1800
|
+
weekday: "on "
|
|
1801
|
+
};
|
|
1611
1802
|
var leadingWords = {
|
|
1612
1803
|
all: "every day",
|
|
1613
1804
|
month: "every day in ",
|
|
1805
|
+
recurringWeekday: false,
|
|
1614
1806
|
stepDate: "",
|
|
1615
1807
|
weekday: "every "
|
|
1616
1808
|
};
|
|
1617
1809
|
function trailingQualifier(ir, opts) {
|
|
1810
|
+
if (isDayUnion(ir, opts)) {
|
|
1811
|
+
return dayUnionCondition(ir, opts);
|
|
1812
|
+
}
|
|
1618
1813
|
const phrase = dayQualifier(ir, trailingWords, opts);
|
|
1619
1814
|
return phrase && " " + phrase;
|
|
1620
1815
|
}
|
|
1621
1816
|
function interpretDayQualifier(ir, opts) {
|
|
1817
|
+
if (isDayUnion(ir, opts)) {
|
|
1818
|
+
return "";
|
|
1819
|
+
}
|
|
1622
1820
|
return dayQualifier(ir, leadingWords, opts) + " ";
|
|
1623
1821
|
}
|
|
1624
1822
|
function dayQualifier(ir, words, opts) {
|
|
@@ -1630,7 +1828,11 @@ function dayQualifier(ir, words, opts) {
|
|
|
1630
1828
|
return datePhrase(ir, words, opts);
|
|
1631
1829
|
}
|
|
1632
1830
|
if (pattern.weekday !== "*") {
|
|
1633
|
-
const
|
|
1831
|
+
const quartzWeekday = quartzWeekdayPhrase(pattern.weekday, opts);
|
|
1832
|
+
if (quartzWeekday) {
|
|
1833
|
+
return monthScopeForRecurrence(quartzWeekday, ir, opts);
|
|
1834
|
+
}
|
|
1835
|
+
const weekdays = words.weekday + weekdayPhrase(ir, words.recurringWeekday, opts);
|
|
1634
1836
|
return weekdays + monthScope(ir, opts);
|
|
1635
1837
|
}
|
|
1636
1838
|
if (pattern.month !== "*") {
|
|
@@ -1642,10 +1844,14 @@ function datePhrase(ir, words, opts) {
|
|
|
1642
1844
|
const pattern = ir.pattern;
|
|
1643
1845
|
const quartzDate = quartzDatePhrase(pattern.date, opts);
|
|
1644
1846
|
if (quartzDate) {
|
|
1645
|
-
return quartzDate
|
|
1847
|
+
return monthScopeForRecurrence(quartzDate, ir, opts);
|
|
1646
1848
|
}
|
|
1647
1849
|
if (isOpenStep(pattern.date)) {
|
|
1648
|
-
return
|
|
1850
|
+
return monthScopeForRecurrence(
|
|
1851
|
+
words.stepDate + stepDates(pattern.date),
|
|
1852
|
+
ir,
|
|
1853
|
+
opts
|
|
1854
|
+
);
|
|
1649
1855
|
}
|
|
1650
1856
|
if (pattern.month !== "*" && !monthFoldsIntoDate(ir)) {
|
|
1651
1857
|
return "on the " + dateOrdinals(ir, opts) + monthScope(ir, opts);
|
|
@@ -1657,13 +1863,88 @@ function datePhrase(ir, words, opts) {
|
|
|
1657
1863
|
}
|
|
1658
1864
|
function monthFoldsIntoDate(ir) {
|
|
1659
1865
|
return !oddEvenMonth(ir.pattern.month) && // Reached only with a restricted month, which has segments.
|
|
1660
|
-
ir
|
|
1866
|
+
segmentsOf(ir, "month").every(function flat(segment) {
|
|
1661
1867
|
return segment.kind !== "range";
|
|
1662
1868
|
});
|
|
1663
1869
|
}
|
|
1870
|
+
function isDayUnion(ir, opts) {
|
|
1871
|
+
return ir.pattern.date !== "*" && ir.pattern.weekday !== "*" && !!opts.style.untilWindow && !opts.short;
|
|
1872
|
+
}
|
|
1873
|
+
function dayUnionCondition(ir, opts) {
|
|
1874
|
+
const pieces = [
|
|
1875
|
+
...dayUnionDatePieces(ir, opts),
|
|
1876
|
+
...dayUnionWeekdayPieces(ir, opts)
|
|
1877
|
+
];
|
|
1878
|
+
return " whenever the day is " + joinOr(pieces, opts);
|
|
1879
|
+
}
|
|
1880
|
+
function dayUnionMonthLead(ir, opts) {
|
|
1881
|
+
if (ir.pattern.month === "*") {
|
|
1882
|
+
return "";
|
|
1883
|
+
}
|
|
1884
|
+
return "in " + monthName(ir, opts) + " ";
|
|
1885
|
+
}
|
|
1886
|
+
function dayUnionDatePieces(ir, opts) {
|
|
1887
|
+
const dateField = ir.pattern.date;
|
|
1888
|
+
const quartz = quartzDatePhrase(dateField, opts);
|
|
1889
|
+
if (quartz) {
|
|
1890
|
+
return [quartz.replace(/^on /, "")];
|
|
1891
|
+
}
|
|
1892
|
+
const oddEven = oddEvenDay(dateField);
|
|
1893
|
+
if (oddEven) {
|
|
1894
|
+
return [oddEven];
|
|
1895
|
+
}
|
|
1896
|
+
const pieces = [];
|
|
1897
|
+
segmentsOf(ir, "date").forEach(function expand(segment) {
|
|
1898
|
+
if (segment.kind === "range") {
|
|
1899
|
+
pieces.push("from the " + getOrdinal(segment.bounds[0]) + through(opts) + "the " + getOrdinal(segment.bounds[1]));
|
|
1900
|
+
} else if (segment.kind === "step") {
|
|
1901
|
+
segment.fires.forEach(function fire(value) {
|
|
1902
|
+
pieces.push("the " + getOrdinal(value));
|
|
1903
|
+
});
|
|
1904
|
+
} else {
|
|
1905
|
+
pieces.push("the " + getOrdinal(segment.value));
|
|
1906
|
+
}
|
|
1907
|
+
});
|
|
1908
|
+
return pieces;
|
|
1909
|
+
}
|
|
1910
|
+
function dayUnionWeekdayPieces(ir, opts) {
|
|
1911
|
+
const weekdayField = ir.pattern.weekday;
|
|
1912
|
+
const quartz = quartzWeekdayPhrase(weekdayField, opts);
|
|
1913
|
+
if (quartz) {
|
|
1914
|
+
return [quartz.replace(/^on /, "")];
|
|
1915
|
+
}
|
|
1916
|
+
const pieces = [];
|
|
1917
|
+
segmentsOf(ir, "weekday").forEach(function expand(segment) {
|
|
1918
|
+
if (segment.kind === "range" && segment.bounds[0] === "1" && segment.bounds[1] === "5") {
|
|
1919
|
+
pieces.push("a weekday");
|
|
1920
|
+
} else if (segment.kind === "range") {
|
|
1921
|
+
pieces.push("a " + getWeekday(segment.bounds[0], opts) + through(opts) + "a " + getWeekday(segment.bounds[1], opts));
|
|
1922
|
+
} else if (segment.kind === "step") {
|
|
1923
|
+
segment.fires.forEach(function fire(value) {
|
|
1924
|
+
pieces.push("a " + getWeekday(value, opts));
|
|
1925
|
+
});
|
|
1926
|
+
} else {
|
|
1927
|
+
pieces.push("a " + getWeekday(segment.value, opts));
|
|
1928
|
+
}
|
|
1929
|
+
});
|
|
1930
|
+
return pieces;
|
|
1931
|
+
}
|
|
1932
|
+
function oddEvenDay(dateField) {
|
|
1933
|
+
if (!isOpenStep(dateField)) {
|
|
1934
|
+
return null;
|
|
1935
|
+
}
|
|
1936
|
+
const [start, step] = dateField.split("/");
|
|
1937
|
+
if (+step !== 2) {
|
|
1938
|
+
return null;
|
|
1939
|
+
}
|
|
1940
|
+
if (start === "*" || start === "1") {
|
|
1941
|
+
return "an odd-numbered day";
|
|
1942
|
+
}
|
|
1943
|
+
return start === "2" ? "an even-numbered day" : null;
|
|
1944
|
+
}
|
|
1664
1945
|
function dateOrWeekday(ir, opts) {
|
|
1665
1946
|
const pattern = ir.pattern;
|
|
1666
|
-
const weekdayPart = quartzWeekdayPhrase(pattern.weekday, opts) || "on " + weekdayPhrase(ir, opts);
|
|
1947
|
+
const weekdayPart = quartzWeekdayPhrase(pattern.weekday, opts) || "on " + weekdayPhrase(ir, false, opts);
|
|
1667
1948
|
if (pattern.month !== "*" && monthFoldsIntoDate(ir) && !quartzDatePhrase(pattern.date, opts) && !isOpenStep(pattern.date)) {
|
|
1668
1949
|
return "on " + monthDatePhrase(ir, opts) + " or " + weekdayPart + " in " + monthName(ir, opts);
|
|
1669
1950
|
}
|
|
@@ -1714,10 +1995,13 @@ function quartzWeekdayPhrase(weekdayField, opts) {
|
|
|
1714
1995
|
function monthDatePhrase(ir, opts) {
|
|
1715
1996
|
const month = monthName(ir, opts);
|
|
1716
1997
|
const days = renderSegments(
|
|
1717
|
-
ir
|
|
1998
|
+
segmentsOf(ir, "date"),
|
|
1718
1999
|
opts.style.ordinals ? getOrdinal : cardinalDay,
|
|
1719
2000
|
opts
|
|
1720
2001
|
);
|
|
2002
|
+
if (opts.style.dayFirst && ir.shapes.date === "single" && ir.shapes.month !== "single") {
|
|
2003
|
+
return "the " + getOrdinal(ir.pattern.date) + " of " + month;
|
|
2004
|
+
}
|
|
1721
2005
|
return opts.style.dayFirst ? days + " " + month : month + " " + days;
|
|
1722
2006
|
}
|
|
1723
2007
|
function cardinalDay(value) {
|
|
@@ -1729,6 +2013,19 @@ function monthScope(ir, opts) {
|
|
|
1729
2013
|
}
|
|
1730
2014
|
return " in " + monthName(ir, opts);
|
|
1731
2015
|
}
|
|
2016
|
+
function monthScopeForRecurrence(phrase, ir, opts) {
|
|
2017
|
+
if (ir.pattern.month === "*") {
|
|
2018
|
+
return phrase;
|
|
2019
|
+
}
|
|
2020
|
+
const carriesRecurrence = phrase.indexOf(" of the month") !== -1;
|
|
2021
|
+
if (carriesRecurrence && ir.shapes.month === "range") {
|
|
2022
|
+
return phrase.replace(" of the month", " of each month") + " from " + monthName(ir, opts);
|
|
2023
|
+
}
|
|
2024
|
+
if (carriesRecurrence && (ir.shapes.month === "single" || ir.shapes.month === "step")) {
|
|
2025
|
+
return phrase.replace(" of the month", "") + " in " + monthName(ir, opts);
|
|
2026
|
+
}
|
|
2027
|
+
return phrase + " in " + monthName(ir, opts);
|
|
2028
|
+
}
|
|
1732
2029
|
function stepDates(dateField) {
|
|
1733
2030
|
const parts = dateField.split("/");
|
|
1734
2031
|
const interval = +parts[1];
|
|
@@ -1741,14 +2038,14 @@ function stepDates(dateField) {
|
|
|
1741
2038
|
return phrase;
|
|
1742
2039
|
}
|
|
1743
2040
|
function dateOrdinals(ir, opts) {
|
|
1744
|
-
return renderSegments(ir
|
|
2041
|
+
return renderSegments(segmentsOf(ir, "date"), getOrdinal, opts);
|
|
1745
2042
|
}
|
|
1746
2043
|
function monthName(ir, opts) {
|
|
1747
2044
|
const oddEven = oddEvenMonth(ir.pattern.month);
|
|
1748
2045
|
if (oddEven) {
|
|
1749
2046
|
return oddEven;
|
|
1750
2047
|
}
|
|
1751
|
-
return renderSegments(ir
|
|
2048
|
+
return renderSegments(segmentsOf(ir, "month"), function name(value) {
|
|
1752
2049
|
return getMonth(value, opts);
|
|
1753
2050
|
}, opts);
|
|
1754
2051
|
}
|
|
@@ -1765,11 +2062,21 @@ function oddEvenMonth(monthField) {
|
|
|
1765
2062
|
}
|
|
1766
2063
|
return start === "2" ? "every even-numbered month" : null;
|
|
1767
2064
|
}
|
|
1768
|
-
function weekdayPhrase(ir, opts) {
|
|
1769
|
-
const segments = orderWeekdaysForDisplay(ir
|
|
1770
|
-
|
|
2065
|
+
function weekdayPhrase(ir, recurring, opts) {
|
|
2066
|
+
const segments = orderWeekdaysForDisplay(segmentsOf(ir, "weekday"));
|
|
2067
|
+
const hasRange = segments.some(function range(segment) {
|
|
2068
|
+
return segment.kind === "range";
|
|
2069
|
+
});
|
|
2070
|
+
const name = recurring && !hasRange ? function plural(value) {
|
|
2071
|
+
return pluralWeekday(value, opts);
|
|
2072
|
+
} : function singular(value) {
|
|
1771
2073
|
return getWeekday(value, opts);
|
|
1772
|
-
}
|
|
2074
|
+
};
|
|
2075
|
+
return renderSegments(segments, name, opts);
|
|
2076
|
+
}
|
|
2077
|
+
function pluralWeekday(value, opts) {
|
|
2078
|
+
const name = getWeekday(value, opts);
|
|
2079
|
+
return opts.short ? name : name + "s";
|
|
1773
2080
|
}
|
|
1774
2081
|
function renderSegments(segments, word, opts) {
|
|
1775
2082
|
const pieces = [];
|
|
@@ -1784,16 +2091,13 @@ function renderSegments(segments, word, opts) {
|
|
|
1784
2091
|
});
|
|
1785
2092
|
return joinList(pieces, opts);
|
|
1786
2093
|
}
|
|
1787
|
-
function isOpenStep(field) {
|
|
1788
|
-
return field.indexOf("/") !== -1 && field.indexOf("-") === -1 && field.indexOf(",") === -1;
|
|
1789
|
-
}
|
|
1790
2094
|
function applyYear(description, ir, opts) {
|
|
1791
2095
|
const yearField = ir.pattern.year;
|
|
1792
2096
|
if (yearField === "*") {
|
|
1793
2097
|
return description;
|
|
1794
2098
|
}
|
|
1795
2099
|
if (yearField.indexOf("/") !== -1) {
|
|
1796
|
-
return description + " " + stepYears(yearField, opts);
|
|
2100
|
+
return description + ", " + stepYears(yearField, opts);
|
|
1797
2101
|
}
|
|
1798
2102
|
const label = yearLabel(yearField, opts);
|
|
1799
2103
|
if (yearField.indexOf("-") === -1 && yearField.indexOf(",") === -1 && ir.pattern.date !== "*" && description.indexOf(" at ") !== -1) {
|
|
@@ -1806,6 +2110,9 @@ function yearLabel(yearField, opts) {
|
|
|
1806
2110
|
if (yearField.indexOf(",") !== -1) {
|
|
1807
2111
|
return joinList(yearField.split(","), opts);
|
|
1808
2112
|
}
|
|
2113
|
+
if (yearField.indexOf("-") !== -1) {
|
|
2114
|
+
return yearField.split("-").join(through(opts));
|
|
2115
|
+
}
|
|
1809
2116
|
return yearField;
|
|
1810
2117
|
}
|
|
1811
2118
|
function stepYears(yearField, opts) {
|
|
@@ -1815,7 +2122,7 @@ function stepYears(yearField, opts) {
|
|
|
1815
2122
|
if (interval <= 1) {
|
|
1816
2123
|
return "every year";
|
|
1817
2124
|
}
|
|
1818
|
-
let phrase = "every " + getNumber(interval, opts) + " years";
|
|
2125
|
+
let phrase = interval === 2 ? "every other year" : "every " + getNumber(interval, opts) + " years";
|
|
1819
2126
|
if (start !== "*" && start !== "0") {
|
|
1820
2127
|
phrase += " from " + start;
|
|
1821
2128
|
}
|
|
@@ -1917,7 +2224,7 @@ function interpretCronPattern(cronPattern, lang, opts) {
|
|
|
1917
2224
|
return lang.reboot;
|
|
1918
2225
|
}
|
|
1919
2226
|
const ir = analyze(prepare(cronPattern, opts));
|
|
1920
|
-
const plan = lang.
|
|
2227
|
+
const plan = lang.plan ? lang.plan(ir, ir.plan) : ir.plan;
|
|
1921
2228
|
return lang.describe({ ...ir, plan }, opts);
|
|
1922
2229
|
}
|
|
1923
2230
|
var cronli5_default = cronli5;
|