UNPKG

@digifi/jexl-functions

Version:
296 lines (295 loc) 13.4 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); const errors_1 = require("../errors"); const dayjs_1 = __importDefault(require("../dayjs")); const module_1 = require("../utils/module"); const DEFAULT_WEEKEND_MASK = '0000011'; const WEEKEND_MASK_BY_NUMBER = { 1: DEFAULT_WEEKEND_MASK, 2: '1000001', 3: '1100000', 4: '0110000', 5: '0011000', 6: '0001100', 7: '0000110', 11: '0000001', 12: '1000000', 13: '0100000', 14: '0010000', 15: '0001000', 16: '0000100', 17: '0000010', }; exports.default = (0, module_1.createModule)(({ validateArrayLikeValueMaxSize, coerceToNumber, coerceToStringWithValidation }, options) => { const shortUnitTypeToLongUnitType = { 'M': 'months', 'D': 'days', 'Y': 'years', }; const validateWeekendMask = (weekend) => { const weekendMaskRegex = new RegExp('^[0|1]{7}$'); if (typeof weekend !== 'string') { throw new errors_1.JexlFunctionExecutionError('Weekend should be a string'); } if (!weekendMaskRegex.test(weekend)) { throw new errors_1.JexlFunctionExecutionError('Weekend string doesn\'t much patter'); } if (!weekend.includes('0')) { throw new errors_1.JexlFunctionExecutionError('At least one working day should exists'); } }; const generateHolidaysSet = (holidays) => { const holidaysSet = new Set(); for (const holiday of holidays) { const holidayDate = (0, dayjs_1.default)(holiday); if (!holidayDate.isValid()) { throw new errors_1.JexlFunctionExecutionError('Holiday date is not valid.'); } holidaysSet.add(`${holidayDate.month()}/${holidayDate.date()}/${holidayDate.year()}`); } return holidaysSet; }; const getWeekendMask = (weekend) => { if (!weekend) { return DEFAULT_WEEKEND_MASK; } if (typeof weekend === 'string') { return weekend; } if (typeof weekend !== 'number') { return weekend; } const mask = WEEKEND_MASK_BY_NUMBER[weekend]; if (!mask) { throw new errors_1.JexlFunctionExecutionError('Incorrect weekend'); } return mask; }; const WEEKNUM = (date, format) => { return (0, dayjs_1.default)(date, coerceToStringWithValidation(format) || undefined).week(); }; const YEAR = (date, format) => { return (0, dayjs_1.default)(date, coerceToStringWithValidation(format) || undefined).year(); }; const YEARFRAC = (firstDate, secondDate, basis = 0, format) => { const coercedFormat = coerceToStringWithValidation(format) || undefined; const coercedBasis = coerceToNumber(basis); const firstDateObject = (0, dayjs_1.default)(firstDate, coercedFormat); const secondDateObject = (0, dayjs_1.default)(secondDate, coercedFormat); const firstDateDay = firstDateObject.date(); const firstDateYear = firstDateObject.year(); const firstDateMonth = firstDateObject.month(); const secondDateDay = secondDateObject.date(); const secondDateYear = secondDateObject.year(); const secondDateMonth = secondDateObject.month(); switch (coercedBasis) { case 0: { const convertedFirstDateDay = firstDateDay === 31 ? 30 : firstDateDay; const convertedSecondDateDay = secondDateDay === 31 ? 30 : secondDateDay; return (convertedSecondDateDay + secondDateMonth * 30 + secondDateYear * 360 - (convertedFirstDateDay + firstDateMonth * 30 + firstDateYear * 360)) / 360; } case 1: { return secondDateObject.diff(firstDateObject, 'days') / 360; } case 2: { return secondDateObject.diff(firstDateObject, 'days') / 365; } case 3: { return (secondDateDay + secondDateMonth * 30 + secondDateYear * 360 - (firstDateDay + firstDateMonth * 30 + firstDateYear * 360)) / 360; } default: { throw new errors_1.JexlFunctionExecutionError('Incorrect basis provided.'); } } }; const NOW = (format) => { return (0, dayjs_1.default)().format(coerceToStringWithValidation(format) || undefined); }; const DATE = (year, month, day, format) => { return (0, dayjs_1.default)({ year: coerceToNumber(year), month: coerceToNumber(month) - 1, day: coerceToNumber(day), }).format(coerceToStringWithValidation(format) || undefined); }; const DAY = (date, format) => { return (0, dayjs_1.default)(date, coerceToStringWithValidation(format) || undefined).date(); }; const DAYS = (firstDate, secondDate, format) => { const coercedFormat = coerceToStringWithValidation(format) || undefined; return (0, dayjs_1.default)(firstDate, coercedFormat).diff((0, dayjs_1.default)(secondDate, coercedFormat), 'days'); }; const DATEVALUE = (date, format) => { return (0, dayjs_1.default)(date).format(coerceToStringWithValidation(format) || undefined); }; const ISOWEEKNUM = (date, format) => { const dateObject = (0, dayjs_1.default)(date, coerceToStringWithValidation(format) || undefined).startOf('date'); const yearStateDateObject = (0, dayjs_1.default)({ year: dateObject.year(), month: 0, day: 0 }); const isoDate = dateObject.add(dateObject.date() + 4 - (dateObject.day() || 7)); return Math.ceil(((isoDate.diff(yearStateDateObject, 'milliseconds')) / 86400000 + 1) / 7); }; const MONTH = (date, format) => { return (0, dayjs_1.default)(date, coerceToStringWithValidation(format) || undefined).month() + 1; }; const TODAY = (format) => { const now = (0, dayjs_1.default)(); return now .set('hour', 0) .set('minute', 0) .set('second', 0) .format(coerceToStringWithValidation(format) || undefined); }; const EOMONTH = (startDate, months, format) => { const coercedMonths = coerceToNumber(months); const flooredMonths = Math.floor(coercedMonths); const startDateObject = (0, dayjs_1.default)(startDate); if (!startDateObject.isValid()) { throw new errors_1.JexlFunctionExecutionError('Invalid start date.'); } return (0, dayjs_1.default)({ year: startDateObject.year(), month: startDateObject.month() + flooredMonths + 1, day: 0, }) .add(-1, 'day') .format(coerceToStringWithValidation(format) || undefined); }; const NETWORKDAYSINTL = (startDate, endDate, weekend, holidays = []) => { const startDateObject = (0, dayjs_1.default)(startDate); const endDateObject = (0, dayjs_1.default)(endDate); const transformedHolidays = Array.isArray(holidays) ? holidays : [holidays]; const weekendMask = getWeekendMask(weekend); validateArrayLikeValueMaxSize(holidays); validateWeekendMask(weekendMask); if (!startDateObject.isValid()) { throw new errors_1.JexlFunctionExecutionError('Start date is invalid'); } if (!endDateObject.isValid()) { throw new errors_1.JexlFunctionExecutionError('End date is invalid'); } const holidaysSet = generateHolidaysSet(transformedHolidays); const typedWeekendMask = weekendMask; const days = endDateObject.diff(startDateObject, 'days') || 1; const daysModule = Math.abs(days); let iterationDate = (0, dayjs_1.default)(startDateObject); if (days > options.maxDaysForWorkdaysFunctions) { throw new errors_1.JexlFunctionExecutionError(`Days between dates should be less than ${options.maxDaysForWorkdaysFunctions}`); } let total = days < 0 ? days - 1 : days + 1; for (let i = 0; i < daysModule; i++) { const iterationDay = iterationDate.date(); const iterationMonth = iterationDate.month(); const iterationYear = iterationDate.year(); const iterationDayOfMonth = iterationDate.day(); const weekendIndex = iterationDayOfMonth ? iterationDayOfMonth - 1 : 6; const isWorkingDay = !Number(typedWeekendMask[weekendIndex]); const isHoliday = holidaysSet.has(`${iterationMonth}/${iterationDay}/${iterationYear}`); if (!isWorkingDay || isHoliday) { total = days < 0 ? total + 1 : total - 1; } iterationDate = iterationDate.add(days < 0 ? -1 : 1, 'day'); } return total; }; const WORKDAYINTL = (startDate, days, weekend, holidays = []) => { const startDateObject = (0, dayjs_1.default)(startDate); const coercedDays = coerceToNumber(days); const transformedHolidays = Array.isArray(holidays) ? holidays : [holidays]; const weekendMask = getWeekendMask(weekend); if (coercedDays < 0) { throw new errors_1.JexlFunctionExecutionError('Days should be more than 0'); } if (coercedDays > options.maxDaysForWorkdaysFunctions) { throw new errors_1.JexlFunctionExecutionError(`Days should be less than ${options.maxDaysForWorkdaysFunctions}`); } validateWeekendMask(weekendMask); validateArrayLikeValueMaxSize(holidays); const holidaysSet = generateHolidaysSet(transformedHolidays); const typedWeekendMask = weekendMask; let workingDays = 0; let iterationDate = startDateObject; while (workingDays < coercedDays) { iterationDate = iterationDate.add(1, 'day'); const iterationDay = iterationDate.date(); const iterationMonth = iterationDate.month(); const iterationYear = iterationDate.year(); const iterationDayOfMonth = iterationDate.day(); const weekendIndex = iterationDayOfMonth ? iterationDayOfMonth - 1 : 6; const isWorkingDay = !Number(typedWeekendMask[weekendIndex]); const isHoliday = holidaysSet.has(`${iterationMonth}/${iterationDay}/${iterationYear}`); if (isWorkingDay && !isHoliday) { workingDays++; } } return iterationDate.format(); }; const EDATE = (date, months, format) => { return (0, dayjs_1.default)(date) .add(coerceToNumber(months), 'months') .format(coerceToStringWithValidation(format) || undefined); }; const DAYS360 = (startDate, endDate, method) => { const startDateObject = (0, dayjs_1.default)(startDate); const endDateObject = (0, dayjs_1.default)(endDate); const endMonth = endDateObject.month(); const startMonth = startDateObject.month(); if (method) { const endMonth = endDateObject.month(); const startMonth = startDateObject.month(); const startDay = startDateObject.date() === 31 ? 30 : startDateObject.date(); const endDay = endDateObject.date() === 31 ? 30 : endDateObject.date(); return 360 * (endDateObject.year() - startDateObject.year()) + 30 * (endMonth - startMonth) + (endDay - startDay); } const nextMonthStartDate = (0, dayjs_1.default)({ year: startDateObject.year(), month: startMonth + 1, day: 0 }) .add(-1, 'day'); const nextMonthEndDate = (0, dayjs_1.default)({ year: endDateObject.year(), month: endMonth + 1, day: 0 }) .add(-1, 'day'); const startDay = startDateObject.date() === nextMonthStartDate.date() ? 30 : startDateObject.date(); if (endDateObject.date() === nextMonthEndDate.date()) { return startDay < 30 ? 360 * (endDateObject.year() - startDateObject.year()) + 30 * (endMonth + 1 - startMonth) + (1 - startDay) : 360 * (endDateObject.year() - startDateObject.year()) + 30 * (endMonth - startMonth) + (30 - startDay); } return 360 * (endDateObject.year() - startDateObject.year()) + 30 * (endMonth - startMonth) + (endDateObject.date() - startDay); }; const DATEDIF = (startDate, endDate, unitType) => { const startDateObject = (0, dayjs_1.default)(startDate); const endDateObject = (0, dayjs_1.default)(endDate); const coercedUnitType = coerceToStringWithValidation(unitType); const longUnitType = shortUnitTypeToLongUnitType[coercedUnitType]; if (!startDateObject.isValid()) { return NaN; } if (!endDateObject.isValid()) { return NaN; } if (!longUnitType) { return NaN; } return endDateObject.diff(startDateObject, longUnitType); }; return { WEEKNUM, YEAR, YEARFRAC, NOW, DATE, DAY, DAYS, DATEVALUE, ISOWEEKNUM, MONTH, TODAY, EOMONTH, NETWORKDAYSINTL, WORKDAYINTL, EDATE, DAYS360, DATEDIF, }; }, { maxDaysForWorkdaysFunctions: 3653, });