umt 2.16.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.
Files changed (275) hide show
  1. package/README.md +42 -0
  2. package/module/Array/chunk.js.map +1 -1
  3. package/module/Array/uniqBy.js.map +1 -1
  4. package/module/Async/debounceAsync.d.ts +18 -0
  5. package/module/Async/debounceAsync.js +59 -0
  6. package/module/Async/debounceAsync.js.map +1 -0
  7. package/module/Async/index.d.ts +5 -0
  8. package/module/Async/index.js +5 -0
  9. package/module/Async/index.js.map +1 -1
  10. package/module/Async/pSettled.d.ts +19 -0
  11. package/module/Async/pSettled.js +54 -0
  12. package/module/Async/pSettled.js.map +1 -0
  13. package/module/Async/retry.d.ts +22 -0
  14. package/module/Async/retry.js +49 -0
  15. package/module/Async/retry.js.map +1 -0
  16. package/module/Async/throttleAsync.d.ts +18 -0
  17. package/module/Async/throttleAsync.js +41 -0
  18. package/module/Async/throttleAsync.js.map +1 -0
  19. package/module/Async/waitFor.d.ts +18 -0
  20. package/module/Async/waitFor.js +32 -0
  21. package/module/Async/waitFor.js.map +1 -0
  22. package/module/Date/addDuration.d.ts +15 -0
  23. package/module/Date/addDuration.js +40 -0
  24. package/module/Date/addDuration.js.map +1 -0
  25. package/module/Date/diff.d.ts +14 -0
  26. package/module/Date/diff.js +45 -0
  27. package/module/Date/diff.js.map +1 -0
  28. package/module/Date/durationUnit.d.ts +12 -0
  29. package/module/Date/durationUnit.js +2 -0
  30. package/module/Date/durationUnit.js.map +1 -0
  31. package/module/Date/endOf.d.ts +13 -0
  32. package/module/Date/endOf.js +58 -0
  33. package/module/Date/endOf.js.map +1 -0
  34. package/module/Date/formatRelative.d.ts +13 -0
  35. package/module/Date/formatRelative.js +35 -0
  36. package/module/Date/formatRelative.js.map +1 -0
  37. package/module/Date/index.d.ts +10 -0
  38. package/module/Date/index.js +10 -0
  39. package/module/Date/index.js.map +1 -1
  40. package/module/Date/isBusinessDay.d.ts +10 -0
  41. package/module/Date/isBusinessDay.js +18 -0
  42. package/module/Date/isBusinessDay.js.map +1 -0
  43. package/module/Date/isSameDay.d.ts +10 -0
  44. package/module/Date/isSameDay.js +13 -0
  45. package/module/Date/isSameDay.js.map +1 -0
  46. package/module/Date/isWeekend.d.ts +9 -0
  47. package/module/Date/isWeekend.js +13 -0
  48. package/module/Date/isWeekend.js.map +1 -0
  49. package/module/Date/msByUnit.d.ts +2 -0
  50. package/module/Date/msByUnit.js +10 -0
  51. package/module/Date/msByUnit.js.map +1 -0
  52. package/module/Date/startOf.d.ts +13 -0
  53. package/module/Date/startOf.js +58 -0
  54. package/module/Date/startOf.js.map +1 -0
  55. package/module/Date/subDuration.d.ts +13 -0
  56. package/module/Date/subDuration.js +14 -0
  57. package/module/Date/subDuration.js.map +1 -0
  58. package/module/Error/index.d.ts +0 -1
  59. package/module/Error/index.js +0 -1
  60. package/module/Error/index.js.map +1 -1
  61. package/module/Object/deepClone.js.map +1 -1
  62. package/module/Object/flattenObject.d.ts +11 -0
  63. package/module/Object/flattenObject.js +29 -0
  64. package/module/Object/flattenObject.js.map +1 -0
  65. package/module/Object/get.d.ts +1 -0
  66. package/module/Object/get.js +26 -0
  67. package/module/Object/get.js.map +1 -0
  68. package/module/Object/has.d.ts +0 -19
  69. package/module/Object/has.js +4 -4
  70. package/module/Object/has.js.map +1 -1
  71. package/module/Object/index.d.ts +8 -0
  72. package/module/Object/index.js +8 -0
  73. package/module/Object/index.js.map +1 -1
  74. package/module/Object/invert.d.ts +12 -0
  75. package/module/Object/invert.js +20 -0
  76. package/module/Object/invert.js.map +1 -0
  77. package/module/Object/mergeDeep.js.map +1 -1
  78. package/module/Object/omitBy.d.ts +11 -0
  79. package/module/Object/omitBy.js +21 -0
  80. package/module/Object/omitBy.js.map +1 -0
  81. package/module/Object/pathSegments.d.ts +1 -0
  82. package/module/Object/pathSegments.js +2 -0
  83. package/module/Object/pathSegments.js.map +1 -0
  84. package/module/Object/pickBy.d.ts +11 -0
  85. package/module/Object/pickBy.js +21 -0
  86. package/module/Object/pickBy.js.map +1 -0
  87. package/module/Object/set.d.ts +19 -0
  88. package/module/Object/set.js +38 -0
  89. package/module/Object/set.js.map +1 -0
  90. package/module/Object/unflattenObject.d.ts +15 -0
  91. package/module/Object/unflattenObject.js +23 -0
  92. package/module/Object/unflattenObject.js.map +1 -0
  93. package/module/Random/index.d.ts +7 -0
  94. package/module/Random/index.js +8 -0
  95. package/module/Random/index.js.map +1 -0
  96. package/module/Random/randomBoolean.d.ts +9 -0
  97. package/module/Random/randomBoolean.js +10 -0
  98. package/module/Random/randomBoolean.js.map +1 -0
  99. package/module/Random/randomChoice.d.ts +9 -0
  100. package/module/Random/randomChoice.js +13 -0
  101. package/module/Random/randomChoice.js.map +1 -0
  102. package/module/Random/randomFloat.d.ts +9 -0
  103. package/module/Random/randomFloat.js +10 -0
  104. package/module/Random/randomFloat.js.map +1 -0
  105. package/module/Random/randomInt.d.ts +9 -0
  106. package/module/Random/randomInt.js +14 -0
  107. package/module/Random/randomInt.js.map +1 -0
  108. package/module/Random/randomUuid.d.ts +9 -0
  109. package/module/Random/randomUuid.js +31 -0
  110. package/module/Random/randomUuid.js.map +1 -0
  111. package/module/Random/seededRandom.d.ts +11 -0
  112. package/module/Random/seededRandom.js +31 -0
  113. package/module/Random/seededRandom.js.map +1 -0
  114. package/module/Random/weightedChoice.d.ts +15 -0
  115. package/module/Random/weightedChoice.js +34 -0
  116. package/module/Random/weightedChoice.js.map +1 -0
  117. package/module/String/capitalize.d.ts +12 -0
  118. package/module/String/capitalize.js +18 -0
  119. package/module/String/capitalize.js.map +1 -0
  120. package/module/String/capitalizeWord.d.ts +1 -0
  121. package/module/String/capitalizeWord.js +2 -0
  122. package/module/String/capitalizeWord.js.map +1 -0
  123. package/module/String/dedent.d.ts +19 -0
  124. package/module/String/dedent.js +56 -0
  125. package/module/String/dedent.js.map +1 -0
  126. package/module/String/index.d.ts +10 -0
  127. package/module/String/index.js +10 -0
  128. package/module/String/index.js.map +1 -1
  129. package/module/String/mask.d.ts +20 -0
  130. package/module/String/mask.js +24 -0
  131. package/module/String/mask.js.map +1 -0
  132. package/module/String/pascalCase.d.ts +9 -0
  133. package/module/String/pascalCase.js +14 -0
  134. package/module/String/pascalCase.js.map +1 -0
  135. package/module/String/snakeCase.d.ts +9 -0
  136. package/module/String/snakeCase.js +13 -0
  137. package/module/String/snakeCase.js.map +1 -0
  138. package/module/String/titleCase.d.ts +9 -0
  139. package/module/String/titleCase.js +14 -0
  140. package/module/String/titleCase.js.map +1 -0
  141. package/module/String/uncapitalize.d.ts +10 -0
  142. package/module/String/uncapitalize.js +16 -0
  143. package/module/String/uncapitalize.js.map +1 -0
  144. package/module/String/wordCount.d.ts +10 -0
  145. package/module/String/wordCount.js +12 -0
  146. package/module/String/wordCount.js.map +1 -0
  147. package/module/String/words.d.ts +12 -0
  148. package/module/String/words.js +21 -0
  149. package/module/String/words.js.map +1 -0
  150. package/module/Tool/createPipeline.d.ts +1 -1
  151. package/module/Tool/createPipeline.js +8 -6
  152. package/module/Tool/createPipeline.js.map +1 -1
  153. package/module/Tool/pipe.js.map +1 -1
  154. package/module/URL/buildUrl.d.ts +10 -0
  155. package/module/URL/buildUrl.js +10 -4
  156. package/module/URL/buildUrl.js.map +1 -1
  157. package/module/URL/parseQueryString.d.ts +6 -0
  158. package/module/URL/parseQueryString.js +6 -4
  159. package/module/URL/parseQueryString.js.map +1 -1
  160. package/module/Validate/isNumber.js.map +1 -1
  161. package/module/Validate/object/core.js +0 -1
  162. package/module/Validate/object/core.js.map +1 -1
  163. package/module/es5/Async/debounceAsync.d.ts +18 -0
  164. package/module/es5/Async/debounceAsync.js +103 -0
  165. package/module/es5/Async/index.d.ts +5 -0
  166. package/module/es5/Async/index.js +55 -0
  167. package/module/es5/Async/pSettled.d.ts +19 -0
  168. package/module/es5/Async/pSettled.js +68 -0
  169. package/module/es5/Async/retry.d.ts +22 -0
  170. package/module/es5/Async/retry.js +106 -0
  171. package/module/es5/Async/throttleAsync.d.ts +18 -0
  172. package/module/es5/Async/throttleAsync.js +46 -0
  173. package/module/es5/Async/waitFor.d.ts +18 -0
  174. package/module/es5/{Error/retry.js → Async/waitFor.js} +68 -74
  175. package/module/es5/Date/addDuration.d.ts +15 -0
  176. package/module/es5/Date/addDuration.js +45 -0
  177. package/module/es5/Date/diff.d.ts +14 -0
  178. package/module/es5/Date/diff.js +40 -0
  179. package/module/es5/Date/durationUnit.d.ts +12 -0
  180. package/module/es5/Date/durationUnit.js +5 -0
  181. package/module/es5/Date/endOf.d.ts +13 -0
  182. package/module/es5/Date/endOf.js +72 -0
  183. package/module/es5/Date/formatRelative.d.ts +13 -0
  184. package/module/es5/Date/formatRelative.js +61 -0
  185. package/module/es5/Date/index.d.ts +10 -0
  186. package/module/es5/Date/index.js +110 -0
  187. package/module/es5/Date/isBusinessDay.d.ts +10 -0
  188. package/module/es5/Date/isBusinessDay.js +26 -0
  189. package/module/es5/Date/isSameDay.d.ts +10 -0
  190. package/module/es5/Date/isSameDay.js +18 -0
  191. package/module/es5/Date/isWeekend.d.ts +9 -0
  192. package/module/es5/Date/isWeekend.js +18 -0
  193. package/module/es5/Date/msByUnit.d.ts +2 -0
  194. package/module/es5/Date/msByUnit.js +15 -0
  195. package/module/es5/Date/startOf.d.ts +13 -0
  196. package/module/es5/Date/startOf.js +72 -0
  197. package/module/es5/Date/subDuration.d.ts +13 -0
  198. package/module/es5/Date/subDuration.js +21 -0
  199. package/module/es5/Error/index.d.ts +0 -1
  200. package/module/es5/Error/index.js +0 -11
  201. package/module/es5/Object/flattenObject.d.ts +11 -0
  202. package/module/es5/Object/flattenObject.js +35 -0
  203. package/module/es5/Object/get.d.ts +1 -0
  204. package/module/es5/Object/get.js +42 -0
  205. package/module/es5/Object/has.d.ts +0 -19
  206. package/module/es5/Object/has.js +4 -4
  207. package/module/es5/Object/index.d.ts +8 -0
  208. package/module/es5/Object/index.js +88 -0
  209. package/module/es5/Object/invert.d.ts +12 -0
  210. package/module/es5/Object/invert.js +26 -0
  211. package/module/es5/Object/omitBy.d.ts +11 -0
  212. package/module/es5/Object/omitBy.js +27 -0
  213. package/module/es5/Object/pathSegments.d.ts +1 -0
  214. package/module/es5/Object/pathSegments.js +9 -0
  215. package/module/es5/Object/pickBy.d.ts +11 -0
  216. package/module/es5/Object/pickBy.js +27 -0
  217. package/module/es5/Object/set.d.ts +19 -0
  218. package/module/es5/Object/set.js +44 -0
  219. package/module/es5/Object/unflattenObject.d.ts +15 -0
  220. package/module/es5/Object/unflattenObject.js +30 -0
  221. package/module/es5/Random/index.d.ts +7 -0
  222. package/module/es5/Random/index.js +82 -0
  223. package/module/es5/Random/randomBoolean.d.ts +9 -0
  224. package/module/es5/Random/randomBoolean.js +18 -0
  225. package/module/es5/Random/randomChoice.d.ts +9 -0
  226. package/module/es5/Random/randomChoice.js +18 -0
  227. package/module/es5/Random/randomFloat.d.ts +9 -0
  228. package/module/es5/Random/randomFloat.js +17 -0
  229. package/module/es5/Random/randomInt.d.ts +9 -0
  230. package/module/es5/Random/randomInt.js +19 -0
  231. package/module/es5/Random/randomUuid.d.ts +9 -0
  232. package/module/es5/Random/randomUuid.js +38 -0
  233. package/module/es5/Random/seededRandom.d.ts +11 -0
  234. package/module/es5/Random/seededRandom.js +46 -0
  235. package/module/es5/Random/weightedChoice.d.ts +15 -0
  236. package/module/es5/Random/weightedChoice.js +50 -0
  237. package/module/es5/String/capitalize.d.ts +12 -0
  238. package/module/es5/String/capitalize.js +35 -0
  239. package/module/es5/String/capitalizeWord.d.ts +1 -0
  240. package/module/es5/String/capitalizeWord.js +9 -0
  241. package/module/es5/String/dedent.d.ts +19 -0
  242. package/module/es5/String/dedent.js +82 -0
  243. package/module/es5/String/index.d.ts +10 -0
  244. package/module/es5/String/index.js +110 -0
  245. package/module/es5/String/mask.d.ts +20 -0
  246. package/module/es5/String/mask.js +39 -0
  247. package/module/es5/String/pascalCase.d.ts +9 -0
  248. package/module/es5/String/pascalCase.js +21 -0
  249. package/module/es5/String/snakeCase.d.ts +9 -0
  250. package/module/es5/String/snakeCase.js +20 -0
  251. package/module/es5/String/titleCase.d.ts +9 -0
  252. package/module/es5/String/titleCase.js +21 -0
  253. package/module/es5/String/uncapitalize.d.ts +10 -0
  254. package/module/es5/String/uncapitalize.js +33 -0
  255. package/module/es5/String/wordCount.d.ts +10 -0
  256. package/module/es5/String/wordCount.js +19 -0
  257. package/module/es5/String/words.d.ts +12 -0
  258. package/module/es5/String/words.js +25 -0
  259. package/module/es5/Tool/createPipeline.d.ts +1 -1
  260. package/module/es5/Tool/createPipeline.js +7 -10
  261. package/module/es5/URL/buildUrl.d.ts +10 -0
  262. package/module/es5/URL/buildUrl.js +10 -4
  263. package/module/es5/URL/parseQueryString.d.ts +6 -0
  264. package/module/es5/URL/parseQueryString.js +6 -4
  265. package/module/es5/Validate/object/core.js +0 -1
  266. package/module/es5/index.d.ts +1 -0
  267. package/module/es5/index.js +20 -9
  268. package/module/index.d.ts +1 -0
  269. package/module/index.js +1 -0
  270. package/module/index.js.map +1 -1
  271. package/package.json +30 -25
  272. package/module/Error/retry.d.ts +0 -37
  273. package/module/Error/retry.js +0 -47
  274. package/module/Error/retry.js.map +0 -1
  275. 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>"); // "&lt;script&gt;alert(&#39;XSS&#39;)&lt;/script&gt;"` |
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,CAAmB,CAAC;IAC9D,CAAC;IAED,OAAO,MAA8B,CAAC;AACxC,CAAC,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,IAAS,CAAC,CAAC;QAChC,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"}
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"}
@@ -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";
@@ -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"}