// @ts-check /// /// /// /// /// /// "use strict"; /** * @name Celestra * @version 6.6.0 node * @author Ferenc Czigler * @see https://github.com/Serrin/Celestra/ * @license MIT https://opensource.org/licenses/MIT */ const VERSION = "Celestra v6.6.0 node"; /** TS types */ /** * @description Map-like object with string or number or symbol keys. * * @private * */ type MapLike = Record; /** * @description Number-like object. * * @private * */ type NumberLike = number | bigint; /** * @description Any iterable or iterator. * * @private */ type IterableLike = Iterable | Iterator | IterableIterator; /** * @description Any iterable, iterator, or array-like structure. * * @private */ type IterableLikeAndArrayLike = | Iterable | Iterator | IterableIterator | ArrayLike; /** * @description Iterable and Iterator and Generator types. * * @private */ type IteratorReturn = | Iterable | Iterator | Generator; /** * @description Type for undefined and null values. * * @private */ type Nullish = undefined | null; /* built-in type: type NonNullable = number | boolean | string | symbol | object | Function; */ /** * @description Not null or undefined or object or function. * * @private */ type NonNullablePrimitive = number | bigint | boolean | string | symbol; /** * @description Not object or function. * * @private */ type Primitive = null | undefined | number | bigint | boolean | string | symbol; /** * Generic comparable types. * * @private */ type Comparable = number | bigint | string | boolean | Date; /** * @description Object key type. * * @private */ type PropertyKey = string | symbol; /** * @description Type AsyncFunction. * * @private */ type AsyncFunction = (...args: ReadonlyArray) => Promise; /** * @description Type ArrowFunction. * * @private */ type ArrowFunction = (this: void, ...args: Args) => R; /** * @description TypedArray types. * * @private */ type TypedArray = Exclude; /** polyfills **/ /* globalThis; */ (function (global) { if (!global.globalThis) { if (Object.defineProperty) { Object.defineProperty(global, "globalThis", { configurable: true, enumerable: false, value: global, writable: true }); } else { global.globalThis = global; } } })(typeof this === "object" ? this : Function("return this")()); /* Math.sumPrecise(); */ if (!("sumPrecise" in Math)) { // @ts-ignore Math.sumPrecise = function sumPrecise ([...array]): number { /* empty iterator */ if (array.length === 0) { return -0; } /* iterator with items */ if (array.every((value: unknown): boolean => typeof value === "number")) { /* return NaN + Infinity + -Infinity */ let inf = array.indexOf(Infinity) >- 1; let negInf = array.indexOf(-Infinity) > -1; if (array.some((value: unknown): boolean => value !== value) || (inf && negInf)) { return NaN; } if (inf) { return Infinity; } if (negInf) { return -Infinity; } /* sum hi */ let hi = array.filter((value: unknown): boolean => (value === 1e20 || value === -1e20)) .reduce((acc, value): number => acc + value, 0); /* sum lo - Kahan sum */ let lo: number = 0.0; let c: number = 0.0; for (let item of array.filter((value: unknown): boolean => (value !== 1e20 && value !== -1e20))) { let y = item - c; let t = lo + y; c = (t - lo) - y; lo = t; } /* return sum values */ /* if (lo === 0 && hi !== 0) { return hi; } if (lo > 0 && hi > 0) { return hi; } if (lo < 0 && hi < 0) { return hi; } if (lo > 0 && hi < 0) { return lo + hi; } if (lo < 0 && hi > 0) { return lo + hi; } if (lo === 0 && hi === 0) { return lo; } if (lo !== 0 && hi === 0) { return lo; } */ if ((lo === 0 && hi !== 0) || (lo > 0 && hi > 0) || (lo < 0 && hi < 0)) { return hi; } if ((lo > 0 && hi < 0) || (lo < 0 && hi > 0)) { return lo + hi; } return lo; } /* not number items -> TypeError */ throw new TypeError("values passed to Math.sumPrecise must be numbers"); }; } /* Error.isError(); */ if (!("isError" in Error)) { // @ts-ignore Error.isError = function isError (value: unknown) { let className = Object.prototype.toString.call(value).slice(8, -1).toLowerCase(); return (className === "error" || className === "domexception"); }; } /* crypto.randomUUID(); */ if (("crypto" in globalThis) && !("randomUUID" in globalThis.crypto)) { // @ts-ignore globalThis.crypto.randomUUID = function randomUUID () { // @ts-ignore return ([1e7]+-1e3+-4e3+-8e3+-1e11).replace(/[018]/g, (c: any): any => (c^crypto.getRandomValues(new Uint8Array(1))[0]&15 >> c/4).toString(16) ); }; } /* globalThis.GeneratorFunction; */ // @ts-ignore if (!globalThis.GeneratorFunction) { // @ts-ignore globalThis.GeneratorFunction = Object.getPrototypeOf(function*(){}).constructor; } /* globalThis.AsyncFunction; */ // @ts-ignore if (!globalThis.AsyncFunction) { // @ts-ignore globalThis.AsyncFunction = Object.getPrototypeOf(async function(){}).constructor; } /* globalThis.AsyncGeneratorFunction; */ // @ts-ignore if (!globalThis.AsyncGeneratorFunction) { // @ts-ignore globalThis.AsyncGeneratorFunction = Object.getPrototypeOf(async function* () {}).constructor; } /** Core API **/ /* Alphabet constans */ const BASE16 = "0123456789ABCDEF"; const BASE32 = "234567ABCDEFGHIJKLMNOPQRSTUVWXYZ"; const BASE36 = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"; const BASE58 = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz"; const BASE62 = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; const WORDSAFEALPHABET = "23456789CFGHJMPQRVWXcfghjmpqvwx"; /* 31 characters */ /** * @description Ensures that `condition` is truthy. Throws an `Error` if falsy. * * @param {unknown} condition The value to check. * @param {unknown} [message] - Optional message or Error to throw. * @throws {Error} If assertion is failed. */ function assert (condition: unknown, message?: unknown): asserts condition { if (!condition) { // @ts-ignore if (Error.isError(message)) { throw message; } let errorMessage = `[assert] Assertion failed: ${condition} should be truly${message ? ` - ${message}` : ""}`; throw new Error(errorMessage, {cause: errorMessage}); } } /** * @description SameValueZero equality (like `Object.is`, but +0 === -0). * * @param {unknown} value1 * @param {unknown} value2 * @returns {boolean} */ const eq = (value1: unknown, value2: unknown): boolean => value1 === value2 || (value1 !== value1 && value2 !== value2); /** * @description Greater than. * * @param {any} value1 * @param {any} value2 * @returns {boolean} */ function gt (value1: Comparable, value2: Comparable): boolean { const _typeOf = (value: unknown): string => value === null ? "null" : typeof value; return _typeOf(value1) === _typeOf(value2) && value1 > value2; } /** * @description Greater than or equal (SameValueZero). * * @param {any} value1 * @param {any} value2 * @returns {boolean} */ function gte (value1: Comparable, value2: Comparable): boolean { const _typeOf = (value: unknown): string => value === null ? "null" : typeof value; return _typeOf(value1) === _typeOf(value2) && (value1 > value2 || value1 === value2 || (value1 !== value1 && value2 !== value2)); } /** * @description Less than. * * @param {any} value1 * @param {any} value2 * @returns {boolean} */ function lt (value1: Comparable, value2: Comparable): boolean { const _typeOf = (value: unknown): string => value === null ? "null" : typeof value; return _typeOf(value1) === _typeOf(value2) && value1 < value2; } /** * @description Less than or equal (SameValueZero). * * @param {any} value1 * @param {any} value2 * @returns {boolean} */ function lte (value1: Comparable, value2: Comparable): boolean { const _typeOf = (value: unknown): string => value === null ? "null" : typeof value; return _typeOf(value1) === _typeOf(value2) && (value1 < value2 || value1 === value2 || (value1 !== value1 && value2 !== value2)); } /** * @description Calls `callback` with the given `value` and then returns `value`. * * @param {Function} callback * @returns {Function} */ function tap (callback: Function): any { return function (value: unknown): any { callback(value); return value; }; } /** * @description Creates a function that is restricted to invoking `callback` once. * * @param {Function} callback * @returns {Function} */ function once (callback: Function): Function { let called: boolean = false; let result: any; return function (...args: any[]): any { if (!called) { called = true; result = callback(...args); } return result; }; } /** * @description Transforms a function of N arguments into N functions of one argument. * * @param {Function} callback * @returns {Function} */ function curry (callback: Function): Function { const curried = (...args: any[]): any => args.length >= callback.length ? callback(...args) : (...rest: any[]): any => curried(...args, ...rest); return curried; } /** * @description Creates a function that is the composition of the provided functions. * * @param {Function} functions * @returns {Function} */ const pipe = (...functions: Function[]): Function => (first: any): any => functions.reduce((value: unknown, callback: Function): any => callback(value), first); /** * @description Creates a function that is the composition of the provided functions. * * @param {Function} functions * @returns {Function} */ const compose = (...functions: Function[]): Function => (first: any): any => functions.reduceRight((value, callback): any => callback(value), first); /** * @description Creates a new object composed of the picked `object` properties. * * @param {object} obj * @param {string[]} keys */ const pick = (obj: MapLike, keys: string[]): MapLike => keys.reduce(function (acc: MapLike, key: string) { if (key in obj) { acc[key] = obj[key]; } return acc; }, {}); /** * @description Creates a new object composed of the `object` properties except for those omitted. * * @param {object} obj * @param {string[]} keys * @returns {object} */ const omit = (obj: MapLike, keys: string[]): MapLike => Object.keys(obj).reduce(function (acc: MapLike, key: string) { // @ts-ignore if (!keys.includes(key)) { acc[key] = obj[key]; } return acc; }, {}); /** * @description Returns a new object with the specified key-value pair added or updated. * * @param {object} obj * @param {string} key * @param {object} value */ const assoc = (obj: MapLike, key: string, value: unknown): MapLike => ({...obj, [key]: value}); /** * @description An asynchronous no-operation function that returns a resolved Promise. * * @returns {Promise} */ // @ts-ignore function asyncNoop (): Promise { return new Promise(function (resolve: Function) { resolve(); }); } /** * @description Asynchronous function that returns a resolved Promise with `true`. * * @returns {Promise} */ async function asyncT (): Promise { return true; } /** * @description Asynchronous function that returns a resolved Promise with `false`. * * @returns {Promise} */ async function asyncF (): Promise { return false; } /** * @description Creates an asynchronous function that returns a resolved Promise with the specified value. * * @param {unknown} value * @returns {Function} */ function asyncConstant (value: unknown): Function { return async function() { return value; }; } /** * @description Asynchronous identity function that returns a resolved Promise with the given value. * * @param {unknown} value * @returns {Promise} */ async function asyncIdentity (value: unknown): Promise { return value; } /** * @description Creates a polyfill method on an object if it does not already exist. * * @param {Object} obj - The object on which to create the method. * @param {string} property - The name of the method to create. * @param {Function} value - The function to assign as the method. * @returns {boolean} - Returns true if the method was created or already exists with the same value. */ function createPolyfillMethod ( obj: Object, property: string, value: Function): boolean { if (!(Object.hasOwn(obj, property))) { Object.defineProperty(obj, property, { writable: true, enumerable: false, configurable: true, value: value }); } // @ts-ignore return (obj[property] === value); } /** * @description Creates a polyfill property on an object if it does not already exist. * * @param {Object} obj - The object on which to create the property. * @param {string} property - The name of the property to create. * @param {unknown} value - The value to assign to the property. * @returns {boolean} - Returns true if the property was created or already exists with the same value. */ function createPolyfillProperty ( obj: object, property: string, value: unknown): boolean { if (!(Object.hasOwn(obj, property))) { Object.defineProperty(obj, property, { writable: true, enumerable: true, configurable: true, value: value }); } // @ts-ignore return (obj[property] === value); } /** * @description Generates a random UUID version 7 or UUID version 7 with version 4 ID. * * @param {boolean} [v4=false] - If true, generates a UUID version 4; otherwise, generates version 7. * @returns {string} A randomly generated UUID string. */ function randomUUIDv7 (v4: boolean = false): string { let ts = Date.now().toString(16).padStart(12,"0") + (v4 ? "4" : "7"); // @ts-ignore let uuid = Array.from(([1e7]+-1e3+-4e3+-8e3+-1e11).replace(/[018]/g, (c: number): any => (c^crypto.getRandomValues(new Uint8Array(1))[0] & 15 >> c / 4).toString(16) )); let index: number = 0; let pos: number = 0; while (index < 13) { if (pos === 8 || pos === 13) { pos++; } uuid[pos] = ts[index]; pos++; index++; } return uuid.join(""); } /** * @description Returns a Promise that resolves after a specified delay in milliseconds. * * @param {number} milisec - The delay duration in milliseconds. * @returns {Promise} A Promise that resolves after the specified delay. */ const delay = (milisec: number): Promise => new Promise(resolve => setTimeout(resolve, milisec)); /** * @description Generates a random boolean value. * * @returns {boolean} A randomly generated boolean value. */ const randomBoolean = (): boolean => !Math.round(Math.random()); /** * @description Parses URL query parameters into an object. * * @param {string} [str=location.search] - The URL query string to parse. Defaults to the current location's search string. * @returns {Object} An object containing the parsed query parameters as key-value pairs. */ const getUrlVars = (str: string = location.search): Object => [...new URLSearchParams(str).entries()] // @ts-ignore .reduce(function (obj, item) { obj[item[0]] = item[1]; return obj; }, {}); /** * @description Create a parsable string from an object. * * @param {object} obj * @returns {string} */ const obj2string = (obj: any): string => Object.keys(obj).reduce( (str, key: string): string => str += encodeURIComponent(key) + "=" + encodeURIComponent(obj[key]) + "&", "" ).slice(0, -1); /** * @description Deep assign of an object (Object, Array, etc.) * * @returns any */ function extend (target: T, source: U): T & U; function extend (target: T, s1: U, s2: V): T & U & V; function extend (deep: true, target: T, ...sources: any[]): T; function extend (deep: false, target: T, ...sources: any[]): T; function extend (target: object, ...sources: any[]): object; function extend (...args: any[]): any { /* Arguments checking */ let deep: boolean = false; let target: any; let i = 0; if (args[0] === true) { deep = true; target = args[1] || {}; i = 2; } else { target = args[0] || {}; i = 1; } /* Helper functions */ const _isPlainObject = (obj: any): obj is Record => obj != null && typeof obj === "object" && (obj.constructor === Object || obj.constructor == null); function merge(target: any, source: any): any { /* Identical or non-object -> direct assign */ if (Object.is(source, target) || source == null || typeof source !== "object") { return source; } /* Date -> clone */ if (source instanceof Date) { return new Date(source.getTime()); } /* RegExp -> clone */ if (source instanceof RegExp) { return new RegExp(source); } /* Map -> deep merge entries */ if (source instanceof Map) { if (target instanceof Map) { target = new Map(); } for (let [key, value] of source) { const tv = target.get(key); target.set(key, deep ? merge(tv, value) : value); } return target; } /* Set -> deep union */ if (source instanceof Set) { if (!(target instanceof Set)) { target = new Set(); } for (let item of source) { if (deep) { if (target.has(item)) { continue; } } target.add(item); } return target; } /* Array -> deep merge by index */ if (Array.isArray(source)) { if (!Array.isArray(target)) { target = []; } const srcLength = source.length; for (let i = 0; i < srcLength; i++) { let sv = source[i]; let tv = target[i]; target[i] = deep ? merge(tv, sv) : sv; } return target; } /* Plain object -> deep merge keys */ if (_isPlainObject(source)) { if (!_isPlainObject(target)) { target = {}; } for (let key in source) { let sv = source[key]; let tv = target[key]; target[key] = deep ? merge(tv, sv) : sv; } return target; } /* Fallback: copy by reference */ return source; } /* Clone all sources */ const length = args.length; for (; i < length; i++) { merge(target, args[i]); } return target; } /** * @description Returns the number of own properties (including symbols) of an object. * * @param {object} obj * @returns {number} */ const sizeIn = (obj: object): number => Object.getOwnPropertyNames(obj).length + Object.getOwnPropertySymbols(obj).length; /** * @description Creates a function that invokes `callback` with its `this` binding removed. * * @param {Function} callback * @returns {Function} */ const unBind = (callback: Function): Function => Function.prototype.call.bind(callback); /** * @description Creates a function that invokes `callback` with its `this` binding set to the provided context. * * @param {Function} callback * @param {Function} context */ const bind = Function.prototype.call.bind(Function.prototype.bind); /** * @description Returns a function that always returns the same value. * * @param {unknown} value * @returns {unknown} */ const constant = (value: T): (() => T) => () => value; /** * @description Returns value unchanged. * * @param {unknown} value * @returns {unknown} */ const identity = (value: T): T => value; /** * @description A function that does nothing. * * @returns {void} */ function noop (): void {} /** * @description Always returns true. * * @returns {true} */ const T = (): boolean => true; /** * @description Always returns false. * * @returns {false} */ const F = (): boolean => false; /** * @description Generates a random string ID of specified size using the provided alphabet. * * @param {number} [size=21] - The length of the generated ID. * @param {string} [alphabet="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_-"] - The set of characters to use for generating the ID. */ function nanoid ( size: number = 21, alphabet: string = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_-" ): string { let result: string = ""; let dl: number = alphabet.length; let pos: number; let index: number = size; while (index--) { do { pos = crypto.getRandomValues(new Uint8Array(1))[0]; } while (pos >= dl); result += alphabet[pos]; } return result; } /** * @description Generates a timestamp-based string ID of specified size using the provided alphabet. * * @param {number} [size=21] - The total length of the generated ID, including the timestamp. * @param {string} [alphabet="123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz"] - The set of characters to use for generating the ID. * @returns {string} The generated timestamp-based ID. */ function timestampID ( size: number = 21, alphabet: string = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz" ): string { let result: string = Date.now().toString(36).padStart(10, "0") + "-"; let dl: number = alphabet.length; let pos: number; let index: number = ((size > 11) ? size : 12) - 11; while (index--) { do { pos = crypto.getRandomValues(new Uint8Array(1))[0]; } while (pos >= dl); result += alphabet[pos]; } return result; } /** String API **/ /** * @description Encodes a string to Base64 format. * * @param {any} str - The string to encode. * @returns {string} The Base64 encoded string. */ function b64Encode (str: any): string { return btoa(encodeURIComponent(String(str)).replace(/%([0-9A-F]{2})/g, function toSolidBytes (_match, p1): string { // @ts-ignore return String.fromCharCode("0x" + p1); } )); } /** * @description Decodes a Base64 encoded string. * * @param {string} str - The Base64 encoded string to decode. * @returns {string} The decoded string. */ function b64Decode (str: any): string { return decodeURIComponent(atob(String(str)).split("").map(function (c) { return "%" + ("00" + c.charCodeAt(0).toString(16)).slice(-2); }).join("")); } /** * @description Counts the occurrences of a substring in a string. * * @param {unknown} str - The string to search in. * @param {unknown} substr - The substring to search for. * @returns {number} The number of occurrences of the substring. */ function strCount (str: unknown, substr: unknown): number { let count = (String(str)?.split(String(substr)) ?? []).length - 1; return count < 0 ? 0 : count; } /** * @description Truncates a string to a specified length, optionally adding an omission string. * * @param {string} str - The string to truncate. * @param {number} newLength - The maximum length of the truncated string. * @param {string} [omission=""] - The string to append to the truncated string. * @returns {string} The truncated string. */ function strTruncate ( str: any, newLength: number, omission: string = ""): string { str = String(str); omission = String(omission); let strUC = Array.from(str); if (newLength >= strUC.length) { return str; } return strUC.slice(0, newLength-Array.from(omission).length).join("") + omission; } /** * @description Converts the first character of each word in a string to uppercase and the rest to lowercase. * * @param {any} str - The string to convert. * @returns {string} The converted string. */ const strPropercase = (str: any): string => String(str).trim().split(" ").map(function (value: string) { let chars = Array.from(value).map( (c: string): string => c.toLowerCase() ); if (chars.length) { chars[0] = chars[0].toUpperCase(); } return chars.join(""); }).join(" "); /** * @description Converts the first character of each word in a string to uppercase and the rest to lowercase. * * @param {any} str - The string to convert. * @returns {string} The converted string. */ const strTitlecase = (str: any): string => String(str).trim().split(" ").map(function (value: string) { let chars = Array.from(value).map( (c: string): string => c.toLowerCase() ); if (chars.length) { chars[0] = chars[0].toUpperCase(); } return chars.join(""); }).join(" "); /** * @description Capitalizes the first character of a string and converts the rest to lowercase. * * @param {any} str - The string to capitalize. * @returns {string} The capitalized string. */ function strCapitalize (str: any): string { let chars = [...String(str).trim().toLowerCase()]; if (chars.length) { chars[0] = chars[0].toUpperCase(); } return chars.join(""); } /** * @description Converts the first character of a string to uppercase. * * @param {any} str - The string to modify. * @returns {string} The modified string. */ function strUpFirst (str: any): string { let chars = [...String(str).trim()]; if (chars.length) { chars[0] = chars[0].toUpperCase(); } return chars.join(""); } /** * @description Converts the first character of a string to lowercase. * * @param {any} str - The string to modify. * @returns {string} The modified string. */ function strDownFirst (str: any): string { let chars = [...String(str).trim()]; if (chars.length) { chars[0] = chars[0].toLowerCase(); } return chars.join(""); } /** * @description Reverses the characters in a string. * * @param {any} str - The string to reverse. * @returns {string} The reversed string. */ const strReverse = (str: any): string => Array.from(String(str)).reverse().join(""); /** * @description Returns an array of Unicode code points for each character in a string. * * @param {any} str - The string to process. * @returns {number[]} An array of Unicode code points. */ const strCodePoints = (str: any): any[] => Array.from(String(str), (value: string): number | undefined => value.codePointAt(0)); /** * @description Creates a string from an array or iterable of Unicode code points. * * @param {Iterable} iterator - An array or iterable of Unicode code points. * @returns {string} The constructed string. */ const strFromCodePoints = ([...array]): string => String.fromCodePoint(...array); /** * @description Gets or sets a unicode character at a specified index in a string. * * @param {string} str - The string to modify. * @param {number} index - The index of the character to get or set. */ function strAt (str: string, index: number, newChar?: string): string { let chars: string[] = Array.from(String(str)); if (newChar == null) { return chars.at(index) || ""; } index = index < 0 ? chars.length + index : index; if (index > chars.length) { return chars.join(""); } chars[index] = newChar; return chars.join(""); } /** * @description Splices a string by removing a specified number of characters at a given index and optionally adding new characters. * * @param {string} str - The string to splice. * @param {number} index - The index at which to start splicing. * @param {number} count - The number of characters to remove. * @param {string} [add] - The string to add at the splice index. * @returns {string} The spliced string. */ const strSplice = (str: string, index: number,count: number, ...add: any[]): string => Array.from(str).toSpliced(index, count, add.join("")).join(""); /** * @description Removes HTML tags from a string. * * @param {any} str - The string from which to remove HTML tags. * @returns {string} The string without HTML tags. */ const strHTMLRemoveTags = (str: any): string => String(str).trim().replace(/<[^>]*>/g, " ").replace(/\s{2,}/g, " ").trim(); /** * @description Escapes special HTML characters in a string. * * @param {any} str - The string to escape. * @returns {string} The escaped string. */ const strHTMLEscape = (str: any): string => String(str).trim() .replace(/&/g, "&") .replace(//g, ">") .replace(/"/g, """) .replace(/'/g, "'"); /** * @description Unescapes special HTML characters in a string. * * @param {any} str - The string to unescape. * @returns {string} The unescaped string. */ const strHTMLUnEscape = (str: string): string => String(str).trim() .replace(/&/g, "&").replace(/&/g, "&") .replace(/</g, "<").replace(/</g, "<") .replace(/>/g, ">").replace(/>/g, ">") .replace(/"/g, '"').replace(/"/g, '"') .replace(/'/g, "'").replace(/'/g, "'"); /** Type API **/ /** * @description Checks if the given value is NonNullable (not null or undefined). * * @param {unknown} value - The value to check. * @returns True if the value is a NonNullable, false otherwise. */ const isNonNullable = (value: unknown): value is NonNullable => value != null; /** * @description Checks if the given value is NonNullablePrimitive. * * @param {unknown} value - The value to check. * @returns True if the value is a NonNullable, false otherwise. */ const isNonNullablePrimitive = (value: unknown): value is NonNullablePrimitive => value != null && typeof value !== "object" && typeof value !== "function"; /** * @description Checks if a value is an arrow function. * @note There is no built-in type for ArrowFunction. * * @param {unknown} value * @returns {boolean} true if the value is an arrow function, false otherwise. */ function isArrowFunction (value: unknown): value is ArrowFunction { if (typeof value !== "function" || ("prototype" in value && value.prototype !== undefined) || !(value.toString().includes("=>")) ) { return false; } /* Arrow functions cannot be used as constructors, so this will throw an error if it's an arrow function */ try { // @ts-expect-error new value(); return false; } catch (error) { return true; } } /** * @description Checks if a value is an async iterator. * * @param {unknown} value * @returns {boolean} true if the value is an async iterator, false otherwise. */ const isAsyncIterator = (value: unknown): value is AsyncIterator => value != null && typeof (value as any).next === "function" && typeof (value as any)[Symbol.asyncIterator] === "function"; /** * @description Checks if all items in an iterable or iterator match the expected type(s) or constructor(s). * * @param {IterableLike} iter - The iterable or iterator to check. * @param {string | Function | Array} expectedType - The expected type(s) or constructor(s) for the items. * @param {boolean} [Throw=false] - If true, throws a TypeError on mismatch; otherwise returns false. * @returns {boolean} True if all items match the expected type(s) or constructor(s), false otherwise. * @throws {TypeError} If `iter` is not iterable or iterator, or if `expectedType` is invalid, or if a mismatch occurs and `Throw` is true. */ function isTypedCollection ( iter: IterableLike, expectedType: string | Function | Array, Throw: boolean = false): boolean { /* helper functions */ const _typeOf = (value: any): string => value === null ? "null" : typeof value; const _isIterator = (value: any): boolean => value != null && typeof value === "object" && typeof value.next === "function"; const _isIterable = (value: any): boolean => value != null && typeof value[Symbol.iterator] === "function"; /* Validate `iter` */ if (!_isIterator(iter) && !_isIterable(iter)) { throw new TypeError( `[isTypedCollection] TypeError: iter must be iterable or iterator. Got ${_typeOf(iter)}` ); } /* Validate `expected` */ if (!(["string", "function"].includes(typeof expectedType)) && !Array.isArray(expectedType)) { throw new TypeError( `[isTypedCollection] TypeError: expectedType must be string, function, array. Got ${_typeOf(expectedType)}` ); } /* Validate `Throw` */ if (typeof Throw !== "boolean") { throw new TypeError( `[isTypedCollection] TypeError: Throw has to be a boolean. Got ${typeof Throw}` ); } /* Normalize expected to an array */ let expectedArray: any[] = Array.isArray(expectedType) ? expectedType : [expectedType]; /* Check values of iter against expected types or constructors */ let matched: boolean = true; for (let value of iter as Iterable) { const valueType: string = _typeOf(value); matched = expectedArray.some( function (item: string | Function): boolean { if (typeof item === "string") { return valueType === item; } if (typeof item === "function") { return value != null && value instanceof item; } /* validate expected array elements */ throw new TypeError( `[isTypedCollection] TypeError: expectedType array elements have to be a string or function. Got ${typeof item}` ); } ); if (!matched) { break; } } /* Throw error if mismatch and `Throw` is true */ if (Throw && !matched) { let eNames: string = expectedArray.map((item: any): string => (typeof item === "string" ? item.toString() : item.name ?? "anonymous") ).join(", "); throw new TypeError( `[isTypedCollection] TypeError: one or more items are not ${eNames}` ); } return matched; } /** * @description Checks if a value matches the expected type(s) or constructor(s). * * @param {any} value - The value to check. * @param {string | Function | Array | undefined} expectedType - The expected type(s) or constructor(s). * @param {boolan} Throw * @returns {string | Function | boolean} */ function is ( value: any, expectedType?: string | Function | Array | undefined, Throw: boolean = false): string | Function | boolean { /* Validate `expected` */ if (!(["string", "function", "undefined"].includes(typeof expectedType)) && !Array.isArray(expectedType)) { throw new TypeError( `[is] TypeError: expectedType must be string, function, array or undefined. Got ${typeof expectedType}` ); } /* Validate `Throw` */ if (typeof Throw !== "boolean") { throw new TypeError( `[is] TypeError: Throw has to be a boolean. Got ${typeof Throw}` ); } /* Determine the type of `value` */ const vType: string = (value === null ? "null" : typeof value); /* If no expected type provided, return type or constructor */ if (expectedType == null) { return vType === "object" ? Object.getPrototypeOf(value)?.constructor ?? "object" : vType; } /* Normalize expected to an array */ let expectedArray: Array = Array.isArray(expectedType) ? expectedType : [expectedType]; /* Check against expected types or constructors */ let matched: boolean = expectedArray.some( function (item: string | Function) { if (typeof item === "string") { return vType === item; } if (typeof item === "function") { return value != null && value instanceof item; } /* validate expected array elements */ throw new TypeError( `[is] TypeError: expectedType array elements have to be a string or function. Got ${typeof item}` ); } ); /* Throw error if mismatch and `Throw` is true */ if (Throw && !matched) { let vName: string = value.toString ? value.toString() : Object.prototype.toString.call(value); let eNames: string = expectedArray.map((item: any): string => (typeof item === "string" ? item.toString() : item.name ?? "anonymous") ).join(", "); throw new TypeError(`[is] TypeError: ${vName} is not a ${eNames}`); } return matched; } /** * @description Converts a given value to an object, symbol, or function. * * @param {unknown} value - The value to convert. * @returns {Object | symbol | Function} The converted object, symbol, or function. * @throws {TypeError} If the value is null or undefined. */ function toObject (value: unknown): Object | symbol | Function { if (value == null) { throw new TypeError(`[toObject] error: ${value}`); } return (["object", "function"].includes(typeof value)) ? value : Object(value); } /* toPrimitive(value: unknown): primitive | object | symbol | Function */ /** * @description Converts wrapper objects to their corresponding primitive values. * * @param {unknown} value - The value to convert. * @returns {any} The primitive value or the original object if not a wrapper. */ function toPrimitive (value: unknown): any { if (value == null || typeof value !== "object") { return value; } const vType = Object.prototype.toString.call(value).slice(8, -1); if (["Boolean", "BigInt", "Number", "String", "Symbol"].includes(vType)) { return value.valueOf(); } return value; } /** * @description This function is a general purpose, type safe, predictable stringifier. Converts a value into a human-readable string for error messages Handles symbols, functions, nullish, circular references, etc. * * @param {unknown} value The value to inspect. * @returns {string} */ function toSafeString (value: unknown): string { const seen = new WeakSet(); function replacer (_key: string, value: unknown): any { if (typeof value === "function") { return `[Function: ${value.name || "anonymous"}]`; } if (typeof value === "symbol") { return value.toString(); } if (value instanceof Date) { return `Date(${value.toISOString()})`; } if (value instanceof Error) { return `${value.name}: ${value.message}, ${value.stack ?? ""}`; } if (value && typeof value === "object") { if (seen.has(value)) { return "[Circular]" }; seen.add(value); } return value; } if (["undefined", "null", "string", "number", "boolean", "bigint"] .includes(value === null ? "null" : typeof value)) { return String(value); } if (Array.isArray(value)) { return `[${value.map(v => toSafeString(v)).join(", ")}]`; } if (value instanceof Map) { return `Map(${value.size}){${Array.from(value.entries()).map(([k, v]): string => `${toSafeString(k)} => ${toSafeString(v)}`).join(", ")}}`; } if (value instanceof Set) { return `Set(${value.size}){${Array.from(value.values()).map(v => toSafeString(v)).join(", ")}}`; } try { return JSON.stringify(value, replacer) ?? String(value); } catch (_e) { return String(value); } } /** * @description Checks if a value is a valid property key (string or symbol). * * @param {unknown} value - The value to check. * @returns {boolean} True if the value is a valid property key, otherwise false. */ const isPropertyKey = (value: unknown): value is PropertyKey => typeof value === "string" || typeof value === "symbol"; /** * @description Converts a value to a property key (string or symbol). * * @param {unknown} value - The value to convert. * @returns {string | symbol} The converted property key. */ const toPropertyKey = (value: unknown): PropertyKey => typeof value === "symbol" ? value : String(value); /** * Checks if a value is a valid array index (integer between 0 and Number.MAX_SAFE_INTEGER). * * @param value - The value to check. * @returns True if the value is a valid array index, otherwise false. */ const isIndex = (value: unknown): value is number => Number.isSafeInteger(value) && (value as number) >= 0 && (value as number) <= Number.MAX_SAFE_INTEGER && 1 / (value as number) !== 1 / -0; /** * Checks if a value is a valid array length (integer between 0 and Number.MAX_SAFE_INTEGER). * * @param value - The value to check. * @returns True if the value is a valid array length, otherwise false. */ const isLength = (value: unknown): value is number => Number.isSafeInteger(value) && (value as number) >= 0 && (value as number) <= Number.MAX_SAFE_INTEGER && 1 / (value as number) !== 1 / -0; /** * @description Converts a value to a valid array index (unsigned integer). * * @param {unknown} value - The value to convert. * @returns {number} The converted unsigned integer index. */ function toIndex (value: any): number { value = ((value = Math.trunc(+value)) !== value || value === 0) ? 0 : value; if (value < 0 || value > Number.MAX_SAFE_INTEGER) { throw new RangeError(`[toIndex] RangeError: ${value}`); } return value; } /** * @description Converts a value to a valid length (unsigned integer). * * @param {unknown} value - The value to convert. * @returns {number} The converted unsigned integer length. */ function toLength (value: any): number { value = ((value = Math.trunc(+value)) !== value || value === 0) ? 0 : value; return Math.min(Math.max(value, 0), Number.MAX_SAFE_INTEGER); } /** * Extended typeof operator with "null" type as string. * * @param {unknown} value * @returns string */ const typeOf = (value: unknown): | "null" | "undefined" | "number" | "bigint" | "boolean" | "string" | "symbol" | "object" | "function" => value === null ? "null" : typeof value; /** * @description Checks if two values are of the same type. * * @param {any} value1 - The first value to compare. * @param {any} value2 - The second value to compare. * @returns {boolean} True if both values are of the same type, false otherwise. */ const isSameType = (value1: any, value2: any): boolean => (value1 == null || value2 == null) ? (value1 === value2) : (typeof value1 === typeof value2); /** * @description Checks if two values are instances of the same constructor. * * @param {any} value1 - The first value to check. * @param {any} value2 - The second value to check. * @param {Function} Contructor - The constructor function to check against. */ const isSameInstance = (value1: any, value2: any, Contructor: Function): boolean => value1 instanceof Contructor && value2 instanceof Contructor; /* type CoercedObjects = String | Number | BigInt | Boolean | Symbol; */ /** * @description Checks if a value is an coerced object (Number, String, etc.). * * @param {unknown} value The value to check. * @returns False if the value is not a coerced object, otherwise the constructor function. */ function isCoercedObject (value: unknown): Function | boolean { if (value != null && typeof value === "object") { if (value instanceof Number) { return Number; } if (value instanceof String) { return String; } if (value instanceof Boolean) { return Boolean; } if (value instanceof BigInt) { return BigInt; } if (typeof value.valueOf?.() === "symbol") { return Symbol; } } return false; } /** * @description Performs a deep strict equality check between two values. * * @param {any} value1 - The first value to compare. * @param {any} value2 - The second value to compare. * @returns {boolean} True if the values are deeply strictly equal, false otherwise. */ function isDeepStrictEqual (value1: any, value2: any): boolean { /* helper functions */ const _deepType = (value: any): string => (value === null) ? "null" : (value !== value) ? "NaN" : (typeof value); const _isPrimitive = (value: any): boolean => value == null || (typeof value !== "object" && typeof value !== "function"); const _isObject = (value: any): boolean => value != null && typeof value === "object"; const _isSameInstance = (value1: any, value2: any, Class: Function): boolean => value1 instanceof Class && value2 instanceof Class; const _classof = (value: any): string => Object.prototype.toString.call(value).slice(8, -1).toLowerCase(); const _ownKeys = (value: object): any[] => [...Object.getOwnPropertyNames(value), ...Object.getOwnPropertySymbols(value)]; /* strict equality helper function */ const _isEqual = (value1: any, value2: any): boolean => Object.is(value1, value2); /* not strict equality helper function */ /* const _isEqual = (value1, value2): boolean => value1 == value1 || (value1 !== value1 && value2 !== value2); */ /* primitives: Boolean, Number, BigInt, String + Function + Symbol */ if (_isEqual(value1, value2)) { return true; } /* Object Wrappers (Boolean, Number, BigInt, String) */ if (_isObject(value1) && _isPrimitive(value2) && _classof(value1) === typeof value2) { return _isEqual(value1.valueOf(), value2); } if (_isPrimitive(value1) && _isObject(value2) && typeof value1 === _classof(value2)) { return _isEqual(value1, value2.valueOf()); } /* type (primitives, object, null, NaN) */ if (_deepType(value1) !== _deepType(value2)) { return false; } /* objects */ if (_isObject(value1) && _isObject(value2)) { /* objects / same memory adress */ if (_isEqual(value1, value2)) { return true; } /* objects / not same constructor */ if (Object.getPrototypeOf(value1).constructor !== Object.getPrototypeOf(value2).constructor ) { return false; } /* objects / WeakMap + WeakSet */ if (_isSameInstance(value1, value2, WeakMap) || _isSameInstance(value1, value2, WeakSet)) { return _isEqual(value1, value2); } /* objects / Wrapper objects: Number, Boolean, String, BigInt */ if (_isSameInstance(value1, value2, Number) || _isSameInstance(value1, value2, Boolean) || _isSameInstance(value1, value2, String) || _isSameInstance(value1, value2, BigInt) ) { return _isEqual(value1.valueOf(), value2.valueOf()); } /* objects / Array */ if (Array.isArray(value1) && Array.isArray(value2)) { if (value1.length !== value2.length) { return false; } if (value1.length === 0) { return true; } return value1.every((value: unknown, index: any): boolean => isDeepStrictEqual(value, value2[index]) ); } /* objects / TypedArrays */ if ( _isSameInstance(value1, value2, Int8Array) || _isSameInstance(value1, value2, Uint8Array) || _isSameInstance(value1, value2, Uint8ClampedArray) || _isSameInstance(value1, value2, Int16Array) || _isSameInstance(value1, value2, Uint16Array) || _isSameInstance(value1, value2, Int32Array) || _isSameInstance(value1, value2, Uint32Array) || ("Float16Array" in globalThis ? _isSameInstance(value1, value2, Float16Array) : false ) || _isSameInstance(value1, value2, Float32Array) || _isSameInstance(value1, value2, Float64Array) || _isSameInstance(value1, value2, BigInt64Array) || _isSameInstance(value1, value2, BigUint64Array) ) { if (value1.length !== value2.length) { return false; } if (value1.length === 0) { return true; } return value1.every((value: unknown, index: any): boolean => _isEqual(value, value2[index])); } /* objects / ArrayBuffer */ if (_isSameInstance(value1, value2, ArrayBuffer)) { if (value1.byteLength !== value2.byteLength) { return false; } if (value1.byteLength === 0) { return true; } let xTA = new Int8Array(value1), yTA = new Int8Array(value2); return xTA.every((value: unknown, index: any): boolean => _isEqual(value, yTA[index])); } /* objects / DataView */ if (_isSameInstance(value1, value2, DataView)) { if (value1.byteLength !== value2.byteLength) { return false; } if (value1.byteLength === 0) { return true; } for (let index = 0; index < value1.byteLength; index++) { if (!_isEqual(value1.getUint8(index), value2.getUint8(index))) { return false; } } return true; } /* objects / Map */ if (_isSameInstance(value1, value2, Map)) { if (value1.size !== value2.size) { return false; } if (value1.size === 0) { return true; } return [...value1.keys()].every((value: unknown): boolean => isDeepStrictEqual(value1.get(value), value2.get(value))); } /* objects / Set */ if (_isSameInstance(value1, value2, Set)) { if (value1.size !== value2.size) { return false; } if (value1.size === 0) { return true; } return [...value1.keys()].every((value: unknown): boolean => value2.has(value)); } /* objects / RegExp */ if (_isSameInstance(value1, value2, RegExp)) { return _isEqual(value1.lastIndex, value2.lastIndex) && _isEqual(value1.flags, value2.flags) && _isEqual(value1.source, value2.source); } /* objects / Error */ if (_isSameInstance(value1, value2, Error)) { return isDeepStrictEqual( Object.getOwnPropertyNames(value1) .reduce( function (acc: any, k: any): object { acc[k] = value1[k]; return acc; }, {} ), Object.getOwnPropertyNames(value2) .reduce( function (acc: any, k: any): object { acc[k] = value2[k]; return acc; }, {} ) ); } /* objects / Date */ if (_isSameInstance(value1, value2, Date)) { return _isEqual(+value1, +value2); } /* objects / Proxy -> not detectable */ /* objects / Objects */ let value1Keys: any[] = _ownKeys(value1); let value2Keys: any[] = _ownKeys(value2); if (value1Keys.length !== value2Keys.length) { return false; } if (value1Keys.length === 0) { return true; } return value1Keys.every((key: any): boolean => isDeepStrictEqual(value1[key], value2[key]) ); } /* default return false */ return false; } /** * Checks if a value is empty. * * - `null`, `undefined`, and `NaN` are empty. * - Arrays, TypedArrays, and strings are empty if length === 0. * - Maps and Sets are empty if size === 0. * - ArrayBuffer and DataView are empty if byteLength === 0. * - Iterable objects are empty if they have no elements. * - Plain objects are empty if they have no own properties. * * @param {any} value The value to check. * @returns boolean */ function isEmpty (value: any): boolean { const _isObject = (value: unknown): value is object => value != null && (typeof value === "object" || typeof value === "function"); /** * Checks if a value is a TypedArray (Int8Array, etc.). * * @param {any} value The value to check. * @returns boolean */ const _isTypedArray = (value: unknown): value is TypedArray => ArrayBuffer.isView(value) && !(value instanceof DataView); /* Check undefined, null, NaN */ if (value == null || Number.isNaN(value)) { return true; } /* Check Array, TypedArrays, string, String */ if (Array.isArray(value) || _isTypedArray(value) || typeof value === "string" || value instanceof String) { return (value as any).length === 0; } /* Check Map and Set */ if (value instanceof Map || value instanceof Set) { return value.size === 0; } /* Check ArrayBuffer and DataView */ if (value instanceof ArrayBuffer || value instanceof DataView) { return value.byteLength === 0; } /* Check Iterable objects */ if (typeof value[Symbol.iterator] === "function") { const it = value[Symbol.iterator](); return it.next().done; /* avoids consuming entire iterator */ } /* Check Iterator objects */ if ("Iterator" in globalThis ? (value instanceof Iterator) : (value != null && typeof value === "object" && typeof value.next === "function")) { try { /* Has at least one element */ for (let _item of value) { return false; } return true; } catch { /* Not iterable */ } } /* Other objects - check own properties (including symbols) */ if (_isObject(value)) { const keys: any[] = [ ...Object.getOwnPropertyNames(value), ...Object.getOwnPropertySymbols(value) ]; if (keys.length === 0) { return true; } /* Special case: object with single "length" property that is 0 */ if (keys.length === 1 && keys[0] === "length" && (value as { length?: unknown }).length === 0) { return true; } } /* Return default false */ return false; } /** * @description Checks if the given value is a Proxy. * * @param {unknown} value - The value to check. * @returns True if the value is a Proxy, false otherwise. */ const isProxy = (value: any): boolean => Boolean(value != null && value.__isProxy); /** * @description Checks if the given value is an Async Generator Function. * @note AsyncGeneratorFunction -> builtin TS type in lib.es2018.asyncgenerator.ts * * @param {unknown} value - The value to check. * @returns True if the value is an Async Generator Function, false otherwise. */ const isAsyncGeneratorFunction = (value: unknown): value is AsyncGeneratorFunction => Object.getPrototypeOf(value).constructor === Object.getPrototypeOf(async function*() {}).constructor; /** * @description Checks if the given value is a plain object (i.e., created using {} or new Object()). * * @param {unknown} value - The value to check. * @returns True if the value is a plain object, false otherwise. */ const isPlainObject = (value: unknown): boolean => value != null && typeof value === "object" && (Object.getPrototypeOf(value) === Object.prototype || Object.getPrototypeOf(value) === null); /** * @description Checks if the given value is an object. * * @param {unknown} value - The value to check. * @returns True if the value is a object, false otherwise. */ const isObject = (value: unknown): value is object => value != null && (typeof value === "object" || typeof value === "function"); /** * @description Checks if the given value is a Function. * @note type Function -> built-in TS type in lib.es5.d.ts * * @param {unknown} value - The value to check. * @returns True if the value is a function, false otherwise. */ const isFunction = (value: unknown): value is Function => typeof value === "function"; /** * @description Checks if a value is an arraylike object. * * @param {unknown} value The value to check. * @returns boolean */ function isArraylike (value: unknown): value is ArrayLike { if (value == null || (typeof value !== "object" && typeof value !== "string")) { return false; } const maybe = value as { length?: unknown }; if (typeof maybe.length !== "number") { return false; } const len: number = maybe.length; return len >= 0 && Number.isFinite(len); } /** * @description Checks if the given value is null. * * @param {unknown} value - The value to check. * @returns True if the value is null, false otherwise. */ const isNull = (value: unknown): value is null => value === null; /** * @description Checks if the given value is undefined. * * @param {unknown} value - The value to check. * @returns True If the value is undefined, false otherwise. */ const isUndefined = (value: unknown): value is undefined => value === undefined; /** * @description Checks if the given value is Nullish (null or undefined). * From MDN: The values null and undefined are nullish. * * @param {unknown} value - The value to check. * @returns True if the value is a Nullish, false otherwise. */ const isNullish = (value: unknown): value is Nullish => value == null; /** * @description Checks if the given value is Primitive. * * @param {unknown} value - The value to check. * @returns True if the value is Primitive, false otherwise. */ const isPrimitive = (value: unknown): value is Primitive => value == null || (typeof value !== "object" && typeof value !== "function"); /** * Tests whether a value is an Iterator. * * @param {unknown} value The value to check. * @returns {boolean} Return true if value is an Iterator, false if not. * @private */ const isIterator = (value: unknown): value is Iterator => "Iterator" in globalThis ? value instanceof Iterator : (value != null && typeof value === "object" && typeof (value as any).next === "function"); /** * Tests whether a value is a RegExp. * * @param {unknown} value The value to check. * @returns {boolean} Return true if value is a RegExp, false if not. */ const isRegexp = (value: unknown): value is RegExp => value instanceof RegExp; /** * Tests whether a value is a HTML element. * * @param {unknown} value The value to check. * @returns {boolean} Return true if value is a HTML element, false if not. */ const isElement = (value: any): boolean => value != null && typeof value === "object" && value.nodeType === 1; /** * Tests whether a value is an Iterable. * * @param {unknown} value The value to check. * @returns {boolean} Return true if value is an Iterable, false if not. * @private */ const isIterable = (value: unknown): value is Iterable => value != null && typeof (value as any)[Symbol.iterator] === "function"; /** * Tests whether a value is an Async Iterable. * * @param {unknown} value The value to check. * @returns {boolean} Return true if value is an Async Iterable, false if not. */ const isAsyncIterable = (value: unknown): boolean => value != null && typeof (value as any)[Symbol.asyncIterator] === "function"; /** * @description Checks if the given value is a TypedArray (Int8Array, etc.). * * @param {unknown} value - The value to check. * @returns True if the value is a TypedArray, false otherwise. */ const isTypedArray = (value: unknown): value is TypedArray => ArrayBuffer.isView(value) && !(value instanceof DataView); /** * @description Checks if the given value is a Generator Function. * @note GeneratorFunction -> built-in TS type in lib.es2015.generator.d.ts * * @param {unknown} value - The value to check. * @returns True if the value is a Generator Function, false otherwise. */ const isGeneratorFunction = (value: unknown): value is GeneratorFunction => Object.getPrototypeOf(value).constructor === Object.getPrototypeOf(function*(){}).constructor; /** * @description Checks if the given value is an Async Function. * * @param {unknown} value - The value to check. * @returns True if the value is an Async Function, false otherwise. */ const isAsyncFunction = (value: unknown): value is AsyncFunction => Object.getPrototypeOf(value).constructor === Object.getPrototypeOf(async function(){}).constructor; /** Collections API **/ /** * Returns an array wrapping the value, or the original array if already one. * * @param {unknown} value * @returns {any[]} An array wrapping the value, or the original array if already one. */ const castArray = (value: unknown): any[] => typeof value === "undefined" ? [] : (Array.isArray(value) ? value : [value]); /** * @description Returns an array with truthy values (but keeps `0`) from the given Iterable or ArrayLike object. * * @param {IterableAndIteratorAndArrayLike} iter * @returns any[] */ const compact = (iter: IterableLikeAndArrayLike): any[] => Array.from(iter as Iterable | ArrayLike).filter( (value: unknown): boolean => Boolean(value) || value === 0 || value === 0n ); /** * @description Returns an array with unique values from the given Iterable. * * @param {IterableLike} iter - The iterable to process. * @param {string | Function} [resolver] - A property name or function to determine uniqueness. * @returns {any[] | void} An array with unique values, or void if no iterable is provided. */ function unique ( iter: IterableLike, resolver?: string | Function | null | undefined): any[] | void { if (resolver == null) { return [...new Set(iter as Iterable)]; } if (typeof resolver === "string") { return Array.from(iter as Iterable).reduce(function (acc: any[], item: any) { if (acc.every((item2: any): boolean => item2[resolver] !== item[resolver])) { acc.push(item); } return acc; }, []); } if (typeof resolver === "function") { let cache = new Map(); for (let item of iter as Iterable) { let key = resolver(item); if (!cache.has(key)) { cache.set(key, item); } } return [...cache.values()]; } } /** * @description Counts the number of elements in an iterable that satisfy a given condition. * * @param {IterableLike} iter - The iterable to process. * @param {Function} callback - The callback function that tests each element. * @returns {number} The count of elements that satisfy the condition. */ function count (iter: IterableLike, callback: Function): number { let index: number = 0; let result: number = 0; for (let item of iter as Iterable) { if (callback(item, index++)) { result++; } } return result; } /** * @description Creates a deep clone of an array, including nested arrays. * * @param {any[]} array - The array to clone. * @returns {any[]} A deep clone of the input array. */ function arrayDeepClone ([...array]: any[]): any[] { const _ADC = (value: unknown): any => Array.isArray(value) ? Array.from(value, _ADC) : value; return _ADC(array); } /** * @description Returns all elements of an iterable except the last one. * * @param {IterableLike} iter - The iterable to process. * @returns {any[]} An array containing all elements except the last one. */ const initial = ([...array]: any[]): unknown[] => array.slice(0, -1); /** * @description Returns a new array with the elements of the input iterable shuffled randomly. * * @param {IterableLike} iter - The iterable to shuffle. * @returns {any[]} A new array with the elements shuffled. */ function shuffle ([...array]: any[]): unknown[] { for (let index = array.length - 1; index > 0; index--) { let pos = Math.floor(Math.random() * (index + 1)); [array[index], array[pos]] = [array[pos], array[index]]; } return array; } /** * @description Splits an iterable into two arrays based on a predicate function. * * @param {IterableLike} iter - The iterable to partition. * @param {Function} callback - The predicate function to test each element. * @returns {any[][]} An array containing two arrays: the first with elements that satisfy the predicate, and the second with elements that do not. */ const partition = ([...array]: any[], callback: Function): any[] => // @ts-ignore [array.filter(callback), array.filter((value, index, a): boolean => !(callback(value, index, a)))]; /** * @description Returns the minimum value from the provided arguments. * * @param {...any} args - The values to compare. * @returns {any} The minimum value among the provided arguments. */ const min = (...args: any[]): any => args.reduce( (acc: any, value: any): any => (value < acc ? value : acc), args[0] ); /** * @description Returns the maximum value from the provided arguments. * * @param {...any} args - The values to compare. * @returns {any} The maximum value among the provided arguments. */ const max = (...args: any[]): any => args.reduce((acc: any, value: any): any => (value > acc ? value : acc), args[0] ); /** * @description Returns an array with the given value repeated n times. * * @param {unknown} value - The value to repeat. * @param {number} [num=100] - The number of times to repeat the value. */ const arrayRepeat = (value: unknown, num: number = 100): any[] => Array(num).fill(value); /** * @description Returns an array by cycling through the elements of the input iterable n times. * * @param {IterableLike} iter - The iterable to cycle through. * @param {number} [num=100] - The number of times to cycle through the iterable. * @returns {any[]} An array containing the cycled elements. */ const arrayCycle = ([...array]: any[], num: number = 100): any[] => Array(num).fill(array).flat(); /** * @description Returns an array representing a range of numbers. * * @param {number} [start=0] - The starting number of the range. * @param {number} [end=99] - The ending number of the range. * @param {number} [step=1] - The step between each number in the range. * @returns {any[]} An array representing the range of numbers. */ const arrayRange = ( start: number = 0, end: number = 99, step: number = 1): any[] => Array.from( {length: (end - start) / step + 1}, (_v, i: number): number => start + (i * step) ); /** * @description Merges multiple iterables into an array of tuples, where each tuple contains elements from the input iterables at the same index. * * @param {...IterableLike} args - The iterables to zip together. * @returns {any[][]} An array of tuples containing elements from the input iterables. */ function zip (...args: any[]): any[] { args = args.map((value: IterableLike): any => Array.from(value as Iterable)); return Array.from({length: Math.min(...args.map(v => v.length))}) .map((_, i: number): any[] => args.map(v => v[i])); } /** * @description Splits an array of tuples into multiple arrays, where each array contains elements from the input tuples at the same index. * * @param {IterableLike} iter - The iterable of tuples to unzip. * @returns {any[][]} An array of arrays containing elements from the input tuples. */ const unzip = ([...array]: any[]): any[] => array.map((iter: IterableLike): any[] => Array.from(iter as Iterable)) .reduce(function (acc, value): any[] { value.forEach(function (item, index): void { if (!Array.isArray(acc[index])) { acc[index] = []; } acc[index].push(item); }); return acc; }, []); /** * @description Merges two iterables into an object, where elements from the first iterable are used as keys and elements from the second iterable are used as values. * * @param {IterableLike} array1 - The iterable to use as keys. * @param {IterableLike} array2 - The iterable to use as values. * @returns {object} An object containing key-value pairs from the input iterables. */ function zipObj ([...array1]: any[], [...array2]: any[]): MapLike { let result: MapLike = {}; let length: number = Math.min(array1.length, array2.length); for (let index = 0; index < length; index++) { result[array1[index]] = array2[index]; } return result; } /** * @description Adds a value to an array if it does not already exist in the array. * * @param {any[]} array - The array to add the value to. * @param {unknown} value - The value to add to the array. * @returns {boolean} True if the value was added, false if it already existed. */ const arrayAdd = (array: any[], value: unknown): boolean => !array.includes(value) ? !!array.push(value) : false; /** * @description Clears all elements from an array. * * @param {any[]} array - The array to clear. * @returns {any[]} The cleared array. */ function arrayClear (array: any[]): any[] { array.length = 0; return array; } /** * @description Removes a value from an array. If `all` is true, removes all occurrences of the value. * * @param {any[]} array - The array to remove the value from. * @param {unknown} value - The value to remove from the array. * @param {boolean} [all=false] - Whether to remove all occurrences of the value. */ function arrayRemove ( array: any[], value: unknown, all: boolean = false): boolean { let found: boolean = array.indexOf(value) > -1; if (!all) { let pos = array.indexOf(value); if (pos > -1) { array.splice(pos, 1); } } else { let pos = -1; while ((pos = array.indexOf(value)) > -1) { array.splice(pos, 1); } } return found; } /** * @description Removes elements from an array that satisfy a given condition. If `all` is true, removes all occurrences that satisfy the condition. * * @param {any[]} array - The array to remove elements from. * @param {Function} callback - The callback function that tests each element. * @param {boolean} [all=false] - Whether to remove all occurrences that satisfy the condition. * @returns {boolean} True if any elements were removed, false otherwise. */ function arrayRemoveBy ( array: any[], callback: Function, all: boolean = false): boolean { // @ts-ignore let found: boolean = array.findIndex(callback) > -1; if (!all) { // @ts-ignore let pos = array.findIndex(callback); if (pos > -1) { array.splice(pos, 1); } } else { let pos = -1; // @ts-ignore while ((pos = array.findIndex(callback)) > -1) { array.splice(pos, 1); } } return found; } /** * @description Merges multiple arrays or values into the target array. * * @param {any[]} target - The array to merge into. * @param {...any} sources - The arrays or values to merge into the target array. * @returns {any[]} The merged array. */ function arrayMerge (target: any[], ...sources: any[]): any[] { target.push(... [].concat(...sources) ); return target; } /** * @description Generates a sequence of numbers within a specified range. * * @param {number} [start=0] - The starting number of the range. * @param {number} [step=1] - The step between each number in the range. * @param {number} [end=Infinity] - The ending number of the range. * @yields {number} The next number in the range. */ function* iterRange ( start: number = 0, step: number = 1, end: number = Infinity): Generator { let index: number = start; while (index <= end) { yield index; index += step; } } /** * @description Cycles through the elements of the input iterable a specified number of times. * * @param {any[]} array - The iterable to cycle through. * @param {number} [num=Infinity] - The number of times to cycle through the iterable. * @yields The next element in the cycled iterable. */ function* iterCycle ([...array]: any[], num: number = Infinity): IteratorReturn { let index: number = 0; while (index++ < num) { yield* array; } } /** * @description Repeats a given value a specified number of times. * * @param {unknown} value - The value to repeat. * @param {number} [num=Infinity] - The number of times to repeat the value. * @yields The next repeated value. */ function* iterRepeat (value: unknown, num: number = Infinity): IteratorReturn { let index: number = 0; while (index++ < num) { yield value; } } /** * Takes the elements from an iterable or iterator and returns a new iterator while the checking function returns true. * * @param {IterableLike} iter - An iterable or iterator to take elements from. * @param callback - Number of elements to take (default: 1). * @yields The next element in the taken iterator. */ function* takeWhile (iter: IterableLike, callback: Function): IteratorReturn { let iterator: Iterator; /* Normalize: if input is an iterator, use it directly; otherwise get an iterator */ if (typeof (iter as Iterator).next === "function") { iterator = iter as Iterator; } else { iterator = (iter as Iterable)[Symbol.iterator](); } /* Yield the elements */ while (true) { const { value, done } = iterator.next(); if (done || !callback(value)) { break; } yield value; } } /** * Take the elements from an iterable or iterator and returns a new iterator after the checking function returns false. * * @param {IterableLike} iter - An iterable or iterator to take elements from. * @param callback - Number of elements to take (default: 1). * @yields The next element in the dropped iterator. */ function* dropWhile (iter: IterableLike, callback: Function): IteratorReturn { let iterator: Iterator; /* Normalize: if input is an iterator, use it directly; otherwise get an iterator */ if (typeof (iter as Iterator).next === "function") { iterator = iter as Iterator; } else { iterator = (iter as Iterable)[Symbol.iterator](); } /* Yield the elements */ let skip = true; while (true) { const { value, done } = iterator.next(); if (done) { break; } if (skip) { skip = callback(value); } if (!skip) { yield value; } } } /** * Takes up to `num` elements from an iterable or iterator and returns a new iterator. * * @param {IterableLike} iter - An iterable or iterator to take elements from. * @param num - Number of elements to take (default: 1). * @yields The next element in the taken iterator. */ function* take (iter: IterableLike, num: number = 1): IteratorReturn { if (num <= 0) { return; } let iterator: Iterator; /* Normalize: if input is an iterator, use it directly; otherwise get an iterator */ if (typeof (iter as Iterator).next === "function") { iterator = iter as Iterator; } else { iterator = (iter as Iterable)[Symbol.iterator](); } for (let i = 0; i < num; i++) { const { value, done } = iterator.next(); if (done) { break }; yield value; } } /** * Skips the first `num` elements from an iterable or iterator and yields the rest. * * @param {IterableLike} iter - An iterable or iterator to drop elements from. * @param num - Number of elements to skip (default: 1). * @yields The next element in the dropped iterator. */ function* drop (iter: IterableLike, num: number = 1): IteratorReturn { if (num <= 0) { /* If nothing to drop, just yield everything */ yield* (typeof (iter as Iterator).next === "function" ? { [Symbol.iterator]: () => iter as Iterator } : (iter as Iterable)); return; } let iterator: Iterator; /* Normalize: if input is an iterator, use it directly; otherwise get an iterator */ if (typeof (iter as Iterator).next === "function") { iterator = iter as Iterator; } else { iterator = (iter as Iterable)[Symbol.iterator](); } /* Drop the first `num` elements */ for (let i = 0; i < num; i++) { const { done } = iterator.next(); if (done) { return }; } /* Yield the rest */ while (true) { const { value, done } = iterator.next(); if (done) { break }; yield value; } } /** * @description Executes a provided function once for each element in an iterable. * * @param {IterableLike} iter - The iterable to iterate over. * @param {Function} callback - The function to call for each element. * @returns {void} */ function forEach (iter: IterableLike, callback: Function): void { let index: number = 0; for (let item of iter as Iterable) { callback(item, index++); } } /** * @description Executes a provided function once for each element in an iterable, in reverse order. * * @param {IterableLike} iter - The iterable to iterate over. * @param {Function} callback - The function to call for each element. * @returns {void} */ function forEachRight ([...array], callback: Function): void { let index: number = array.length; while (index--) { callback(array[index], index); } } /** * @description Creates a new iterator with the results of calling a provided function on every element in the given iterable. * * @param {IterableLike} iter - The iterable to map over. * @param {Function} callback - The function to call for each element. * @returns {Iterator} A new iterator with the mapped values. */ function* map (iter: IterableLike, callback: Function): IteratorReturn { let index: number = 0; for (let item of iter as Iterable) { yield callback(item, index++); } } /** * @description Creates a new iterator with all elements that pass the test implemented by the provided function. * * @param {IterableLike} iter - The iterable to filter. * @param {Function} callback - The function to test each element. * @returns {Iterator} A new iterator with the filtered values. */ function* filter (iter: IterableLike, callback: Function): IteratorReturn { let index: number = 0; for (let item of iter as Iterable) { if (callback(item, index++)) { yield item; } } } /** * @description Creates a new iterator with all elements that do not pass the test implemented by the provided function. * * @param {IterableLike} iter - The iterable to reject from. * @param {Function} callback - The function to test each element. * @returns {Iterator} A new iterator with the rejected values. */ function* reject (iter: IterableLike, callback: Function): IteratorReturn { let index: number = 0; for (let item of iter as Iterable) { if (!callback(item, index++)) { yield item; } } } /** * @description Yields elements from `begin` (inclusive) up to `end` (exclusive) from an iterable or iterator. Works similarly to Array.prototype.slice. * * @param {IterableLike} iter - Iterable or iterator to slice. * @param begin - Start index (inclusive, default: 0). * @param end - End index (exclusive, default: Infinity). * @yields The elements from the specified slice of the input iterable or iterator. */ function* slice ( iter: IterableLike, begin: number = 0, end: number = Infinity): IteratorReturn { if (begin < 0) { begin = 0; } if (end <= begin) { return; } let iterator: Iterator; /* Normalize input: use iterator directly, or get one from iterable */ if (typeof (iter as Iterator).next === "function") { iterator = iter as Iterator; } else { iterator = (iter as Iterable)[Symbol.iterator](); } let index = 0; while (true) { const { value, done } = iterator.next(); if (done) { break }; if (index >= begin && index <= end) { yield value; } if (index > end - 1) break; index++; } } /** * @description Yields all elements of an iterable or iterator except the first one. Similar to Array.prototype.slice(1). * * @param input - Iterable or iterator to process. * @yields The next element in the tail iterator. */ function* tail (input: IterableLike): IteratorReturn { let iterator: Iterator; /* Normalize: if input is already an iterator, use it directly */ if (typeof (input as Iterator).next === "function") { iterator = input as Iterator; } else { iterator = (input as Iterable)[Symbol.iterator](); } /* Skip the first element */ const first = iterator.next(); if (first.done) { return; } /* Yield the rest */ while (true) { const { value, done } = iterator.next(); if (done) { break; } yield value; } } /** * @description Returns the element at a specific position from an iterable or iterator. If the position is out of range, returns undefined. * * @param {IterableLike} iter - Iterable or iterator to extract from. * @param pos - Zero-based index of the desired element. * @returns The element at the specified position, or undefined if out of range. */ function item (iter: IterableLike, pos: number): T | undefined { if (pos < 0) { return undefined; } let iterator: Iterator; /* Normalize input: use iterator directly or create one from iterable */ if (typeof (iter as Iterator).next === "function") { iterator = iter as Iterator; } else { iterator = (iter as Iterable)[Symbol.iterator](); } let index = 0; while (true) { const { value, done } = iterator.next(); if (done) { return undefined; } if (index === pos) { return value; } index++; } } /** * @description Returns the element at a specific position from an iterable or iterator. If the position is out of range, returns undefined. * @param {IterableLike} iter - Iterable or iterator to extract from. * @param pos - Zero-based index of the desired element. * @returns The element at the specified position, or undefined if out of range. */ function nth (iter: IterableLike, pos: number): T | undefined { if (pos < 0) { return undefined; } let iterator: Iterator; /* Normalize input: use iterator directly or create one from iterable */ if (typeof (iter as Iterator).next === "function") { iterator = iter as Iterator; } else { iterator = (iter as Iterable)[Symbol.iterator](); } let index = 0; while (true) { const { value, done } = iterator.next(); if (done) { return undefined; } if (index === pos) { return value; } index++; } } /** * @description Return the size of the given value. * * @param {unknown} value - The value to check. * @returns {number} The size of the given value. */ function size (value: any): number { /* Check Array */ if (Array.isArray(value)) { return value.length; } /* Check Map and Set */ if (value instanceof Map || value instanceof Set) { return value.size; } /* Check ArrayBuffer and DataView */ if (value instanceof ArrayBuffer || value instanceof DataView) { return value.byteLength; } /* Other objects with size property */ if (typeof value.size === "number") { return value.size; } /* Check Iterable objects */ let iterator: IterableLike; /* Normalize input: use iterator directly or create one from iterable */ if (typeof (value as Iterator).next === "function") { iterator = value as Iterator; } else { iterator = (value as Iterable)[Symbol.iterator](); } let index: number = 0; for (let _item of iterator as any) { index++; } return index; } /** * @description Returns the first element from an iterable or iterator. If the iterable is empty, returns undefined. * * @param input - Iterable or iterator to extract from. * @returns The first element, or undefined if the iterable is empty. */ function first (input: IterableLike): T | undefined { let iterator: Iterator; /* If input is already an iterator, use it directly */ if (typeof (input as Iterator).next === "function") { iterator = input as Iterator; } else { /* Otherwise, get an iterator from the iterable */ iterator = (input as Iterable)[Symbol.iterator](); } const result = iterator.next(); return result.done ? undefined : result.value; } /** * @description Returns the first element from an iterable or iterator. If the iterable is empty, returns undefined. * * @param input - Iterable or iterator to extract from. * @returns The first element, or undefined if the iterable is empty. */ function head (input: IterableLike): T | undefined { let iterator: Iterator; /* If input is already an iterator, use it directly */ if (typeof (input as Iterator).next === "function") { iterator = input as Iterator; } else { /* Otherwise, get an iterator from the iterable */ iterator = (input as Iterable)[Symbol.iterator](); } const result = iterator?.next() ?? {value: undefined, done: true }; return result.done ? undefined : result.value; } /** * @description Returns the last element from an iterable or iterator. If the iterable is empty, returns undefined. * * @param {any[]} array - Iterable or iterator to extract from. * @returns {any} The last element, or undefined if the iterable is empty. */ const last = ([...array]: any[]): any => array[array.length - 1]; /** * @description Yields the elements of an iterable or iterator in reverse order. * * @param {any[]} array - Iterable or iterator to reverse. * @yields The elements of the input iterable or iterator in reverse order. */ function* reverse ([...array]: any[]): IteratorReturn { let index: number = array.length; while (index--) { yield array[index]; } } /** * @description Returns a new array with the elements of the input iterable sorted. * * @param {IterableLike} iter - The iterable to sort. * @param numbers - Whether to sort the elements as numbers. * @returns A new array with the sorted elements. */ const sort = ([...array], numbers: boolean = false): any[] => array.sort( numbers ? (value1: number, value2: number): number => value1 - value2 : undefined ); /** * @param {any} collection - The collection to search through. * @param {any} value - The value to look for. * @param {undefined | Function} [comparator] - Optional comparator for equality check. * @returns {boolean} - Whether the value was found. * @throws {TypeError} - If comparator is not a Function or undefined. */ function includes ( collection: any, value: any, comparator?: Function): boolean { /* Comparator Validation - has to be a function or undefined. */ if (comparator !== undefined && typeof comparator !== "function") { throw new TypeError( `[includes] TypeError: comparator is not a function or undefined. Got ${typeof comparator}` ); } /* helper functions */ const _isIterator = (value: any): boolean => value != null && typeof value === "object" && typeof value.next === "function"; const _isIterable = (value: unknown): boolean => value != null && typeof (value as any)[Symbol.iterator] === "function"; const _isEqual = comparator || ((value1: unknown, value2: unknown): boolean => value1 === value2 || (value1 !== value1 && value2 !== value2)); /* SameValueZero */ /* Collection: Primitives, WeakMap, WeakSet */ const cType = (collection === null ? "null" : typeof collection); if (collection == null || !(["object", "function", "string"].includes(cType)) || collection instanceof WeakMap || collection instanceof WeakSet) { return false; } /* string and String object */ if (typeof collection === "string" || collection instanceof String) { return collection.includes(String(value)); } /* Map */ if (collection instanceof Map) { if ([...collection.keys()].findIndex((item) => _isEqual(item, value)) > -1) { return true; } if ([...collection.values()].findIndex((item) => _isEqual(item, value)) > -1) { return true; } return false; } /* Iterator or Iterables (Array, Set, TypedArrays, other Iterables, etc.) */ if (_isIterator(collection) || _isIterable(collection)) { if ([...collection].findIndex((item) => _isEqual(item, value)) > -1) { return true; } return false; } /* Plain object or function */ if (["object", "function"].includes(cType)) { if (Object.keys(collection).findIndex((item) => _isEqual(item, value)) > -1) { return true; } if (Object.values(collection).findIndex((item) => _isEqual(item, value)) > -1) { return true; } if (Object.getOwnPropertySymbols(collection) .findIndex((item) => _isEqual(item, value)) > -1) { return true; } return false; } /* default return false */ return false; } /** * @description Returns the first element in an iterable that satisfies the provided testing function. * * @param {any[]} array - The iterable to search through. * @param {Function} callback - The function to test each element. * @returns {any} The first element that satisfies the testing function, or undefined if none do. */ const find = ([...array]: any[], callback: Function): unknown => array.find((value, index) => callback(value, index)); /** * @description Returns the last element in an iterable that satisfies the provided testing function. * * @param {any[]} array - The iterable to search through. * @param {Function} callback - The function to test each element. * @returns {any} The last element that satisfies the testing function, or undefined if none do. */ const findLast = ([...array], callback: Function): unknown => array.findLast((value, index) => callback(value, index)); /** * @description Tests whether all elements in the iterable pass the test implemented by the provided function. * * @param {any[]} array - The iterable to test. * @param {Function} callback - The function to test each element. * @returns {boolean} True if all elements pass the test, false otherwise. */ const every = ([...array]: any[], callback: Function): boolean => array.length ? array.every((value, index) => callback(value, index)) : false; /** * @description Tests whether at least one element in the iterable passes the test implemented by the provided function. * * @param {any[]} array - The iterable to test. * @param {Function} callback - The function to test each element. * @returns {boolean} True if at least one element passes the test, false otherwise. */ const some = ([...array]: any[], callback: Function): boolean => array.length ? array.some((value, index) => callback(value, index)) : false; /** * @description Tests whether no elements in the iterable pass the test implemented by the provided function. * * @param {any[]} array - The iterable to test. * @param {Function} callback - The function to test each element. * @returns {boolean} True if no elements pass the test, false otherwise. */ const none = ([...array]: any[], callback: Function): boolean => !array.some((value, index) => callback(value, index)); /** * @description Returns the last `num` elements from an iterable as an array. * * @param {any[]} array - The iterable to take elements from. * @param {number} [num=1] - The number of elements to take from the end. * @returns {any[]} An array containing the last `num` elements. */ const takeRight = ([...array]: any[], num: number = 1): any[] => array.reverse().slice(0, num); /** * @description Yields elements from the end of an iterable while the provided function returns true. * * @param {any[]} array - The iterable to take elements from. * @param {Function} callback - The function to test each element. * @yields The elements from the end of the iterable that satisfy the testing function. */ function* takeRightWhile ([...array]: any[], callback: Function): IteratorReturn { if (!array.length) { return; } let index = array.length; while (index--) { let item = array[index]; if (!callback(item, index)) { break; } yield item; } } /** * @description Returns a new array with the last `num` elements removed from the input iterable. * * @param {any[]} array - The iterable to drop elements from. * @param {number} [num=1] - The number of elements to drop from the end. * @returns {any[]} A new array with the last `num` elements removed. */ const dropRight = ([...array]: any[], num: number = 1): any[] => array.reverse().slice(num); /** * @description Yields elements from the end of an iterable after the provided function returns false. * * @param {any[]} array - The iterable to drop elements from. * @param {Function} callback - The function to test each element. * @yields The elements from the end of the iterable after the testing function returns false. */ function* dropRightWhile ([...array]: any[], callback: Function): IteratorReturn { if (!array.length) { return; } let index = array.length; let skip = true; while (index--) { let item = array[index]; if (skip) { skip = callback(item, index); } if (!skip) { yield item; } } } /** * @description Concatenates multiple iterables or values into a single iterator. * * @param {any[]} args - The iterables or values to concatenate. * @yields The elements from the concatenated iterables or values. */ function* concat (...args: any[]): IteratorReturn { for (let item of args) { if (typeof item[Symbol.iterator] === "function" || ("Iterator" in globalThis ? (item instanceof Iterator) : (typeof item === "object" && typeof item.next === "function") ) ) { yield* item; } else { yield item; } } } /** * @description Reduces an iterable to a single value by applying a function to each element and an accumulator. * * @param {IterableLike} iter - The iterable to reduce. * @param {Function} callback - The function to apply to each element and the accumulator. * @param {any} [initialvalue] - The initial value for the accumulator. * @returns {any} The reduced value. */ function reduce ( iter: IterableLike, callback: Function, initialvalue?: any): any { let acc: any = initialvalue; let index: number = 0; for (let item of iter as Iterable) { if (index === 0 && acc === undefined) { acc = item; } else { acc = callback(acc, item, index++); } } return acc; } /** * @description Yields pairs of index and element from an iterable, starting from the specified offset. * * @param {IterableLike} iter - The iterable to enumerate. * @param {number} [offset=0] - The starting index for enumeration. * @yields {[number, any]} Pairs of index and element from the iterable. */ function* enumerate ( iter: IterableLike, offset: number = 0): IteratorReturn { let index: number = offset; for (let item of iter as Iterable) { yield [index++, item]; } } /** * @description Flattens a nested iterable structure into a single-level iterator. * * @param {IterableLike} iter - The nested iterable to flatten. * @yields The elements from the flattened iterable. */ function* flat (iter: IterableLike): IteratorReturn { for (let item of iter as Iterable) { if (typeof item[Symbol.iterator] === "function" || ("Iterator" in globalThis ? (item instanceof Iterator) : (typeof item === "object" && typeof item.next === "function") ) ) { yield* item; } else { yield item; } } } /** * @description Joins the elements of an iterable into a single string, separated by the specified separator. * * @param {IterableLike} iter - The iterable to join. * @param {string} [separator=","] - The separator to use between elements. * @returns {string} The joined string. */ function join (iter: IterableLike, separator: string = ","): string { separator = String(separator); let result: string = ""; for (let item of iter as Iterable) { result += separator + item; } return result.slice(separator.length); } /** * @description Returns a new array with elements from the input iterable that are not present in the filter iterable. * * @param {any[]} array - The iterable to filter. * @param {any[]} filterValues - The iterable containing values to exclude. * @returns {any[]} A new array with the filtered elements. */ const withOut = ([...array], [...filterValues]): any[] => array.filter((value: unknown): boolean => !filterValues.includes(value)); /** Math API **/ /** * @description Adds two numbers or bigints. * * @param {NumberLike} value1 * @param {NumberLike} value2 * @returns {NumberLike} The result of the operation. * @throws {TypeError} If x and y are of mixed types. */ function add (value1: number, value2: number): number; function add (value1: bigint, value2: bigint): bigint; function add (value1: NumberLike, value2: NumberLike): NumberLike { if (typeof value1 !== typeof value2 || (typeof value1 !== "number" && typeof value1 !== "bigint")) { throw new TypeError( `[add] value1 and value2 must be of the same type and either number or bigint. Got: ${typeof value1} and ${typeof value2}` ); } if (typeof value1 === "number" && typeof value2 === "number") { // @ts-ignore return Math.sumPrecise([value1, value2]); } return (value1 as bigint) + (value2 as bigint); } /** * @description Subtract two numbers or bigints. * * @param {NumberLike} value1 * @param {NumberLike} value2 * @returns {NumberLike} The result of the operation. * @throws {TypeError} If x and y are of mixed types. */ function sub (value1: number, value2: number): number; function sub (value1: bigint, value2: bigint): bigint; function sub (value1: NumberLike, value2: NumberLike): NumberLike { if (typeof value1 !== typeof value2 || (typeof value1 !== "number" && typeof value1 !== "bigint")) { throw new TypeError( `[sub] value1 and value2 must be of the same type and either number or bigint. Got: ${typeof value1} and ${typeof value2}` ); } if (typeof value1 === "number" && typeof value2 === "number") { // @ts-ignore Math.sumPrecise([value1, -value2]); } return (value1 as bigint) - (value2 as bigint); } /** * @description Multiply two numbers or bigints. * * @param {NumberLike} value1 * @param {NumberLike} value2 * @returns {NumberLike} The result of the operation. * @throws {TypeError} If x and y are of mixed types. */ function mul (value1: number, value2: number): number; function mul (value1: bigint, value2: bigint): bigint; function mul (value1: NumberLike, value2: NumberLike): NumberLike { if (typeof value1 !== typeof value2 || (typeof value1 !== "number" && typeof value1 !== "bigint")) { throw new TypeError( `[mul] value1 and value2 must be of the same type and either number or bigint. Got: ${typeof value1} and ${typeof value2}` ); } if (typeof value1 === "number" && typeof value2 === "number") { return value1 * value2; } return (value1 as bigint) * (value2 as bigint); } /** * @description Divide two numbers or bigints. * * @param {NumberLike} value1 * @param {NumberLike} value2 * @returns {NumberLike} The result of the operation. * @throws {RangeError} If y is zero. * @throws {TypeError} If x and y are of mixed types. */ function div (value1: number, value2: number): number; function div (value1: bigint, value2: bigint): bigint; function div (value1: NumberLike, value2: NumberLike): NumberLike { if (typeof value1 !== typeof value2 || (typeof value1 !== "number" && typeof value1 !== "bigint")) { throw new TypeError( `[div] value1 and value2 must be of the same type and either number or bigint. Got: ${typeof value1} and ${typeof value2}` ); } if (value2 === 0 || value2 === 0n) { throw new RangeError("[div] Cannot divide by zero"); } if (typeof value1 === "number" && typeof value2 === "number") { return value1 / value2; } return (value1 as bigint) / (value2 as bigint); } /** * @description Performs integer division of two numbers or bigints. * * @param {NumberLike} value1 * @param {NumberLike} value2 * @returns {NumberLike} The result of the operation. * @throws {RangeError} If y is zero. * @throws {TypeError} If x and y are of mixed types. */ function divMod (value1: number, value2: number): number; function divMod (value1: bigint, value2: bigint): bigint; function divMod (value1: NumberLike, value2: NumberLike): NumberLike { if (typeof value1 !== typeof value2 || (typeof value1 !== "number" && typeof value1 !== "bigint")) { throw new TypeError( `[divMod] value1 and value2 must be of the same type and either number or bigint. Got: ${typeof value1} and ${typeof value2}` ); } if (value2 === 0 || value2 === 0n) { throw new RangeError("[divMod] Cannot divide by zero"); } if (typeof value1 === "number" && typeof value2 === "number") { return Math.trunc(value1 / value2); } return (value1 as bigint) / (value2 as bigint); } /** * @description Remainder of division (modulus) of two numbers or bigints. * * @param {NumberLike} value1 * @param {NumberLike} value2 * @returns {NumberLike} The result of the operation. * @throws {RangeError} If y is zero. * @throws {TypeError} If x and y are of mixed types. */ function mod (value1: number, value2: number): number; function mod (value1: bigint, value2: bigint): bigint; function mod (value1: NumberLike, value2: NumberLike): NumberLike { if (typeof value1 !== typeof value2 || (typeof value1 !== "number" && typeof value1 !== "bigint")) { throw new TypeError( `[mod] value1 and value2 must be of the same type and either number or bigint. Got: ${typeof value1} and ${typeof value2}` ); } if (value2 === 0 || value2 === 0n) { throw new RangeError("[mod] Cannot divide by zero"); } if (typeof value1 === "number" && typeof value2 === "number") { return Math.trunc(value1 % value2); } return (value1 as bigint) % (value2 as bigint); } /** * @description Checks if a value is a floating-point number. * * @param {unknown} value - The value to check. * @returns {boolean} True if the value is a float, false otherwise. */ const isFloat = (value: unknown): boolean => typeof value === "number" && value === value && Boolean(value % 1); /** * @description Converts a value to an integer within the safe integer range. * * @param {unknown} value - The value to convert. * @returns {number} The converted integer. */ function toInteger (value: any): number { value = ((value = Math.trunc(Number(value))) !== value || value === 0) ? 0 : value; return Math.min( Math.max(value, Number.MIN_SAFE_INTEGER), Number.MAX_SAFE_INTEGER ); } /* toIntegerOrInfinity(value: unknown): integer | Infinity | -Infinity */ /** * @description Converts a value to an integer or infinity. * * @param {unknown} value - The value to convert. * @returns {number} The converted integer or infinity. */ const toIntegerOrInfinity = (value: unknown): number => ((value = Math.trunc(Number(value))) !== value || value === 0) ? 0 : value as number; /** * @description Sums multiple values, using precise addition for numbers. * * @param {...any} args - The values to sum. * @returns {any} The sum of the values. * @throws {TypeError} If all parameter are not number or bigint. */ function sum (...args: any[]): any { if (!args.every((value: unknown): boolean => typeof value === "number") && !args.every((value: unknown): boolean => typeof value === "bigint") ) { throw new TypeError( `[sum] all arguments must be of the same type and either number or bigint. Got: ${args.map((v) => typeof v).join(", ")}` ); } return args.every((value: unknown): boolean => typeof value === "number") // @ts-ignore ? Math.sumPrecise(args) : args.slice(1).reduce((acc: any, value: any): any => acc + value, args[0]); } /** * @description Calculates the average of multiple numbers using precise addition. * * @param {...number} args - The numbers to average. * @returns {number} The average of the numbers. */ // @ts-ignore const avg = (...args: number[]): number => Math.sumPrecise(args) / args.length; /** * @description Calculates the product of multiple numbers and bigints. * * @param {...NumberLike} args - The numbers to multiply. * @returns {NumberLike} The product of the numbers. */ function product (first: number, ...args: number[]): number; function product (first: bigint, ...args: bigint[]): bigint; function product (first: NumberLike, ...args: NumberLike[]): NumberLike { if (typeof first === "bigint") { return (args as bigint[]).reduce((acc: bigint, v: bigint): bigint => acc * v, first as bigint); } return (args as number[]).reduce((acc: number, v: number): number => acc * v, first as number); } /** * @description Returns the value of a base raised to a power. * * @param {NumberLike} base - The base value. * @param {NumberLike} power - The power value. * @returns {NumberLike} The product of the numbers. * @throws {TypeError} if base and power are of mixed types or not number or bigint. */ function pow (base: number, power: number): number; function pow (base: bigint, power: bigint): bigint; function pow (base: NumberLike, power: NumberLike): NumberLike { if (typeof base !== typeof power || (typeof base !== "number" && typeof base !== "bigint") ) { throw new TypeError( `[pow] base and power must be of the same type and either number or bigint. Got: ${typeof base} and ${typeof power}` ); } if (typeof base === "bigint" && typeof power === "bigint") { return (base as bigint) ** (power as bigint); } return Math.pow(base as number, power as number); } /** * @description Clamps a value between a minimum and maximum. * * @param {NumberLike} value - The value to clamp. * @param {NumberLike} min - The minimum value. * @param {NumberLike} max - The maximum value. * @returns {NumberLike} The clamped value. */ function clamp (value: number, min: number, max: number): number; function clamp (value: bigint, min: bigint, max: bigint): bigint; function clamp ( value: NumberLike, min: NumberLike = Number.MIN_SAFE_INTEGER, max: NumberLike = Number.MAX_SAFE_INTEGER): NumberLike { /* normalize */ function _numberNormalize (value: any): NumberLike { if (typeof value !== "bigint" && typeof value !== "number") { value = Number(value); } if (value === -Infinity) { return Number.MIN_SAFE_INTEGER; } if (value === Infinity) { return Number.MAX_SAFE_INTEGER; } if (value === 0) { return 0; } return value; } if (typeof value !== "bigint" && typeof min !== "bigint" && typeof min !== "bigint") { value = _numberNormalize(value); min = _numberNormalize(min); max = _numberNormalize(max); } /* NaN: val, min, max */ if (value !== value) { return value; } if (min !== min || max !== max) { throw new RangeError( "[clamp] RangeError: minimum and maximum should not to be NaN" ); } /* min > max -> throw RangeError */ if (min > max) { throw new RangeError( "[clamp] RangeError: minimum should be lower than maximum" ); } /* clamp */ return (value < min) ? min : ((value > max) ? max : value); } /** * @description Clamps a value between a minimum and maximum. * * @param {NumberLike} value - The value to clamp. * @param {NumberLike} min - The minimum value. * @param {NumberLike} max - The maximum value. * @returns {NumberLike} The clamped value. */ function minmax( value: NumberLike, min: NumberLike = Number.MIN_SAFE_INTEGER, max: NumberLike = Number.MAX_SAFE_INTEGER): NumberLike { /* normalize */ function _numberNormalize (value: any): NumberLike { if (typeof value !== "bigint" && typeof value !== "number") { value = Number(value); } if (value === -Infinity) { return Number.MIN_SAFE_INTEGER; } if (value === Infinity) { return Number.MAX_SAFE_INTEGER; } if (value === 0) { return 0; } return value; } if (typeof value !== "bigint" && typeof min !== "bigint" && typeof min !== "bigint") { value = _numberNormalize(value); min = _numberNormalize(min); max = _numberNormalize(max); } /* NaN: val, min, max */ if (value !== value) { return value; } if (min !== min || max !== max) { throw new RangeError( "[minmax] RangeError: minimum and maximum should not to be NaN" ); } /* min > max -> throw RangeError */ if (min > max) { throw new RangeError( "[minmax] RangeError: minimum should be lower than maximum" ); } /* clamp */ return (value < min) ? min : ((value > max) ? max : value); } /** * @description Checks if a number is safe integer and even. * * @param {unknown} value - The number to check. * @returns {boolean} True if the number is even, false otherwise. */ function isEven (value: unknown): boolean { if (typeof value === "number" && Number.isSafeInteger(value)) { return value % 2 === 0; } if (typeof value === "bigint") { return value % 2n === 0n; } return false; } /** * @description Checks if a number is safe integer and odd. * * @param {unknown} value - The number to check. * @returns {boolean} True if the number is odd, false otherwise. */ function isOdd (value: unknown): boolean { if (typeof value === "number" && Number.isSafeInteger(value)) { return value % 2 !== 0; } if (typeof value === "bigint") { return value % 2n !== 0n; } return false; } /* toInt8(value: unknown): integer -127..128 */ /** * @description Converts a value to an 8-bit signed integer. * * @param {unknown} value - The value to convert. * @returns {number} The converted 8-bit signed integer. */ const toInt8 = (value: unknown): number => ((value = Math.min(Math.max(-128, Math.trunc(Number(value))), 127)) === value) ? value as number : 0; /* toUInt8(value: unknown): integer 0..255 */ /** * @description Converts a value to an 8-bit unsigned integer. * * @param {unknown} value - The value to convert. * @returns {number} The converted 8-bit unsigned integer. */ const toUInt8 = (value: unknown): number => ((value = Math.min(Math.max(0, Math.trunc(Number(value))), 255)) === value) ? value as number : 0; /* toInt16(value: unknown): integer -32768..32767 */ /** * @description Converts a value to a 16-bit signed integer. * * @param {unknown} value - The value to convert. * @returns {number} The converted 16-bit signed integer. */ const toInt16 = (value: unknown): number => ((value = Math.min(Math.max(-32768, Math.trunc(Number(value))), 32767)) === value) ? value as number : 0; /* toUInt16(value: unknown) integer 0..65535 */ /** * @description Converts a value to a 16-bit unsigned integer. * * @param {unknown} value - The value to convert. * @returns {number} The converted 16-bit unsigned integer. */ const toUInt16 = (value: unknown): number => ((value = Math.min(Math.max(0, Math.trunc(Number(value))), 65535)) === value) ? value as number : 0; /* toInt32(value: unknown): integer -2147483648..2147483647 */ /** * @description Converts a value to a 32-bit signed integer. * * @param {unknown} value - The value to convert. * @returns {number} The converted 32-bit signed integer. */ const toInt32 = (value: unknown): number => ((value = Math.min(Math.max(-2147483648, Math.trunc(Number(value))), 2147483647)) === value) ? value as number : 0; /* toUInt32(value: unknown): integer 0..4294967295 */ /** * @description Converts a value to a 32-bit unsigned integer. * * @param {unknown} value - The value to convert. * @returns {number} The converted 32-bit unsigned integer. */ const toUInt32 = (value: unknown): number => ((value = Math.min(Math.max(0, Math.trunc(Number(value))), 4294967295)) === value) ? value as number : 0; /** * @description Converts a value to a 64-bit signed bigint. * * @param {unknown} value - The value to convert. * @returns {bigint} The converted 64-bit signed bigint. */ const toBigInt64 = (value: any | bigint): bigint => BigInt(typeof value === "bigint" ? (value > Math.pow(2,63) -1 ? Math.pow(2, 63) -1 : value < Math.pow(-2, 63) ? Math.pow(-2, 63) : value) : ((value = Math.min(Math.max(Math.pow(-2, 63), Math.trunc(Number(value))), Math.pow(2, 63) - 1)) === value ) ? value : 0); /** * @description Converts a value to a 64-bit unsigned bigint. * * @param {unknown} value - The value to convert. * @returns {bigint} The converted 64-bit unsigned bigint. */ const toBigUInt64 = (value: unknown): bigint => BigInt(typeof value === "bigint" ? (value > Math.pow(2, 64) - 1 ? Math.pow(2,64) - 1 : value < 0 ? 0 : value) : ((value = Math.min(Math.max(0, Math.trunc(Number(value))), Math.pow(2, 64) -1)) === value) ? value as bigint : 0); /** * @description Converts a value to a 32-bit floating-point number. * * @param {unknown} value - The value to convert. * @returns {number} The converted 32-bit floating-point number. */ const toFloat32 = (value: unknown): number => ((value = Math.min(Math.max(-3.4e38, Number(value)), 3.4e38)) === value) ? value as number : 0; /** * @description Checks if a value is an 8-bit signed integer. * * @param {unknown} value - The value to check. * @returns {boolean} True if the value is an 8-bit signed integer, false otherwise. */ const isInt8 = (value: unknown | number): boolean => Number.isInteger(value) && value as number >= -128 && value as number <= 127; /** * @description Checks if a value is an 8-bit unsigned integer. * * @param {unknown} value - The value to check. * @returns {boolean} True if the value is an 8-bit unsigned integer, false otherwise. */ const isUInt8 = (value: unknown | number): boolean => Number.isInteger(value) && value as number >= 0 && value as number <= 255; /** * @description Checks if a value is a 16-bit signed integer. * * @param {unknown} value - The value to check. * @returns {boolean} True if the value is a 16-bit signed integer, false otherwise. */ const isInt16 = (value: unknown): boolean => Number.isInteger(value) && value as number >= -32768 && value as number <= 32767; /** * @description Checks if a value is a 16-bit unsigned integer. * * @param {unknown} value - The value to check. * @returns {boolean} True if the value is a 16-bit unsigned integer, false otherwise. */ const isUInt16 = (value: unknown): boolean => Number.isInteger(value) && value as number >= 0 && value as number <= 65535; /** * @description Checks if a value is a 32-bit signed integer. * * @param {unknown} value - The value to check. * @returns {boolean} True if the value is a 32-bit signed integer, false otherwise. */ const isInt32 = (value: unknown): boolean => Number.isInteger(value) && value as number >= -2147483648 && value as number <= 2147483647; /** * @description Checks if a value is a 32-bit unsigned integer. * * @param {unknown} value - The value to check. * @returns {boolean} True if the value is a 32-bit unsigned integer, false otherwise. */ const isUInt32 = (value: unknown | number): boolean => Number.isInteger(value) && value as number >= 0 && value as number <= 4294967295; /** * @description Checks if a value is a 64-bit signed integer. * * @param {unknown} value - The value to check. * @returns {boolean} True if the value is a 64-bit signed integer, false otherwise. */ const isBigInt64 = (value: unknown): boolean => typeof value === "bigint" && value >= Math.pow(-2, 63) && value <= Math.pow(2, 63)-1; /** * @description Checks if a value is a 64-bit unsigned integer. * * @param {unknown} value - The value to check. * @returns {boolean} True if the value is a 64-bit unsigned integer, false otherwise. */ const isBigUInt64 = (value: unknown | NumberLike): boolean => typeof value === "bigint" && value >= 0 && value <= Math.pow(2, 64) - 1; /** * @description Converts a value to a 16-bit floating-point number. * * @param {unknown} value - The value to convert. */ const toFloat16 = (value: unknown): number => ((value = Math.min(Math.max(-65504, Number(value)), 65504)) === value ) ? value as number : 0; /** * @description Checks if a value is a 16-bit floating-point number. * * @param {unknown} value - The value to check. * @returns {boolean} True if the value is a 16-bit floating-point number, false otherwise. */ const isFloat16 = (value: unknown | NumberLike): boolean => typeof value === "number" && value === value && value >= -65504 && value <= 65504; /** * @description Checks if the sign bit of a number or bigint is set (i.e., if the value is negative). * * @param {unknown | NumberLike} value - The value to check. * @returns {boolean} True if the sign bit is set, false otherwise. */ const signbit = (value: unknown | NumberLike): boolean => ((value = Number(value)) !== value) ? false : (Object.is(value, -0) || ( typeof value === "number" && value < 0 || typeof value === "bigint" && value < 0n ) ); /* randomInt([max: integer]): integer */ /* randomInt(min: integer, max: integer): integer */ /** * @description Generates a random integer between the specified minimum and maximum values. * * @param {number} [min=100] - The minimum value (inclusive) or the maximum value if only one argument is provided. * @param {number} [max] - The maximum value (inclusive). * @returns {number} A random integer between the specified range. */ function randomInt ( min: number | undefined = 100, max?: number | null | undefined): number { if (max == null) { max = min; min = 0; } min = Math.ceil(Number(min)); return Math.floor(Math.random() * (Math.floor(Number(max)) - min + 1) + min); } /* randomFloat([max: float]): float */ /* randomFloat(min: float, max: float): float */ /** * @description Generates a random floating-point number between the specified minimum and maximum values. * * @param {number} [min=100] - The minimum value (inclusive) or the maximum value if only one argument is provided. * @param {number} [max] - The maximum value (inclusive). * @returns {number} A random floating-point number between the specified range. */ function randomFloat ( min: number | undefined = 100, max?: number | null | undefined): number { if (max == null) { max = min; min = 0; } let result: number = (Math.random() * (max - min + 1)) + min; return result > max ? max : result; } /** * @description Checks if a number is within a specified range (inclusive). * * @param {NumberLike} value - The number to check. * @param {NumberLike} min - The minimum value of the range. * @param {NumberLike} max - The maximum value of the range. * @returns {boolean} True if the number is within the range, false otherwise. */ function inRange (value: number, min: number, max: number): boolean; function inRange (value: bigint, min: bigint, max: number): boolean; function inRange (value: NumberLike, min: NumberLike, max: NumberLike): boolean { if ( (typeof value === "number" && typeof min === "number" && typeof max === "number") || (typeof value === "bigint" && typeof min === "bigint" && typeof max === "bigint") ) { return value >= min && value <= max; } return false; } export default { /** object header **/ VERSION, /** Core API **/ BASE16, BASE32, BASE36, BASE58, BASE62, WORDSAFEALPHABET, assert, eq, gt, gte, lt, lte, tap, once, curry, pipe, compose, pick, omit, assoc, asyncNoop, asyncT, asyncF, asyncConstant, asyncIdentity, createPolyfillMethod, createPolyfillProperty, randomUUIDv7, delay, randomBoolean, getUrlVars, obj2string, extend, sizeIn, unBind, bind, constant, identity, noop, T, F, nanoid, timestampID, /** String API **/ b64Encode, b64Decode, strCount, strTruncate, strPropercase, strTitlecase, strCapitalize, strUpFirst, strDownFirst, strReverse, strCodePoints, strFromCodePoints, strAt, strSplice, strHTMLRemoveTags, strHTMLEscape, strHTMLUnEscape, /** Type API **/ isNonNullable, isNonNullablePrimitive, isArrowFunction, isAsyncIterator, isTypedCollection, is, toObject, toPrimitive, toSafeString, isPropertyKey, toPropertyKey, isIndex, isLength, toIndex, toLength, typeOf, isSameType, isSameInstance, isCoercedObject, isDeepStrictEqual, isEmpty, isProxy, isAsyncGeneratorFunction, isPlainObject, isObject, isFunction, isArraylike, isNull, isUndefined, isNullish, isPrimitive, isIterator, isRegexp, isElement, isIterable, isAsyncIterable, isTypedArray, isGeneratorFunction, isAsyncFunction, /** Collections API **/ castArray, compact, unique, count, arrayDeepClone, initial, shuffle, partition, min, max, arrayRepeat, arrayCycle, arrayRange, zip, unzip, zipObj, arrayAdd, arrayClear, arrayRemove, arrayRemoveBy, arrayMerge, iterRange, iterCycle, iterRepeat, takeWhile, dropWhile, take, drop, forEach, forEachRight, map, filter, reject, slice, tail, item, nth, size, first, head, last, reverse, sort, includes, find, findLast, every, some, none, takeRight, takeRightWhile, dropRight, dropRightWhile, concat, reduce, enumerate, flat, join, withOut, /** Math API **/ add, sub, mul, div, divMod, mod, isFloat, toInteger, toIntegerOrInfinity, sum, avg, product, pow, clamp, minmax, isEven, isOdd, toInt8, toUInt8, toInt16, toUInt16, toInt32, toUInt32, toBigInt64, toBigUInt64, toFloat32, isInt8, isUInt8, isInt16, isUInt16, isInt32, isUInt32, isBigInt64, isBigUInt64, toFloat16, isFloat16, signbit, randomInt, randomFloat, inRange }; export { /** object header **/ VERSION, /** Core API **/ BASE16, BASE32, BASE36, BASE58, BASE62, WORDSAFEALPHABET, assert, eq, gt, gte, lt, lte, tap, once, curry, pipe, compose, pick, omit, assoc, asyncNoop, asyncT, asyncF, asyncConstant, asyncIdentity, createPolyfillMethod, createPolyfillProperty, randomUUIDv7, delay, randomBoolean, getUrlVars, obj2string, extend, sizeIn, unBind, bind, constant, identity, noop, T, F, nanoid, timestampID, /** String API **/ b64Encode, b64Decode, strCount, strTruncate, strPropercase, strTitlecase, strCapitalize, strUpFirst, strDownFirst, strReverse, strCodePoints, strFromCodePoints, strAt, strSplice, strHTMLRemoveTags, strHTMLEscape, strHTMLUnEscape, /** Type API **/ isNonNullable, isNonNullablePrimitive, isArrowFunction, isAsyncIterator, isTypedCollection, is, toObject, toPrimitive, toSafeString, isPropertyKey, toPropertyKey, isIndex, isLength, toIndex, toLength, typeOf, isSameType, isSameInstance, isCoercedObject, isDeepStrictEqual, isEmpty, isProxy, isAsyncGeneratorFunction, isPlainObject, isObject, isFunction, isArraylike, isNull, isUndefined, isNullish, isPrimitive, isIterator, isRegexp, isElement, isIterable, isAsyncIterable, isTypedArray, isGeneratorFunction, isAsyncFunction, /** Collections API **/ castArray, compact, unique, count, arrayDeepClone, initial, shuffle, partition, min, max, arrayRepeat, arrayCycle, arrayRange, zip, unzip, zipObj, arrayAdd, arrayClear, arrayRemove, arrayRemoveBy, arrayMerge, iterRange, iterCycle, iterRepeat, takeWhile, dropWhile, take, drop, forEach, forEachRight, map, filter, reject, slice, tail, item, nth, size, first, head, last, reverse, sort, includes, find, findLast, every, some, none, takeRight, takeRightWhile, dropRight, dropRightWhile, concat, reduce, enumerate, flat, join, withOut, /** Math API **/ add, sub, mul, div, divMod, mod, isFloat, toInteger, toIntegerOrInfinity, sum, avg, product, pow, clamp, minmax, isEven, isOdd, toInt8, toUInt8, toInt16, toUInt16, toInt32, toUInt32, toBigInt64, toBigUInt64, toFloat32, isInt8, isUInt8, isInt16, isUInt16, isInt32, isUInt32, isBigInt64, isBigUInt64, toFloat16, isFloat16, signbit, randomInt, randomFloat, inRange };