UNPKG

mauss

Version:

practical functions and reusable configurations

993 lines (979 loc) 45 kB
declare module 'mauss' { /** A convenience function to declare a variable with multiple conditionals to determine its final value, without cluttering the global or top-level scope with temporary variables that are only used once, and avoid nested ternary hell. */ export function scope<T>(fn: () => T): T; /** * A function that accepts an array and returns the same without any duplicate values. This can also handle an array of object by passing in a `key` as an identifier to access the object, with the same behavior as `key` from `'/compare'` module. * * @param array items to be inspected * @returns duplicate-free version of the array input */ export function unique<Inferred extends Record<IndexSignature, any>, Identifier extends Paths<Inferred>>(array: readonly Inferred[], key: string & Identifier): Inferred[]; export function unique<T>(array: readonly T[]): T[]; export function partition<T>(array: T[], predicate: (item: T) => boolean): [included: T[], excluded: T[]]; /** * Calculates the mean from a list of numbers using an incremental approach (moving average algorithm), which uses a constant space and updates in constant time. This method helps avoid potential numerical instability issues when dealing with a large sum, such as an integer overflow. * * @example * ```javascript * // returns 3 * average([1, 2, 3, 4, 5]); * ``` */ export function average(numbers: number[]): number; export function count<T>(array: T[], predicate?: (item: T) => boolean): number; /** * Find the minimum and maximum values in an array of numbers */ export function minmax(array: number[]): [min: number, max: number]; /** * A function that accepts an indexable object. * @returns `{ head, last }` of the object */ export function sides<T extends string | any[]>(x: T): Record<'head' | 'last', T[0]>; export function sum(array: number[]): number; /** * Binary search algorithm on a sorted array * @returns the first item that passes the check */ export function binary<T>(sorted: T[], check: { item: UnaryFunction<T, false | UnaryFunction<T>>; pointer: UnaryFunction<T, boolean>; }): T | undefined; /** * A function that will execute a `work` asynchronously and will not throw an error. * * @param work a function with an asynchronous operation * @template T the type of the data returned by the promise * @returns an object with either `data` or `error` property * @example * ```typescript * const { data, error } = await attempt(async () => { * // some async operation * return 'result'; * }); * if (error) { // could also be `data` * // log error or do other things * } * ``` */ export function attempt<T>(work: () => Promise<T>): Promise<{ data?: T; error?: unknown; }>; export namespace attempt { var sync: <T>(work: () => T) => { data?: T; error?: unknown; }; var wrap: <F extends AnyFunction>(fn: F) => (...args: Parameters<F>) => { data?: ReturnType<F>; error?: unknown; }; } type Wildcard =AnyFunction<[x: any, y: any], number>; /** * A higher-order function that accepts an array of strings and returns a comparator function that sorts the strings in the order they appear in the array. */ export function arrange(weights: readonly string[]): Wildcard; type KeyValidator<Keys, Expected> = Keys extends [infer I extends string, ...infer R] ? Expected & Record<I, KeyValidator<R, I extends keyof Expected ? Expected[I] : never>> : Expected; /** * A higher-order function that accepts a string as an identifier and an optional comparator function, it breaks up the identifier described by the dot (`.`) character and returns a curried function that accepts `(x, y)` with an object defined by the identifier. * * The optional comparator can be used when you have an existing custom sort function, e.g. in combination with `arrange` to sort a set of string. * * @example * * ```javascript * const posts = [ * { date: { month: 'March' } }, * { date: { month: 'June' } }, * { date: { month: 'May' } }, * { date: { month: 'April' } }, * { date: { month: 'January' } }, * { date: { month: 'June' } }, * { date: { month: 'February' } }, * ]; * * const months = [ * 'January', * 'February', * 'March', * 'April', * 'May', * 'June', * 'July', * 'August', * 'September', * 'October', * 'November', * 'December', * ]; * * posts.sort(drill('date.month', arrange(months))); * ``` */ export function drill<Inferred extends Record<IndexSignature, any>, Identifier extends keyof Inferred =Paths<Inferred>>(identifier: string & Identifier, comparator?: typeof wildcard): <X extends Inferred, Y extends Inferred>(x:WhenAny<keyof X, X, KeyValidator<Split<Identifier, ".">, X>>, y:WhenAny<keyof Y, Y, KeyValidator<Split<Identifier, ".">, Y>>) => number; /** * A function to check for value equality between two variables. This will work for any data type except `function`, which will always return `true` when two function are being compared. The heuristics are as follows: * - fails immediately when the type of `x` and `y` are not the same * - type of `function` are not comparable, always returns true * - type of `symbol` is converted and compared as a `string` * - primitive values are compared using strict equality operator * - type of `object`, two empty array or object are considered the same * - type of `object`, comparing array also considers its length and item order * - type of `object`, two object must have the same keys before comparing its values * - type of `object`, the order of key-value pair does not matter for equality check * - `identical` is infinitely recursive for any amount of nested array/object */ export function identical(x: unknown, y: unknown): boolean; export const compare: { /** Compares nullish values, sorting `null` and `undefined` to the end */ undefined(x: unknown, y: unknown): number; /** Compares boolean values, prioritizing `true` over `false` */ boolean(x: boolean, y: boolean): number; /** * Put `(x, y)` for bigger number first, and `(y, x)` for smaller number first * @returns `y - x` which defaults to descending order */ number(x: number, y: number): number; /** Compares bigint values, defaults to ascending order */ bigint(x: bigint, y: bigint): number; /** Compares symbols using its string values */ symbol(x: symbol, y: symbol): number; /** Compares string values using `.localeCompare` */ string(x: string, y: string): number; /** Compares generic object values using {@link inspect} */ object(x: object, y: object): number; }; /** Compares anything with anything */ export function wildcard(x: any, y: any): number; /** * Recursively compares common object properties until the first difference is found * @returns `0` if both objects are identical or completely different, otherwise their respective primitive difference */ export function inspect(x: Record<IndexSignature, any>, y: Record<IndexSignature, any>): number; type Unit = 'millisecond' | 'second' | 'minute' | 'hour' | 'day' | 'month' | 'year'; type DateLike = string | number | Date; /** * Creates a fluent, immutable date utility wrapper around a given date. * * Supports manipulation, comparison, formatting, and localization. * * @throws {Error} If the provided input date is invalid. */ export function date(input?: DateLike): { /** Returns a new `date()` instance with the same timestamp */ clone(): /*elided*/ any; /** Returns a fresh copy of the native `Date` representing the internal timestamp */ readonly raw: Date; /** Returns the internal timestamp in milliseconds */ epoch: number; /** Returns a new `date()` instance with the specified time added */ add(amount: number, unit: Unit): /*elided*/ any; /** Returns a new `date()` instance with the specified time subtracted */ subtract(amount: number, unit: Unit): /*elided*/ any; /** Computes the time difference between this date and the `other` */ delta(other: DateLike): { /** Returns the raw time difference in milliseconds */ readonly milliseconds: number; /** Returns the time difference in seconds */ readonly seconds: number; /** Returns the time difference in minutes */ readonly minutes: number; /** Returns the time difference in hours */ readonly hours: number; /** Returns the time difference in days */ readonly days: number; /** Returns the time difference in months, adjusted for day of month */ readonly months: number; /** Returns the time difference in years, derived from months */ readonly years: number; }; /** A set of boolean checks and comparisons for the current date */ is: { /** True if the date falls on the current day */ readonly today: boolean; /** True if the date is exactly one day before today */ readonly yesterday: boolean; /** True if the date is exactly one day after today */ readonly tomorrow: boolean; /** True if the date falls between Monday and Friday */ readonly weekday: boolean; /** True if the date is Saturday or Sunday */ readonly weekend: boolean; /** True if the date's year is a leap year */ readonly leap: boolean; /** True if the date is before the given date */ before(other: DateLike): boolean; /** True if the date is after the given date */ after(other: DateLike): boolean; /** True if the date is the same as the given date */ same(other: DateLike): boolean; }; to: { /** * Returns a localized, human-readable relative time string such as "yesterday", "in 2 hours", "3 months ago", etc. * * Falls back to "now" if the difference is negligible. */ relative(base?: DateLike, locale?: Intl.LocalesArgument): string; }; /** * Returns a formatted string of the current date based on a mask pattern. * Supports common patterns (e.g. `YYYY-MM-DD`) and localized weekday/month names. * * Default format: `YYYY-MM-DDTHH:mm:ssZZZ` * Locale affects the output of tokens like `MMM`, `MMMM`, `DDD`, `DDDD`. * * Token reference: * - Date: `D`, `DD` * - Weekday: `DDD`, `DDDD` * - Month: `M`, `MM`, `MMM`, `MMMM` * - Year: `YY`, `YYYY` * - Hour (24): `H`, `HH` * - Hour (12): `h`, `hh` * - Minute: `m`, `mm` * - Second: `s`, `ss` * - Meridiem: `a`, `A`, `p`, `P` * - Timezone: `Z`, `ZZ`, `ZZZ` * - Literal text: wrap in square brackets `[like this]` */ readonly format: (mask?: string, locale?: Intl.LocalesArgument) => string; }; export namespace date { var sort: { oldest(x: DateLike, y: DateLike): number; newest(x: DateLike, y: DateLike): number; }; } interface Rules { optional: typeof optional; boolean: typeof boolean; number: typeof number; string: typeof string; literal: typeof literal; date: typeof date_1; array: typeof array; record: typeof record; } type I_1<T> = T extends Validator<infer R> ? R : N<T>; type N<T> = T extends Record<string, any> ? { [K in keyof T]: I_1<T[K]>; } : never; export function define<T>(builder: (r: Rules) => T): (input: unknown) => I_1<T>; type Validator<T = unknown> = (input: unknown) => T; type Req<T> = T extends Validator<infer U> ? U : never; function optional<T>(validator: Validator<T>): Validator<T | undefined>; function optional<T extends Validator>(validator: T, fallback: Req<T>): Validator<Req<T>>; function optional<T extends Record<string, I_1<any>>>(item: T): Validator<undefined | N<T>>; function boolean<T = boolean>(transform?: (value: boolean) => T): Validator<T>; function number<T = number>(transform?: (value: number) => T): Validator<T>; function string<T = string>(transform?: (value: string) => T): Validator<T>; function literal<const T extends readonly string[]>(...values: T): Validator<T[number]>; function date_1<T = Date>(transform?: (value: Date) => T): Validator<T>; function array<T, R = T[]>(item: Validator<T>, transform?: (values: T[]) => R): Validator<R>; function array<T extends Record<string, I_1<any>>>(item: T): Validator<undefined | N<T>[]>; function record<T, R = Record<string, T>>(value: Validator<T>, transform?: (record: Record<string, T>) => R): Validator<R>; type Currying<Fun extends AnyFunction> = <Arguments extends Progressive<Parameters<Fun>>>(...args: Arguments) => Arguments['length'] extends Parameters<Fun>['length'] ? ReturnType<Fun> : Currying<(...args: Slice<Parameters<Fun>, Arguments['length']>) => ReturnType<Fun>>; /** * A type-safe higher-order function that accepts a function with one or more parameters and returns a function that can take in one or more arguments with a max of the parameters length. * If the total arguments provided has not yet reached the initial function parameters length, it will return a function until all the required parameters are fulfilled. * * @returns a curried function to take in the arguments */ export function curry<F extends AnyFunction>(fn: F, expected?: number): Currying<F>; /** * A function that accepts a function and returns the same function with the order of parameters reversed. This can be used in conjunction with `compare` methods to sort the items in ascending values. * * @param fn any function with one or more arguments * @returns a curried function to take in the arguments */ export function inverse<Function extends AnyFunction>(fn: Function): (...parameters: Reverse<Parameters<Function>>) => ReturnType<Function>; type Validator_1<Functions extends UnaryFunction[], Computed extends UnaryFunction = (v: ReturnType<Functions[0]>) => ReturnType<Functions[1]>> = Functions extends [infer Resolved, infer _, ...infer Rest] ? Rest extends UnaryFunction[] ? [Resolved, ...Validator_1<[Computed, ...Rest]>] : never : Functions; /** * A type-safe higher-order function that accepts any number of arguments, it returns a function with the parameters of the first function passed and a return type/value of the last function. * * @returns a function that takes in the initial type and returns the final type */ export function pipe<F extends UnaryFunction[]>(...functions: Validator_1<F>): (arg: Parameters<F[0]>[0]) => ReturnType<F extends [...any[], infer L] ? L : any>; /** A higher-order function that returns a function to clamp a number between a minimum and maximum value */ export function clamp(min: number, max: number): (value: number) => number; /** * The `%` is a remainder operator, this function computes the modulo operation and ensures a non-negative number for a non-negative divisor. * * @example * ```javascript * // returns 1 * modulo(5, 2); * * // returns 1 * modulo(-3, 2); * ``` */ export function modulo(a: number, n: number): number; /** * Creating a copy of a data type, especially an object, is useful for removing the reference to the original object, keeping it clean from unexpected changes and side effects. This is possible because we are creating a new instance, making sure that any mutation or changes that are applied won't affect one or the other * @returns a deep copy of the object input */ export function clone<T>(i: T): T; /** * Iterate over the key-value pair of an object, returns a new object using the pairs returned from the callback function. If callback is omitted, the default behavior will create a deep copy of the original object * * The returned object will be filtered to only contain a key-value pair of the 2-tuple from `fn()`, any other values returned from the callback will be ignored, i.e. `void | Falsy` */ export function iterate<T extends object, I = T[keyof T]>(object: T, callback?: AnyFunction<[ entry: Entries<T>[number], index: number ], void | Falsy | [IndexSignature, I]>): I extends T[keyof T] ? T : unknown; export const random: { /** * Generates a random floating point number between `min` and `max` (exclusive) * @default min=0 * @default max=1 */ float(min?: number, max?: number): number; /** * Generates a random integer between `min` and `max` (inclusive) * @default min=0 * @default max=1 */ int(min?: number, max?: number): number; /** Returns a random boolean value */ readonly bool: boolean; /** Returns an array of random integers */ array(length: number, min?: number, max?: number): number[]; /** Picks a random enumerable string key from a dictionary */ key(dict: Record<IndexSignature, any>): string; /** Picks a random value from the object's enumerable string keys */ val<T>(dict: Record<IndexSignature, T>): T; /** Picks a random item from an array */ item<T>(list: T[]): T; /** Returns a random 6-digit hexadecimal color code */ readonly hex: string; /** Generates a random IPv4 address */ readonly ipv4: string; /** Generates a random UUID v4 */ uuid(): string; }; /** * A function to work with template strings and removes indentation based on the first line. This is useful when the template string is written with indentation for better readability, but the indentation is not desired in the final output. */ export function indent(text: string): { depth: number; trim(): string; }; interface CapitalizeOptions { /** only capitalize the very first letter */ cap?: boolean; /** convert the remaining word to lowercase */ normalize?: boolean; } /** * A function that accepts a string and returns the same with the first letter of each word capitalized. This can also be used to capitalize only the first letter of the entire string, or normalize the entire string to lowercase before capitalizing. */ export function capitalize(text: string, { cap, normalize }?: CapitalizeOptions): string; /** Joins all given parameters together using `/`, regardless of the platform */ export function catenate(...paths: string[]): string; type Parse<T> = T extends `${string}{${infer P}}${infer R}` ? P | Parse<R> : never; /** * A type-safe template string function that accepts a string template with placeholders and returns a function that can take in an object with the same keys as the placeholders. The function will replace the placeholders with the corresponding values from the object. Parameters of the braces can be prefixed with a question mark `?` to make it optional to the type system and will fallback to an empty string if it's not defined in the table. * * This assumes the braces inside the template string are balanced and not nested. The function will not throw an error if the braces are not balanced, but the result will be unexpected. If you're using TypeScript and are passing a [string literal](https://www.typescriptlang.org/docs/handbook/2/everyday-types.html#literal-types), it will point out any unbalanced braces by throwing an error from the compiler. * * The template string is parsed into an array of strings, which are then executed with the provided table of functions, which is an object with the key being the name of the braces from the template string, and the value being the function to manipulate the name of the braces. * * @example * * ```javascript * const render = tsf('https://api.example.com/v1/{category}/{id}'); * * function publish({ category, id }) { * const url = render({ * category: () => category !== 'new' && category, * id: (v) => '<PREFIX>' + uuid(`${v}-${id}`), * }); * return fetch(url); * } * ``` * * @returns a function to replace the placeholders */ export function tsf<Input extends string>(template: Input extends `${string}{}${string}` ? 'Empty braces are not allowed in template' : Input extends `${string}{{${string}}}${string}` | `${string}{{${string}}${string}` | `${string}{${string}}}${string}` ? 'Unbalanced braces detected in template' : Input): (table: Record<Exclude<string extends Input ? string : Parse<Input>, `?${string}`>, (string | false | null | undefined) | UnaryFunction<string, string | false | null | undefined>> & { [K in Extract<string extends Input ? string : Parse<Input>, `?${string}`>]?: (string | false | null | undefined) | UnaryFunction<string, string | false | null | undefined>; }) => string; /** * A drop-in replacement for `new RegExp()` with special characters from source string escaped. This is useful when the pattern is not known at compile time and is dynamically constructed. * * @param pattern passed in the form of string literal * @param flags unique set of characters from `d|g|i|m|s|u|y` * @returns dynamically constructed RegExp object */ export function regexp(pattern: string, flags?: string): RegExp; /** * Immediately execute `fn` and block subsequent calls for `time` ms * * @example * ```js * onclick = () => immediate(() => {...}, 500); * ``` */ export function immediate<F extends AnyFunction>(fn: F, time?: number): <A extends Parameters<F>>(...args: A) => void; /** * Allow `fn` to be called at most once every `time` ms * * @example * ```js * const search = throttle((query) => {...}, 500); * * onclick = () => search('mauss'); // execute every 500ms * ``` */ export function throttle<F extends AnyFunction>(fn: F, time?: number): <A extends Parameters<F>>(...args: A) => void; /** Nullish values, which are only `null` and `undefined` */ type Nullish = null | undefined; /** Falsy values, value considered false in boolean context */ type Falsy = false | 0 | '' | Nullish; /** Primitives that are extended by `Record<..., any>` */ type IndexSignature = string | number | symbol; type Concat<Left, Right, Delimiter = '.'> = When<[ Left, Right ], [ string, string ], `${Left & string}${'' extends Right ? '' : Delimiter & string}${Right & string}`>; /** Extends a list to a certain specified length */ type Extend<Size extends number, List extends any[] = []> = List['length'] extends Size ? List : Extend<Size, [...List, any]>; /** * Generates all possible properties of nested object, * starting from the root and ends anywhere in the tree. * @returns string union with dot (.) as the delimiter */ type Paths<T> = T extends object ? When<T, Date, '', { [K in keyof T]-?: `${K & string}` | Concat<K, Paths<T[K]>>; }[keyof T]> : ''; /** Define a union of tuple that accepts a progressively increasing (LTR) items */ type Progressive<List extends any[]> = List extends [...infer Rest, any] ? List | (Rest['length'] extends 1 ? Rest : Progressive<Rest>) : List; /** Slices a list beginning from the starting index */ type Slice<List extends any[], Start extends number = 0> = List extends [ ...Extend<Start>, ...infer Sliced ] ? Sliced : []; /** Splits a string with custom separator */ type Split<Key extends IndexSignature, Separator extends string> = Key extends `${infer Prefix}${Separator}${infer Rest}` ? [Prefix, ...Split<Rest, Separator>] : [Key]; /** Generic for making any arbitrary function */ type AnyFunction<P extends any[] = any[], R = any> = (...parameters: P) => R; /** Strongly-type array of tuple from object in `Object.entries` */ type Entries<T> = { [K in keyof T]-?: [string & NonNullable<keyof PickByValue<T, T[K]>>, T[K]]; }[keyof T][]; /** Pick the properties of T that satisfies type of V */ type PickByValue<T, V> = Pick<T, { [K in keyof T]: T[K] extends V ? K : never; }[keyof T]>; /** Reverses any tuple values */ type Reverse<T extends any[]> = T extends [infer H, ...infer R] ? [...Reverse<R>, H] : []; /** Any function that has exactly one parameter */ type UnaryFunction<P = any, R = any> = (parameter: P) => R; /** When L extends R, returns `Y`, else `N` */ type When<L, R, Y = true, N = never> = L extends R ? Y : N; /** When T is type of `any`, returns `Y`, else `N` */ type WhenAny<T, Y = true, N = false> = When<0, 1 & T, Y, N>; export {}; } declare module 'mauss/api' { type HTTPMethods = 'GET' | 'POST' | 'PUT' | 'DELETE'; export interface FetcherConfig { /** * Prepares an object to pass into fetch that is called before the request is sent, it receives the specified `method` and `to` url string, and optionally a `body`, `from` URL, and `headers` object. It should _prepare_ and return an object that satisfies the [`RequestInit`](https://developer.mozilla.org/en-US/docs/Web/API/Request/Request) interface * @param opts request init options * @default ({ method, body }) => ({ method, body: JSON.stringify(body) }) */ prepare?(opts: { method: HTTPMethods; to: string; body?: BodyInit; from?: URL; headers?: Record<string, string>; }): RequestInit; /** * Intercepts the `url` before the request passed to fetch * @param path url received from all api methods * @default (url) => url */ intercept?(path: string): string; /** * Catches error from `fetch` failure and returns a string * @default () => 'NetworkError: Please try again later.' */ sweep?(exception: unknown): string; /** * Transforms raw response to desired data structure, it receives the response and can return anything that will used as the `payload` * @param res response object from fetch * @default () => r.json().catch(() => ({})) */ transform?(res: Response): Promise<unknown>; /** * Determines if fetcher should exit with an error, this function is called after the response is transformed and receives a clone of the initial response and the `payload` * @param res response object from fetch * @returns `string` if the request was unsuccessful or anything falsy if it was successful * @default ({ ok }) => !ok && 'UnexpectedError: Try again later.' */ exit?(res: Response, payload: any): AlsoPromise<string | false | Nullish>; } export interface SendOptions { from?: URL; headers?: Record<string, string>; using?: typeof fetch; } /** * Fetcher factory to create a `send` function to make requests that abstracts the `fetch` API. * * @example * * ```javascript * import { fetcher, type SendOptions } from 'mauss/api'; * const send = fetcher({ * prepare({ method, to, body }) { * // ... do some checks or logging * return { * method: method || 'GET', * mode: 'cors', * credentials: 'include', * headers: { * 'Content-Type': 'application/json', * }, * body: JSON.stringify(body), * }; * }, * exit({ status }, payload) { * if (status >= 500) return 'ServerError'; * if (status >= 400) return 'ClientError'; * // void or non-string means successful * }, * }); * // use the `send` function above to make and export an abstraction * export const API = { * // use getter to determine the template and infer the defined parameters * get 'session/:id'() { * // `tsf` function from 'mauss/std' * const render = tsf('https://auth.example/{id}/login'); * return (params: Parameters<typeof render>[0], options: SendOptions = {}) => { * const target = send(render(params), options); * return { * // ... abstraction methods, for example * async post() { * return await target.post(); * }, * }; * }; * }, * }; * ``` */ export function fetcher({ prepare, intercept, sweep, transform, exit, }: FetcherConfig): (url: string, options?: SendOptions) => { get<T>(): Promise<{ data?: T | undefined; error?: string; }>; post<T>(payload?: any): Promise<{ data?: T | undefined; error?: string; }>; put<T>(payload?: any): Promise<{ data?: T | undefined; error?: string; }>; delete<T>(): Promise<{ data?: T | undefined; error?: string; }>; }; /** Nullish values, which are only `null` and `undefined` */ type Nullish = null | undefined; /** Expand T to also be a promise */ type AlsoPromise<T> = T | Promise<T>; export {}; } declare module 'mauss/csv' { /** * Parse a CSV content into a 2D array. * * @example * ```javascript * import { readFileSync } from 'fs'; * import { read } from 'mauss/csv'; * const csv = read(readFileSync('./data.csv', 'utf-8')); * ``` * * @returns a 2D array of the CSV content */ export function read(content: string): string[][]; export {}; } declare module 'mauss/guards' { /** * A guard for exhaustive checks with `if`/`else`/`switch` statements, this will help branching logic in consuming enumeration and union types. * * @example * * ```typescript * let key = 'a' as 'a' | 'z'; * switch (key) { * case 'a': * return key.charCodeAt(); * default: * // Argument of type 'string' is not assignable to parameter of type 'never'. * return bulwark(key); * } * ``` */ export function bulwark(nothing: never): void; type Empty = '' | Nullish; /** @returns true if input is not `nullish` or an empty string */ export function exists<T>(i: T | Empty): i is T; /** @returns true if input is `null` or `undefined` */ export function nullish<T>(i: T | FullPrimitives): i is T; /** @returns true if input is truthy in general */ export function truthy<T>(i: T | Falsy): i is T; /** @returns true if input exists or is a number greater than 0 */ export function natural<T>(i: T | Empty): i is T; /** @returns true if input exists or is a number greater than or equal to 0 */ export function whole<T>(i: T | Empty): i is T; type ValidNegatives = typeof exists | typeof nullish | typeof truthy; /** @returns negation of the guard function passed, e.g. `not(nullish)` */ export function not<F extends ValidNegatives>(fn: F): <T>(i: T | (F extends typeof exists ? FullPrimitives : F extends typeof nullish ? Nullish : Empty)) => i is T; /** @returns true if string input is all lowercase letters */ export function lowercase(s: string): boolean; /** @returns true if string input is all uppercase letters */ export function uppercase(s: string): boolean; /** Nullish values, which are only `null` and `undefined` */ type Nullish = null | undefined; /** Falsy values, value considered false in boolean context */ type Falsy = false | 0 | '' | Nullish; /** Basic primitives consisting of `string`, `number`, and `boolean` */ type Primitives = string | number | boolean; /** Primitives from `typeof` as their actual type */ type FullPrimitives = Primitives | bigint | symbol; export {}; } declare module 'mauss/promises' { /** * Creates an async debounced version of `fn` that delays its execution until after `time` milliseconds have passed since the last call. * * Unlike traditional debounce functions, this version is `await`-able and resolves with the return value of `fn`. * @template F a function to debounce * @param fn the function to debounce * @param time delay in milliseconds (default: 300ms) * @returns a debounced async wrapper around `fn` * @example * ```typescript * function sift(name: string) {...} * * const search = debounce(sift, 500); * * await search('mauss'); // execute after 500ms * ``` */ export function debounce<F extends AnyFunction>(fn: F, time?: number): <A extends Parameters<F>>(...args: A) => Promise<ReturnType<F>>; export function pause(ms: number): Promise<void>; /** Generic for making any arbitrary function */ type AnyFunction<P extends any[] = any[], R = any> = (...parameters: P) => R; export {}; } declare module 'mauss/web' { /** Possible cookie inputs, `null | undefined` from headers */ type CookieInput = string | null | undefined; interface CookieOptions { /** * Expiry in days * @default 6 */ expires?: number; /** * MaxAge in days * @default undefined */ maxAge?: number; /** * Domain * @default undefined */ domain?: string; /** * Path * @default '/' */ path?: string; /** * HttpOnly * @default false */ secure?: boolean; /** * HttpOnly * @default true */ httpOnly?: boolean; /** * SameSite * @default 'Strict' */ sameSite?: 'Strict' | 'Lax' | 'None'; } export const cookies: { parse(source?: CookieInput): { has: (key: string) => boolean; get: (key: string) => string | undefined; keys: () => string[]; values: () => (string | undefined)[]; entries: () => [string, string | undefined][]; }; /** * Locates a cookie and immediately returns the raw value * @param source cookie source to parse * @param name cookie name to search for * @param trim remove quotes in cookie value, if there is any * @returns the value of cookie name and empty string if it doesn't exist */ raw(source: CookieInput, name: string, trim?: boolean): string | undefined; /** * @param options cookie settings * @returns a set-cookie function */ create({ path, domain, maxAge, expires, sameSite, secure, httpOnly, }?: CookieOptions): (name: string, value: string) => string; /** * A convenience function for the default `create()` * * @param name name for cookie * @param value value to be saved as cookie name * @returns the complete 'Set-Cookie' value */ readonly set: (name: string, value: string) => string; /** * @param values object of string pair as name and value for cookies * @param options cookie settings * @returns array of the complete 'Set-Cookie' values */ bulk(values: Record<string, string>, options?: CookieOptions): string[]; /** * Automatically remove cookie in browser * @param name cookie to expire * @returns expiring 'Set-Cookie' value */ remove(name: string): string; }; function copy(data: string | ClipboardItem, handler?: { accept?(): AlsoPromise<void>; reject?(): AlsoPromise<void>; }): Promise<void>; function paste(type: 'blob'): Promise<ClipboardItems>; function paste(type: 'text'): Promise<string>; /** * This namespace extends the [`Navigator` object](https://developer.mozilla.org/en-US/docs/Web/API/Navigator), make sure to execute the function in environments where `window.navigator` exists */ export const clipboard: { copy: typeof copy; paste: typeof paste; item(type: string, data: string | Blob, options?: ClipboardItemOptions): ClipboardItem; }; /** * Query string decoder (`qsd`) decodes a query string into an object. It accepts a query string with or without the leading `?` and returns a mapped object of decoded query string * * @param qs query string of a URL with or without the leading `?` * @returns mapped object of decoded query string */ export function qsd(qs: string): Record<IndexSignature, undefined | Primitives[]>; type BoundValues = Nullish | Primitives; /** * Query string encoder (`qse`) encodes key-value pairs from an object into a query string. It optionally accepts a second argument for a transformer function that will be applied to the final value if it exists, else an empty string will be returned * * @param bound object with key-value pair to be updated in the URL, only accepts an object with nullish and primitive literals or an array of those values * @param transformer function that is applied to the final string if it exists, useful in cases where we want to add a leading `?` when the query exists but not when it's empty, or when we would like to append another existing query string after only if the output of `qse` exists * @returns final query string */ export function qse<T extends object>(bound: T[keyof T] extends BoundValues | readonly BoundValues[] ? T : never, transformer?: (final: string) => string): string; /** Expand T to also be a promise */ type AlsoPromise<T> = T | Promise<T>; /** Nullish values, which are only `null` and `undefined` */ type Nullish = null | undefined; /** Basic primitives consisting of `string`, `number`, and `boolean` */ type Primitives = string | number | boolean; /** Primitives that are extended by `Record<..., any>` */ type IndexSignature = string | number | symbol; export {}; } declare module 'mauss/typings' { export type Narrowable = void | symbol | Nullish | Primitives | object | {}; /** Nullish values, which are only `null` and `undefined` */ export type Nullish = null | undefined; /** Falsy values, value considered false in boolean context */ export type Falsy = false | 0 | '' | Nullish; /** Basic primitives consisting of `string`, `number`, and `boolean` */ export type Primitives = string | number | boolean; /** Primitives from `typeof` as their actual type */ export type FullPrimitives = Primitives | bigint | symbol; /** Primitive values from `typeof` as string union */ export type TypePrimitive = 'string' | 'number' | 'bigint' | 'boolean' | 'symbol'; /** The complete values from `typeof` as string union */ export type TypeTable = TypePrimitive | 'undefined' | 'object' | 'function'; /** Primitives that are extended by `Record<..., any>` */ export type IndexSignature = string | number | symbol; /** Integer-based instances of https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/TypedArray#typedarray_objects */ export type TypedIntArray = Int8Array | Uint8Array | Uint8ClampedArray | Int16Array | Uint16Array | Int32Array | Uint32Array | BigUint64Array | BigInt64Array; /** Complete instances of https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/TypedArray#typedarray_objects */ export type TypedArray = TypedIntArray | Float32Array | Float64Array; /** When L extends R, returns `Y`, else `N` */ export type When<L, R, Y = true, N = never> = L extends R ? Y : N; /** When T is type of `any`, returns `Y`, else `N` */ export type WhenAny<T, Y = true, N = false> = When<0, 1 & T, Y, N>; /** When T is type of `Function`, returns `Y`, else `N` */ export type WhenFunction<T, Y = true, N = false> = When<T, Function, Y, N>; /** When T is type of `never`, returns `Y`, else `N` */ export type WhenNever<T, Y = true, N = false> = When<[T], [never], Y, N>; /** When T is type of `object`, returns `Y`, else `N` */ export type WhenObject<T, Y = true, N = false> = When<T, object, Y, N>; /** When T is type of `unknown`, returns `Y`, else `N` */ export type WhenUnknown<T, Y = true, N = false> = When<unknown, T, Y, N>; /** Expand T to also be an array */ export type AlsoArray<T> = T | T[]; /** Expand T to also be a promise */ export type AlsoPromise<T> = T | Promise<T>; /** Expand T to an array and the readonly version */ export type ArrayConstant<T> = T[] | readonly T[]; /** Generic for making any arbitrary function */ export type AnyFunction<P extends any[] = any[], R = any> = (...parameters: P) => R; /** Exclude `undefined` from T */ export type Definable<T> = T extends undefined ? never : T; /** Exclude all union that is in both A and B and get the difference */ export type Difference<A, B> = Exclude<A | B, A & B>; /** Allow either A or B but not both at the same time */ export type Either<A, B> = Only<A, B> | Only<B, A>; /** Strongly-type array of tuple from object in `Object.entries` */ export type Entries<T> = { [K in keyof T]-?: [string & NonNullable<keyof PickByValue<T, T[K]>>, T[K]]; }[keyof T][]; export type Fallback<A, B> = A extends B ? A : B; /** Remove type from T that does not satisfy type of Validator */ export type Filter<T, Validator> = T extends Validator ? T : never; /** Get the first item from an array, fallback defaults to `never` */ export type First<T extends any[], Fallback = never> = T extends [infer F, ...any[]] ? F : Fallback; /** Allow autocompletion of union in addition to arbitrary values */ export type Flexible<Union extends T, T = string> = Union | (T & Record<never, never>); /** Recursively make all properties of object T as readonly */ export type Freeze<T> = { readonly [P in keyof T]: T[P] extends Function ? T[P] : Freeze<T[P]>; }; /** Pick the properties of A that also exists in B */ type Intersection_1<A, B> = Pick<A, Extract<keyof A, keyof B> & Extract<keyof B, keyof A>>; /** Infers the return value of toJSON on the properties */ export type JSONState<T> = { [P in keyof T]: T[P] extends { toJSON: () => infer J; } ? J : T[P]; }; /** Get the last item from an array, fallback defaults to `never` */ export type Last<T extends any[], Fallback = never> = T extends [...any[], infer L] ? L : Fallback; /** Defines a type with at least one item */ export type NonEmptyArray<T> = [T, ...T[]]; /** Disallow any properties from B when defining A */ export type Only<A, B> = { [P in keyof A]: A[P]; } & Omit<{ [P in keyof B]?: never; }, keyof A>; /** Overwrite properties in A with values from B */ export type Overwrite<A, B> = Omit<A, keyof B> & B; /** Pick the properties of T that satisfies type of V */ export type PickByValue<T, V> = Pick<T, { [K in keyof T]: T[K] extends V ? K : never; }[keyof T]>; /** Reverses any tuple values */ export type Reverse<T extends any[]> = T extends [infer H, ...infer R] ? [...Reverse<R>, H] : []; /** Strict properties narrowing and remove Index Signatures */ export type Strict<T> = { [P in keyof T as {} extends Record<P, any> ? never : P]: T[P]; }; /** Workaround for a type not fulfilling index signature constraint */ export type Typify<T> = { [P in keyof T]: Typify<T[P]>; }; /** Any function that has exactly one parameter */ export type UnaryFunction<P = any, R = any> = (parameter: P) => R; export type Concat<Left, Right, Delimiter = '.'> = When<[ Left, Right ], [ string, string ], `${Left & string}${'' extends Right ? '' : Delimiter & string}${Right & string}`>; /** Extends a list to a certain specified length */ export type Extend<Size extends number, List extends any[] = []> = List['length'] extends Size ? List : Extend<Size, [...List, any]>; /** Flattens any array recursively */ export type Flatten<List extends any[], Memory extends any[] = []> = List extends [] ? Memory : List extends [infer Head, ...infer Rest] ? Head extends any[] ? Flatten<[...Head, ...Rest], Memory> : Flatten<Rest, [...Memory, Head]> : never; /** Convert Union to Intersection */ export type IntersectUnion<U> = (U extends any ? (_: U) => void : never) extends (_: infer Intersection) => void ? Intersection : never; /** Joins a list of string with custom delimiter */ export type Join<StringList extends readonly string[], Delimiter extends string = '-'> = StringList extends readonly [infer Head, infer Next, ...infer Rest] ? Join<[ `${Head & string}${Delimiter}${Next & string}`, ...Extract<Rest, readonly string[]> ], Delimiter> : StringList extends readonly [infer OnlyItem] ? OnlyItem : ''; export type Narrow<T> = Fallback<T, [ ] | (T extends Narrowable ? T : never) | { [K in keyof T]: Narrow<T[K]>; }>; /** * Merge an object properties and make all of them optional. * But, when one of it is defined, all of it's other properties * needs to be defined as well. */ export type OptionalAnnex<T, Annex> = T extends { [P in keyof Annex]: { [K in P]: Annex[K]; }; }[keyof Annex] ? Annex & T : T; /** * Partially omits object properties, like {@link Omit} but * makes them optional instead */ export type PartialOmit<T, Keys extends keyof T, Saved = { [P in Exclude<keyof T, Keys>]: T[P]; }, Final = Saved & { [P in keyof T]?: T[P]; }> = { [P in keyof Final]: Final[P]; }; /** * Generates all possible properties of nested object, * starting from the root and ends anywhere in the tree. * @returns string union with dot (.) as the delimiter */ export type Paths<T> = T extends object ? When<T, Date, '', { [K in keyof T]-?: `${K & string}` | Concat<K, Paths<T[K]>>; }[keyof T]> : ''; /** Generates a list of tuples from union */ export type Permutation<Union, Sliced = Union> = [Union] extends [never] ? [] : Union extends Union ? [Union, ...Permutation<Sliced extends Union ? never : Sliced>] : never; /** Define a union of tuple that accepts a progressively increasing (LTR) items */ export type Progressive<List extends any[]> = List extends [...infer Rest, any] ? List | (Rest['length'] extends 1 ? Rest : Progressive<Rest>) : List; /** * Single out a property from an object, receives object of * any properties and only allow one property to be defined */ export type SingleProperty<T> = { [P in keyof T]: { [K in P]: T[P]; } & { [K in Exclude<keyof T, P>]?: undefined; }; }[keyof T]; /** Slices a list beginning from the starting index */ export type Slice<List extends any[], Start extends number = 0> = List extends [ ...Extend<Start>, ...infer Sliced ] ? Sliced : []; /** Splits a string with custom separator */ export type Split<Key extends IndexSignature, Separator extends string> = Key extends `${infer Prefix}${Separator}${infer Rest}` ? [Prefix, ...Split<Rest, Separator>] : [Key]; /** * Specify tuple of `Size` with items of `T` */ export type Tuple<Size extends number, T extends any[] = [], Virtual extends any[] = []> = Virtual['length'] extends Size ? Virtual : Tuple<Size, T, [T, ...Virtual]>; export { Intersection_1 as Intersection }; } //# sourceMappingURL=index.d.ts.map