{"version":3,"sources":["../../src/util/array.ts","../../src/util/date.ts"],"sourcesContent":["export const equalSizeGroups = <T >(array: T[], groupSize: number): T[][] => {\n  if (groupSize <= 0) {\n    console.warn(`group size should be greater than 0: groupSize = ${groupSize}`)\n    return [[...array]]\n  }\n\n  const groups = []\n  for (let i = 0; i < array.length; i += groupSize) {\n    groups.push(array.slice(i, Math.min(i + groupSize, array.length)))\n  }\n  return groups\n}\n\n/**\n * @param start\n * @param end inclusive\n * @param allowEmptyRange Whether the range can be defined empty via end < start\n */\nexport const range = (start: number, end: number, allowEmptyRange: boolean = false): number[] => {\n  if (end < start) {\n    if (!allowEmptyRange) {\n      console.warn(`range: end (${end}) < start (${start}) should be allowed explicitly, set allowEmptyRange to true`)\n    }\n    return []\n  }\n  return Array.from({ length: end - start + 1 }, (_, index) => index + start)\n}\n\n/** Finds the closest match\n * @param list The list of all possible matches\n * @param firstCloser Return whether item1 is closer than item2\n */\nexport const closestMatch = <T >(list: T[], firstCloser: (item1: T, item2: T) => boolean) => {\n  return list.reduce((item1, item2) => {\n    return firstCloser(item1, item2) ? item1 : item2\n  })\n}\n\n/**\n * returns the item in middle of a list and its neighbours before and after\n * e.g. [1,2,3,4,5,6] for item = 1 would return [5,6,1,2,3]\n */\nexport const getNeighbours = <T >(list: T[], item: T, neighbourDistance: number = 2) => {\n  const index = list.indexOf(item)\n  const totalItems = neighbourDistance * 2 + 1\n  if (list.length < totalItems) {\n    console.warn('List is to short')\n    return list\n  }\n\n  if (index === -1) {\n    console.error('item not found in list')\n    return list.splice(0, totalItems)\n  }\n\n  let start = index - neighbourDistance\n  if (start < 0) {\n    start += list.length\n  }\n  const end = (index + neighbourDistance + 1) % list.length\n\n  const result: T[] = []\n  let ignoreOnce = list.length === totalItems\n  for (let i = start; i !== end || ignoreOnce; i = (i + 1) % list.length) {\n    result.push(list[i]!)\n    if (end === i && ignoreOnce) {\n      ignoreOnce = false\n    }\n  }\n  return result\n}\n\nexport const createLoopingListWithIndex = <T >(list: T[], startIndex: number = 0, length: number = 0, forwards: boolean = true) => {\n  if (length < 0) {\n    console.warn(`createLoopingList: length must be >= 0, given ${length}`)\n  } else if (length === 0) {\n    length = list.length\n  }\n\n  const returnList: [number, T][] = []\n\n  if (forwards) {\n    for (let i = startIndex; returnList.length < length; i = (i + 1) % list.length) {\n      returnList.push([i, list[i]!])\n    }\n  } else {\n    for (let i = startIndex; returnList.length < length; i = i === 0 ? i = list.length - 1 : i - 1) {\n      returnList.push([i, list[i]!])\n    }\n  }\n\n  return returnList\n}\n\nexport const createLoopingList = <T >(list: T[], startIndex: number = 0, length: number = 0, forwards: boolean = true) => {\n  return createLoopingListWithIndex(list, startIndex, length, forwards).map(([_, item]) => item)\n}\n\nexport const ArrayUtil = {\n  unique: <T>(list: T[]): T[] => {\n    const seen = new Set<T>()\n    return list.filter((item) => {\n      if (seen.has(item)) {\n        return false\n      }\n      seen.add(item)\n      return true\n    })\n  },\n\n  difference: <T>(list: T[], removeList: T[]): T[] => {\n    const remove = new Set<T>(removeList)\n    return list.filter((item) => !remove.has(item))\n  }\n}\n","import { equalSizeGroups } from './array'\n\nexport const monthsList = ['january', 'february', 'march', 'april', 'may', 'june', 'july', 'august', 'september', 'october', 'november', 'december'] as const\nexport type Month = typeof monthsList[number]\n\nexport const weekDayList = ['sunday', 'monday', 'tuesday', 'wednesday', 'thursday', 'friday', 'saturday'] as const\nexport type WeekDay = typeof weekDayList[number]\n\nexport const formatDate = (date: Date) => {\n  const year = date.getFullYear().toString().padStart(4, '0')\n  const month = (date.getMonth() + 1).toString().padStart(2, '0')\n  const day = (date.getDate()).toString().padStart(2, '0')\n  return `${year}-${month}-${day}`\n}\n\nexport const formatDateTime = (date: Date) => {\n  const dateString = formatDate(date)\n  const hours = date.getHours().toString().padStart(2, '0')\n  const minutes = date.getMinutes().toString().padStart(2, '0')\n  return `${dateString}T${hours}:${minutes}`\n}\n\nexport const getDaysInMonth = (year: number, month: number): number => {\n  const lastDayOfMonth = new Date(year, month + 1, 0)\n  return lastDayOfMonth.getDate()\n}\n\nexport type Duration = {\n  years?: number,\n  months?: number,\n  days?: number,\n  hours?: number,\n  minutes?: number,\n  seconds?: number,\n  milliseconds?: number,\n}\n\nexport const changeDuration = (date: Date, duration: Duration, isAdding?: boolean): Date => {\n  const {\n    years = 0,\n    months = 0,\n    days = 0,\n    hours = 0,\n    minutes = 0,\n    seconds = 0,\n    milliseconds = 0,\n  } = duration\n\n  // Check ranges\n  if (years < 0) {\n    console.error(`Range error years must be greater than 0: received ${years}`)\n    return new Date(date)\n  }\n  if (months < 0 || months > 11) {\n    console.error(`Range error month must be 0 <= month <= 11: received ${months}`)\n    return new Date(date)\n  }\n  if (days < 0) {\n    console.error(`Range error days must be greater than 0: received ${days}`)\n    return new Date(date)\n  }\n  if (hours < 0 || hours > 23) {\n    console.error(`Range error hours must be 0 <= hours <= 23: received ${hours}`)\n    return new Date(date)\n  }\n  if (minutes < 0 || minutes > 59) {\n    console.error(`Range error minutes must be 0 <= minutes <= 59: received ${minutes}`)\n    return new Date(date)\n  }\n  if (seconds < 0 || seconds > 59) {\n    console.error(`Range error seconds must be 0 <= seconds <= 59: received ${seconds}`)\n    return new Date(date)\n  }\n  if (milliseconds < 0) {\n    console.error(`Range error seconds must be greater than 0: received ${milliseconds}`)\n    return new Date(date)\n  }\n\n  const multiplier = isAdding ? 1 : -1\n\n  const newDate = new Date(date)\n\n  newDate.setFullYear(newDate.getFullYear() + multiplier * years)\n\n  newDate.setMonth(newDate.getMonth() + multiplier * months)\n\n  newDate.setDate(newDate.getDate() + multiplier * days)\n\n  newDate.setHours(newDate.getHours() + multiplier * hours)\n\n  newDate.setMinutes(newDate.getMinutes() + multiplier * minutes)\n\n  newDate.setSeconds(newDate.getSeconds() + multiplier * seconds)\n\n  newDate.setMilliseconds(newDate.getMilliseconds() + multiplier * milliseconds)\n\n  return newDate\n}\n\nexport const addDuration = (date: Date, duration: Duration): Date => {\n  return changeDuration(date, duration, true)\n}\n\nexport const subtractDuration = (date: Date, duration: Duration): Date => {\n  return changeDuration(date, duration, false)\n}\n\nexport const getBetweenDuration = (startDate: Date, endDate: Date): Duration => {\n  const durationInMilliseconds = endDate.getTime() - startDate.getTime()\n\n  const millisecondsInSecond = 1000\n  const millisecondsInMinute = 60 * millisecondsInSecond\n  const millisecondsInHour = 60 * millisecondsInMinute\n  const millisecondsInDay = 24 * millisecondsInHour\n  const millisecondsInMonth = 30 * millisecondsInDay // Rough estimation, can be adjusted\n\n  const years = Math.floor(durationInMilliseconds / (365.25 * millisecondsInDay))\n  const months = Math.floor(durationInMilliseconds / millisecondsInMonth)\n  const days = Math.floor(durationInMilliseconds / millisecondsInDay)\n  const hours = Math.floor((durationInMilliseconds % millisecondsInDay) / millisecondsInHour)\n  const seconds = Math.floor((durationInMilliseconds % millisecondsInHour) / millisecondsInSecond)\n  const milliseconds = durationInMilliseconds % millisecondsInSecond\n\n  return {\n    years,\n    months,\n    days,\n    hours,\n    seconds,\n    milliseconds,\n  }\n}\n\n/** Checks if a given date is in the range of two dates\n *\n * An undefined value for startDate or endDate means no bound for the start or end respectively\n */\nexport const isInTimeSpan = (value: Date, startDate?: Date, endDate?: Date): boolean => {\n  if(startDate && endDate) {\n    console.assert(startDate <= endDate)\n    return startDate <= value && value <= endDate\n  } else if (startDate) {\n    return startDate <= value\n  } else if(endDate) {\n    return endDate >= value\n  } else {\n    return true\n  }\n}\n\n/** Compare two dates on the year, month, day */\nexport const equalDate = (date1: Date, date2: Date) => {\n  return date1.getFullYear() === date2.getFullYear()\n    && date1.getMonth() === date2.getMonth()\n    && date1.getDate() === date2.getDate()\n}\n\nexport const getWeeksForCalenderMonth = (date: Date, weekStart: WeekDay, weeks: number = 6) => {\n  const month = date.getMonth()\n  const year = date.getFullYear()\n\n  const dayList: Date[] = []\n  let currentDate = new Date(year, month, 1) // Start of month\n  const weekStartIndex = weekDayList.indexOf(weekStart)\n\n  // Move the current day to the week before\n  while (currentDate.getDay() !== weekStartIndex) {\n    currentDate = subtractDuration(currentDate, { days: 1 })\n  }\n\n  while (dayList.length < 7 * weeks) {\n    const date = new Date(currentDate)\n    date.setHours(date.getHours(), date.getMinutes()) // To make sure we are not overwriting the time\n    dayList.push(date)\n    currentDate = addDuration(currentDate, { days: 1 })\n  }\n\n  // weeks\n  return equalSizeGroups(dayList, 7)\n}\n"],"mappings":"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","names":["date"]}