UNPKG

tupleson

Version:

A hackable JSON serializer/deserializer

134 lines (113 loc) 3.08 kB
const brand = Symbol("branded"); export type TsonBranded<TType, TBrand> = TType & { [brand]: TBrand }; export type TsonNonce = TsonBranded<string, "TsonNonce">; export type TsonTypeHandlerKey = TsonBranded<string, "TsonTypeHandlerKey">; export type TsonSerializedValue = unknown; export type TsonTuple = [TsonTypeHandlerKey, TsonSerializedValue, TsonNonce]; // there's probably a better way of getting this type export type TsonAllTypes = | "bigint" | "boolean" | "function" | "number" | "object" | "string" | "symbol" | "undefined"; type SerializedType = | Record<string, unknown> | boolean | number | string | unknown[]; export interface TsonTransformerNone { async?: false; deserialize?: never; /** * The key to use when serialized */ key?: never; serialize?: never; serializeIterator?: never; } export interface TsonTransformerSerializeDeserialize< TValue, TSerializedType extends SerializedType, > { async?: false; /** * From JSON-serializable value */ deserialize: (v: TSerializedType) => TValue; /** * The key to use when serialized */ key: string; /** * JSON-serializable value */ serialize: (v: TValue) => TSerializedType; serializeIterator?: never; } export type TsonTransformer<TValue, TSerializedType extends SerializedType> = | TsonTransformerNone | TsonTransformerSerializeDeserialize<TValue, TSerializedType>; export interface TsonTypeTesterPrimitive { /** * The type of the primitive */ primitive: TsonAllTypes; /** * Test if the value is of this type */ test?: (v: unknown) => boolean; } export interface TsonTypeTesterCustom { /** * The type of the primitive */ primitive?: never; /** * Test if the value is of this type */ test: (v: unknown) => boolean; } type TsonTypeTester = TsonTypeTesterCustom | TsonTypeTesterPrimitive; export type TsonType< /** * The type of the value */ TValue, /** * JSON-serializable value how it's stored after it's serialized */ TSerializedType extends SerializedType, > = TsonTypeTester & TsonTransformer<TValue, TSerializedType>; export interface TsonOptions { /** * The nonce function every time we start serializing a new object * Should return a unique value every time it's called * @default `${crypto.randomUUID} if available, otherwise a random string generated by Math.random` */ nonce?: () => number | string; /** * The list of types to use */ types: (TsonType<any, any> | TsonType<any, never>)[]; } export const serialized = Symbol("serialized"); export interface TsonSerialized<TValue = unknown> { json: TsonSerializedValue; nonce: TsonNonce; [serialized]: TValue; } export type TsonSerializeFn = <TValue>(obj: TValue) => TsonSerialized<TValue>; export type TsonDeserializeFn = <TValue>( data: TsonSerialized<TValue>, ) => TValue; export type TsonStringified<TValue> = string & { [serialized]: TValue }; export type TsonStringifyFn = <TValue>( obj: TValue, space?: number | string, ) => TsonStringified<TValue>; export type TsonParseFn = <TValue>(string: TsonStringified<TValue>) => TValue;