@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,15 @@
1
+ /**
2
+ * Ensures given value is an instance of Error.
3
+ * @param {*} e - value to check
4
+ * @returns Error - original error or new Error instance
5
+ */
6
+ const ensureError = (e: unknown) => {
7
+ if (e instanceof Error) {
8
+ return e;
9
+ }
10
+ return new Error("Expected error instance, got something else: " + String(e));
11
+ };
12
+
13
+ export {
14
+ ensureError,
15
+ };
@@ -0,0 +1,183 @@
1
+ import { get as _get } from "lodash";
2
+
3
+ import { get } from "./get.js";
4
+
5
+ const otherObject = { a: 5 };
6
+ const testObject = {
7
+ "product": {
8
+ name: "abc",
9
+ price: 123,
10
+ value: undefined,
11
+ empty: null,
12
+ notANumber: NaN,
13
+ object: otherObject,
14
+ },
15
+ "product[price]": 400,
16
+ "name": "string",
17
+ };
18
+
19
+ const Test = function() {};
20
+ Test.prototype.nonOwn = 1;
21
+
22
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
23
+ const testInstance = new Test();
24
+ testInstance.own = 1;
25
+ Object.defineProperty(testInstance, "nonEnum", {
26
+ enumerable: false,
27
+ value: 15,
28
+ });
29
+
30
+ describe("get", () => {
31
+ it("returns shallow property of an object, behaves like lodash", () => {
32
+ const value = get(testObject, "name");
33
+ value.must.equal("string");
34
+
35
+ const _value = _get(testObject, "name");
36
+ value.must.equal(_value);
37
+ });
38
+
39
+ it("returns deep property of an object using array, behaves like lodash", () => {
40
+ const value = get(testObject, ["product", "name"]);
41
+ value.must.equal("abc");
42
+
43
+ const _value = _get(testObject, ["product", "name"]);
44
+ value.must.equal(_value);
45
+ });
46
+
47
+ it("returns deep property of an object using dot-string, behaves like lodash", () => {
48
+ const value = get(testObject, "product.name");
49
+ value.must.equal("abc");
50
+
51
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
52
+ const _value = _get(testObject, "product.name");
53
+ value.must.equal(_value);
54
+ });
55
+
56
+ it("doesn't parse string as js code, behaves NOT like lodash", () => {
57
+ // Lodash intention-guessing example, inconsistency detected
58
+ const name = get(testObject, "product[name]");
59
+ (name === undefined).must.be.true();
60
+
61
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
62
+ const _name = _get(testObject, "product[name]"); // deep value
63
+ _name.must.equal("abc");
64
+
65
+ const price = get(testObject, "product[price]");
66
+ price.must.be.equal(400);
67
+
68
+ const _price = _get(testObject, "product[price]"); // shallow value
69
+ _price.must.equal(400);
70
+ });
71
+
72
+ it("returns undefined when value is not found and default isn't provided, behaves like lodash", () => {
73
+ const value = get(testObject, "product.something");
74
+ (value === undefined).must.be.true();
75
+
76
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
77
+ const _value = _get(testObject, "product.something");
78
+ (_value === undefined).must.be.true();
79
+ });
80
+
81
+ it("returns default value when property is missing, behaves like lodash", () => {
82
+ const value = get(testObject, "product.something", 3);
83
+ value.must.equal(3);
84
+
85
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
86
+ const _value = _get(testObject, "product.something", 3);
87
+ _value.must.equal(3);
88
+ });
89
+
90
+ it("returns undefined when found value is explicitly undefined, behaves NOT like lodash", () => {
91
+ const value = get(testObject, "product.value", 3);
92
+ (value === undefined).must.be.true();
93
+
94
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
95
+ const _value = _get(testObject, "product.value", 3);
96
+ _value.must.equal(3);
97
+ });
98
+
99
+ it("returns null when found value is explicitly null, behaves like lodash", () => {
100
+ const value = get(testObject, "product.empty", 3);
101
+ (value === null).must.be.true();
102
+
103
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
104
+ const _value = _get(testObject, "product.empty", 3);
105
+ (_value === null).must.be.true();
106
+ });
107
+
108
+ it("returns NaN when found value is NaN, behaves like lodash", () => {
109
+ const value = get(testObject, "product.notANumber", 3);
110
+ value.must.be.nan();
111
+
112
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
113
+ const _value = _get(testObject, "product.notANumber", 3);
114
+ _value.must.be.nan();
115
+ });
116
+
117
+ it("returns objects, behaves like lodash", () => {
118
+ const value = get(testObject, "product.object");
119
+ value.must.equal(otherObject);
120
+
121
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
122
+ const _value = _get(testObject, "product.object");
123
+ _value.must.equal(otherObject);
124
+ });
125
+
126
+ it("works on nulls, behaves like lodash", () => {
127
+ const value = get(null, "product.object", 3);
128
+ value.must.equal(3);
129
+
130
+ const _value = _get(null, "product.object", 3);
131
+ _value.must.equal(3);
132
+ });
133
+
134
+ it("works on undefined, behaves like lodash", () => {
135
+ const value = get(undefined, "product.object", 3);
136
+ value.must.equal(3);
137
+
138
+ const _value = _get(undefined, "product.object", 3);
139
+ _value.must.equal(3);
140
+ });
141
+
142
+ it("works on NaN, behaves like lodash", () => {
143
+ const value = get(NaN, "product.object", 3);
144
+ value.must.equal(3);
145
+
146
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
147
+ const _value = _get(NaN, "product.object", 3);
148
+ _value.must.equal(3);
149
+ });
150
+
151
+ it("returns inherited properties value, behaves like lodash", () => {
152
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-argument
153
+ const value = get(testInstance, "nonOwn", 3);
154
+ value.must.equal(1);
155
+
156
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
157
+ const _value = _get(testInstance, "nonOwn", 3);
158
+ _value.must.equal(1);
159
+ });
160
+
161
+ it("returns non-enumerable properties value, behaves like lodash", () => {
162
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-argument
163
+ const value = get(testInstance, "nonEnum", 3);
164
+ value.must.equal(15);
165
+
166
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
167
+ const _value = _get(testInstance, "nonEnum", 3);
168
+ _value.must.equal(15);
169
+ });
170
+
171
+ it("doesn't parse mixed array/dot-strings property selectors, behaves like lodash", () => {
172
+ const value = get(testObject, ["product", "object.a"], "def");
173
+ const value2 = get(testObject, "product.object.a", "def");
174
+ value.must.equal("def");
175
+ value2.must.equal(5);
176
+
177
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
178
+ const _value = _get(testObject, ["product", "object.a"], "def");
179
+ _value.must.equal("def");
180
+ });
181
+
182
+ // @todo test Maps, Sets etc
183
+ });
package/src/get.ts ADDED
@@ -0,0 +1,53 @@
1
+ /**
2
+ * Source object to search in.
3
+ *
4
+ * @see {@link get}.
5
+ */
6
+ interface Source { [key: string]: unknown }
7
+
8
+ /**
9
+ * Returns the value at given path of given object. If path is not found then default value is returned. No exceptions
10
+ * are thrown when undefined/null value gets in the way.
11
+ *
12
+ * This is still too dynamic in nature to get full TypeScript support. Properties are not typed, return type is unknown.
13
+ * If your data access is statically known there is no need to use this function, just use `object.property` syntax with
14
+ * optional chaining.
15
+ *
16
+ * @param {Object} source - source object to search in
17
+ * @param {string|Array<string>} property - path to the expected value written as dot-separated property names or array
18
+ * with property names. Use Array when your keys includes dots. Keys are treated literally, no parsing is done on keys.
19
+ * @param {*} [defaultValue] - value to return if path is not found. If path is found, but the value is undefined -
20
+ * default value will NOT be used, use `get(...) || default` instead
21
+ * @example get(object, "deep.property") // equals to safe `object.deep.property`
22
+ * @example get(object, ["deep", "property"]) // same as above
23
+ * @example get(object, "deep[0].property")
24
+ * // equals to:
25
+ * object["deep[0]"].property
26
+ * // not:
27
+ * object.deep[0].property
28
+ * @example get(object, "very.deep.property", 5)
29
+ * // if object.very.deep has also `property` property then it value will be returned, even if undefined
30
+ * // else `5` will be returned
31
+ * @returns {*} - found value or default value
32
+ */
33
+ const get = (source: Source, property: string | string[], defaultValue: unknown = undefined): unknown => {
34
+ const properties = typeof property === "string" ? property.split(".") : [...property];
35
+
36
+ let result: unknown = source;
37
+ while (properties.length) {
38
+ const current = properties.shift()!;
39
+ if (result && typeof result === "object" && current in result) {
40
+ result = (result as Source)[current];
41
+ }
42
+ else {
43
+ return defaultValue;
44
+ }
45
+ }
46
+ return result;
47
+ };
48
+
49
+ export { get };
50
+
51
+ export type {
52
+ Source as GetSource,
53
+ };
@@ -0,0 +1,25 @@
1
+ import { getMultiple } from "./getMultiple.js";
2
+
3
+ const testObject = {
4
+ product: {
5
+ title: "abc",
6
+ nothing: undefined,
7
+ },
8
+ };
9
+
10
+ describe("getMultiple", () => {
11
+ it("returns first property that exist, with mixed selectors", () => {
12
+ const value = getMultiple(testObject, 123, ["product", "xxx"], "product.title");
13
+ value.must.equal("abc");
14
+ });
15
+
16
+ it("returns first property that exist even if value is undefined", () => {
17
+ const value = getMultiple(testObject, 123, ["product", "nothing"], "product.title");
18
+ (value === undefined).must.be.true();
19
+ });
20
+
21
+ it("returns default value when nothing exists", () => {
22
+ const value = getMultiple(testObject, 123, ["product", "name"], "product.price");
23
+ value.must.equal(123);
24
+ });
25
+ });
@@ -0,0 +1,47 @@
1
+ import { get } from "./get.js";
2
+
3
+ /**
4
+ * Source object to search in.
5
+ *
6
+ * @see {@link getMultiple}.
7
+ */
8
+ interface Source { [key: string]: unknown }
9
+
10
+ const DEFAULT = {};
11
+
12
+ /**
13
+ * Returns first found value at given list of paths of given object. Will return and stop at undefined if found! If
14
+ * nothing is found then default value (required to pass) will be returned.
15
+ *
16
+ * This is still too dynamic in nature to get full TypeScript support. Properties are not typed, return type is unknown.
17
+ * If your data access is statically known there is no need to use this function, just use `object.property` syntax with
18
+ * optional chaining.
19
+ *
20
+ * @param {Object} source - source object to search in
21
+ * @param {*} defaultValue - default value to return if nothing is found
22
+ * @param {...string|Array.<string>} paths - paths defined as dot-separated properties names or array of properties name
23
+ * @see {@link get} - for base usage example with single path only
24
+ * @example getMultiple(obj, 5, "details.error.message", ["error", "message"], "errorMessage")
25
+ * // will look for obj.details.error.message - if path does not exist
26
+ * // will look for obj.error.message - if not defined
27
+ * // will look for obj.errorMessage - if not defined
28
+ * // will return 5
29
+ * @returns {*} - found value or default value
30
+ */
31
+ const getMultiple = (source: Source, defaultValue: unknown, ...paths: (string | string[])[]): unknown => {
32
+ const length = paths.length;
33
+ for (let i = 0; i < length; i++) {
34
+ const properties = paths[i];
35
+ const result = get(source, properties, DEFAULT);
36
+ if (result !== DEFAULT) {
37
+ return result;
38
+ }
39
+ }
40
+ return defaultValue;
41
+ };
42
+
43
+ export { getMultiple };
44
+
45
+ export type {
46
+ Source as GetMultipleSource,
47
+ };
package/src/index.ts ADDED
@@ -0,0 +1,33 @@
1
+ /* eslint-disable import/max-dependencies */
2
+ export * from "./cap.js";
3
+ export * from "./capitalize.js";
4
+ export * from "./coalesce.js";
5
+ export * from "./ensureArray.js";
6
+ export * from "./ensureError.js";
7
+ export * from "./get.js";
8
+ export * from "./getMultiple.js";
9
+ export * from "./insertSeparator.js";
10
+ export * from "./isEmpty.js";
11
+ export * from "./isPlainObject.js";
12
+ export * from "./last.js";
13
+ export * from "./mapAsync.js";
14
+ export * from "./mapValues.js";
15
+ export * from "./match.js";
16
+ export * from "./merge.js";
17
+ export * from "./mostFrequent.js";
18
+ export * from "./noop.js";
19
+ export * from "./omit.js";
20
+ export * from "./pick.js";
21
+ export * from "./pull.js";
22
+ export * from "./remove.js";
23
+ export * from "./rethrow.js";
24
+ export * from "./scale.js";
25
+ export * from "./seq.js";
26
+ export * from "./set.js";
27
+ export * from "./setImmutable.js";
28
+ export * from "./sortBy.js";
29
+ export * from "./throttle.js";
30
+ export * from "./truthy.js";
31
+ export * from "./wait.js";
32
+ export * from "./waitFor.js";
33
+ export * from "./waitSync.js";
@@ -0,0 +1,29 @@
1
+ import { insertSeparator } from "./insertSeparator.js";
2
+
3
+ describe("insertSeparator", () => {
4
+ it("inserts value on array with data", () => {
5
+ const source = [5, 6, 7];
6
+ insertSeparator(source, "a").must.eql([5, "a", 6, "a", 7]);
7
+ insertSeparator(source, "a").must.not.equal(source);
8
+ });
9
+
10
+ it("do nothing on array without data (returns source array)", () => {
11
+ const source = [];
12
+ insertSeparator(source, "a").must.equal(source);
13
+ source.length.must.equal(0);
14
+ });
15
+
16
+ it("do nothing on array with single item (returns source array)", () => {
17
+ const source = [1];
18
+ insertSeparator(source, "a").must.equal(source);
19
+ source.length.must.equal(1);
20
+ });
21
+
22
+ it("crashes on non-array", () => {
23
+ (() => insertSeparator(null, "a")).must.throw();
24
+ (() => insertSeparator(undefined, "a")).must.throw();
25
+ (() => insertSeparator({}, "a")).must.throw();
26
+ (() => insertSeparator(4, "a")).must.throw();
27
+ (() => insertSeparator("4", "a")).must.throw();
28
+ });
29
+ });
@@ -0,0 +1,22 @@
1
+ /**
2
+ * Inserts given separator between all array elements
3
+ *
4
+ * @param {Array} source - source array to put new elements between
5
+ * @param {*} separator - separator to inset
6
+ * @returns {Array} - new array with separator items added or same array if there isn't enough items to put separator
7
+ */
8
+ const insertSeparator = <T, S>(source: T[], separator: S): (T | S)[] => {
9
+ if (!Array.isArray(source)) {
10
+ throw new TypeError("Source must be an array");
11
+ }
12
+ if (source.length <= 1) {
13
+ return source;
14
+ }
15
+ const result: (T | S)[] = [...source];
16
+ for (let i = result.length - 1; i > 0; i--) {
17
+ result.splice(i, 0, separator);
18
+ }
19
+ return result;
20
+ };
21
+
22
+ export { insertSeparator };
@@ -0,0 +1,130 @@
1
+ import { isEmpty as _isEmpty } from "lodash";
2
+
3
+ import { isEmpty } from "./isEmpty.js";
4
+
5
+ const emptyMap = new Map();
6
+ const filledMap = new Map();
7
+ filledMap.set("x", "x");
8
+
9
+ const emptySet = new Set();
10
+ const filledSet = new Set();
11
+ filledSet.add("x");
12
+
13
+ const emptyString = "";
14
+ const filledString = "abc";
15
+
16
+ const emptyArray = [];
17
+ const holeyArray = [,]; // eslint-disable-line no-sparse-arrays
18
+ const filledArray = [1];
19
+
20
+ let emptyArgs;
21
+ (function() { emptyArgs = arguments; })(); // eslint-disable-line prefer-rest-params
22
+ let filledArgs;
23
+ (function() { filledArgs = arguments; })(1, 2, 3); // eslint-disable-line prefer-rest-params
24
+
25
+ const emptyBuffer = Buffer.from("");
26
+ const filledBuffer = Buffer.from("abc");
27
+
28
+ const emptyObject = {};
29
+ const filledObject = { a: 5 };
30
+ const nonEnumObject = {};
31
+ Object.defineProperty(nonEnumObject, "prop", { enumerable: false, value: 666 });
32
+
33
+ const SomeElement = function() {};
34
+ SomeElement.prototype.prop = 5;
35
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
36
+ const inheritedObject = new SomeElement();
37
+
38
+ const emptyTypedArray = new Uint8Array();
39
+ const filledTypedArray = new Uint8Array(1);
40
+ filledTypedArray[0] = 69;
41
+
42
+ describe("isEmpty", () => {
43
+ it("works with Maps, behaves like lodash", () => {
44
+ isEmpty(emptyMap).must.be.true();
45
+ _isEmpty(emptyMap).must.be.true();
46
+
47
+ isEmpty(filledMap).must.be.false();
48
+ _isEmpty(filledMap).must.be.false();
49
+ });
50
+
51
+ it("works with Sets, behaves like lodash", () => {
52
+ isEmpty(emptySet).must.be.true();
53
+ _isEmpty(emptySet).must.be.true();
54
+
55
+ isEmpty(filledSet).must.be.false();
56
+ _isEmpty(filledSet).must.be.false();
57
+ });
58
+
59
+ it("works with strings, behaves like lodash", () => {
60
+ isEmpty(emptyString).must.be.true();
61
+ _isEmpty(emptyString).must.be.true();
62
+
63
+ isEmpty(filledString).must.be.false();
64
+ _isEmpty(filledString).must.be.false();
65
+ });
66
+
67
+ it("works with arrays, behaves like lodash except for holey arrays", () => {
68
+ isEmpty(emptyArray).must.be.true();
69
+ _isEmpty(emptyArray).must.be.true();
70
+
71
+ isEmpty(filledArray).must.be.false();
72
+ _isEmpty(filledArray).must.be.false();
73
+
74
+ isEmpty(holeyArray).must.be.true();
75
+ _isEmpty(holeyArray).must.be.false();
76
+ });
77
+
78
+ it("works with arguments, behaves like lodash", () => {
79
+ isEmpty(emptyArgs).must.be.true();
80
+ _isEmpty(emptyArgs).must.be.true();
81
+
82
+ isEmpty(filledArgs).must.be.false();
83
+ _isEmpty(filledArgs).must.be.false();
84
+ });
85
+
86
+ it("works with Buffers, behaves like lodash", () => {
87
+ isEmpty(emptyBuffer).must.be.true();
88
+ _isEmpty(emptyBuffer).must.be.true();
89
+
90
+ isEmpty(filledBuffer).must.be.false();
91
+ _isEmpty(filledBuffer).must.be.false();
92
+ });
93
+
94
+ it("works with objects, behaves like lodash", () => {
95
+ isEmpty(emptyObject).must.be.true();
96
+ _isEmpty(emptyObject).must.be.true();
97
+
98
+ isEmpty(filledObject).must.be.false();
99
+ _isEmpty({ a: 555, b: 666 }).must.be.false();
100
+
101
+ isEmpty(nonEnumObject).must.be.true();
102
+ _isEmpty(nonEnumObject).must.be.true();
103
+
104
+ isEmpty(inheritedObject).must.be.true();
105
+ _isEmpty(inheritedObject).must.be.true();
106
+ });
107
+
108
+ it("works with typed arrays, behaves like lodash", () => {
109
+ isEmpty(emptyTypedArray).must.be.true();
110
+ _isEmpty(emptyTypedArray).must.be.true();
111
+
112
+ isEmpty(filledTypedArray).must.be.false();
113
+ _isEmpty(filledTypedArray).must.be.false();
114
+ });
115
+
116
+ it("returns true for nil values", function() {
117
+ isEmpty(null).must.be.true();
118
+ isEmpty(undefined).must.be.true();
119
+ });
120
+
121
+ it("throws on primitives", () => {
122
+ (() => isEmpty(0)).must.throw();
123
+ (() => isEmpty(100)).must.throw();
124
+ (() => isEmpty(true)).must.throw();
125
+ (() => isEmpty(false)).must.throw();
126
+ (() => isEmpty(Infinity)).must.throw();
127
+ (() => isEmpty(NaN)).must.throw();
128
+ (() => isEmpty(() => {})).must.throw();
129
+ });
130
+ });
package/src/isEmpty.ts ADDED
@@ -0,0 +1,50 @@
1
+ interface ObjectWithLength {
2
+ length: number;
3
+ }
4
+
5
+ interface ObjectWithSize {
6
+ size: number;
7
+ }
8
+
9
+ /**
10
+ * Returns true if passed argument seems to be empty.
11
+ * Nil values are empty.
12
+ * Strings are considered empty when length is 0.
13
+ * Other primitives will throw an error.
14
+ * Objects are considered empty when doesn't have any enumerable & own property.
15
+ * Arrays and array-like objects are considered empty when length value is 0.
16
+ * Map, Set and -like objects are considered empty when size value is 0.
17
+ *
18
+ * @param {*} obj - source value
19
+ * @example isEmpty({}) // true
20
+ * @example isEmpty(100) // throws
21
+ * @example isEmpty([]) // true
22
+ * @example isEmpty([1]) // false
23
+ * @example isEmpty({ length: 5 }) // false
24
+ * @example isEmpty({ length: 0 }) // true
25
+ * @example isEmpty({ size: 0 }) // true
26
+ * @returns {boolean} - is value considered empty
27
+ */
28
+ const isEmpty = (obj: unknown) => {
29
+ if (typeof obj === "string") {
30
+ return !obj.length;
31
+ }
32
+ if (obj == null) {
33
+ return true;
34
+ }
35
+ if (typeof obj !== "object") {
36
+ throw new Error("isEmpty cannot be used on primitives");
37
+ }
38
+ if (Array.isArray(obj)) {
39
+ return !Object.keys(obj).length;
40
+ }
41
+ if ("length" in obj) {
42
+ return !(obj as ObjectWithLength).length;
43
+ }
44
+ if ("size" in obj) {
45
+ return !(obj as ObjectWithSize).size;
46
+ }
47
+ return !Object.keys(obj).length;
48
+ };
49
+
50
+ export { isEmpty };
@@ -0,0 +1,42 @@
1
+ import { isPlainObject } from "./isPlainObject.js";
2
+
3
+ describe("isPlainObject", function() {
4
+ it("rejects anything non object-like", function() {
5
+ isPlainObject(null).must.be.false();
6
+ isPlainObject(5).must.be.false();
7
+ isPlainObject(() => ({})).must.be.false();
8
+ isPlainObject(false).must.be.false();
9
+ isPlainObject(new URL("https://ezez.dev")).must.be.false();
10
+ isPlainObject([]).must.be.false();
11
+
12
+ // eslint-disable-next-line @typescript-eslint/no-extraneous-class
13
+ class X {}
14
+ isPlainObject(X).must.be.false();
15
+ });
16
+
17
+ it("accepts plain objects", function() {
18
+ isPlainObject({}).must.be.true();
19
+ isPlainObject({ some: "data" }).must.be.true();
20
+ isPlainObject({ some: function fn() {} }).must.be.true();
21
+ isPlainObject(Object.create(null)).must.be.true();
22
+ isPlainObject({ constructor: () => null }).must.be.true();
23
+ });
24
+
25
+ it("accepts plain objects", function() {
26
+ isPlainObject({}).must.be.true();
27
+ isPlainObject({ some: "data" }).must.be.true();
28
+ isPlainObject({ some: function fn() {} }).must.be.true();
29
+ isPlainObject(Object.create(null)).must.be.true();
30
+ });
31
+
32
+ it("shouldn't accept any instances", function() {
33
+ // eslint-disable-next-line @typescript-eslint/no-extraneous-class
34
+ class X {}
35
+ isPlainObject(new X()).must.be.false();
36
+
37
+ // eslint-disable-next-line func-style
38
+ function MyObject() {}
39
+ // @ts-expect-error we don't care
40
+ isPlainObject(new MyObject()).must.be.false();
41
+ });
42
+ });
@@ -0,0 +1,18 @@
1
+ /**
2
+ * Checks if given value is a plain object. Plain object should be an object that's not an instance of anything.
3
+ * @param value - value to test
4
+ */
5
+ const isPlainObject = (value: unknown) => Boolean(
6
+ value
7
+ && typeof value === "object"
8
+ && (
9
+ value.constructor === Object // default constructor
10
+ || !("constructor" in value) // no constructor
11
+ || Object.getOwnPropertyNames(value).includes("constructor") // constructor is set by user
12
+ ),
13
+ );
14
+
15
+ export {
16
+ isPlainObject,
17
+ };
18
+