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.js
CHANGED
|
@@ -24,12 +24,28 @@ var weekdayNumbers = {
|
|
|
24
24
|
FRI: 5,
|
|
25
25
|
SAT: 6
|
|
26
26
|
};
|
|
27
|
+
var maxClockTimes = 6;
|
|
27
28
|
|
|
28
29
|
// src/core/util.ts
|
|
29
30
|
function isNonNegativeInteger(value) {
|
|
30
31
|
const digits = /^\d+$/;
|
|
31
32
|
return digits.test(value);
|
|
32
33
|
}
|
|
34
|
+
function arithmeticStep(values) {
|
|
35
|
+
if (values.length < 5) {
|
|
36
|
+
return null;
|
|
37
|
+
}
|
|
38
|
+
const interval = values[1] - values[0];
|
|
39
|
+
if (interval < 2) {
|
|
40
|
+
return null;
|
|
41
|
+
}
|
|
42
|
+
for (let i = 2; i < values.length; i += 1) {
|
|
43
|
+
if (values[i] - values[i - 1] !== interval) {
|
|
44
|
+
return null;
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
return { start: values[0], interval, last: values[values.length - 1] };
|
|
48
|
+
}
|
|
33
49
|
function toFieldNumber(token, numberMap) {
|
|
34
50
|
return isNonNegativeInteger(token) ? +token : numberMap[token.toUpperCase()];
|
|
35
51
|
}
|
|
@@ -165,12 +181,14 @@ var units = {
|
|
|
165
181
|
mark: "joka tunti",
|
|
166
182
|
anchor: "jokaisen tunnin",
|
|
167
183
|
ela: "minuutista",
|
|
184
|
+
ill: "minuuttiin",
|
|
168
185
|
gen: "minuutin"
|
|
169
186
|
},
|
|
170
187
|
second: {
|
|
171
188
|
mark: "joka minuutti",
|
|
172
189
|
anchor: "jokaisen minuutin",
|
|
173
190
|
ela: "sekunnista",
|
|
191
|
+
ill: "sekuntiin",
|
|
174
192
|
gen: "sekunnin"
|
|
175
193
|
}
|
|
176
194
|
};
|
|
@@ -226,28 +244,55 @@ function renderSecondsWithinMinute(ir, plan, opts) {
|
|
|
226
244
|
}
|
|
227
245
|
return secondsLeadClause(ir, opts) + ", " + atMarks(minuteField, units.minute, true) + trailingQualifier(ir, opts);
|
|
228
246
|
}
|
|
247
|
+
function composeSecondsOverMinuteStep(ir, freq, opts) {
|
|
248
|
+
const seg = stepSegment(ir.analyses.segments.minute);
|
|
249
|
+
const stepPhrase = stepCycle60(seg, units.minute, opts);
|
|
250
|
+
if (freq.hours.kind === "during" && minuteStepIsAnchored(seg)) {
|
|
251
|
+
const bareHours = kloFromTimes(ir, freq.hours.times, opts);
|
|
252
|
+
return hoursFirstMinutes(bareHours, ir, opts) + ", " + secondsLeadClause(ir, opts) + trailingQualifier(ir, opts);
|
|
253
|
+
}
|
|
254
|
+
let hourClause = "";
|
|
255
|
+
if (freq.hours.kind === "during") {
|
|
256
|
+
hourClause = " " + hourWindowsFromTimes(ir, freq.hours.times, opts);
|
|
257
|
+
} else if (freq.hours.kind === "window") {
|
|
258
|
+
hourClause = " " + hourWindow(freq.hours, opts);
|
|
259
|
+
} else if (freq.hours.kind === "step") {
|
|
260
|
+
hourClause = " " + everyNthHour(stepSegment(ir.analyses.segments.hour), opts);
|
|
261
|
+
}
|
|
262
|
+
return stepPhrase + ", " + secondsLeadClause(ir, opts) + hourClause + trailingQualifier(ir, opts);
|
|
263
|
+
}
|
|
264
|
+
function composeHourCadence(ir, plan, opts) {
|
|
265
|
+
const clockRest = plan.rest.kind === "clockTimes" || plan.rest.kind === "compactClockTimes";
|
|
266
|
+
if (!clockRest || ir.shapes.minute !== "single") {
|
|
267
|
+
return null;
|
|
268
|
+
}
|
|
269
|
+
const minute = +ir.pattern.minute;
|
|
270
|
+
return hourCadence(ir, minute, opts) ?? hourRangeCadence(ir, minute, opts);
|
|
271
|
+
}
|
|
229
272
|
function renderComposeSeconds(ir, plan, opts) {
|
|
273
|
+
const cadence = composeHourCadence(ir, plan, opts);
|
|
274
|
+
if (cadence !== null) {
|
|
275
|
+
return cadence;
|
|
276
|
+
}
|
|
230
277
|
if (plan.rest.kind === "minuteFrequency" && ir.pattern.second !== "*") {
|
|
231
|
-
|
|
232
|
-
const seg = stepSegment(ir.analyses.segments.minute);
|
|
233
|
-
const stepPhrase = stepCycle60(seg, units.minute, opts);
|
|
234
|
-
let hourClause = "";
|
|
235
|
-
if (freq.hours.kind === "during" && minuteStepIsAnchored(seg)) {
|
|
236
|
-
const bareHours = kloFromTimes(ir, freq.hours.times, opts);
|
|
237
|
-
return hoursFirstMinutes(bareHours, ir) + ", " + secondsLeadClause(ir, opts) + trailingQualifier(ir, opts);
|
|
238
|
-
} else if (freq.hours.kind === "during" && !minuteStepIsAnchored(seg)) {
|
|
239
|
-
hourClause = " " + hourWindowsFromTimes(ir, freq.hours.times, opts);
|
|
240
|
-
} else if (freq.hours.kind === "window") {
|
|
241
|
-
hourClause = " " + hourWindow(freq.hours, opts);
|
|
242
|
-
} else if (freq.hours.kind === "step") {
|
|
243
|
-
hourClause = " " + everyNthHour(stepSegment(ir.analyses.segments.hour), opts);
|
|
244
|
-
}
|
|
245
|
-
return stepPhrase + ", " + secondsLeadClause(ir, opts) + hourClause + trailingQualifier(ir, opts);
|
|
278
|
+
return composeSecondsOverMinuteStep(ir, plan.rest, opts);
|
|
246
279
|
}
|
|
247
280
|
if (plan.rest.kind === "clockTimes" && plan.rest.times.every((time) => +time.minute === 0)) {
|
|
248
281
|
return composeMinuteZero(ir, plan.rest, opts);
|
|
249
282
|
}
|
|
250
|
-
|
|
283
|
+
if (isEveryOtherMinuteSeconds(ir, plan)) {
|
|
284
|
+
return secondsLeadClause(ir, opts) + " joka toisena minuuttina";
|
|
285
|
+
}
|
|
286
|
+
const restOwnsLead = plan.rest.kind === "compactClockTimes" && ir.analyses.clockSecond;
|
|
287
|
+
const lead = restOwnsLead ? "" : secondsLeadClause(ir, opts) + ", ";
|
|
288
|
+
return lead + render(ir, plan.rest, opts);
|
|
289
|
+
}
|
|
290
|
+
function isEveryOtherMinuteSeconds(ir, plan) {
|
|
291
|
+
if (plan.rest.kind !== "minuteFrequency" || ir.pattern.second !== "*" || ir.shapes.hour !== "wildcard") {
|
|
292
|
+
return false;
|
|
293
|
+
}
|
|
294
|
+
const seg = stepSegment(ir.analyses.segments.minute);
|
|
295
|
+
return seg.startToken === "*" && seg.interval === 2;
|
|
251
296
|
}
|
|
252
297
|
function composeMinuteZero(ir, rest, opts) {
|
|
253
298
|
const clocks = rest.times.map(function clock(time) {
|
|
@@ -277,7 +322,7 @@ function secondsLeadClause(ir, opts) {
|
|
|
277
322
|
if (shape === "single") {
|
|
278
323
|
return atMarks(secondField, units.second, marked);
|
|
279
324
|
}
|
|
280
|
-
return atMarks(
|
|
325
|
+
return strideFromSegments(ir.analyses.segments.second, units.second, opts) ?? atMarks(
|
|
281
326
|
joinList(segmentWords(ir.analyses.segments.second)),
|
|
282
327
|
units.second,
|
|
283
328
|
marked
|
|
@@ -290,20 +335,20 @@ function renderSingleMinute(ir, plan, opts) {
|
|
|
290
335
|
return atMarks(ir.pattern.minute, units.minute, true) + trailingQualifier(ir, opts);
|
|
291
336
|
}
|
|
292
337
|
function renderRangeOfMinutes(ir, plan, opts) {
|
|
293
|
-
return minutesList(ir) + trailingQualifier(ir, opts);
|
|
338
|
+
return minutesList(ir, opts) + trailingQualifier(ir, opts);
|
|
294
339
|
}
|
|
295
340
|
function renderMultipleMinutes(ir, plan, opts) {
|
|
296
|
-
return minutesList(ir) + trailingQualifier(ir, opts);
|
|
341
|
+
return minutesList(ir, opts) + trailingQualifier(ir, opts);
|
|
297
342
|
}
|
|
298
|
-
function minutesList(ir) {
|
|
299
|
-
return atMarks(
|
|
343
|
+
function minutesList(ir, opts) {
|
|
344
|
+
return strideFromSegments(ir.analyses.segments.minute, units.minute, opts) ?? atMarks(
|
|
300
345
|
joinList(segmentWords(ir.analyses.segments.minute)),
|
|
301
346
|
units.minute,
|
|
302
347
|
true
|
|
303
348
|
);
|
|
304
349
|
}
|
|
305
|
-
function bareMinutes(ir) {
|
|
306
|
-
return atMarks(
|
|
350
|
+
function bareMinutes(ir, opts) {
|
|
351
|
+
return strideFromSegments(ir.analyses.segments.minute, units.minute, opts) ?? atMarks(
|
|
307
352
|
joinList(segmentWords(ir.analyses.segments.minute)),
|
|
308
353
|
units.minute,
|
|
309
354
|
false
|
|
@@ -334,7 +379,11 @@ function hoursAreRangeIsolated(segments) {
|
|
|
334
379
|
}
|
|
335
380
|
return hasRange && hasSingle;
|
|
336
381
|
}
|
|
337
|
-
function hoursFirstMinutes(hoursStr, ir) {
|
|
382
|
+
function hoursFirstMinutes(hoursStr, ir, opts) {
|
|
383
|
+
const stride = strideFromSegments(ir.analyses.segments.minute, units.minute, opts);
|
|
384
|
+
if (stride) {
|
|
385
|
+
return hoursStr + " aina " + stride;
|
|
386
|
+
}
|
|
338
387
|
return hoursStr + " aina minuuttien " + joinList(segmentWords(ir.analyses.segments.minute)) + " kohdalla";
|
|
339
388
|
}
|
|
340
389
|
function hourSegmentTimesWithSeka(ir, minute, second, opts) {
|
|
@@ -355,9 +404,13 @@ function hourSegmentTimesWithSeka(ir, minute, second, opts) {
|
|
|
355
404
|
function renderMinuteFrequency(ir, plan, opts) {
|
|
356
405
|
const seg = stepSegment(ir.analyses.segments.minute);
|
|
357
406
|
if (plan.hours.kind === "during") {
|
|
407
|
+
const cadence = unevenHourCadence(ir, opts);
|
|
408
|
+
if (cadence !== null) {
|
|
409
|
+
return stepCycle60(seg, units.minute, opts) + ", " + cadence + trailingQualifier(ir, opts);
|
|
410
|
+
}
|
|
358
411
|
if (minuteStepIsAnchored(seg)) {
|
|
359
412
|
const bareHours = kloFromTimes(ir, plan.hours.times, opts);
|
|
360
|
-
return hoursFirstMinutes(bareHours, ir) + trailingQualifier(ir, opts);
|
|
413
|
+
return hoursFirstMinutes(bareHours, ir, opts) + trailingQualifier(ir, opts);
|
|
361
414
|
}
|
|
362
415
|
return stepCycle60(seg, units.minute, opts) + " " + hourWindowsFromTimes(ir, plan.hours.times, opts) + trailingQualifier(ir, opts);
|
|
363
416
|
}
|
|
@@ -380,25 +433,29 @@ function renderMinuteSpanInHour(ir, plan, opts) {
|
|
|
380
433
|
) + trailingQualifier(ir, opts);
|
|
381
434
|
}
|
|
382
435
|
function renderMinutesAcrossHours(ir, plan, opts) {
|
|
436
|
+
const cadence = unevenHourCadence(ir, opts);
|
|
383
437
|
if (plan.form === "wildcard") {
|
|
384
|
-
return "joka minuutti " + hourWindowsFromTimes(ir, plan.times, opts) + trailingQualifier(ir, opts);
|
|
438
|
+
return cadence ? "joka minuutti, " + cadence + trailingQualifier(ir, opts) : "joka minuutti " + hourWindowsFromTimes(ir, plan.times, opts) + trailingQualifier(ir, opts);
|
|
439
|
+
}
|
|
440
|
+
if (cadence !== null) {
|
|
441
|
+
return bareMinutes(ir, opts) + ", " + cadence + trailingQualifier(ir, opts);
|
|
385
442
|
}
|
|
386
443
|
if (hoursAreRangeIsolated(ir.analyses.segments.hour)) {
|
|
387
|
-
return bareMinutes(ir) + " " + hourSegmentTimesWithSeka(ir, 0, null, opts) + trailingQualifier(ir, opts);
|
|
444
|
+
return bareMinutes(ir, opts) + " " + hourSegmentTimesWithSeka(ir, 0, null, opts) + trailingQualifier(ir, opts);
|
|
388
445
|
}
|
|
389
446
|
const hoursStr = kloFromTimes(ir, plan.times, opts);
|
|
390
|
-
return hoursFirstMinutes(hoursStr, ir) + trailingQualifier(ir, opts);
|
|
447
|
+
return hoursFirstMinutes(hoursStr, ir, opts) + trailingQualifier(ir, opts);
|
|
391
448
|
}
|
|
392
449
|
function renderMinuteSpanAcrossHourStep(ir, plan, opts) {
|
|
393
450
|
const segment = stepSegment(ir.analyses.segments.hour);
|
|
451
|
+
const cadence = unevenHourCadence(ir, opts);
|
|
394
452
|
if (plan.form === "wildcard") {
|
|
395
453
|
return "joka minuutti " + everyNthHour(segment, opts) + trailingQualifier(ir, opts);
|
|
396
454
|
}
|
|
397
|
-
if (
|
|
398
|
-
|
|
399
|
-
return hoursFirstMinutes(hoursStr, ir) + trailingQualifier(ir, opts);
|
|
455
|
+
if (cadence !== null) {
|
|
456
|
+
return bareMinutes(ir, opts) + ", " + cadence + trailingQualifier(ir, opts);
|
|
400
457
|
}
|
|
401
|
-
return bareMinutes(ir) + hourStepTail(segment, opts) + trailingQualifier(ir, opts);
|
|
458
|
+
return bareMinutes(ir, opts) + hourStepTail(segment, opts) + trailingQualifier(ir, opts);
|
|
402
459
|
}
|
|
403
460
|
function plainHourStep(segment) {
|
|
404
461
|
return segment.startToken === "*" && 24 % segment.interval === 0;
|
|
@@ -456,7 +513,7 @@ function renderHourRange(ir, plan, opts) {
|
|
|
456
513
|
return "joka minuutti " + window + trailingQualifier(ir, opts);
|
|
457
514
|
}
|
|
458
515
|
if (plan.minuteForm === "range") {
|
|
459
|
-
return hoursFirstMinutes(window, ir) + trailingQualifier(ir, opts);
|
|
516
|
+
return hoursFirstMinutes(window, ir, opts) + trailingQualifier(ir, opts);
|
|
460
517
|
}
|
|
461
518
|
if (ir.pattern.minute === "0") {
|
|
462
519
|
return "joka tunti " + window + trailingQualifier(ir, opts);
|
|
@@ -468,9 +525,13 @@ function renderHourRange(ir, plan, opts) {
|
|
|
468
525
|
opts
|
|
469
526
|
) + trailingQualifier(ir, opts);
|
|
470
527
|
}
|
|
471
|
-
return hoursFirstMinutes(window, ir) + trailingQualifier(ir, opts);
|
|
528
|
+
return hoursFirstMinutes(window, ir, opts) + trailingQualifier(ir, opts);
|
|
472
529
|
}
|
|
473
530
|
function renderHourStep(ir, plan, opts) {
|
|
531
|
+
const cadence = unevenHourCadence(ir, opts);
|
|
532
|
+
if (cadence !== null) {
|
|
533
|
+
return cadence + trailingQualifier(ir, opts);
|
|
534
|
+
}
|
|
474
535
|
return stepHours(stepSegment(ir.analyses.segments.hour), opts) + trailingQualifier(ir, opts);
|
|
475
536
|
}
|
|
476
537
|
function boundedWindow(plan) {
|
|
@@ -484,6 +545,13 @@ function hourWindow(window, opts) {
|
|
|
484
545
|
);
|
|
485
546
|
}
|
|
486
547
|
function renderClockTimes(ir, plan, opts) {
|
|
548
|
+
if (ir.shapes.minute === "single") {
|
|
549
|
+
const minute = +ir.pattern.minute;
|
|
550
|
+
const cadence = hourCadence(ir, minute, opts) ?? hourRangeCadence(ir, minute, opts);
|
|
551
|
+
if (cadence !== null) {
|
|
552
|
+
return cadence;
|
|
553
|
+
}
|
|
554
|
+
}
|
|
487
555
|
if (plan.times.length === 1) {
|
|
488
556
|
const time = plan.times[0];
|
|
489
557
|
return leadingQualifier(ir, opts) + timeWord(time.hour, time.minute, time.second, opts);
|
|
@@ -494,6 +562,12 @@ function renderClockTimes(ir, plan, opts) {
|
|
|
494
562
|
return leadingQualifier(ir, opts) + "klo " + joinList(digits);
|
|
495
563
|
}
|
|
496
564
|
function renderCompactClockTimes(ir, plan, opts) {
|
|
565
|
+
if (plan.fold) {
|
|
566
|
+
const cadence2 = hourCadence(ir, plan.minute, opts) ?? hourRangeCadence(ir, plan.minute, opts);
|
|
567
|
+
if (cadence2 !== null) {
|
|
568
|
+
return cadence2;
|
|
569
|
+
}
|
|
570
|
+
}
|
|
497
571
|
const hourSegs = ir.analyses.segments.hour;
|
|
498
572
|
if (hoursAreRangeIsolated(hourSegs)) {
|
|
499
573
|
if (plan.fold) {
|
|
@@ -504,14 +578,18 @@ function renderCompactClockTimes(ir, plan, opts) {
|
|
|
504
578
|
opts
|
|
505
579
|
);
|
|
506
580
|
}
|
|
507
|
-
const phrase2 = bareMinutes(ir) + " " + hourSegmentTimesWithSeka(ir, 0, null, opts) + trailingQualifier(ir, opts);
|
|
581
|
+
const phrase2 = bareMinutes(ir, opts) + " " + hourSegmentTimesWithSeka(ir, 0, null, opts) + trailingQualifier(ir, opts);
|
|
508
582
|
return ir.analyses.clockSecond ? secondsLeadClause(ir, opts) + ", " + phrase2 : phrase2;
|
|
509
583
|
}
|
|
510
584
|
if (plan.fold) {
|
|
511
585
|
return leadingQualifier(ir, opts) + hourSegmentTimes(ir, plan.minute, ir.analyses.clockSecond, opts);
|
|
512
586
|
}
|
|
513
|
-
const
|
|
514
|
-
const phrase =
|
|
587
|
+
const cadence = unevenHourCadence(ir, opts);
|
|
588
|
+
const phrase = cadence ? bareMinutes(ir, opts) + ", " + cadence + trailingQualifier(ir, opts) : (
|
|
589
|
+
// A minute list over purely enumerated hours (step fires, all singles) —
|
|
590
|
+
// hours-first, drop "joka tunti".
|
|
591
|
+
hoursFirstMinutes(hourSegmentTimes(ir, 0, null, opts), ir, opts) + trailingQualifier(ir, opts)
|
|
592
|
+
);
|
|
515
593
|
return ir.analyses.clockSecond ? secondsLeadClause(ir, opts) + ", " + phrase : phrase;
|
|
516
594
|
}
|
|
517
595
|
var renderers = {
|
|
@@ -534,20 +612,48 @@ var renderers = {
|
|
|
534
612
|
singleMinute: renderSingleMinute,
|
|
535
613
|
standaloneSeconds: renderStandaloneSeconds
|
|
536
614
|
};
|
|
615
|
+
function renderStride(stride, opts) {
|
|
616
|
+
const { interval, start, last, cycle, unit } = stride;
|
|
617
|
+
const cadence = genitive(interval, opts) + " " + unit.gen + " v\xE4lein";
|
|
618
|
+
const tiles = cycle % interval === 0;
|
|
619
|
+
if (start === 0 && tiles) {
|
|
620
|
+
return cadence;
|
|
621
|
+
}
|
|
622
|
+
if (start < interval && tiles) {
|
|
623
|
+
return cadence + " " + unit.anchor + " " + unit.ela + " " + start + " alkaen";
|
|
624
|
+
}
|
|
625
|
+
return cadence + " " + unit.ela + " " + start + " " + unit.ill + " " + last;
|
|
626
|
+
}
|
|
627
|
+
function strideFromSegments(segments, unit, opts) {
|
|
628
|
+
const values = singleValues(segments);
|
|
629
|
+
const step = values && arithmeticStep(values);
|
|
630
|
+
return step ? renderStride({ ...step, cycle: 60, unit }, opts) : null;
|
|
631
|
+
}
|
|
632
|
+
function singleValues(segments) {
|
|
633
|
+
const values = [];
|
|
634
|
+
for (const segment of segments) {
|
|
635
|
+
if (segment.kind !== "single") {
|
|
636
|
+
return null;
|
|
637
|
+
}
|
|
638
|
+
values.push(+segment.value);
|
|
639
|
+
}
|
|
640
|
+
return values;
|
|
641
|
+
}
|
|
537
642
|
function stepCycle60(segment, unit, opts) {
|
|
538
643
|
if (segment.startToken.indexOf("-") !== -1) {
|
|
539
644
|
return atMarks(joinList(wordList(segment.fires)), unit, true);
|
|
540
645
|
}
|
|
541
646
|
const start = segment.startToken === "*" ? 0 : +segment.startToken;
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
if (start !== 0) {
|
|
545
|
-
if (segment.fires.length <= 3) {
|
|
546
|
-
return atMarks(joinList(wordList(segment.fires)), unit, true);
|
|
547
|
-
}
|
|
548
|
-
return cadence + " " + unit.anchor + " " + unit.ela + " " + start + " alkaen";
|
|
647
|
+
if (start !== 0 && segment.fires.length <= 3) {
|
|
648
|
+
return atMarks(joinList(wordList(segment.fires)), unit, true);
|
|
549
649
|
}
|
|
550
|
-
return
|
|
650
|
+
return renderStride({
|
|
651
|
+
interval: segment.interval,
|
|
652
|
+
start,
|
|
653
|
+
last: segment.fires[segment.fires.length - 1],
|
|
654
|
+
cycle: 60,
|
|
655
|
+
unit
|
|
656
|
+
}, opts);
|
|
551
657
|
}
|
|
552
658
|
function stepHours(segment, opts) {
|
|
553
659
|
if (segment.startToken.indexOf("-") !== -1) {
|
|
@@ -564,6 +670,121 @@ function stepHours(segment, opts) {
|
|
|
564
670
|
}
|
|
565
671
|
return cadence + " klo " + hourElatives[start] + " alkaen";
|
|
566
672
|
}
|
|
673
|
+
function hourStrideCadence(stride, opts) {
|
|
674
|
+
const { start, interval, last } = stride;
|
|
675
|
+
const cadence = genitive(interval, opts) + " tunnin v\xE4lein";
|
|
676
|
+
const tiles = 24 % interval === 0;
|
|
677
|
+
if (start === 0 && tiles) {
|
|
678
|
+
return cadence;
|
|
679
|
+
}
|
|
680
|
+
if (start < interval && tiles) {
|
|
681
|
+
return cadence + " klo " + hourElatives[start] + " alkaen";
|
|
682
|
+
}
|
|
683
|
+
return cadence + " " + kloRange({ hour: start, minute: 0 }, { hour: last, minute: 0 }, opts);
|
|
684
|
+
}
|
|
685
|
+
function hourListStride(values) {
|
|
686
|
+
if (values.length < 2) {
|
|
687
|
+
return null;
|
|
688
|
+
}
|
|
689
|
+
const interval = values[1] - values[0];
|
|
690
|
+
if (interval < 2) {
|
|
691
|
+
return null;
|
|
692
|
+
}
|
|
693
|
+
for (let i = 2; i < values.length; i += 1) {
|
|
694
|
+
if (values[i] - values[i - 1] !== interval) {
|
|
695
|
+
return null;
|
|
696
|
+
}
|
|
697
|
+
}
|
|
698
|
+
if (values[0] !== 0 && values.length < 5) {
|
|
699
|
+
return null;
|
|
700
|
+
}
|
|
701
|
+
return { interval, last: values[values.length - 1], start: values[0] };
|
|
702
|
+
}
|
|
703
|
+
function offsetCleanStride(stride) {
|
|
704
|
+
return stride.start < stride.interval && 24 % stride.interval === 0;
|
|
705
|
+
}
|
|
706
|
+
function hourStride(ir) {
|
|
707
|
+
const segments = ir.analyses.segments.hour;
|
|
708
|
+
if (!segments) {
|
|
709
|
+
return null;
|
|
710
|
+
}
|
|
711
|
+
if (segments.length === 1 && segments[0].kind === "step") {
|
|
712
|
+
const segment = segments[0];
|
|
713
|
+
if (segment.fires.length < 2) {
|
|
714
|
+
return null;
|
|
715
|
+
}
|
|
716
|
+
const start = segment.startToken === "*" ? 0 : +segment.startToken.split("-")[0];
|
|
717
|
+
return { interval: segment.interval, last: segment.fires[segment.fires.length - 1], start };
|
|
718
|
+
}
|
|
719
|
+
const values = singleValues(segments);
|
|
720
|
+
return values && hourListStride(values);
|
|
721
|
+
}
|
|
722
|
+
function unevenHourCadence(ir, opts) {
|
|
723
|
+
const stride = hourStride(ir);
|
|
724
|
+
if (!stride || offsetCleanStride(stride)) {
|
|
725
|
+
return null;
|
|
726
|
+
}
|
|
727
|
+
return hourStrideCadence(stride, opts);
|
|
728
|
+
}
|
|
729
|
+
function subMinuteSecond(ir) {
|
|
730
|
+
return ir.pattern.second === "*" || ir.shapes.second === "step";
|
|
731
|
+
}
|
|
732
|
+
function hourCadenceLead(ir, minute, opts) {
|
|
733
|
+
if (minute === 0) {
|
|
734
|
+
if (subMinuteSecond(ir)) {
|
|
735
|
+
return secondsLeadClause(ir, opts) + " minuutin ajan";
|
|
736
|
+
}
|
|
737
|
+
return secondsLeadClause(ir, opts);
|
|
738
|
+
}
|
|
739
|
+
const minutePhrase = atMarks(String(minute), units.minute, false);
|
|
740
|
+
if (ir.pattern.second === "0") {
|
|
741
|
+
return minutePhrase;
|
|
742
|
+
}
|
|
743
|
+
return secondsLeadClause(ir, opts) + ", " + minutePhrase;
|
|
744
|
+
}
|
|
745
|
+
function hourCadence(ir, minute, opts) {
|
|
746
|
+
const stride = hourStride(ir);
|
|
747
|
+
if (!stride) {
|
|
748
|
+
return null;
|
|
749
|
+
}
|
|
750
|
+
const fires = (stride.last - stride.start) / stride.interval + 1;
|
|
751
|
+
if (ir.pattern.second === "0" && fires <= maxClockTimes && offsetCleanStride(stride)) {
|
|
752
|
+
return null;
|
|
753
|
+
}
|
|
754
|
+
const segment = ir.analyses.segments.hour[0];
|
|
755
|
+
const confined = minute === 0 && subMinuteSecond(ir) && ir.analyses.segments.hour.length === 1 && segment.kind === "step" && cleanHourStride(segment);
|
|
756
|
+
if (confined) {
|
|
757
|
+
return secondsLeadClause(ir, opts) + " minuutin ajan " + everyNthHour(segment, opts) + trailingQualifier(ir, opts);
|
|
758
|
+
}
|
|
759
|
+
if (minute === 0 && ir.pattern.second === "0") {
|
|
760
|
+
return hourStrideCadence(stride, opts) + trailingQualifier(ir, opts);
|
|
761
|
+
}
|
|
762
|
+
return hourCadenceLead(ir, minute, opts) + ", " + hourStrideCadence(stride, opts) + trailingQualifier(ir, opts);
|
|
763
|
+
}
|
|
764
|
+
function cleanHourStride(segment) {
|
|
765
|
+
if (segment.startToken.indexOf("-") !== -1) {
|
|
766
|
+
return false;
|
|
767
|
+
}
|
|
768
|
+
const start = segment.startToken === "*" ? 0 : +segment.startToken;
|
|
769
|
+
return 24 % segment.interval === 0 && start < segment.interval;
|
|
770
|
+
}
|
|
771
|
+
function hasHourWindow(ir) {
|
|
772
|
+
const segments = ir.analyses.segments.hour;
|
|
773
|
+
return !!segments && segments.some(function range(segment) {
|
|
774
|
+
return segment.kind === "range";
|
|
775
|
+
});
|
|
776
|
+
}
|
|
777
|
+
function hourRangeWindowTail(ir, opts) {
|
|
778
|
+
return ir.analyses.segments.hour.length === 1 ? hourSegmentTimes(ir, 0, null, opts) : hourSegmentTimesWithSeka(ir, 0, null, opts);
|
|
779
|
+
}
|
|
780
|
+
function hourRangeCadence(ir, minute, opts) {
|
|
781
|
+
if (minute !== 0 || !hasHourWindow(ir) || ir.pattern.second === "0") {
|
|
782
|
+
return null;
|
|
783
|
+
}
|
|
784
|
+
const tail = hourRangeWindowTail(ir, opts);
|
|
785
|
+
const joiner = subMinuteSecond(ir) ? " " : ", ";
|
|
786
|
+
return hourCadenceLead(ir, minute, opts) + joiner + tail + trailingQualifier(ir, opts);
|
|
787
|
+
}
|
|
567
788
|
function kloList(hours, opts) {
|
|
568
789
|
if (hours.length === 1) {
|
|
569
790
|
return timeWord(hours[0], 0, null, opts);
|
|
@@ -580,12 +801,16 @@ function kloFromTimes(ir, times, opts) {
|
|
|
580
801
|
}
|
|
581
802
|
function hourWindowsFromTimes(ir, times, opts) {
|
|
582
803
|
if (times.kind === "fires") {
|
|
583
|
-
return
|
|
584
|
-
|
|
585
|
-
|
|
804
|
+
return kloList(times.fires, opts);
|
|
805
|
+
}
|
|
806
|
+
const segments = ir.analyses.segments.hour;
|
|
807
|
+
if (!segments.some(function ranged(segment) {
|
|
808
|
+
return segment.kind === "range";
|
|
809
|
+
})) {
|
|
810
|
+
return kloList(hourSegmentFires(segments), opts);
|
|
586
811
|
}
|
|
587
812
|
const pieces = [];
|
|
588
|
-
|
|
813
|
+
segments.forEach(function window(segment) {
|
|
589
814
|
if (segment.kind === "range") {
|
|
590
815
|
pieces.push(rangeDigits(
|
|
591
816
|
{ hour: +segment.bounds[0], minute: 0 },
|
|
@@ -602,6 +827,17 @@ function hourWindowsFromTimes(ir, times, opts) {
|
|
|
602
827
|
});
|
|
603
828
|
return "klo " + joinList(pieces);
|
|
604
829
|
}
|
|
830
|
+
function hourSegmentFires(segments) {
|
|
831
|
+
const hours = [];
|
|
832
|
+
segments.forEach(function each(segment) {
|
|
833
|
+
if (segment.kind === "step") {
|
|
834
|
+
hours.push(...segment.fires);
|
|
835
|
+
} else if (segment.kind === "single") {
|
|
836
|
+
hours.push(+segment.value);
|
|
837
|
+
}
|
|
838
|
+
});
|
|
839
|
+
return hours;
|
|
840
|
+
}
|
|
605
841
|
function hourWindowDigits(hour, opts) {
|
|
606
842
|
return rangeDigits({ hour, minute: 0 }, { hour, minute: 59 }, opts);
|
|
607
843
|
}
|