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/en.js CHANGED
@@ -1,3 +1,23 @@
1
+ // src/core/util.ts
2
+ function arithmeticStep(values) {
3
+ if (values.length < 5) {
4
+ return null;
5
+ }
6
+ const interval = values[1] - values[0];
7
+ if (interval < 2) {
8
+ return null;
9
+ }
10
+ for (let i = 2; i < values.length; i += 1) {
11
+ if (values[i] - values[i - 1] !== interval) {
12
+ return null;
13
+ }
14
+ }
15
+ return { start: values[0], interval, last: values[values.length - 1] };
16
+ }
17
+
18
+ // src/core/specs.ts
19
+ var maxClockTimes = 6;
20
+
1
21
  // src/core/format.ts
2
22
  function pad(n) {
3
23
  n = "" + n;
@@ -105,20 +125,6 @@ var weekdayNames = [
105
125
  ["Friday", "Fri"],
106
126
  ["Saturday", "Sat"]
107
127
  ];
108
- var monthAbbreviations = {
109
- JAN: monthNames[1],
110
- FEB: monthNames[2],
111
- MAR: monthNames[3],
112
- APR: monthNames[4],
113
- MAY: monthNames[5],
114
- JUN: monthNames[6],
115
- JUL: monthNames[7],
116
- AUG: monthNames[8],
117
- SEP: monthNames[9],
118
- OCT: monthNames[10],
119
- NOV: monthNames[11],
120
- DEC: monthNames[12]
121
- };
122
128
  var weekdayAbbreviations = {
123
129
  SUN: weekdayNames[0],
124
130
  MON: weekdayNames[1],
@@ -167,10 +173,50 @@ function renderSecondsWithinMinute(ir, plan, opts) {
167
173
  }
168
174
  return secondsLeadClause(ir, opts) + ", " + minuteWord + " " + minuteUnit + " past the hour, every hour" + trailingQualifier(ir, opts);
169
175
  }
176
+ function composeHourCadence(ir, plan, opts) {
177
+ const clockRest = plan.rest.kind === "clockTimes" || plan.rest.kind === "compactClockTimes";
178
+ return clockRest && ir.shapes.minute === "single" ? hourCadence(ir, +ir.pattern.minute, opts) : null;
179
+ }
170
180
  function renderComposeSeconds(ir, plan, opts) {
181
+ const cadence = composeHourCadence(ir, plan, opts);
182
+ if (cadence !== null) {
183
+ return cadence;
184
+ }
185
+ if (plan.rest.kind === "clockTimes" && (ir.shapes.second === "wildcard" || ir.shapes.second === "step")) {
186
+ const minute = plan.rest.times[0].minute;
187
+ if (+minute === 0) {
188
+ return secondsLeadClause(ir, opts) + " for one minute at " + durationHours(ir, plan.rest, opts);
189
+ }
190
+ return secondsLeadClause(ir, opts) + " of " + clockTimesOf(ir, plan.rest, opts);
191
+ }
192
+ if (ir.shapes.second === "wildcard" && plan.rest.kind === "minuteFrequency" && plan.rest.hours.kind === "none" && ir.pattern.minute === "*/2") {
193
+ return "every second of every other minute" + trailingQualifier(ir, opts);
194
+ }
171
195
  return secondsLeadClause(ir, opts) + ", " + render(ir, plan.rest, opts);
172
196
  }
197
+ function durationHours(ir, plan, opts) {
198
+ const hours = plan.times.map(function clock(time) {
199
+ return getTime({ hour: time.hour, minute: 0 }, opts);
200
+ });
201
+ const trail = dayQualifier(ir, leadingWords, opts);
202
+ return joinList(hours, opts) + (trail && ", " + trail);
203
+ }
204
+ function clockTimesOf(ir, plan, opts) {
205
+ const times = plan.times.map(function clock(time) {
206
+ return getTime({
207
+ hour: time.hour,
208
+ minute: time.minute,
209
+ second: time.second,
210
+ explicit: true
211
+ }, opts);
212
+ });
213
+ const trail = dayQualifier(ir, leadingWords, opts);
214
+ return joinList(times, opts) + (trail && ", " + trail);
215
+ }
173
216
  function secondsLeadClause(ir, opts) {
217
+ return secondsClause(ir, "minute", opts);
218
+ }
219
+ function secondsClause(ir, anchor, opts) {
174
220
  const secondField = ir.pattern.second;
175
221
  const shape = ir.shapes.second;
176
222
  if (secondField === "*") {
@@ -180,22 +226,27 @@ function secondsLeadClause(ir, opts) {
180
226
  return stepCycle60(
181
227
  ir.analyses.segments.second[0],
182
228
  "second",
183
- "minute",
229
+ anchor,
184
230
  opts
185
231
  );
186
232
  }
187
233
  if (shape === "range") {
188
234
  const bounds = secondField.split("-");
189
235
  const num = seriesNumber(bounds, opts);
190
- return "every second from " + num(bounds[0]) + through(opts) + num(bounds[1]) + " past the minute";
236
+ return "every second from " + num(bounds[0]) + through(opts) + num(bounds[1]) + " past the " + anchor;
191
237
  }
192
238
  if (shape === "single") {
193
- return "at " + getNumber(secondField, opts) + " " + pluralize(secondField, "second") + " past the minute";
239
+ return "at " + getNumber(secondField, opts) + " " + pluralize(secondField, "second") + " past the " + anchor;
194
240
  }
195
- return listPastThe(
241
+ return strideFromSegments(
242
+ ir.analyses.segments.second,
243
+ "second",
244
+ anchor,
245
+ opts
246
+ ) ?? listPastThe(
196
247
  segmentWords(ir.analyses.segments.second, opts),
197
248
  "second",
198
- "minute",
249
+ anchor,
199
250
  opts
200
251
  );
201
252
  }
@@ -210,12 +261,11 @@ function renderRangeOfMinutes(ir, plan, opts) {
210
261
  return minuteRangeLead(ir.pattern.minute, opts) + trailingQualifier(ir, opts);
211
262
  }
212
263
  function renderMultipleMinutes(ir, plan, opts) {
213
- return listPastThe(
214
- segmentWords(ir.analyses.segments.minute, opts),
215
- "minute",
216
- "hour",
264
+ const stride = strideFromSegments(ir.analyses.segments.minute, "minute", "hour", opts);
265
+ return (stride ?? listPastThe(segmentWords(
266
+ ir.analyses.segments.minute,
217
267
  opts
218
- ) + trailingQualifier(ir, opts);
268
+ ), "minute", "hour", opts)) + trailingQualifier(ir, opts);
219
269
  }
220
270
  function renderMinuteFrequency(ir, plan, opts) {
221
271
  let phrase = stepCycle60(
@@ -234,6 +284,9 @@ function renderMinuteFrequency(ir, plan, opts) {
234
284
  return phrase + trailingQualifier(ir, opts);
235
285
  }
236
286
  function renderMinuteSpanInHour(ir, plan, opts) {
287
+ if (ir.pattern.minute === "*") {
288
+ return "every minute of the " + getTime({ hour: plan.hour, minute: 0 }, opts) + " hour" + trailingQualifier(ir, opts);
289
+ }
237
290
  return "every minute from " + getTime({ hour: plan.hour, minute: plan.span[0] }, opts) + through(opts) + getTime({ hour: plan.hour, minute: plan.span[1] }, opts) + trailingQualifier(ir, opts);
238
291
  }
239
292
  function renderMinutesAcrossHours(ir, plan, opts) {
@@ -242,8 +295,9 @@ function renderMinutesAcrossHours(ir, plan, opts) {
242
295
  }
243
296
  const times = hourTimesFromPlan(ir, plan.times, true, opts);
244
297
  const lead = plan.form === "range" ? minuteRangeLead(ir.pattern.minute, opts) : (
245
- // The 'list' form is a minute list, which has segments.
246
- listPastThe(
298
+ // The 'list' form is a minute list, which has segments; an offset/uneven
299
+ // step enumerated to that list reads as a stride.
300
+ strideFromSegments(ir.analyses.segments.minute, "minute", "hour", opts) ?? listPastThe(
247
301
  segmentWords(ir.analyses.segments.minute, opts),
248
302
  "minute",
249
303
  "hour",
@@ -270,7 +324,13 @@ function renderMinuteSpanAcrossHourStep(ir, plan, opts) {
270
324
  if (plan.form === "wildcard") {
271
325
  return "every minute " + everyNthHour(segment, opts) + trailingQualifier(ir, opts);
272
326
  }
273
- return minuteRangeLead(ir.pattern.minute, opts) + ", " + stepHours(segment, opts) + trailingQualifier(ir, opts);
327
+ const lead = plan.form === "list" ? strideFromSegments(ir.analyses.segments.minute, "minute", "hour", opts) ?? listPastThe(
328
+ segmentWords(ir.analyses.segments.minute, opts),
329
+ "minute",
330
+ "hour",
331
+ opts
332
+ ) : minuteRangeLead(ir.pattern.minute, opts);
333
+ return lead + ", " + stepHours(segment, opts) + trailingQualifier(ir, opts);
274
334
  }
275
335
  function minuteRangeLead(minuteField, opts) {
276
336
  const bounds = minuteField.split("-");
@@ -294,7 +354,12 @@ function rangeMinuteLead(ir, opts) {
294
354
  if (ir.pattern.minute === "0") {
295
355
  return "every hour";
296
356
  }
297
- return listPastThe(
357
+ return strideFromSegments(
358
+ ir.analyses.segments.minute,
359
+ "minute",
360
+ "hour",
361
+ opts
362
+ ) ?? listPastThe(
298
363
  segmentWords(ir.analyses.segments.minute, opts),
299
364
  "minute",
300
365
  "hour",
@@ -311,6 +376,12 @@ function hourWindow(window, opts) {
311
376
  return "from " + getTime({ hour: window.from, minute: 0 }, opts) + through(opts) + getTime({ hour: window.to, minute: window.last }, opts);
312
377
  }
313
378
  function renderClockTimes(ir, plan, opts) {
379
+ if (ir.shapes.minute === "single") {
380
+ const cadence = hourCadence(ir, +ir.pattern.minute, opts);
381
+ if (cadence !== null) {
382
+ return cadence;
383
+ }
384
+ }
314
385
  const plain = mixedTwelve(plan.times);
315
386
  const times = plan.times.map(function clock(time) {
316
387
  return getTime({
@@ -324,6 +395,10 @@ function renderClockTimes(ir, plan, opts) {
324
395
  }
325
396
  function renderCompactClockTimes(ir, plan, opts) {
326
397
  if (plan.fold) {
398
+ const cadence = hourCadence(ir, +plan.minute, opts);
399
+ if (cadence !== null) {
400
+ return cadence;
401
+ }
327
402
  const hasRange = ir.analyses.segments.hour.some(function range(segment) {
328
403
  return segment.kind === "range";
329
404
  });
@@ -334,13 +409,14 @@ function renderCompactClockTimes(ir, plan, opts) {
334
409
  return interpretDayQualifier(ir, opts) + "at " + hourSegmentTimes(ir, fold, true, opts);
335
410
  }
336
411
  const phrase = (
337
- // The non-fold branch is a minute list, which has segments.
338
- listPastThe(
412
+ // The non-fold branch is a minute list, which has segments. An
413
+ // offset/uneven step enumerated to that list reads as a stride.
414
+ (strideFromSegments(ir.analyses.segments.minute, "minute", "hour", opts) ?? listPastThe(
339
415
  segmentWords(ir.analyses.segments.minute, opts),
340
416
  "minute",
341
417
  "hour",
342
418
  opts
343
- ) + ", at " + hourSegmentTimes(ir, { minute: 0, second: null }, true, opts) + trailingQualifier(ir, opts)
419
+ )) + ", at " + hourSegmentTimes(ir, { minute: 0, second: null }, true, opts) + trailingQualifier(ir, opts)
344
420
  );
345
421
  return ir.analyses.clockSecond ? secondsLeadClause(ir, opts) + ", " + phrase : phrase;
346
422
  }
@@ -388,24 +464,50 @@ var renderers = {
388
464
  singleMinute: renderSingleMinute,
389
465
  standaloneSeconds: renderStandaloneSeconds
390
466
  };
467
+ function renderStride(stride, opts) {
468
+ const { interval, start, last, cycle, unit, anchor } = stride;
469
+ const cadence = "every " + getNumber(interval, opts) + " " + unit + "s";
470
+ const tiles = cycle % interval === 0;
471
+ if (start === 0 && tiles) {
472
+ return cadence;
473
+ }
474
+ if (start < interval && tiles) {
475
+ return cadence + " from " + getNumber(start, opts) + " " + pluralize(start, unit) + " past the " + anchor;
476
+ }
477
+ const num = seriesNumber([start, last], opts);
478
+ return cadence + " from " + num(start) + through(opts) + num(last) + " " + pluralize(last, unit) + " past the " + anchor;
479
+ }
480
+ function singleValues(segments) {
481
+ const values = [];
482
+ for (const segment of segments) {
483
+ if (segment.kind !== "single") {
484
+ return null;
485
+ }
486
+ values.push(+segment.value);
487
+ }
488
+ return values;
489
+ }
490
+ function strideFromSegments(segments, unit, anchor, opts) {
491
+ const values = singleValues(segments);
492
+ const step = values && arithmeticStep(values);
493
+ return step ? renderStride({ ...step, cycle: 60, unit, anchor }, opts) : null;
494
+ }
391
495
  function stepCycle60(segment, unit, anchor, opts) {
392
496
  if (segment.startToken.indexOf("-") !== -1) {
393
497
  return listPastThe(numberWords(segment.fires, opts), unit, anchor, opts);
394
498
  }
395
499
  const start = segment.startToken === "*" ? 0 : +segment.startToken;
396
- const interval = segment.interval;
397
- if (start !== 0) {
398
- if (segment.fires.length <= 3) {
399
- return listPastThe(
400
- numberWords(segment.fires, opts),
401
- unit,
402
- anchor,
403
- opts
404
- );
405
- }
406
- return "every " + getNumber(interval, opts) + " " + unit + "s from " + getNumber(start, opts) + " " + pluralize(start, unit) + " past the " + anchor;
500
+ if (start !== 0 && segment.fires.length <= 3) {
501
+ return listPastThe(numberWords(segment.fires, opts), unit, anchor, opts);
407
502
  }
408
- return "every " + getNumber(interval, opts) + " " + unit + "s";
503
+ return renderStride({
504
+ interval: segment.interval,
505
+ start,
506
+ last: segment.fires[segment.fires.length - 1],
507
+ cycle: 60,
508
+ unit,
509
+ anchor
510
+ }, opts);
409
511
  }
410
512
  function stepHours(segment, opts) {
411
513
  if (segment.startToken.indexOf("-") !== -1) {
@@ -421,6 +523,68 @@ function stepHours(segment, opts) {
421
523
  }
422
524
  return "every " + getNumber(interval, opts) + " hours from " + getTime({ hour: start, minute: 0 }, opts);
423
525
  }
526
+ function hourStrideCadence(stride, opts) {
527
+ const { start, interval, last } = stride;
528
+ const cadence = "every " + getNumber(interval, opts) + " hours";
529
+ const tiles = 24 % interval === 0;
530
+ if (start === 0 && tiles) {
531
+ return cadence;
532
+ }
533
+ if (start < interval && tiles) {
534
+ return cadence + " from " + getTime({ hour: start, minute: 0 }, opts);
535
+ }
536
+ return cadence + " from " + getTime({ hour: start, minute: 0 }, opts) + through(opts) + getTime({ hour: last, minute: 0 }, opts);
537
+ }
538
+ function hourStride(ir) {
539
+ const segments = ir.analyses.segments.hour;
540
+ if (segments.length === 1 && segments[0].kind === "step") {
541
+ const segment = segments[0];
542
+ const start = segment.startToken === "*" ? 0 : +segment.startToken.split("-")[0];
543
+ return { interval: segment.interval, last: segment.fires[segment.fires.length - 1], start };
544
+ }
545
+ const values = singleValues(segments);
546
+ const step = values && arithmeticStep(values);
547
+ return step || null;
548
+ }
549
+ function subMinuteSecond(ir) {
550
+ return ir.pattern.second === "*" || ir.shapes.second === "step";
551
+ }
552
+ function hourCadenceLead(ir, minute, opts) {
553
+ if (minute === 0) {
554
+ if (subMinuteSecond(ir)) {
555
+ return secondsClause(ir, "minute", opts) + " for one minute";
556
+ }
557
+ return secondsClause(ir, "hour", opts);
558
+ }
559
+ const minutePhrase = getNumber(minute, opts) + " " + pluralize(minute, "minute") + " past the hour";
560
+ if (ir.pattern.second === "0") {
561
+ return minutePhrase;
562
+ }
563
+ return secondsClause(ir, "minute", opts) + ", " + minutePhrase;
564
+ }
565
+ function hourCadence(ir, minute, opts) {
566
+ const stride = hourStride(ir);
567
+ if (!stride) {
568
+ return null;
569
+ }
570
+ const fires = (stride.last - stride.start) / stride.interval + 1;
571
+ if (ir.pattern.second === "0" && fires <= maxClockTimes) {
572
+ return null;
573
+ }
574
+ const confinement = minute === 0 && subMinuteSecond(ir) && cleanStrideSegment(ir);
575
+ if (confinement) {
576
+ return secondsClause(ir, "minute", opts) + " for one minute " + everyNthHour(confinement, opts) + trailingQualifier(ir, opts);
577
+ }
578
+ return hourCadenceLead(ir, minute, opts) + ", " + hourStrideCadence(stride, opts) + trailingQualifier(ir, opts);
579
+ }
580
+ function cleanStrideSegment(ir) {
581
+ const segments = ir.analyses.segments.hour;
582
+ const segment = segments.length === 1 && segments[0];
583
+ if (!segment || segment.kind !== "step" || segment.startToken.indexOf("-") !== -1 || !(segment.interval in stepOrdinals)) {
584
+ return null;
585
+ }
586
+ return segment;
587
+ }
424
588
  function seriesNumber(values, opts) {
425
589
  const anyBig = values.some(function big(v) {
426
590
  return +v > 10;
@@ -732,7 +896,7 @@ function stepYears(yearField, opts) {
732
896
  return phrase;
733
897
  }
734
898
  function getTime(time, opts) {
735
- const { hour, minute, plain } = time;
899
+ const { hour, minute, plain, explicit } = time;
736
900
  const second = typeof time.second === "number" && time.second > 0 ? time.second : 0;
737
901
  if (!opts.ampm) {
738
902
  return clockDigits({
@@ -741,12 +905,12 @@ function getTime(time, opts) {
741
905
  second
742
906
  }, { pad: true, sep: opts.style.sep });
743
907
  }
744
- return twelveHourTime({ hour, minute, second, plain }, opts);
908
+ return twelveHourTime({ hour, minute, second, plain, explicit }, opts);
745
909
  }
746
910
  function twelveHourTime(time, opts) {
747
- const { hour, minute, second, plain } = time;
911
+ const { hour, minute, second, plain, explicit } = time;
748
912
  const style = opts.style;
749
- if (!plain && +minute === 0 && !second) {
913
+ if (!plain && !explicit && +minute === 0 && !second) {
750
914
  if (+hour === 0) {
751
915
  return style.midnight;
752
916
  }
@@ -756,7 +920,7 @@ function twelveHourTime(time, opts) {
756
920
  }
757
921
  const digits = clockDigits(
758
922
  { hour: hour % 12 || 12, minute, second },
759
- { lean: true, sep: style.sep }
923
+ { lean: !explicit, sep: style.sep }
760
924
  );
761
925
  return digits + (style.closeUp ? "" : " ") + (hour < 12 ? style.am : style.pm);
762
926
  }
@@ -779,7 +943,7 @@ function getOrdinal(n) {
779
943
  return n + suffix;
780
944
  }
781
945
  function getMonth(m, opts) {
782
- const month = monthNames[m] || monthAbbreviations[m];
946
+ const month = monthNames[+m];
783
947
  return month && month[opts.short ? 1 : 0];
784
948
  }
785
949
  function getWeekday(d, opts) {
@@ -792,7 +956,9 @@ var en = {
792
956
  fallback: "an unrecognizable cron pattern",
793
957
  options: normalizeOptions,
794
958
  reboot: "at system startup",
795
- sentence: (description) => "Runs " + description + "."
959
+ // A description ending in an abbreviation already carries its period
960
+ // ("…9 a.m."), so closing the sentence must not double it.
961
+ sentence: (description) => "Runs " + description + (description.endsWith(".") ? "" : ".")
796
962
  };
797
963
  var index_default = en;
798
964
  export {