cron-converter-u2q 1.2.1 → 1.3.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 +16 -8
- package/lib/converter.d.ts +17 -4
- package/lib/converter.js +93 -28
- package/lib/describer.d.ts +41 -0
- package/lib/describer.js +272 -0
- package/lib/helper.d.ts +7 -0
- package/lib/helper.js +22 -0
- package/lib/index.d.ts +2 -0
- package/lib/index.js +2 -0
- package/lib/validator.d.ts +6 -0
- package/lib/validator.js +215 -0
- package/package.json +4 -1
- package/src/__tests__/index.test.ts +194 -34
- package/src/__tests__/specs-compliance.test.ts +137 -0
- package/src/converter.ts +43 -33
- package/src/describer.ts +169 -57
- package/src/helper.ts +2 -2
- package/src/index.ts +1 -0
- package/src/validator.ts +228 -0
- package/types/index.d.ts +15 -5
package/README.md
CHANGED
|
@@ -54,7 +54,7 @@ pnpm add cron-converter-u2q
|
|
|
54
54
|
## 🚀 Quick Start
|
|
55
55
|
|
|
56
56
|
```typescript
|
|
57
|
-
import { CronConverterU2Q } from 'cron-converter-u2q';
|
|
57
|
+
import { CronConverterU2Q, CronDescriberU2Q } from 'cron-converter-u2q';
|
|
58
58
|
|
|
59
59
|
// Convert Unix to Quartz
|
|
60
60
|
const quartzExpression = CronConverterU2Q.unixToQuartz('5 * * * *');
|
|
@@ -63,9 +63,8 @@ console.log(quartzExpression); // "0 5 * * * ? *"
|
|
|
63
63
|
// Convert Quartz to Unix
|
|
64
64
|
const unixExpression = CronConverterU2Q.quartzToUnix('0 0 8 * * ?');
|
|
65
65
|
console.log(unixExpression); // "0 8 * * *"
|
|
66
|
-
|
|
67
66
|
// Get human-readable description
|
|
68
|
-
const description =
|
|
67
|
+
const description = CronDescriberU2Q.describeUnix('*/5 * * * *');
|
|
69
68
|
console.log(description); // "Every 5 minutes"
|
|
70
69
|
```
|
|
71
70
|
|
|
@@ -77,7 +76,6 @@ console.log(description); // "Every 5 minutes"
|
|
|
77
76
|
// Unix to Quartz
|
|
78
77
|
CronConverterU2Q.unixToQuartz('0 12 * * *'); // "0 0 12 * * ? *"
|
|
79
78
|
CronConverterU2Q.unixToQuartz('*/15 * * * *'); // "0 */15 * * * ? *"
|
|
80
|
-
|
|
81
79
|
// Quartz to Unix
|
|
82
80
|
CronConverterU2Q.quartzToUnix('0 0 8 * * ?'); // "0 8 * * *"
|
|
83
81
|
CronConverterU2Q.quartzToUnix('0 */5 * * * ?'); // "*/5 * * * *"
|
|
@@ -87,12 +85,12 @@ CronConverterU2Q.quartzToUnix('0 */5 * * * ?'); // "*/5 * * * *"
|
|
|
87
85
|
|
|
88
86
|
```typescript
|
|
89
87
|
// Unix format descriptions
|
|
90
|
-
|
|
91
|
-
|
|
88
|
+
CronDescriberU2Q.describeUnix('0 12 * * *'); // "At 12 o'clock"
|
|
89
|
+
CronDescriberU2Q.describeUnix('*/15 * * * *'); // "Every 15 minutes"
|
|
92
90
|
|
|
93
91
|
// Quartz format descriptions
|
|
94
|
-
|
|
95
|
-
|
|
92
|
+
CronDescriberU2Q.describeQuartz('0 0 8 * * ?'); // "At 8 o'clock"
|
|
93
|
+
CronDescriberU2Q.describeQuartz('0 */5 * * * ?'); // "Every 5 minutes"
|
|
96
94
|
```
|
|
97
95
|
|
|
98
96
|
## 🤝 Contributing
|
|
@@ -121,3 +119,13 @@ This project is licensed under the MIT License - see the [LICENSE](LICENSE) file
|
|
|
121
119
|
- Inspired by the need for a simple, reliable cron expression converter
|
|
122
120
|
- Built with TypeScript for better developer experience
|
|
123
121
|
|
|
122
|
+
## 📖 Specifications
|
|
123
|
+
|
|
124
|
+
This library's conversion logic is grounded in the following official specifications:
|
|
125
|
+
|
|
126
|
+
- **POSIX IEEE Std 1003.1** – Defines the standard Unix cron expression format (5 fields: minute, hour, day-of-month, month, day-of-week).
|
|
127
|
+
[https://pubs.opengroup.org/onlinepubs/9699919799/utilities/crontab.html](https://pubs.opengroup.org/onlinepubs/9699919799/utilities/crontab.html)
|
|
128
|
+
|
|
129
|
+
- **Quartz Scheduler** – Defines the extended Quartz cron trigger format (6–7 fields: seconds, minute, hour, day-of-month, month, day-of-week, optional year). Notably, exactly one of `day-of-month` or `day-of-week` must be `?` to avoid scheduling conflicts.
|
|
130
|
+
[https://www.quartz-scheduler.org/documentation/quartz-2.3.0/tutorials/crontrigger.html](https://www.quartz-scheduler.org/documentation/quartz-2.3.0/tutorials/crontrigger.html)
|
|
131
|
+
|
package/lib/converter.d.ts
CHANGED
|
@@ -1,7 +1,4 @@
|
|
|
1
1
|
export declare class CronConverterU2Q {
|
|
2
|
-
static readonly delimiter = " ";
|
|
3
|
-
static readonly unixExpressionLength = 5;
|
|
4
|
-
static readonly quartzExpressionLengths: number[];
|
|
5
2
|
/**
|
|
6
3
|
* Converts a unix cron expression to a quartz cron expression by adding '0' seconds
|
|
7
4
|
* @param unixExpression - the unix expression
|
|
@@ -14,5 +11,21 @@ export declare class CronConverterU2Q {
|
|
|
14
11
|
* @returns the corresponding unix expression
|
|
15
12
|
*/
|
|
16
13
|
static quartzToUnix(quartzExpression: string): string;
|
|
17
|
-
|
|
14
|
+
/**
|
|
15
|
+
* Converts interval parts for both Unix and Quartz expressions.
|
|
16
|
+
* In both directions, normalises step notation to the Unix `*\/N` format.
|
|
17
|
+
*/
|
|
18
|
+
private static convertIntervalParts;
|
|
19
|
+
/**
|
|
20
|
+
* Converts Unix DOW to Quartz DOW, supporting lists, ranges, and special cases.
|
|
21
|
+
* Unix: 0=Sun, 1=Mon, ..., 6=Sat, 7=Sun(alias)
|
|
22
|
+
* Quartz: 1=Sun, 2=Mon, ..., 7=Sat
|
|
23
|
+
*/
|
|
24
|
+
private static unixDowToQuartz;
|
|
25
|
+
/**
|
|
26
|
+
* Converts Quartz DOW to Unix DOW, supporting lists, ranges, and special cases.
|
|
27
|
+
* Quartz: 1=Sun, 2=Mon, ..., 7=Sat
|
|
28
|
+
* Unix: 0=Sun, 1=Mon, ..., 6=Sat
|
|
29
|
+
*/
|
|
30
|
+
static quartzDowToUnix(dow: string): string;
|
|
18
31
|
}
|
package/lib/converter.js
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.CronConverterU2Q = void 0;
|
|
4
|
+
const helper_1 = require("./helper");
|
|
5
|
+
const validator_1 = require("./validator");
|
|
4
6
|
class CronConverterU2Q {
|
|
5
7
|
/**
|
|
6
8
|
* Converts a unix cron expression to a quartz cron expression by adding '0' seconds
|
|
@@ -8,18 +10,21 @@ class CronConverterU2Q {
|
|
|
8
10
|
* @returns the corresponding quartz expression
|
|
9
11
|
*/
|
|
10
12
|
static unixToQuartz(unixExpression) {
|
|
11
|
-
|
|
12
|
-
const parts =
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
13
|
+
validator_1.CronValidatorU2Q.validateUnix(unixExpression);
|
|
14
|
+
const parts = helper_1.ExpressionHelper.GetExpressionParts(unixExpression);
|
|
15
|
+
const [min, hour, dom, month, dow] = parts.map(part => this.convertIntervalParts(part));
|
|
16
|
+
// Enhanced DOW conversion: handle lists, ranges, and special cases
|
|
17
|
+
let quartzDow = this.unixDowToQuartz(dow);
|
|
16
18
|
let quartzDom = dom;
|
|
17
|
-
|
|
18
|
-
|
|
19
|
+
// Per Quartz spec, exactly one of DOM or DOW must be '?'
|
|
20
|
+
// When DOM is '*' and DOW is specific, DOM gets '?'; otherwise DOW gets '?'
|
|
21
|
+
if (dom === '*' && dow !== '*') {
|
|
19
22
|
quartzDom = '?';
|
|
20
|
-
|
|
23
|
+
}
|
|
24
|
+
else if (dom !== '*' && dow === '*') {
|
|
21
25
|
quartzDow = '?';
|
|
22
|
-
|
|
26
|
+
}
|
|
27
|
+
return `0 ${min} ${hour} ${quartzDom} ${month} ${quartzDow} *`;
|
|
23
28
|
}
|
|
24
29
|
/**
|
|
25
30
|
* Converts a quartz cron expression to a unix cron expression
|
|
@@ -27,27 +32,87 @@ class CronConverterU2Q {
|
|
|
27
32
|
* @returns the corresponding unix expression
|
|
28
33
|
*/
|
|
29
34
|
static quartzToUnix(quartzExpression) {
|
|
30
|
-
|
|
31
|
-
const parts =
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
unixDom = '*';
|
|
35
|
+
validator_1.CronValidatorU2Q.validateQuartz(quartzExpression);
|
|
36
|
+
const parts = helper_1.ExpressionHelper.GetExpressionParts(quartzExpression);
|
|
37
|
+
const [_, min, hour, dom, month, dow] = parts.map(part => this.convertIntervalParts(part, true));
|
|
38
|
+
if (dom.includes('L') || dom.includes('W')) {
|
|
39
|
+
throw new Error("Unix cron does not support 'L' or 'W' in Day of Month");
|
|
40
|
+
}
|
|
41
|
+
if (dow.includes('L') || dow.includes('#')) {
|
|
42
|
+
throw new Error("Unix cron does not support 'L' or '#' in Day of Week");
|
|
43
|
+
}
|
|
44
|
+
// Enhanced DOW conversion: handle lists, ranges, and special cases
|
|
45
|
+
let unixDow = this.quartzDowToUnix(dow);
|
|
46
|
+
let unixDom = dom === '?' ? '*' : dom;
|
|
43
47
|
return `${min} ${hour} ${unixDom} ${month} ${unixDow}`;
|
|
44
48
|
}
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
49
|
+
/**
|
|
50
|
+
* Converts interval parts for both Unix and Quartz expressions.
|
|
51
|
+
* In both directions, normalises step notation to the Unix `*\/N` format.
|
|
52
|
+
*/
|
|
53
|
+
static convertIntervalParts(part, isQuartz = false) {
|
|
54
|
+
if (isQuartz) {
|
|
55
|
+
return part.replace(/^0\/(\d+)$/, '*/$1');
|
|
56
|
+
}
|
|
57
|
+
return part;
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Converts Unix DOW to Quartz DOW, supporting lists, ranges, and special cases.
|
|
61
|
+
* Unix: 0=Sun, 1=Mon, ..., 6=Sat, 7=Sun(alias)
|
|
62
|
+
* Quartz: 1=Sun, 2=Mon, ..., 7=Sat
|
|
63
|
+
*/
|
|
64
|
+
static unixDowToQuartz(dow) {
|
|
65
|
+
if (dow === '*' || dow === '?')
|
|
66
|
+
return dow;
|
|
67
|
+
if (dow.includes(','))
|
|
68
|
+
return dow.split(',').map(d => this.unixDowToQuartz(d)).join(',');
|
|
69
|
+
if (dow.includes('-'))
|
|
70
|
+
return dow.split('-').map(d => this.unixDowToQuartz(d)).join('-');
|
|
71
|
+
if (dow.endsWith('L')) {
|
|
72
|
+
const day = dow.slice(0, -1);
|
|
73
|
+
return `${this.unixDowToQuartz(day)}L`;
|
|
74
|
+
}
|
|
75
|
+
if (dow.includes('#')) {
|
|
76
|
+
const [day, nth] = dow.split('#');
|
|
77
|
+
return `${this.unixDowToQuartz(day)}#${nth}`;
|
|
78
|
+
}
|
|
79
|
+
if (dow === '0' || dow === '7')
|
|
80
|
+
return '1'; // Sunday
|
|
81
|
+
const num = parseInt(dow, 10);
|
|
82
|
+
if (!isNaN(num) && num >= 1 && num <= 6)
|
|
83
|
+
return (num + 1).toString(); // Mon(1)→2 … Sat(6)→7
|
|
84
|
+
return dow;
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* Converts Quartz DOW to Unix DOW, supporting lists, ranges, and special cases.
|
|
88
|
+
* Quartz: 1=Sun, 2=Mon, ..., 7=Sat
|
|
89
|
+
* Unix: 0=Sun, 1=Mon, ..., 6=Sat
|
|
90
|
+
*/
|
|
91
|
+
static quartzDowToUnix(dow) {
|
|
92
|
+
if (dow === '*' || dow === '?')
|
|
93
|
+
return dow === '?' ? '*' : dow;
|
|
94
|
+
// Split compound expressions so each element is converted individually
|
|
95
|
+
if (dow.includes(','))
|
|
96
|
+
return dow.split(',').map(d => this.quartzDowToUnix(d)).join(',');
|
|
97
|
+
if (dow.includes('-'))
|
|
98
|
+
return dow.split('-').map(d => this.quartzDowToUnix(d)).join('-');
|
|
99
|
+
// Last (L) — convert the numeric day part, preserve L suffix
|
|
100
|
+
if (dow.endsWith('L')) {
|
|
101
|
+
const day = dow.slice(0, -1);
|
|
102
|
+
return `${this.quartzDowToUnix(day)}L`;
|
|
103
|
+
}
|
|
104
|
+
// Nth weekday (#) — convert the numeric day part, preserve #N
|
|
105
|
+
if (dow.includes('#')) {
|
|
106
|
+
const [day, nth] = dow.split('#');
|
|
107
|
+
return `${this.quartzDowToUnix(day)}#${nth}`;
|
|
108
|
+
}
|
|
109
|
+
// Numeric mapping
|
|
110
|
+
if (dow === '1')
|
|
111
|
+
return '0'; // Sunday
|
|
112
|
+
const num = parseInt(dow, 10);
|
|
113
|
+
if (!isNaN(num) && num >= 2 && num <= 7)
|
|
114
|
+
return (num - 1).toString(); // Mon(2)→1 … Sat(7)→6
|
|
115
|
+
return dow;
|
|
48
116
|
}
|
|
49
117
|
}
|
|
50
118
|
exports.CronConverterU2Q = CronConverterU2Q;
|
|
51
|
-
CronConverterU2Q.delimiter = ' ';
|
|
52
|
-
CronConverterU2Q.unixExpressionLength = 5;
|
|
53
|
-
CronConverterU2Q.quartzExpressionLengths = [6, 7];
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
export declare class CronDescriberU2Q {
|
|
2
|
+
/**
|
|
3
|
+
* Generates a human-readable description for a Unix-style cron expression.
|
|
4
|
+
*
|
|
5
|
+
* Unix-style cron expressions consist of 5 parts:
|
|
6
|
+
* - Minute (0-59)
|
|
7
|
+
* - Hour (0-23)
|
|
8
|
+
* - Day of Month (1-31)
|
|
9
|
+
* - Month (1-12)
|
|
10
|
+
* - Day of Week (0-6, where 0 = Sunday)
|
|
11
|
+
* @param unixExpression - A string containing the Unix-style cron expression.
|
|
12
|
+
* @returns A human-readable description or an error message if invalid.
|
|
13
|
+
*/
|
|
14
|
+
static describeUnix(unixExpression: string): string;
|
|
15
|
+
/**
|
|
16
|
+
* Generates a human-readable description for a Quartz-style cron expression.
|
|
17
|
+
*
|
|
18
|
+
* Quartz-style cron expressions consist of 6 or 7 parts:
|
|
19
|
+
* - Second (0-59)
|
|
20
|
+
* - Minute (0-59)
|
|
21
|
+
* - Hour (0-23)
|
|
22
|
+
* - Day of Month (1-31)
|
|
23
|
+
* - Month (1-12)
|
|
24
|
+
* - Day of Week (1-7, where 1 = Sunday)
|
|
25
|
+
* - Year (optional)
|
|
26
|
+
* @param quartzExpression - A string containing the Quartz-style cron expression.
|
|
27
|
+
* @returns A human-readable description or an error message if invalid.
|
|
28
|
+
*/
|
|
29
|
+
static describeQuartz(quartzExpression: string): string;
|
|
30
|
+
private static describeSecond;
|
|
31
|
+
private static describeMinute;
|
|
32
|
+
private static describeHour;
|
|
33
|
+
private static describeDayOfMonth;
|
|
34
|
+
private static describeMonth;
|
|
35
|
+
private static describeDayOfWeek;
|
|
36
|
+
private static describeYear;
|
|
37
|
+
private static resolveValue;
|
|
38
|
+
private static describeField;
|
|
39
|
+
private static ordinalSuffix;
|
|
40
|
+
private static combineDescriptions;
|
|
41
|
+
}
|
package/lib/describer.js
ADDED
|
@@ -0,0 +1,272 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.CronDescriberU2Q = void 0;
|
|
4
|
+
const helper_1 = require("./helper");
|
|
5
|
+
const validator_1 = require("./validator");
|
|
6
|
+
const converter_1 = require("./converter");
|
|
7
|
+
class CronDescriberU2Q {
|
|
8
|
+
/**
|
|
9
|
+
* Generates a human-readable description for a Unix-style cron expression.
|
|
10
|
+
*
|
|
11
|
+
* Unix-style cron expressions consist of 5 parts:
|
|
12
|
+
* - Minute (0-59)
|
|
13
|
+
* - Hour (0-23)
|
|
14
|
+
* - Day of Month (1-31)
|
|
15
|
+
* - Month (1-12)
|
|
16
|
+
* - Day of Week (0-6, where 0 = Sunday)
|
|
17
|
+
* @param unixExpression - A string containing the Unix-style cron expression.
|
|
18
|
+
* @returns A human-readable description or an error message if invalid.
|
|
19
|
+
*/
|
|
20
|
+
static describeUnix(unixExpression) {
|
|
21
|
+
try {
|
|
22
|
+
validator_1.CronValidatorU2Q.validateUnix(unixExpression);
|
|
23
|
+
const parts = helper_1.ExpressionHelper.GetExpressionParts(unixExpression);
|
|
24
|
+
const [min, hour, dom, month, dow] = parts;
|
|
25
|
+
const descriptions = [
|
|
26
|
+
this.describeMinute(min, true),
|
|
27
|
+
this.describeHour(hour),
|
|
28
|
+
this.describeDayOfMonth(dom),
|
|
29
|
+
this.describeMonth(month),
|
|
30
|
+
this.describeDayOfWeek(dow),
|
|
31
|
+
];
|
|
32
|
+
return this.combineDescriptions(descriptions);
|
|
33
|
+
}
|
|
34
|
+
catch (error) {
|
|
35
|
+
return "Invalid Unix cron expression";
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Generates a human-readable description for a Quartz-style cron expression.
|
|
40
|
+
*
|
|
41
|
+
* Quartz-style cron expressions consist of 6 or 7 parts:
|
|
42
|
+
* - Second (0-59)
|
|
43
|
+
* - Minute (0-59)
|
|
44
|
+
* - Hour (0-23)
|
|
45
|
+
* - Day of Month (1-31)
|
|
46
|
+
* - Month (1-12)
|
|
47
|
+
* - Day of Week (1-7, where 1 = Sunday)
|
|
48
|
+
* - Year (optional)
|
|
49
|
+
* @param quartzExpression - A string containing the Quartz-style cron expression.
|
|
50
|
+
* @returns A human-readable description or an error message if invalid.
|
|
51
|
+
*/
|
|
52
|
+
static describeQuartz(quartzExpression) {
|
|
53
|
+
try {
|
|
54
|
+
validator_1.CronValidatorU2Q.validateQuartz(quartzExpression);
|
|
55
|
+
const parts = helper_1.ExpressionHelper.GetExpressionParts(quartzExpression);
|
|
56
|
+
const [second, min, hour, dom, month, dow, year] = parts;
|
|
57
|
+
// Normalize Quartz DOW to Unix DOW for consistent description mapping
|
|
58
|
+
const normalizedDow = converter_1.CronConverterU2Q.quartzDowToUnix(dow);
|
|
59
|
+
const descriptions = [
|
|
60
|
+
this.describeSecond(second, true),
|
|
61
|
+
this.describeMinute(min, true),
|
|
62
|
+
this.describeHour(hour),
|
|
63
|
+
this.describeDayOfMonth(dom),
|
|
64
|
+
this.describeMonth(month),
|
|
65
|
+
this.describeDayOfWeek(normalizedDow),
|
|
66
|
+
this.describeYear(year),
|
|
67
|
+
];
|
|
68
|
+
return this.combineDescriptions(descriptions);
|
|
69
|
+
}
|
|
70
|
+
catch (error) {
|
|
71
|
+
return "Invalid Quartz cron expression";
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
static describeSecond(second, suppressZero = false) {
|
|
75
|
+
if (second === "*" || (suppressZero && second === "0"))
|
|
76
|
+
return "";
|
|
77
|
+
const desc = this.describeField(second, { nameMap: null, unitSingular: "second", unitPlural: "seconds" });
|
|
78
|
+
if (desc.startsWith("every") || desc.startsWith("from")) {
|
|
79
|
+
return desc.charAt(0).toUpperCase() + desc.slice(1);
|
|
80
|
+
}
|
|
81
|
+
return `At second ${desc}`;
|
|
82
|
+
}
|
|
83
|
+
static describeMinute(min, suppressZero = false) {
|
|
84
|
+
if (min === "*" || (suppressZero && min === "0"))
|
|
85
|
+
return "";
|
|
86
|
+
const desc = this.describeField(min, { nameMap: null, unitSingular: "minute", unitPlural: "minutes" });
|
|
87
|
+
if (desc.startsWith("every") || desc.startsWith("from")) {
|
|
88
|
+
return desc.charAt(0).toUpperCase() + desc.slice(1);
|
|
89
|
+
}
|
|
90
|
+
return `At minute ${desc}`;
|
|
91
|
+
}
|
|
92
|
+
static describeHour(hour) {
|
|
93
|
+
if (hour === "*")
|
|
94
|
+
return "";
|
|
95
|
+
const desc = this.describeField(hour, { nameMap: null, unitSingular: "hour", unitPlural: "hours" });
|
|
96
|
+
if (desc.startsWith("every") || desc.startsWith("from")) {
|
|
97
|
+
return desc.charAt(0).toUpperCase() + desc.slice(1);
|
|
98
|
+
}
|
|
99
|
+
return `At ${desc} o'clock`;
|
|
100
|
+
}
|
|
101
|
+
static describeDayOfMonth(dom) {
|
|
102
|
+
const desc = this.describeField(dom, {
|
|
103
|
+
nameMap: null,
|
|
104
|
+
unitSingular: "day of month",
|
|
105
|
+
unitPlural: "days of month",
|
|
106
|
+
isDom: true
|
|
107
|
+
});
|
|
108
|
+
if (!desc)
|
|
109
|
+
return "";
|
|
110
|
+
if (desc.startsWith("every") || desc.startsWith("from"))
|
|
111
|
+
return desc;
|
|
112
|
+
return `on the ${desc} of the month`;
|
|
113
|
+
}
|
|
114
|
+
static describeMonth(month) {
|
|
115
|
+
const desc = this.describeField(month, {
|
|
116
|
+
nameMap: [
|
|
117
|
+
"January",
|
|
118
|
+
"February",
|
|
119
|
+
"March",
|
|
120
|
+
"April",
|
|
121
|
+
"May",
|
|
122
|
+
"June",
|
|
123
|
+
"July",
|
|
124
|
+
"August",
|
|
125
|
+
"September",
|
|
126
|
+
"October",
|
|
127
|
+
"November",
|
|
128
|
+
"December",
|
|
129
|
+
],
|
|
130
|
+
unitSingular: "month",
|
|
131
|
+
unitPlural: "months"
|
|
132
|
+
});
|
|
133
|
+
if (!desc)
|
|
134
|
+
return "";
|
|
135
|
+
if (desc.startsWith("every") || desc.startsWith("from"))
|
|
136
|
+
return desc;
|
|
137
|
+
return `in ${desc}`;
|
|
138
|
+
}
|
|
139
|
+
static describeDayOfWeek(dow) {
|
|
140
|
+
const desc = this.describeField(dow, {
|
|
141
|
+
nameMap: [
|
|
142
|
+
"Sunday",
|
|
143
|
+
"Monday",
|
|
144
|
+
"Tuesday",
|
|
145
|
+
"Wednesday",
|
|
146
|
+
"Thursday",
|
|
147
|
+
"Friday",
|
|
148
|
+
"Saturday",
|
|
149
|
+
],
|
|
150
|
+
unitSingular: "day of week",
|
|
151
|
+
unitPlural: "days of week",
|
|
152
|
+
isDow: true
|
|
153
|
+
});
|
|
154
|
+
if (!desc)
|
|
155
|
+
return "";
|
|
156
|
+
if (desc.startsWith("every") || desc.startsWith("from"))
|
|
157
|
+
return desc;
|
|
158
|
+
return `on ${desc}`;
|
|
159
|
+
}
|
|
160
|
+
static describeYear(year) {
|
|
161
|
+
if (!year || year === "*")
|
|
162
|
+
return "";
|
|
163
|
+
const desc = this.describeField(year, {
|
|
164
|
+
nameMap: null,
|
|
165
|
+
unitSingular: "year",
|
|
166
|
+
unitPlural: "years"
|
|
167
|
+
});
|
|
168
|
+
if (!desc)
|
|
169
|
+
return "";
|
|
170
|
+
if (desc.startsWith("every") || desc.startsWith("from"))
|
|
171
|
+
return desc;
|
|
172
|
+
return `in ${desc}`;
|
|
173
|
+
}
|
|
174
|
+
static resolveValue(val, config) {
|
|
175
|
+
if (config.isDow) {
|
|
176
|
+
if (val.endsWith("L")) {
|
|
177
|
+
const day = val.slice(0, -1);
|
|
178
|
+
return `last ${this.resolveValue(day, config)}`;
|
|
179
|
+
}
|
|
180
|
+
if (val.includes("#")) {
|
|
181
|
+
const [day, nth] = val.split("#");
|
|
182
|
+
const nthStr = this.ordinalSuffix(Number(nth));
|
|
183
|
+
return `${nthStr} ${this.resolveValue(day, config)}`;
|
|
184
|
+
}
|
|
185
|
+
let dowVal = val.toUpperCase();
|
|
186
|
+
const dayNames = ["SUN", "MON", "TUE", "WED", "THU", "FRI", "SAT"];
|
|
187
|
+
const aliasIndex = dayNames.indexOf(dowVal);
|
|
188
|
+
let index = aliasIndex !== -1 ? aliasIndex : Number(val);
|
|
189
|
+
if (index === 7)
|
|
190
|
+
index = 0;
|
|
191
|
+
return config.nameMap ? config.nameMap[index] || val : val;
|
|
192
|
+
}
|
|
193
|
+
if (config.isDom) {
|
|
194
|
+
if (val === "L")
|
|
195
|
+
return "last day";
|
|
196
|
+
if (val === "LW")
|
|
197
|
+
return "last weekday";
|
|
198
|
+
if (val.endsWith("W")) {
|
|
199
|
+
const day = val.slice(0, -1);
|
|
200
|
+
return `nearest weekday to the ${this.resolveValue(day, config)}`;
|
|
201
|
+
}
|
|
202
|
+
if (val.startsWith("L-")) {
|
|
203
|
+
const offset = val.slice(2);
|
|
204
|
+
return `${offset} days before the last day`;
|
|
205
|
+
}
|
|
206
|
+
return this.ordinalSuffix(Number(val));
|
|
207
|
+
}
|
|
208
|
+
if (config.nameMap) {
|
|
209
|
+
let mVal = val.toUpperCase();
|
|
210
|
+
const monthNames = ["JAN", "FEB", "MAR", "APR", "MAY", "JUN", "JUL", "AUG", "SEP", "OCT", "NOV", "DEC"];
|
|
211
|
+
const aliasIndex = monthNames.indexOf(mVal);
|
|
212
|
+
let index = aliasIndex !== -1 ? aliasIndex : Number(val) - 1;
|
|
213
|
+
return config.nameMap[index] || val;
|
|
214
|
+
}
|
|
215
|
+
return val;
|
|
216
|
+
}
|
|
217
|
+
static describeField(value, config) {
|
|
218
|
+
if (value === "*" || value === "?")
|
|
219
|
+
return "";
|
|
220
|
+
const parts = value.split(",");
|
|
221
|
+
const descriptions = parts.map(part => {
|
|
222
|
+
if (part.includes("/")) {
|
|
223
|
+
const [start, step] = part.split("/");
|
|
224
|
+
const stepNum = Number(step);
|
|
225
|
+
const unit = stepNum === 1 ? config.unitSingular : config.unitPlural;
|
|
226
|
+
if (start === "*" || start === "0") {
|
|
227
|
+
return `every ${step} ${unit}`;
|
|
228
|
+
}
|
|
229
|
+
else {
|
|
230
|
+
const startDesc = this.resolveValue(start, config);
|
|
231
|
+
return `every ${step} ${unit} starting from ${startDesc}`;
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
if (part.includes("-")) {
|
|
235
|
+
const [start, end] = part.split("-");
|
|
236
|
+
const startDesc = this.resolveValue(start, config);
|
|
237
|
+
const endDesc = this.resolveValue(end, config);
|
|
238
|
+
return `from ${startDesc} to ${endDesc}`;
|
|
239
|
+
}
|
|
240
|
+
return this.resolveValue(part, config);
|
|
241
|
+
});
|
|
242
|
+
if (descriptions.length === 1) {
|
|
243
|
+
return descriptions[0];
|
|
244
|
+
}
|
|
245
|
+
else if (descriptions.length === 2) {
|
|
246
|
+
return `${descriptions[0]} and ${descriptions[1]}`;
|
|
247
|
+
}
|
|
248
|
+
else {
|
|
249
|
+
return `${descriptions.slice(0, -1).join(", ")}, and ${descriptions[descriptions.length - 1]}`;
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
static ordinalSuffix(i) {
|
|
253
|
+
if (isNaN(i) || i <= 0)
|
|
254
|
+
return "Invalid day";
|
|
255
|
+
const j = i % 10;
|
|
256
|
+
const k = i % 100;
|
|
257
|
+
if (j === 1 && k !== 11)
|
|
258
|
+
return i + "st";
|
|
259
|
+
if (j === 2 && k !== 12)
|
|
260
|
+
return i + "nd";
|
|
261
|
+
if (j === 3 && k !== 13)
|
|
262
|
+
return i + "rd";
|
|
263
|
+
return i + "th";
|
|
264
|
+
}
|
|
265
|
+
static combineDescriptions(descriptions) {
|
|
266
|
+
const filteredDescriptions = descriptions.filter((part) => part && part !== "");
|
|
267
|
+
return filteredDescriptions.length > 0
|
|
268
|
+
? filteredDescriptions.join(" ").trim()
|
|
269
|
+
: "Every moment";
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
exports.CronDescriberU2Q = CronDescriberU2Q;
|
package/lib/helper.d.ts
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export declare class ExpressionHelper {
|
|
2
|
+
static readonly delimiter = " ";
|
|
3
|
+
static readonly unixExpressionLength = 5;
|
|
4
|
+
static readonly quartzExpressionLengths: number[];
|
|
5
|
+
static GetExpressionParts(expression: string): string[];
|
|
6
|
+
private static validateIfNullOrEmpty;
|
|
7
|
+
}
|
package/lib/helper.js
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.ExpressionHelper = void 0;
|
|
4
|
+
class ExpressionHelper {
|
|
5
|
+
static GetExpressionParts(expression) {
|
|
6
|
+
this.validateIfNullOrEmpty(expression);
|
|
7
|
+
const parts = expression.split(this.delimiter).map(part => part.trim());
|
|
8
|
+
if (this.quartzExpressionLengths.includes(parts.length))
|
|
9
|
+
return parts;
|
|
10
|
+
if (this.unixExpressionLength == parts.length)
|
|
11
|
+
return parts;
|
|
12
|
+
throw new Error(`Invalid cron expression!`);
|
|
13
|
+
}
|
|
14
|
+
static validateIfNullOrEmpty(cronExpression) {
|
|
15
|
+
if (!cronExpression || cronExpression.trim() === '')
|
|
16
|
+
throw new Error('Empty or null expression');
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
exports.ExpressionHelper = ExpressionHelper;
|
|
20
|
+
ExpressionHelper.delimiter = ' ';
|
|
21
|
+
ExpressionHelper.unixExpressionLength = 5;
|
|
22
|
+
ExpressionHelper.quartzExpressionLengths = [6, 7];
|
package/lib/index.d.ts
CHANGED
package/lib/index.js
CHANGED
|
@@ -15,3 +15,5 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
|
15
15
|
};
|
|
16
16
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
17
|
__exportStar(require("./converter"), exports);
|
|
18
|
+
__exportStar(require("./describer"), exports);
|
|
19
|
+
__exportStar(require("./validator"), exports);
|