@ezez/utils 1.0.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 (391) hide show
  1. package/.prettierignore +3 -0
  2. package/.prettierrc.json +1 -0
  3. package/CHANGELOG.md +244 -0
  4. package/LICENSE +21 -0
  5. package/README.md +79 -0
  6. package/babel.config.cjs +6 -0
  7. package/dist/cap.d.ts +3 -0
  8. package/dist/cap.d.ts.map +1 -0
  9. package/dist/cap.js +14 -0
  10. package/dist/cap.js.map +1 -0
  11. package/dist/capitalize.d.ts +3 -0
  12. package/dist/capitalize.d.ts.map +1 -0
  13. package/dist/capitalize.js +9 -0
  14. package/dist/capitalize.js.map +1 -0
  15. package/dist/coalesce.d.ts +3 -0
  16. package/dist/coalesce.d.ts.map +1 -0
  17. package/dist/coalesce.js +14 -0
  18. package/dist/coalesce.js.map +1 -0
  19. package/dist/ensureArray.d.ts +3 -0
  20. package/dist/ensureArray.d.ts.map +1 -0
  21. package/dist/ensureArray.js +11 -0
  22. package/dist/ensureArray.js.map +1 -0
  23. package/dist/ensureError.d.ts +3 -0
  24. package/dist/ensureError.d.ts.map +1 -0
  25. package/dist/ensureError.js +11 -0
  26. package/dist/ensureError.js.map +1 -0
  27. package/dist/get.d.ts +7 -0
  28. package/dist/get.d.ts.map +1 -0
  29. package/dist/get.js +19 -0
  30. package/dist/get.js.map +1 -0
  31. package/dist/getMultiple.d.ts +7 -0
  32. package/dist/getMultiple.d.ts.map +1 -0
  33. package/dist/getMultiple.js +18 -0
  34. package/dist/getMultiple.js.map +1 -0
  35. package/dist/index.d.ts +33 -0
  36. package/dist/index.d.ts.map +1 -0
  37. package/dist/index.js +49 -0
  38. package/dist/index.js.map +1 -0
  39. package/dist/insertSeparator.d.ts +3 -0
  40. package/dist/insertSeparator.d.ts.map +1 -0
  41. package/dist/insertSeparator.js +18 -0
  42. package/dist/insertSeparator.js.map +1 -0
  43. package/dist/isEmpty.d.ts +3 -0
  44. package/dist/isEmpty.d.ts.map +1 -0
  45. package/dist/isEmpty.js +26 -0
  46. package/dist/isEmpty.js.map +1 -0
  47. package/dist/isPlainObject.d.ts +3 -0
  48. package/dist/isPlainObject.d.ts.map +1 -0
  49. package/dist/isPlainObject.js +10 -0
  50. package/dist/isPlainObject.js.map +1 -0
  51. package/dist/last.d.ts +3 -0
  52. package/dist/last.d.ts.map +1 -0
  53. package/dist/last.js +6 -0
  54. package/dist/last.js.map +1 -0
  55. package/dist/mapAsync.d.ts +3 -0
  56. package/dist/mapAsync.d.ts.map +1 -0
  57. package/dist/mapAsync.js +22 -0
  58. package/dist/mapAsync.js.map +1 -0
  59. package/dist/mapValues.d.ts +6 -0
  60. package/dist/mapValues.d.ts.map +1 -0
  61. package/dist/mapValues.js +18 -0
  62. package/dist/mapValues.js.map +1 -0
  63. package/dist/match.d.ts +8 -0
  64. package/dist/match.d.ts.map +1 -0
  65. package/dist/match.js +20 -0
  66. package/dist/match.js.map +1 -0
  67. package/dist/merge.d.ts +15 -0
  68. package/dist/merge.d.ts.map +1 -0
  69. package/dist/merge.js +28 -0
  70. package/dist/merge.js.map +1 -0
  71. package/dist/mostFrequent.d.ts +3 -0
  72. package/dist/mostFrequent.d.ts.map +1 -0
  73. package/dist/mostFrequent.js +21 -0
  74. package/dist/mostFrequent.js.map +1 -0
  75. package/dist/noop.d.ts +3 -0
  76. package/dist/noop.d.ts.map +1 -0
  77. package/dist/noop.js +6 -0
  78. package/dist/noop.js.map +1 -0
  79. package/dist/omit.d.ts +5 -0
  80. package/dist/omit.d.ts.map +1 -0
  81. package/dist/omit.js +21 -0
  82. package/dist/omit.js.map +1 -0
  83. package/dist/package.json +1 -0
  84. package/dist/pick.d.ts +5 -0
  85. package/dist/pick.d.ts.map +1 -0
  86. package/dist/pick.js +20 -0
  87. package/dist/pick.js.map +1 -0
  88. package/dist/pull.d.ts +3 -0
  89. package/dist/pull.d.ts.map +1 -0
  90. package/dist/pull.js +14 -0
  91. package/dist/pull.js.map +1 -0
  92. package/dist/remove.d.ts +3 -0
  93. package/dist/remove.d.ts.map +1 -0
  94. package/dist/remove.js +18 -0
  95. package/dist/remove.js.map +1 -0
  96. package/dist/rethrow.d.ts +3 -0
  97. package/dist/rethrow.d.ts.map +1 -0
  98. package/dist/rethrow.js +8 -0
  99. package/dist/rethrow.js.map +1 -0
  100. package/dist/scale.d.ts +3 -0
  101. package/dist/scale.d.ts.map +1 -0
  102. package/dist/scale.js +8 -0
  103. package/dist/scale.js.map +1 -0
  104. package/dist/seq.d.ts +8 -0
  105. package/dist/seq.d.ts.map +1 -0
  106. package/dist/seq.js +45 -0
  107. package/dist/seq.js.map +1 -0
  108. package/dist/set.d.ts +7 -0
  109. package/dist/set.d.ts.map +1 -0
  110. package/dist/set.js +25 -0
  111. package/dist/set.js.map +1 -0
  112. package/dist/setImmutable.d.ts +8 -0
  113. package/dist/setImmutable.d.ts.map +1 -0
  114. package/dist/setImmutable.js +59 -0
  115. package/dist/setImmutable.js.map +1 -0
  116. package/dist/sortBy.d.ts +3 -0
  117. package/dist/sortBy.d.ts.map +1 -0
  118. package/dist/sortBy.js +15 -0
  119. package/dist/sortBy.js.map +1 -0
  120. package/dist/throttle.d.ts +13 -0
  121. package/dist/throttle.d.ts.map +1 -0
  122. package/dist/throttle.js +82 -0
  123. package/dist/throttle.js.map +1 -0
  124. package/dist/truthy.d.ts +3 -0
  125. package/dist/truthy.d.ts.map +1 -0
  126. package/dist/truthy.js +8 -0
  127. package/dist/truthy.js.map +1 -0
  128. package/dist/wait.d.ts +3 -0
  129. package/dist/wait.d.ts.map +1 -0
  130. package/dist/wait.js +10 -0
  131. package/dist/wait.js.map +1 -0
  132. package/dist/waitFor.d.ts +3 -0
  133. package/dist/waitFor.d.ts.map +1 -0
  134. package/dist/waitFor.js +34 -0
  135. package/dist/waitFor.js.map +1 -0
  136. package/dist/waitSync.d.ts +3 -0
  137. package/dist/waitSync.d.ts.map +1 -0
  138. package/dist/waitSync.js +9 -0
  139. package/dist/waitSync.js.map +1 -0
  140. package/docs/.nojekyll +1 -0
  141. package/docs/assets/highlight.css +78 -0
  142. package/docs/assets/main.js +58 -0
  143. package/docs/assets/pages.css +14 -0
  144. package/docs/assets/search.js +1 -0
  145. package/docs/assets/style.css +1280 -0
  146. package/docs/functions/cap.html +116 -0
  147. package/docs/functions/capitalize.html +121 -0
  148. package/docs/functions/coalesce.html +127 -0
  149. package/docs/functions/ensureArray.html +114 -0
  150. package/docs/functions/ensureError.html +110 -0
  151. package/docs/functions/get.html +138 -0
  152. package/docs/functions/getMultiple.html +129 -0
  153. package/docs/functions/insertSeparator.html +123 -0
  154. package/docs/functions/isEmpty.html +139 -0
  155. package/docs/functions/isPlainObject.html +108 -0
  156. package/docs/functions/last.html +126 -0
  157. package/docs/functions/mapAsync.html +144 -0
  158. package/docs/functions/mapValues.html +130 -0
  159. package/docs/functions/match.html +122 -0
  160. package/docs/functions/merge.html +464 -0
  161. package/docs/functions/mostFrequent.html +111 -0
  162. package/docs/functions/noop.html +101 -0
  163. package/docs/functions/omit.html +129 -0
  164. package/docs/functions/pick.html +129 -0
  165. package/docs/functions/pull.html +113 -0
  166. package/docs/functions/remove.html +129 -0
  167. package/docs/functions/rethrow.html +106 -0
  168. package/docs/functions/scale.html +117 -0
  169. package/docs/functions/seq.html +128 -0
  170. package/docs/functions/seqEarlyBreak.html +126 -0
  171. package/docs/functions/set.html +138 -0
  172. package/docs/functions/setImmutable.html +137 -0
  173. package/docs/functions/sortBy.html +135 -0
  174. package/docs/functions/throttle.html +131 -0
  175. package/docs/functions/truthy.html +118 -0
  176. package/docs/functions/wait.html +109 -0
  177. package/docs/functions/waitFor.html +130 -0
  178. package/docs/functions/waitSync.html +109 -0
  179. package/docs/index.html +182 -0
  180. package/docs/interfaces/GetMultipleSource.html +106 -0
  181. package/docs/interfaces/GetSource.html +106 -0
  182. package/docs/interfaces/SetImmutableSource.html +106 -0
  183. package/docs/interfaces/SetSource.html +106 -0
  184. package/docs/interfaces/ThrottleOptions.html +80 -0
  185. package/docs/interfaces/ThrottledFunctionExtras.html +96 -0
  186. package/docs/modules.html +152 -0
  187. package/docs/pages/Introduction.html +94 -0
  188. package/docs/types/MapValuesFn.html +134 -0
  189. package/docs/types/MatchCallback.html +113 -0
  190. package/docs/types/SeqEarlyBreaker.html +114 -0
  191. package/docs/types/SeqFn.html +112 -0
  192. package/docs/types/SeqFunctions.html +105 -0
  193. package/docs/types/SetImmutablePath.html +99 -0
  194. package/docs/types/ThrottledFunction.html +113 -0
  195. package/docs/variables/mapValuesUNSET.html +101 -0
  196. package/docs/variables/mergeUNSET.html +103 -0
  197. package/esm/cap.d.ts +3 -0
  198. package/esm/cap.d.ts.map +1 -0
  199. package/esm/cap.js +11 -0
  200. package/esm/cap.js.map +1 -0
  201. package/esm/capitalize.d.ts +3 -0
  202. package/esm/capitalize.d.ts.map +1 -0
  203. package/esm/capitalize.js +6 -0
  204. package/esm/capitalize.js.map +1 -0
  205. package/esm/coalesce.d.ts +3 -0
  206. package/esm/coalesce.d.ts.map +1 -0
  207. package/esm/coalesce.js +11 -0
  208. package/esm/coalesce.js.map +1 -0
  209. package/esm/ensureArray.d.ts +3 -0
  210. package/esm/ensureArray.d.ts.map +1 -0
  211. package/esm/ensureArray.js +8 -0
  212. package/esm/ensureArray.js.map +1 -0
  213. package/esm/ensureError.d.ts +3 -0
  214. package/esm/ensureError.d.ts.map +1 -0
  215. package/esm/ensureError.js +8 -0
  216. package/esm/ensureError.js.map +1 -0
  217. package/esm/get.d.ts +7 -0
  218. package/esm/get.d.ts.map +1 -0
  219. package/esm/get.js +16 -0
  220. package/esm/get.js.map +1 -0
  221. package/esm/getMultiple.d.ts +7 -0
  222. package/esm/getMultiple.d.ts.map +1 -0
  223. package/esm/getMultiple.js +15 -0
  224. package/esm/getMultiple.js.map +1 -0
  225. package/esm/index.d.ts +33 -0
  226. package/esm/index.d.ts.map +1 -0
  227. package/esm/index.js +33 -0
  228. package/esm/index.js.map +1 -0
  229. package/esm/insertSeparator.d.ts +3 -0
  230. package/esm/insertSeparator.d.ts.map +1 -0
  231. package/esm/insertSeparator.js +15 -0
  232. package/esm/insertSeparator.js.map +1 -0
  233. package/esm/isEmpty.d.ts +3 -0
  234. package/esm/isEmpty.d.ts.map +1 -0
  235. package/esm/isEmpty.js +23 -0
  236. package/esm/isEmpty.js.map +1 -0
  237. package/esm/isPlainObject.d.ts +3 -0
  238. package/esm/isPlainObject.d.ts.map +1 -0
  239. package/esm/isPlainObject.js +7 -0
  240. package/esm/isPlainObject.js.map +1 -0
  241. package/esm/last.d.ts +3 -0
  242. package/esm/last.d.ts.map +1 -0
  243. package/esm/last.js +3 -0
  244. package/esm/last.js.map +1 -0
  245. package/esm/mapAsync.d.ts +3 -0
  246. package/esm/mapAsync.d.ts.map +1 -0
  247. package/esm/mapAsync.js +19 -0
  248. package/esm/mapAsync.js.map +1 -0
  249. package/esm/mapValues.d.ts +6 -0
  250. package/esm/mapValues.d.ts.map +1 -0
  251. package/esm/mapValues.js +14 -0
  252. package/esm/mapValues.js.map +1 -0
  253. package/esm/match.d.ts +8 -0
  254. package/esm/match.d.ts.map +1 -0
  255. package/esm/match.js +17 -0
  256. package/esm/match.js.map +1 -0
  257. package/esm/merge.d.ts +15 -0
  258. package/esm/merge.d.ts.map +1 -0
  259. package/esm/merge.js +24 -0
  260. package/esm/merge.js.map +1 -0
  261. package/esm/mostFrequent.d.ts +3 -0
  262. package/esm/mostFrequent.d.ts.map +1 -0
  263. package/esm/mostFrequent.js +18 -0
  264. package/esm/mostFrequent.js.map +1 -0
  265. package/esm/noop.d.ts +3 -0
  266. package/esm/noop.d.ts.map +1 -0
  267. package/esm/noop.js +3 -0
  268. package/esm/noop.js.map +1 -0
  269. package/esm/omit.d.ts +5 -0
  270. package/esm/omit.d.ts.map +1 -0
  271. package/esm/omit.js +20 -0
  272. package/esm/omit.js.map +1 -0
  273. package/esm/pick.d.ts +5 -0
  274. package/esm/pick.d.ts.map +1 -0
  275. package/esm/pick.js +17 -0
  276. package/esm/pick.js.map +1 -0
  277. package/esm/pull.d.ts +3 -0
  278. package/esm/pull.d.ts.map +1 -0
  279. package/esm/pull.js +11 -0
  280. package/esm/pull.js.map +1 -0
  281. package/esm/remove.d.ts +3 -0
  282. package/esm/remove.d.ts.map +1 -0
  283. package/esm/remove.js +15 -0
  284. package/esm/remove.js.map +1 -0
  285. package/esm/rethrow.d.ts +3 -0
  286. package/esm/rethrow.d.ts.map +1 -0
  287. package/esm/rethrow.js +5 -0
  288. package/esm/rethrow.js.map +1 -0
  289. package/esm/scale.d.ts +3 -0
  290. package/esm/scale.d.ts.map +1 -0
  291. package/esm/scale.js +5 -0
  292. package/esm/scale.js.map +1 -0
  293. package/esm/seq.d.ts +8 -0
  294. package/esm/seq.d.ts.map +1 -0
  295. package/esm/seq.js +41 -0
  296. package/esm/seq.js.map +1 -0
  297. package/esm/set.d.ts +7 -0
  298. package/esm/set.d.ts.map +1 -0
  299. package/esm/set.js +22 -0
  300. package/esm/set.js.map +1 -0
  301. package/esm/setImmutable.d.ts +8 -0
  302. package/esm/setImmutable.d.ts.map +1 -0
  303. package/esm/setImmutable.js +56 -0
  304. package/esm/setImmutable.js.map +1 -0
  305. package/esm/sortBy.d.ts +3 -0
  306. package/esm/sortBy.d.ts.map +1 -0
  307. package/esm/sortBy.js +12 -0
  308. package/esm/sortBy.js.map +1 -0
  309. package/esm/throttle.d.ts +13 -0
  310. package/esm/throttle.d.ts.map +1 -0
  311. package/esm/throttle.js +79 -0
  312. package/esm/throttle.js.map +1 -0
  313. package/esm/truthy.d.ts +3 -0
  314. package/esm/truthy.d.ts.map +1 -0
  315. package/esm/truthy.js +5 -0
  316. package/esm/truthy.js.map +1 -0
  317. package/esm/wait.d.ts +3 -0
  318. package/esm/wait.d.ts.map +1 -0
  319. package/esm/wait.js +7 -0
  320. package/esm/wait.js.map +1 -0
  321. package/esm/waitFor.d.ts +3 -0
  322. package/esm/waitFor.d.ts.map +1 -0
  323. package/esm/waitFor.js +31 -0
  324. package/esm/waitFor.js.map +1 -0
  325. package/esm/waitSync.d.ts +3 -0
  326. package/esm/waitSync.d.ts.map +1 -0
  327. package/esm/waitSync.js +6 -0
  328. package/esm/waitSync.js.map +1 -0
  329. package/package.json +75 -0
  330. package/src/cap.spec.ts +36 -0
  331. package/src/cap.ts +19 -0
  332. package/src/capitalize.spec.ts +18 -0
  333. package/src/capitalize.ts +16 -0
  334. package/src/coalesce.spec.ts +23 -0
  335. package/src/coalesce.ts +21 -0
  336. package/src/ensureArray.spec.ts +87 -0
  337. package/src/ensureArray.ts +13 -0
  338. package/src/ensureError.spec.ts +29 -0
  339. package/src/ensureError.ts +15 -0
  340. package/src/get.spec.ts +183 -0
  341. package/src/get.ts +53 -0
  342. package/src/getMultiple.spec.ts +25 -0
  343. package/src/getMultiple.ts +47 -0
  344. package/src/index.ts +33 -0
  345. package/src/insertSeparator.spec.ts +29 -0
  346. package/src/insertSeparator.ts +22 -0
  347. package/src/isEmpty.spec.ts +130 -0
  348. package/src/isEmpty.ts +50 -0
  349. package/src/isPlainObject.spec.ts +42 -0
  350. package/src/isPlainObject.ts +18 -0
  351. package/src/last.spec.ts +88 -0
  352. package/src/last.ts +12 -0
  353. package/src/mapAsync.spec.ts +39 -0
  354. package/src/mapAsync.ts +41 -0
  355. package/src/mapValues.spec.ts +178 -0
  356. package/src/mapValues.ts +57 -0
  357. package/src/match.spec.ts +11 -0
  358. package/src/match.ts +30 -0
  359. package/src/merge.spec.ts +69 -0
  360. package/src/merge.ts +58 -0
  361. package/src/mostFrequent.spec.ts +35 -0
  362. package/src/mostFrequent.ts +27 -0
  363. package/src/noop.ts +8 -0
  364. package/src/omit.spec.ts +181 -0
  365. package/src/omit.ts +43 -0
  366. package/src/pick.spec.ts +168 -0
  367. package/src/pick.ts +39 -0
  368. package/src/pull.spec.ts +54 -0
  369. package/src/pull.ts +18 -0
  370. package/src/remove.spec.ts +63 -0
  371. package/src/remove.ts +26 -0
  372. package/src/rethrow.ts +12 -0
  373. package/src/scale.ts +18 -0
  374. package/src/seq.spec.ts +157 -0
  375. package/src/seq.ts +104 -0
  376. package/src/set.spec.ts +348 -0
  377. package/src/set.ts +59 -0
  378. package/src/setImmutable.spec.ts +241 -0
  379. package/src/setImmutable.ts +104 -0
  380. package/src/sortBy.spec.ts +56 -0
  381. package/src/sortBy.ts +24 -0
  382. package/src/throttle.spec.ts +136 -0
  383. package/src/throttle.ts +153 -0
  384. package/src/truthy.spec.ts +21 -0
  385. package/src/truthy.ts +13 -0
  386. package/src/wait.spec.ts +21 -0
  387. package/src/wait.ts +14 -0
  388. package/src/waitFor.ts +47 -0
  389. package/src/waitSync.spec.ts +21 -0
  390. package/src/waitSync.ts +14 -0
  391. package/tutorials/Introduction.md +1 -0
@@ -0,0 +1,153 @@
1
+ interface Opts {
2
+ /**
3
+ * Should function be invoked immediately on first call to throttled function
4
+ */
5
+ leading?: boolean;
6
+ /**
7
+ * Should function be called after given time
8
+ */
9
+ trailing?: boolean;
10
+ }
11
+
12
+ interface Extras {
13
+ /**
14
+ * Stops any planned calls (and resets the `time` array progress)
15
+ */
16
+ cancel: () => void;
17
+ /**
18
+ * Immediately runs planned call.
19
+ */
20
+ flush: () => void;
21
+ }
22
+
23
+ const defaultOptions: Required<Opts> = {
24
+ leading: true,
25
+ trailing: true,
26
+ };
27
+
28
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
29
+ type CanReturnUndefined<F extends (...args: any[]) => any> = (...args: Parameters<F>) => ReturnType<F> | undefined;
30
+
31
+ /**
32
+ * Creates a throttled function that calls given function only once every given time. Throttled function takes the same
33
+ * arguments, returns "cached" value of last "real" call to the given function.
34
+ * Time (in ms) can be specified as an array - each "real" call to the function will then pick next value of that array
35
+ * as a time to wait for the next "real" call. This is useful for throttled notifications or auto-retries. Last value of
36
+ * the array will be used if no more values.
37
+ * Returned function also includes `cancel` property - call it to stop any planned calls (and reset the `time` array
38
+ * progress) and `flush` property - call it to immediately run planned call.
39
+ *
40
+ * You can provide options to specify if function should be invoked immediately on first call to throttled function
41
+ * (`leading` property) and if it should be called after given time (`trailing` property).
42
+ *
43
+ * If (this is default) both `leading` and `trailing` property are true then it's required to call throttled function at
44
+ * least twice.
45
+ * @param {function} fn - function to throttle
46
+ * @param {number | number[]} time - throttle time as number or array of numbers (min 1 element)
47
+ * @param {Opts} options
48
+ */
49
+ const throttle = <RT, F extends (...args: any[]) => RT>( // eslint-disable-line max-lines-per-function, @typescript-eslint/no-explicit-any, max-len
50
+ fn: F, time: number | [number, ...number[]] = 0, options?: Opts,
51
+ ): CanReturnUndefined<F> & Extras => {
52
+ const opts: Required<Opts> = {
53
+ leading: options?.leading ?? defaultOptions.leading,
54
+ trailing: options?.trailing ?? defaultOptions.trailing,
55
+ };
56
+
57
+ if (!opts.trailing && !opts.leading) {
58
+ throw new TypeError("Throttle with trailing & leading options `false` won't do anything.");
59
+ }
60
+ if (typeof time !== "number" && !time.length) {
61
+ throw new TypeError("`time` must be an array with at least one number.");
62
+ }
63
+
64
+ const finalTime = typeof time === "number" ? time : time[time.length - 1];
65
+
66
+ let lastRun = 0,
67
+ timeoutId: ReturnType<typeof setTimeout> | null = null,
68
+ lastResult: RT | undefined,
69
+ lastArgs: Parameters<F>,
70
+ lastTime = typeof time === "number" ? time : time[0],
71
+ leadingCalled = false;
72
+
73
+ const times = typeof time === "number" ? [time] : [...time];
74
+
75
+ // eslint-disable-next-line max-statements
76
+ const throttledFn = ((...args: Parameters<F>) => {
77
+ lastArgs = args;
78
+ if (timeoutId !== null) { // if timer goes on, then we shouldn't do anything
79
+ return lastResult;
80
+ }
81
+
82
+ if (!opts.trailing) { // we don't want a timer
83
+ if (Date.now() - lastRun < lastTime) { // it's not yet the time to call the func
84
+ return lastResult;
85
+ }
86
+ lastTime = times.shift() ?? finalTime;
87
+ lastRun = Date.now();
88
+ lastResult = fn(...args);
89
+ return lastResult;
90
+ }
91
+
92
+ // we want timers here!
93
+ const diffLastRun = Date.now() - lastRun;
94
+ if (opts.leading && (!leadingCalled || typeof time === "number") && diffLastRun >= (times[0] ?? finalTime)) {
95
+ // we want initial run and last run was long time ago
96
+ lastRun = Date.now();
97
+ lastResult = fn(...args);
98
+ leadingCalled = true;
99
+ return lastResult;
100
+ }
101
+
102
+ if (lastRun || !opts.leading) {
103
+ lastTime = times.shift() ?? finalTime;
104
+ }
105
+ timeoutId = setTimeout(() => {
106
+ timeoutId = null;
107
+ lastRun = Date.now();
108
+ lastResult = fn(...args);
109
+ }, lastRun ? (lastTime - diffLastRun + 1) : lastTime);
110
+
111
+ return lastResult;
112
+ }) as (CanReturnUndefined<F> & Extras);
113
+
114
+ throttledFn.cancel = () => {
115
+ timeoutId !== null && clearTimeout(timeoutId);
116
+ timeoutId = null;
117
+ lastRun = 0;
118
+ lastResult = undefined;
119
+
120
+ // we can't replace `times` with different instance - throttledFn already has one, so we clear the array
121
+ // and refill it
122
+ times.length = 0;
123
+ if (typeof time === "number") {
124
+ times.push(time);
125
+ }
126
+ else {
127
+ times.push(...time);
128
+ }
129
+ lastTime = typeof time === "number" ? time : time[0];
130
+ };
131
+ throttledFn.flush = () => {
132
+ if (timeoutId !== null) {
133
+ lastRun = Date.now();
134
+ lastResult = fn(...lastArgs);
135
+ clearTimeout(timeoutId);
136
+ timeoutId = null;
137
+ return throttledFn(...lastArgs);
138
+ }
139
+ return lastResult;
140
+ };
141
+
142
+ return throttledFn;
143
+ };
144
+
145
+ export {
146
+ throttle,
147
+ };
148
+
149
+ export type {
150
+ Extras as ThrottledFunctionExtras,
151
+ Opts as ThrottleOptions,
152
+ CanReturnUndefined as ThrottledFunction,
153
+ };
@@ -0,0 +1,21 @@
1
+ import { truthy } from "./truthy.js";
2
+
3
+ describe("truthy", function() {
4
+ it("returns true on truthy values", function() {
5
+ truthy(true).must.be.true();
6
+ truthy(() => {}).must.be.true();
7
+ truthy(1).must.be.true();
8
+ truthy("a").must.be.true();
9
+ truthy([]).must.be.true();
10
+ truthy({}).must.be.true();
11
+ });
12
+
13
+ it("returns false on falsy values", function() {
14
+ truthy(false).must.be.false();
15
+ truthy(null).must.be.false();
16
+ truthy(0).must.be.false();
17
+ truthy("").must.be.false();
18
+ truthy(NaN).must.be.false();
19
+ truthy(undefined).must.be.false();
20
+ });
21
+ });
package/src/truthy.ts ADDED
@@ -0,0 +1,13 @@
1
+ /**
2
+ * Returns true if value is truthy, useful with `Array.prototype.filter` and TypeScript (`[].filter(Boolean)` won't
3
+ * filter out falsy values from the types)
4
+ * @param {*} val - test value
5
+ * @returns {boolean} - is value truthy
6
+ */
7
+ const truthy = <T>(val: T | null | undefined | "" | false | 0): val is T => {
8
+ return Boolean(val);
9
+ };
10
+
11
+ export {
12
+ truthy,
13
+ };
@@ -0,0 +1,21 @@
1
+ import { wait } from "./wait.js";
2
+
3
+ describe("wait", () => {
4
+ it("returns a promise", () => {
5
+ wait(0).must.be.instanceof(Promise);
6
+ });
7
+
8
+ it("waits given time", async () => {
9
+ const start1 = Date.now();
10
+ await wait(5);
11
+ const end1 = Date.now();
12
+ (end1 - start1).must.be.gte(5);
13
+
14
+ const start2 = Date.now();
15
+ await wait(100);
16
+ const end2 = Date.now();
17
+ (end2 - start2).must.be.gte(100);
18
+ });
19
+
20
+ // @TODO does not block test
21
+ });
package/src/wait.ts ADDED
@@ -0,0 +1,14 @@
1
+ /**
2
+ * Returns a promise that resolves after given time
3
+ * @param {number} timeMs - time to wait
4
+ * @returns {Promise<void>}
5
+ */
6
+ const wait = (timeMs = 0) => {
7
+ return new Promise<void>((resolve) => {
8
+ setTimeout(() => { resolve(); }, timeMs);
9
+ });
10
+ };
11
+
12
+ export {
13
+ wait,
14
+ };
package/src/waitFor.ts ADDED
@@ -0,0 +1,47 @@
1
+ const DEFAULT_INTERVAL = 50;
2
+
3
+ type TTimeout = ReturnType<typeof setTimeout>;
4
+ type TInterval = ReturnType<typeof setInterval>;
5
+
6
+ /**
7
+ * Runs the callback function every specified interval and returns a Promise that resolves when the callback returns
8
+ * truthy value.
9
+ * Pro-tip: Value returned from the callback is returned via resolved Promise. If you want to pass back falsy value then
10
+ * wrap your potential return value with an object or array.
11
+ * @param {function} fn - callback function
12
+ * @param {number} interval - interval between checks
13
+ * @param {number} timeout - optional timeout
14
+ */
15
+ const waitFor = <T>(fn: () => T, interval = DEFAULT_INTERVAL, timeout = Infinity) => {
16
+ return new Promise<T>((resolve, reject) => {
17
+ let intervalTimer: TInterval, failTimer: TTimeout;
18
+
19
+ if (isFinite(timeout)) {
20
+ failTimer = setTimeout(() => {
21
+ reject(new Error("[waitFor] Timeout"));
22
+ clearInterval(intervalTimer);
23
+ }, timeout);
24
+ }
25
+
26
+ intervalTimer = setInterval(() => {
27
+ try {
28
+ const result = fn();
29
+ if (result) {
30
+ clearTimeout(failTimer);
31
+ clearInterval(intervalTimer);
32
+ resolve(result);
33
+ }
34
+ }
35
+ catch (error: unknown) {
36
+ clearTimeout(failTimer);
37
+ clearInterval(intervalTimer);
38
+
39
+ const e: Error & { details?: unknown } = new Error("[waitFor] check function threw an error");
40
+ e.details = { error };
41
+ reject(e);
42
+ }
43
+ }, interval);
44
+ });
45
+ };
46
+
47
+ export { waitFor };
@@ -0,0 +1,21 @@
1
+ import { waitSync } from "./waitSync.js";
2
+
3
+ describe("wait", () => {
4
+ it("doesn't return value", () => {
5
+ must(waitSync(0)).be.equal(undefined); // eslint-disable-line @typescript-eslint/no-confusing-void-expression
6
+ });
7
+
8
+ it("waits given time", () => {
9
+ const start1 = Date.now();
10
+ waitSync(5);
11
+ const end1 = Date.now();
12
+ (end1 - start1).must.be.gte(5);
13
+
14
+ const start2 = Date.now();
15
+ waitSync(100);
16
+ const end2 = Date.now();
17
+ (end2 - start2).must.be.gte(100);
18
+ });
19
+
20
+ // @TODO test that nothing else could happen during wait
21
+ });
@@ -0,0 +1,14 @@
1
+ /**
2
+ * Synchronously wait for a given time, blocking the event loop [!]
3
+ * @param {number} timeMs - time to wait
4
+ * @returns {Promise<void>}
5
+ */
6
+ const waitSync = (timeMs = 0) => {
7
+ const s = Date.now();
8
+ // eslint-disable-next-line no-empty
9
+ while (Date.now() - s < timeMs) {}
10
+ };
11
+
12
+ export {
13
+ waitSync,
14
+ };
@@ -0,0 +1 @@
1
+ WIP.