@tachybase/module-cron 1.3.16 → 1.3.18

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 (48) hide show
  1. package/dist/client/cron-jobs-table/CronJobsTable.schema.d.ts +3 -2
  2. package/dist/client/index.js +3 -3
  3. package/dist/externalVersion.js +7 -7
  4. package/dist/index.js +4 -4
  5. package/dist/node_modules/cron-parser/LICENSE +1 -1
  6. package/dist/node_modules/cron-parser/dist/CronDate.js +497 -0
  7. package/dist/node_modules/cron-parser/dist/CronExpression.js +376 -0
  8. package/dist/node_modules/cron-parser/dist/CronExpressionParser.js +384 -0
  9. package/dist/node_modules/cron-parser/dist/CronFieldCollection.js +371 -0
  10. package/dist/node_modules/cron-parser/dist/CronFileParser.js +109 -0
  11. package/dist/node_modules/cron-parser/dist/fields/CronDayOfMonth.js +44 -0
  12. package/dist/node_modules/cron-parser/dist/fields/CronDayOfWeek.js +51 -0
  13. package/dist/node_modules/cron-parser/dist/fields/CronField.js +183 -0
  14. package/dist/node_modules/cron-parser/dist/fields/CronHour.js +40 -0
  15. package/dist/node_modules/cron-parser/dist/fields/CronMinute.js +40 -0
  16. package/dist/node_modules/cron-parser/dist/fields/CronMonth.js +44 -0
  17. package/dist/node_modules/cron-parser/dist/fields/CronSecond.js +40 -0
  18. package/dist/node_modules/cron-parser/dist/fields/index.js +24 -0
  19. package/dist/node_modules/cron-parser/dist/fields/types.js +2 -0
  20. package/dist/node_modules/cron-parser/dist/index.js +1 -0
  21. package/dist/node_modules/cron-parser/dist/types/CronDate.d.ts +273 -0
  22. package/dist/node_modules/cron-parser/dist/types/CronExpression.d.ts +110 -0
  23. package/dist/node_modules/cron-parser/dist/types/CronExpressionParser.d.ts +70 -0
  24. package/dist/node_modules/cron-parser/dist/types/CronFieldCollection.d.ts +153 -0
  25. package/dist/node_modules/cron-parser/dist/types/CronFileParser.d.ts +30 -0
  26. package/dist/node_modules/cron-parser/dist/types/fields/CronDayOfMonth.d.ts +25 -0
  27. package/dist/node_modules/cron-parser/dist/types/fields/CronDayOfWeek.d.ts +30 -0
  28. package/dist/node_modules/cron-parser/dist/types/fields/CronField.d.ts +114 -0
  29. package/dist/node_modules/cron-parser/dist/types/fields/CronHour.d.ts +23 -0
  30. package/dist/node_modules/cron-parser/dist/types/fields/CronMinute.d.ts +23 -0
  31. package/dist/node_modules/cron-parser/dist/types/fields/CronMonth.d.ts +24 -0
  32. package/dist/node_modules/cron-parser/dist/types/fields/CronSecond.d.ts +23 -0
  33. package/dist/node_modules/cron-parser/dist/types/fields/index.d.ts +8 -0
  34. package/dist/node_modules/cron-parser/dist/types/fields/types.d.ts +18 -0
  35. package/dist/node_modules/cron-parser/dist/types/index.d.ts +8 -0
  36. package/dist/node_modules/cron-parser/dist/types/utils/random.d.ts +10 -0
  37. package/dist/node_modules/cron-parser/dist/utils/random.js +38 -0
  38. package/dist/node_modules/cron-parser/package.json +1 -1
  39. package/dist/server/service/StaticScheduleTrigger.d.ts +1 -1
  40. package/package.json +10 -10
  41. package/dist/node_modules/cron-parser/lib/date.js +0 -252
  42. package/dist/node_modules/cron-parser/lib/expression.js +0 -1002
  43. package/dist/node_modules/cron-parser/lib/field_compactor.js +0 -70
  44. package/dist/node_modules/cron-parser/lib/field_stringify.js +0 -58
  45. package/dist/node_modules/cron-parser/lib/parser.js +0 -1
  46. package/dist/node_modules/cron-parser/types/common.d.ts +0 -131
  47. package/dist/node_modules/cron-parser/types/index.d.ts +0 -45
  48. package/dist/node_modules/cron-parser/types/ts3/index.d.ts +0 -28
@@ -1,1002 +0,0 @@
1
- 'use strict';
2
-
3
- // Load Date class extensions
4
- var CronDate = require('./date');
5
-
6
- var stringifyField = require('./field_stringify');
7
-
8
- /**
9
- * Cron iteration loop safety limit
10
- */
11
- var LOOP_LIMIT = 10000;
12
-
13
- /**
14
- * Construct a new expression parser
15
- *
16
- * Options:
17
- * currentDate: iterator start date
18
- * endDate: iterator end date
19
- *
20
- * @constructor
21
- * @private
22
- * @param {Object} fields Expression fields parsed values
23
- * @param {Object} options Parser options
24
- */
25
- function CronExpression (fields, options) {
26
- this._options = options;
27
- this._utc = options.utc || false;
28
- this._tz = this._utc ? 'UTC' : options.tz;
29
- this._currentDate = new CronDate(options.currentDate, this._tz);
30
- this._startDate = options.startDate ? new CronDate(options.startDate, this._tz) : null;
31
- this._endDate = options.endDate ? new CronDate(options.endDate, this._tz) : null;
32
- this._isIterator = options.iterator || false;
33
- this._hasIterated = false;
34
- this._nthDayOfWeek = options.nthDayOfWeek || 0;
35
- this.fields = CronExpression._freezeFields(fields);
36
- }
37
-
38
- /**
39
- * Field mappings
40
- * @type {Array}
41
- */
42
- CronExpression.map = [ 'second', 'minute', 'hour', 'dayOfMonth', 'month', 'dayOfWeek' ];
43
-
44
- /**
45
- * Prefined intervals
46
- * @type {Object}
47
- */
48
- CronExpression.predefined = {
49
- '@yearly': '0 0 1 1 *',
50
- '@monthly': '0 0 1 * *',
51
- '@weekly': '0 0 * * 0',
52
- '@daily': '0 0 * * *',
53
- '@hourly': '0 * * * *'
54
- };
55
-
56
- /**
57
- * Fields constraints
58
- * @type {Array}
59
- */
60
- CronExpression.constraints = [
61
- { min: 0, max: 59, chars: [] }, // Second
62
- { min: 0, max: 59, chars: [] }, // Minute
63
- { min: 0, max: 23, chars: [] }, // Hour
64
- { min: 1, max: 31, chars: ['L'] }, // Day of month
65
- { min: 1, max: 12, chars: [] }, // Month
66
- { min: 0, max: 7, chars: ['L'] }, // Day of week
67
- ];
68
-
69
- /**
70
- * Days in month
71
- * @type {number[]}
72
- */
73
- CronExpression.daysInMonth = [
74
- 31,
75
- 29,
76
- 31,
77
- 30,
78
- 31,
79
- 30,
80
- 31,
81
- 31,
82
- 30,
83
- 31,
84
- 30,
85
- 31
86
- ];
87
-
88
- /**
89
- * Field aliases
90
- * @type {Object}
91
- */
92
- CronExpression.aliases = {
93
- month: {
94
- jan: 1,
95
- feb: 2,
96
- mar: 3,
97
- apr: 4,
98
- may: 5,
99
- jun: 6,
100
- jul: 7,
101
- aug: 8,
102
- sep: 9,
103
- oct: 10,
104
- nov: 11,
105
- dec: 12
106
- },
107
-
108
- dayOfWeek: {
109
- sun: 0,
110
- mon: 1,
111
- tue: 2,
112
- wed: 3,
113
- thu: 4,
114
- fri: 5,
115
- sat: 6
116
- }
117
- };
118
-
119
- /**
120
- * Field defaults
121
- * @type {Array}
122
- */
123
- CronExpression.parseDefaults = [ '0', '*', '*', '*', '*', '*' ];
124
-
125
- CronExpression.standardValidCharacters = /^[,*\d/-]+$/;
126
- CronExpression.dayOfWeekValidCharacters = /^[?,*\dL#/-]+$/;
127
- CronExpression.dayOfMonthValidCharacters = /^[?,*\dL/-]+$/;
128
- CronExpression.validCharacters = {
129
- second: CronExpression.standardValidCharacters,
130
- minute: CronExpression.standardValidCharacters,
131
- hour: CronExpression.standardValidCharacters,
132
- dayOfMonth: CronExpression.dayOfMonthValidCharacters,
133
- month: CronExpression.standardValidCharacters,
134
- dayOfWeek: CronExpression.dayOfWeekValidCharacters,
135
- };
136
-
137
- CronExpression._isValidConstraintChar = function _isValidConstraintChar(constraints, value) {
138
- if (typeof value !== 'string') {
139
- return false;
140
- }
141
-
142
- return constraints.chars.some(function(char) {
143
- return value.indexOf(char) > -1;
144
- });
145
- };
146
-
147
- /**
148
- * Parse input interval
149
- *
150
- * @param {String} field Field symbolic name
151
- * @param {String} value Field value
152
- * @param {Array} constraints Range upper and lower constraints
153
- * @return {Array} Sequence of sorted values
154
- * @private
155
- */
156
- CronExpression._parseField = function _parseField (field, value, constraints) {
157
- // Replace aliases
158
- switch (field) {
159
- case 'month':
160
- case 'dayOfWeek':
161
- var aliases = CronExpression.aliases[field];
162
-
163
- value = value.replace(/[a-z]{3}/gi, function(match) {
164
- match = match.toLowerCase();
165
-
166
- if (typeof aliases[match] !== 'undefined') {
167
- return aliases[match];
168
- } else {
169
- throw new Error('Validation error, cannot resolve alias "' + match + '"');
170
- }
171
- });
172
- break;
173
- }
174
-
175
- // Check for valid characters.
176
- if (!(CronExpression.validCharacters[field].test(value))) {
177
- throw new Error('Invalid characters, got value: ' + value);
178
- }
179
-
180
- // Replace '*' and '?'
181
- if (value.indexOf('*') !== -1) {
182
- value = value.replace(/\*/g, constraints.min + '-' + constraints.max);
183
- } else if (value.indexOf('?') !== -1) {
184
- value = value.replace(/\?/g, constraints.min + '-' + constraints.max);
185
- }
186
-
187
- //
188
- // Inline parsing functions
189
- //
190
- // Parser path:
191
- // - parseSequence
192
- // - parseRepeat
193
- // - parseRange
194
-
195
- /**
196
- * Parse sequence
197
- *
198
- * @param {String} val
199
- * @return {Array}
200
- * @private
201
- */
202
- function parseSequence (val) {
203
- var stack = [];
204
-
205
- function handleResult (result) {
206
- if (result instanceof Array) { // Make sequence linear
207
- for (var i = 0, c = result.length; i < c; i++) {
208
- var value = result[i];
209
-
210
- if (CronExpression._isValidConstraintChar(constraints, value)) {
211
- stack.push(value);
212
- continue;
213
- }
214
- // Check constraints
215
- if (typeof value !== 'number' || Number.isNaN(value) || value < constraints.min || value > constraints.max) {
216
- throw new Error(
217
- 'Constraint error, got value ' + value + ' expected range ' +
218
- constraints.min + '-' + constraints.max
219
- );
220
- }
221
-
222
- stack.push(value);
223
- }
224
- } else { // Scalar value
225
-
226
- if (CronExpression._isValidConstraintChar(constraints, result)) {
227
- stack.push(result);
228
- return;
229
- }
230
-
231
- var numResult = +result;
232
-
233
- // Check constraints
234
- if (Number.isNaN(numResult) || numResult < constraints.min || numResult > constraints.max) {
235
- throw new Error(
236
- 'Constraint error, got value ' + result + ' expected range ' +
237
- constraints.min + '-' + constraints.max
238
- );
239
- }
240
-
241
- if (field === 'dayOfWeek') {
242
- numResult = numResult % 7;
243
- }
244
-
245
- stack.push(numResult);
246
- }
247
- }
248
-
249
- var atoms = val.split(',');
250
- if (!atoms.every(function (atom) {
251
- return atom.length > 0;
252
- })) {
253
- throw new Error('Invalid list value format');
254
- }
255
-
256
- if (atoms.length > 1) {
257
- for (var i = 0, c = atoms.length; i < c; i++) {
258
- handleResult(parseRepeat(atoms[i]));
259
- }
260
- } else {
261
- handleResult(parseRepeat(val));
262
- }
263
-
264
- stack.sort(CronExpression._sortCompareFn);
265
-
266
- return stack;
267
- }
268
-
269
- /**
270
- * Parse repetition interval
271
- *
272
- * @param {String} val
273
- * @return {Array}
274
- */
275
- function parseRepeat (val) {
276
- var repeatInterval = 1;
277
- var atoms = val.split('/');
278
-
279
- if (atoms.length > 2) {
280
- throw new Error('Invalid repeat: ' + val);
281
- }
282
-
283
- if (atoms.length > 1) {
284
- if (atoms[0] == +atoms[0]) {
285
- atoms = [atoms[0] + '-' + constraints.max, atoms[1]];
286
- }
287
- return parseRange(atoms[0], atoms[atoms.length - 1]);
288
- }
289
-
290
- return parseRange(val, repeatInterval);
291
- }
292
-
293
- /**
294
- * Parse range
295
- *
296
- * @param {String} val
297
- * @param {Number} repeatInterval Repetition interval
298
- * @return {Array}
299
- * @private
300
- */
301
- function parseRange (val, repeatInterval) {
302
- var stack = [];
303
- var atoms = val.split('-');
304
-
305
- if (atoms.length > 1 ) {
306
- // Invalid range, return value
307
- if (atoms.length < 2) {
308
- return +val;
309
- }
310
-
311
- if (!atoms[0].length) {
312
- if (!atoms[1].length) {
313
- throw new Error('Invalid range: ' + val);
314
- }
315
-
316
- return +val;
317
- }
318
-
319
- // Validate range
320
- var min = +atoms[0];
321
- var max = +atoms[1];
322
-
323
- if (Number.isNaN(min) || Number.isNaN(max) ||
324
- min < constraints.min || max > constraints.max) {
325
- throw new Error(
326
- 'Constraint error, got range ' +
327
- min + '-' + max +
328
- ' expected range ' +
329
- constraints.min + '-' + constraints.max
330
- );
331
- } else if (min > max) {
332
- throw new Error('Invalid range: ' + val);
333
- }
334
-
335
- // Create range
336
- var repeatIndex = +repeatInterval;
337
-
338
- if (Number.isNaN(repeatIndex) || repeatIndex <= 0) {
339
- throw new Error('Constraint error, cannot repeat at every ' + repeatIndex + ' time.');
340
- }
341
-
342
- // JS DOW is in range of 0-6 (SUN-SAT) but we also support 7 in the expression
343
- // Handle case when range contains 7 instead of 0 and translate this value to 0
344
- if (field === 'dayOfWeek' && max % 7 === 0) {
345
- stack.push(0);
346
- }
347
-
348
- for (var index = min, count = max; index <= count; index++) {
349
- var exists = stack.indexOf(index) !== -1;
350
- if (!exists && repeatIndex > 0 && (repeatIndex % repeatInterval) === 0) {
351
- repeatIndex = 1;
352
- stack.push(index);
353
- } else {
354
- repeatIndex++;
355
- }
356
- }
357
- return stack;
358
- }
359
-
360
- return Number.isNaN(+val) ? val : +val;
361
- }
362
-
363
- return parseSequence(value);
364
- };
365
-
366
- CronExpression._sortCompareFn = function(a, b) {
367
- var aIsNumber = typeof a === 'number';
368
- var bIsNumber = typeof b === 'number';
369
-
370
- if (aIsNumber && bIsNumber) {
371
- return a - b;
372
- }
373
-
374
- if (!aIsNumber && bIsNumber) {
375
- return 1;
376
- }
377
-
378
- if (aIsNumber && !bIsNumber) {
379
- return -1;
380
- }
381
-
382
- return a.localeCompare(b);
383
- };
384
-
385
- CronExpression._handleMaxDaysInMonth = function(mappedFields) {
386
- // Filter out any day of month value that is larger than given month expects
387
- if (mappedFields.month.length === 1) {
388
- var daysInMonth = CronExpression.daysInMonth[mappedFields.month[0] - 1];
389
-
390
- if (mappedFields.dayOfMonth[0] > daysInMonth) {
391
- throw new Error('Invalid explicit day of month definition');
392
- }
393
-
394
- return mappedFields.dayOfMonth
395
- .filter(function(dayOfMonth) {
396
- return dayOfMonth === 'L' ? true : dayOfMonth <= daysInMonth;
397
- })
398
- .sort(CronExpression._sortCompareFn);
399
- }
400
- };
401
-
402
- CronExpression._freezeFields = function(fields) {
403
- for (var i = 0, c = CronExpression.map.length; i < c; ++i) {
404
- var field = CronExpression.map[i]; // Field name
405
- var value = fields[field];
406
- fields[field] = Object.freeze(value);
407
- }
408
- return Object.freeze(fields);
409
- };
410
-
411
- CronExpression.prototype._applyTimezoneShift = function(currentDate, dateMathVerb, method) {
412
- if ((method === 'Month') || (method === 'Day')) {
413
- var prevTime = currentDate.getTime();
414
- currentDate[dateMathVerb + method]();
415
- var currTime = currentDate.getTime();
416
- if (prevTime === currTime) {
417
- // Jumped into a not existent date due to a DST transition
418
- if ((currentDate.getMinutes() === 0) &&
419
- (currentDate.getSeconds() === 0)) {
420
- currentDate.addHour();
421
- } else if ((currentDate.getMinutes() === 59) &&
422
- (currentDate.getSeconds() === 59)) {
423
- currentDate.subtractHour();
424
- }
425
- }
426
- } else {
427
- var previousHour = currentDate.getHours();
428
- currentDate[dateMathVerb + method]();
429
- var currentHour = currentDate.getHours();
430
- var diff = currentHour - previousHour;
431
- if (diff === 2) {
432
- // Starting DST
433
- if (this.fields.hour.length !== 24) {
434
- // Hour is specified
435
- this._dstStart = currentHour;
436
- }
437
- } else if ((diff === 0) &&
438
- (currentDate.getMinutes() === 0) &&
439
- (currentDate.getSeconds() === 0)) {
440
- // Ending DST
441
- if (this.fields.hour.length !== 24) {
442
- // Hour is specified
443
- this._dstEnd = currentHour;
444
- }
445
- }
446
- }
447
- };
448
-
449
-
450
- /**
451
- * Find next or previous matching schedule date
452
- *
453
- * @return {CronDate}
454
- * @private
455
- */
456
- CronExpression.prototype._findSchedule = function _findSchedule (reverse) {
457
-
458
- /**
459
- * Match field value
460
- *
461
- * @param {String} value
462
- * @param {Array} sequence
463
- * @return {Boolean}
464
- * @private
465
- */
466
- function matchSchedule (value, sequence) {
467
- for (var i = 0, c = sequence.length; i < c; i++) {
468
- if (sequence[i] >= value) {
469
- return sequence[i] === value;
470
- }
471
- }
472
-
473
- return sequence[0] === value;
474
- }
475
-
476
- /**
477
- * Helps determine if the provided date is the correct nth occurence of the
478
- * desired day of week.
479
- *
480
- * @param {CronDate} date
481
- * @param {Number} nthDayOfWeek
482
- * @return {Boolean}
483
- * @private
484
- */
485
- function isNthDayMatch(date, nthDayOfWeek) {
486
- if (nthDayOfWeek < 6) {
487
- if (
488
- date.getDate() < 8 &&
489
- nthDayOfWeek === 1 // First occurence has to happen in first 7 days of the month
490
- ) {
491
- return true;
492
- }
493
-
494
- var offset = date.getDate() % 7 ? 1 : 0; // Math is off by 1 when dayOfWeek isn't divisible by 7
495
- var adjustedDate = date.getDate() - (date.getDate() % 7); // find the first occurance
496
- var occurrence = Math.floor(adjustedDate / 7) + offset;
497
-
498
- return occurrence === nthDayOfWeek;
499
- }
500
-
501
- return false;
502
- }
503
-
504
- /**
505
- * Helper function that checks if 'L' is in the array
506
- *
507
- * @param {Array} expressions
508
- */
509
- function isLInExpressions(expressions) {
510
- return expressions.length > 0 && expressions.some(function(expression) {
511
- return typeof expression === 'string' && expression.indexOf('L') >= 0;
512
- });
513
- }
514
-
515
-
516
- // Whether to use backwards directionality when searching
517
- reverse = reverse || false;
518
- var dateMathVerb = reverse ? 'subtract' : 'add';
519
-
520
- var currentDate = new CronDate(this._currentDate, this._tz);
521
- var startDate = this._startDate;
522
- var endDate = this._endDate;
523
-
524
- // Find matching schedule
525
- var startTimestamp = currentDate.getTime();
526
- var stepCount = 0;
527
-
528
- function isLastWeekdayOfMonthMatch(expressions) {
529
- return expressions.some(function(expression) {
530
- // There might be multiple expressions and not all of them will contain
531
- // the "L".
532
- if (!isLInExpressions([expression])) {
533
- return false;
534
- }
535
-
536
- // The first character represents the weekday
537
- var weekday = Number.parseInt(expression[0]) % 7;
538
-
539
- if (Number.isNaN(weekday)) {
540
- throw new Error('Invalid last weekday of the month expression: ' + expression);
541
- }
542
-
543
- return currentDate.getDay() === weekday && currentDate.isLastWeekdayOfMonth();
544
- });
545
- }
546
-
547
- while (stepCount < LOOP_LIMIT) {
548
- stepCount++;
549
-
550
- // Validate timespan
551
- if (reverse) {
552
- if (startDate && (currentDate.getTime() - startDate.getTime() < 0)) {
553
- throw new Error('Out of the timespan range');
554
- }
555
- } else {
556
- if (endDate && (endDate.getTime() - currentDate.getTime()) < 0) {
557
- throw new Error('Out of the timespan range');
558
- }
559
- }
560
-
561
- // Day of month and week matching:
562
- //
563
- // "The day of a command's execution can be specified by two fields --
564
- // day of month, and day of week. If both fields are restricted (ie,
565
- // aren't *), the command will be run when either field matches the cur-
566
- // rent time. For example, "30 4 1,15 * 5" would cause a command to be
567
- // run at 4:30 am on the 1st and 15th of each month, plus every Friday."
568
- //
569
- // http://unixhelp.ed.ac.uk/CGI/man-cgi?crontab+5
570
- //
571
-
572
- var dayOfMonthMatch = matchSchedule(currentDate.getDate(), this.fields.dayOfMonth);
573
- if (isLInExpressions(this.fields.dayOfMonth)) {
574
- dayOfMonthMatch = dayOfMonthMatch || currentDate.isLastDayOfMonth();
575
- }
576
- var dayOfWeekMatch = matchSchedule(currentDate.getDay(), this.fields.dayOfWeek);
577
- if (isLInExpressions(this.fields.dayOfWeek)) {
578
- dayOfWeekMatch = dayOfWeekMatch || isLastWeekdayOfMonthMatch(this.fields.dayOfWeek);
579
- }
580
- var isDayOfMonthWildcardMatch = this.fields.dayOfMonth.length >= CronExpression.daysInMonth[currentDate.getMonth()];
581
- var isDayOfWeekWildcardMatch = this.fields.dayOfWeek.length === CronExpression.constraints[5].max - CronExpression.constraints[5].min + 1;
582
- var currentHour = currentDate.getHours();
583
-
584
- // Add or subtract day if select day not match with month (according to calendar)
585
- if (!dayOfMonthMatch && (!dayOfWeekMatch || isDayOfWeekWildcardMatch)) {
586
- this._applyTimezoneShift(currentDate, dateMathVerb, 'Day');
587
- continue;
588
- }
589
-
590
- // Add or subtract day if not day of month is set (and no match) and day of week is wildcard
591
- if (!isDayOfMonthWildcardMatch && isDayOfWeekWildcardMatch && !dayOfMonthMatch) {
592
- this._applyTimezoneShift(currentDate, dateMathVerb, 'Day');
593
- continue;
594
- }
595
-
596
- // Add or subtract day if not day of week is set (and no match) and day of month is wildcard
597
- if (isDayOfMonthWildcardMatch && !isDayOfWeekWildcardMatch && !dayOfWeekMatch) {
598
- this._applyTimezoneShift(currentDate, dateMathVerb, 'Day');
599
- continue;
600
- }
601
-
602
- // Add or subtract day if day of week & nthDayOfWeek are set (and no match)
603
- if (
604
- this._nthDayOfWeek > 0 &&
605
- !isNthDayMatch(currentDate, this._nthDayOfWeek)
606
- ) {
607
- this._applyTimezoneShift(currentDate, dateMathVerb, 'Day');
608
- continue;
609
- }
610
-
611
- // Match month
612
- if (!matchSchedule(currentDate.getMonth() + 1, this.fields.month)) {
613
- this._applyTimezoneShift(currentDate, dateMathVerb, 'Month');
614
- continue;
615
- }
616
-
617
- // Match hour
618
- if (!matchSchedule(currentHour, this.fields.hour)) {
619
- if (this._dstStart !== currentHour) {
620
- this._dstStart = null;
621
- this._applyTimezoneShift(currentDate, dateMathVerb, 'Hour');
622
- continue;
623
- } else if (!matchSchedule(currentHour - 1, this.fields.hour)) {
624
- currentDate[dateMathVerb + 'Hour']();
625
- continue;
626
- }
627
- } else if (this._dstEnd === currentHour) {
628
- if (!reverse) {
629
- this._dstEnd = null;
630
- this._applyTimezoneShift(currentDate, 'add', 'Hour');
631
- continue;
632
- }
633
- }
634
-
635
- // Match minute
636
- if (!matchSchedule(currentDate.getMinutes(), this.fields.minute)) {
637
- this._applyTimezoneShift(currentDate, dateMathVerb, 'Minute');
638
- continue;
639
- }
640
-
641
- // Match second
642
- if (!matchSchedule(currentDate.getSeconds(), this.fields.second)) {
643
- this._applyTimezoneShift(currentDate, dateMathVerb, 'Second');
644
- continue;
645
- }
646
-
647
- // Increase a second in case in the first iteration the currentDate was not
648
- // modified
649
- if (startTimestamp === currentDate.getTime()) {
650
- if ((dateMathVerb === 'add') || (currentDate.getMilliseconds() === 0)) {
651
- this._applyTimezoneShift(currentDate, dateMathVerb, 'Second');
652
- } else {
653
- currentDate.setMilliseconds(0);
654
- }
655
-
656
- continue;
657
- }
658
-
659
- break;
660
- }
661
-
662
- if (stepCount >= LOOP_LIMIT) {
663
- throw new Error('Invalid expression, loop limit exceeded');
664
- }
665
-
666
- this._currentDate = new CronDate(currentDate, this._tz);
667
- this._hasIterated = true;
668
-
669
- return currentDate;
670
- };
671
-
672
- /**
673
- * Find next suitable date
674
- *
675
- * @public
676
- * @return {CronDate|Object}
677
- */
678
- CronExpression.prototype.next = function next () {
679
- var schedule = this._findSchedule();
680
-
681
- // Try to return ES6 compatible iterator
682
- if (this._isIterator) {
683
- return {
684
- value: schedule,
685
- done: !this.hasNext()
686
- };
687
- }
688
-
689
- return schedule;
690
- };
691
-
692
- /**
693
- * Find previous suitable date
694
- *
695
- * @public
696
- * @return {CronDate|Object}
697
- */
698
- CronExpression.prototype.prev = function prev () {
699
- var schedule = this._findSchedule(true);
700
-
701
- // Try to return ES6 compatible iterator
702
- if (this._isIterator) {
703
- return {
704
- value: schedule,
705
- done: !this.hasPrev()
706
- };
707
- }
708
-
709
- return schedule;
710
- };
711
-
712
- /**
713
- * Check if next suitable date exists
714
- *
715
- * @public
716
- * @return {Boolean}
717
- */
718
- CronExpression.prototype.hasNext = function() {
719
- var current = this._currentDate;
720
- var hasIterated = this._hasIterated;
721
-
722
- try {
723
- this._findSchedule();
724
- return true;
725
- } catch (err) {
726
- return false;
727
- } finally {
728
- this._currentDate = current;
729
- this._hasIterated = hasIterated;
730
- }
731
- };
732
-
733
- /**
734
- * Check if previous suitable date exists
735
- *
736
- * @public
737
- * @return {Boolean}
738
- */
739
- CronExpression.prototype.hasPrev = function() {
740
- var current = this._currentDate;
741
- var hasIterated = this._hasIterated;
742
-
743
- try {
744
- this._findSchedule(true);
745
- return true;
746
- } catch (err) {
747
- return false;
748
- } finally {
749
- this._currentDate = current;
750
- this._hasIterated = hasIterated;
751
- }
752
- };
753
-
754
- /**
755
- * Iterate over expression iterator
756
- *
757
- * @public
758
- * @param {Number} steps Numbers of steps to iterate
759
- * @param {Function} callback Optional callback
760
- * @return {Array} Array of the iterated results
761
- */
762
- CronExpression.prototype.iterate = function iterate (steps, callback) {
763
- var dates = [];
764
-
765
- if (steps >= 0) {
766
- for (var i = 0, c = steps; i < c; i++) {
767
- try {
768
- var item = this.next();
769
- dates.push(item);
770
-
771
- // Fire the callback
772
- if (callback) {
773
- callback(item, i);
774
- }
775
- } catch (err) {
776
- break;
777
- }
778
- }
779
- } else {
780
- for (var i = 0, c = steps; i > c; i--) {
781
- try {
782
- var item = this.prev();
783
- dates.push(item);
784
-
785
- // Fire the callback
786
- if (callback) {
787
- callback(item, i);
788
- }
789
- } catch (err) {
790
- break;
791
- }
792
- }
793
- }
794
-
795
- return dates;
796
- };
797
-
798
- /**
799
- * Reset expression iterator state
800
- *
801
- * @public
802
- */
803
- CronExpression.prototype.reset = function reset (newDate) {
804
- this._currentDate = new CronDate(newDate || this._options.currentDate);
805
- };
806
-
807
- /**
808
- * Stringify the expression
809
- *
810
- * @public
811
- * @param {Boolean} [includeSeconds] Should stringify seconds
812
- * @return {String}
813
- */
814
- CronExpression.prototype.stringify = function stringify(includeSeconds) {
815
- var resultArr = [];
816
- for (var i = includeSeconds ? 0 : 1, c = CronExpression.map.length; i < c; ++i) {
817
- var field = CronExpression.map[i];
818
- var value = this.fields[field];
819
- var constraint = CronExpression.constraints[i];
820
-
821
- if (field === 'dayOfMonth' && this.fields.month.length === 1) {
822
- constraint = { min: 1, max: CronExpression.daysInMonth[this.fields.month[0] - 1] };
823
- } else if (field === 'dayOfWeek') {
824
- // Prefer 0-6 range when serializing day of week field
825
- constraint = { min: 0, max: 6 };
826
- value = value[value.length - 1] === 7 ? value.slice(0, -1) : value;
827
- }
828
-
829
- resultArr.push(stringifyField(value, constraint.min, constraint.max));
830
- }
831
- return resultArr.join(' ');
832
- };
833
-
834
- /**
835
- * Parse input expression (async)
836
- *
837
- * @public
838
- * @param {String} expression Input expression
839
- * @param {Object} [options] Parsing options
840
- */
841
- CronExpression.parse = function parse(expression, options) {
842
- var self = this;
843
- if (typeof options === 'function') {
844
- options = {};
845
- }
846
-
847
- function parse (expression, options) {
848
- if (!options) {
849
- options = {};
850
- }
851
-
852
- if (typeof options.currentDate === 'undefined') {
853
- options.currentDate = new CronDate(undefined, self._tz);
854
- }
855
-
856
- // Is input expression predefined?
857
- if (CronExpression.predefined[expression]) {
858
- expression = CronExpression.predefined[expression];
859
- }
860
-
861
- // Split fields
862
- var fields = [];
863
- var atoms = (expression + '').trim().split(/\s+/);
864
-
865
- if (atoms.length > 6) {
866
- throw new Error('Invalid cron expression');
867
- }
868
-
869
- // Resolve fields
870
- var start = (CronExpression.map.length - atoms.length);
871
- for (var i = 0, c = CronExpression.map.length; i < c; ++i) {
872
- var field = CronExpression.map[i]; // Field name
873
- var value = atoms[atoms.length > c ? i : i - start]; // Field value
874
-
875
- if (i < start || !value) { // Use default value
876
- fields.push(CronExpression._parseField(
877
- field,
878
- CronExpression.parseDefaults[i],
879
- CronExpression.constraints[i]
880
- )
881
- );
882
- } else {
883
- var val = field === 'dayOfWeek' ? parseNthDay(value) : value;
884
-
885
- fields.push(CronExpression._parseField(
886
- field,
887
- val,
888
- CronExpression.constraints[i]
889
- )
890
- );
891
- }
892
- }
893
-
894
- var mappedFields = {};
895
- for (var i = 0, c = CronExpression.map.length; i < c; i++) {
896
- var key = CronExpression.map[i];
897
- mappedFields[key] = fields[i];
898
- }
899
-
900
- var dayOfMonth = CronExpression._handleMaxDaysInMonth(mappedFields);
901
- mappedFields.dayOfMonth = dayOfMonth || mappedFields.dayOfMonth;
902
- return new CronExpression(mappedFields, options);
903
-
904
- /**
905
- * Parses out the # special character for the dayOfWeek field & adds it to options.
906
- *
907
- * @param {String} val
908
- * @return {String}
909
- * @private
910
- */
911
- function parseNthDay(val) {
912
- var atoms = val.split('#');
913
- if (atoms.length > 1) {
914
- var nthValue = +atoms[atoms.length - 1];
915
- if(/,/.test(val)) {
916
- throw new Error('Constraint error, invalid dayOfWeek `#` and `,` '
917
- + 'special characters are incompatible');
918
- }
919
- if(/\//.test(val)) {
920
- throw new Error('Constraint error, invalid dayOfWeek `#` and `/` '
921
- + 'special characters are incompatible');
922
- }
923
- if(/-/.test(val)) {
924
- throw new Error('Constraint error, invalid dayOfWeek `#` and `-` '
925
- + 'special characters are incompatible');
926
- }
927
- if (atoms.length > 2 || Number.isNaN(nthValue) || (nthValue < 1 || nthValue > 5)) {
928
- throw new Error('Constraint error, invalid dayOfWeek occurrence number (#)');
929
- }
930
-
931
- options.nthDayOfWeek = nthValue;
932
- return atoms[0];
933
- }
934
- return val;
935
- }
936
- }
937
-
938
- return parse(expression, options);
939
- };
940
-
941
- /**
942
- * Convert cron fields back to Cron Expression
943
- *
944
- * @public
945
- * @param {Object} fields Input fields
946
- * @param {Object} [options] Parsing options
947
- * @return {Object}
948
- */
949
- CronExpression.fieldsToExpression = function fieldsToExpression(fields, options) {
950
- function validateConstraints (field, values, constraints) {
951
- if (!values) {
952
- throw new Error('Validation error, Field ' + field + ' is missing');
953
- }
954
- if (values.length === 0) {
955
- throw new Error('Validation error, Field ' + field + ' contains no values');
956
- }
957
- for (var i = 0, c = values.length; i < c; i++) {
958
- var value = values[i];
959
-
960
- if (CronExpression._isValidConstraintChar(constraints, value)) {
961
- continue;
962
- }
963
-
964
- // Check constraints
965
- if (typeof value !== 'number' || Number.isNaN(value) || value < constraints.min || value > constraints.max) {
966
- throw new Error(
967
- 'Constraint error, got value ' + value + ' expected range ' +
968
- constraints.min + '-' + constraints.max
969
- );
970
- }
971
- }
972
- }
973
-
974
- var mappedFields = {};
975
- for (var i = 0, c = CronExpression.map.length; i < c; ++i) {
976
- var field = CronExpression.map[i]; // Field name
977
- var values = fields[field];
978
- validateConstraints(
979
- field,
980
- values,
981
- CronExpression.constraints[i]
982
- );
983
- var copy = [];
984
- var j = -1;
985
- while (++j < values.length) {
986
- copy[j] = values[j];
987
- }
988
- values = copy.sort(CronExpression._sortCompareFn)
989
- .filter(function(item, pos, ary) {
990
- return !pos || item !== ary[pos - 1];
991
- });
992
- if (values.length !== copy.length) {
993
- throw new Error('Validation error, Field ' + field + ' contains duplicate values');
994
- }
995
- mappedFields[field] = values;
996
- }
997
- var dayOfMonth = CronExpression._handleMaxDaysInMonth(mappedFields);
998
- mappedFields.dayOfMonth = dayOfMonth || mappedFields.dayOfMonth;
999
- return new CronExpression(mappedFields, options || {});
1000
- };
1001
-
1002
- module.exports = CronExpression;