@ibnlanre/builder
Version:
Creates a builder object for defining keys and values.
103 lines (89 loc) • 4.78 kB
TypeScript
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 };