import { formatAbsoluteDate } from '@/lib/relativeDate' const ISO_DAY_PREFIX = /^(\d{4})-(\d{2})-(\d{2})/ const ISO_DAY = /^(\d{4})-(\d{2})-(\d{2})$/ export function isBlank(value: unknown) { return value === null || value === undefined || value === '' } export function charCount(text: string) { return Array.from(text).length } export function isIsoDay(value: unknown): value is string { if (typeof value !== 'string') { return false } const match = ISO_DAY.exec(value) if (!match) { return false } const [year, month, day] = [Number(match[1]), Number(match[2]), Number(match[3])] const date = new Date(year, month - 1, day) return date.getFullYear() === year && date.getMonth() === month - 1 && date.getDate() === day } export function asText(value: unknown) { return value === null || value === undefined ? '' : String(value) } export function asNumber(value: unknown) { if (typeof value === 'number' && Number.isFinite(value)) { return value } if (typeof value === 'string' && value.trim() !== '' && Number.isFinite(Number(value))) { return Number(value) } return null } export function asBoolean(value: unknown) { return typeof value === 'boolean' ? value : null } export function formatDayValue(value: string) { const match = ISO_DAY_PREFIX.exec(value) if (!match) { return value } return formatAbsoluteDate(new Date(Number(match[1]), Number(match[2]) - 1, Number(match[3]))) } export function freeSentinel(taken: string[], base = '__none__') { let sentinel = base while (taken.includes(sentinel)) { sentinel += '_' } return sentinel } export function sameValue(left: unknown, right: unknown) { if (Array.isArray(left) && Array.isArray(right)) { return ( left.length === right.length && left.every((item, index) => Object.is(item, right[index])) ) } return Object.is(left, right) }