superjs-core 0.1.0
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/async/index.d.ts +44 -0
- package/dist/async/index.js +88 -0
- package/dist/async/index.js.map +1 -0
- package/dist/collection/index.d.ts +75 -0
- package/dist/collection/index.js +140 -0
- package/dist/collection/index.js.map +1 -0
- package/dist/core/index.d.ts +95 -0
- package/dist/core/index.js +272 -0
- package/dist/core/index.js.map +1 -0
- package/dist/crypto/index.d.ts +78 -0
- package/dist/crypto/index.js +147 -0
- package/dist/crypto/index.js.map +1 -0
- package/dist/date/index.d.ts +203 -0
- package/dist/date/index.js +282 -0
- package/dist/date/index.js.map +1 -0
- package/dist/index.d.ts +10 -0
- package/dist/index.js +1505 -0
- package/dist/index.js.map +1 -0
- package/dist/io/index.d.ts +39 -0
- package/dist/io/index.js +110 -0
- package/dist/io/index.js.map +1 -0
- package/dist/math/index.d.ts +117 -0
- package/dist/math/index.js +104 -0
- package/dist/math/index.js.map +1 -0
- package/dist/path/index.d.ts +81 -0
- package/dist/path/index.js +134 -0
- package/dist/path/index.js.map +1 -0
- package/dist/string/index.d.ts +91 -0
- package/dist/string/index.js +146 -0
- package/dist/string/index.js.map +1 -0
- package/dist/type/index.d.ts +87 -0
- package/dist/type/index.js +109 -0
- package/dist/type/index.js.map +1 -0
- package/package.json +103 -0
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { RetryOptions } from '../core/index.js';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Delays execution for the given number of milliseconds.
|
|
5
|
+
*/
|
|
6
|
+
declare function sleep(ms: number): Promise<void>;
|
|
7
|
+
/**
|
|
8
|
+
* Rejects a promise if it does not resolve within the specified timeout.
|
|
9
|
+
*/
|
|
10
|
+
declare function timeout<T>(promise: Promise<T>, ms: number, errorMessage?: string): Promise<T>;
|
|
11
|
+
/**
|
|
12
|
+
* Races a promise against a timeout, returning 'timeout' if the timer wins.
|
|
13
|
+
*/
|
|
14
|
+
declare function raceWithTimeout<T>(promise: Promise<T>, ms: number): Promise<T | 'timeout'>;
|
|
15
|
+
/**
|
|
16
|
+
* Maps over an array with an async function, using Promise.allSettled.
|
|
17
|
+
* Returns an array of PromiseSettledResult.
|
|
18
|
+
*/
|
|
19
|
+
declare function allSettledMap<T, R>(items: T[], fn: (item: T) => Promise<R>): Promise<PromiseSettledResult<R>[]>;
|
|
20
|
+
/**
|
|
21
|
+
* Maps over an array with an async function, limiting concurrency.
|
|
22
|
+
*
|
|
23
|
+
* @param concurrency - Maximum number of concurrent operations (default Infinity)
|
|
24
|
+
*/
|
|
25
|
+
declare function parallelMap<T, R>(items: T[], fn: (item: T) => Promise<R>, concurrency?: number): Promise<R[]>;
|
|
26
|
+
/**
|
|
27
|
+
* Retries an async function with exponential backoff.
|
|
28
|
+
*/
|
|
29
|
+
declare function retryAsync<T>(fn: () => Promise<T>, options?: RetryOptions): Promise<T>;
|
|
30
|
+
/**
|
|
31
|
+
* Composes async functions, passing the result of each to the next.
|
|
32
|
+
*/
|
|
33
|
+
declare function pipeline<T>(initial: T, ...fns: Array<(arg: T) => Promise<T>>): Promise<T>;
|
|
34
|
+
/**
|
|
35
|
+
* Creates a deferred promise with external resolve and reject methods.
|
|
36
|
+
*/
|
|
37
|
+
declare function deferred<T>(): Deferred<T>;
|
|
38
|
+
interface Deferred<T> {
|
|
39
|
+
promise: Promise<T>;
|
|
40
|
+
resolve: (value: T) => void;
|
|
41
|
+
reject: (reason: unknown) => void;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export { type Deferred, allSettledMap, deferred, parallelMap, pipeline, raceWithTimeout, retryAsync, sleep, timeout };
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
// src/async/index.ts
|
|
2
|
+
function sleep(ms) {
|
|
3
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
4
|
+
}
|
|
5
|
+
async function timeout(promise, ms, errorMessage) {
|
|
6
|
+
let timer;
|
|
7
|
+
const timeoutPromise = new Promise((_, reject) => {
|
|
8
|
+
timer = setTimeout(() => reject(new Error(errorMessage ?? `Promise timed out after ${ms}ms`)), ms);
|
|
9
|
+
});
|
|
10
|
+
try {
|
|
11
|
+
return await Promise.race([promise, timeoutPromise]);
|
|
12
|
+
} finally {
|
|
13
|
+
if (timer !== void 0) clearTimeout(timer);
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
async function raceWithTimeout(promise, ms) {
|
|
17
|
+
let timer;
|
|
18
|
+
const timeoutPromise = new Promise((resolve) => {
|
|
19
|
+
timer = setTimeout(() => resolve("timeout"), ms);
|
|
20
|
+
});
|
|
21
|
+
try {
|
|
22
|
+
return await Promise.race([promise, timeoutPromise]);
|
|
23
|
+
} finally {
|
|
24
|
+
if (timer !== void 0) clearTimeout(timer);
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
async function allSettledMap(items, fn) {
|
|
28
|
+
return await Promise.allSettled(items.map(fn));
|
|
29
|
+
}
|
|
30
|
+
async function parallelMap(items, fn, concurrency = Number.POSITIVE_INFINITY) {
|
|
31
|
+
if (concurrency === Number.POSITIVE_INFINITY) {
|
|
32
|
+
return await Promise.all(items.map(fn));
|
|
33
|
+
}
|
|
34
|
+
const results = [];
|
|
35
|
+
const queue = [...items];
|
|
36
|
+
const worker = async () => {
|
|
37
|
+
while (queue.length > 0) {
|
|
38
|
+
const item = queue.shift();
|
|
39
|
+
results.push(await fn(item));
|
|
40
|
+
}
|
|
41
|
+
};
|
|
42
|
+
const workerCount = Math.min(concurrency, items.length);
|
|
43
|
+
const workers = Array.from({ length: workerCount }, () => worker());
|
|
44
|
+
await Promise.all(workers);
|
|
45
|
+
return results;
|
|
46
|
+
}
|
|
47
|
+
async function retryAsync(fn, options) {
|
|
48
|
+
const { attempts = 3, baseDelay = 1e3, maxDelay = 3e4, shouldRetry = () => true } = options ?? {};
|
|
49
|
+
let lastError;
|
|
50
|
+
for (let attempt = 0; attempt < attempts; attempt++) {
|
|
51
|
+
try {
|
|
52
|
+
return await fn();
|
|
53
|
+
} catch (error) {
|
|
54
|
+
lastError = error;
|
|
55
|
+
if (!shouldRetry(error) || attempt >= attempts - 1) break;
|
|
56
|
+
const delay = Math.min(baseDelay * 2 ** attempt + Math.random() * baseDelay, maxDelay);
|
|
57
|
+
await sleep(delay);
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
throw lastError;
|
|
61
|
+
}
|
|
62
|
+
async function pipeline(initial, ...fns) {
|
|
63
|
+
let result = initial;
|
|
64
|
+
for (const fn of fns) {
|
|
65
|
+
result = await fn(result);
|
|
66
|
+
}
|
|
67
|
+
return result;
|
|
68
|
+
}
|
|
69
|
+
function deferred() {
|
|
70
|
+
let resolve;
|
|
71
|
+
let reject;
|
|
72
|
+
const promise = new Promise((res, rej) => {
|
|
73
|
+
resolve = res;
|
|
74
|
+
reject = rej;
|
|
75
|
+
});
|
|
76
|
+
return { promise, resolve, reject };
|
|
77
|
+
}
|
|
78
|
+
export {
|
|
79
|
+
allSettledMap,
|
|
80
|
+
deferred,
|
|
81
|
+
parallelMap,
|
|
82
|
+
pipeline,
|
|
83
|
+
raceWithTimeout,
|
|
84
|
+
retryAsync,
|
|
85
|
+
sleep,
|
|
86
|
+
timeout
|
|
87
|
+
};
|
|
88
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/async/index.ts"],"sourcesContent":["import type { RetryOptions } from '../core/index.js'\n\n/**\n * Delays execution for the given number of milliseconds.\n */\nexport function sleep(ms: number): Promise<void> {\n return new Promise(resolve => setTimeout(resolve, ms))\n}\n\n/**\n * Rejects a promise if it does not resolve within the specified timeout.\n */\nexport async function timeout<T>(promise: Promise<T>, ms: number, errorMessage?: string): Promise<T> {\n let timer: ReturnType<typeof setTimeout> | undefined\n const timeoutPromise = new Promise<never>((_, reject) => {\n timer = setTimeout(() => reject(new Error(errorMessage ?? `Promise timed out after ${ms}ms`)), ms)\n })\n try {\n return await Promise.race([promise, timeoutPromise])\n } finally {\n if (timer !== undefined) clearTimeout(timer)\n }\n}\n\n/**\n * Races a promise against a timeout, returning 'timeout' if the timer wins.\n */\nexport async function raceWithTimeout<T>(promise: Promise<T>, ms: number): Promise<T | 'timeout'> {\n let timer: ReturnType<typeof setTimeout> | undefined\n const timeoutPromise = new Promise<'timeout'>(resolve => {\n timer = setTimeout(() => resolve('timeout'), ms)\n })\n try {\n return await Promise.race([promise, timeoutPromise])\n } finally {\n if (timer !== undefined) clearTimeout(timer)\n }\n}\n\n/**\n * Maps over an array with an async function, using Promise.allSettled.\n * Returns an array of PromiseSettledResult.\n */\nexport async function allSettledMap<T, R>(\n items: T[],\n fn: (item: T) => Promise<R>,\n): Promise<PromiseSettledResult<R>[]> {\n return await Promise.allSettled(items.map(fn))\n}\n\n/**\n * Maps over an array with an async function, limiting concurrency.\n *\n * @param concurrency - Maximum number of concurrent operations (default Infinity)\n */\nexport async function parallelMap<T, R>(\n items: T[],\n fn: (item: T) => Promise<R>,\n concurrency = Number.POSITIVE_INFINITY,\n): Promise<R[]> {\n if (concurrency === Number.POSITIVE_INFINITY) {\n return await Promise.all(items.map(fn))\n }\n\n const results: R[] = []\n const queue = [...items]\n\n const worker = async (): Promise<void> => {\n while (queue.length > 0) {\n const item = queue.shift()!\n results.push(await fn(item))\n }\n }\n\n const workerCount = Math.min(concurrency, items.length)\n const workers = Array.from({ length: workerCount }, () => worker())\n await Promise.all(workers)\n return results\n}\n\n/**\n * Retries an async function with exponential backoff.\n */\nexport async function retryAsync<T>(fn: () => Promise<T>, options?: RetryOptions): Promise<T> {\n const { attempts = 3, baseDelay = 1000, maxDelay = 30000, shouldRetry = () => true } = options ?? {}\n let lastError: unknown\n for (let attempt = 0; attempt < attempts; attempt++) {\n try {\n return await fn()\n } catch (error) {\n lastError = error\n if (!shouldRetry(error) || attempt >= attempts - 1) break\n const delay = Math.min(baseDelay * 2 ** attempt + Math.random() * baseDelay, maxDelay)\n await sleep(delay)\n }\n }\n throw lastError\n}\n\n/**\n * Composes async functions, passing the result of each to the next.\n */\nexport async function pipeline<T>(initial: T, ...fns: Array<(arg: T) => Promise<T>>): Promise<T> {\n let result = initial\n for (const fn of fns) {\n result = await fn(result)\n }\n return result\n}\n\n/**\n * Creates a deferred promise with external resolve and reject methods.\n */\nexport function deferred<T>(): Deferred<T> {\n let resolve!: (value: T) => void\n let reject!: (reason: unknown) => void\n const promise = new Promise<T>((res, rej) => {\n resolve = res\n reject = rej\n })\n return { promise, resolve, reject }\n}\n\nexport interface Deferred<T> {\n promise: Promise<T>\n resolve: (value: T) => void\n reject: (reason: unknown) => void\n}\n"],"mappings":";AAKO,SAAS,MAAM,IAA2B;AAC/C,SAAO,IAAI,QAAQ,aAAW,WAAW,SAAS,EAAE,CAAC;AACvD;AAKA,eAAsB,QAAW,SAAqB,IAAY,cAAmC;AACnG,MAAI;AACJ,QAAM,iBAAiB,IAAI,QAAe,CAAC,GAAG,WAAW;AACvD,YAAQ,WAAW,MAAM,OAAO,IAAI,MAAM,gBAAgB,2BAA2B,EAAE,IAAI,CAAC,GAAG,EAAE;AAAA,EACnG,CAAC;AACD,MAAI;AACF,WAAO,MAAM,QAAQ,KAAK,CAAC,SAAS,cAAc,CAAC;AAAA,EACrD,UAAE;AACA,QAAI,UAAU,OAAW,cAAa,KAAK;AAAA,EAC7C;AACF;AAKA,eAAsB,gBAAmB,SAAqB,IAAoC;AAChG,MAAI;AACJ,QAAM,iBAAiB,IAAI,QAAmB,aAAW;AACvD,YAAQ,WAAW,MAAM,QAAQ,SAAS,GAAG,EAAE;AAAA,EACjD,CAAC;AACD,MAAI;AACF,WAAO,MAAM,QAAQ,KAAK,CAAC,SAAS,cAAc,CAAC;AAAA,EACrD,UAAE;AACA,QAAI,UAAU,OAAW,cAAa,KAAK;AAAA,EAC7C;AACF;AAMA,eAAsB,cACpB,OACA,IACoC;AACpC,SAAO,MAAM,QAAQ,WAAW,MAAM,IAAI,EAAE,CAAC;AAC/C;AAOA,eAAsB,YACpB,OACA,IACA,cAAc,OAAO,mBACP;AACd,MAAI,gBAAgB,OAAO,mBAAmB;AAC5C,WAAO,MAAM,QAAQ,IAAI,MAAM,IAAI,EAAE,CAAC;AAAA,EACxC;AAEA,QAAM,UAAe,CAAC;AACtB,QAAM,QAAQ,CAAC,GAAG,KAAK;AAEvB,QAAM,SAAS,YAA2B;AACxC,WAAO,MAAM,SAAS,GAAG;AACvB,YAAM,OAAO,MAAM,MAAM;AACzB,cAAQ,KAAK,MAAM,GAAG,IAAI,CAAC;AAAA,IAC7B;AAAA,EACF;AAEA,QAAM,cAAc,KAAK,IAAI,aAAa,MAAM,MAAM;AACtD,QAAM,UAAU,MAAM,KAAK,EAAE,QAAQ,YAAY,GAAG,MAAM,OAAO,CAAC;AAClE,QAAM,QAAQ,IAAI,OAAO;AACzB,SAAO;AACT;AAKA,eAAsB,WAAc,IAAsB,SAAoC;AAC5F,QAAM,EAAE,WAAW,GAAG,YAAY,KAAM,WAAW,KAAO,cAAc,MAAM,KAAK,IAAI,WAAW,CAAC;AACnG,MAAI;AACJ,WAAS,UAAU,GAAG,UAAU,UAAU,WAAW;AACnD,QAAI;AACF,aAAO,MAAM,GAAG;AAAA,IAClB,SAAS,OAAO;AACd,kBAAY;AACZ,UAAI,CAAC,YAAY,KAAK,KAAK,WAAW,WAAW,EAAG;AACpD,YAAM,QAAQ,KAAK,IAAI,YAAY,KAAK,UAAU,KAAK,OAAO,IAAI,WAAW,QAAQ;AACrF,YAAM,MAAM,KAAK;AAAA,IACnB;AAAA,EACF;AACA,QAAM;AACR;AAKA,eAAsB,SAAY,YAAe,KAAgD;AAC/F,MAAI,SAAS;AACb,aAAW,MAAM,KAAK;AACpB,aAAS,MAAM,GAAG,MAAM;AAAA,EAC1B;AACA,SAAO;AACT;AAKO,SAAS,WAA2B;AACzC,MAAI;AACJ,MAAI;AACJ,QAAM,UAAU,IAAI,QAAW,CAAC,KAAK,QAAQ;AAC3C,cAAU;AACV,aAAS;AAAA,EACX,CAAC;AACD,SAAO,EAAE,SAAS,SAAS,OAAO;AACpC;","names":[]}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Groups an array of items by a key extracted from each item.
|
|
3
|
+
*
|
|
4
|
+
* @example groupBy([{ type: 'a' }, { type: 'b' }, { type: 'a' }], x => x.type)
|
|
5
|
+
* // => { a: [{ type: 'a' }, { type: 'a' }], b: [{ type: 'b' }] }
|
|
6
|
+
*/
|
|
7
|
+
declare function groupBy<T, K extends string | number | symbol>(items: T[], keyFn: (item: T) => K): Record<K, T[]>;
|
|
8
|
+
/**
|
|
9
|
+
* Creates an object keyed by the result of keyFn for each item.
|
|
10
|
+
*
|
|
11
|
+
* @example keyBy([{ id: 1, name: 'a' }, { id: 2, name: 'b' }], x => x.id)
|
|
12
|
+
* // => { 1: { id: 1, name: 'a' }, 2: { id: 2, name: 'b' } }
|
|
13
|
+
*/
|
|
14
|
+
declare function keyBy<T, K extends string | number | symbol>(items: T[], keyFn: (item: T) => K): Record<K, T>;
|
|
15
|
+
/**
|
|
16
|
+
* Returns a copy of the object with the specified keys omitted.
|
|
17
|
+
*/
|
|
18
|
+
declare function omit<T extends Record<string, unknown>, K extends keyof T>(obj: T, keys: K[]): Omit<T, K>;
|
|
19
|
+
/**
|
|
20
|
+
* Returns a copy of the object with only the specified keys.
|
|
21
|
+
*/
|
|
22
|
+
declare function pick<T extends Record<string, unknown>, K extends keyof T>(obj: T, keys: K[]): Pick<T, K>;
|
|
23
|
+
/**
|
|
24
|
+
* Extracts a property value from each item in an array.
|
|
25
|
+
*/
|
|
26
|
+
declare function pluck<T, K extends keyof T>(items: T[], key: K): T[K][];
|
|
27
|
+
/**
|
|
28
|
+
* Randomizes array order in-place using the Fisher-Yates algorithm.
|
|
29
|
+
*/
|
|
30
|
+
declare function shuffle<T>(items: T[]): T[];
|
|
31
|
+
/**
|
|
32
|
+
* Returns a random element from the array, or undefined if empty.
|
|
33
|
+
*/
|
|
34
|
+
declare function sample<T>(items: T[]): T | undefined;
|
|
35
|
+
/**
|
|
36
|
+
* Returns an array of `size` random elements (without duplicates).
|
|
37
|
+
*/
|
|
38
|
+
declare function sampleSize<T>(items: T[], size: number): T[];
|
|
39
|
+
/**
|
|
40
|
+
* Splits an array into chunks of the specified size.
|
|
41
|
+
*/
|
|
42
|
+
declare function chunk<T>(items: T[], size: number): T[][];
|
|
43
|
+
declare function sortBy<T>(items: T[], ...criteria: Array<(item: T) => unknown>): T[];
|
|
44
|
+
/**
|
|
45
|
+
* Returns a sorted copy of the array by a single key and direction.
|
|
46
|
+
*/
|
|
47
|
+
declare function orderBy<T>(items: T[], key: (item: T) => unknown, direction?: SortDirection): T[];
|
|
48
|
+
/**
|
|
49
|
+
* Returns unique elements based on the result of keyFn.
|
|
50
|
+
*/
|
|
51
|
+
declare function uniqueBy<T>(items: T[], keyFn: (item: T) => unknown): T[];
|
|
52
|
+
/**
|
|
53
|
+
* Flattens an array of arrays one level.
|
|
54
|
+
*/
|
|
55
|
+
declare function flatten<T>(items: T[][]): T[];
|
|
56
|
+
/**
|
|
57
|
+
* Returns an array with unique primitive values.
|
|
58
|
+
*/
|
|
59
|
+
declare function uniq<T>(items: T[]): T[];
|
|
60
|
+
/**
|
|
61
|
+
* Returns the first element, or undefined if empty.
|
|
62
|
+
*/
|
|
63
|
+
declare function first<T>(items: T[]): T | undefined;
|
|
64
|
+
/**
|
|
65
|
+
* Returns the last element, or undefined if empty.
|
|
66
|
+
*/
|
|
67
|
+
declare function last<T>(items: T[]): T | undefined;
|
|
68
|
+
/**
|
|
69
|
+
* Checks if a value is empty.
|
|
70
|
+
* Works for arrays, objects, strings, Map, and Set.
|
|
71
|
+
*/
|
|
72
|
+
declare function isEmpty(value: unknown): boolean;
|
|
73
|
+
type SortDirection = 'asc' | 'desc';
|
|
74
|
+
|
|
75
|
+
export { type SortDirection, chunk, first, flatten, groupBy, isEmpty, keyBy, last, omit, orderBy, pick, pluck, sample, sampleSize, shuffle, sortBy, uniq, uniqueBy };
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
// src/collection/index.ts
|
|
2
|
+
function groupBy(items, keyFn) {
|
|
3
|
+
const result = {};
|
|
4
|
+
for (const item of items) {
|
|
5
|
+
const key = keyFn(item);
|
|
6
|
+
if (!result[key]) result[key] = [];
|
|
7
|
+
result[key].push(item);
|
|
8
|
+
}
|
|
9
|
+
return result;
|
|
10
|
+
}
|
|
11
|
+
function keyBy(items, keyFn) {
|
|
12
|
+
const result = {};
|
|
13
|
+
for (const item of items) {
|
|
14
|
+
const key = keyFn(item);
|
|
15
|
+
result[key] = item;
|
|
16
|
+
}
|
|
17
|
+
return result;
|
|
18
|
+
}
|
|
19
|
+
function omit(obj, keys) {
|
|
20
|
+
const result = { ...obj };
|
|
21
|
+
for (const key of keys) {
|
|
22
|
+
delete result[key];
|
|
23
|
+
}
|
|
24
|
+
return result;
|
|
25
|
+
}
|
|
26
|
+
function pick(obj, keys) {
|
|
27
|
+
const result = {};
|
|
28
|
+
for (const key of keys) {
|
|
29
|
+
if (key in obj) {
|
|
30
|
+
result[key] = obj[key];
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
return result;
|
|
34
|
+
}
|
|
35
|
+
function pluck(items, key) {
|
|
36
|
+
return items.map((item) => item[key]);
|
|
37
|
+
}
|
|
38
|
+
function shuffle(items) {
|
|
39
|
+
const result = [...items];
|
|
40
|
+
for (let i = result.length - 1; i > 0; i--) {
|
|
41
|
+
const j = Math.floor(Math.random() * (i + 1));
|
|
42
|
+
const temp = result[i];
|
|
43
|
+
result[i] = result[j];
|
|
44
|
+
result[j] = temp;
|
|
45
|
+
}
|
|
46
|
+
return result;
|
|
47
|
+
}
|
|
48
|
+
function sample(items) {
|
|
49
|
+
return items.length > 0 ? items[Math.floor(Math.random() * items.length)] : void 0;
|
|
50
|
+
}
|
|
51
|
+
function sampleSize(items, size) {
|
|
52
|
+
if (size <= 0 || items.length === 0) return [];
|
|
53
|
+
const pool = shuffle(items);
|
|
54
|
+
return pool.slice(0, Math.min(size, items.length));
|
|
55
|
+
}
|
|
56
|
+
function chunk(items, size) {
|
|
57
|
+
if (size <= 0 || items.length === 0) return [];
|
|
58
|
+
const result = [];
|
|
59
|
+
for (let i = 0; i < items.length; i += size) {
|
|
60
|
+
result.push(items.slice(i, i + size));
|
|
61
|
+
}
|
|
62
|
+
return result;
|
|
63
|
+
}
|
|
64
|
+
function compareValues(a, b) {
|
|
65
|
+
if (a === b) return 0;
|
|
66
|
+
if (a == null) return -1;
|
|
67
|
+
if (b == null) return 1;
|
|
68
|
+
if (typeof a === "string" && typeof b === "string") return a < b ? -1 : 1;
|
|
69
|
+
if (typeof a === "number" && typeof b === "number") return a < b ? -1 : 1;
|
|
70
|
+
return String(a) < String(b) ? -1 : 1;
|
|
71
|
+
}
|
|
72
|
+
function sortBy(items, ...criteria) {
|
|
73
|
+
return [...items].sort((a, b) => {
|
|
74
|
+
for (const criterion of criteria) {
|
|
75
|
+
const cmp = compareValues(criterion(a), criterion(b));
|
|
76
|
+
if (cmp !== 0) return cmp;
|
|
77
|
+
}
|
|
78
|
+
return 0;
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
function orderBy(items, key, direction = "asc") {
|
|
82
|
+
return [...items].sort((a, b) => {
|
|
83
|
+
const cmp = compareValues(key(a), key(b));
|
|
84
|
+
return direction === "asc" ? cmp : -cmp;
|
|
85
|
+
});
|
|
86
|
+
}
|
|
87
|
+
function uniqueBy(items, keyFn) {
|
|
88
|
+
const seen = /* @__PURE__ */ new Set();
|
|
89
|
+
return items.filter((item) => {
|
|
90
|
+
const key = keyFn(item);
|
|
91
|
+
if (seen.has(key)) return false;
|
|
92
|
+
seen.add(key);
|
|
93
|
+
return true;
|
|
94
|
+
});
|
|
95
|
+
}
|
|
96
|
+
function flatten(items) {
|
|
97
|
+
const result = [];
|
|
98
|
+
for (const sub of items) {
|
|
99
|
+
for (const item of sub) {
|
|
100
|
+
result.push(item);
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
return result;
|
|
104
|
+
}
|
|
105
|
+
function uniq(items) {
|
|
106
|
+
return [...new Set(items)];
|
|
107
|
+
}
|
|
108
|
+
function first(items) {
|
|
109
|
+
return items[0];
|
|
110
|
+
}
|
|
111
|
+
function last(items) {
|
|
112
|
+
return items[items.length - 1];
|
|
113
|
+
}
|
|
114
|
+
function isEmpty(value) {
|
|
115
|
+
if (Array.isArray(value)) return value.length === 0;
|
|
116
|
+
if (typeof value === "string") return value.length === 0;
|
|
117
|
+
if (value instanceof Map || value instanceof Set) return value.size === 0;
|
|
118
|
+
if (value !== null && typeof value === "object") return Object.keys(value).length === 0;
|
|
119
|
+
return false;
|
|
120
|
+
}
|
|
121
|
+
export {
|
|
122
|
+
chunk,
|
|
123
|
+
first,
|
|
124
|
+
flatten,
|
|
125
|
+
groupBy,
|
|
126
|
+
isEmpty,
|
|
127
|
+
keyBy,
|
|
128
|
+
last,
|
|
129
|
+
omit,
|
|
130
|
+
orderBy,
|
|
131
|
+
pick,
|
|
132
|
+
pluck,
|
|
133
|
+
sample,
|
|
134
|
+
sampleSize,
|
|
135
|
+
shuffle,
|
|
136
|
+
sortBy,
|
|
137
|
+
uniq,
|
|
138
|
+
uniqueBy
|
|
139
|
+
};
|
|
140
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/collection/index.ts"],"sourcesContent":["/**\n * Groups an array of items by a key extracted from each item.\n *\n * @example groupBy([{ type: 'a' }, { type: 'b' }, { type: 'a' }], x => x.type)\n * // => { a: [{ type: 'a' }, { type: 'a' }], b: [{ type: 'b' }] }\n */\nexport function groupBy<T, K extends string | number | symbol>(items: T[], keyFn: (item: T) => K): Record<K, T[]> {\n const result = {} as Record<K, T[]>\n for (const item of items) {\n const key = keyFn(item)\n if (!result[key]) result[key] = []\n result[key]!.push(item)\n }\n return result\n}\n\n/**\n * Creates an object keyed by the result of keyFn for each item.\n *\n * @example keyBy([{ id: 1, name: 'a' }, { id: 2, name: 'b' }], x => x.id)\n * // => { 1: { id: 1, name: 'a' }, 2: { id: 2, name: 'b' } }\n */\nexport function keyBy<T, K extends string | number | symbol>(items: T[], keyFn: (item: T) => K): Record<K, T> {\n const result = {} as Record<K, T>\n for (const item of items) {\n const key = keyFn(item)\n result[key] = item\n }\n return result\n}\n\n/**\n * Returns a copy of the object with the specified keys omitted.\n */\nexport function omit<T extends Record<string, unknown>, K extends keyof T>(obj: T, keys: K[]): Omit<T, K> {\n const result = { ...obj } as T\n for (const key of keys) {\n delete result[key]\n }\n return result as Omit<T, K>\n}\n\n/**\n * Returns a copy of the object with only the specified keys.\n */\nexport function pick<T extends Record<string, unknown>, K extends keyof T>(obj: T, keys: K[]): Pick<T, K> {\n const result = {} as Pick<T, K>\n for (const key of keys) {\n if (key in obj) {\n result[key] = obj[key]\n }\n }\n return result\n}\n\n/**\n * Extracts a property value from each item in an array.\n */\nexport function pluck<T, K extends keyof T>(items: T[], key: K): T[K][] {\n return items.map(item => item[key])\n}\n\n/**\n * Randomizes array order in-place using the Fisher-Yates algorithm.\n */\nexport function shuffle<T>(items: T[]): T[] {\n const result = [...items]\n for (let i = result.length - 1; i > 0; i--) {\n const j = Math.floor(Math.random() * (i + 1))\n const temp = result[i]!\n result[i] = result[j]!\n result[j] = temp\n }\n return result\n}\n\n/**\n * Returns a random element from the array, or undefined if empty.\n */\nexport function sample<T>(items: T[]): T | undefined {\n return items.length > 0 ? items[Math.floor(Math.random() * items.length)] : undefined\n}\n\n/**\n * Returns an array of `size` random elements (without duplicates).\n */\nexport function sampleSize<T>(items: T[], size: number): T[] {\n if (size <= 0 || items.length === 0) return []\n const pool = shuffle(items)\n return pool.slice(0, Math.min(size, items.length))\n}\n\n/**\n * Splits an array into chunks of the specified size.\n */\nexport function chunk<T>(items: T[], size: number): T[][] {\n if (size <= 0 || items.length === 0) return []\n const result: T[][] = []\n for (let i = 0; i < items.length; i += size) {\n result.push(items.slice(i, i + size))\n }\n return result\n}\n\n/**\n * Returns a sorted copy of the array using the provided criteria functions.\n * Earlier criteria take precedence.\n */\nfunction compareValues(a: unknown, b: unknown): number {\n if (a === b) return 0\n if (a == null) return -1\n if (b == null) return 1\n if (typeof a === 'string' && typeof b === 'string') return a < b ? -1 : 1\n if (typeof a === 'number' && typeof b === 'number') return a < b ? -1 : 1\n return String(a) < String(b) ? -1 : 1\n}\n\nexport function sortBy<T>(items: T[], ...criteria: Array<(item: T) => unknown>): T[] {\n return [...items].sort((a, b) => {\n for (const criterion of criteria) {\n const cmp = compareValues(criterion(a), criterion(b))\n if (cmp !== 0) return cmp\n }\n return 0\n })\n}\n\n/**\n * Returns a sorted copy of the array by a single key and direction.\n */\nexport function orderBy<T>(items: T[], key: (item: T) => unknown, direction: SortDirection = 'asc'): T[] {\n return [...items].sort((a, b) => {\n const cmp = compareValues(key(a), key(b))\n return direction === 'asc' ? cmp : -cmp\n })\n}\n\n/**\n * Returns unique elements based on the result of keyFn.\n */\nexport function uniqueBy<T>(items: T[], keyFn: (item: T) => unknown): T[] {\n const seen = new Set<unknown>()\n return items.filter(item => {\n const key = keyFn(item)\n if (seen.has(key)) return false\n seen.add(key)\n return true\n })\n}\n\n/**\n * Flattens an array of arrays one level.\n */\nexport function flatten<T>(items: T[][]): T[] {\n const result: T[] = []\n for (const sub of items) {\n for (const item of sub) {\n result.push(item)\n }\n }\n return result\n}\n\n/**\n * Returns an array with unique primitive values.\n */\nexport function uniq<T>(items: T[]): T[] {\n return [...new Set(items)]\n}\n\n/**\n * Returns the first element, or undefined if empty.\n */\nexport function first<T>(items: T[]): T | undefined {\n return items[0]\n}\n\n/**\n * Returns the last element, or undefined if empty.\n */\nexport function last<T>(items: T[]): T | undefined {\n return items[items.length - 1]\n}\n\n/**\n * Checks if a value is empty.\n * Works for arrays, objects, strings, Map, and Set.\n */\nexport function isEmpty(value: unknown): boolean {\n if (Array.isArray(value)) return value.length === 0\n if (typeof value === 'string') return value.length === 0\n if (value instanceof Map || value instanceof Set) return value.size === 0\n if (value !== null && typeof value === 'object') return Object.keys(value as Record<string, unknown>).length === 0\n return false\n}\n\nexport type SortDirection = 'asc' | 'desc'\n"],"mappings":"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","names":[]}
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
interface DebounceOptions {
|
|
2
|
+
leading?: boolean;
|
|
3
|
+
trailing?: boolean;
|
|
4
|
+
maxWait?: number;
|
|
5
|
+
}
|
|
6
|
+
interface DebouncedFunction<T extends (...args: unknown[]) => unknown> {
|
|
7
|
+
(...args: Parameters<T>): void;
|
|
8
|
+
cancel(): void;
|
|
9
|
+
flush(): void;
|
|
10
|
+
}
|
|
11
|
+
interface MemoizedFunction<T extends (...args: unknown[]) => unknown> {
|
|
12
|
+
(...args: Parameters<T>): ReturnType<T>;
|
|
13
|
+
cache: Map<string, ReturnType<T>>;
|
|
14
|
+
}
|
|
15
|
+
interface RetryOptions {
|
|
16
|
+
attempts?: number;
|
|
17
|
+
baseDelay?: number;
|
|
18
|
+
maxDelay?: number;
|
|
19
|
+
shouldRetry?: (error: unknown) => boolean;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Deep clone a value, supporting objects, arrays, Date, RegExp, Map, Set,
|
|
23
|
+
* and cyclic references.
|
|
24
|
+
*
|
|
25
|
+
* @param value - The value to clone.
|
|
26
|
+
* @returns A deep copy of the input value.
|
|
27
|
+
*/
|
|
28
|
+
declare function deepClone<T>(value: T): T;
|
|
29
|
+
/**
|
|
30
|
+
* Deep merge multiple objects. Arrays are overwritten, not concatenated.
|
|
31
|
+
* `null` and `undefined` source objects are skipped.
|
|
32
|
+
*
|
|
33
|
+
* @param objects - The objects to merge.
|
|
34
|
+
* @returns A new object with merged properties.
|
|
35
|
+
*/
|
|
36
|
+
declare function deepMerge<T extends Record<string, unknown>>(...objects: Partial<T>[]): T;
|
|
37
|
+
/**
|
|
38
|
+
* Creates a debounced function that delays invoking `fn` until after `wait`
|
|
39
|
+
* milliseconds have elapsed since the last invocation. Supports leading,
|
|
40
|
+
* trailing, and maxWait options. The returned function also has `.cancel()`
|
|
41
|
+
* and `.flush()` methods.
|
|
42
|
+
*
|
|
43
|
+
* @param fn - The function to debounce.
|
|
44
|
+
* @param wait - The number of milliseconds to delay.
|
|
45
|
+
* @param options - Optional configuration.
|
|
46
|
+
* @returns A debounced function with `.cancel()` and `.flush()`.
|
|
47
|
+
*/
|
|
48
|
+
declare function debounce<T extends (...args: unknown[]) => unknown>(fn: T, wait: number, options?: DebounceOptions): DebouncedFunction<T>;
|
|
49
|
+
/**
|
|
50
|
+
* Creates a throttled function that only invokes `fn` at most once per
|
|
51
|
+
* `wait` milliseconds.
|
|
52
|
+
*
|
|
53
|
+
* @param fn - The function to throttle.
|
|
54
|
+
* @param wait - The number of milliseconds to throttle invocations to.
|
|
55
|
+
* @returns A throttled function.
|
|
56
|
+
*/
|
|
57
|
+
declare function throttle<T extends (...args: unknown[]) => unknown>(fn: T, wait: number): (...args: Parameters<T>) => void;
|
|
58
|
+
/**
|
|
59
|
+
* Creates a memoized version of `fn`. Uses a `Map` cache keyed by the
|
|
60
|
+
* first argument by default, or by a custom `resolver` function.
|
|
61
|
+
*
|
|
62
|
+
* @param fn - The function to memoize.
|
|
63
|
+
* @param resolver - Optional function to determine the cache key.
|
|
64
|
+
* @returns The memoized function with a `.cache` property.
|
|
65
|
+
*/
|
|
66
|
+
declare function memoize<T extends (...args: unknown[]) => unknown>(fn: T, resolver?: (...args: Parameters<T>) => string): MemoizedFunction<T>;
|
|
67
|
+
/**
|
|
68
|
+
* Retries an async function with exponential backoff and jitter.
|
|
69
|
+
*
|
|
70
|
+
* @param fn - The async function to retry.
|
|
71
|
+
* @param options - Retry configuration.
|
|
72
|
+
* @returns A promise that resolves with the function result.
|
|
73
|
+
*/
|
|
74
|
+
declare function retry<T>(fn: () => Promise<T>, options?: RetryOptions): Promise<T>;
|
|
75
|
+
/**
|
|
76
|
+
* A no-operation function that returns `undefined`.
|
|
77
|
+
*/
|
|
78
|
+
declare function noop(): void;
|
|
79
|
+
/**
|
|
80
|
+
* Returns the given value unchanged.
|
|
81
|
+
*
|
|
82
|
+
* @param value - The value to return.
|
|
83
|
+
* @returns The same value.
|
|
84
|
+
*/
|
|
85
|
+
declare function identity<T>(value: T): T;
|
|
86
|
+
/**
|
|
87
|
+
* Creates a function that invokes `fn` only once. Subsequent calls return
|
|
88
|
+
* the result of the first invocation.
|
|
89
|
+
*
|
|
90
|
+
* @param fn - The function to wrap.
|
|
91
|
+
* @returns A function that runs only once.
|
|
92
|
+
*/
|
|
93
|
+
declare function once<T extends (...args: unknown[]) => unknown>(fn: T): (...args: Parameters<T>) => ReturnType<T>;
|
|
94
|
+
|
|
95
|
+
export { type DebounceOptions, type DebouncedFunction, type MemoizedFunction, type RetryOptions, debounce, deepClone, deepMerge, identity, memoize, noop, once, retry, throttle };
|