cron-converter-u2q 1.3.1 → 1.3.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -4,18 +4,13 @@ export declare class CronConverterU2Q {
4
4
  * @param unixExpression - the unix expression
5
5
  * @returns the corresponding quartz expression
6
6
  */
7
- static unixToQuartz(unixExpression: string): string;
7
+ static unixToQuartz(unixExpression: string, year?: string): string;
8
8
  /**
9
9
  * Converts a quartz cron expression to a unix cron expression
10
10
  * @param quartzExpression - the quartz expression
11
11
  * @returns the corresponding unix expression
12
12
  */
13
13
  static quartzToUnix(quartzExpression: string): string;
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
14
  /**
20
15
  * Converts Unix DOW to Quartz DOW, supporting lists, ranges, and special cases.
21
16
  * Unix: 0=Sun, 1=Mon, ..., 6=Sat, 7=Sun(alias)
package/lib/converter.js CHANGED
@@ -9,10 +9,10 @@ class CronConverterU2Q {
9
9
  * @param unixExpression - the unix expression
10
10
  * @returns the corresponding quartz expression
11
11
  */
12
- static unixToQuartz(unixExpression) {
12
+ static unixToQuartz(unixExpression, year = '*') {
13
13
  validator_1.CronValidatorU2Q.validateUnix(unixExpression);
14
14
  const parts = helper_1.ExpressionHelper.GetExpressionParts(unixExpression);
15
- const [min, hour, dom, month, dow] = parts.map(part => this.convertIntervalParts(part));
15
+ const [min, hour, dom, month, dow] = parts;
16
16
  // Enhanced DOW conversion: handle lists, ranges, and special cases
17
17
  let quartzDow = this.unixDowToQuartz(dow);
18
18
  let quartzDom = dom;
@@ -24,7 +24,14 @@ class CronConverterU2Q {
24
24
  else if (dom !== '*' && dow === '*') {
25
25
  quartzDow = '?';
26
26
  }
27
- return `0 ${min} ${hour} ${quartzDom} ${month} ${quartzDow} *`;
27
+ else if (dom !== '*' && dow !== '*') {
28
+ throw new Error("Quartz cron does not support specifying both Day of Month and Day of Week");
29
+ }
30
+ const result = `0 ${min} ${hour} ${quartzDom} ${month} ${quartzDow} ${year}`;
31
+ if (year !== '*') {
32
+ validator_1.CronValidatorU2Q.validateQuartz(result);
33
+ }
34
+ return result;
28
35
  }
29
36
  /**
30
37
  * Converts a quartz cron expression to a unix cron expression
@@ -34,7 +41,7 @@ class CronConverterU2Q {
34
41
  static quartzToUnix(quartzExpression) {
35
42
  validator_1.CronValidatorU2Q.validateQuartz(quartzExpression);
36
43
  const parts = helper_1.ExpressionHelper.GetExpressionParts(quartzExpression);
37
- const [_, min, hour, dom, month, dow] = parts.map(part => this.convertIntervalParts(part, true));
44
+ const [_, min, hour, dom, month, dow] = parts.map(part => part.replace(/^0\/(\d+)$/, '*/$1'));
38
45
  if (dom.includes('L') || dom.includes('W')) {
39
46
  throw new Error("Unix cron does not support 'L' or 'W' in Day of Month");
40
47
  }
@@ -46,16 +53,6 @@ class CronConverterU2Q {
46
53
  let unixDom = dom === '?' ? '*' : dom;
47
54
  return `${min} ${hour} ${unixDom} ${month} ${unixDow}`;
48
55
  }
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
56
  /**
60
57
  * Converts Unix DOW to Quartz DOW, supporting lists, ranges, and special cases.
61
58
  * Unix: 0=Sun, 1=Mon, ..., 6=Sat, 7=Sun(alias)
@@ -64,8 +61,10 @@ class CronConverterU2Q {
64
61
  static unixDowToQuartz(dow) {
65
62
  if (dow === '*' || dow === '?')
66
63
  return dow;
67
- if (dow.includes(','))
68
- return dow.split(',').map(d => this.unixDowToQuartz(d)).join(',');
64
+ if (dow.includes(',')) {
65
+ const mapped = dow.split(',').map(d => this.unixDowToQuartz(d));
66
+ return Array.from(new Set(mapped)).join(',');
67
+ }
69
68
  if (dow.includes('-'))
70
69
  return dow.split('-').map(d => this.unixDowToQuartz(d)).join('-');
71
70
  if (dow.endsWith('L')) {
@@ -92,8 +91,10 @@ class CronConverterU2Q {
92
91
  if (dow === '*' || dow === '?')
93
92
  return dow === '?' ? '*' : dow;
94
93
  // Split compound expressions so each element is converted individually
95
- if (dow.includes(','))
96
- return dow.split(',').map(d => this.quartzDowToUnix(d)).join(',');
94
+ if (dow.includes(',')) {
95
+ const mapped = dow.split(',').map(d => this.quartzDowToUnix(d));
96
+ return Array.from(new Set(mapped)).join(',');
97
+ }
97
98
  if (dow.includes('-'))
98
99
  return dow.split('-').map(d => this.quartzDowToUnix(d)).join('-');
99
100
  // Last (L) — convert the numeric day part, preserve L suffix
package/lib/helper.js CHANGED
@@ -4,10 +4,10 @@ exports.ExpressionHelper = void 0;
4
4
  class ExpressionHelper {
5
5
  static GetExpressionParts(expression) {
6
6
  this.validateIfNullOrEmpty(expression);
7
- const parts = expression.split(this.delimiter).map(part => part.trim());
7
+ const parts = expression.trim().split(/\s+/);
8
8
  if (this.quartzExpressionLengths.includes(parts.length))
9
9
  return parts;
10
- if (this.unixExpressionLength == parts.length)
10
+ if (this.unixExpressionLength === parts.length)
11
11
  return parts;
12
12
  throw new Error(`Invalid cron expression!`);
13
13
  }
package/package.json CHANGED
@@ -1,9 +1,9 @@
1
1
  {
2
2
  "name": "cron-converter-u2q",
3
- "version": "1.3.1",
3
+ "version": "1.3.3",
4
4
  "description": "Converts cron expressions between unix and quartz formats",
5
5
  "main": "lib/index.js",
6
- "types": "types/index.d.ts",
6
+ "types": "lib/index.d.ts",
7
7
  "scripts": {
8
8
  "build": "tsc",
9
9
  "test": "jest --no-watchman --coverage",
@@ -290,6 +290,49 @@ describe("Converter: error handling", () => {
290
290
  test("quartzToUnix throws on 8-field expression", () => {
291
291
  expect(() => converter.quartzToUnix("* * * * * * * *")).toThrow();
292
292
  });
293
+
294
+ test("unixToQuartz throws when both DOM and DOW are specific", () => {
295
+ expect(() => converter.unixToQuartz("0 0 15 * 1")).toThrow("Quartz cron does not support specifying both Day of Month and Day of Week");
296
+ });
297
+ });
298
+
299
+ describe("Converter: deduplication of DOW values", () => {
300
+ test("unixToQuartz deduplicates redundant DOW values (e.g. 0,7)", () => {
301
+ expect(converter.unixToQuartz("0 0 * * 0,7")).toBe("0 0 0 ? * 1 *");
302
+ });
303
+
304
+ test("quartzToUnix deduplicates redundant DOW values (e.g. 2,2)", () => {
305
+ expect(converter.quartzToUnix("0 0 0 ? * 2,2")).toBe("0 0 * * 1");
306
+ });
307
+ });
308
+
309
+ describe("ExpressionHelper whitespace robustness", () => {
310
+ test("handles multiple spaces, tabs, and leading/trailing whitespace correctly", () => {
311
+ expect(converter.unixToQuartz(" 0 12 * * * ")).toBe("0 0 12 * * * *");
312
+ expect(converter.unixToQuartz("0\t12\t*\t*\t*")).toBe("0 0 12 * * * *");
313
+ });
314
+ });
315
+
316
+ describe("Converter: optional year parameter", () => {
317
+ test("unixToQuartz accepts specific year", () => {
318
+ expect(converter.unixToQuartz("0 12 * * 1", "2026")).toBe("0 0 12 ? * 2 2026");
319
+ });
320
+
321
+ test("unixToQuartz throws on invalid specific year", () => {
322
+ expect(() => converter.unixToQuartz("0 12 * * 1", "invalid_year")).toThrow();
323
+ expect(() => converter.unixToQuartz("0 12 * * 1", "1969")).toThrow(); // out of range
324
+ });
325
+
326
+ test("round-tripping Quartz -> Unix -> Quartz with specific years", () => {
327
+ const originalQuartz = "0 0 12 ? * 2 2026";
328
+ const unix = converter.quartzToUnix(originalQuartz); // "0 12 * * 1"
329
+
330
+ const parts = originalQuartz.split(/\s+/);
331
+ const year = parts.length === 7 ? parts[6] : "*";
332
+
333
+ const reconstructedQuartz = converter.unixToQuartz(unix, year);
334
+ expect(reconstructedQuartz).toBe(originalQuartz);
335
+ });
293
336
  });
294
337
 
295
338
  describe("Validator Checks", () => {
package/src/converter.ts CHANGED
@@ -7,10 +7,10 @@ export class CronConverterU2Q {
7
7
  * @param unixExpression - the unix expression
8
8
  * @returns the corresponding quartz expression
9
9
  */
10
- public static unixToQuartz(unixExpression: string): string {
10
+ public static unixToQuartz(unixExpression: string, year = '*'): string {
11
11
  CronValidatorU2Q.validateUnix(unixExpression);
12
12
  const parts = helper.GetExpressionParts(unixExpression);
13
- const [min, hour, dom, month, dow] = parts.map(part => this.convertIntervalParts(part));
13
+ const [min, hour, dom, month, dow] = parts;
14
14
 
15
15
  // Enhanced DOW conversion: handle lists, ranges, and special cases
16
16
  let quartzDow = this.unixDowToQuartz(dow);
@@ -22,9 +22,15 @@ export class CronConverterU2Q {
22
22
  quartzDom = '?';
23
23
  } else if (dom !== '*' && dow === '*') {
24
24
  quartzDow = '?';
25
+ } else if (dom !== '*' && dow !== '*') {
26
+ throw new Error("Quartz cron does not support specifying both Day of Month and Day of Week");
25
27
  }
26
28
 
27
- return `0 ${min} ${hour} ${quartzDom} ${month} ${quartzDow} *`;
29
+ const result = `0 ${min} ${hour} ${quartzDom} ${month} ${quartzDow} ${year}`;
30
+ if (year !== '*') {
31
+ CronValidatorU2Q.validateQuartz(result);
32
+ }
33
+ return result;
28
34
  }
29
35
 
30
36
  /**
@@ -35,7 +41,7 @@ export class CronConverterU2Q {
35
41
  public static quartzToUnix(quartzExpression: string): string {
36
42
  CronValidatorU2Q.validateQuartz(quartzExpression);
37
43
  const parts = helper.GetExpressionParts(quartzExpression);
38
- const [_, min, hour, dom, month, dow] = parts.map(part => this.convertIntervalParts(part, true));
44
+ const [_, min, hour, dom, month, dow] = parts.map(part => part.replace(/^0\/(\d+)$/, '*/$1'));
39
45
 
40
46
  if (dom.includes('L') || dom.includes('W')) {
41
47
  throw new Error("Unix cron does not support 'L' or 'W' in Day of Month");
@@ -51,17 +57,6 @@ export class CronConverterU2Q {
51
57
  return `${min} ${hour} ${unixDom} ${month} ${unixDow}`;
52
58
  }
53
59
 
54
- /**
55
- * Converts interval parts for both Unix and Quartz expressions.
56
- * In both directions, normalises step notation to the Unix `*\/N` format.
57
- */
58
- private static convertIntervalParts(part: string, isQuartz = false): string {
59
- if (isQuartz) {
60
- return part.replace(/^0\/(\d+)$/, '*/$1');
61
- }
62
- return part;
63
- }
64
-
65
60
  /**
66
61
  * Converts Unix DOW to Quartz DOW, supporting lists, ranges, and special cases.
67
62
  * Unix: 0=Sun, 1=Mon, ..., 6=Sat, 7=Sun(alias)
@@ -69,7 +64,10 @@ export class CronConverterU2Q {
69
64
  */
70
65
  private static unixDowToQuartz(dow: string): string {
71
66
  if (dow === '*' || dow === '?') return dow;
72
- if (dow.includes(',')) return dow.split(',').map(d => this.unixDowToQuartz(d)).join(',');
67
+ if (dow.includes(',')) {
68
+ const mapped = dow.split(',').map(d => this.unixDowToQuartz(d));
69
+ return Array.from(new Set(mapped)).join(',');
70
+ }
73
71
  if (dow.includes('-')) return dow.split('-').map(d => this.unixDowToQuartz(d)).join('-');
74
72
  if (dow.endsWith('L')) {
75
73
  const day = dow.slice(0, -1);
@@ -94,7 +92,10 @@ export class CronConverterU2Q {
94
92
  if (dow === '*' || dow === '?') return dow === '?' ? '*' : dow;
95
93
 
96
94
  // Split compound expressions so each element is converted individually
97
- if (dow.includes(',')) return dow.split(',').map(d => this.quartzDowToUnix(d)).join(',');
95
+ if (dow.includes(',')) {
96
+ const mapped = dow.split(',').map(d => this.quartzDowToUnix(d));
97
+ return Array.from(new Set(mapped)).join(',');
98
+ }
98
99
  if (dow.includes('-')) return dow.split('-').map(d => this.quartzDowToUnix(d)).join('-');
99
100
 
100
101
  // Last (L) — convert the numeric day part, preserve L suffix
package/src/helper.ts CHANGED
@@ -5,9 +5,9 @@ export class ExpressionHelper {
5
5
 
6
6
  public static GetExpressionParts(expression: string): string[] {
7
7
  this.validateIfNullOrEmpty(expression);
8
- const parts = expression.split(this.delimiter).map(part => part.trim());
8
+ const parts = expression.trim().split(/\s+/);
9
9
  if (this.quartzExpressionLengths.includes(parts.length)) return parts;
10
- if (this.unixExpressionLength == parts.length) return parts;
10
+ if (this.unixExpressionLength === parts.length) return parts;
11
11
 
12
12
  throw new Error(`Invalid cron expression!`)
13
13
  }
package/types/index.d.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  declare module 'cron-converter-u2q' {
2
2
  export class CronConverterU2Q {
3
- static unixToQuartz(unixExpression: string): string;
3
+ static unixToQuartz(unixExpression: string, year?: string): string;
4
4
  static quartzToUnix(quartzExpression: string): string;
5
5
  }
6
6