Suite of AT Protocol TypeScript libraries built on web standards
21
fork

Configure Feed

Select the types of activity you want to include in your feed.

at main 118 lines 3.4 kB view raw
1export const SECOND = 1000; 2export const MINUTE = SECOND * 60; 3export const HOUR = MINUTE * 60; 4export const DAY = HOUR * 24; 5 6const SEPARATORS_TO_ESCAPE = new Set([ 7 "\\", 8 "^", 9 "$", 10 ".", 11 "|", 12 "?", 13 "*", 14 "+", 15 "(", 16 ")", 17 "[", 18 "]", 19 "{", 20 "}", 21]); 22 23function getStringSeparator(dateString: string): string { 24 const separator = /\D/.exec(dateString); 25 return separator ? separator[0] : ""; 26} 27 28function getTimeStringSeparator(timeString: string): string { 29 const matches = timeString.match(/([^Z+\-\d])(?=\d+\1)/); 30 return Array.isArray(matches) ? matches[0] : ""; 31} 32 33export function isValidDate(date: string, s = "-"): boolean { 34 if (SEPARATORS_TO_ESCAPE.has(s)) { 35 s = `\\${s}`; 36 } 37 38 const validator = new RegExp( 39 `^(?!0{4}${s}0{2}${s}0{2})((?=[0-9]{4}${s}(((0[^2])|1[0-2])|02(?=${s}(([0-1][0-9])|2[0-8])))${s}[0-9]{2})|(?=((([13579][26])|([2468][048])|(0[48]))0{2})|([0-9]{2}((((0|[2468])[48])|[2468][048])|([13579][26])))${s}02${s}29))([0-9]{4})${s}(?!((0[469])|11)${s}31)((0[1,3-9]|1[0-2])|(02(?!${s}3)))${s}(0[1-9]|[1-2][0-9]|3[0-1])$`, 40 ); 41 return validator.test(date); 42} 43 44function isValidTime( 45 timeWithOffset: string, 46 s = ":", 47 isTimezoneCheckOn = false, 48): boolean { 49 const validator = new RegExp( 50 `^([0-1]|2(?=([0-3])|4${s}00))[0-9]${s}[0-5][0-9](${s}([0-5]|6(?=0))[0-9])?(\.[0-9]{1,9})?$`, 51 ); 52 53 if (!isTimezoneCheckOn || !/[Z+\-]/.test(timeWithOffset)) { 54 return validator.test(timeWithOffset); 55 } 56 57 if (/Z$/.test(timeWithOffset)) { 58 return validator.test(timeWithOffset.replace("Z", "")); 59 } 60 61 const isPositiveTimezoneOffset = timeWithOffset.includes("+"); 62 const [time, offset] = timeWithOffset.split(/[+-]/); 63 64 return validator.test(time) && 65 isValidZoneOffset( 66 offset, 67 isPositiveTimezoneOffset, 68 getStringSeparator(offset), 69 ); 70} 71 72function isValidZoneOffset( 73 offset: string, 74 isPositiveOffset: boolean, 75 s = ":", 76): boolean { 77 const validator = new RegExp( 78 isPositiveOffset 79 ? `^(0(?!(2${s}4)|0${s}3)|1(?=([0-1]|2(?=${s}[04])|[34](?=${s}0))))([03469](?=${s}[03])|[17](?=${s}0)|2(?=${s}[04])|5(?=${s}[034])|8(?=${s}[04]))${s}([03](?=0)|4(?=5))[05]$` 80 : `^(0(?=[^0])|1(?=[0-2]))([39](?=${s}[03])|[0-24-8](?=${s}00))${s}[03]0$`, 81 ); 82 return validator.test(offset); 83} 84 85export function isValidISODateString(dateString: string): boolean { 86 const [date, timeWithOffset] = dateString.split("T"); 87 const dateSeparator = getStringSeparator(date); 88 const isDateValid = isValidDate(date, dateSeparator); 89 90 if (!timeWithOffset) { 91 return false; 92 } 93 94 const timeStringSeparator = getTimeStringSeparator(timeWithOffset); 95 return isDateValid && isValidTime(timeWithOffset, timeStringSeparator, true); 96} 97 98export const lessThanAgoMs = (time: Date, range: number): boolean => { 99 return Date.now() < time.getTime() + range; 100}; 101 102export const addHoursToDate = (hours: number, startingDate?: Date): Date => { 103 const currentDate = startingDate ? new Date(startingDate) : new Date(); 104 currentDate.setHours(currentDate.getHours() + hours); 105 return currentDate; 106}; 107 108export function toSimplifiedISOSafe(dateStr: string): string { 109 const date = new Date(dateStr); 110 if (isNaN(date.getTime())) { 111 return new Date(0).toISOString(); 112 } 113 const iso = date.toISOString(); 114 if (!isValidISODateString(iso)) { 115 return new Date(0).toISOString(); 116 } 117 return iso; 118}