croner 3.0.49 → 4.0.53

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 CHANGED
@@ -3,12 +3,17 @@
3
3
  [![Build status](https://travis-ci.org/Hexagon/croner.svg)](https://travis-ci.org/Hexagon/croner) [![npm version](https://badge.fury.io/js/croner.svg)](https://badge.fury.io/js/croner) [![Codacy Badge](https://app.codacy.com/project/badge/Grade/4978bdbf495941c087ecb32b120f28ff)](https://www.codacy.com/gh/Hexagon/croner/dashboard?utm_source=github.com&utm_medium=referral&utm_content=Hexagon/croner&utm_campaign=Badge_Grade)
4
4
  [![MIT License](https://img.shields.io/badge/license-MIT-blue.svg)](https://github.com/Hexagon/croner/blob/master/LICENSE) [![jsdelivr](https://data.jsdelivr.com/v1/package/npm/croner/badge?style=rounded)](https://www.jsdelivr.com/package/npm/croner)
5
5
 
6
- Pure JavaScript minimal isomorphic cron parser and scheduler. Or simply speaking - setInterval on steroids.
6
+ * Trigger functions in javascript using [Cron](https://en.wikipedia.org/wiki/Cron#CRON_expression) syntax.
7
+ * Pause, resume or stop exection efter a task is scheduled.
8
+ * Find first date of next month, find date of next tuesday, etc.
9
+ * Supports Node.js from 4.0 to current. Both require (commonjs) and import (module).
10
+ * Supports browser use ([UMD](https://github.com/umdjs/umd) (standalone, requirejs etc.), [ES-module](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Modules))
11
+ * *Experimental:* Schedule in other timezone than default.
7
12
 
8
13
  Documented with [JSDoc](https://jsdoc.app/) for intellisense, and include [TypeScript](https://www.typescriptlang.org/) typings.
9
14
 
10
15
  ```html
11
- <script src="https://cdn.jsdelivr.net/npm/croner@3/dist/croner.min.js"></script>
16
+ <script src="https://cdn.jsdelivr.net/npm/croner@4/dist/croner.min.js"></script>
12
17
  ```
13
18
 
14
19
  ```javascript
@@ -16,15 +21,18 @@ Documented with [JSDoc](https://jsdoc.app/) for intellisense, and include [TypeS
16
21
  Cron('* * * * * *', function () {
17
22
  console.log('This will run every second');
18
23
  });
24
+
25
+ // What date is next sunday?
26
+ console.log(Cron('0 0 0 * * 7').next().toLocaleDateString());
19
27
  ```
20
28
 
21
29
  ## Installation
22
30
 
23
31
  ### Manual
24
32
 
25
- * Download latest [zipball](http://github.com/Hexagon/croner/zipball/master/)
26
- * Unpack
27
- * Grab ```croner.min.js``` ([UMD](https://github.com/umdjs/umd)) or ```croner.min.mjs``` ([ES-module](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Modules)) from the [dist/](/dist) folder
33
+ * Download latest [zipball](http://github.com/Hexagon/croner/zipball/master/)
34
+ * Unpack
35
+ * Grab ```croner.min.js``` ([UMD](https://github.com/umdjs/umd)) or ```croner.min.mjs``` ([ES-module](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Modules)) from the [dist/](/dist) folder
28
36
 
29
37
  ### Node.js
30
38
 
@@ -46,14 +54,14 @@ const Cron = require("croner");
46
54
  To use as a [UMD](https://github.com/umdjs/umd)-module (stand alone, [RequireJS](https://requirejs.org/) etc.)
47
55
 
48
56
  ```html
49
- <script src="https://cdn.jsdelivr.net/npm/croner@3/dist/croner.min.js"></script>
57
+ <script src="https://cdn.jsdelivr.net/npm/croner@4/dist/croner.min.js"></script>
50
58
  ```
51
59
 
52
60
  To use as a [ES-module](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Modules)
53
61
 
54
62
  ```html
55
63
  <script type="module">
56
- import Cron from "https://cdn.jsdelivr.net/npm/croner@3/dist/croner.min.mjs";
64
+ import Cron from "https://cdn.jsdelivr.net/npm/croner@4/dist/croner.min.mjs";
57
65
 
58
66
  // ... see usage section ...
59
67
  </script>
@@ -64,7 +72,7 @@ To use as a [ES-module](https://developer.mozilla.org/en-US/docs/Web/JavaScript/
64
72
  <script type="importmap">
65
73
  {
66
74
  "imports": {
67
- "croner": "https://cdn.jsdelivr.net/npm/croner@3/dist/croner.min.mjs"
75
+ "croner": "https://cdn.jsdelivr.net/npm/croner@4/dist/croner.min.mjs"
68
76
  }
69
77
  }
70
78
  </script>
@@ -85,10 +93,20 @@ Cron('* * * * * *', function () {
85
93
  });
86
94
  ```
87
95
 
96
+ ### Find dates
97
+ ```javascript
98
+ // Find next month
99
+ let nextMonth = Cron('0 0 0 1 * *').next(),
100
+ nextSunday = Cron('0 0 0 * * 7').next();
101
+
102
+ console.log("First day of next month: " + nextMonth.toLocaleDateString());
103
+ console.log("Next sunday: " + nextSunday.toLocaleDateString());
104
+ ```
105
+
88
106
  ### Minimalist scheduling with stepping and custom timezone
89
107
  ```javascript
90
108
  // Run a function every fifth second
91
- Cron('*/5 * * * * *', { timezone: 'Europe/Stockholm' } function () {
109
+ Cron('*/5 * * * * *', { timezone: 'Europe/Stockholm' }, function () {
92
110
  console.log('This will run every fifth second');
93
111
  });
94
112
  ```
@@ -142,49 +160,41 @@ scheduler.schedule(function() {
142
160
  ```javascript
143
161
 
144
162
  // Run every minute
145
- var scheduler = Cron('0 * * * * *');
163
+ var scheduler = Cron('0 * * * * *', { maxRuns: 5 });
146
164
 
147
165
  // Schedule with options (all options are optional)
148
- scheduler.schedule({ maxRuns: 5 }, function() {
166
+ scheduler.schedule(function() {
149
167
  console.log('This will run every minute.');
150
168
  });
151
169
  ```
152
- ### Scheduling with job controls controlled by croner
170
+ ### Scheduling with controls
153
171
  ```javascript
154
172
  let scheduler = Cron('* * * * * *')
155
173
 
156
- let job = scheduler.schedule(function () {
174
+ scheduler.schedule(function () {
157
175
  console.log('This will run every second. Pause on second 10. Resume on second 15. And quit on second 20.');
158
176
  console.log('Current second: ', new Date().getSeconds());
159
- console.log('Previous run: ' + scheduler.next());
177
+ console.log('Previous run: ' + scheduler.previous());
160
178
  console.log('Next run: ' + scheduler.next());
161
179
  });
162
180
 
163
- Cron('10 * * * * *', {maxRuns: 1}, () => job.pause());
164
- Cron('15 * * * * *', {maxRuns: 1}, () => job.resume());
165
- Cron('20 * * * * *', {maxRuns: 1}, () => job.stop());
181
+ Cron('10 * * * * *', {maxRuns: 1}, () => scheduler.pause());
182
+ Cron('15 * * * * *', {maxRuns: 1}, () => scheduler.resume());
183
+ Cron('20 * * * * *', {maxRuns: 1}, () => scheduler.stop());
166
184
  ```
167
185
 
168
186
  ## Full API
169
187
  ```javascript
170
188
 
171
- var o = Cron( <string pattern> [, <object options>] [, <function callback> ] );
172
- ```
173
- ```javascript
174
- // If Cron is initialized without a scheduled function, cron itself is returned
175
- // and the following member functions is available.
176
- o.next( [ <date previous> ] );
177
- o.msToNext();
178
- o.previous();
179
-
180
- // If Cron is initialized _with_ a scheduled function, the job is retured instead.
181
- // Otherwise you get a reference to the job when scheduling a new job.
182
- var job = o.schedule( [ { startAt: <date|string>, stopAt: <date|string>, maxRuns: <integer>, timezone: <string> } ,] callback);
189
+ var scheduler = Cron( <string pattern> [, { startAt: <date|string>, stopAt: <date|string>, maxRuns: <integer>, timezone: <string> } ] [, <function job> ] )
183
190
 
184
- // These self-explanatory functions is available to control the job
185
- job.pause();
186
- job.resume();
187
- job.stop();
191
+ scheduler.next( [ <date previous> ] );
192
+ scheduler.msToNext( [ <date previous> ] );
193
+ scheduler.previous();
194
+ scheduler.schedule( <fn job> );
195
+ scheduler.pause();
196
+ scheduler.resume();
197
+ scheduler.stop();
188
198
 
189
199
  ```
190
200
 
@@ -204,4 +214,4 @@ job.stop();
204
214
 
205
215
  ## License
206
216
 
207
- MIT
217
+ MIT
@@ -1 +1 @@
1
- !function(t,e){"object"==typeof exports&&"object"==typeof module?module.exports=e():"function"==typeof define&&define.amd?define([],e):"object"==typeof exports?exports.Cron=e():t.Cron=e()}(this,(function(){return(()=>{"use strict";var t={d:(e,r)=>{for(var s in r)t.o(r,s)&&!t.o(e,s)&&Object.defineProperty(e,s,{enumerable:!0,get:r[s]})},o:(t,e)=>Object.prototype.hasOwnProperty.call(t,e)},e={};t.d(e,{default:()=>i});function r(t,e){if(this.timezone=e,t&&t instanceof Date)this.fromDate(t);else if(void 0===t)this.fromDate(new Date);else if(t&&"string"==typeof t)this.fromString(t);else{if(!(t instanceof r))throw new TypeError("CronDate: Invalid type passed as parameter to CronDate constructor");this.fromCronDate(t)}}function s(t){this.pattern=t,this.seconds=Array(60).fill(0),this.minutes=Array(60).fill(0),this.hours=Array(24).fill(0),this.days=Array(31).fill(0),this.months=Array(12).fill(0),this.daysOfWeek=Array(8).fill(0),this.parse()}r.prototype.fromDate=function(t){let e=t.getTime();this.timezone&&(t=function(t,e){return new Date(t.toLocaleString("en-US",{timeZone:e}))}(t,this.timezone));let r=t.getTime();this.UTCmsOffset=r-e,this.milliseconds=t.getMilliseconds(),this.seconds=t.getSeconds(),this.minutes=t.getMinutes(),this.hours=t.getHours(),this.days=t.getDate(),this.months=t.getMonth(),this.years=t.getFullYear()},r.prototype.fromCronDate=function(t){this.UTCmsOffset=t.UTCmsOffset,this.milliseconds=t.milliseconds,this.seconds=t.seconds,this.minutes=t.minutes,this.hours=t.hours,this.days=t.days,this.months=t.months,this.years=t.years},r.prototype.fromString=function(t){let e=Date.parse(t);if(isNaN(e))throw new TypeError("CronDate: Provided string value for CronDate could not be parsed as date.");this.fromDate(new Date(e))},r.prototype.increment=function(t){this.seconds+=1,this.milliseconds=0;let e=this,r=function(t,r,s,o){for(let n=void 0===o?e[t]+s:0+s;n<r[t].length;n++)if(r[t][n])return e[t]=n-s,!0;return!1},s=[["seconds","minutes",0],["minutes","hours",0],["hours","days",0],["days","months",-1],["months","years",0]],o=0;for(;o<5;){if(!r(s[o][0],t,s[o][2]))for(this[s[o][1]]++;o>=0;)r(s[o][0],t,s[o][2],0),o--;o++}for(;!t.daysOfWeek[this.getDate().getDay()];)this.days+=1;return this},r.prototype.getDate=function(){return new Date(this.years,this.months,this.days,this.hours,this.minutes,this.seconds,this.milliseconds-this.UTCmsOffset)},r.prototype.getTime=function(){return new Date(this.years,this.months,this.days,this.hours,this.minutes,this.seconds,this.milliseconds-this.UTCmsOffset).getTime()},s.prototype.parse=function(){if("string"!=typeof this.pattern&&this.pattern.constructor!==String)throw new TypeError("CronPattern: Pattern has to be of type string.");let t,e,r,s,o,n=this.pattern.trim().replace(/\s+/g," ").split(" "),i=/[^/*0-9,-]+/;if(n.length<5||n.length>6)throw new TypeError("CronPattern: invalid configuration format ('"+this.pattern+"'), exacly five or six space separated parts required.");for(5===n.length&&n.unshift("0"),e=0;e<n.length;e++)if(t=n[e].trim(),i.test(t))throw new TypeError("CronPattern: configuration entry "+(e+1)+" ("+t+") contains illegal characters.");if(r="*"!==n[4],s="*"!==n[5],o="*"!==n[3],s&&(r||o))throw new TypeError("CronPattern: configuration invalid, you can not combine month/date with day of week.");this.partToArray("seconds",n[0],0),this.partToArray("minutes",n[1],0),this.partToArray("hours",n[2],0),this.partToArray("days",n[3],-1),this.partToArray("months",n[4],-1),this.partToArray("daysOfWeek",n[5],0),this.daysOfWeek[7]&&(this.daysOfWeek[0]=1)},s.prototype.partToArray=function(t,e,r){let s,o,n,i,a,h=this[t];if("*"!==e)if(o=e.split(","),o.length>1)for(s=0;s<o.length;s++)this.partToArray(t,o[s],r);else if(-1!==e.indexOf("-")){if(o=e.split("-"),2!==o.length)throw new TypeError("CronPattern: Syntax error, illegal range: '"+e+"'");if(n=parseInt(o[0],10)+r,i=parseInt(o[1],10)+r,isNaN(n))throw new TypeError("CronPattern: Syntax error, illegal lower range (NaN)");if(isNaN(i))throw new TypeError("CronPattern: Syntax error, illegal upper range (NaN)");if(n<0||i>=h.length)throw new TypeError("CronPattern: Value out of range: '"+e+"'");if(n>i)throw new TypeError("CronPattern: From value is larger than to value: '"+e+"'");for(s=n;s<=i;s++)h[s+r]=1}else if(-1!==e.indexOf("/")){if(o=e.split("/"),2!==o.length)throw new TypeError("CronPattern: Syntax error, illegal stepping: '"+e+"'");if("*"!==o[0])throw new TypeError("CronPattern: Syntax error, left part of / needs to be * : '"+e+"'");if(a=parseInt(o[1],10),isNaN(a))throw new TypeError("CronPattern: Syntax error, illegal stepping: (NaN)");if(0===a)throw new TypeError("CronPattern: Syntax error, illegal stepping: 0");if(a>h.length)throw new TypeError("CronPattern: Syntax error, steps cannot be greater than maximum value of part ("+h.length+")");for(s=0;s<h.length;s+=a)h[s+r]=1}else{if(s=parseInt(e,10)+r,s<0||s>=h.length)throw new TypeError("CronPattern: "+t+" value out of range: '"+e+"'");h[s]=1}else for(s=0;s<h.length;s++)h[s]=1};const o=Math.pow(2,31)-1;function n(t,e,r){let o=this;return this instanceof n?(o.pattern=new s(t),o.schedulerDefaults={maxRuns:1/0,kill:!1},"function"==typeof e&&(r=e,e={}),o.opts=o.validateOpts(e||{}),void 0===r?o:this.schedule(e,r)):new n(t,e,r)}n.prototype.next=function(t){let e=this._next(t);return e?e.getDate():null},n.prototype.previous=function(){return this.opts.previous?this.opts.previous.getDate():null},n.prototype._next=function(t){t=new r(t,this.opts.timezone),this.opts.startAt&&t&&t.getTime()<this.opts.startAt.getTime()&&(t=new r(this.opts.startAt,this.opts.timezone));let e=new r(t,this.opts.timezone).increment(this.pattern);return this.opts.maxRuns<=0||this.opts.kill||this.opts.stopAt&&e.getTime()>=this.opts.stopAt.getTime()?null:e},n.prototype.validateOpts=function(t){return t.startAt&&(t.startAt=new r(t.startAt,t.timezone)),t.stopAt&&(t.stopAt=new r(t.stopAt,t.timezone)),t},n.prototype.msToNext=function(t){t=t||new r(void 0,this.opts.timezone);let e=this._next(t);return e?e.getTime()-t.getTime():null},n.prototype.schedule=function(t,e){let r=this;return e||(e=t,t=this.opts),t.paused=void 0!==t.paused&&t.paused,t.kill=t.kill||this.schedulerDefaults.kill,t.maxRuns||0===t.maxRuns||(t.maxRuns=this.schedulerDefaults.maxRuns),this.opts=this.validateOpts(t||{}),this._schedule(e),{stop:function(){r.opts.kill=!0,r.opts.currentTimeout&&clearTimeout(r.opts.currentTimeout)},pause:function(){return(r.opts.paused=!0)&&!r.opts.kill},resume:function(){return!(r.opts.paused=!1)&&!r.opts.kill}}},n.prototype._schedule=function(t){let e,s=this,n=s.maxDelay||o;e=this.msToNext(s.opts.previous),null!==e&&(e>n&&(e=n),s.opts.currentTimeout=setTimeout((function(){e!==n&&(s.opts.paused||(s.opts.maxRuns--,t()),s.opts.previous=new r(void 0,s.opts.timezone)),s._schedule(t)}),e))};const i=n;return e.default})()}));
1
+ !function(t,e){"object"==typeof exports&&"object"==typeof module?module.exports=e():"function"==typeof define&&define.amd?define([],e):"object"==typeof exports?exports.Cron=e():t.Cron=e()}(this,(function(){return(()=>{"use strict";var t={d:(e,r)=>{for(var o in r)t.o(r,o)&&!t.o(e,o)&&Object.defineProperty(e,o,{enumerable:!0,get:r[o]})},o:(t,e)=>Object.prototype.hasOwnProperty.call(t,e)},e={};t.d(e,{default:()=>i});function r(t,e){if(this.timezone=e,t&&t instanceof Date)this.fromDate(t);else if(void 0===t)this.fromDate(new Date);else if(t&&"string"==typeof t)this.fromString(t);else{if(!(t instanceof r))throw new TypeError("CronDate: Invalid type ("+typeof t+") passed as parameter to CronDate constructor");this.fromCronDate(t)}}function o(t){this.pattern=t,this.seconds=Array(60).fill(0),this.minutes=Array(60).fill(0),this.hours=Array(24).fill(0),this.days=Array(31).fill(0),this.months=Array(12).fill(0),this.daysOfWeek=Array(8).fill(0),this.parse()}r.prototype.fromDate=function(t){let e=t.getTime();this.timezone&&(t=function(t,e){return new Date(t.toLocaleString("en-US",{timeZone:e}))}(t,this.timezone));let r=t.getTime();this.UTCmsOffset=r-e,this.milliseconds=t.getMilliseconds(),this.seconds=t.getSeconds(),this.minutes=t.getMinutes(),this.hours=t.getHours(),this.days=t.getDate(),this.months=t.getMonth(),this.years=t.getFullYear()},r.prototype.fromCronDate=function(t){this.UTCmsOffset=t.UTCmsOffset,this.timezone=t.timezone;let e=new Date(t.years,t.months,t.days,t.hours,t.minutes,t.seconds,t.milliseconds);this.milliseconds=e.getMilliseconds(),this.seconds=e.getSeconds(),this.minutes=e.getMinutes(),this.hours=e.getHours(),this.days=e.getDate(),this.months=e.getMonth(),this.years=e.getFullYear()},r.prototype.fromString=function(t){let e=Date.parse(t);if(isNaN(e))throw new TypeError("CronDate: Provided string value for CronDate could not be parsed as date.");this.fromDate(new Date(e))},r.prototype.increment=function(t,e){e||(this.seconds+=1);let o=this.getTime();this.milliseconds=0;let n=this,s=function(t,e,r,o){for(let s=void 0===o?n[t]+r:0+r;s<e[t].length;s++)if(e[t][s])return n[t]=s-r,!0;return!1},i=function(){for(;h>=0;)s(a[h][0],t,a[h][2],0),h--},a=[["seconds","minutes",0],["minutes","hours",0],["hours","days",0],["days","months",-1],["months","years",0]],h=0;for(;h<5;)s(a[h][0],t,a[h][2])||(this[a[h][1]]++,i()),h++;for(;!t.daysOfWeek[this.getDate().getDay()];)this.days+=1,h=2,i();return o!=n.getTime()?(n=new r(n),this.years>=4e3?null:n.increment(t,!0)):this},r.prototype.getDate=function(){return new Date(this.years,this.months,this.days,this.hours,this.minutes,this.seconds,this.milliseconds-this.UTCmsOffset)},r.prototype.getTime=function(){return new Date(this.years,this.months,this.days,this.hours,this.minutes,this.seconds,this.milliseconds-this.UTCmsOffset).getTime()},o.prototype.parse=function(){if("string"!=typeof this.pattern&&this.pattern.constructor!==String)throw new TypeError("CronPattern: Pattern has to be of type string.");let t,e,r=this.pattern.trim().replace(/\s+/g," ").split(" "),o=/[^/*0-9,-]+/;if(r.length<5||r.length>6)throw new TypeError("CronPattern: invalid configuration format ('"+this.pattern+"'), exacly five or six space separated parts required.");for(5===r.length&&r.unshift("0"),e=0;e<r.length;e++)if(t=r[e].trim(),o.test(t))throw new TypeError("CronPattern: configuration entry "+(e+1)+" ("+t+") contains illegal characters.");this.partToArray("seconds",r[0],0),this.partToArray("minutes",r[1],0),this.partToArray("hours",r[2],0),this.partToArray("days",r[3],-1),this.partToArray("months",r[4],-1),this.partToArray("daysOfWeek",r[5],0),this.daysOfWeek[7]&&(this.daysOfWeek[0]=1)},o.prototype.partToArray=function(t,e,r){let o,n,s,i,a,h=this[t];if("*"!==e)if(n=e.split(","),n.length>1)for(o=0;o<n.length;o++)this.partToArray(t,n[o],r);else if(-1!==e.indexOf("-")){if(n=e.split("-"),2!==n.length)throw new TypeError("CronPattern: Syntax error, illegal range: '"+e+"'");if(s=parseInt(n[0],10)+r,i=parseInt(n[1],10)+r,isNaN(s))throw new TypeError("CronPattern: Syntax error, illegal lower range (NaN)");if(isNaN(i))throw new TypeError("CronPattern: Syntax error, illegal upper range (NaN)");if(s<0||i>=h.length)throw new TypeError("CronPattern: Value out of range: '"+e+"'");if(s>i)throw new TypeError("CronPattern: From value is larger than to value: '"+e+"'");for(o=s;o<=i;o++)h[o+r]=1}else if(-1!==e.indexOf("/")){if(n=e.split("/"),2!==n.length)throw new TypeError("CronPattern: Syntax error, illegal stepping: '"+e+"'");if("*"!==n[0])throw new TypeError("CronPattern: Syntax error, left part of / needs to be * : '"+e+"'");if(a=parseInt(n[1],10),isNaN(a))throw new TypeError("CronPattern: Syntax error, illegal stepping: (NaN)");if(0===a)throw new TypeError("CronPattern: Syntax error, illegal stepping: 0");if(a>h.length)throw new TypeError("CronPattern: Syntax error, steps cannot be greater than maximum value of part ("+h.length+")");for(o=0;o<h.length;o+=a)h[o+r]=1}else{if(o=parseInt(e,10)+r,o<0||o>=h.length)throw new TypeError("CronPattern: "+t+" value out of range: '"+e+"'");h[o]=1}else for(o=0;o<h.length;o++)h[o]=1};const n=Math.pow(2,31)-1;function s(t,e,r){return this instanceof s?(this.pattern=new o(t),"function"==typeof e&&(r=e,e=void 0),this.options=this.processOptions(e),void 0!==r&&this.schedule(r),this):new s(t,e,r)}s.prototype.processOptions=function(t){return void 0===t&&(t={}),t.paused=void 0!==t.paused&&t.paused,t.maxRuns=void 0===t.maxRuns?1/0:t.maxRuns,t.kill=!1,t.startAt&&(t.startAt=new r(t.startAt,t.timezone)),t.stopAt&&(t.stopAt=new r(t.stopAt,t.timezone)),t},s.prototype.next=function(t){let e=this._next(t);return e?e.getDate():null},s.prototype.previous=function(){return this.previousrun?this.previousrun.getDate():null},s.prototype._next=function(t){t=new r(t,this.options.timezone),this.options.startAt&&t&&t.getTime()<this.options.startAt.getTime()&&(t=new r(this.options.startAt,this.options.timezone));let e=new r(t,this.options.timezone).increment(this.pattern);return null===e||this.options.maxRuns<=0||this.options.kill||this.options.stopAt&&e.getTime()>=this.options.stopAt.getTime()?null:e},s.prototype.msToNext=function(t){t=t||new r(void 0,this.options.timezone);let e=this._next(t);return e?e.getTime()-t.getTime():null},s.prototype.stop=function(){this.options.kill=!0,this.currentTimeout&&clearTimeout(this.currentTimeout)},s.prototype.pause=function(){return(this.options.paused=!0)&&!this.options.kill},s.prototype.resume=function(){return!(this.options.paused=!1)&&!this.options.kill},s.prototype.schedule=function(t){let e=this,o=this.msToNext(e.previousrun),s=e.maxDelay||n;return o>s&&(o=s),null!==o&&(e.currentTimeout=setTimeout((function(){o!==s&&(e.options.paused||(e.options.maxRuns--,t()),e.previousrun=new r(void 0,e.options.timezone)),e.schedule(t)}),o)),this};const i=s;return e.default})()}));
@@ -1 +1 @@
1
- var t={d:(e,r)=>{for(var s in r)t.o(r,s)&&!t.o(e,s)&&Object.defineProperty(e,s,{enumerable:!0,get:r[s]})},o:(t,e)=>Object.prototype.hasOwnProperty.call(t,e)},e={};t.d(e,{P:()=>n,Z:()=>i});function r(t,e){if(this.timezone=e,t&&t instanceof Date)this.fromDate(t);else if(void 0===t)this.fromDate(new Date);else if(t&&"string"==typeof t)this.fromString(t);else{if(!(t instanceof r))throw new TypeError("CronDate: Invalid type passed as parameter to CronDate constructor");this.fromCronDate(t)}}function s(t){this.pattern=t,this.seconds=Array(60).fill(0),this.minutes=Array(60).fill(0),this.hours=Array(24).fill(0),this.days=Array(31).fill(0),this.months=Array(12).fill(0),this.daysOfWeek=Array(8).fill(0),this.parse()}r.prototype.fromDate=function(t){let e=t.getTime();this.timezone&&(t=function(t,e){return new Date(t.toLocaleString("en-US",{timeZone:e}))}(t,this.timezone));let r=t.getTime();this.UTCmsOffset=r-e,this.milliseconds=t.getMilliseconds(),this.seconds=t.getSeconds(),this.minutes=t.getMinutes(),this.hours=t.getHours(),this.days=t.getDate(),this.months=t.getMonth(),this.years=t.getFullYear()},r.prototype.fromCronDate=function(t){this.UTCmsOffset=t.UTCmsOffset,this.milliseconds=t.milliseconds,this.seconds=t.seconds,this.minutes=t.minutes,this.hours=t.hours,this.days=t.days,this.months=t.months,this.years=t.years},r.prototype.fromString=function(t){let e=Date.parse(t);if(isNaN(e))throw new TypeError("CronDate: Provided string value for CronDate could not be parsed as date.");this.fromDate(new Date(e))},r.prototype.increment=function(t){this.seconds+=1,this.milliseconds=0;let e=this,r=function(t,r,s,o){for(let n=void 0===o?e[t]+s:0+s;n<r[t].length;n++)if(r[t][n])return e[t]=n-s,!0;return!1},s=[["seconds","minutes",0],["minutes","hours",0],["hours","days",0],["days","months",-1],["months","years",0]],o=0;for(;o<5;){if(!r(s[o][0],t,s[o][2]))for(this[s[o][1]]++;o>=0;)r(s[o][0],t,s[o][2],0),o--;o++}for(;!t.daysOfWeek[this.getDate().getDay()];)this.days+=1;return this},r.prototype.getDate=function(){return new Date(this.years,this.months,this.days,this.hours,this.minutes,this.seconds,this.milliseconds-this.UTCmsOffset)},r.prototype.getTime=function(){return new Date(this.years,this.months,this.days,this.hours,this.minutes,this.seconds,this.milliseconds-this.UTCmsOffset).getTime()},s.prototype.parse=function(){if("string"!=typeof this.pattern&&this.pattern.constructor!==String)throw new TypeError("CronPattern: Pattern has to be of type string.");let t,e,r,s,o,n=this.pattern.trim().replace(/\s+/g," ").split(" "),i=/[^/*0-9,-]+/;if(n.length<5||n.length>6)throw new TypeError("CronPattern: invalid configuration format ('"+this.pattern+"'), exacly five or six space separated parts required.");for(5===n.length&&n.unshift("0"),e=0;e<n.length;e++)if(t=n[e].trim(),i.test(t))throw new TypeError("CronPattern: configuration entry "+(e+1)+" ("+t+") contains illegal characters.");if(r="*"!==n[4],s="*"!==n[5],o="*"!==n[3],s&&(r||o))throw new TypeError("CronPattern: configuration invalid, you can not combine month/date with day of week.");this.partToArray("seconds",n[0],0),this.partToArray("minutes",n[1],0),this.partToArray("hours",n[2],0),this.partToArray("days",n[3],-1),this.partToArray("months",n[4],-1),this.partToArray("daysOfWeek",n[5],0),this.daysOfWeek[7]&&(this.daysOfWeek[0]=1)},s.prototype.partToArray=function(t,e,r){let s,o,n,i,a,h=this[t];if("*"!==e)if(o=e.split(","),o.length>1)for(s=0;s<o.length;s++)this.partToArray(t,o[s],r);else if(-1!==e.indexOf("-")){if(o=e.split("-"),2!==o.length)throw new TypeError("CronPattern: Syntax error, illegal range: '"+e+"'");if(n=parseInt(o[0],10)+r,i=parseInt(o[1],10)+r,isNaN(n))throw new TypeError("CronPattern: Syntax error, illegal lower range (NaN)");if(isNaN(i))throw new TypeError("CronPattern: Syntax error, illegal upper range (NaN)");if(n<0||i>=h.length)throw new TypeError("CronPattern: Value out of range: '"+e+"'");if(n>i)throw new TypeError("CronPattern: From value is larger than to value: '"+e+"'");for(s=n;s<=i;s++)h[s+r]=1}else if(-1!==e.indexOf("/")){if(o=e.split("/"),2!==o.length)throw new TypeError("CronPattern: Syntax error, illegal stepping: '"+e+"'");if("*"!==o[0])throw new TypeError("CronPattern: Syntax error, left part of / needs to be * : '"+e+"'");if(a=parseInt(o[1],10),isNaN(a))throw new TypeError("CronPattern: Syntax error, illegal stepping: (NaN)");if(0===a)throw new TypeError("CronPattern: Syntax error, illegal stepping: 0");if(a>h.length)throw new TypeError("CronPattern: Syntax error, steps cannot be greater than maximum value of part ("+h.length+")");for(s=0;s<h.length;s+=a)h[s+r]=1}else{if(s=parseInt(e,10)+r,s<0||s>=h.length)throw new TypeError("CronPattern: "+t+" value out of range: '"+e+"'");h[s]=1}else for(s=0;s<h.length;s++)h[s]=1};const o=Math.pow(2,31)-1;function n(t,e,r){let o=this;return this instanceof n?(o.pattern=new s(t),o.schedulerDefaults={maxRuns:1/0,kill:!1},"function"==typeof e&&(r=e,e={}),o.opts=o.validateOpts(e||{}),void 0===r?o:this.schedule(e,r)):new n(t,e,r)}n.prototype.next=function(t){let e=this._next(t);return e?e.getDate():null},n.prototype.previous=function(){return this.opts.previous?this.opts.previous.getDate():null},n.prototype._next=function(t){t=new r(t,this.opts.timezone),this.opts.startAt&&t&&t.getTime()<this.opts.startAt.getTime()&&(t=new r(this.opts.startAt,this.opts.timezone));let e=new r(t,this.opts.timezone).increment(this.pattern);return this.opts.maxRuns<=0||this.opts.kill||this.opts.stopAt&&e.getTime()>=this.opts.stopAt.getTime()?null:e},n.prototype.validateOpts=function(t){return t.startAt&&(t.startAt=new r(t.startAt,t.timezone)),t.stopAt&&(t.stopAt=new r(t.stopAt,t.timezone)),t},n.prototype.msToNext=function(t){t=t||new r(void 0,this.opts.timezone);let e=this._next(t);return e?e.getTime()-t.getTime():null},n.prototype.schedule=function(t,e){let r=this;return e||(e=t,t=this.opts),t.paused=void 0!==t.paused&&t.paused,t.kill=t.kill||this.schedulerDefaults.kill,t.maxRuns||0===t.maxRuns||(t.maxRuns=this.schedulerDefaults.maxRuns),this.opts=this.validateOpts(t||{}),this._schedule(e),{stop:function(){r.opts.kill=!0,r.opts.currentTimeout&&clearTimeout(r.opts.currentTimeout)},pause:function(){return(r.opts.paused=!0)&&!r.opts.kill},resume:function(){return!(r.opts.paused=!1)&&!r.opts.kill}}},n.prototype._schedule=function(t){let e,s=this,n=s.maxDelay||o;e=this.msToNext(s.opts.previous),null!==e&&(e>n&&(e=n),s.opts.currentTimeout=setTimeout((function(){e!==n&&(s.opts.paused||(s.opts.maxRuns--,t()),s.opts.previous=new r(void 0,s.opts.timezone)),s._schedule(t)}),e))};const i=n;var a=e.P,h=e.Z;export{a as Cron,h as default};
1
+ var t={d:(e,r)=>{for(var s in r)t.o(r,s)&&!t.o(e,s)&&Object.defineProperty(e,s,{enumerable:!0,get:r[s]})},o:(t,e)=>Object.prototype.hasOwnProperty.call(t,e)},e={};t.d(e,{P:()=>o,Z:()=>i});function r(t,e){if(this.timezone=e,t&&t instanceof Date)this.fromDate(t);else if(void 0===t)this.fromDate(new Date);else if(t&&"string"==typeof t)this.fromString(t);else{if(!(t instanceof r))throw new TypeError("CronDate: Invalid type ("+typeof t+") passed as parameter to CronDate constructor");this.fromCronDate(t)}}function s(t){this.pattern=t,this.seconds=Array(60).fill(0),this.minutes=Array(60).fill(0),this.hours=Array(24).fill(0),this.days=Array(31).fill(0),this.months=Array(12).fill(0),this.daysOfWeek=Array(8).fill(0),this.parse()}r.prototype.fromDate=function(t){let e=t.getTime();this.timezone&&(t=function(t,e){return new Date(t.toLocaleString("en-US",{timeZone:e}))}(t,this.timezone));let r=t.getTime();this.UTCmsOffset=r-e,this.milliseconds=t.getMilliseconds(),this.seconds=t.getSeconds(),this.minutes=t.getMinutes(),this.hours=t.getHours(),this.days=t.getDate(),this.months=t.getMonth(),this.years=t.getFullYear()},r.prototype.fromCronDate=function(t){this.UTCmsOffset=t.UTCmsOffset,this.timezone=t.timezone;let e=new Date(t.years,t.months,t.days,t.hours,t.minutes,t.seconds,t.milliseconds);this.milliseconds=e.getMilliseconds(),this.seconds=e.getSeconds(),this.minutes=e.getMinutes(),this.hours=e.getHours(),this.days=e.getDate(),this.months=e.getMonth(),this.years=e.getFullYear()},r.prototype.fromString=function(t){let e=Date.parse(t);if(isNaN(e))throw new TypeError("CronDate: Provided string value for CronDate could not be parsed as date.");this.fromDate(new Date(e))},r.prototype.increment=function(t,e){e||(this.seconds+=1);let s=this.getTime();this.milliseconds=0;let n=this,o=function(t,e,r,s){for(let o=void 0===s?n[t]+r:0+r;o<e[t].length;o++)if(e[t][o])return n[t]=o-r,!0;return!1},i=function(){for(;h>=0;)o(a[h][0],t,a[h][2],0),h--},a=[["seconds","minutes",0],["minutes","hours",0],["hours","days",0],["days","months",-1],["months","years",0]],h=0;for(;h<5;)o(a[h][0],t,a[h][2])||(this[a[h][1]]++,i()),h++;for(;!t.daysOfWeek[this.getDate().getDay()];)this.days+=1,h=2,i();return s!=n.getTime()?(n=new r(n),this.years>=4e3?null:n.increment(t,!0)):this},r.prototype.getDate=function(){return new Date(this.years,this.months,this.days,this.hours,this.minutes,this.seconds,this.milliseconds-this.UTCmsOffset)},r.prototype.getTime=function(){return new Date(this.years,this.months,this.days,this.hours,this.minutes,this.seconds,this.milliseconds-this.UTCmsOffset).getTime()},s.prototype.parse=function(){if("string"!=typeof this.pattern&&this.pattern.constructor!==String)throw new TypeError("CronPattern: Pattern has to be of type string.");let t,e,r=this.pattern.trim().replace(/\s+/g," ").split(" "),s=/[^/*0-9,-]+/;if(r.length<5||r.length>6)throw new TypeError("CronPattern: invalid configuration format ('"+this.pattern+"'), exacly five or six space separated parts required.");for(5===r.length&&r.unshift("0"),e=0;e<r.length;e++)if(t=r[e].trim(),s.test(t))throw new TypeError("CronPattern: configuration entry "+(e+1)+" ("+t+") contains illegal characters.");this.partToArray("seconds",r[0],0),this.partToArray("minutes",r[1],0),this.partToArray("hours",r[2],0),this.partToArray("days",r[3],-1),this.partToArray("months",r[4],-1),this.partToArray("daysOfWeek",r[5],0),this.daysOfWeek[7]&&(this.daysOfWeek[0]=1)},s.prototype.partToArray=function(t,e,r){let s,n,o,i,a,h=this[t];if("*"!==e)if(n=e.split(","),n.length>1)for(s=0;s<n.length;s++)this.partToArray(t,n[s],r);else if(-1!==e.indexOf("-")){if(n=e.split("-"),2!==n.length)throw new TypeError("CronPattern: Syntax error, illegal range: '"+e+"'");if(o=parseInt(n[0],10)+r,i=parseInt(n[1],10)+r,isNaN(o))throw new TypeError("CronPattern: Syntax error, illegal lower range (NaN)");if(isNaN(i))throw new TypeError("CronPattern: Syntax error, illegal upper range (NaN)");if(o<0||i>=h.length)throw new TypeError("CronPattern: Value out of range: '"+e+"'");if(o>i)throw new TypeError("CronPattern: From value is larger than to value: '"+e+"'");for(s=o;s<=i;s++)h[s+r]=1}else if(-1!==e.indexOf("/")){if(n=e.split("/"),2!==n.length)throw new TypeError("CronPattern: Syntax error, illegal stepping: '"+e+"'");if("*"!==n[0])throw new TypeError("CronPattern: Syntax error, left part of / needs to be * : '"+e+"'");if(a=parseInt(n[1],10),isNaN(a))throw new TypeError("CronPattern: Syntax error, illegal stepping: (NaN)");if(0===a)throw new TypeError("CronPattern: Syntax error, illegal stepping: 0");if(a>h.length)throw new TypeError("CronPattern: Syntax error, steps cannot be greater than maximum value of part ("+h.length+")");for(s=0;s<h.length;s+=a)h[s+r]=1}else{if(s=parseInt(e,10)+r,s<0||s>=h.length)throw new TypeError("CronPattern: "+t+" value out of range: '"+e+"'");h[s]=1}else for(s=0;s<h.length;s++)h[s]=1};const n=Math.pow(2,31)-1;function o(t,e,r){return this instanceof o?(this.pattern=new s(t),"function"==typeof e&&(r=e,e=void 0),this.options=this.processOptions(e),void 0!==r&&this.schedule(r),this):new o(t,e,r)}o.prototype.processOptions=function(t){return void 0===t&&(t={}),t.paused=void 0!==t.paused&&t.paused,t.maxRuns=void 0===t.maxRuns?1/0:t.maxRuns,t.kill=!1,t.startAt&&(t.startAt=new r(t.startAt,t.timezone)),t.stopAt&&(t.stopAt=new r(t.stopAt,t.timezone)),t},o.prototype.next=function(t){let e=this._next(t);return e?e.getDate():null},o.prototype.previous=function(){return this.previousrun?this.previousrun.getDate():null},o.prototype._next=function(t){t=new r(t,this.options.timezone),this.options.startAt&&t&&t.getTime()<this.options.startAt.getTime()&&(t=new r(this.options.startAt,this.options.timezone));let e=new r(t,this.options.timezone).increment(this.pattern);return null===e||this.options.maxRuns<=0||this.options.kill||this.options.stopAt&&e.getTime()>=this.options.stopAt.getTime()?null:e},o.prototype.msToNext=function(t){t=t||new r(void 0,this.options.timezone);let e=this._next(t);return e?e.getTime()-t.getTime():null},o.prototype.stop=function(){this.options.kill=!0,this.currentTimeout&&clearTimeout(this.currentTimeout)},o.prototype.pause=function(){return(this.options.paused=!0)&&!this.options.kill},o.prototype.resume=function(){return!(this.options.paused=!1)&&!this.options.kill},o.prototype.schedule=function(t){let e=this,s=this.msToNext(e.previousrun),o=e.maxDelay||n;return s>o&&(s=o),null!==s&&(e.currentTimeout=setTimeout((function(){s!==o&&(e.options.paused||(e.options.maxRuns--,t()),e.previousrun=new r(void 0,e.options.timezone)),e.schedule(t)}),s)),this};const i=o;var a=e.P,h=e.Z;export{a as Cron,h as default};
@@ -1 +1 @@
1
- !function(t,e){"object"==typeof exports&&"object"==typeof module?module.exports=e():"function"==typeof define&&define.amd?define([],e):"object"==typeof exports?exports.Cron=e():t.Cron=e()}(this,(function(){return(()=>{"use strict";var t={d:(e,r)=>{for(var s in r)t.o(r,s)&&!t.o(e,s)&&Object.defineProperty(e,s,{enumerable:!0,get:r[s]})},o:(t,e)=>Object.prototype.hasOwnProperty.call(t,e)},e={};t.d(e,{default:()=>i});function r(t,e){if(this.timezone=e,t&&t instanceof Date)this.fromDate(t);else if(void 0===t)this.fromDate(new Date);else if(t&&"string"==typeof t)this.fromString(t);else{if(!(t instanceof r))throw new TypeError("CronDate: Invalid type passed as parameter to CronDate constructor");this.fromCronDate(t)}}function s(t){this.pattern=t,this.seconds=Array(60).fill(0),this.minutes=Array(60).fill(0),this.hours=Array(24).fill(0),this.days=Array(31).fill(0),this.months=Array(12).fill(0),this.daysOfWeek=Array(8).fill(0),this.parse()}r.prototype.fromDate=function(t){let e=t.getTime();this.timezone&&(t=function(t,e){return new Date(t.toLocaleString("en-US",{timeZone:e}))}(t,this.timezone));let r=t.getTime();this.UTCmsOffset=r-e,this.milliseconds=t.getMilliseconds(),this.seconds=t.getSeconds(),this.minutes=t.getMinutes(),this.hours=t.getHours(),this.days=t.getDate(),this.months=t.getMonth(),this.years=t.getFullYear()},r.prototype.fromCronDate=function(t){this.UTCmsOffset=t.UTCmsOffset,this.milliseconds=t.milliseconds,this.seconds=t.seconds,this.minutes=t.minutes,this.hours=t.hours,this.days=t.days,this.months=t.months,this.years=t.years},r.prototype.fromString=function(t){let e=Date.parse(t);if(isNaN(e))throw new TypeError("CronDate: Provided string value for CronDate could not be parsed as date.");this.fromDate(new Date(e))},r.prototype.increment=function(t){this.seconds+=1,this.milliseconds=0;let e=this,r=function(t,r,s,o){for(let n=void 0===o?e[t]+s:0+s;n<r[t].length;n++)if(r[t][n])return e[t]=n-s,!0;return!1},s=[["seconds","minutes",0],["minutes","hours",0],["hours","days",0],["days","months",-1],["months","years",0]],o=0;for(;o<5;){if(!r(s[o][0],t,s[o][2]))for(this[s[o][1]]++;o>=0;)r(s[o][0],t,s[o][2],0),o--;o++}for(;!t.daysOfWeek[this.getDate().getDay()];)this.days+=1;return this},r.prototype.getDate=function(){return new Date(this.years,this.months,this.days,this.hours,this.minutes,this.seconds,this.milliseconds-this.UTCmsOffset)},r.prototype.getTime=function(){return new Date(this.years,this.months,this.days,this.hours,this.minutes,this.seconds,this.milliseconds-this.UTCmsOffset).getTime()},s.prototype.parse=function(){if("string"!=typeof this.pattern&&this.pattern.constructor!==String)throw new TypeError("CronPattern: Pattern has to be of type string.");let t,e,r,s,o,n=this.pattern.trim().replace(/\s+/g," ").split(" "),i=/[^/*0-9,-]+/;if(n.length<5||n.length>6)throw new TypeError("CronPattern: invalid configuration format ('"+this.pattern+"'), exacly five or six space separated parts required.");for(5===n.length&&n.unshift("0"),e=0;e<n.length;e++)if(t=n[e].trim(),i.test(t))throw new TypeError("CronPattern: configuration entry "+(e+1)+" ("+t+") contains illegal characters.");if(r="*"!==n[4],s="*"!==n[5],o="*"!==n[3],s&&(r||o))throw new TypeError("CronPattern: configuration invalid, you can not combine month/date with day of week.");this.partToArray("seconds",n[0],0),this.partToArray("minutes",n[1],0),this.partToArray("hours",n[2],0),this.partToArray("days",n[3],-1),this.partToArray("months",n[4],-1),this.partToArray("daysOfWeek",n[5],0),this.daysOfWeek[7]&&(this.daysOfWeek[0]=1)},s.prototype.partToArray=function(t,e,r){let s,o,n,i,a,h=this[t];if("*"!==e)if(o=e.split(","),o.length>1)for(s=0;s<o.length;s++)this.partToArray(t,o[s],r);else if(-1!==e.indexOf("-")){if(o=e.split("-"),2!==o.length)throw new TypeError("CronPattern: Syntax error, illegal range: '"+e+"'");if(n=parseInt(o[0],10)+r,i=parseInt(o[1],10)+r,isNaN(n))throw new TypeError("CronPattern: Syntax error, illegal lower range (NaN)");if(isNaN(i))throw new TypeError("CronPattern: Syntax error, illegal upper range (NaN)");if(n<0||i>=h.length)throw new TypeError("CronPattern: Value out of range: '"+e+"'");if(n>i)throw new TypeError("CronPattern: From value is larger than to value: '"+e+"'");for(s=n;s<=i;s++)h[s+r]=1}else if(-1!==e.indexOf("/")){if(o=e.split("/"),2!==o.length)throw new TypeError("CronPattern: Syntax error, illegal stepping: '"+e+"'");if("*"!==o[0])throw new TypeError("CronPattern: Syntax error, left part of / needs to be * : '"+e+"'");if(a=parseInt(o[1],10),isNaN(a))throw new TypeError("CronPattern: Syntax error, illegal stepping: (NaN)");if(0===a)throw new TypeError("CronPattern: Syntax error, illegal stepping: 0");if(a>h.length)throw new TypeError("CronPattern: Syntax error, steps cannot be greater than maximum value of part ("+h.length+")");for(s=0;s<h.length;s+=a)h[s+r]=1}else{if(s=parseInt(e,10)+r,s<0||s>=h.length)throw new TypeError("CronPattern: "+t+" value out of range: '"+e+"'");h[s]=1}else for(s=0;s<h.length;s++)h[s]=1};const o=Math.pow(2,31)-1;function n(t,e,r){let o=this;return this instanceof n?(o.pattern=new s(t),o.schedulerDefaults={maxRuns:1/0,kill:!1},"function"==typeof e&&(r=e,e={}),o.opts=o.validateOpts(e||{}),void 0===r?o:this.schedule(e,r)):new n(t,e,r)}n.prototype.next=function(t){let e=this._next(t);return e?e.getDate():null},n.prototype.previous=function(){return this.opts.previous?this.opts.previous.getDate():null},n.prototype._next=function(t){t=new r(t,this.opts.timezone),this.opts.startAt&&t&&t.getTime()<this.opts.startAt.getTime()&&(t=new r(this.opts.startAt,this.opts.timezone));let e=new r(t,this.opts.timezone).increment(this.pattern);return this.opts.maxRuns<=0||this.opts.kill||this.opts.stopAt&&e.getTime()>=this.opts.stopAt.getTime()?null:e},n.prototype.validateOpts=function(t){return t.startAt&&(t.startAt=new r(t.startAt,t.timezone)),t.stopAt&&(t.stopAt=new r(t.stopAt,t.timezone)),t},n.prototype.msToNext=function(t){t=t||new r(void 0,this.opts.timezone);let e=this._next(t);return e?e.getTime()-t.getTime():null},n.prototype.schedule=function(t,e){let r=this;return e||(e=t,t=this.opts),t.paused=void 0!==t.paused&&t.paused,t.kill=t.kill||this.schedulerDefaults.kill,t.maxRuns||0===t.maxRuns||(t.maxRuns=this.schedulerDefaults.maxRuns),this.opts=this.validateOpts(t||{}),this._schedule(e),{stop:function(){r.opts.kill=!0,r.opts.currentTimeout&&clearTimeout(r.opts.currentTimeout)},pause:function(){return(r.opts.paused=!0)&&!r.opts.kill},resume:function(){return!(r.opts.paused=!1)&&!r.opts.kill}}},n.prototype._schedule=function(t){let e,s=this,n=s.maxDelay||o;e=this.msToNext(s.opts.previous),null!==e&&(e>n&&(e=n),s.opts.currentTimeout=setTimeout((function(){e!==n&&(s.opts.paused||(s.opts.maxRuns--,t()),s.opts.previous=new r(void 0,s.opts.timezone)),s._schedule(t)}),e))};const i=n;return e.default})()}));
1
+ !function(t,e){"object"==typeof exports&&"object"==typeof module?module.exports=e():"function"==typeof define&&define.amd?define([],e):"object"==typeof exports?exports.Cron=e():t.Cron=e()}(this,(function(){return(()=>{"use strict";var t={d:(e,r)=>{for(var o in r)t.o(r,o)&&!t.o(e,o)&&Object.defineProperty(e,o,{enumerable:!0,get:r[o]})},o:(t,e)=>Object.prototype.hasOwnProperty.call(t,e)},e={};t.d(e,{default:()=>i});function r(t,e){if(this.timezone=e,t&&t instanceof Date)this.fromDate(t);else if(void 0===t)this.fromDate(new Date);else if(t&&"string"==typeof t)this.fromString(t);else{if(!(t instanceof r))throw new TypeError("CronDate: Invalid type ("+typeof t+") passed as parameter to CronDate constructor");this.fromCronDate(t)}}function o(t){this.pattern=t,this.seconds=Array(60).fill(0),this.minutes=Array(60).fill(0),this.hours=Array(24).fill(0),this.days=Array(31).fill(0),this.months=Array(12).fill(0),this.daysOfWeek=Array(8).fill(0),this.parse()}r.prototype.fromDate=function(t){let e=t.getTime();this.timezone&&(t=function(t,e){return new Date(t.toLocaleString("en-US",{timeZone:e}))}(t,this.timezone));let r=t.getTime();this.UTCmsOffset=r-e,this.milliseconds=t.getMilliseconds(),this.seconds=t.getSeconds(),this.minutes=t.getMinutes(),this.hours=t.getHours(),this.days=t.getDate(),this.months=t.getMonth(),this.years=t.getFullYear()},r.prototype.fromCronDate=function(t){this.UTCmsOffset=t.UTCmsOffset,this.timezone=t.timezone;let e=new Date(t.years,t.months,t.days,t.hours,t.minutes,t.seconds,t.milliseconds);this.milliseconds=e.getMilliseconds(),this.seconds=e.getSeconds(),this.minutes=e.getMinutes(),this.hours=e.getHours(),this.days=e.getDate(),this.months=e.getMonth(),this.years=e.getFullYear()},r.prototype.fromString=function(t){let e=Date.parse(t);if(isNaN(e))throw new TypeError("CronDate: Provided string value for CronDate could not be parsed as date.");this.fromDate(new Date(e))},r.prototype.increment=function(t,e){e||(this.seconds+=1);let o=this.getTime();this.milliseconds=0;let n=this,s=function(t,e,r,o){for(let s=void 0===o?n[t]+r:0+r;s<e[t].length;s++)if(e[t][s])return n[t]=s-r,!0;return!1},i=function(){for(;h>=0;)s(a[h][0],t,a[h][2],0),h--},a=[["seconds","minutes",0],["minutes","hours",0],["hours","days",0],["days","months",-1],["months","years",0]],h=0;for(;h<5;)s(a[h][0],t,a[h][2])||(this[a[h][1]]++,i()),h++;for(;!t.daysOfWeek[this.getDate().getDay()];)this.days+=1,h=2,i();return o!=n.getTime()?(n=new r(n),this.years>=4e3?null:n.increment(t,!0)):this},r.prototype.getDate=function(){return new Date(this.years,this.months,this.days,this.hours,this.minutes,this.seconds,this.milliseconds-this.UTCmsOffset)},r.prototype.getTime=function(){return new Date(this.years,this.months,this.days,this.hours,this.minutes,this.seconds,this.milliseconds-this.UTCmsOffset).getTime()},o.prototype.parse=function(){if("string"!=typeof this.pattern&&this.pattern.constructor!==String)throw new TypeError("CronPattern: Pattern has to be of type string.");let t,e,r=this.pattern.trim().replace(/\s+/g," ").split(" "),o=/[^/*0-9,-]+/;if(r.length<5||r.length>6)throw new TypeError("CronPattern: invalid configuration format ('"+this.pattern+"'), exacly five or six space separated parts required.");for(5===r.length&&r.unshift("0"),e=0;e<r.length;e++)if(t=r[e].trim(),o.test(t))throw new TypeError("CronPattern: configuration entry "+(e+1)+" ("+t+") contains illegal characters.");this.partToArray("seconds",r[0],0),this.partToArray("minutes",r[1],0),this.partToArray("hours",r[2],0),this.partToArray("days",r[3],-1),this.partToArray("months",r[4],-1),this.partToArray("daysOfWeek",r[5],0),this.daysOfWeek[7]&&(this.daysOfWeek[0]=1)},o.prototype.partToArray=function(t,e,r){let o,n,s,i,a,h=this[t];if("*"!==e)if(n=e.split(","),n.length>1)for(o=0;o<n.length;o++)this.partToArray(t,n[o],r);else if(-1!==e.indexOf("-")){if(n=e.split("-"),2!==n.length)throw new TypeError("CronPattern: Syntax error, illegal range: '"+e+"'");if(s=parseInt(n[0],10)+r,i=parseInt(n[1],10)+r,isNaN(s))throw new TypeError("CronPattern: Syntax error, illegal lower range (NaN)");if(isNaN(i))throw new TypeError("CronPattern: Syntax error, illegal upper range (NaN)");if(s<0||i>=h.length)throw new TypeError("CronPattern: Value out of range: '"+e+"'");if(s>i)throw new TypeError("CronPattern: From value is larger than to value: '"+e+"'");for(o=s;o<=i;o++)h[o+r]=1}else if(-1!==e.indexOf("/")){if(n=e.split("/"),2!==n.length)throw new TypeError("CronPattern: Syntax error, illegal stepping: '"+e+"'");if("*"!==n[0])throw new TypeError("CronPattern: Syntax error, left part of / needs to be * : '"+e+"'");if(a=parseInt(n[1],10),isNaN(a))throw new TypeError("CronPattern: Syntax error, illegal stepping: (NaN)");if(0===a)throw new TypeError("CronPattern: Syntax error, illegal stepping: 0");if(a>h.length)throw new TypeError("CronPattern: Syntax error, steps cannot be greater than maximum value of part ("+h.length+")");for(o=0;o<h.length;o+=a)h[o+r]=1}else{if(o=parseInt(e,10)+r,o<0||o>=h.length)throw new TypeError("CronPattern: "+t+" value out of range: '"+e+"'");h[o]=1}else for(o=0;o<h.length;o++)h[o]=1};const n=Math.pow(2,31)-1;function s(t,e,r){return this instanceof s?(this.pattern=new o(t),"function"==typeof e&&(r=e,e=void 0),this.options=this.processOptions(e),void 0!==r&&this.schedule(r),this):new s(t,e,r)}s.prototype.processOptions=function(t){return void 0===t&&(t={}),t.paused=void 0!==t.paused&&t.paused,t.maxRuns=void 0===t.maxRuns?1/0:t.maxRuns,t.kill=!1,t.startAt&&(t.startAt=new r(t.startAt,t.timezone)),t.stopAt&&(t.stopAt=new r(t.stopAt,t.timezone)),t},s.prototype.next=function(t){let e=this._next(t);return e?e.getDate():null},s.prototype.previous=function(){return this.previousrun?this.previousrun.getDate():null},s.prototype._next=function(t){t=new r(t,this.options.timezone),this.options.startAt&&t&&t.getTime()<this.options.startAt.getTime()&&(t=new r(this.options.startAt,this.options.timezone));let e=new r(t,this.options.timezone).increment(this.pattern);return null===e||this.options.maxRuns<=0||this.options.kill||this.options.stopAt&&e.getTime()>=this.options.stopAt.getTime()?null:e},s.prototype.msToNext=function(t){t=t||new r(void 0,this.options.timezone);let e=this._next(t);return e?e.getTime()-t.getTime():null},s.prototype.stop=function(){this.options.kill=!0,this.currentTimeout&&clearTimeout(this.currentTimeout)},s.prototype.pause=function(){return(this.options.paused=!0)&&!this.options.kill},s.prototype.resume=function(){return!(this.options.paused=!1)&&!this.options.kill},s.prototype.schedule=function(t){let e=this,o=this.msToNext(e.previousrun),s=e.maxDelay||n;return o>s&&(o=s),null!==o&&(e.currentTimeout=setTimeout((function(){o!==s&&(e.options.paused||(e.options.maxRuns--,t()),e.previousrun=new r(void 0,e.options.timezone)),e.schedule(t)}),o)),this};const i=s;return e.default})()}));
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "croner",
3
- "version": "3.0.49",
4
- "description": "Isomorphic JavaScript cron parser and scheduler.",
3
+ "version": "4.0.53",
4
+ "description": "Trigger functions in javascript using Cron syntax. No deps. All features.",
5
5
  "author": "Hexagon <github.com/hexagon>",
6
6
  "contributors": [
7
7
  {
@@ -25,11 +25,12 @@
25
25
  "isomorphic"
26
26
  ],
27
27
  "scripts": {
28
- "test": "npm run test:mocha",
29
- "test:mocha": "mocha",
28
+ "test": "npm run test:coverage",
29
+ "test:dist": "mocha",
30
+ "test:coverage": "c8 --reporter=text mocha test/test.croner.js",
30
31
  "test:lint": "eslint ./**/*.js ./**/*.cjs",
31
32
  "test:lint:fix": "eslint --fix ./**/*.js ./**/*.cjs",
32
- "build": "npm run test:lint && npm run build:typings && npm run build:webpack && npm run test:mocha && npm run build:finalize",
33
+ "build": "npm run test:lint && npm run build:typings && npm run build:webpack && npm run test:coverage && npm run build:finalize",
33
34
  "build:webpack": "webpack",
34
35
  "build:typings": "tsc",
35
36
  "build:finalize": "echo \"All good\""
@@ -52,6 +53,7 @@
52
53
  },
53
54
  "types": "types/croner.d.ts",
54
55
  "devDependencies": {
56
+ "c8": "^7.10.0",
55
57
  "eslint": "^7.32.0",
56
58
  "mocha": "^9.1.2",
57
59
  "should": "^13.2.3",
package/src/croner.js CHANGED
@@ -35,10 +35,8 @@ import { CronPattern } from "./pattern.js";
35
35
  *
36
36
  * @typedef {Object} CronOptions - Cron scheduler options
37
37
  * @property {boolean} [paused] - Job is paused
38
- * @property {boolean} [kill] - Job is about to be killed
38
+ * @property {boolean} [kill] - Job is about to be killed or killed
39
39
  * @property {number} [maxRuns] - Maximum nuber of executions
40
- * @property {number} [currentTimeout] - Internal: setTimeout "id"
41
- * @property {CronNextResult} [previous] - Previous run time
42
40
  * @property {string | Date} [startAt] - When to start running
43
41
  * @property {string | Date} [stopAt] - When to stop running
44
42
  * @property {string} [timezone] - Time zone in Europe/Stockholm format
@@ -99,36 +97,53 @@ function Cron (pattern, options, fn) {
99
97
  /** @type {CronPattern} */
100
98
  self.pattern = new CronPattern(pattern);
101
99
 
102
- /** @type {CronOptions} */
103
- self.schedulerDefaults = {
104
- maxRuns: Infinity,
105
- kill: false
106
- };
107
-
108
100
  // Make options optional
109
101
  if( typeof options === "function" ) {
110
102
  fn = options;
111
- options = {};
103
+ options = void 0;
112
104
  }
113
105
 
114
- /**
115
- * Store and validate options
116
- * @type {CronOptions}
106
+ /** @type {CronOptions} */
107
+ this.options = this.processOptions(options);
108
+
109
+ /**
110
+ * Allow shorthand scheduling
117
111
  */
118
- self.opts = self.validateOpts(options || {});
112
+ if( fn !== void 0 ) {
113
+ this.schedule(fn);
114
+ }
119
115
 
120
- // Determine what to return, default is self
121
- if( fn === void 0 ) {
122
- // Normal initialization, return self
123
- return self;
116
+ return this;
124
117
 
125
- } else {
126
- // Shorthand schedule requested, return job
127
- return this.schedule(options, fn);
118
+ }
128
119
 
120
+ /**
121
+ *
122
+ * @param {CronOptions} options
123
+ * @returns {CronOptions}
124
+ */
125
+ Cron.prototype.processOptions = function (options) {
126
+
127
+ // If no options are passed, create empty object
128
+ if (options === void 0) {
129
+ options = {};
129
130
  }
130
131
 
131
- }
132
+ // Keep options, or set defaults
133
+ options.paused = (options.paused === void 0) ? false : options.paused;
134
+ options.maxRuns = (options.maxRuns === void 0) ? Infinity : options.maxRuns;
135
+ options.kill = false;
136
+
137
+ // startAt is set, validate it
138
+ if( options.startAt ) {
139
+ options.startAt = new CronDate(options.startAt, options.timezone);
140
+ }
141
+ if( options.stopAt ) {
142
+ options.stopAt = new CronDate(options.stopAt, options.timezone);
143
+ }
144
+
145
+ return options;
146
+ };
132
147
 
133
148
  /**
134
149
  * Find next runtime, based on supplied date. Strips milliseconds.
@@ -147,7 +162,7 @@ Cron.prototype.next = function (prev) {
147
162
  * @returns {Date | null} - Previous run time
148
163
  */
149
164
  Cron.prototype.previous = function () {
150
- return this.opts.previous ? this.opts.previous.getDate() : null;
165
+ return this.previousrun ? this.previousrun.getDate() : null;
151
166
  };
152
167
 
153
168
  /**
@@ -155,24 +170,25 @@ Cron.prototype.previous = function () {
155
170
  * @private
156
171
  *
157
172
  * @param {Date} prev - Input pattern
158
- * @returns {CronNextResult | null} - Next run time
173
+ * @returns {CronDate | null} - Next run time
159
174
  */
160
175
  Cron.prototype._next = function (prev) {
161
-
162
- prev = new CronDate(prev, this.opts.timezone);
176
+
177
+ prev = new CronDate(prev, this.options.timezone);
163
178
 
164
179
  // Previous run should never be before startAt
165
- if( this.opts.startAt && prev && prev.getTime() < this.opts.startAt.getTime() ) {
166
- prev = new CronDate(this.opts.startAt, this.opts.timezone);
180
+ if( this.options.startAt && prev && prev.getTime() < this.options.startAt.getTime() ) {
181
+ prev = new CronDate(this.options.startAt, this.options.timezone);
167
182
  }
168
183
 
169
184
  // Calculate next run
170
- let nextRun = new CronDate(prev, this.opts.timezone).increment(this.pattern);
185
+ let nextRun = new CronDate(prev, this.options.timezone).increment(this.pattern);
171
186
 
172
187
  // Check for stop condition
173
- if ((this.opts.maxRuns <= 0) ||
174
- (this.opts.kill) ||
175
- (this.opts.stopAt && nextRun.getTime() >= this.opts.stopAt.getTime() )) {
188
+ if ((nextRun === null) ||
189
+ (this.options.maxRuns <= 0) ||
190
+ (this.options.kill) ||
191
+ (this.options.stopAt && nextRun.getTime() >= this.options.stopAt.getTime() )) {
176
192
  return null;
177
193
  } else {
178
194
  // All seem good, return next run
@@ -181,23 +197,6 @@ Cron.prototype._next = function (prev) {
181
197
 
182
198
  };
183
199
 
184
- /**
185
- * Validate (and cleans) options. Raises error on failure.
186
- *
187
- * @param {CronOptions} opts - Input options
188
- * @returns {CronOptions} - Clean and validated options.
189
- */
190
- Cron.prototype.validateOpts = function (opts) {
191
- // startAt is set, validate it
192
- if( opts.startAt ) {
193
- opts.startAt = new CronDate(opts.startAt, opts.timezone);
194
- }
195
- if( opts.stopAt ) {
196
- opts.stopAt = new CronDate(opts.stopAt, opts.timezone);
197
- }
198
- return opts;
199
- };
200
-
201
200
  /**
202
201
  * Returns number of milliseconds to next run
203
202
  *
@@ -205,7 +204,7 @@ Cron.prototype.validateOpts = function (opts) {
205
204
  * @returns {number | null}
206
205
  */
207
206
  Cron.prototype.msToNext = function (prev) {
208
- prev = prev || new CronDate(void 0, this.opts.timezone);
207
+ prev = prev || new CronDate(void 0, this.options.timezone);
209
208
  let next = this._next(prev);
210
209
  if( next ) {
211
210
  return (next.getTime() - prev.getTime());
@@ -215,115 +214,84 @@ Cron.prototype.msToNext = function (prev) {
215
214
  };
216
215
 
217
216
  /**
218
- * Schedule a new job
219
- *
220
- * @signature
221
- * @param {CronOptions | Function} [options] - Options
222
- * @param {Function} [func] - Function to be run each iteration of pattern
223
- * @returns {CronJob}
224
- *
217
+ * Stop execution
218
+ * @public
225
219
  */
226
- Cron.prototype.schedule = function (opts, func) {
227
-
228
- let self = this;
229
-
230
- // Make opts optional
231
- if( !func ) {
232
- func = opts;
233
-
234
- // If options isn't passed to schedule, use stored options
235
- opts = this.opts;
220
+ Cron.prototype.stop = function () {
221
+ this.options.kill = true;
222
+ // Stop any awaiting call
223
+ if( this.currentTimeout ) {
224
+ clearTimeout( this.currentTimeout );
236
225
  }
226
+ };
237
227
 
238
- // Keep options, or set defaults
239
- opts.paused = (opts.paused === void 0) ? false : opts.paused;
240
- opts.kill = opts.kill || this.schedulerDefaults.kill;
241
- if( !opts.maxRuns && opts.maxRuns !== 0 ) {
242
- opts.maxRuns = this.schedulerDefaults.maxRuns;
243
- }
244
-
245
- // Store options
246
- this.opts = this.validateOpts(opts || {});
247
-
248
- this._schedule(func);
249
-
250
-
251
- // Return control functions
252
- return {
253
-
254
- // Return undefined
255
- stop: function() {
256
- self.opts.kill = true;
257
- // Stop any awaiting call
258
- if( self.opts.currentTimeout ) {
259
- clearTimeout( self.opts.currentTimeout );
260
- }
261
- },
262
-
263
- // Return bool wether pause were successful
264
- pause: function() {
265
- return (self.opts.paused = true) && !self.opts.kill;
266
- },
267
-
268
- // Return bool wether resume were successful
269
- resume: function () {
270
- return !(self.opts.paused = false) && !self.opts.kill;
271
- }
228
+ /**
229
+ * Pause execution
230
+ * @public
231
+ *
232
+ * @returns {boolean} - Wether pause was successful
233
+ */
234
+ Cron.prototype.pause = function () {
235
+ return (this.options.paused = true) && !this.options.kill;
236
+ };
272
237
 
273
- };
238
+ /**
239
+ * Pause execution
240
+ * @public
241
+ *
242
+ * @returns {boolean} - Wether resume was successful
243
+ */
244
+ Cron.prototype.resume = function () {
245
+ return !(this.options.paused = false) && !this.options.kill;
274
246
  };
275
247
 
276
248
  /**
277
249
  * Schedule a new job
278
- * @private
250
+ * @public
279
251
  *
280
- * @param {Function} [func] - Function to be run each iteration of pattern
252
+ * @param {Function} func - Function to be run each iteration of pattern
281
253
  * @returns {CronJob}
282
254
  */
283
- Cron.prototype._schedule = function (func) {
255
+ Cron.prototype.schedule = function (func) {
284
256
 
285
257
  let self = this,
286
- waitMs,
258
+
259
+ // Get ms to next run
260
+ waitMs = this.msToNext(self.previousrun),
287
261
 
288
262
  // Prioritize context before closure,
289
263
  // to allow testing of maximum delay.
290
264
  _maxDelay = self.maxDelay || maxDelay;
291
265
 
292
- // Get ms to next run
293
- waitMs = this.msToNext(self.opts.previous);
294
-
295
- // Check for stop conditions
296
- if ( waitMs === null ) {
297
- return;
298
- }
299
-
300
266
  // setTimeout cant handle more than Math.pow(2, 32 - 1) - 1 ms
301
267
  if( waitMs > _maxDelay ) {
302
268
  waitMs = _maxDelay;
303
269
  }
304
270
 
305
271
  // All ok, go go!
306
- self.opts.currentTimeout = setTimeout(function () {
272
+ if ( waitMs !== null ) {
273
+ self.currentTimeout = setTimeout(function () {
307
274
 
308
- // Are we running? If waitMs is maxed out, this is a blank run
309
- if( waitMs !== _maxDelay ) {
275
+ // Are we running? If waitMs is maxed out, this is a blank run
276
+ if( waitMs !== _maxDelay ) {
310
277
 
311
- if ( !self.opts.paused ) {
312
- self.opts.maxRuns--;
313
- func();
314
- }
278
+ if ( !self.options.paused ) {
279
+ self.options.maxRuns--;
280
+ func();
281
+ }
315
282
 
316
- self.opts.previous = new CronDate(void 0, self.opts.timezone);
283
+ self.previousrun = new CronDate(void 0, self.options.timezone);
284
+ }
317
285
 
318
- }
286
+ // Recurseg
287
+ self.schedule(func);
319
288
 
320
- // Recurse
321
- self._schedule(func);
289
+ }, waitMs );
290
+ }
322
291
 
323
- }, waitMs );
292
+ return this;
324
293
 
325
294
  };
326
295
 
327
-
328
296
  export default Cron;
329
297
  export { Cron };
package/src/date.js CHANGED
@@ -10,7 +10,7 @@ import convertTZ from "./timezone.js";
10
10
  function CronDate (date, timezone) {
11
11
 
12
12
  this.timezone = timezone;
13
-
13
+
14
14
  if (date && date instanceof Date) {
15
15
  this.fromDate(date);
16
16
  } else if (date === void 0) {
@@ -20,7 +20,7 @@ function CronDate (date, timezone) {
20
20
  } else if (date instanceof CronDate) {
21
21
  this.fromCronDate(date);
22
22
  } else {
23
- throw new TypeError("CronDate: Invalid type passed as parameter to CronDate constructor");
23
+ throw new TypeError("CronDate: Invalid type (" + typeof date + ") passed as parameter to CronDate constructor");
24
24
  }
25
25
  }
26
26
 
@@ -60,14 +60,18 @@ CronDate.prototype.fromDate = function (date) {
60
60
  CronDate.prototype.fromCronDate = function (date) {
61
61
 
62
62
  this.UTCmsOffset = date.UTCmsOffset;
63
+ this.timezone = date.timezone;
63
64
 
64
- this.milliseconds = date.milliseconds;
65
- this.seconds = date.seconds;
66
- this.minutes = date.minutes;
67
- this.hours = date.hours;
68
- this.days = date.days;
69
- this.months = date.months;
70
- this.years = date.years;
65
+ // Recreate date object to avoid getDate > 31 etc...
66
+ let newDate = new Date(date.years, date.months, date.days, date.hours, date.minutes, date.seconds, date.milliseconds);
67
+
68
+ this.milliseconds = newDate.getMilliseconds();
69
+ this.seconds = newDate.getSeconds();
70
+ this.minutes = newDate.getMinutes();
71
+ this.hours = newDate.getHours();
72
+ this.days = newDate.getDate();
73
+ this.months = newDate.getMonth();
74
+ this.years = newDate.getFullYear();
71
75
  };
72
76
 
73
77
  /**
@@ -93,11 +97,17 @@ CronDate.prototype.fromString = function (str) {
93
97
  * @public
94
98
  *
95
99
  * @param {string} pattern - The pattern used to increment current state
96
- * @return {CronPattern} - Returns itself for chaining
100
+ * @param {boolean} [rerun=false] - If this is an internal incremental run
101
+ * @return {CronDate|null} - Returns itself for chaining, or null if increment wasnt possible
97
102
  */
98
- CronDate.prototype.increment = function (pattern) {
103
+ CronDate.prototype.increment = function (pattern, rerun) {
104
+
105
+ if (!rerun) {
106
+ this.seconds += 1;
107
+ }
108
+
109
+ let origTime = this.getTime();
99
110
 
100
- this.seconds += 1;
101
111
  this.milliseconds = 0;
102
112
 
103
113
  let self = this,
@@ -119,14 +129,33 @@ CronDate.prototype.increment = function (pattern) {
119
129
  let startPos = (override === void 0) ? self[target] + offset : 0 + offset;
120
130
 
121
131
  for( let i = startPos; i < pattern[target].length; i++ ) {
132
+
122
133
  if( pattern[target][i] ) {
123
134
  self[target] = i-offset;
124
135
  return true;
125
136
  }
126
137
  }
127
-
128
138
  return false;
129
139
 
140
+ },
141
+
142
+ resetPrevious = function () {
143
+ // Now when we have gone to next minute, we have to set seconds to the first match
144
+ // Now we are at 00:01:05 following the same example.
145
+ //
146
+ // This goes all the way back to seconds, hence the reverse loop.
147
+ while(doing >= 0) {
148
+
149
+ // Ok, reset current member(e.g. seconds) to first match in pattern, using
150
+ // the same method as aerlier
151
+ //
152
+ // Note the fourth parameter, stating that we should start matching the pattern
153
+ // from zero, instead of current time.
154
+ findNext(toDo[doing][0], pattern, toDo[doing][2], 0);
155
+
156
+ // Go back up, days -> hours -> minutes -> seconds
157
+ doing--;
158
+ }
130
159
  };
131
160
 
132
161
  // Array of work to be done, consisting of subarrays described below:
@@ -152,27 +181,11 @@ CronDate.prototype.increment = function (pattern) {
152
181
  // findNext sets the current member to next match in pattern
153
182
  // If time is 00:00:01 and pattern says *:*:05, seconds will
154
183
  // be set to 5
155
- if(!findNext(toDo[doing][0], pattern, toDo[doing][2])) {
156
184
 
157
- // If pattern didn't provide a match, increment next vanlue (e.g. minues)
185
+ // If pattern didn't provide a match, increment next vanlue (e.g. minues)
186
+ if(!findNext(toDo[doing][0], pattern, toDo[doing][2])) {
158
187
  this[toDo[doing][1]]++;
159
-
160
- // Now when we have gone to next minute, we have to set seconds to the first match
161
- // Now we are at 00:01:05 following the same example.
162
- //
163
- // This goes all the way back to seconds, hence the reverse loop.
164
- while(doing >= 0) {
165
-
166
- // Ok, reset current member(e.g. seconds) to first match in pattern, using
167
- // the same method as aerlier
168
- //
169
- // Note the fourth parameter, stating that we should start matching the pattern
170
- // from zero, instead of current time.
171
- findNext(toDo[doing][0], pattern, toDo[doing][2], 0);
172
-
173
- // Go back up, days -> hours -> minutes -> seconds
174
- doing--;
175
- }
188
+ resetPrevious();
176
189
  }
177
190
 
178
191
  // Gp down, seconds -> minutes -> hours -> days -> months -> year
@@ -183,9 +196,22 @@ CronDate.prototype.increment = function (pattern) {
183
196
  // with weekday patterns, it's just to increment days until we get a match.
184
197
  while (!pattern.daysOfWeek[this.getDate().getDay()]) {
185
198
  this.days += 1;
199
+ doing = 2;
200
+ resetPrevious();
186
201
  }
187
202
 
188
- return this;
203
+ // If anything changed, recreate this CronDate and run again without incrementing
204
+ if (origTime != self.getTime()) {
205
+ self = new CronDate(self);
206
+ if (this.years >= 4000) {
207
+ // Stop incrementing, an impossible pattern is used
208
+ return null;
209
+ } else {
210
+ return self.increment(pattern, true);
211
+ }
212
+ } else {
213
+ return this;
214
+ }
189
215
 
190
216
  };
191
217
 
package/src/pattern.js CHANGED
@@ -37,10 +37,7 @@ CronPattern.prototype.parse = function () {
37
37
  let parts = this.pattern.trim().replace(/\s+/g, " ").split(" "),
38
38
  part,
39
39
  i,
40
- reValidCron = /[^/*0-9,-]+/,
41
- hasMonths,
42
- hasDaysOfWeek,
43
- hasDates;
40
+ reValidCron = /[^/*0-9,-]+/;
44
41
 
45
42
  // Validite number of configuration entries
46
43
  if( parts.length < 5 || parts.length > 6 ) {
@@ -62,16 +59,6 @@ CronPattern.prototype.parse = function () {
62
59
  }
63
60
  }
64
61
 
65
- // Check that we dont have both months and daysofweek
66
- hasMonths = (parts[4] !== "*");
67
- hasDaysOfWeek = (parts[5] !== "*");
68
- hasDates = (parts[3] !== "*");
69
-
70
- // Month/Date and dayofweek is incompatible
71
- if( hasDaysOfWeek && (hasMonths || hasDates) ) {
72
- throw new TypeError("CronPattern: configuration invalid, you can not combine month/date with day of week.");
73
- }
74
-
75
62
  // Parse parts into arrays, validates as we go
76
63
  this.partToArray("seconds", parts[0], 0);
77
64
  this.partToArray("minutes", parts[1], 0);
@@ -120,6 +120,13 @@ module.exports = function (Cron) {
120
120
  }).should.throw();
121
121
  });
122
122
 
123
+ it("Multiple stepping should throw", function () {
124
+ (function(){
125
+ let scheduler = new Cron("* */5/5 * * * *");
126
+ scheduler.next();
127
+ }).should.throw();
128
+ });
129
+
123
130
  it("Missing lower range should throw", function () {
124
131
  (function(){
125
132
  let scheduler = new Cron("* -9 * * * *");
@@ -134,6 +141,27 @@ module.exports = function (Cron) {
134
141
  }).should.throw();
135
142
  });
136
143
 
144
+ it("Higher upper range than lower range should throw", function () {
145
+ (function(){
146
+ let scheduler = new Cron("* 12-2 * * * *");
147
+ scheduler.next();
148
+ }).should.throw();
149
+ });
150
+
151
+ it("Rangerange should throw", function () {
152
+ (function(){
153
+ let scheduler = new Cron("* 0-0-0 * * * *");
154
+ scheduler.next();
155
+ }).should.throw();
156
+ });
157
+
158
+ it("Invalid data type of pattern should throw", function () {
159
+ (function(){
160
+ let scheduler = new Cron(new Date());
161
+ scheduler.next();
162
+ }).should.throw();
163
+ });
164
+
137
165
  it("Valid range should not throw", function () {
138
166
  (function(){
139
167
  let scheduler = new Cron("* 0-9 * * * *");
@@ -182,6 +210,13 @@ module.exports = function (Cron) {
182
210
  scheduler.next();
183
211
  }).should.throw();
184
212
  });
213
+
214
+ it("Array passed as next date should throw", function () {
215
+ (function(){
216
+ let scheduler = new Cron("* * * * * *");
217
+ scheduler.next([]);
218
+ }).should.throw();
219
+ });
185
220
 
186
221
  it("Valid days should not throw", function () {
187
222
  (function(){
@@ -365,15 +400,14 @@ module.exports = function (Cron) {
365
400
 
366
401
  it("* * * * * * with maxRuns: 1 should return undefined after 1.5 seconds", function (done) {
367
402
  let
368
- scheduler = new Cron("* * * * * *");
369
- scheduler.schedule({ maxRuns: 1 }, function () {});
403
+ scheduler = new Cron("* * * * * *", { maxRuns: 1 });
404
+ scheduler.schedule(function () {});
370
405
  setTimeout(function () {
371
406
  let nextRun = scheduler.next();
372
407
  // Do comparison
373
408
  should.equal(nextRun, void 0);
374
409
  done();
375
410
  },1500);
376
-
377
411
  });
378
412
 
379
413
  it("0 0 0 * * * with 40 iterations should return 40 days from now", function () {
@@ -524,10 +558,7 @@ module.exports = function (Cron) {
524
558
  nextRun0.getTime().should.equal(nextRun7.getTime());
525
559
  });
526
560
 
527
- });
528
-
529
- describe("Comprehensive testing ( will fail first day of the year)", function () {
530
- it("Test milliseconds to 01:01:91 XXXX-01-01 (most often next year), 1000s steps", function () {
561
+ it("Test milliseconds to 01:01:01 XXXX-01-01 (most often next year), 1000s steps", function () {
531
562
 
532
563
  let prevRun = new Date(new Date().setMilliseconds(0)),
533
564
  target = new Date(new Date((prevRun.getFullYear()+1) + "-01-01 01:01:01").getTime()),
@@ -569,5 +600,77 @@ module.exports = function (Cron) {
569
600
  }
570
601
 
571
602
  });
603
+ it("Test when next thursday 1st november occurr, starting from 2021-10-13 00:00:00", function () {
604
+ //Cron("0 0 0 1 11 4").next(new Date(1634076000000)).getTime().should.equal(1888182000000);
605
+ Cron("0 0 0 1 11 4").next(new Date(1634076000000)).getFullYear().should.equal(2029);
606
+ });
607
+ it("getTime should return expcted difference with different timezones (now)", function () {
608
+ let timeStockholm = Cron("* * * * * *", {timezone: "Europe/Stockholm"}).next(new Date()).getTime(),
609
+ timeNewYork = Cron("* * * * * *", {timezone: "America/New_York"}).next(new Date()).getTime();
610
+
611
+ // The time right now should be the same in utc wether in new york or stockholm
612
+ timeStockholm.should.be.above(timeNewYork-1000);
613
+ timeStockholm.should.be.below(timeNewYork+1000);
614
+ });
615
+ /*it("getTime should return expcted difference with different timezones (net sunday 1st november)", function () {
616
+ let timeStockholm = Cron("* * * 1 11 4", {timezone: "Europe/Stockholm"}).next(new Date(1634076000000)).getTime(),
617
+ timeNewYork = Cron("* * * 1 11 4", {timezone: "America/New_York"}).next(new Date(1634076000000)).getTime();
618
+
619
+ // The time when next sunday 1st november occur should be with 6 hours difference (seen from utc)
620
+ timeStockholm.should.equal(timeNewYork-6*1000*3600);
621
+ });*/
622
+ it("maxRuns should be inherited from scheduler to job", function () {
623
+ let scheduler = Cron("* * * 1 11 4", {maxRuns: 14}),
624
+ job = scheduler.schedule(() => {});
625
+ job.options.maxRuns.should.equal(14);
626
+ job.stop();
627
+ });
628
+ it("Next saturday at 29th of february should occur 2048", function () {
629
+ let nextSaturday29feb = Cron("0 0 0 29 2 6").next(new Date(1634076000000));
630
+ nextSaturday29feb.getFullYear().should.equal(2048);
631
+ });
632
+ it("Impossible combination should result in null", function () {
633
+ let impossible = Cron("0 0 0 30 2 6").next(new Date(1634076000000));
634
+ should.equal(null, impossible);
635
+ });
636
+ it("shorthand schedule without options should not throw, and execute", function (done) {
637
+ (function(){
638
+ let job = Cron("* * * * * *",() => { job.stop(); done(); });
639
+ }).should.not.throw();
640
+ });
641
+ it("sanity check start stop resume", function () {
642
+ let job = Cron("* * * 1 11 4",() => {});
643
+ (function(){
644
+ job.pause();
645
+ job.resume();
646
+ job.stop();
647
+ }).should.not.throw();
648
+ });
649
+ it("pause by options work", function (done) {
650
+ let job = Cron("* * * * * *",{paused:true},() => { throw new Error("This should not happen"); });
651
+ setTimeout(function () {
652
+ job.stop();
653
+ done();
654
+ },1500);
655
+ });
656
+ it("previous run time should be null if not yet executed", function () {
657
+ let job = Cron("* * * 1 11 4",() => {});
658
+ let result = job.previous();
659
+ should.equal(result,null);
660
+ job.stop();
661
+ });
662
+ it("previous run time should be set if executed", function (done) {
663
+ let
664
+ scheduler = new Cron("* * * * * *", { maxRuns: 1 });
665
+ scheduler.schedule(function () {});
666
+ setTimeout(function () {
667
+ let previous = scheduler.previous();
668
+ // Do comparison
669
+ previous.should.be.above(new Date().getTime()-3000);
670
+ previous.should.be.below(new Date().getTime()+3000);
671
+ scheduler.stop();
672
+ done();
673
+ },1500);
674
+ });
572
675
  });
573
676
  };
package/types/croner.d.ts CHANGED
@@ -9,21 +9,13 @@ export type CronOptions = {
9
9
  */
10
10
  paused?: boolean;
11
11
  /**
12
- * - Job is about to be killed
12
+ * - Job is about to be killed or killed
13
13
  */
14
14
  kill?: boolean;
15
15
  /**
16
16
  * - Maximum nuber of executions
17
17
  */
18
18
  maxRuns?: number;
19
- /**
20
- * - Internal: setTimeout "id"
21
- */
22
- currentTimeout?: number;
23
- /**
24
- * - Previous run time
25
- */
26
- previous?: CronNextResult;
27
19
  /**
28
20
  * - When to start running
29
21
  */
@@ -95,12 +87,13 @@ export class Cron {
95
87
  /** @type {CronPattern} */
96
88
  pattern: CronPattern;
97
89
  /** @type {CronOptions} */
98
- schedulerDefaults: CronOptions;
90
+ options: CronOptions;
99
91
  /**
100
- * Store and validate options
101
- * @type {CronOptions}
92
+ *
93
+ * @param {CronOptions} options
94
+ * @returns {CronOptions}
102
95
  */
103
- opts: CronOptions;
96
+ processOptions(options: CronOptions): CronOptions;
104
97
  /**
105
98
  * Find next runtime, based on supplied date. Strips milliseconds.
106
99
  *
@@ -115,13 +108,6 @@ export class Cron {
115
108
  */
116
109
  previous(): Date | null;
117
110
  private _next;
118
- /**
119
- * Validate (and cleans) options. Raises error on failure.
120
- *
121
- * @param {CronOptions} opts - Input options
122
- * @returns {CronOptions} - Clean and validated options.
123
- */
124
- validateOpts(opts: CronOptions): CronOptions;
125
111
  /**
126
112
  * Returns number of milliseconds to next run
127
113
  *
@@ -129,17 +115,33 @@ export class Cron {
129
115
  * @returns {number | null}
130
116
  */
131
117
  msToNext(prev?: CronNextResult): number | null;
118
+ /**
119
+ * Stop execution
120
+ * @public
121
+ */
122
+ public stop(): void;
123
+ /**
124
+ * Pause execution
125
+ * @public
126
+ *
127
+ * @returns {boolean} - Wether pause was successful
128
+ */
129
+ public pause(): boolean;
130
+ /**
131
+ * Pause execution
132
+ * @public
133
+ *
134
+ * @returns {boolean} - Wether resume was successful
135
+ */
136
+ public resume(): boolean;
132
137
  /**
133
138
  * Schedule a new job
139
+ * @public
134
140
  *
135
- * @signature
136
- * @param {CronOptions | Function} [options] - Options
137
- * @param {Function} [func] - Function to be run each iteration of pattern
141
+ * @param {Function} func - Function to be run each iteration of pattern
138
142
  * @returns {CronJob}
139
- *
140
143
  */
141
- schedule(opts: any, func?: Function): CronJob;
142
- private _schedule;
144
+ public schedule(func: Function): CronJob;
143
145
  }
144
146
  import { CronDate } from "./date.js";
145
147
  import { CronPattern } from "./pattern.js";
package/types/date.d.ts CHANGED
@@ -32,9 +32,10 @@ export class CronDate {
32
32
  * @public
33
33
  *
34
34
  * @param {string} pattern - The pattern used to increment current state
35
- * @return {CronPattern} - Returns itself for chaining
35
+ * @param {boolean} [rerun=false] - If this is an internal incremental run
36
+ * @return {CronDate|null} - Returns itself for chaining, or null if increment wasnt possible
36
37
  */
37
- public increment(pattern: string): any;
38
+ public increment(pattern: string, rerun?: boolean): CronDate | null;
38
39
  /**
39
40
  * Convert current state back to a javascript Date()
40
41
  * @public