cronli5 0.1.4 → 0.1.6
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 +53 -0
- package/cronli5.min.js +2 -2
- package/dist/cronli5.cjs +286 -45
- package/dist/cronli5.js +286 -45
- package/dist/lang/de.cjs +252 -13
- package/dist/lang/de.js +252 -13
- package/dist/lang/en.cjs +281 -38
- package/dist/lang/en.js +281 -38
- package/dist/lang/es.cjs +259 -29
- package/dist/lang/es.js +259 -29
- package/dist/lang/fi.cjs +285 -49
- package/dist/lang/fi.js +285 -49
- package/dist/lang/zh.cjs +225 -42
- package/dist/lang/zh.js +225 -42
- package/package.json +3 -2
- package/src/core/analyze.ts +7 -0
- package/src/core/ir.ts +1 -1
- package/src/core/util.ts +31 -1
- package/src/lang/de/index.ts +561 -30
- package/src/lang/en/index.ts +593 -59
- package/src/lang/es/index.ts +576 -52
- package/src/lang/fi/index.ts +633 -95
- package/src/lang/zh/index.ts +484 -77
- package/types/core/ir.d.ts +1 -1
- package/types/core/util.d.ts +6 -1
package/dist/lang/fi.cjs
CHANGED
|
@@ -50,12 +50,28 @@ var weekdayNumbers = {
|
|
|
50
50
|
FRI: 5,
|
|
51
51
|
SAT: 6
|
|
52
52
|
};
|
|
53
|
+
var maxClockTimes = 6;
|
|
53
54
|
|
|
54
55
|
// src/core/util.ts
|
|
55
56
|
function isNonNegativeInteger(value) {
|
|
56
57
|
const digits = /^\d+$/;
|
|
57
58
|
return digits.test(value);
|
|
58
59
|
}
|
|
60
|
+
function arithmeticStep(values) {
|
|
61
|
+
if (values.length < 5) {
|
|
62
|
+
return null;
|
|
63
|
+
}
|
|
64
|
+
const interval = values[1] - values[0];
|
|
65
|
+
if (interval < 2) {
|
|
66
|
+
return null;
|
|
67
|
+
}
|
|
68
|
+
for (let i = 2; i < values.length; i += 1) {
|
|
69
|
+
if (values[i] - values[i - 1] !== interval) {
|
|
70
|
+
return null;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
return { start: values[0], interval, last: values[values.length - 1] };
|
|
74
|
+
}
|
|
59
75
|
function toFieldNumber(token, numberMap) {
|
|
60
76
|
return isNonNegativeInteger(token) ? +token : numberMap[token.toUpperCase()];
|
|
61
77
|
}
|
|
@@ -191,12 +207,14 @@ var units = {
|
|
|
191
207
|
mark: "joka tunti",
|
|
192
208
|
anchor: "jokaisen tunnin",
|
|
193
209
|
ela: "minuutista",
|
|
210
|
+
ill: "minuuttiin",
|
|
194
211
|
gen: "minuutin"
|
|
195
212
|
},
|
|
196
213
|
second: {
|
|
197
214
|
mark: "joka minuutti",
|
|
198
215
|
anchor: "jokaisen minuutin",
|
|
199
216
|
ela: "sekunnista",
|
|
217
|
+
ill: "sekuntiin",
|
|
200
218
|
gen: "sekunnin"
|
|
201
219
|
}
|
|
202
220
|
};
|
|
@@ -252,28 +270,55 @@ function renderSecondsWithinMinute(ir, plan, opts) {
|
|
|
252
270
|
}
|
|
253
271
|
return secondsLeadClause(ir, opts) + ", " + atMarks(minuteField, units.minute, true) + trailingQualifier(ir, opts);
|
|
254
272
|
}
|
|
273
|
+
function composeSecondsOverMinuteStep(ir, freq, opts) {
|
|
274
|
+
const seg = stepSegment(ir.analyses.segments.minute);
|
|
275
|
+
const stepPhrase = stepCycle60(seg, units.minute, opts);
|
|
276
|
+
if (freq.hours.kind === "during" && minuteStepIsAnchored(seg)) {
|
|
277
|
+
const bareHours = kloFromTimes(ir, freq.hours.times, opts);
|
|
278
|
+
return hoursFirstMinutes(bareHours, ir, opts) + ", " + secondsLeadClause(ir, opts) + trailingQualifier(ir, opts);
|
|
279
|
+
}
|
|
280
|
+
let hourClause = "";
|
|
281
|
+
if (freq.hours.kind === "during") {
|
|
282
|
+
hourClause = " " + hourWindowsFromTimes(ir, freq.hours.times, opts);
|
|
283
|
+
} else if (freq.hours.kind === "window") {
|
|
284
|
+
hourClause = " " + hourWindow(freq.hours, opts);
|
|
285
|
+
} else if (freq.hours.kind === "step") {
|
|
286
|
+
hourClause = " " + everyNthHour(stepSegment(ir.analyses.segments.hour), opts);
|
|
287
|
+
}
|
|
288
|
+
return stepPhrase + ", " + secondsLeadClause(ir, opts) + hourClause + trailingQualifier(ir, opts);
|
|
289
|
+
}
|
|
290
|
+
function composeHourCadence(ir, plan, opts) {
|
|
291
|
+
const clockRest = plan.rest.kind === "clockTimes" || plan.rest.kind === "compactClockTimes";
|
|
292
|
+
if (!clockRest || ir.shapes.minute !== "single") {
|
|
293
|
+
return null;
|
|
294
|
+
}
|
|
295
|
+
const minute = +ir.pattern.minute;
|
|
296
|
+
return hourCadence(ir, minute, opts) ?? hourRangeCadence(ir, minute, opts);
|
|
297
|
+
}
|
|
255
298
|
function renderComposeSeconds(ir, plan, opts) {
|
|
299
|
+
const cadence = composeHourCadence(ir, plan, opts);
|
|
300
|
+
if (cadence !== null) {
|
|
301
|
+
return cadence;
|
|
302
|
+
}
|
|
256
303
|
if (plan.rest.kind === "minuteFrequency" && ir.pattern.second !== "*") {
|
|
257
|
-
|
|
258
|
-
const seg = stepSegment(ir.analyses.segments.minute);
|
|
259
|
-
const stepPhrase = stepCycle60(seg, units.minute, opts);
|
|
260
|
-
let hourClause = "";
|
|
261
|
-
if (freq.hours.kind === "during" && minuteStepIsAnchored(seg)) {
|
|
262
|
-
const bareHours = kloFromTimes(ir, freq.hours.times, opts);
|
|
263
|
-
return hoursFirstMinutes(bareHours, ir) + ", " + secondsLeadClause(ir, opts) + trailingQualifier(ir, opts);
|
|
264
|
-
} else if (freq.hours.kind === "during" && !minuteStepIsAnchored(seg)) {
|
|
265
|
-
hourClause = " " + hourWindowsFromTimes(ir, freq.hours.times, opts);
|
|
266
|
-
} else if (freq.hours.kind === "window") {
|
|
267
|
-
hourClause = " " + hourWindow(freq.hours, opts);
|
|
268
|
-
} else if (freq.hours.kind === "step") {
|
|
269
|
-
hourClause = " " + everyNthHour(stepSegment(ir.analyses.segments.hour), opts);
|
|
270
|
-
}
|
|
271
|
-
return stepPhrase + ", " + secondsLeadClause(ir, opts) + hourClause + trailingQualifier(ir, opts);
|
|
304
|
+
return composeSecondsOverMinuteStep(ir, plan.rest, opts);
|
|
272
305
|
}
|
|
273
306
|
if (plan.rest.kind === "clockTimes" && plan.rest.times.every((time) => +time.minute === 0)) {
|
|
274
307
|
return composeMinuteZero(ir, plan.rest, opts);
|
|
275
308
|
}
|
|
276
|
-
|
|
309
|
+
if (isEveryOtherMinuteSeconds(ir, plan)) {
|
|
310
|
+
return secondsLeadClause(ir, opts) + " joka toisena minuuttina";
|
|
311
|
+
}
|
|
312
|
+
const restOwnsLead = plan.rest.kind === "compactClockTimes" && ir.analyses.clockSecond;
|
|
313
|
+
const lead = restOwnsLead ? "" : secondsLeadClause(ir, opts) + ", ";
|
|
314
|
+
return lead + render(ir, plan.rest, opts);
|
|
315
|
+
}
|
|
316
|
+
function isEveryOtherMinuteSeconds(ir, plan) {
|
|
317
|
+
if (plan.rest.kind !== "minuteFrequency" || ir.pattern.second !== "*" || ir.shapes.hour !== "wildcard") {
|
|
318
|
+
return false;
|
|
319
|
+
}
|
|
320
|
+
const seg = stepSegment(ir.analyses.segments.minute);
|
|
321
|
+
return seg.startToken === "*" && seg.interval === 2;
|
|
277
322
|
}
|
|
278
323
|
function composeMinuteZero(ir, rest, opts) {
|
|
279
324
|
const clocks = rest.times.map(function clock(time) {
|
|
@@ -303,7 +348,7 @@ function secondsLeadClause(ir, opts) {
|
|
|
303
348
|
if (shape === "single") {
|
|
304
349
|
return atMarks(secondField, units.second, marked);
|
|
305
350
|
}
|
|
306
|
-
return atMarks(
|
|
351
|
+
return strideFromSegments(ir.analyses.segments.second, units.second, opts) ?? atMarks(
|
|
307
352
|
joinList(segmentWords(ir.analyses.segments.second)),
|
|
308
353
|
units.second,
|
|
309
354
|
marked
|
|
@@ -316,20 +361,20 @@ function renderSingleMinute(ir, plan, opts) {
|
|
|
316
361
|
return atMarks(ir.pattern.minute, units.minute, true) + trailingQualifier(ir, opts);
|
|
317
362
|
}
|
|
318
363
|
function renderRangeOfMinutes(ir, plan, opts) {
|
|
319
|
-
return minutesList(ir) + trailingQualifier(ir, opts);
|
|
364
|
+
return minutesList(ir, opts) + trailingQualifier(ir, opts);
|
|
320
365
|
}
|
|
321
366
|
function renderMultipleMinutes(ir, plan, opts) {
|
|
322
|
-
return minutesList(ir) + trailingQualifier(ir, opts);
|
|
367
|
+
return minutesList(ir, opts) + trailingQualifier(ir, opts);
|
|
323
368
|
}
|
|
324
|
-
function minutesList(ir) {
|
|
325
|
-
return atMarks(
|
|
369
|
+
function minutesList(ir, opts) {
|
|
370
|
+
return strideFromSegments(ir.analyses.segments.minute, units.minute, opts) ?? atMarks(
|
|
326
371
|
joinList(segmentWords(ir.analyses.segments.minute)),
|
|
327
372
|
units.minute,
|
|
328
373
|
true
|
|
329
374
|
);
|
|
330
375
|
}
|
|
331
|
-
function bareMinutes(ir) {
|
|
332
|
-
return atMarks(
|
|
376
|
+
function bareMinutes(ir, opts) {
|
|
377
|
+
return strideFromSegments(ir.analyses.segments.minute, units.minute, opts) ?? atMarks(
|
|
333
378
|
joinList(segmentWords(ir.analyses.segments.minute)),
|
|
334
379
|
units.minute,
|
|
335
380
|
false
|
|
@@ -360,7 +405,11 @@ function hoursAreRangeIsolated(segments) {
|
|
|
360
405
|
}
|
|
361
406
|
return hasRange && hasSingle;
|
|
362
407
|
}
|
|
363
|
-
function hoursFirstMinutes(hoursStr, ir) {
|
|
408
|
+
function hoursFirstMinutes(hoursStr, ir, opts) {
|
|
409
|
+
const stride = strideFromSegments(ir.analyses.segments.minute, units.minute, opts);
|
|
410
|
+
if (stride) {
|
|
411
|
+
return hoursStr + " aina " + stride;
|
|
412
|
+
}
|
|
364
413
|
return hoursStr + " aina minuuttien " + joinList(segmentWords(ir.analyses.segments.minute)) + " kohdalla";
|
|
365
414
|
}
|
|
366
415
|
function hourSegmentTimesWithSeka(ir, minute, second, opts) {
|
|
@@ -381,9 +430,13 @@ function hourSegmentTimesWithSeka(ir, minute, second, opts) {
|
|
|
381
430
|
function renderMinuteFrequency(ir, plan, opts) {
|
|
382
431
|
const seg = stepSegment(ir.analyses.segments.minute);
|
|
383
432
|
if (plan.hours.kind === "during") {
|
|
433
|
+
const cadence = unevenHourCadence(ir, opts);
|
|
434
|
+
if (cadence !== null) {
|
|
435
|
+
return stepCycle60(seg, units.minute, opts) + ", " + cadence + trailingQualifier(ir, opts);
|
|
436
|
+
}
|
|
384
437
|
if (minuteStepIsAnchored(seg)) {
|
|
385
438
|
const bareHours = kloFromTimes(ir, plan.hours.times, opts);
|
|
386
|
-
return hoursFirstMinutes(bareHours, ir) + trailingQualifier(ir, opts);
|
|
439
|
+
return hoursFirstMinutes(bareHours, ir, opts) + trailingQualifier(ir, opts);
|
|
387
440
|
}
|
|
388
441
|
return stepCycle60(seg, units.minute, opts) + " " + hourWindowsFromTimes(ir, plan.hours.times, opts) + trailingQualifier(ir, opts);
|
|
389
442
|
}
|
|
@@ -406,25 +459,29 @@ function renderMinuteSpanInHour(ir, plan, opts) {
|
|
|
406
459
|
) + trailingQualifier(ir, opts);
|
|
407
460
|
}
|
|
408
461
|
function renderMinutesAcrossHours(ir, plan, opts) {
|
|
462
|
+
const cadence = unevenHourCadence(ir, opts);
|
|
409
463
|
if (plan.form === "wildcard") {
|
|
410
|
-
return "joka minuutti " + hourWindowsFromTimes(ir, plan.times, opts) + trailingQualifier(ir, opts);
|
|
464
|
+
return cadence ? "joka minuutti, " + cadence + trailingQualifier(ir, opts) : "joka minuutti " + hourWindowsFromTimes(ir, plan.times, opts) + trailingQualifier(ir, opts);
|
|
465
|
+
}
|
|
466
|
+
if (cadence !== null) {
|
|
467
|
+
return bareMinutes(ir, opts) + ", " + cadence + trailingQualifier(ir, opts);
|
|
411
468
|
}
|
|
412
469
|
if (hoursAreRangeIsolated(ir.analyses.segments.hour)) {
|
|
413
|
-
return bareMinutes(ir) + " " + hourSegmentTimesWithSeka(ir, 0, null, opts) + trailingQualifier(ir, opts);
|
|
470
|
+
return bareMinutes(ir, opts) + " " + hourSegmentTimesWithSeka(ir, 0, null, opts) + trailingQualifier(ir, opts);
|
|
414
471
|
}
|
|
415
472
|
const hoursStr = kloFromTimes(ir, plan.times, opts);
|
|
416
|
-
return hoursFirstMinutes(hoursStr, ir) + trailingQualifier(ir, opts);
|
|
473
|
+
return hoursFirstMinutes(hoursStr, ir, opts) + trailingQualifier(ir, opts);
|
|
417
474
|
}
|
|
418
475
|
function renderMinuteSpanAcrossHourStep(ir, plan, opts) {
|
|
419
476
|
const segment = stepSegment(ir.analyses.segments.hour);
|
|
477
|
+
const cadence = unevenHourCadence(ir, opts);
|
|
420
478
|
if (plan.form === "wildcard") {
|
|
421
479
|
return "joka minuutti " + everyNthHour(segment, opts) + trailingQualifier(ir, opts);
|
|
422
480
|
}
|
|
423
|
-
if (
|
|
424
|
-
|
|
425
|
-
return hoursFirstMinutes(hoursStr, ir) + trailingQualifier(ir, opts);
|
|
481
|
+
if (cadence !== null) {
|
|
482
|
+
return bareMinutes(ir, opts) + ", " + cadence + trailingQualifier(ir, opts);
|
|
426
483
|
}
|
|
427
|
-
return bareMinutes(ir) + hourStepTail(segment, opts) + trailingQualifier(ir, opts);
|
|
484
|
+
return bareMinutes(ir, opts) + hourStepTail(segment, opts) + trailingQualifier(ir, opts);
|
|
428
485
|
}
|
|
429
486
|
function plainHourStep(segment) {
|
|
430
487
|
return segment.startToken === "*" && 24 % segment.interval === 0;
|
|
@@ -482,7 +539,7 @@ function renderHourRange(ir, plan, opts) {
|
|
|
482
539
|
return "joka minuutti " + window + trailingQualifier(ir, opts);
|
|
483
540
|
}
|
|
484
541
|
if (plan.minuteForm === "range") {
|
|
485
|
-
return hoursFirstMinutes(window, ir) + trailingQualifier(ir, opts);
|
|
542
|
+
return hoursFirstMinutes(window, ir, opts) + trailingQualifier(ir, opts);
|
|
486
543
|
}
|
|
487
544
|
if (ir.pattern.minute === "0") {
|
|
488
545
|
return "joka tunti " + window + trailingQualifier(ir, opts);
|
|
@@ -494,9 +551,13 @@ function renderHourRange(ir, plan, opts) {
|
|
|
494
551
|
opts
|
|
495
552
|
) + trailingQualifier(ir, opts);
|
|
496
553
|
}
|
|
497
|
-
return hoursFirstMinutes(window, ir) + trailingQualifier(ir, opts);
|
|
554
|
+
return hoursFirstMinutes(window, ir, opts) + trailingQualifier(ir, opts);
|
|
498
555
|
}
|
|
499
556
|
function renderHourStep(ir, plan, opts) {
|
|
557
|
+
const cadence = unevenHourCadence(ir, opts);
|
|
558
|
+
if (cadence !== null) {
|
|
559
|
+
return cadence + trailingQualifier(ir, opts);
|
|
560
|
+
}
|
|
500
561
|
return stepHours(stepSegment(ir.analyses.segments.hour), opts) + trailingQualifier(ir, opts);
|
|
501
562
|
}
|
|
502
563
|
function boundedWindow(plan) {
|
|
@@ -510,6 +571,13 @@ function hourWindow(window, opts) {
|
|
|
510
571
|
);
|
|
511
572
|
}
|
|
512
573
|
function renderClockTimes(ir, plan, opts) {
|
|
574
|
+
if (ir.shapes.minute === "single") {
|
|
575
|
+
const minute = +ir.pattern.minute;
|
|
576
|
+
const cadence = hourCadence(ir, minute, opts) ?? hourRangeCadence(ir, minute, opts);
|
|
577
|
+
if (cadence !== null) {
|
|
578
|
+
return cadence;
|
|
579
|
+
}
|
|
580
|
+
}
|
|
513
581
|
if (plan.times.length === 1) {
|
|
514
582
|
const time = plan.times[0];
|
|
515
583
|
return leadingQualifier(ir, opts) + timeWord(time.hour, time.minute, time.second, opts);
|
|
@@ -520,6 +588,12 @@ function renderClockTimes(ir, plan, opts) {
|
|
|
520
588
|
return leadingQualifier(ir, opts) + "klo " + joinList(digits);
|
|
521
589
|
}
|
|
522
590
|
function renderCompactClockTimes(ir, plan, opts) {
|
|
591
|
+
if (plan.fold) {
|
|
592
|
+
const cadence2 = hourCadence(ir, plan.minute, opts) ?? hourRangeCadence(ir, plan.minute, opts);
|
|
593
|
+
if (cadence2 !== null) {
|
|
594
|
+
return cadence2;
|
|
595
|
+
}
|
|
596
|
+
}
|
|
523
597
|
const hourSegs = ir.analyses.segments.hour;
|
|
524
598
|
if (hoursAreRangeIsolated(hourSegs)) {
|
|
525
599
|
if (plan.fold) {
|
|
@@ -530,14 +604,18 @@ function renderCompactClockTimes(ir, plan, opts) {
|
|
|
530
604
|
opts
|
|
531
605
|
);
|
|
532
606
|
}
|
|
533
|
-
const phrase2 = bareMinutes(ir) + " " + hourSegmentTimesWithSeka(ir, 0, null, opts) + trailingQualifier(ir, opts);
|
|
607
|
+
const phrase2 = bareMinutes(ir, opts) + " " + hourSegmentTimesWithSeka(ir, 0, null, opts) + trailingQualifier(ir, opts);
|
|
534
608
|
return ir.analyses.clockSecond ? secondsLeadClause(ir, opts) + ", " + phrase2 : phrase2;
|
|
535
609
|
}
|
|
536
610
|
if (plan.fold) {
|
|
537
611
|
return leadingQualifier(ir, opts) + hourSegmentTimes(ir, plan.minute, ir.analyses.clockSecond, opts);
|
|
538
612
|
}
|
|
539
|
-
const
|
|
540
|
-
const phrase =
|
|
613
|
+
const cadence = unevenHourCadence(ir, opts);
|
|
614
|
+
const phrase = cadence ? bareMinutes(ir, opts) + ", " + cadence + trailingQualifier(ir, opts) : (
|
|
615
|
+
// A minute list over purely enumerated hours (step fires, all singles) —
|
|
616
|
+
// hours-first, drop "joka tunti".
|
|
617
|
+
hoursFirstMinutes(hourSegmentTimes(ir, 0, null, opts), ir, opts) + trailingQualifier(ir, opts)
|
|
618
|
+
);
|
|
541
619
|
return ir.analyses.clockSecond ? secondsLeadClause(ir, opts) + ", " + phrase : phrase;
|
|
542
620
|
}
|
|
543
621
|
var renderers = {
|
|
@@ -560,20 +638,48 @@ var renderers = {
|
|
|
560
638
|
singleMinute: renderSingleMinute,
|
|
561
639
|
standaloneSeconds: renderStandaloneSeconds
|
|
562
640
|
};
|
|
641
|
+
function renderStride(stride, opts) {
|
|
642
|
+
const { interval, start, last, cycle, unit } = stride;
|
|
643
|
+
const cadence = genitive(interval, opts) + " " + unit.gen + " v\xE4lein";
|
|
644
|
+
const tiles = cycle % interval === 0;
|
|
645
|
+
if (start === 0 && tiles) {
|
|
646
|
+
return cadence;
|
|
647
|
+
}
|
|
648
|
+
if (start < interval && tiles) {
|
|
649
|
+
return cadence + " " + unit.anchor + " " + unit.ela + " " + start + " alkaen";
|
|
650
|
+
}
|
|
651
|
+
return cadence + " " + unit.ela + " " + start + " " + unit.ill + " " + last;
|
|
652
|
+
}
|
|
653
|
+
function strideFromSegments(segments, unit, opts) {
|
|
654
|
+
const values = singleValues(segments);
|
|
655
|
+
const step = values && arithmeticStep(values);
|
|
656
|
+
return step ? renderStride({ ...step, cycle: 60, unit }, opts) : null;
|
|
657
|
+
}
|
|
658
|
+
function singleValues(segments) {
|
|
659
|
+
const values = [];
|
|
660
|
+
for (const segment of segments) {
|
|
661
|
+
if (segment.kind !== "single") {
|
|
662
|
+
return null;
|
|
663
|
+
}
|
|
664
|
+
values.push(+segment.value);
|
|
665
|
+
}
|
|
666
|
+
return values;
|
|
667
|
+
}
|
|
563
668
|
function stepCycle60(segment, unit, opts) {
|
|
564
669
|
if (segment.startToken.indexOf("-") !== -1) {
|
|
565
670
|
return atMarks(joinList(wordList(segment.fires)), unit, true);
|
|
566
671
|
}
|
|
567
672
|
const start = segment.startToken === "*" ? 0 : +segment.startToken;
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
if (start !== 0) {
|
|
571
|
-
if (segment.fires.length <= 3) {
|
|
572
|
-
return atMarks(joinList(wordList(segment.fires)), unit, true);
|
|
573
|
-
}
|
|
574
|
-
return cadence + " " + unit.anchor + " " + unit.ela + " " + start + " alkaen";
|
|
673
|
+
if (start !== 0 && segment.fires.length <= 3) {
|
|
674
|
+
return atMarks(joinList(wordList(segment.fires)), unit, true);
|
|
575
675
|
}
|
|
576
|
-
return
|
|
676
|
+
return renderStride({
|
|
677
|
+
interval: segment.interval,
|
|
678
|
+
start,
|
|
679
|
+
last: segment.fires[segment.fires.length - 1],
|
|
680
|
+
cycle: 60,
|
|
681
|
+
unit
|
|
682
|
+
}, opts);
|
|
577
683
|
}
|
|
578
684
|
function stepHours(segment, opts) {
|
|
579
685
|
if (segment.startToken.indexOf("-") !== -1) {
|
|
@@ -590,6 +696,121 @@ function stepHours(segment, opts) {
|
|
|
590
696
|
}
|
|
591
697
|
return cadence + " klo " + hourElatives[start] + " alkaen";
|
|
592
698
|
}
|
|
699
|
+
function hourStrideCadence(stride, opts) {
|
|
700
|
+
const { start, interval, last } = stride;
|
|
701
|
+
const cadence = genitive(interval, opts) + " tunnin v\xE4lein";
|
|
702
|
+
const tiles = 24 % interval === 0;
|
|
703
|
+
if (start === 0 && tiles) {
|
|
704
|
+
return cadence;
|
|
705
|
+
}
|
|
706
|
+
if (start < interval && tiles) {
|
|
707
|
+
return cadence + " klo " + hourElatives[start] + " alkaen";
|
|
708
|
+
}
|
|
709
|
+
return cadence + " " + kloRange({ hour: start, minute: 0 }, { hour: last, minute: 0 }, opts);
|
|
710
|
+
}
|
|
711
|
+
function hourListStride(values) {
|
|
712
|
+
if (values.length < 2) {
|
|
713
|
+
return null;
|
|
714
|
+
}
|
|
715
|
+
const interval = values[1] - values[0];
|
|
716
|
+
if (interval < 2) {
|
|
717
|
+
return null;
|
|
718
|
+
}
|
|
719
|
+
for (let i = 2; i < values.length; i += 1) {
|
|
720
|
+
if (values[i] - values[i - 1] !== interval) {
|
|
721
|
+
return null;
|
|
722
|
+
}
|
|
723
|
+
}
|
|
724
|
+
if (values[0] !== 0 && values.length < 5) {
|
|
725
|
+
return null;
|
|
726
|
+
}
|
|
727
|
+
return { interval, last: values[values.length - 1], start: values[0] };
|
|
728
|
+
}
|
|
729
|
+
function offsetCleanStride(stride) {
|
|
730
|
+
return stride.start < stride.interval && 24 % stride.interval === 0;
|
|
731
|
+
}
|
|
732
|
+
function hourStride(ir) {
|
|
733
|
+
const segments = ir.analyses.segments.hour;
|
|
734
|
+
if (!segments) {
|
|
735
|
+
return null;
|
|
736
|
+
}
|
|
737
|
+
if (segments.length === 1 && segments[0].kind === "step") {
|
|
738
|
+
const segment = segments[0];
|
|
739
|
+
if (segment.fires.length < 2) {
|
|
740
|
+
return null;
|
|
741
|
+
}
|
|
742
|
+
const start = segment.startToken === "*" ? 0 : +segment.startToken.split("-")[0];
|
|
743
|
+
return { interval: segment.interval, last: segment.fires[segment.fires.length - 1], start };
|
|
744
|
+
}
|
|
745
|
+
const values = singleValues(segments);
|
|
746
|
+
return values && hourListStride(values);
|
|
747
|
+
}
|
|
748
|
+
function unevenHourCadence(ir, opts) {
|
|
749
|
+
const stride = hourStride(ir);
|
|
750
|
+
if (!stride || offsetCleanStride(stride)) {
|
|
751
|
+
return null;
|
|
752
|
+
}
|
|
753
|
+
return hourStrideCadence(stride, opts);
|
|
754
|
+
}
|
|
755
|
+
function subMinuteSecond(ir) {
|
|
756
|
+
return ir.pattern.second === "*" || ir.shapes.second === "step";
|
|
757
|
+
}
|
|
758
|
+
function hourCadenceLead(ir, minute, opts) {
|
|
759
|
+
if (minute === 0) {
|
|
760
|
+
if (subMinuteSecond(ir)) {
|
|
761
|
+
return secondsLeadClause(ir, opts) + " minuutin ajan";
|
|
762
|
+
}
|
|
763
|
+
return secondsLeadClause(ir, opts);
|
|
764
|
+
}
|
|
765
|
+
const minutePhrase = atMarks(String(minute), units.minute, false);
|
|
766
|
+
if (ir.pattern.second === "0") {
|
|
767
|
+
return minutePhrase;
|
|
768
|
+
}
|
|
769
|
+
return secondsLeadClause(ir, opts) + ", " + minutePhrase;
|
|
770
|
+
}
|
|
771
|
+
function hourCadence(ir, minute, opts) {
|
|
772
|
+
const stride = hourStride(ir);
|
|
773
|
+
if (!stride) {
|
|
774
|
+
return null;
|
|
775
|
+
}
|
|
776
|
+
const fires = (stride.last - stride.start) / stride.interval + 1;
|
|
777
|
+
if (ir.pattern.second === "0" && fires <= maxClockTimes && offsetCleanStride(stride)) {
|
|
778
|
+
return null;
|
|
779
|
+
}
|
|
780
|
+
const segment = ir.analyses.segments.hour[0];
|
|
781
|
+
const confined = minute === 0 && subMinuteSecond(ir) && ir.analyses.segments.hour.length === 1 && segment.kind === "step" && cleanHourStride(segment);
|
|
782
|
+
if (confined) {
|
|
783
|
+
return secondsLeadClause(ir, opts) + " minuutin ajan " + everyNthHour(segment, opts) + trailingQualifier(ir, opts);
|
|
784
|
+
}
|
|
785
|
+
if (minute === 0 && ir.pattern.second === "0") {
|
|
786
|
+
return hourStrideCadence(stride, opts) + trailingQualifier(ir, opts);
|
|
787
|
+
}
|
|
788
|
+
return hourCadenceLead(ir, minute, opts) + ", " + hourStrideCadence(stride, opts) + trailingQualifier(ir, opts);
|
|
789
|
+
}
|
|
790
|
+
function cleanHourStride(segment) {
|
|
791
|
+
if (segment.startToken.indexOf("-") !== -1) {
|
|
792
|
+
return false;
|
|
793
|
+
}
|
|
794
|
+
const start = segment.startToken === "*" ? 0 : +segment.startToken;
|
|
795
|
+
return 24 % segment.interval === 0 && start < segment.interval;
|
|
796
|
+
}
|
|
797
|
+
function hasHourWindow(ir) {
|
|
798
|
+
const segments = ir.analyses.segments.hour;
|
|
799
|
+
return !!segments && segments.some(function range(segment) {
|
|
800
|
+
return segment.kind === "range";
|
|
801
|
+
});
|
|
802
|
+
}
|
|
803
|
+
function hourRangeWindowTail(ir, opts) {
|
|
804
|
+
return ir.analyses.segments.hour.length === 1 ? hourSegmentTimes(ir, 0, null, opts) : hourSegmentTimesWithSeka(ir, 0, null, opts);
|
|
805
|
+
}
|
|
806
|
+
function hourRangeCadence(ir, minute, opts) {
|
|
807
|
+
if (minute !== 0 || !hasHourWindow(ir) || ir.pattern.second === "0") {
|
|
808
|
+
return null;
|
|
809
|
+
}
|
|
810
|
+
const tail = hourRangeWindowTail(ir, opts);
|
|
811
|
+
const joiner = subMinuteSecond(ir) ? " " : ", ";
|
|
812
|
+
return hourCadenceLead(ir, minute, opts) + joiner + tail + trailingQualifier(ir, opts);
|
|
813
|
+
}
|
|
593
814
|
function kloList(hours, opts) {
|
|
594
815
|
if (hours.length === 1) {
|
|
595
816
|
return timeWord(hours[0], 0, null, opts);
|
|
@@ -606,12 +827,16 @@ function kloFromTimes(ir, times, opts) {
|
|
|
606
827
|
}
|
|
607
828
|
function hourWindowsFromTimes(ir, times, opts) {
|
|
608
829
|
if (times.kind === "fires") {
|
|
609
|
-
return
|
|
610
|
-
|
|
611
|
-
|
|
830
|
+
return kloList(times.fires, opts);
|
|
831
|
+
}
|
|
832
|
+
const segments = ir.analyses.segments.hour;
|
|
833
|
+
if (!segments.some(function ranged(segment) {
|
|
834
|
+
return segment.kind === "range";
|
|
835
|
+
})) {
|
|
836
|
+
return kloList(hourSegmentFires(segments), opts);
|
|
612
837
|
}
|
|
613
838
|
const pieces = [];
|
|
614
|
-
|
|
839
|
+
segments.forEach(function window(segment) {
|
|
615
840
|
if (segment.kind === "range") {
|
|
616
841
|
pieces.push(rangeDigits(
|
|
617
842
|
{ hour: +segment.bounds[0], minute: 0 },
|
|
@@ -628,6 +853,17 @@ function hourWindowsFromTimes(ir, times, opts) {
|
|
|
628
853
|
});
|
|
629
854
|
return "klo " + joinList(pieces);
|
|
630
855
|
}
|
|
856
|
+
function hourSegmentFires(segments) {
|
|
857
|
+
const hours = [];
|
|
858
|
+
segments.forEach(function each(segment) {
|
|
859
|
+
if (segment.kind === "step") {
|
|
860
|
+
hours.push(...segment.fires);
|
|
861
|
+
} else if (segment.kind === "single") {
|
|
862
|
+
hours.push(+segment.value);
|
|
863
|
+
}
|
|
864
|
+
});
|
|
865
|
+
return hours;
|
|
866
|
+
}
|
|
631
867
|
function hourWindowDigits(hour, opts) {
|
|
632
868
|
return rangeDigits({ hour, minute: 0 }, { hour, minute: 59 }, opts);
|
|
633
869
|
}
|