import { Result } from 'resulty'; import { Maybe } from 'maybeasy'; /** * A function type that represents a decoder which takes an input of any type * and returns a `Result` containing either a string error message or a value of type `A`. * * @template A - The type of the successfully decoded value. * @param thing - The input value to be decoded. * @returns A `Result` object containing either a string error message or a value of type `A`. */ type DecoderFn = (thing: any) => Result; /** * A class representing a Decoder that can be used to decode values of type `A`. * * @template A - The type of the value that this decoder will decode. */ declare class Decoder { private fn; /** * The constructor for the Decoder class. * * @param fn - The decoder function that will be used to decode values of type `A`. */ constructor(fn: DecoderFn); /** * Transforms the output of this decoder using the provided function. * * @template B - The type of the output after applying the transformation function. * @param {function(A): B} f - A function that takes a value of type A and returns a value of type B. * @returns {Decoder} A new decoder that applies the transformation function to the output of this decoder. */ map: (f: (a: A) => B) => Decoder; /** * Chains the current decoder with another decoder that depends on the result of the current decoder. * * @template B - The type of the value that the resulting decoder will decode to. * @param f - A function that takes the result of the current decoder and returns a new decoder. * @returns A new decoder that first decodes the value using the current decoder, * and then uses the result to decode further using the provided function. */ andThen: (f: (a: A) => Decoder) => Decoder; /** * Assigns a new key-value pair to the decoded object. * * The idea for assign came from this blog: * https://medium.com/@dhruvrajvanshi/simulating-haskells-do-notation-in-typescript-e48a9501751c * * @template K - The type of the key to be added. * @template B - The type of the value to be added. * @param {K} k - The key to be added to the decoded object. * @param {Decoder | ((a: A) => Decoder)} other - A decoder for the value to be added, or a function that takes the current decoded object and returns a decoder for the value. * @returns {Decoder} A new decoder that decodes an object with the new key-value pair added. */ assign: (k: K, other: Decoder | ((a: A) => Decoder)) => Decoder; /** * Applies a given function to the decoded value and returns the original value. * * @param fn - A function that takes the decoded value as an argument and performs some operation on it. * @returns A new Decoder instance with the same value. */ do: (fn: (a: A) => void) => Decoder; /** * Transforms the error message of the decoder using the provided function. * * @param f - A function that takes an error message string and returns a transformed error message string. * @returns A new `Decoder` instance with the transformed error message. */ mapError: (f: (e: string) => string) => Decoder; /** * Provides an alternative decoder to use if the current decoder fails. * * @param f - A function that takes an error message and returns an alternative decoder. * @returns A new decoder that attempts to decode the value using the current decoder, * and if it fails, uses the alternative decoder provided by the function `f`. */ orElse: (f: (e: string) => Decoder) => Decoder; /** * Registers a callback function to be executed if the decoding process fails. * * @param f - A function that takes an error message as a parameter and returns void. * @returns A new `Decoder` instance with the registered callback function. */ elseDo: (f: (e: string) => void) => Decoder; /** * Decodes any given value using the provided decoding function. * * @param value - The value to be decoded. * @returns The result of the decoding function applied to the given value. */ decodeAny: (value: any) => Result; /** * Decodes a JSON string into a Result type. * * @param json - The JSON string to decode. * @returns A Result containing either the decoded value of type `A` or an error message. * * @template A - The type of the decoded value. */ decodeJson: (json: string) => Result; /** * Converts the current decoder into a function that can decode any value. * * @returns A function that takes any value and returns a `Result` containing either a string error message or a decoded value of type `A`. */ toAnyFn: () => ((value: any) => Result); /** * Converts the current decoder into a function that takes a JSON string * and returns a `Result` containing either a decoded value of type `A` or an error message. * * @returns A function that takes a JSON string and returns a `Result`. */ toJsonFn: () => ((json: string) => Result); } /** * Creates a decoder that always succeeds with the given value. * * @template A - The type of the value to be returned by the decoder. * @param value - The value to be returned by the decoder. * @returns A new decoder that always returns the provided value. */ declare const succeed: (value: A) => Decoder; /** * Creates a decoder that always fails with the given message. * * @template A - The type of the value to be returned by the decoder. * @param message - The error message to be returned by the decoder. * @returns A new decoder that always fails with the provided message. */ declare const fail: (message: string) => Decoder; /** * A decoder that validates if a given value is a string. * * @constant * @type {Decoder} * * @example * const result = string.decode("hello"); * // result is Ok("hello") * * const result = string.decode(123); * // result is Err("I expected to find a string but instead I found 123") * * @param {any} value - The value to be decoded. * @returns {Result} - Returns an Ok with the string value if the value is a string, * otherwise returns an Err with an error message. */ declare const string: Decoder; /** * A decoder that validates if a given value is a number. * * This decoder checks the type of the input value. If the value is not a number, * it returns an error with a message indicating the expected type and the actual value. * If the value is a number, it returns the value wrapped in an `ok` result. * * @constant * @type {Decoder} * @example * const result = number.decode(42); // ok(42) * const result = number.decode("42"); // err("I expected to find a number but instead I found \"42\"") */ declare const number: Decoder; /** * A decoder that validates if a given value is a boolean. * * @constant * @type {Decoder} * @example * const result = boolean.decode(true); // ok(true) * const result = boolean.decode("true"); // err("I expected to find a boolean but instead I found \"true\"") */ declare const boolean: Decoder; /** * Applies the `decoder` to all of the elements of an array. */ declare const array: (decoder: Decoder) => Decoder; /** * Decodes the value at a particular field in a JavaScript object. */ declare const field: (name: string, decoder: Decoder) => Decoder; /** * Decodes the value at a particular path in a nested JavaScript object. */ declare const at: (path: Array, decoder: Decoder) => Decoder; /** * Converts a JSON object to an array of key value pairs ((string, A)[]). The * passed in decoder is applied to the object value. The key will always be * converted to a string. * * @param decoder The internal decoder to be applied to the object values */ declare const keyValuePairs: (decoder: Decoder) => Decoder<[string, A][]>; /** * Converts a JSON object to a Map. * * I would reccomend using this as a decoder of last resort. For correctness, you are * probably better off using field decoders and explicitly declaring the shape of the * objects you are expecting. * * @param decoder The internal decoder to be applied to the object values */ declare const dict: (decoder: Decoder) => Decoder>; /** * Creates a decoder for objects where all keys are strings and all values * conform to a specific type. * * This function is a higher-order decoder factory. It takes a `valueDecoder` * as an argument, which is responsible for decoding the individual values * within the object. The `objectOf` function then creates a new decoder that * can decode an entire object, ensuring that all keys are strings and all * values are successfully decoded by the provided `valueDecoder`. * * @param valueDecoder - A decoder that will be used to decode each value * within the object. This decoder determines the type of the values in the * resulting object. * @returns A decoder that can decode objects with string keys and values * of the type specified by `valueDecoder`. * * @example * ```typescript * import { string, number, objectOf } from './associative'; // Assuming these are in the same file * import { InferType } from './base'; // Assuming InferType is defined in base.ts * * // Decoder for an object where values are strings * const stringObjectDecoder = objectOf(string); * type StringObject = InferType; * * // Decoder for an object where values are numbers * const numberObjectDecoder = objectOf(number); * type NumberObject = InferType; * * // Example usage * const validStringObject: StringObject = { a: 'hello', b: 'world' }; * const validNumberObject: NumberObject = { x: 1, y: 2, z: 3 }; * * // Example of invalid data * const invalidStringObject = { a: 'hello', b: 123 }; // Error: 'b' is not a string * const invalidNumberObject = { x: 1, y: '2', z: 3 }; // Error: 'y' is not a number * ``` */ declare function objectOf(valueDecoder: Decoder): Decoder<{ [key: string]: T; }>; /** * Makes any decoder optional. Be aware that this can mask a failing * decoder because it makes any failed decoder result a nothing. */ declare const maybe: (decoder: Decoder) => Decoder>; /** * Decodes possibly null or undefined values into types. * There is overlap between `nullable` and `maybe` decoders. * The difference is that `maybe` will always succeed, even if * there is an error in the decoder. * * Maybe example: * * maybe(string).decodeAny('foo') // => Ok('foo') * maybe(string).decodeAny(null) // => Ok(Nothing) * maybe(string).decodeAny(42) // => Ok(Nothing) * * Nullable example: * * nullable(string).decodeAny('foo') // => Ok('foo') * nullable(string).decodeAny(null) // => Ok(Nothing) * nullable(string).decodeAny(42) // => Err... */ declare const nullable: (decoder: Decoder) => Decoder>; /** * Date decoder. * * Date decoder expects a value that is a number or a string. It will then try * to construct a JavaScript date object from the value. * * This decoder use the Date constructor, and so assumes the same cross browser * inconsistencies. */ declare const date: Decoder; /** * Date ISO decoder * * The Date ISO decoder expects a value that is a string formatted in some * variation of ISO 8601. It will fail if the date is invalid or is not a * recognized ISO 8601 format. * * Relies on parseISO from date-fns * https://date-fns.org/v2.16.1/docs/parseISO */ declare const dateISO: Decoder; /** * Date JSON decoder * * This decoder parses date formats common in JSON APIs * * See parseJSON from date-fns for more information on supported formats * https://date-fns.org/v2.16.1/docs/parseJSON * */ declare const dateJSON: Decoder; /** * Creates a decoder that checks if the input value is equal to the specified value. * * @typeParam T - The type of the value to compare. * @param t - The value to compare against the input. * @returns A `Decoder` that succeeds if the input value is equal to `t`, otherwise fails with an error message. */ declare const eql: (t: T) => Decoder; /** * Infers the resulting type of a Decoder. * * This type utility takes a Decoder type and extracts the type it decodes to. * * @template D - The Decoder type. * @returns The type that the Decoder decodes to. */ type InferType> = D extends Decoder ? T : never; /** * Infers the resulting type of a Decoder function. * * This type utility takes a Decoder function and extracts the type it decodes to. * * @template F - The Decoder function type. * @returns The type that the Decoder function decodes to. */ type InferTypeFromFn Result> = F extends (value: any) => Result ? T : never; /** * Creates a decoder that checks if the input is equal to the specified string literal. * * @template T - The type of the string literal. * @param t - The string literal to compare against. * @returns A decoder that validates if the input matches the string literal. */ declare const stringLiteral: (t: T) => Decoder; /** * Creates a decoder that tries to decode a value using a list of provided decoders. * If none of the decoders succeed, it returns an error with a combined message of all errors. * * @template A - The type of the value to decode. * @param {Array>} decoders - An array of decoders to try. * @returns {Decoder} A decoder that tries each provided decoder in order. */ declare function oneOf(decoders: Decoder[]): Decoder; /** * Creates a decoder from a given structure of decoders or nested structures. * * This function takes a structure where each value is either a `Decoder` or another * nested structure of decoders, and returns a `Decoder` that can decode objects * matching the given structure. * * @template T - The type of the structure, which is a record where each value is either * a `Decoder` or another nested structure. * * @param {T} structure - The structure of decoders or nested structures. * * @returns {Decoder>} - A decoder that can decode objects matching the given structure. */ declare function createDecoderFromStructure(structure: T, keyToLookup?: (key: string) => string): Decoder>; /** * Represents a structure where each key is associated with either a `Decoder` of any type or another nested `Structure`. * This allows for the creation of complex, nested data structures that can be decoded. * * @typeParam key - The key of the structure, which is a string. * @typeParam Decoder - A generic type representing a decoder for any type. */ type Structure = { [key: string]: Decoder | Structure; }; /** * Infers the TypeScript type from a given `Structure` type. * * This utility type recursively maps over the keys of the `Structure` type `T` * and infers the corresponding TypeScript type for each key. * * - If the value of a key is a `Decoder` type, it infers the type `U` that the `Decoder` decodes to. * - If the value of a key is another `Structure`, it recursively infers the structure of that nested `Structure`. * - Otherwise, it results in `never`. * * @template T - The `Structure` type from which to infer the TypeScript type. */ type InferStructure = { [K in keyof T]: T[K] extends Decoder ? U : T[K] extends Structure ? InferStructure : never; }; type InferUnionFromMapping; }> = { [K in keyof T]: InferType; }[keyof T]; /** * Creates a decoder for a discriminated union type. A discriminated union is a union of object types * where each object type is identified by a specific value in a shared discriminator field. * * @template DiscriminatorKey - The name of the discriminator field (e.g., `'type'`). * @template Mapping - A mapping object where keys are discriminator values and values are decoders * for the corresponding object types. * * @param discriminatorField - The name of the field used to discriminate between union variants. * @param mapping - An object mapping discriminator values to their respective decoders. * * @returns A `Decoder` that decodes values into the appropriate union variant based on the discriminator field. * * @throws If the discriminator field is missing, has an invalid value, or if the value does not match * any key in the mapping, an error is returned. * * @example * ```typescript * const userDecoder = object({ type: stringLiteral('user'), name: string }); * const adminDecoder = object({ type: stringLiteral('admin'), permissions: array(string) }); * * const unionDecoder = discriminatedUnion('type', { * user: userDecoder, * admin: adminDecoder, * }); * * const result = unionDecoder.decode({ * type: 'user', * name: 'Alice', * }); * // result: { type: 'user', name: 'Alice' } * ``` */ declare function discriminatedUnion; }>(discriminatorField: DiscriminatorKey, mapping: Mapping): Decoder>; /** * Creates a decoder that validates if a string matches a given regular expression. * * @param regex - The regular expression to test against the input string. * @returns A `Decoder` that checks if the input string matches the provided regular expression. * * The decoder will return: * - `ok(RegExpExecArray)` if the input string matches the regular expression. * - `err(string)` if the input is not a string or does not match the regular expression. * * @example * ```typescript * const emailDecoder = regex(/^[^\s@]+@[^\s@]+\.[^\s@]+$/); * const result = emailDecoder.decode("example@example.com"); * // result is ok(["example@example.com"]) * * const invalidResult = emailDecoder.decode("invalid-email"); * // invalidResult is err('The string "invalid-email" does not match the regular expression: /^[^\s@]+@[^\s@]+\.[^\s@]+$/') * ``` */ declare const regex: (regex: RegExp) => Decoder; /** * Safely converts a JavaScript value to a JSON string, handling cyclical references. * * @param value - The value to be stringified. * @returns The JSON string representation of the value. */ declare function safeStringify(value: any): string; /** * A generic function that returns the value it receives as an argument. * * @template T - The type of the value. * @param {T} value - The value to be returned. * @returns {T} The same value that was passed as an argument. */ declare function identity(value: T): T; /** * Converts a snake_case string to camelCase. * * @param str - The snake_case string to be converted. * @returns The converted camelCase string. */ declare function camelCase(str: string): string; /** * Converts a camelCase string to snake_case. * * @param str - The camelCase string to be converted. * @returns The converted snake_case string. * * @example * ```typescript * const result = camelCaseToSnakeCase('camelCaseString'); * console.log(result); // Outputs: camel_case_string * ``` */ declare function snakeCase(str: string): string; export { Decoder, type DecoderFn, type InferType, type InferTypeFromFn, array, at, boolean, camelCase, createDecoderFromStructure, date, dateISO, dateJSON, dict, discriminatedUnion, eql, fail, field, identity, keyValuePairs, maybe, nullable, number, objectOf, oneOf, regex, safeStringify, snakeCase, string, stringLiteral, succeed };