@kermank/slots
Version:
A TypeScript library for handling time slots, scheduling, and timezone operations
93 lines (92 loc) • 3.48 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.doSlotsOverlap = doSlotsOverlap;
exports.mergeSlots = mergeSlots;
exports.mergeOverlappingSlots = mergeOverlappingSlots;
exports.generateSlots = generateSlots;
const luxon_1 = require("luxon");
const types_1 = require("../types");
/**
* Checks if two slots overlap based on the specified strategy
*/
function doSlotsOverlap(a, b, strategy = 'strict') {
// Special case: if either slot has zero duration, check if it touches the other slot
if (a.start.equals(a.end) || b.start.equals(b.end)) {
return a.start.equals(b.start) ||
a.start.equals(b.end) ||
a.end.equals(b.start) ||
a.end.equals(b.end);
}
const interval1 = luxon_1.Interval.fromDateTimes(a.start, a.end);
const interval2 = luxon_1.Interval.fromDateTimes(b.start, b.end);
if (strategy === 'strict') {
return interval1.overlaps(interval2);
}
else {
// inclusive: slots touching at boundaries are considered overlapping
return interval1.abutsStart(interval2) ||
interval1.abutsEnd(interval2) ||
interval1.overlaps(interval2);
}
}
/**
* Merges two slots and their metadata
*/
function mergeSlots(a, b, metadataMerger = types_1.defaultMetadataMerger) {
return {
start: luxon_1.DateTime.min(a.start, b.start),
end: luxon_1.DateTime.max(a.end, b.end),
metadata: metadataMerger(a.metadata, b.metadata)
};
}
/**
* Merges an array of slots, combining any that overlap based on the specified strategy
*/
function mergeOverlappingSlots(slots, metadataMerger = types_1.defaultMetadataMerger, overlapStrategy = 'strict') {
if (slots.length <= 1)
return slots;
// Sort slots by start time
const sortedSlots = [...slots].sort((a, b) => a.start.toMillis() - b.start.toMillis());
const result = [];
let i = 0;
while (i < sortedSlots.length) {
let current = sortedSlots[i];
let j = i + 1;
// Find next overlapping slot
while (j < sortedSlots.length && doSlotsOverlap(current, sortedSlots[j], overlapStrategy)) {
current = mergeSlots(current, sortedSlots[j], metadataMerger);
j++;
}
result.push(current);
i = j;
}
return result;
}
/**
* Generates an array of slots between start and end date with given duration and overlap interval
* @param startDate The start date for the first slot
* @param endDate The end date for the last slot
* @param duration Duration of each slot in milliseconds
* @param overlapInterval Interval between start of consecutive slots in milliseconds
* @param metadata Optional metadata to apply to all generated slots
* @returns Array of generated slots
*/
function generateSlots(start, end, duration, overlapInterval, metadata = {}) {
if (start >= end) {
return [];
}
if (!duration.isValid || !overlapInterval.isValid || duration.toMillis() <= 0 || overlapInterval.toMillis() <= 0) {
throw new Error('Duration and overlap interval must be positive and valid');
}
const slots = [];
let currentStart = start;
while (currentStart.plus(duration) <= end) {
slots.push({
start: currentStart,
end: currentStart.plus(duration),
metadata: { ...metadata }
});
currentStart = currentStart.plus(overlapInterval);
}
return slots;
}