UNPKG

@ibnlanre/builder

Version:

Creates a builder object for defining keys and values.

103 lines (89 loc) 4.78 kB
import * as react from 'react'; import { PropsWithChildren } from 'react'; /** * Represents a store key. * * @param {Field} Field The type of the field. * @param {Prefix} Prefix The type of the prefix. * * @returns {Base<Field, Prefix>} A store key object with get and use functions. */ type Base<Field, Prefix extends readonly string[] = []> = { $get: <Arguments extends unknown[]>(...args: Arguments) => [...Prefix, Field, ...Arguments]; $use: () => [...Prefix, Field]; }; type Dictionary = { readonly [k: string]: unknown; readonly [k: number]: unknown; readonly [k: symbol]: unknown; }; type Primitives = string | number | bigint | boolean | null | undefined; type Serialize<Head extends Primitives> = Head extends Exclude<Primitives, null | undefined> ? `${Head}` : ""; type JoinHelper<Head, Rest extends unknown[], Separator extends string> = Head extends Primitives ? Rest extends [] ? `${Serialize<Head>}` : Rest extends Primitives[] ? `${Serialize<Head>}${Separator}${Join<Rest, Separator>}` : "" : ""; /** * Represents a list of primitives joined by a separator. * * @template List The type of the list. * @template Separator The type of the separator. * * @returns {string} The joined list. */ type Join<List extends ReadonlyArray<Primitives>, Separator extends string = ""> = List extends [infer Head, ...infer Rest] ? JoinHelper<Head, Rest, Separator> : ""; /** * Represents a builder for a store key. * * @params Register The type of the store. * @params Prefix The type of the path. * * @return KeyBuilder<Register, Prefix> A store key builder object. */ type KeyBuilder<Register extends Dictionary, Prefix extends readonly string[] = []> = { [Field in keyof Register]: Register[Field] extends (...args: infer Arguments) => unknown ? { $get: <Variables extends any[]>(...args: Variables) => [...Prefix, Extract<Field, string>, ...Variables]; $use: (...args: Parameters<Register[Field]>) => [...Prefix, Extract<Field, string>, ...Arguments]; } : Register[Field] extends Dictionary ? Base<Field, Prefix> & KeyBuilder<Register[Field], [...Prefix, Extract<Field, string>]> : Base<Field, Prefix>; }; type Values<List extends readonly string[], Separator extends string = ".", Result extends string = ""> = List extends [infer Head extends string, ...infer Tail extends string[]] ? Result extends "" ? Values<Tail, Separator, `${Head}`> : Result | Values<Tail, Separator, `${Result}${Separator}${Head}`> : Result; type PathsHelper<Prefix extends readonly string[], Key extends string, Separator extends string = "."> = Values<[...Prefix, Key], Separator>; type Paths<Register extends Dictionary, Prefix extends readonly string[] = [], Separator extends string = "."> = Register extends Dictionary ? { [Key in keyof Register]: Key extends string | number ? Register[Key] extends Dictionary ? PathsHelper<Prefix, `${Key}`, Separator> | PathsHelper<Prefix, `${Key}${Separator}${Paths<Register[Key], [], Separator>}`, Separator> : PathsHelper<Prefix, `${Key}`, Separator> : never; }[keyof Register] : never; interface Get<Register extends Dictionary, Prefix extends readonly string[] = [], Separator extends string = "."> { /** * Returns the prefix array. * * @returns {Prefix} The prefix array. */ (): Prefix; /** * Returns the key passed to the method. * If no key is provided, it returns the prefix array. * * @template {Paths<Register, Prefix, Separator>} Path * @template {readonly [Path, ...Array<Primitives>]} Key * * @param {Key} path The key to return. * @returns {Join<Key, Separator>} The key passed to the method. */ <Path extends Paths<Register, Prefix, Separator>, Key extends readonly [Path, ...Array<Primitives>]>(...path: Key): Join<Key, Separator>; } /** * Represents the builder for a store. * * @template Register The type of the store. * @template Prefix The type of the path. * @template Separator The type of the separator. */ type Builder<Register extends Dictionary, Prefix extends readonly string[] = [], Separator extends string = "."> = { $use: Register; $get: Get<Register, Prefix, Separator>; } & KeyBuilder<Register, Prefix>; type BuilderRecord<Register extends Dictionary = {}, Prefix extends string[] = []> = Record<string, Builder<Register, Prefix>>; type BuilderProviderProps<Builders extends BuilderRecord> = PropsWithChildren<{ builders: Builders; }>; declare function createBuilderProvider<Builders extends BuilderRecord>(builders: Builders): { useBuilder: () => Builders; BuilderProvider: ({ children }: BuilderProviderProps<Builders>) => react.JSX.Element; }; export { type BuilderProviderProps, type BuilderRecord, createBuilderProvider };