cronli5 0.1.2 → 0.1.5

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/dist/lang/fi.cjs CHANGED
@@ -40,6 +40,42 @@ function clockDigits(time, { sep, pad: padHour, lean }) {
40
40
  return head + sep + pad(time.minute) + (time.second ? sep + pad(time.second) : "");
41
41
  }
42
42
 
43
+ // src/core/specs.ts
44
+ var weekdayNumbers = {
45
+ SUN: 0,
46
+ MON: 1,
47
+ TUE: 2,
48
+ WED: 3,
49
+ THU: 4,
50
+ FRI: 5,
51
+ SAT: 6
52
+ };
53
+ var maxClockTimes = 6;
54
+
55
+ // src/core/util.ts
56
+ function isNonNegativeInteger(value) {
57
+ const digits = /^\d+$/;
58
+ return digits.test(value);
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
+ }
75
+ function toFieldNumber(token, numberMap) {
76
+ return isNonNegativeInteger(token) ? +token : numberMap[token.toUpperCase()];
77
+ }
78
+
43
79
  // src/lang/fi/dialects.ts
44
80
  var dialects = {
45
81
  fi: {
@@ -166,40 +202,19 @@ var monthStems = [
166
202
  "marras",
167
203
  "joulu"
168
204
  ];
169
- var monthTokens = {
170
- JAN: 1,
171
- FEB: 2,
172
- MAR: 3,
173
- APR: 4,
174
- MAY: 5,
175
- JUN: 6,
176
- JUL: 7,
177
- AUG: 8,
178
- SEP: 9,
179
- OCT: 10,
180
- NOV: 11,
181
- DEC: 12
182
- };
183
- var weekdayTokens = {
184
- SUN: 0,
185
- MON: 1,
186
- TUE: 2,
187
- WED: 3,
188
- THU: 4,
189
- FRI: 5,
190
- SAT: 6
191
- };
192
205
  var units = {
193
206
  minute: {
194
207
  mark: "joka tunti",
195
208
  anchor: "jokaisen tunnin",
196
209
  ela: "minuutista",
210
+ ill: "minuuttiin",
197
211
  gen: "minuutin"
198
212
  },
199
213
  second: {
200
214
  mark: "joka minuutti",
201
215
  anchor: "jokaisen minuutin",
202
216
  ela: "sekunnista",
217
+ ill: "sekuntiin",
203
218
  gen: "sekunnin"
204
219
  }
205
220
  };
@@ -255,26 +270,61 @@ function renderSecondsWithinMinute(ir, plan, opts) {
255
270
  }
256
271
  return secondsLeadClause(ir, opts) + ", " + atMarks(minuteField, units.minute, true) + trailingQualifier(ir, opts);
257
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
+ return clockRest && ir.shapes.minute === "single" ? hourCadence(ir, +ir.pattern.minute, opts) : null;
293
+ }
258
294
  function renderComposeSeconds(ir, plan, opts) {
295
+ const cadence = composeHourCadence(ir, plan, opts);
296
+ if (cadence !== null) {
297
+ return cadence;
298
+ }
259
299
  if (plan.rest.kind === "minuteFrequency" && ir.pattern.second !== "*") {
260
- const freq = plan.rest;
261
- const seg = stepSegment(ir.analyses.segments.minute);
262
- const stepPhrase = stepCycle60(seg, units.minute, opts);
263
- let hourClause = "";
264
- if (freq.hours.kind === "during" && minuteStepIsAnchored(seg)) {
265
- const bareHours = kloFromTimes(ir, freq.hours.times, opts);
266
- return hoursFirstMinutes(bareHours, ir) + ", " + secondsLeadClause(ir, opts) + trailingQualifier(ir, opts);
267
- } else if (freq.hours.kind === "during" && !minuteStepIsAnchored(seg)) {
268
- hourClause = " " + hourWindowsFromTimes(ir, freq.hours.times, opts);
269
- } else if (freq.hours.kind === "window") {
270
- hourClause = " " + hourWindow(freq.hours, opts);
271
- } else if (freq.hours.kind === "step") {
272
- hourClause = " " + everyNthHour(stepSegment(ir.analyses.segments.hour), opts);
273
- }
274
- return stepPhrase + ", " + secondsLeadClause(ir, opts) + hourClause + trailingQualifier(ir, opts);
300
+ return composeSecondsOverMinuteStep(ir, plan.rest, opts);
301
+ }
302
+ if (plan.rest.kind === "clockTimes" && plan.rest.times.every((time) => +time.minute === 0)) {
303
+ return composeMinuteZero(ir, plan.rest, opts);
304
+ }
305
+ if (isEveryOtherMinuteSeconds(ir, plan)) {
306
+ return secondsLeadClause(ir, opts) + " joka toisena minuuttina";
275
307
  }
276
308
  return secondsLeadClause(ir, opts) + ", " + render(ir, plan.rest, opts);
277
309
  }
310
+ function isEveryOtherMinuteSeconds(ir, plan) {
311
+ if (plan.rest.kind !== "minuteFrequency" || ir.pattern.second !== "*" || ir.shapes.hour !== "wildcard") {
312
+ return false;
313
+ }
314
+ const seg = stepSegment(ir.analyses.segments.minute);
315
+ return seg.startToken === "*" && seg.interval === 2;
316
+ }
317
+ function composeMinuteZero(ir, rest, opts) {
318
+ const clocks = rest.times.map(function clock(time) {
319
+ return clockDigits(
320
+ { hour: time.hour, minute: time.minute },
321
+ { sep: opts.style.sep }
322
+ );
323
+ });
324
+ const frame = clocks.length === 1 ? "minuutin " + clocks[0] : "minuuttien " + joinList(clocks);
325
+ const dayTrail = leadingQualifier(ir, opts).trimEnd();
326
+ return secondsLeadClause(ir, opts) + " " + frame + " aikana" + (dayTrail ? ", " + dayTrail : "");
327
+ }
278
328
  function secondsLeadClause(ir, opts) {
279
329
  const secondField = ir.pattern.second;
280
330
  const shape = ir.shapes.second;
@@ -292,7 +342,7 @@ function secondsLeadClause(ir, opts) {
292
342
  if (shape === "single") {
293
343
  return atMarks(secondField, units.second, marked);
294
344
  }
295
- return atMarks(
345
+ return strideFromSegments(ir.analyses.segments.second, units.second, opts) ?? atMarks(
296
346
  joinList(segmentWords(ir.analyses.segments.second)),
297
347
  units.second,
298
348
  marked
@@ -305,20 +355,20 @@ function renderSingleMinute(ir, plan, opts) {
305
355
  return atMarks(ir.pattern.minute, units.minute, true) + trailingQualifier(ir, opts);
306
356
  }
307
357
  function renderRangeOfMinutes(ir, plan, opts) {
308
- return minutesList(ir) + trailingQualifier(ir, opts);
358
+ return minutesList(ir, opts) + trailingQualifier(ir, opts);
309
359
  }
310
360
  function renderMultipleMinutes(ir, plan, opts) {
311
- return minutesList(ir) + trailingQualifier(ir, opts);
361
+ return minutesList(ir, opts) + trailingQualifier(ir, opts);
312
362
  }
313
- function minutesList(ir) {
314
- return atMarks(
363
+ function minutesList(ir, opts) {
364
+ return strideFromSegments(ir.analyses.segments.minute, units.minute, opts) ?? atMarks(
315
365
  joinList(segmentWords(ir.analyses.segments.minute)),
316
366
  units.minute,
317
367
  true
318
368
  );
319
369
  }
320
- function bareMinutes(ir) {
321
- return atMarks(
370
+ function bareMinutes(ir, opts) {
371
+ return strideFromSegments(ir.analyses.segments.minute, units.minute, opts) ?? atMarks(
322
372
  joinList(segmentWords(ir.analyses.segments.minute)),
323
373
  units.minute,
324
374
  false
@@ -349,7 +399,11 @@ function hoursAreRangeIsolated(segments) {
349
399
  }
350
400
  return hasRange && hasSingle;
351
401
  }
352
- function hoursFirstMinutes(hoursStr, ir) {
402
+ function hoursFirstMinutes(hoursStr, ir, opts) {
403
+ const stride = strideFromSegments(ir.analyses.segments.minute, units.minute, opts);
404
+ if (stride) {
405
+ return hoursStr + " aina " + stride;
406
+ }
353
407
  return hoursStr + " aina minuuttien " + joinList(segmentWords(ir.analyses.segments.minute)) + " kohdalla";
354
408
  }
355
409
  function hourSegmentTimesWithSeka(ir, minute, second, opts) {
@@ -372,7 +426,7 @@ function renderMinuteFrequency(ir, plan, opts) {
372
426
  if (plan.hours.kind === "during") {
373
427
  if (minuteStepIsAnchored(seg)) {
374
428
  const bareHours = kloFromTimes(ir, plan.hours.times, opts);
375
- return hoursFirstMinutes(bareHours, ir) + trailingQualifier(ir, opts);
429
+ return hoursFirstMinutes(bareHours, ir, opts) + trailingQualifier(ir, opts);
376
430
  }
377
431
  return stepCycle60(seg, units.minute, opts) + " " + hourWindowsFromTimes(ir, plan.hours.times, opts) + trailingQualifier(ir, opts);
378
432
  }
@@ -385,6 +439,9 @@ function renderMinuteFrequency(ir, plan, opts) {
385
439
  return phrase + trailingQualifier(ir, opts);
386
440
  }
387
441
  function renderMinuteSpanInHour(ir, plan, opts) {
442
+ if (ir.pattern.minute === "*") {
443
+ return "joka minuutti kello " + plan.hour + " aikana" + trailingQualifier(ir, opts);
444
+ }
388
445
  return "joka minuutti " + kloRange(
389
446
  { hour: plan.hour, minute: plan.span[0] },
390
447
  { hour: plan.hour, minute: plan.span[1] },
@@ -396,10 +453,10 @@ function renderMinutesAcrossHours(ir, plan, opts) {
396
453
  return "joka minuutti " + hourWindowsFromTimes(ir, plan.times, opts) + trailingQualifier(ir, opts);
397
454
  }
398
455
  if (hoursAreRangeIsolated(ir.analyses.segments.hour)) {
399
- return bareMinutes(ir) + " " + hourSegmentTimesWithSeka(ir, 0, null, opts) + trailingQualifier(ir, opts);
456
+ return bareMinutes(ir, opts) + " " + hourSegmentTimesWithSeka(ir, 0, null, opts) + trailingQualifier(ir, opts);
400
457
  }
401
458
  const hoursStr = kloFromTimes(ir, plan.times, opts);
402
- return hoursFirstMinutes(hoursStr, ir) + trailingQualifier(ir, opts);
459
+ return hoursFirstMinutes(hoursStr, ir, opts) + trailingQualifier(ir, opts);
403
460
  }
404
461
  function renderMinuteSpanAcrossHourStep(ir, plan, opts) {
405
462
  const segment = stepSegment(ir.analyses.segments.hour);
@@ -408,9 +465,9 @@ function renderMinuteSpanAcrossHourStep(ir, plan, opts) {
408
465
  }
409
466
  if (segment.startToken.indexOf("-") !== -1) {
410
467
  const hoursStr = kloList(segment.fires, opts);
411
- return hoursFirstMinutes(hoursStr, ir) + trailingQualifier(ir, opts);
468
+ return hoursFirstMinutes(hoursStr, ir, opts) + trailingQualifier(ir, opts);
412
469
  }
413
- return bareMinutes(ir) + hourStepTail(segment, opts) + trailingQualifier(ir, opts);
470
+ return bareMinutes(ir, opts) + hourStepTail(segment, opts) + trailingQualifier(ir, opts);
414
471
  }
415
472
  function plainHourStep(segment) {
416
473
  return segment.startToken === "*" && 24 % segment.interval === 0;
@@ -468,7 +525,7 @@ function renderHourRange(ir, plan, opts) {
468
525
  return "joka minuutti " + window + trailingQualifier(ir, opts);
469
526
  }
470
527
  if (plan.minuteForm === "range") {
471
- return hoursFirstMinutes(window, ir) + trailingQualifier(ir, opts);
528
+ return hoursFirstMinutes(window, ir, opts) + trailingQualifier(ir, opts);
472
529
  }
473
530
  if (ir.pattern.minute === "0") {
474
531
  return "joka tunti " + window + trailingQualifier(ir, opts);
@@ -480,7 +537,7 @@ function renderHourRange(ir, plan, opts) {
480
537
  opts
481
538
  ) + trailingQualifier(ir, opts);
482
539
  }
483
- return hoursFirstMinutes(window, ir) + trailingQualifier(ir, opts);
540
+ return hoursFirstMinutes(window, ir, opts) + trailingQualifier(ir, opts);
484
541
  }
485
542
  function renderHourStep(ir, plan, opts) {
486
543
  return stepHours(stepSegment(ir.analyses.segments.hour), opts) + trailingQualifier(ir, opts);
@@ -496,6 +553,12 @@ function hourWindow(window, opts) {
496
553
  );
497
554
  }
498
555
  function renderClockTimes(ir, plan, opts) {
556
+ if (ir.shapes.minute === "single") {
557
+ const cadence = hourCadence(ir, +ir.pattern.minute, opts);
558
+ if (cadence !== null) {
559
+ return cadence;
560
+ }
561
+ }
499
562
  if (plan.times.length === 1) {
500
563
  const time = plan.times[0];
501
564
  return leadingQualifier(ir, opts) + timeWord(time.hour, time.minute, time.second, opts);
@@ -506,6 +569,12 @@ function renderClockTimes(ir, plan, opts) {
506
569
  return leadingQualifier(ir, opts) + "klo " + joinList(digits);
507
570
  }
508
571
  function renderCompactClockTimes(ir, plan, opts) {
572
+ if (plan.fold) {
573
+ const cadence = hourCadence(ir, plan.minute, opts);
574
+ if (cadence !== null) {
575
+ return cadence;
576
+ }
577
+ }
509
578
  const hourSegs = ir.analyses.segments.hour;
510
579
  if (hoursAreRangeIsolated(hourSegs)) {
511
580
  if (plan.fold) {
@@ -516,14 +585,14 @@ function renderCompactClockTimes(ir, plan, opts) {
516
585
  opts
517
586
  );
518
587
  }
519
- const phrase2 = bareMinutes(ir) + " " + hourSegmentTimesWithSeka(ir, 0, null, opts) + trailingQualifier(ir, opts);
588
+ const phrase2 = bareMinutes(ir, opts) + " " + hourSegmentTimesWithSeka(ir, 0, null, opts) + trailingQualifier(ir, opts);
520
589
  return ir.analyses.clockSecond ? secondsLeadClause(ir, opts) + ", " + phrase2 : phrase2;
521
590
  }
522
591
  if (plan.fold) {
523
592
  return leadingQualifier(ir, opts) + hourSegmentTimes(ir, plan.minute, ir.analyses.clockSecond, opts);
524
593
  }
525
594
  const hoursStr = hourSegmentTimes(ir, 0, null, opts);
526
- const phrase = hoursFirstMinutes(hoursStr, ir) + trailingQualifier(ir, opts);
595
+ const phrase = hoursFirstMinutes(hoursStr, ir, opts) + trailingQualifier(ir, opts);
527
596
  return ir.analyses.clockSecond ? secondsLeadClause(ir, opts) + ", " + phrase : phrase;
528
597
  }
529
598
  var renderers = {
@@ -546,20 +615,48 @@ var renderers = {
546
615
  singleMinute: renderSingleMinute,
547
616
  standaloneSeconds: renderStandaloneSeconds
548
617
  };
618
+ function renderStride(stride, opts) {
619
+ const { interval, start, last, cycle, unit } = stride;
620
+ const cadence = genitive(interval, opts) + " " + unit.gen + " v\xE4lein";
621
+ const tiles = cycle % interval === 0;
622
+ if (start === 0 && tiles) {
623
+ return cadence;
624
+ }
625
+ if (start < interval && tiles) {
626
+ return cadence + " " + unit.anchor + " " + unit.ela + " " + start + " alkaen";
627
+ }
628
+ return cadence + " " + unit.ela + " " + start + " " + unit.ill + " " + last;
629
+ }
630
+ function strideFromSegments(segments, unit, opts) {
631
+ const values = singleValues(segments);
632
+ const step = values && arithmeticStep(values);
633
+ return step ? renderStride({ ...step, cycle: 60, unit }, opts) : null;
634
+ }
635
+ function singleValues(segments) {
636
+ const values = [];
637
+ for (const segment of segments) {
638
+ if (segment.kind !== "single") {
639
+ return null;
640
+ }
641
+ values.push(+segment.value);
642
+ }
643
+ return values;
644
+ }
549
645
  function stepCycle60(segment, unit, opts) {
550
646
  if (segment.startToken.indexOf("-") !== -1) {
551
647
  return atMarks(joinList(wordList(segment.fires)), unit, true);
552
648
  }
553
649
  const start = segment.startToken === "*" ? 0 : +segment.startToken;
554
- const interval = segment.interval;
555
- const cadence = genitive(interval, opts) + " " + unit.gen + " v\xE4lein";
556
- if (start !== 0) {
557
- if (segment.fires.length <= 3) {
558
- return atMarks(joinList(wordList(segment.fires)), unit, true);
559
- }
560
- return cadence + " " + unit.anchor + " " + unit.ela + " " + start + " alkaen";
650
+ if (start !== 0 && segment.fires.length <= 3) {
651
+ return atMarks(joinList(wordList(segment.fires)), unit, true);
561
652
  }
562
- return cadence;
653
+ return renderStride({
654
+ interval: segment.interval,
655
+ start,
656
+ last: segment.fires[segment.fires.length - 1],
657
+ cycle: 60,
658
+ unit
659
+ }, opts);
563
660
  }
564
661
  function stepHours(segment, opts) {
565
662
  if (segment.startToken.indexOf("-") !== -1) {
@@ -576,6 +673,71 @@ function stepHours(segment, opts) {
576
673
  }
577
674
  return cadence + " klo " + hourElatives[start] + " alkaen";
578
675
  }
676
+ function hourStrideCadence(stride, opts) {
677
+ const { start, interval, last } = stride;
678
+ const cadence = genitive(interval, opts) + " tunnin v\xE4lein";
679
+ const tiles = 24 % interval === 0;
680
+ if (start === 0 && tiles) {
681
+ return cadence;
682
+ }
683
+ if (start < interval && tiles) {
684
+ return cadence + " klo " + hourElatives[start] + " alkaen";
685
+ }
686
+ return cadence + " " + kloRange({ hour: start, minute: 0 }, { hour: last, minute: 0 }, opts);
687
+ }
688
+ function hourStride(ir) {
689
+ const segments = ir.analyses.segments.hour;
690
+ if (!segments) {
691
+ return null;
692
+ }
693
+ if (segments.length === 1 && segments[0].kind === "step") {
694
+ const segment = segments[0];
695
+ const start = segment.startToken === "*" ? 0 : +segment.startToken.split("-")[0];
696
+ return { interval: segment.interval, last: segment.fires[segment.fires.length - 1], start };
697
+ }
698
+ const values = singleValues(segments);
699
+ const step = values && arithmeticStep(values);
700
+ return step || null;
701
+ }
702
+ function subMinuteSecond(ir) {
703
+ return ir.pattern.second === "*" || ir.shapes.second === "step";
704
+ }
705
+ function hourCadenceLead(ir, minute, opts) {
706
+ if (minute === 0) {
707
+ if (subMinuteSecond(ir)) {
708
+ return secondsLeadClause(ir, opts) + " minuutin ajan";
709
+ }
710
+ return secondsLeadClause(ir, opts);
711
+ }
712
+ const minutePhrase = atMarks(String(minute), units.minute, false);
713
+ if (ir.pattern.second === "0") {
714
+ return minutePhrase;
715
+ }
716
+ return secondsLeadClause(ir, opts) + ", " + minutePhrase;
717
+ }
718
+ function hourCadence(ir, minute, opts) {
719
+ const stride = hourStride(ir);
720
+ if (!stride) {
721
+ return null;
722
+ }
723
+ const fires = (stride.last - stride.start) / stride.interval + 1;
724
+ if (ir.pattern.second === "0" && fires <= maxClockTimes) {
725
+ return null;
726
+ }
727
+ const segment = ir.analyses.segments.hour[0];
728
+ const confined = minute === 0 && subMinuteSecond(ir) && ir.analyses.segments.hour.length === 1 && segment.kind === "step" && cleanHourStride(segment);
729
+ if (confined) {
730
+ return secondsLeadClause(ir, opts) + " minuutin ajan " + everyNthHour(segment, opts) + trailingQualifier(ir, opts);
731
+ }
732
+ return hourCadenceLead(ir, minute, opts) + ", " + hourStrideCadence(stride, opts) + trailingQualifier(ir, opts);
733
+ }
734
+ function cleanHourStride(segment) {
735
+ if (segment.startToken.indexOf("-") !== -1) {
736
+ return false;
737
+ }
738
+ const start = segment.startToken === "*" ? 0 : +segment.startToken;
739
+ return 24 % segment.interval === 0 && start < segment.interval;
740
+ }
579
741
  function kloList(hours, opts) {
580
742
  if (hours.length === 1) {
581
743
  return timeWord(hours[0], 0, null, opts);
@@ -840,13 +1002,10 @@ function quartzWeekdayPhrase(weekdayField) {
840
1002
  }
841
1003
  }
842
1004
  function weekdayNumber(token) {
843
- if (token in weekdayTokens) {
844
- return weekdayTokens[token];
845
- }
846
- return +token % 7;
1005
+ return toFieldNumber("" + token, weekdayNumbers) % 7;
847
1006
  }
848
1007
  function monthNumber(token) {
849
- return monthTokens[token] || +token;
1008
+ return +token;
850
1009
  }
851
1010
  function applyYear(description, ir, opts) {
852
1011
  const yearField = ir.pattern.year;
@@ -928,7 +1087,9 @@ var fi = {
928
1087
  fallback: "tunnistamaton cron-lauseke",
929
1088
  options: normalizeOptions,
930
1089
  reboot: "j\xE4rjestelm\xE4n k\xE4ynnistyess\xE4",
931
- sentence: (description) => "Suoritetaan " + description + "."
1090
+ // A description ending in a period already carries it, so closing the
1091
+ // sentence must not double it.
1092
+ sentence: (description) => "Suoritetaan " + description + (description.endsWith(".") ? "" : ".")
932
1093
  };
933
1094
  var index_default = fi;
934
1095
  module.exports = module.exports.default;