import sanitizeHtml from 'sanitize-html' import { CronExpressionParser } from 'cron-parser' export function getCronDate(cronString: string, n: number) { const interval = CronExpressionParser.parse(cronString, { tz: 'UTC' }) let date = interval.next().toDate() for (let i = 0; i < Math.abs(n); i++) { if (n > 0) { date = interval.next().toDate() } else { date = interval.prev().toDate() } } return date } export function displayDuration(seconds: number) { const minute = 60 const hour = minute * 60 const day = hour * 24 const week = day * 7 const month = day * 30 const year = day * 365 if (seconds < minute) { return `${Math.round(seconds)} seconds` } else if (seconds < hour) { const minutes = Math.round(seconds / minute) return `${minutes} ${minutes === 1 ? 'minute' : 'minutes'}` } else if (seconds < day) { const hours = Math.round(seconds / hour) return `${hours} ${hours === 1 ? 'hour' : 'hours'}` } else if (seconds < week) { const days = Math.round(seconds / day) return `${days} ${days === 1 ? 'day' : 'days'}` } else if (seconds < month) { const weeks = Math.round(seconds / week) return `${weeks} ${weeks === 1 ? 'week' : 'weeks'}` } else if (seconds < year) { const months = Math.round(seconds / month) return `${months} ${months === 1 ? 'month' : 'months'}` } else { const years = Math.round(seconds / year) return `${years} ${years === 1 ? 'year' : 'years'}` } } interface ElementAttributes { [key: string]: string } interface ElementChild { outerHTML: string } export interface CustomElement { tagName: string attributes: ElementAttributes children: ElementChild[] _innerText: string setAttribute(name: string, value: string): void getAttribute(name: string): string | undefined appendChild(child: ElementChild): void href: string target: string innerText: string innerHTML: string outerHTML: string } export function createElement(tagName: string) { const element: CustomElement = { tagName: tagName.toLowerCase(), attributes: {}, children: [], _innerText: '', setAttribute(name: string, value: string) { this.attributes[name] = value }, getAttribute(name: string): string | undefined { return this.attributes[name] }, appendChild(child: ElementChild) { this.children.push(child) }, get href() { return this.attributes.href || '' }, set href(value: string) { this.attributes.href = value }, get target() { return this.attributes.target || '' }, set target(value: string) { this.attributes.target = value }, get innerText() { return this._innerText }, set innerText(value: string) { this._innerText = sanitizeHtml(value, { allowedTags: [], allowedAttributes: {}, }) }, get innerHTML() { return this._innerText }, set innerHTML(value: string) { this._innerText = value }, get outerHTML() { const attributesString = Object.entries(this.attributes) .map(([key, value]) => `${key}="${value}"`) .join(' ') return `<${this.tagName}${attributesString ? ' ' + attributesString : ''}>${this._innerText}` }, } return element }