import type { Returns, Join, Showable, UnionToTuple } from '@traversable/registry' import { symbol } from '@traversable/registry' import { t } from '@traversable/schema' export { neverToString as never, unknownToString as unknown, anyToString as any, voidToString as void, nullToString as null, undefinedToString as undefined, symbolToString as symbol, booleanToString as boolean, integerToString as integer, bigintToString as bigint, numberToString as number, stringToString as string, eqToString as eq, refToString as ref, arrayToString as array, recordToString as record, unionToString as union, intersectToString as intersect, optionalToString as optional, tupleToString as tuple, objectToString as object, } /** @internal */ type Symbol_optional = typeof Symbol_optional const Symbol_optional: typeof symbol.optional = symbol.optional /** @internal */ const isArray = globalThis.Array.isArray /** @internal */ const hasToType = (x: unknown): x is { toType(): string } => !!x && typeof x === 'function' && 'toType' in x && typeof x.toType === 'function' /** @internal */ const isOptional = (u: unknown): u is { toType(): T } => !!u && typeof u === 'function' && Symbol_optional in u && typeof u[Symbol_optional] === 'number' /** @internal */ const isShowable = (u: unknown) => u == null || typeof u === 'boolean' || typeof u === 'number' || typeof u === 'bigint' || typeof u === 'string' /** @internal */ const stringify = (u: unknown) => typeof u === 'string' ? `'${u}'` : isShowable(u) ? globalThis.String(u) : 'string' export function toType(x: unknown): string { return hasToType(x) ? x.toType() : 'unknown' } export declare namespace toType { export type eq = [_] extends [never] ? [T] extends [symbol] ? 'symbol' : string : [T] extends [string] ? `'${_}'` : _ export type ref = `${Id & string}` export type intersect = never | [T] extends [readonly []] ? 'unknown' /** @ts-expect-error */ : `(${Join<{ [I in keyof T]: Returns }, ' & '>})` export type union = never | [T] extends [readonly []] ? 'never' /** @ts-expect-error */ : `(${Join<{ [I in keyof T]: Returns }, ' | '>})` /** @ts-expect-error */ export type record = never | `Record}>` export type tuple = never | `[${Join<{ [I in keyof T]: `${ /** @ts-expect-error */ T[I] extends { [Symbol_optional]: any } ? `_?: ${Returns}` : Returns }` }, ', '>}]` /** @ts-expect-error */ export type optional = never | `(${Returns} | undefined)` /** @ts-expect-error */ export type array = `(${Returns})[]` export { object_ as object } export type object_> = never | [keyof T] extends [never] ? '{}' /** @ts-expect-error */ : `{ ${Join<{ [I in keyof _]: `'${_[I]}${T[_[I]] extends { [Symbol_optional]: any } ? `'?` : `'`}: ${Returns}` }, ', '>} }` } toType.never = 'never' as const toType.unknown = 'unknown' as const toType.any = 'any' as const toType.void = 'void' as const toType.undefined = 'undefined' as const toType.null = 'null' as const toType.symbol = 'symbol' as const toType.boolean = 'boolean' as const toType.integer = 'number' as const toType.number = 'number' as const toType.bigint = 'bigint' as const toType.string = 'string' as const toType.optional = (x: S): toType.optional => `(${toType(x)} | undefined)` toType.array = (x: S): toType.array => ('(' + toType(x) + ')[]') toType.record = (x: S): toType.record => `Record` toType.ref = (id: Id): toType.ref => id as never toType.eq = (x: S): toType.eq => (isShowable(typeof x) ? stringify(x) : typeof x === 'symbol' ? 'symbol' : 'string') toType.union = (xs: S): toType.union => (isArray(xs) ? xs.length === 0 ? 'never' : `(${xs.map(toType).join(' | ')})` : 'unknown') toType.intersect = (xs: S): toType.intersect => (isArray(xs) ? xs.length === 0 ? 'unknown' : `(${xs.map(toType).join(' & ')})` : 'unknown') toType.tuple = (xs: S): toType.tuple => (isArray(xs) ? `[${xs.map((x) => isOptional(x) ? `_?: ${toType(x)}` : toType(x)).join(', ')}]` : 'unknown[]') toType.object = >(xs: S): toType.object => { if (!!xs && typeof xs === 'object') { const entries = Object.entries(xs) if (entries.length === 0) return '{}' else return `{ ${entries.map(([k, x]) => `'${k}${isOptional(x) ? "'?" : "'"}: ${toType(x)}`).join(', ')} }` } else return '{ [x: string]: unknown }' } interface neverToString { toType(): typeof toType.never } interface unknownToString { toType(): typeof toType.unknown } interface anyToString { toType(): typeof toType.any } interface voidToString { toType(): typeof toType.void } interface nullToString { toType(): typeof toType.null } interface undefinedToString { toType(): typeof toType.undefined } interface bigintToString { toType(): typeof toType.bigint } interface symbolToString { toType(): typeof toType.symbol } interface booleanToString { toType(): typeof toType.boolean } interface integerToString { toType(): typeof toType.integer } interface numberToString { toType(): typeof toType.number } interface stringToString { toType(): typeof toType.string } function neverToString() { return toType.never } function unknownToString() { return toType.unknown } function anyToString() { return toType.any } function voidToString() { return toType.void } function undefinedToString() { return toType.undefined } function nullToString() { return toType.null } function symbolToString() { return toType.symbol } function booleanToString() { return toType.boolean } function integerToString() { return toType.integer } function bigintToString() { return toType.bigint } function numberToString() { return toType.number } function stringToString() { return toType.string } interface eqToString { toType(): Returns> } interface refToString { toType(): Returns> } interface arrayToString { toType(): Returns> } interface optionalToString { toType(): Returns>, [Symbol_optional]: number } interface recordToString { toType(): Returns> } interface unionToString { toType(): Returns> } interface intersectToString { toType(): Returns> } interface tupleToString { toType(): Returns> } interface objectToString> { toType(): Returns> } function eqToString(this: t.eq) { return toType.eq(this.def) } function refToString(this: t.ref) { return toType.ref(this.id) } function arrayToString(this: t.array) { return toType.array(this.def) } function optionalToString(this: t.optional) { return toType.optional(this.def) } function recordToString(this: t.record) { return toType.record(this.def) } function unionToString(this: t.union) { return toType.union(this.def) } function intersectToString(this: t.intersect) { return toType.intersect(this.def) } function tupleToString(this: t.tuple) { return toType.tuple(this.def) } function objectToString(this: t.object) { return toType.object(this.def) }