445 lines
11 KiB
JavaScript
445 lines
11 KiB
JavaScript
// From crontab.guru.
|
|
|
|
// 10
|
|
let describe = (function (e, t, n) {
|
|
'use strict';
|
|
function u(e) {
|
|
var t = parseInt(e);
|
|
switch (20 < t ? t % 10 : t) {
|
|
case 1:
|
|
return e + 'st';
|
|
case 2:
|
|
return e + 'nd';
|
|
case 3:
|
|
return e + 'rd';
|
|
default:
|
|
return e + 'th'
|
|
}
|
|
}
|
|
function i(e, t, n, r) {
|
|
return '*' === e ? 'every ' + t : function (e, t, n, r) {
|
|
var o = e.match(/\d+|./g).map(function (e) {
|
|
var t = Number(e);
|
|
return isNaN(t) ? e : t
|
|
}),
|
|
a = o[0];
|
|
if (Number.isInteger(a)) {
|
|
if (1 === o.length) return '' + (n[a] || a);
|
|
if (3 === o.length && '/' === o[1] && Number.isInteger(o[2])) return 'every ' + u(o[2]) + ' ' + t + ' from ' + (n[a] || a) + ' through ' + (n[r] || r);
|
|
if (3 === o.length && '-' === o[1] && Number.isInteger(o[2]) && o[2] >= a) return 'every ' + t + ' from ' + (n[a] || a) + ' through ' + (n[o[2]] || o[2]);
|
|
if (5 === o.length && '-' === o[1] && Number.isInteger(o[2]) && o[2] >= a && '/' === o[3] && Number.isInteger(o[4]) && 1 <= o[4]) return 'every ' + u(o[4]) + ' ' + t + ' from ' + (n[a] || a) + ' through ' + (n[o[2]] || o[2])
|
|
} else if (3 === o.length && '/' === o[1] && Number.isInteger(o[2]) && '*' === o[0]) return 'every ' + u(o[2]) + ' ' + t;
|
|
return ''
|
|
}(e, t, n, r)
|
|
}
|
|
function h(e, t, n, r, o) {
|
|
var a = e.split(',');
|
|
return ((o ? '' : t + ' ') + function (e) {
|
|
switch (e.length) {
|
|
case 0:
|
|
return '';
|
|
case 1:
|
|
return e[0];
|
|
case 2:
|
|
return e[0] + ' and ' + e[1];
|
|
default:
|
|
return e.slice(0, e.length - 1).join(', ') + ', and ' + e[e.length - 1]
|
|
}
|
|
}(a.map(function (e) {
|
|
return i(e, t, n, r)
|
|
}))).replace('every 1st', 'every').replace(t + ' every', 'every').replace(', ' + t, ', ').replace(', and ' + t, ', and ')
|
|
}
|
|
var v = [
|
|
null,
|
|
'January',
|
|
'February',
|
|
'March',
|
|
'April',
|
|
'May',
|
|
'June',
|
|
'July',
|
|
'August',
|
|
'September',
|
|
'October',
|
|
'November',
|
|
'December'
|
|
];
|
|
var y = [
|
|
'Sunday',
|
|
'Monday',
|
|
'Tuesday',
|
|
'Wednesday',
|
|
'Thursday',
|
|
'Friday',
|
|
'Saturday',
|
|
'Sunday'
|
|
];
|
|
var b = /^0*\d\d?$/;
|
|
var g = 'After rebooting.';
|
|
return function (e) {
|
|
if ('@reboot' === e.originalParts[0]) return {
|
|
full: g,
|
|
special: g
|
|
};
|
|
var t,
|
|
n,
|
|
r,
|
|
o = e.parts,
|
|
a = '*' === (r = o[2]) ? '' : 'on ' + h(r, 'day-of-month', {
|
|
}, 31),
|
|
u = '*' === (n = o[3]) ? '' : 'in ' + h(n, 'month', v, 12, !0),
|
|
i = '*' === (t = o[4]) ? '' : 'on ' + h(t, 'day-of-week', y, 7, !0),
|
|
s = '';
|
|
a && i && (s = e.daysAnded ? 'if it\'s' : 'and');
|
|
var c,
|
|
l,
|
|
d = (c = o[0], l = o[1], b.test(c) && b.test(l) ? [
|
|
('0' + c).slice( - 2),
|
|
('0' + l).slice( - 2)
|
|
] : null);
|
|
if (d) return {
|
|
start: 'At',
|
|
minutes: d[0],
|
|
hours: d[1],
|
|
isTime: !0,
|
|
dates: a || null,
|
|
datesWeekdays: s || null,
|
|
weekdays: i || null,
|
|
months: u || null,
|
|
end: '.',
|
|
full: ('At ' + d[1] + ':' + d[0] + ' ' + a + ' ' + s + ' ' + i + ' ' + u).replace(/ +/g, ' ').trim() + '.'
|
|
};
|
|
var m,
|
|
f = h(o[0], 'minute', {
|
|
}, 59),
|
|
p = '*' === (m = o[1]) ? '' : 'past ' + h(m, 'hour', {
|
|
}, 23);
|
|
return {
|
|
start: 'At',
|
|
minutes: f || null,
|
|
hours: p || null,
|
|
dates: a || null,
|
|
datesWeekdays: s || null,
|
|
weekdays: i || null,
|
|
months: u || null,
|
|
end: '.',
|
|
full: ('At ' + f + ' ' + p + ' ' + a + ' ' + s + ' ' + i + ' ' + u).replace(/ +/g, ' ').trim() + '.'
|
|
}
|
|
};
|
|
})();
|
|
|
|
// 13
|
|
let normalize = (
|
|
function (e, t, n) {
|
|
'use strict';
|
|
function h(e, t) {
|
|
return e - t
|
|
}
|
|
function v(e) {
|
|
return e.reduce(function (e, t) {
|
|
return e.indexOf(t) < 0 && e.push(t),
|
|
e
|
|
}, [
|
|
])
|
|
}
|
|
function r(e) {
|
|
return e.reduce(function (e, t) {
|
|
return e.concat(Array.isArray(t) ? r(t) : t)
|
|
}, [
|
|
])
|
|
}
|
|
function o(e, t, n) {
|
|
for (var r = [
|
|
], o = e; o <= t; o += n) r.push(o);
|
|
return r
|
|
}
|
|
var a = /(^|[,-/])\*($|[,-/])/g;
|
|
function y(e, t) {
|
|
var n = '$1' + t + '$2';
|
|
return e.replace(a, n).replace(a, n)
|
|
}
|
|
function b(e, t) {
|
|
var n = e.split(',').map(function (e) {
|
|
return function (e, t) {
|
|
var n = e ? e.match(/\d+|./g).map(function (e) {
|
|
var t = Number(e);
|
|
return isNaN(t) ? e : t
|
|
}) : [
|
|
],
|
|
r = n[0];
|
|
if (Number.isInteger(r)) {
|
|
if (1 === n.length) return {
|
|
list: [
|
|
r
|
|
]
|
|
};
|
|
if (3 === n.length && '/' === n[1] && Number.isInteger(n[2]) && 1 <= n[2]) return {
|
|
list: o(r, t, n[2]),
|
|
warnings: [
|
|
'nonstandard'
|
|
]
|
|
};
|
|
if (3 === n.length && '-' === n[1] && Number.isInteger(n[2]) && n[2] >= r) return {
|
|
list: o(r, n[2], 1)
|
|
};
|
|
if (5 === n.length && '-' === n[1] && Number.isInteger(n[2]) && n[2] >= r && '/' === n[3] && Number.isInteger(n[4]) && 1 <= n[4]) return {
|
|
list: o(r, n[2], n[4])
|
|
}
|
|
}
|
|
return {
|
|
errors: [
|
|
'invalid part'
|
|
]
|
|
}
|
|
}(e, t)
|
|
});
|
|
return {
|
|
list: v(r(n.map(function (e) {
|
|
return e.list || [
|
|
]
|
|
}))).sort(h).filter(function (e) {
|
|
return !isNaN(e)
|
|
}),
|
|
errors: v(r(n.map(function (e) {
|
|
return e.errors || [
|
|
]
|
|
}))),
|
|
warnings: v(r(n.map(function (e) {
|
|
return e.warnings || [
|
|
]
|
|
})))
|
|
}
|
|
}
|
|
function g(e, t, n) {
|
|
return e.length && (e[0] < t || e[e.length - 1] > n)
|
|
}
|
|
var w = /[^\d\-\/\,]/i;
|
|
return function (e) {
|
|
var t = e.parts.map(function (e) {
|
|
return e.slice(0)
|
|
}).map(function (e) {
|
|
return e.replace(/\*\/1(?!\d)/g, '*')
|
|
});
|
|
if (0 === t.length && e.originalParts.length) return {
|
|
};
|
|
var n = {
|
|
errors: [
|
|
],
|
|
warnings: [
|
|
]
|
|
};
|
|
if (void 0 !== e.daysAnded && (n.daysAnded = e.daysAnded), 5 !== t.length && n.errors.push('fields'), t[0] && t[0].length) {
|
|
var r = y(t[0], '0-59'),
|
|
o = b(r, 59);
|
|
n.minutes = o.list,
|
|
(o.errors.length || g(n.minutes, 0, 59) || w.test(r)) && (n.minutes = [
|
|
], n.errors.push('minutes')),
|
|
o.warnings.length && n.warnings.push('minutes')
|
|
} else void 0 === t[0] && n.errors.push('minutes');
|
|
if (t[1] && t[1].length) {
|
|
var a = y(t[1], '0-23'),
|
|
u = b(a, 23);
|
|
n.hours = u.list,
|
|
(u.errors.length || g(n.hours, 0, 23) || w.test(a)) && (n.hours = [
|
|
], n.errors.push('hours')),
|
|
u.warnings.length && n.warnings.push('hours')
|
|
} else void 0 === t[1] && n.errors.push('hours');
|
|
if (t[2] && t[2].length) {
|
|
var i = y(t[2], '1-31'),
|
|
s = b(i, 31);
|
|
n.dates = s.list,
|
|
(s.errors.length || g(n.dates, 1, 31) || w.test(i)) && (n.dates = [
|
|
], n.errors.push('dates')),
|
|
s.warnings.length && n.warnings.push('dates')
|
|
} else void 0 === t[2] && n.errors.push('dates');
|
|
if (t[3] && t[3].length) {
|
|
var c = y(t[3], '1-12'),
|
|
l = e.originalParts[3],
|
|
d = b(c, 12);
|
|
n.months = d.list,
|
|
(d.errors.length || g(n.months, 1, 12) || w.test(c)) && (n.months = [
|
|
], n.errors.push('months')),
|
|
(d.warnings.length || l && t[3] !== l && 3 < l.length && /\D/.test(l)) && n.warnings.push('months')
|
|
} else void 0 === t[3] && n.errors.push('months');
|
|
if (t[4] && t[4].length) {
|
|
var m = y(t[4], '0-6'),
|
|
f = e.originalParts[4],
|
|
p = b(m, 7);
|
|
n.weekdays = v(p.list.map(function (e) {
|
|
return 7 === e ? 0 : e
|
|
})).sort(h),
|
|
(p.errors.length || g(n.weekdays, 0, 6) || w.test(m)) && (n.weekdays = [
|
|
], n.errors.push('weekdays')),
|
|
(p.warnings.length || p.list.includes(7) || f && t[4] !== f && 3 < f.length && /\D/.test(f)) && n.warnings.push('weekdays')
|
|
} else void 0 === t[4] && n.errors.push('weekdays');
|
|
return n.errors.length || delete n.errors,
|
|
n.warnings.length || delete n.warnings,
|
|
n
|
|
}
|
|
}
|
|
)();
|
|
|
|
// 15
|
|
let parse = (function (e, t, n) {
|
|
'use strict';
|
|
function a(e, i) {
|
|
return Object.keys(i).reduce(function (e, t) {
|
|
return n = e,
|
|
o = i[r = t],
|
|
a = new RegExp('(^|[ ,-/])' + r + '($|[ ,-/])', 'gi'),
|
|
u = '$1' + o + '$2',
|
|
n.replace(a, u).replace(a, u);
|
|
var n,
|
|
r,
|
|
o,
|
|
a,
|
|
u
|
|
}, e)
|
|
}
|
|
var u = {
|
|
sun: '0',
|
|
mon: '1',
|
|
tue: '2',
|
|
wed: '3',
|
|
thu: '4',
|
|
fri: '5',
|
|
sat: '6'
|
|
};
|
|
var i = {
|
|
jan: '1',
|
|
feb: '2',
|
|
mar: '3',
|
|
apr: '4',
|
|
may: '5',
|
|
jun: '6',
|
|
jul: '7',
|
|
aug: '8',
|
|
sep: '9',
|
|
oct: '10',
|
|
nov: '11',
|
|
dec: '12'
|
|
};
|
|
var s = {
|
|
'@yearly': [
|
|
'0',
|
|
'0',
|
|
'1',
|
|
'1',
|
|
'*'
|
|
],
|
|
'@annually': [
|
|
'0',
|
|
'0',
|
|
'1',
|
|
'1',
|
|
'*'
|
|
],
|
|
'@monthly': [
|
|
'0',
|
|
'0',
|
|
'1',
|
|
'*',
|
|
'*'
|
|
],
|
|
'@weekly': [
|
|
'0',
|
|
'0',
|
|
'*',
|
|
'*',
|
|
'0'
|
|
],
|
|
'@daily': [
|
|
'0',
|
|
'0',
|
|
'*',
|
|
'*',
|
|
'*'
|
|
],
|
|
'@midnight': [
|
|
'0',
|
|
'0',
|
|
'*',
|
|
'*',
|
|
'*'
|
|
],
|
|
'@hourly': [
|
|
'0',
|
|
'*',
|
|
'*',
|
|
'*',
|
|
'*'
|
|
]
|
|
};
|
|
return function (e) {
|
|
var t = e.trim().split(/\s+/).filter(function (e) {
|
|
return e
|
|
});
|
|
if (1 === t.length && '@reboot' === t[0]) return {
|
|
originalParts: t,
|
|
parts: [
|
|
]
|
|
};
|
|
var n,
|
|
r,
|
|
o = (1 === t.length ? (n = t[0], r = s[n], void 0 !== r ? r : [
|
|
n
|
|
]) : t).map(function (e, t) {
|
|
switch (t) {
|
|
case 3:
|
|
return a(e, i);
|
|
case 4:
|
|
return a(e, u);
|
|
default:
|
|
return e
|
|
}
|
|
}); return {
|
|
originalParts: t,
|
|
parts: o,
|
|
daysAnded: !!o[2] && '*' === o[2][0] || !!o[4] && '*' === o[4][0]
|
|
}
|
|
}
|
|
})();
|
|
|
|
let parsed, schedule;
|
|
|
|
try {
|
|
parsed = parse(process.argv[2]);
|
|
} catch (error) {
|
|
console.log("Could not parse crontab (#1).");
|
|
process.exit(1);
|
|
}
|
|
|
|
try {
|
|
schedule = normalize(parsed);
|
|
if (schedule.errors) {
|
|
if (schedule.errors.includes('fields')) {
|
|
console.log('Errors with crontab fields. Should be: minute hour day-of-month month day-of-week');
|
|
} else {
|
|
let copy = parsed.parts;
|
|
let r = [
|
|
'minutes',
|
|
'hours',
|
|
'dates',
|
|
'months',
|
|
'weekdays'
|
|
];
|
|
for (let f of schedule.errors) {
|
|
let c = r.indexOf(f);
|
|
copy[c] = '\x0304' + copy[c] + '\x03';
|
|
}
|
|
console.log('Error with crontab: ' + copy.join(' ') + ' (' + schedule.errors.join(', ') + ')')
|
|
}
|
|
process.exit(0);
|
|
}
|
|
} catch (error) {
|
|
console.log("Could not parse crontab (#2).");
|
|
process.exit(1);
|
|
}
|
|
|
|
try {
|
|
console.log(describe(parsed).full);
|
|
} catch (error) {
|
|
console.log("Could not describe crontab.");
|
|
process.exit(1);
|
|
}
|