Scenario generator for vore roleplay and story ideas. https://scenario-generator.deliciousreya.net/responses
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 

112 lines
3.0 KiB

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<T extends (value: undefined) => string|number>(transformer: T): (value: Parameters<T>[0]|null) => ReturnType<T>|null {
return (value: Parameters<T>[0]|null): ReturnType<T>|null => value === null ? null : transformer(value) as ReturnType<T>
}