radashi 12.2.1 → 12.3.0-beta.8c8abf6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/radashi.cjs CHANGED
@@ -18,6 +18,23 @@ function boil(array, compareFunc) {
18
18
  return array.reduce(compareFunc);
19
19
  }
20
20
 
21
+ // src/array/cartesianProduct.ts
22
+ function cartesianProduct(...arrays) {
23
+ let out = [[]];
24
+ for (const array of arrays) {
25
+ const result = [];
26
+ for (const currentArray of out) {
27
+ for (const item of array) {
28
+ const currentArrayCopy = currentArray.slice();
29
+ currentArrayCopy.push(item);
30
+ result.push(currentArrayCopy);
31
+ }
32
+ }
33
+ out = result;
34
+ }
35
+ return out;
36
+ }
37
+
21
38
  // src/array/castArray.ts
22
39
  function castArray(value) {
23
40
  return Array.isArray(value) ? value.slice() : [value];
@@ -358,20 +375,17 @@ function zipToObject(keys2, values) {
358
375
  }
359
376
 
360
377
  // src/async/AggregateError.ts
361
- var AggregateErrorOrPolyfill = /* @__PURE__ */ (() => (
362
- // eslint-disable-next-line compat/compat
363
- globalThis.AggregateError ?? class AggregateError extends Error {
364
- constructor(errors = []) {
365
- var _a, _b;
366
- super();
367
- const name = ((_a = errors.find((e) => e.name)) == null ? void 0 : _a.name) ?? "";
368
- this.name = `AggregateError(${name}...)`;
369
- this.message = `AggregateError with ${errors.length} errors`;
370
- this.stack = ((_b = errors.find((e) => e.stack)) == null ? void 0 : _b.stack) ?? this.stack;
371
- this.errors = errors;
372
- }
378
+ var AggregateErrorOrPolyfill = /* @__PURE__ */ (() => globalThis.AggregateError ?? class AggregateError extends Error {
379
+ constructor(errors = []) {
380
+ var _a, _b;
381
+ super();
382
+ const name = ((_a = errors.find((e) => e.name)) == null ? void 0 : _a.name) ?? "";
383
+ this.name = `AggregateError(${name}...)`;
384
+ this.message = `AggregateError with ${errors.length} errors`;
385
+ this.stack = ((_b = errors.find((e) => e.stack)) == null ? void 0 : _b.stack) ?? this.stack;
386
+ this.errors = errors;
373
387
  }
374
- ))();
388
+ })();
375
389
 
376
390
  // src/async/all.ts
377
391
  async function all(promises) {
@@ -448,17 +462,27 @@ async function map(array, asyncMapFunc) {
448
462
  }
449
463
 
450
464
  // src/async/parallel.ts
451
- async function parallel(limit, array, func) {
465
+ async function parallel(options, array, func) {
466
+ var _a;
452
467
  const work = array.map((item, index) => ({
453
468
  index,
454
469
  item
455
470
  }));
456
- const processor = async (res) => {
471
+ if (isNumber(options)) {
472
+ options = {
473
+ limit: options
474
+ };
475
+ }
476
+ (_a = options.signal) == null ? void 0 : _a.throwIfAborted();
477
+ const processor = async (resolve, reject) => {
478
+ var _a2, _b;
457
479
  const results2 = [];
480
+ const abortListener = () => reject(new Error("This operation was aborted"));
481
+ (_a2 = options.signal) == null ? void 0 : _a2.addEventListener("abort", abortListener);
458
482
  while (true) {
459
483
  const next = work.pop();
460
484
  if (!next) {
461
- return res(results2);
485
+ break;
462
486
  }
463
487
  const [error, result] = await tryit(func)(next.item);
464
488
  results2.push({
@@ -467,8 +491,10 @@ async function parallel(limit, array, func) {
467
491
  index: next.index
468
492
  });
469
493
  }
494
+ (_b = options.signal) == null ? void 0 : _b.removeEventListener("abort", abortListener);
495
+ return resolve(results2);
470
496
  };
471
- const queues = list(1, limit).map(() => new Promise(processor));
497
+ const queues = list(1, options.limit).map(() => new Promise(processor));
472
498
  const itemResults = await Promise.all(queues);
473
499
  const [errors, results] = fork(
474
500
  sort(flat(itemResults), (r) => r.index),
@@ -499,11 +525,13 @@ async function retry(options, func) {
499
525
  const times = (options == null ? void 0 : options.times) ?? 3;
500
526
  const delay = options == null ? void 0 : options.delay;
501
527
  const backoff = (options == null ? void 0 : options.backoff) ?? null;
528
+ const signal = options == null ? void 0 : options.signal;
502
529
  let i = 0;
503
530
  while (true) {
504
531
  const [err, result] = await tryit(func)((err2) => {
505
532
  throw { _exited: err2 };
506
533
  });
534
+ signal == null ? void 0 : signal.throwIfAborted();
507
535
  if (!err) {
508
536
  return result;
509
537
  }
@@ -527,6 +555,19 @@ function sleep(milliseconds) {
527
555
  return new Promise((res) => setTimeout(res, milliseconds));
528
556
  }
529
557
 
558
+ // src/async/timeout.ts
559
+ function timeout(milliseconds, error = "timeout") {
560
+ return new Promise(
561
+ (_, rej) => setTimeout(() => {
562
+ if (isString(error)) {
563
+ rej(new Error(error));
564
+ } else {
565
+ rej(error());
566
+ }
567
+ }, milliseconds)
568
+ );
569
+ }
570
+
530
571
  // src/async/tryit.ts
531
572
  function tryit(func) {
532
573
  return (...args) => {
@@ -1372,6 +1413,30 @@ function dash(str) {
1372
1413
  });
1373
1414
  }
1374
1415
 
1416
+ // src/string/dedent.ts
1417
+ function dedent(text, ...values) {
1418
+ var _a;
1419
+ if (isArray(text)) {
1420
+ if (values.length > 0) {
1421
+ return dedent(
1422
+ text.reduce((acc, input, i) => {
1423
+ var _a2;
1424
+ let value = String(values[i] ?? "");
1425
+ const indent2 = value.includes("\n") && ((_a2 = input.match(/[ \t]*(?=[^\n]*$)/)) == null ? void 0 : _a2[0]);
1426
+ if (indent2) {
1427
+ value = value.replace(/\n(?=[^\n]*?\S)/g, "\n" + indent2);
1428
+ }
1429
+ return acc + input + value;
1430
+ }, "")
1431
+ );
1432
+ }
1433
+ text = text[0];
1434
+ }
1435
+ const indent = values[0] ?? ((_a = text.match(/^[ \t]*(?=\S)/m)) == null ? void 0 : _a[0]);
1436
+ const output = indent ? text.replace(new RegExp(`^${indent}`, "gm"), "") : text;
1437
+ return output.replace(/^[ \t]*\n|\n[ \t]*$/g, "");
1438
+ }
1439
+
1375
1440
  // src/string/pascal.ts
1376
1441
  function pascal(str) {
1377
1442
  if (!str) {
@@ -1490,6 +1555,11 @@ function isBoolean(value) {
1490
1555
  return typeof value === "boolean";
1491
1556
  }
1492
1557
 
1558
+ // src/typed/isClass.ts
1559
+ function isClass(value) {
1560
+ return isFunction(value) && Function.prototype.toString.call(value).startsWith("class ");
1561
+ }
1562
+
1493
1563
  // src/typed/isDate.ts
1494
1564
  function isDate(value) {
1495
1565
  return isTagged(value, "[object Date]");
@@ -1594,6 +1664,11 @@ function isMap(value) {
1594
1664
  return isTagged(value, "[object Map]");
1595
1665
  }
1596
1666
 
1667
+ // src/typed/isNullish.ts
1668
+ function isNullish(value) {
1669
+ return value === null || value === void 0;
1670
+ }
1671
+
1597
1672
  // src/typed/isNumber.ts
1598
1673
  function isNumber(value) {
1599
1674
  return typeof value === "number" && !Number.isNaN(value);
@@ -1689,6 +1764,7 @@ exports.boil = boil;
1689
1764
  exports.callable = callable;
1690
1765
  exports.camel = camel;
1691
1766
  exports.capitalize = capitalize;
1767
+ exports.cartesianProduct = cartesianProduct;
1692
1768
  exports.castArray = castArray;
1693
1769
  exports.castArrayIfExists = castArrayIfExists;
1694
1770
  exports.castComparator = castComparator;
@@ -1704,6 +1780,7 @@ exports.counting = counting;
1704
1780
  exports.crush = crush;
1705
1781
  exports.dash = dash;
1706
1782
  exports.debounce = debounce;
1783
+ exports.dedent = dedent;
1707
1784
  exports.defer = defer;
1708
1785
  exports.diff = diff;
1709
1786
  exports.draw = draw;
@@ -1720,6 +1797,7 @@ exports.intersects = intersects;
1720
1797
  exports.invert = invert;
1721
1798
  exports.isArray = isArray;
1722
1799
  exports.isBoolean = isBoolean;
1800
+ exports.isClass = isClass;
1723
1801
  exports.isDate = isDate;
1724
1802
  exports.isEmpty = isEmpty;
1725
1803
  exports.isEqual = isEqual;
@@ -1730,6 +1808,7 @@ exports.isInt = isInt;
1730
1808
  exports.isIntString = isIntString;
1731
1809
  exports.isIterable = isIterable;
1732
1810
  exports.isMap = isMap;
1811
+ exports.isNullish = isNullish;
1733
1812
  exports.isNumber = isNumber;
1734
1813
  exports.isObject = isObject;
1735
1814
  exports.isPlainObject = isPlainObject;
@@ -1793,6 +1872,7 @@ exports.sort = sort;
1793
1872
  exports.sum = sum;
1794
1873
  exports.template = template;
1795
1874
  exports.throttle = throttle;
1875
+ exports.timeout = timeout;
1796
1876
  exports.title = title;
1797
1877
  exports.toFloat = toFloat;
1798
1878
  exports.toInt = toInt;
@@ -21,6 +21,29 @@ declare function alphabetical<T>(array: readonly T[], getter: (item: T) => strin
21
21
  */
22
22
  declare function boil<T>(array: readonly T[], compareFunc: (a: T, b: T) => T): T | null;
23
23
 
24
+ /**
25
+ * Create an [n-ary Cartesian product](https://en.wikipedia.org/wiki/Cartesian_product#n-ary_Cartesian_product) from the given arrays.
26
+ *
27
+ * @see https://radashi.js.org/reference/array/cartesianProduct
28
+ * @example
29
+ * ```ts
30
+ * product([['red', 'blue'], ['big', 'small'], ['fast', 'slow']])
31
+ * // [
32
+ * // ['red', 'big', 'fast'],
33
+ * // ['red', 'big', 'slow'],
34
+ * // ['red', 'small', 'fast'],
35
+ * // ['red', 'small', 'slow'],
36
+ * // ['blue', 'big', 'fast'],
37
+ * // ['blue', 'big', 'slow'],
38
+ * // ['blue', 'small', 'fast'],
39
+ * // ['blue', 'small', 'slow']
40
+ * // ]
41
+ * ```
42
+ */
43
+ declare function cartesianProduct<T extends any[][]>(...arrays: [...T]): Array<{
44
+ [K in keyof T]: T[K][number];
45
+ }>;
46
+
24
47
  /**
25
48
  * Casts the given value to an array. If the value is already an
26
49
  * array, a shallow copy is returned. Otherwise, a new array
@@ -125,8 +148,7 @@ declare function diff<T>(root: readonly T[], other: readonly T[], identity?: (it
125
148
  * ```
126
149
  * @version 12.1.0
127
150
  */
128
- declare function first<T>(array: readonly T[]): T | undefined;
129
- declare function first<T, U>(array: readonly T[], defaultValue: U): T | U;
151
+ declare function first<const TArray extends readonly any[], const TDefault = undefined>(array: TArray, defaultValue?: TDefault): TArray extends readonly [infer TFirst, ...any[]] ? TFirst : TArray[number] | TDefault;
130
152
 
131
153
  /**
132
154
  * Given an array of arrays, returns a single dimensional array with
@@ -220,8 +242,7 @@ declare function iterate<T>(count: number, func: (currentValue: T, iteration: nu
220
242
  * ```
221
243
  * @version 12.1.0
222
244
  */
223
- declare function last<T>(array: readonly T[]): T | undefined;
224
- declare function last<T, U>(array: readonly T[], defaultValue: U): T | U;
245
+ declare function last<const TArray extends readonly any[], const TDefault = undefined>(array: TArray, defaultValue?: TDefault): TArray extends readonly [...any[], infer TLast] ? TLast : TArray[number] | TDefault;
225
246
 
226
247
  /**
227
248
  * Creates a list of given start, end, value, and step parameters.
@@ -532,6 +553,14 @@ declare function zip<T1, T2>(array1: readonly T1[], array2: readonly T2[]): [T1,
532
553
  */
533
554
  declare function zipToObject<K extends string | number | symbol, V>(keys: readonly K[], values: V | ((key: K, idx: number) => V) | readonly V[]): Record<K, V>;
534
555
 
556
+ interface AggregateError extends Error {
557
+ errors: any[];
558
+ }
559
+ interface AggregateErrorConstructor {
560
+ new (errors: Iterable<any>, message?: string): AggregateError;
561
+ (errors: Iterable<any>, message?: string): AggregateError;
562
+ readonly prototype: AggregateError;
563
+ }
535
564
  /**
536
565
  * The `AggregateError` object represents an error when several errors
537
566
  * need to be wrapped in a single error.
@@ -639,23 +668,44 @@ declare function guard<TFunction extends () => any>(func: TFunction, shouldGuard
639
668
  */
640
669
  declare function map<T, K>(array: readonly T[], asyncMapFunc: (item: T, index: number) => Promise<K>): Promise<K[]>;
641
670
 
671
+ type AbortSignal$1 = {
672
+ readonly aborted: boolean;
673
+ addEventListener(type: 'abort', listener: () => void): void;
674
+ removeEventListener(type: 'abort', listener: () => void): void;
675
+ throwIfAborted(): void;
676
+ };
677
+ type ParallelOptions = {
678
+ limit: number;
679
+ signal?: AbortSignal$1;
680
+ } | number;
642
681
  /**
643
682
  * Executes many async functions in parallel. Returns the results from
644
683
  * all functions as an array. After all functions have resolved, if
645
684
  * any errors were thrown, they are rethrown in an instance of
646
- * AggregateError.
685
+ * AggregateError. The operation can be aborted by passing optional AbortSignal,
686
+ * which will throw an Error if aborted.
647
687
  *
648
688
  * @see https://radashi.js.org/reference/async/parallel
649
689
  * @example
650
690
  * ```ts
651
691
  * // Process images concurrently, resizing each image to a standard size.
652
- * const images = await parallel(2, imageFiles, async (file) => {
692
+ * const abortController = new AbortController();
693
+ * const images = await parallel(
694
+ * {
695
+ * limit: 2,
696
+ * signal: abortController.signal,
697
+ * },
698
+ * imageFiles,
699
+ * async file => {
653
700
  * return await resizeImage(file)
654
701
  * })
702
+ *
703
+ * // To abort the operation:
704
+ * // abortController.abort()
655
705
  * ```
656
706
  * @version 12.1.0
657
707
  */
658
- declare function parallel<T, K>(limit: number, array: readonly T[], func: (item: T) => Promise<K>): Promise<K[]>;
708
+ declare function parallel<T, K>(options: ParallelOptions, array: readonly T[], func: (item: T) => Promise<K>): Promise<K[]>;
659
709
 
660
710
  /**
661
711
  * An async reduce function. Works like the built-in Array.reduce
@@ -672,10 +722,14 @@ declare function parallel<T, K>(limit: number, array: readonly T[], func: (item:
672
722
  */
673
723
  declare function reduce<T, K>(array: readonly T[], asyncReducer: (acc: K, item: T, index: number) => Promise<K>, initValue?: K): Promise<K>;
674
724
 
725
+ type AbortSignal = {
726
+ throwIfAborted(): void;
727
+ };
675
728
  type RetryOptions = {
676
729
  times?: number;
677
730
  delay?: number | null;
678
731
  backoff?: (count: number) => number;
732
+ signal?: AbortSignal;
679
733
  };
680
734
  /**
681
735
  * Retries the given function the specified number of times.
@@ -683,9 +737,12 @@ type RetryOptions = {
683
737
  * @see https://radashi.js.org/reference/async/retry
684
738
  * @example
685
739
  * ```ts
686
- * const result = await retry({ times: 3, delay: 1000 }, async () => {
740
+ * const abortController = new AbortController();
741
+ * const result = await retry({ times: 3, delay: 1000, signal: abortController.signal }, async () => {
687
742
  * return await fetch('https://example.com')
688
743
  * })
744
+ * // To abort the operation:
745
+ * // abortController.abort()
689
746
  * ```
690
747
  * @version 12.1.0
691
748
  */
@@ -703,6 +760,39 @@ declare function retry<TResponse>(options: RetryOptions, func: (exit: (err: any)
703
760
  */
704
761
  declare function sleep(milliseconds: number): Promise<void>;
705
762
 
763
+ /**
764
+ * Creates a promise that will reject after a specified amount of time.
765
+ * You can provide a custom error message or a function that returns an error.
766
+ *
767
+ * @see https://radashi.js.org/reference/async/timeout
768
+ *
769
+ * @example
770
+ * ```ts
771
+ * // Reject after 1000 milliseconds with default message "timeout"
772
+ * await timeout(1000)
773
+ *
774
+ * // Reject after 1000 milliseconds with a custom message
775
+ * await timeout(1000, "Optional message")
776
+ *
777
+ * // Reject after 1000 milliseconds with a custom error
778
+ * await timeout(1000, () => new Error("Custom error"))
779
+ *
780
+ * // Example usage with Promise.race to set a timeout for an asynchronous task
781
+ * await Promise.race([
782
+ * someAsyncTask(),
783
+ * timeout(1000, "Optional message"),
784
+ * ])
785
+ * ```
786
+ * @version 12.3.0
787
+ */
788
+ declare function timeout<E extends Error>(milliseconds: number,
789
+ /**
790
+ * The error message to reject with.
791
+ *
792
+ * @default "timeout"
793
+ */
794
+ error?: string | (() => E)): Promise<void>;
795
+
706
796
  /**
707
797
  * The result of a `tryit` function.
708
798
  *
@@ -1978,7 +2068,7 @@ declare function upperize<T extends Record<string, any>>(obj: T): UppercaseKeys<
1978
2068
  * ```
1979
2069
  * @version 12.1.0
1980
2070
  */
1981
- declare function draw<T>(array: readonly T[]): T | null;
2071
+ declare function draw<const T extends readonly any[]>(array: T): T extends readonly [any, ...any[]] ? T[number] : T[number] | null;
1982
2072
 
1983
2073
  /**
1984
2074
  * Generates a random integer between min and max. Both min and max
@@ -2093,6 +2183,44 @@ declare function capitalize(str: string): string;
2093
2183
  */
2094
2184
  declare function dash(str: string): string;
2095
2185
 
2186
+ /**
2187
+ * Remove indentation from a string. The given string is expected to
2188
+ * be consistently indented (i.e. the leading whitespace of the first
2189
+ * non-empty line is the minimum required for all non-empty lines).
2190
+ *
2191
+ * If the `indent` argument is nullish, the indentation is detected
2192
+ * from the first non-empty line. Detection is cheap and robust for
2193
+ * most use cases, so you should only set an explicit `indent` if
2194
+ * necessary.
2195
+ *
2196
+ * @see https://radashi-org.github.io/reference/string/dedent
2197
+ * @example
2198
+ * ```ts
2199
+ * // This is indented with 4 spaces.
2200
+ * const input = `
2201
+ * Hello
2202
+ * World
2203
+ * `
2204
+ *
2205
+ * // Explicit indentation
2206
+ * dedent(input, ' ')
2207
+ * // => ' Hello\n World\n'
2208
+ *
2209
+ * // Detected indentation
2210
+ * dedent(input)
2211
+ * // => 'Hello\nWorld\n'
2212
+ *
2213
+ * // Tagged template strings
2214
+ * const str = dedent`
2215
+ * Foo ${1 + 1}
2216
+ * Bar ${2 * 2}
2217
+ * `
2218
+ * // => 'Foo 2\nBar 4'
2219
+ * ```
2220
+ */
2221
+ declare function dedent(template: TemplateStringsArray, ...values: unknown[]): string;
2222
+ declare function dedent(text: string, indent?: string | null): string;
2223
+
2096
2224
  /**
2097
2225
  * Formats the given string in pascal case fashion.
2098
2226
  *
@@ -2219,6 +2347,27 @@ type ExtractArray<T> = T extends any ? [StrictExtract<T, readonly any[]>] extend
2219
2347
 
2220
2348
  declare function isBoolean(value: unknown): value is boolean;
2221
2349
 
2350
+ /**
2351
+ * Checks if the given value is a class. This function verifies
2352
+ * if the value was defined using the `class` syntax. Old school
2353
+ * classes (defined with constructor functions) will return false.
2354
+ * "Native classes" like `Error` will also return false.
2355
+ *
2356
+ * @see https://radashi.js.org/reference/typed/isClass
2357
+ * @example
2358
+ * ```ts
2359
+ * isClass(class CustomClass {}) // => true
2360
+ * isClass('abc') // => false
2361
+ * isClass({}) // => false
2362
+ * ```
2363
+ */
2364
+ declare function isClass<T>(value: T): value is ExtractClass<T>;
2365
+ /**
2366
+ * Used by the `isClass` type guard. It handles type narrowing for
2367
+ * class constructors and even narrows `any` types.
2368
+ */
2369
+ type ExtractClass<T> = [StrictExtract<T, Class>] extends [Class] ? Extract<T, Class> : T extends any ? Class<unknown[], unknown> extends T ? Class<unknown[], unknown> : never : never;
2370
+
2222
2371
  /**
2223
2372
  * Return true if the given value is a Date object.
2224
2373
  *
@@ -2238,15 +2387,14 @@ declare function isDate(value: unknown): value is Date;
2238
2387
 
2239
2388
  /**
2240
2389
  * Return true if the given value is empty.
2390
+ * This function also uses [Type Guards](https://www.typescriptlang.org/docs/handbook/advanced-types.html#user-defined-type-guards) to ensure type safety
2241
2391
  *
2242
2392
  * Empty values include:
2243
2393
  * - `null`
2244
2394
  * - `undefined`
2245
2395
  * - `0`
2246
- * - `NaN`
2247
- * - `''`
2248
- * - `[]`
2249
- * - `{}`
2396
+ * - empty string
2397
+ * - empty array
2250
2398
  * - invalid `Date` time
2251
2399
  * - object with `length` property of `0`
2252
2400
  * - object with `size` property of `0`
@@ -2263,7 +2411,20 @@ declare function isDate(value: unknown): value is Date;
2263
2411
  * ```
2264
2412
  * @version 12.1.0
2265
2413
  */
2266
- declare function isEmpty(value: any): boolean;
2414
+ declare function isEmpty<T extends ToEmptyAble>(value: T): value is ToEmpty<T>;
2415
+ declare function isEmpty(value: unknown): boolean;
2416
+ type NeverEmpty = symbol | Function;
2417
+ /**
2418
+ * A type that can be narrowed by `isEmpty`.
2419
+ */
2420
+ type ToEmptyAble = NeverEmpty | boolean | number | string | readonly any[] | null | undefined;
2421
+ /**
2422
+ * Narrow a type to an empty value.
2423
+ *
2424
+ * Due to TypeScript limitations, object types cannot be narrowed,
2425
+ * except for arrays and functions.
2426
+ */
2427
+ type ToEmpty<T extends ToEmptyAble> = (T extends any[] ? never[] : Extract<false | 0 | '' | readonly never[] | null | undefined, T>) extends infer U ? Extract<U, T> : never;
2267
2428
 
2268
2429
  /**
2269
2430
  * Return true if the given values are equal.
@@ -2385,6 +2546,21 @@ type ExtractMap<T> = T extends any ? [StrictExtract<T, ReadonlyMap<unknown, unkn
2385
2546
  ReadonlyMap<unknown, unknown>
2386
2547
  ] ? Extract<T, ReadonlyMap<unknown, unknown>> : [StrictExtract<T, Map<unknown, unknown>>] extends [Map<unknown, unknown>] ? Extract<T, Map<unknown, unknown>> : Map<unknown, unknown> extends T ? Map<unknown, unknown> : never : never;
2387
2548
 
2549
+ /**
2550
+ * Return true if the given value is null or undefined.
2551
+ *
2552
+ * @see https://radashi.js.org/reference/typed/isNullish
2553
+ * @example
2554
+ * ```ts
2555
+ * isNullish(null) // => true
2556
+ * isNullish(undefined) // => true
2557
+ * isNullish('') // => false
2558
+ * isNullish(0) // => false
2559
+ * ```
2560
+ * @version 12.2.0
2561
+ */
2562
+ declare function isNullish(value: unknown): value is null | undefined;
2563
+
2388
2564
  /**
2389
2565
  * Return true if the given value is a number.
2390
2566
  *
@@ -3164,6 +3340,10 @@ type Falsy = null | undefined | false | '' | 0 | 0n;
3164
3340
  declare class Any {
3165
3341
  private any;
3166
3342
  }
3343
+ /**
3344
+ * Represents a class constructor.
3345
+ */
3346
+ type Class<TArgs extends any[] = any[], TReturn = any> = new (...args: TArgs) => TReturn;
3167
3347
  /**
3168
3348
  * Extracts `T` if `T` is not `any`, otherwise `never`.
3169
3349
  *
@@ -3361,4 +3541,4 @@ type GlobalObjectType<Identifier extends string> = [Identifier] extends [Any] ?
3361
3541
  [P in Identifier]: any;
3362
3542
  } ? InstanceType<(typeof globalThis)[Identifier]> : never;
3363
3543
 
3364
- export { AggregateErrorOrPolyfill as AggregateError, Any, type Assign, type BoxedPrimitive, type BuiltInType, type CastArray, type CastArrayIfExists, type CloningStrategy, type Comparable, type ComparableProperty, type Comparator, type ComparatorMapping, type CompatibleProperty, type Crush, type CustomClass, type CustomClassRegistry, type DebounceFunction, type DebounceOptions, DefaultCloningStrategy, type Err, type ExtractArray, type ExtractMap, type ExtractNotAny, type ExtractSet, type Falsy, FastCloningStrategy, type FilteredKeys, type Flip, type Intersect, type IsExactType, type KeyFilter, type KeyFilterFunction, type LowercaseKeys, type MappedInput, type MappedOutput, type Mapping, type MappingFunction, type MemoOptions, type NoInfer, type Ok, type OnceFunction, type OptionalKeys, type OptionalMapping, type Primitive, type RequiredKeys, type Result, type ResultPromise, type RetryOptions, type Series, type Simplify, type StrictExtract, type SwitchAny, type SwitchNever, type ThrottledFunction, type TraverseContext, type TraverseOptions, type TraverseVisitor, type TryitResult, type TypedArray, type UppercaseKeys, all, alphabetical, always, assign, boil, callable, camel, capitalize, castArray, castArrayIfExists, castComparator, castMapping, chain, clamp, clone, cloneDeep, cluster, compose, construct, counting, crush, dash, debounce, defer, diff, draw, filterKey, first, flat, flip, fork, get, group, guard, inRange, intersects, invert, isArray, isBoolean, isDate, isEmpty, isEqual, isError, isFloat, isFunction, isInt, isIntString, isIterable, isMap, isNumber, isObject, isPlainObject, isPrimitive, isPromise, isRegExp, isResult, isResultErr, isResultOk, isSet, isString, isSymbol, isTagged, isWeakMap, isWeakSet, iterate, keys, last, lerp, list, listify, lowerize, map, mapEntries, mapKeys, mapValues, mapify, max, memo, merge, min, noop, objectify, omit, once, parallel, partial, partob, pascal, pick, proxied, random, range, reduce, replace, replaceOrAppend, retry, round, select, selectFirst, series, set, shake, shift, shuffle, sift, similarity, sleep, snake, sort, sum, template, throttle, title, toFloat, toInt, toggle, traverse, trim, tryit as try, tryit, uid, unique, unzip, upperize, withResolvers, zip, zipToObject };
3544
+ export { AggregateErrorOrPolyfill as AggregateError, Any, type Assign, type BoxedPrimitive, type BuiltInType, type CastArray, type CastArrayIfExists, type Class, type CloningStrategy, type Comparable, type ComparableProperty, type Comparator, type ComparatorMapping, type CompatibleProperty, type Crush, type CustomClass, type CustomClassRegistry, type DebounceFunction, type DebounceOptions, DefaultCloningStrategy, type Err, type ExtractArray, type ExtractClass, type ExtractMap, type ExtractNotAny, type ExtractSet, type Falsy, FastCloningStrategy, type FilteredKeys, type Flip, type Intersect, type IsExactType, type KeyFilter, type KeyFilterFunction, type LowercaseKeys, type MappedInput, type MappedOutput, type Mapping, type MappingFunction, type MemoOptions, type NoInfer, type Ok, type OnceFunction, type OptionalKeys, type OptionalMapping, type ParallelOptions, type Primitive, type PromiseWithResolvers, type RequiredKeys, type Result, type ResultPromise, type RetryOptions, type Series, type Simplify, type StrictExtract, type SwitchAny, type SwitchNever, type ThrottledFunction, type ToEmpty, type ToEmptyAble, type TraverseContext, type TraverseOptions, type TraverseVisitor, type TryitResult, type TypedArray, type UppercaseKeys, all, alphabetical, always, assign, boil, callable, camel, capitalize, cartesianProduct, castArray, castArrayIfExists, castComparator, castMapping, chain, clamp, clone, cloneDeep, cluster, compose, construct, counting, crush, dash, debounce, dedent, defer, diff, draw, filterKey, first, flat, flip, fork, get, group, guard, inRange, intersects, invert, isArray, isBoolean, isClass, isDate, isEmpty, isEqual, isError, isFloat, isFunction, isInt, isIntString, isIterable, isMap, isNullish, isNumber, isObject, isPlainObject, isPrimitive, isPromise, isRegExp, isResult, isResultErr, isResultOk, isSet, isString, isSymbol, isTagged, isWeakMap, isWeakSet, iterate, keys, last, lerp, list, listify, lowerize, map, mapEntries, mapKeys, mapValues, mapify, max, memo, merge, min, noop, objectify, omit, once, parallel, partial, partob, pascal, pick, proxied, random, range, reduce, replace, replaceOrAppend, retry, round, select, selectFirst, series, set, shake, shift, shuffle, sift, similarity, sleep, snake, sort, sum, template, throttle, timeout, title, toFloat, toInt, toggle, traverse, trim, tryit as try, tryit, uid, unique, unzip, upperize, withResolvers, zip, zipToObject };
package/dist/radashi.d.ts CHANGED
@@ -21,6 +21,29 @@ declare function alphabetical<T>(array: readonly T[], getter: (item: T) => strin
21
21
  */
22
22
  declare function boil<T>(array: readonly T[], compareFunc: (a: T, b: T) => T): T | null;
23
23
 
24
+ /**
25
+ * Create an [n-ary Cartesian product](https://en.wikipedia.org/wiki/Cartesian_product#n-ary_Cartesian_product) from the given arrays.
26
+ *
27
+ * @see https://radashi.js.org/reference/array/cartesianProduct
28
+ * @example
29
+ * ```ts
30
+ * product([['red', 'blue'], ['big', 'small'], ['fast', 'slow']])
31
+ * // [
32
+ * // ['red', 'big', 'fast'],
33
+ * // ['red', 'big', 'slow'],
34
+ * // ['red', 'small', 'fast'],
35
+ * // ['red', 'small', 'slow'],
36
+ * // ['blue', 'big', 'fast'],
37
+ * // ['blue', 'big', 'slow'],
38
+ * // ['blue', 'small', 'fast'],
39
+ * // ['blue', 'small', 'slow']
40
+ * // ]
41
+ * ```
42
+ */
43
+ declare function cartesianProduct<T extends any[][]>(...arrays: [...T]): Array<{
44
+ [K in keyof T]: T[K][number];
45
+ }>;
46
+
24
47
  /**
25
48
  * Casts the given value to an array. If the value is already an
26
49
  * array, a shallow copy is returned. Otherwise, a new array
@@ -125,8 +148,7 @@ declare function diff<T>(root: readonly T[], other: readonly T[], identity?: (it
125
148
  * ```
126
149
  * @version 12.1.0
127
150
  */
128
- declare function first<T>(array: readonly T[]): T | undefined;
129
- declare function first<T, U>(array: readonly T[], defaultValue: U): T | U;
151
+ declare function first<const TArray extends readonly any[], const TDefault = undefined>(array: TArray, defaultValue?: TDefault): TArray extends readonly [infer TFirst, ...any[]] ? TFirst : TArray[number] | TDefault;
130
152
 
131
153
  /**
132
154
  * Given an array of arrays, returns a single dimensional array with
@@ -220,8 +242,7 @@ declare function iterate<T>(count: number, func: (currentValue: T, iteration: nu
220
242
  * ```
221
243
  * @version 12.1.0
222
244
  */
223
- declare function last<T>(array: readonly T[]): T | undefined;
224
- declare function last<T, U>(array: readonly T[], defaultValue: U): T | U;
245
+ declare function last<const TArray extends readonly any[], const TDefault = undefined>(array: TArray, defaultValue?: TDefault): TArray extends readonly [...any[], infer TLast] ? TLast : TArray[number] | TDefault;
225
246
 
226
247
  /**
227
248
  * Creates a list of given start, end, value, and step parameters.
@@ -532,6 +553,14 @@ declare function zip<T1, T2>(array1: readonly T1[], array2: readonly T2[]): [T1,
532
553
  */
533
554
  declare function zipToObject<K extends string | number | symbol, V>(keys: readonly K[], values: V | ((key: K, idx: number) => V) | readonly V[]): Record<K, V>;
534
555
 
556
+ interface AggregateError extends Error {
557
+ errors: any[];
558
+ }
559
+ interface AggregateErrorConstructor {
560
+ new (errors: Iterable<any>, message?: string): AggregateError;
561
+ (errors: Iterable<any>, message?: string): AggregateError;
562
+ readonly prototype: AggregateError;
563
+ }
535
564
  /**
536
565
  * The `AggregateError` object represents an error when several errors
537
566
  * need to be wrapped in a single error.
@@ -639,23 +668,44 @@ declare function guard<TFunction extends () => any>(func: TFunction, shouldGuard
639
668
  */
640
669
  declare function map<T, K>(array: readonly T[], asyncMapFunc: (item: T, index: number) => Promise<K>): Promise<K[]>;
641
670
 
671
+ type AbortSignal$1 = {
672
+ readonly aborted: boolean;
673
+ addEventListener(type: 'abort', listener: () => void): void;
674
+ removeEventListener(type: 'abort', listener: () => void): void;
675
+ throwIfAborted(): void;
676
+ };
677
+ type ParallelOptions = {
678
+ limit: number;
679
+ signal?: AbortSignal$1;
680
+ } | number;
642
681
  /**
643
682
  * Executes many async functions in parallel. Returns the results from
644
683
  * all functions as an array. After all functions have resolved, if
645
684
  * any errors were thrown, they are rethrown in an instance of
646
- * AggregateError.
685
+ * AggregateError. The operation can be aborted by passing optional AbortSignal,
686
+ * which will throw an Error if aborted.
647
687
  *
648
688
  * @see https://radashi.js.org/reference/async/parallel
649
689
  * @example
650
690
  * ```ts
651
691
  * // Process images concurrently, resizing each image to a standard size.
652
- * const images = await parallel(2, imageFiles, async (file) => {
692
+ * const abortController = new AbortController();
693
+ * const images = await parallel(
694
+ * {
695
+ * limit: 2,
696
+ * signal: abortController.signal,
697
+ * },
698
+ * imageFiles,
699
+ * async file => {
653
700
  * return await resizeImage(file)
654
701
  * })
702
+ *
703
+ * // To abort the operation:
704
+ * // abortController.abort()
655
705
  * ```
656
706
  * @version 12.1.0
657
707
  */
658
- declare function parallel<T, K>(limit: number, array: readonly T[], func: (item: T) => Promise<K>): Promise<K[]>;
708
+ declare function parallel<T, K>(options: ParallelOptions, array: readonly T[], func: (item: T) => Promise<K>): Promise<K[]>;
659
709
 
660
710
  /**
661
711
  * An async reduce function. Works like the built-in Array.reduce
@@ -672,10 +722,14 @@ declare function parallel<T, K>(limit: number, array: readonly T[], func: (item:
672
722
  */
673
723
  declare function reduce<T, K>(array: readonly T[], asyncReducer: (acc: K, item: T, index: number) => Promise<K>, initValue?: K): Promise<K>;
674
724
 
725
+ type AbortSignal = {
726
+ throwIfAborted(): void;
727
+ };
675
728
  type RetryOptions = {
676
729
  times?: number;
677
730
  delay?: number | null;
678
731
  backoff?: (count: number) => number;
732
+ signal?: AbortSignal;
679
733
  };
680
734
  /**
681
735
  * Retries the given function the specified number of times.
@@ -683,9 +737,12 @@ type RetryOptions = {
683
737
  * @see https://radashi.js.org/reference/async/retry
684
738
  * @example
685
739
  * ```ts
686
- * const result = await retry({ times: 3, delay: 1000 }, async () => {
740
+ * const abortController = new AbortController();
741
+ * const result = await retry({ times: 3, delay: 1000, signal: abortController.signal }, async () => {
687
742
  * return await fetch('https://example.com')
688
743
  * })
744
+ * // To abort the operation:
745
+ * // abortController.abort()
689
746
  * ```
690
747
  * @version 12.1.0
691
748
  */
@@ -703,6 +760,39 @@ declare function retry<TResponse>(options: RetryOptions, func: (exit: (err: any)
703
760
  */
704
761
  declare function sleep(milliseconds: number): Promise<void>;
705
762
 
763
+ /**
764
+ * Creates a promise that will reject after a specified amount of time.
765
+ * You can provide a custom error message or a function that returns an error.
766
+ *
767
+ * @see https://radashi.js.org/reference/async/timeout
768
+ *
769
+ * @example
770
+ * ```ts
771
+ * // Reject after 1000 milliseconds with default message "timeout"
772
+ * await timeout(1000)
773
+ *
774
+ * // Reject after 1000 milliseconds with a custom message
775
+ * await timeout(1000, "Optional message")
776
+ *
777
+ * // Reject after 1000 milliseconds with a custom error
778
+ * await timeout(1000, () => new Error("Custom error"))
779
+ *
780
+ * // Example usage with Promise.race to set a timeout for an asynchronous task
781
+ * await Promise.race([
782
+ * someAsyncTask(),
783
+ * timeout(1000, "Optional message"),
784
+ * ])
785
+ * ```
786
+ * @version 12.3.0
787
+ */
788
+ declare function timeout<E extends Error>(milliseconds: number,
789
+ /**
790
+ * The error message to reject with.
791
+ *
792
+ * @default "timeout"
793
+ */
794
+ error?: string | (() => E)): Promise<void>;
795
+
706
796
  /**
707
797
  * The result of a `tryit` function.
708
798
  *
@@ -1978,7 +2068,7 @@ declare function upperize<T extends Record<string, any>>(obj: T): UppercaseKeys<
1978
2068
  * ```
1979
2069
  * @version 12.1.0
1980
2070
  */
1981
- declare function draw<T>(array: readonly T[]): T | null;
2071
+ declare function draw<const T extends readonly any[]>(array: T): T extends readonly [any, ...any[]] ? T[number] : T[number] | null;
1982
2072
 
1983
2073
  /**
1984
2074
  * Generates a random integer between min and max. Both min and max
@@ -2093,6 +2183,44 @@ declare function capitalize(str: string): string;
2093
2183
  */
2094
2184
  declare function dash(str: string): string;
2095
2185
 
2186
+ /**
2187
+ * Remove indentation from a string. The given string is expected to
2188
+ * be consistently indented (i.e. the leading whitespace of the first
2189
+ * non-empty line is the minimum required for all non-empty lines).
2190
+ *
2191
+ * If the `indent` argument is nullish, the indentation is detected
2192
+ * from the first non-empty line. Detection is cheap and robust for
2193
+ * most use cases, so you should only set an explicit `indent` if
2194
+ * necessary.
2195
+ *
2196
+ * @see https://radashi-org.github.io/reference/string/dedent
2197
+ * @example
2198
+ * ```ts
2199
+ * // This is indented with 4 spaces.
2200
+ * const input = `
2201
+ * Hello
2202
+ * World
2203
+ * `
2204
+ *
2205
+ * // Explicit indentation
2206
+ * dedent(input, ' ')
2207
+ * // => ' Hello\n World\n'
2208
+ *
2209
+ * // Detected indentation
2210
+ * dedent(input)
2211
+ * // => 'Hello\nWorld\n'
2212
+ *
2213
+ * // Tagged template strings
2214
+ * const str = dedent`
2215
+ * Foo ${1 + 1}
2216
+ * Bar ${2 * 2}
2217
+ * `
2218
+ * // => 'Foo 2\nBar 4'
2219
+ * ```
2220
+ */
2221
+ declare function dedent(template: TemplateStringsArray, ...values: unknown[]): string;
2222
+ declare function dedent(text: string, indent?: string | null): string;
2223
+
2096
2224
  /**
2097
2225
  * Formats the given string in pascal case fashion.
2098
2226
  *
@@ -2219,6 +2347,27 @@ type ExtractArray<T> = T extends any ? [StrictExtract<T, readonly any[]>] extend
2219
2347
 
2220
2348
  declare function isBoolean(value: unknown): value is boolean;
2221
2349
 
2350
+ /**
2351
+ * Checks if the given value is a class. This function verifies
2352
+ * if the value was defined using the `class` syntax. Old school
2353
+ * classes (defined with constructor functions) will return false.
2354
+ * "Native classes" like `Error` will also return false.
2355
+ *
2356
+ * @see https://radashi.js.org/reference/typed/isClass
2357
+ * @example
2358
+ * ```ts
2359
+ * isClass(class CustomClass {}) // => true
2360
+ * isClass('abc') // => false
2361
+ * isClass({}) // => false
2362
+ * ```
2363
+ */
2364
+ declare function isClass<T>(value: T): value is ExtractClass<T>;
2365
+ /**
2366
+ * Used by the `isClass` type guard. It handles type narrowing for
2367
+ * class constructors and even narrows `any` types.
2368
+ */
2369
+ type ExtractClass<T> = [StrictExtract<T, Class>] extends [Class] ? Extract<T, Class> : T extends any ? Class<unknown[], unknown> extends T ? Class<unknown[], unknown> : never : never;
2370
+
2222
2371
  /**
2223
2372
  * Return true if the given value is a Date object.
2224
2373
  *
@@ -2238,15 +2387,14 @@ declare function isDate(value: unknown): value is Date;
2238
2387
 
2239
2388
  /**
2240
2389
  * Return true if the given value is empty.
2390
+ * This function also uses [Type Guards](https://www.typescriptlang.org/docs/handbook/advanced-types.html#user-defined-type-guards) to ensure type safety
2241
2391
  *
2242
2392
  * Empty values include:
2243
2393
  * - `null`
2244
2394
  * - `undefined`
2245
2395
  * - `0`
2246
- * - `NaN`
2247
- * - `''`
2248
- * - `[]`
2249
- * - `{}`
2396
+ * - empty string
2397
+ * - empty array
2250
2398
  * - invalid `Date` time
2251
2399
  * - object with `length` property of `0`
2252
2400
  * - object with `size` property of `0`
@@ -2263,7 +2411,20 @@ declare function isDate(value: unknown): value is Date;
2263
2411
  * ```
2264
2412
  * @version 12.1.0
2265
2413
  */
2266
- declare function isEmpty(value: any): boolean;
2414
+ declare function isEmpty<T extends ToEmptyAble>(value: T): value is ToEmpty<T>;
2415
+ declare function isEmpty(value: unknown): boolean;
2416
+ type NeverEmpty = symbol | Function;
2417
+ /**
2418
+ * A type that can be narrowed by `isEmpty`.
2419
+ */
2420
+ type ToEmptyAble = NeverEmpty | boolean | number | string | readonly any[] | null | undefined;
2421
+ /**
2422
+ * Narrow a type to an empty value.
2423
+ *
2424
+ * Due to TypeScript limitations, object types cannot be narrowed,
2425
+ * except for arrays and functions.
2426
+ */
2427
+ type ToEmpty<T extends ToEmptyAble> = (T extends any[] ? never[] : Extract<false | 0 | '' | readonly never[] | null | undefined, T>) extends infer U ? Extract<U, T> : never;
2267
2428
 
2268
2429
  /**
2269
2430
  * Return true if the given values are equal.
@@ -2385,6 +2546,21 @@ type ExtractMap<T> = T extends any ? [StrictExtract<T, ReadonlyMap<unknown, unkn
2385
2546
  ReadonlyMap<unknown, unknown>
2386
2547
  ] ? Extract<T, ReadonlyMap<unknown, unknown>> : [StrictExtract<T, Map<unknown, unknown>>] extends [Map<unknown, unknown>] ? Extract<T, Map<unknown, unknown>> : Map<unknown, unknown> extends T ? Map<unknown, unknown> : never : never;
2387
2548
 
2549
+ /**
2550
+ * Return true if the given value is null or undefined.
2551
+ *
2552
+ * @see https://radashi.js.org/reference/typed/isNullish
2553
+ * @example
2554
+ * ```ts
2555
+ * isNullish(null) // => true
2556
+ * isNullish(undefined) // => true
2557
+ * isNullish('') // => false
2558
+ * isNullish(0) // => false
2559
+ * ```
2560
+ * @version 12.2.0
2561
+ */
2562
+ declare function isNullish(value: unknown): value is null | undefined;
2563
+
2388
2564
  /**
2389
2565
  * Return true if the given value is a number.
2390
2566
  *
@@ -3164,6 +3340,10 @@ type Falsy = null | undefined | false | '' | 0 | 0n;
3164
3340
  declare class Any {
3165
3341
  private any;
3166
3342
  }
3343
+ /**
3344
+ * Represents a class constructor.
3345
+ */
3346
+ type Class<TArgs extends any[] = any[], TReturn = any> = new (...args: TArgs) => TReturn;
3167
3347
  /**
3168
3348
  * Extracts `T` if `T` is not `any`, otherwise `never`.
3169
3349
  *
@@ -3361,4 +3541,4 @@ type GlobalObjectType<Identifier extends string> = [Identifier] extends [Any] ?
3361
3541
  [P in Identifier]: any;
3362
3542
  } ? InstanceType<(typeof globalThis)[Identifier]> : never;
3363
3543
 
3364
- export { AggregateErrorOrPolyfill as AggregateError, Any, type Assign, type BoxedPrimitive, type BuiltInType, type CastArray, type CastArrayIfExists, type CloningStrategy, type Comparable, type ComparableProperty, type Comparator, type ComparatorMapping, type CompatibleProperty, type Crush, type CustomClass, type CustomClassRegistry, type DebounceFunction, type DebounceOptions, DefaultCloningStrategy, type Err, type ExtractArray, type ExtractMap, type ExtractNotAny, type ExtractSet, type Falsy, FastCloningStrategy, type FilteredKeys, type Flip, type Intersect, type IsExactType, type KeyFilter, type KeyFilterFunction, type LowercaseKeys, type MappedInput, type MappedOutput, type Mapping, type MappingFunction, type MemoOptions, type NoInfer, type Ok, type OnceFunction, type OptionalKeys, type OptionalMapping, type Primitive, type RequiredKeys, type Result, type ResultPromise, type RetryOptions, type Series, type Simplify, type StrictExtract, type SwitchAny, type SwitchNever, type ThrottledFunction, type TraverseContext, type TraverseOptions, type TraverseVisitor, type TryitResult, type TypedArray, type UppercaseKeys, all, alphabetical, always, assign, boil, callable, camel, capitalize, castArray, castArrayIfExists, castComparator, castMapping, chain, clamp, clone, cloneDeep, cluster, compose, construct, counting, crush, dash, debounce, defer, diff, draw, filterKey, first, flat, flip, fork, get, group, guard, inRange, intersects, invert, isArray, isBoolean, isDate, isEmpty, isEqual, isError, isFloat, isFunction, isInt, isIntString, isIterable, isMap, isNumber, isObject, isPlainObject, isPrimitive, isPromise, isRegExp, isResult, isResultErr, isResultOk, isSet, isString, isSymbol, isTagged, isWeakMap, isWeakSet, iterate, keys, last, lerp, list, listify, lowerize, map, mapEntries, mapKeys, mapValues, mapify, max, memo, merge, min, noop, objectify, omit, once, parallel, partial, partob, pascal, pick, proxied, random, range, reduce, replace, replaceOrAppend, retry, round, select, selectFirst, series, set, shake, shift, shuffle, sift, similarity, sleep, snake, sort, sum, template, throttle, title, toFloat, toInt, toggle, traverse, trim, tryit as try, tryit, uid, unique, unzip, upperize, withResolvers, zip, zipToObject };
3544
+ export { AggregateErrorOrPolyfill as AggregateError, Any, type Assign, type BoxedPrimitive, type BuiltInType, type CastArray, type CastArrayIfExists, type Class, type CloningStrategy, type Comparable, type ComparableProperty, type Comparator, type ComparatorMapping, type CompatibleProperty, type Crush, type CustomClass, type CustomClassRegistry, type DebounceFunction, type DebounceOptions, DefaultCloningStrategy, type Err, type ExtractArray, type ExtractClass, type ExtractMap, type ExtractNotAny, type ExtractSet, type Falsy, FastCloningStrategy, type FilteredKeys, type Flip, type Intersect, type IsExactType, type KeyFilter, type KeyFilterFunction, type LowercaseKeys, type MappedInput, type MappedOutput, type Mapping, type MappingFunction, type MemoOptions, type NoInfer, type Ok, type OnceFunction, type OptionalKeys, type OptionalMapping, type ParallelOptions, type Primitive, type PromiseWithResolvers, type RequiredKeys, type Result, type ResultPromise, type RetryOptions, type Series, type Simplify, type StrictExtract, type SwitchAny, type SwitchNever, type ThrottledFunction, type ToEmpty, type ToEmptyAble, type TraverseContext, type TraverseOptions, type TraverseVisitor, type TryitResult, type TypedArray, type UppercaseKeys, all, alphabetical, always, assign, boil, callable, camel, capitalize, cartesianProduct, castArray, castArrayIfExists, castComparator, castMapping, chain, clamp, clone, cloneDeep, cluster, compose, construct, counting, crush, dash, debounce, dedent, defer, diff, draw, filterKey, first, flat, flip, fork, get, group, guard, inRange, intersects, invert, isArray, isBoolean, isClass, isDate, isEmpty, isEqual, isError, isFloat, isFunction, isInt, isIntString, isIterable, isMap, isNullish, isNumber, isObject, isPlainObject, isPrimitive, isPromise, isRegExp, isResult, isResultErr, isResultOk, isSet, isString, isSymbol, isTagged, isWeakMap, isWeakSet, iterate, keys, last, lerp, list, listify, lowerize, map, mapEntries, mapKeys, mapValues, mapify, max, memo, merge, min, noop, objectify, omit, once, parallel, partial, partob, pascal, pick, proxied, random, range, reduce, replace, replaceOrAppend, retry, round, select, selectFirst, series, set, shake, shift, shuffle, sift, similarity, sleep, snake, sort, sum, template, throttle, timeout, title, toFloat, toInt, toggle, traverse, trim, tryit as try, tryit, uid, unique, unzip, upperize, withResolvers, zip, zipToObject };
package/dist/radashi.js CHANGED
@@ -16,6 +16,23 @@ function boil(array, compareFunc) {
16
16
  return array.reduce(compareFunc);
17
17
  }
18
18
 
19
+ // src/array/cartesianProduct.ts
20
+ function cartesianProduct(...arrays) {
21
+ let out = [[]];
22
+ for (const array of arrays) {
23
+ const result = [];
24
+ for (const currentArray of out) {
25
+ for (const item of array) {
26
+ const currentArrayCopy = currentArray.slice();
27
+ currentArrayCopy.push(item);
28
+ result.push(currentArrayCopy);
29
+ }
30
+ }
31
+ out = result;
32
+ }
33
+ return out;
34
+ }
35
+
19
36
  // src/array/castArray.ts
20
37
  function castArray(value) {
21
38
  return Array.isArray(value) ? value.slice() : [value];
@@ -356,20 +373,17 @@ function zipToObject(keys2, values) {
356
373
  }
357
374
 
358
375
  // src/async/AggregateError.ts
359
- var AggregateErrorOrPolyfill = /* @__PURE__ */ (() => (
360
- // eslint-disable-next-line compat/compat
361
- globalThis.AggregateError ?? class AggregateError extends Error {
362
- constructor(errors = []) {
363
- var _a, _b;
364
- super();
365
- const name = ((_a = errors.find((e) => e.name)) == null ? void 0 : _a.name) ?? "";
366
- this.name = `AggregateError(${name}...)`;
367
- this.message = `AggregateError with ${errors.length} errors`;
368
- this.stack = ((_b = errors.find((e) => e.stack)) == null ? void 0 : _b.stack) ?? this.stack;
369
- this.errors = errors;
370
- }
376
+ var AggregateErrorOrPolyfill = /* @__PURE__ */ (() => globalThis.AggregateError ?? class AggregateError extends Error {
377
+ constructor(errors = []) {
378
+ var _a, _b;
379
+ super();
380
+ const name = ((_a = errors.find((e) => e.name)) == null ? void 0 : _a.name) ?? "";
381
+ this.name = `AggregateError(${name}...)`;
382
+ this.message = `AggregateError with ${errors.length} errors`;
383
+ this.stack = ((_b = errors.find((e) => e.stack)) == null ? void 0 : _b.stack) ?? this.stack;
384
+ this.errors = errors;
371
385
  }
372
- ))();
386
+ })();
373
387
 
374
388
  // src/async/all.ts
375
389
  async function all(promises) {
@@ -446,17 +460,27 @@ async function map(array, asyncMapFunc) {
446
460
  }
447
461
 
448
462
  // src/async/parallel.ts
449
- async function parallel(limit, array, func) {
463
+ async function parallel(options, array, func) {
464
+ var _a;
450
465
  const work = array.map((item, index) => ({
451
466
  index,
452
467
  item
453
468
  }));
454
- const processor = async (res) => {
469
+ if (isNumber(options)) {
470
+ options = {
471
+ limit: options
472
+ };
473
+ }
474
+ (_a = options.signal) == null ? void 0 : _a.throwIfAborted();
475
+ const processor = async (resolve, reject) => {
476
+ var _a2, _b;
455
477
  const results2 = [];
478
+ const abortListener = () => reject(new Error("This operation was aborted"));
479
+ (_a2 = options.signal) == null ? void 0 : _a2.addEventListener("abort", abortListener);
456
480
  while (true) {
457
481
  const next = work.pop();
458
482
  if (!next) {
459
- return res(results2);
483
+ break;
460
484
  }
461
485
  const [error, result] = await tryit(func)(next.item);
462
486
  results2.push({
@@ -465,8 +489,10 @@ async function parallel(limit, array, func) {
465
489
  index: next.index
466
490
  });
467
491
  }
492
+ (_b = options.signal) == null ? void 0 : _b.removeEventListener("abort", abortListener);
493
+ return resolve(results2);
468
494
  };
469
- const queues = list(1, limit).map(() => new Promise(processor));
495
+ const queues = list(1, options.limit).map(() => new Promise(processor));
470
496
  const itemResults = await Promise.all(queues);
471
497
  const [errors, results] = fork(
472
498
  sort(flat(itemResults), (r) => r.index),
@@ -497,11 +523,13 @@ async function retry(options, func) {
497
523
  const times = (options == null ? void 0 : options.times) ?? 3;
498
524
  const delay = options == null ? void 0 : options.delay;
499
525
  const backoff = (options == null ? void 0 : options.backoff) ?? null;
526
+ const signal = options == null ? void 0 : options.signal;
500
527
  let i = 0;
501
528
  while (true) {
502
529
  const [err, result] = await tryit(func)((err2) => {
503
530
  throw { _exited: err2 };
504
531
  });
532
+ signal == null ? void 0 : signal.throwIfAborted();
505
533
  if (!err) {
506
534
  return result;
507
535
  }
@@ -525,6 +553,19 @@ function sleep(milliseconds) {
525
553
  return new Promise((res) => setTimeout(res, milliseconds));
526
554
  }
527
555
 
556
+ // src/async/timeout.ts
557
+ function timeout(milliseconds, error = "timeout") {
558
+ return new Promise(
559
+ (_, rej) => setTimeout(() => {
560
+ if (isString(error)) {
561
+ rej(new Error(error));
562
+ } else {
563
+ rej(error());
564
+ }
565
+ }, milliseconds)
566
+ );
567
+ }
568
+
528
569
  // src/async/tryit.ts
529
570
  function tryit(func) {
530
571
  return (...args) => {
@@ -1370,6 +1411,30 @@ function dash(str) {
1370
1411
  });
1371
1412
  }
1372
1413
 
1414
+ // src/string/dedent.ts
1415
+ function dedent(text, ...values) {
1416
+ var _a;
1417
+ if (isArray(text)) {
1418
+ if (values.length > 0) {
1419
+ return dedent(
1420
+ text.reduce((acc, input, i) => {
1421
+ var _a2;
1422
+ let value = String(values[i] ?? "");
1423
+ const indent2 = value.includes("\n") && ((_a2 = input.match(/[ \t]*(?=[^\n]*$)/)) == null ? void 0 : _a2[0]);
1424
+ if (indent2) {
1425
+ value = value.replace(/\n(?=[^\n]*?\S)/g, "\n" + indent2);
1426
+ }
1427
+ return acc + input + value;
1428
+ }, "")
1429
+ );
1430
+ }
1431
+ text = text[0];
1432
+ }
1433
+ const indent = values[0] ?? ((_a = text.match(/^[ \t]*(?=\S)/m)) == null ? void 0 : _a[0]);
1434
+ const output = indent ? text.replace(new RegExp(`^${indent}`, "gm"), "") : text;
1435
+ return output.replace(/^[ \t]*\n|\n[ \t]*$/g, "");
1436
+ }
1437
+
1373
1438
  // src/string/pascal.ts
1374
1439
  function pascal(str) {
1375
1440
  if (!str) {
@@ -1488,6 +1553,11 @@ function isBoolean(value) {
1488
1553
  return typeof value === "boolean";
1489
1554
  }
1490
1555
 
1556
+ // src/typed/isClass.ts
1557
+ function isClass(value) {
1558
+ return isFunction(value) && Function.prototype.toString.call(value).startsWith("class ");
1559
+ }
1560
+
1491
1561
  // src/typed/isDate.ts
1492
1562
  function isDate(value) {
1493
1563
  return isTagged(value, "[object Date]");
@@ -1592,6 +1662,11 @@ function isMap(value) {
1592
1662
  return isTagged(value, "[object Map]");
1593
1663
  }
1594
1664
 
1665
+ // src/typed/isNullish.ts
1666
+ function isNullish(value) {
1667
+ return value === null || value === void 0;
1668
+ }
1669
+
1595
1670
  // src/typed/isNumber.ts
1596
1671
  function isNumber(value) {
1597
1672
  return typeof value === "number" && !Number.isNaN(value);
@@ -1676,4 +1751,4 @@ function isWeakSet(value) {
1676
1751
  return isTagged(value, "[object WeakSet]");
1677
1752
  }
1678
1753
 
1679
- export { AggregateErrorOrPolyfill as AggregateError, DefaultCloningStrategy, FastCloningStrategy, all, alphabetical, always, assign, boil, callable, camel, capitalize, castArray, castArrayIfExists, castComparator, castMapping, chain, clamp, clone, cloneDeep, cluster, compose, construct, counting, crush, dash, debounce, defer, diff, draw, filterKey, first, flat, flip, fork, get, group, guard, inRange, intersects, invert, isArray, isBoolean, isDate, isEmpty, isEqual, isError, isFloat, isFunction, isInt, isIntString, isIterable, isMap, isNumber, isObject, isPlainObject, isPrimitive, isPromise, isRegExp, isResult, isResultErr, isResultOk, isSet, isString, isSymbol, isTagged, isWeakMap, isWeakSet, iterate, keys, last, lerp, list, listify, lowerize, map, mapEntries, mapKeys, mapValues, mapify, max, memo, merge, min, noop, objectify, omit, once, parallel, partial, partob, pascal, pick, proxied, random, range, reduce, replace, replaceOrAppend, retry, round, select, selectFirst, series, set, shake, shift, shuffle, sift, similarity, sleep, snake, sort, sum, template, throttle, title, toFloat, toInt, toggle, traverse, trim, tryit as try, tryit, uid, unique, unzip, upperize, withResolvers, zip, zipToObject };
1754
+ export { AggregateErrorOrPolyfill as AggregateError, DefaultCloningStrategy, FastCloningStrategy, all, alphabetical, always, assign, boil, callable, camel, capitalize, cartesianProduct, castArray, castArrayIfExists, castComparator, castMapping, chain, clamp, clone, cloneDeep, cluster, compose, construct, counting, crush, dash, debounce, dedent, defer, diff, draw, filterKey, first, flat, flip, fork, get, group, guard, inRange, intersects, invert, isArray, isBoolean, isClass, isDate, isEmpty, isEqual, isError, isFloat, isFunction, isInt, isIntString, isIterable, isMap, isNullish, isNumber, isObject, isPlainObject, isPrimitive, isPromise, isRegExp, isResult, isResultErr, isResultOk, isSet, isString, isSymbol, isTagged, isWeakMap, isWeakSet, iterate, keys, last, lerp, list, listify, lowerize, map, mapEntries, mapKeys, mapValues, mapify, max, memo, merge, min, noop, objectify, omit, once, parallel, partial, partob, pascal, pick, proxied, random, range, reduce, replace, replaceOrAppend, retry, round, select, selectFirst, series, set, shake, shift, shuffle, sift, similarity, sleep, snake, sort, sum, template, throttle, timeout, title, toFloat, toInt, toggle, traverse, trim, tryit as try, tryit, uid, unique, unzip, upperize, withResolvers, zip, zipToObject };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "radashi",
3
- "version": "12.2.1",
3
+ "version": "12.3.0-beta.8c8abf6",
4
4
  "type": "module",
5
5
  "description": "The modern, community-first TypeScript toolkit with all of the fast, readable, and minimal utility functions you need. Type-safe, dependency-free, tree-shakeable, fully tested.",
6
6
  "repository": {