@wabot-dev/framework 0.4.0-beta.2 → 0.4.0-beta.3

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 (44) hide show
  1. package/dist/src/_virtual/CronDate.js +3 -0
  2. package/dist/src/_virtual/CronDayOfMonth.js +3 -0
  3. package/dist/src/_virtual/CronDayOfWeek.js +3 -0
  4. package/dist/src/_virtual/CronExpression.js +3 -0
  5. package/dist/src/_virtual/CronExpressionParser.js +3 -0
  6. package/dist/src/_virtual/CronField.js +3 -0
  7. package/dist/src/_virtual/CronFieldCollection.js +3 -0
  8. package/dist/src/_virtual/CronFileParser.js +3 -0
  9. package/dist/src/_virtual/CronHour.js +3 -0
  10. package/dist/src/_virtual/CronMinute.js +3 -0
  11. package/dist/src/_virtual/CronMonth.js +3 -0
  12. package/dist/src/_virtual/CronSecond.js +3 -0
  13. package/dist/src/_virtual/index.js +5 -0
  14. package/dist/src/_virtual/index2.js +3 -0
  15. package/dist/src/_virtual/index3.js +3 -0
  16. package/dist/src/_virtual/luxon.js +3 -0
  17. package/dist/src/_virtual/random.js +3 -0
  18. package/dist/src/_virtual/types.js +3 -0
  19. package/dist/src/addon/async/pg/PgJobRepository.js +1 -0
  20. package/dist/src/feature/async/@cron.js +17 -0
  21. package/dist/src/feature/async/CronJob.js +67 -0
  22. package/dist/src/feature/async/CronJobRepository.js +19 -0
  23. package/dist/src/feature/async/CronScheduler.js +165 -0
  24. package/dist/src/feature/async/runCronHandlers.js +18 -0
  25. package/dist/src/index.d.ts +11 -1
  26. package/dist/src/index.js +2 -0
  27. package/dist/src/node_modules/cron-parser/dist/CronDate.js +510 -0
  28. package/dist/src/node_modules/cron-parser/dist/CronExpression.js +420 -0
  29. package/dist/src/node_modules/cron-parser/dist/CronExpressionParser.js +396 -0
  30. package/dist/src/node_modules/cron-parser/dist/CronFieldCollection.js +382 -0
  31. package/dist/src/node_modules/cron-parser/dist/CronFileParser.js +122 -0
  32. package/dist/src/node_modules/cron-parser/dist/fields/CronDayOfMonth.js +55 -0
  33. package/dist/src/node_modules/cron-parser/dist/fields/CronDayOfWeek.js +62 -0
  34. package/dist/src/node_modules/cron-parser/dist/fields/CronField.js +193 -0
  35. package/dist/src/node_modules/cron-parser/dist/fields/CronHour.js +51 -0
  36. package/dist/src/node_modules/cron-parser/dist/fields/CronMinute.js +51 -0
  37. package/dist/src/node_modules/cron-parser/dist/fields/CronMonth.js +56 -0
  38. package/dist/src/node_modules/cron-parser/dist/fields/CronSecond.js +51 -0
  39. package/dist/src/node_modules/cron-parser/dist/fields/index.js +44 -0
  40. package/dist/src/node_modules/cron-parser/dist/fields/types.js +12 -0
  41. package/dist/src/node_modules/cron-parser/dist/index.js +49 -0
  42. package/dist/src/node_modules/cron-parser/dist/utils/random.js +48 -0
  43. package/dist/src/node_modules/luxon/build/node/luxon.js +7802 -0
  44. package/package.json +1 -1
@@ -0,0 +1,420 @@
1
+ import { __exports as CronExpression } from '../../../_virtual/CronExpression.js';
2
+ import { __require as requireCronDate } from './CronDate.js';
3
+
4
+ var hasRequiredCronExpression;
5
+
6
+ function requireCronExpression () {
7
+ if (hasRequiredCronExpression) return CronExpression;
8
+ hasRequiredCronExpression = 1;
9
+ (function (exports) {
10
+ Object.defineProperty(exports, "__esModule", { value: true });
11
+ exports.CronExpression = exports.LOOPS_LIMIT_EXCEEDED_ERROR_MESSAGE = exports.TIME_SPAN_OUT_OF_BOUNDS_ERROR_MESSAGE = void 0;
12
+ const CronDate_1 = requireCronDate();
13
+ /**
14
+ * Error message for when the current date is outside the specified time span.
15
+ */
16
+ exports.TIME_SPAN_OUT_OF_BOUNDS_ERROR_MESSAGE = 'Out of the time span range';
17
+ /**
18
+ * Error message for when the loop limit is exceeded during iteration.
19
+ */
20
+ exports.LOOPS_LIMIT_EXCEEDED_ERROR_MESSAGE = 'Invalid expression, loop limit exceeded';
21
+ /**
22
+ * Cron iteration loop safety limit
23
+ */
24
+ const LOOP_LIMIT = 10000;
25
+ /**
26
+ * Class representing a Cron expression.
27
+ */
28
+ class CronExpression {
29
+ #options;
30
+ #tz;
31
+ #currentDate;
32
+ #startDate;
33
+ #endDate;
34
+ #fields;
35
+ /**
36
+ * Creates a new CronExpression instance.
37
+ *
38
+ * @param {CronFieldCollection} fields - Cron fields.
39
+ * @param {CronExpressionOptions} options - Parser options.
40
+ */
41
+ constructor(fields, options) {
42
+ this.#options = options;
43
+ this.#tz = options.tz;
44
+ this.#startDate = options.startDate ? new CronDate_1.CronDate(options.startDate, this.#tz) : null;
45
+ this.#endDate = options.endDate ? new CronDate_1.CronDate(options.endDate, this.#tz) : null;
46
+ let currentDateValue = options.currentDate ?? options.startDate;
47
+ if (currentDateValue) {
48
+ const tempCurrentDate = new CronDate_1.CronDate(currentDateValue, this.#tz);
49
+ if (this.#startDate && tempCurrentDate.getTime() < this.#startDate.getTime()) {
50
+ currentDateValue = this.#startDate;
51
+ }
52
+ else if (this.#endDate && tempCurrentDate.getTime() > this.#endDate.getTime()) {
53
+ currentDateValue = this.#endDate;
54
+ }
55
+ }
56
+ this.#currentDate = new CronDate_1.CronDate(currentDateValue, this.#tz);
57
+ this.#fields = fields;
58
+ }
59
+ /**
60
+ * Getter for the cron fields.
61
+ *
62
+ * @returns {CronFieldCollection} Cron fields.
63
+ */
64
+ get fields() {
65
+ return this.#fields;
66
+ }
67
+ /**
68
+ * Converts cron fields back to a CronExpression instance.
69
+ *
70
+ * @public
71
+ * @param {Record<string, number[]>} fields - The input cron fields object.
72
+ * @param {CronExpressionOptions} [options] - Optional parsing options.
73
+ * @returns {CronExpression} - A new CronExpression instance.
74
+ */
75
+ static fieldsToExpression(fields, options) {
76
+ return new CronExpression(fields, options || {});
77
+ }
78
+ /**
79
+ * Checks if the given value matches any element in the sequence.
80
+ *
81
+ * @param {number} value - The value to be matched.
82
+ * @param {number[]} sequence - The sequence to be checked against.
83
+ * @returns {boolean} - True if the value matches an element in the sequence; otherwise, false.
84
+ * @memberof CronExpression
85
+ * @private
86
+ */
87
+ static #matchSchedule(value, sequence) {
88
+ return sequence.some((element) => element === value);
89
+ }
90
+ /**
91
+ * Determines if the current date matches the last specified weekday of the month.
92
+ *
93
+ * @param {Array<(number|string)>} expressions - An array of expressions containing weekdays and "L" for the last weekday.
94
+ * @param {CronDate} currentDate - The current date object.
95
+ * @returns {boolean} - True if the current date matches the last specified weekday of the month; otherwise, false.
96
+ * @memberof CronExpression
97
+ * @private
98
+ */
99
+ static #isLastWeekdayOfMonthMatch(expressions, currentDate) {
100
+ const isLastWeekdayOfMonth = currentDate.isLastWeekdayOfMonth();
101
+ return expressions.some((expression) => {
102
+ // The first character represents the weekday
103
+ const weekday = parseInt(expression.toString().charAt(0), 10) % 7;
104
+ if (Number.isNaN(weekday)) {
105
+ throw new Error(`Invalid last weekday of the month expression: ${expression}`);
106
+ }
107
+ // Check if the current date matches the last specified weekday of the month
108
+ return currentDate.getDay() === weekday && isLastWeekdayOfMonth;
109
+ });
110
+ }
111
+ /**
112
+ * Find the next scheduled date based on the cron expression.
113
+ * @returns {CronDate} - The next scheduled date or an ES6 compatible iterator object.
114
+ * @memberof CronExpression
115
+ * @public
116
+ */
117
+ next() {
118
+ return this.#findSchedule();
119
+ }
120
+ /**
121
+ * Find the previous scheduled date based on the cron expression.
122
+ * @returns {CronDate} - The previous scheduled date or an ES6 compatible iterator object.
123
+ * @memberof CronExpression
124
+ * @public
125
+ */
126
+ prev() {
127
+ return this.#findSchedule(true);
128
+ }
129
+ /**
130
+ * Check if there is a next scheduled date based on the current date and cron expression.
131
+ * @returns {boolean} - Returns true if there is a next scheduled date, false otherwise.
132
+ * @memberof CronExpression
133
+ * @public
134
+ */
135
+ hasNext() {
136
+ const current = this.#currentDate;
137
+ try {
138
+ this.#findSchedule();
139
+ return true;
140
+ }
141
+ catch {
142
+ return false;
143
+ }
144
+ finally {
145
+ this.#currentDate = current;
146
+ }
147
+ }
148
+ /**
149
+ * Check if there is a previous scheduled date based on the current date and cron expression.
150
+ * @returns {boolean} - Returns true if there is a previous scheduled date, false otherwise.
151
+ * @memberof CronExpression
152
+ * @public
153
+ */
154
+ hasPrev() {
155
+ const current = this.#currentDate;
156
+ try {
157
+ this.#findSchedule(true);
158
+ return true;
159
+ }
160
+ catch {
161
+ return false;
162
+ }
163
+ finally {
164
+ this.#currentDate = current;
165
+ }
166
+ }
167
+ /**
168
+ * Iterate over a specified number of steps and optionally execute a callback function for each step.
169
+ * @param {number} steps - The number of steps to iterate. Positive value iterates forward, negative value iterates backward.
170
+ * @returns {CronDate[]} - An array of iterator fields or CronDate objects.
171
+ * @memberof CronExpression
172
+ * @public
173
+ */
174
+ take(limit) {
175
+ const items = [];
176
+ if (limit >= 0) {
177
+ for (let i = 0; i < limit; i++) {
178
+ try {
179
+ items.push(this.next());
180
+ }
181
+ catch {
182
+ return items;
183
+ }
184
+ }
185
+ }
186
+ else {
187
+ for (let i = 0; i > limit; i--) {
188
+ try {
189
+ items.push(this.prev());
190
+ }
191
+ catch {
192
+ return items;
193
+ }
194
+ }
195
+ }
196
+ return items;
197
+ }
198
+ /**
199
+ * Reset the iterators current date to a new date or the initial date.
200
+ * @param {Date | CronDate} [newDate] - Optional new date to reset to. If not provided, it will reset to the initial date.
201
+ * @memberof CronExpression
202
+ * @public
203
+ */
204
+ reset(newDate) {
205
+ this.#currentDate = new CronDate_1.CronDate(newDate || this.#options.currentDate);
206
+ }
207
+ /**
208
+ * Generate a string representation of the cron expression.
209
+ * @param {boolean} [includeSeconds=false] - Whether to include the seconds field in the string representation.
210
+ * @returns {string} - The string representation of the cron expression.
211
+ * @memberof CronExpression
212
+ * @public
213
+ */
214
+ stringify(includeSeconds = false) {
215
+ return this.#fields.stringify(includeSeconds);
216
+ }
217
+ /**
218
+ * Check if the cron expression includes the given date
219
+ * @param {Date|CronDate} date
220
+ * @returns {boolean}
221
+ */
222
+ includesDate(date) {
223
+ const { second, minute, hour, month } = this.#fields;
224
+ const dt = new CronDate_1.CronDate(date, this.#tz);
225
+ // Check basic time fields first
226
+ if (!second.values.includes(dt.getSeconds()) ||
227
+ !minute.values.includes(dt.getMinutes()) ||
228
+ !hour.values.includes(dt.getHours()) ||
229
+ !month.values.includes((dt.getMonth() + 1))) {
230
+ return false;
231
+ }
232
+ // Check day of month and day of week using the same logic as #findSchedule
233
+ if (!this.#matchDayOfMonth(dt)) {
234
+ return false;
235
+ }
236
+ // Check nth day of week if specified
237
+ if (this.#fields.dayOfWeek.nthDay > 0) {
238
+ const weekInMonth = Math.ceil(dt.getDate() / 7);
239
+ if (weekInMonth !== this.#fields.dayOfWeek.nthDay) {
240
+ return false;
241
+ }
242
+ }
243
+ return true;
244
+ }
245
+ /**
246
+ * Returns the string representation of the cron expression.
247
+ * @returns {CronDate} - The next schedule date.
248
+ */
249
+ toString() {
250
+ /* istanbul ignore next - should be impossible under normal use to trigger the or branch */
251
+ return this.#options.expression || this.stringify(true);
252
+ }
253
+ /**
254
+ * Determines if the given date matches the cron expression's day of month and day of week fields.
255
+ *
256
+ * The function checks the following rules:
257
+ * Rule 1: If both "day of month" and "day of week" are restricted (not wildcard), then one or both must match the current day.
258
+ * Rule 2: If "day of month" is restricted and "day of week" is not restricted, then "day of month" must match the current day.
259
+ * Rule 3: If "day of month" is a wildcard, "day of week" is not a wildcard, and "day of week" matches the current day, then the match is accepted.
260
+ * If none of the rules match, the match is rejected.
261
+ *
262
+ * @param {CronDate} currentDate - The current date to be evaluated against the cron expression.
263
+ * @returns {boolean} Returns true if the current date matches the cron expression's day of month and day of week fields, otherwise false.
264
+ * @memberof CronExpression
265
+ * @private
266
+ */
267
+ #matchDayOfMonth(currentDate) {
268
+ // Check if day of month and day of week fields are wildcards or restricted (not wildcard).
269
+ const isDayOfMonthWildcardMatch = this.#fields.dayOfMonth.isWildcard;
270
+ const isRestrictedDayOfMonth = !isDayOfMonthWildcardMatch;
271
+ const isDayOfWeekWildcardMatch = this.#fields.dayOfWeek.isWildcard;
272
+ const isRestrictedDayOfWeek = !isDayOfWeekWildcardMatch;
273
+ // Calculate if the current date matches the day of month and day of week fields.
274
+ const matchedDOM = CronExpression.#matchSchedule(currentDate.getDate(), this.#fields.dayOfMonth.values) ||
275
+ (this.#fields.dayOfMonth.hasLastChar && currentDate.isLastDayOfMonth());
276
+ const matchedDOW = CronExpression.#matchSchedule(currentDate.getDay(), this.#fields.dayOfWeek.values) ||
277
+ (this.#fields.dayOfWeek.hasLastChar &&
278
+ CronExpression.#isLastWeekdayOfMonthMatch(this.#fields.dayOfWeek.values, currentDate));
279
+ // Rule 1: Both "day of month" and "day of week" are restricted; one or both must match the current day.
280
+ if (isRestrictedDayOfMonth && isRestrictedDayOfWeek && (matchedDOM || matchedDOW)) {
281
+ return true;
282
+ }
283
+ // Rule 2: "day of month" restricted and "day of week" not restricted; "day of month" must match the current day.
284
+ if (matchedDOM && !isRestrictedDayOfWeek) {
285
+ return true;
286
+ }
287
+ // Rule 3: "day of month" is a wildcard, "day of week" is not a wildcard, and "day of week" matches the current day.
288
+ if (isDayOfMonthWildcardMatch && !isDayOfWeekWildcardMatch && matchedDOW) {
289
+ return true;
290
+ }
291
+ // If none of the rules match, the match is rejected.
292
+ return false;
293
+ }
294
+ /**
295
+ * Determines if the current hour matches the cron expression.
296
+ *
297
+ * @param {CronDate} currentDate - The current date object.
298
+ * @param {DateMathOp} dateMathVerb - The date math operation enumeration value.
299
+ * @param {boolean} reverse - A flag indicating whether the matching should be done in reverse order.
300
+ * @returns {boolean} - True if the current hour matches the cron expression; otherwise, false.
301
+ */
302
+ #matchHour(currentDate, dateMathVerb, reverse) {
303
+ const currentHour = currentDate.getHours();
304
+ const isMatch = CronExpression.#matchSchedule(currentHour, this.#fields.hour.values);
305
+ const isDstStart = currentDate.dstStart === currentHour;
306
+ const isDstEnd = currentDate.dstEnd === currentHour;
307
+ if (!isMatch && !isDstStart) {
308
+ currentDate.dstStart = null;
309
+ currentDate.applyDateOperation(dateMathVerb, CronDate_1.TimeUnit.Hour, this.#fields.hour.values.length);
310
+ return false;
311
+ }
312
+ if (isDstStart && !CronExpression.#matchSchedule(currentHour - 1, this.#fields.hour.values)) {
313
+ currentDate.invokeDateOperation(dateMathVerb, CronDate_1.TimeUnit.Hour);
314
+ return false;
315
+ }
316
+ if (isDstEnd && !reverse) {
317
+ currentDate.dstEnd = null;
318
+ currentDate.applyDateOperation(CronDate_1.DateMathOp.Add, CronDate_1.TimeUnit.Hour, this.#fields.hour.values.length);
319
+ return false;
320
+ }
321
+ return true;
322
+ }
323
+ /**
324
+ * Validates the current date against the start and end dates of the cron expression.
325
+ * If the current date is outside the specified time span, an error is thrown.
326
+ *
327
+ * @param currentDate {CronDate} - The current date to validate.
328
+ * @throws {Error} If the current date is outside the specified time span.
329
+ * @private
330
+ */
331
+ #validateTimeSpan(currentDate) {
332
+ if (!this.#startDate && !this.#endDate) {
333
+ return;
334
+ }
335
+ const currentTime = currentDate.getTime();
336
+ if (this.#startDate && currentTime < this.#startDate.getTime()) {
337
+ throw new Error(exports.TIME_SPAN_OUT_OF_BOUNDS_ERROR_MESSAGE);
338
+ }
339
+ if (this.#endDate && currentTime > this.#endDate.getTime()) {
340
+ throw new Error(exports.TIME_SPAN_OUT_OF_BOUNDS_ERROR_MESSAGE);
341
+ }
342
+ }
343
+ /**
344
+ * Finds the next or previous schedule based on the cron expression.
345
+ *
346
+ * @param {boolean} [reverse=false] - If true, finds the previous schedule; otherwise, finds the next schedule.
347
+ * @returns {CronDate} - The next or previous schedule date.
348
+ * @private
349
+ */
350
+ #findSchedule(reverse = false) {
351
+ const dateMathVerb = reverse ? CronDate_1.DateMathOp.Subtract : CronDate_1.DateMathOp.Add;
352
+ const currentDate = new CronDate_1.CronDate(this.#currentDate);
353
+ const startTimestamp = currentDate.getTime();
354
+ let stepCount = 0;
355
+ while (++stepCount < LOOP_LIMIT) {
356
+ this.#validateTimeSpan(currentDate);
357
+ if (!this.#matchDayOfMonth(currentDate)) {
358
+ currentDate.applyDateOperation(dateMathVerb, CronDate_1.TimeUnit.Day, this.#fields.hour.values.length);
359
+ continue;
360
+ }
361
+ if (!(this.#fields.dayOfWeek.nthDay <= 0 || Math.ceil(currentDate.getDate() / 7) === this.#fields.dayOfWeek.nthDay)) {
362
+ currentDate.applyDateOperation(dateMathVerb, CronDate_1.TimeUnit.Day, this.#fields.hour.values.length);
363
+ continue;
364
+ }
365
+ if (!CronExpression.#matchSchedule(currentDate.getMonth() + 1, this.#fields.month.values)) {
366
+ currentDate.applyDateOperation(dateMathVerb, CronDate_1.TimeUnit.Month, this.#fields.hour.values.length);
367
+ continue;
368
+ }
369
+ if (!this.#matchHour(currentDate, dateMathVerb, reverse)) {
370
+ continue;
371
+ }
372
+ if (!CronExpression.#matchSchedule(currentDate.getMinutes(), this.#fields.minute.values)) {
373
+ currentDate.applyDateOperation(dateMathVerb, CronDate_1.TimeUnit.Minute, this.#fields.hour.values.length);
374
+ continue;
375
+ }
376
+ if (!CronExpression.#matchSchedule(currentDate.getSeconds(), this.#fields.second.values)) {
377
+ currentDate.applyDateOperation(dateMathVerb, CronDate_1.TimeUnit.Second, this.#fields.hour.values.length);
378
+ continue;
379
+ }
380
+ if (startTimestamp === currentDate.getTime()) {
381
+ if (dateMathVerb === 'Add' || currentDate.getMilliseconds() === 0) {
382
+ currentDate.applyDateOperation(dateMathVerb, CronDate_1.TimeUnit.Second, this.#fields.hour.values.length);
383
+ }
384
+ continue;
385
+ }
386
+ break;
387
+ }
388
+ /* istanbul ignore next - should be impossible under normal use to trigger the branch */
389
+ if (stepCount > LOOP_LIMIT) {
390
+ throw new Error(exports.LOOPS_LIMIT_EXCEEDED_ERROR_MESSAGE);
391
+ }
392
+ if (currentDate.getMilliseconds() !== 0) {
393
+ currentDate.setMilliseconds(0);
394
+ }
395
+ this.#currentDate = currentDate;
396
+ return currentDate;
397
+ }
398
+ /**
399
+ * Returns an iterator for iterating through future CronDate instances
400
+ *
401
+ * @name Symbol.iterator
402
+ * @memberof CronExpression
403
+ * @returns {Iterator<CronDate>} An iterator object for CronExpression that returns CronDate values.
404
+ */
405
+ [Symbol.iterator]() {
406
+ return {
407
+ next: () => {
408
+ const schedule = this.#findSchedule();
409
+ return { value: schedule, done: !this.hasNext() };
410
+ },
411
+ };
412
+ }
413
+ }
414
+ exports.CronExpression = CronExpression;
415
+ exports.default = CronExpression;
416
+ } (CronExpression));
417
+ return CronExpression;
418
+ }
419
+
420
+ export { requireCronExpression as __require };