@iobroker/adapter-react
Version:
React classes to develop admin interfaces for ioBroker with react.
564 lines (480 loc) • 17 kB
JavaScript
Object.defineProperty(exports, "__esModule", {
value: true
});
exports["default"] = void 0;
/**
* Given a cronspec, return the human-readable string.
* @param {string} cronspec
* @param withSeconds
* @param {Object=} locale
*/
function cronToText(cronspec, withSeconds, locale) {
// Constant array to convert valid names to values
var NAMES = {
JAN: 1,
FEB: 2,
MAR: 3,
APR: 4,
MAY: 5,
JUN: 6,
JUL: 7,
AUG: 8,
SEP: 9,
OCT: 10,
NOV: 11,
DEC: 12,
SUN: 1,
MON: 2,
TUE: 3,
WED: 4,
THU: 5,
FRI: 6,
SAT: 7
}; // Parsable replacements for common expressions
var REPLACEMENTS = {
'* * * * * *': '0/1 * * * * *',
'@YEARLY': '0 0 1 1 *',
'@ANNUALLY': '0 0 1 1 *',
'@MONTHLY': '0 0 1 * *',
'@WEEKLY': '0 0 * * 0',
'@DAILY': '0 0 * * *',
'@HOURLY': '0 * * * *'
}; // Contains the index, min, and max for each of the constraints
var FIELDS = {
s: [0, 0, 59],
// seconds
m: [1, 0, 59],
// minutes
h: [2, 0, 23],
// hours
D: [3, 1, 31],
// day of month
M: [4, 1, 12],
// month
Y: [6, 1970, 2099],
// year
d: [5, 1, 7, 1] // day of week
};
/**
* Returns the value + offset if value is a number, otherwise it
* attempts to look up the value in the NAMES table and returns
* that result instead.
*
* @param {Number,String} value: The value that should be parsed
* @param {Number=} offset: Any offset that must be added to the value
* @param {Number=} max
* @returns {Number|null}
*/
function getValue(value) {
var offset = arguments.length <= 1 || arguments[1] === undefined ? 0 : arguments[1];
var max = arguments.length <= 2 || arguments[2] === undefined ? 9999 : arguments[2];
return isNaN(value) ? NAMES[value] || null : Math.min(+value + offset, max);
}
/**
* Returns a deep clone of a schedule skipping any day of week
* constraints.
*
* @param {Object} sched: The schedule that will be cloned
* @returns {Object}
*/
function cloneSchedule(sched) {
var clone = {};
var field;
for (field in sched) {
if (field !== 'dc' && field !== 'd') {
clone[field] = sched[field].slice(0);
}
}
return clone;
}
/**
* Adds values to the specified constraint in the current schedule.
*
* @param {Object} sched: The schedule to add the constraint to
* @param {String} name: Name of constraint to add
* @param {Number} min: Minimum value for this constraint
* @param {Number} max: Maximum value for this constraint
*/
function add(sched, name, min, max) {
var inc = arguments.length <= 4 || arguments[4] === undefined ? 0 : arguments[4];
var i = min;
if (!sched[name]) {
sched[name] = [];
}
while (i <= max) {
if (sched[name].indexOf(i) < 0) {
sched[name].push(i);
}
i += inc || 1;
}
sched[name].sort(function (a, b) {
return a - b;
});
}
/**
* Adds a hash item (of the form x#y or xL) to the schedule.
*
* @param {Object} schedules: The current schedule array to add to
* @param {Object} curSched: The current schedule to add to
* @param {Number} value: The value to add (x of x#y or xL)
* @param {Number} hash: The hash value to add (y of x#y)
*/
function addHash(schedules, curSched, value, hash) {
// if there are any existing day of week constraints that
// aren't equal to the one we're adding, create a new
// composite schedule
if (curSched.d && !curSched.dc || curSched.dc && curSched.dc.indexOf(hash) < 0) {
schedules.push(cloneSchedule(curSched));
curSched = schedules[schedules.length - 1];
}
add(curSched, 'd', value, value);
add(curSched, 'dc', hash, hash);
}
/**
*
* @param {Object} s: The existing set of schedules
* @param {Object} curSched: The current schedule to add to
* @param {Number} value
*/
function addWeekday(s, curSched, value) {
var except1 = {},
except2 = {};
if (value === 1) {
// cron doesn't pass month boundaries, so if 1st is a
// weekend then we need to use 2nd or 3rd instead
add(curSched, 'D', 1, 3);
add(curSched, 'd', NAMES.MON, NAMES.FRI);
add(except1, 'D', 2, 2);
add(except1, 'd', NAMES.TUE, NAMES.FRI);
add(except2, 'D', 3, 3);
add(except2, 'd', NAMES.TUE, NAMES.FRI);
} else {
// normally you want the closest day, so if v is a
// Saturday, use the previous Friday. If it's a
// sunday, use the following Monday.
add(curSched, 'D', value - 1, value + 1);
add(curSched, 'd', NAMES.MON, NAMES.FRI);
add(except1, 'D', value - 1, value - 1);
add(except1, 'd', NAMES.MON, NAMES.THU);
add(except2, 'D', value + 1, value + 1);
add(except2, 'd', NAMES.TUE, NAMES.FRI);
}
s.exceptions.push(except1);
s.exceptions.push(except2);
}
/**
* Adds a range item (of the form x-y/z) to the schedule.
*
* @param {String} item: The cron expression item to add
* @param {Object} curSched: The current schedule to add to
* @param {String} name: The name to use for this constraint
* @param {Number} min: The min value for the constraint
* @param {Number} max: The max value for the constraint
* @param {Number} offset: The offset to apply to the cron value
*/
function addRange(item, curSched, name, min, max, offset) {
// parse range/x
var incSplit = item.split('/'),
inc = +incSplit[1],
range = incSplit[0]; // parse x-y or * or 0
if (range !== '*' && range !== '0') {
var rangeSplit = range.split('-');
min = getValue(rangeSplit[0], offset, max); // fix for issue #13, range may be single digit
max = getValue(rangeSplit[1], offset, max) || max;
}
add(curSched, name, min, max, inc);
}
/**
* Parses a particular item within a cron expression.
*
* @param {String} item: The cron expression item to parse
* @param {Object} s: The existing set of schedules
* @param {String} name: The name to use for this constraint
* @param {Number} min: The min value for the constraint
* @param {Number} max: The max value for the constraint
* @param {Number} offset: The offset to apply to the cron value
*/
function parse(item, s, name, min, max, offset) {
var value,
split,
schedules = s.schedules,
curSched = schedules[schedules.length - 1]; // L just means min - 1 (this also makes it work for any field)
if (item === 'L') {
item = (min - 1).toString(10);
} // parse x
if ((value = getValue(item, offset, max)) !== null) {
add(curSched, name, value, value);
} // parse xW
else if ((value = getValue(item.replace('W', ''), offset, max)) !== null) {
addWeekday(s, curSched, value);
} // parse xL
else if ((value = getValue(item.replace('L', ''), offset, max)) !== null) {
addHash(schedules, curSched, value, min - 1);
} // parse x#y
else if ((split = item.split('#')).length === 2) {
value = getValue(split[0], offset, max);
addHash(schedules, curSched, value, getValue(split[1]));
} // parse x-y or x-y/z or */z or 0/z
else {
addRange(item, curSched, name, min, max, offset);
}
}
/**
* Returns true if the item is either of the form x#y or xL.
*
* @param {String} item: The expression item to check
*/
function isHash(item) {
return item.indexOf('#') > -1 || item.indexOf('L') > 0;
}
function itemSorter(a, b) {
return isHash(a) && !isHash(b) ? 1 : a - b;
}
/**
* Parses each of the fields in a cron expression. The expression must
* include the seconds field, the year field is optional.
*
* @param {String} expr: The cron expression to parse
*/
function parseExpr(expr) {
var schedule = {
schedules: [{}],
exceptions: []
};
var components = expr.replace(/(\s)+/g, ' ').split(' ');
var field;
var f;
var component;
var items;
for (field in FIELDS) {
f = FIELDS[field];
component = components[f[0]];
if (component && component !== '*' && component !== '?') {
// need to sort so that any #'s come last, otherwise
// schedule clones to handle # won't contain all of the
// other constraints
items = component.split(',').sort(itemSorter);
var i = void 0;
var length = items.length;
for (i = 0; i < length; i++) {
parse(items[i], schedule, field, f[1], f[2], f[3]);
}
}
}
return schedule;
}
/**
* Make cron expression parsable.
*
* @param {String} expr: The cron expression to prepare
*/
function prepareExpr(expr) {
var prepared = expr.toUpperCase();
return REPLACEMENTS[prepared] || prepared;
}
function parseCron(expr, hasSeconds) {
var e = prepareExpr(expr);
return parseExpr(hasSeconds ? e : '0 ' + e);
}
var schedule = parseCron(cronspec, withSeconds);
function absFloor(number) {
if (number < 0) {
return Math.ceil(number);
} else {
return Math.floor(number);
}
}
function toInt(argumentForCoercion) {
var coercedNumber = +argumentForCoercion;
var value = 0;
if (coercedNumber !== 0 && isFinite(coercedNumber)) {
value = absFloor(coercedNumber);
}
return value;
}
function ordinal(number) {
var b = number % 10,
output = toInt(number % 100 / 10) === 1 ? locale.ORDINALS.th : b === 1 ? locale.ORDINALS.st : b === 2 ? locale.ORDINALS.nd : b === 3 ? locale.ORDINALS.rd : locale.ORDINALS.th;
return number + output;
}
/**
* For an array of numbers, e.g. a list of hours in a schedule,
* return a string listing out all of the values (complete with
* "and" plus ordinal text on the last item).
* @param {Number[]} numbers
* @returns {string}
*/
function numberList(numbers) {
if (numbers.length < 2) {
return ordinal(numbers);
}
var lastVal = numbers.pop();
return numbers.join(', ') + ' ' + locale['and'] + ' ' + ordinal(lastVal);
}
/**
* Parse a number into day of week, or a month name;
* used in dateList below.
* @param {Number|String} value
* @param {String} type
* @returns {String}
*/
function numberToDateName(value, type) {
if (type === 'dow') {
return locale.DOW[value - 1];
} else if (type === 'mon') {
return locale.MONTH[value - 1];
}
}
/**
* From an array of numbers corresponding to dates (given in type: either
* days of the week, or months), return a string listing all the values.
* @param {Number[]} numbers
* @param {String} type
* @returns {String}
*/
function dateList(numbers, type) {
if (numbers.length < 2) {
return numberToDateName('' + numbers[0], type);
}
var lastVal = '' + numbers.pop();
var outputText = '';
for (var i = 0, value; value = numbers[i]; i++) {
if (outputText.length > 0) {
outputText += ', ';
}
outputText += numberToDateName(value, type);
}
return outputText + ' ' + locale['and'] + ' ' + numberToDateName(lastVal, type);
}
/**
* Pad to equivalent of sprintf('%02d').
* @param {Number} x
* @returns {string}
*/
function zeroPad(x) {
return x < 10 ? '0' + x : x;
} //----------------
/**
* Given a schedule, generate a friendly sentence description.
* @param {Object} schedule
* @param {boolean} withSeconds
* @returns {string}
*/
function scheduleToSentence(schedule, withSeconds) {
var outputText = locale.Every + ' ';
if (schedule['h'] && schedule['m'] && schedule['h'].length <= 2 && schedule['m'].length <= 2 && withSeconds && schedule['s'] && schedule['s'].length <= 2) {
// If there are only one or two specified values for
// hour or minute, print them in HH:MM:SS format
var hm = [];
for (var i = 0; i < schedule['h'].length; i++) {
for (var j = 0; j < schedule['m'].length; j++) {
for (var k = 0; k < schedule['s'].length; k++) {
hm.push(zeroPad(schedule['h'][i]) + ':' + zeroPad(schedule['m'][j]) + ':' + zeroPad(schedule['s'][k]));
}
}
}
if (hm.length < 2) {
outputText = locale['At'] + ' ' + hm[0];
} else {
var lastVal = hm.pop();
outputText = locale['At'] + ' ' + hm.join(', ') + ' ' + locale.and + ' ' + lastVal;
}
if (!schedule['d'] && !schedule['D']) {
outputText += ' ' + locale['every day'] + ' ';
}
} else if (schedule['h'] && schedule['m'] && schedule['h'].length <= 2 && schedule['m'].length <= 2) {
// If there are only one or two specified values for
// hour or minute, print them in HH:MM format
var _hm = [];
for (var _i = 0; _i < schedule['h'].length; _i++) {
for (var _j = 0; _j < schedule['m'].length; _j++) {
_hm.push(zeroPad(schedule['h'][_i]) + ':' + zeroPad(schedule['m'][_j]));
}
}
if (_hm.length < 2) {
outputText = locale['At'] + ' ' + _hm[0];
} else {
var _lastVal = _hm.pop();
outputText = locale['At'] + ' ' + _hm.join(', ') + ' ' + locale.and + ' ' + _lastVal;
}
if (!schedule['d'] && !schedule['D']) {
outputText += ' ' + locale['every day'] + ' ';
}
} else {
// Otherwise, list out every specified hour/minute value.
if (schedule['h']) {
// runs only at specific hours
if (schedule['m']) {
// and only at specific minutes
if (withSeconds) {
if (!schedule['s'] || schedule['s'].length === 60) {
outputText += locale['second of every'] + ' ' + numberList(schedule['m']) + ' ' + locale['minute past the'] + ' ' + numberList(schedule['h']) + ' ' + locale['hour'];
} else {
outputText += numberList(schedule['s']) + ' ' + locale['second of every'] + ' ' + numberList(schedule['m']) + ' ' + locale['minute past the'] + ' ' + numberList(schedule['h']) + ' ' + locale['hour'];
}
} else {
outputText += numberList(schedule['m']) + ' ' + locale['minute past the'] + ' ' + numberList(schedule['h']) + ' ' + locale['hour'];
}
} else {
// specific hours, but every minute
if (withSeconds) {
if (!schedule['s'] || schedule['s'].length === 60) {
outputText += locale['second of every'] + ' ' + locale['minute of'] + ' ' + numberList(schedule['h']) + ' ' + locale['hour'];
} else {
outputText += numberList(schedule['s']) + ' ' + locale['second of every'] + ' ' + locale['minute of'] + ' ' + numberList(schedule['h']) + ' ' + locale['hour'];
}
} else {
outputText += locale['minute of'] + ' ' + numberList(schedule['h']) + ' ' + locale['hour'];
}
}
} else if (schedule['m']) {
// every hour, but specific minutes
if (withSeconds) {
if (!schedule['s'] || schedule['s'].length === 60) {
outputText += locale['second of every'] + ' ' + numberList(schedule['m']) + ' ' + locale['minute every hour'];
} else {
outputText += numberList(schedule['s']) + ' ' + locale['second of every'] + ' ' + numberList(schedule['m']) + ' ' + locale['minute every hour'];
}
} else {
outputText += numberList(schedule['m']) + ' ' + locale['minute every hour'];
}
} else if (withSeconds) {
if (!schedule['s'] || schedule['s'].length === 60) {
outputText += locale['second'];
} else {
outputText += numberList(schedule['s']) + ' ' + locale['second'];
}
} else {
// cronspec has "*" for both hour and minute
outputText += locale['minute'];
}
}
if (schedule['D']) {
// runs only on specific day(s) of month
outputText += (locale['on the'] ? ' ' + locale['on the'] + ' ' : ' ') + numberList(schedule['D']);
if (!schedule['M']) {
outputText += ' ' + locale['of every month'];
}
}
if (schedule['d']) {
// runs only on specific day(s) of week
if (schedule['D']) {
// if both day fields are specified, cron uses both; superuser.com/a/348372
outputText += ' ' + locale['and every'] + ' ';
} else {
outputText += ' ' + locale['on'] + ' ';
}
outputText += dateList(schedule['d'], 'dow');
}
if (schedule['M']) {
// runs only in specific months; put this output last
outputText += ' ' + locale['in'] + ' ' + dateList(schedule['M'], 'mon');
}
return outputText;
}
return scheduleToSentence(schedule.schedules[0], withSeconds);
}
var _default = cronToText;
exports["default"] = _default;
//# sourceMappingURL=cron2text.js.map
;