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