UNPKG

jasone

Version:

A lightweight, extensible JSON encoder and decoder that supports custom types.

259 lines 8.31 kB
//#region src/types.d.ts /** * A JSON-compatible value. */ type JsonValue = string | number | boolean | null | JsonValue[] | { [key: string]: JsonValue; }; /** * The id of an encoded type to identify it on decoding. */ type TypeId = string | number; type ClassLike<TInstance> = new (...args: any[]) => TInstance; declare const nonJsonTypes: ("bigint" | "symbol" | "undefined" | "object" | "function")[]; type NonJsonType = { bigint: bigint; function: Function; object: object; symbol: symbol; undefined: undefined; }; type EncodeFilter<TType> = { class?: ClassLike<TType>; any?: (value: unknown) => boolean; } & { [Key in keyof NonJsonType]?: ((value: NonJsonType[Key]) => boolean) | boolean }; type EncodeHandler<TType, TJson extends JsonValue> = (ctx: EncodeContext<TType>) => EncodeResult<TJson>; type EncodeContext<TType> = { value: TType; jasone: Jasone; }; type EncodeResult<TJson extends JsonValue> = TJson extends Record<string, JsonValue> ? [TypeId, TJson] | [null, JsonValue] : [null, JsonValue]; type Encoder<TType = unknown, TJson extends JsonValue = JsonValue> = { filter?: EncodeFilter<TType> | EncodeFilter<TType>[]; handler: EncodeHandler<TType, TJson>; }; type DecodeFilter = TypeId | ((typeId: TypeId, value: Record<string, JsonValue>) => boolean); type DecodeContext<TJson extends Record<string, JsonValue>> = { value: TJson; typeId: TypeId; jasone: Jasone; }; type DecodeHandler<TType, TJson extends Record<string, JsonValue>> = (ctx: DecodeContext<TJson>) => TType; type Decoder<TType = unknown, TJson extends Record<string, JsonValue> = Record<string, JsonValue>> = { filter?: DecodeFilter | DecodeFilter[]; handler: DecodeHandler<TType, TJson>; }; type Transformer<TType = unknown, TJson extends JsonValue = JsonValue> = { encoder?: Encoder<TType, TJson>; decoder?: TJson extends Record<string, JsonValue> ? Decoder<TType, TJson> : never; }; //#endregion //#region src/jasone.d.ts /** * Jasone options that can be passed to the Jasone constructor. */ type JasoneOptions = { /** * The type identifier that is used to determine if an object is a typed object. * * @default "$" */ typeIdentifier?: string; /** * The type transformers that are used to transform types. * * If not provided, the default transformers are used. By providing your own transformers, * the default transformers are not used anymore, so be sure to also include them if needed. * * @example * ```ts * // your custom transformer WITH default type transformers * const jasone = new Jasone({ types: [myCustomTransformer, ...defaultTransformers] }); * * // your custom transformer WITHOUT default type transformers * const jasone = new Jasone({ types: [myCustomTransformer] }); * ``` */ types?: Transformer<any, any>[]; }; /** * Jasone is a JSON encoder and decoder that can handle custom types. * * It exposes the default Jasone instance as `Jasone.default` and also * registers the methods as static methods on the class itself, so you * can easily use them without having to create an instance. * * ```ts * const encoded = Jasone.encode(value); * const decoded = Jasone.decode(value); * ``` * * If you want to use your own types, you can either register them on any * instance (even on `Jasone.default`) or instantiate your own Jasone instance. * * ```ts * // use our own types without the default types (Date, BigInt, Map, etc.) * const myInstance = new Jasone({ * types: [myCustomTransformer] * }); * * // or use our own types with the default types (recommend) * const myInstance = new Jasone({ * types: [myCustomTransformer, ...defaultTransformers], * }); * * const encoded = myInstance.encode(value); * const decoded = myInstance.decode(value); * ``` */ declare class Jasone { #private; constructor(options?: JasoneOptions); /** * Register a new type to this Jasone instance. * * @param type The type to register. */ register<TType, TJson extends JsonValue>(transformer: Transformer<TType, TJson>): void; /** * Encode an arbitrary value to a JSON-compatible Jasone encoded value. * * @param value The value to encode. * @returns A JSON-compatible Jasone encoded value. */ encode(value: unknown): JsonValue; /** * Decode an Jasone encoded value to its decoded value. * * @param value The Jasone encoded value to decode. * @returns The decoded value. */ decode<T = unknown>(value: JsonValue): T; /** * Alias for `encode`. */ serialize(value: unknown): JsonValue; /** * Alias for `decode`. */ deserialize<T = unknown>(value: JsonValue): T; /** * A wrapper around `JSON.stringify` that encodes a value and stringifies it. * * Under the hood, this functions looks like this: * * ```ts * JSON.stringify(this.encode(value)); * ``` */ stringify(value: unknown): string; /** * A wrapper around `JSON.parse` that parses a Jasone encoded value and decodes it. * * Under the hood, this functions looks like this: * * ```ts * this.decode(JSON.parse(value)); * ``` */ parse<T = unknown>(value: string): T; /** * The default Jasone instance with the default types already registered. */ static default: Jasone; /** * Register a new type to the default Jasone instance. * * @param type The type to register. */ /** * Encode an arbitrary value to a JSON-compatible Jasone encoded value. * * @param value The value to encode. * @returns A JSON-compatible Jasone encoded value. */ static encode: (value: unknown) => JsonValue; /** * Alias for `encode`. */ static serialize: (value: unknown) => JsonValue; /** * Decode an Jasone encoded value to its decoded value. * * @param value The Jasone encoded value to decode. * @returns The decoded value. */ static decode: <T = unknown>(value: JsonValue) => T; /** * Alias for `decode`. */ static deserialize: <T = unknown>(value: JsonValue) => T; /** * A wrapper around `JSON.stringify` that encodes a value and stringifies it. * * Under the hood, this functions looks like this: * * ```ts * JSON.stringify(Jasone.encode(value)); * ``` */ static stringify: (value: unknown) => string; /** * A wrapper around `JSON.parse` that parses a Jasone encoded value and decodes it. * * Under the hood, this functions looks like this: * * ```ts * Jasone.decode(JSON.parse(value)); * ``` */ static parse: <T = unknown>(value: string) => T; /** * Register a new type to this Jasone instance. * * @param type The type to register. */ static register: <TType, TJson extends JsonValue>(transformer: Transformer<TType, TJson>) => void; } //#endregion //#region src/transformers/bigint.d.ts declare const bigIntTransformer: Transformer<bigint, { bigint: string; }>; //#endregion //#region src/transformers/date.d.ts declare const dateTransformer: Transformer<Date, { iso: string; }>; //#endregion //#region src/transformers/map.d.ts declare const mapTransformer: Transformer<Map<unknown, unknown>, { entries: [key: JsonValue, value: JsonValue][]; }>; //#endregion //#region src/transformers/regexp.d.ts declare const regExpTransformer: Transformer<RegExp, { source: string; flags: string; }>; //#endregion //#region src/transformers/set.d.ts declare const setTransformer: Transformer<Set<unknown>, { values: JsonValue[]; }>; //#endregion //#region src/transformers/undefined.d.ts declare const undefinedTransformer: Transformer<undefined, {}>; //#endregion //#region src/transformers/url.d.ts declare const urlTransformer: Transformer<URL, { url: string; }>; //#endregion //#region src/transformers/index.d.ts /** * The default type transformers that are used by the default Jasone instance. */ declare const defaultTransformers: Transformer[]; //#endregion export { ClassLike, DecodeContext, DecodeFilter, DecodeHandler, Decoder, EncodeContext, EncodeFilter, EncodeHandler, EncodeResult, Encoder, Jasone, JasoneOptions, JsonValue, NonJsonType, Transformer, TypeId, type bigIntTransformer, type dateTransformer, defaultTransformers, type mapTransformer, nonJsonTypes, type regExpTransformer, type setTransformer, type undefinedTransformer, type urlTransformer };