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