umt 2.15.0 → 2.17.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/README.md +42 -0
- package/module/Array/chunk.js.map +1 -1
- package/module/Array/uniqBy.js.map +1 -1
- package/module/Async/debounceAsync.d.ts +18 -0
- package/module/Async/debounceAsync.js +59 -0
- package/module/Async/debounceAsync.js.map +1 -0
- package/module/Async/index.d.ts +5 -0
- package/module/Async/index.js +5 -0
- package/module/Async/index.js.map +1 -1
- package/module/Async/pSettled.d.ts +19 -0
- package/module/Async/pSettled.js +54 -0
- package/module/Async/pSettled.js.map +1 -0
- package/module/Async/retry.d.ts +22 -0
- package/module/Async/retry.js +49 -0
- package/module/Async/retry.js.map +1 -0
- package/module/Async/throttleAsync.d.ts +18 -0
- package/module/Async/throttleAsync.js +41 -0
- package/module/Async/throttleAsync.js.map +1 -0
- package/module/Async/waitFor.d.ts +18 -0
- package/module/Async/waitFor.js +32 -0
- package/module/Async/waitFor.js.map +1 -0
- package/module/Date/addDuration.d.ts +15 -0
- package/module/Date/addDuration.js +40 -0
- package/module/Date/addDuration.js.map +1 -0
- package/module/Date/diff.d.ts +14 -0
- package/module/Date/diff.js +45 -0
- package/module/Date/diff.js.map +1 -0
- package/module/Date/durationUnit.d.ts +12 -0
- package/module/Date/durationUnit.js +2 -0
- package/module/Date/durationUnit.js.map +1 -0
- package/module/Date/endOf.d.ts +13 -0
- package/module/Date/endOf.js +58 -0
- package/module/Date/endOf.js.map +1 -0
- package/module/Date/formatRelative.d.ts +13 -0
- package/module/Date/formatRelative.js +35 -0
- package/module/Date/formatRelative.js.map +1 -0
- package/module/Date/index.d.ts +10 -0
- package/module/Date/index.js +10 -0
- package/module/Date/index.js.map +1 -1
- package/module/Date/isBusinessDay.d.ts +10 -0
- package/module/Date/isBusinessDay.js +18 -0
- package/module/Date/isBusinessDay.js.map +1 -0
- package/module/Date/isSameDay.d.ts +10 -0
- package/module/Date/isSameDay.js +13 -0
- package/module/Date/isSameDay.js.map +1 -0
- package/module/Date/isWeekend.d.ts +9 -0
- package/module/Date/isWeekend.js +13 -0
- package/module/Date/isWeekend.js.map +1 -0
- package/module/Date/msByUnit.d.ts +2 -0
- package/module/Date/msByUnit.js +10 -0
- package/module/Date/msByUnit.js.map +1 -0
- package/module/Date/startOf.d.ts +13 -0
- package/module/Date/startOf.js +58 -0
- package/module/Date/startOf.js.map +1 -0
- package/module/Date/subDuration.d.ts +13 -0
- package/module/Date/subDuration.js +14 -0
- package/module/Date/subDuration.js.map +1 -0
- package/module/Error/index.d.ts +0 -1
- package/module/Error/index.js +0 -1
- package/module/Error/index.js.map +1 -1
- package/module/Object/deepClone.js.map +1 -1
- package/module/Object/flattenObject.d.ts +11 -0
- package/module/Object/flattenObject.js +29 -0
- package/module/Object/flattenObject.js.map +1 -0
- package/module/Object/get.d.ts +1 -0
- package/module/Object/get.js +26 -0
- package/module/Object/get.js.map +1 -0
- package/module/Object/has.d.ts +0 -19
- package/module/Object/has.js +4 -3
- package/module/Object/has.js.map +1 -1
- package/module/Object/index.d.ts +8 -0
- package/module/Object/index.js +8 -0
- package/module/Object/index.js.map +1 -1
- package/module/Object/invert.d.ts +12 -0
- package/module/Object/invert.js +20 -0
- package/module/Object/invert.js.map +1 -0
- package/module/Object/mergeDeep.js.map +1 -1
- package/module/Object/omitBy.d.ts +11 -0
- package/module/Object/omitBy.js +21 -0
- package/module/Object/omitBy.js.map +1 -0
- package/module/Object/pathSegments.d.ts +1 -0
- package/module/Object/pathSegments.js +2 -0
- package/module/Object/pathSegments.js.map +1 -0
- package/module/Object/pick.d.ts +10 -0
- package/module/Object/pick.js +10 -0
- package/module/Object/pick.js.map +1 -1
- package/module/Object/pickBy.d.ts +11 -0
- package/module/Object/pickBy.js +21 -0
- package/module/Object/pickBy.js.map +1 -0
- package/module/Object/set.d.ts +19 -0
- package/module/Object/set.js +38 -0
- package/module/Object/set.js.map +1 -0
- package/module/Object/unflattenObject.d.ts +15 -0
- package/module/Object/unflattenObject.js +23 -0
- package/module/Object/unflattenObject.js.map +1 -0
- package/module/Random/index.d.ts +7 -0
- package/module/Random/index.js +8 -0
- package/module/Random/index.js.map +1 -0
- package/module/Random/randomBoolean.d.ts +9 -0
- package/module/Random/randomBoolean.js +10 -0
- package/module/Random/randomBoolean.js.map +1 -0
- package/module/Random/randomChoice.d.ts +9 -0
- package/module/Random/randomChoice.js +13 -0
- package/module/Random/randomChoice.js.map +1 -0
- package/module/Random/randomFloat.d.ts +9 -0
- package/module/Random/randomFloat.js +10 -0
- package/module/Random/randomFloat.js.map +1 -0
- package/module/Random/randomInt.d.ts +9 -0
- package/module/Random/randomInt.js +14 -0
- package/module/Random/randomInt.js.map +1 -0
- package/module/Random/randomUuid.d.ts +9 -0
- package/module/Random/randomUuid.js +31 -0
- package/module/Random/randomUuid.js.map +1 -0
- package/module/Random/seededRandom.d.ts +11 -0
- package/module/Random/seededRandom.js +31 -0
- package/module/Random/seededRandom.js.map +1 -0
- package/module/Random/weightedChoice.d.ts +15 -0
- package/module/Random/weightedChoice.js +34 -0
- package/module/Random/weightedChoice.js.map +1 -0
- package/module/String/capitalize.d.ts +12 -0
- package/module/String/capitalize.js +18 -0
- package/module/String/capitalize.js.map +1 -0
- package/module/String/capitalizeWord.d.ts +1 -0
- package/module/String/capitalizeWord.js +2 -0
- package/module/String/capitalizeWord.js.map +1 -0
- package/module/String/dedent.d.ts +19 -0
- package/module/String/dedent.js +56 -0
- package/module/String/dedent.js.map +1 -0
- package/module/String/index.d.ts +10 -0
- package/module/String/index.js +10 -0
- package/module/String/index.js.map +1 -1
- package/module/String/mask.d.ts +20 -0
- package/module/String/mask.js +24 -0
- package/module/String/mask.js.map +1 -0
- package/module/String/pascalCase.d.ts +9 -0
- package/module/String/pascalCase.js +14 -0
- package/module/String/pascalCase.js.map +1 -0
- package/module/String/snakeCase.d.ts +9 -0
- package/module/String/snakeCase.js +13 -0
- package/module/String/snakeCase.js.map +1 -0
- package/module/String/titleCase.d.ts +9 -0
- package/module/String/titleCase.js +14 -0
- package/module/String/titleCase.js.map +1 -0
- package/module/String/uncapitalize.d.ts +10 -0
- package/module/String/uncapitalize.js +16 -0
- package/module/String/uncapitalize.js.map +1 -0
- package/module/String/wordCount.d.ts +10 -0
- package/module/String/wordCount.js +12 -0
- package/module/String/wordCount.js.map +1 -0
- package/module/String/words.d.ts +12 -0
- package/module/String/words.js +21 -0
- package/module/String/words.js.map +1 -0
- package/module/Tool/createPipeline.d.ts +1 -1
- package/module/Tool/createPipeline.js +8 -6
- package/module/Tool/createPipeline.js.map +1 -1
- package/module/Tool/pipe.js.map +1 -1
- package/module/URL/buildUrl.d.ts +10 -0
- package/module/URL/buildUrl.js +10 -4
- package/module/URL/buildUrl.js.map +1 -1
- package/module/URL/parseQueryString.d.ts +6 -0
- package/module/URL/parseQueryString.js +6 -4
- package/module/URL/parseQueryString.js.map +1 -1
- package/module/Validate/isNumber.js.map +1 -1
- package/module/Validate/object/core.js +0 -1
- package/module/Validate/object/core.js.map +1 -1
- package/module/es5/Async/debounceAsync.d.ts +18 -0
- package/module/es5/Async/debounceAsync.js +103 -0
- package/module/es5/Async/index.d.ts +5 -0
- package/module/es5/Async/index.js +55 -0
- package/module/es5/Async/pSettled.d.ts +19 -0
- package/module/es5/Async/pSettled.js +68 -0
- package/module/es5/Async/retry.d.ts +22 -0
- package/module/es5/Async/retry.js +106 -0
- package/module/es5/Async/throttleAsync.d.ts +18 -0
- package/module/es5/Async/throttleAsync.js +46 -0
- package/module/es5/Async/waitFor.d.ts +18 -0
- package/module/es5/{Error/retry.js → Async/waitFor.js} +68 -74
- package/module/es5/Date/addDuration.d.ts +15 -0
- package/module/es5/Date/addDuration.js +45 -0
- package/module/es5/Date/diff.d.ts +14 -0
- package/module/es5/Date/diff.js +40 -0
- package/module/es5/Date/durationUnit.d.ts +12 -0
- package/module/es5/Date/durationUnit.js +5 -0
- package/module/es5/Date/endOf.d.ts +13 -0
- package/module/es5/Date/endOf.js +72 -0
- package/module/es5/Date/formatRelative.d.ts +13 -0
- package/module/es5/Date/formatRelative.js +61 -0
- package/module/es5/Date/index.d.ts +10 -0
- package/module/es5/Date/index.js +110 -0
- package/module/es5/Date/isBusinessDay.d.ts +10 -0
- package/module/es5/Date/isBusinessDay.js +26 -0
- package/module/es5/Date/isSameDay.d.ts +10 -0
- package/module/es5/Date/isSameDay.js +18 -0
- package/module/es5/Date/isWeekend.d.ts +9 -0
- package/module/es5/Date/isWeekend.js +18 -0
- package/module/es5/Date/msByUnit.d.ts +2 -0
- package/module/es5/Date/msByUnit.js +15 -0
- package/module/es5/Date/startOf.d.ts +13 -0
- package/module/es5/Date/startOf.js +72 -0
- package/module/es5/Date/subDuration.d.ts +13 -0
- package/module/es5/Date/subDuration.js +21 -0
- package/module/es5/Error/index.d.ts +0 -1
- package/module/es5/Error/index.js +0 -11
- package/module/es5/Object/flattenObject.d.ts +11 -0
- package/module/es5/Object/flattenObject.js +35 -0
- package/module/es5/Object/get.d.ts +1 -0
- package/module/es5/Object/get.js +42 -0
- package/module/es5/Object/has.d.ts +0 -19
- package/module/es5/Object/has.js +5 -11
- package/module/es5/Object/index.d.ts +8 -0
- package/module/es5/Object/index.js +88 -0
- package/module/es5/Object/invert.d.ts +12 -0
- package/module/es5/Object/invert.js +26 -0
- package/module/es5/Object/omitBy.d.ts +11 -0
- package/module/es5/Object/omitBy.js +27 -0
- package/module/es5/Object/pathSegments.d.ts +1 -0
- package/module/es5/Object/pathSegments.js +9 -0
- package/module/es5/Object/pick.d.ts +10 -0
- package/module/es5/Object/pick.js +10 -0
- package/module/es5/Object/pickBy.d.ts +11 -0
- package/module/es5/Object/pickBy.js +27 -0
- package/module/es5/Object/set.d.ts +19 -0
- package/module/es5/Object/set.js +44 -0
- package/module/es5/Object/unflattenObject.d.ts +15 -0
- package/module/es5/Object/unflattenObject.js +30 -0
- package/module/es5/Random/index.d.ts +7 -0
- package/module/es5/Random/index.js +82 -0
- package/module/es5/Random/randomBoolean.d.ts +9 -0
- package/module/es5/Random/randomBoolean.js +18 -0
- package/module/es5/Random/randomChoice.d.ts +9 -0
- package/module/es5/Random/randomChoice.js +18 -0
- package/module/es5/Random/randomFloat.d.ts +9 -0
- package/module/es5/Random/randomFloat.js +17 -0
- package/module/es5/Random/randomInt.d.ts +9 -0
- package/module/es5/Random/randomInt.js +19 -0
- package/module/es5/Random/randomUuid.d.ts +9 -0
- package/module/es5/Random/randomUuid.js +38 -0
- package/module/es5/Random/seededRandom.d.ts +11 -0
- package/module/es5/Random/seededRandom.js +46 -0
- package/module/es5/Random/weightedChoice.d.ts +15 -0
- package/module/es5/Random/weightedChoice.js +50 -0
- package/module/es5/String/capitalize.d.ts +12 -0
- package/module/es5/String/capitalize.js +35 -0
- package/module/es5/String/capitalizeWord.d.ts +1 -0
- package/module/es5/String/capitalizeWord.js +9 -0
- package/module/es5/String/dedent.d.ts +19 -0
- package/module/es5/String/dedent.js +82 -0
- package/module/es5/String/index.d.ts +10 -0
- package/module/es5/String/index.js +110 -0
- package/module/es5/String/mask.d.ts +20 -0
- package/module/es5/String/mask.js +39 -0
- package/module/es5/String/pascalCase.d.ts +9 -0
- package/module/es5/String/pascalCase.js +21 -0
- package/module/es5/String/snakeCase.d.ts +9 -0
- package/module/es5/String/snakeCase.js +20 -0
- package/module/es5/String/titleCase.d.ts +9 -0
- package/module/es5/String/titleCase.js +21 -0
- package/module/es5/String/uncapitalize.d.ts +10 -0
- package/module/es5/String/uncapitalize.js +33 -0
- package/module/es5/String/wordCount.d.ts +10 -0
- package/module/es5/String/wordCount.js +19 -0
- package/module/es5/String/words.d.ts +12 -0
- package/module/es5/String/words.js +25 -0
- package/module/es5/Tool/createPipeline.d.ts +1 -1
- package/module/es5/Tool/createPipeline.js +7 -10
- package/module/es5/URL/buildUrl.d.ts +10 -0
- package/module/es5/URL/buildUrl.js +10 -4
- package/module/es5/URL/parseQueryString.d.ts +6 -0
- package/module/es5/URL/parseQueryString.js +6 -4
- package/module/es5/Validate/object/core.js +0 -1
- package/module/es5/index.d.ts +1 -0
- package/module/es5/index.js +20 -9
- package/module/index.d.ts +1 -0
- package/module/index.js +1 -0
- package/module/index.js.map +1 -1
- package/package.json +34 -29
- package/module/Error/retry.d.ts +0 -37
- package/module/Error/retry.js +0 -47
- package/module/Error/retry.js.map +0 -1
- package/module/es5/Error/retry.d.ts +0 -37
package/README.md
CHANGED
|
@@ -64,10 +64,15 @@ bun add umt
|
|
|
64
64
|
|
|
65
65
|
| name | type | description | example |
|
|
66
66
|
|------|------|-------------|---------|
|
|
67
|
+
| debounceAsync | `<A, R>(function_: (...args: A) => Promise<R>, wait: number) => DebouncedAsyncFunction<A, R>` | Debounced async function; latest args win and callers in the window share resolution | `const d = debounceAsync(search, 300); await d("foo");` |
|
|
67
68
|
| defer | `<T>() => Deferred<T>` | Creates a deferred promise with externally accessible resolve and reject | `const d = defer<number>(); d.resolve(42); await d.promise; // 42` |
|
|
68
69
|
| parallel | `<T, U>(limit: number, items: T[], function_: (item: T, index: number) => Promise<U>) => Promise<U[]>` | Executes async functions in parallel with a concurrency limit | `await parallel(2, [1, 2, 3], async (n) => n * 2); // [2, 4, 6]` |
|
|
70
|
+
| pSettled | `<T>(tasks: Iterable<Promise<T> \| (() => Promise<T>)>, limit?: number) => Promise<SettledResult<T>[]>` | Awaits all promises and returns settled results with optional concurrency limit | `await pSettled([Promise.resolve(1), Promise.reject(new Error("x"))]);` |
|
|
71
|
+
| retry | `<T>(function_: () => Promise<T>, options?: RetryOptions) => Promise<T>` | Retries an async function with fixed/linear/exponential backoff, jitter, and AbortSignal | `await retry(() => fetch("/api"), { retries: 5, backoff: "exponential" });` |
|
|
69
72
|
| sleep | `(ms: number) => Promise<void>` | Returns a promise that resolves after the specified milliseconds | `await sleep(1000);` |
|
|
73
|
+
| throttleAsync | `<A, R>(function_: (...args: A) => Promise<R>, wait: number) => ThrottledAsyncFunction<A, R>` | Throttled async function; coalesces concurrent calls into a single inflight promise | `const t = throttleAsync(loadUser, 1000); await t();` |
|
|
70
74
|
| timeout | `<T>(promise: Promise<T>, ms: number) => Promise<T>` | Wraps a promise with a timeout, rejecting if it does not resolve in time | `await timeout(fetch("/api"), 5000);` |
|
|
75
|
+
| waitFor | `<T>(condition: () => T \| Promise<T>, options?: WaitForOptions) => Promise<NonNullable<T>>` | Polls a condition until truthy or timeout | `await waitFor(() => document.querySelector("#root"));` |
|
|
71
76
|
|
|
72
77
|
### DataStructure
|
|
73
78
|
|
|
@@ -103,6 +108,15 @@ bun add umt
|
|
|
103
108
|
|
|
104
109
|
| name | type | description | example |
|
|
105
110
|
|------|------|-------------|---------|
|
|
111
|
+
| addDuration | `(date: Date, amount: number, unit: DurationUnit) => Date` | Adds a duration to a date; calendar-aware for months and years | `addDuration(new Date("2025-01-31"), 1, "M"); // 2025-02-28` |
|
|
112
|
+
| diff | `(left: Date, right: Date, unit: DurationUnit) => number` | Returns the difference between two dates in the given unit | `diff(new Date("2025-12-31"), new Date("2025-01-01"), "d"); // 364` |
|
|
113
|
+
| endOf | `(date: Date, unit: DateBoundaryUnit) => Date` | Returns a new Date set to the end of the given unit | `endOf(new Date("2025-04-15"), "month"); // 2025-04-30T23:59:59.999` |
|
|
114
|
+
| formatRelative | `(date: Date, baseDate?: Date, locale?: string) => string` | Formats a date relative to a base date using Intl.RelativeTimeFormat | `formatRelative(new Date(Date.now() - 3600_000), new Date(), "en"); // "1 hour ago"` |
|
|
115
|
+
| isBusinessDay | `(date: Date, holidays?: Date[]) => boolean` | Returns true when a weekday and not in the holiday list | `isBusinessDay(new Date("2025-04-21")); // true` |
|
|
116
|
+
| isSameDay | `(left: Date, right: Date) => boolean` | Returns true when two dates are the same calendar day | `isSameDay(new Date("2025-04-15T01:00"), new Date("2025-04-15T23:00")); // true` |
|
|
117
|
+
| isWeekend | `(date: Date) => boolean` | Returns true when Saturday or Sunday | `isWeekend(new Date("2025-04-19")); // true` |
|
|
118
|
+
| startOf | `(date: Date, unit: DateBoundaryUnit) => Date` | Returns a new Date set to the start of the given unit | `startOf(new Date("2025-04-15"), "month"); // 2025-04-01T00:00:00` |
|
|
119
|
+
| subDuration | `(date: Date, amount: number, unit: DurationUnit) => Date` | Subtracts a duration from a date | `subDuration(new Date("2025-03-31"), 1, "M"); // 2025-02-28` |
|
|
106
120
|
| birthday | `<T extends MonTypeInt>(year: number, mon: T, day: DayTypeInt<T>, timeDifference?: HoursTypeInt) => number` | Calculate age based on birthdate | `birthday(2000, 1, 1); // Returns age of someone born on Jan 1, 2000` |
|
|
107
121
|
| dateRange | `(startDate: Date, endDate: Date) => Date[]` | Generate an array containing all dates between the specified start and end dates | `dateRange(new Date('2025-01-01'), new Date('2025-01-03'))` |
|
|
108
122
|
| dayOfWeek | `<T extends MonTypeInt>(properties?: { year?: number; mon?: T; day?: DayTypeInt<T> }, timeDifference?: HoursTypeInt) => number` | Get the day of the week | `dayOfWeek({ year: 2000, mon: 1, day: 1 });` |
|
|
@@ -234,6 +248,13 @@ bun add umt
|
|
|
234
248
|
| omit | `<T extends Record<string, unknown>, K extends keyof T>(object: T, ...keys: K[]) => Omit<T, K>` | Creates an object without the specified keys | `omit({a: 1, b: 2, c: 3}, 'b'); // {a: 1, c: 3}` |
|
|
235
249
|
| pick | `<T extends object, K extends keyof T>(object: T, ...keys: K[]) => Pick<T, K>` | Creates a new object with only the specified properties from the source object | `pick({ id: 1, name: 'Alice', age: 30 }, 'id', 'name'); // { id: 1, name: 'Alice' }` |
|
|
236
250
|
| pickDeep | `<T extends object, K extends PickDeepKey<T>>(object: T, ...keys: K[]) => PickDeep<T>` | Creates a new object by deeply selecting properties from the source object based on specified keys | `pickDeep({ a: { b: { c: 1, d: 2 }, e: 3 }, f: 4 }, 'a.b.c', 'f'); // { a: { b: { c: 1 } }, f: 4 }` |
|
|
251
|
+
| flattenObject | `<T extends Record<string, unknown>>(object: T, separator?: string) => Record<string, unknown>` | Flattens a nested object into path-keyed entries | `flattenObject({ a: { b: { c: 1 } } }); // { "a.b.c": 1 }` |
|
|
252
|
+
| get | `<T>(object: unknown, path: string \| string[], defaultValue?: T) => T \| undefined` | Reads a deeply nested property by path | `get({ a: { b: 1 } }, "a.b"); // 1` |
|
|
253
|
+
| invert | `<K, V>(object: Record<K, V>) => Record<V, K>` | Creates a new object with keys and values swapped | `invert({ a: 1, b: 2 }); // { 1: "a", 2: "b" }` |
|
|
254
|
+
| omitBy | `<T>(object: T, predicate: (value, key) => boolean) => Partial<T>` | Removes entries for which the predicate returns true | `omitBy({ a: 1, b: undefined }, (v) => v === undefined); // { a: 1 }` |
|
|
255
|
+
| pickBy | `<T>(object: T, predicate: (value, key) => boolean) => Partial<T>` | Selects entries for which the predicate returns true | `pickBy({ a: 1, b: 2 }, (v) => v > 1); // { b: 2 }` |
|
|
256
|
+
| set | `<T extends object>(object: T, path: string \| string[], value: unknown) => T` | Sets a deeply nested property by path, mutating the object | `set({}, "a.b.c", 1); // { a: { b: { c: 1 } } }` |
|
|
257
|
+
| unflattenObject | `(flat: Record<string, unknown>, separator?: string) => Record<string, unknown>` | Reconstructs a nested object from path-keyed input | `unflattenObject({ "a.b": 1 }); // { a: { b: 1 } }` |
|
|
237
258
|
|
|
238
259
|
### Predicate
|
|
239
260
|
|
|
@@ -245,6 +266,18 @@ bun add umt
|
|
|
245
266
|
| not | `<T extends unknown[]>(function_: (...args: T) => boolean) => (...args: T) => boolean` | Creates a predicate that negates the given predicate | `const isOdd = not((n: number) => n % 2 === 0); isOdd(3); // true` |
|
|
246
267
|
| some | `<T extends unknown[]>(...predicates: ((...args: T) => boolean)[]) => (...args: T) => boolean` | Creates a predicate that returns true when at least one predicate returns true | `some((n: number) => n === 0, (n) => n < 0)(0); // true` |
|
|
247
268
|
|
|
269
|
+
### Random
|
|
270
|
+
|
|
271
|
+
| name | type | description | example |
|
|
272
|
+
|------|------|-------------|---------|
|
|
273
|
+
| randomBoolean | `(probability?: number) => boolean` | Random boolean with optional weight | `randomBoolean(0.9); // true ~90% of the time` |
|
|
274
|
+
| randomChoice | `<T>(items: readonly T[]) => T` | Uniformly random element from an array | `randomChoice(["a", "b", "c"]);` |
|
|
275
|
+
| randomFloat | `(min: number, max: number) => number` | Random float in `[min, max)` | `randomFloat(0, 1);` |
|
|
276
|
+
| randomInt | `(min: number, max: number) => number` | Random integer in `[min, max]` | `randomInt(1, 6); // 1..6` |
|
|
277
|
+
| randomUUID | `() => string` | UUID v4, prefers `crypto.randomUUID` | `randomUUID();` |
|
|
278
|
+
| seededRandom | `(seed: number \| string) => () => number` | Deterministic PRNG (SplitMix32) | `const rand = seededRandom("hello"); rand();` |
|
|
279
|
+
| weightedChoice | `<T>(items: readonly { value: T; weight: number }[]) => T` | Weighted random pick using cumulative binary search | `weightedChoice([{ value: "a", weight: 1 }, { value: "b", weight: 4 }]);` |
|
|
280
|
+
|
|
248
281
|
### Simple
|
|
249
282
|
|
|
250
283
|
| name | type | description | example |
|
|
@@ -260,6 +293,15 @@ bun add umt
|
|
|
260
293
|
| name | type | description | example |
|
|
261
294
|
|------|------|-------------|---------|
|
|
262
295
|
| camelCase | `(str: string) => string` | Converts a string to camelCase | `camelCase("hello-world"); // "helloWorld"` |
|
|
296
|
+
| capitalize | `(str: string) => string` | Capitalizes the first grapheme of a string | `capitalize("hello"); // "Hello"` |
|
|
297
|
+
| dedent | `(str: string \| TemplateStringsArray, ...values: unknown[]) => string` | Removes minimum common leading whitespace; works as a tag | `` dedent` line` // "line"`` |
|
|
298
|
+
| mask | `(str: string, options?: MaskOptions) => string` | Masks the middle of a string preserving leading/trailing characters | `mask("1234567890", { start: 2, end: 4 }); // "12****7890"` |
|
|
299
|
+
| pascalCase | `(str: string) => string` | Converts a string to PascalCase | `pascalCase("hello-world"); // "HelloWorld"` |
|
|
300
|
+
| snakeCase | `(str: string) => string` | Converts a string to snake_case | `snakeCase("helloWorld"); // "hello_world"` |
|
|
301
|
+
| titleCase | `(str: string) => string` | Converts a string to Title Case | `titleCase("hello world"); // "Hello World"` |
|
|
302
|
+
| uncapitalize | `(str: string) => string` | Lowercases the first grapheme of a string | `uncapitalize("Hello"); // "hello"` |
|
|
303
|
+
| wordCount | `(str: string) => number` | Counts words using `words` boundaries | `wordCount("hello world"); // 2` |
|
|
304
|
+
| words | `(str: string, pattern?: RegExp) => string[]` | Splits a string into words on case boundaries and non-alphanumeric separators | `words("XMLHttpRequest"); // ["XML", "Http", "Request"]` |
|
|
263
305
|
| deleteSpaces | `(string_: string) => string` | Removes all whitespace characters from a string | `deleteSpaces("Hello World"); // "HelloWorld"` |
|
|
264
306
|
| escapeHtml | `(str: string) => string` | Escapes HTML special characters in a string | `escapeHtml("<script>alert('XSS')</script>"); // "<script>alert('XSS')</script>"` |
|
|
265
307
|
| formatString | `(template: string, ...values: unknown[]) => string` | Replaces placeholders in a template string with specified values | `formatString("Hello, {0}!", "World"); // "Hello, World!"` |
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"chunk.js","sourceRoot":"","sources":["../../src/Array/chunk.ts"],"names":[],"mappings":"AAOA,MAAM,CAAC,MAAM,KAAK,GAAG,CACnB,KAAQ,EACR,CAAI,EACkB,EAAE;IACxB,MAAM,MAAM,GAAG,KAAK,CAAC,MAAM,CAAC;IAC5B,MAAM,MAAM,GAAG,KAAK,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,IAAI,CAAC,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC,EAAE,CAAC,CAAC;IAE7D,KAAK,IAAI,KAAK,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,KAAK,GAAG,MAAM,EAAE,KAAK,IAAI,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;QAC3D,MAAM,CAAC,CAAC,CAAC,GAAG,KAAK,CAAC,KAAK,CAAC,KAAK,EAAE,KAAK,GAAG,CAAC,
|
|
1
|
+
{"version":3,"file":"chunk.js","sourceRoot":"","sources":["../../src/Array/chunk.ts"],"names":[],"mappings":"AAOA,MAAM,CAAC,MAAM,KAAK,GAAG,CACnB,KAAQ,EACR,CAAI,EACkB,EAAE;IACxB,MAAM,MAAM,GAAG,KAAK,CAAC,MAAM,CAAC;IAC5B,MAAM,MAAM,GAAG,KAAK,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,IAAI,CAAC,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC,EAAE,CAAC,CAAC;IAE7D,KAAK,IAAI,KAAK,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,KAAK,GAAG,MAAM,EAAE,KAAK,IAAI,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;QAC3D,MAAM,CAAC,CAAC,CAAC,GAAG,KAAK,CAAC,KAAK,CAAC,KAAK,EAAE,KAAK,GAAG,CAAC,CAAC,CAAC;IAC5C,CAAC;IAED,OAAO,MAA8B,CAAC;AACxC,CAAC,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"uniqBy.js","sourceRoot":"","sources":["../../src/Array/uniqBy.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,MAAM,CAAC,MAAM,MAAM,GAAG,CACpB,KAAQ,EACR,QAAgC,EAC7B,EAAE;IACL,MAAM,IAAI,GAAG,IAAI,GAAG,EAAK,CAAC;IAC1B,MAAM,MAAM,GAAM,EAAkB,CAAC;IAErC,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,MAAM,GAAG,GAAG,QAAQ,CAAC,
|
|
1
|
+
{"version":3,"file":"uniqBy.js","sourceRoot":"","sources":["../../src/Array/uniqBy.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,MAAM,CAAC,MAAM,MAAM,GAAG,CACpB,KAAQ,EACR,QAAgC,EAC7B,EAAE;IACL,MAAM,IAAI,GAAG,IAAI,GAAG,EAAK,CAAC;IAC1B,MAAM,MAAM,GAAM,EAAkB,CAAC;IAErC,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,MAAM,GAAG,GAAG,QAAQ,CAAC,IAAI,CAAC,CAAC;QAC3B,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC;YACnB,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;YACd,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACpB,CAAC;IACH,CAAC;IAED,OAAO,MAAM,CAAC;AAChB,CAAC,CAAC"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
export interface DebouncedAsyncFunction<A extends unknown[], R> {
|
|
2
|
+
(...arguments_: A): Promise<R>;
|
|
3
|
+
cancel: () => void;
|
|
4
|
+
}
|
|
5
|
+
/**
|
|
6
|
+
* Creates a debounced async function. Subsequent calls within `wait` ms reset
|
|
7
|
+
* the timer and share a single resolution; the latest arguments win.
|
|
8
|
+
*
|
|
9
|
+
* @template A - Argument tuple type
|
|
10
|
+
* @template R - Resolved value type
|
|
11
|
+
* @param {(...args: A) => Promise<R>} function_ - Async function to debounce
|
|
12
|
+
* @param {number} wait - Debounce window in milliseconds
|
|
13
|
+
* @returns {DebouncedAsyncFunction<A, R>} Debounced wrapper with cancel support
|
|
14
|
+
* @example
|
|
15
|
+
* const search = debounceAsync(query, 300);
|
|
16
|
+
* await search("foo");
|
|
17
|
+
*/
|
|
18
|
+
export declare const debounceAsync: <A extends unknown[], R>(function_: (...arguments_: A) => Promise<R>, wait: number) => DebouncedAsyncFunction<A, R>;
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Creates a debounced async function. Subsequent calls within `wait` ms reset
|
|
3
|
+
* the timer and share a single resolution; the latest arguments win.
|
|
4
|
+
*
|
|
5
|
+
* @template A - Argument tuple type
|
|
6
|
+
* @template R - Resolved value type
|
|
7
|
+
* @param {(...args: A) => Promise<R>} function_ - Async function to debounce
|
|
8
|
+
* @param {number} wait - Debounce window in milliseconds
|
|
9
|
+
* @returns {DebouncedAsyncFunction<A, R>} Debounced wrapper with cancel support
|
|
10
|
+
* @example
|
|
11
|
+
* const search = debounceAsync(query, 300);
|
|
12
|
+
* await search("foo");
|
|
13
|
+
*/
|
|
14
|
+
export const debounceAsync = (function_, wait) => {
|
|
15
|
+
let timer;
|
|
16
|
+
let pendingResolvers = [];
|
|
17
|
+
let pendingRejecters = [];
|
|
18
|
+
const flushPromises = () => {
|
|
19
|
+
const resolvers = pendingResolvers;
|
|
20
|
+
const rejecters = pendingRejecters;
|
|
21
|
+
pendingResolvers = [];
|
|
22
|
+
pendingRejecters = [];
|
|
23
|
+
return { resolvers, rejecters };
|
|
24
|
+
};
|
|
25
|
+
const debounced = ((...arguments_) => {
|
|
26
|
+
if (timer) {
|
|
27
|
+
clearTimeout(timer);
|
|
28
|
+
}
|
|
29
|
+
return new Promise((resolve, reject) => {
|
|
30
|
+
pendingResolvers.push(resolve);
|
|
31
|
+
pendingRejecters.push(reject);
|
|
32
|
+
timer = setTimeout(() => {
|
|
33
|
+
timer = undefined;
|
|
34
|
+
const { resolvers, rejecters } = flushPromises();
|
|
35
|
+
function_(...arguments_).then((value) => {
|
|
36
|
+
for (const resolver of resolvers) {
|
|
37
|
+
resolver(value);
|
|
38
|
+
}
|
|
39
|
+
}, (error) => {
|
|
40
|
+
for (const rejecter of rejecters) {
|
|
41
|
+
rejecter(error);
|
|
42
|
+
}
|
|
43
|
+
});
|
|
44
|
+
}, wait);
|
|
45
|
+
});
|
|
46
|
+
});
|
|
47
|
+
debounced.cancel = () => {
|
|
48
|
+
if (timer) {
|
|
49
|
+
clearTimeout(timer);
|
|
50
|
+
timer = undefined;
|
|
51
|
+
}
|
|
52
|
+
const { rejecters } = flushPromises();
|
|
53
|
+
for (const rejecter of rejecters) {
|
|
54
|
+
rejecter(new Error("debounceAsync cancelled"));
|
|
55
|
+
}
|
|
56
|
+
};
|
|
57
|
+
return debounced;
|
|
58
|
+
};
|
|
59
|
+
//# sourceMappingURL=debounceAsync.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"debounceAsync.js","sourceRoot":"","sources":["../../src/Async/debounceAsync.ts"],"names":[],"mappings":"AAKA;;;;;;;;;;;;GAYG;AACH,MAAM,CAAC,MAAM,aAAa,GAAG,CAC3B,SAA2C,EAC3C,IAAY,EACkB,EAAE;IAChC,IAAI,KAAgD,CAAC;IACrD,IAAI,gBAAgB,GAA2B,EAAE,CAAC;IAClD,IAAI,gBAAgB,GAAkC,EAAE,CAAC;IAEzD,MAAM,aAAa,GAAG,GAGpB,EAAE;QACF,MAAM,SAAS,GAAG,gBAAgB,CAAC;QACnC,MAAM,SAAS,GAAG,gBAAgB,CAAC;QACnC,gBAAgB,GAAG,EAAE,CAAC;QACtB,gBAAgB,GAAG,EAAE,CAAC;QACtB,OAAO,EAAE,SAAS,EAAE,SAAS,EAAE,CAAC;IAClC,CAAC,CAAC;IAEF,MAAM,SAAS,GAAG,CAAC,CAAC,GAAG,UAAa,EAAc,EAAE;QAClD,IAAI,KAAK,EAAE,CAAC;YACV,YAAY,CAAC,KAAK,CAAC,CAAC;QACtB,CAAC;QACD,OAAO,IAAI,OAAO,CAAI,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;YACxC,gBAAgB,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;YAC/B,gBAAgB,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;YAC9B,KAAK,GAAG,UAAU,CAAC,GAAG,EAAE;gBACtB,KAAK,GAAG,SAAS,CAAC;gBAClB,MAAM,EAAE,SAAS,EAAE,SAAS,EAAE,GAAG,aAAa,EAAE,CAAC;gBACjD,SAAS,CAAC,GAAG,UAAU,CAAC,CAAC,IAAI,CAC3B,CAAC,KAAK,EAAE,EAAE;oBACR,KAAK,MAAM,QAAQ,IAAI,SAAS,EAAE,CAAC;wBACjC,QAAQ,CAAC,KAAK,CAAC,CAAC;oBAClB,CAAC;gBACH,CAAC,EACD,CAAC,KAAK,EAAE,EAAE;oBACR,KAAK,MAAM,QAAQ,IAAI,SAAS,EAAE,CAAC;wBACjC,QAAQ,CAAC,KAAK,CAAC,CAAC;oBAClB,CAAC;gBACH,CAAC,CACF,CAAC;YACJ,CAAC,EAAE,IAAI,CAAC,CAAC;QACX,CAAC,CAAC,CAAC;IACL,CAAC,CAAiC,CAAC;IAEnC,SAAS,CAAC,MAAM,GAAG,GAAS,EAAE;QAC5B,IAAI,KAAK,EAAE,CAAC;YACV,YAAY,CAAC,KAAK,CAAC,CAAC;YACpB,KAAK,GAAG,SAAS,CAAC;QACpB,CAAC;QACD,MAAM,EAAE,SAAS,EAAE,GAAG,aAAa,EAAE,CAAC;QACtC,KAAK,MAAM,QAAQ,IAAI,SAAS,EAAE,CAAC;YACjC,QAAQ,CAAC,IAAI,KAAK,CAAC,yBAAyB,CAAC,CAAC,CAAC;QACjD,CAAC;IACH,CAAC,CAAC;IAEF,OAAO,SAAS,CAAC;AACnB,CAAC,CAAC"}
|
package/module/Async/index.d.ts
CHANGED
|
@@ -1,4 +1,9 @@
|
|
|
1
|
+
export * from "./debounceAsync";
|
|
1
2
|
export * from "./defer";
|
|
2
3
|
export * from "./parallel";
|
|
4
|
+
export * from "./pSettled";
|
|
5
|
+
export * from "./retry";
|
|
3
6
|
export * from "./sleep";
|
|
7
|
+
export * from "./throttleAsync";
|
|
4
8
|
export * from "./timeout";
|
|
9
|
+
export * from "./waitFor";
|
package/module/Async/index.js
CHANGED
|
@@ -1,5 +1,10 @@
|
|
|
1
|
+
export * from "./debounceAsync";
|
|
1
2
|
export * from "./defer";
|
|
2
3
|
export * from "./parallel";
|
|
4
|
+
export * from "./pSettled";
|
|
5
|
+
export * from "./retry";
|
|
3
6
|
export * from "./sleep";
|
|
7
|
+
export * from "./throttleAsync";
|
|
4
8
|
export * from "./timeout";
|
|
9
|
+
export * from "./waitFor";
|
|
5
10
|
//# sourceMappingURL=index.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/Async/index.ts"],"names":[],"mappings":"AAAA,cAAc,SAAS,CAAC;AACxB,cAAc,YAAY,CAAC;AAC3B,cAAc,SAAS,CAAC;AACxB,cAAc,WAAW,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/Async/index.ts"],"names":[],"mappings":"AAAA,cAAc,iBAAiB,CAAC;AAChC,cAAc,SAAS,CAAC;AACxB,cAAc,YAAY,CAAC;AAC3B,cAAc,YAAY,CAAC;AAC3B,cAAc,SAAS,CAAC;AACxB,cAAc,SAAS,CAAC;AACxB,cAAc,iBAAiB,CAAC;AAChC,cAAc,WAAW,CAAC;AAC1B,cAAc,WAAW,CAAC"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
export type SettledResult<T> = {
|
|
2
|
+
status: "fulfilled";
|
|
3
|
+
value: T;
|
|
4
|
+
} | {
|
|
5
|
+
status: "rejected";
|
|
6
|
+
reason: unknown;
|
|
7
|
+
};
|
|
8
|
+
/**
|
|
9
|
+
* Awaits all promises and returns their settled results, with an optional
|
|
10
|
+
* concurrency limit applied during execution.
|
|
11
|
+
*
|
|
12
|
+
* @template T - Resolved value type
|
|
13
|
+
* @param {Iterable<Promise<T> | (() => Promise<T>)>} tasks - Promises or thunks
|
|
14
|
+
* @param {number} [limit] - Maximum concurrent in-flight tasks; unlimited when omitted
|
|
15
|
+
* @returns {Promise<SettledResult<T>[]>} Settled results in input order
|
|
16
|
+
* @example
|
|
17
|
+
* await pSettled([Promise.resolve(1), Promise.reject(new Error("x"))]);
|
|
18
|
+
*/
|
|
19
|
+
export declare const pSettled: <T>(tasks: Iterable<Promise<T> | (() => Promise<T>)>, limit?: number) => Promise<SettledResult<T>[]>;
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Awaits all promises and returns their settled results, with an optional
|
|
3
|
+
* concurrency limit applied during execution.
|
|
4
|
+
*
|
|
5
|
+
* @template T - Resolved value type
|
|
6
|
+
* @param {Iterable<Promise<T> | (() => Promise<T>)>} tasks - Promises or thunks
|
|
7
|
+
* @param {number} [limit] - Maximum concurrent in-flight tasks; unlimited when omitted
|
|
8
|
+
* @returns {Promise<SettledResult<T>[]>} Settled results in input order
|
|
9
|
+
* @example
|
|
10
|
+
* await pSettled([Promise.resolve(1), Promise.reject(new Error("x"))]);
|
|
11
|
+
*/
|
|
12
|
+
export const pSettled = (tasks, limit) => {
|
|
13
|
+
const items = [...tasks];
|
|
14
|
+
const results = Array.from({ length: items.length });
|
|
15
|
+
if (items.length === 0) {
|
|
16
|
+
return Promise.resolve(results);
|
|
17
|
+
}
|
|
18
|
+
const effectiveLimit = limit && limit > 0 ? limit : items.length;
|
|
19
|
+
let nextIndex = 0;
|
|
20
|
+
let resolvedCount = 0;
|
|
21
|
+
return new Promise((resolve) => {
|
|
22
|
+
const runNext = () => {
|
|
23
|
+
if (nextIndex >= items.length) {
|
|
24
|
+
return;
|
|
25
|
+
}
|
|
26
|
+
const currentIndex = nextIndex;
|
|
27
|
+
nextIndex += 1;
|
|
28
|
+
const task = items[currentIndex];
|
|
29
|
+
const promise = typeof task === "function"
|
|
30
|
+
? Promise.resolve().then(task)
|
|
31
|
+
: Promise.resolve(task);
|
|
32
|
+
promise
|
|
33
|
+
.then((value) => {
|
|
34
|
+
results[currentIndex] = { status: "fulfilled", value };
|
|
35
|
+
}, (error) => {
|
|
36
|
+
results[currentIndex] = { status: "rejected", reason: error };
|
|
37
|
+
})
|
|
38
|
+
.then(() => {
|
|
39
|
+
resolvedCount += 1;
|
|
40
|
+
if (resolvedCount === items.length) {
|
|
41
|
+
resolve(results);
|
|
42
|
+
}
|
|
43
|
+
else {
|
|
44
|
+
runNext();
|
|
45
|
+
}
|
|
46
|
+
});
|
|
47
|
+
};
|
|
48
|
+
const initialBatch = Math.min(effectiveLimit, items.length);
|
|
49
|
+
for (let index = 0; index < initialBatch; index += 1) {
|
|
50
|
+
runNext();
|
|
51
|
+
}
|
|
52
|
+
});
|
|
53
|
+
};
|
|
54
|
+
//# sourceMappingURL=pSettled.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pSettled.js","sourceRoot":"","sources":["../../src/Async/pSettled.ts"],"names":[],"mappings":"AAIA;;;;;;;;;;GAUG;AACH,MAAM,CAAC,MAAM,QAAQ,GAAG,CACtB,KAAgD,EAChD,KAAc,EACe,EAAE;IAC/B,MAAM,KAAK,GAAG,CAAC,GAAG,KAAK,CAAC,CAAC;IACzB,MAAM,OAAO,GAAuB,KAAK,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,KAAK,CAAC,MAAM,EAAE,CAAC,CAAC;IACzE,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACvB,OAAO,OAAO,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;IAClC,CAAC;IACD,MAAM,cAAc,GAAG,KAAK,IAAI,KAAK,GAAG,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC;IACjE,IAAI,SAAS,GAAG,CAAC,CAAC;IAClB,IAAI,aAAa,GAAG,CAAC,CAAC;IAEtB,OAAO,IAAI,OAAO,CAAqB,CAAC,OAAO,EAAE,EAAE;QACjD,MAAM,OAAO,GAAG,GAAS,EAAE;YACzB,IAAI,SAAS,IAAI,KAAK,CAAC,MAAM,EAAE,CAAC;gBAC9B,OAAO;YACT,CAAC;YACD,MAAM,YAAY,GAAG,SAAS,CAAC;YAC/B,SAAS,IAAI,CAAC,CAAC;YACf,MAAM,IAAI,GAAG,KAAK,CAAC,YAAY,CAAC,CAAC;YACjC,MAAM,OAAO,GACX,OAAO,IAAI,KAAK,UAAU;gBACxB,CAAC,CAAC,OAAO,CAAC,OAAO,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC;gBAC9B,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;YAE5B,OAAO;iBACJ,IAAI,CACH,CAAC,KAAK,EAAE,EAAE;gBACR,OAAO,CAAC,YAAY,CAAC,GAAG,EAAE,MAAM,EAAE,WAAW,EAAE,KAAK,EAAE,CAAC;YACzD,CAAC,EACD,CAAC,KAAK,EAAE,EAAE;gBACR,OAAO,CAAC,YAAY,CAAC,GAAG,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC;YAChE,CAAC,CACF;iBACA,IAAI,CAAC,GAAG,EAAE;gBACT,aAAa,IAAI,CAAC,CAAC;gBACnB,IAAI,aAAa,KAAK,KAAK,CAAC,MAAM,EAAE,CAAC;oBACnC,OAAO,CAAC,OAAO,CAAC,CAAC;gBACnB,CAAC;qBAAM,CAAC;oBACN,OAAO,EAAE,CAAC;gBACZ,CAAC;YACH,CAAC,CAAC,CAAC;QACP,CAAC,CAAC;QAEF,MAAM,YAAY,GAAG,IAAI,CAAC,GAAG,CAAC,cAAc,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC;QAC5D,KAAK,IAAI,KAAK,GAAG,CAAC,EAAE,KAAK,GAAG,YAAY,EAAE,KAAK,IAAI,CAAC,EAAE,CAAC;YACrD,OAAO,EAAE,CAAC;QACZ,CAAC;IACH,CAAC,CAAC,CAAC;AACL,CAAC,CAAC"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
export interface RetryOptions {
|
|
2
|
+
retries?: number;
|
|
3
|
+
delay?: number;
|
|
4
|
+
backoff?: "fixed" | "exponential" | "linear";
|
|
5
|
+
jitter?: boolean;
|
|
6
|
+
shouldRetry?: (error: unknown, attempt: number) => boolean;
|
|
7
|
+
onRetry?: (error: unknown, attempt: number) => void;
|
|
8
|
+
signal?: AbortSignal;
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* Retries an async function until it succeeds or the retry budget is exhausted.
|
|
12
|
+
* Supports fixed, linear, or exponential backoff, optional jitter, and
|
|
13
|
+
* AbortSignal cancellation.
|
|
14
|
+
*
|
|
15
|
+
* @template T - Return type of the function
|
|
16
|
+
* @param {() => Promise<T>} function_ - The async function to invoke
|
|
17
|
+
* @param {RetryOptions} [options] - Retry configuration
|
|
18
|
+
* @returns {Promise<T>} Result of the first successful invocation
|
|
19
|
+
* @example
|
|
20
|
+
* await retry(() => fetch("/api"), { retries: 5, backoff: "exponential", jitter: true });
|
|
21
|
+
*/
|
|
22
|
+
export declare const retry: <T>(function_: () => Promise<T>, options?: RetryOptions) => Promise<T>;
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { sleep } from "./sleep";
|
|
2
|
+
const computeDelay = (baseDelay, attemptNumber, backoff, jitter) => {
|
|
3
|
+
let waitMs = baseDelay;
|
|
4
|
+
if (backoff === "linear") {
|
|
5
|
+
waitMs = baseDelay * attemptNumber;
|
|
6
|
+
}
|
|
7
|
+
else if (backoff === "exponential") {
|
|
8
|
+
waitMs = baseDelay * 2 ** (attemptNumber - 1);
|
|
9
|
+
}
|
|
10
|
+
if (jitter) {
|
|
11
|
+
waitMs *= Math.random();
|
|
12
|
+
}
|
|
13
|
+
return waitMs;
|
|
14
|
+
};
|
|
15
|
+
/**
|
|
16
|
+
* Retries an async function until it succeeds or the retry budget is exhausted.
|
|
17
|
+
* Supports fixed, linear, or exponential backoff, optional jitter, and
|
|
18
|
+
* AbortSignal cancellation.
|
|
19
|
+
*
|
|
20
|
+
* @template T - Return type of the function
|
|
21
|
+
* @param {() => Promise<T>} function_ - The async function to invoke
|
|
22
|
+
* @param {RetryOptions} [options] - Retry configuration
|
|
23
|
+
* @returns {Promise<T>} Result of the first successful invocation
|
|
24
|
+
* @example
|
|
25
|
+
* await retry(() => fetch("/api"), { retries: 5, backoff: "exponential", jitter: true });
|
|
26
|
+
*/
|
|
27
|
+
export const retry = async (function_, options = {}) => {
|
|
28
|
+
const { retries = 3, delay = 1000, backoff = "fixed", jitter = false, shouldRetry = () => true, onRetry, signal, } = options;
|
|
29
|
+
let attemptNumber = 0;
|
|
30
|
+
while (true) {
|
|
31
|
+
if (signal?.aborted) {
|
|
32
|
+
throw signal.reason ?? new Error("Aborted");
|
|
33
|
+
}
|
|
34
|
+
try {
|
|
35
|
+
// biome-ignore lint/performance/noAwaitInLoops: retry must await sequentially
|
|
36
|
+
return await function_();
|
|
37
|
+
}
|
|
38
|
+
catch (error) {
|
|
39
|
+
const remaining = retries - attemptNumber;
|
|
40
|
+
if (remaining <= 0 || !shouldRetry(error, attemptNumber)) {
|
|
41
|
+
throw error;
|
|
42
|
+
}
|
|
43
|
+
onRetry?.(error, attemptNumber);
|
|
44
|
+
await sleep(computeDelay(delay, attemptNumber + 1, backoff, jitter));
|
|
45
|
+
attemptNumber += 1;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
};
|
|
49
|
+
//# sourceMappingURL=retry.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"retry.js","sourceRoot":"","sources":["../../src/Async/retry.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,SAAS,CAAC;AAYhC,MAAM,YAAY,GAAG,CACnB,SAAiB,EACjB,aAAqB,EACrB,OAA6C,EAC7C,MAAe,EACP,EAAE;IACV,IAAI,MAAM,GAAG,SAAS,CAAC;IACvB,IAAI,OAAO,KAAK,QAAQ,EAAE,CAAC;QACzB,MAAM,GAAG,SAAS,GAAG,aAAa,CAAC;IACrC,CAAC;SAAM,IAAI,OAAO,KAAK,aAAa,EAAE,CAAC;QACrC,MAAM,GAAG,SAAS,GAAG,CAAC,IAAI,CAAC,aAAa,GAAG,CAAC,CAAC,CAAC;IAChD,CAAC;IACD,IAAI,MAAM,EAAE,CAAC;QACX,MAAM,IAAI,IAAI,CAAC,MAAM,EAAE,CAAC;IAC1B,CAAC;IACD,OAAO,MAAM,CAAC;AAChB,CAAC,CAAC;AAEF;;;;;;;;;;;GAWG;AACH,MAAM,CAAC,MAAM,KAAK,GAAG,KAAK,EACxB,SAA2B,EAC3B,UAAwB,EAAE,EACd,EAAE;IACd,MAAM,EACJ,OAAO,GAAG,CAAC,EACX,KAAK,GAAG,IAAI,EACZ,OAAO,GAAG,OAAO,EACjB,MAAM,GAAG,KAAK,EACd,WAAW,GAAG,GAAG,EAAE,CAAC,IAAI,EACxB,OAAO,EACP,MAAM,GACP,GAAG,OAAO,CAAC;IAEZ,IAAI,aAAa,GAAG,CAAC,CAAC;IACtB,OAAO,IAAI,EAAE,CAAC;QACZ,IAAI,MAAM,EAAE,OAAO,EAAE,CAAC;YACpB,MAAM,MAAM,CAAC,MAAM,IAAI,IAAI,KAAK,CAAC,SAAS,CAAC,CAAC;QAC9C,CAAC;QACD,IAAI,CAAC;YACH,8EAA8E;YAC9E,OAAO,MAAM,SAAS,EAAE,CAAC;QAC3B,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,MAAM,SAAS,GAAG,OAAO,GAAG,aAAa,CAAC;YAC1C,IAAI,SAAS,IAAI,CAAC,IAAI,CAAC,WAAW,CAAC,KAAK,EAAE,aAAa,CAAC,EAAE,CAAC;gBACzD,MAAM,KAAK,CAAC;YACd,CAAC;YACD,OAAO,EAAE,CAAC,KAAK,EAAE,aAAa,CAAC,CAAC;YAChC,MAAM,KAAK,CAAC,YAAY,CAAC,KAAK,EAAE,aAAa,GAAG,CAAC,EAAE,OAAO,EAAE,MAAM,CAAC,CAAC,CAAC;YACrE,aAAa,IAAI,CAAC,CAAC;QACrB,CAAC;IACH,CAAC;AACH,CAAC,CAAC"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
export interface ThrottledAsyncFunction<A extends unknown[], R> {
|
|
2
|
+
(...arguments_: A): Promise<R>;
|
|
3
|
+
cancel: () => void;
|
|
4
|
+
}
|
|
5
|
+
/**
|
|
6
|
+
* Creates a throttled async function. Coalesces concurrent calls within the
|
|
7
|
+
* `wait` window so only one underlying invocation runs; all callers in the
|
|
8
|
+
* window receive the same result.
|
|
9
|
+
*
|
|
10
|
+
* @template A - Argument tuple type
|
|
11
|
+
* @template R - Resolved value type
|
|
12
|
+
* @param {(...args: A) => Promise<R>} function_ - Async function to throttle
|
|
13
|
+
* @param {number} wait - Window length in milliseconds
|
|
14
|
+
* @returns {ThrottledAsyncFunction<A, R>} Throttled wrapper with cancel support
|
|
15
|
+
* @example
|
|
16
|
+
* const fetchUser = throttleAsync(loadUser, 1000);
|
|
17
|
+
*/
|
|
18
|
+
export declare const throttleAsync: <A extends unknown[], R>(function_: (...arguments_: A) => Promise<R>, wait: number) => ThrottledAsyncFunction<A, R>;
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Creates a throttled async function. Coalesces concurrent calls within the
|
|
3
|
+
* `wait` window so only one underlying invocation runs; all callers in the
|
|
4
|
+
* window receive the same result.
|
|
5
|
+
*
|
|
6
|
+
* @template A - Argument tuple type
|
|
7
|
+
* @template R - Resolved value type
|
|
8
|
+
* @param {(...args: A) => Promise<R>} function_ - Async function to throttle
|
|
9
|
+
* @param {number} wait - Window length in milliseconds
|
|
10
|
+
* @returns {ThrottledAsyncFunction<A, R>} Throttled wrapper with cancel support
|
|
11
|
+
* @example
|
|
12
|
+
* const fetchUser = throttleAsync(loadUser, 1000);
|
|
13
|
+
*/
|
|
14
|
+
export const throttleAsync = (function_, wait) => {
|
|
15
|
+
let inflight;
|
|
16
|
+
let lockedUntil = 0;
|
|
17
|
+
const throttled = ((...arguments_) => {
|
|
18
|
+
if (inflight) {
|
|
19
|
+
return inflight;
|
|
20
|
+
}
|
|
21
|
+
if (Date.now() < lockedUntil) {
|
|
22
|
+
return Promise.reject(new Error("throttleAsync window not elapsed"));
|
|
23
|
+
}
|
|
24
|
+
const current = function_(...arguments_);
|
|
25
|
+
inflight = current;
|
|
26
|
+
const cleanup = () => {
|
|
27
|
+
if (inflight === current) {
|
|
28
|
+
inflight = undefined;
|
|
29
|
+
lockedUntil = Date.now() + wait;
|
|
30
|
+
}
|
|
31
|
+
};
|
|
32
|
+
current.then(cleanup, cleanup);
|
|
33
|
+
return current;
|
|
34
|
+
});
|
|
35
|
+
throttled.cancel = () => {
|
|
36
|
+
inflight = undefined;
|
|
37
|
+
lockedUntil = 0;
|
|
38
|
+
};
|
|
39
|
+
return throttled;
|
|
40
|
+
};
|
|
41
|
+
//# sourceMappingURL=throttleAsync.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"throttleAsync.js","sourceRoot":"","sources":["../../src/Async/throttleAsync.ts"],"names":[],"mappings":"AAKA;;;;;;;;;;;;GAYG;AACH,MAAM,CAAC,MAAM,aAAa,GAAG,CAC3B,SAA2C,EAC3C,IAAY,EACkB,EAAE;IAChC,IAAI,QAAgC,CAAC;IACrC,IAAI,WAAW,GAAG,CAAC,CAAC;IAEpB,MAAM,SAAS,GAAG,CAAC,CAAC,GAAG,UAAa,EAAc,EAAE;QAClD,IAAI,QAAQ,EAAE,CAAC;YACb,OAAO,QAAQ,CAAC;QAClB,CAAC;QACD,IAAI,IAAI,CAAC,GAAG,EAAE,GAAG,WAAW,EAAE,CAAC;YAC7B,OAAO,OAAO,CAAC,MAAM,CAAC,IAAI,KAAK,CAAC,kCAAkC,CAAC,CAAC,CAAC;QACvE,CAAC;QACD,MAAM,OAAO,GAAG,SAAS,CAAC,GAAG,UAAU,CAAC,CAAC;QACzC,QAAQ,GAAG,OAAO,CAAC;QACnB,MAAM,OAAO,GAAG,GAAS,EAAE;YACzB,IAAI,QAAQ,KAAK,OAAO,EAAE,CAAC;gBACzB,QAAQ,GAAG,SAAS,CAAC;gBACrB,WAAW,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC;YAClC,CAAC;QACH,CAAC,CAAC;QACF,OAAO,CAAC,IAAI,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;QAC/B,OAAO,OAAO,CAAC;IACjB,CAAC,CAAiC,CAAC;IAEnC,SAAS,CAAC,MAAM,GAAG,GAAS,EAAE;QAC5B,QAAQ,GAAG,SAAS,CAAC;QACrB,WAAW,GAAG,CAAC,CAAC;IAClB,CAAC,CAAC;IAEF,OAAO,SAAS,CAAC;AACnB,CAAC,CAAC"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
export interface WaitForOptions {
|
|
2
|
+
timeout?: number;
|
|
3
|
+
interval?: number;
|
|
4
|
+
signal?: AbortSignal;
|
|
5
|
+
}
|
|
6
|
+
/**
|
|
7
|
+
* Repeatedly evaluates a condition until it returns a truthy value or the
|
|
8
|
+
* timeout elapses. Resolves with the final truthy value.
|
|
9
|
+
*
|
|
10
|
+
* @template T - Truthy result type
|
|
11
|
+
* @param {() => T | Promise<T>} condition - Condition predicate
|
|
12
|
+
* @param {WaitForOptions} [options] - Polling configuration
|
|
13
|
+
* @returns {Promise<NonNullable<T>>} The first truthy value
|
|
14
|
+
* @throws {Error} When the timeout elapses or the signal aborts
|
|
15
|
+
* @example
|
|
16
|
+
* await waitFor(() => document.querySelector("#root"), { interval: 100 });
|
|
17
|
+
*/
|
|
18
|
+
export declare const waitFor: <T>(condition: () => T | Promise<T>, options?: WaitForOptions) => Promise<NonNullable<T>>;
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { sleep } from "./sleep";
|
|
2
|
+
/**
|
|
3
|
+
* Repeatedly evaluates a condition until it returns a truthy value or the
|
|
4
|
+
* timeout elapses. Resolves with the final truthy value.
|
|
5
|
+
*
|
|
6
|
+
* @template T - Truthy result type
|
|
7
|
+
* @param {() => T | Promise<T>} condition - Condition predicate
|
|
8
|
+
* @param {WaitForOptions} [options] - Polling configuration
|
|
9
|
+
* @returns {Promise<NonNullable<T>>} The first truthy value
|
|
10
|
+
* @throws {Error} When the timeout elapses or the signal aborts
|
|
11
|
+
* @example
|
|
12
|
+
* await waitFor(() => document.querySelector("#root"), { interval: 100 });
|
|
13
|
+
*/
|
|
14
|
+
export const waitFor = async (condition, options = {}) => {
|
|
15
|
+
const { timeout = 5000, interval = 100, signal } = options;
|
|
16
|
+
const startTime = Date.now();
|
|
17
|
+
while (true) {
|
|
18
|
+
if (signal?.aborted) {
|
|
19
|
+
throw signal.reason ?? new Error("Aborted");
|
|
20
|
+
}
|
|
21
|
+
// biome-ignore lint/performance/noAwaitInLoops: waitFor polls sequentially
|
|
22
|
+
const value = await condition();
|
|
23
|
+
if (value) {
|
|
24
|
+
return value;
|
|
25
|
+
}
|
|
26
|
+
if (Date.now() - startTime >= timeout) {
|
|
27
|
+
throw new Error(`waitFor timed out after ${timeout}ms`);
|
|
28
|
+
}
|
|
29
|
+
await sleep(interval);
|
|
30
|
+
}
|
|
31
|
+
};
|
|
32
|
+
//# sourceMappingURL=waitFor.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"waitFor.js","sourceRoot":"","sources":["../../src/Async/waitFor.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,SAAS,CAAC;AAQhC;;;;;;;;;;;GAWG;AACH,MAAM,CAAC,MAAM,OAAO,GAAG,KAAK,EAC1B,SAA+B,EAC/B,UAA0B,EAAE,EACH,EAAE;IAC3B,MAAM,EAAE,OAAO,GAAG,IAAI,EAAE,QAAQ,GAAG,GAAG,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC;IAC3D,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;IAE7B,OAAO,IAAI,EAAE,CAAC;QACZ,IAAI,MAAM,EAAE,OAAO,EAAE,CAAC;YACpB,MAAM,MAAM,CAAC,MAAM,IAAI,IAAI,KAAK,CAAC,SAAS,CAAC,CAAC;QAC9C,CAAC;QACD,2EAA2E;QAC3E,MAAM,KAAK,GAAG,MAAM,SAAS,EAAE,CAAC;QAChC,IAAI,KAAK,EAAE,CAAC;YACV,OAAO,KAAK,CAAC;QACf,CAAC;QACD,IAAI,IAAI,CAAC,GAAG,EAAE,GAAG,SAAS,IAAI,OAAO,EAAE,CAAC;YACtC,MAAM,IAAI,KAAK,CAAC,2BAA2B,OAAO,IAAI,CAAC,CAAC;QAC1D,CAAC;QACD,MAAM,KAAK,CAAC,QAAQ,CAAC,CAAC;IACxB,CAAC;AACH,CAAC,CAAC"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { DurationUnit } from "./durationUnit";
|
|
2
|
+
/**
|
|
3
|
+
* Adds a duration to a date and returns a new Date.
|
|
4
|
+
* Calendar-aware for "M" (months) and "y" (years), so end-of-month
|
|
5
|
+
* is preserved (e.g. Jan 31 + 1 month = Feb 28/29).
|
|
6
|
+
*
|
|
7
|
+
* @param {Date} date - Base date
|
|
8
|
+
* @param {number} amount - Amount to add (can be negative)
|
|
9
|
+
* @param {DurationUnit} unit - Unit of the amount
|
|
10
|
+
* @returns {Date} A new Date with the duration added
|
|
11
|
+
* @example
|
|
12
|
+
* addDuration(new Date("2025-01-31"), 1, "M"); // 2025-02-28
|
|
13
|
+
* addDuration(new Date("2025-01-01"), 7, "d"); // 2025-01-08
|
|
14
|
+
*/
|
|
15
|
+
export declare const addDuration: (date: Date, amount: number, unit: DurationUnit) => Date;
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { msByUnit } from "./msByUnit";
|
|
2
|
+
/**
|
|
3
|
+
* Adds a duration to a date and returns a new Date.
|
|
4
|
+
* Calendar-aware for "M" (months) and "y" (years), so end-of-month
|
|
5
|
+
* is preserved (e.g. Jan 31 + 1 month = Feb 28/29).
|
|
6
|
+
*
|
|
7
|
+
* @param {Date} date - Base date
|
|
8
|
+
* @param {number} amount - Amount to add (can be negative)
|
|
9
|
+
* @param {DurationUnit} unit - Unit of the amount
|
|
10
|
+
* @returns {Date} A new Date with the duration added
|
|
11
|
+
* @example
|
|
12
|
+
* addDuration(new Date("2025-01-31"), 1, "M"); // 2025-02-28
|
|
13
|
+
* addDuration(new Date("2025-01-01"), 7, "d"); // 2025-01-08
|
|
14
|
+
*/
|
|
15
|
+
export const addDuration = (date, amount, unit) => {
|
|
16
|
+
const ms = msByUnit[unit];
|
|
17
|
+
if (ms !== undefined) {
|
|
18
|
+
return new Date(date.getTime() + amount * ms);
|
|
19
|
+
}
|
|
20
|
+
const result = new Date(date);
|
|
21
|
+
if (unit === "M") {
|
|
22
|
+
const targetMonth = result.getMonth() + amount;
|
|
23
|
+
const day = result.getDate();
|
|
24
|
+
result.setDate(1);
|
|
25
|
+
result.setMonth(targetMonth);
|
|
26
|
+
const lastDayOfTargetMonth = new Date(result.getFullYear(), result.getMonth() + 1, 0).getDate();
|
|
27
|
+
result.setDate(Math.min(day, lastDayOfTargetMonth));
|
|
28
|
+
return result;
|
|
29
|
+
}
|
|
30
|
+
const targetYear = result.getFullYear() + amount;
|
|
31
|
+
const month = result.getMonth();
|
|
32
|
+
const day = result.getDate();
|
|
33
|
+
result.setDate(1);
|
|
34
|
+
result.setFullYear(targetYear);
|
|
35
|
+
result.setMonth(month);
|
|
36
|
+
const lastDayOfTargetMonth = new Date(targetYear, month + 1, 0).getDate();
|
|
37
|
+
result.setDate(Math.min(day, lastDayOfTargetMonth));
|
|
38
|
+
return result;
|
|
39
|
+
};
|
|
40
|
+
//# sourceMappingURL=addDuration.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"addDuration.js","sourceRoot":"","sources":["../../src/Date/addDuration.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAEtC;;;;;;;;;;;;GAYG;AACH,MAAM,CAAC,MAAM,WAAW,GAAG,CACzB,IAAU,EACV,MAAc,EACd,IAAkB,EACZ,EAAE;IACR,MAAM,EAAE,GAAG,QAAQ,CAAC,IAAI,CAAC,CAAC;IAC1B,IAAI,EAAE,KAAK,SAAS,EAAE,CAAC;QACrB,OAAO,IAAI,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,GAAG,MAAM,GAAG,EAAE,CAAC,CAAC;IAChD,CAAC;IAED,MAAM,MAAM,GAAG,IAAI,IAAI,CAAC,IAAI,CAAC,CAAC;IAC9B,IAAI,IAAI,KAAK,GAAG,EAAE,CAAC;QACjB,MAAM,WAAW,GAAG,MAAM,CAAC,QAAQ,EAAE,GAAG,MAAM,CAAC;QAC/C,MAAM,GAAG,GAAG,MAAM,CAAC,OAAO,EAAE,CAAC;QAC7B,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;QAClB,MAAM,CAAC,QAAQ,CAAC,WAAW,CAAC,CAAC;QAC7B,MAAM,oBAAoB,GAAG,IAAI,IAAI,CACnC,MAAM,CAAC,WAAW,EAAE,EACpB,MAAM,CAAC,QAAQ,EAAE,GAAG,CAAC,EACrB,CAAC,CACF,CAAC,OAAO,EAAE,CAAC;QACZ,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,EAAE,oBAAoB,CAAC,CAAC,CAAC;QACpD,OAAO,MAAM,CAAC;IAChB,CAAC;IAED,MAAM,UAAU,GAAG,MAAM,CAAC,WAAW,EAAE,GAAG,MAAM,CAAC;IACjD,MAAM,KAAK,GAAG,MAAM,CAAC,QAAQ,EAAE,CAAC;IAChC,MAAM,GAAG,GAAG,MAAM,CAAC,OAAO,EAAE,CAAC;IAC7B,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;IAClB,MAAM,CAAC,WAAW,CAAC,UAAU,CAAC,CAAC;IAC/B,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;IACvB,MAAM,oBAAoB,GAAG,IAAI,IAAI,CAAC,UAAU,EAAE,KAAK,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC,OAAO,EAAE,CAAC;IAC1E,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,EAAE,oBAAoB,CAAC,CAAC,CAAC;IACpD,OAAO,MAAM,CAAC;AAChB,CAAC,CAAC"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { DurationUnit } from "./durationUnit";
|
|
2
|
+
/**
|
|
3
|
+
* Returns the difference between two dates in the given unit, truncated toward zero.
|
|
4
|
+
* Calendar-aware for "M" (months) and "y" (years).
|
|
5
|
+
*
|
|
6
|
+
* @param {Date} left - End date
|
|
7
|
+
* @param {Date} right - Start date
|
|
8
|
+
* @param {DurationUnit} unit - Unit of the result
|
|
9
|
+
* @returns {number} The difference, truncated toward zero
|
|
10
|
+
* @example
|
|
11
|
+
* diff(new Date("2025-12-31"), new Date("2025-01-01"), "d"); // 364
|
|
12
|
+
* diff(new Date("2026-01-01"), new Date("2025-01-01"), "y"); // 1
|
|
13
|
+
*/
|
|
14
|
+
export declare const diff: (left: Date, right: Date, unit: DurationUnit) => number;
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { OneHourMs, OneMinuteMs, OneSecondMs } from "../Consts/clock";
|
|
2
|
+
import { msByUnit } from "./msByUnit";
|
|
3
|
+
/**
|
|
4
|
+
* Returns the difference between two dates in the given unit, truncated toward zero.
|
|
5
|
+
* Calendar-aware for "M" (months) and "y" (years).
|
|
6
|
+
*
|
|
7
|
+
* @param {Date} left - End date
|
|
8
|
+
* @param {Date} right - Start date
|
|
9
|
+
* @param {DurationUnit} unit - Unit of the result
|
|
10
|
+
* @returns {number} The difference, truncated toward zero
|
|
11
|
+
* @example
|
|
12
|
+
* diff(new Date("2025-12-31"), new Date("2025-01-01"), "d"); // 364
|
|
13
|
+
* diff(new Date("2026-01-01"), new Date("2025-01-01"), "y"); // 1
|
|
14
|
+
*/
|
|
15
|
+
export const diff = (left, right, unit) => {
|
|
16
|
+
const ms = msByUnit[unit];
|
|
17
|
+
if (ms !== undefined) {
|
|
18
|
+
return Math.trunc((left.getTime() - right.getTime()) / ms);
|
|
19
|
+
}
|
|
20
|
+
const yearsDelta = left.getFullYear() - right.getFullYear();
|
|
21
|
+
const monthsDelta = left.getMonth() - right.getMonth();
|
|
22
|
+
const dayDelta = left.getDate() - right.getDate();
|
|
23
|
+
const subDayDelta = left.getHours() * OneHourMs +
|
|
24
|
+
left.getMinutes() * OneMinuteMs +
|
|
25
|
+
left.getSeconds() * OneSecondMs +
|
|
26
|
+
left.getMilliseconds() -
|
|
27
|
+
(right.getHours() * OneHourMs +
|
|
28
|
+
right.getMinutes() * OneMinuteMs +
|
|
29
|
+
right.getSeconds() * OneSecondMs +
|
|
30
|
+
right.getMilliseconds());
|
|
31
|
+
let calendarMonths = yearsDelta * 12 + monthsDelta;
|
|
32
|
+
if (calendarMonths > 0 &&
|
|
33
|
+
(dayDelta < 0 || (dayDelta === 0 && subDayDelta < 0))) {
|
|
34
|
+
calendarMonths -= 1;
|
|
35
|
+
}
|
|
36
|
+
else if (calendarMonths < 0 &&
|
|
37
|
+
(dayDelta > 0 || (dayDelta === 0 && subDayDelta > 0))) {
|
|
38
|
+
calendarMonths += 1;
|
|
39
|
+
}
|
|
40
|
+
if (unit === "M") {
|
|
41
|
+
return calendarMonths;
|
|
42
|
+
}
|
|
43
|
+
return Math.trunc(calendarMonths / 12);
|
|
44
|
+
};
|
|
45
|
+
//# sourceMappingURL=diff.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"diff.js","sourceRoot":"","sources":["../../src/Date/diff.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,WAAW,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAC;AAGtE,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAEtC;;;;;;;;;;;GAWG;AACH,MAAM,CAAC,MAAM,IAAI,GAAG,CAAC,IAAU,EAAE,KAAW,EAAE,IAAkB,EAAU,EAAE;IAC1E,MAAM,EAAE,GAAG,QAAQ,CAAC,IAAI,CAAC,CAAC;IAC1B,IAAI,EAAE,KAAK,SAAS,EAAE,CAAC;QACrB,OAAO,IAAI,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,OAAO,EAAE,GAAG,KAAK,CAAC,OAAO,EAAE,CAAC,GAAG,EAAE,CAAC,CAAC;IAC7D,CAAC;IAED,MAAM,UAAU,GAAG,IAAI,CAAC,WAAW,EAAE,GAAG,KAAK,CAAC,WAAW,EAAE,CAAC;IAC5D,MAAM,WAAW,GAAG,IAAI,CAAC,QAAQ,EAAE,GAAG,KAAK,CAAC,QAAQ,EAAE,CAAC;IACvD,MAAM,QAAQ,GAAG,IAAI,CAAC,OAAO,EAAE,GAAG,KAAK,CAAC,OAAO,EAAE,CAAC;IAClD,MAAM,WAAW,GACf,IAAI,CAAC,QAAQ,EAAE,GAAG,SAAS;QAC3B,IAAI,CAAC,UAAU,EAAE,GAAG,WAAW;QAC/B,IAAI,CAAC,UAAU,EAAE,GAAG,WAAW;QAC/B,IAAI,CAAC,eAAe,EAAE;QACtB,CAAC,KAAK,CAAC,QAAQ,EAAE,GAAG,SAAS;YAC3B,KAAK,CAAC,UAAU,EAAE,GAAG,WAAW;YAChC,KAAK,CAAC,UAAU,EAAE,GAAG,WAAW;YAChC,KAAK,CAAC,eAAe,EAAE,CAAC,CAAC;IAE7B,IAAI,cAAc,GAAG,UAAU,GAAG,EAAE,GAAG,WAAW,CAAC;IACnD,IACE,cAAc,GAAG,CAAC;QAClB,CAAC,QAAQ,GAAG,CAAC,IAAI,CAAC,QAAQ,KAAK,CAAC,IAAI,WAAW,GAAG,CAAC,CAAC,CAAC,EACrD,CAAC;QACD,cAAc,IAAI,CAAC,CAAC;IACtB,CAAC;SAAM,IACL,cAAc,GAAG,CAAC;QAClB,CAAC,QAAQ,GAAG,CAAC,IAAI,CAAC,QAAQ,KAAK,CAAC,IAAI,WAAW,GAAG,CAAC,CAAC,CAAC,EACrD,CAAC;QACD,cAAc,IAAI,CAAC,CAAC;IACtB,CAAC;IAED,IAAI,IAAI,KAAK,GAAG,EAAE,CAAC;QACjB,OAAO,cAAc,CAAC;IACxB,CAAC;IACD,OAAO,IAAI,CAAC,KAAK,CAAC,cAAc,GAAG,EAAE,CAAC,CAAC;AACzC,CAAC,CAAC"}
|