UNPKG

ok-tools

Version:

My personal JS tools and utilities

354 lines 11.6 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.processHours = exports.formatWeek = exports.formatDay = exports.formatInterval = exports.formatHour = exports.parseHour = exports.parseInterval = exports.parseDay = exports.parseWeek = exports.OpeningHoursStatus = void 0; var OpeningHoursStatus; (function (OpeningHoursStatus) { OpeningHoursStatus[OpeningHoursStatus["CLOSED"] = 0] = "CLOSED"; OpeningHoursStatus[OpeningHoursStatus["OPEN"] = 1] = "OPEN"; })(OpeningHoursStatus = exports.OpeningHoursStatus || (exports.OpeningHoursStatus = {})); function parseWeek(input, returnNullIfEmpty) { if (returnNullIfEmpty === void 0) { returnNullIfEmpty = false; } var r = { 1: [], 2: [], 3: [], 4: [], 5: [], 6: [], 7: [], }; if (Array.isArray(input) && !(input.length === 8 && !input[0] && (input[7] || input[7] === ''))) { for (var i = 6; i >= 0; i--) { input[i + 1] = input[i]; } delete input[0]; } var isAnything = false; for (var i = 1; i <= 7; i++) { // @ts-ignore r[i] = parseDay(input[i]); // @ts-ignore if (r[i].length > 0) { isAnything = true; } } if (!isAnything && returnNullIfEmpty) { return null; } return r; } exports.parseWeek = parseWeek; function parseDay(input) { if (!input) { return []; } var intervals = input.split(/[,;]+/).filter(function (r) { return !!r; }); var ints = intervals.map(function (i) { var r; try { r = parseInterval(i); return r; } catch (e) { return null; } }).filter(function (r) { return !!r; }); ints.sort(function (i1, i2) { return i1.open - i2.open; }); ints = filterIntervalsForOverlapping(ints); return ints; } exports.parseDay = parseDay; function filterIntervalsForOverlapping(ints, recursiveFailsafe) { if (recursiveFailsafe === void 0) { recursiveFailsafe = 0; } if (recursiveFailsafe > 10) { throw new Error('Could not resolve overlapping intervals: ' + JSON.stringify(ints)); } // Check for interlapping intervals and merge them if necessary var omitIntervalsWithTheseIndices = {}; ints.forEach(function (thisInterval, index) { var nextInterval = ints[index + 1]; if (!nextInterval) { return; } if (omitIntervalsWithTheseIndices[index]) { return; } // Intervals are adjacent - we just merge them if (thisInterval.close === nextInterval.open) { thisInterval.close = nextInterval.close; omitIntervalsWithTheseIndices[index + 1] = true; return; } // Next is contained inside this one - we just omit the inner one if (thisInterval.open <= nextInterval.open && thisInterval.close >= nextInterval.close) { omitIntervalsWithTheseIndices[index + 1] = true; return; } // Next is extending this one - we move ending time to the latter one if (nextInterval.open <= thisInterval.close && nextInterval.close >= thisInterval.close) { thisInterval.close = nextInterval.close; omitIntervalsWithTheseIndices[index + 1] = true; return; } }); // if (Object.keys(omitIntervalsWithTheseIndices).length > 0) { // console.log('This failed check: ', ints, omitIntervalsWithTheseIndices); // } ints = ints.filter(function (interval, index) { return !omitIntervalsWithTheseIndices[index]; }); if (Object.keys(omitIntervalsWithTheseIndices).length > 0) { ints = filterIntervalsForOverlapping(ints, recursiveFailsafe + 1); } return ints; } function parseInterval(input) { if (!input) { return null; } var parts = input.trim().split(/[\s-]+/).filter(function (r) { return !!r; }); if (parts.length === 2) { var p = { open: parseHour(parts[0]), close: parseHour(parts[1]), }; if (p.open === p.close) { throw new Error('Interval is meaningless - ' + input); } if (p.open > p.close) { p.close += 24; } return p; } throw new Error('Can not parse interval: ' + input); } exports.parseInterval = parseInterval; function parseHour(input) { var parts = input.trim().split(/[:\.]+/).filter(function (r) { return !!r; }); if (parts.length === 2) { var hour = clamp(parseInt(parts[0], 10), 0, 24); var minute = clamp(parseInt(parts[1], 10), 0, 60); if (isNaN(hour) || isNaN(minute)) { throw new Error('Can not parse hour'); } if (minute >= 60) { minute = 0; hour++; } if (hour === 24) { minute = 0; } return hour + (minute / 60); } if (parts.length === 1) { var t = parseInt(parts[0], 10); if (isNaN(t)) { throw new Error('Can not parse hour: ' + input); } return clamp(t, 0, 24); } throw new Error('Can not parse hour: ' + input); } exports.parseHour = parseHour; function formatHour(input) { var fixedInput = input; if (fixedInput > 24) { fixedInput -= 24; } if (fixedInput > 24) { throw new Error('Invalid input time - ' + input); } var hour = Math.floor(fixedInput); var hourString = hour + ''; if (hour < 10) { if (!hour) { hourString = '00'; } else { hourString = '0' + hourString; } } var minutes = Math.round((fixedInput - hour) * 60); var minutesString = minutes + ''; if (minutes < 10) { if (!minutes) { minutesString = '00'; } else { minutesString = '0' + minutesString; } } return hourString + ':' + minutesString; } exports.formatHour = formatHour; function formatInterval(input) { return formatHour(input.open) + ' - ' + formatHour(input.close); } exports.formatInterval = formatInterval; function formatDay(input) { return input.map(function (r) { return formatInterval(r); }).join(', '); } exports.formatDay = formatDay; function formatWeek(input, now) { if (now === void 0) { now = null; } if (!now) { now = new Date(); } var day = now.getDay(); if (!day) { day = 7; } var result = []; var currentRow = null; for (var i = 1; i <= 7; i++) { // @ts-ignore var theDay = input[i]; var thisDayFormatted = formatDay(theDay); if (!currentRow || thisDayFormatted !== currentRow.hours) { if (currentRow) { result.push(currentRow); } currentRow = { dayFrom: i, dayTo: i, isSingleDay: true, hours: thisDayFormatted, isCurrent: false, isOpen: !!thisDayFormatted, }; } else if (currentRow) { currentRow.isSingleDay = false; currentRow.dayTo = i; } } if (currentRow) { result.push(currentRow); } result.map(function (row) { if (row.dayFrom <= day && row.dayTo >= day) { row.isCurrent = true; } }); return result; } exports.formatWeek = formatWeek; function processHours(hours, now) { if (now === void 0) { now = null; } if (!now) { now = new Date(); } var day = now.getDay(); if (!day) { day = 7; } // @ts-ignore var todayRules = hours[day]; // @ts-ignore var yesterdayRules = day === 1 ? hours[7] : hours[day - 1]; var thisTime = now.getHours() + now.getMinutes() / 60; var isOpen = false; var nextChange = null; var nextChangeDay = null; var nextChangeIsOpening = null; var nextChangeIsToday = false; var nextChangeIsTomorrow = false; // Standard scenario - today is just open or we open this day later for (var _i = 0, todayRules_1 = todayRules; _i < todayRules_1.length; _i++) { var interval = todayRules_1[_i]; if (interval.open <= thisTime && interval.close >= thisTime) { isOpen = true; nextChangeIsOpening = false; nextChange = interval.close; nextChangeDay = day; nextChangeIsToday = true; } else if (interval.open > thisTime) { if (nextChange === null) { nextChangeIsOpening = true; nextChange = interval.open; nextChangeIsToday = true; nextChangeDay = day; } } } // Special scenario - we opened yesterday and still are open if (!nextChange !== null && yesterdayRules.length) { var thisTimeOverlapped = thisTime + 24; for (var _a = 0, yesterdayRules_1 = yesterdayRules; _a < yesterdayRules_1.length; _a++) { var interval = yesterdayRules_1[_a]; if (interval.open <= thisTimeOverlapped && interval.close >= thisTimeOverlapped) { isOpen = true; nextChangeIsOpening = false; nextChange = interval.close - 24; nextChangeDay = day; nextChangeIsToday = true; } } } // Special scenario - we are open and we close tomorrow if (nextChange && nextChange > 24) { nextChange -= 24; if (!nextChangeDay) { nextChangeDay = 0; } nextChangeDay += 1; nextChangeIsToday = false; nextChangeIsTomorrow = true; if (nextChangeDay > 7) { nextChangeDay -= 7; } } // Standard scenario - we open tomorrow or some later day if (nextChange === null) { var followingDays = []; var tomorrow = day + 1; if (tomorrow >= 8) { tomorrow = 1; } for (var i = day + 1; i <= 7; i++) { followingDays.push(i); } for (var i = 1; i < day; i++) { followingDays.push(i); } for (var _b = 0, followingDays_1 = followingDays; _b < followingDays_1.length; _b++) { var nextDay = followingDays_1[_b]; if (nextChange !== null) { break; } // @ts-ignore for (var _c = 0, _d = hours[nextDay]; _c < _d.length; _c++) { var interval = _d[_c]; if (nextChange !== null) { break; } if (interval.open) { nextChange = interval.open; nextChangeIsOpening = true; nextChangeIsTomorrow = (nextDay === tomorrow); nextChangeDay = nextDay; } } } } return { currentStatus: isOpen ? OpeningHoursStatus.OPEN : OpeningHoursStatus.CLOSED, nextStatus: nextChangeIsOpening ? OpeningHoursStatus.OPEN : OpeningHoursStatus.CLOSED, nextChangeDay: nextChangeDay, nextChangeTime: nextChange, nextChangeIsToday: nextChangeIsToday, nextChangeIsTomorrow: nextChangeIsTomorrow, }; } exports.processHours = processHours; function clamp(n, low, high) { if (n < low) { return low; } if (n > high) { return high; } return n; } //# sourceMappingURL=opening-hours.js.map