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/lang/en.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
// src/core/
|
|
1
|
+
// src/core/cadence.ts
|
|
2
2
|
function arithmeticStep(values) {
|
|
3
3
|
if (values.length < 5) {
|
|
4
4
|
return null;
|
|
@@ -14,6 +14,56 @@ function arithmeticStep(values) {
|
|
|
14
14
|
}
|
|
15
15
|
return { start: values[0], interval, last: values[values.length - 1] };
|
|
16
16
|
}
|
|
17
|
+
function segmentsOf(schedule, field) {
|
|
18
|
+
return schedule.analyses.segments[field] ?? [];
|
|
19
|
+
}
|
|
20
|
+
function stepSegment(schedule, field) {
|
|
21
|
+
return segmentsOf(schedule, field)[0];
|
|
22
|
+
}
|
|
23
|
+
function singleValues(segments) {
|
|
24
|
+
const values = [];
|
|
25
|
+
for (const segment of segments) {
|
|
26
|
+
if (segment.kind !== "single") {
|
|
27
|
+
return null;
|
|
28
|
+
}
|
|
29
|
+
values.push(+segment.value);
|
|
30
|
+
}
|
|
31
|
+
return values;
|
|
32
|
+
}
|
|
33
|
+
function offsetCleanStride(stride) {
|
|
34
|
+
return stride.start < stride.interval && 24 % stride.interval === 0;
|
|
35
|
+
}
|
|
36
|
+
function renderStride(spec, parts) {
|
|
37
|
+
const { start, interval, cycle } = spec;
|
|
38
|
+
const tiles = cycle % interval === 0;
|
|
39
|
+
if (start === 0 && tiles) {
|
|
40
|
+
return parts.bare();
|
|
41
|
+
}
|
|
42
|
+
if (start < interval && tiles) {
|
|
43
|
+
return parts.offset();
|
|
44
|
+
}
|
|
45
|
+
return parts.bounded();
|
|
46
|
+
}
|
|
47
|
+
function hourListStride(values) {
|
|
48
|
+
if (values.length < 2) {
|
|
49
|
+
return null;
|
|
50
|
+
}
|
|
51
|
+
const interval = values[1] - values[0];
|
|
52
|
+
if (interval < 2) {
|
|
53
|
+
return null;
|
|
54
|
+
}
|
|
55
|
+
for (let i = 2; i < values.length; i += 1) {
|
|
56
|
+
if (values[i] - values[i - 1] !== interval) {
|
|
57
|
+
return null;
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
if (values[0] !== 0 && values.length < 5) {
|
|
61
|
+
return null;
|
|
62
|
+
}
|
|
63
|
+
return { interval, last: values[values.length - 1], start: values[0] };
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
// src/core/weekday.ts
|
|
17
67
|
function weekdayDisplayKey(value) {
|
|
18
68
|
return value === 0 ? 7 : value;
|
|
19
69
|
}
|
|
@@ -35,6 +85,11 @@ function orderWeekdaysForDisplay(segments) {
|
|
|
35
85
|
});
|
|
36
86
|
}
|
|
37
87
|
|
|
88
|
+
// src/core/shapes.ts
|
|
89
|
+
function isOpenStep(field) {
|
|
90
|
+
return field.indexOf("/") !== -1 && field.indexOf("-") === -1 && field.indexOf(",") === -1;
|
|
91
|
+
}
|
|
92
|
+
|
|
38
93
|
// src/core/specs.ts
|
|
39
94
|
var maxClockTimes = 6;
|
|
40
95
|
|
|
@@ -167,72 +222,134 @@ function normalizeOptions(options) {
|
|
|
167
222
|
years: !!options.years
|
|
168
223
|
};
|
|
169
224
|
}
|
|
170
|
-
function describe(
|
|
171
|
-
const
|
|
172
|
-
|
|
173
|
-
|
|
225
|
+
function describe(schedule, opts) {
|
|
226
|
+
const dense = denseCadence(schedule, opts);
|
|
227
|
+
if (dense !== null) {
|
|
228
|
+
return applyYear(dense, schedule, opts);
|
|
229
|
+
}
|
|
230
|
+
const body = confinement(schedule, opts) ?? render(schedule, schedule.plan, opts);
|
|
231
|
+
const lead = isDayUnion(schedule, opts) ? dayUnionMonthLead(schedule, opts) : "";
|
|
232
|
+
return applyYear(lead + body, schedule, opts);
|
|
174
233
|
}
|
|
175
|
-
function render(
|
|
234
|
+
function render(schedule, plan, opts) {
|
|
176
235
|
const renderer = renderers[plan.kind];
|
|
177
|
-
return renderer(
|
|
236
|
+
return renderer(schedule, plan, opts);
|
|
178
237
|
}
|
|
179
|
-
function
|
|
180
|
-
return "
|
|
238
|
+
function isCadenceShape(shape) {
|
|
239
|
+
return shape === "step" || shape === "range" || shape === "list";
|
|
240
|
+
}
|
|
241
|
+
function isDenseCadence(schedule, opts) {
|
|
242
|
+
if (!opts.style.untilWindow || opts.short || schedule.plan.kind !== "composeSeconds" || schedule.plan.rest.kind === "clockTimes" || isDayUnion(schedule, opts)) {
|
|
243
|
+
return false;
|
|
244
|
+
}
|
|
245
|
+
const { shapes } = schedule;
|
|
246
|
+
return isCadenceShape(shapes.second) && isCadenceShape(shapes.minute) && isCadenceShape(shapes.hour);
|
|
181
247
|
}
|
|
182
|
-
function
|
|
183
|
-
|
|
248
|
+
function denseHourFragment(schedule, opts) {
|
|
249
|
+
const stride = hourStride(schedule);
|
|
250
|
+
if (stride) {
|
|
251
|
+
return hourStrideCadence(stride, opts);
|
|
252
|
+
}
|
|
253
|
+
if (schedule.shapes.hour === "range") {
|
|
254
|
+
const segment = segmentsOf(schedule, "hour").find(function range(part) {
|
|
255
|
+
return part.kind === "range";
|
|
256
|
+
});
|
|
257
|
+
return rangeWindow({
|
|
258
|
+
continuous: false,
|
|
259
|
+
from: +segment.bounds[0],
|
|
260
|
+
throughMinute: 0,
|
|
261
|
+
to: +segment.bounds[1]
|
|
262
|
+
}, opts);
|
|
263
|
+
}
|
|
264
|
+
return "during the " + hourSegmentTimes(schedule, { minute: 0, second: null }, false, opts) + " hours";
|
|
265
|
+
}
|
|
266
|
+
function denseMinuteFragment(schedule, opts) {
|
|
267
|
+
if (schedule.shapes.minute === "step") {
|
|
268
|
+
return stepCycle60(stepSegment(schedule, "minute"), "minute", "hour", opts);
|
|
269
|
+
}
|
|
270
|
+
if (schedule.shapes.minute === "range") {
|
|
271
|
+
return minuteRangeLead(schedule.pattern.minute, opts);
|
|
272
|
+
}
|
|
273
|
+
return strideFromSegments(
|
|
274
|
+
segmentsOf(schedule, "minute"),
|
|
275
|
+
"minute",
|
|
276
|
+
"hour",
|
|
277
|
+
opts
|
|
278
|
+
) ?? listPastThe(
|
|
279
|
+
segmentWords(segmentsOf(schedule, "minute"), opts),
|
|
280
|
+
"minute",
|
|
281
|
+
"hour",
|
|
282
|
+
opts
|
|
283
|
+
);
|
|
284
|
+
}
|
|
285
|
+
function denseCadence(schedule, opts) {
|
|
286
|
+
if (!isDenseCadence(schedule, opts)) {
|
|
287
|
+
return null;
|
|
288
|
+
}
|
|
289
|
+
const hour = denseHourFragment(schedule, opts);
|
|
290
|
+
const minute = denseMinuteFragment(schedule, opts);
|
|
291
|
+
const second = secondsClause(schedule, "minute", opts);
|
|
292
|
+
const nested = hour + ", " + minute + ", and within each of those minutes, " + second;
|
|
293
|
+
const anchor = trailingQualifier(schedule, opts).trim();
|
|
294
|
+
return anchor ? anchor + ", " + nested : nested;
|
|
184
295
|
}
|
|
185
|
-
function
|
|
186
|
-
|
|
187
|
-
return getNumber(secondField, opts) + " " + pluralize(secondField, "second") + " past the minute, every minute" + trailingQualifier(ir, opts);
|
|
296
|
+
function renderEverySecond(schedule, plan, opts) {
|
|
297
|
+
return "every second" + trailingQualifier(schedule, opts);
|
|
188
298
|
}
|
|
189
|
-
function
|
|
190
|
-
|
|
299
|
+
function renderStandaloneSeconds(schedule, plan, opts) {
|
|
300
|
+
return secondsLeadClause(schedule, opts) + trailingQualifier(schedule, opts);
|
|
301
|
+
}
|
|
302
|
+
function renderSecondPastMinute(schedule, plan, opts) {
|
|
303
|
+
const secondField = schedule.pattern.second;
|
|
304
|
+
return getNumber(secondField, opts) + " " + pluralize(secondField, "second") + " past the minute, every minute" + trailingQualifier(schedule, opts);
|
|
305
|
+
}
|
|
306
|
+
function renderSecondsWithinMinute(schedule, plan, opts) {
|
|
307
|
+
const minuteField = schedule.pattern.minute;
|
|
191
308
|
const minuteWord = getNumber(minuteField, opts);
|
|
192
309
|
const minuteUnit = pluralize(minuteField, "minute");
|
|
193
310
|
if (plan.singleSecond) {
|
|
194
|
-
const secondField =
|
|
195
|
-
return minuteWord + " " + minuteUnit + " and " + getNumber(secondField, opts) + " " + pluralize(secondField, "second") + " past the hour, every hour" + trailingQualifier(
|
|
311
|
+
const secondField = schedule.pattern.second;
|
|
312
|
+
return minuteWord + " " + minuteUnit + " and " + getNumber(secondField, opts) + " " + pluralize(secondField, "second") + " past the hour, every hour" + trailingQualifier(schedule, opts);
|
|
196
313
|
}
|
|
197
|
-
return secondsLeadClause(
|
|
314
|
+
return secondsLeadClause(schedule, opts) + ", " + minuteWord + " " + minuteUnit + " past the hour, every hour" + trailingQualifier(schedule, opts);
|
|
198
315
|
}
|
|
199
|
-
function composeHourCadence(
|
|
316
|
+
function composeHourCadence(schedule, plan, opts) {
|
|
200
317
|
const clockRest = plan.rest.kind === "clockTimes" || plan.rest.kind === "compactClockTimes";
|
|
201
|
-
if (!clockRest ||
|
|
318
|
+
if (!clockRest || schedule.shapes.minute !== "single") {
|
|
202
319
|
return null;
|
|
203
320
|
}
|
|
204
|
-
const minute = +
|
|
205
|
-
return hourCadence(
|
|
321
|
+
const minute = +schedule.pattern.minute;
|
|
322
|
+
return hourCadence(schedule, minute, opts) ?? hourRangeCadence(schedule, minute, opts);
|
|
206
323
|
}
|
|
207
|
-
function clockTimesConfinement(
|
|
208
|
-
if (+rest.times[0].minute === 0 &&
|
|
209
|
-
return secondsLeadClause(
|
|
324
|
+
function clockTimesConfinement(schedule, rest, opts) {
|
|
325
|
+
if (+rest.times[0].minute === 0 && schedule.shapes.minute === "single") {
|
|
326
|
+
return secondsLeadClause(schedule, opts) + " for one minute at " + durationHours(schedule, rest, opts);
|
|
210
327
|
}
|
|
211
|
-
return secondsLeadClause(
|
|
328
|
+
return secondsLeadClause(schedule, opts) + " of " + clockTimesOf(schedule, rest, opts);
|
|
212
329
|
}
|
|
213
|
-
function renderComposeSeconds(
|
|
214
|
-
const cadence = composeHourCadence(
|
|
330
|
+
function renderComposeSeconds(schedule, plan, opts) {
|
|
331
|
+
const cadence = composeHourCadence(schedule, plan, opts);
|
|
215
332
|
if (cadence !== null) {
|
|
216
333
|
return cadence;
|
|
217
334
|
}
|
|
218
|
-
if (plan.rest.kind === "clockTimes" && (
|
|
219
|
-
return clockTimesConfinement(
|
|
335
|
+
if (plan.rest.kind === "clockTimes" && (schedule.shapes.second === "wildcard" || schedule.shapes.second === "step")) {
|
|
336
|
+
return clockTimesConfinement(schedule, plan.rest, opts);
|
|
220
337
|
}
|
|
221
|
-
if (
|
|
222
|
-
return "every second of every other minute" + trailingQualifier(
|
|
338
|
+
if (schedule.shapes.second === "wildcard" && plan.rest.kind === "minuteFrequency" && plan.rest.hours.kind === "none" && schedule.pattern.minute === "*/2") {
|
|
339
|
+
return "every second of every other minute" + trailingQualifier(schedule, opts);
|
|
223
340
|
}
|
|
224
|
-
const restOwnsLead = plan.rest.kind === "compactClockTimes" &&
|
|
225
|
-
const lead = restOwnsLead ? "" : secondsLeadClause(
|
|
226
|
-
return lead + render(
|
|
341
|
+
const restOwnsLead = plan.rest.kind === "compactClockTimes" && schedule.analyses.clockSecond;
|
|
342
|
+
const lead = restOwnsLead ? "" : secondsLeadClause(schedule, opts) + ", ";
|
|
343
|
+
return lead + render(schedule, plan.rest, opts);
|
|
227
344
|
}
|
|
228
|
-
function durationHours(
|
|
345
|
+
function durationHours(schedule, plan, opts) {
|
|
229
346
|
const hours = plan.times.map(function clock(time) {
|
|
230
347
|
return getTime({ hour: time.hour, minute: 0 }, opts);
|
|
231
348
|
});
|
|
232
|
-
const trail = dayQualifier(
|
|
349
|
+
const trail = dayQualifier(schedule, leadingWords, opts);
|
|
233
350
|
return joinList(hours, opts) + (trail && ", " + trail);
|
|
234
351
|
}
|
|
235
|
-
function clockTimesOf(
|
|
352
|
+
function clockTimesOf(schedule, plan, opts) {
|
|
236
353
|
const times = plan.times.map(function clock(time) {
|
|
237
354
|
return getTime({
|
|
238
355
|
hour: time.hour,
|
|
@@ -241,21 +358,21 @@ function clockTimesOf(ir, plan, opts) {
|
|
|
241
358
|
explicit: true
|
|
242
359
|
}, opts);
|
|
243
360
|
});
|
|
244
|
-
const trail = dayQualifier(
|
|
361
|
+
const trail = dayQualifier(schedule, leadingWords, opts);
|
|
245
362
|
return joinList(times, opts) + (trail && ", " + trail);
|
|
246
363
|
}
|
|
247
|
-
function secondsLeadClause(
|
|
248
|
-
return secondsClause(
|
|
364
|
+
function secondsLeadClause(schedule, opts) {
|
|
365
|
+
return secondsClause(schedule, "minute", opts);
|
|
249
366
|
}
|
|
250
|
-
function secondsClause(
|
|
251
|
-
const secondField =
|
|
252
|
-
const shape =
|
|
367
|
+
function secondsClause(schedule, anchor, opts) {
|
|
368
|
+
const secondField = schedule.pattern.second;
|
|
369
|
+
const shape = schedule.shapes.second;
|
|
253
370
|
if (secondField === "*") {
|
|
254
371
|
return "every second";
|
|
255
372
|
}
|
|
256
373
|
if (shape === "step") {
|
|
257
374
|
return stepCycle60(
|
|
258
|
-
|
|
375
|
+
stepSegment(schedule, "second"),
|
|
259
376
|
"second",
|
|
260
377
|
anchor,
|
|
261
378
|
opts
|
|
@@ -270,86 +387,96 @@ function secondsClause(ir, anchor, opts) {
|
|
|
270
387
|
return "at " + getNumber(secondField, opts) + " " + pluralize(secondField, "second") + " past the " + anchor;
|
|
271
388
|
}
|
|
272
389
|
return strideFromSegments(
|
|
273
|
-
|
|
390
|
+
segmentsOf(schedule, "second"),
|
|
274
391
|
"second",
|
|
275
392
|
anchor,
|
|
276
393
|
opts
|
|
277
394
|
) ?? listPastThe(
|
|
278
|
-
segmentWords(
|
|
395
|
+
segmentWords(segmentsOf(schedule, "second"), opts),
|
|
279
396
|
"second",
|
|
280
397
|
anchor,
|
|
281
398
|
opts
|
|
282
399
|
);
|
|
283
400
|
}
|
|
284
|
-
function renderEveryMinute(
|
|
285
|
-
return "every minute" + trailingQualifier(
|
|
401
|
+
function renderEveryMinute(schedule, plan, opts) {
|
|
402
|
+
return "every minute" + trailingQualifier(schedule, opts);
|
|
286
403
|
}
|
|
287
|
-
function renderSingleMinute(
|
|
288
|
-
const minuteField =
|
|
289
|
-
return getNumber(minuteField, opts) + " " + pluralize(minuteField, "minute") + " past the hour, every hour" + trailingQualifier(
|
|
404
|
+
function renderSingleMinute(schedule, plan, opts) {
|
|
405
|
+
const minuteField = schedule.pattern.minute;
|
|
406
|
+
return getNumber(minuteField, opts) + " " + pluralize(minuteField, "minute") + " past the hour, every hour" + trailingQualifier(schedule, opts);
|
|
290
407
|
}
|
|
291
|
-
function renderRangeOfMinutes(
|
|
292
|
-
return minuteRangeLead(
|
|
408
|
+
function renderRangeOfMinutes(schedule, plan, opts) {
|
|
409
|
+
return minuteRangeLead(schedule.pattern.minute, opts) + trailingQualifier(schedule, opts);
|
|
293
410
|
}
|
|
294
|
-
function renderMultipleMinutes(
|
|
295
|
-
const stride = strideFromSegments(
|
|
411
|
+
function renderMultipleMinutes(schedule, plan, opts) {
|
|
412
|
+
const stride = strideFromSegments(segmentsOf(schedule, "minute"), "minute", "hour", opts);
|
|
296
413
|
return (stride ?? listPastThe(segmentWords(
|
|
297
|
-
|
|
414
|
+
segmentsOf(schedule, "minute"),
|
|
298
415
|
opts
|
|
299
|
-
), "minute", "hour", opts)) + trailingQualifier(
|
|
416
|
+
), "minute", "hour", opts)) + trailingQualifier(schedule, opts);
|
|
300
417
|
}
|
|
301
|
-
function renderMinuteFrequency(
|
|
418
|
+
function renderMinuteFrequency(schedule, plan, opts) {
|
|
302
419
|
let phrase = stepCycle60(
|
|
303
|
-
|
|
420
|
+
stepSegment(schedule, "minute"),
|
|
304
421
|
"minute",
|
|
305
422
|
"hour",
|
|
306
423
|
opts
|
|
307
424
|
);
|
|
308
425
|
if (plan.hours.kind === "during") {
|
|
309
|
-
const cadence = unevenHourCadence(
|
|
310
|
-
phrase += cadence ? ", " + cadence : " during the " + hourTimesFromPlan(
|
|
426
|
+
const cadence = unevenHourCadence(schedule, opts);
|
|
427
|
+
phrase += cadence ? ", " + cadence : " during the " + hourTimesFromPlan(schedule, plan.hours.times, false, opts) + " hours";
|
|
311
428
|
} else if (plan.hours.kind === "window") {
|
|
312
|
-
phrase += " " +
|
|
429
|
+
phrase += " " + rangeWindow({
|
|
430
|
+
continuous: false,
|
|
431
|
+
from: plan.hours.from,
|
|
432
|
+
throughMinute: plan.hours.last,
|
|
433
|
+
to: plan.hours.to
|
|
434
|
+
}, opts);
|
|
313
435
|
} else if (plan.hours.kind === "step") {
|
|
314
|
-
phrase += " " + everyNthHour(
|
|
436
|
+
phrase += " " + everyNthHour(stepSegment(schedule, "hour"), opts);
|
|
315
437
|
}
|
|
316
|
-
return phrase + trailingQualifier(
|
|
438
|
+
return phrase + trailingQualifier(schedule, opts);
|
|
317
439
|
}
|
|
318
|
-
function renderMinuteSpanInHour(
|
|
319
|
-
if (
|
|
320
|
-
return "every minute of the " + getTime({ hour: plan.hour, minute: 0 }, opts) + " hour" + trailingQualifier(
|
|
440
|
+
function renderMinuteSpanInHour(schedule, plan, opts) {
|
|
441
|
+
if (schedule.pattern.minute === "*") {
|
|
442
|
+
return "every minute of the " + getTime({ hour: plan.hour, minute: 0 }, opts) + " hour" + trailingQualifier(schedule, opts);
|
|
321
443
|
}
|
|
322
|
-
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(
|
|
444
|
+
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);
|
|
323
445
|
}
|
|
324
|
-
function renderMinutesAcrossHours(
|
|
325
|
-
const cadence = unevenHourCadence(
|
|
446
|
+
function renderMinutesAcrossHours(schedule, plan, opts) {
|
|
447
|
+
const cadence = unevenHourCadence(schedule, opts);
|
|
326
448
|
if (plan.form === "wildcard") {
|
|
327
449
|
if (cadence !== null) {
|
|
328
|
-
return "every minute, " + cadence + trailingQualifier(
|
|
450
|
+
return "every minute, " + cadence + trailingQualifier(schedule, opts);
|
|
329
451
|
}
|
|
330
|
-
return "every minute during the " + hourTimesFromPlan(
|
|
452
|
+
return "every minute during the " + hourTimesFromPlan(schedule, plan.times, false, opts) + " hours" + trailingQualifier(schedule, opts);
|
|
331
453
|
}
|
|
332
454
|
if (plan.form === "range") {
|
|
333
|
-
const lead2 = minuteRangeLead(
|
|
455
|
+
const lead2 = minuteRangeLead(schedule.pattern.minute, opts);
|
|
334
456
|
if (cadence !== null) {
|
|
335
|
-
return lead2 + ", " + cadence + trailingQualifier(
|
|
457
|
+
return lead2 + ", " + cadence + trailingQualifier(schedule, opts);
|
|
336
458
|
}
|
|
337
459
|
if (singleHourFire(plan.times)) {
|
|
338
|
-
return lead2 + ", at " + hourTimesFromPlan(
|
|
460
|
+
return lead2 + ", at " + hourTimesFromPlan(schedule, plan.times, true, opts) + trailingQualifier(schedule, opts);
|
|
339
461
|
}
|
|
340
|
-
return lead2 + " during the " + hourTimesFromPlan(
|
|
462
|
+
return lead2 + " during the " + hourTimesFromPlan(schedule, plan.times, false, opts) + " hours" + trailingQualifier(schedule, opts);
|
|
341
463
|
}
|
|
342
|
-
const lead = strideFromSegments(
|
|
343
|
-
|
|
464
|
+
const lead = strideFromSegments(
|
|
465
|
+
segmentsOf(schedule, "minute"),
|
|
466
|
+
"minute",
|
|
467
|
+
"hour",
|
|
468
|
+
opts
|
|
469
|
+
) ?? listPastThe(
|
|
470
|
+
segmentWords(segmentsOf(schedule, "minute"), opts),
|
|
344
471
|
"minute",
|
|
345
472
|
"hour",
|
|
346
473
|
opts
|
|
347
474
|
);
|
|
348
475
|
if (cadence !== null) {
|
|
349
|
-
return lead + ", " + cadence + trailingQualifier(
|
|
476
|
+
return lead + ", " + cadence + trailingQualifier(schedule, opts);
|
|
350
477
|
}
|
|
351
|
-
const times = hourTimesFromPlan(
|
|
352
|
-
return lead + ", at " + times + trailingQualifier(
|
|
478
|
+
const times = hourTimesFromPlan(schedule, plan.times, true, opts);
|
|
479
|
+
return lead + ", at " + times + trailingQualifier(schedule, opts);
|
|
353
480
|
}
|
|
354
481
|
var stepOrdinals = {
|
|
355
482
|
2: "other",
|
|
@@ -364,79 +491,91 @@ function everyNthHour(segment, opts) {
|
|
|
364
491
|
const start = segment.startToken === "*" ? 0 : +segment.startToken;
|
|
365
492
|
return start === 0 ? base : base + " starting at " + getTime({ hour: start, minute: 0 }, opts);
|
|
366
493
|
}
|
|
367
|
-
function renderMinuteSpanAcrossHourStep(
|
|
368
|
-
const segment =
|
|
494
|
+
function renderMinuteSpanAcrossHourStep(schedule, plan, opts) {
|
|
495
|
+
const segment = stepSegment(schedule, "hour");
|
|
369
496
|
if (plan.form === "wildcard") {
|
|
370
|
-
return "every minute " + everyNthHour(segment, opts) + trailingQualifier(
|
|
497
|
+
return "every minute " + everyNthHour(segment, opts) + trailingQualifier(schedule, opts);
|
|
371
498
|
}
|
|
372
|
-
const lead = plan.form === "list" ? strideFromSegments(
|
|
373
|
-
|
|
499
|
+
const lead = plan.form === "list" ? strideFromSegments(
|
|
500
|
+
segmentsOf(schedule, "minute"),
|
|
374
501
|
"minute",
|
|
375
502
|
"hour",
|
|
376
503
|
opts
|
|
377
|
-
)
|
|
378
|
-
|
|
379
|
-
|
|
504
|
+
) ?? listPastThe(
|
|
505
|
+
segmentWords(segmentsOf(schedule, "minute"), opts),
|
|
506
|
+
"minute",
|
|
507
|
+
"hour",
|
|
508
|
+
opts
|
|
509
|
+
) : minuteRangeLead(schedule.pattern.minute, opts);
|
|
510
|
+
const cadence = unevenHourCadence(schedule, opts);
|
|
511
|
+
return lead + ", " + (cadence ?? stepHours(segment, opts)) + trailingQualifier(schedule, opts);
|
|
380
512
|
}
|
|
381
513
|
function minuteRangeLead(minuteField, opts) {
|
|
382
514
|
const bounds = minuteField.split("-");
|
|
383
515
|
const num = seriesNumber();
|
|
384
516
|
return "every minute from " + num(bounds[0]) + through(opts) + num(bounds[1]) + " past the hour";
|
|
385
517
|
}
|
|
386
|
-
function renderEveryHour(
|
|
387
|
-
return "every hour" + trailingQualifier(
|
|
518
|
+
function renderEveryHour(schedule, plan, opts) {
|
|
519
|
+
return "every hour" + trailingQualifier(schedule, opts);
|
|
388
520
|
}
|
|
389
|
-
function renderHourRange(
|
|
521
|
+
function renderHourRange(schedule, plan, opts) {
|
|
390
522
|
const window = hourWindow(boundedWindow(plan), opts);
|
|
391
523
|
if (plan.minuteForm === "wildcard") {
|
|
392
|
-
return "every minute " + window + trailingQualifier(
|
|
524
|
+
return "every minute " + window + trailingQualifier(schedule, opts);
|
|
393
525
|
}
|
|
394
526
|
if (plan.minuteForm === "range") {
|
|
395
|
-
return minuteRangeLead(
|
|
527
|
+
return minuteRangeLead(schedule.pattern.minute, opts) + ", " + window + trailingQualifier(schedule, opts);
|
|
396
528
|
}
|
|
397
|
-
return rangeMinuteLead(
|
|
529
|
+
return rangeMinuteLead(schedule, opts) + " " + window + trailingQualifier(schedule, opts);
|
|
398
530
|
}
|
|
399
|
-
function rangeMinuteLead(
|
|
400
|
-
if (
|
|
531
|
+
function rangeMinuteLead(schedule, opts) {
|
|
532
|
+
if (schedule.pattern.minute === "0") {
|
|
401
533
|
return "every hour";
|
|
402
534
|
}
|
|
403
535
|
return strideFromSegments(
|
|
404
|
-
|
|
536
|
+
segmentsOf(schedule, "minute"),
|
|
405
537
|
"minute",
|
|
406
538
|
"hour",
|
|
407
539
|
opts
|
|
408
540
|
) ?? listPastThe(
|
|
409
|
-
segmentWords(
|
|
541
|
+
segmentWords(segmentsOf(schedule, "minute"), opts),
|
|
410
542
|
"minute",
|
|
411
543
|
"hour",
|
|
412
544
|
opts
|
|
413
545
|
);
|
|
414
546
|
}
|
|
415
|
-
function renderHourStep(
|
|
416
|
-
const cadence = unevenHourCadence(
|
|
547
|
+
function renderHourStep(schedule, plan, opts) {
|
|
548
|
+
const cadence = unevenHourCadence(schedule, opts);
|
|
417
549
|
if (cadence !== null) {
|
|
418
|
-
return cadence + trailingQualifier(
|
|
550
|
+
return cadence + trailingQualifier(schedule, opts);
|
|
419
551
|
}
|
|
420
|
-
return stepHours(
|
|
552
|
+
return stepHours(stepSegment(schedule, "hour"), opts) + trailingQualifier(schedule, opts);
|
|
421
553
|
}
|
|
422
554
|
function boundedWindow(plan) {
|
|
423
|
-
const
|
|
424
|
-
|
|
555
|
+
const continuous = plan.minuteForm === "wildcard";
|
|
556
|
+
const closeMinute = continuous ? plan.boundMinute ?? 0 : 0;
|
|
557
|
+
return { from: plan.from, closeMinute, to: plan.to, continuous };
|
|
425
558
|
}
|
|
426
|
-
function rangeWindow(
|
|
559
|
+
function rangeWindow(window, opts) {
|
|
560
|
+
const { from, to, throughMinute, continuous } = window;
|
|
427
561
|
const open = "from " + getTime({ hour: from, minute: 0 }, opts);
|
|
428
562
|
if (opts.style.untilWindow && !opts.short && from !== to) {
|
|
429
|
-
return open + " until " + getTime({ hour: (to + 1) % 24, minute: 0 }, opts);
|
|
563
|
+
return continuous ? open + " until " + getTime({ hour: (to + 1) % 24, minute: 0 }, opts) : open + through(opts) + getTime({ hour: to, minute: 0 }, opts);
|
|
430
564
|
}
|
|
431
565
|
return open + through(opts) + getTime({ hour: to, minute: throughMinute }, opts);
|
|
432
566
|
}
|
|
433
567
|
function hourWindow(window, opts) {
|
|
434
|
-
return rangeWindow(
|
|
568
|
+
return rangeWindow({
|
|
569
|
+
continuous: window.continuous,
|
|
570
|
+
from: window.from,
|
|
571
|
+
throughMinute: window.closeMinute,
|
|
572
|
+
to: window.to
|
|
573
|
+
}, opts);
|
|
435
574
|
}
|
|
436
|
-
function renderClockTimes(
|
|
437
|
-
if (
|
|
438
|
-
const minute = +
|
|
439
|
-
const cadence = hourCadence(
|
|
575
|
+
function renderClockTimes(schedule, plan, opts) {
|
|
576
|
+
if (schedule.shapes.minute === "single") {
|
|
577
|
+
const minute = +schedule.pattern.minute;
|
|
578
|
+
const cadence = hourCadence(schedule, minute, opts) ?? hourRangeCadence(schedule, minute, opts);
|
|
440
579
|
if (cadence !== null) {
|
|
441
580
|
return cadence;
|
|
442
581
|
}
|
|
@@ -450,93 +589,94 @@ function renderClockTimes(ir, plan, opts) {
|
|
|
450
589
|
plain
|
|
451
590
|
}, opts);
|
|
452
591
|
});
|
|
453
|
-
return interpretDayQualifier(
|
|
592
|
+
return interpretDayQualifier(schedule, opts) + "at " + joinList(times, opts) + dayUnionTrail(schedule, opts);
|
|
454
593
|
}
|
|
455
|
-
function dayUnionTrail(
|
|
456
|
-
return isDayUnion(
|
|
594
|
+
function dayUnionTrail(schedule, opts) {
|
|
595
|
+
return isDayUnion(schedule, opts) ? dayUnionCondition(schedule, opts) : "";
|
|
457
596
|
}
|
|
458
|
-
function renderCompactClockTimes(
|
|
597
|
+
function renderCompactClockTimes(schedule, plan, opts) {
|
|
459
598
|
if (plan.fold) {
|
|
460
|
-
const cadence2 = hourCadence(
|
|
599
|
+
const cadence2 = hourCadence(schedule, +plan.minute, opts) ?? hourRangeCadence(schedule, +plan.minute, opts);
|
|
461
600
|
if (cadence2 !== null) {
|
|
462
601
|
return cadence2;
|
|
463
602
|
}
|
|
464
|
-
const hasRange =
|
|
603
|
+
const hasRange = segmentsOf(schedule, "hour").some(function range(segment) {
|
|
465
604
|
return segment.kind === "range";
|
|
466
605
|
});
|
|
467
|
-
if (hasRange && !
|
|
468
|
-
return foldedHourWindows(
|
|
606
|
+
if (hasRange && !schedule.analyses.clockSecond) {
|
|
607
|
+
return foldedHourWindows(schedule, plan, opts) + trailingQualifier(schedule, opts);
|
|
469
608
|
}
|
|
470
|
-
const fold = { minute: plan.minute, second:
|
|
471
|
-
return interpretDayQualifier(
|
|
609
|
+
const fold = { minute: plan.minute, second: schedule.analyses.clockSecond };
|
|
610
|
+
return interpretDayQualifier(schedule, opts) + "at " + hourSegmentTimes(schedule, fold, true, opts) + dayUnionTrail(schedule, opts);
|
|
472
611
|
}
|
|
473
612
|
const minuteLead = (
|
|
474
613
|
// The non-fold branch is a minute list, which has segments. An
|
|
475
614
|
// offset/uneven step enumerated to that list reads as a stride.
|
|
476
|
-
strideFromSegments(
|
|
477
|
-
|
|
615
|
+
strideFromSegments(
|
|
616
|
+
segmentsOf(schedule, "minute"),
|
|
617
|
+
"minute",
|
|
618
|
+
"hour",
|
|
619
|
+
opts
|
|
620
|
+
) ?? listPastThe(
|
|
621
|
+
segmentWords(segmentsOf(schedule, "minute"), opts),
|
|
478
622
|
"minute",
|
|
479
623
|
"hour",
|
|
480
624
|
opts
|
|
481
625
|
)
|
|
482
626
|
);
|
|
483
|
-
const cadence = unevenHourCadence(
|
|
484
|
-
const phrase = cadence ? minuteLead + ", " + cadence + trailingQualifier(
|
|
485
|
-
return
|
|
627
|
+
const cadence = unevenHourCadence(schedule, opts);
|
|
628
|
+
const phrase = cadence ? minuteLead + ", " + cadence + trailingQualifier(schedule, opts) : minuteLead + ", at " + hourSegmentTimes(schedule, { minute: 0, second: null }, true, opts) + trailingQualifier(schedule, opts);
|
|
629
|
+
return schedule.analyses.clockSecond ? secondsLeadClause(schedule, opts) + ", " + phrase : phrase;
|
|
486
630
|
}
|
|
487
|
-
function foldedHourWindows(
|
|
631
|
+
function foldedHourWindows(schedule, plan, opts) {
|
|
488
632
|
const minute = plan.minute;
|
|
489
633
|
const windows = [];
|
|
490
|
-
const
|
|
491
|
-
const times = outliers.hours.map(function time(hour) {
|
|
634
|
+
const times = collectHourOutliers(schedule).map(function time(hour) {
|
|
492
635
|
return getTime({ hour, minute }, opts);
|
|
493
636
|
});
|
|
494
|
-
|
|
637
|
+
segmentsOf(schedule, "hour").forEach(function classify(segment) {
|
|
495
638
|
if (segment.kind === "range") {
|
|
496
|
-
windows.push(rangeWindow(
|
|
497
|
-
|
|
498
|
-
+segment.bounds[
|
|
499
|
-
minute,
|
|
500
|
-
|
|
501
|
-
));
|
|
639
|
+
windows.push(rangeWindow({
|
|
640
|
+
continuous: false,
|
|
641
|
+
from: +segment.bounds[0],
|
|
642
|
+
throughMinute: minute,
|
|
643
|
+
to: +segment.bounds[1]
|
|
644
|
+
}, opts));
|
|
502
645
|
}
|
|
503
646
|
});
|
|
504
|
-
const phrase = rangeMinuteLead(
|
|
505
|
-
return phrase + outlierTail(times,
|
|
647
|
+
const phrase = rangeMinuteLead(schedule, opts) + " " + joinList(windows, opts);
|
|
648
|
+
return phrase + outlierTail(times, opts);
|
|
506
649
|
}
|
|
507
|
-
function collectHourOutliers(
|
|
650
|
+
function collectHourOutliers(schedule) {
|
|
508
651
|
const hours = [];
|
|
509
|
-
|
|
510
|
-
ir.analyses.segments.hour.forEach(function classify(segment) {
|
|
652
|
+
segmentsOf(schedule, "hour").forEach(function classify(segment) {
|
|
511
653
|
if (segment.kind === "step") {
|
|
512
654
|
hours.push(...segment.fires);
|
|
513
|
-
pureStrays = false;
|
|
514
655
|
} else if (segment.kind !== "range") {
|
|
515
656
|
hours.push(+segment.value);
|
|
516
657
|
}
|
|
517
658
|
});
|
|
518
|
-
return
|
|
659
|
+
return hours;
|
|
519
660
|
}
|
|
520
|
-
function outlierTail(times,
|
|
661
|
+
function outlierTail(times, opts) {
|
|
521
662
|
if (!times.length) {
|
|
522
663
|
return "";
|
|
523
664
|
}
|
|
524
|
-
|
|
525
|
-
return connector + joinList(times, opts);
|
|
665
|
+
return " and at " + joinList(times, opts);
|
|
526
666
|
}
|
|
527
667
|
function isCadenceField(token) {
|
|
528
668
|
return token === "*" || token.startsWith("*/") && token.indexOf("-") === -1;
|
|
529
669
|
}
|
|
530
|
-
function leadingCadence(
|
|
531
|
-
const { second, minute } =
|
|
670
|
+
function leadingCadence(schedule, opts) {
|
|
671
|
+
const { second, minute } = schedule.pattern;
|
|
532
672
|
if (isCadenceField(second)) {
|
|
533
|
-
return { secondLead: true, text: secondsClause(
|
|
673
|
+
return { secondLead: true, text: secondsClause(schedule, "minute", opts) };
|
|
534
674
|
}
|
|
535
675
|
if (second === "0" && isCadenceField(minute)) {
|
|
536
676
|
const text = minute === "*" ? "every minute" : (
|
|
537
677
|
// A clean minute step's first segment is a step segment.
|
|
538
678
|
stepCycle60(
|
|
539
|
-
|
|
679
|
+
stepSegment(schedule, "minute"),
|
|
540
680
|
"minute",
|
|
541
681
|
"hour",
|
|
542
682
|
opts
|
|
@@ -546,19 +686,19 @@ function leadingCadence(ir, opts) {
|
|
|
546
686
|
}
|
|
547
687
|
return null;
|
|
548
688
|
}
|
|
549
|
-
function minuteConfinement(
|
|
550
|
-
const minute =
|
|
689
|
+
function minuteConfinement(schedule, opts) {
|
|
690
|
+
const minute = schedule.pattern.minute;
|
|
551
691
|
if (minute === "*") {
|
|
552
692
|
return "";
|
|
553
693
|
}
|
|
554
694
|
if (isCadenceField(minute)) {
|
|
555
695
|
return " of every other minute";
|
|
556
696
|
}
|
|
557
|
-
const segments =
|
|
558
|
-
if (
|
|
697
|
+
const segments = segmentsOf(schedule, "minute");
|
|
698
|
+
if (schedule.shapes.minute === "single") {
|
|
559
699
|
return " during minute :" + pad(minute);
|
|
560
700
|
}
|
|
561
|
-
if (
|
|
701
|
+
if (schedule.shapes.minute === "range") {
|
|
562
702
|
const bounds = minute.split("-");
|
|
563
703
|
return " during minutes :" + pad(bounds[0]) + through(opts) + ":" + pad(bounds[1]);
|
|
564
704
|
}
|
|
@@ -567,59 +707,61 @@ function minuteConfinement(ir, opts) {
|
|
|
567
707
|
});
|
|
568
708
|
return " during minutes " + joinList(values, opts);
|
|
569
709
|
}
|
|
570
|
-
function hourConfinement(
|
|
571
|
-
const hour =
|
|
710
|
+
function hourConfinement(schedule, opts) {
|
|
711
|
+
const hour = schedule.pattern.hour;
|
|
572
712
|
if (hour === "*") {
|
|
573
|
-
const minutePinned =
|
|
713
|
+
const minutePinned = schedule.pattern.minute !== "*" && !isCadenceField(schedule.pattern.minute);
|
|
574
714
|
return minutePinned ? " of every hour" : "";
|
|
575
715
|
}
|
|
576
716
|
if (isCadenceField(hour)) {
|
|
577
717
|
return hour === "*/2" ? " of every other hour" : "";
|
|
578
718
|
}
|
|
579
|
-
if (
|
|
719
|
+
if (schedule.shapes.hour === "single") {
|
|
580
720
|
const h = +hour;
|
|
581
|
-
if (
|
|
721
|
+
if (schedule.shapes.minute === "step") {
|
|
582
722
|
return " from " + getTime({ hour: h, minute: 0 }, opts) + " until " + getTime({ hour: (h + 1) % 24, minute: 0 }, opts);
|
|
583
723
|
}
|
|
584
|
-
if (
|
|
724
|
+
if (schedule.pattern.minute !== "*" && !isCadenceField(schedule.pattern.minute)) {
|
|
585
725
|
return " at " + getTime({ hour: h, minute: 0 }, opts);
|
|
586
726
|
}
|
|
587
727
|
return " of the " + getTime({ hour: h, minute: 0 }, opts) + " hour";
|
|
588
728
|
}
|
|
589
|
-
if (
|
|
729
|
+
if (schedule.shapes.hour === "range") {
|
|
590
730
|
const bounds = hour.split("-");
|
|
591
|
-
return " " + rangeWindow(
|
|
731
|
+
return " " + rangeWindow({
|
|
732
|
+
continuous: schedule.pattern.minute === "*",
|
|
733
|
+
from: +bounds[0],
|
|
734
|
+
throughMinute: 0,
|
|
735
|
+
to: +bounds[1]
|
|
736
|
+
}, opts);
|
|
592
737
|
}
|
|
593
|
-
return " during the " + hourSegmentTimes(
|
|
738
|
+
return " during the " + hourSegmentTimes(schedule, { minute: 0, second: null }, false, opts) + " hours";
|
|
594
739
|
}
|
|
595
|
-
function
|
|
596
|
-
|
|
597
|
-
}
|
|
598
|
-
function confinableHour(ir) {
|
|
599
|
-
if (ir.shapes.hour !== "step") {
|
|
740
|
+
function confinableHour(schedule) {
|
|
741
|
+
if (schedule.shapes.hour !== "step") {
|
|
600
742
|
return true;
|
|
601
743
|
}
|
|
602
|
-
const segment =
|
|
603
|
-
return
|
|
744
|
+
const segment = stepSegment(schedule, "hour");
|
|
745
|
+
return schedule.pattern.hour === "*/2" || segment.startToken.indexOf("-") !== -1;
|
|
604
746
|
}
|
|
605
|
-
function isMinuteStride(
|
|
606
|
-
if (
|
|
747
|
+
function isMinuteStride(schedule) {
|
|
748
|
+
if (schedule.shapes.minute !== "list") {
|
|
607
749
|
return false;
|
|
608
750
|
}
|
|
609
|
-
const values = singleValues(
|
|
751
|
+
const values = singleValues(segmentsOf(schedule, "minute"));
|
|
610
752
|
return values !== null && arithmeticStep(values) !== null;
|
|
611
753
|
}
|
|
612
|
-
function confinementEligible(
|
|
613
|
-
const { minute, hour } =
|
|
754
|
+
function confinementEligible(schedule, lead) {
|
|
755
|
+
const { minute, hour } = schedule.pattern;
|
|
614
756
|
const minuteStep = isCadenceField(minute) && minute !== "*";
|
|
615
|
-
if (!confinableHour(
|
|
757
|
+
if (!confinableHour(schedule)) {
|
|
616
758
|
return false;
|
|
617
759
|
}
|
|
618
760
|
if (lead.secondLead) {
|
|
619
761
|
if (minuteStep) {
|
|
620
|
-
return minute === "*/2" &&
|
|
762
|
+
return minute === "*/2" && schedule.shapes.hour !== "range";
|
|
621
763
|
}
|
|
622
|
-
if (isMinuteStride(
|
|
764
|
+
if (isMinuteStride(schedule) || schedule.shapes.minute === "list" && schedule.shapes.hour === "list") {
|
|
623
765
|
return false;
|
|
624
766
|
}
|
|
625
767
|
return true;
|
|
@@ -627,21 +769,21 @@ function confinementEligible(ir, lead) {
|
|
|
627
769
|
if (hour === "*/2") {
|
|
628
770
|
return true;
|
|
629
771
|
}
|
|
630
|
-
return
|
|
772
|
+
return schedule.shapes.hour === "single" && minute === "*/2";
|
|
631
773
|
}
|
|
632
|
-
function confinement(
|
|
774
|
+
function confinement(schedule, opts) {
|
|
633
775
|
if (!opts.style.untilWindow || opts.short) {
|
|
634
776
|
return null;
|
|
635
777
|
}
|
|
636
|
-
if (
|
|
778
|
+
if (schedule.pattern.minute === "*" && schedule.pattern.hour === "*") {
|
|
637
779
|
return null;
|
|
638
780
|
}
|
|
639
|
-
const lead = leadingCadence(
|
|
640
|
-
if (!lead || !confinementEligible(
|
|
781
|
+
const lead = leadingCadence(schedule, opts);
|
|
782
|
+
if (!lead || !confinementEligible(schedule, lead)) {
|
|
641
783
|
return null;
|
|
642
784
|
}
|
|
643
|
-
const minutePart = lead.secondLead ? minuteConfinement(
|
|
644
|
-
return lead.text + minutePart + hourConfinement(
|
|
785
|
+
const minutePart = lead.secondLead ? minuteConfinement(schedule, opts) : "";
|
|
786
|
+
return lead.text + minutePart + hourConfinement(schedule, opts) + trailingQualifier(schedule, opts);
|
|
645
787
|
}
|
|
646
788
|
var renderers = {
|
|
647
789
|
clockTimes: renderClockTimes,
|
|
@@ -663,33 +805,25 @@ var renderers = {
|
|
|
663
805
|
singleMinute: renderSingleMinute,
|
|
664
806
|
standaloneSeconds: renderStandaloneSeconds
|
|
665
807
|
};
|
|
666
|
-
function
|
|
808
|
+
function renderStride2(stride, opts) {
|
|
667
809
|
const { interval, start, last, cycle, unit, anchor } = stride;
|
|
668
810
|
const cadence = "every " + getNumber(interval, opts) + " " + unit + "s";
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
}
|
|
679
|
-
function singleValues(segments) {
|
|
680
|
-
const values = [];
|
|
681
|
-
for (const segment of segments) {
|
|
682
|
-
if (segment.kind !== "single") {
|
|
683
|
-
return null;
|
|
811
|
+
return renderStride({ start, interval, cycle }, {
|
|
812
|
+
bare: () => cadence,
|
|
813
|
+
// A clean wrap from a non-zero offset: name the start, no endpoint.
|
|
814
|
+
offset: () => cadence + " from " + getNumber(start, opts) + " " + pluralize(start, unit) + " past the " + anchor,
|
|
815
|
+
// A bounded, non-wrapping set: pin both endpoints. Each bound is a value,
|
|
816
|
+
// so it reads as a digit, matching the range idiom ("from 0 through 30").
|
|
817
|
+
bounded: () => {
|
|
818
|
+
const num = seriesNumber();
|
|
819
|
+
return cadence + " from " + num(start) + through(opts) + num(last) + " " + pluralize(last, unit) + " past the " + anchor;
|
|
684
820
|
}
|
|
685
|
-
|
|
686
|
-
}
|
|
687
|
-
return values;
|
|
821
|
+
});
|
|
688
822
|
}
|
|
689
823
|
function strideFromSegments(segments, unit, anchor, opts) {
|
|
690
824
|
const values = singleValues(segments);
|
|
691
825
|
const step = values && arithmeticStep(values);
|
|
692
|
-
return step ?
|
|
826
|
+
return step ? renderStride2({ ...step, cycle: 60, unit, anchor }, opts) : null;
|
|
693
827
|
}
|
|
694
828
|
function stepCycle60(segment, unit, anchor, opts) {
|
|
695
829
|
if (segment.startToken.indexOf("-") !== -1) {
|
|
@@ -699,7 +833,7 @@ function stepCycle60(segment, unit, anchor, opts) {
|
|
|
699
833
|
if (start !== 0 && segment.fires.length <= 3) {
|
|
700
834
|
return listPastThe(numberWords(segment.fires, opts), unit, anchor, opts);
|
|
701
835
|
}
|
|
702
|
-
return
|
|
836
|
+
return renderStride2({
|
|
703
837
|
interval: segment.interval,
|
|
704
838
|
start,
|
|
705
839
|
last: segment.fires[segment.fires.length - 1],
|
|
@@ -725,45 +859,21 @@ function stepHours(segment, opts) {
|
|
|
725
859
|
function hourStrideCadence(stride, opts) {
|
|
726
860
|
const { start, interval, last } = stride;
|
|
727
861
|
const cadence = "every " + getNumber(interval, opts) + " hours";
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
return cadence + " from " + getTime({ hour: start, minute: 0 }, opts);
|
|
734
|
-
}
|
|
735
|
-
return cadence + " from " + getTime({ hour: start, minute: 0 }, opts) + through(opts) + getTime({ hour: last, minute: 0 }, opts);
|
|
736
|
-
}
|
|
737
|
-
function offsetCleanStride(stride) {
|
|
738
|
-
return stride.start < stride.interval && 24 % stride.interval === 0;
|
|
862
|
+
return renderStride({ start, interval, cycle: 24 }, {
|
|
863
|
+
bare: () => cadence,
|
|
864
|
+
offset: () => cadence + " from " + getTime({ hour: start, minute: 0 }, opts),
|
|
865
|
+
bounded: () => cadence + " from " + getTime({ hour: start, minute: 0 }, opts) + through(opts) + getTime({ hour: last, minute: 0 }, opts)
|
|
866
|
+
});
|
|
739
867
|
}
|
|
740
|
-
function unevenHourCadence(
|
|
741
|
-
const stride = hourStride(
|
|
868
|
+
function unevenHourCadence(schedule, opts) {
|
|
869
|
+
const stride = hourStride(schedule);
|
|
742
870
|
if (!stride || offsetCleanStride(stride)) {
|
|
743
871
|
return null;
|
|
744
872
|
}
|
|
745
873
|
return hourStrideCadence(stride, opts);
|
|
746
874
|
}
|
|
747
|
-
function
|
|
748
|
-
|
|
749
|
-
return null;
|
|
750
|
-
}
|
|
751
|
-
const interval = values[1] - values[0];
|
|
752
|
-
if (interval < 2) {
|
|
753
|
-
return null;
|
|
754
|
-
}
|
|
755
|
-
for (let i = 2; i < values.length; i += 1) {
|
|
756
|
-
if (values[i] - values[i - 1] !== interval) {
|
|
757
|
-
return null;
|
|
758
|
-
}
|
|
759
|
-
}
|
|
760
|
-
if (values[0] !== 0 && values.length < 5) {
|
|
761
|
-
return null;
|
|
762
|
-
}
|
|
763
|
-
return { interval, last: values[values.length - 1], start: values[0] };
|
|
764
|
-
}
|
|
765
|
-
function hourStride(ir) {
|
|
766
|
-
const segments = ir.analyses.segments.hour;
|
|
875
|
+
function hourStride(schedule) {
|
|
876
|
+
const segments = segmentsOf(schedule, "hour");
|
|
767
877
|
if (segments.length === 1 && segments[0].kind === "step") {
|
|
768
878
|
const segment = segments[0];
|
|
769
879
|
if (segment.fires.length < 2) {
|
|
@@ -775,83 +885,83 @@ function hourStride(ir) {
|
|
|
775
885
|
const values = singleValues(segments);
|
|
776
886
|
return values && hourListStride(values);
|
|
777
887
|
}
|
|
778
|
-
function subMinuteSecond(
|
|
779
|
-
return
|
|
888
|
+
function subMinuteSecond(schedule) {
|
|
889
|
+
return schedule.pattern.second === "*" || schedule.shapes.second === "step";
|
|
780
890
|
}
|
|
781
|
-
function hourCadenceLead(
|
|
891
|
+
function hourCadenceLead(schedule, minute, opts) {
|
|
782
892
|
if (minute === 0) {
|
|
783
|
-
if (subMinuteSecond(
|
|
784
|
-
return secondsClause(
|
|
893
|
+
if (subMinuteSecond(schedule)) {
|
|
894
|
+
return secondsClause(schedule, "minute", opts) + " for one minute";
|
|
785
895
|
}
|
|
786
|
-
return secondsClause(
|
|
896
|
+
return secondsClause(schedule, "hour", opts);
|
|
787
897
|
}
|
|
788
898
|
const minutePhrase = getNumber(minute, opts) + " " + pluralize(minute, "minute") + " past the hour";
|
|
789
|
-
if (
|
|
899
|
+
if (schedule.pattern.second === "0") {
|
|
790
900
|
return minutePhrase;
|
|
791
901
|
}
|
|
792
|
-
return secondsClause(
|
|
902
|
+
return secondsClause(schedule, "minute", opts) + ", " + minutePhrase;
|
|
793
903
|
}
|
|
794
|
-
function hourCadence(
|
|
795
|
-
const stride = hourStride(
|
|
904
|
+
function hourCadence(schedule, minute, opts) {
|
|
905
|
+
const stride = hourStride(schedule);
|
|
796
906
|
if (!stride) {
|
|
797
907
|
return null;
|
|
798
908
|
}
|
|
799
909
|
const fires = (stride.last - stride.start) / stride.interval + 1;
|
|
800
|
-
if (
|
|
910
|
+
if (schedule.pattern.second === "0" && fires <= maxClockTimes && offsetCleanStride(stride)) {
|
|
801
911
|
return null;
|
|
802
912
|
}
|
|
803
|
-
const minuteZeroStride = minute === 0 && subMinuteSecond(
|
|
913
|
+
const minuteZeroStride = minute === 0 && subMinuteSecond(schedule) && cleanStrideSegment(schedule);
|
|
804
914
|
if (minuteZeroStride) {
|
|
805
|
-
return secondsClause(
|
|
915
|
+
return secondsClause(schedule, "minute", opts) + " for one minute " + everyNthHour(minuteZeroStride, opts) + trailingQualifier(schedule, opts);
|
|
806
916
|
}
|
|
807
|
-
if (minute === 0 &&
|
|
808
|
-
return hourStrideCadence(stride, opts) + trailingQualifier(
|
|
917
|
+
if (minute === 0 && schedule.pattern.second === "0") {
|
|
918
|
+
return hourStrideCadence(stride, opts) + trailingQualifier(schedule, opts);
|
|
809
919
|
}
|
|
810
|
-
return hourCadenceLead(
|
|
920
|
+
return hourCadenceLead(schedule, minute, opts) + ", " + hourStrideCadence(stride, opts) + trailingQualifier(schedule, opts);
|
|
811
921
|
}
|
|
812
|
-
function cleanStrideSegment(
|
|
813
|
-
const segments =
|
|
922
|
+
function cleanStrideSegment(schedule) {
|
|
923
|
+
const segments = segmentsOf(schedule, "hour");
|
|
814
924
|
const segment = segments.length === 1 && segments[0];
|
|
815
925
|
if (!segment || segment.kind !== "step" || segment.startToken.indexOf("-") !== -1 || !(segment.interval in stepOrdinals)) {
|
|
816
926
|
return null;
|
|
817
927
|
}
|
|
818
928
|
return segment;
|
|
819
929
|
}
|
|
820
|
-
function hasHourWindow(
|
|
821
|
-
return
|
|
930
|
+
function hasHourWindow(schedule) {
|
|
931
|
+
return segmentsOf(schedule, "hour").some(function range(segment) {
|
|
822
932
|
return segment.kind === "range";
|
|
823
933
|
});
|
|
824
934
|
}
|
|
825
|
-
function hourRangeWindowTail(
|
|
935
|
+
function hourRangeWindowTail(schedule, opts) {
|
|
826
936
|
const windows = [];
|
|
827
|
-
const
|
|
828
|
-
|
|
937
|
+
const outlierHours = collectHourOutliers(schedule);
|
|
938
|
+
segmentsOf(schedule, "hour").forEach(function classify(segment) {
|
|
829
939
|
if (segment.kind === "range") {
|
|
830
|
-
windows.push(rangeWindow(
|
|
831
|
-
|
|
832
|
-
+segment.bounds[
|
|
833
|
-
0,
|
|
834
|
-
|
|
835
|
-
));
|
|
940
|
+
windows.push(rangeWindow({
|
|
941
|
+
continuous: false,
|
|
942
|
+
from: +segment.bounds[0],
|
|
943
|
+
throughMinute: 0,
|
|
944
|
+
to: +segment.bounds[1]
|
|
945
|
+
}, opts));
|
|
836
946
|
}
|
|
837
947
|
});
|
|
838
948
|
const phrase = "every hour " + joinList(windows, opts);
|
|
839
|
-
const times =
|
|
949
|
+
const times = outlierHours.map(function time(hour) {
|
|
840
950
|
return getTime({ hour, minute: 0 }, opts);
|
|
841
951
|
});
|
|
842
|
-
return phrase + outlierTail(times,
|
|
952
|
+
return phrase + outlierTail(times, opts);
|
|
843
953
|
}
|
|
844
|
-
function hourRangeCadence(
|
|
845
|
-
if (minute !== 0 || !hasHourWindow(
|
|
954
|
+
function hourRangeCadence(schedule, minute, opts) {
|
|
955
|
+
if (minute !== 0 || !hasHourWindow(schedule)) {
|
|
846
956
|
return null;
|
|
847
957
|
}
|
|
848
|
-
if (
|
|
958
|
+
if (schedule.pattern.second === "0") {
|
|
849
959
|
return null;
|
|
850
960
|
}
|
|
851
|
-
if (subMinuteSecond(
|
|
852
|
-
return secondsClause(
|
|
961
|
+
if (subMinuteSecond(schedule)) {
|
|
962
|
+
return secondsClause(schedule, "minute", opts) + " for one minute during the " + hourSegmentTimes(schedule, { minute: 0, second: null }, false, opts) + " hours" + trailingQualifier(schedule, opts);
|
|
853
963
|
}
|
|
854
|
-
return hourCadenceLead(
|
|
964
|
+
return hourCadenceLead(schedule, minute, opts) + ", " + hourRangeWindowTail(schedule, opts) + trailingQualifier(schedule, opts);
|
|
855
965
|
}
|
|
856
966
|
function seriesNumber() {
|
|
857
967
|
return function format(n) {
|
|
@@ -910,11 +1020,11 @@ function hourTimes(hours, opts) {
|
|
|
910
1020
|
function singleHourFire(times) {
|
|
911
1021
|
return times.kind === "fires" && times.fires.length === 1;
|
|
912
1022
|
}
|
|
913
|
-
function hourTimesFromPlan(
|
|
1023
|
+
function hourTimesFromPlan(schedule, times, atContext, opts) {
|
|
914
1024
|
if (times.kind === "fires") {
|
|
915
1025
|
return hourTimes(times.fires, opts);
|
|
916
1026
|
}
|
|
917
|
-
return hourSegmentTimes(
|
|
1027
|
+
return hourSegmentTimes(schedule, { minute: 0, second: null }, atContext, opts);
|
|
918
1028
|
}
|
|
919
1029
|
function segmentHours(segment) {
|
|
920
1030
|
if (segment.kind === "range") {
|
|
@@ -922,9 +1032,9 @@ function segmentHours(segment) {
|
|
|
922
1032
|
}
|
|
923
1033
|
return segment.kind === "step" ? segment.fires : [segment.value];
|
|
924
1034
|
}
|
|
925
|
-
function hourSegmentTimes(
|
|
1035
|
+
function hourSegmentTimes(schedule, fold, atContext, opts) {
|
|
926
1036
|
const { minute, second } = fold;
|
|
927
|
-
const segments =
|
|
1037
|
+
const segments = segmentsOf(schedule, "hour");
|
|
928
1038
|
const plain = mixedTwelve(segments.flatMap(function entries(segment) {
|
|
929
1039
|
return segmentHours(segment).map(function entry(hour) {
|
|
930
1040
|
return { hour: +hour, minute, second };
|
|
@@ -987,85 +1097,85 @@ var leadingWords = {
|
|
|
987
1097
|
stepDate: "",
|
|
988
1098
|
weekday: "every "
|
|
989
1099
|
};
|
|
990
|
-
function trailingQualifier(
|
|
991
|
-
if (isDayUnion(
|
|
992
|
-
return dayUnionCondition(
|
|
1100
|
+
function trailingQualifier(schedule, opts) {
|
|
1101
|
+
if (isDayUnion(schedule, opts)) {
|
|
1102
|
+
return dayUnionCondition(schedule, opts);
|
|
993
1103
|
}
|
|
994
|
-
const phrase = dayQualifier(
|
|
1104
|
+
const phrase = dayQualifier(schedule, trailingWords, opts);
|
|
995
1105
|
return phrase && " " + phrase;
|
|
996
1106
|
}
|
|
997
|
-
function interpretDayQualifier(
|
|
998
|
-
if (isDayUnion(
|
|
1107
|
+
function interpretDayQualifier(schedule, opts) {
|
|
1108
|
+
if (isDayUnion(schedule, opts)) {
|
|
999
1109
|
return "";
|
|
1000
1110
|
}
|
|
1001
|
-
return dayQualifier(
|
|
1111
|
+
return dayQualifier(schedule, leadingWords, opts) + " ";
|
|
1002
1112
|
}
|
|
1003
|
-
function dayQualifier(
|
|
1004
|
-
const pattern =
|
|
1113
|
+
function dayQualifier(schedule, words, opts) {
|
|
1114
|
+
const pattern = schedule.pattern;
|
|
1005
1115
|
if (pattern.date !== "*" && pattern.weekday !== "*") {
|
|
1006
|
-
return dateOrWeekday(
|
|
1116
|
+
return dateOrWeekday(schedule, opts);
|
|
1007
1117
|
}
|
|
1008
1118
|
if (pattern.date !== "*") {
|
|
1009
|
-
return datePhrase(
|
|
1119
|
+
return datePhrase(schedule, words, opts);
|
|
1010
1120
|
}
|
|
1011
1121
|
if (pattern.weekday !== "*") {
|
|
1012
1122
|
const quartzWeekday = quartzWeekdayPhrase(pattern.weekday, opts);
|
|
1013
1123
|
if (quartzWeekday) {
|
|
1014
|
-
return monthScopeForRecurrence(quartzWeekday,
|
|
1124
|
+
return monthScopeForRecurrence(quartzWeekday, schedule, opts);
|
|
1015
1125
|
}
|
|
1016
|
-
const weekdays = words.weekday + weekdayPhrase(
|
|
1017
|
-
return weekdays + monthScope(
|
|
1126
|
+
const weekdays = words.weekday + weekdayPhrase(schedule, words.recurringWeekday, opts);
|
|
1127
|
+
return weekdays + monthScope(schedule, opts);
|
|
1018
1128
|
}
|
|
1019
1129
|
if (pattern.month !== "*") {
|
|
1020
|
-
return words.month + monthName(
|
|
1130
|
+
return words.month + monthName(schedule, opts);
|
|
1021
1131
|
}
|
|
1022
1132
|
return words.all;
|
|
1023
1133
|
}
|
|
1024
|
-
function datePhrase(
|
|
1025
|
-
const pattern =
|
|
1134
|
+
function datePhrase(schedule, words, opts) {
|
|
1135
|
+
const pattern = schedule.pattern;
|
|
1026
1136
|
const quartzDate = quartzDatePhrase(pattern.date, opts);
|
|
1027
1137
|
if (quartzDate) {
|
|
1028
|
-
return monthScopeForRecurrence(quartzDate,
|
|
1138
|
+
return monthScopeForRecurrence(quartzDate, schedule, opts);
|
|
1029
1139
|
}
|
|
1030
1140
|
if (isOpenStep(pattern.date)) {
|
|
1031
1141
|
return monthScopeForRecurrence(
|
|
1032
1142
|
words.stepDate + stepDates(pattern.date),
|
|
1033
|
-
|
|
1143
|
+
schedule,
|
|
1034
1144
|
opts
|
|
1035
1145
|
);
|
|
1036
1146
|
}
|
|
1037
|
-
if (pattern.month !== "*" && !monthFoldsIntoDate(
|
|
1038
|
-
return "on the " + dateOrdinals(
|
|
1147
|
+
if (pattern.month !== "*" && !monthFoldsIntoDate(schedule)) {
|
|
1148
|
+
return "on the " + dateOrdinals(schedule, opts) + monthScope(schedule, opts);
|
|
1039
1149
|
}
|
|
1040
1150
|
if (pattern.month !== "*") {
|
|
1041
|
-
return "on " + monthDatePhrase(
|
|
1151
|
+
return "on " + monthDatePhrase(schedule, opts);
|
|
1042
1152
|
}
|
|
1043
|
-
return "on the " + dateOrdinals(
|
|
1153
|
+
return "on the " + dateOrdinals(schedule, opts);
|
|
1044
1154
|
}
|
|
1045
|
-
function monthFoldsIntoDate(
|
|
1046
|
-
return !oddEvenMonth(
|
|
1047
|
-
|
|
1155
|
+
function monthFoldsIntoDate(schedule) {
|
|
1156
|
+
return !oddEvenMonth(schedule.pattern.month) && // Reached only with a restricted month, which has segments.
|
|
1157
|
+
segmentsOf(schedule, "month").every(function flat(segment) {
|
|
1048
1158
|
return segment.kind !== "range";
|
|
1049
1159
|
});
|
|
1050
1160
|
}
|
|
1051
|
-
function isDayUnion(
|
|
1052
|
-
return
|
|
1161
|
+
function isDayUnion(schedule, opts) {
|
|
1162
|
+
return schedule.pattern.date !== "*" && schedule.pattern.weekday !== "*" && !!opts.style.untilWindow && !opts.short;
|
|
1053
1163
|
}
|
|
1054
|
-
function dayUnionCondition(
|
|
1164
|
+
function dayUnionCondition(schedule, opts) {
|
|
1055
1165
|
const pieces = [
|
|
1056
|
-
...dayUnionDatePieces(
|
|
1057
|
-
...dayUnionWeekdayPieces(
|
|
1166
|
+
...dayUnionDatePieces(schedule, opts),
|
|
1167
|
+
...dayUnionWeekdayPieces(schedule, opts)
|
|
1058
1168
|
];
|
|
1059
1169
|
return " whenever the day is " + joinOr(pieces, opts);
|
|
1060
1170
|
}
|
|
1061
|
-
function dayUnionMonthLead(
|
|
1062
|
-
if (
|
|
1171
|
+
function dayUnionMonthLead(schedule, opts) {
|
|
1172
|
+
if (schedule.pattern.month === "*") {
|
|
1063
1173
|
return "";
|
|
1064
1174
|
}
|
|
1065
|
-
return "in " + monthName(
|
|
1175
|
+
return "in " + monthName(schedule, opts) + " ";
|
|
1066
1176
|
}
|
|
1067
|
-
function dayUnionDatePieces(
|
|
1068
|
-
const dateField =
|
|
1177
|
+
function dayUnionDatePieces(schedule, opts) {
|
|
1178
|
+
const dateField = schedule.pattern.date;
|
|
1069
1179
|
const quartz = quartzDatePhrase(dateField, opts);
|
|
1070
1180
|
if (quartz) {
|
|
1071
1181
|
return [quartz.replace(/^on /, "")];
|
|
@@ -1075,7 +1185,7 @@ function dayUnionDatePieces(ir, opts) {
|
|
|
1075
1185
|
return [oddEven];
|
|
1076
1186
|
}
|
|
1077
1187
|
const pieces = [];
|
|
1078
|
-
|
|
1188
|
+
segmentsOf(schedule, "date").forEach(function expand(segment) {
|
|
1079
1189
|
if (segment.kind === "range") {
|
|
1080
1190
|
pieces.push("from the " + getOrdinal(segment.bounds[0]) + through(opts) + "the " + getOrdinal(segment.bounds[1]));
|
|
1081
1191
|
} else if (segment.kind === "step") {
|
|
@@ -1088,14 +1198,14 @@ function dayUnionDatePieces(ir, opts) {
|
|
|
1088
1198
|
});
|
|
1089
1199
|
return pieces;
|
|
1090
1200
|
}
|
|
1091
|
-
function dayUnionWeekdayPieces(
|
|
1092
|
-
const weekdayField =
|
|
1201
|
+
function dayUnionWeekdayPieces(schedule, opts) {
|
|
1202
|
+
const weekdayField = schedule.pattern.weekday;
|
|
1093
1203
|
const quartz = quartzWeekdayPhrase(weekdayField, opts);
|
|
1094
1204
|
if (quartz) {
|
|
1095
1205
|
return [quartz.replace(/^on /, "")];
|
|
1096
1206
|
}
|
|
1097
1207
|
const pieces = [];
|
|
1098
|
-
|
|
1208
|
+
segmentsOf(schedule, "weekday").forEach(function expand(segment) {
|
|
1099
1209
|
if (segment.kind === "range" && segment.bounds[0] === "1" && segment.bounds[1] === "5") {
|
|
1100
1210
|
pieces.push("a weekday");
|
|
1101
1211
|
} else if (segment.kind === "range") {
|
|
@@ -1123,16 +1233,16 @@ function oddEvenDay(dateField) {
|
|
|
1123
1233
|
}
|
|
1124
1234
|
return start === "2" ? "an even-numbered day" : null;
|
|
1125
1235
|
}
|
|
1126
|
-
function dateOrWeekday(
|
|
1127
|
-
const pattern =
|
|
1128
|
-
const weekdayPart = quartzWeekdayPhrase(pattern.weekday, opts) || "on " + weekdayPhrase(
|
|
1129
|
-
if (pattern.month !== "*" && monthFoldsIntoDate(
|
|
1130
|
-
return "on " + monthDatePhrase(
|
|
1236
|
+
function dateOrWeekday(schedule, opts) {
|
|
1237
|
+
const pattern = schedule.pattern;
|
|
1238
|
+
const weekdayPart = quartzWeekdayPhrase(pattern.weekday, opts) || "on " + weekdayPhrase(schedule, false, opts);
|
|
1239
|
+
if (pattern.month !== "*" && monthFoldsIntoDate(schedule) && !quartzDatePhrase(pattern.date, opts) && !isOpenStep(pattern.date)) {
|
|
1240
|
+
return "on " + monthDatePhrase(schedule, opts) + " or " + weekdayPart + " in " + monthName(schedule, opts);
|
|
1131
1241
|
}
|
|
1132
|
-
return datePart(
|
|
1242
|
+
return datePart(schedule, opts) + " or " + weekdayPart + orMonthScope(schedule, opts);
|
|
1133
1243
|
}
|
|
1134
|
-
function datePart(
|
|
1135
|
-
const pattern =
|
|
1244
|
+
function datePart(schedule, opts) {
|
|
1245
|
+
const pattern = schedule.pattern;
|
|
1136
1246
|
const quartzDate = quartzDatePhrase(pattern.date, opts);
|
|
1137
1247
|
if (quartzDate) {
|
|
1138
1248
|
return quartzDate;
|
|
@@ -1140,13 +1250,13 @@ function datePart(ir, opts) {
|
|
|
1140
1250
|
if (isOpenStep(pattern.date)) {
|
|
1141
1251
|
return stepDates(pattern.date);
|
|
1142
1252
|
}
|
|
1143
|
-
return "on the " + dateOrdinals(
|
|
1253
|
+
return "on the " + dateOrdinals(schedule, opts);
|
|
1144
1254
|
}
|
|
1145
|
-
function orMonthScope(
|
|
1146
|
-
if (
|
|
1255
|
+
function orMonthScope(schedule, opts) {
|
|
1256
|
+
if (schedule.pattern.month === "*") {
|
|
1147
1257
|
return "";
|
|
1148
1258
|
}
|
|
1149
|
-
return ", in " + monthName(
|
|
1259
|
+
return ", in " + monthName(schedule, opts);
|
|
1150
1260
|
}
|
|
1151
1261
|
function quartzDatePhrase(dateField, opts) {
|
|
1152
1262
|
if (dateField === "L") {
|
|
@@ -1173,39 +1283,39 @@ function quartzWeekdayPhrase(weekdayField, opts) {
|
|
|
1173
1283
|
return "on the last " + getWeekday(weekdayField.slice(0, -1), opts) + " of the month";
|
|
1174
1284
|
}
|
|
1175
1285
|
}
|
|
1176
|
-
function monthDatePhrase(
|
|
1177
|
-
const month = monthName(
|
|
1286
|
+
function monthDatePhrase(schedule, opts) {
|
|
1287
|
+
const month = monthName(schedule, opts);
|
|
1178
1288
|
const days = renderSegments(
|
|
1179
|
-
|
|
1289
|
+
segmentsOf(schedule, "date"),
|
|
1180
1290
|
opts.style.ordinals ? getOrdinal : cardinalDay,
|
|
1181
1291
|
opts
|
|
1182
1292
|
);
|
|
1183
|
-
if (opts.style.dayFirst &&
|
|
1184
|
-
return "the " + getOrdinal(
|
|
1293
|
+
if (opts.style.dayFirst && schedule.shapes.date === "single" && schedule.shapes.month !== "single") {
|
|
1294
|
+
return "the " + getOrdinal(schedule.pattern.date) + " of " + month;
|
|
1185
1295
|
}
|
|
1186
1296
|
return opts.style.dayFirst ? days + " " + month : month + " " + days;
|
|
1187
1297
|
}
|
|
1188
1298
|
function cardinalDay(value) {
|
|
1189
1299
|
return "" + value;
|
|
1190
1300
|
}
|
|
1191
|
-
function monthScope(
|
|
1192
|
-
if (
|
|
1301
|
+
function monthScope(schedule, opts) {
|
|
1302
|
+
if (schedule.pattern.month === "*") {
|
|
1193
1303
|
return "";
|
|
1194
1304
|
}
|
|
1195
|
-
return " in " + monthName(
|
|
1305
|
+
return " in " + monthName(schedule, opts);
|
|
1196
1306
|
}
|
|
1197
|
-
function monthScopeForRecurrence(phrase,
|
|
1198
|
-
if (
|
|
1307
|
+
function monthScopeForRecurrence(phrase, schedule, opts) {
|
|
1308
|
+
if (schedule.pattern.month === "*") {
|
|
1199
1309
|
return phrase;
|
|
1200
1310
|
}
|
|
1201
1311
|
const carriesRecurrence = phrase.indexOf(" of the month") !== -1;
|
|
1202
|
-
if (carriesRecurrence &&
|
|
1203
|
-
return phrase.replace(" of the month", " of each month") + " from " + monthName(
|
|
1312
|
+
if (carriesRecurrence && schedule.shapes.month === "range") {
|
|
1313
|
+
return phrase.replace(" of the month", " of each month") + " from " + monthName(schedule, opts);
|
|
1204
1314
|
}
|
|
1205
|
-
if (carriesRecurrence && (
|
|
1206
|
-
return phrase.replace(" of the month", "") + " in " + monthName(
|
|
1315
|
+
if (carriesRecurrence && (schedule.shapes.month === "single" || schedule.shapes.month === "step")) {
|
|
1316
|
+
return phrase.replace(" of the month", "") + " in " + monthName(schedule, opts);
|
|
1207
1317
|
}
|
|
1208
|
-
return phrase + " in " + monthName(
|
|
1318
|
+
return phrase + " in " + monthName(schedule, opts);
|
|
1209
1319
|
}
|
|
1210
1320
|
function stepDates(dateField) {
|
|
1211
1321
|
const parts = dateField.split("/");
|
|
@@ -1218,15 +1328,15 @@ function stepDates(dateField) {
|
|
|
1218
1328
|
}
|
|
1219
1329
|
return phrase;
|
|
1220
1330
|
}
|
|
1221
|
-
function dateOrdinals(
|
|
1222
|
-
return renderSegments(
|
|
1331
|
+
function dateOrdinals(schedule, opts) {
|
|
1332
|
+
return renderSegments(segmentsOf(schedule, "date"), getOrdinal, opts);
|
|
1223
1333
|
}
|
|
1224
|
-
function monthName(
|
|
1225
|
-
const oddEven = oddEvenMonth(
|
|
1334
|
+
function monthName(schedule, opts) {
|
|
1335
|
+
const oddEven = oddEvenMonth(schedule.pattern.month);
|
|
1226
1336
|
if (oddEven) {
|
|
1227
1337
|
return oddEven;
|
|
1228
1338
|
}
|
|
1229
|
-
return renderSegments(
|
|
1339
|
+
return renderSegments(segmentsOf(schedule, "month"), function name(value) {
|
|
1230
1340
|
return getMonth(value, opts);
|
|
1231
1341
|
}, opts);
|
|
1232
1342
|
}
|
|
@@ -1243,8 +1353,8 @@ function oddEvenMonth(monthField) {
|
|
|
1243
1353
|
}
|
|
1244
1354
|
return start === "2" ? "every even-numbered month" : null;
|
|
1245
1355
|
}
|
|
1246
|
-
function weekdayPhrase(
|
|
1247
|
-
const segments = orderWeekdaysForDisplay(
|
|
1356
|
+
function weekdayPhrase(schedule, recurring, opts) {
|
|
1357
|
+
const segments = orderWeekdaysForDisplay(segmentsOf(schedule, "weekday"));
|
|
1248
1358
|
const hasRange = segments.some(function range(segment) {
|
|
1249
1359
|
return segment.kind === "range";
|
|
1250
1360
|
});
|
|
@@ -1272,11 +1382,8 @@ function renderSegments(segments, word, opts) {
|
|
|
1272
1382
|
});
|
|
1273
1383
|
return joinList(pieces, opts);
|
|
1274
1384
|
}
|
|
1275
|
-
function
|
|
1276
|
-
|
|
1277
|
-
}
|
|
1278
|
-
function applyYear(description, ir, opts) {
|
|
1279
|
-
const yearField = ir.pattern.year;
|
|
1385
|
+
function applyYear(description, schedule, opts) {
|
|
1386
|
+
const yearField = schedule.pattern.year;
|
|
1280
1387
|
if (yearField === "*") {
|
|
1281
1388
|
return description;
|
|
1282
1389
|
}
|
|
@@ -1284,7 +1391,7 @@ function applyYear(description, ir, opts) {
|
|
|
1284
1391
|
return description + ", " + stepYears(yearField, opts);
|
|
1285
1392
|
}
|
|
1286
1393
|
const label = yearLabel(yearField, opts);
|
|
1287
|
-
if (yearField.indexOf("-") === -1 && yearField.indexOf(",") === -1 &&
|
|
1394
|
+
if (yearField.indexOf("-") === -1 && yearField.indexOf(",") === -1 && schedule.pattern.date !== "*" && description.indexOf(" at ") !== -1) {
|
|
1288
1395
|
const yearGlue = opts.style.dayFirst ? " " : ", ";
|
|
1289
1396
|
return description.replace(" at ", yearGlue + label + " at ");
|
|
1290
1397
|
}
|