|
|
import {DateTime, IANAZone} from "luxon";
|
|
|
|
|
|
export type NullableType = "function"|"string"|"object"|"number"|"bigint"|"boolean"|"undefined"|"symbol"|"null"|"array"
|
|
|
|
|
|
export function nullableType(x: unknown): NullableType {
|
|
|
return x === null ? "null" : Array.isArray(x) ? "array" : typeof x
|
|
|
}
|
|
|
|
|
|
export function assertType(x:unknown, expected: "array", context?: string): x is readonly unknown[]
|
|
|
export function assertType(x:unknown, expected: "null", context?: string): x is null
|
|
|
export function assertType(x:unknown, expected: "symbol", context?: string): x is symbol
|
|
|
export function assertType(x:unknown, expected: "undefined", context?: string): x is undefined
|
|
|
export function assertType(x:unknown, expected: "boolean", context?: string): x is boolean
|
|
|
export function assertType(x:unknown, expected: "bigint", context?: string): x is bigint
|
|
|
export function assertType(x:unknown, expected: "number", context?: string): x is number
|
|
|
export function assertType(x:unknown, expected: "object", context?: string): x is object
|
|
|
export function assertType(x:unknown, expected: "string", context?: string): x is string
|
|
|
export function assertType(x:unknown, expected: "function", context?: string): x is Function
|
|
|
export function assertType(x: unknown, expected: NullableType, context?: string):
|
|
|
x is Function|string|object|number|bigint|boolean|undefined|symbol|null|readonly unknown[] {
|
|
|
const actual = nullableType(x)
|
|
|
if (expected !== actual) {
|
|
|
console.log(`expected ${expected}, was ${actual} ${context ? `(in ${context})` : ""}`)
|
|
|
return false
|
|
|
} else {
|
|
|
return true
|
|
|
}
|
|
|
}
|
|
|
|
|
|
export function isObject(x: unknown, context?: string): x is object {
|
|
|
return assertType(x, "object", context)
|
|
|
}
|
|
|
|
|
|
export function isArray(x: unknown, context?: string): x is readonly unknown[] {
|
|
|
return assertType(x, "array", context)
|
|
|
}
|
|
|
|
|
|
export function isString(x: unknown, context?: string): x is string {
|
|
|
return assertType(x, "string", context)
|
|
|
}
|
|
|
|
|
|
export function asString(x: unknown, context?: string): string|null {
|
|
|
if (!isString(x, context)) {
|
|
|
return null
|
|
|
}
|
|
|
return x
|
|
|
}
|
|
|
|
|
|
export function isNumber(x: unknown, context?: string): x is number {
|
|
|
return assertType(x, "number", context)
|
|
|
}
|
|
|
|
|
|
export function asNumber(x: unknown, context?: string): number|null {
|
|
|
if (!isNumber(x, context)) {
|
|
|
return null
|
|
|
}
|
|
|
return x
|
|
|
}
|
|
|
|
|
|
export function isDate(x: unknown, context?: string): x is string {
|
|
|
return asDate(x, context) !== null
|
|
|
}
|
|
|
|
|
|
export function asDate(x: unknown, context?: string): DateTime|null {
|
|
|
if (!isString(x, context)) {
|
|
|
return null
|
|
|
}
|
|
|
const result = DateTime.fromFormat(x, "EEEE', 'MMMM' 'd', 'yyyy' at 'h:mm:ss' 'a' 'z", {zone: IANAZone.create("UTC"), setZone: true, locale: "en-US"})
|
|
|
if (!result.isValid) {
|
|
|
return null
|
|
|
}
|
|
|
return result
|
|
|
}
|
|
|
|
|
|
export function assertField<T extends string|symbol>(x: object, field: T, context?: string): x is object & {[ key in T ]: unknown} {
|
|
|
if (!(field in x)) {
|
|
|
console.log(`expected ${String(field)} not found${context ? ` (in ${context})` : ""}`)
|
|
|
return false
|
|
|
}
|
|
|
return true
|
|
|
}
|
|
|
|
|
|
export function assertNoExtraFields(x: object, known: Set<string>, context?: string): boolean {
|
|
|
const unknown = Object.keys(x).filter(key => !known.has(key))
|
|
|
if (unknown.length > 1) {
|
|
|
console.log(`unknown fields ${unknown.join(", ")}${context ? ` (in ${context})` : ""}`)
|
|
|
return false
|
|
|
} else if (unknown.length > 0) {
|
|
|
console.log(`unknown field ${unknown[0]}${context ? ` (in ${context})` : ""}`)
|
|
|
return false
|
|
|
}
|
|
|
return true
|
|
|
} |