croner 5.6.3 → 5.7.0-dev.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.
- package/README.md +31 -182
- package/dist/croner.min.cjs +1 -1
- package/dist/croner.min.js +1 -1
- package/dist/croner.min.mjs +1 -1
- package/package.json +2 -2
- package/types/croner.d.ts +19 -2
- package/types/options.d.ts +13 -1
package/README.md
CHANGED
|
@@ -1,22 +1,21 @@
|
|
|
1
1
|
<p align="center">
|
|
2
2
|
<img src="https://cdn.jsdelivr.net/gh/hexagon/croner@master/croner.png" alt="Croner" width="150" height="150"><br>
|
|
3
|
-
Trigger functions or evaluate cron expressions in JavaScript or TypeScript. No dependencies.
|
|
3
|
+
Trigger functions or evaluate cron expressions in JavaScript or TypeScript. No dependencies. All features. Node. Deno. Bun. Browser. <br><br>Try it live on <a href="https://jsfiddle.net/hexag0n/hoa8kwsb/">jsfiddle</a>.<br>
|
|
4
4
|
</p>
|
|
5
5
|
|
|
6
|
-
# Croner
|
|
6
|
+
# Croner - Cron for JavaScript and TypeScript
|
|
7
7
|
|
|
8
|
-
|
|
8
|
+
[](https://badge.fury.io/js/croner) [](https://www.codacy.com/gh/Hexagon/croner/dashboard?utm_source=github.com&utm_medium=referral&utm_content=Hexagon/croner&utm_campaign=Badge_Grade) [](https://www.npmjs.org/package/croner)
|
|
9
9
|
 [](https://github.com/Hexagon/croner/blob/master/LICENSE)
|
|
10
10
|
|
|
11
11
|
* Trigger functions in JavaScript using [Cron](https://en.wikipedia.org/wiki/Cron#CRON_expression) syntax.
|
|
12
12
|
* Find the first date of the next month, the date of the next Tuesday, etc.
|
|
13
13
|
* Pause, resume, or stop execution after a task is scheduled.
|
|
14
|
-
* Works in Node.js >=7.6 (both require and import).
|
|
15
|
-
* Works in Deno >=1.16.
|
|
16
|
-
* Works in Bun >=0.2.2
|
|
14
|
+
* Works in Node.js >=7.6 (both require and import), Deno >=1.16 and Bun >=0.2.2.
|
|
17
15
|
* Works in browsers as standalone, UMD or ES-module.
|
|
18
|
-
*
|
|
19
|
-
*
|
|
16
|
+
* Schedule using specific target [time zones](/docs/EXAMPLES.md#time-zone).
|
|
17
|
+
* [Over-run protection](/docs/EXAMPLES.md#over-run-protection) with callback
|
|
18
|
+
* Built in [error handling](/docs/EXAMPLES.md#error-handling) with callback
|
|
20
19
|
* Includes [TypeScript](https://www.typescriptlang.org/) typings.
|
|
21
20
|
|
|
22
21
|
Quick examples:
|
|
@@ -37,7 +36,7 @@ console.log(Math.floor(msLeft/1000/3600/24) + " days left to next christmas eve"
|
|
|
37
36
|
|
|
38
37
|
// Run a function at a specific date/time using a non-local timezone (time is ISO 8601 local time)
|
|
39
38
|
// This will run 2023-01-23 00:00:00 according to the time in Asia/Kolkata
|
|
40
|
-
Cron('2023-01-23T00:00:00', { timezone: 'Asia/Kolkata' }, () => { console.log('Yay') });
|
|
39
|
+
Cron('2023-01-23T00:00:00', { timezone: 'Asia/Kolkata' }, () => { console.log('Yay!') });
|
|
41
40
|
|
|
42
41
|
```
|
|
43
42
|
|
|
@@ -54,6 +53,8 @@ Because the existing ones are not good enough. They have serious bugs, use bloat
|
|
|
54
53
|
| Browser (ESMCommonJS) | ✓ | ✓ | | | |
|
|
55
54
|
| Deno (ESM) | ✓ | | | | |
|
|
56
55
|
| **Features** |
|
|
56
|
+
| Over-run protection | ✓ | | | | |
|
|
57
|
+
| Error handling | ✓ | | | | |
|
|
57
58
|
| Typescript typings | ✓ | ✓ | | | |
|
|
58
59
|
| dom-AND-dow | ✓ | | | | |
|
|
59
60
|
| dom-OR-dow | ✓ | ✓ | ✓ | ✓ | ✓ |
|
|
@@ -107,6 +108,8 @@ Because the existing ones are not good enough. They have serious bugs, use bloat
|
|
|
107
108
|
|
|
108
109
|
## Installation
|
|
109
110
|
|
|
111
|
+
If you are migrating from a different library such as `cron` or `node-cron`, or upgrading from a older version of croner, see [MIGRATION.md](MIGRATION.md).
|
|
112
|
+
|
|
110
113
|
### Node.js
|
|
111
114
|
|
|
112
115
|
```npm install croner --save```
|
|
@@ -150,7 +153,7 @@ import Cron from "croner";
|
|
|
150
153
|
JavaScript
|
|
151
154
|
|
|
152
155
|
```javascript
|
|
153
|
-
import Cron from "https://deno.land/x/croner@5.6.
|
|
156
|
+
import Cron from "https://deno.land/x/croner@5.6.4/src/croner.js";
|
|
154
157
|
|
|
155
158
|
Cron("* * * * * *", () => {
|
|
156
159
|
console.log("This will run every second.");
|
|
@@ -160,7 +163,7 @@ Cron("* * * * * *", () => {
|
|
|
160
163
|
TypeScript
|
|
161
164
|
|
|
162
165
|
```typescript
|
|
163
|
-
import { Cron } from "https://deno.land/x/croner@5.6.
|
|
166
|
+
import { Cron } from "https://deno.land/x/croner@5.6.4/src/croner.js";
|
|
164
167
|
|
|
165
168
|
const _scheduler : Cron = new Cron("* * * * * *", () => {
|
|
166
169
|
console.log("This will run every second.");
|
|
@@ -233,7 +236,7 @@ job.stop();
|
|
|
233
236
|
|--------------|----------------|----------------|---------------------------------------|
|
|
234
237
|
| name | undefined | String | If you specify a name for the job, Croner will keep a reference to the job in exported array `scheduledJobs` |
|
|
235
238
|
| maxRuns | Infinite | Number | |
|
|
236
|
-
| catch | false | Boolean | Catch unhandled errors in triggered function. Passing `true` will silently ignore errors. Passing a callback function will trigger this callback on error. |
|
|
239
|
+
| catch | false | Boolean\|Function | Catch unhandled errors in triggered function. Passing `true` will silently ignore errors. Passing a callback function will trigger this callback on error. |
|
|
237
240
|
| timezone | undefined | String | Timezone in Europe/Stockholm format |
|
|
238
241
|
| startAt | undefined | String | ISO 8601 formatted datetime (2021-10-17T23:43:00)<br>in local time (according to timezone parameter if passed) |
|
|
239
242
|
| stopAt | undefined | String | ISO 8601 formatted datetime (2021-10-17T23:43:00)<br>in local time (according to timezone parameter if passed) |
|
|
@@ -243,6 +246,7 @@ job.stop();
|
|
|
243
246
|
| legacyMode | true | boolean | Combine day-of-month and day-of-week using true = OR, false = AND |
|
|
244
247
|
| unref | false | boolean | Setting this to true unrefs the internal timer, which allows the process to exit even if a cron job is running. |
|
|
245
248
|
| utcOffset | undefined | number | Schedule using a specific utc offset in minutes. This does not take care of daylight savings time, you probably want to use option `timezone` instead. |
|
|
249
|
+
| protect | undefined | boolean\|Function | Enabled over-run protection. Will block new triggers as long as an old trigger is in progrss. Pass either true of a callback function to enable |
|
|
246
250
|
|
|
247
251
|
> **Warning**
|
|
248
252
|
> Unreferencing timers (option `unref`) is only supported by Node.js and Deno.
|
|
@@ -252,14 +256,6 @@ job.stop();
|
|
|
252
256
|
|
|
253
257
|
The expressions used by Croner are very similar to those of Vixie Cron, but with a few additions and changes as outlined below:
|
|
254
258
|
|
|
255
|
-
* Croner expressions have the following additional modifiers:
|
|
256
|
-
- *?* A question mark is substituted with the time of Croner's initialization. For example `? ? * * * *` would be substituted with `25 8 * * * *` if the time is `<any hour>:08:25` at the time of `new Cron('? ? * * * *', <...>)`. The question mark can be used in any field.
|
|
257
|
-
- *L* L can be used in the day of the month field to specify the last day of the month.
|
|
258
|
-
|
|
259
|
-
* Croner allows you to pass a JavaScript Date object or an ISO 8601 formatted string as a pattern. The scheduled function will trigger at the specified date/time and only once. If you use a timezone different from the local timezone, you should pass the ISO 8601 local time in the target location and specify the timezone using the options (2nd parameter).
|
|
260
|
-
|
|
261
|
-
* Croner also allows you to change how the day-of-week and day-of-month conditions are combined. By default, Croner (and Vixie cron) will trigger when either the day-of-month OR the day-of-week conditions match. For example, `0 20 1 * MON` will trigger on the first of the month as well as each Monday. If you want to use AND (so that it only triggers on Mondays that are also the first of the month), you can pass `{ legacyMode: false }`. For more information, see issue [#53](https://github.com/Hexagon/croner/issues/53).
|
|
262
|
-
|
|
263
259
|
```javascript
|
|
264
260
|
// ┌──────────────── (optional) second (0 - 59)
|
|
265
261
|
// │ ┌────────────── minute (0 - 59)
|
|
@@ -272,6 +268,14 @@ The expressions used by Croner are very similar to those of Vixie Cron, but with
|
|
|
272
268
|
// * * * * * *
|
|
273
269
|
```
|
|
274
270
|
|
|
271
|
+
* Croner expressions have the following additional modifiers:
|
|
272
|
+
- *?* A question mark is substituted with the time of Croner's initialization. For example `? ? * * * *` would be substituted with `25 8 * * * *` if the time is `<any hour>:08:25` at the time of `new Cron('? ? * * * *', <...>)`. The question mark can be used in any field.
|
|
273
|
+
- *L* L can be used in the day of the month field to specify the last day of the month.
|
|
274
|
+
|
|
275
|
+
* Croner allows you to pass a JavaScript Date object or an ISO 8601 formatted string as a pattern. The scheduled function will trigger at the specified date/time and only once. If you use a timezone different from the local timezone, you should pass the ISO 8601 local time in the target location and specify the timezone using the options (2nd parameter).
|
|
276
|
+
|
|
277
|
+
* Croner also allows you to change how the day-of-week and day-of-month conditions are combined. By default, Croner (and Vixie cron) will trigger when either the day-of-month OR the day-of-week conditions match. For example, `0 20 1 * MON` will trigger on the first of the month as well as each Monday. If you want to use AND (so that it only triggers on Mondays that are also the first of the month), you can pass `{ legacyMode: false }`. For more information, see issue [#53](https://github.com/Hexagon/croner/issues/53).
|
|
278
|
+
|
|
275
279
|
| Field | Required | Allowed values | Allowed special characters | Remarks |
|
|
276
280
|
|--------------|----------|----------------|----------------------------|---------------------------------------|
|
|
277
281
|
| Seconds | Optional | 0-59 | * , - / ? | |
|
|
@@ -295,177 +299,22 @@ It is also possible to use the following "nicknames" as pattern.
|
|
|
295
299
|
| \@daily | Run once a day, ie. "0 0 * * *". |
|
|
296
300
|
| \@hourly | Run once an hour, ie. "0 * * * *". |
|
|
297
301
|
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
#### Expressions
|
|
301
|
-
```javascript
|
|
302
|
-
// Run a function according to pattern
|
|
303
|
-
Cron('15-45/10 */5 1,2,3 ? JAN-MAR SAT', { legacyMode: false }, function () {
|
|
304
|
-
console.log('This will run every tenth second between second 15-45');
|
|
305
|
-
console.log('every fifth minute of hour 1,2 and 3 when day of month');
|
|
306
|
-
console.log('is the same as when Cron started, every saturday in January to March.');
|
|
307
|
-
});
|
|
308
|
-
```
|
|
309
|
-
|
|
310
|
-
#### Interval
|
|
311
|
-
```javascript
|
|
312
|
-
// Trigger on specific interval combined with cron expression
|
|
313
|
-
Cron('* * * 7-16 * MON-FRI', { interval: 90, legacyMode: false }, function () {
|
|
314
|
-
console.log('This will trigger every 90th second at 7-16 on mondays to fridays.');
|
|
315
|
-
});
|
|
316
|
-
```
|
|
317
|
-
|
|
318
|
-
#### Find dates
|
|
319
|
-
```javascript
|
|
320
|
-
// Find next month
|
|
321
|
-
const nextMonth = Cron("@monthly").next(),
|
|
322
|
-
nextSunday = Cron("@weekly").next(),
|
|
323
|
-
nextSat29feb = Cron("0 0 0 29 2 6", { legacyMode: false }).next(),
|
|
324
|
-
nextSunLastOfMonth = Cron("0 0 0 L * 7", { legacyMode: false }).next();
|
|
325
|
-
|
|
326
|
-
console.log("First day of next month: " + nextMonth.toLocaleDateString());
|
|
327
|
-
console.log("Next sunday: " + nextSunday.toLocaleDateString());
|
|
328
|
-
console.log("Next saturday at 29th of february: " + nextSat29feb.toLocaleDateString()); // 2048-02-29
|
|
329
|
-
console.log("Next month ending with a sunday: " + nextSunLastOfMonth.toLocaleDateString());
|
|
330
|
-
```
|
|
331
|
-
|
|
332
|
-
#### With options
|
|
333
|
-
```javascript
|
|
334
|
-
|
|
335
|
-
const job = Cron(
|
|
336
|
-
'* * * * *',
|
|
337
|
-
{
|
|
338
|
-
maxRuns: Infinity,
|
|
339
|
-
startAt: "2021-11-01T00:00:00",
|
|
340
|
-
stopAt: "2021-12-01T00:00:00",
|
|
341
|
-
timezone: "Europe/Stockholm"
|
|
342
|
-
},
|
|
343
|
-
function() {
|
|
344
|
-
console.log('This will run every minute, from 2021-11-01 to 2021-12-01 00:00:00');
|
|
345
|
-
}
|
|
346
|
-
);
|
|
347
|
-
```
|
|
348
|
-
|
|
349
|
-
#### Job controls
|
|
350
|
-
```javascript
|
|
351
|
-
const job = Cron('* * * * * *', (self) => {
|
|
352
|
-
console.log('This will run every second. Pause on second 10. Resume on 15. And quit on 20.');
|
|
353
|
-
console.log('Current second: ', new Date().getSeconds());
|
|
354
|
-
console.log('Previous run: ' + self.previous());
|
|
355
|
-
console.log('Next run: ' + self.next());
|
|
356
|
-
});
|
|
357
|
-
|
|
358
|
-
Cron('10 * * * * *', {maxRuns: 1}, () => job.pause());
|
|
359
|
-
Cron('15 * * * * *', {maxRuns: 1}, () => job.resume());
|
|
360
|
-
Cron('20 * * * * *', {maxRuns: 1}, () => job.stop());
|
|
361
|
-
```
|
|
362
|
-
|
|
363
|
-
#### Passing a context
|
|
364
|
-
```javascript
|
|
365
|
-
const data = {
|
|
366
|
-
what: "stuff"
|
|
367
|
-
};
|
|
368
|
-
|
|
369
|
-
Cron('* * * * * *', { context: data }, (_self, context) => {
|
|
370
|
-
console.log('This will print stuff: ' + context.what);
|
|
371
|
-
});
|
|
372
|
-
|
|
373
|
-
Cron('*/5 * * * * *', { context: data }, (self, context) => {
|
|
374
|
-
console.log('After this, other stuff will be printed instead');
|
|
375
|
-
context.what = "other stuff";
|
|
376
|
-
self.stop();
|
|
377
|
-
});
|
|
378
|
-
```
|
|
379
|
-
|
|
380
|
-
#### Fire on a specific date/time
|
|
381
|
-
```javascript
|
|
382
|
-
// A javascript date, or a ISO 8601 local time string can be passed, to fire a function once.
|
|
383
|
-
// Always specify which timezone the ISO 8601 time string has with the timezone option.
|
|
384
|
-
let job = Cron("2025-01-01T23:00:00",{timezone: "Europe/Stockholm"},() => {
|
|
385
|
-
console.log('This will run at 2025-01-01 23:00:00 in timezone Europe/Stockholm');
|
|
386
|
-
});
|
|
387
|
-
|
|
388
|
-
if (job.next() === null) {
|
|
389
|
-
// The job will not fire for some reason
|
|
390
|
-
} else {
|
|
391
|
-
console.log("Job will fire at " + job.next());
|
|
392
|
-
}
|
|
393
|
-
```
|
|
394
|
-
|
|
395
|
-
#### Naming jobs
|
|
396
|
-
|
|
397
|
-
If you provide a name for the job using the option { name: '...' }, a reference to the job will be stored in the exported array `scheduledJobs`. Naming a job makes it accessible throughout your application.
|
|
398
|
-
|
|
399
|
-
> **Note**
|
|
400
|
-
> If a job is stopped using `.stop()`, and goes out of scope, it will normally be eligible for garbage collection and will be deleted during the next garbage collection cycle. Keeping a reference by specifying option `name` prevents this from happening.
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
```javascript
|
|
404
|
-
// import { Cron, scheduledJobs } ...
|
|
405
|
-
|
|
406
|
-
// Scoped job
|
|
407
|
-
(() => {
|
|
408
|
-
|
|
409
|
-
// As we specify a name for the job, a reference will be kept in `scheduledJobs`
|
|
410
|
-
const job = Cron("* * * * * *", { name: "Job1" }, function () {
|
|
411
|
-
console.log("This will run every second");
|
|
412
|
-
});
|
|
413
|
-
|
|
414
|
-
job.pause();
|
|
415
|
-
console.log("Job paused");
|
|
302
|
+
## Contributing
|
|
416
303
|
|
|
417
|
-
|
|
304
|
+
### Master branch
|
|
418
305
|
|
|
419
|
-
|
|
420
|
-
setTimeout(() => {
|
|
306
|
+
  
|
|
421
307
|
|
|
422
|
-
|
|
423
|
-
// - scheduledJobs can either be imported separately { Cron, scheduledJobs }
|
|
424
|
-
// or access through Cron.scheduledJobs
|
|
425
|
-
const job = scheduledJobs.find(j => j.name === "Job1");
|
|
308
|
+
### Dev branch
|
|
426
309
|
|
|
427
|
-
|
|
428
|
-
if (job) {
|
|
429
|
-
if(job.resume()) {
|
|
430
|
-
// This will happen
|
|
431
|
-
console.log("Job resumed successfully");
|
|
432
|
-
} else {
|
|
433
|
-
console.log("Job found, but could not be restarted. The job were probably stopped using `.stop()` which prevents resuming.");
|
|
434
|
-
}
|
|
435
|
-
} else {
|
|
436
|
-
console.error("Job not found");
|
|
437
|
-
}
|
|
310
|
+
  
|
|
438
311
|
|
|
439
|
-
|
|
312
|
+
All development happen in the dev branch, you can install latest development version of croner using
|
|
440
313
|
|
|
441
314
|
```
|
|
442
|
-
|
|
443
|
-
#### Act at completion
|
|
444
|
-
|
|
445
|
-
```javascript
|
|
446
|
-
// Start a job firing once each 5th second, run at most 3 times
|
|
447
|
-
const job = new Cron("0/5 * * * * *", { maxRuns: 3 }, (job) => {
|
|
448
|
-
|
|
449
|
-
// Do work
|
|
450
|
-
console.log('Job Running');
|
|
451
|
-
|
|
452
|
-
// Is this the last execution?
|
|
453
|
-
if (!job.next()) {
|
|
454
|
-
console.log('Last execution');
|
|
455
|
-
}
|
|
456
|
-
|
|
457
|
-
});
|
|
458
|
-
|
|
459
|
-
// Will there be no executions?
|
|
460
|
-
// This would trigger if you change maxRuns to 0, or manage to compose
|
|
461
|
-
// an impossible cron expression.
|
|
462
|
-
if (!job.next() && !job.previous()) {
|
|
463
|
-
console.log('No executions scheduled');
|
|
464
|
-
}
|
|
315
|
+
npm install croner@dev
|
|
465
316
|
```
|
|
466
317
|
|
|
467
|
-
## Contributing
|
|
468
|
-
|
|
469
318
|
See [Contribution Guide](/CONTRIBUTING.md)
|
|
470
319
|
|
|
471
320
|
... or ...
|
package/dist/croner.min.cjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
(function(global,factory){typeof exports==="object"&&typeof module!=="undefined"?module.exports=factory():typeof define==="function"&&define.amd?define(factory):(global=typeof globalThis!=="undefined"?globalThis:global||self,global.Cron=factory())})(this,function(){"use strict";function minitz(y,m,d,h,i,s,tz,throwOnInvalid){return minitz.fromTZ(minitz.tp(y,m,d,h,i,s,tz),throwOnInvalid)}minitz.fromTZISO=(localTimeStr,tz,throwOnInvalid)=>{return minitz.fromTZ(parseISOLocal(localTimeStr,tz),throwOnInvalid)};minitz.fromTZ=function(tp,throwOnInvalid){const inDate=new Date(Date.UTC(tp.y,tp.m-1,tp.d,tp.h,tp.i,tp.s)),offset=getTimezoneOffset(tp.tz,inDate),dateGuess=new Date(inDate.getTime()-offset),dateOffsGuess=getTimezoneOffset(tp.tz,dateGuess);if(dateOffsGuess-offset===0){return dateGuess}else{const dateGuess2=new Date(inDate.getTime()-dateOffsGuess),dateOffsGuess2=getTimezoneOffset(tp.tz,dateGuess2);if(dateOffsGuess2-dateOffsGuess===0){return dateGuess2}else if(!throwOnInvalid&&dateOffsGuess2-dateOffsGuess>0){return dateGuess2}else if(!throwOnInvalid){return dateGuess}else{throw new Error("Invalid date passed to fromTZ()")}}};minitz.toTZ=function(d,tzStr){const td=new Date(d.toLocaleString("sv-SE",{timeZone:tzStr}));return{y:td.getFullYear(),m:td.getMonth()+1,d:td.getDate(),h:td.getHours(),i:td.getMinutes(),s:td.getSeconds(),tz:tzStr}};minitz.tp=(y,m,d,h,i,s,tz)=>{return{y:y,m:m,d:d,h:h,i:i,s:s,tz:tz}};function getTimezoneOffset(timeZone,date=new Date){const tz=date.toLocaleString("en",{timeZone:timeZone,timeStyle:"long"}).split(" ").slice(-1)[0];const dateString=date.toLocaleString("en-US").replace(/[\u202f]/," ");return Date.parse(`${dateString} GMT`)-Date.parse(`${dateString} ${tz}`)}function parseISOLocal(dtStr,tz){const pd=new Date(Date.parse(dtStr));if(isNaN(pd)){throw new Error("minitz: Invalid ISO8601 passed to parser.")}const stringEnd=dtStr.substring(9);if(dtStr.includes("Z")||stringEnd.includes("-")||stringEnd.includes("+")){return minitz.tp(pd.getUTCFullYear(),pd.getUTCMonth()+1,pd.getUTCDate(),pd.getUTCHours(),pd.getUTCMinutes(),pd.getUTCSeconds(),"Etc/UTC")}else{return minitz.tp(pd.getFullYear(),pd.getMonth()+1,pd.getDate(),pd.getHours(),pd.getMinutes(),pd.getSeconds(),tz)}}minitz.minitz=minitz;function CronOptions(options){if(options===void 0){options={}}delete options.name;options.legacyMode=options.legacyMode===void 0?true:options.legacyMode;options.paused=options.paused===void 0?false:options.paused;options.maxRuns=options.maxRuns===void 0?Infinity:options.maxRuns;options.catch=options.catch===void 0?false:options.catch;options.interval=options.interval===void 0?0:parseInt(options.interval,10);options.utcOffset=options.utcOffset===void 0?void 0:parseInt(options.utcOffset,10);options.unref=options.unref===void 0?false:options.unref;options.kill=false;if(options.startAt){options.startAt=new CronDate(options.startAt,options.timezone)}if(options.stopAt){options.stopAt=new CronDate(options.stopAt,options.timezone)}if(options.interval!==null){if(isNaN(options.interval)){throw new Error("CronOptions: Supplied value for interval is not a number")}else if(options.interval<0){throw new Error("CronOptions: Supplied value for interval can not be negative")}}if(options.utcOffset!==void 0){if(isNaN(options.utcOffset)){throw new Error("CronOptions: Invalid value passed for utcOffset, should be number representing minutes offset from UTC.")}else if(options.utcOffset<-870||options.utcOffset>870){throw new Error("CronOptions: utcOffset out of bounds.")}if(options.utcOffset!==void 0&&options.timezone){throw new Error("CronOptions: Combining 'utcOffset' with 'timezone' is not allowed.")}}if(options.unref!==true&&options.unref!==false){throw new Error("CronOptions: Unref should be either true, false or undefined(false).")}return options}const DaysOfMonth=[31,28,31,30,31,30,31,31,30,31,30,31];const RecursionSteps=[["month","year",0],["day","month",-1],["hour","day",0],["minute","hour",0],["second","minute",0]];function CronDate(d,tz){this.tz=tz;if(d&&d instanceof Date){if(!isNaN(d)){this.fromDate(d)}else{throw new TypeError("CronDate: Invalid date passed to CronDate constructor")}}else if(d===void 0){this.fromDate(new Date)}else if(d&&typeof d==="string"){this.fromString(d)}else if(d instanceof CronDate){this.fromCronDate(d)}else{throw new TypeError("CronDate: Invalid type ("+typeof d+") passed to CronDate constructor")}}CronDate.prototype.fromDate=function(inDate){if(this.tz!==void 0){if(typeof this.tz==="number"){this.ms=inDate.getMilliseconds();this.second=inDate.getSeconds();this.minute=inDate.getMinutes()+this.tz;this.hour=inDate.getHours();this.day=inDate.getDate();this.month=inDate.getMonth();this.year=inDate.getFullYear();this.apply()}else{const d=minitz.toTZ(inDate,this.tz);this.ms=inDate.getMilliseconds();this.second=d.s;this.minute=d.i;this.hour=d.h;this.day=d.d;this.month=d.m-1;this.year=d.y}}else{this.ms=inDate.getMilliseconds();this.second=inDate.getSeconds();this.minute=inDate.getMinutes();this.hour=inDate.getHours();this.day=inDate.getDate();this.month=inDate.getMonth();this.year=inDate.getFullYear()}};CronDate.prototype.fromCronDate=function(d){this.tz=d.tz;this.year=d.year;this.month=d.month;this.day=d.day;this.hour=d.hour;this.minute=d.minute;this.second=d.second;this.ms=d.ms};CronDate.prototype.apply=function(){if(this.month>11||this.day>DaysOfMonth[this.month]||this.hour>59||this.minute>59||this.second>59||this.hour<0||this.minute<0||this.second<0){const d=new Date(Date.UTC(this.year,this.month,this.day,this.hour,this.minute,this.second,this.ms));this.ms=d.getUTCMilliseconds();this.second=d.getUTCSeconds();this.minute=d.getUTCMinutes();this.hour=d.getUTCHours();this.day=d.getUTCDate();this.month=d.getUTCMonth();this.year=d.getUTCFullYear();return true}else{return false}};CronDate.prototype.fromString=function(str){return this.fromDate(minitz.fromTZISO(str,this.tz))};CronDate.prototype.findNext=function(options,target,pattern,offset){const originalTarget=this[target];let lastDayOfMonth;if(pattern.lastDayOfMonth){if(this.month!==1){lastDayOfMonth=DaysOfMonth[this.month]}else{lastDayOfMonth=new Date(Date.UTC(this.year,this.month+1,0,0,0,0,0)).getUTCDate()}}const fDomWeekDay=!pattern.starDOW&&target=="day"?new Date(Date.UTC(this.year,this.month,1,0,0,0,0)).getUTCDay():undefined;for(let i=this[target]+offset;i<pattern[target].length;i++){let match=pattern[target][i];if(target==="day"&&pattern.lastDayOfMonth&&i-offset==lastDayOfMonth){match=true}if(target==="day"&&!pattern.starDOW){const dowMatch=pattern.dow[(fDomWeekDay+(i-offset-1))%7];if(options.legacyMode&&!pattern.starDOM){match=match||dowMatch}else{match=match&&dowMatch}}if(match){this[target]=i-offset;return originalTarget!==this[target]?2:1}}return 3};CronDate.prototype.recurse=function(pattern,options,doing){const res=this.findNext(options,RecursionSteps[doing][0],pattern,RecursionSteps[doing][2]);if(res>1){let resetLevel=doing+1;while(resetLevel<RecursionSteps.length){this[RecursionSteps[resetLevel][0]]=-RecursionSteps[resetLevel][2];resetLevel++}if(res===3){this[RecursionSteps[doing][1]]++;this[RecursionSteps[doing][0]]=-RecursionSteps[doing][2];this.apply();return this.recurse(pattern,options,0)}else if(this.apply()){return this.recurse(pattern,options,doing-1)}}doing+=1;if(doing>=RecursionSteps.length){return this}else if(this.year>=3e3){return null}else{return this.recurse(pattern,options,doing)}};CronDate.prototype.increment=function(pattern,options,hasPreviousRun){if(options.interval>1&&hasPreviousRun){this.second+=options.interval}else{this.second+=1}this.ms=0;this.apply();return this.recurse(pattern,options,0)};CronDate.prototype.getDate=function(internal){if(internal||!(this.tz!==void 0)){return new Date(this.year,this.month,this.day,this.hour,this.minute,this.second,this.ms)}else{if(typeof this.tz==="number"){return new Date(Date.UTC(this.year,this.month,this.day,this.hour,this.minute-this.tz,this.second,this.ms))}else{return minitz(this.year,this.month+1,this.day,this.hour,this.minute,this.second,this.tz)}}};CronDate.prototype.getTime=function(){return this.getDate().getTime()};function CronPattern(pattern,timezone){this.pattern=pattern;this.timezone=timezone;this.second=Array(60).fill(0);this.minute=Array(60).fill(0);this.hour=Array(24).fill(0);this.day=Array(31).fill(0);this.month=Array(12).fill(0);this.dow=Array(8).fill(0);this.lastDayOfMonth=false;this.starDOM=false;this.starDOW=false;this.parse()}CronPattern.prototype.parse=function(){if(!(typeof this.pattern==="string"||this.pattern.constructor===String)){throw new TypeError("CronPattern: Pattern has to be of type string.")}if(this.pattern.indexOf("@")>=0)this.pattern=this.handleNicknames(this.pattern).trim();const parts=this.pattern.replace(/\s+/g," ").split(" ");if(parts.length<5||parts.length>6){throw new TypeError("CronPattern: invalid configuration format ('"+this.pattern+"'), exacly five or six space separated parts required.")}if(parts.length===5){parts.unshift("0")}if(parts[3].indexOf("L")>=0){parts[3]=parts[3].replace("L","");this.lastDayOfMonth=true}if(parts[3]=="*"){this.starDOM=true}if(parts[4].length>=3)parts[4]=this.replaceAlphaMonths(parts[4]);if(parts[5].length>=3)parts[5]=this.replaceAlphaDays(parts[5]);if(parts[5]=="*"){this.starDOW=true}if(this.pattern.indexOf("?")>=0){const initDate=new CronDate(new Date,this.timezone).getDate(true);parts[0]=parts[0].replace("?",initDate.getSeconds());parts[1]=parts[1].replace("?",initDate.getMinutes());parts[2]=parts[2].replace("?",initDate.getHours());if(!this.starDOM)parts[3]=parts[3].replace("?",initDate.getDate());parts[4]=parts[4].replace("?",initDate.getMonth()+1);if(!this.starDOW)parts[5]=parts[5].replace("?",initDate.getDay())}this.throwAtIllegalCharacters(parts);this.partToArray("second",parts[0],0);this.partToArray("minute",parts[1],0);this.partToArray("hour",parts[2],0);this.partToArray("day",parts[3],-1);this.partToArray("month",parts[4],-1);this.partToArray("dow",parts[5],0);if(this.dow[7]){this.dow[0]=1}};CronPattern.prototype.partToArray=function(type,conf,valueIndexOffset){const arr=this[type];if(conf==="*")return arr.fill(1);const split=conf.split(",");if(split.length>1){for(let i=0;i<split.length;i++){this.partToArray(type,split[i],valueIndexOffset)}}else if(conf.indexOf("-")!==-1&&conf.indexOf("/")!==-1){this.handleRangeWithStepping(conf,type,valueIndexOffset)}else if(conf.indexOf("-")!==-1){this.handleRange(conf,type,valueIndexOffset)}else if(conf.indexOf("/")!==-1){this.handleStepping(conf,type,valueIndexOffset)}else if(conf!==""){this.handleNumber(conf,type,valueIndexOffset)}};CronPattern.prototype.throwAtIllegalCharacters=function(parts){const reValidCron=/[^/*0-9,-]+/;for(let i=0;i<parts.length;i++){if(reValidCron.test(parts[i])){throw new TypeError("CronPattern: configuration entry "+i+" ("+parts[i]+") contains illegal characters.")}}};CronPattern.prototype.handleNumber=function(conf,type,valueIndexOffset){const i=parseInt(conf,10)+valueIndexOffset;if(isNaN(i)){throw new TypeError("CronPattern: "+type+" is not a number: '"+conf+"'")}if(i<0||i>=this[type].length){throw new TypeError("CronPattern: "+type+" value out of range: '"+conf+"'")}this[type][i]=1};CronPattern.prototype.handleRangeWithStepping=function(conf,type,valueIndexOffset){const matches=conf.match(/^(\d+)-(\d+)\/(\d+)$/);if(matches===null)throw new TypeError("CronPattern: Syntax error, illegal range with stepping: '"+conf+"'");let[,lower,upper,steps]=matches;lower=parseInt(lower,10)+valueIndexOffset;upper=parseInt(upper,10)+valueIndexOffset;steps=parseInt(steps,10);if(isNaN(lower))throw new TypeError("CronPattern: Syntax error, illegal lower range (NaN)");if(isNaN(upper))throw new TypeError("CronPattern: Syntax error, illegal upper range (NaN)");if(isNaN(steps))throw new TypeError("CronPattern: Syntax error, illegal stepping: (NaN)");if(steps===0)throw new TypeError("CronPattern: Syntax error, illegal stepping: 0");if(steps>this[type].length)throw new TypeError("CronPattern: Syntax error, steps cannot be greater than maximum value of part ("+this[type].length+")");if(lower<0||upper>=this[type].length)throw new TypeError("CronPattern: Value out of range: '"+conf+"'");if(lower>upper)throw new TypeError("CronPattern: From value is larger than to value: '"+conf+"'");for(let i=lower;i<=upper;i+=steps){this[type][i]=1}};CronPattern.prototype.handleRange=function(conf,type,valueIndexOffset){const split=conf.split("-");if(split.length!==2){throw new TypeError("CronPattern: Syntax error, illegal range: '"+conf+"'")}const lower=parseInt(split[0],10)+valueIndexOffset,upper=parseInt(split[1],10)+valueIndexOffset;if(isNaN(lower)){throw new TypeError("CronPattern: Syntax error, illegal lower range (NaN)")}else if(isNaN(upper)){throw new TypeError("CronPattern: Syntax error, illegal upper range (NaN)")}if(lower<0||upper>=this[type].length){throw new TypeError("CronPattern: Value out of range: '"+conf+"'")}if(lower>upper){throw new TypeError("CronPattern: From value is larger than to value: '"+conf+"'")}for(let i=lower;i<=upper;i++){this[type][i]=1}};CronPattern.prototype.handleStepping=function(conf,type){const split=conf.split("/");if(split.length!==2){throw new TypeError("CronPattern: Syntax error, illegal stepping: '"+conf+"'")}let start=0;if(split[0]!=="*"){start=parseInt(split[0],10)}const steps=parseInt(split[1],10);if(isNaN(steps))throw new TypeError("CronPattern: Syntax error, illegal stepping: (NaN)");if(steps===0)throw new TypeError("CronPattern: Syntax error, illegal stepping: 0");if(steps>this[type].length)throw new TypeError("CronPattern: Syntax error, max steps for part is ("+this[type].length+")");for(let i=start;i<this[type].length;i+=steps){this[type][i]=1}};CronPattern.prototype.replaceAlphaDays=function(conf){return conf.replace(/-sun/gi,"-7").replace(/sun/gi,"0").replace(/mon/gi,"1").replace(/tue/gi,"2").replace(/wed/gi,"3").replace(/thu/gi,"4").replace(/fri/gi,"5").replace(/sat/gi,"6")};CronPattern.prototype.replaceAlphaMonths=function(conf){return conf.replace(/jan/gi,"1").replace(/feb/gi,"2").replace(/mar/gi,"3").replace(/apr/gi,"4").replace(/may/gi,"5").replace(/jun/gi,"6").replace(/jul/gi,"7").replace(/aug/gi,"8").replace(/sep/gi,"9").replace(/oct/gi,"10").replace(/nov/gi,"11").replace(/dec/gi,"12")};CronPattern.prototype.handleNicknames=function(pattern){const cleanPattern=pattern.trim().toLowerCase();if(cleanPattern==="@yearly"||cleanPattern==="@annually"){return"0 0 1 1 *"}else if(cleanPattern==="@monthly"){return"0 0 1 * *"}else if(cleanPattern==="@weekly"){return"0 0 * * 0"}else if(cleanPattern==="@daily"){return"0 0 * * *"}else if(cleanPattern==="@hourly"){return"0 * * * *"}else{return pattern}};const maxDelay=Math.pow(2,32-1)-1;const scheduledJobs=[];function Cron(pattern,fnOrOptions1,fnOrOptions2){if(!(this instanceof Cron)){return new Cron(pattern,fnOrOptions1,fnOrOptions2)}let options,func;if(typeof fnOrOptions1==="function"){func=fnOrOptions1}else if(typeof fnOrOptions1==="object"){options=fnOrOptions1}else if(fnOrOptions1!==void 0){throw new Error("Cron: Invalid argument passed for optionsIn. Should be one of function, or object (options).")}if(typeof fnOrOptions2==="function"){func=fnOrOptions2}else if(typeof fnOrOptions2==="object"){options=fnOrOptions2}else if(fnOrOptions2!==void 0){throw new Error("Cron: Invalid argument passed for funcIn. Should be one of function, or object (options).")}this.name=options?options.name:void 0;this.options=CronOptions(options);this.once=void 0;this.pattern=void 0;if(pattern&&(pattern instanceof Date||typeof pattern==="string"&&pattern.indexOf(":")>0)){this.once=new CronDate(pattern,this.options.timezone||this.options.utcOffset)}else{this.pattern=new CronPattern(pattern,this.options.timezone)}if(func!==void 0){this.fn=func;this.schedule()}if(this.name){const existing=scheduledJobs.find(j=>j.name===this.name);if(existing){throw new Error("Cron: Tried to initialize new named job '"+this.name+"', but name already taken.")}else{scheduledJobs.push(this)}}return this}Cron.prototype.next=function(prev){const next=this._next(prev);return next?next.getDate():null};Cron.prototype.enumerate=function(n,previous){if(n>this.options.maxRuns){n=this.options.maxRuns}const enumeration=[];let prev=previous||this.previousrun;while(n--&&(prev=this.next(prev))){enumeration.push(prev)}return enumeration};Cron.prototype.running=function(){const msLeft=this.msToNext(this.previousrun);const running=!this.options.paused&&this.fn!==void 0;return msLeft!==null&&running};Cron.prototype.previous=function(){return this.previousrun?this.previousrun.getDate():null};Cron.prototype.msToNext=function(prev){const next=this._next(prev);prev=new CronDate(prev,this.options.timezone||this.options.utcOffset);if(next){return next.getTime(true)-prev.getTime(true)}else{return null}};Cron.prototype.stop=function(){this.options.kill=true;if(this.currentTimeout){clearTimeout(this.currentTimeout)}};Cron.prototype.pause=function(){return(this.options.paused=true)&&!this.options.kill};Cron.prototype.resume=function(){return!(this.options.paused=false)&&!this.options.kill};Cron.prototype.schedule=function(func,partial){if(func&&this.fn){throw new Error("Cron: It is not allowed to schedule two functions using the same Croner instance.")}else if(func){this.fn=func}let waitMs=this.msToNext(partial?partial:this.previousrun);const target=this.next(partial?partial:this.previousrun);if(waitMs===null)return this;if(waitMs>maxDelay){waitMs=maxDelay}this.currentTimeout=setTimeout(()=>{const now=new Date;if(waitMs!==maxDelay&&!this.options.paused&&now.getTime()>=target){this.options.maxRuns--;if(this.options.catch){(async inst=>{try{await inst.fn(inst,inst.options.context)}catch(_e){if(Object.prototype.toString.call(inst.options.catch)==="[object Function]"||"function"===typeof inst.options.catch||inst.options.catch instanceof Function){inst.options.catch(_e)}}})(this)}else{this.fn(this,this.options.context)}this.previousrun=new CronDate(void 0,this.options.timezone||this.options.utcOffset);this.schedule()}else{this.schedule(undefined,now)}},waitMs);if(this.currentTimeout&&this.options.unref){if(typeof Deno!=="undefined"&&typeof Deno.unrefTimer!=="undefined"){Deno.unrefTimer(this.currentTimeout)}else if(typeof this.currentTimeout.unref!=="undefined"){this.currentTimeout.unref()}}return this};Cron.prototype._next=function(prev){const hasPreviousRun=prev||this.previousrun?true:false;prev=new CronDate(prev,this.options.timezone||this.options.utcOffset);if(this.options.startAt&&prev&&prev.getTime()<this.options.startAt.getTime()){prev=this.options.startAt}const nextRun=this.once||new CronDate(prev,this.options.timezone||this.options.utcOffset).increment(this.pattern,this.options,hasPreviousRun);if(this.once&&this.once.getTime()<=prev.getTime()){return null}else if(nextRun===null||this.options.maxRuns<=0||this.options.kill||this.options.stopAt&&nextRun.getTime()>=this.options.stopAt.getTime()){return null}else{return nextRun}};Cron.Cron=Cron;Cron.scheduledJobs=scheduledJobs;return Cron});
|
|
1
|
+
(function(global,factory){typeof exports==="object"&&typeof module!=="undefined"?module.exports=factory():typeof define==="function"&&define.amd?define(factory):(global=typeof globalThis!=="undefined"?globalThis:global||self,global.Cron=factory())})(this,function(){"use strict";function minitz(y,m,d,h,i,s,tz,throwOnInvalid){return minitz.fromTZ(minitz.tp(y,m,d,h,i,s,tz),throwOnInvalid)}minitz.fromTZISO=(localTimeStr,tz,throwOnInvalid)=>{return minitz.fromTZ(parseISOLocal(localTimeStr,tz),throwOnInvalid)};minitz.fromTZ=function(tp,throwOnInvalid){const inDate=new Date(Date.UTC(tp.y,tp.m-1,tp.d,tp.h,tp.i,tp.s)),offset=getTimezoneOffset(tp.tz,inDate),dateGuess=new Date(inDate.getTime()-offset),dateOffsGuess=getTimezoneOffset(tp.tz,dateGuess);if(dateOffsGuess-offset===0){return dateGuess}else{const dateGuess2=new Date(inDate.getTime()-dateOffsGuess),dateOffsGuess2=getTimezoneOffset(tp.tz,dateGuess2);if(dateOffsGuess2-dateOffsGuess===0){return dateGuess2}else if(!throwOnInvalid&&dateOffsGuess2-dateOffsGuess>0){return dateGuess2}else if(!throwOnInvalid){return dateGuess}else{throw new Error("Invalid date passed to fromTZ()")}}};minitz.toTZ=function(d,tzStr){const td=new Date(d.toLocaleString("sv-SE",{timeZone:tzStr}));return{y:td.getFullYear(),m:td.getMonth()+1,d:td.getDate(),h:td.getHours(),i:td.getMinutes(),s:td.getSeconds(),tz:tzStr}};minitz.tp=(y,m,d,h,i,s,tz)=>{return{y:y,m:m,d:d,h:h,i:i,s:s,tz:tz}};function getTimezoneOffset(timeZone,date=new Date){const tz=date.toLocaleString("en",{timeZone:timeZone,timeStyle:"long"}).split(" ").slice(-1)[0];const dateString=date.toLocaleString("en-US").replace(/[\u202f]/," ");return Date.parse(`${dateString} GMT`)-Date.parse(`${dateString} ${tz}`)}function parseISOLocal(dtStr,tz){const pd=new Date(Date.parse(dtStr));if(isNaN(pd)){throw new Error("minitz: Invalid ISO8601 passed to parser.")}const stringEnd=dtStr.substring(9);if(dtStr.includes("Z")||stringEnd.includes("-")||stringEnd.includes("+")){return minitz.tp(pd.getUTCFullYear(),pd.getUTCMonth()+1,pd.getUTCDate(),pd.getUTCHours(),pd.getUTCMinutes(),pd.getUTCSeconds(),"Etc/UTC")}else{return minitz.tp(pd.getFullYear(),pd.getMonth()+1,pd.getDate(),pd.getHours(),pd.getMinutes(),pd.getSeconds(),tz)}}minitz.minitz=minitz;function CronOptions(options){if(options===void 0){options={}}delete options.name;options.legacyMode=options.legacyMode===void 0?true:options.legacyMode;options.paused=options.paused===void 0?false:options.paused;options.maxRuns=options.maxRuns===void 0?Infinity:options.maxRuns;options.catch=options.catch===void 0?false:options.catch;options.interval=options.interval===void 0?0:parseInt(options.interval,10);options.utcOffset=options.utcOffset===void 0?void 0:parseInt(options.utcOffset,10);options.unref=options.unref===void 0?false:options.unref;options.kill=false;if(options.startAt){options.startAt=new CronDate(options.startAt,options.timezone)}if(options.stopAt){options.stopAt=new CronDate(options.stopAt,options.timezone)}if(options.interval!==null){if(isNaN(options.interval)){throw new Error("CronOptions: Supplied value for interval is not a number")}else if(options.interval<0){throw new Error("CronOptions: Supplied value for interval can not be negative")}}if(options.utcOffset!==void 0){if(isNaN(options.utcOffset)){throw new Error("CronOptions: Invalid value passed for utcOffset, should be number representing minutes offset from UTC.")}else if(options.utcOffset<-870||options.utcOffset>870){throw new Error("CronOptions: utcOffset out of bounds.")}if(options.utcOffset!==void 0&&options.timezone){throw new Error("CronOptions: Combining 'utcOffset' with 'timezone' is not allowed.")}}if(options.unref!==true&&options.unref!==false){throw new Error("CronOptions: Unref should be either true, false or undefined(false).")}return options}const DaysOfMonth=[31,28,31,30,31,30,31,31,30,31,30,31];const RecursionSteps=[["month","year",0],["day","month",-1],["hour","day",0],["minute","hour",0],["second","minute",0]];function CronDate(d,tz){this.tz=tz;if(d&&d instanceof Date){if(!isNaN(d)){this.fromDate(d)}else{throw new TypeError("CronDate: Invalid date passed to CronDate constructor")}}else if(d===void 0){this.fromDate(new Date)}else if(d&&typeof d==="string"){this.fromString(d)}else if(d instanceof CronDate){this.fromCronDate(d)}else{throw new TypeError("CronDate: Invalid type ("+typeof d+") passed to CronDate constructor")}}CronDate.prototype.fromDate=function(inDate){if(this.tz!==void 0){if(typeof this.tz==="number"){this.ms=inDate.getUTCMilliseconds();this.second=inDate.getUTCSeconds();this.minute=inDate.getUTCMinutes()+this.tz;this.hour=inDate.getUTCHours();this.day=inDate.getUTCDate();this.month=inDate.getUTCMonth();this.year=inDate.getUTCFullYear();this.apply()}else{const d=minitz.toTZ(inDate,this.tz);this.ms=inDate.getMilliseconds();this.second=d.s;this.minute=d.i;this.hour=d.h;this.day=d.d;this.month=d.m-1;this.year=d.y}}else{this.ms=inDate.getMilliseconds();this.second=inDate.getSeconds();this.minute=inDate.getMinutes();this.hour=inDate.getHours();this.day=inDate.getDate();this.month=inDate.getMonth();this.year=inDate.getFullYear()}};CronDate.prototype.fromCronDate=function(d){this.tz=d.tz;this.year=d.year;this.month=d.month;this.day=d.day;this.hour=d.hour;this.minute=d.minute;this.second=d.second;this.ms=d.ms};CronDate.prototype.apply=function(){if(this.month>11||this.day>DaysOfMonth[this.month]||this.hour>59||this.minute>59||this.second>59||this.hour<0||this.minute<0||this.second<0){const d=new Date(Date.UTC(this.year,this.month,this.day,this.hour,this.minute,this.second,this.ms));this.ms=d.getUTCMilliseconds();this.second=d.getUTCSeconds();this.minute=d.getUTCMinutes();this.hour=d.getUTCHours();this.day=d.getUTCDate();this.month=d.getUTCMonth();this.year=d.getUTCFullYear();return true}else{return false}};CronDate.prototype.fromString=function(str){return this.fromDate(minitz.fromTZISO(str,this.tz))};CronDate.prototype.findNext=function(options,target,pattern,offset){const originalTarget=this[target];let lastDayOfMonth;if(pattern.lastDayOfMonth){if(this.month!==1){lastDayOfMonth=DaysOfMonth[this.month]}else{lastDayOfMonth=new Date(Date.UTC(this.year,this.month+1,0,0,0,0,0)).getUTCDate()}}const fDomWeekDay=!pattern.starDOW&&target=="day"?new Date(Date.UTC(this.year,this.month,1,0,0,0,0)).getUTCDay():undefined;for(let i=this[target]+offset;i<pattern[target].length;i++){let match=pattern[target][i];if(target==="day"&&pattern.lastDayOfMonth&&i-offset==lastDayOfMonth){match=true}if(target==="day"&&!pattern.starDOW){const dowMatch=pattern.dow[(fDomWeekDay+(i-offset-1))%7];if(options.legacyMode&&!pattern.starDOM){match=match||dowMatch}else{match=match&&dowMatch}}if(match){this[target]=i-offset;return originalTarget!==this[target]?2:1}}return 3};CronDate.prototype.recurse=function(pattern,options,doing){const res=this.findNext(options,RecursionSteps[doing][0],pattern,RecursionSteps[doing][2]);if(res>1){let resetLevel=doing+1;while(resetLevel<RecursionSteps.length){this[RecursionSteps[resetLevel][0]]=-RecursionSteps[resetLevel][2];resetLevel++}if(res===3){this[RecursionSteps[doing][1]]++;this[RecursionSteps[doing][0]]=-RecursionSteps[doing][2];this.apply();return this.recurse(pattern,options,0)}else if(this.apply()){return this.recurse(pattern,options,doing-1)}}doing+=1;if(doing>=RecursionSteps.length){return this}else if(this.year>=3e3){return null}else{return this.recurse(pattern,options,doing)}};CronDate.prototype.increment=function(pattern,options,hasPreviousRun){if(options.interval>1&&hasPreviousRun){this.second+=options.interval}else{this.second+=1}this.ms=0;this.apply();return this.recurse(pattern,options,0)};CronDate.prototype.getDate=function(internal){if(internal||this.tz===void 0&&this.utcOffset===void 0){return new Date(this.year,this.month,this.day,this.hour,this.minute,this.second,this.ms)}else{if(typeof this.tz==="number"){return new Date(Date.UTC(this.year,this.month,this.day,this.hour,this.minute-this.tz,this.second,this.ms))}else{return minitz(this.year,this.month+1,this.day,this.hour,this.minute,this.second,this.tz)}}};CronDate.prototype.getTime=function(){return this.getDate().getTime()};function CronPattern(pattern,timezone){this.pattern=pattern;this.timezone=timezone;this.second=Array(60).fill(0);this.minute=Array(60).fill(0);this.hour=Array(24).fill(0);this.day=Array(31).fill(0);this.month=Array(12).fill(0);this.dow=Array(8).fill(0);this.lastDayOfMonth=false;this.starDOM=false;this.starDOW=false;this.parse()}CronPattern.prototype.parse=function(){if(!(typeof this.pattern==="string"||this.pattern.constructor===String)){throw new TypeError("CronPattern: Pattern has to be of type string.")}if(this.pattern.indexOf("@")>=0)this.pattern=this.handleNicknames(this.pattern).trim();const parts=this.pattern.replace(/\s+/g," ").split(" ");if(parts.length<5||parts.length>6){throw new TypeError("CronPattern: invalid configuration format ('"+this.pattern+"'), exacly five or six space separated parts required.")}if(parts.length===5){parts.unshift("0")}if(parts[3].indexOf("L")>=0){parts[3]=parts[3].replace("L","");this.lastDayOfMonth=true}if(parts[3]=="*"){this.starDOM=true}if(parts[4].length>=3)parts[4]=this.replaceAlphaMonths(parts[4]);if(parts[5].length>=3)parts[5]=this.replaceAlphaDays(parts[5]);if(parts[5]=="*"){this.starDOW=true}if(this.pattern.indexOf("?")>=0){const initDate=new CronDate(new Date,this.timezone).getDate(true);parts[0]=parts[0].replace("?",initDate.getSeconds());parts[1]=parts[1].replace("?",initDate.getMinutes());parts[2]=parts[2].replace("?",initDate.getHours());if(!this.starDOM)parts[3]=parts[3].replace("?",initDate.getDate());parts[4]=parts[4].replace("?",initDate.getMonth()+1);if(!this.starDOW)parts[5]=parts[5].replace("?",initDate.getDay())}this.throwAtIllegalCharacters(parts);this.partToArray("second",parts[0],0);this.partToArray("minute",parts[1],0);this.partToArray("hour",parts[2],0);this.partToArray("day",parts[3],-1);this.partToArray("month",parts[4],-1);this.partToArray("dow",parts[5],0);if(this.dow[7]){this.dow[0]=1}};CronPattern.prototype.partToArray=function(type,conf,valueIndexOffset){const arr=this[type];if(conf==="*")return arr.fill(1);const split=conf.split(",");if(split.length>1){for(let i=0;i<split.length;i++){this.partToArray(type,split[i],valueIndexOffset)}}else if(conf.indexOf("-")!==-1&&conf.indexOf("/")!==-1){this.handleRangeWithStepping(conf,type,valueIndexOffset)}else if(conf.indexOf("-")!==-1){this.handleRange(conf,type,valueIndexOffset)}else if(conf.indexOf("/")!==-1){this.handleStepping(conf,type,valueIndexOffset)}else if(conf!==""){this.handleNumber(conf,type,valueIndexOffset)}};CronPattern.prototype.throwAtIllegalCharacters=function(parts){const reValidCron=/[^/*0-9,-]+/;for(let i=0;i<parts.length;i++){if(reValidCron.test(parts[i])){throw new TypeError("CronPattern: configuration entry "+i+" ("+parts[i]+") contains illegal characters.")}}};CronPattern.prototype.handleNumber=function(conf,type,valueIndexOffset){const i=parseInt(conf,10)+valueIndexOffset;if(isNaN(i)){throw new TypeError("CronPattern: "+type+" is not a number: '"+conf+"'")}if(i<0||i>=this[type].length){throw new TypeError("CronPattern: "+type+" value out of range: '"+conf+"'")}this[type][i]=1};CronPattern.prototype.handleRangeWithStepping=function(conf,type,valueIndexOffset){const matches=conf.match(/^(\d+)-(\d+)\/(\d+)$/);if(matches===null)throw new TypeError("CronPattern: Syntax error, illegal range with stepping: '"+conf+"'");let[,lower,upper,steps]=matches;lower=parseInt(lower,10)+valueIndexOffset;upper=parseInt(upper,10)+valueIndexOffset;steps=parseInt(steps,10);if(isNaN(lower))throw new TypeError("CronPattern: Syntax error, illegal lower range (NaN)");if(isNaN(upper))throw new TypeError("CronPattern: Syntax error, illegal upper range (NaN)");if(isNaN(steps))throw new TypeError("CronPattern: Syntax error, illegal stepping: (NaN)");if(steps===0)throw new TypeError("CronPattern: Syntax error, illegal stepping: 0");if(steps>this[type].length)throw new TypeError("CronPattern: Syntax error, steps cannot be greater than maximum value of part ("+this[type].length+")");if(lower<0||upper>=this[type].length)throw new TypeError("CronPattern: Value out of range: '"+conf+"'");if(lower>upper)throw new TypeError("CronPattern: From value is larger than to value: '"+conf+"'");for(let i=lower;i<=upper;i+=steps){this[type][i]=1}};CronPattern.prototype.handleRange=function(conf,type,valueIndexOffset){const split=conf.split("-");if(split.length!==2){throw new TypeError("CronPattern: Syntax error, illegal range: '"+conf+"'")}const lower=parseInt(split[0],10)+valueIndexOffset,upper=parseInt(split[1],10)+valueIndexOffset;if(isNaN(lower)){throw new TypeError("CronPattern: Syntax error, illegal lower range (NaN)")}else if(isNaN(upper)){throw new TypeError("CronPattern: Syntax error, illegal upper range (NaN)")}if(lower<0||upper>=this[type].length){throw new TypeError("CronPattern: Value out of range: '"+conf+"'")}if(lower>upper){throw new TypeError("CronPattern: From value is larger than to value: '"+conf+"'")}for(let i=lower;i<=upper;i++){this[type][i]=1}};CronPattern.prototype.handleStepping=function(conf,type){const split=conf.split("/");if(split.length!==2){throw new TypeError("CronPattern: Syntax error, illegal stepping: '"+conf+"'")}let start=0;if(split[0]!=="*"){start=parseInt(split[0],10)}const steps=parseInt(split[1],10);if(isNaN(steps))throw new TypeError("CronPattern: Syntax error, illegal stepping: (NaN)");if(steps===0)throw new TypeError("CronPattern: Syntax error, illegal stepping: 0");if(steps>this[type].length)throw new TypeError("CronPattern: Syntax error, max steps for part is ("+this[type].length+")");for(let i=start;i<this[type].length;i+=steps){this[type][i]=1}};CronPattern.prototype.replaceAlphaDays=function(conf){return conf.replace(/-sun/gi,"-7").replace(/sun/gi,"0").replace(/mon/gi,"1").replace(/tue/gi,"2").replace(/wed/gi,"3").replace(/thu/gi,"4").replace(/fri/gi,"5").replace(/sat/gi,"6")};CronPattern.prototype.replaceAlphaMonths=function(conf){return conf.replace(/jan/gi,"1").replace(/feb/gi,"2").replace(/mar/gi,"3").replace(/apr/gi,"4").replace(/may/gi,"5").replace(/jun/gi,"6").replace(/jul/gi,"7").replace(/aug/gi,"8").replace(/sep/gi,"9").replace(/oct/gi,"10").replace(/nov/gi,"11").replace(/dec/gi,"12")};CronPattern.prototype.handleNicknames=function(pattern){const cleanPattern=pattern.trim().toLowerCase();if(cleanPattern==="@yearly"||cleanPattern==="@annually"){return"0 0 1 1 *"}else if(cleanPattern==="@monthly"){return"0 0 1 * *"}else if(cleanPattern==="@weekly"){return"0 0 * * 0"}else if(cleanPattern==="@daily"){return"0 0 * * *"}else if(cleanPattern==="@hourly"){return"0 * * * *"}else{return pattern}};const maxDelay=Math.pow(2,32-1)-1;const scheduledJobs=[];function Cron(pattern,fnOrOptions1,fnOrOptions2){if(!(this instanceof Cron)){return new Cron(pattern,fnOrOptions1,fnOrOptions2)}let options,func;if(typeof fnOrOptions1==="function"){func=fnOrOptions1}else if(typeof fnOrOptions1==="object"){options=fnOrOptions1}else if(fnOrOptions1!==void 0){throw new Error("Cron: Invalid argument passed for optionsIn. Should be one of function, or object (options).")}if(typeof fnOrOptions2==="function"){func=fnOrOptions2}else if(typeof fnOrOptions2==="object"){options=fnOrOptions2}else if(fnOrOptions2!==void 0){throw new Error("Cron: Invalid argument passed for funcIn. Should be one of function, or object (options).")}this.name=options?options.name:void 0;this.options=CronOptions(options);this.once=void 0;this.pattern=void 0;this.blocking=false;this.previousrun=void 0;this.runstarted=void 0;if(pattern&&(pattern instanceof Date||typeof pattern==="string"&&pattern.indexOf(":")>0)){this.once=new CronDate(pattern,this.options.timezone||this.options.utcOffset)}else{this.pattern=new CronPattern(pattern,this.options.timezone)}if(func!==void 0){this.fn=func;this.schedule()}if(this.name){const existing=scheduledJobs.find(j=>j.name===this.name);if(existing){throw new Error("Cron: Tried to initialize new named job '"+this.name+"', but name already taken.")}else{scheduledJobs.push(this)}}return this}Cron.prototype.next=function(prev){const next=this._next(prev);return next?next.getDate():null};Cron.prototype.enumerate=function(n,previous){if(n>this.options.maxRuns){n=this.options.maxRuns}const enumeration=[];let prev=previous||this.previousrun;while(n--&&(prev=this.next(prev))){enumeration.push(prev)}return enumeration};Cron.prototype.running=function(){const msLeft=this.msToNext(this.previousrun);const running=!this.options.paused&&this.fn!==void 0;return msLeft!==null&&running};Cron.prototype.working=function(){return this.blocking};Cron.prototype.started=function(){return this.runstarted?this.runstarted.getDate():null};Cron.prototype.previous=function(){return this.previousrun?this.previousrun.getDate():null};Cron.prototype.msToNext=function(prev){const next=this._next(prev);prev=new CronDate(prev,this.options.timezone||this.options.utcOffset);if(next){return next.getTime(true)-prev.getTime(true)}else{return null}};Cron.prototype.stop=function(){this.options.kill=true;if(this.currentTimeout){clearTimeout(this.currentTimeout)}};Cron.prototype.pause=function(){return(this.options.paused=true)&&!this.options.kill};Cron.prototype.resume=function(){return!(this.options.paused=false)&&!this.options.kill};Cron.prototype.schedule=function(func,partial){if(func&&this.fn){throw new Error("Cron: It is not allowed to schedule two functions using the same Croner instance.")}else if(func){this.fn=func}let waitMs=this.msToNext(partial?partial:this.previousrun);const target=this.next(partial?partial:this.previousrun);if(waitMs===null)return this;if(waitMs>maxDelay){waitMs=maxDelay}this.currentTimeout=setTimeout(()=>{const now=new Date,shouldRun=waitMs!==maxDelay&&!this.options.paused&&now.getTime()>=target,isBlocked=this.blocking&&this.options.protect;if(shouldRun&&!isBlocked){this.options.maxRuns--;(async inst=>{inst.blocking=true;this.runstarted=new CronDate(void 0,this.options.timezone||this.options.utcOffset);if(this.options.catch){try{await inst.fn(inst,inst.options.context)}catch(_e){if(Object.prototype.toString.call(inst.options.catch)==="[object Function]"||"function"===typeof inst.options.catch||inst.options.catch instanceof Function){inst.options.catch(_e,inst)}}finally{inst.blocking=false}}else{await this.fn(this,this.options.context);inst.blocking=false}})(this);this.previousrun=new CronDate(void 0,this.options.timezone||this.options.utcOffset);this.schedule()}else{if(shouldRun&&isBlocked&&Object.prototype.toString.call(this.options.protect)==="[object Function]"||"function"===typeof this.options.protect||this.options.protect instanceof Function){(async inst=>{inst.options.protect(inst)})(this)}this.schedule(undefined,now)}},waitMs);if(this.currentTimeout&&this.options.unref){if(typeof Deno!=="undefined"&&typeof Deno.unrefTimer!=="undefined"){Deno.unrefTimer(this.currentTimeout)}else if(typeof this.currentTimeout.unref!=="undefined"){this.currentTimeout.unref()}}return this};Cron.prototype._next=function(prev){const hasPreviousRun=prev||this.previousrun?true:false;prev=new CronDate(prev,this.options.timezone||this.options.utcOffset);if(this.options.startAt&&prev&&prev.getTime()<this.options.startAt.getTime()){prev=this.options.startAt}const nextRun=this.once||new CronDate(prev,this.options.timezone||this.options.utcOffset).increment(this.pattern,this.options,hasPreviousRun);if(this.once&&this.once.getTime()<=prev.getTime()){return null}else if(nextRun===null||this.options.maxRuns<=0||this.options.kill||this.options.stopAt&&nextRun.getTime()>=this.options.stopAt.getTime()){return null}else{return nextRun}};Cron.Cron=Cron;Cron.scheduledJobs=scheduledJobs;return Cron});
|
package/dist/croner.min.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
(function(global,factory){typeof exports==="object"&&typeof module!=="undefined"?module.exports=factory():typeof define==="function"&&define.amd?define(factory):(global=typeof globalThis!=="undefined"?globalThis:global||self,global.Cron=factory())})(this,function(){"use strict";function minitz(y,m,d,h,i,s,tz,throwOnInvalid){return minitz.fromTZ(minitz.tp(y,m,d,h,i,s,tz),throwOnInvalid)}minitz.fromTZISO=(localTimeStr,tz,throwOnInvalid)=>{return minitz.fromTZ(parseISOLocal(localTimeStr,tz),throwOnInvalid)};minitz.fromTZ=function(tp,throwOnInvalid){const inDate=new Date(Date.UTC(tp.y,tp.m-1,tp.d,tp.h,tp.i,tp.s)),offset=getTimezoneOffset(tp.tz,inDate),dateGuess=new Date(inDate.getTime()-offset),dateOffsGuess=getTimezoneOffset(tp.tz,dateGuess);if(dateOffsGuess-offset===0){return dateGuess}else{const dateGuess2=new Date(inDate.getTime()-dateOffsGuess),dateOffsGuess2=getTimezoneOffset(tp.tz,dateGuess2);if(dateOffsGuess2-dateOffsGuess===0){return dateGuess2}else if(!throwOnInvalid&&dateOffsGuess2-dateOffsGuess>0){return dateGuess2}else if(!throwOnInvalid){return dateGuess}else{throw new Error("Invalid date passed to fromTZ()")}}};minitz.toTZ=function(d,tzStr){const td=new Date(d.toLocaleString("sv-SE",{timeZone:tzStr}));return{y:td.getFullYear(),m:td.getMonth()+1,d:td.getDate(),h:td.getHours(),i:td.getMinutes(),s:td.getSeconds(),tz:tzStr}};minitz.tp=(y,m,d,h,i,s,tz)=>{return{y:y,m:m,d:d,h:h,i:i,s:s,tz:tz}};function getTimezoneOffset(timeZone,date=new Date){const tz=date.toLocaleString("en",{timeZone:timeZone,timeStyle:"long"}).split(" ").slice(-1)[0];const dateString=date.toLocaleString("en-US").replace(/[\u202f]/," ");return Date.parse(`${dateString} GMT`)-Date.parse(`${dateString} ${tz}`)}function parseISOLocal(dtStr,tz){const pd=new Date(Date.parse(dtStr));if(isNaN(pd)){throw new Error("minitz: Invalid ISO8601 passed to parser.")}const stringEnd=dtStr.substring(9);if(dtStr.includes("Z")||stringEnd.includes("-")||stringEnd.includes("+")){return minitz.tp(pd.getUTCFullYear(),pd.getUTCMonth()+1,pd.getUTCDate(),pd.getUTCHours(),pd.getUTCMinutes(),pd.getUTCSeconds(),"Etc/UTC")}else{return minitz.tp(pd.getFullYear(),pd.getMonth()+1,pd.getDate(),pd.getHours(),pd.getMinutes(),pd.getSeconds(),tz)}}minitz.minitz=minitz;function CronOptions(options){if(options===void 0){options={}}delete options.name;options.legacyMode=options.legacyMode===void 0?true:options.legacyMode;options.paused=options.paused===void 0?false:options.paused;options.maxRuns=options.maxRuns===void 0?Infinity:options.maxRuns;options.catch=options.catch===void 0?false:options.catch;options.interval=options.interval===void 0?0:parseInt(options.interval,10);options.utcOffset=options.utcOffset===void 0?void 0:parseInt(options.utcOffset,10);options.unref=options.unref===void 0?false:options.unref;options.kill=false;if(options.startAt){options.startAt=new CronDate(options.startAt,options.timezone)}if(options.stopAt){options.stopAt=new CronDate(options.stopAt,options.timezone)}if(options.interval!==null){if(isNaN(options.interval)){throw new Error("CronOptions: Supplied value for interval is not a number")}else if(options.interval<0){throw new Error("CronOptions: Supplied value for interval can not be negative")}}if(options.utcOffset!==void 0){if(isNaN(options.utcOffset)){throw new Error("CronOptions: Invalid value passed for utcOffset, should be number representing minutes offset from UTC.")}else if(options.utcOffset<-870||options.utcOffset>870){throw new Error("CronOptions: utcOffset out of bounds.")}if(options.utcOffset!==void 0&&options.timezone){throw new Error("CronOptions: Combining 'utcOffset' with 'timezone' is not allowed.")}}if(options.unref!==true&&options.unref!==false){throw new Error("CronOptions: Unref should be either true, false or undefined(false).")}return options}const DaysOfMonth=[31,28,31,30,31,30,31,31,30,31,30,31];const RecursionSteps=[["month","year",0],["day","month",-1],["hour","day",0],["minute","hour",0],["second","minute",0]];function CronDate(d,tz){this.tz=tz;if(d&&d instanceof Date){if(!isNaN(d)){this.fromDate(d)}else{throw new TypeError("CronDate: Invalid date passed to CronDate constructor")}}else if(d===void 0){this.fromDate(new Date)}else if(d&&typeof d==="string"){this.fromString(d)}else if(d instanceof CronDate){this.fromCronDate(d)}else{throw new TypeError("CronDate: Invalid type ("+typeof d+") passed to CronDate constructor")}}CronDate.prototype.fromDate=function(inDate){if(this.tz!==void 0){if(typeof this.tz==="number"){this.ms=inDate.getMilliseconds();this.second=inDate.getSeconds();this.minute=inDate.getMinutes()+this.tz;this.hour=inDate.getHours();this.day=inDate.getDate();this.month=inDate.getMonth();this.year=inDate.getFullYear();this.apply()}else{const d=minitz.toTZ(inDate,this.tz);this.ms=inDate.getMilliseconds();this.second=d.s;this.minute=d.i;this.hour=d.h;this.day=d.d;this.month=d.m-1;this.year=d.y}}else{this.ms=inDate.getMilliseconds();this.second=inDate.getSeconds();this.minute=inDate.getMinutes();this.hour=inDate.getHours();this.day=inDate.getDate();this.month=inDate.getMonth();this.year=inDate.getFullYear()}};CronDate.prototype.fromCronDate=function(d){this.tz=d.tz;this.year=d.year;this.month=d.month;this.day=d.day;this.hour=d.hour;this.minute=d.minute;this.second=d.second;this.ms=d.ms};CronDate.prototype.apply=function(){if(this.month>11||this.day>DaysOfMonth[this.month]||this.hour>59||this.minute>59||this.second>59||this.hour<0||this.minute<0||this.second<0){const d=new Date(Date.UTC(this.year,this.month,this.day,this.hour,this.minute,this.second,this.ms));this.ms=d.getUTCMilliseconds();this.second=d.getUTCSeconds();this.minute=d.getUTCMinutes();this.hour=d.getUTCHours();this.day=d.getUTCDate();this.month=d.getUTCMonth();this.year=d.getUTCFullYear();return true}else{return false}};CronDate.prototype.fromString=function(str){return this.fromDate(minitz.fromTZISO(str,this.tz))};CronDate.prototype.findNext=function(options,target,pattern,offset){const originalTarget=this[target];let lastDayOfMonth;if(pattern.lastDayOfMonth){if(this.month!==1){lastDayOfMonth=DaysOfMonth[this.month]}else{lastDayOfMonth=new Date(Date.UTC(this.year,this.month+1,0,0,0,0,0)).getUTCDate()}}const fDomWeekDay=!pattern.starDOW&&target=="day"?new Date(Date.UTC(this.year,this.month,1,0,0,0,0)).getUTCDay():undefined;for(let i=this[target]+offset;i<pattern[target].length;i++){let match=pattern[target][i];if(target==="day"&&pattern.lastDayOfMonth&&i-offset==lastDayOfMonth){match=true}if(target==="day"&&!pattern.starDOW){const dowMatch=pattern.dow[(fDomWeekDay+(i-offset-1))%7];if(options.legacyMode&&!pattern.starDOM){match=match||dowMatch}else{match=match&&dowMatch}}if(match){this[target]=i-offset;return originalTarget!==this[target]?2:1}}return 3};CronDate.prototype.recurse=function(pattern,options,doing){const res=this.findNext(options,RecursionSteps[doing][0],pattern,RecursionSteps[doing][2]);if(res>1){let resetLevel=doing+1;while(resetLevel<RecursionSteps.length){this[RecursionSteps[resetLevel][0]]=-RecursionSteps[resetLevel][2];resetLevel++}if(res===3){this[RecursionSteps[doing][1]]++;this[RecursionSteps[doing][0]]=-RecursionSteps[doing][2];this.apply();return this.recurse(pattern,options,0)}else if(this.apply()){return this.recurse(pattern,options,doing-1)}}doing+=1;if(doing>=RecursionSteps.length){return this}else if(this.year>=3e3){return null}else{return this.recurse(pattern,options,doing)}};CronDate.prototype.increment=function(pattern,options,hasPreviousRun){if(options.interval>1&&hasPreviousRun){this.second+=options.interval}else{this.second+=1}this.ms=0;this.apply();return this.recurse(pattern,options,0)};CronDate.prototype.getDate=function(internal){if(internal||!(this.tz!==void 0)){return new Date(this.year,this.month,this.day,this.hour,this.minute,this.second,this.ms)}else{if(typeof this.tz==="number"){return new Date(Date.UTC(this.year,this.month,this.day,this.hour,this.minute-this.tz,this.second,this.ms))}else{return minitz(this.year,this.month+1,this.day,this.hour,this.minute,this.second,this.tz)}}};CronDate.prototype.getTime=function(){return this.getDate().getTime()};function CronPattern(pattern,timezone){this.pattern=pattern;this.timezone=timezone;this.second=Array(60).fill(0);this.minute=Array(60).fill(0);this.hour=Array(24).fill(0);this.day=Array(31).fill(0);this.month=Array(12).fill(0);this.dow=Array(8).fill(0);this.lastDayOfMonth=false;this.starDOM=false;this.starDOW=false;this.parse()}CronPattern.prototype.parse=function(){if(!(typeof this.pattern==="string"||this.pattern.constructor===String)){throw new TypeError("CronPattern: Pattern has to be of type string.")}if(this.pattern.indexOf("@")>=0)this.pattern=this.handleNicknames(this.pattern).trim();const parts=this.pattern.replace(/\s+/g," ").split(" ");if(parts.length<5||parts.length>6){throw new TypeError("CronPattern: invalid configuration format ('"+this.pattern+"'), exacly five or six space separated parts required.")}if(parts.length===5){parts.unshift("0")}if(parts[3].indexOf("L")>=0){parts[3]=parts[3].replace("L","");this.lastDayOfMonth=true}if(parts[3]=="*"){this.starDOM=true}if(parts[4].length>=3)parts[4]=this.replaceAlphaMonths(parts[4]);if(parts[5].length>=3)parts[5]=this.replaceAlphaDays(parts[5]);if(parts[5]=="*"){this.starDOW=true}if(this.pattern.indexOf("?")>=0){const initDate=new CronDate(new Date,this.timezone).getDate(true);parts[0]=parts[0].replace("?",initDate.getSeconds());parts[1]=parts[1].replace("?",initDate.getMinutes());parts[2]=parts[2].replace("?",initDate.getHours());if(!this.starDOM)parts[3]=parts[3].replace("?",initDate.getDate());parts[4]=parts[4].replace("?",initDate.getMonth()+1);if(!this.starDOW)parts[5]=parts[5].replace("?",initDate.getDay())}this.throwAtIllegalCharacters(parts);this.partToArray("second",parts[0],0);this.partToArray("minute",parts[1],0);this.partToArray("hour",parts[2],0);this.partToArray("day",parts[3],-1);this.partToArray("month",parts[4],-1);this.partToArray("dow",parts[5],0);if(this.dow[7]){this.dow[0]=1}};CronPattern.prototype.partToArray=function(type,conf,valueIndexOffset){const arr=this[type];if(conf==="*")return arr.fill(1);const split=conf.split(",");if(split.length>1){for(let i=0;i<split.length;i++){this.partToArray(type,split[i],valueIndexOffset)}}else if(conf.indexOf("-")!==-1&&conf.indexOf("/")!==-1){this.handleRangeWithStepping(conf,type,valueIndexOffset)}else if(conf.indexOf("-")!==-1){this.handleRange(conf,type,valueIndexOffset)}else if(conf.indexOf("/")!==-1){this.handleStepping(conf,type,valueIndexOffset)}else if(conf!==""){this.handleNumber(conf,type,valueIndexOffset)}};CronPattern.prototype.throwAtIllegalCharacters=function(parts){const reValidCron=/[^/*0-9,-]+/;for(let i=0;i<parts.length;i++){if(reValidCron.test(parts[i])){throw new TypeError("CronPattern: configuration entry "+i+" ("+parts[i]+") contains illegal characters.")}}};CronPattern.prototype.handleNumber=function(conf,type,valueIndexOffset){const i=parseInt(conf,10)+valueIndexOffset;if(isNaN(i)){throw new TypeError("CronPattern: "+type+" is not a number: '"+conf+"'")}if(i<0||i>=this[type].length){throw new TypeError("CronPattern: "+type+" value out of range: '"+conf+"'")}this[type][i]=1};CronPattern.prototype.handleRangeWithStepping=function(conf,type,valueIndexOffset){const matches=conf.match(/^(\d+)-(\d+)\/(\d+)$/);if(matches===null)throw new TypeError("CronPattern: Syntax error, illegal range with stepping: '"+conf+"'");let[,lower,upper,steps]=matches;lower=parseInt(lower,10)+valueIndexOffset;upper=parseInt(upper,10)+valueIndexOffset;steps=parseInt(steps,10);if(isNaN(lower))throw new TypeError("CronPattern: Syntax error, illegal lower range (NaN)");if(isNaN(upper))throw new TypeError("CronPattern: Syntax error, illegal upper range (NaN)");if(isNaN(steps))throw new TypeError("CronPattern: Syntax error, illegal stepping: (NaN)");if(steps===0)throw new TypeError("CronPattern: Syntax error, illegal stepping: 0");if(steps>this[type].length)throw new TypeError("CronPattern: Syntax error, steps cannot be greater than maximum value of part ("+this[type].length+")");if(lower<0||upper>=this[type].length)throw new TypeError("CronPattern: Value out of range: '"+conf+"'");if(lower>upper)throw new TypeError("CronPattern: From value is larger than to value: '"+conf+"'");for(let i=lower;i<=upper;i+=steps){this[type][i]=1}};CronPattern.prototype.handleRange=function(conf,type,valueIndexOffset){const split=conf.split("-");if(split.length!==2){throw new TypeError("CronPattern: Syntax error, illegal range: '"+conf+"'")}const lower=parseInt(split[0],10)+valueIndexOffset,upper=parseInt(split[1],10)+valueIndexOffset;if(isNaN(lower)){throw new TypeError("CronPattern: Syntax error, illegal lower range (NaN)")}else if(isNaN(upper)){throw new TypeError("CronPattern: Syntax error, illegal upper range (NaN)")}if(lower<0||upper>=this[type].length){throw new TypeError("CronPattern: Value out of range: '"+conf+"'")}if(lower>upper){throw new TypeError("CronPattern: From value is larger than to value: '"+conf+"'")}for(let i=lower;i<=upper;i++){this[type][i]=1}};CronPattern.prototype.handleStepping=function(conf,type){const split=conf.split("/");if(split.length!==2){throw new TypeError("CronPattern: Syntax error, illegal stepping: '"+conf+"'")}let start=0;if(split[0]!=="*"){start=parseInt(split[0],10)}const steps=parseInt(split[1],10);if(isNaN(steps))throw new TypeError("CronPattern: Syntax error, illegal stepping: (NaN)");if(steps===0)throw new TypeError("CronPattern: Syntax error, illegal stepping: 0");if(steps>this[type].length)throw new TypeError("CronPattern: Syntax error, max steps for part is ("+this[type].length+")");for(let i=start;i<this[type].length;i+=steps){this[type][i]=1}};CronPattern.prototype.replaceAlphaDays=function(conf){return conf.replace(/-sun/gi,"-7").replace(/sun/gi,"0").replace(/mon/gi,"1").replace(/tue/gi,"2").replace(/wed/gi,"3").replace(/thu/gi,"4").replace(/fri/gi,"5").replace(/sat/gi,"6")};CronPattern.prototype.replaceAlphaMonths=function(conf){return conf.replace(/jan/gi,"1").replace(/feb/gi,"2").replace(/mar/gi,"3").replace(/apr/gi,"4").replace(/may/gi,"5").replace(/jun/gi,"6").replace(/jul/gi,"7").replace(/aug/gi,"8").replace(/sep/gi,"9").replace(/oct/gi,"10").replace(/nov/gi,"11").replace(/dec/gi,"12")};CronPattern.prototype.handleNicknames=function(pattern){const cleanPattern=pattern.trim().toLowerCase();if(cleanPattern==="@yearly"||cleanPattern==="@annually"){return"0 0 1 1 *"}else if(cleanPattern==="@monthly"){return"0 0 1 * *"}else if(cleanPattern==="@weekly"){return"0 0 * * 0"}else if(cleanPattern==="@daily"){return"0 0 * * *"}else if(cleanPattern==="@hourly"){return"0 * * * *"}else{return pattern}};const maxDelay=Math.pow(2,32-1)-1;const scheduledJobs=[];function Cron(pattern,fnOrOptions1,fnOrOptions2){if(!(this instanceof Cron)){return new Cron(pattern,fnOrOptions1,fnOrOptions2)}let options,func;if(typeof fnOrOptions1==="function"){func=fnOrOptions1}else if(typeof fnOrOptions1==="object"){options=fnOrOptions1}else if(fnOrOptions1!==void 0){throw new Error("Cron: Invalid argument passed for optionsIn. Should be one of function, or object (options).")}if(typeof fnOrOptions2==="function"){func=fnOrOptions2}else if(typeof fnOrOptions2==="object"){options=fnOrOptions2}else if(fnOrOptions2!==void 0){throw new Error("Cron: Invalid argument passed for funcIn. Should be one of function, or object (options).")}this.name=options?options.name:void 0;this.options=CronOptions(options);this.once=void 0;this.pattern=void 0;if(pattern&&(pattern instanceof Date||typeof pattern==="string"&&pattern.indexOf(":")>0)){this.once=new CronDate(pattern,this.options.timezone||this.options.utcOffset)}else{this.pattern=new CronPattern(pattern,this.options.timezone)}if(func!==void 0){this.fn=func;this.schedule()}if(this.name){const existing=scheduledJobs.find(j=>j.name===this.name);if(existing){throw new Error("Cron: Tried to initialize new named job '"+this.name+"', but name already taken.")}else{scheduledJobs.push(this)}}return this}Cron.prototype.next=function(prev){const next=this._next(prev);return next?next.getDate():null};Cron.prototype.enumerate=function(n,previous){if(n>this.options.maxRuns){n=this.options.maxRuns}const enumeration=[];let prev=previous||this.previousrun;while(n--&&(prev=this.next(prev))){enumeration.push(prev)}return enumeration};Cron.prototype.running=function(){const msLeft=this.msToNext(this.previousrun);const running=!this.options.paused&&this.fn!==void 0;return msLeft!==null&&running};Cron.prototype.previous=function(){return this.previousrun?this.previousrun.getDate():null};Cron.prototype.msToNext=function(prev){const next=this._next(prev);prev=new CronDate(prev,this.options.timezone||this.options.utcOffset);if(next){return next.getTime(true)-prev.getTime(true)}else{return null}};Cron.prototype.stop=function(){this.options.kill=true;if(this.currentTimeout){clearTimeout(this.currentTimeout)}};Cron.prototype.pause=function(){return(this.options.paused=true)&&!this.options.kill};Cron.prototype.resume=function(){return!(this.options.paused=false)&&!this.options.kill};Cron.prototype.schedule=function(func,partial){if(func&&this.fn){throw new Error("Cron: It is not allowed to schedule two functions using the same Croner instance.")}else if(func){this.fn=func}let waitMs=this.msToNext(partial?partial:this.previousrun);const target=this.next(partial?partial:this.previousrun);if(waitMs===null)return this;if(waitMs>maxDelay){waitMs=maxDelay}this.currentTimeout=setTimeout(()=>{const now=new Date;if(waitMs!==maxDelay&&!this.options.paused&&now.getTime()>=target){this.options.maxRuns--;if(this.options.catch){(async inst=>{try{await inst.fn(inst,inst.options.context)}catch(_e){if(Object.prototype.toString.call(inst.options.catch)==="[object Function]"||"function"===typeof inst.options.catch||inst.options.catch instanceof Function){inst.options.catch(_e)}}})(this)}else{this.fn(this,this.options.context)}this.previousrun=new CronDate(void 0,this.options.timezone||this.options.utcOffset);this.schedule()}else{this.schedule(undefined,now)}},waitMs);if(this.currentTimeout&&this.options.unref){if(typeof Deno!=="undefined"&&typeof Deno.unrefTimer!=="undefined"){Deno.unrefTimer(this.currentTimeout)}else if(typeof this.currentTimeout.unref!=="undefined"){this.currentTimeout.unref()}}return this};Cron.prototype._next=function(prev){const hasPreviousRun=prev||this.previousrun?true:false;prev=new CronDate(prev,this.options.timezone||this.options.utcOffset);if(this.options.startAt&&prev&&prev.getTime()<this.options.startAt.getTime()){prev=this.options.startAt}const nextRun=this.once||new CronDate(prev,this.options.timezone||this.options.utcOffset).increment(this.pattern,this.options,hasPreviousRun);if(this.once&&this.once.getTime()<=prev.getTime()){return null}else if(nextRun===null||this.options.maxRuns<=0||this.options.kill||this.options.stopAt&&nextRun.getTime()>=this.options.stopAt.getTime()){return null}else{return nextRun}};Cron.Cron=Cron;Cron.scheduledJobs=scheduledJobs;return Cron});
|
|
1
|
+
(function(global,factory){typeof exports==="object"&&typeof module!=="undefined"?module.exports=factory():typeof define==="function"&&define.amd?define(factory):(global=typeof globalThis!=="undefined"?globalThis:global||self,global.Cron=factory())})(this,function(){"use strict";function minitz(y,m,d,h,i,s,tz,throwOnInvalid){return minitz.fromTZ(minitz.tp(y,m,d,h,i,s,tz),throwOnInvalid)}minitz.fromTZISO=(localTimeStr,tz,throwOnInvalid)=>{return minitz.fromTZ(parseISOLocal(localTimeStr,tz),throwOnInvalid)};minitz.fromTZ=function(tp,throwOnInvalid){const inDate=new Date(Date.UTC(tp.y,tp.m-1,tp.d,tp.h,tp.i,tp.s)),offset=getTimezoneOffset(tp.tz,inDate),dateGuess=new Date(inDate.getTime()-offset),dateOffsGuess=getTimezoneOffset(tp.tz,dateGuess);if(dateOffsGuess-offset===0){return dateGuess}else{const dateGuess2=new Date(inDate.getTime()-dateOffsGuess),dateOffsGuess2=getTimezoneOffset(tp.tz,dateGuess2);if(dateOffsGuess2-dateOffsGuess===0){return dateGuess2}else if(!throwOnInvalid&&dateOffsGuess2-dateOffsGuess>0){return dateGuess2}else if(!throwOnInvalid){return dateGuess}else{throw new Error("Invalid date passed to fromTZ()")}}};minitz.toTZ=function(d,tzStr){const td=new Date(d.toLocaleString("sv-SE",{timeZone:tzStr}));return{y:td.getFullYear(),m:td.getMonth()+1,d:td.getDate(),h:td.getHours(),i:td.getMinutes(),s:td.getSeconds(),tz:tzStr}};minitz.tp=(y,m,d,h,i,s,tz)=>{return{y:y,m:m,d:d,h:h,i:i,s:s,tz:tz}};function getTimezoneOffset(timeZone,date=new Date){const tz=date.toLocaleString("en",{timeZone:timeZone,timeStyle:"long"}).split(" ").slice(-1)[0];const dateString=date.toLocaleString("en-US").replace(/[\u202f]/," ");return Date.parse(`${dateString} GMT`)-Date.parse(`${dateString} ${tz}`)}function parseISOLocal(dtStr,tz){const pd=new Date(Date.parse(dtStr));if(isNaN(pd)){throw new Error("minitz: Invalid ISO8601 passed to parser.")}const stringEnd=dtStr.substring(9);if(dtStr.includes("Z")||stringEnd.includes("-")||stringEnd.includes("+")){return minitz.tp(pd.getUTCFullYear(),pd.getUTCMonth()+1,pd.getUTCDate(),pd.getUTCHours(),pd.getUTCMinutes(),pd.getUTCSeconds(),"Etc/UTC")}else{return minitz.tp(pd.getFullYear(),pd.getMonth()+1,pd.getDate(),pd.getHours(),pd.getMinutes(),pd.getSeconds(),tz)}}minitz.minitz=minitz;function CronOptions(options){if(options===void 0){options={}}delete options.name;options.legacyMode=options.legacyMode===void 0?true:options.legacyMode;options.paused=options.paused===void 0?false:options.paused;options.maxRuns=options.maxRuns===void 0?Infinity:options.maxRuns;options.catch=options.catch===void 0?false:options.catch;options.interval=options.interval===void 0?0:parseInt(options.interval,10);options.utcOffset=options.utcOffset===void 0?void 0:parseInt(options.utcOffset,10);options.unref=options.unref===void 0?false:options.unref;options.kill=false;if(options.startAt){options.startAt=new CronDate(options.startAt,options.timezone)}if(options.stopAt){options.stopAt=new CronDate(options.stopAt,options.timezone)}if(options.interval!==null){if(isNaN(options.interval)){throw new Error("CronOptions: Supplied value for interval is not a number")}else if(options.interval<0){throw new Error("CronOptions: Supplied value for interval can not be negative")}}if(options.utcOffset!==void 0){if(isNaN(options.utcOffset)){throw new Error("CronOptions: Invalid value passed for utcOffset, should be number representing minutes offset from UTC.")}else if(options.utcOffset<-870||options.utcOffset>870){throw new Error("CronOptions: utcOffset out of bounds.")}if(options.utcOffset!==void 0&&options.timezone){throw new Error("CronOptions: Combining 'utcOffset' with 'timezone' is not allowed.")}}if(options.unref!==true&&options.unref!==false){throw new Error("CronOptions: Unref should be either true, false or undefined(false).")}return options}const DaysOfMonth=[31,28,31,30,31,30,31,31,30,31,30,31];const RecursionSteps=[["month","year",0],["day","month",-1],["hour","day",0],["minute","hour",0],["second","minute",0]];function CronDate(d,tz){this.tz=tz;if(d&&d instanceof Date){if(!isNaN(d)){this.fromDate(d)}else{throw new TypeError("CronDate: Invalid date passed to CronDate constructor")}}else if(d===void 0){this.fromDate(new Date)}else if(d&&typeof d==="string"){this.fromString(d)}else if(d instanceof CronDate){this.fromCronDate(d)}else{throw new TypeError("CronDate: Invalid type ("+typeof d+") passed to CronDate constructor")}}CronDate.prototype.fromDate=function(inDate){if(this.tz!==void 0){if(typeof this.tz==="number"){this.ms=inDate.getUTCMilliseconds();this.second=inDate.getUTCSeconds();this.minute=inDate.getUTCMinutes()+this.tz;this.hour=inDate.getUTCHours();this.day=inDate.getUTCDate();this.month=inDate.getUTCMonth();this.year=inDate.getUTCFullYear();this.apply()}else{const d=minitz.toTZ(inDate,this.tz);this.ms=inDate.getMilliseconds();this.second=d.s;this.minute=d.i;this.hour=d.h;this.day=d.d;this.month=d.m-1;this.year=d.y}}else{this.ms=inDate.getMilliseconds();this.second=inDate.getSeconds();this.minute=inDate.getMinutes();this.hour=inDate.getHours();this.day=inDate.getDate();this.month=inDate.getMonth();this.year=inDate.getFullYear()}};CronDate.prototype.fromCronDate=function(d){this.tz=d.tz;this.year=d.year;this.month=d.month;this.day=d.day;this.hour=d.hour;this.minute=d.minute;this.second=d.second;this.ms=d.ms};CronDate.prototype.apply=function(){if(this.month>11||this.day>DaysOfMonth[this.month]||this.hour>59||this.minute>59||this.second>59||this.hour<0||this.minute<0||this.second<0){const d=new Date(Date.UTC(this.year,this.month,this.day,this.hour,this.minute,this.second,this.ms));this.ms=d.getUTCMilliseconds();this.second=d.getUTCSeconds();this.minute=d.getUTCMinutes();this.hour=d.getUTCHours();this.day=d.getUTCDate();this.month=d.getUTCMonth();this.year=d.getUTCFullYear();return true}else{return false}};CronDate.prototype.fromString=function(str){return this.fromDate(minitz.fromTZISO(str,this.tz))};CronDate.prototype.findNext=function(options,target,pattern,offset){const originalTarget=this[target];let lastDayOfMonth;if(pattern.lastDayOfMonth){if(this.month!==1){lastDayOfMonth=DaysOfMonth[this.month]}else{lastDayOfMonth=new Date(Date.UTC(this.year,this.month+1,0,0,0,0,0)).getUTCDate()}}const fDomWeekDay=!pattern.starDOW&&target=="day"?new Date(Date.UTC(this.year,this.month,1,0,0,0,0)).getUTCDay():undefined;for(let i=this[target]+offset;i<pattern[target].length;i++){let match=pattern[target][i];if(target==="day"&&pattern.lastDayOfMonth&&i-offset==lastDayOfMonth){match=true}if(target==="day"&&!pattern.starDOW){const dowMatch=pattern.dow[(fDomWeekDay+(i-offset-1))%7];if(options.legacyMode&&!pattern.starDOM){match=match||dowMatch}else{match=match&&dowMatch}}if(match){this[target]=i-offset;return originalTarget!==this[target]?2:1}}return 3};CronDate.prototype.recurse=function(pattern,options,doing){const res=this.findNext(options,RecursionSteps[doing][0],pattern,RecursionSteps[doing][2]);if(res>1){let resetLevel=doing+1;while(resetLevel<RecursionSteps.length){this[RecursionSteps[resetLevel][0]]=-RecursionSteps[resetLevel][2];resetLevel++}if(res===3){this[RecursionSteps[doing][1]]++;this[RecursionSteps[doing][0]]=-RecursionSteps[doing][2];this.apply();return this.recurse(pattern,options,0)}else if(this.apply()){return this.recurse(pattern,options,doing-1)}}doing+=1;if(doing>=RecursionSteps.length){return this}else if(this.year>=3e3){return null}else{return this.recurse(pattern,options,doing)}};CronDate.prototype.increment=function(pattern,options,hasPreviousRun){if(options.interval>1&&hasPreviousRun){this.second+=options.interval}else{this.second+=1}this.ms=0;this.apply();return this.recurse(pattern,options,0)};CronDate.prototype.getDate=function(internal){if(internal||this.tz===void 0&&this.utcOffset===void 0){return new Date(this.year,this.month,this.day,this.hour,this.minute,this.second,this.ms)}else{if(typeof this.tz==="number"){return new Date(Date.UTC(this.year,this.month,this.day,this.hour,this.minute-this.tz,this.second,this.ms))}else{return minitz(this.year,this.month+1,this.day,this.hour,this.minute,this.second,this.tz)}}};CronDate.prototype.getTime=function(){return this.getDate().getTime()};function CronPattern(pattern,timezone){this.pattern=pattern;this.timezone=timezone;this.second=Array(60).fill(0);this.minute=Array(60).fill(0);this.hour=Array(24).fill(0);this.day=Array(31).fill(0);this.month=Array(12).fill(0);this.dow=Array(8).fill(0);this.lastDayOfMonth=false;this.starDOM=false;this.starDOW=false;this.parse()}CronPattern.prototype.parse=function(){if(!(typeof this.pattern==="string"||this.pattern.constructor===String)){throw new TypeError("CronPattern: Pattern has to be of type string.")}if(this.pattern.indexOf("@")>=0)this.pattern=this.handleNicknames(this.pattern).trim();const parts=this.pattern.replace(/\s+/g," ").split(" ");if(parts.length<5||parts.length>6){throw new TypeError("CronPattern: invalid configuration format ('"+this.pattern+"'), exacly five or six space separated parts required.")}if(parts.length===5){parts.unshift("0")}if(parts[3].indexOf("L")>=0){parts[3]=parts[3].replace("L","");this.lastDayOfMonth=true}if(parts[3]=="*"){this.starDOM=true}if(parts[4].length>=3)parts[4]=this.replaceAlphaMonths(parts[4]);if(parts[5].length>=3)parts[5]=this.replaceAlphaDays(parts[5]);if(parts[5]=="*"){this.starDOW=true}if(this.pattern.indexOf("?")>=0){const initDate=new CronDate(new Date,this.timezone).getDate(true);parts[0]=parts[0].replace("?",initDate.getSeconds());parts[1]=parts[1].replace("?",initDate.getMinutes());parts[2]=parts[2].replace("?",initDate.getHours());if(!this.starDOM)parts[3]=parts[3].replace("?",initDate.getDate());parts[4]=parts[4].replace("?",initDate.getMonth()+1);if(!this.starDOW)parts[5]=parts[5].replace("?",initDate.getDay())}this.throwAtIllegalCharacters(parts);this.partToArray("second",parts[0],0);this.partToArray("minute",parts[1],0);this.partToArray("hour",parts[2],0);this.partToArray("day",parts[3],-1);this.partToArray("month",parts[4],-1);this.partToArray("dow",parts[5],0);if(this.dow[7]){this.dow[0]=1}};CronPattern.prototype.partToArray=function(type,conf,valueIndexOffset){const arr=this[type];if(conf==="*")return arr.fill(1);const split=conf.split(",");if(split.length>1){for(let i=0;i<split.length;i++){this.partToArray(type,split[i],valueIndexOffset)}}else if(conf.indexOf("-")!==-1&&conf.indexOf("/")!==-1){this.handleRangeWithStepping(conf,type,valueIndexOffset)}else if(conf.indexOf("-")!==-1){this.handleRange(conf,type,valueIndexOffset)}else if(conf.indexOf("/")!==-1){this.handleStepping(conf,type,valueIndexOffset)}else if(conf!==""){this.handleNumber(conf,type,valueIndexOffset)}};CronPattern.prototype.throwAtIllegalCharacters=function(parts){const reValidCron=/[^/*0-9,-]+/;for(let i=0;i<parts.length;i++){if(reValidCron.test(parts[i])){throw new TypeError("CronPattern: configuration entry "+i+" ("+parts[i]+") contains illegal characters.")}}};CronPattern.prototype.handleNumber=function(conf,type,valueIndexOffset){const i=parseInt(conf,10)+valueIndexOffset;if(isNaN(i)){throw new TypeError("CronPattern: "+type+" is not a number: '"+conf+"'")}if(i<0||i>=this[type].length){throw new TypeError("CronPattern: "+type+" value out of range: '"+conf+"'")}this[type][i]=1};CronPattern.prototype.handleRangeWithStepping=function(conf,type,valueIndexOffset){const matches=conf.match(/^(\d+)-(\d+)\/(\d+)$/);if(matches===null)throw new TypeError("CronPattern: Syntax error, illegal range with stepping: '"+conf+"'");let[,lower,upper,steps]=matches;lower=parseInt(lower,10)+valueIndexOffset;upper=parseInt(upper,10)+valueIndexOffset;steps=parseInt(steps,10);if(isNaN(lower))throw new TypeError("CronPattern: Syntax error, illegal lower range (NaN)");if(isNaN(upper))throw new TypeError("CronPattern: Syntax error, illegal upper range (NaN)");if(isNaN(steps))throw new TypeError("CronPattern: Syntax error, illegal stepping: (NaN)");if(steps===0)throw new TypeError("CronPattern: Syntax error, illegal stepping: 0");if(steps>this[type].length)throw new TypeError("CronPattern: Syntax error, steps cannot be greater than maximum value of part ("+this[type].length+")");if(lower<0||upper>=this[type].length)throw new TypeError("CronPattern: Value out of range: '"+conf+"'");if(lower>upper)throw new TypeError("CronPattern: From value is larger than to value: '"+conf+"'");for(let i=lower;i<=upper;i+=steps){this[type][i]=1}};CronPattern.prototype.handleRange=function(conf,type,valueIndexOffset){const split=conf.split("-");if(split.length!==2){throw new TypeError("CronPattern: Syntax error, illegal range: '"+conf+"'")}const lower=parseInt(split[0],10)+valueIndexOffset,upper=parseInt(split[1],10)+valueIndexOffset;if(isNaN(lower)){throw new TypeError("CronPattern: Syntax error, illegal lower range (NaN)")}else if(isNaN(upper)){throw new TypeError("CronPattern: Syntax error, illegal upper range (NaN)")}if(lower<0||upper>=this[type].length){throw new TypeError("CronPattern: Value out of range: '"+conf+"'")}if(lower>upper){throw new TypeError("CronPattern: From value is larger than to value: '"+conf+"'")}for(let i=lower;i<=upper;i++){this[type][i]=1}};CronPattern.prototype.handleStepping=function(conf,type){const split=conf.split("/");if(split.length!==2){throw new TypeError("CronPattern: Syntax error, illegal stepping: '"+conf+"'")}let start=0;if(split[0]!=="*"){start=parseInt(split[0],10)}const steps=parseInt(split[1],10);if(isNaN(steps))throw new TypeError("CronPattern: Syntax error, illegal stepping: (NaN)");if(steps===0)throw new TypeError("CronPattern: Syntax error, illegal stepping: 0");if(steps>this[type].length)throw new TypeError("CronPattern: Syntax error, max steps for part is ("+this[type].length+")");for(let i=start;i<this[type].length;i+=steps){this[type][i]=1}};CronPattern.prototype.replaceAlphaDays=function(conf){return conf.replace(/-sun/gi,"-7").replace(/sun/gi,"0").replace(/mon/gi,"1").replace(/tue/gi,"2").replace(/wed/gi,"3").replace(/thu/gi,"4").replace(/fri/gi,"5").replace(/sat/gi,"6")};CronPattern.prototype.replaceAlphaMonths=function(conf){return conf.replace(/jan/gi,"1").replace(/feb/gi,"2").replace(/mar/gi,"3").replace(/apr/gi,"4").replace(/may/gi,"5").replace(/jun/gi,"6").replace(/jul/gi,"7").replace(/aug/gi,"8").replace(/sep/gi,"9").replace(/oct/gi,"10").replace(/nov/gi,"11").replace(/dec/gi,"12")};CronPattern.prototype.handleNicknames=function(pattern){const cleanPattern=pattern.trim().toLowerCase();if(cleanPattern==="@yearly"||cleanPattern==="@annually"){return"0 0 1 1 *"}else if(cleanPattern==="@monthly"){return"0 0 1 * *"}else if(cleanPattern==="@weekly"){return"0 0 * * 0"}else if(cleanPattern==="@daily"){return"0 0 * * *"}else if(cleanPattern==="@hourly"){return"0 * * * *"}else{return pattern}};const maxDelay=Math.pow(2,32-1)-1;const scheduledJobs=[];function Cron(pattern,fnOrOptions1,fnOrOptions2){if(!(this instanceof Cron)){return new Cron(pattern,fnOrOptions1,fnOrOptions2)}let options,func;if(typeof fnOrOptions1==="function"){func=fnOrOptions1}else if(typeof fnOrOptions1==="object"){options=fnOrOptions1}else if(fnOrOptions1!==void 0){throw new Error("Cron: Invalid argument passed for optionsIn. Should be one of function, or object (options).")}if(typeof fnOrOptions2==="function"){func=fnOrOptions2}else if(typeof fnOrOptions2==="object"){options=fnOrOptions2}else if(fnOrOptions2!==void 0){throw new Error("Cron: Invalid argument passed for funcIn. Should be one of function, or object (options).")}this.name=options?options.name:void 0;this.options=CronOptions(options);this.once=void 0;this.pattern=void 0;this.blocking=false;this.previousrun=void 0;this.runstarted=void 0;if(pattern&&(pattern instanceof Date||typeof pattern==="string"&&pattern.indexOf(":")>0)){this.once=new CronDate(pattern,this.options.timezone||this.options.utcOffset)}else{this.pattern=new CronPattern(pattern,this.options.timezone)}if(func!==void 0){this.fn=func;this.schedule()}if(this.name){const existing=scheduledJobs.find(j=>j.name===this.name);if(existing){throw new Error("Cron: Tried to initialize new named job '"+this.name+"', but name already taken.")}else{scheduledJobs.push(this)}}return this}Cron.prototype.next=function(prev){const next=this._next(prev);return next?next.getDate():null};Cron.prototype.enumerate=function(n,previous){if(n>this.options.maxRuns){n=this.options.maxRuns}const enumeration=[];let prev=previous||this.previousrun;while(n--&&(prev=this.next(prev))){enumeration.push(prev)}return enumeration};Cron.prototype.running=function(){const msLeft=this.msToNext(this.previousrun);const running=!this.options.paused&&this.fn!==void 0;return msLeft!==null&&running};Cron.prototype.working=function(){return this.blocking};Cron.prototype.started=function(){return this.runstarted?this.runstarted.getDate():null};Cron.prototype.previous=function(){return this.previousrun?this.previousrun.getDate():null};Cron.prototype.msToNext=function(prev){const next=this._next(prev);prev=new CronDate(prev,this.options.timezone||this.options.utcOffset);if(next){return next.getTime(true)-prev.getTime(true)}else{return null}};Cron.prototype.stop=function(){this.options.kill=true;if(this.currentTimeout){clearTimeout(this.currentTimeout)}};Cron.prototype.pause=function(){return(this.options.paused=true)&&!this.options.kill};Cron.prototype.resume=function(){return!(this.options.paused=false)&&!this.options.kill};Cron.prototype.schedule=function(func,partial){if(func&&this.fn){throw new Error("Cron: It is not allowed to schedule two functions using the same Croner instance.")}else if(func){this.fn=func}let waitMs=this.msToNext(partial?partial:this.previousrun);const target=this.next(partial?partial:this.previousrun);if(waitMs===null)return this;if(waitMs>maxDelay){waitMs=maxDelay}this.currentTimeout=setTimeout(()=>{const now=new Date,shouldRun=waitMs!==maxDelay&&!this.options.paused&&now.getTime()>=target,isBlocked=this.blocking&&this.options.protect;if(shouldRun&&!isBlocked){this.options.maxRuns--;(async inst=>{inst.blocking=true;this.runstarted=new CronDate(void 0,this.options.timezone||this.options.utcOffset);if(this.options.catch){try{await inst.fn(inst,inst.options.context)}catch(_e){if(Object.prototype.toString.call(inst.options.catch)==="[object Function]"||"function"===typeof inst.options.catch||inst.options.catch instanceof Function){inst.options.catch(_e,inst)}}finally{inst.blocking=false}}else{await this.fn(this,this.options.context);inst.blocking=false}})(this);this.previousrun=new CronDate(void 0,this.options.timezone||this.options.utcOffset);this.schedule()}else{if(shouldRun&&isBlocked&&Object.prototype.toString.call(this.options.protect)==="[object Function]"||"function"===typeof this.options.protect||this.options.protect instanceof Function){(async inst=>{inst.options.protect(inst)})(this)}this.schedule(undefined,now)}},waitMs);if(this.currentTimeout&&this.options.unref){if(typeof Deno!=="undefined"&&typeof Deno.unrefTimer!=="undefined"){Deno.unrefTimer(this.currentTimeout)}else if(typeof this.currentTimeout.unref!=="undefined"){this.currentTimeout.unref()}}return this};Cron.prototype._next=function(prev){const hasPreviousRun=prev||this.previousrun?true:false;prev=new CronDate(prev,this.options.timezone||this.options.utcOffset);if(this.options.startAt&&prev&&prev.getTime()<this.options.startAt.getTime()){prev=this.options.startAt}const nextRun=this.once||new CronDate(prev,this.options.timezone||this.options.utcOffset).increment(this.pattern,this.options,hasPreviousRun);if(this.once&&this.once.getTime()<=prev.getTime()){return null}else if(nextRun===null||this.options.maxRuns<=0||this.options.kill||this.options.stopAt&&nextRun.getTime()>=this.options.stopAt.getTime()){return null}else{return nextRun}};Cron.Cron=Cron;Cron.scheduledJobs=scheduledJobs;return Cron});
|
package/dist/croner.min.mjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
function minitz(y,m,d,h,i,s,tz,throwOnInvalid){return minitz.fromTZ(minitz.tp(y,m,d,h,i,s,tz),throwOnInvalid)}minitz.fromTZISO=(localTimeStr,tz,throwOnInvalid)=>{return minitz.fromTZ(parseISOLocal(localTimeStr,tz),throwOnInvalid)};minitz.fromTZ=function(tp,throwOnInvalid){const inDate=new Date(Date.UTC(tp.y,tp.m-1,tp.d,tp.h,tp.i,tp.s)),offset=getTimezoneOffset(tp.tz,inDate),dateGuess=new Date(inDate.getTime()-offset),dateOffsGuess=getTimezoneOffset(tp.tz,dateGuess);if(dateOffsGuess-offset===0){return dateGuess}else{const dateGuess2=new Date(inDate.getTime()-dateOffsGuess),dateOffsGuess2=getTimezoneOffset(tp.tz,dateGuess2);if(dateOffsGuess2-dateOffsGuess===0){return dateGuess2}else if(!throwOnInvalid&&dateOffsGuess2-dateOffsGuess>0){return dateGuess2}else if(!throwOnInvalid){return dateGuess}else{throw new Error("Invalid date passed to fromTZ()")}}};minitz.toTZ=function(d,tzStr){const td=new Date(d.toLocaleString("sv-SE",{timeZone:tzStr}));return{y:td.getFullYear(),m:td.getMonth()+1,d:td.getDate(),h:td.getHours(),i:td.getMinutes(),s:td.getSeconds(),tz:tzStr}};minitz.tp=(y,m,d,h,i,s,tz)=>{return{y:y,m:m,d:d,h:h,i:i,s:s,tz:tz}};function getTimezoneOffset(timeZone,date=new Date){const tz=date.toLocaleString("en",{timeZone:timeZone,timeStyle:"long"}).split(" ").slice(-1)[0];const dateString=date.toLocaleString("en-US").replace(/[\u202f]/," ");return Date.parse(`${dateString} GMT`)-Date.parse(`${dateString} ${tz}`)}function parseISOLocal(dtStr,tz){const pd=new Date(Date.parse(dtStr));if(isNaN(pd)){throw new Error("minitz: Invalid ISO8601 passed to parser.")}const stringEnd=dtStr.substring(9);if(dtStr.includes("Z")||stringEnd.includes("-")||stringEnd.includes("+")){return minitz.tp(pd.getUTCFullYear(),pd.getUTCMonth()+1,pd.getUTCDate(),pd.getUTCHours(),pd.getUTCMinutes(),pd.getUTCSeconds(),"Etc/UTC")}else{return minitz.tp(pd.getFullYear(),pd.getMonth()+1,pd.getDate(),pd.getHours(),pd.getMinutes(),pd.getSeconds(),tz)}}minitz.minitz=minitz;function CronOptions(options){if(options===void 0){options={}}delete options.name;options.legacyMode=options.legacyMode===void 0?true:options.legacyMode;options.paused=options.paused===void 0?false:options.paused;options.maxRuns=options.maxRuns===void 0?Infinity:options.maxRuns;options.catch=options.catch===void 0?false:options.catch;options.interval=options.interval===void 0?0:parseInt(options.interval,10);options.utcOffset=options.utcOffset===void 0?void 0:parseInt(options.utcOffset,10);options.unref=options.unref===void 0?false:options.unref;options.kill=false;if(options.startAt){options.startAt=new CronDate(options.startAt,options.timezone)}if(options.stopAt){options.stopAt=new CronDate(options.stopAt,options.timezone)}if(options.interval!==null){if(isNaN(options.interval)){throw new Error("CronOptions: Supplied value for interval is not a number")}else if(options.interval<0){throw new Error("CronOptions: Supplied value for interval can not be negative")}}if(options.utcOffset!==void 0){if(isNaN(options.utcOffset)){throw new Error("CronOptions: Invalid value passed for utcOffset, should be number representing minutes offset from UTC.")}else if(options.utcOffset<-870||options.utcOffset>870){throw new Error("CronOptions: utcOffset out of bounds.")}if(options.utcOffset!==void 0&&options.timezone){throw new Error("CronOptions: Combining 'utcOffset' with 'timezone' is not allowed.")}}if(options.unref!==true&&options.unref!==false){throw new Error("CronOptions: Unref should be either true, false or undefined(false).")}return options}const DaysOfMonth=[31,28,31,30,31,30,31,31,30,31,30,31];const RecursionSteps=[["month","year",0],["day","month",-1],["hour","day",0],["minute","hour",0],["second","minute",0]];function CronDate(d,tz){this.tz=tz;if(d&&d instanceof Date){if(!isNaN(d)){this.fromDate(d)}else{throw new TypeError("CronDate: Invalid date passed to CronDate constructor")}}else if(d===void 0){this.fromDate(new Date)}else if(d&&typeof d==="string"){this.fromString(d)}else if(d instanceof CronDate){this.fromCronDate(d)}else{throw new TypeError("CronDate: Invalid type ("+typeof d+") passed to CronDate constructor")}}CronDate.prototype.fromDate=function(inDate){if(this.tz!==void 0){if(typeof this.tz==="number"){this.ms=inDate.getMilliseconds();this.second=inDate.getSeconds();this.minute=inDate.getMinutes()+this.tz;this.hour=inDate.getHours();this.day=inDate.getDate();this.month=inDate.getMonth();this.year=inDate.getFullYear();this.apply()}else{const d=minitz.toTZ(inDate,this.tz);this.ms=inDate.getMilliseconds();this.second=d.s;this.minute=d.i;this.hour=d.h;this.day=d.d;this.month=d.m-1;this.year=d.y}}else{this.ms=inDate.getMilliseconds();this.second=inDate.getSeconds();this.minute=inDate.getMinutes();this.hour=inDate.getHours();this.day=inDate.getDate();this.month=inDate.getMonth();this.year=inDate.getFullYear()}};CronDate.prototype.fromCronDate=function(d){this.tz=d.tz;this.year=d.year;this.month=d.month;this.day=d.day;this.hour=d.hour;this.minute=d.minute;this.second=d.second;this.ms=d.ms};CronDate.prototype.apply=function(){if(this.month>11||this.day>DaysOfMonth[this.month]||this.hour>59||this.minute>59||this.second>59||this.hour<0||this.minute<0||this.second<0){const d=new Date(Date.UTC(this.year,this.month,this.day,this.hour,this.minute,this.second,this.ms));this.ms=d.getUTCMilliseconds();this.second=d.getUTCSeconds();this.minute=d.getUTCMinutes();this.hour=d.getUTCHours();this.day=d.getUTCDate();this.month=d.getUTCMonth();this.year=d.getUTCFullYear();return true}else{return false}};CronDate.prototype.fromString=function(str){return this.fromDate(minitz.fromTZISO(str,this.tz))};CronDate.prototype.findNext=function(options,target,pattern,offset){const originalTarget=this[target];let lastDayOfMonth;if(pattern.lastDayOfMonth){if(this.month!==1){lastDayOfMonth=DaysOfMonth[this.month]}else{lastDayOfMonth=new Date(Date.UTC(this.year,this.month+1,0,0,0,0,0)).getUTCDate()}}const fDomWeekDay=!pattern.starDOW&&target=="day"?new Date(Date.UTC(this.year,this.month,1,0,0,0,0)).getUTCDay():undefined;for(let i=this[target]+offset;i<pattern[target].length;i++){let match=pattern[target][i];if(target==="day"&&pattern.lastDayOfMonth&&i-offset==lastDayOfMonth){match=true}if(target==="day"&&!pattern.starDOW){const dowMatch=pattern.dow[(fDomWeekDay+(i-offset-1))%7];if(options.legacyMode&&!pattern.starDOM){match=match||dowMatch}else{match=match&&dowMatch}}if(match){this[target]=i-offset;return originalTarget!==this[target]?2:1}}return 3};CronDate.prototype.recurse=function(pattern,options,doing){const res=this.findNext(options,RecursionSteps[doing][0],pattern,RecursionSteps[doing][2]);if(res>1){let resetLevel=doing+1;while(resetLevel<RecursionSteps.length){this[RecursionSteps[resetLevel][0]]=-RecursionSteps[resetLevel][2];resetLevel++}if(res===3){this[RecursionSteps[doing][1]]++;this[RecursionSteps[doing][0]]=-RecursionSteps[doing][2];this.apply();return this.recurse(pattern,options,0)}else if(this.apply()){return this.recurse(pattern,options,doing-1)}}doing+=1;if(doing>=RecursionSteps.length){return this}else if(this.year>=3e3){return null}else{return this.recurse(pattern,options,doing)}};CronDate.prototype.increment=function(pattern,options,hasPreviousRun){if(options.interval>1&&hasPreviousRun){this.second+=options.interval}else{this.second+=1}this.ms=0;this.apply();return this.recurse(pattern,options,0)};CronDate.prototype.getDate=function(internal){if(internal||!(this.tz!==void 0)){return new Date(this.year,this.month,this.day,this.hour,this.minute,this.second,this.ms)}else{if(typeof this.tz==="number"){return new Date(Date.UTC(this.year,this.month,this.day,this.hour,this.minute-this.tz,this.second,this.ms))}else{return minitz(this.year,this.month+1,this.day,this.hour,this.minute,this.second,this.tz)}}};CronDate.prototype.getTime=function(){return this.getDate().getTime()};function CronPattern(pattern,timezone){this.pattern=pattern;this.timezone=timezone;this.second=Array(60).fill(0);this.minute=Array(60).fill(0);this.hour=Array(24).fill(0);this.day=Array(31).fill(0);this.month=Array(12).fill(0);this.dow=Array(8).fill(0);this.lastDayOfMonth=false;this.starDOM=false;this.starDOW=false;this.parse()}CronPattern.prototype.parse=function(){if(!(typeof this.pattern==="string"||this.pattern.constructor===String)){throw new TypeError("CronPattern: Pattern has to be of type string.")}if(this.pattern.indexOf("@")>=0)this.pattern=this.handleNicknames(this.pattern).trim();const parts=this.pattern.replace(/\s+/g," ").split(" ");if(parts.length<5||parts.length>6){throw new TypeError("CronPattern: invalid configuration format ('"+this.pattern+"'), exacly five or six space separated parts required.")}if(parts.length===5){parts.unshift("0")}if(parts[3].indexOf("L")>=0){parts[3]=parts[3].replace("L","");this.lastDayOfMonth=true}if(parts[3]=="*"){this.starDOM=true}if(parts[4].length>=3)parts[4]=this.replaceAlphaMonths(parts[4]);if(parts[5].length>=3)parts[5]=this.replaceAlphaDays(parts[5]);if(parts[5]=="*"){this.starDOW=true}if(this.pattern.indexOf("?")>=0){const initDate=new CronDate(new Date,this.timezone).getDate(true);parts[0]=parts[0].replace("?",initDate.getSeconds());parts[1]=parts[1].replace("?",initDate.getMinutes());parts[2]=parts[2].replace("?",initDate.getHours());if(!this.starDOM)parts[3]=parts[3].replace("?",initDate.getDate());parts[4]=parts[4].replace("?",initDate.getMonth()+1);if(!this.starDOW)parts[5]=parts[5].replace("?",initDate.getDay())}this.throwAtIllegalCharacters(parts);this.partToArray("second",parts[0],0);this.partToArray("minute",parts[1],0);this.partToArray("hour",parts[2],0);this.partToArray("day",parts[3],-1);this.partToArray("month",parts[4],-1);this.partToArray("dow",parts[5],0);if(this.dow[7]){this.dow[0]=1}};CronPattern.prototype.partToArray=function(type,conf,valueIndexOffset){const arr=this[type];if(conf==="*")return arr.fill(1);const split=conf.split(",");if(split.length>1){for(let i=0;i<split.length;i++){this.partToArray(type,split[i],valueIndexOffset)}}else if(conf.indexOf("-")!==-1&&conf.indexOf("/")!==-1){this.handleRangeWithStepping(conf,type,valueIndexOffset)}else if(conf.indexOf("-")!==-1){this.handleRange(conf,type,valueIndexOffset)}else if(conf.indexOf("/")!==-1){this.handleStepping(conf,type,valueIndexOffset)}else if(conf!==""){this.handleNumber(conf,type,valueIndexOffset)}};CronPattern.prototype.throwAtIllegalCharacters=function(parts){const reValidCron=/[^/*0-9,-]+/;for(let i=0;i<parts.length;i++){if(reValidCron.test(parts[i])){throw new TypeError("CronPattern: configuration entry "+i+" ("+parts[i]+") contains illegal characters.")}}};CronPattern.prototype.handleNumber=function(conf,type,valueIndexOffset){const i=parseInt(conf,10)+valueIndexOffset;if(isNaN(i)){throw new TypeError("CronPattern: "+type+" is not a number: '"+conf+"'")}if(i<0||i>=this[type].length){throw new TypeError("CronPattern: "+type+" value out of range: '"+conf+"'")}this[type][i]=1};CronPattern.prototype.handleRangeWithStepping=function(conf,type,valueIndexOffset){const matches=conf.match(/^(\d+)-(\d+)\/(\d+)$/);if(matches===null)throw new TypeError("CronPattern: Syntax error, illegal range with stepping: '"+conf+"'");let[,lower,upper,steps]=matches;lower=parseInt(lower,10)+valueIndexOffset;upper=parseInt(upper,10)+valueIndexOffset;steps=parseInt(steps,10);if(isNaN(lower))throw new TypeError("CronPattern: Syntax error, illegal lower range (NaN)");if(isNaN(upper))throw new TypeError("CronPattern: Syntax error, illegal upper range (NaN)");if(isNaN(steps))throw new TypeError("CronPattern: Syntax error, illegal stepping: (NaN)");if(steps===0)throw new TypeError("CronPattern: Syntax error, illegal stepping: 0");if(steps>this[type].length)throw new TypeError("CronPattern: Syntax error, steps cannot be greater than maximum value of part ("+this[type].length+")");if(lower<0||upper>=this[type].length)throw new TypeError("CronPattern: Value out of range: '"+conf+"'");if(lower>upper)throw new TypeError("CronPattern: From value is larger than to value: '"+conf+"'");for(let i=lower;i<=upper;i+=steps){this[type][i]=1}};CronPattern.prototype.handleRange=function(conf,type,valueIndexOffset){const split=conf.split("-");if(split.length!==2){throw new TypeError("CronPattern: Syntax error, illegal range: '"+conf+"'")}const lower=parseInt(split[0],10)+valueIndexOffset,upper=parseInt(split[1],10)+valueIndexOffset;if(isNaN(lower)){throw new TypeError("CronPattern: Syntax error, illegal lower range (NaN)")}else if(isNaN(upper)){throw new TypeError("CronPattern: Syntax error, illegal upper range (NaN)")}if(lower<0||upper>=this[type].length){throw new TypeError("CronPattern: Value out of range: '"+conf+"'")}if(lower>upper){throw new TypeError("CronPattern: From value is larger than to value: '"+conf+"'")}for(let i=lower;i<=upper;i++){this[type][i]=1}};CronPattern.prototype.handleStepping=function(conf,type){const split=conf.split("/");if(split.length!==2){throw new TypeError("CronPattern: Syntax error, illegal stepping: '"+conf+"'")}let start=0;if(split[0]!=="*"){start=parseInt(split[0],10)}const steps=parseInt(split[1],10);if(isNaN(steps))throw new TypeError("CronPattern: Syntax error, illegal stepping: (NaN)");if(steps===0)throw new TypeError("CronPattern: Syntax error, illegal stepping: 0");if(steps>this[type].length)throw new TypeError("CronPattern: Syntax error, max steps for part is ("+this[type].length+")");for(let i=start;i<this[type].length;i+=steps){this[type][i]=1}};CronPattern.prototype.replaceAlphaDays=function(conf){return conf.replace(/-sun/gi,"-7").replace(/sun/gi,"0").replace(/mon/gi,"1").replace(/tue/gi,"2").replace(/wed/gi,"3").replace(/thu/gi,"4").replace(/fri/gi,"5").replace(/sat/gi,"6")};CronPattern.prototype.replaceAlphaMonths=function(conf){return conf.replace(/jan/gi,"1").replace(/feb/gi,"2").replace(/mar/gi,"3").replace(/apr/gi,"4").replace(/may/gi,"5").replace(/jun/gi,"6").replace(/jul/gi,"7").replace(/aug/gi,"8").replace(/sep/gi,"9").replace(/oct/gi,"10").replace(/nov/gi,"11").replace(/dec/gi,"12")};CronPattern.prototype.handleNicknames=function(pattern){const cleanPattern=pattern.trim().toLowerCase();if(cleanPattern==="@yearly"||cleanPattern==="@annually"){return"0 0 1 1 *"}else if(cleanPattern==="@monthly"){return"0 0 1 * *"}else if(cleanPattern==="@weekly"){return"0 0 * * 0"}else if(cleanPattern==="@daily"){return"0 0 * * *"}else if(cleanPattern==="@hourly"){return"0 * * * *"}else{return pattern}};const maxDelay=Math.pow(2,32-1)-1;const scheduledJobs=[];function Cron(pattern,fnOrOptions1,fnOrOptions2){if(!(this instanceof Cron)){return new Cron(pattern,fnOrOptions1,fnOrOptions2)}let options,func;if(typeof fnOrOptions1==="function"){func=fnOrOptions1}else if(typeof fnOrOptions1==="object"){options=fnOrOptions1}else if(fnOrOptions1!==void 0){throw new Error("Cron: Invalid argument passed for optionsIn. Should be one of function, or object (options).")}if(typeof fnOrOptions2==="function"){func=fnOrOptions2}else if(typeof fnOrOptions2==="object"){options=fnOrOptions2}else if(fnOrOptions2!==void 0){throw new Error("Cron: Invalid argument passed for funcIn. Should be one of function, or object (options).")}this.name=options?options.name:void 0;this.options=CronOptions(options);this.once=void 0;this.pattern=void 0;if(pattern&&(pattern instanceof Date||typeof pattern==="string"&&pattern.indexOf(":")>0)){this.once=new CronDate(pattern,this.options.timezone||this.options.utcOffset)}else{this.pattern=new CronPattern(pattern,this.options.timezone)}if(func!==void 0){this.fn=func;this.schedule()}if(this.name){const existing=scheduledJobs.find(j=>j.name===this.name);if(existing){throw new Error("Cron: Tried to initialize new named job '"+this.name+"', but name already taken.")}else{scheduledJobs.push(this)}}return this}Cron.prototype.next=function(prev){const next=this._next(prev);return next?next.getDate():null};Cron.prototype.enumerate=function(n,previous){if(n>this.options.maxRuns){n=this.options.maxRuns}const enumeration=[];let prev=previous||this.previousrun;while(n--&&(prev=this.next(prev))){enumeration.push(prev)}return enumeration};Cron.prototype.running=function(){const msLeft=this.msToNext(this.previousrun);const running=!this.options.paused&&this.fn!==void 0;return msLeft!==null&&running};Cron.prototype.previous=function(){return this.previousrun?this.previousrun.getDate():null};Cron.prototype.msToNext=function(prev){const next=this._next(prev);prev=new CronDate(prev,this.options.timezone||this.options.utcOffset);if(next){return next.getTime(true)-prev.getTime(true)}else{return null}};Cron.prototype.stop=function(){this.options.kill=true;if(this.currentTimeout){clearTimeout(this.currentTimeout)}};Cron.prototype.pause=function(){return(this.options.paused=true)&&!this.options.kill};Cron.prototype.resume=function(){return!(this.options.paused=false)&&!this.options.kill};Cron.prototype.schedule=function(func,partial){if(func&&this.fn){throw new Error("Cron: It is not allowed to schedule two functions using the same Croner instance.")}else if(func){this.fn=func}let waitMs=this.msToNext(partial?partial:this.previousrun);const target=this.next(partial?partial:this.previousrun);if(waitMs===null)return this;if(waitMs>maxDelay){waitMs=maxDelay}this.currentTimeout=setTimeout(()=>{const now=new Date;if(waitMs!==maxDelay&&!this.options.paused&&now.getTime()>=target){this.options.maxRuns--;if(this.options.catch){(async inst=>{try{await inst.fn(inst,inst.options.context)}catch(_e){if(Object.prototype.toString.call(inst.options.catch)==="[object Function]"||"function"===typeof inst.options.catch||inst.options.catch instanceof Function){inst.options.catch(_e)}}})(this)}else{this.fn(this,this.options.context)}this.previousrun=new CronDate(void 0,this.options.timezone||this.options.utcOffset);this.schedule()}else{this.schedule(undefined,now)}},waitMs);if(this.currentTimeout&&this.options.unref){if(typeof Deno!=="undefined"&&typeof Deno.unrefTimer!=="undefined"){Deno.unrefTimer(this.currentTimeout)}else if(typeof this.currentTimeout.unref!=="undefined"){this.currentTimeout.unref()}}return this};Cron.prototype._next=function(prev){const hasPreviousRun=prev||this.previousrun?true:false;prev=new CronDate(prev,this.options.timezone||this.options.utcOffset);if(this.options.startAt&&prev&&prev.getTime()<this.options.startAt.getTime()){prev=this.options.startAt}const nextRun=this.once||new CronDate(prev,this.options.timezone||this.options.utcOffset).increment(this.pattern,this.options,hasPreviousRun);if(this.once&&this.once.getTime()<=prev.getTime()){return null}else if(nextRun===null||this.options.maxRuns<=0||this.options.kill||this.options.stopAt&&nextRun.getTime()>=this.options.stopAt.getTime()){return null}else{return nextRun}};Cron.Cron=Cron;Cron.scheduledJobs=scheduledJobs;export{Cron,Cron as default,scheduledJobs};
|
|
1
|
+
function minitz(y,m,d,h,i,s,tz,throwOnInvalid){return minitz.fromTZ(minitz.tp(y,m,d,h,i,s,tz),throwOnInvalid)}minitz.fromTZISO=(localTimeStr,tz,throwOnInvalid)=>{return minitz.fromTZ(parseISOLocal(localTimeStr,tz),throwOnInvalid)};minitz.fromTZ=function(tp,throwOnInvalid){const inDate=new Date(Date.UTC(tp.y,tp.m-1,tp.d,tp.h,tp.i,tp.s)),offset=getTimezoneOffset(tp.tz,inDate),dateGuess=new Date(inDate.getTime()-offset),dateOffsGuess=getTimezoneOffset(tp.tz,dateGuess);if(dateOffsGuess-offset===0){return dateGuess}else{const dateGuess2=new Date(inDate.getTime()-dateOffsGuess),dateOffsGuess2=getTimezoneOffset(tp.tz,dateGuess2);if(dateOffsGuess2-dateOffsGuess===0){return dateGuess2}else if(!throwOnInvalid&&dateOffsGuess2-dateOffsGuess>0){return dateGuess2}else if(!throwOnInvalid){return dateGuess}else{throw new Error("Invalid date passed to fromTZ()")}}};minitz.toTZ=function(d,tzStr){const td=new Date(d.toLocaleString("sv-SE",{timeZone:tzStr}));return{y:td.getFullYear(),m:td.getMonth()+1,d:td.getDate(),h:td.getHours(),i:td.getMinutes(),s:td.getSeconds(),tz:tzStr}};minitz.tp=(y,m,d,h,i,s,tz)=>{return{y:y,m:m,d:d,h:h,i:i,s:s,tz:tz}};function getTimezoneOffset(timeZone,date=new Date){const tz=date.toLocaleString("en",{timeZone:timeZone,timeStyle:"long"}).split(" ").slice(-1)[0];const dateString=date.toLocaleString("en-US").replace(/[\u202f]/," ");return Date.parse(`${dateString} GMT`)-Date.parse(`${dateString} ${tz}`)}function parseISOLocal(dtStr,tz){const pd=new Date(Date.parse(dtStr));if(isNaN(pd)){throw new Error("minitz: Invalid ISO8601 passed to parser.")}const stringEnd=dtStr.substring(9);if(dtStr.includes("Z")||stringEnd.includes("-")||stringEnd.includes("+")){return minitz.tp(pd.getUTCFullYear(),pd.getUTCMonth()+1,pd.getUTCDate(),pd.getUTCHours(),pd.getUTCMinutes(),pd.getUTCSeconds(),"Etc/UTC")}else{return minitz.tp(pd.getFullYear(),pd.getMonth()+1,pd.getDate(),pd.getHours(),pd.getMinutes(),pd.getSeconds(),tz)}}minitz.minitz=minitz;function CronOptions(options){if(options===void 0){options={}}delete options.name;options.legacyMode=options.legacyMode===void 0?true:options.legacyMode;options.paused=options.paused===void 0?false:options.paused;options.maxRuns=options.maxRuns===void 0?Infinity:options.maxRuns;options.catch=options.catch===void 0?false:options.catch;options.interval=options.interval===void 0?0:parseInt(options.interval,10);options.utcOffset=options.utcOffset===void 0?void 0:parseInt(options.utcOffset,10);options.unref=options.unref===void 0?false:options.unref;options.kill=false;if(options.startAt){options.startAt=new CronDate(options.startAt,options.timezone)}if(options.stopAt){options.stopAt=new CronDate(options.stopAt,options.timezone)}if(options.interval!==null){if(isNaN(options.interval)){throw new Error("CronOptions: Supplied value for interval is not a number")}else if(options.interval<0){throw new Error("CronOptions: Supplied value for interval can not be negative")}}if(options.utcOffset!==void 0){if(isNaN(options.utcOffset)){throw new Error("CronOptions: Invalid value passed for utcOffset, should be number representing minutes offset from UTC.")}else if(options.utcOffset<-870||options.utcOffset>870){throw new Error("CronOptions: utcOffset out of bounds.")}if(options.utcOffset!==void 0&&options.timezone){throw new Error("CronOptions: Combining 'utcOffset' with 'timezone' is not allowed.")}}if(options.unref!==true&&options.unref!==false){throw new Error("CronOptions: Unref should be either true, false or undefined(false).")}return options}const DaysOfMonth=[31,28,31,30,31,30,31,31,30,31,30,31];const RecursionSteps=[["month","year",0],["day","month",-1],["hour","day",0],["minute","hour",0],["second","minute",0]];function CronDate(d,tz){this.tz=tz;if(d&&d instanceof Date){if(!isNaN(d)){this.fromDate(d)}else{throw new TypeError("CronDate: Invalid date passed to CronDate constructor")}}else if(d===void 0){this.fromDate(new Date)}else if(d&&typeof d==="string"){this.fromString(d)}else if(d instanceof CronDate){this.fromCronDate(d)}else{throw new TypeError("CronDate: Invalid type ("+typeof d+") passed to CronDate constructor")}}CronDate.prototype.fromDate=function(inDate){if(this.tz!==void 0){if(typeof this.tz==="number"){this.ms=inDate.getUTCMilliseconds();this.second=inDate.getUTCSeconds();this.minute=inDate.getUTCMinutes()+this.tz;this.hour=inDate.getUTCHours();this.day=inDate.getUTCDate();this.month=inDate.getUTCMonth();this.year=inDate.getUTCFullYear();this.apply()}else{const d=minitz.toTZ(inDate,this.tz);this.ms=inDate.getMilliseconds();this.second=d.s;this.minute=d.i;this.hour=d.h;this.day=d.d;this.month=d.m-1;this.year=d.y}}else{this.ms=inDate.getMilliseconds();this.second=inDate.getSeconds();this.minute=inDate.getMinutes();this.hour=inDate.getHours();this.day=inDate.getDate();this.month=inDate.getMonth();this.year=inDate.getFullYear()}};CronDate.prototype.fromCronDate=function(d){this.tz=d.tz;this.year=d.year;this.month=d.month;this.day=d.day;this.hour=d.hour;this.minute=d.minute;this.second=d.second;this.ms=d.ms};CronDate.prototype.apply=function(){if(this.month>11||this.day>DaysOfMonth[this.month]||this.hour>59||this.minute>59||this.second>59||this.hour<0||this.minute<0||this.second<0){const d=new Date(Date.UTC(this.year,this.month,this.day,this.hour,this.minute,this.second,this.ms));this.ms=d.getUTCMilliseconds();this.second=d.getUTCSeconds();this.minute=d.getUTCMinutes();this.hour=d.getUTCHours();this.day=d.getUTCDate();this.month=d.getUTCMonth();this.year=d.getUTCFullYear();return true}else{return false}};CronDate.prototype.fromString=function(str){return this.fromDate(minitz.fromTZISO(str,this.tz))};CronDate.prototype.findNext=function(options,target,pattern,offset){const originalTarget=this[target];let lastDayOfMonth;if(pattern.lastDayOfMonth){if(this.month!==1){lastDayOfMonth=DaysOfMonth[this.month]}else{lastDayOfMonth=new Date(Date.UTC(this.year,this.month+1,0,0,0,0,0)).getUTCDate()}}const fDomWeekDay=!pattern.starDOW&&target=="day"?new Date(Date.UTC(this.year,this.month,1,0,0,0,0)).getUTCDay():undefined;for(let i=this[target]+offset;i<pattern[target].length;i++){let match=pattern[target][i];if(target==="day"&&pattern.lastDayOfMonth&&i-offset==lastDayOfMonth){match=true}if(target==="day"&&!pattern.starDOW){const dowMatch=pattern.dow[(fDomWeekDay+(i-offset-1))%7];if(options.legacyMode&&!pattern.starDOM){match=match||dowMatch}else{match=match&&dowMatch}}if(match){this[target]=i-offset;return originalTarget!==this[target]?2:1}}return 3};CronDate.prototype.recurse=function(pattern,options,doing){const res=this.findNext(options,RecursionSteps[doing][0],pattern,RecursionSteps[doing][2]);if(res>1){let resetLevel=doing+1;while(resetLevel<RecursionSteps.length){this[RecursionSteps[resetLevel][0]]=-RecursionSteps[resetLevel][2];resetLevel++}if(res===3){this[RecursionSteps[doing][1]]++;this[RecursionSteps[doing][0]]=-RecursionSteps[doing][2];this.apply();return this.recurse(pattern,options,0)}else if(this.apply()){return this.recurse(pattern,options,doing-1)}}doing+=1;if(doing>=RecursionSteps.length){return this}else if(this.year>=3e3){return null}else{return this.recurse(pattern,options,doing)}};CronDate.prototype.increment=function(pattern,options,hasPreviousRun){if(options.interval>1&&hasPreviousRun){this.second+=options.interval}else{this.second+=1}this.ms=0;this.apply();return this.recurse(pattern,options,0)};CronDate.prototype.getDate=function(internal){if(internal||this.tz===void 0&&this.utcOffset===void 0){return new Date(this.year,this.month,this.day,this.hour,this.minute,this.second,this.ms)}else{if(typeof this.tz==="number"){return new Date(Date.UTC(this.year,this.month,this.day,this.hour,this.minute-this.tz,this.second,this.ms))}else{return minitz(this.year,this.month+1,this.day,this.hour,this.minute,this.second,this.tz)}}};CronDate.prototype.getTime=function(){return this.getDate().getTime()};function CronPattern(pattern,timezone){this.pattern=pattern;this.timezone=timezone;this.second=Array(60).fill(0);this.minute=Array(60).fill(0);this.hour=Array(24).fill(0);this.day=Array(31).fill(0);this.month=Array(12).fill(0);this.dow=Array(8).fill(0);this.lastDayOfMonth=false;this.starDOM=false;this.starDOW=false;this.parse()}CronPattern.prototype.parse=function(){if(!(typeof this.pattern==="string"||this.pattern.constructor===String)){throw new TypeError("CronPattern: Pattern has to be of type string.")}if(this.pattern.indexOf("@")>=0)this.pattern=this.handleNicknames(this.pattern).trim();const parts=this.pattern.replace(/\s+/g," ").split(" ");if(parts.length<5||parts.length>6){throw new TypeError("CronPattern: invalid configuration format ('"+this.pattern+"'), exacly five or six space separated parts required.")}if(parts.length===5){parts.unshift("0")}if(parts[3].indexOf("L")>=0){parts[3]=parts[3].replace("L","");this.lastDayOfMonth=true}if(parts[3]=="*"){this.starDOM=true}if(parts[4].length>=3)parts[4]=this.replaceAlphaMonths(parts[4]);if(parts[5].length>=3)parts[5]=this.replaceAlphaDays(parts[5]);if(parts[5]=="*"){this.starDOW=true}if(this.pattern.indexOf("?")>=0){const initDate=new CronDate(new Date,this.timezone).getDate(true);parts[0]=parts[0].replace("?",initDate.getSeconds());parts[1]=parts[1].replace("?",initDate.getMinutes());parts[2]=parts[2].replace("?",initDate.getHours());if(!this.starDOM)parts[3]=parts[3].replace("?",initDate.getDate());parts[4]=parts[4].replace("?",initDate.getMonth()+1);if(!this.starDOW)parts[5]=parts[5].replace("?",initDate.getDay())}this.throwAtIllegalCharacters(parts);this.partToArray("second",parts[0],0);this.partToArray("minute",parts[1],0);this.partToArray("hour",parts[2],0);this.partToArray("day",parts[3],-1);this.partToArray("month",parts[4],-1);this.partToArray("dow",parts[5],0);if(this.dow[7]){this.dow[0]=1}};CronPattern.prototype.partToArray=function(type,conf,valueIndexOffset){const arr=this[type];if(conf==="*")return arr.fill(1);const split=conf.split(",");if(split.length>1){for(let i=0;i<split.length;i++){this.partToArray(type,split[i],valueIndexOffset)}}else if(conf.indexOf("-")!==-1&&conf.indexOf("/")!==-1){this.handleRangeWithStepping(conf,type,valueIndexOffset)}else if(conf.indexOf("-")!==-1){this.handleRange(conf,type,valueIndexOffset)}else if(conf.indexOf("/")!==-1){this.handleStepping(conf,type,valueIndexOffset)}else if(conf!==""){this.handleNumber(conf,type,valueIndexOffset)}};CronPattern.prototype.throwAtIllegalCharacters=function(parts){const reValidCron=/[^/*0-9,-]+/;for(let i=0;i<parts.length;i++){if(reValidCron.test(parts[i])){throw new TypeError("CronPattern: configuration entry "+i+" ("+parts[i]+") contains illegal characters.")}}};CronPattern.prototype.handleNumber=function(conf,type,valueIndexOffset){const i=parseInt(conf,10)+valueIndexOffset;if(isNaN(i)){throw new TypeError("CronPattern: "+type+" is not a number: '"+conf+"'")}if(i<0||i>=this[type].length){throw new TypeError("CronPattern: "+type+" value out of range: '"+conf+"'")}this[type][i]=1};CronPattern.prototype.handleRangeWithStepping=function(conf,type,valueIndexOffset){const matches=conf.match(/^(\d+)-(\d+)\/(\d+)$/);if(matches===null)throw new TypeError("CronPattern: Syntax error, illegal range with stepping: '"+conf+"'");let[,lower,upper,steps]=matches;lower=parseInt(lower,10)+valueIndexOffset;upper=parseInt(upper,10)+valueIndexOffset;steps=parseInt(steps,10);if(isNaN(lower))throw new TypeError("CronPattern: Syntax error, illegal lower range (NaN)");if(isNaN(upper))throw new TypeError("CronPattern: Syntax error, illegal upper range (NaN)");if(isNaN(steps))throw new TypeError("CronPattern: Syntax error, illegal stepping: (NaN)");if(steps===0)throw new TypeError("CronPattern: Syntax error, illegal stepping: 0");if(steps>this[type].length)throw new TypeError("CronPattern: Syntax error, steps cannot be greater than maximum value of part ("+this[type].length+")");if(lower<0||upper>=this[type].length)throw new TypeError("CronPattern: Value out of range: '"+conf+"'");if(lower>upper)throw new TypeError("CronPattern: From value is larger than to value: '"+conf+"'");for(let i=lower;i<=upper;i+=steps){this[type][i]=1}};CronPattern.prototype.handleRange=function(conf,type,valueIndexOffset){const split=conf.split("-");if(split.length!==2){throw new TypeError("CronPattern: Syntax error, illegal range: '"+conf+"'")}const lower=parseInt(split[0],10)+valueIndexOffset,upper=parseInt(split[1],10)+valueIndexOffset;if(isNaN(lower)){throw new TypeError("CronPattern: Syntax error, illegal lower range (NaN)")}else if(isNaN(upper)){throw new TypeError("CronPattern: Syntax error, illegal upper range (NaN)")}if(lower<0||upper>=this[type].length){throw new TypeError("CronPattern: Value out of range: '"+conf+"'")}if(lower>upper){throw new TypeError("CronPattern: From value is larger than to value: '"+conf+"'")}for(let i=lower;i<=upper;i++){this[type][i]=1}};CronPattern.prototype.handleStepping=function(conf,type){const split=conf.split("/");if(split.length!==2){throw new TypeError("CronPattern: Syntax error, illegal stepping: '"+conf+"'")}let start=0;if(split[0]!=="*"){start=parseInt(split[0],10)}const steps=parseInt(split[1],10);if(isNaN(steps))throw new TypeError("CronPattern: Syntax error, illegal stepping: (NaN)");if(steps===0)throw new TypeError("CronPattern: Syntax error, illegal stepping: 0");if(steps>this[type].length)throw new TypeError("CronPattern: Syntax error, max steps for part is ("+this[type].length+")");for(let i=start;i<this[type].length;i+=steps){this[type][i]=1}};CronPattern.prototype.replaceAlphaDays=function(conf){return conf.replace(/-sun/gi,"-7").replace(/sun/gi,"0").replace(/mon/gi,"1").replace(/tue/gi,"2").replace(/wed/gi,"3").replace(/thu/gi,"4").replace(/fri/gi,"5").replace(/sat/gi,"6")};CronPattern.prototype.replaceAlphaMonths=function(conf){return conf.replace(/jan/gi,"1").replace(/feb/gi,"2").replace(/mar/gi,"3").replace(/apr/gi,"4").replace(/may/gi,"5").replace(/jun/gi,"6").replace(/jul/gi,"7").replace(/aug/gi,"8").replace(/sep/gi,"9").replace(/oct/gi,"10").replace(/nov/gi,"11").replace(/dec/gi,"12")};CronPattern.prototype.handleNicknames=function(pattern){const cleanPattern=pattern.trim().toLowerCase();if(cleanPattern==="@yearly"||cleanPattern==="@annually"){return"0 0 1 1 *"}else if(cleanPattern==="@monthly"){return"0 0 1 * *"}else if(cleanPattern==="@weekly"){return"0 0 * * 0"}else if(cleanPattern==="@daily"){return"0 0 * * *"}else if(cleanPattern==="@hourly"){return"0 * * * *"}else{return pattern}};const maxDelay=Math.pow(2,32-1)-1;const scheduledJobs=[];function Cron(pattern,fnOrOptions1,fnOrOptions2){if(!(this instanceof Cron)){return new Cron(pattern,fnOrOptions1,fnOrOptions2)}let options,func;if(typeof fnOrOptions1==="function"){func=fnOrOptions1}else if(typeof fnOrOptions1==="object"){options=fnOrOptions1}else if(fnOrOptions1!==void 0){throw new Error("Cron: Invalid argument passed for optionsIn. Should be one of function, or object (options).")}if(typeof fnOrOptions2==="function"){func=fnOrOptions2}else if(typeof fnOrOptions2==="object"){options=fnOrOptions2}else if(fnOrOptions2!==void 0){throw new Error("Cron: Invalid argument passed for funcIn. Should be one of function, or object (options).")}this.name=options?options.name:void 0;this.options=CronOptions(options);this.once=void 0;this.pattern=void 0;this.blocking=false;this.previousrun=void 0;this.runstarted=void 0;if(pattern&&(pattern instanceof Date||typeof pattern==="string"&&pattern.indexOf(":")>0)){this.once=new CronDate(pattern,this.options.timezone||this.options.utcOffset)}else{this.pattern=new CronPattern(pattern,this.options.timezone)}if(func!==void 0){this.fn=func;this.schedule()}if(this.name){const existing=scheduledJobs.find(j=>j.name===this.name);if(existing){throw new Error("Cron: Tried to initialize new named job '"+this.name+"', but name already taken.")}else{scheduledJobs.push(this)}}return this}Cron.prototype.next=function(prev){const next=this._next(prev);return next?next.getDate():null};Cron.prototype.enumerate=function(n,previous){if(n>this.options.maxRuns){n=this.options.maxRuns}const enumeration=[];let prev=previous||this.previousrun;while(n--&&(prev=this.next(prev))){enumeration.push(prev)}return enumeration};Cron.prototype.running=function(){const msLeft=this.msToNext(this.previousrun);const running=!this.options.paused&&this.fn!==void 0;return msLeft!==null&&running};Cron.prototype.working=function(){return this.blocking};Cron.prototype.started=function(){return this.runstarted?this.runstarted.getDate():null};Cron.prototype.previous=function(){return this.previousrun?this.previousrun.getDate():null};Cron.prototype.msToNext=function(prev){const next=this._next(prev);prev=new CronDate(prev,this.options.timezone||this.options.utcOffset);if(next){return next.getTime(true)-prev.getTime(true)}else{return null}};Cron.prototype.stop=function(){this.options.kill=true;if(this.currentTimeout){clearTimeout(this.currentTimeout)}};Cron.prototype.pause=function(){return(this.options.paused=true)&&!this.options.kill};Cron.prototype.resume=function(){return!(this.options.paused=false)&&!this.options.kill};Cron.prototype.schedule=function(func,partial){if(func&&this.fn){throw new Error("Cron: It is not allowed to schedule two functions using the same Croner instance.")}else if(func){this.fn=func}let waitMs=this.msToNext(partial?partial:this.previousrun);const target=this.next(partial?partial:this.previousrun);if(waitMs===null)return this;if(waitMs>maxDelay){waitMs=maxDelay}this.currentTimeout=setTimeout(()=>{const now=new Date,shouldRun=waitMs!==maxDelay&&!this.options.paused&&now.getTime()>=target,isBlocked=this.blocking&&this.options.protect;if(shouldRun&&!isBlocked){this.options.maxRuns--;(async inst=>{inst.blocking=true;this.runstarted=new CronDate(void 0,this.options.timezone||this.options.utcOffset);if(this.options.catch){try{await inst.fn(inst,inst.options.context)}catch(_e){if(Object.prototype.toString.call(inst.options.catch)==="[object Function]"||"function"===typeof inst.options.catch||inst.options.catch instanceof Function){inst.options.catch(_e,inst)}}finally{inst.blocking=false}}else{await this.fn(this,this.options.context);inst.blocking=false}})(this);this.previousrun=new CronDate(void 0,this.options.timezone||this.options.utcOffset);this.schedule()}else{if(shouldRun&&isBlocked&&Object.prototype.toString.call(this.options.protect)==="[object Function]"||"function"===typeof this.options.protect||this.options.protect instanceof Function){(async inst=>{inst.options.protect(inst)})(this)}this.schedule(undefined,now)}},waitMs);if(this.currentTimeout&&this.options.unref){if(typeof Deno!=="undefined"&&typeof Deno.unrefTimer!=="undefined"){Deno.unrefTimer(this.currentTimeout)}else if(typeof this.currentTimeout.unref!=="undefined"){this.currentTimeout.unref()}}return this};Cron.prototype._next=function(prev){const hasPreviousRun=prev||this.previousrun?true:false;prev=new CronDate(prev,this.options.timezone||this.options.utcOffset);if(this.options.startAt&&prev&&prev.getTime()<this.options.startAt.getTime()){prev=this.options.startAt}const nextRun=this.once||new CronDate(prev,this.options.timezone||this.options.utcOffset).increment(this.pattern,this.options,hasPreviousRun);if(this.once&&this.once.getTime()<=prev.getTime()){return null}else if(nextRun===null||this.options.maxRuns<=0||this.options.kill||this.options.stopAt&&nextRun.getTime()>=this.options.stopAt.getTime()){return null}else{return nextRun}};Cron.Cron=Cron;Cron.scheduledJobs=scheduledJobs;export{Cron,Cron as default,scheduledJobs};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "croner",
|
|
3
|
-
"version": "5.
|
|
3
|
+
"version": "5.7.0-dev.0",
|
|
4
4
|
"description": "Trigger functions and/or evaluate cron expressions in JavaScript. No dependencies. Most features. All environments.",
|
|
5
5
|
"author": "Hexagon <github.com/hexagon>",
|
|
6
6
|
"homepage": "https://hexagon.github.io/croner",
|
|
@@ -53,7 +53,7 @@
|
|
|
53
53
|
"build:minify": "uglifyjs dist/croner.cjs --source-map -o dist/croner.min.js && uglifyjs dist/croner.cjs --source-map -o dist/croner.min.cjs && uglifyjs dist/croner.mjs --source-map -o dist/croner.min.mjs",
|
|
54
54
|
"build:typings": "tsc",
|
|
55
55
|
"build:cleanup": "(rm dist/croner.mjs || del dist\\croner.mjs) || (rm dist/croner.cjs || del dist\\croner.cjs)",
|
|
56
|
-
"build:docs": "(rm -rf docs/* || rd /S /Q docs) && jsdoc -c .jsdoc.json"
|
|
56
|
+
"build:docs": "((rm -rf dist-docs/* || rd /S /Q dist-docs) && jsdoc -c .jsdoc.json) || jsdoc -c .jsdoc.json"
|
|
57
57
|
},
|
|
58
58
|
"type": "module",
|
|
59
59
|
"main": "./dist/croner.min.cjs",
|
package/types/croner.d.ts
CHANGED
|
@@ -24,6 +24,8 @@ export class Cron {
|
|
|
24
24
|
name: string | undefined;
|
|
25
25
|
/** @type {CronOptions} */
|
|
26
26
|
options: CronOptions;
|
|
27
|
+
/** @type {boolean} */
|
|
28
|
+
blocking: boolean;
|
|
27
29
|
once: CronDate;
|
|
28
30
|
pattern: CronPattern;
|
|
29
31
|
fn: Function;
|
|
@@ -43,14 +45,28 @@ export class Cron {
|
|
|
43
45
|
*/
|
|
44
46
|
enumerate(n: number, previous?: Date | string): Date[];
|
|
45
47
|
/**
|
|
46
|
-
*
|
|
48
|
+
* Indicates wether or not the cron job is active, e.g. awaiting next trigger
|
|
47
49
|
* @public
|
|
48
50
|
*
|
|
49
51
|
* @returns {boolean} - Running or not
|
|
50
52
|
*/
|
|
51
53
|
public running(): boolean;
|
|
52
54
|
/**
|
|
53
|
-
*
|
|
55
|
+
* Indicates wether or not the cron job is working
|
|
56
|
+
* @public
|
|
57
|
+
*
|
|
58
|
+
* @returns {boolean} - Running or not
|
|
59
|
+
*/
|
|
60
|
+
public working(): boolean;
|
|
61
|
+
/**
|
|
62
|
+
* Return current/previous run start time
|
|
63
|
+
* @public
|
|
64
|
+
*
|
|
65
|
+
* @returns {Date | null} - Previous run time
|
|
66
|
+
*/
|
|
67
|
+
public started(): Date | null;
|
|
68
|
+
/**
|
|
69
|
+
* Return previous run end time
|
|
54
70
|
* @public
|
|
55
71
|
*
|
|
56
72
|
* @returns {Date | null} - Previous run time
|
|
@@ -96,6 +112,7 @@ export class Cron {
|
|
|
96
112
|
*/
|
|
97
113
|
public schedule(func: Function, partial?: Date): Cron;
|
|
98
114
|
currentTimeout: number;
|
|
115
|
+
runstarted: CronDate;
|
|
99
116
|
previousrun: CronDate;
|
|
100
117
|
private _next;
|
|
101
118
|
}
|
package/types/options.d.ts
CHANGED
|
@@ -31,6 +31,10 @@ export type CronOptions = {
|
|
|
31
31
|
* - Minimum interval between executions, in seconds
|
|
32
32
|
*/
|
|
33
33
|
interval?: number;
|
|
34
|
+
/**
|
|
35
|
+
* - Skip current run if job is already running
|
|
36
|
+
*/
|
|
37
|
+
protect?: boolean | ProtectCallbackFn;
|
|
34
38
|
/**
|
|
35
39
|
* - When to start running
|
|
36
40
|
*/
|
|
@@ -56,10 +60,16 @@ export type CronOptions = {
|
|
|
56
60
|
*/
|
|
57
61
|
context?: unknown;
|
|
58
62
|
};
|
|
59
|
-
export type CatchCallbackFn = (e: unknown) => any;
|
|
63
|
+
export type CatchCallbackFn = (e: unknown, job: Cron) => any;
|
|
64
|
+
export type ProtectCallbackFn = (job: Cron) => any;
|
|
60
65
|
/**
|
|
61
66
|
* @callback CatchCallbackFn
|
|
62
67
|
* @param {unknown} e
|
|
68
|
+
* @param {Cron} job
|
|
69
|
+
*/
|
|
70
|
+
/**
|
|
71
|
+
* @callback ProtectCallbackFn
|
|
72
|
+
* @param {Cron} job
|
|
63
73
|
*/
|
|
64
74
|
/**
|
|
65
75
|
* @typedef {Object} CronOptions - Cron scheduler options
|
|
@@ -71,6 +81,7 @@ export type CatchCallbackFn = (e: unknown) => any;
|
|
|
71
81
|
* @property {boolean} [unref] - Abort job instantly if nothing else keeps the event loop running.
|
|
72
82
|
* @property {number} [maxRuns] - Maximum nuber of executions
|
|
73
83
|
* @property {number} [interval] - Minimum interval between executions, in seconds
|
|
84
|
+
* @property {boolean | ProtectCallbackFn} [protect] - Skip current run if job is already running
|
|
74
85
|
* @property {string | Date} [startAt] - When to start running
|
|
75
86
|
* @property {string | Date} [stopAt] - When to stop running
|
|
76
87
|
* @property {string} [timezone] - Time zone in Europe/Stockholm format
|
|
@@ -86,3 +97,4 @@ export type CatchCallbackFn = (e: unknown) => any;
|
|
|
86
97
|
* @returns {CronOptions}
|
|
87
98
|
*/
|
|
88
99
|
export function CronOptions(options: CronOptions): CronOptions;
|
|
100
|
+
import { Cron } from "./croner.js";
|