cronli5 0.0.0-beta.6 → 0.1.0

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.
Files changed (98) hide show
  1. package/CHANGELOG.md +276 -0
  2. package/LICENSE.md +2 -2
  3. package/README.md +328 -91
  4. package/cli.js +73 -10
  5. package/cronli5.min.js +3 -0
  6. package/dist/cronli5.cjs +1556 -0
  7. package/dist/cronli5.js +1532 -0
  8. package/dist/lang/de.cjs +546 -0
  9. package/dist/lang/de.js +522 -0
  10. package/dist/lang/en.cjs +830 -0
  11. package/dist/lang/en.js +806 -0
  12. package/dist/lang/es.cjs +1024 -0
  13. package/dist/lang/es.js +1000 -0
  14. package/dist/lang/fi.cjs +942 -0
  15. package/dist/lang/fi.js +918 -0
  16. package/dist/lang/zh.cjs +612 -0
  17. package/dist/lang/zh.js +588 -0
  18. package/package.json +92 -13
  19. package/src/browser.ts +9 -0
  20. package/src/core/analyze.ts +549 -0
  21. package/src/core/format.ts +51 -0
  22. package/src/core/index.ts +28 -0
  23. package/src/core/ir.ts +167 -0
  24. package/src/core/normalize.ts +143 -0
  25. package/src/core/parse.ts +132 -0
  26. package/src/core/shapes.ts +41 -0
  27. package/src/core/specs.ts +93 -0
  28. package/src/core/util.ts +28 -0
  29. package/src/core/validate.ts +170 -0
  30. package/src/cronli5.ts +95 -0
  31. package/src/lang/de/dialects.ts +52 -0
  32. package/src/lang/de/index.ts +820 -0
  33. package/src/lang/de/notes.md +79 -0
  34. package/src/lang/de/status.json +18 -0
  35. package/src/lang/en/dialects.ts +70 -0
  36. package/src/lang/en/index.ts +1290 -0
  37. package/src/lang/en/notes.md +44 -0
  38. package/src/lang/en/status.json +20 -0
  39. package/src/lang/es/dialects.ts +55 -0
  40. package/src/lang/es/index.ts +1737 -0
  41. package/src/lang/es/notes.md +63 -0
  42. package/src/lang/es/status.json +19 -0
  43. package/src/lang/fi/dialects.ts +31 -0
  44. package/src/lang/fi/index.ts +1499 -0
  45. package/src/lang/fi/notes.md +163 -0
  46. package/src/lang/fi/status.json +7 -0
  47. package/src/lang/zh/dialects.ts +27 -0
  48. package/src/lang/zh/index.ts +863 -0
  49. package/src/lang/zh/notes.md +118 -0
  50. package/src/lang/zh/status.json +7 -0
  51. package/src/types.ts +143 -0
  52. package/types/browser.d.ts +2 -0
  53. package/types/core/analyze.d.ts +13 -0
  54. package/types/core/format.d.ts +16 -0
  55. package/types/core/index.d.ts +8 -0
  56. package/types/core/ir.d.ts +185 -0
  57. package/types/core/normalize.d.ts +5 -0
  58. package/types/core/parse.d.ts +5 -0
  59. package/types/core/shapes.d.ts +6 -0
  60. package/types/core/specs.d.ts +27 -0
  61. package/types/core/util.d.ts +7 -0
  62. package/types/core/validate.d.ts +5 -0
  63. package/types/cronli5.d.ts +7 -0
  64. package/types/lang/de/dialects.d.ts +7 -0
  65. package/types/lang/de/index.d.ts +4 -0
  66. package/types/lang/en/dialects.d.ts +4 -0
  67. package/types/lang/en/index.d.ts +3 -0
  68. package/types/lang/es/dialects.d.ts +13 -0
  69. package/types/lang/es/index.d.ts +4 -0
  70. package/types/lang/fi/dialects.d.ts +4 -0
  71. package/types/lang/fi/index.d.ts +3 -0
  72. package/types/lang/zh/dialects.d.ts +6 -0
  73. package/types/lang/zh/index.d.ts +4 -0
  74. package/types/types.d.ts +113 -0
  75. package/.eslintrc.json +0 -217
  76. package/.npmignore +0 -2
  77. package/conli5.min.js +0 -4
  78. package/cronli5.js +0 -559
  79. package/test/.eslintrc.json +0 -10
  80. package/test/bad_input/arrays.js +0 -34
  81. package/test/bad_input/bad-types.js +0 -33
  82. package/test/bad_input/error-types.js +0 -7
  83. package/test/bad_input/objects.js +0 -47
  84. package/test/bad_input/strings.js +0 -10
  85. package/test/baseline/baseline.js +0 -14
  86. package/test/basic/arrays.js +0 -76
  87. package/test/basic/objects.js +0 -70
  88. package/test/basic/strings.js +0 -76
  89. package/test/complex/steps/strings.js +0 -42
  90. package/test/mocha.opts +0 -5
  91. package/test/options/ampm.js +0 -17
  92. package/test/options/seconds.js +0 -0
  93. package/test/options/short.js +0 -27
  94. package/test/options/years.js +0 -0
  95. package/test/runner.js +0 -52
  96. package/test/simple/arrays.js +0 -33
  97. package/test/simple/objects.js +0 -23
  98. package/test/simple/strings.js +0 -33
@@ -0,0 +1,1556 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // src/cronli5.ts
21
+ var cronli5_exports = {};
22
+ __export(cronli5_exports, {
23
+ default: () => cronli5_default
24
+ });
25
+ module.exports = __toCommonJS(cronli5_exports);
26
+
27
+ // src/core/specs.ts
28
+ var weekdayNumbers = {
29
+ SUN: 0,
30
+ MON: 1,
31
+ TUE: 2,
32
+ WED: 3,
33
+ THU: 4,
34
+ FRI: 5,
35
+ SAT: 6
36
+ };
37
+ var monthNumbers = {
38
+ JAN: 1,
39
+ FEB: 2,
40
+ MAR: 3,
41
+ APR: 4,
42
+ MAY: 5,
43
+ JUN: 6,
44
+ JUL: 7,
45
+ AUG: 8,
46
+ SEP: 9,
47
+ OCT: 10,
48
+ NOV: 11,
49
+ DEC: 12
50
+ };
51
+ var fieldSpecs = {
52
+ second: { cyclic: true, max: 59, min: 0, top: 59 },
53
+ minute: { cyclic: true, max: 59, min: 0, top: 59 },
54
+ hour: { cyclic: true, max: 23, min: 0, top: 23 },
55
+ date: { aliases: { "?": "*" }, cyclic: true, max: 31, min: 1, top: 31 },
56
+ month: { cyclic: true, max: 12, min: 1, numbers: monthNumbers, top: 12 },
57
+ weekday: {
58
+ aliases: { "?": "*", L: "6" },
59
+ cyclic: true,
60
+ max: 7,
61
+ min: 0,
62
+ numbers: weekdayNumbers,
63
+ top: 6
64
+ },
65
+ year: { max: 9999, min: 1970 }
66
+ };
67
+ var fieldOrder = [
68
+ "second",
69
+ "minute",
70
+ "hour",
71
+ "date",
72
+ "month",
73
+ "weekday",
74
+ "year"
75
+ ];
76
+ var macros = {
77
+ "@annually": "0 0 1 1 *",
78
+ "@yearly": "0 0 1 1 *",
79
+ "@monthly": "0 0 1 * *",
80
+ "@weekly": "0 0 * * 0",
81
+ "@daily": "0 0 * * *",
82
+ "@midnight": "0 0 * * *",
83
+ "@hourly": "0 * * * *"
84
+ };
85
+ var maxClockTimes = 6;
86
+
87
+ // src/core/util.ts
88
+ function includes(str, sub) {
89
+ return ("" + str).indexOf(sub) !== -1;
90
+ }
91
+ function unique(items) {
92
+ return Array.from(new Set(items));
93
+ }
94
+ function isNonNegativeInteger(value) {
95
+ const digits = /^\d+$/;
96
+ return digits.test(value);
97
+ }
98
+ function toFieldNumber(token, numberMap) {
99
+ return isNonNegativeInteger(token) ? +token : numberMap[token.toUpperCase()];
100
+ }
101
+
102
+ // src/core/validate.ts
103
+ function validateCronPattern(cronPattern) {
104
+ fieldOrder.forEach(function validate(field) {
105
+ validateField(cronPattern[field], fieldSpecs[field], field);
106
+ });
107
+ return cronPattern;
108
+ }
109
+ function validateField(value, spec, field) {
110
+ if (typeof value !== "string" && typeof value !== "number") {
111
+ throwInvalidField(value, field);
112
+ }
113
+ const stringValue = "" + value;
114
+ if (stringValue === "*") {
115
+ return;
116
+ }
117
+ if (field === "date" && isQuartzDate(stringValue) || field === "weekday" && isQuartzWeekday(stringValue, spec)) {
118
+ return;
119
+ }
120
+ stringValue.split(",").forEach(function check(segment) {
121
+ if (!isValidSegment(segment, spec)) {
122
+ throwInvalidField(segment, field);
123
+ }
124
+ });
125
+ }
126
+ function isQuartzDate(value) {
127
+ if (value === "L" || value === "LW" || value === "WL") {
128
+ return true;
129
+ }
130
+ const offset = /^L-(\d{1,2})$/.exec(value);
131
+ if (offset) {
132
+ return +offset[1] >= 1 && +offset[1] <= 30;
133
+ }
134
+ const nearest = /^(\d{1,2})W$|^W(\d{1,2})$/.exec(value);
135
+ if (nearest) {
136
+ const day = +(nearest[1] || nearest[2]);
137
+ return day >= 1 && day <= 31;
138
+ }
139
+ return false;
140
+ }
141
+ function isQuartzWeekday(value, spec) {
142
+ if (/L$/.test(value)) {
143
+ return isValidSingle(value.slice(0, -1), spec);
144
+ }
145
+ const parts = value.split("#");
146
+ if (parts.length === 2) {
147
+ return isValidSingle(parts[0], spec) && /^[1-5]$/.test(parts[1]);
148
+ }
149
+ return false;
150
+ }
151
+ function isValidSegment(segment, spec) {
152
+ if (includes(segment, "/")) {
153
+ return isValidStep(segment, spec);
154
+ }
155
+ if (includes(segment, "-")) {
156
+ return isValidRange(segment, spec);
157
+ }
158
+ return isValidSingle(segment, spec);
159
+ }
160
+ function isValidStep(segment, spec) {
161
+ const parts = segment.split("/");
162
+ if (parts.length !== 2 || !isNonNegativeInteger(parts[1]) || +parts[1] < 1) {
163
+ return false;
164
+ }
165
+ return parts[0] === "*" || isValidSingle(parts[0], spec) || isValidRange(parts[0], spec, true);
166
+ }
167
+ function isValidRange(segment, spec, requireOrdered) {
168
+ const parts = segment.split("-");
169
+ if (parts.length !== 2) {
170
+ return false;
171
+ }
172
+ if (!isValidSingle(parts[0], spec) || !isValidSingle(parts[1], spec)) {
173
+ return false;
174
+ }
175
+ if (spec.cyclic && !requireOrdered) {
176
+ return true;
177
+ }
178
+ return toFieldNumber(parts[0], spec.numbers) <= toFieldNumber(parts[1], spec.numbers);
179
+ }
180
+ function isValidSingle(value, spec) {
181
+ if (value === "*") {
182
+ return false;
183
+ }
184
+ if (isNonNegativeInteger(value)) {
185
+ return +value >= spec.min && +value <= spec.max;
186
+ }
187
+ if (spec.numbers) {
188
+ return value.toUpperCase() in spec.numbers;
189
+ }
190
+ return false;
191
+ }
192
+ function throwInvalidField(value, field) {
193
+ throw new Error('`cronli5` was passed an invalid field value "' + value + '" for the ' + field + " field.");
194
+ }
195
+
196
+ // src/core/normalize.ts
197
+ function applyQuartzAliases(cronPattern) {
198
+ fieldOrder.forEach(function apply(field) {
199
+ const aliases = fieldSpecs[field].aliases;
200
+ const alias = aliases && aliases["" + cronPattern[field]];
201
+ if (alias) {
202
+ cronPattern[field] = alias;
203
+ }
204
+ });
205
+ }
206
+ function normalizeCronPattern(cronPattern) {
207
+ fieldOrder.forEach(function normalize(field) {
208
+ const value = "" + cronPattern[field];
209
+ if (field === "date" && isQuartzDate(value) || field === "weekday" && isQuartzWeekday(value, fieldSpecs[field])) {
210
+ cronPattern[field] = value;
211
+ return;
212
+ }
213
+ cronPattern[field] = normalizeField(value, fieldSpecs[field]);
214
+ });
215
+ return cronPattern;
216
+ }
217
+ function normalizeField(value, spec) {
218
+ const stringValue = "" + value;
219
+ if (stringValue === "*") {
220
+ return stringValue;
221
+ }
222
+ const segments = stringValue.split(",").map(function canonical(segment) {
223
+ return collapseDegenerateRange(
224
+ collapseOnceStep(collapseUnitStep(segment, spec), spec),
225
+ spec
226
+ );
227
+ });
228
+ if (segments.indexOf("*") !== -1) {
229
+ return "*";
230
+ }
231
+ return unique(segments).sort(function ascending(a, b) {
232
+ return firstFire(a, spec) - firstFire(b, spec);
233
+ }).join(",");
234
+ }
235
+ function collapseUnitStep(segment, spec) {
236
+ const parts = segment.split("/");
237
+ if (!spec.cyclic || parts.length !== 2 || +parts[1] !== 1) {
238
+ return segment;
239
+ }
240
+ const start = parts[0];
241
+ if (includes(start, "-")) {
242
+ return start;
243
+ }
244
+ if (start === "*" || toFieldNumber(start, spec.numbers) === spec.min) {
245
+ return "*";
246
+ }
247
+ return start + "-" + spec.top;
248
+ }
249
+ function collapseOnceStep(segment, spec) {
250
+ const parts = segment.split("/");
251
+ if (!spec.cyclic || typeof spec.top !== "number" || parts.length !== 2 || includes(parts[0], "-")) {
252
+ return segment;
253
+ }
254
+ const start = parts[0];
255
+ const first = start === "*" ? spec.min : toFieldNumber(start, spec.numbers);
256
+ if (first + +parts[1] <= spec.top) {
257
+ return segment;
258
+ }
259
+ return start === "*" ? "" + spec.min : start;
260
+ }
261
+ function collapseDegenerateRange(segment, spec) {
262
+ const start = segment.split("/")[0];
263
+ if (!includes(start, "-")) {
264
+ return segment;
265
+ }
266
+ const bounds = start.split("-");
267
+ if (toFieldNumber(bounds[0], spec.numbers) !== toFieldNumber(bounds[1], spec.numbers)) {
268
+ return segment;
269
+ }
270
+ return bounds[0];
271
+ }
272
+ function firstFire(segment, spec) {
273
+ const start = segment.split("/")[0].split("-")[0];
274
+ return start === "*" ? spec.min : toFieldNumber(start, spec.numbers);
275
+ }
276
+
277
+ // src/core/parse.ts
278
+ function parseCronPattern(cronPattern, opts) {
279
+ const isArray = cronPattern instanceof Array;
280
+ const isEmpty = cronPattern === null || typeof cronPattern === "undefined" || cronPattern === "" || isArray && cronPattern.length === 0;
281
+ if (isEmpty) {
282
+ throw new Error(
283
+ "`cronli5` expects a non-empty cron pattern as the first argument."
284
+ );
285
+ }
286
+ if (isArray) {
287
+ return cronifyArray(cronPattern, opts);
288
+ }
289
+ if (typeof cronPattern === "object") {
290
+ return cronifyObject(cronPattern);
291
+ }
292
+ if (typeof cronPattern === "string") {
293
+ return cronifyString(cronPattern, opts);
294
+ }
295
+ throw new Error("`cronli5` was passed an unexpected type.");
296
+ }
297
+ function cronifyArray(cronlikeArray, opts) {
298
+ if (cronlikeArray.length > 7) {
299
+ throw new Error(
300
+ "`cronli5` was passed a cron pattern with more than seven fields."
301
+ );
302
+ }
303
+ if (!opts.seconds && cronlikeArray.length < (opts.years ? 7 : 6)) {
304
+ cronlikeArray.unshift("0");
305
+ }
306
+ return {
307
+ second: cronlikeArray[0] || "0",
308
+ minute: cronlikeArray[1] || "*",
309
+ hour: cronlikeArray[2] || "*",
310
+ date: cronlikeArray[3] || "*",
311
+ month: cronlikeArray[4] || "*",
312
+ weekday: cronlikeArray[5] || "*",
313
+ year: cronlikeArray[6] || "*"
314
+ };
315
+ }
316
+ function cronifyObject(cronable) {
317
+ if (!cronable.second && !cronable.minute && !cronable.hour) {
318
+ throw new Error(
319
+ "`cronli5` expects that any object being interpreted as a cron pattern have at least one of the following properties: `second`, `minute`, or `hour`"
320
+ );
321
+ }
322
+ const hasSecond = typeof cronable.second !== "undefined";
323
+ const hasMinute = typeof cronable.minute !== "undefined";
324
+ const defaultMinute = hasSecond ? "*" : "0";
325
+ const defaultHour = hasSecond || hasMinute ? "*" : "0";
326
+ return {
327
+ second: pick(cronable.second, "0"),
328
+ minute: pick(cronable.minute, defaultMinute),
329
+ hour: pick(cronable.hour, defaultHour),
330
+ date: pick(cronable.date, "*"),
331
+ month: pick(cronable.month, "*"),
332
+ weekday: pick(cronable.weekday, "*"),
333
+ year: pick(cronable.year, "*")
334
+ };
335
+ }
336
+ function pick(value, fallback) {
337
+ return typeof value === "undefined" ? fallback : value;
338
+ }
339
+ function cronifyString(cronString, opts) {
340
+ const cronlikeArray = expandMacro(cronString).split(/\s+/);
341
+ return cronifyArray(cronlikeArray, opts);
342
+ }
343
+ function expandMacro(cronString) {
344
+ const trimmed = cronString.trim();
345
+ if (trimmed.charAt(0) !== "@") {
346
+ return cronString;
347
+ }
348
+ const macro = trimmed.toLowerCase();
349
+ if (Object.hasOwn(macros, macro)) {
350
+ return macros[macro];
351
+ }
352
+ throw new Error("`cronli5` does not recognize the macro `" + trimmed + "`.");
353
+ }
354
+
355
+ // src/core/shapes.ts
356
+ function isSingleValue(field) {
357
+ return field !== "*" && !includes(field, ",") && !includes(field, "-") && !includes(field, "/");
358
+ }
359
+ function isPlainRange(field) {
360
+ return includes(field, "-") && !includes(field, ",") && !includes(field, "/");
361
+ }
362
+ function isPlainStep(field) {
363
+ return includes(field, "/") && !includes(field, ",");
364
+ }
365
+ function isDiscreteList(field) {
366
+ return field !== "*" && !includes(field, "-") && !includes(field, "/");
367
+ }
368
+ function isDiscreteHours(hourField) {
369
+ return hourField !== "*" && !isPlainRange(hourField) && !isPlainStep(hourField);
370
+ }
371
+
372
+ // src/core/analyze.ts
373
+ function getOccurrences(start, interval, max) {
374
+ const occurrences = [];
375
+ let value = start;
376
+ while (value <= max) {
377
+ occurrences.push(value);
378
+ value += interval;
379
+ }
380
+ return occurrences;
381
+ }
382
+ function enumerateStep(field, min, max, numberMap) {
383
+ const parts = field.split("/");
384
+ const interval = +parts[1];
385
+ if (includes(parts[0], "-")) {
386
+ const bounds = parts[0].split("-");
387
+ return getOccurrences(
388
+ toFieldNumber(bounds[0], numberMap),
389
+ interval,
390
+ toFieldNumber(bounds[1], numberMap)
391
+ );
392
+ }
393
+ const start = parts[0] === "*" ? min : toFieldNumber(parts[0], numberMap);
394
+ return getOccurrences(start, interval, max);
395
+ }
396
+ function enumerateFires(field, min, max) {
397
+ const fires = [];
398
+ field.split(",").forEach(function expand(segment) {
399
+ if (includes(segment, "/")) {
400
+ fires.push(...enumerateStep(segment, min, max));
401
+ } else if (includes(segment, "-")) {
402
+ const bounds = segment.split("-");
403
+ if (+bounds[0] <= +bounds[1]) {
404
+ fires.push(...getOccurrences(+bounds[0], 1, +bounds[1]));
405
+ } else {
406
+ fires.push(...getOccurrences(+bounds[0], 1, max));
407
+ fires.push(...getOccurrences(min, 1, +bounds[1]));
408
+ }
409
+ } else {
410
+ fires.push(+segment);
411
+ }
412
+ });
413
+ return unique(fires);
414
+ }
415
+ function enumerateValues(field) {
416
+ if (!isDiscreteList(field)) {
417
+ return [0];
418
+ }
419
+ return field.split(",").map(Number);
420
+ }
421
+ function minuteSpan(minuteField) {
422
+ if (minuteField === "*") {
423
+ return [0, 59];
424
+ }
425
+ if (isPlainRange(minuteField)) {
426
+ const bounds = minuteField.split("-");
427
+ if (+bounds[0] <= +bounds[1]) {
428
+ return [+bounds[0], +bounds[1]];
429
+ }
430
+ }
431
+ return null;
432
+ }
433
+ function lastMinuteFire(minuteField) {
434
+ if (minuteField === "*") {
435
+ return 59;
436
+ }
437
+ return Math.max(...enumerateFires(minuteField, 0, 59));
438
+ }
439
+ function clockSecond(secondField) {
440
+ if (isSingleValue(secondField) && secondField !== "0") {
441
+ return +secondField;
442
+ }
443
+ }
444
+ function fieldShape(value, field) {
445
+ if (value === "*") {
446
+ return "wildcard";
447
+ }
448
+ if (field === "date" && isQuartzDate(value) || field === "weekday" && isQuartzWeekday(value, fieldSpecs.weekday)) {
449
+ return "quartz";
450
+ }
451
+ if (includes(value, ",")) {
452
+ return "list";
453
+ }
454
+ if (includes(value, "/")) {
455
+ return "step";
456
+ }
457
+ if (includes(value, "-")) {
458
+ return "range";
459
+ }
460
+ return "single";
461
+ }
462
+ function fieldSegments(value, shape, spec) {
463
+ if (shape === "wildcard" || shape === "quartz") {
464
+ return null;
465
+ }
466
+ return value.split(",").map(function classify(segment) {
467
+ if (includes(segment, "/")) {
468
+ const parts = segment.split("/");
469
+ return {
470
+ // Only the named/cyclic fields are segmented this way; `top` is
471
+ // always present for them (year has no segmentable step form).
472
+ fires: enumerateStep(
473
+ segment,
474
+ spec.min,
475
+ spec.top,
476
+ spec.numbers
477
+ ),
478
+ interval: +parts[1],
479
+ kind: "step",
480
+ startToken: parts[0]
481
+ };
482
+ }
483
+ if (includes(segment, "-")) {
484
+ return { bounds: segment.split("-"), kind: "range" };
485
+ }
486
+ return { kind: "single", value: segment };
487
+ });
488
+ }
489
+ function analyze(pattern) {
490
+ const shapes = {};
491
+ const segments = {};
492
+ fieldOrder.forEach(function classify(field) {
493
+ shapes[field] = fieldShape(pattern[field], field);
494
+ segments[field] = fieldSegments(
495
+ pattern[field],
496
+ shapes[field],
497
+ fieldSpecs[field]
498
+ );
499
+ });
500
+ const analyses = {
501
+ clockSecond: clockSecond(pattern.second),
502
+ lastMinuteFire: lastMinuteFire(pattern.minute),
503
+ minuteSpan: minuteSpan(pattern.minute),
504
+ segments
505
+ };
506
+ const content = { analyses, pattern, shapes };
507
+ return { ...content, plan: selectStrategy(content) };
508
+ }
509
+ function selectStrategy(content) {
510
+ const { analyses, pattern, shapes } = content;
511
+ if (pattern.second !== "0") {
512
+ const seconds = planSeconds(pattern, shapes, analyses);
513
+ if (seconds) {
514
+ return seconds;
515
+ }
516
+ }
517
+ return planMinutes(pattern, shapes, analyses) || planHours(pattern, shapes, analyses);
518
+ }
519
+ function planSeconds(pattern, shapes, analyses) {
520
+ const standalone = planStandaloneSeconds(pattern, shapes);
521
+ if (standalone) {
522
+ return standalone;
523
+ }
524
+ if (pattern.hour === "*" && shapes.minute === "single" && pattern.second !== "*") {
525
+ return {
526
+ kind: "secondsWithinMinute",
527
+ singleSecond: shapes.second === "single"
528
+ };
529
+ }
530
+ if (shapes.second === "single" && isDiscreteList(pattern.minute) && isDiscreteHours(pattern.hour)) {
531
+ return null;
532
+ }
533
+ return {
534
+ kind: "composeSeconds",
535
+ rest: planMinutes(pattern, shapes, analyses) || planHours(pattern, shapes, analyses)
536
+ };
537
+ }
538
+ function planStandaloneSeconds(pattern, shapes) {
539
+ if (pattern.minute !== "*" || pattern.hour !== "*") {
540
+ return null;
541
+ }
542
+ if (pattern.second === "*") {
543
+ return { kind: "everySecond" };
544
+ }
545
+ if (shapes.second === "single") {
546
+ return { kind: "secondPastMinute" };
547
+ }
548
+ return { kind: "standaloneSeconds" };
549
+ }
550
+ function planMinutes(pattern, shapes, analyses) {
551
+ if (shapes.minute === "step") {
552
+ return {
553
+ hours: planFrequencyHours(pattern, shapes, analyses),
554
+ kind: "minuteFrequency"
555
+ };
556
+ }
557
+ if (shapes.hour === "single" && analyses.minuteSpan) {
558
+ return {
559
+ hour: +pattern.hour,
560
+ kind: "minuteSpanInHour",
561
+ span: analyses.minuteSpan
562
+ };
563
+ }
564
+ const acrossHours = planMinutesAcrossHours(pattern, shapes);
565
+ if (acrossHours) {
566
+ return acrossHours;
567
+ }
568
+ const underStep = planMinuteUnderHourStep(pattern, shapes);
569
+ if (underStep) {
570
+ return underStep;
571
+ }
572
+ if (pattern.hour === "*") {
573
+ return planMinutesUnderOpenHour(pattern, shapes);
574
+ }
575
+ }
576
+ function cleanHourStride(hourField) {
577
+ const [start, step] = hourField.split("/");
578
+ const startHour = start === "*" ? 0 : +start;
579
+ return start.indexOf("-") === -1 && 24 % +step === 0 && startHour < +step;
580
+ }
581
+ function planMinuteUnderHourStep(pattern, shapes) {
582
+ if (shapes.hour !== "step") {
583
+ return null;
584
+ }
585
+ if (pattern.minute === "*") {
586
+ return cleanHourStride(pattern.hour) ? { form: "wildcard", kind: "minuteSpanAcrossHourStep" } : {
587
+ form: "wildcard",
588
+ kind: "minutesAcrossHours",
589
+ times: hourTimesPlan(pattern.hour)
590
+ };
591
+ }
592
+ if (shapes.minute === "range") {
593
+ return { form: "range", kind: "minuteSpanAcrossHourStep" };
594
+ }
595
+ return null;
596
+ }
597
+ function planFrequencyHours(pattern, shapes, analyses) {
598
+ if (shapes.hour === "list") {
599
+ return { kind: "during", times: hourTimesPlan(pattern.hour) };
600
+ }
601
+ if (shapes.hour === "range") {
602
+ const bounds = pattern.hour.split("-");
603
+ return {
604
+ from: +bounds[0],
605
+ kind: "window",
606
+ last: analyses.lastMinuteFire,
607
+ to: +bounds[1]
608
+ };
609
+ }
610
+ if (shapes.hour === "single") {
611
+ return {
612
+ from: +pattern.hour,
613
+ kind: "window",
614
+ last: analyses.lastMinuteFire,
615
+ to: +pattern.hour
616
+ };
617
+ }
618
+ if (shapes.hour === "step") {
619
+ return cleanHourStride(pattern.hour) ? { kind: "step" } : { kind: "during", times: hourTimesPlan(pattern.hour) };
620
+ }
621
+ return { kind: "none" };
622
+ }
623
+ function planMinutesAcrossHours(pattern, shapes) {
624
+ if (!isDiscreteHours(pattern.hour)) {
625
+ return null;
626
+ }
627
+ if (pattern.minute === "*") {
628
+ return {
629
+ form: "wildcard",
630
+ kind: "minutesAcrossHours",
631
+ times: hourTimesPlan(pattern.hour)
632
+ };
633
+ }
634
+ if (shapes.minute === "range" || shapes.minute === "list" && includes(pattern.minute, "-") && !includes(pattern.minute, "/")) {
635
+ return {
636
+ form: shapes.minute === "range" ? "range" : "list",
637
+ kind: "minutesAcrossHours",
638
+ times: hourTimesPlan(pattern.hour)
639
+ };
640
+ }
641
+ return null;
642
+ }
643
+ function planMinutesUnderOpenHour(pattern, shapes) {
644
+ if (shapes.minute === "range") {
645
+ return { kind: "rangeOfMinutes" };
646
+ }
647
+ if (shapes.minute === "list") {
648
+ return { kind: "multipleMinutes" };
649
+ }
650
+ if (pattern.minute === "*") {
651
+ return { kind: "everyMinute" };
652
+ }
653
+ if (pattern.minute !== "0") {
654
+ return { kind: "singleMinute" };
655
+ }
656
+ }
657
+ function planHours(pattern, shapes, analyses) {
658
+ if (shapes.hour === "range") {
659
+ const bounds = pattern.hour.split("-");
660
+ let minuteForm = "lead";
661
+ if (pattern.minute === "*") {
662
+ minuteForm = "wildcard";
663
+ } else if (shapes.minute === "range") {
664
+ minuteForm = "range";
665
+ }
666
+ return {
667
+ from: +bounds[0],
668
+ kind: "hourRange",
669
+ last: analyses.lastMinuteFire,
670
+ minuteForm,
671
+ to: +bounds[1]
672
+ };
673
+ }
674
+ if (shapes.hour === "step" && pattern.minute === "0") {
675
+ return { kind: "hourStep" };
676
+ }
677
+ if (pattern.hour === "*") {
678
+ return { kind: "everyHour" };
679
+ }
680
+ return planClockTimes(pattern, analyses);
681
+ }
682
+ function planClockTimes(pattern, analyses) {
683
+ const hours = enumerateFires(pattern.hour, 0, 23);
684
+ const minutes = enumerateValues(pattern.minute);
685
+ if (hours.length * minutes.length > maxClockTimes) {
686
+ return {
687
+ fold: minutes.length === 1,
688
+ kind: "compactClockTimes",
689
+ minute: minutes[0]
690
+ };
691
+ }
692
+ const times = [];
693
+ hours.forEach(function eachHour(hour) {
694
+ minutes.forEach(function eachMinute(minute) {
695
+ times.push({ hour, minute, second: analyses.clockSecond });
696
+ });
697
+ });
698
+ return { kind: "clockTimes", times };
699
+ }
700
+ function hourTimesPlan(hourField) {
701
+ const fires = enumerateFires(hourField, 0, 23);
702
+ if (fires.length <= maxClockTimes) {
703
+ return { fires, kind: "fires" };
704
+ }
705
+ return { kind: "segments" };
706
+ }
707
+
708
+ // src/core/index.ts
709
+ function prepare(cronPattern, opts) {
710
+ const pattern = parseCronPattern(cronPattern, opts);
711
+ applyQuartzAliases(pattern);
712
+ validateCronPattern(pattern);
713
+ return normalizeCronPattern(pattern);
714
+ }
715
+
716
+ // src/core/format.ts
717
+ function pad(n) {
718
+ n = "" + n;
719
+ return n.length < 2 ? "0" + n : n;
720
+ }
721
+ function numeral(n, words, opts) {
722
+ return opts.short ? n : words[n] || n;
723
+ }
724
+ function clockDigits(time, { sep, pad: padHour, lean }) {
725
+ const head = padHour ? pad(time.hour) : "" + time.hour;
726
+ if (lean && !time.minute && !time.second) {
727
+ return head;
728
+ }
729
+ return head + sep + pad(time.minute) + (time.second ? sep + pad(time.second) : "");
730
+ }
731
+
732
+ // src/lang/en/dialects.ts
733
+ var dialects = {
734
+ gb: {
735
+ am: "am",
736
+ closeUp: true,
737
+ dayFirst: true,
738
+ midday: "midday",
739
+ midnight: "midnight",
740
+ ordinals: false,
741
+ pm: "pm",
742
+ sep: ".",
743
+ serialComma: false,
744
+ through: " to "
745
+ },
746
+ us: {
747
+ am: "a.m.",
748
+ closeUp: false,
749
+ dayFirst: false,
750
+ midday: "noon",
751
+ midnight: "midnight",
752
+ ordinals: false,
753
+ pm: "p.m.",
754
+ sep: ":",
755
+ serialComma: true,
756
+ through: " through "
757
+ },
758
+ house: {
759
+ am: "AM",
760
+ closeUp: false,
761
+ dayFirst: false,
762
+ midday: "noon",
763
+ midnight: "midnight",
764
+ ordinals: true,
765
+ pm: "PM",
766
+ sep: ":",
767
+ serialComma: true,
768
+ through: " - "
769
+ }
770
+ };
771
+ function resolveDialect(dialect) {
772
+ if (typeof dialect === "object" && dialect !== null) {
773
+ return { ...dialects.us, ...dialect };
774
+ }
775
+ const name = dialect === "uk" ? "gb" : dialect;
776
+ return dialects[name] || dialects.us;
777
+ }
778
+
779
+ // src/lang/en/index.ts
780
+ var numbers = [
781
+ "zero",
782
+ "one",
783
+ "two",
784
+ "three",
785
+ "four",
786
+ "five",
787
+ "six",
788
+ "seven",
789
+ "eight",
790
+ "nine",
791
+ "ten"
792
+ ];
793
+ var suffixes = [
794
+ "th",
795
+ "st",
796
+ "nd",
797
+ "rd"
798
+ ];
799
+ var monthNames = [
800
+ null,
801
+ ["January", "Jan"],
802
+ ["February", "Feb"],
803
+ ["March", "Mar"],
804
+ ["April", "Apr"],
805
+ ["May", "May"],
806
+ ["June", "Jun"],
807
+ ["July", "Jul"],
808
+ ["August", "Aug"],
809
+ ["September", "Sep"],
810
+ ["October", "Oct"],
811
+ ["November", "Nov"],
812
+ ["December", "Dec"]
813
+ ];
814
+ var weekdayNames = [
815
+ ["Sunday", "Sun"],
816
+ ["Monday", "Mon"],
817
+ ["Tuesday", "Tue"],
818
+ ["Wednesday", "Wed"],
819
+ ["Thursday", "Thu"],
820
+ ["Friday", "Fri"],
821
+ ["Saturday", "Sat"]
822
+ ];
823
+ var monthAbbreviations = {
824
+ JAN: monthNames[1],
825
+ FEB: monthNames[2],
826
+ MAR: monthNames[3],
827
+ APR: monthNames[4],
828
+ MAY: monthNames[5],
829
+ JUN: monthNames[6],
830
+ JUL: monthNames[7],
831
+ AUG: monthNames[8],
832
+ SEP: monthNames[9],
833
+ OCT: monthNames[10],
834
+ NOV: monthNames[11],
835
+ DEC: monthNames[12]
836
+ };
837
+ var weekdayAbbreviations = {
838
+ SUN: weekdayNames[0],
839
+ MON: weekdayNames[1],
840
+ TUE: weekdayNames[2],
841
+ WED: weekdayNames[3],
842
+ THU: weekdayNames[4],
843
+ FRI: weekdayNames[5],
844
+ SAT: weekdayNames[6]
845
+ };
846
+ var nthWeekdayNames = [null, "first", "second", "third", "fourth", "fifth"];
847
+ function normalizeOptions(options) {
848
+ options = options || {};
849
+ return {
850
+ ampm: typeof options.ampm === "boolean" ? options.ampm : true,
851
+ lenient: !!options.lenient,
852
+ seconds: !!options.seconds,
853
+ short: !!options.short,
854
+ style: resolveDialect(options.dialect),
855
+ years: !!options.years
856
+ };
857
+ }
858
+ function describe(ir, opts) {
859
+ return applyYear(render(ir, ir.plan, opts), ir, opts);
860
+ }
861
+ function render(ir, plan, opts) {
862
+ const renderer = renderers[plan.kind];
863
+ return renderer(ir, plan, opts);
864
+ }
865
+ function renderEverySecond(ir, plan, opts) {
866
+ return "every second" + trailingQualifier(ir, opts);
867
+ }
868
+ function renderStandaloneSeconds(ir, plan, opts) {
869
+ return secondsLeadClause(ir, opts) + trailingQualifier(ir, opts);
870
+ }
871
+ function renderSecondPastMinute(ir, plan, opts) {
872
+ const secondField = ir.pattern.second;
873
+ return getNumber(secondField, opts) + " " + pluralize(secondField, "second") + " past the minute, every minute" + trailingQualifier(ir, opts);
874
+ }
875
+ function renderSecondsWithinMinute(ir, plan, opts) {
876
+ const minuteField = ir.pattern.minute;
877
+ const minuteWord = getNumber(minuteField, opts);
878
+ const minuteUnit = pluralize(minuteField, "minute");
879
+ if (plan.singleSecond) {
880
+ const secondField = ir.pattern.second;
881
+ return minuteWord + " " + minuteUnit + " and " + getNumber(secondField, opts) + " " + pluralize(secondField, "second") + " past the hour, every hour" + trailingQualifier(ir, opts);
882
+ }
883
+ return secondsLeadClause(ir, opts) + ", " + minuteWord + " " + minuteUnit + " past the hour, every hour" + trailingQualifier(ir, opts);
884
+ }
885
+ function renderComposeSeconds(ir, plan, opts) {
886
+ return secondsLeadClause(ir, opts) + ", " + render(ir, plan.rest, opts);
887
+ }
888
+ function secondsLeadClause(ir, opts) {
889
+ const secondField = ir.pattern.second;
890
+ const shape = ir.shapes.second;
891
+ if (secondField === "*") {
892
+ return "every second";
893
+ }
894
+ if (shape === "step") {
895
+ return stepCycle60(
896
+ ir.analyses.segments.second[0],
897
+ "second",
898
+ "minute",
899
+ opts
900
+ );
901
+ }
902
+ if (shape === "range") {
903
+ const bounds = secondField.split("-");
904
+ const num = seriesNumber(bounds, opts);
905
+ return "every second from " + num(bounds[0]) + through(opts) + num(bounds[1]) + " past the minute";
906
+ }
907
+ if (shape === "single") {
908
+ return "at " + getNumber(secondField, opts) + " " + pluralize(secondField, "second") + " past the minute";
909
+ }
910
+ return listPastThe(
911
+ segmentWords(ir.analyses.segments.second, opts),
912
+ "second",
913
+ "minute",
914
+ opts
915
+ );
916
+ }
917
+ function renderEveryMinute(ir, plan, opts) {
918
+ return "every minute" + trailingQualifier(ir, opts);
919
+ }
920
+ function renderSingleMinute(ir, plan, opts) {
921
+ const minuteField = ir.pattern.minute;
922
+ return getNumber(minuteField, opts) + " " + pluralize(minuteField, "minute") + " past the hour, every hour" + trailingQualifier(ir, opts);
923
+ }
924
+ function renderRangeOfMinutes(ir, plan, opts) {
925
+ return minuteRangeLead(ir.pattern.minute, opts) + trailingQualifier(ir, opts);
926
+ }
927
+ function renderMultipleMinutes(ir, plan, opts) {
928
+ return listPastThe(
929
+ segmentWords(ir.analyses.segments.minute, opts),
930
+ "minute",
931
+ "hour",
932
+ opts
933
+ ) + trailingQualifier(ir, opts);
934
+ }
935
+ function renderMinuteFrequency(ir, plan, opts) {
936
+ let phrase = stepCycle60(
937
+ ir.analyses.segments.minute[0],
938
+ "minute",
939
+ "hour",
940
+ opts
941
+ );
942
+ if (plan.hours.kind === "during") {
943
+ phrase += " during the " + hourTimesFromPlan(ir, plan.hours.times, false, opts) + " hours";
944
+ } else if (plan.hours.kind === "window") {
945
+ phrase += " " + hourWindow(plan.hours, opts);
946
+ } else if (plan.hours.kind === "step") {
947
+ phrase += " " + everyNthHour(ir.analyses.segments.hour[0], opts);
948
+ }
949
+ return phrase + trailingQualifier(ir, opts);
950
+ }
951
+ function renderMinuteSpanInHour(ir, plan, opts) {
952
+ 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);
953
+ }
954
+ function renderMinutesAcrossHours(ir, plan, opts) {
955
+ if (plan.form === "wildcard") {
956
+ return "every minute during the " + hourTimesFromPlan(ir, plan.times, false, opts) + " hours" + trailingQualifier(ir, opts);
957
+ }
958
+ const times = hourTimesFromPlan(ir, plan.times, true, opts);
959
+ const lead = plan.form === "range" ? minuteRangeLead(ir.pattern.minute, opts) : (
960
+ // The 'list' form is a minute list, which has segments.
961
+ listPastThe(
962
+ segmentWords(ir.analyses.segments.minute, opts),
963
+ "minute",
964
+ "hour",
965
+ opts
966
+ )
967
+ );
968
+ return lead + ", at " + times + trailingQualifier(ir, opts);
969
+ }
970
+ var stepOrdinals = {
971
+ 2: "other",
972
+ 3: "third",
973
+ 4: "fourth",
974
+ 6: "sixth",
975
+ 8: "eighth",
976
+ 12: "twelfth"
977
+ };
978
+ function everyNthHour(segment, opts) {
979
+ const base = "during every " + stepOrdinals[segment.interval] + " hour";
980
+ const start = segment.startToken === "*" ? 0 : +segment.startToken;
981
+ return start === 0 ? base : base + " starting at " + getTime({ hour: start, minute: 0 }, opts);
982
+ }
983
+ function renderMinuteSpanAcrossHourStep(ir, plan, opts) {
984
+ const segment = ir.analyses.segments.hour[0];
985
+ if (plan.form === "wildcard") {
986
+ return "every minute " + everyNthHour(segment, opts) + trailingQualifier(ir, opts);
987
+ }
988
+ return minuteRangeLead(ir.pattern.minute, opts) + ", " + stepHours(segment, opts) + trailingQualifier(ir, opts);
989
+ }
990
+ function minuteRangeLead(minuteField, opts) {
991
+ const bounds = minuteField.split("-");
992
+ const num = seriesNumber(bounds, opts);
993
+ return "every minute from " + num(bounds[0]) + through(opts) + num(bounds[1]) + " past the hour";
994
+ }
995
+ function renderEveryHour(ir, plan, opts) {
996
+ return "every hour" + trailingQualifier(ir, opts);
997
+ }
998
+ function renderHourRange(ir, plan, opts) {
999
+ const window = hourWindow(plan, opts);
1000
+ if (plan.minuteForm === "wildcard") {
1001
+ return "every minute " + window + trailingQualifier(ir, opts);
1002
+ }
1003
+ if (plan.minuteForm === "range") {
1004
+ return minuteRangeLead(ir.pattern.minute, opts) + ", " + window + trailingQualifier(ir, opts);
1005
+ }
1006
+ return rangeMinuteLead(ir, opts) + " " + window + trailingQualifier(ir, opts);
1007
+ }
1008
+ function rangeMinuteLead(ir, opts) {
1009
+ if (ir.pattern.minute === "0") {
1010
+ return "every hour";
1011
+ }
1012
+ return listPastThe(
1013
+ segmentWords(ir.analyses.segments.minute, opts),
1014
+ "minute",
1015
+ "hour",
1016
+ opts
1017
+ );
1018
+ }
1019
+ function renderHourStep(ir, plan, opts) {
1020
+ return stepHours(ir.analyses.segments.hour[0], opts) + trailingQualifier(ir, opts);
1021
+ }
1022
+ function hourWindow(window, opts) {
1023
+ return "from " + getTime({ hour: window.from, minute: 0 }, opts) + through(opts) + getTime({ hour: window.to, minute: window.last }, opts);
1024
+ }
1025
+ function renderClockTimes(ir, plan, opts) {
1026
+ const plain = mixedTwelve(plan.times);
1027
+ const times = plan.times.map(function clock(time) {
1028
+ return getTime({
1029
+ hour: time.hour,
1030
+ minute: time.minute,
1031
+ second: time.second,
1032
+ plain
1033
+ }, opts);
1034
+ });
1035
+ return interpretDayQualifier(ir, opts) + "at " + joinList(times, opts);
1036
+ }
1037
+ function renderCompactClockTimes(ir, plan, opts) {
1038
+ if (plan.fold) {
1039
+ const hasRange = ir.analyses.segments.hour.some(function range(segment) {
1040
+ return segment.kind === "range";
1041
+ });
1042
+ if (hasRange && !ir.analyses.clockSecond) {
1043
+ return foldedHourWindows(ir, plan, opts) + trailingQualifier(ir, opts);
1044
+ }
1045
+ const fold = { minute: plan.minute, second: ir.analyses.clockSecond };
1046
+ return interpretDayQualifier(ir, opts) + "at " + hourSegmentTimes(ir, fold, true, opts);
1047
+ }
1048
+ const phrase = (
1049
+ // The non-fold branch is a minute list, which has segments.
1050
+ listPastThe(
1051
+ segmentWords(ir.analyses.segments.minute, opts),
1052
+ "minute",
1053
+ "hour",
1054
+ opts
1055
+ ) + ", at " + hourSegmentTimes(ir, { minute: 0, second: null }, true, opts) + trailingQualifier(ir, opts)
1056
+ );
1057
+ return ir.analyses.clockSecond ? secondsLeadClause(ir, opts) + ", " + phrase : phrase;
1058
+ }
1059
+ function foldedHourWindows(ir, plan, opts) {
1060
+ const minute = plan.minute;
1061
+ const windows = [];
1062
+ const singles = [];
1063
+ ir.analyses.segments.hour.forEach(function classify(segment) {
1064
+ if (segment.kind === "range") {
1065
+ windows.push("from " + getTime(
1066
+ { hour: segment.bounds[0], minute: 0 },
1067
+ opts
1068
+ ) + through(opts) + getTime({ hour: segment.bounds[1], minute }, opts));
1069
+ } else if (segment.kind === "step") {
1070
+ singles.push(...segment.fires);
1071
+ } else {
1072
+ singles.push(+segment.value);
1073
+ }
1074
+ });
1075
+ let phrase = rangeMinuteLead(ir, opts) + " " + joinList(windows, opts);
1076
+ if (singles.length) {
1077
+ phrase += " and at " + joinList(singles.map(function time(hour) {
1078
+ return getTime({ hour, minute }, opts);
1079
+ }), opts);
1080
+ }
1081
+ return phrase;
1082
+ }
1083
+ var renderers = {
1084
+ clockTimes: renderClockTimes,
1085
+ compactClockTimes: renderCompactClockTimes,
1086
+ composeSeconds: renderComposeSeconds,
1087
+ everyHour: renderEveryHour,
1088
+ everyMinute: renderEveryMinute,
1089
+ everySecond: renderEverySecond,
1090
+ hourRange: renderHourRange,
1091
+ hourStep: renderHourStep,
1092
+ minuteFrequency: renderMinuteFrequency,
1093
+ minuteSpanAcrossHourStep: renderMinuteSpanAcrossHourStep,
1094
+ minuteSpanInHour: renderMinuteSpanInHour,
1095
+ minutesAcrossHours: renderMinutesAcrossHours,
1096
+ multipleMinutes: renderMultipleMinutes,
1097
+ rangeOfMinutes: renderRangeOfMinutes,
1098
+ secondPastMinute: renderSecondPastMinute,
1099
+ secondsWithinMinute: renderSecondsWithinMinute,
1100
+ singleMinute: renderSingleMinute,
1101
+ standaloneSeconds: renderStandaloneSeconds
1102
+ };
1103
+ function stepCycle60(segment, unit, anchor, opts) {
1104
+ if (segment.startToken.indexOf("-") !== -1) {
1105
+ return listPastThe(numberWords(segment.fires, opts), unit, anchor, opts);
1106
+ }
1107
+ const start = segment.startToken === "*" ? 0 : +segment.startToken;
1108
+ const interval = segment.interval;
1109
+ if (start !== 0) {
1110
+ if (segment.fires.length <= 3) {
1111
+ return listPastThe(
1112
+ numberWords(segment.fires, opts),
1113
+ unit,
1114
+ anchor,
1115
+ opts
1116
+ );
1117
+ }
1118
+ return "every " + getNumber(interval, opts) + " " + unit + "s from " + getNumber(start, opts) + " " + pluralize(start, unit) + " past the " + anchor;
1119
+ }
1120
+ if (60 % interval === 0) {
1121
+ return "every " + getNumber(interval, opts) + " " + unit + "s";
1122
+ }
1123
+ if (segment.fires.length <= 2) {
1124
+ return listPastThe(numberWords(segment.fires, opts), unit, anchor, opts);
1125
+ }
1126
+ return "every " + getNumber(interval, opts) + " " + unit + "s past the " + anchor;
1127
+ }
1128
+ function stepHours(segment, opts) {
1129
+ if (segment.startToken.indexOf("-") !== -1) {
1130
+ return "at " + hourTimes(segment.fires, opts);
1131
+ }
1132
+ const start = segment.startToken === "*" ? 0 : +segment.startToken;
1133
+ const interval = segment.interval;
1134
+ if (start === 0 && 24 % interval === 0) {
1135
+ return "every " + getNumber(interval, opts) + " hours";
1136
+ }
1137
+ if (segment.fires.length <= 3) {
1138
+ return "at " + hourTimes(segment.fires, opts);
1139
+ }
1140
+ if (start === 0) {
1141
+ return "every " + getNumber(interval, opts) + " hours from midnight";
1142
+ }
1143
+ return "every " + getNumber(interval, opts) + " hours from " + getTime({ hour: start, minute: 0 }, opts);
1144
+ }
1145
+ function seriesNumber(values, opts) {
1146
+ const anyBig = values.some(function big(v) {
1147
+ return +v > 10;
1148
+ });
1149
+ return function format(n) {
1150
+ return anyBig ? "" + n : getNumber(n, opts);
1151
+ };
1152
+ }
1153
+ function numberWords(fires, opts) {
1154
+ return fires.map(seriesNumber(fires, opts));
1155
+ }
1156
+ function segmentWords(segments, opts) {
1157
+ const values = segments.flatMap(function collect(segment) {
1158
+ if (segment.kind === "range") {
1159
+ return segment.bounds;
1160
+ }
1161
+ return segment.kind === "step" ? segment.fires : [segment.value];
1162
+ });
1163
+ const num = seriesNumber(values, opts);
1164
+ return segments.flatMap(function word(segment) {
1165
+ if (segment.kind === "range") {
1166
+ return [num(segment.bounds[0]) + through(opts) + num(segment.bounds[1])];
1167
+ }
1168
+ if (segment.kind === "step") {
1169
+ return segment.fires.map(num);
1170
+ }
1171
+ return [num(segment.value)];
1172
+ });
1173
+ }
1174
+ function listPastThe(words, unit, anchor, opts) {
1175
+ return "at " + joinList(words, opts) + " " + unit + "s past the " + anchor;
1176
+ }
1177
+ function wordTime(hour, minute, second) {
1178
+ return (+hour === 0 || +hour === 12) && +minute === 0 && !(typeof second === "number" && second > 0);
1179
+ }
1180
+ function mixedTwelve(entries) {
1181
+ const words = entries.filter(function word(e) {
1182
+ return wordTime(e.hour, e.minute, e.second);
1183
+ });
1184
+ return words.length > 0 && words.length < entries.length;
1185
+ }
1186
+ function hourTimes(hours, opts) {
1187
+ const plain = mixedTwelve(hours.map(function entry(hour) {
1188
+ return { hour, minute: 0 };
1189
+ }));
1190
+ const times = hours.map(function clock(hour) {
1191
+ return getTime({ hour, minute: 0, plain }, opts);
1192
+ });
1193
+ return joinList(times, opts);
1194
+ }
1195
+ function hourTimesFromPlan(ir, times, atContext, opts) {
1196
+ if (times.kind === "fires") {
1197
+ return hourTimes(times.fires, opts);
1198
+ }
1199
+ return hourSegmentTimes(ir, { minute: 0, second: null }, atContext, opts);
1200
+ }
1201
+ function segmentHours(segment) {
1202
+ if (segment.kind === "range") {
1203
+ return segment.bounds;
1204
+ }
1205
+ return segment.kind === "step" ? segment.fires : [segment.value];
1206
+ }
1207
+ function hourSegmentTimes(ir, fold, atContext, opts) {
1208
+ const { minute, second } = fold;
1209
+ const segments = ir.analyses.segments.hour;
1210
+ const plain = mixedTwelve(segments.flatMap(function entries(segment) {
1211
+ return segmentHours(segment).map(function entry(hour) {
1212
+ return { hour: +hour, minute, second };
1213
+ });
1214
+ }));
1215
+ const pieces = [];
1216
+ segments.forEach(function clock(segment) {
1217
+ if (segment.kind === "step") {
1218
+ pieces.push(...segment.fires.map(function time(hour) {
1219
+ return getTime({ hour, minute, second, plain }, opts);
1220
+ }));
1221
+ } else if (segment.kind === "range") {
1222
+ pieces.push(
1223
+ getTime({ hour: segment.bounds[0], minute, second, plain }, opts) + through(opts) + getTime({ hour: segment.bounds[1], minute, second, plain }, opts)
1224
+ );
1225
+ } else {
1226
+ pieces.push(getTime({ hour: segment.value, minute, second, plain }, opts));
1227
+ }
1228
+ });
1229
+ return joinList(disambiguateTimes(pieces, segments, atContext), opts);
1230
+ }
1231
+ function disambiguateTimes(pieces, segments, atContext) {
1232
+ const hasRange = segments.some(function range(segment) {
1233
+ return segment.kind === "range";
1234
+ });
1235
+ if (!atContext || !hasRange) {
1236
+ return pieces;
1237
+ }
1238
+ return pieces.map(function at(piece, index) {
1239
+ return index === 0 ? piece : "at " + piece;
1240
+ });
1241
+ }
1242
+ function joinList(items, opts) {
1243
+ if (items.length <= 1) {
1244
+ return items.join("");
1245
+ }
1246
+ if (items.length === 2) {
1247
+ return items[0] + " and " + items[1];
1248
+ }
1249
+ const and = opts.style.serialComma ? ", and " : " and ";
1250
+ return items.slice(0, -1).join(", ") + and + items[items.length - 1];
1251
+ }
1252
+ var trailingWords = { all: "", month: "in ", stepDate: "on ", weekday: "on " };
1253
+ var leadingWords = {
1254
+ all: "every day",
1255
+ month: "every day in ",
1256
+ stepDate: "",
1257
+ weekday: "every "
1258
+ };
1259
+ function trailingQualifier(ir, opts) {
1260
+ const phrase = dayQualifier(ir, trailingWords, opts);
1261
+ return phrase && " " + phrase;
1262
+ }
1263
+ function interpretDayQualifier(ir, opts) {
1264
+ return dayQualifier(ir, leadingWords, opts) + " ";
1265
+ }
1266
+ function dayQualifier(ir, words, opts) {
1267
+ const pattern = ir.pattern;
1268
+ if (pattern.date !== "*" && pattern.weekday !== "*") {
1269
+ return dateOrWeekday(ir, opts);
1270
+ }
1271
+ if (pattern.date !== "*") {
1272
+ return datePhrase(ir, words, opts);
1273
+ }
1274
+ if (pattern.weekday !== "*") {
1275
+ const weekdays = quartzWeekdayPhrase(pattern.weekday, opts) || words.weekday + weekdayPhrase(ir, opts);
1276
+ return weekdays + monthScope(ir, opts);
1277
+ }
1278
+ if (pattern.month !== "*") {
1279
+ return words.month + monthName(ir, opts);
1280
+ }
1281
+ return words.all;
1282
+ }
1283
+ function datePhrase(ir, words, opts) {
1284
+ const pattern = ir.pattern;
1285
+ const quartzDate = quartzDatePhrase(pattern.date, opts);
1286
+ if (quartzDate) {
1287
+ return quartzDate + monthScope(ir, opts);
1288
+ }
1289
+ if (isOpenStep(pattern.date)) {
1290
+ return words.stepDate + stepDates(pattern.date) + monthScope(ir, opts);
1291
+ }
1292
+ if (pattern.month !== "*" && !monthFoldsIntoDate(ir)) {
1293
+ return "on the " + dateOrdinals(ir, opts) + monthScope(ir, opts);
1294
+ }
1295
+ if (pattern.month !== "*") {
1296
+ return "on " + monthDatePhrase(ir, opts);
1297
+ }
1298
+ return "on the " + dateOrdinals(ir, opts);
1299
+ }
1300
+ function monthFoldsIntoDate(ir) {
1301
+ return !oddEvenMonth(ir.pattern.month) && // Reached only with a restricted month, which has segments.
1302
+ ir.analyses.segments.month.every(function flat(segment) {
1303
+ return segment.kind !== "range";
1304
+ });
1305
+ }
1306
+ function dateOrWeekday(ir, opts) {
1307
+ const pattern = ir.pattern;
1308
+ const weekdayPart = quartzWeekdayPhrase(pattern.weekday, opts) || "on " + weekdayPhrase(ir, opts);
1309
+ const quartzDate = quartzDatePhrase(pattern.date, opts);
1310
+ if (quartzDate) {
1311
+ return quartzDate + monthScope(ir, opts) + " or " + weekdayPart;
1312
+ }
1313
+ if (isOpenStep(pattern.date)) {
1314
+ return stepDates(pattern.date) + monthScope(ir, opts) + " or " + weekdayPart;
1315
+ }
1316
+ if (pattern.month !== "*" && monthFoldsIntoDate(ir)) {
1317
+ return "on " + monthDatePhrase(ir, opts) + " or " + weekdayPart + " in " + monthName(ir, opts);
1318
+ }
1319
+ return "on the " + dateOrdinals(ir, opts) + " or " + weekdayPart + monthScope(ir, opts);
1320
+ }
1321
+ function quartzDatePhrase(dateField, opts) {
1322
+ if (dateField === "L") {
1323
+ return "on the last day of the month";
1324
+ }
1325
+ if (dateField === "LW" || dateField === "WL") {
1326
+ return "on the last weekday of the month";
1327
+ }
1328
+ const offset = /^L-(\d{1,2})$/.exec(dateField);
1329
+ if (offset) {
1330
+ return getNumber(+offset[1], opts) + " " + pluralize(offset[1], "day") + " before the last day of the month";
1331
+ }
1332
+ const nearest = /^(\d{1,2})W$|^W(\d{1,2})$/.exec(dateField);
1333
+ if (nearest) {
1334
+ return "on the weekday nearest the " + getOrdinal(nearest[1] || nearest[2]);
1335
+ }
1336
+ }
1337
+ function quartzWeekdayPhrase(weekdayField, opts) {
1338
+ const parts = weekdayField.split("#");
1339
+ if (parts.length === 2) {
1340
+ return "on the " + nthWeekdayNames[+parts[1]] + " " + getWeekday(parts[0], opts) + " of the month";
1341
+ }
1342
+ if (/L$/.test(weekdayField)) {
1343
+ return "on the last " + getWeekday(weekdayField.slice(0, -1), opts) + " of the month";
1344
+ }
1345
+ }
1346
+ function monthDatePhrase(ir, opts) {
1347
+ const month = monthName(ir, opts);
1348
+ const days = renderSegments(
1349
+ ir.analyses.segments.date,
1350
+ opts.style.ordinals ? getOrdinal : cardinalDay,
1351
+ opts
1352
+ );
1353
+ return opts.style.dayFirst ? days + " " + month : month + " " + days;
1354
+ }
1355
+ function cardinalDay(value) {
1356
+ return "" + value;
1357
+ }
1358
+ function monthScope(ir, opts) {
1359
+ if (ir.pattern.month === "*") {
1360
+ return "";
1361
+ }
1362
+ return " in " + monthName(ir, opts);
1363
+ }
1364
+ function stepDates(dateField) {
1365
+ const parts = dateField.split("/");
1366
+ const interval = +parts[1];
1367
+ const start = parts[0];
1368
+ const cadence = interval === 2 ? "every other" : "every " + getOrdinal(interval);
1369
+ let phrase = cadence + " day of the month";
1370
+ if (start !== "*" && start !== "1") {
1371
+ phrase += " from the " + getOrdinal(start);
1372
+ }
1373
+ return phrase;
1374
+ }
1375
+ function dateOrdinals(ir, opts) {
1376
+ return renderSegments(ir.analyses.segments.date, getOrdinal, opts);
1377
+ }
1378
+ function monthName(ir, opts) {
1379
+ const oddEven = oddEvenMonth(ir.pattern.month);
1380
+ if (oddEven) {
1381
+ return oddEven;
1382
+ }
1383
+ return renderSegments(ir.analyses.segments.month, function name(value) {
1384
+ return getMonth(value, opts);
1385
+ }, opts);
1386
+ }
1387
+ function oddEvenMonth(monthField) {
1388
+ if (!isOpenStep(monthField)) {
1389
+ return null;
1390
+ }
1391
+ const [start, step] = monthField.split("/");
1392
+ if (+step !== 2) {
1393
+ return null;
1394
+ }
1395
+ if (start === "*" || start === "1") {
1396
+ return "every odd-numbered month";
1397
+ }
1398
+ return start === "2" ? "every even-numbered month" : null;
1399
+ }
1400
+ function weekdayPhrase(ir, opts) {
1401
+ return renderSegments(ir.analyses.segments.weekday, function name(value) {
1402
+ return getWeekday(value, opts);
1403
+ }, opts);
1404
+ }
1405
+ function renderSegments(segments, word, opts) {
1406
+ const pieces = [];
1407
+ segments.forEach(function expand(segment) {
1408
+ if (segment.kind === "step") {
1409
+ pieces.push(...segment.fires.map(word));
1410
+ } else if (segment.kind === "range") {
1411
+ pieces.push(segment.bounds.map(word).join(through(opts)));
1412
+ } else {
1413
+ pieces.push(word(segment.value));
1414
+ }
1415
+ });
1416
+ return joinList(pieces, opts);
1417
+ }
1418
+ function isOpenStep(field) {
1419
+ return field.indexOf("/") !== -1 && field.indexOf("-") === -1 && field.indexOf(",") === -1;
1420
+ }
1421
+ function applyYear(description, ir, opts) {
1422
+ const yearField = ir.pattern.year;
1423
+ if (yearField === "*") {
1424
+ return description;
1425
+ }
1426
+ if (yearField.indexOf("/") !== -1) {
1427
+ return description + " " + stepYears(yearField, opts);
1428
+ }
1429
+ const label = yearLabel(yearField, opts);
1430
+ if (yearField.indexOf("-") === -1 && yearField.indexOf(",") === -1 && ir.pattern.date !== "*" && description.indexOf(" at ") !== -1) {
1431
+ const yearGlue = opts.style.dayFirst ? " " : ", ";
1432
+ return description.replace(" at ", yearGlue + label + " at ");
1433
+ }
1434
+ return description + " in " + label;
1435
+ }
1436
+ function yearLabel(yearField, opts) {
1437
+ if (yearField.indexOf(",") !== -1) {
1438
+ return joinList(yearField.split(","), opts);
1439
+ }
1440
+ return yearField;
1441
+ }
1442
+ function stepYears(yearField, opts) {
1443
+ const parts = yearField.split("/");
1444
+ const interval = +parts[1];
1445
+ const start = parts[0];
1446
+ if (interval <= 1) {
1447
+ return "every year";
1448
+ }
1449
+ let phrase = "every " + getNumber(interval, opts) + " years";
1450
+ if (start !== "*" && start !== "0") {
1451
+ phrase += " from " + start;
1452
+ }
1453
+ return phrase;
1454
+ }
1455
+ function getTime(time, opts) {
1456
+ const { hour, minute, plain } = time;
1457
+ const second = typeof time.second === "number" && time.second > 0 ? time.second : 0;
1458
+ if (!opts.ampm) {
1459
+ return clockDigits({
1460
+ hour,
1461
+ minute,
1462
+ second
1463
+ }, { pad: true, sep: opts.style.sep });
1464
+ }
1465
+ return twelveHourTime({ hour, minute, second, plain }, opts);
1466
+ }
1467
+ function twelveHourTime(time, opts) {
1468
+ const { hour, minute, second, plain } = time;
1469
+ const style = opts.style;
1470
+ if (!plain && +minute === 0 && !second) {
1471
+ if (+hour === 0) {
1472
+ return style.midnight;
1473
+ }
1474
+ if (+hour === 12) {
1475
+ return style.midday;
1476
+ }
1477
+ }
1478
+ const digits = clockDigits(
1479
+ { hour: hour % 12 || 12, minute, second },
1480
+ { lean: true, sep: style.sep }
1481
+ );
1482
+ return digits + (style.closeUp ? "" : " ") + (hour < 12 ? style.am : style.pm);
1483
+ }
1484
+ function getNumber(n, opts) {
1485
+ return numeral(n, numbers, opts);
1486
+ }
1487
+ function pluralize(value, unit) {
1488
+ return +value === 1 ? unit : unit + "s";
1489
+ }
1490
+ function through(opts) {
1491
+ return opts.short ? "-" : opts.style.through;
1492
+ }
1493
+ function getOrdinal(n) {
1494
+ let m = Math.abs(n);
1495
+ let suffix = suffixes[m];
1496
+ if (!suffix) {
1497
+ m = (m % 100 - 20) % 10;
1498
+ suffix = suffixes[m] || suffixes[0];
1499
+ }
1500
+ return n + suffix;
1501
+ }
1502
+ function getMonth(m, opts) {
1503
+ const month = monthNames[m] || monthAbbreviations[m];
1504
+ return month && month[opts.short ? 1 : 0];
1505
+ }
1506
+ function getWeekday(d, opts) {
1507
+ const day = d === 7 || d === "7" ? 0 : d;
1508
+ const weekday = weekdayNames[day] || weekdayAbbreviations[day];
1509
+ return weekday && weekday[opts.short ? 1 : 0];
1510
+ }
1511
+ var en = {
1512
+ describe,
1513
+ fallback: "an unrecognizable cron pattern",
1514
+ options: normalizeOptions,
1515
+ reboot: "at system startup",
1516
+ sentence: (description) => "Runs " + description + "."
1517
+ };
1518
+ var en_default = en;
1519
+
1520
+ // src/cronli5.ts
1521
+ function cronli5(cronPattern, options) {
1522
+ const lang = options && options.lang || en_default;
1523
+ const opts = lang.options(options);
1524
+ if (!opts.lenient) {
1525
+ return present(
1526
+ interpretCronPattern(cronPattern, lang, opts),
1527
+ lang,
1528
+ options
1529
+ );
1530
+ }
1531
+ try {
1532
+ return present(
1533
+ interpretCronPattern(cronPattern, lang, opts),
1534
+ lang,
1535
+ options
1536
+ );
1537
+ } catch {
1538
+ return lang.fallback;
1539
+ }
1540
+ }
1541
+ function present(description, lang, options) {
1542
+ return options && options.sentence ? lang.sentence(description) : description;
1543
+ }
1544
+ function interpretCronPattern(cronPattern, lang, opts) {
1545
+ if (typeof cronPattern === "string" && cronPattern.trim().toLowerCase() === "@reboot") {
1546
+ return lang.reboot;
1547
+ }
1548
+ const ir = analyze(prepare(cronPattern, opts));
1549
+ const plan = lang.strategy ? lang.strategy(ir, ir.plan) : ir.plan;
1550
+ return lang.describe({ ...ir, plan }, opts);
1551
+ }
1552
+ var cronli5_default = cronli5;
1553
+ /**
1554
+ * @license MIT, Copyright (c) 2026 Andrew Brož
1555
+ */
1556
+ module.exports = module.exports.default;