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/fi.cjs
CHANGED
|
@@ -57,6 +57,16 @@ function isNonNegativeInteger(value) {
|
|
|
57
57
|
const digits = /^\d+$/;
|
|
58
58
|
return digits.test(value);
|
|
59
59
|
}
|
|
60
|
+
function toFieldNumber(token, numberMap) {
|
|
61
|
+
return isNonNegativeInteger(token) ? +token : numberMap[token.toUpperCase()];
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
// src/core/shapes.ts
|
|
65
|
+
function isOpenStep(field) {
|
|
66
|
+
return field.indexOf("/") !== -1 && field.indexOf("-") === -1 && field.indexOf(",") === -1;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
// src/core/cadence.ts
|
|
60
70
|
function arithmeticStep(values) {
|
|
61
71
|
if (values.length < 5) {
|
|
62
72
|
return null;
|
|
@@ -72,6 +82,56 @@ function arithmeticStep(values) {
|
|
|
72
82
|
}
|
|
73
83
|
return { start: values[0], interval, last: values[values.length - 1] };
|
|
74
84
|
}
|
|
85
|
+
function segmentsOf(schedule, field) {
|
|
86
|
+
return schedule.analyses.segments[field] ?? [];
|
|
87
|
+
}
|
|
88
|
+
function stepSegment(schedule, field) {
|
|
89
|
+
return segmentsOf(schedule, field)[0];
|
|
90
|
+
}
|
|
91
|
+
function singleValues(segments) {
|
|
92
|
+
const values = [];
|
|
93
|
+
for (const segment of segments) {
|
|
94
|
+
if (segment.kind !== "single") {
|
|
95
|
+
return null;
|
|
96
|
+
}
|
|
97
|
+
values.push(+segment.value);
|
|
98
|
+
}
|
|
99
|
+
return values;
|
|
100
|
+
}
|
|
101
|
+
function offsetCleanStride(stride) {
|
|
102
|
+
return stride.start < stride.interval && 24 % stride.interval === 0;
|
|
103
|
+
}
|
|
104
|
+
function renderStride(spec, parts) {
|
|
105
|
+
const { start, interval, cycle } = spec;
|
|
106
|
+
const tiles = cycle % interval === 0;
|
|
107
|
+
if (start === 0 && tiles) {
|
|
108
|
+
return parts.bare();
|
|
109
|
+
}
|
|
110
|
+
if (start < interval && tiles) {
|
|
111
|
+
return parts.offset();
|
|
112
|
+
}
|
|
113
|
+
return parts.bounded();
|
|
114
|
+
}
|
|
115
|
+
function hourListStride(values) {
|
|
116
|
+
if (values.length < 2) {
|
|
117
|
+
return null;
|
|
118
|
+
}
|
|
119
|
+
const interval = values[1] - values[0];
|
|
120
|
+
if (interval < 2) {
|
|
121
|
+
return null;
|
|
122
|
+
}
|
|
123
|
+
for (let i = 2; i < values.length; i += 1) {
|
|
124
|
+
if (values[i] - values[i - 1] !== interval) {
|
|
125
|
+
return null;
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
if (values[0] !== 0 && values.length < 5) {
|
|
129
|
+
return null;
|
|
130
|
+
}
|
|
131
|
+
return { interval, last: values[values.length - 1], start: values[0] };
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
// src/core/weekday.ts
|
|
75
135
|
function weekdayDisplayKey(value) {
|
|
76
136
|
return value === 0 ? 7 : value;
|
|
77
137
|
}
|
|
@@ -92,9 +152,6 @@ function orderWeekdaysForDisplay(segments) {
|
|
|
92
152
|
return pair[0];
|
|
93
153
|
});
|
|
94
154
|
}
|
|
95
|
-
function toFieldNumber(token, numberMap) {
|
|
96
|
-
return isNonNegativeInteger(token) ? +token : numberMap[token.toUpperCase()];
|
|
97
|
-
}
|
|
98
155
|
|
|
99
156
|
// src/lang/fi/dialects.ts
|
|
100
157
|
var dialects = {
|
|
@@ -113,9 +170,6 @@ function resolveDialect(dialect) {
|
|
|
113
170
|
}
|
|
114
171
|
|
|
115
172
|
// src/lang/fi/index.ts
|
|
116
|
-
function stepSegment(segments) {
|
|
117
|
-
return segments[0];
|
|
118
|
-
}
|
|
119
173
|
var genitives = [
|
|
120
174
|
null,
|
|
121
175
|
"yhden",
|
|
@@ -253,94 +307,108 @@ function normalizeOptions(options) {
|
|
|
253
307
|
years: !!options.years
|
|
254
308
|
};
|
|
255
309
|
}
|
|
256
|
-
function restrictedMonthUnion(
|
|
257
|
-
return
|
|
310
|
+
function restrictedMonthUnion(schedule) {
|
|
311
|
+
return schedule.pattern.date !== "*" && schedule.pattern.weekday !== "*" && schedule.pattern.month !== "*";
|
|
258
312
|
}
|
|
259
|
-
function
|
|
260
|
-
|
|
313
|
+
function oddDayUnion(dateField) {
|
|
314
|
+
if (!isOpenStep(dateField)) {
|
|
315
|
+
return null;
|
|
316
|
+
}
|
|
317
|
+
const [start, step] = dateField.split("/");
|
|
318
|
+
return (start === "*" || start === "1") && +step === 2 ? "kuukauden parittomina p\xE4ivin\xE4" : null;
|
|
319
|
+
}
|
|
320
|
+
function unionDateArm(schedule) {
|
|
321
|
+
return quartzDatePhrase(schedule.pattern.date) || oddDayUnion(schedule.pattern.date) || dateWords(schedule) + " p\xE4iv\xE4n\xE4";
|
|
322
|
+
}
|
|
323
|
+
function unionWeekdayArm(schedule) {
|
|
324
|
+
const segments = segmentsOf(schedule, "weekday");
|
|
325
|
+
if (segments.length === 1 && segments[0].kind === "range" && segments[0].bounds[0] === "1" && segments[0].bounds[1] === "5") {
|
|
326
|
+
return "arkisin";
|
|
327
|
+
}
|
|
328
|
+
return weekdayQualifier(schedule);
|
|
261
329
|
}
|
|
262
|
-
function describe(
|
|
263
|
-
if (restrictedMonthUnion(
|
|
264
|
-
const timePart = render(
|
|
330
|
+
function describe(schedule, opts) {
|
|
331
|
+
if (restrictedMonthUnion(schedule)) {
|
|
332
|
+
const timePart = render(schedule, schedule.plan, opts);
|
|
265
333
|
return applyYear(
|
|
266
|
-
monthPhrase(
|
|
267
|
-
|
|
334
|
+
monthPhrase(schedule) + " " + timePart + " " + unionDateArm(schedule) + " tai " + unionWeekdayArm(schedule),
|
|
335
|
+
schedule,
|
|
268
336
|
opts
|
|
269
337
|
);
|
|
270
338
|
}
|
|
271
|
-
return applyYear(render(
|
|
339
|
+
return applyYear(render(schedule, schedule.plan, opts), schedule, opts);
|
|
272
340
|
}
|
|
273
|
-
function render(
|
|
341
|
+
function render(schedule, plan, opts) {
|
|
274
342
|
const renderer = renderers[plan.kind];
|
|
275
|
-
return renderer(
|
|
343
|
+
return renderer(schedule, plan, opts);
|
|
276
344
|
}
|
|
277
|
-
function renderEverySecond(
|
|
278
|
-
return "joka sekunti" + trailingQualifier(
|
|
345
|
+
function renderEverySecond(schedule, plan, opts) {
|
|
346
|
+
return "joka sekunti" + trailingQualifier(schedule, opts);
|
|
279
347
|
}
|
|
280
|
-
function renderStandaloneSeconds(
|
|
281
|
-
return secondsLeadClause(
|
|
348
|
+
function renderStandaloneSeconds(schedule, plan, opts) {
|
|
349
|
+
return secondsLeadClause(schedule, opts) + trailingQualifier(schedule, opts);
|
|
282
350
|
}
|
|
283
|
-
function renderSecondPastMinute(
|
|
284
|
-
return atMarks(
|
|
351
|
+
function renderSecondPastMinute(schedule, plan, opts) {
|
|
352
|
+
return atMarks(schedule.pattern.second, units.second, true) + trailingQualifier(schedule, opts);
|
|
285
353
|
}
|
|
286
|
-
function renderSecondsWithinMinute(
|
|
287
|
-
const minuteField =
|
|
354
|
+
function renderSecondsWithinMinute(schedule, plan, opts) {
|
|
355
|
+
const minuteField = schedule.pattern.minute;
|
|
288
356
|
if (plan.singleSecond) {
|
|
289
|
-
return units.minute.mark + " " + minuteField + " " + units.minute.gen + " ja " +
|
|
357
|
+
return units.minute.mark + " " + minuteField + " " + units.minute.gen + " ja " + schedule.pattern.second + " " + units.second.gen + " kohdalla" + trailingQualifier(schedule, opts);
|
|
290
358
|
}
|
|
291
|
-
return secondsLeadClause(
|
|
359
|
+
return secondsLeadClause(schedule, opts) + ", " + atMarks(minuteField, units.minute, true) + trailingQualifier(schedule, opts);
|
|
292
360
|
}
|
|
293
|
-
function composeSecondsOverMinuteStep(
|
|
294
|
-
const seg = stepSegment(
|
|
361
|
+
function composeSecondsOverMinuteStep(schedule, freq, opts) {
|
|
362
|
+
const seg = stepSegment(schedule, "minute");
|
|
295
363
|
const stepPhrase = stepCycle60(seg, units.minute, opts);
|
|
296
364
|
if (freq.hours.kind === "during" && minuteStepIsAnchored(seg)) {
|
|
297
|
-
const bareHours = kloFromTimes(
|
|
298
|
-
return hoursFirstMinutes(bareHours,
|
|
365
|
+
const bareHours = kloFromTimes(schedule, freq.hours.times, opts);
|
|
366
|
+
return hoursFirstMinutes(bareHours, schedule, opts) + ", " + secondsLeadClause(schedule, opts) + trailingQualifier(schedule, opts);
|
|
299
367
|
}
|
|
300
368
|
let hourClause = "";
|
|
301
369
|
if (freq.hours.kind === "during") {
|
|
302
|
-
hourClause = " " + hourWindowsFromTimes(
|
|
370
|
+
hourClause = " " + hourWindowsFromTimes(schedule, freq.hours.times, opts);
|
|
303
371
|
} else if (freq.hours.kind === "window") {
|
|
304
372
|
hourClause = " " + hourWindow(freq.hours, opts);
|
|
305
373
|
} else if (freq.hours.kind === "step") {
|
|
306
|
-
hourClause = " " + everyNthHour(stepSegment(
|
|
374
|
+
hourClause = " " + everyNthHour(stepSegment(schedule, "hour"), opts);
|
|
307
375
|
}
|
|
308
|
-
return stepPhrase + ", " + secondsLeadClause(
|
|
376
|
+
return stepPhrase + ", " + secondsLeadClause(schedule, opts) + hourClause + trailingQualifier(schedule, opts);
|
|
309
377
|
}
|
|
310
|
-
function composeHourCadence(
|
|
378
|
+
function composeHourCadence(schedule, plan, opts) {
|
|
311
379
|
const clockRest = plan.rest.kind === "clockTimes" || plan.rest.kind === "compactClockTimes";
|
|
312
|
-
if (!clockRest ||
|
|
380
|
+
if (!clockRest || schedule.shapes.minute !== "single") {
|
|
313
381
|
return null;
|
|
314
382
|
}
|
|
315
|
-
const minute = +
|
|
316
|
-
return hourCadence(
|
|
383
|
+
const minute = +schedule.pattern.minute;
|
|
384
|
+
return hourCadence(schedule, minute, opts) ?? hourRangeCadence(schedule, minute, opts);
|
|
317
385
|
}
|
|
318
|
-
function renderComposeSeconds(
|
|
319
|
-
const cadence = composeHourCadence(
|
|
386
|
+
function renderComposeSeconds(schedule, plan, opts) {
|
|
387
|
+
const cadence = composeHourCadence(schedule, plan, opts);
|
|
320
388
|
if (cadence !== null) {
|
|
321
389
|
return cadence;
|
|
322
390
|
}
|
|
323
|
-
if (plan.rest.kind === "minuteFrequency" &&
|
|
324
|
-
return composeSecondsOverMinuteStep(
|
|
391
|
+
if (plan.rest.kind === "minuteFrequency" && schedule.pattern.second !== "*") {
|
|
392
|
+
return composeSecondsOverMinuteStep(schedule, plan.rest, opts);
|
|
325
393
|
}
|
|
326
394
|
if (plan.rest.kind === "clockTimes" && plan.rest.times.every((time) => +time.minute === 0)) {
|
|
327
|
-
return composeMinuteZero(
|
|
395
|
+
return composeMinuteZero(schedule, plan.rest, opts);
|
|
328
396
|
}
|
|
329
|
-
if (isEveryOtherMinuteSeconds(
|
|
330
|
-
return secondsLeadClause(
|
|
397
|
+
if (isEveryOtherMinuteSeconds(schedule, plan)) {
|
|
398
|
+
return secondsLeadClause(schedule, opts) + " joka toisena minuuttina";
|
|
331
399
|
}
|
|
332
|
-
const restOwnsLead = plan.rest.kind === "compactClockTimes" &&
|
|
333
|
-
const lead = restOwnsLead ? "" : secondsLeadClause(
|
|
334
|
-
return lead + render(
|
|
400
|
+
const restOwnsLead = plan.rest.kind === "compactClockTimes" && schedule.analyses.clockSecond;
|
|
401
|
+
const lead = restOwnsLead ? "" : secondsLeadClause(schedule, opts) + ", ";
|
|
402
|
+
return lead + render(schedule, plan.rest, opts);
|
|
335
403
|
}
|
|
336
|
-
function isEveryOtherMinuteSeconds(
|
|
337
|
-
if (plan.rest.kind !== "minuteFrequency" ||
|
|
404
|
+
function isEveryOtherMinuteSeconds(schedule, plan) {
|
|
405
|
+
if (plan.rest.kind !== "minuteFrequency" || schedule.pattern.second !== "*" || schedule.shapes.hour !== "wildcard") {
|
|
338
406
|
return false;
|
|
339
407
|
}
|
|
340
|
-
const seg = stepSegment(
|
|
408
|
+
const seg = stepSegment(schedule, "minute");
|
|
341
409
|
return seg.startToken === "*" && seg.interval === 2;
|
|
342
410
|
}
|
|
343
|
-
function composeMinuteZero(
|
|
411
|
+
function composeMinuteZero(schedule, rest, opts) {
|
|
344
412
|
const clocks = rest.times.map(function clock(time) {
|
|
345
413
|
return clockDigits(
|
|
346
414
|
{ hour: time.hour, minute: time.minute },
|
|
@@ -348,54 +416,66 @@ function composeMinuteZero(ir, rest, opts) {
|
|
|
348
416
|
);
|
|
349
417
|
});
|
|
350
418
|
const frame = clocks.length === 1 ? "minuutin " + clocks[0] : "minuuttien " + joinList(clocks);
|
|
351
|
-
const dayTrail = leadingQualifier(
|
|
352
|
-
return secondsLeadClause(
|
|
419
|
+
const dayTrail = leadingQualifier(schedule, opts).trimEnd();
|
|
420
|
+
return secondsLeadClause(schedule, opts) + " " + frame + " aikana" + (dayTrail ? ", " + dayTrail : "");
|
|
353
421
|
}
|
|
354
|
-
function secondsLeadClause(
|
|
355
|
-
const secondField =
|
|
356
|
-
const shape =
|
|
422
|
+
function secondsLeadClause(schedule, opts) {
|
|
423
|
+
const secondField = schedule.pattern.second;
|
|
424
|
+
const shape = schedule.shapes.second;
|
|
357
425
|
if (secondField === "*") {
|
|
358
426
|
return "joka sekunti";
|
|
359
427
|
}
|
|
360
428
|
if (shape === "step") {
|
|
361
429
|
return stepCycle60(
|
|
362
|
-
stepSegment(
|
|
430
|
+
stepSegment(schedule, "second"),
|
|
363
431
|
units.second,
|
|
364
432
|
opts
|
|
365
433
|
);
|
|
366
434
|
}
|
|
367
|
-
const marked =
|
|
435
|
+
const marked = schedule.pattern.minute === "*";
|
|
368
436
|
if (shape === "single") {
|
|
369
437
|
return atMarks(secondField, units.second, marked);
|
|
370
438
|
}
|
|
371
|
-
return strideFromSegments(
|
|
372
|
-
|
|
439
|
+
return strideFromSegments(
|
|
440
|
+
segmentsOf(schedule, "second"),
|
|
441
|
+
units.second,
|
|
442
|
+
opts
|
|
443
|
+
) ?? atMarks(
|
|
444
|
+
joinList(segmentWords(segmentsOf(schedule, "second"))),
|
|
373
445
|
units.second,
|
|
374
446
|
marked
|
|
375
447
|
);
|
|
376
448
|
}
|
|
377
|
-
function renderEveryMinute(
|
|
378
|
-
return "joka minuutti" + trailingQualifier(
|
|
449
|
+
function renderEveryMinute(schedule, plan, opts) {
|
|
450
|
+
return "joka minuutti" + trailingQualifier(schedule, opts);
|
|
379
451
|
}
|
|
380
|
-
function renderSingleMinute(
|
|
381
|
-
return atMarks(
|
|
452
|
+
function renderSingleMinute(schedule, plan, opts) {
|
|
453
|
+
return atMarks(schedule.pattern.minute, units.minute, true) + trailingQualifier(schedule, opts);
|
|
382
454
|
}
|
|
383
|
-
function renderRangeOfMinutes(
|
|
384
|
-
return minutesList(
|
|
455
|
+
function renderRangeOfMinutes(schedule, plan, opts) {
|
|
456
|
+
return minutesList(schedule, opts) + trailingQualifier(schedule, opts);
|
|
385
457
|
}
|
|
386
|
-
function renderMultipleMinutes(
|
|
387
|
-
return minutesList(
|
|
458
|
+
function renderMultipleMinutes(schedule, plan, opts) {
|
|
459
|
+
return minutesList(schedule, opts) + trailingQualifier(schedule, opts);
|
|
388
460
|
}
|
|
389
|
-
function minutesList(
|
|
390
|
-
return strideFromSegments(
|
|
391
|
-
|
|
461
|
+
function minutesList(schedule, opts) {
|
|
462
|
+
return strideFromSegments(
|
|
463
|
+
segmentsOf(schedule, "minute"),
|
|
464
|
+
units.minute,
|
|
465
|
+
opts
|
|
466
|
+
) ?? atMarks(
|
|
467
|
+
joinList(segmentWords(segmentsOf(schedule, "minute"))),
|
|
392
468
|
units.minute,
|
|
393
469
|
true
|
|
394
470
|
);
|
|
395
471
|
}
|
|
396
|
-
function bareMinutes(
|
|
397
|
-
return strideFromSegments(
|
|
398
|
-
|
|
472
|
+
function bareMinutes(schedule, opts) {
|
|
473
|
+
return strideFromSegments(
|
|
474
|
+
segmentsOf(schedule, "minute"),
|
|
475
|
+
units.minute,
|
|
476
|
+
opts
|
|
477
|
+
) ?? atMarks(
|
|
478
|
+
joinList(segmentWords(segmentsOf(schedule, "minute"))),
|
|
399
479
|
units.minute,
|
|
400
480
|
false
|
|
401
481
|
);
|
|
@@ -425,16 +505,16 @@ function hoursAreRangeIsolated(segments) {
|
|
|
425
505
|
}
|
|
426
506
|
return hasRange && hasSingle;
|
|
427
507
|
}
|
|
428
|
-
function hoursFirstMinutes(hoursStr,
|
|
429
|
-
const stride = strideFromSegments(
|
|
508
|
+
function hoursFirstMinutes(hoursStr, schedule, opts) {
|
|
509
|
+
const stride = strideFromSegments(segmentsOf(schedule, "minute"), units.minute, opts);
|
|
430
510
|
if (stride) {
|
|
431
511
|
return hoursStr + " aina " + stride;
|
|
432
512
|
}
|
|
433
|
-
return hoursStr + " aina minuuttien " + joinList(segmentWords(
|
|
513
|
+
return hoursStr + " aina minuuttien " + joinList(segmentWords(segmentsOf(schedule, "minute"))) + " kohdalla";
|
|
434
514
|
}
|
|
435
|
-
function hourSegmentTimesWithSeka(
|
|
515
|
+
function hourSegmentTimesWithSeka(schedule, minute, second, opts) {
|
|
436
516
|
const pieces = [];
|
|
437
|
-
|
|
517
|
+
segmentsOf(schedule, "hour").forEach(function clock(segment) {
|
|
438
518
|
if (segment.kind === "range") {
|
|
439
519
|
pieces.push(rangeDigits(
|
|
440
520
|
{ hour: +segment.bounds[0], minute, second },
|
|
@@ -447,61 +527,61 @@ function hourSegmentTimesWithSeka(ir, minute, second, opts) {
|
|
|
447
527
|
});
|
|
448
528
|
return "klo " + pieces.slice(0, -1).join(", ") + " sek\xE4 klo " + pieces[pieces.length - 1];
|
|
449
529
|
}
|
|
450
|
-
function renderMinuteFrequency(
|
|
451
|
-
const seg = stepSegment(
|
|
530
|
+
function renderMinuteFrequency(schedule, plan, opts) {
|
|
531
|
+
const seg = stepSegment(schedule, "minute");
|
|
452
532
|
if (plan.hours.kind === "during") {
|
|
453
|
-
const cadence = unevenHourCadence(
|
|
533
|
+
const cadence = unevenHourCadence(schedule, opts);
|
|
454
534
|
if (cadence !== null) {
|
|
455
|
-
return stepCycle60(seg, units.minute, opts) + ", " + cadence + trailingQualifier(
|
|
535
|
+
return stepCycle60(seg, units.minute, opts) + ", " + cadence + trailingQualifier(schedule, opts);
|
|
456
536
|
}
|
|
457
537
|
if (minuteStepIsAnchored(seg)) {
|
|
458
|
-
const bareHours = kloFromTimes(
|
|
459
|
-
return hoursFirstMinutes(bareHours,
|
|
538
|
+
const bareHours = kloFromTimes(schedule, plan.hours.times, opts);
|
|
539
|
+
return hoursFirstMinutes(bareHours, schedule, opts) + trailingQualifier(schedule, opts);
|
|
460
540
|
}
|
|
461
|
-
return stepCycle60(seg, units.minute, opts) + " " + hourWindowsFromTimes(
|
|
541
|
+
return stepCycle60(seg, units.minute, opts) + " " + hourWindowsFromTimes(schedule, plan.hours.times, opts) + trailingQualifier(schedule, opts);
|
|
462
542
|
}
|
|
463
543
|
let phrase = stepCycle60(seg, units.minute, opts);
|
|
464
544
|
if (plan.hours.kind === "window") {
|
|
465
545
|
phrase += " " + hourWindow(plan.hours, opts);
|
|
466
546
|
} else if (plan.hours.kind === "step") {
|
|
467
|
-
phrase += " " + everyNthHour(stepSegment(
|
|
547
|
+
phrase += " " + everyNthHour(stepSegment(schedule, "hour"), opts);
|
|
468
548
|
}
|
|
469
|
-
return phrase + trailingQualifier(
|
|
549
|
+
return phrase + trailingQualifier(schedule, opts);
|
|
470
550
|
}
|
|
471
|
-
function renderMinuteSpanInHour(
|
|
472
|
-
if (
|
|
473
|
-
return "joka minuutti kello " + plan.hour + " aikana" + trailingQualifier(
|
|
551
|
+
function renderMinuteSpanInHour(schedule, plan, opts) {
|
|
552
|
+
if (schedule.pattern.minute === "*") {
|
|
553
|
+
return "joka minuutti kello " + plan.hour + " aikana" + trailingQualifier(schedule, opts);
|
|
474
554
|
}
|
|
475
555
|
return "joka minuutti " + kloRange(
|
|
476
556
|
{ hour: plan.hour, minute: plan.span[0] },
|
|
477
557
|
{ hour: plan.hour, minute: plan.span[1] },
|
|
478
558
|
opts
|
|
479
|
-
) + trailingQualifier(
|
|
559
|
+
) + trailingQualifier(schedule, opts);
|
|
480
560
|
}
|
|
481
|
-
function renderMinutesAcrossHours(
|
|
482
|
-
const cadence = unevenHourCadence(
|
|
561
|
+
function renderMinutesAcrossHours(schedule, plan, opts) {
|
|
562
|
+
const cadence = unevenHourCadence(schedule, opts);
|
|
483
563
|
if (plan.form === "wildcard") {
|
|
484
|
-
return cadence ? "joka minuutti, " + cadence + trailingQualifier(
|
|
564
|
+
return cadence ? "joka minuutti, " + cadence + trailingQualifier(schedule, opts) : "joka minuutti " + hourWindowsFromTimes(schedule, plan.times, opts) + trailingQualifier(schedule, opts);
|
|
485
565
|
}
|
|
486
566
|
if (cadence !== null) {
|
|
487
|
-
return bareMinutes(
|
|
567
|
+
return bareMinutes(schedule, opts) + ", " + cadence + trailingQualifier(schedule, opts);
|
|
488
568
|
}
|
|
489
|
-
if (hoursAreRangeIsolated(
|
|
490
|
-
return bareMinutes(
|
|
569
|
+
if (hoursAreRangeIsolated(segmentsOf(schedule, "hour"))) {
|
|
570
|
+
return bareMinutes(schedule, opts) + " " + hourSegmentTimesWithSeka(schedule, 0, null, opts) + trailingQualifier(schedule, opts);
|
|
491
571
|
}
|
|
492
|
-
const hoursStr = kloFromTimes(
|
|
493
|
-
return hoursFirstMinutes(hoursStr,
|
|
572
|
+
const hoursStr = kloFromTimes(schedule, plan.times, opts);
|
|
573
|
+
return hoursFirstMinutes(hoursStr, schedule, opts) + trailingQualifier(schedule, opts);
|
|
494
574
|
}
|
|
495
|
-
function renderMinuteSpanAcrossHourStep(
|
|
496
|
-
const segment = stepSegment(
|
|
497
|
-
const cadence = unevenHourCadence(
|
|
575
|
+
function renderMinuteSpanAcrossHourStep(schedule, plan, opts) {
|
|
576
|
+
const segment = stepSegment(schedule, "hour");
|
|
577
|
+
const cadence = unevenHourCadence(schedule, opts);
|
|
498
578
|
if (plan.form === "wildcard") {
|
|
499
|
-
return "joka minuutti " + everyNthHour(segment, opts) + trailingQualifier(
|
|
579
|
+
return "joka minuutti " + everyNthHour(segment, opts) + trailingQualifier(schedule, opts);
|
|
500
580
|
}
|
|
501
581
|
if (cadence !== null) {
|
|
502
|
-
return bareMinutes(
|
|
582
|
+
return bareMinutes(schedule, opts) + ", " + cadence + trailingQualifier(schedule, opts);
|
|
503
583
|
}
|
|
504
|
-
return bareMinutes(
|
|
584
|
+
return bareMinutes(schedule, opts) + hourStepTail(segment, opts) + trailingQualifier(schedule, opts);
|
|
505
585
|
}
|
|
506
586
|
function plainHourStep(segment) {
|
|
507
587
|
return segment.startToken === "*" && 24 % segment.interval === 0;
|
|
@@ -550,35 +630,35 @@ function hourStepTail(segment, opts) {
|
|
|
550
630
|
const sep = plainHourStep(segment) ? " " : ", ";
|
|
551
631
|
return sep + plainOrFullHourStep(segment, opts);
|
|
552
632
|
}
|
|
553
|
-
function renderEveryHour(
|
|
554
|
-
return "joka tunti" + trailingQualifier(
|
|
633
|
+
function renderEveryHour(schedule, plan, opts) {
|
|
634
|
+
return "joka tunti" + trailingQualifier(schedule, opts);
|
|
555
635
|
}
|
|
556
|
-
function renderHourRange(
|
|
636
|
+
function renderHourRange(schedule, plan, opts) {
|
|
557
637
|
const window = hourWindow(boundedWindow(plan), opts);
|
|
558
638
|
if (plan.minuteForm === "wildcard") {
|
|
559
|
-
return "joka minuutti " + window + trailingQualifier(
|
|
639
|
+
return "joka minuutti " + window + trailingQualifier(schedule, opts);
|
|
560
640
|
}
|
|
561
641
|
if (plan.minuteForm === "range") {
|
|
562
|
-
return hoursFirstMinutes(window,
|
|
642
|
+
return hoursFirstMinutes(window, schedule, opts) + trailingQualifier(schedule, opts);
|
|
563
643
|
}
|
|
564
|
-
if (
|
|
565
|
-
return "joka tunti " + window + trailingQualifier(
|
|
644
|
+
if (schedule.pattern.minute === "0") {
|
|
645
|
+
return "joka tunti " + window + trailingQualifier(schedule, opts);
|
|
566
646
|
}
|
|
567
|
-
if (
|
|
568
|
-
return atMarks(
|
|
569
|
-
{ hour: plan.from, minute: +
|
|
647
|
+
if (schedule.shapes.minute === "single") {
|
|
648
|
+
return atMarks(schedule.pattern.minute, units.minute, false) + " " + kloRange(
|
|
649
|
+
{ hour: plan.from, minute: +schedule.pattern.minute },
|
|
570
650
|
{ hour: plan.to, minute: plan.last },
|
|
571
651
|
opts
|
|
572
|
-
) + trailingQualifier(
|
|
652
|
+
) + trailingQualifier(schedule, opts);
|
|
573
653
|
}
|
|
574
|
-
return hoursFirstMinutes(window,
|
|
654
|
+
return hoursFirstMinutes(window, schedule, opts) + trailingQualifier(schedule, opts);
|
|
575
655
|
}
|
|
576
|
-
function renderHourStep(
|
|
577
|
-
const cadence = unevenHourCadence(
|
|
656
|
+
function renderHourStep(schedule, plan, opts) {
|
|
657
|
+
const cadence = unevenHourCadence(schedule, opts);
|
|
578
658
|
if (cadence !== null) {
|
|
579
|
-
return cadence + trailingQualifier(
|
|
659
|
+
return cadence + trailingQualifier(schedule, opts);
|
|
580
660
|
}
|
|
581
|
-
return stepHours(stepSegment(
|
|
661
|
+
return stepHours(stepSegment(schedule, "hour"), opts) + trailingQualifier(schedule, opts);
|
|
582
662
|
}
|
|
583
663
|
function boundedWindow(plan) {
|
|
584
664
|
return { from: plan.from, last: plan.boundMinute ?? 0, to: plan.to };
|
|
@@ -590,53 +670,62 @@ function hourWindow(window, opts) {
|
|
|
590
670
|
opts
|
|
591
671
|
);
|
|
592
672
|
}
|
|
593
|
-
function renderClockTimes(
|
|
594
|
-
if (
|
|
595
|
-
const minute = +
|
|
596
|
-
const cadence = hourCadence(
|
|
673
|
+
function renderClockTimes(schedule, plan, opts) {
|
|
674
|
+
if (schedule.shapes.minute === "single") {
|
|
675
|
+
const minute = +schedule.pattern.minute;
|
|
676
|
+
const cadence = hourCadence(schedule, minute, opts) ?? hourRangeCadence(schedule, minute, opts);
|
|
597
677
|
if (cadence !== null) {
|
|
598
678
|
return cadence;
|
|
599
679
|
}
|
|
600
680
|
}
|
|
601
681
|
if (plan.times.length === 1) {
|
|
602
682
|
const time = plan.times[0];
|
|
603
|
-
return leadingQualifier(
|
|
683
|
+
return leadingQualifier(schedule, opts) + timeWord(time.hour, time.minute, time.second, opts);
|
|
604
684
|
}
|
|
605
685
|
const digits = plan.times.map(function clock(time) {
|
|
606
686
|
return timeDigits(time.hour, time.minute, time.second, opts);
|
|
607
687
|
});
|
|
608
|
-
return leadingQualifier(
|
|
688
|
+
return leadingQualifier(schedule, opts) + "klo " + joinList(digits);
|
|
609
689
|
}
|
|
610
|
-
function renderCompactClockTimes(
|
|
690
|
+
function renderCompactClockTimes(schedule, plan, opts) {
|
|
611
691
|
if (plan.fold) {
|
|
612
|
-
const cadence2 = hourCadence(
|
|
692
|
+
const cadence2 = hourCadence(schedule, plan.minute, opts) ?? hourRangeCadence(schedule, plan.minute, opts);
|
|
613
693
|
if (cadence2 !== null) {
|
|
614
694
|
return cadence2;
|
|
615
695
|
}
|
|
616
696
|
}
|
|
617
|
-
const hourSegs =
|
|
697
|
+
const hourSegs = segmentsOf(schedule, "hour");
|
|
618
698
|
if (hoursAreRangeIsolated(hourSegs)) {
|
|
619
699
|
if (plan.fold) {
|
|
620
|
-
return leadingQualifier(
|
|
621
|
-
|
|
700
|
+
return leadingQualifier(schedule, opts) + hourSegmentTimesWithSeka(
|
|
701
|
+
schedule,
|
|
622
702
|
plan.minute,
|
|
623
|
-
|
|
703
|
+
schedule.analyses.clockSecond,
|
|
624
704
|
opts
|
|
625
705
|
);
|
|
626
706
|
}
|
|
627
|
-
const phrase2 = bareMinutes(
|
|
628
|
-
return
|
|
707
|
+
const phrase2 = bareMinutes(schedule, opts) + " " + hourSegmentTimesWithSeka(schedule, 0, null, opts) + trailingQualifier(schedule, opts);
|
|
708
|
+
return schedule.analyses.clockSecond ? secondsLeadClause(schedule, opts) + ", " + phrase2 : phrase2;
|
|
629
709
|
}
|
|
630
710
|
if (plan.fold) {
|
|
631
|
-
return leadingQualifier(
|
|
711
|
+
return leadingQualifier(schedule, opts) + hourSegmentTimes(
|
|
712
|
+
schedule,
|
|
713
|
+
plan.minute,
|
|
714
|
+
schedule.analyses.clockSecond,
|
|
715
|
+
opts
|
|
716
|
+
);
|
|
632
717
|
}
|
|
633
|
-
const cadence = unevenHourCadence(
|
|
634
|
-
const phrase = cadence ? bareMinutes(
|
|
718
|
+
const cadence = unevenHourCadence(schedule, opts);
|
|
719
|
+
const phrase = cadence ? bareMinutes(schedule, opts) + ", " + cadence + trailingQualifier(schedule, opts) : (
|
|
635
720
|
// A minute list over purely enumerated hours (step fires, all singles) —
|
|
636
721
|
// hours-first, drop "joka tunti".
|
|
637
|
-
hoursFirstMinutes(
|
|
722
|
+
hoursFirstMinutes(
|
|
723
|
+
hourSegmentTimes(schedule, 0, null, opts),
|
|
724
|
+
schedule,
|
|
725
|
+
opts
|
|
726
|
+
) + trailingQualifier(schedule, opts)
|
|
638
727
|
);
|
|
639
|
-
return
|
|
728
|
+
return schedule.analyses.clockSecond ? secondsLeadClause(schedule, opts) + ", " + phrase : phrase;
|
|
640
729
|
}
|
|
641
730
|
var renderers = {
|
|
642
731
|
clockTimes: renderClockTimes,
|
|
@@ -658,32 +747,19 @@ var renderers = {
|
|
|
658
747
|
singleMinute: renderSingleMinute,
|
|
659
748
|
standaloneSeconds: renderStandaloneSeconds
|
|
660
749
|
};
|
|
661
|
-
function
|
|
750
|
+
function renderStride2(stride, opts) {
|
|
662
751
|
const { interval, start, last, cycle, unit } = stride;
|
|
663
752
|
const cadence = genitive(interval, opts) + " " + unit.gen + " v\xE4lein";
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
return cadence + " " + unit.anchor + " " + unit.ela + " " + start + " alkaen";
|
|
670
|
-
}
|
|
671
|
-
return cadence + " " + unit.ela + " " + start + " " + unit.ill + " " + last;
|
|
753
|
+
return renderStride({ start, interval, cycle }, {
|
|
754
|
+
bare: () => cadence,
|
|
755
|
+
offset: () => cadence + " " + unit.anchor + " " + unit.ela + " " + start + " alkaen",
|
|
756
|
+
bounded: () => cadence + " " + unit.ela + " " + start + " " + unit.ill + " " + last
|
|
757
|
+
});
|
|
672
758
|
}
|
|
673
759
|
function strideFromSegments(segments, unit, opts) {
|
|
674
760
|
const values = singleValues(segments);
|
|
675
761
|
const step = values && arithmeticStep(values);
|
|
676
|
-
return step ?
|
|
677
|
-
}
|
|
678
|
-
function singleValues(segments) {
|
|
679
|
-
const values = [];
|
|
680
|
-
for (const segment of segments) {
|
|
681
|
-
if (segment.kind !== "single") {
|
|
682
|
-
return null;
|
|
683
|
-
}
|
|
684
|
-
values.push(+segment.value);
|
|
685
|
-
}
|
|
686
|
-
return values;
|
|
762
|
+
return step ? renderStride2({ ...step, cycle: 60, unit }, opts) : null;
|
|
687
763
|
}
|
|
688
764
|
function stepCycle60(segment, unit, opts) {
|
|
689
765
|
if (segment.startToken.indexOf("-") !== -1) {
|
|
@@ -693,7 +769,7 @@ function stepCycle60(segment, unit, opts) {
|
|
|
693
769
|
if (start !== 0 && segment.fires.length <= 3) {
|
|
694
770
|
return atMarks(joinList(wordList(segment.fires)), unit, true);
|
|
695
771
|
}
|
|
696
|
-
return
|
|
772
|
+
return renderStride2({
|
|
697
773
|
interval: segment.interval,
|
|
698
774
|
start,
|
|
699
775
|
last: segment.fires[segment.fires.length - 1],
|
|
@@ -719,38 +795,14 @@ function stepHours(segment, opts) {
|
|
|
719
795
|
function hourStrideCadence(stride, opts) {
|
|
720
796
|
const { start, interval, last } = stride;
|
|
721
797
|
const cadence = genitive(interval, opts) + " tunnin v\xE4lein";
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
return cadence + " klo " + hourElatives[start] + " alkaen";
|
|
728
|
-
}
|
|
729
|
-
return cadence + " " + kloRange({ hour: start, minute: 0 }, { hour: last, minute: 0 }, opts);
|
|
730
|
-
}
|
|
731
|
-
function hourListStride(values) {
|
|
732
|
-
if (values.length < 2) {
|
|
733
|
-
return null;
|
|
734
|
-
}
|
|
735
|
-
const interval = values[1] - values[0];
|
|
736
|
-
if (interval < 2) {
|
|
737
|
-
return null;
|
|
738
|
-
}
|
|
739
|
-
for (let i = 2; i < values.length; i += 1) {
|
|
740
|
-
if (values[i] - values[i - 1] !== interval) {
|
|
741
|
-
return null;
|
|
742
|
-
}
|
|
743
|
-
}
|
|
744
|
-
if (values[0] !== 0 && values.length < 5) {
|
|
745
|
-
return null;
|
|
746
|
-
}
|
|
747
|
-
return { interval, last: values[values.length - 1], start: values[0] };
|
|
748
|
-
}
|
|
749
|
-
function offsetCleanStride(stride) {
|
|
750
|
-
return stride.start < stride.interval && 24 % stride.interval === 0;
|
|
798
|
+
return renderStride({ start, interval, cycle: 24 }, {
|
|
799
|
+
bare: () => cadence,
|
|
800
|
+
offset: () => cadence + " klo " + hourElatives[start] + " alkaen",
|
|
801
|
+
bounded: () => cadence + " " + kloRange({ hour: start, minute: 0 }, { hour: last, minute: 0 }, opts)
|
|
802
|
+
});
|
|
751
803
|
}
|
|
752
|
-
function hourStride(
|
|
753
|
-
const segments =
|
|
804
|
+
function hourStride(schedule) {
|
|
805
|
+
const segments = schedule.analyses.segments.hour;
|
|
754
806
|
if (!segments) {
|
|
755
807
|
return null;
|
|
756
808
|
}
|
|
@@ -765,47 +817,47 @@ function hourStride(ir) {
|
|
|
765
817
|
const values = singleValues(segments);
|
|
766
818
|
return values && hourListStride(values);
|
|
767
819
|
}
|
|
768
|
-
function unevenHourCadence(
|
|
769
|
-
const stride = hourStride(
|
|
820
|
+
function unevenHourCadence(schedule, opts) {
|
|
821
|
+
const stride = hourStride(schedule);
|
|
770
822
|
if (!stride || offsetCleanStride(stride)) {
|
|
771
823
|
return null;
|
|
772
824
|
}
|
|
773
825
|
return hourStrideCadence(stride, opts);
|
|
774
826
|
}
|
|
775
|
-
function subMinuteSecond(
|
|
776
|
-
return
|
|
827
|
+
function subMinuteSecond(schedule) {
|
|
828
|
+
return schedule.pattern.second === "*" || schedule.shapes.second === "step";
|
|
777
829
|
}
|
|
778
|
-
function hourCadenceLead(
|
|
830
|
+
function hourCadenceLead(schedule, minute, opts) {
|
|
779
831
|
if (minute === 0) {
|
|
780
|
-
if (subMinuteSecond(
|
|
781
|
-
return secondsLeadClause(
|
|
832
|
+
if (subMinuteSecond(schedule)) {
|
|
833
|
+
return secondsLeadClause(schedule, opts) + " minuutin ajan";
|
|
782
834
|
}
|
|
783
|
-
return secondsLeadClause(
|
|
835
|
+
return secondsLeadClause(schedule, opts);
|
|
784
836
|
}
|
|
785
837
|
const minutePhrase = atMarks(String(minute), units.minute, false);
|
|
786
|
-
if (
|
|
838
|
+
if (schedule.pattern.second === "0") {
|
|
787
839
|
return minutePhrase;
|
|
788
840
|
}
|
|
789
|
-
return secondsLeadClause(
|
|
841
|
+
return secondsLeadClause(schedule, opts) + ", " + minutePhrase;
|
|
790
842
|
}
|
|
791
|
-
function hourCadence(
|
|
792
|
-
const stride = hourStride(
|
|
843
|
+
function hourCadence(schedule, minute, opts) {
|
|
844
|
+
const stride = hourStride(schedule);
|
|
793
845
|
if (!stride) {
|
|
794
846
|
return null;
|
|
795
847
|
}
|
|
796
848
|
const fires = (stride.last - stride.start) / stride.interval + 1;
|
|
797
|
-
if (
|
|
849
|
+
if (schedule.pattern.second === "0" && fires <= maxClockTimes && offsetCleanStride(stride)) {
|
|
798
850
|
return null;
|
|
799
851
|
}
|
|
800
|
-
const segment =
|
|
801
|
-
const confined = minute === 0 && subMinuteSecond(
|
|
852
|
+
const segment = segmentsOf(schedule, "hour")[0];
|
|
853
|
+
const confined = minute === 0 && subMinuteSecond(schedule) && segmentsOf(schedule, "hour").length === 1 && segment.kind === "step" && cleanHourStride(segment);
|
|
802
854
|
if (confined) {
|
|
803
|
-
return secondsLeadClause(
|
|
855
|
+
return secondsLeadClause(schedule, opts) + " minuutin ajan " + everyNthHour(segment, opts) + trailingQualifier(schedule, opts);
|
|
804
856
|
}
|
|
805
|
-
if (minute === 0 &&
|
|
806
|
-
return hourStrideCadence(stride, opts) + trailingQualifier(
|
|
857
|
+
if (minute === 0 && schedule.pattern.second === "0") {
|
|
858
|
+
return hourStrideCadence(stride, opts) + trailingQualifier(schedule, opts);
|
|
807
859
|
}
|
|
808
|
-
return hourCadenceLead(
|
|
860
|
+
return hourCadenceLead(schedule, minute, opts) + ", " + hourStrideCadence(stride, opts) + trailingQualifier(schedule, opts);
|
|
809
861
|
}
|
|
810
862
|
function cleanHourStride(segment) {
|
|
811
863
|
if (segment.startToken.indexOf("-") !== -1) {
|
|
@@ -814,22 +866,22 @@ function cleanHourStride(segment) {
|
|
|
814
866
|
const start = segment.startToken === "*" ? 0 : +segment.startToken;
|
|
815
867
|
return 24 % segment.interval === 0 && start < segment.interval;
|
|
816
868
|
}
|
|
817
|
-
function hasHourWindow(
|
|
818
|
-
const segments =
|
|
869
|
+
function hasHourWindow(schedule) {
|
|
870
|
+
const segments = schedule.analyses.segments.hour;
|
|
819
871
|
return !!segments && segments.some(function range(segment) {
|
|
820
872
|
return segment.kind === "range";
|
|
821
873
|
});
|
|
822
874
|
}
|
|
823
|
-
function hourRangeWindowTail(
|
|
824
|
-
return
|
|
875
|
+
function hourRangeWindowTail(schedule, opts) {
|
|
876
|
+
return segmentsOf(schedule, "hour").length === 1 ? hourSegmentTimes(schedule, 0, null, opts) : hourSegmentTimesWithSeka(schedule, 0, null, opts);
|
|
825
877
|
}
|
|
826
|
-
function hourRangeCadence(
|
|
827
|
-
if (minute !== 0 || !hasHourWindow(
|
|
878
|
+
function hourRangeCadence(schedule, minute, opts) {
|
|
879
|
+
if (minute !== 0 || !hasHourWindow(schedule) || schedule.pattern.second === "0") {
|
|
828
880
|
return null;
|
|
829
881
|
}
|
|
830
|
-
const tail = hourRangeWindowTail(
|
|
831
|
-
const joiner = subMinuteSecond(
|
|
832
|
-
return hourCadenceLead(
|
|
882
|
+
const tail = hourRangeWindowTail(schedule, opts);
|
|
883
|
+
const joiner = subMinuteSecond(schedule) ? " " : ", ";
|
|
884
|
+
return hourCadenceLead(schedule, minute, opts) + joiner + tail + trailingQualifier(schedule, opts);
|
|
833
885
|
}
|
|
834
886
|
function kloList(hours, opts) {
|
|
835
887
|
if (hours.length === 1) {
|
|
@@ -839,17 +891,17 @@ function kloList(hours, opts) {
|
|
|
839
891
|
return timeDigits(hour, 0, null, opts);
|
|
840
892
|
}));
|
|
841
893
|
}
|
|
842
|
-
function kloFromTimes(
|
|
894
|
+
function kloFromTimes(schedule, times, opts) {
|
|
843
895
|
if (times.kind === "fires") {
|
|
844
896
|
return kloList(times.fires, opts);
|
|
845
897
|
}
|
|
846
|
-
return hourSegmentTimes(
|
|
898
|
+
return hourSegmentTimes(schedule, 0, null, opts);
|
|
847
899
|
}
|
|
848
|
-
function hourWindowsFromTimes(
|
|
900
|
+
function hourWindowsFromTimes(schedule, times, opts) {
|
|
849
901
|
if (times.kind === "fires") {
|
|
850
902
|
return kloList(times.fires, opts);
|
|
851
903
|
}
|
|
852
|
-
const segments =
|
|
904
|
+
const segments = segmentsOf(schedule, "hour");
|
|
853
905
|
if (!segments.some(function ranged(segment) {
|
|
854
906
|
return segment.kind === "range";
|
|
855
907
|
})) {
|
|
@@ -887,9 +939,9 @@ function hourSegmentFires(segments) {
|
|
|
887
939
|
function hourWindowDigits(hour, opts) {
|
|
888
940
|
return rangeDigits({ hour, minute: 0 }, { hour, minute: 59 }, opts);
|
|
889
941
|
}
|
|
890
|
-
function hourSegmentTimes(
|
|
942
|
+
function hourSegmentTimes(schedule, minute, second, opts) {
|
|
891
943
|
const pieces = [];
|
|
892
|
-
|
|
944
|
+
segmentsOf(schedule, "hour").forEach(function clock(segment) {
|
|
893
945
|
if (segment.kind === "step") {
|
|
894
946
|
pieces.push(...segment.fires.map(function each(hour) {
|
|
895
947
|
return timeDigits(hour, minute, second, opts);
|
|
@@ -939,53 +991,54 @@ function timeDigits(hour, minute, second, opts) {
|
|
|
939
991
|
{ lean: true, sep: opts.style.sep }
|
|
940
992
|
);
|
|
941
993
|
}
|
|
942
|
-
function leadingQualifier(
|
|
943
|
-
const pattern =
|
|
944
|
-
if (restrictedMonthUnion(
|
|
994
|
+
function leadingQualifier(schedule, opts) {
|
|
995
|
+
const pattern = schedule.pattern;
|
|
996
|
+
if (restrictedMonthUnion(schedule)) {
|
|
945
997
|
return "";
|
|
946
998
|
}
|
|
947
999
|
if (pattern.date !== "*" && pattern.weekday !== "*") {
|
|
948
|
-
return dateOrWeekday(
|
|
1000
|
+
return dateOrWeekday(schedule, opts) + " ";
|
|
949
1001
|
}
|
|
950
1002
|
if (pattern.date !== "*") {
|
|
951
|
-
return datePhrase(
|
|
1003
|
+
return datePhrase(schedule, opts) + " ";
|
|
952
1004
|
}
|
|
953
1005
|
if (pattern.weekday !== "*") {
|
|
954
|
-
return weekdayQualifier(
|
|
1006
|
+
return weekdayQualifier(schedule) + monthScope(schedule) + " ";
|
|
955
1007
|
}
|
|
956
1008
|
if (pattern.month !== "*") {
|
|
957
|
-
return "joka p\xE4iv\xE4 " + monthPhrase(
|
|
1009
|
+
return "joka p\xE4iv\xE4 " + monthPhrase(schedule) + " ";
|
|
958
1010
|
}
|
|
959
1011
|
return "joka p\xE4iv\xE4 ";
|
|
960
1012
|
}
|
|
961
|
-
function trailingQualifier(
|
|
962
|
-
const pattern =
|
|
963
|
-
if (restrictedMonthUnion(
|
|
1013
|
+
function trailingQualifier(schedule, opts) {
|
|
1014
|
+
const pattern = schedule.pattern;
|
|
1015
|
+
if (restrictedMonthUnion(schedule)) {
|
|
964
1016
|
return "";
|
|
965
1017
|
}
|
|
966
1018
|
if (pattern.date !== "*" && pattern.weekday !== "*") {
|
|
967
|
-
return " " + dateOrWeekday(
|
|
1019
|
+
return " " + dateOrWeekday(schedule, opts);
|
|
968
1020
|
}
|
|
969
1021
|
if (pattern.date !== "*") {
|
|
970
|
-
return " " + datePhrase(
|
|
1022
|
+
return " " + datePhrase(schedule, opts);
|
|
971
1023
|
}
|
|
972
1024
|
if (pattern.weekday !== "*") {
|
|
973
|
-
return " " + weekdayQualifier(
|
|
1025
|
+
return " " + weekdayQualifier(schedule) + monthScope(schedule);
|
|
974
1026
|
}
|
|
975
1027
|
if (pattern.month !== "*") {
|
|
976
|
-
return " " + monthPhrase(
|
|
1028
|
+
return " " + monthPhrase(schedule);
|
|
977
1029
|
}
|
|
978
1030
|
return "";
|
|
979
1031
|
}
|
|
980
|
-
function dateOrWeekday(
|
|
981
|
-
|
|
1032
|
+
function dateOrWeekday(schedule, opts) {
|
|
1033
|
+
const dateArm = oddDayUnion(schedule.pattern.date) || datePhrase(schedule, opts);
|
|
1034
|
+
return dateArm + " tai " + unionWeekdayArm(schedule) + monthScope(schedule);
|
|
982
1035
|
}
|
|
983
|
-
function weekdayQualifier(
|
|
984
|
-
const quartz = quartzWeekdayPhrase(
|
|
1036
|
+
function weekdayQualifier(schedule) {
|
|
1037
|
+
const quartz = quartzWeekdayPhrase(schedule.pattern.weekday);
|
|
985
1038
|
if (quartz) {
|
|
986
1039
|
return quartz;
|
|
987
1040
|
}
|
|
988
|
-
const segments = orderWeekdaysForDisplay(
|
|
1041
|
+
const segments = orderWeekdaysForDisplay(segmentsOf(schedule, "weekday"));
|
|
989
1042
|
return joinList(segments.map(function piece(segment) {
|
|
990
1043
|
if (segment.kind === "range") {
|
|
991
1044
|
return weekdays[weekdayNumber(segment.bounds[0])].ela + " " + weekdays[weekdayNumber(segment.bounds[1])].ill;
|
|
@@ -993,8 +1046,8 @@ function weekdayQualifier(ir) {
|
|
|
993
1046
|
return weekdays[weekdayNumber(segment.value)].isin;
|
|
994
1047
|
}));
|
|
995
1048
|
}
|
|
996
|
-
function monthPhrase(
|
|
997
|
-
const segments = flattenSteps(
|
|
1049
|
+
function monthPhrase(schedule) {
|
|
1050
|
+
const segments = flattenSteps(segmentsOf(schedule, "month"));
|
|
998
1051
|
return joinList(segments.map(function piece(segment) {
|
|
999
1052
|
if (segment.kind === "range") {
|
|
1000
1053
|
return monthStems[monthNumber(segment.bounds[0])] + "kuusta " + monthStems[monthNumber(segment.bounds[1])] + "kuuhun";
|
|
@@ -1002,11 +1055,11 @@ function monthPhrase(ir) {
|
|
|
1002
1055
|
return monthStems[monthNumber(segment.value)] + "kuussa";
|
|
1003
1056
|
}));
|
|
1004
1057
|
}
|
|
1005
|
-
function monthScope(
|
|
1006
|
-
if (
|
|
1058
|
+
function monthScope(schedule) {
|
|
1059
|
+
if (schedule.pattern.month === "*") {
|
|
1007
1060
|
return "";
|
|
1008
1061
|
}
|
|
1009
|
-
return " " + monthPhrase(
|
|
1062
|
+
return " " + monthPhrase(schedule);
|
|
1010
1063
|
}
|
|
1011
1064
|
function flattenSteps(segments) {
|
|
1012
1065
|
return segments.flatMap(function flat(segment) {
|
|
@@ -1015,16 +1068,16 @@ function flattenSteps(segments) {
|
|
|
1015
1068
|
}) : [segment];
|
|
1016
1069
|
});
|
|
1017
1070
|
}
|
|
1018
|
-
function datePhrase(
|
|
1019
|
-
const pattern =
|
|
1071
|
+
function datePhrase(schedule, opts) {
|
|
1072
|
+
const pattern = schedule.pattern;
|
|
1020
1073
|
const quartz = quartzDatePhrase(pattern.date);
|
|
1021
1074
|
if (quartz) {
|
|
1022
|
-
return quartz + monthScope(
|
|
1075
|
+
return quartz + monthScope(schedule);
|
|
1023
1076
|
}
|
|
1024
1077
|
if (isOpenStep(pattern.date)) {
|
|
1025
|
-
return stepDates(pattern.date, opts) + monthScope(
|
|
1078
|
+
return stepDates(pattern.date, opts) + monthScope(schedule);
|
|
1026
1079
|
}
|
|
1027
|
-
return monthAnchor(
|
|
1080
|
+
return monthAnchor(schedule, opts) + " " + dateWords(schedule) + " p\xE4iv\xE4n\xE4" + foldedYear(schedule) + monthStepStart(pattern.month) + rangedMonthScope(schedule);
|
|
1028
1081
|
}
|
|
1029
1082
|
function monthStepStart(monthField) {
|
|
1030
1083
|
if (!isOpenStep(monthField)) {
|
|
@@ -1036,30 +1089,30 @@ function monthStepStart(monthField) {
|
|
|
1036
1089
|
}
|
|
1037
1090
|
return " " + monthStems[monthNumber(start)] + "kuusta alkaen";
|
|
1038
1091
|
}
|
|
1039
|
-
function monthAnchor(
|
|
1040
|
-
const monthField =
|
|
1041
|
-
if (monthField === "*" || monthRanged(
|
|
1092
|
+
function monthAnchor(schedule, opts) {
|
|
1093
|
+
const monthField = schedule.pattern.month;
|
|
1094
|
+
if (monthField === "*" || monthRanged(schedule)) {
|
|
1042
1095
|
return "kuukauden";
|
|
1043
1096
|
}
|
|
1044
1097
|
if (isOpenStep(monthField)) {
|
|
1045
1098
|
return stepMonths(monthField, opts);
|
|
1046
1099
|
}
|
|
1047
|
-
const segments = flattenSteps(
|
|
1100
|
+
const segments = flattenSteps(segmentsOf(schedule, "month"));
|
|
1048
1101
|
return joinList(segments.map(function genitiveOf(segment) {
|
|
1049
1102
|
const single = segment;
|
|
1050
1103
|
return monthStems[monthNumber(single.value)] + "kuun";
|
|
1051
1104
|
}));
|
|
1052
1105
|
}
|
|
1053
|
-
function rangedMonthScope(
|
|
1054
|
-
return monthRanged(
|
|
1106
|
+
function rangedMonthScope(schedule) {
|
|
1107
|
+
return monthRanged(schedule) ? " " + monthPhrase(schedule) : "";
|
|
1055
1108
|
}
|
|
1056
|
-
function monthRanged(
|
|
1057
|
-
return
|
|
1109
|
+
function monthRanged(schedule) {
|
|
1110
|
+
return schedule.pattern.month !== "*" && segmentsOf(schedule, "month").some(function range(segment) {
|
|
1058
1111
|
return segment.kind === "range";
|
|
1059
1112
|
});
|
|
1060
1113
|
}
|
|
1061
|
-
function dateWords(
|
|
1062
|
-
return joinList(
|
|
1114
|
+
function dateWords(schedule) {
|
|
1115
|
+
return joinList(segmentsOf(schedule, "date").flatMap(
|
|
1063
1116
|
function word(segment) {
|
|
1064
1117
|
if (segment.kind === "range") {
|
|
1065
1118
|
return [segment.bounds[0] + ".\u2013" + segment.bounds[1] + "."];
|
|
@@ -1115,15 +1168,15 @@ function weekdayNumber(token) {
|
|
|
1115
1168
|
function monthNumber(token) {
|
|
1116
1169
|
return +token;
|
|
1117
1170
|
}
|
|
1118
|
-
function applyYear(description,
|
|
1119
|
-
const yearField =
|
|
1171
|
+
function applyYear(description, schedule, opts) {
|
|
1172
|
+
const yearField = schedule.pattern.year;
|
|
1120
1173
|
if (yearField === "*") {
|
|
1121
1174
|
return description;
|
|
1122
1175
|
}
|
|
1123
1176
|
if (yearField.indexOf("/") !== -1) {
|
|
1124
1177
|
return description + " " + stepYears(yearField, opts);
|
|
1125
1178
|
}
|
|
1126
|
-
if (foldedYear(
|
|
1179
|
+
if (foldedYear(schedule) && schedule.pattern.date !== "*") {
|
|
1127
1180
|
return description;
|
|
1128
1181
|
}
|
|
1129
1182
|
if (yearField.indexOf(",") !== -1) {
|
|
@@ -1143,8 +1196,8 @@ function stepYears(yearField, opts) {
|
|
|
1143
1196
|
}
|
|
1144
1197
|
return phrase;
|
|
1145
1198
|
}
|
|
1146
|
-
function foldedYear(
|
|
1147
|
-
const yearField =
|
|
1199
|
+
function foldedYear(schedule) {
|
|
1200
|
+
const yearField = schedule.pattern.year;
|
|
1148
1201
|
if (yearField === "*" || yearField.indexOf("/") !== -1 || yearField.indexOf("-") !== -1 || yearField.indexOf(",") !== -1) {
|
|
1149
1202
|
return "";
|
|
1150
1203
|
}
|
|
@@ -1161,9 +1214,6 @@ function segmentWords(segments) {
|
|
|
1161
1214
|
return [segment.value];
|
|
1162
1215
|
});
|
|
1163
1216
|
}
|
|
1164
|
-
function isOpenStep(field) {
|
|
1165
|
-
return field.indexOf("/") !== -1 && field.indexOf("-") === -1 && field.indexOf(",") === -1;
|
|
1166
|
-
}
|
|
1167
1217
|
function wordList(fires) {
|
|
1168
1218
|
return fires.map(function digit(value) {
|
|
1169
1219
|
return "" + value;
|