@aarunyaapps/cron-utils 1.0.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/dist/index.d.mts +18 -0
- package/dist/index.d.ts +18 -0
- package/dist/index.js +202 -0
- package/dist/index.mjs +174 -0
- package/package.json +31 -0
package/dist/index.d.mts
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
interface CronFields {
|
|
2
|
+
minute: string;
|
|
3
|
+
hour: string;
|
|
4
|
+
dayOfMonth: string;
|
|
5
|
+
month: string;
|
|
6
|
+
dayOfWeek: string;
|
|
7
|
+
}
|
|
8
|
+
interface ValidationResult {
|
|
9
|
+
valid: boolean;
|
|
10
|
+
errors: string[];
|
|
11
|
+
fields?: CronFields;
|
|
12
|
+
}
|
|
13
|
+
declare function expandField(field: string, min: number, max: number): number[];
|
|
14
|
+
declare function validate(expression: string): ValidationResult;
|
|
15
|
+
declare function nextRuns(expression: string, count?: number, from?: Date): Date[];
|
|
16
|
+
declare function toHumanReadable(expression: string): string;
|
|
17
|
+
|
|
18
|
+
export { type CronFields, type ValidationResult, expandField, nextRuns, toHumanReadable, validate };
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
interface CronFields {
|
|
2
|
+
minute: string;
|
|
3
|
+
hour: string;
|
|
4
|
+
dayOfMonth: string;
|
|
5
|
+
month: string;
|
|
6
|
+
dayOfWeek: string;
|
|
7
|
+
}
|
|
8
|
+
interface ValidationResult {
|
|
9
|
+
valid: boolean;
|
|
10
|
+
errors: string[];
|
|
11
|
+
fields?: CronFields;
|
|
12
|
+
}
|
|
13
|
+
declare function expandField(field: string, min: number, max: number): number[];
|
|
14
|
+
declare function validate(expression: string): ValidationResult;
|
|
15
|
+
declare function nextRuns(expression: string, count?: number, from?: Date): Date[];
|
|
16
|
+
declare function toHumanReadable(expression: string): string;
|
|
17
|
+
|
|
18
|
+
export { type CronFields, type ValidationResult, expandField, nextRuns, toHumanReadable, validate };
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,202 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
|
|
20
|
+
// src/index.ts
|
|
21
|
+
var index_exports = {};
|
|
22
|
+
__export(index_exports, {
|
|
23
|
+
expandField: () => expandField,
|
|
24
|
+
nextRuns: () => nextRuns,
|
|
25
|
+
toHumanReadable: () => toHumanReadable,
|
|
26
|
+
validate: () => validate
|
|
27
|
+
});
|
|
28
|
+
module.exports = __toCommonJS(index_exports);
|
|
29
|
+
var FIELD_RANGES = [
|
|
30
|
+
{ name: "minute", min: 0, max: 59 },
|
|
31
|
+
{ name: "hour", min: 0, max: 23 },
|
|
32
|
+
{ name: "dayOfMonth", min: 1, max: 31 },
|
|
33
|
+
{ name: "month", min: 1, max: 12 },
|
|
34
|
+
{ name: "dayOfWeek", min: 0, max: 7 }
|
|
35
|
+
];
|
|
36
|
+
function expandField(field, min, max) {
|
|
37
|
+
const result = /* @__PURE__ */ new Set();
|
|
38
|
+
for (const part of field.split(",")) {
|
|
39
|
+
if (part === "*" || part === "?") {
|
|
40
|
+
for (let i = min; i <= max; i++) result.add(i);
|
|
41
|
+
} else if (part.includes("/")) {
|
|
42
|
+
const [rangeStr, stepStr] = part.split("/");
|
|
43
|
+
const step = parseInt(stepStr, 10);
|
|
44
|
+
if (isNaN(step) || step < 1) continue;
|
|
45
|
+
let lo = min, hi = max;
|
|
46
|
+
if (rangeStr !== "*" && rangeStr !== "?") {
|
|
47
|
+
if (rangeStr.includes("-")) {
|
|
48
|
+
const [a, b] = rangeStr.split("-").map(Number);
|
|
49
|
+
lo = a;
|
|
50
|
+
hi = b;
|
|
51
|
+
} else {
|
|
52
|
+
lo = parseInt(rangeStr, 10);
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
for (let i = lo; i <= hi; i += step) result.add(i);
|
|
56
|
+
} else if (part.includes("-")) {
|
|
57
|
+
const [a, b] = part.split("-").map(Number);
|
|
58
|
+
for (let i = a; i <= b; i++) result.add(i);
|
|
59
|
+
} else {
|
|
60
|
+
const n = parseInt(part, 10);
|
|
61
|
+
if (!isNaN(n)) result.add(n);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
if (result.has(7)) {
|
|
65
|
+
result.add(0);
|
|
66
|
+
result.delete(7);
|
|
67
|
+
}
|
|
68
|
+
return [...result].filter((n) => n >= min && n <= max).sort((a, b) => a - b);
|
|
69
|
+
}
|
|
70
|
+
function validate(expression) {
|
|
71
|
+
const parts = expression.trim().split(/\s+/);
|
|
72
|
+
if (parts.length !== 5) {
|
|
73
|
+
return { valid: false, errors: [`Expected 5 fields, got ${parts.length}`] };
|
|
74
|
+
}
|
|
75
|
+
const errors = [];
|
|
76
|
+
const fields = {
|
|
77
|
+
minute: parts[0],
|
|
78
|
+
hour: parts[1],
|
|
79
|
+
dayOfMonth: parts[2],
|
|
80
|
+
month: parts[3],
|
|
81
|
+
dayOfWeek: parts[4]
|
|
82
|
+
};
|
|
83
|
+
for (let i = 0; i < FIELD_RANGES.length; i++) {
|
|
84
|
+
const { name, min, max } = FIELD_RANGES[i];
|
|
85
|
+
const field = parts[i];
|
|
86
|
+
if (field === "*" || field === "?") continue;
|
|
87
|
+
try {
|
|
88
|
+
const vals = expandField(field, min, max);
|
|
89
|
+
if (vals.length === 0) errors.push(`${name}: no valid values in "${field}"`);
|
|
90
|
+
} catch {
|
|
91
|
+
errors.push(`${name}: invalid value "${field}"`);
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
return { valid: errors.length === 0, errors, fields };
|
|
95
|
+
}
|
|
96
|
+
function nextRuns(expression, count = 10, from = /* @__PURE__ */ new Date()) {
|
|
97
|
+
const parts = expression.trim().split(/\s+/);
|
|
98
|
+
if (parts.length !== 5) throw new Error("Expected 5-field cron expression");
|
|
99
|
+
const [mF, hF, domF, monF, dowF] = parts;
|
|
100
|
+
const minutes = expandField(mF, 0, 59);
|
|
101
|
+
const hours = expandField(hF, 0, 23);
|
|
102
|
+
const months = expandField(monF, 1, 12);
|
|
103
|
+
const domRestricted = domF !== "*" && domF !== "?";
|
|
104
|
+
const dowRestricted = dowF !== "*" && dowF !== "?";
|
|
105
|
+
const doms = domRestricted ? expandField(domF, 1, 31) : [];
|
|
106
|
+
const dows = dowRestricted ? expandField(dowF, 0, 6) : [];
|
|
107
|
+
if (minutes.length === 0 || hours.length === 0 || months.length === 0) {
|
|
108
|
+
throw new Error("Cron expression produces no valid run times");
|
|
109
|
+
}
|
|
110
|
+
const results = [];
|
|
111
|
+
const d = new Date(from);
|
|
112
|
+
d.setSeconds(0, 0);
|
|
113
|
+
d.setMinutes(d.getMinutes() + 1);
|
|
114
|
+
let iterations = 0;
|
|
115
|
+
const MAX_ITER = 5e5;
|
|
116
|
+
while (results.length < count && iterations++ < MAX_ITER) {
|
|
117
|
+
const month = d.getMonth() + 1;
|
|
118
|
+
if (!months.includes(month)) {
|
|
119
|
+
d.setDate(1);
|
|
120
|
+
d.setHours(0);
|
|
121
|
+
d.setMinutes(0);
|
|
122
|
+
d.setMonth(d.getMonth() + 1);
|
|
123
|
+
continue;
|
|
124
|
+
}
|
|
125
|
+
const dayOk = !domRestricted && !dowRestricted ? true : domRestricted && dowRestricted ? doms.includes(d.getDate()) || dows.includes(d.getDay()) : domRestricted ? doms.includes(d.getDate()) : dows.includes(d.getDay());
|
|
126
|
+
if (!dayOk) {
|
|
127
|
+
d.setDate(d.getDate() + 1);
|
|
128
|
+
d.setHours(0);
|
|
129
|
+
d.setMinutes(0);
|
|
130
|
+
continue;
|
|
131
|
+
}
|
|
132
|
+
if (!hours.includes(d.getHours())) {
|
|
133
|
+
const next = hours.find((h) => h > d.getHours());
|
|
134
|
+
if (next !== void 0) {
|
|
135
|
+
d.setHours(next);
|
|
136
|
+
d.setMinutes(0);
|
|
137
|
+
} else {
|
|
138
|
+
d.setDate(d.getDate() + 1);
|
|
139
|
+
d.setHours(hours[0]);
|
|
140
|
+
d.setMinutes(0);
|
|
141
|
+
}
|
|
142
|
+
continue;
|
|
143
|
+
}
|
|
144
|
+
const nextMin = minutes.find((m) => m >= d.getMinutes());
|
|
145
|
+
if (nextMin !== void 0) {
|
|
146
|
+
if (nextMin === d.getMinutes()) {
|
|
147
|
+
results.push(new Date(d));
|
|
148
|
+
d.setMinutes(d.getMinutes() + 1);
|
|
149
|
+
} else {
|
|
150
|
+
d.setMinutes(nextMin);
|
|
151
|
+
}
|
|
152
|
+
} else {
|
|
153
|
+
const nextHour = hours.find((h) => h > d.getHours());
|
|
154
|
+
if (nextHour !== void 0) {
|
|
155
|
+
d.setHours(nextHour);
|
|
156
|
+
d.setMinutes(minutes[0]);
|
|
157
|
+
} else {
|
|
158
|
+
d.setDate(d.getDate() + 1);
|
|
159
|
+
d.setHours(hours[0]);
|
|
160
|
+
d.setMinutes(minutes[0]);
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
return results;
|
|
165
|
+
}
|
|
166
|
+
var MONTH_SHORT = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"];
|
|
167
|
+
var DOW_LONG = ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"];
|
|
168
|
+
function toHumanReadable(expression) {
|
|
169
|
+
const parts = expression.trim().split(/\s+/);
|
|
170
|
+
if (parts.length !== 5) return "Invalid expression";
|
|
171
|
+
const [min, hour, dom, month, dow] = parts;
|
|
172
|
+
if (min === "*" && hour === "*" && dom === "*" && month === "*" && dow === "*") return "Every minute";
|
|
173
|
+
if (min.startsWith("*/")) return `Every ${min.slice(2)} minutes`;
|
|
174
|
+
if (min === "0" && hour.startsWith("*/")) return `Every ${hour.slice(2)} hours`;
|
|
175
|
+
if (min === "0" && hour === "0" && dom === "*" && month === "*" && dow === "*") return "Daily at midnight";
|
|
176
|
+
if (min === "0" && dom === "*" && month === "*" && dow === "*") return `Daily at ${hour.padStart(2, "0")}:00`;
|
|
177
|
+
const parts2 = [];
|
|
178
|
+
if (min === "*") parts2.push("every minute");
|
|
179
|
+
else if (min.startsWith("*/")) parts2.push(`every ${min.slice(2)} min`);
|
|
180
|
+
else parts2.push(`at :${min.padStart(2, "0")}`);
|
|
181
|
+
if (hour !== "*") {
|
|
182
|
+
if (hour.startsWith("*/")) parts2.push(`every ${hour.slice(2)}h`);
|
|
183
|
+
else parts2.push(`${hour.padStart(2, "0")}:xx`);
|
|
184
|
+
}
|
|
185
|
+
if (dom !== "*" && dom !== "?") parts2.push(`on day ${dom}`);
|
|
186
|
+
if (month !== "*") {
|
|
187
|
+
const mIdx = parseInt(month, 10);
|
|
188
|
+
parts2.push(`in ${!isNaN(mIdx) ? MONTH_SHORT[mIdx - 1] : month}`);
|
|
189
|
+
}
|
|
190
|
+
if (dow !== "*" && dow !== "?") {
|
|
191
|
+
const d = parseInt(dow, 10);
|
|
192
|
+
parts2.push(`on ${!isNaN(d) ? DOW_LONG[d % 7] : dow}`);
|
|
193
|
+
}
|
|
194
|
+
return parts2.join(", ");
|
|
195
|
+
}
|
|
196
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
197
|
+
0 && (module.exports = {
|
|
198
|
+
expandField,
|
|
199
|
+
nextRuns,
|
|
200
|
+
toHumanReadable,
|
|
201
|
+
validate
|
|
202
|
+
});
|
package/dist/index.mjs
ADDED
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
// src/index.ts
|
|
2
|
+
var FIELD_RANGES = [
|
|
3
|
+
{ name: "minute", min: 0, max: 59 },
|
|
4
|
+
{ name: "hour", min: 0, max: 23 },
|
|
5
|
+
{ name: "dayOfMonth", min: 1, max: 31 },
|
|
6
|
+
{ name: "month", min: 1, max: 12 },
|
|
7
|
+
{ name: "dayOfWeek", min: 0, max: 7 }
|
|
8
|
+
];
|
|
9
|
+
function expandField(field, min, max) {
|
|
10
|
+
const result = /* @__PURE__ */ new Set();
|
|
11
|
+
for (const part of field.split(",")) {
|
|
12
|
+
if (part === "*" || part === "?") {
|
|
13
|
+
for (let i = min; i <= max; i++) result.add(i);
|
|
14
|
+
} else if (part.includes("/")) {
|
|
15
|
+
const [rangeStr, stepStr] = part.split("/");
|
|
16
|
+
const step = parseInt(stepStr, 10);
|
|
17
|
+
if (isNaN(step) || step < 1) continue;
|
|
18
|
+
let lo = min, hi = max;
|
|
19
|
+
if (rangeStr !== "*" && rangeStr !== "?") {
|
|
20
|
+
if (rangeStr.includes("-")) {
|
|
21
|
+
const [a, b] = rangeStr.split("-").map(Number);
|
|
22
|
+
lo = a;
|
|
23
|
+
hi = b;
|
|
24
|
+
} else {
|
|
25
|
+
lo = parseInt(rangeStr, 10);
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
for (let i = lo; i <= hi; i += step) result.add(i);
|
|
29
|
+
} else if (part.includes("-")) {
|
|
30
|
+
const [a, b] = part.split("-").map(Number);
|
|
31
|
+
for (let i = a; i <= b; i++) result.add(i);
|
|
32
|
+
} else {
|
|
33
|
+
const n = parseInt(part, 10);
|
|
34
|
+
if (!isNaN(n)) result.add(n);
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
if (result.has(7)) {
|
|
38
|
+
result.add(0);
|
|
39
|
+
result.delete(7);
|
|
40
|
+
}
|
|
41
|
+
return [...result].filter((n) => n >= min && n <= max).sort((a, b) => a - b);
|
|
42
|
+
}
|
|
43
|
+
function validate(expression) {
|
|
44
|
+
const parts = expression.trim().split(/\s+/);
|
|
45
|
+
if (parts.length !== 5) {
|
|
46
|
+
return { valid: false, errors: [`Expected 5 fields, got ${parts.length}`] };
|
|
47
|
+
}
|
|
48
|
+
const errors = [];
|
|
49
|
+
const fields = {
|
|
50
|
+
minute: parts[0],
|
|
51
|
+
hour: parts[1],
|
|
52
|
+
dayOfMonth: parts[2],
|
|
53
|
+
month: parts[3],
|
|
54
|
+
dayOfWeek: parts[4]
|
|
55
|
+
};
|
|
56
|
+
for (let i = 0; i < FIELD_RANGES.length; i++) {
|
|
57
|
+
const { name, min, max } = FIELD_RANGES[i];
|
|
58
|
+
const field = parts[i];
|
|
59
|
+
if (field === "*" || field === "?") continue;
|
|
60
|
+
try {
|
|
61
|
+
const vals = expandField(field, min, max);
|
|
62
|
+
if (vals.length === 0) errors.push(`${name}: no valid values in "${field}"`);
|
|
63
|
+
} catch {
|
|
64
|
+
errors.push(`${name}: invalid value "${field}"`);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
return { valid: errors.length === 0, errors, fields };
|
|
68
|
+
}
|
|
69
|
+
function nextRuns(expression, count = 10, from = /* @__PURE__ */ new Date()) {
|
|
70
|
+
const parts = expression.trim().split(/\s+/);
|
|
71
|
+
if (parts.length !== 5) throw new Error("Expected 5-field cron expression");
|
|
72
|
+
const [mF, hF, domF, monF, dowF] = parts;
|
|
73
|
+
const minutes = expandField(mF, 0, 59);
|
|
74
|
+
const hours = expandField(hF, 0, 23);
|
|
75
|
+
const months = expandField(monF, 1, 12);
|
|
76
|
+
const domRestricted = domF !== "*" && domF !== "?";
|
|
77
|
+
const dowRestricted = dowF !== "*" && dowF !== "?";
|
|
78
|
+
const doms = domRestricted ? expandField(domF, 1, 31) : [];
|
|
79
|
+
const dows = dowRestricted ? expandField(dowF, 0, 6) : [];
|
|
80
|
+
if (minutes.length === 0 || hours.length === 0 || months.length === 0) {
|
|
81
|
+
throw new Error("Cron expression produces no valid run times");
|
|
82
|
+
}
|
|
83
|
+
const results = [];
|
|
84
|
+
const d = new Date(from);
|
|
85
|
+
d.setSeconds(0, 0);
|
|
86
|
+
d.setMinutes(d.getMinutes() + 1);
|
|
87
|
+
let iterations = 0;
|
|
88
|
+
const MAX_ITER = 5e5;
|
|
89
|
+
while (results.length < count && iterations++ < MAX_ITER) {
|
|
90
|
+
const month = d.getMonth() + 1;
|
|
91
|
+
if (!months.includes(month)) {
|
|
92
|
+
d.setDate(1);
|
|
93
|
+
d.setHours(0);
|
|
94
|
+
d.setMinutes(0);
|
|
95
|
+
d.setMonth(d.getMonth() + 1);
|
|
96
|
+
continue;
|
|
97
|
+
}
|
|
98
|
+
const dayOk = !domRestricted && !dowRestricted ? true : domRestricted && dowRestricted ? doms.includes(d.getDate()) || dows.includes(d.getDay()) : domRestricted ? doms.includes(d.getDate()) : dows.includes(d.getDay());
|
|
99
|
+
if (!dayOk) {
|
|
100
|
+
d.setDate(d.getDate() + 1);
|
|
101
|
+
d.setHours(0);
|
|
102
|
+
d.setMinutes(0);
|
|
103
|
+
continue;
|
|
104
|
+
}
|
|
105
|
+
if (!hours.includes(d.getHours())) {
|
|
106
|
+
const next = hours.find((h) => h > d.getHours());
|
|
107
|
+
if (next !== void 0) {
|
|
108
|
+
d.setHours(next);
|
|
109
|
+
d.setMinutes(0);
|
|
110
|
+
} else {
|
|
111
|
+
d.setDate(d.getDate() + 1);
|
|
112
|
+
d.setHours(hours[0]);
|
|
113
|
+
d.setMinutes(0);
|
|
114
|
+
}
|
|
115
|
+
continue;
|
|
116
|
+
}
|
|
117
|
+
const nextMin = minutes.find((m) => m >= d.getMinutes());
|
|
118
|
+
if (nextMin !== void 0) {
|
|
119
|
+
if (nextMin === d.getMinutes()) {
|
|
120
|
+
results.push(new Date(d));
|
|
121
|
+
d.setMinutes(d.getMinutes() + 1);
|
|
122
|
+
} else {
|
|
123
|
+
d.setMinutes(nextMin);
|
|
124
|
+
}
|
|
125
|
+
} else {
|
|
126
|
+
const nextHour = hours.find((h) => h > d.getHours());
|
|
127
|
+
if (nextHour !== void 0) {
|
|
128
|
+
d.setHours(nextHour);
|
|
129
|
+
d.setMinutes(minutes[0]);
|
|
130
|
+
} else {
|
|
131
|
+
d.setDate(d.getDate() + 1);
|
|
132
|
+
d.setHours(hours[0]);
|
|
133
|
+
d.setMinutes(minutes[0]);
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
return results;
|
|
138
|
+
}
|
|
139
|
+
var MONTH_SHORT = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"];
|
|
140
|
+
var DOW_LONG = ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"];
|
|
141
|
+
function toHumanReadable(expression) {
|
|
142
|
+
const parts = expression.trim().split(/\s+/);
|
|
143
|
+
if (parts.length !== 5) return "Invalid expression";
|
|
144
|
+
const [min, hour, dom, month, dow] = parts;
|
|
145
|
+
if (min === "*" && hour === "*" && dom === "*" && month === "*" && dow === "*") return "Every minute";
|
|
146
|
+
if (min.startsWith("*/")) return `Every ${min.slice(2)} minutes`;
|
|
147
|
+
if (min === "0" && hour.startsWith("*/")) return `Every ${hour.slice(2)} hours`;
|
|
148
|
+
if (min === "0" && hour === "0" && dom === "*" && month === "*" && dow === "*") return "Daily at midnight";
|
|
149
|
+
if (min === "0" && dom === "*" && month === "*" && dow === "*") return `Daily at ${hour.padStart(2, "0")}:00`;
|
|
150
|
+
const parts2 = [];
|
|
151
|
+
if (min === "*") parts2.push("every minute");
|
|
152
|
+
else if (min.startsWith("*/")) parts2.push(`every ${min.slice(2)} min`);
|
|
153
|
+
else parts2.push(`at :${min.padStart(2, "0")}`);
|
|
154
|
+
if (hour !== "*") {
|
|
155
|
+
if (hour.startsWith("*/")) parts2.push(`every ${hour.slice(2)}h`);
|
|
156
|
+
else parts2.push(`${hour.padStart(2, "0")}:xx`);
|
|
157
|
+
}
|
|
158
|
+
if (dom !== "*" && dom !== "?") parts2.push(`on day ${dom}`);
|
|
159
|
+
if (month !== "*") {
|
|
160
|
+
const mIdx = parseInt(month, 10);
|
|
161
|
+
parts2.push(`in ${!isNaN(mIdx) ? MONTH_SHORT[mIdx - 1] : month}`);
|
|
162
|
+
}
|
|
163
|
+
if (dow !== "*" && dow !== "?") {
|
|
164
|
+
const d = parseInt(dow, 10);
|
|
165
|
+
parts2.push(`on ${!isNaN(d) ? DOW_LONG[d % 7] : dow}`);
|
|
166
|
+
}
|
|
167
|
+
return parts2.join(", ");
|
|
168
|
+
}
|
|
169
|
+
export {
|
|
170
|
+
expandField,
|
|
171
|
+
nextRuns,
|
|
172
|
+
toHumanReadable,
|
|
173
|
+
validate
|
|
174
|
+
};
|
package/package.json
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@aarunyaapps/cron-utils",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Parse, validate, and calculate next run times for 5-field cron expressions. Zero dependencies. Browser + Node.js compatible.",
|
|
5
|
+
"main": "./dist/index.js",
|
|
6
|
+
"module": "./dist/index.mjs",
|
|
7
|
+
"types": "./dist/index.d.ts",
|
|
8
|
+
"exports": {
|
|
9
|
+
".": {
|
|
10
|
+
"types": "./dist/index.d.ts",
|
|
11
|
+
"import": "./dist/index.mjs",
|
|
12
|
+
"require": "./dist/index.js"
|
|
13
|
+
}
|
|
14
|
+
},
|
|
15
|
+
"files": ["dist", "README.md"],
|
|
16
|
+
"scripts": {
|
|
17
|
+
"build": "tsup src/index.ts --format cjs,esm --dts --clean",
|
|
18
|
+
"dev": "tsup src/index.ts --format cjs,esm --dts --watch",
|
|
19
|
+
"type-check": "tsc --noEmit"
|
|
20
|
+
},
|
|
21
|
+
"keywords": ["cron", "cron-expression", "scheduler", "next-run", "cron-parser"],
|
|
22
|
+
"license": "MIT",
|
|
23
|
+
"repository": {
|
|
24
|
+
"type": "git",
|
|
25
|
+
"url": "https://github.com/aarunyaapps/cron-utils"
|
|
26
|
+
},
|
|
27
|
+
"devDependencies": {
|
|
28
|
+
"tsup": "^8.0.0",
|
|
29
|
+
"typescript": "^5.8.3"
|
|
30
|
+
}
|
|
31
|
+
}
|