react-js-cron-mui
Version:
A React cron editor with Material UI a forked repo from Xavier Rutayisire (https://github.com/xrutayisire/react-js-cron)
301 lines • 9.63 kB
JavaScript
import { UNITS, SUPPORTED_SHORTCUTS } from './constants';
import { range, sort, dedup, setError } from './utils';
export function setValuesFromCronString(cronString, setInternalError, onError, allowEmpty, internalValueRef, firstRender, locale, shortcuts, setMinutes, setHours, setMonthDays, setMonths, setWeekDays, setPeriod) {
onError && onError(undefined);
setInternalError(false);
let error = false;
if (!cronString) {
if (allowEmpty === 'always' || firstRender && allowEmpty === 'for-default-value') {
return;
}
error = true;
}
if (!error) {
if (shortcuts && (shortcuts === true || shortcuts.includes(cronString))) {
if (cronString === '@reboot') {
setPeriod('reboot');
return;
}
const shortcutObject = SUPPORTED_SHORTCUTS.find(supportedShortcut => supportedShortcut.name === cronString);
if (shortcutObject) {
cronString = shortcutObject.value;
}
}
try {
const cronParts = parseCronString(cronString);
const period = getPeriodFromCronparts(cronParts);
setPeriod(period);
setMinutes(cronParts[0]);
setHours(cronParts[1]);
setMonthDays(cronParts[2]);
setMonths(cronParts[3]);
setWeekDays(cronParts[4]);
} catch (err) {
error = true;
}
}
if (error) {
internalValueRef.current = cronString;
setInternalError(true);
setError(onError, locale);
}
}
export function getCronStringFromValues(period, months, monthDays, weekDays, hours, minutes, humanizeValue, useCronIntervals) {
if (period === 'reboot') {
return '@reboot';
}
const newMonths = period === 'year' && months ? months : [];
const newMonthDays = (period === 'year' || period === 'month') && monthDays ? monthDays : [];
const newWeekDays = (period === 'year' || period === 'month' || period === 'week') && weekDays ? weekDays : [];
const newHours = period !== 'minute' && period !== 'hour' && hours ? hours : [];
const newMinutes = period !== 'minute' && minutes ? minutes : [];
const parsedArray = parseCronArray([newMinutes, newHours, newMonthDays, newMonths, newWeekDays], humanizeValue, useCronIntervals);
return cronToString(parsedArray);
}
export function partToString(cronPart, unit, humanize, useCronIntervals, leadingZero, clockFormat) {
let retval = '';
if (isFull(cronPart, unit) || cronPart.length === 0) {
retval = '*';
} else {
const step = getStep(cronPart);
if (useCronIntervals && step && isInterval(cronPart, step)) {
if (isFullInterval(cronPart, unit, step)) {
retval = `*/${step}`;
} else {
retval = `${formatValue(getMin(cronPart), unit, humanize, leadingZero, clockFormat)}-${formatValue(getMax(cronPart), unit, humanize, leadingZero, clockFormat)}/${step}`;
}
} else {
retval = toRanges(cronPart).map(range => {
if (Array.isArray(range)) {
return `${formatValue(range[0], unit, humanize, leadingZero, clockFormat)}-${formatValue(range[1], unit, humanize, leadingZero, clockFormat)}`;
}
return formatValue(range, unit, humanize, leadingZero, clockFormat);
}).join(',');
}
}
return retval;
}
export function formatValue(value, unit, humanize, leadingZero, clockFormat) {
let cronPartString = value.toString();
const {
type,
alt,
min
} = unit;
const needLeadingZero = leadingZero && (leadingZero === true || leadingZero.includes(type));
const need24HourClock = clockFormat === '24-hour-clock' && (type === 'hours' || type === 'minutes');
if (humanize && type === 'week-days' || humanize && type === 'months') {
cronPartString = alt[value - min];
} else if (value < 10 && (needLeadingZero || need24HourClock)) {
cronPartString = cronPartString.padStart(2, '0');
}
if (type === 'hours' && clockFormat === '12-hour-clock') {
const suffix = value >= 12 ? 'PM' : 'AM';
let hour = value % 12 || 12;
if (hour < 10 && needLeadingZero) {
hour = hour.toString().padStart(2, '0');
}
cronPartString = `${hour}${suffix}`;
}
return cronPartString;
}
function parseCronArray(cronArr, humanizeValue, useCronIntervals) {
if (cronArr.length === 5) {
return cronArr.map((partArr, idx) => {
const unit = UNITS[idx];
const parsedArray = parsePartArray(partArr, unit);
return partToString(parsedArray, unit, humanizeValue, useCronIntervals);
});
}
throw new Error('Invalid cron array');
}
function cronToString(parts) {
return parts.join(' ');
}
function getPeriodFromCronparts(cronParts) {
if (cronParts[3].length > 0) {
return 'year';
} else if (cronParts[2].length > 0) {
return 'month';
} else if (cronParts[4].length > 0) {
return 'week';
} else if (cronParts[1].length > 0) {
return 'day';
} else if (cronParts[0].length > 0) {
return 'hour';
}
return 'minute';
}
function parseCronString(str) {
if (typeof str !== 'string') {
throw new Error('Invalid cron string');
}
const parts = str.replace(/\s+/g, ' ').trim().split(' ');
if (parts.length === 5) {
return parts.map((partStr, idx) => {
return parsePartString(partStr, UNITS[idx]);
});
}
throw new Error('Invalid cron string format');
}
function parsePartString(str, unit) {
if (str === '*' || str === '*/1') {
return [];
}
const stringParts = str.split('/');
if (stringParts.length > 2) {
throw new Error(`Invalid value "${unit.type}"`);
}
const rangeString = replaceAlternatives(stringParts[0], unit.min, unit.alt);
let parsedValues;
if (rangeString === '*') {
parsedValues = range(unit.min, unit.max);
} else {
parsedValues = sort(dedup(fixSunday(rangeString.split(',').map(range => {
return parseRange(range, str, unit);
}).flat(), unit)));
const value = outOfRange(parsedValues, unit);
if (typeof value !== 'undefined') {
throw new Error(`Value "${value}" out of range for ${unit.type}`);
}
}
const step = parseStep(stringParts[1], unit);
const intervalValues = applyInterval(parsedValues, step);
if (intervalValues.length === unit.total) {
return [];
} else if (intervalValues.length === 0) {
throw new Error(`Empty interval value "${str}" for ${unit.type}`);
}
return intervalValues;
}
function replaceAlternatives(str, min, alt) {
if (alt) {
str = str.toUpperCase();
for (let i = 0; i < alt.length; i++) {
str = str.replace(alt[i], `${i + min}`);
}
}
return str;
}
function fixSunday(values, unit) {
if (unit.type === 'week-days') {
values = values.map(function (value) {
if (value === 7) {
return 0;
}
return value;
});
}
return values;
}
function parseRange(rangeStr, context, unit) {
const subparts = rangeStr.split('-');
if (subparts.length === 1) {
const value = parseInt(subparts[0], 10);
if (isNaN(value)) {
throw new Error(`Invalid value "${context}" for ${unit.type}`);
}
return [value];
} else if (subparts.length === 2) {
const minValue = parseInt(subparts[0], 10);
const maxValue = parseInt(subparts[1], 10);
if (maxValue <= minValue) {
throw new Error(`Max range is less than min range in "${rangeStr}" for ${unit.type}`);
}
return range(minValue, maxValue);
} else {
throw new Error(`Invalid value "${rangeStr}" for ${unit.type}`);
}
}
function outOfRange(values, unit) {
const first = values[0];
const last = values[values.length - 1];
if (first < unit.min) {
return first;
} else if (last > unit.max) {
return last;
}
return;
}
function parseStep(step, unit) {
if (typeof step !== 'undefined') {
const parsedStep = parseInt(step, 10);
if (isNaN(parsedStep) || parsedStep < 1) {
throw new Error(`Invalid interval step value "${step}" for ${unit.type}`);
}
return parsedStep;
}
}
function applyInterval(values, step) {
if (step) {
const minVal = values[0];
values = values.filter(value => {
return value % step === minVal % step || value === minVal;
});
}
return values;
}
export function parsePartArray(arr, unit) {
const values = sort(dedup(fixSunday(arr, unit)));
if (values.length === 0) {
return values;
}
const value = outOfRange(values, unit);
if (typeof value !== 'undefined') {
throw new Error(`Value "${value}" out of range for ${unit.type}`);
}
return values;
}
function isFull(values, unit) {
return values.length === unit.max - unit.min + 1;
}
function getStep(values) {
if (values.length > 2) {
const step = values[1] - values[0];
if (step > 1) {
return step;
}
}
}
function isInterval(values, step) {
for (let i = 1; i < values.length; i++) {
const prev = values[i - 1];
const value = values[i];
if (value - prev !== step) {
return false;
}
}
return true;
}
function isFullInterval(values, unit, step) {
const min = getMin(values);
const max = getMax(values);
const haveAllValues = values.length === (max - min) / step + 1;
if (min === unit.min && max + step > unit.max && haveAllValues) {
return true;
}
return false;
}
function getMin(values) {
return values[0];
}
function getMax(values) {
return values[values.length - 1];
}
function toRanges(values) {
const retval = [];
let startPart = null;
values.forEach((value, index, self) => {
if (value !== self[index + 1] - 1) {
if (startPart !== null) {
retval.push([startPart, value]);
startPart = null;
} else {
retval.push(value);
}
} else if (startPart === null) {
startPart = value;
}
});
return retval;
}