UNPKG

@kermank/slots

Version:

A TypeScript library for handling time slots, scheduling, and timezone operations

93 lines (92 loc) 3.48 kB
"use strict"; 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; }