import { Function } from "../function"; import { Parts } from "../list/_parts"; import { ElementOf, IsEmpty, IsReadonly as IsReadonlyList, List } from "../list"; import { _IncNonneg } from "../number/int"; import { UnionToTuple, IsUnion } from "../set"; import { Quote, Serializable, IsLiteral, IsLiteralString } from "../string"; import { Equals, IsAny, IsNever, IsUnknown, Unreachable } from "."; /** * limits recursion depth */ type Step = [never, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9]; type Depth = ElementOf; type TooDeep = ' ... '; /** * ensures consistent symbol naming in introspection: maps symbol to number id associated with it */ type SymbolsMap = Record; /** * identifier for specific symbols */ type IndividualSymbol = '__nomicon_introspect__symbol'; /** * returns a State with the updated symbols map + number, and the string corresponding to the serialized symbol `S` * * basically does * ```ts * return S in Symbols * ? State(`${IndividualSymbol}${Symbols[S]}`, Symbols, N) * : State(`${IndividualSymbol}${N}`, { ...Symbols, [S]: N }, N + 1) * ``` */ type GetSymbol = K extends keyof Symbols ? State<`${IndividualSymbol}${Symbols[K]}`, Symbols, N> : State<`${IndividualSymbol}${N}`, Symbols & { [x in K]: N; }, _IncNonneg>; declare const depth: unique symbol; declare const symbols: unique symbol; declare const n: unique symbol; /** * provides additional information for introspection * * - `D` is the recursion depth * - `Symbols` provides the symbol mapping * - `N` provides the next number to use for symbol mapping */ type Context = { [depth]: D; [symbols]: Symbols; [n]: N; }; declare const s: unique symbol; /** * State wrapper. Stores the resultant serialized type and the current symbols mapping + number * * I wish this was a monad. */ type State = { [s]: S; [symbols]: Symbols; [n]: N; }; /** * introspects a nonvariadic list (i.e. finite number of elements) * * essentially does * ```ts * L.join(', ') * ``` * but properly updating the symbol mapping */ type IntrospectNonvariadicList> = Ctx extends Context ? IsNever extends true ? State : Acc extends State ? IsEmpty extends true ? Acc : L extends readonly [infer Last] ? _Introspect> extends State ? State<`${SAcc}${S}`, Symbols, N> : Unreachable : L extends readonly [_?: infer Last] ? _Introspect> extends State ? State<`${SAcc}${S}?`, Symbols, N> : Unreachable : L extends readonly [infer H, ...infer T] ? _Introspect> extends State ? IntrospectNonvariadicList, State<`${SAcc}${S}, `, Symbols, N>> : Unreachable : L extends readonly [_?: infer H, ...__: infer T] ? _Introspect> extends State ? IntrospectNonvariadicList, State<`${SAcc}${S}?, `, Symbols, N>> : Unreachable : Unreachable : Unreachable : Unreachable; /** * the prefix to any given list. * basically, if the list is readonly, adds "readonly " to the start */ type ListPrefix = IsReadonlyList extends true ? 'readonly ' : ''; /** * introspects an arbitrary list */ type IntrospectList = Ctx extends Context ? IsNever extends true ? TooDeep : Parts extends [infer I extends List, infer S extends List, infer T extends List] ? IsEmpty extends true ? IsEmpty extends true ? State<`${ListPrefix}[]`, Symbols, N> : IsEmpty extends true ? _Introspect, Context> extends State ? State<`${ListPrefix}${SS}[]`, Symbols, N> : Unreachable : _Introspect, Context> extends State ? IntrospectNonvariadicList> extends State ? State<`${ListPrefix}[...${SS}[], ${ST}]`> : Unreachable : Unreachable : IsEmpty extends true ? IntrospectNonvariadicList> extends State ? State<`${ListPrefix}[${SI}]`, Symbols, N> : Unreachable : IsEmpty extends true ? IntrospectNonvariadicList> extends State ? _Introspect, Context> extends State ? State<`${ListPrefix}[${SI}, ...${SS}[]]`, Symbols, N> : Unreachable : Unreachable : IntrospectNonvariadicList> extends State ? _Introspect, Context> extends State ? IntrospectNonvariadicList> extends State ? State<`${ListPrefix}[${SI}, ...${SS}[], ${ST}]`, Symbols, N> : Unreachable : Unreachable : Unreachable : Unreachable : Unreachable; /** * introspects union tuple `L` * * assumes `L` is nonvariadic since union types are always finite */ type _IntrospectUnionTuple> = Ctx extends Context ? Acc extends State ? IsEmpty extends true ? Acc : L extends readonly [infer Last] ? _Introspect> extends State ? State<`${SAcc}${S}`, Symbols, N> : Unreachable : L extends readonly [infer H, ...infer T] ? _Introspect> extends State ? _IntrospectUnionTuple, State<`${SAcc}${S} | `, Symbols, N>> : Unreachable : Unreachable : Unreachable : Unreachable; /** * introspects a union. * * essentially does * ```ts * return `( ${Members.join(' | ')} )` * ``` * but properly updating the symbol mapping */ type IntrospectUnion = UnionToTuple extends (infer L extends List) ? _IntrospectUnionTuple extends State ? State<`(${S})`, Symbols, N> : Unreachable : Unreachable; /** * introspects the mapped keys (i.e. exact `string`, `number`, `symbol` types) of an object * * mapped keys are represented as `[x: ${K}]: ${O[K]}` */ type _IntrospectMappedObjectKeys, Ctx extends Context, Acc extends State = State<'', Ctx[typeof symbols], Ctx[typeof n]>> = Ctx extends Context ? IsEmpty extends true ? Acc : L extends [infer Last extends keyof O] ? _Introspect> extends State ? _Introspect> extends State ? Acc extends State ? State<`${SAcc}[x: ${SK}]: ${SV}`, Symbols, N> : Unreachable : Unreachable : Unreachable : L extends [infer H extends keyof O, ...infer T extends List] ? _Introspect> extends State ? _Introspect> extends State ? Acc extends State ? _IntrospectMappedObjectKeys, State<`${SAcc}[x: ${SK}]: ${SV}, `, Symbols, N>> : Unreachable : Unreachable : Unreachable : Unreachable : Unreachable; /** * introspects the individual keys of an object * * individual keys are represented as `${K}: ${O[K]}` */ type _IntrospectIndividualObjectKeys, Ctx extends Context, Acc extends State = State<'', Ctx[typeof symbols], Ctx[typeof n]>> = Ctx extends Context ? Acc extends State ? IsEmpty extends true ? Acc : L extends readonly [infer Last extends keyof O] ? Last extends symbol ? GetSymbol extends State ? _Introspect> extends State ? State<`${SAcc}[${Sym}]: ${S}`, Symbols, N> : Unreachable : Unreachable : _Introspect> extends State ? _Introspect> extends State ? State<`${SAcc}${SK}: ${SV}`, Symbols, N> : Unreachable : Unreachable : L extends readonly [infer H extends keyof O, ...infer T extends List] ? H extends symbol ? GetSymbol extends State ? _Introspect> extends State ? _IntrospectIndividualObjectKeys, State<`${SAcc}[${Sym}]: ${S}, `, Symbols, N>> : Unreachable : Unreachable : _Introspect> extends State ? _Introspect> extends State ? _IntrospectIndividualObjectKeys, State<`${SAcc}${SK}: ${SV}, `, Symbols, N>> : Unreachable : Unreachable : Unreachable : Unreachable : Unreachable; /** * extracts the individual keys of object `O` */ type IndividualKeys = keyof { [K in keyof O as IsLiteralString extends true ? K : symbol extends K ? never : K extends symbol ? K : never]: never; }; /** * extracts the mapped keys of object `O` */ type MappedKeys = Omit> extends infer O ? number extends keyof O ? string extends keyof O ? Equals extends true ? Exclude : keyof O : keyof O : keyof O : Unreachable; /** * extracts the mapped and individual keys of object `O` */ type AllKeys = [ MappedKeys, IndividualKeys ]; /** * introspects an object */ type IntrospectObject = Ctx extends Context ? AllKeys extends [infer MK, infer LK] ? [UnionToTuple, UnionToTuple] extends [infer LMK extends List, infer LLK extends List] ? IsEmpty extends true ? IsEmpty extends true ? State<'{}', Symbols, N> : _IntrospectIndividualObjectKeys> extends State ? State<`{ ${S} }`, Symbols, N> : Unreachable : IsEmpty extends true ? _IntrospectMappedObjectKeys> extends State ? State<`{ ${S} }`, Symbols, N> : Unreachable : _IntrospectMappedObjectKeys> extends State ? _IntrospectIndividualObjectKeys> extends State ? State<`{ ${SM}, ${SI} }`, Symbols, N> : Unreachable : Unreachable : Unreachable : Unreachable : Unreachable; type SerializeStringTemplate = S extends '' ? Quote : S extends `${infer H}${infer T}` ? IsLiteral extends true ? SerializeStringTemplate : SerializeStringTemplate}}`> : Quote<`${Acc}\${${Introspect}}`, "`">; type SerializeString = string extends S ? 'string' : IsLiteral extends true ? Quote : SerializeStringTemplate; type _Introspect = Ctx extends Context ? IsNever extends true ? State : IsAny extends true ? State<'any', Symbols, N> : IsNever extends true ? State<'never', Symbols, N> : IsUnknown extends true ? State<'unknown', Symbols, N> : IsUnion extends true ? IntrospectUnion : Equals extends true ? State<'string', Symbols, N> : Equals extends true ? State<'number', Symbols, N> : Equals extends true ? State<'bigint', Symbols, N> : Equals extends true ? State<'boolean', Symbols, N> : Equals extends true ? State<'null', Symbols, N> : Equals extends true ? State<'undefined', Symbols, N> : T extends string ? State, Symbols, N> : T extends Serializable ? State<`${T}`, Symbols, N> : Equals extends true ? State<'symbol', Symbols, N> : T extends symbol ? GetSymbol : T extends List ? IntrospectList : T extends Function ? _Introspect> extends State ? _Introspect> extends State ? State<`Function<${SA}, ${SR}>`, Symbols, N> : Unreachable : Unreachable : T extends Promise ? _Introspect> extends State ? State<`Promise<${S}>}>`, Symbols, N> : Unreachable : T extends Date ? State<'Date', Symbols, N> : T extends RegExp ? State<'RegExp', Symbols, N> : T extends Error ? State<'Error', Symbols, N> : T extends Map ? _Introspect> extends State ? _Introspect> extends State ? State<`Map<${SK}>}, ${SV}>`, Symbols, N> : Unreachable : Unreachable : T extends Set ? _Introspect> extends State ? State<`Set<${S}>`, Symbols, N> : Unreachable : T extends WeakMap ? _Introspect> extends State ? _Introspect> extends State ? State<`WeakMap<${SK}, ${SV}>`, Symbols, N> : Unreachable : Unreachable : T extends WeakSet ? _Introspect> extends State ? State<`WeakSet<${S}>`, Symbols, N> : Unreachable : IntrospectObject> : Unreachable; /** * attempts to introspect type `T` up to depth `D`. * * recognizes `never`, `any`, `unknown`, primitives, lists, functions, objects, `Promise`, `Date`, `RegExp`, `Error`, `Map`, `Set`, `WeakMap`, `WeakSet` * * @warning may have extraneous parentheses * @warning loses tuple label information * @warning loses symbol name information and instead replaces it with `__nomicon_introspect__symbol${N}`. symbol mappings should be stable within any given introspection though * @warning unions may not appear in the same order * @warning object keys may not appear in the same order. mapped keys will always appear before individual keys * @warning does not work on intersection types * * @since 0.0.2 * * @example * ```ts * declare const s0: unique symbol * declare const s1: unique symbol * * type e0 = Introspect // "never" * type e1 = Introspect // "any" * type e2 = Introspect // "unknown" * type e3 = Introspect<0 | 1> // "(1 | 0)" * type e4 = Introspect // "(true | false | bigint | number | null | undefined | symbol | string)" * type e5 = Introspect<'foo' | `"'\``> // "('\"\\'`' | 'foo')" * type e6 = Introspect<`foo` | 0 | 1n | true> // "(1 | 'foo' | true | 0)" * type e7 = Introspect // "(Error | Date | RegExp)" * type e8 = Introspect | Set<3 | 4> | WeakMap<{}, 5 | 6> | Set<7>> // "(Set<7> | WeakMap<{}, (6 | 5)> | Set<(4 | 3)> | Map<(1 | 0), 2>)" * type e9 = Introspect> // "Promise<(number | string)>" * type e10 = Introspect<[]> // "[]" * type e11 = Introspect<['foo']> // "['foo']" * type e12 = Introspect<['foo', (0 | 'bar')?, ...('baz' | ['qux'])[]]> // "['foo', ('bar' | 0)?, ...(['qux'] | 'baz')[]]" * type e13 = Introspect<['foo', ...'bar'[], 'baz']> // "['foo', ...'bar'[], 'baz']" * type e14 = Introspect<(a: 1, b?: 2, ...c: 3[]) => 4> // "Function<[1, 2?, ...3[]], 4>" * * type t15 = { [s: number]: string, 0: 'foo', [x: `foo${string}`]: 'bar', b: 'baz', [s0]: 'qux', [sym: symbol]: unknown, [s1]: ['foo', 'bar' | 'baz', { a: 'qux', b: typeof s0 | typeof s1 }] } * // "{ [x: symbol]: unknown, [x: number]: string, [x: `foo${string}`]: 'bar', 'b': 'baz', [__nomicon_introspect__symbol0]: ['foo', ('baz' | 'bar'), { 'a': 'qux', 'b': (__nomicon_introspect__symbol0 | __nomicon_introspect__symbol1) }], [__nomicon_introspect__symbol1]: 'qux' }" * type e15 = Introspect * ``` */ export type Introspect = _Introspect extends State ? S : Unreachable; export {}; //# sourceMappingURL=introspect.d.ts.map