import { collapseWhiteSpace } from 'collapse-white-space'; import { isSnowflake, type Snowflake } from 'discord-snowflake'; const VALID_URL_PATTERN = new URLPattern({ protocol: '(http(?:s)?|mailto)' }); export function typeOf(data: unknown): string { if (data === null) { return 'null' } if (Array.isArray(data)) { return 'array' } return typeof data } export function string(data: string|undefined, trim?: boolean): string { if (typeof data !== 'string') { throw Error(`expected string, but was ${typeOf(data)}`) } return collapseWhiteSpace(data, { style: 'js', trim: trim ?? true, preserveLineEndings: false }) } export function discordSnowflake(data: string|Snowflake|undefined): Snowflake { const text = string(data) if (!isSnowflake(text)) { throw Error(`expected Discord snowflake, but was ${typeOf(data)}`) } return text } export function substring(data: string|undefined): string { const text = string(data, false) if (text.length === 0) { return '%'; } return '%' + text.replaceAll('\\', '\\\\') .replaceAll('_', '\\_') .replaceAll('%', '\\%') + '%'; } export function tableIdentifierOrId(data: string|undefined): string export function tableIdentifierOrId(data: string|number|undefined): string|number export function tableIdentifierOrId(data: string|number|undefined): string|number { if (typeof data === 'number') { return integer(data) } else { return string(data).toLowerCase() } } export function tableIdentifierSubstring(data: string|undefined): string { return substring(tableIdentifierOrId(data)) } export function URL(data: string|undefined): string { const url = string(data) if (!VALID_URL_PATTERN.test(url)) { throw Error('url must be a valid HTTP, HTTPS, or MAILTO URL'); } return url } export function boolean(data: boolean|undefined): number { if (typeof data !== 'boolean') { throw Error(`expected boolean but was ${typeof(data)}`) } return data ? 1 : 0 } export function integer(data: number|undefined): number { const num = number(data) if (!Number.isInteger(num)) { throw Error(`expected integer but was ${data}`) } return num } export function number(data: number|undefined): number { if (typeof data !== 'number') { throw Error(`expected number but was ${typeof(data)}`) } return data } export function timestamp(data: number|undefined): number { return integer(data) } export function jsonObject(data: object|undefined): string { if (typeof data !== 'object' || typeOf(data) !== 'object') { throw Error(`expected object but was ${typeof(data)}`) } return JSON.stringify(data) } export function jsonArray(data: (readonly unknown[])|undefined): string { if (!Array.isArray(data)) { throw Error(`expected object but was ${typeof(data)}`) } return JSON.stringify(data) } export function nullable string|number>(transformer: T): (value: Parameters[0]|null) => ReturnType|null { return (value: Parameters[0]|null): ReturnType|null => value === null ? null : transformer(value) as ReturnType }