ts-data-forge 3.2.0 → 3.3.1

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 (426) hide show
  1. package/README.md +45 -21
  2. package/dist/array/impl/array-utils-creation.d.mts +116 -0
  3. package/dist/array/impl/array-utils-creation.d.mts.map +1 -0
  4. package/dist/array/impl/array-utils-creation.mjs +110 -0
  5. package/dist/array/impl/array-utils-creation.mjs.map +1 -0
  6. package/dist/array/impl/array-utils-element-access.d.mts +61 -0
  7. package/dist/array/impl/array-utils-element-access.d.mts.map +1 -0
  8. package/dist/array/impl/array-utils-element-access.mjs +66 -0
  9. package/dist/array/impl/array-utils-element-access.mjs.map +1 -0
  10. package/dist/array/impl/array-utils-iterators.d.mts +59 -0
  11. package/dist/array/impl/array-utils-iterators.d.mts.map +1 -0
  12. package/dist/array/impl/array-utils-iterators.mjs +104 -0
  13. package/dist/array/impl/array-utils-iterators.mjs.map +1 -0
  14. package/dist/array/impl/array-utils-modification.d.mts +154 -0
  15. package/dist/array/impl/array-utils-modification.d.mts.map +1 -0
  16. package/dist/array/impl/array-utils-modification.mjs +139 -0
  17. package/dist/array/impl/array-utils-modification.mjs.map +1 -0
  18. package/dist/array/impl/array-utils-reducing-value.d.mts +214 -0
  19. package/dist/array/impl/array-utils-reducing-value.d.mts.map +1 -0
  20. package/dist/array/impl/array-utils-reducing-value.mjs +160 -0
  21. package/dist/array/impl/array-utils-reducing-value.mjs.map +1 -0
  22. package/dist/array/impl/array-utils-search.d.mts +179 -0
  23. package/dist/array/impl/array-utils-search.d.mts.map +1 -0
  24. package/dist/array/impl/array-utils-search.mjs +153 -0
  25. package/dist/array/impl/array-utils-search.mjs.map +1 -0
  26. package/dist/array/impl/array-utils-set-op.d.mts +100 -0
  27. package/dist/array/impl/array-utils-set-op.d.mts.map +1 -0
  28. package/dist/array/impl/array-utils-set-op.mjs +137 -0
  29. package/dist/array/impl/array-utils-set-op.mjs.map +1 -0
  30. package/dist/array/impl/array-utils-size.d.mts +24 -0
  31. package/dist/array/impl/array-utils-size.d.mts.map +1 -0
  32. package/dist/array/impl/array-utils-size.mjs +28 -0
  33. package/dist/array/impl/array-utils-size.mjs.map +1 -0
  34. package/dist/array/impl/array-utils-slice-clamped.d.mts +18 -0
  35. package/dist/array/impl/array-utils-slice-clamped.d.mts.map +1 -0
  36. package/dist/array/impl/array-utils-slice-clamped.mjs +49 -0
  37. package/dist/array/impl/array-utils-slice-clamped.mjs.map +1 -0
  38. package/dist/array/impl/array-utils-slicing.d.mts +120 -0
  39. package/dist/array/impl/array-utils-slicing.d.mts.map +1 -0
  40. package/dist/array/impl/array-utils-slicing.mjs +140 -0
  41. package/dist/array/impl/array-utils-slicing.mjs.map +1 -0
  42. package/dist/array/impl/array-utils-transformation.d.mts +348 -0
  43. package/dist/array/impl/array-utils-transformation.d.mts.map +1 -0
  44. package/dist/array/impl/array-utils-transformation.mjs +331 -0
  45. package/dist/array/impl/array-utils-transformation.mjs.map +1 -0
  46. package/dist/array/impl/array-utils-validation.d.mts +149 -0
  47. package/dist/array/impl/array-utils-validation.d.mts.map +1 -0
  48. package/dist/array/impl/array-utils-validation.mjs +166 -0
  49. package/dist/array/impl/array-utils-validation.mjs.map +1 -0
  50. package/dist/array/impl/index.d.mts +13 -0
  51. package/dist/array/impl/index.d.mts.map +1 -0
  52. package/dist/array/impl/index.mjs +13 -0
  53. package/dist/array/impl/index.mjs.map +1 -0
  54. package/dist/array/index.d.mts +1 -1
  55. package/dist/array/index.d.mts.map +1 -1
  56. package/dist/array/index.mjs +2 -1
  57. package/dist/array/index.mjs.map +1 -1
  58. package/dist/collections/imap-mapped.d.mts +83 -253
  59. package/dist/collections/imap-mapped.d.mts.map +1 -1
  60. package/dist/collections/imap-mapped.mjs +33 -164
  61. package/dist/collections/imap-mapped.mjs.map +1 -1
  62. package/dist/collections/imap.d.mts +436 -163
  63. package/dist/collections/imap.d.mts.map +1 -1
  64. package/dist/collections/imap.mjs +74 -94
  65. package/dist/collections/imap.mjs.map +1 -1
  66. package/dist/collections/iset-mapped.d.mts +828 -345
  67. package/dist/collections/iset-mapped.d.mts.map +1 -1
  68. package/dist/collections/iset-mapped.mjs +200 -242
  69. package/dist/collections/iset-mapped.mjs.map +1 -1
  70. package/dist/collections/iset.d.mts +397 -205
  71. package/dist/collections/iset.d.mts.map +1 -1
  72. package/dist/collections/iset.mjs +102 -184
  73. package/dist/collections/iset.mjs.map +1 -1
  74. package/dist/collections/queue.d.mts +155 -135
  75. package/dist/collections/queue.d.mts.map +1 -1
  76. package/dist/collections/queue.mjs +55 -156
  77. package/dist/collections/queue.mjs.map +1 -1
  78. package/dist/collections/stack.d.mts +154 -154
  79. package/dist/collections/stack.d.mts.map +1 -1
  80. package/dist/collections/stack.mjs +54 -203
  81. package/dist/collections/stack.mjs.map +1 -1
  82. package/dist/entry-point.d.mts +3 -0
  83. package/dist/entry-point.d.mts.map +1 -0
  84. package/dist/entry-point.mjs +62 -0
  85. package/dist/entry-point.mjs.map +1 -0
  86. package/dist/expect-type.d.mts +43 -172
  87. package/dist/expect-type.d.mts.map +1 -1
  88. package/dist/expect-type.mjs +43 -172
  89. package/dist/expect-type.mjs.map +1 -1
  90. package/dist/functional/match.d.mts +35 -140
  91. package/dist/functional/match.d.mts.map +1 -1
  92. package/dist/functional/match.mjs.map +1 -1
  93. package/dist/functional/optional.d.mts +282 -160
  94. package/dist/functional/optional.d.mts.map +1 -1
  95. package/dist/functional/optional.mjs +131 -71
  96. package/dist/functional/optional.mjs.map +1 -1
  97. package/dist/functional/pipe.d.mts +59 -113
  98. package/dist/functional/pipe.d.mts.map +1 -1
  99. package/dist/functional/pipe.mjs.map +1 -1
  100. package/dist/functional/result.d.mts +433 -332
  101. package/dist/functional/result.d.mts.map +1 -1
  102. package/dist/functional/result.mjs +233 -239
  103. package/dist/functional/result.mjs.map +1 -1
  104. package/dist/globals.d.mts +12 -5
  105. package/dist/guard/has-key.d.mts +23 -74
  106. package/dist/guard/has-key.d.mts.map +1 -1
  107. package/dist/guard/has-key.mjs +23 -74
  108. package/dist/guard/has-key.mjs.map +1 -1
  109. package/dist/guard/is-non-empty-string.d.mts +20 -87
  110. package/dist/guard/is-non-empty-string.d.mts.map +1 -1
  111. package/dist/guard/is-non-empty-string.mjs +20 -87
  112. package/dist/guard/is-non-empty-string.mjs.map +1 -1
  113. package/dist/guard/is-non-null-object.d.mts +14 -84
  114. package/dist/guard/is-non-null-object.d.mts.map +1 -1
  115. package/dist/guard/is-non-null-object.mjs +14 -84
  116. package/dist/guard/is-non-null-object.mjs.map +1 -1
  117. package/dist/guard/is-primitive.d.mts +13 -126
  118. package/dist/guard/is-primitive.d.mts.map +1 -1
  119. package/dist/guard/is-primitive.mjs +13 -126
  120. package/dist/guard/is-primitive.mjs.map +1 -1
  121. package/dist/guard/is-record.d.mts +21 -132
  122. package/dist/guard/is-record.d.mts.map +1 -1
  123. package/dist/guard/is-record.mjs +21 -132
  124. package/dist/guard/is-record.mjs.map +1 -1
  125. package/dist/guard/is-type.d.mts +201 -238
  126. package/dist/guard/is-type.d.mts.map +1 -1
  127. package/dist/guard/is-type.mjs +201 -238
  128. package/dist/guard/is-type.mjs.map +1 -1
  129. package/dist/guard/key-is-in.d.mts +22 -139
  130. package/dist/guard/key-is-in.d.mts.map +1 -1
  131. package/dist/guard/key-is-in.mjs +22 -139
  132. package/dist/guard/key-is-in.mjs.map +1 -1
  133. package/dist/index.d.mts +0 -1
  134. package/dist/index.d.mts.map +1 -1
  135. package/dist/index.mjs +0 -1
  136. package/dist/index.mjs.map +1 -1
  137. package/dist/iterator/range.d.mts +29 -62
  138. package/dist/iterator/range.d.mts.map +1 -1
  139. package/dist/iterator/range.mjs.map +1 -1
  140. package/dist/json/json.d.mts +191 -121
  141. package/dist/json/json.d.mts.map +1 -1
  142. package/dist/json/json.mjs +238 -136
  143. package/dist/json/json.mjs.map +1 -1
  144. package/dist/number/branded-types/finite-number.d.mts +24 -156
  145. package/dist/number/branded-types/finite-number.d.mts.map +1 -1
  146. package/dist/number/branded-types/finite-number.mjs +27 -159
  147. package/dist/number/branded-types/finite-number.mjs.map +1 -1
  148. package/dist/number/branded-types/int.d.mts +122 -120
  149. package/dist/number/branded-types/int.d.mts.map +1 -1
  150. package/dist/number/branded-types/int.mjs +122 -120
  151. package/dist/number/branded-types/int.mjs.map +1 -1
  152. package/dist/number/branded-types/int16.d.mts +22 -30
  153. package/dist/number/branded-types/int16.d.mts.map +1 -1
  154. package/dist/number/branded-types/int16.mjs +22 -30
  155. package/dist/number/branded-types/int16.mjs.map +1 -1
  156. package/dist/number/branded-types/int32.d.mts +22 -31
  157. package/dist/number/branded-types/int32.d.mts.map +1 -1
  158. package/dist/number/branded-types/int32.mjs +22 -31
  159. package/dist/number/branded-types/int32.mjs.map +1 -1
  160. package/dist/number/branded-types/non-negative-finite-number.d.mts +28 -36
  161. package/dist/number/branded-types/non-negative-finite-number.d.mts.map +1 -1
  162. package/dist/number/branded-types/non-negative-finite-number.mjs +31 -39
  163. package/dist/number/branded-types/non-negative-finite-number.mjs.map +1 -1
  164. package/dist/number/branded-types/non-negative-int16.d.mts +24 -34
  165. package/dist/number/branded-types/non-negative-int16.d.mts.map +1 -1
  166. package/dist/number/branded-types/non-negative-int16.mjs +24 -34
  167. package/dist/number/branded-types/non-negative-int16.mjs.map +1 -1
  168. package/dist/number/branded-types/non-negative-int32.d.mts +26 -35
  169. package/dist/number/branded-types/non-negative-int32.d.mts.map +1 -1
  170. package/dist/number/branded-types/non-negative-int32.mjs +26 -35
  171. package/dist/number/branded-types/non-negative-int32.mjs.map +1 -1
  172. package/dist/number/branded-types/non-zero-finite-number.d.mts +22 -37
  173. package/dist/number/branded-types/non-zero-finite-number.d.mts.map +1 -1
  174. package/dist/number/branded-types/non-zero-finite-number.mjs +25 -40
  175. package/dist/number/branded-types/non-zero-finite-number.mjs.map +1 -1
  176. package/dist/number/branded-types/non-zero-int.d.mts +15 -30
  177. package/dist/number/branded-types/non-zero-int.d.mts.map +1 -1
  178. package/dist/number/branded-types/non-zero-int.mjs +15 -30
  179. package/dist/number/branded-types/non-zero-int.mjs.map +1 -1
  180. package/dist/number/branded-types/non-zero-int16.d.mts +27 -35
  181. package/dist/number/branded-types/non-zero-int16.d.mts.map +1 -1
  182. package/dist/number/branded-types/non-zero-int16.mjs +27 -35
  183. package/dist/number/branded-types/non-zero-int16.mjs.map +1 -1
  184. package/dist/number/branded-types/non-zero-int32.d.mts +29 -36
  185. package/dist/number/branded-types/non-zero-int32.d.mts.map +1 -1
  186. package/dist/number/branded-types/non-zero-int32.mjs +29 -36
  187. package/dist/number/branded-types/non-zero-int32.mjs.map +1 -1
  188. package/dist/number/branded-types/non-zero-safe-int.d.mts +37 -38
  189. package/dist/number/branded-types/non-zero-safe-int.d.mts.map +1 -1
  190. package/dist/number/branded-types/non-zero-safe-int.mjs +39 -40
  191. package/dist/number/branded-types/non-zero-safe-int.mjs.map +1 -1
  192. package/dist/number/branded-types/non-zero-uint16.d.mts +24 -35
  193. package/dist/number/branded-types/non-zero-uint16.d.mts.map +1 -1
  194. package/dist/number/branded-types/non-zero-uint16.mjs +24 -35
  195. package/dist/number/branded-types/non-zero-uint16.mjs.map +1 -1
  196. package/dist/number/branded-types/non-zero-uint32.d.mts +24 -35
  197. package/dist/number/branded-types/non-zero-uint32.d.mts.map +1 -1
  198. package/dist/number/branded-types/non-zero-uint32.mjs +24 -35
  199. package/dist/number/branded-types/non-zero-uint32.mjs.map +1 -1
  200. package/dist/number/branded-types/positive-finite-number.d.mts +26 -40
  201. package/dist/number/branded-types/positive-finite-number.d.mts.map +1 -1
  202. package/dist/number/branded-types/positive-finite-number.mjs +29 -43
  203. package/dist/number/branded-types/positive-finite-number.mjs.map +1 -1
  204. package/dist/number/branded-types/positive-int.d.mts +133 -123
  205. package/dist/number/branded-types/positive-int.d.mts.map +1 -1
  206. package/dist/number/branded-types/positive-int.mjs +133 -123
  207. package/dist/number/branded-types/positive-int.mjs.map +1 -1
  208. package/dist/number/branded-types/positive-int16.d.mts +24 -35
  209. package/dist/number/branded-types/positive-int16.d.mts.map +1 -1
  210. package/dist/number/branded-types/positive-int16.mjs +24 -35
  211. package/dist/number/branded-types/positive-int16.mjs.map +1 -1
  212. package/dist/number/branded-types/positive-int32.d.mts +24 -35
  213. package/dist/number/branded-types/positive-int32.d.mts.map +1 -1
  214. package/dist/number/branded-types/positive-int32.mjs +24 -35
  215. package/dist/number/branded-types/positive-int32.mjs.map +1 -1
  216. package/dist/number/branded-types/positive-safe-int.d.mts +159 -33
  217. package/dist/number/branded-types/positive-safe-int.d.mts.map +1 -1
  218. package/dist/number/branded-types/positive-safe-int.mjs +160 -34
  219. package/dist/number/branded-types/positive-safe-int.mjs.map +1 -1
  220. package/dist/number/branded-types/positive-uint16.d.mts +24 -35
  221. package/dist/number/branded-types/positive-uint16.d.mts.map +1 -1
  222. package/dist/number/branded-types/positive-uint16.mjs +24 -35
  223. package/dist/number/branded-types/positive-uint16.mjs.map +1 -1
  224. package/dist/number/branded-types/positive-uint32.d.mts +26 -36
  225. package/dist/number/branded-types/positive-uint32.d.mts.map +1 -1
  226. package/dist/number/branded-types/positive-uint32.mjs +26 -36
  227. package/dist/number/branded-types/positive-uint32.mjs.map +1 -1
  228. package/dist/number/branded-types/safe-int.d.mts +140 -99
  229. package/dist/number/branded-types/safe-int.d.mts.map +1 -1
  230. package/dist/number/branded-types/safe-int.mjs +142 -101
  231. package/dist/number/branded-types/safe-int.mjs.map +1 -1
  232. package/dist/number/branded-types/safe-uint.d.mts +24 -33
  233. package/dist/number/branded-types/safe-uint.d.mts.map +1 -1
  234. package/dist/number/branded-types/safe-uint.mjs +25 -34
  235. package/dist/number/branded-types/safe-uint.mjs.map +1 -1
  236. package/dist/number/branded-types/uint.d.mts +121 -30
  237. package/dist/number/branded-types/uint.d.mts.map +1 -1
  238. package/dist/number/branded-types/uint.mjs +121 -30
  239. package/dist/number/branded-types/uint.mjs.map +1 -1
  240. package/dist/number/branded-types/uint16.d.mts +26 -34
  241. package/dist/number/branded-types/uint16.d.mts.map +1 -1
  242. package/dist/number/branded-types/uint16.mjs +26 -34
  243. package/dist/number/branded-types/uint16.mjs.map +1 -1
  244. package/dist/number/branded-types/uint32.d.mts +26 -68
  245. package/dist/number/branded-types/uint32.d.mts.map +1 -1
  246. package/dist/number/branded-types/uint32.mjs +26 -68
  247. package/dist/number/branded-types/uint32.mjs.map +1 -1
  248. package/dist/number/enum/int8.d.mts +37 -101
  249. package/dist/number/enum/int8.d.mts.map +1 -1
  250. package/dist/number/enum/int8.mjs +39 -170
  251. package/dist/number/enum/int8.mjs.map +1 -1
  252. package/dist/number/enum/uint8.d.mts +45 -55
  253. package/dist/number/enum/uint8.d.mts.map +1 -1
  254. package/dist/number/enum/uint8.mjs +46 -155
  255. package/dist/number/enum/uint8.mjs.map +1 -1
  256. package/dist/number/num.d.mts +145 -206
  257. package/dist/number/num.d.mts.map +1 -1
  258. package/dist/number/num.mjs +143 -199
  259. package/dist/number/num.mjs.map +1 -1
  260. package/dist/number/refined-number-utils.d.mts +97 -21
  261. package/dist/number/refined-number-utils.d.mts.map +1 -1
  262. package/dist/number/refined-number-utils.mjs +91 -20
  263. package/dist/number/refined-number-utils.mjs.map +1 -1
  264. package/dist/object/object.d.mts +126 -208
  265. package/dist/object/object.d.mts.map +1 -1
  266. package/dist/object/object.mjs +68 -102
  267. package/dist/object/object.mjs.map +1 -1
  268. package/dist/others/cast-mutable.d.mts +12 -88
  269. package/dist/others/cast-mutable.d.mts.map +1 -1
  270. package/dist/others/cast-mutable.mjs +13 -89
  271. package/dist/others/cast-mutable.mjs.map +1 -1
  272. package/dist/others/cast-readonly.d.mts +12 -168
  273. package/dist/others/cast-readonly.d.mts.map +1 -1
  274. package/dist/others/cast-readonly.mjs +13 -169
  275. package/dist/others/cast-readonly.mjs.map +1 -1
  276. package/dist/others/if-then.d.mts +6 -83
  277. package/dist/others/if-then.d.mts.map +1 -1
  278. package/dist/others/if-then.mjs +6 -83
  279. package/dist/others/if-then.mjs.map +1 -1
  280. package/dist/others/map-nullable.d.mts +12 -136
  281. package/dist/others/map-nullable.d.mts.map +1 -1
  282. package/dist/others/map-nullable.mjs.map +1 -1
  283. package/dist/others/memoize-function.d.mts +14 -157
  284. package/dist/others/memoize-function.d.mts.map +1 -1
  285. package/dist/others/memoize-function.mjs +14 -157
  286. package/dist/others/memoize-function.mjs.map +1 -1
  287. package/dist/others/tuple.d.mts +33 -151
  288. package/dist/others/tuple.d.mts.map +1 -1
  289. package/dist/others/tuple.mjs +33 -151
  290. package/dist/others/tuple.mjs.map +1 -1
  291. package/dist/others/unknown-to-string.d.mts +11 -125
  292. package/dist/others/unknown-to-string.d.mts.map +1 -1
  293. package/dist/others/unknown-to-string.mjs +14 -127
  294. package/dist/others/unknown-to-string.mjs.map +1 -1
  295. package/dist/promise/promise.d.mts +33 -20
  296. package/dist/promise/promise.d.mts.map +1 -1
  297. package/dist/promise/promise.mjs +34 -21
  298. package/dist/promise/promise.mjs.map +1 -1
  299. package/dist/types.d.mts +1 -1
  300. package/package.json +54 -50
  301. package/src/array/impl/array-utils-creation.mts +192 -0
  302. package/src/array/{array-utils-creation.test.mts → impl/array-utils-creation.test.mts} +121 -72
  303. package/src/array/impl/array-utils-element-access.mts +115 -0
  304. package/src/array/impl/array-utils-element-access.test.mts +151 -0
  305. package/src/array/impl/array-utils-iterators.mts +79 -0
  306. package/src/array/impl/array-utils-iterators.test.mts +98 -0
  307. package/src/array/impl/array-utils-modification.mts +434 -0
  308. package/src/array/{array-utils-modification.test.mts → impl/array-utils-modification.test.mts} +41 -28
  309. package/src/array/{array-utils-overload-type-error.test.mts → impl/array-utils-overload-type-error.test.mts} +33 -33
  310. package/src/array/impl/array-utils-reducing-value.mts +551 -0
  311. package/src/array/{array-utils-reducing-value.test.mts → impl/array-utils-reducing-value.test.mts} +45 -50
  312. package/src/array/impl/array-utils-search.mts +509 -0
  313. package/src/array/impl/array-utils-search.test.mts +346 -0
  314. package/src/array/impl/array-utils-set-op.mts +166 -0
  315. package/src/array/{array-utils-set-op.test.mts → impl/array-utils-set-op.test.mts} +42 -35
  316. package/src/array/impl/array-utils-size.mts +30 -0
  317. package/src/array/impl/array-utils-size.test.mts +9 -0
  318. package/src/array/impl/array-utils-slice-clamped.mts +51 -0
  319. package/src/array/{array-utils-slice-clamped.test.mts → impl/array-utils-slice-clamped.test.mts} +12 -12
  320. package/src/array/impl/array-utils-slicing.mts +275 -0
  321. package/src/array/impl/array-utils-slicing.test.mts +158 -0
  322. package/src/array/impl/array-utils-transformation.mts +746 -0
  323. package/src/array/{array-utils-transformation.test.mts → impl/array-utils-transformation.test.mts} +662 -889
  324. package/src/array/impl/array-utils-validation.mts +241 -0
  325. package/src/array/{array-utils-validation.test.mts → impl/array-utils-validation.test.mts} +194 -107
  326. package/src/array/{array.test.mts → impl/array.test.mts} +2 -2
  327. package/src/array/impl/index.mts +12 -0
  328. package/src/array/index.mts +1 -1
  329. package/src/collections/imap-mapped.mts +99 -265
  330. package/src/collections/imap.mts +477 -174
  331. package/src/collections/imap.test.mts +12 -19
  332. package/src/collections/iset-mapped.mts +892 -358
  333. package/src/collections/iset.mts +429 -213
  334. package/src/collections/queue.mts +174 -200
  335. package/src/collections/stack.mts +172 -245
  336. package/src/collections/stack.test.mts +9 -1
  337. package/src/entry-point.mts +2 -0
  338. package/src/expect-type.mts +43 -172
  339. package/src/functional/match.mts +35 -145
  340. package/src/functional/optional.mts +285 -163
  341. package/src/functional/optional.test.mts +4 -1
  342. package/src/functional/pipe.mts +60 -113
  343. package/src/functional/result.mts +452 -351
  344. package/src/functional/result.test.mts +9 -2
  345. package/src/globals.d.mts +12 -5
  346. package/src/guard/has-key.mts +23 -74
  347. package/src/guard/is-non-empty-string.mts +20 -87
  348. package/src/guard/is-non-null-object.mts +14 -84
  349. package/src/guard/is-non-null-object.test.mts +1 -1
  350. package/src/guard/is-primitive.mts +13 -126
  351. package/src/guard/is-primitive.test.mts +1 -1
  352. package/src/guard/is-record.mts +21 -132
  353. package/src/guard/is-record.test.mts +0 -1
  354. package/src/guard/is-type.mts +201 -238
  355. package/src/guard/is-type.test.mts +7 -7
  356. package/src/guard/key-is-in.mts +22 -139
  357. package/src/index.mts +0 -1
  358. package/src/iterator/range.mts +29 -62
  359. package/src/json/json.mts +202 -134
  360. package/src/json/json.test.mts +1 -3
  361. package/src/number/branded-types/finite-number.mts +27 -159
  362. package/src/number/branded-types/int.mts +122 -120
  363. package/src/number/branded-types/int16.mts +22 -30
  364. package/src/number/branded-types/int16.test.mts +24 -24
  365. package/src/number/branded-types/int32.mts +22 -31
  366. package/src/number/branded-types/int32.test.mts +39 -39
  367. package/src/number/branded-types/non-negative-finite-number.mts +31 -39
  368. package/src/number/branded-types/non-negative-int16.mts +24 -34
  369. package/src/number/branded-types/non-negative-int16.test.mts +16 -16
  370. package/src/number/branded-types/non-negative-int32.mts +26 -35
  371. package/src/number/branded-types/non-negative-int32.test.mts +30 -30
  372. package/src/number/branded-types/non-zero-finite-number.mts +25 -40
  373. package/src/number/branded-types/non-zero-int.mts +15 -30
  374. package/src/number/branded-types/non-zero-int16.mts +27 -35
  375. package/src/number/branded-types/non-zero-int16.test.mts +26 -26
  376. package/src/number/branded-types/non-zero-int32.mts +29 -36
  377. package/src/number/branded-types/non-zero-int32.test.mts +45 -42
  378. package/src/number/branded-types/non-zero-safe-int.mts +39 -40
  379. package/src/number/branded-types/non-zero-uint16.mts +24 -35
  380. package/src/number/branded-types/non-zero-uint16.test.mts +16 -16
  381. package/src/number/branded-types/non-zero-uint32.mts +24 -35
  382. package/src/number/branded-types/non-zero-uint32.test.mts +28 -28
  383. package/src/number/branded-types/positive-finite-number.mts +29 -43
  384. package/src/number/branded-types/positive-int.mts +134 -124
  385. package/src/number/branded-types/positive-int16.mts +24 -35
  386. package/src/number/branded-types/positive-int16.test.mts +14 -14
  387. package/src/number/branded-types/positive-int32.mts +24 -35
  388. package/src/number/branded-types/positive-int32.test.mts +26 -26
  389. package/src/number/branded-types/positive-safe-int.mts +160 -34
  390. package/src/number/branded-types/positive-uint16.mts +24 -35
  391. package/src/number/branded-types/positive-uint16.test.mts +16 -16
  392. package/src/number/branded-types/positive-uint32.mts +26 -36
  393. package/src/number/branded-types/positive-uint32.test.mts +31 -28
  394. package/src/number/branded-types/safe-int.mts +142 -101
  395. package/src/number/branded-types/safe-uint.mts +25 -34
  396. package/src/number/branded-types/uint.mts +121 -30
  397. package/src/number/branded-types/uint16.mts +26 -34
  398. package/src/number/branded-types/uint16.test.mts +16 -16
  399. package/src/number/branded-types/uint32.mts +26 -68
  400. package/src/number/branded-types/uint32.test.mts +28 -28
  401. package/src/number/enum/int8.mts +39 -170
  402. package/src/number/enum/uint8.mts +46 -155
  403. package/src/number/num.mts +157 -212
  404. package/src/number/num.test.mts +4 -4
  405. package/src/number/refined-number-utils.mts +109 -26
  406. package/src/object/object.mts +130 -212
  407. package/src/object/object.test.mts +29 -0
  408. package/src/others/cast-mutable.mts +13 -89
  409. package/src/others/cast-mutable.test.mts +80 -0
  410. package/src/others/cast-readonly.mts +13 -169
  411. package/src/others/if-then.mts +6 -83
  412. package/src/others/map-nullable.mts +12 -136
  413. package/src/others/map-nullable.test.mts +6 -6
  414. package/src/others/memoize-function.mts +14 -157
  415. package/src/others/tuple.mts +33 -151
  416. package/src/others/unknown-to-string.mts +15 -127
  417. package/src/others/unknown-to-string.test.mts +14 -2
  418. package/src/promise/promise.mts +34 -21
  419. package/src/promise/promise.test.mts +43 -0
  420. package/dist/array/array-utils.d.mts +0 -2956
  421. package/dist/array/array-utils.d.mts.map +0 -1
  422. package/dist/array/array-utils.mjs +0 -1838
  423. package/dist/array/array-utils.mjs.map +0 -1
  424. package/src/array/array-utils-search.test.mts +0 -169
  425. package/src/array/array-utils-slicing.test.mts +0 -274
  426. package/src/array/array-utils.mts +0 -4834
@@ -1,151 +1,185 @@
1
- import { IMap } from '../collections/index.mjs';
2
- import { expectType } from '../expect-type.mjs';
3
- import { Optional } from '../functional/index.mjs';
4
- import { SafeUint } from '../number/index.mjs';
5
- import { Arr } from './array-utils.mjs';
1
+ import { IMap } from '../../collections/index.mjs';
2
+ import { expectType } from '../../expect-type.mjs';
3
+ import { Optional } from '../../functional/index.mjs';
4
+ import { SafeUint } from '../../number/index.mjs';
5
+ import {
6
+ concat,
7
+ filter,
8
+ filterNot,
9
+ flat,
10
+ flatMap,
11
+ groupBy,
12
+ map,
13
+ partition,
14
+ scan,
15
+ toReversed,
16
+ toSorted,
17
+ toSortedBy,
18
+ uniq,
19
+ uniqBy,
20
+ zip,
21
+ } from './array-utils-transformation.mjs';
6
22
 
7
23
  describe('Arr transformations', () => {
8
- describe('partition', () => {
9
- const xs = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12] as const;
24
+ describe('map', () => {
25
+ const mapped = map([1, 2, 3], (x, i): number => x * x * i);
10
26
 
11
- {
12
- const result = Arr.partition(xs, 4);
27
+ expectType<typeof mapped, ArrayOfLength<3, number>>('=');
13
28
 
14
- expectType<
15
- typeof result,
16
- readonly (readonly (
17
- | 1
18
- | 2
19
- | 3
20
- | 4
21
- | 5
22
- | 6
23
- | 7
24
- | 8
25
- | 9
26
- | 10
27
- | 11
28
- | 12
29
- )[])[]
30
- >('=');
29
+ test('case 1', () => {
30
+ expect(mapped).toStrictEqual([0, 4, 18]);
31
+ });
31
32
 
32
- test('case 1', () => {
33
- expect(result).toStrictEqual([
34
- [1, 2, 3, 4],
35
- [5, 6, 7, 8],
36
- [9, 10, 11, 12],
37
- ]);
38
- });
39
- }
33
+ test('should work with empty tuple', () => {
34
+ const empty = [] as const;
35
+ const mappedEmpty = map(empty, (x) => String(x));
36
+ expectType<typeof mappedEmpty, readonly []>('=');
37
+ expect(mappedEmpty).toStrictEqual([]);
38
+ });
40
39
 
41
- {
42
- const result = Arr.partition(xs, 3);
40
+ test('should preserve tuple length with different types', () => {
41
+ const mixed = [1, 'hello', true] as const;
42
+ const mappedMixed = map(mixed, (x) => typeof x);
43
+ expectType<typeof mappedMixed, readonly [string, string, string]>('<=');
44
+ expect(mappedMixed).toStrictEqual(['number', 'string', 'boolean']);
45
+ });
43
46
 
44
- expectType<
45
- typeof result,
46
- readonly (readonly (
47
- | 1
48
- | 2
49
- | 3
50
- | 4
51
- | 5
52
- | 6
53
- | 7
54
- | 8
55
- | 9
56
- | 10
57
- | 11
58
- | 12
59
- )[])[]
60
- >('=');
47
+ test('should work with index parameter', () => {
48
+ const tuple = ['a', 'b', 'c'] as const;
49
+ const mappedWithIndex = map(tuple, (x, i) => `${i}:${x}`);
50
+ expectType<typeof mappedWithIndex, readonly [string, string, string]>(
51
+ '<=',
52
+ );
53
+ expect(mappedWithIndex).toStrictEqual(['0:a', '1:b', '2:c']);
54
+ });
55
+ });
61
56
 
62
- test('case 2', () => {
63
- expect(result).toStrictEqual([
64
- [1, 2, 3],
65
- [4, 5, 6],
66
- [7, 8, 9],
67
- [10, 11, 12],
68
- ]);
69
- });
70
- }
57
+ describe('scan', () => {
58
+ test('should compute running sum', () => {
59
+ const numbers = [1, 2, 3, 4];
60
+ const runningSum = scan(numbers, (acc, curr) => acc + curr, 0);
71
61
 
72
- {
73
- const result = Arr.partition(xs, 5);
62
+ expectType<typeof runningSum, readonly [number, ...number[]]>('<=');
63
+ expect(runningSum).toStrictEqual([0, 1, 3, 6, 10]);
64
+ });
74
65
 
75
- expectType<
76
- typeof result,
77
- readonly (readonly (
78
- | 1
79
- | 2
80
- | 3
81
- | 4
82
- | 5
83
- | 6
84
- | 7
85
- | 8
86
- | 9
87
- | 10
88
- | 11
89
- | 12
90
- )[])[]
91
- >('=');
66
+ test('should include initial value as first element', () => {
67
+ const numbers = [10, 20, 30];
68
+ const result = scan(numbers, (acc, curr) => acc + curr, 100);
92
69
 
93
- test('case 3', () => {
94
- expect(result).toStrictEqual([
95
- [1, 2, 3, 4, 5],
96
- [6, 7, 8, 9, 10],
97
- [11, 12],
98
- ]);
99
- });
100
- }
70
+ expect(result).toStrictEqual([100, 110, 130, 160]);
71
+ expect(result).toHaveLength(4); // original length + 1
72
+ });
101
73
 
102
- test('should partition array into chunks', () => {
103
- const numbers = [1, 2, 3, 4, 5, 6];
104
- const result = Arr.partition(numbers, 2);
74
+ test('should work with curried version', () => {
75
+ const scanSum = scan<number, number>((acc, curr) => acc + curr, 0);
105
76
 
106
- expect(result).toStrictEqual([
107
- [1, 2],
108
- [3, 4],
109
- [5, 6],
110
- ]);
77
+ const result1 = scanSum([1, 2, 3]);
78
+ const result2 = scanSum([5, 10]);
79
+
80
+ expect(result1).toStrictEqual([0, 1, 3, 6]);
81
+ expect(result2).toStrictEqual([0, 5, 15]);
111
82
  });
112
83
 
113
- test('should handle arrays not evenly divisible by chunk size', () => {
114
- const numbers = [1, 2, 3, 4, 5];
115
- const result = Arr.partition(numbers, 2);
84
+ test('should provide index to reducer', () => {
85
+ const numbers = [10, 20, 30];
86
+ const mut_indices: number[] = [];
116
87
 
117
- expect(result).toStrictEqual([[1, 2], [3, 4], [5]]);
88
+ scan(
89
+ numbers,
90
+ (acc, curr, index) => {
91
+ mut_indices.push(index);
92
+ return acc + curr;
93
+ },
94
+ 0,
95
+ );
96
+
97
+ expect(mut_indices).toStrictEqual([0, 1, 2]);
118
98
  });
119
99
 
120
- test('should work with chunk size < 2 (returns empty)', () => {
100
+ test('should work with empty array', () => {
101
+ const empty: readonly number[] = [];
102
+ const result = scan(empty, (acc, curr) => acc + curr, 42);
103
+
104
+ expect(result).toStrictEqual([42]);
105
+ });
106
+
107
+ test('should work with different accumulator and element types', () => {
108
+ const strings = ['a', 'b', 'c'];
109
+ const result = scan(strings, (acc, curr) => acc + curr.length, 0);
110
+
111
+ expectType<typeof result, readonly [number, ...number[]]>('<=');
112
+ expect(result).toStrictEqual([0, 1, 2, 3]);
113
+ });
114
+
115
+ test('should compute running product', () => {
116
+ const numbers = [2, 3, 4];
117
+ const runningProduct = scan(numbers, (acc, curr) => acc * curr, 1);
118
+
119
+ expect(runningProduct).toStrictEqual([1, 2, 6, 24]);
120
+ });
121
+
122
+ test('should work with objects', () => {
123
+ const items = [{ value: 10 }, { value: 20 }, { value: 30 }] as const;
124
+
125
+ const result = scan(items, (acc, curr) => acc + curr.value, 0);
126
+
127
+ expect(result).toStrictEqual([0, 10, 30, 60]);
128
+ });
129
+
130
+ test('should preserve all intermediate values', () => {
121
131
  const numbers = [1, 2, 3];
122
- const result = Arr.partition(numbers, 1);
132
+ const result = scan(numbers, (acc, curr) => acc - curr, 10);
123
133
 
124
- // According to docs, returns empty array if chunkSize < 2
125
- expect(result).toStrictEqual([]);
134
+ // 10 -> 10-1=9 -> 9-2=7 -> 7-3=4
135
+ expect(result).toStrictEqual([10, 9, 7, 4]);
126
136
  });
137
+ });
127
138
 
128
- test('should work with chunk size larger than array', () => {
129
- const numbers = [1, 2];
130
- const result = Arr.partition(numbers, 5);
139
+ describe('toReversed', () => {
140
+ {
141
+ const xs = [1, 2, 3] as const;
142
+ const _nativeResult = xs.toReversed();
131
143
 
132
- expect(result).toStrictEqual([[1, 2]]);
144
+ expectType<typeof _nativeResult, (1 | 2 | 3)[]>('=');
145
+
146
+ const result = toReversed([1, 2, 3]);
147
+
148
+ expectType<typeof result, readonly [3, 2, 1]>('=');
149
+
150
+ test('case 1', () => {
151
+ expect(result).toStrictEqual([3, 2, 1]);
152
+ });
153
+ }
154
+
155
+ test('should work with empty tuple', () => {
156
+ const empty = [] as const;
157
+ const reversed = toReversed(empty);
158
+ expectType<typeof reversed, readonly []>('=');
159
+ expect(reversed).toStrictEqual([]);
133
160
  });
134
161
 
135
- test('partition should work with empty array', () => {
136
- const empty: readonly number[] = [];
137
- const result = Arr.partition(empty, 2);
162
+ test('should work with single element', () => {
163
+ const single = [42] as const;
164
+ const reversed = toReversed(single);
165
+ expectType<typeof reversed, readonly [42]>('=');
166
+ expect(reversed).toStrictEqual([42]);
167
+ });
138
168
 
139
- expect(result).toStrictEqual([]);
169
+ test('should preserve mixed types in reverse order', () => {
170
+ const mixed = [1, 'hello', true, null] as const;
171
+ const reversed = toReversed(mixed);
172
+ expectType<typeof reversed, readonly [null, true, 'hello', 1]>('=');
173
+ expect(reversed).toStrictEqual([null, true, 'hello', 1]);
140
174
  });
141
175
  });
142
176
 
143
177
  describe('toSorted', () => {
144
178
  {
145
179
  const xs = [2, 1, 3] as const;
146
- const result = xs.toSorted();
180
+ const result = toSorted(xs);
147
181
 
148
- expectType<typeof result, (1 | 2 | 3)[]>('=');
182
+ expectType<typeof result, ArrayOfLength<3, 1 | 2 | 3>>('=');
149
183
 
150
184
  test('case 1', () => {
151
185
  expect(result).toStrictEqual([1, 2, 3]);
@@ -153,9 +187,9 @@ describe('Arr transformations', () => {
153
187
  }
154
188
  {
155
189
  const xs = [2, 1, 3] as const;
156
- const result = xs.toSorted((a, b) => a - b);
190
+ const result = toSorted(xs, (a, b) => a - b);
157
191
 
158
- expectType<typeof result, (1 | 2 | 3)[]>('=');
192
+ expectType<typeof result, ArrayOfLength<3, 1 | 2 | 3>>('=');
159
193
 
160
194
  test('case 2', () => {
161
195
  expect(result).toStrictEqual([1, 2, 3]);
@@ -163,9 +197,9 @@ describe('Arr transformations', () => {
163
197
  }
164
198
  {
165
199
  const xs = [2, 1, 3] as const;
166
- const result = xs.toSorted((a, b) => b - a);
200
+ const result = toSorted(xs, (a, b) => b - a);
167
201
 
168
- expectType<typeof result, (1 | 2 | 3)[]>('=');
202
+ expectType<typeof result, ArrayOfLength<3, 1 | 2 | 3>>('=');
169
203
 
170
204
  test('case 3', () => {
171
205
  expect(result).toStrictEqual([3, 2, 1]);
@@ -176,7 +210,7 @@ describe('Arr transformations', () => {
176
210
  describe('toSortedBy', () => {
177
211
  {
178
212
  const xs = [{ v: 2 }, { v: 1 }, { v: 3 }] as const;
179
- const sorted = Arr.toSortedBy(xs, (x) => x.v);
213
+ const sorted = toSortedBy(xs, (x) => x.v);
180
214
 
181
215
  expectType<
182
216
  typeof sorted,
@@ -189,7 +223,7 @@ describe('Arr transformations', () => {
189
223
  }
190
224
  {
191
225
  const xs = [{ v: 2 }, { v: 1 }, { v: 3 }] as const;
192
- const sorted = Arr.toSortedBy(
226
+ const sorted = toSortedBy(
193
227
  xs,
194
228
  (x) => x.v,
195
229
  (a, b) => a - b,
@@ -211,7 +245,7 @@ describe('Arr transformations', () => {
211
245
  { name: 'Bob', age: 20 },
212
246
  { name: 'Charlie', age: 25 },
213
247
  ];
214
- const result = Arr.toSortedBy(people, (person) => person.age);
248
+ const result = toSortedBy(people, (person) => person.age);
215
249
 
216
250
  expect(result).toHaveLength(3);
217
251
  expect(result[0]?.name).toBe('Bob');
@@ -221,7 +255,7 @@ describe('Arr transformations', () => {
221
255
 
222
256
  test('should work with string sorting', () => {
223
257
  const words = ['banana', 'apple', 'cherry'];
224
- const result = Arr.toSortedBy(
258
+ const result = toSortedBy(
225
259
  words,
226
260
  (word: string) => word,
227
261
  (a: string, b: string) => a.localeCompare(b),
@@ -231,267 +265,81 @@ describe('Arr transformations', () => {
231
265
 
232
266
  test('should work with custom key extraction', () => {
233
267
  const items = ['hello', 'hi', 'welcome', 'bye'];
234
- const result = Arr.toSortedBy(items, (item) => item.length);
268
+ const result = toSortedBy(items, (item) => item.length);
235
269
  expect(result).toStrictEqual(['hi', 'bye', 'hello', 'welcome']);
236
270
  });
237
271
 
238
272
  test('should work with empty array', () => {
239
273
  const empty: readonly { value: number }[] = [];
240
- const result = Arr.toSortedBy(empty, (item) => item.value);
274
+ const result = toSortedBy(empty, (item) => item.value);
241
275
  expect(result).toStrictEqual([]);
242
276
  });
243
277
 
244
278
  test('toSortedBy should work with empty array', () => {
245
279
  const empty: readonly { value: number }[] = [];
246
- const result = Arr.toSortedBy(empty, (item) => item.value);
280
+ const result = toSortedBy(empty, (item) => item.value);
247
281
  expect(result).toStrictEqual([]);
248
282
  });
249
283
  });
250
284
 
251
- describe('groupBy', () => {
252
- const xs = [
253
- { x: 1, y: 1 },
254
- { x: 2, y: 1 },
255
- { x: 3, y: 1 },
256
- { x: 1, y: 2 },
257
- { x: 2, y: 2 },
258
- { x: 1, y: 3 },
259
- ] as const;
285
+ describe('filter', () => {
286
+ test('should filter array with predicate', () => {
287
+ const numbers = [1, 2, 3, 4, 5];
288
+ const evens = filter(numbers, (n) => n % 2 === 0);
289
+ expect(evens).toStrictEqual([2, 4]);
290
+ });
260
291
 
261
- const result = Arr.groupBy(xs, (a) => a.x);
292
+ test('should work with type guards', () => {
293
+ const mixed: (string | number | null)[] = [
294
+ 'hello',
295
+ 42,
296
+ null,
297
+ 'world',
298
+ 123,
299
+ ];
300
+ const strings = filter(mixed, (x): x is string => typeof x === 'string');
301
+ expectType<typeof strings, readonly string[]>('=');
302
+ expect(strings).toStrictEqual(['hello', 'world']);
303
+ });
262
304
 
263
- expectType<
264
- typeof result,
265
- IMap<
266
- 1 | 2 | 3,
267
- readonly (
268
- | Readonly<{ x: 1; y: 1 }>
269
- | Readonly<{ x: 1; y: 2 }>
270
- | Readonly<{ x: 1; y: 3 }>
271
- | Readonly<{ x: 2; y: 1 }>
272
- | Readonly<{ x: 2; y: 2 }>
273
- | Readonly<{ x: 3; y: 1 }>
274
- )[]
275
- >
276
- >('=');
305
+ test('should work with curried version', () => {
306
+ const isPositive = (n: number): boolean => n > 0;
307
+ const filterPositive = filter(isPositive);
308
+ const result = filterPositive([-1, 2, -3, 4]);
309
+ expect(result).toStrictEqual([2, 4]);
310
+ });
277
311
 
278
- test('case 1', () => {
279
- expect(result).toStrictEqual(
280
- IMap.create<
281
- 1 | 2 | 3,
282
- readonly (
283
- | Readonly<{ x: 1; y: 1 }>
284
- | Readonly<{ x: 1; y: 2 }>
285
- | Readonly<{ x: 1; y: 3 }>
286
- | Readonly<{ x: 2; y: 1 }>
287
- | Readonly<{ x: 2; y: 2 }>
288
- | Readonly<{ x: 3; y: 1 }>
289
- )[]
290
- >([
291
- [
292
- 1,
293
- [
294
- { x: 1, y: 1 },
295
- { x: 1, y: 2 },
296
- { x: 1, y: 3 },
297
- ],
298
- ],
299
- [
300
- 2,
301
- [
302
- { x: 2, y: 1 },
303
- { x: 2, y: 2 },
304
- ],
305
- ],
306
- [3, [{ x: 3, y: 1 }]],
307
- ]),
308
- );
312
+ test('should work with curried type guards', () => {
313
+ const isString = (x: unknown): x is string => typeof x === 'string';
314
+ const filterStrings = filter(isString);
315
+ const result = filterStrings(['a', 1, 'b', 2]);
316
+ expectType<typeof result, readonly string[]>('=');
317
+ expect(result).toStrictEqual(['a', 'b']);
309
318
  });
310
319
 
311
- test('should group elements by key', () => {
312
- const array = [
313
- { type: 'fruit', name: 'apple' },
314
- { type: 'vegetable', name: 'carrot' },
315
- { type: 'fruit', name: 'banana' },
316
- ];
317
- const grouped = Arr.groupBy(array, (item) => item.type);
318
-
319
- expect(grouped.size).toBe(2);
320
- const fruits = grouped.get('fruit');
321
- const vegetables = grouped.get('vegetable');
322
-
323
- expect(Optional.isSome(fruits)).toBe(true);
324
- expect(Optional.isSome(vegetables)).toBe(true);
325
-
326
- if (Optional.isSome(fruits)) {
327
- expect(fruits.value).toHaveLength(2);
328
- expect(fruits.value[0]?.name).toBe('apple');
329
- expect(fruits.value[1]?.name).toBe('banana');
330
- }
331
-
332
- if (Optional.isSome(vegetables)) {
333
- expect(vegetables.value).toHaveLength(1);
334
- expect(vegetables.value[0]?.name).toBe('carrot');
335
- }
336
- });
337
-
338
- test('should work with numeric keys', () => {
339
- const numbers = [1, 2, 3, 4, 5, 6];
340
- const grouped = Arr.groupBy(numbers, (n) => n % 2);
341
-
342
- expect(grouped.size).toBe(2);
343
- const evens = grouped.get(0);
344
- const odds = grouped.get(1);
345
-
346
- if (Optional.isSome(evens)) {
347
- expect(evens.value).toStrictEqual([2, 4, 6]);
348
- }
349
-
350
- if (Optional.isSome(odds)) {
351
- expect(odds.value).toStrictEqual([1, 3, 5]);
352
- }
320
+ test('should preserve array type with generic predicate', () => {
321
+ const tuple = [1, 2, 3] as const;
322
+ const filtered = filter(tuple, (x) => x > 1);
323
+ expectType<typeof filtered, readonly (1 | 2 | 3)[]>('=');
324
+ expect(filtered).toStrictEqual([2, 3]);
353
325
  });
354
326
 
355
327
  test('should work with empty array', () => {
356
- const empty: readonly number[] = [];
357
- const grouped = Arr.groupBy(empty, (n) => n % 2);
358
- expect(grouped.size).toBe(0);
359
- });
360
-
361
- test('should handle all elements in same group', () => {
362
- const array = [1, 2, 3, 4];
363
- const grouped = Arr.groupBy(array, () => 'all');
364
-
365
- expect(grouped.size).toBe(1);
366
- const all = grouped.get('all');
367
-
368
- if (Optional.isSome(all)) {
369
- expect(all.value).toStrictEqual([1, 2, 3, 4]);
370
- }
371
- });
372
- });
373
-
374
- describe('zip', () => {
375
- {
376
- const xs = [1, 2, 3] as const;
377
- const ys = [4, 5, 6] as const;
378
- const zipped = Arr.zip(xs, ys);
379
-
380
- expectType<
381
- typeof zipped,
382
- readonly [readonly [1, 4], readonly [2, 5], readonly [3, 6]]
383
- >('=');
384
-
385
- test('case 1', () => {
386
- expect(zipped).toStrictEqual([
387
- [1, 4],
388
- [2, 5],
389
- [3, 6],
390
- ]);
391
- });
392
- }
393
- {
394
- const xs: readonly number[] = [1, 2, 3];
395
- const ys: readonly number[] = [4];
396
- const zipped = Arr.zip(xs, ys);
397
-
398
- expectType<typeof zipped, readonly (readonly [number, number])[]>('=');
399
-
400
- test('case 2', () => {
401
- expect(zipped).toStrictEqual([[1, 4]]);
402
- });
403
- }
404
- {
405
- const xs = [1] as const;
406
- const ys: readonly number[] = [4, 5, 6];
407
- const zipped = Arr.zip(xs, ys);
408
-
409
- expectType<typeof zipped, readonly [readonly [1, number]]>('=');
410
-
411
- test('case 3', () => {
412
- expect(zipped).toStrictEqual([[1, 4]]);
413
- });
414
- }
415
-
416
- // testArrayEquality({
417
- // testName: 'zip',
418
- // target: zip([0, 1, 2, 3, 4], [5, 6, 7, 8, 9]),
419
- // toBe: [
420
- // [0, 5],
421
- // [1, 6],
422
- // [2, 7],
423
- // [3, 8],
424
- // [4, 9],
425
- // ],
426
- // });
427
-
428
- // testArrayEquality({
429
- // testName: 'zipArrays 2 arrays',
430
- // target: zipArrays([0, 1, 2, 3, 4], [5, 6, 7, 8, 9]),
431
- // toBe: [
432
- // [0, 5],
433
- // [1, 6],
434
- // [2, 7],
435
- // [3, 8],
436
- // [4, 9],
437
- // ],
438
- // });
439
-
440
- // testArrayEquality({
441
- // testName: 'zipArrays 3 arrays',
442
- // target: zipArrays(
443
- // [0, 1, 2, 3, 4],
444
- // [5, 6, 7, 8, 9, 999, 999],
445
- // [10, 11, 12, 13, 14, 999]
446
- // ),
447
- // toBe: [
448
- // [0, 5, 10],
449
- // [1, 6, 11],
450
- // [2, 7, 12],
451
- // [3, 8, 13],
452
- // [4, 9, 14],
453
- // ],
454
- // });
455
-
456
- test('should zip two arrays', () => {
457
- const arr1 = [1, 2, 3];
458
- const arr2 = ['a', 'b', 'c'];
459
- const result = Arr.zip(arr1, arr2);
460
- expect(result).toStrictEqual([
461
- [1, 'a'],
462
- [2, 'b'],
463
- [3, 'c'],
464
- ]);
465
- });
466
-
467
- test('should handle arrays of different lengths', () => {
468
- const arr1 = [1, 2, 3, 4];
469
- const arr2 = ['a', 'b'];
470
- const result = Arr.zip(arr1, arr2);
471
- expect(result).toStrictEqual([
472
- [1, 'a'],
473
- [2, 'b'],
474
- ]);
475
- });
476
-
477
- test('should work with empty arrays', () => {
478
- const arr1: readonly number[] = [];
479
- const arr2: readonly string[] = [];
480
- const result = Arr.zip(arr1, arr2);
328
+ const empty: number[] = [];
329
+ const result = filter(empty, (n) => n > 0);
481
330
  expect(result).toStrictEqual([]);
482
331
  });
483
332
 
484
- test('should handle one empty array', () => {
485
- const arr1 = [1, 2, 3];
486
- const arr2: readonly string[] = [];
487
- const result = Arr.zip(arr1, arr2);
488
- expect(result).toStrictEqual([]);
333
+ test('should pass index to predicate', () => {
334
+ const numbers = [10, 20, 30, 40];
335
+ const evenIndexes = filter(numbers, (_, i) => i % 2 === 0);
336
+ expect(evenIndexes).toStrictEqual([10, 30]);
489
337
  });
490
338
  });
491
339
 
492
340
  describe('filterNot', () => {
493
341
  const xs = [1, 2, 3] as const;
494
- const filtered = Arr.filterNot(xs, (x) => x % 2 === 0);
342
+ const filtered = filterNot(xs, (x) => x % 2 === 0);
495
343
 
496
344
  expectType<typeof filtered, readonly (1 | 2 | 3)[]>('=');
497
345
 
@@ -500,70 +348,28 @@ describe('Arr transformations', () => {
500
348
  });
501
349
  });
502
350
 
503
- describe('concat', () => {
504
- const xs = [1, 2, 3] as const;
505
- const ys = [4, 5] as const;
506
- const result = Arr.concat(xs, ys);
507
-
508
- expectType<typeof result, readonly [1, 2, 3, 4, 5]>('=');
509
-
510
- test('case 1', () => {
511
- expect(result).toStrictEqual([1, 2, 3, 4, 5]);
512
- });
513
-
514
- // testArrayEquality({
515
- // testName: 'concat 2 arrays',
516
- // target: concat([1, 2, 3], [4, 5, 6]),
517
- // toBe: [1, 2, 3, 4, 5, 6],
518
- // });
519
-
520
- // testArrayEquality({
521
- // testName: 'concat 2 arrays',
522
- // target: concat([1, 2, 3], []),
523
- // toBe: [1, 2, 3],
524
- // });
525
-
526
- // testArrayEquality({
527
- // testName: 'concat 2 arrays',
528
- // target: concat([], [4, 5, 6]),
529
- // toBe: [4, 5, 6],
530
- // });
531
-
532
- // testArrayEquality({
533
- // testName: 'concat 2 arrays',
534
- // target: concat([], []),
535
- // toBe: [],
536
- // });
537
-
538
- // testArrayEquality({
539
- // testName: 'concat 2 arrays',
540
- // target: concat(['1', '2', '3'], [4, 5, 6]),
541
- // toBe: ['1', '2', '3', 4, 5, 6],
542
- // });
543
- });
544
-
545
351
  describe('uniq', () => {
546
352
  test('should remove duplicate primitives', () => {
547
353
  const array = [1, 2, 2, 3, 1, 4, 3];
548
- const result = Arr.uniq(array);
354
+ const result = uniq(array);
549
355
  expect(result).toStrictEqual([1, 2, 3, 4]);
550
356
  });
551
357
 
552
358
  test('should work with strings', () => {
553
359
  const array = ['a', 'b', 'a', 'c', 'b'];
554
- const result = Arr.uniq(array);
360
+ const result = uniq(array);
555
361
  expect(result).toStrictEqual(['a', 'b', 'c']);
556
362
  });
557
363
 
558
364
  test('should work with empty array', () => {
559
365
  const array: readonly number[] = [];
560
- const result = Arr.uniq(array);
366
+ const result = uniq(array);
561
367
  expect(result).toStrictEqual([]);
562
368
  });
563
369
 
564
370
  test('should preserve order of first occurrence', () => {
565
371
  const array = [3, 1, 2, 1, 3, 2];
566
- const result = Arr.uniq(array);
372
+ const result = uniq(array);
567
373
  expect(result).toStrictEqual([3, 1, 2]);
568
374
  });
569
375
  });
@@ -576,7 +382,7 @@ describe('Arr transformations', () => {
576
382
  { id: 1, name: 'Alice Duplicate' },
577
383
  { id: 3, name: 'Charlie' },
578
384
  ];
579
- const result = Arr.uniqBy(array, (item) => item.id);
385
+ const result = uniqBy(array, (item) => item.id);
580
386
 
581
387
  expect(result).toHaveLength(3);
582
388
  expect(result[0]).toStrictEqual({ id: 1, name: 'Alice' });
@@ -586,7 +392,7 @@ describe('Arr transformations', () => {
586
392
 
587
393
  test('should work with string key function', () => {
588
394
  const words = ['hello', 'world', 'hi', 'welcome'];
589
- const result = Arr.uniqBy(words, (word) => word.length);
395
+ const result = uniqBy(words, (word) => word.length);
590
396
 
591
397
  expect(result).toHaveLength(3);
592
398
  expect(result).toContain('hello'); // length 5
@@ -596,494 +402,43 @@ describe('Arr transformations', () => {
596
402
 
597
403
  test('should work with empty array', () => {
598
404
  const empty: readonly { id: number }[] = [];
599
- const result = Arr.uniqBy(empty, (item) => item.id);
405
+ const result = uniqBy(empty, (item) => item.id);
600
406
  expect(result).toStrictEqual([]);
601
407
  });
602
408
  });
603
409
 
604
- describe('map', () => {
605
- const mapped = Arr.map([1, 2, 3], (x, i): number => x * x * i);
606
-
607
- expectType<typeof mapped, ArrayOfLength<3, number>>('=');
608
-
609
- test('case 1', () => {
610
- expect(mapped).toStrictEqual([0, 4, 18]);
410
+ describe('flat', () => {
411
+ test('should flatten nested arrays with default depth 1', () => {
412
+ const nested = [
413
+ [1, 2],
414
+ [3, 4],
415
+ [5, 6],
416
+ ];
417
+ const flattened = flat(nested);
418
+ expect(flattened).toStrictEqual([1, 2, 3, 4, 5, 6]);
611
419
  });
612
420
 
613
- test('should work with empty tuple', () => {
614
- const empty = [] as const;
615
- const mappedEmpty = Arr.map(empty, (x) => String(x));
616
- expectType<typeof mappedEmpty, readonly []>('=');
617
- expect(mappedEmpty).toStrictEqual([]);
421
+ test('should flatten with specified depth', () => {
422
+ const deepNested = [1, [2, [3, 4]], 5];
423
+ const flat1 = flat(deepNested, 1);
424
+ const flat2 = flat(deepNested, 2);
425
+ expect(flat1).toStrictEqual([1, 2, [3, 4], 5]);
426
+ expect(flat2).toStrictEqual([1, 2, 3, 4, 5]);
618
427
  });
619
428
 
620
- test('should preserve tuple length with different types', () => {
621
- const mixed = [1, 'hello', true] as const;
622
- const mappedMixed = Arr.map(mixed, (x) => typeof x);
623
- expectType<typeof mappedMixed, readonly [string, string, string]>('<=');
624
- expect(mappedMixed).toStrictEqual(['number', 'string', 'boolean']);
429
+ test('should work with curried version', () => {
430
+ const flattenOnce = flat();
431
+ const result = flattenOnce([
432
+ [1, 2],
433
+ [3, 4],
434
+ ]);
435
+ expect(result).toStrictEqual([1, 2, 3, 4]);
625
436
  });
626
437
 
627
- test('should work with index parameter', () => {
628
- const tuple = ['a', 'b', 'c'] as const;
629
- const mappedWithIndex = Arr.map(tuple, (x, i) => `${i}:${x}`);
630
- expectType<typeof mappedWithIndex, readonly [string, string, string]>(
631
- '<=',
632
- );
633
- expect(mappedWithIndex).toStrictEqual(['0:a', '1:b', '2:c']);
634
- });
635
- });
636
-
637
- describe('toReversed', () => {
638
- {
639
- const xs = [1, 2, 3] as const;
640
- const _nativeResult = xs.toReversed();
641
-
642
- expectType<typeof _nativeResult, (1 | 2 | 3)[]>('=');
643
-
644
- const result = Arr.toReversed([1, 2, 3]);
645
-
646
- expectType<typeof result, readonly [3, 2, 1]>('=');
647
-
648
- test('case 1', () => {
649
- expect(result).toStrictEqual([3, 2, 1]);
650
- });
651
- }
652
-
653
- test('should work with empty tuple', () => {
654
- const empty = [] as const;
655
- const reversed = Arr.toReversed(empty);
656
- expectType<typeof reversed, readonly []>('=');
657
- expect(reversed).toStrictEqual([]);
658
- });
659
-
660
- test('should work with single element', () => {
661
- const single = [42] as const;
662
- const reversed = Arr.toReversed(single);
663
- expectType<typeof reversed, readonly [42]>('=');
664
- expect(reversed).toStrictEqual([42]);
665
- });
666
-
667
- test('should preserve mixed types in reverse order', () => {
668
- const mixed = [1, 'hello', true, null] as const;
669
- const reversed = Arr.toReversed(mixed);
670
- expectType<typeof reversed, readonly [null, true, 'hello', 1]>('=');
671
- expect(reversed).toStrictEqual([null, true, 'hello', 1]);
672
- });
673
- });
674
-
675
- describe('filter', () => {
676
- test('should filter array with predicate', () => {
677
- const numbers = [1, 2, 3, 4, 5];
678
- const evens = Arr.filter(numbers, (n) => n % 2 === 0);
679
- expect(evens).toStrictEqual([2, 4]);
680
- });
681
-
682
- test('should work with type guards', () => {
683
- const mixed: (string | number | null)[] = [
684
- 'hello',
685
- 42,
686
- null,
687
- 'world',
688
- 123,
689
- ];
690
- const strings = Arr.filter(
691
- mixed,
692
- (x): x is string => typeof x === 'string',
693
- );
694
- expectType<typeof strings, readonly string[]>('=');
695
- expect(strings).toStrictEqual(['hello', 'world']);
696
- });
697
-
698
- test('should work with curried version', () => {
699
- const isPositive = (n: number): boolean => n > 0;
700
- const filterPositive = Arr.filter(isPositive);
701
- const result = filterPositive([-1, 2, -3, 4]);
702
- expect(result).toStrictEqual([2, 4]);
703
- });
704
-
705
- test('should work with curried type guards', () => {
706
- const isString = (x: unknown): x is string => typeof x === 'string';
707
- const filterStrings = Arr.filter(isString);
708
- const result = filterStrings(['a', 1, 'b', 2]);
709
- expectType<typeof result, readonly string[]>('=');
710
- expect(result).toStrictEqual(['a', 'b']);
711
- });
712
-
713
- test('should preserve array type with generic predicate', () => {
714
- const tuple = [1, 2, 3] as const;
715
- const filtered = Arr.filter(tuple, (x) => x > 1);
716
- expectType<typeof filtered, readonly (1 | 2 | 3)[]>('=');
717
- expect(filtered).toStrictEqual([2, 3]);
718
- });
719
-
720
- test('should work with empty array', () => {
721
- const empty: number[] = [];
722
- const result = Arr.filter(empty, (n) => n > 0);
723
- expect(result).toStrictEqual([]);
724
- });
725
-
726
- test('should pass index to predicate', () => {
727
- const numbers = [10, 20, 30, 40];
728
- const evenIndexes = Arr.filter(numbers, (_, i) => i % 2 === 0);
729
- expect(evenIndexes).toStrictEqual([10, 30]);
730
- });
731
- });
732
-
733
- describe('every', () => {
734
- test('should return true when all elements satisfy predicate', () => {
735
- const evens = [2, 4, 6, 8];
736
- const allEven = Arr.every(evens, (n) => n % 2 === 0);
737
- expect(allEven).toBe(true);
738
- });
739
-
740
- test('should return false when not all elements satisfy predicate', () => {
741
- const mixed = [2, 3, 4, 6];
742
- const allEven = Arr.every(mixed, (n) => n % 2 === 0);
743
- expect(allEven).toBe(false);
744
- });
745
-
746
- test('should work as type guard', () => {
747
- const mixed: (string | number)[] = ['hello', 'world'];
748
- if (Arr.every(mixed, (x): x is string => typeof x === 'string')) {
749
- // TypeScript narrows mixed to readonly string[] here
750
- expect(mixed.every((s) => typeof s === 'string')).toBe(true);
751
- }
752
- });
753
-
754
- test('should work with curried version', () => {
755
- const isPositive = (n: number): boolean => n > 0;
756
- const allPositive = Arr.every(isPositive);
757
- expect(allPositive([1, 2, 3])).toBe(true);
758
- expect(allPositive([1, -2, 3])).toBe(false);
759
- });
760
-
761
- test('should work with curried type guards', () => {
762
- const isString = (x: unknown): x is string => typeof x === 'string';
763
- const allStrings = Arr.every(isString);
764
- const data: unknown[] = ['a', 'b', 'c'];
765
- if (allStrings(data)) {
766
- // TypeScript narrows data to readonly string[] here
767
- expect(data.join('')).toBe('abc');
768
- }
769
- });
770
-
771
- test('should return true for empty array', () => {
772
- const empty: number[] = [];
773
- const result = Arr.every(empty, (n) => n > 0);
774
- expect(result).toBe(true);
775
- });
776
-
777
- test('should pass index to predicate', () => {
778
- const numbers = [0, 1, 2, 3];
779
- const indexMatchesValue = Arr.every(numbers, (val, idx) => val === idx);
780
- expect(indexMatchesValue).toBe(true);
781
- });
782
- });
783
-
784
- describe('some', () => {
785
- test('should return true when at least one element satisfies predicate', () => {
786
- const numbers = [1, 3, 5, 8];
787
- const hasEven = Arr.some(numbers, (n) => n % 2 === 0);
788
- expect(hasEven).toBe(true);
789
- });
790
-
791
- test('should return false when no elements satisfy predicate', () => {
792
- const odds = [1, 3, 5, 7];
793
- const hasEven = Arr.some(odds, (n) => n % 2 === 0);
794
- expect(hasEven).toBe(false);
795
- });
796
-
797
- test('should work with curried version', () => {
798
- const isNegative = (n: number): boolean => n < 0;
799
- const hasNegative = Arr.some(isNegative);
800
- expect(hasNegative([1, 2, -3])).toBe(true);
801
- expect(hasNegative([1, 2, 3])).toBe(false);
802
- });
803
-
804
- test('should return false for empty array', () => {
805
- const empty: number[] = [];
806
- const result = Arr.some(empty, (n) => n > 0);
807
- expect(result).toBe(false);
808
- });
809
-
810
- test('should pass index to predicate', () => {
811
- const numbers = [10, 10, 10, 30];
812
- const hasValueMatchingIndex = Arr.some(
813
- numbers,
814
- (val, idx) => val === idx * 10,
815
- );
816
- expect(hasValueMatchingIndex).toBe(true);
817
- });
818
- });
819
-
820
- describe('entries', () => {
821
- test('should return array of index-value pairs', () => {
822
- const fruits = ['apple', 'banana', 'cherry'];
823
- const entries = Array.from(Arr.entries(fruits));
824
- expect(entries).toStrictEqual([
825
- [0, 'apple'],
826
- [1, 'banana'],
827
- [2, 'cherry'],
828
- ]);
829
- });
830
-
831
- test('should work with tuples', () => {
832
- const tuple = [10, 20, 30] as const;
833
- const entries = Array.from(Arr.entries(tuple));
834
- expectType<typeof entries, (readonly [Uint32, 10 | 20 | 30])[]>('=');
835
- expect(entries).toStrictEqual([
836
- [0, 10],
837
- [1, 20],
838
- [2, 30],
839
- ]);
840
- });
841
-
842
- test('should work with empty array', () => {
843
- const empty: string[] = [];
844
- const entries = Array.from(Arr.entries(empty));
845
- expect(entries).toStrictEqual([]);
846
- });
847
-
848
- test('should preserve mixed types', () => {
849
- const mixed = [1, 'hello', true] as const;
850
- const entries = Array.from(Arr.entries(mixed));
851
- expectType<typeof entries, (readonly [Uint32, 1 | 'hello' | true])[]>(
852
- '=',
853
- );
854
- expect(entries).toStrictEqual([
855
- [0, 1],
856
- [1, 'hello'],
857
- [2, true],
858
- ]);
859
- });
860
- });
861
-
862
- describe('values', () => {
863
- test('should return copy of array values', () => {
864
- const numbers = [1, 2, 3];
865
- const values = Array.from(Arr.values(numbers));
866
- expect(values).toStrictEqual([1, 2, 3]);
867
- expect(values).not.toBe(numbers); // Should be a copy
868
- });
869
-
870
- test('should work with tuples', () => {
871
- const tuple = ['a', 'b', 'c'] as const;
872
- const values = Array.from(Arr.values(tuple));
873
- expectType<typeof values, ('a' | 'b' | 'c')[]>('=');
874
- expect(values).toStrictEqual(['a', 'b', 'c']);
875
- });
876
-
877
- test('should work with empty array', () => {
878
- const empty: number[] = [];
879
- const values = Array.from(Arr.values(empty));
880
- expect(values).toStrictEqual([]);
881
- });
882
-
883
- test('should preserve mixed types', () => {
884
- const mixed = [1, 'hello', null] as const;
885
- const values = Array.from(Arr.values(mixed));
886
- expectType<typeof values, (1 | 'hello' | null)[]>('=');
887
- expect(values).toStrictEqual([1, 'hello', null]);
888
- });
889
- });
890
-
891
- describe('indices', () => {
892
- test('should return array of indices', () => {
893
- const fruits = ['apple', 'banana', 'cherry'];
894
- const indices = Array.from(Arr.indices(fruits));
895
- expect(indices).toStrictEqual([0, 1, 2]);
896
- });
897
-
898
- test('should work with tuples', () => {
899
- const tuple = ['a', 'b'] as const;
900
- const indices = Array.from(Arr.indices(tuple));
901
- expectType<typeof indices, Uint32[]>('=');
902
- expect(indices).toStrictEqual([0, 1]);
903
- });
904
-
905
- test('should work with empty array', () => {
906
- const empty: string[] = [];
907
- const indices = Array.from(Arr.indices(empty));
908
- expect(indices).toStrictEqual([]);
909
- });
910
-
911
- test('should work with larger arrays', () => {
912
- const large = Array.from({ length: 5 }, () => 'x');
913
- const indices = Array.from(Arr.indices(large));
914
- expect(indices).toStrictEqual([0, 1, 2, 3, 4]);
915
- });
916
- });
917
-
918
- describe('findLast', () => {
919
- test('should find last element matching predicate', () => {
920
- const numbers = [1, 2, 3, 4, 5];
921
- const lastEven = Arr.findLast(numbers, (n) => n % 2 === 0);
922
- expect(Optional.isSome(lastEven)).toBe(true);
923
- expect(Optional.unwrap(lastEven)).toBe(4);
924
- });
925
-
926
- test('should return None when no element matches', () => {
927
- const odds = [1, 3, 5];
928
- const lastEven = Arr.findLast(odds, (n) => n % 2 === 0);
929
- expect(Optional.isNone(lastEven)).toBe(true);
930
- });
931
-
932
- test('should work with curried version', () => {
933
- const isPositive = (n: number): boolean => n > 0;
934
- const findLastPositive = Arr.findLast(isPositive);
935
- const result = findLastPositive([-1, 2, -3, 4]);
936
- expect(Optional.isSome(result)).toBe(true);
937
- expect(Optional.unwrap(result)).toBe(4);
938
- });
939
-
940
- test('should work with empty array', () => {
941
- const empty: number[] = [];
942
- const result = Arr.findLast(empty, (n) => n > 0);
943
- expect(Optional.isNone(result)).toBe(true);
944
- });
945
-
946
- test('should pass index and array to predicate', () => {
947
- const numbers = [10, 20, 30, 40];
948
- const lastWithIndex2 = Arr.findLast(numbers, (_, idx, arr) => {
949
- expect(arr).toBe(numbers);
950
- return idx === 2;
951
- });
952
- expect(Optional.unwrap(lastWithIndex2)).toBe(30);
953
- });
954
-
955
- test('should find last occurrence', () => {
956
- const numbers = [1, 2, 2, 3, 2, 4];
957
- const lastTwo = Arr.findLast(numbers, (n) => n === 2);
958
- expect(Optional.unwrap(lastTwo)).toBe(2);
959
-
960
- // Verify it's actually the last occurrence by checking behavior
961
- const index = numbers.lastIndexOf(2);
962
- expect(index).toBe(4); // Last 2 is at index 4
963
- });
964
- });
965
-
966
- describe('findLastIndex', () => {
967
- test('should find last index matching predicate', () => {
968
- const numbers = [1, 2, 3, 4, 2, 5];
969
- const lastTwoIndex = Arr.findLastIndex(numbers, (n) => n === 2);
970
- expect(lastTwoIndex).toBe(4);
971
- });
972
-
973
- test('should return -1 when no element matches', () => {
974
- const odds = [1, 3, 5];
975
- const lastEvenIndex = Arr.findLastIndex(odds, (n) => n % 2 === 0);
976
- expect(lastEvenIndex).toBe(-1);
977
- });
978
-
979
- test('should work with curried version', () => {
980
- const isPositive = (n: number): boolean => n > 0;
981
- const findLastPositiveIndex = Arr.findLastIndex(isPositive);
982
- const result = findLastPositiveIndex([-1, 2, -3, 4, -5]);
983
- expect(result).toBe(3); // index of last positive number (4)
984
- });
985
-
986
- test('should work with empty array', () => {
987
- const empty: number[] = [];
988
- const result = Arr.findLastIndex(empty, (n) => n > 0);
989
- expect(result).toBe(-1);
990
- });
991
-
992
- test('should pass index and array to predicate', () => {
993
- const numbers = [10, 20, 30, 40];
994
- const lastWithIndex2OrHigher = Arr.findLastIndex(
995
- numbers,
996
- (_, idx, arr) => {
997
- expect(arr).toBe(numbers);
998
- return idx >= 2;
999
- },
1000
- );
1001
- expect(lastWithIndex2OrHigher).toBe(3); // last index >= 2
1002
- });
1003
-
1004
- test('should find last occurrence with complex conditions', () => {
1005
- const data = [
1006
- { id: 1, active: true },
1007
- { id: 2, active: false },
1008
- { id: 3, active: true },
1009
- { id: 4, active: false },
1010
- { id: 5, active: true },
1011
- ];
1012
- const lastActiveIndex = Arr.findLastIndex(data, (item) => item.active);
1013
- expect(lastActiveIndex).toBe(4); // last active item
1014
- });
1015
-
1016
- test('should work with tuples', () => {
1017
- const tuple = [10, 20, 30, 20, 40] as const;
1018
- const lastTwentyIndex = Arr.findLastIndex(tuple, (x) => x === 20);
1019
- expect(lastTwentyIndex).toBe(3); // last occurrence of 20
1020
- });
1021
-
1022
- test('should search from end to beginning', () => {
1023
- // Verify search order by using side effects
1024
- const numbers = [1, 2, 3, 4, 5];
1025
- const mut_searchOrder: number[] = [];
1026
-
1027
- Arr.findLastIndex(numbers, (val, idx) => {
1028
- mut_searchOrder.push(idx);
1029
- return val === 3;
1030
- });
1031
-
1032
- // Should search from end: 4, 3, 2 (stops at 2 when found)
1033
- expect(mut_searchOrder).toStrictEqual([4, 3, 2]);
1034
- });
1035
-
1036
- test('should handle single element array', () => {
1037
- const single = [42];
1038
- const foundIndex = Arr.findLastIndex(single, (n) => n === 42);
1039
- const notFoundIndex = Arr.findLastIndex(single, (n) => n === 0);
1040
-
1041
- expect(foundIndex).toBe(0);
1042
- expect(notFoundIndex).toBe(-1);
1043
- });
1044
-
1045
- test('should work with string arrays', () => {
1046
- const words = ['hello', 'world', 'test', 'hello', 'end'];
1047
- const lastHelloIndex = Arr.findLastIndex(
1048
- words,
1049
- (word) => word === 'hello',
1050
- );
1051
- expect(lastHelloIndex).toBe(3);
1052
- });
1053
- });
1054
-
1055
- describe('flat', () => {
1056
- test('should flatten nested arrays with default depth 1', () => {
1057
- const nested = [
1058
- [1, 2],
1059
- [3, 4],
1060
- [5, 6],
1061
- ];
1062
- const flattened = Arr.flat(nested);
1063
- expect(flattened).toStrictEqual([1, 2, 3, 4, 5, 6]);
1064
- });
1065
-
1066
- test('should flatten with specified depth', () => {
1067
- const deepNested = [1, [2, [3, 4]], 5];
1068
- const flat1 = Arr.flat(deepNested, 1);
1069
- const flat2 = Arr.flat(deepNested, 2);
1070
- expect(flat1).toStrictEqual([1, 2, [3, 4], 5]);
1071
- expect(flat2).toStrictEqual([1, 2, 3, 4, 5]);
1072
- });
1073
-
1074
- test('should work with curried version', () => {
1075
- const flattenOnce = Arr.flat(1);
1076
- const result = flattenOnce([
1077
- [1, 2],
1078
- [3, 4],
1079
- ]);
1080
- expect(result).toStrictEqual([1, 2, 3, 4]);
1081
- });
1082
-
1083
- test('should work with empty arrays', () => {
1084
- const withEmpties = [[1], [], [2, 3]];
1085
- const flattened = Arr.flat(withEmpties);
1086
- expect(flattened).toStrictEqual([1, 2, 3]);
438
+ test('should work with empty arrays', () => {
439
+ const withEmpties = [[1], [], [2, 3]];
440
+ const flattened = flat(withEmpties);
441
+ expect(flattened).toStrictEqual([1, 2, 3]);
1087
442
  });
1088
443
 
1089
444
  test('should work with depth 0', () => {
@@ -1091,7 +446,7 @@ describe('Arr transformations', () => {
1091
446
  [1, 2],
1092
447
  [3, 4],
1093
448
  ];
1094
- const unflattened = Arr.flat(nested, 0);
449
+ const unflattened = flat(nested, 0);
1095
450
  expect(unflattened).toStrictEqual([
1096
451
  [1, 2],
1097
452
  [3, 4],
@@ -1100,7 +455,7 @@ describe('Arr transformations', () => {
1100
455
 
1101
456
  test('should work with infinite depth', () => {
1102
457
  const veryDeep = [1, [2, [3, [4, [5]]]]];
1103
- const allFlat = Arr.flat(veryDeep, SafeUint.MAX_VALUE);
458
+ const allFlat = flat(veryDeep, SafeUint.MAX_VALUE);
1104
459
  expect(allFlat).toStrictEqual([1, 2, 3, 4, 5]);
1105
460
  });
1106
461
  });
@@ -1108,7 +463,7 @@ describe('Arr transformations', () => {
1108
463
  describe('flatMap', () => {
1109
464
  test('should map and flatten results', () => {
1110
465
  const words = ['hello', 'world'];
1111
- const chars = Arr.flatMap(words, (word) => word.split(''));
466
+ const chars = flatMap(words, (word) => word.split(''));
1112
467
  expect(chars).toStrictEqual([
1113
468
  'h',
1114
469
  'e',
@@ -1124,39 +479,457 @@ describe('Arr transformations', () => {
1124
479
  });
1125
480
 
1126
481
  test('should work with curried version', () => {
1127
- const splitWords = Arr.flatMap((word: string) => word.split(''));
482
+ const splitWords = flatMap((word: string) => word.split(''));
1128
483
  const result = splitWords(['foo', 'bar']);
1129
484
  expect(result).toStrictEqual(['f', 'o', 'o', 'b', 'a', 'r']);
1130
485
  });
1131
486
 
1132
487
  test('should work with numbers', () => {
1133
488
  const numbers = [1, 2, 3];
1134
- const doubled = Arr.flatMap(numbers, (n) => [n, n * 2]);
489
+ const doubled = flatMap(numbers, (n) => [n, n * 2]);
1135
490
  expect(doubled).toStrictEqual([1, 2, 2, 4, 3, 6]);
1136
491
  });
1137
492
 
1138
493
  test('should pass index to mapping function', () => {
1139
494
  const numbers = [10, 20];
1140
- const result = Arr.flatMap(numbers, (n, i) => [n, i]);
495
+ const result = flatMap(numbers, (n, i) => [n, i]);
1141
496
  expect(result).toStrictEqual([10, 0, 20, 1]);
1142
497
  });
1143
498
 
1144
499
  test('should work with empty arrays', () => {
1145
500
  const empty: string[] = [];
1146
- const result = Arr.flatMap(empty, (s) => s.split(''));
501
+ const result = flatMap(empty, (s) => s.split(''));
1147
502
  expect(result).toStrictEqual([]);
1148
503
  });
1149
504
 
1150
505
  test('should handle mapping to empty arrays', () => {
1151
506
  const numbers = [1, 2, 3];
1152
- const result = Arr.flatMap(numbers, (n) => (n % 2 === 0 ? [n] : []));
507
+ const result = flatMap(numbers, (n) => (n % 2 === 0 ? [n] : []));
1153
508
  expect(result).toStrictEqual([2]);
1154
509
  });
1155
510
 
1156
511
  test('should work with tuples', () => {
1157
512
  const tuple = [1, 2] as const;
1158
- const result = Arr.flatMap(tuple, (n) => [n, n]);
513
+ const result = flatMap(tuple, (n) => [n, n]);
1159
514
  expect(result).toStrictEqual([1, 1, 2, 2]);
1160
515
  });
1161
516
  });
517
+
518
+ describe('partition', () => {
519
+ const xs = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12] as const;
520
+
521
+ {
522
+ const result = partition(xs, 4);
523
+
524
+ expectType<
525
+ typeof result,
526
+ readonly (readonly (
527
+ | 1
528
+ | 2
529
+ | 3
530
+ | 4
531
+ | 5
532
+ | 6
533
+ | 7
534
+ | 8
535
+ | 9
536
+ | 10
537
+ | 11
538
+ | 12
539
+ )[])[]
540
+ >('=');
541
+
542
+ test('case 1', () => {
543
+ expect(result).toStrictEqual([
544
+ [1, 2, 3, 4],
545
+ [5, 6, 7, 8],
546
+ [9, 10, 11, 12],
547
+ ]);
548
+ });
549
+ }
550
+
551
+ {
552
+ const result = partition(xs, 3);
553
+
554
+ expectType<
555
+ typeof result,
556
+ readonly (readonly (
557
+ | 1
558
+ | 2
559
+ | 3
560
+ | 4
561
+ | 5
562
+ | 6
563
+ | 7
564
+ | 8
565
+ | 9
566
+ | 10
567
+ | 11
568
+ | 12
569
+ )[])[]
570
+ >('=');
571
+
572
+ test('case 2', () => {
573
+ expect(result).toStrictEqual([
574
+ [1, 2, 3],
575
+ [4, 5, 6],
576
+ [7, 8, 9],
577
+ [10, 11, 12],
578
+ ]);
579
+ });
580
+ }
581
+
582
+ {
583
+ const result = partition(xs, 5);
584
+
585
+ expectType<
586
+ typeof result,
587
+ readonly (readonly (
588
+ | 1
589
+ | 2
590
+ | 3
591
+ | 4
592
+ | 5
593
+ | 6
594
+ | 7
595
+ | 8
596
+ | 9
597
+ | 10
598
+ | 11
599
+ | 12
600
+ )[])[]
601
+ >('=');
602
+
603
+ test('case 3', () => {
604
+ expect(result).toStrictEqual([
605
+ [1, 2, 3, 4, 5],
606
+ [6, 7, 8, 9, 10],
607
+ [11, 12],
608
+ ]);
609
+ });
610
+ }
611
+
612
+ test('should partition array into chunks', () => {
613
+ const numbers = [1, 2, 3, 4, 5, 6];
614
+ const result = partition(numbers, 2);
615
+
616
+ expect(result).toStrictEqual([
617
+ [1, 2],
618
+ [3, 4],
619
+ [5, 6],
620
+ ]);
621
+ });
622
+
623
+ test('should handle arrays not evenly divisible by chunk size', () => {
624
+ const numbers = [1, 2, 3, 4, 5];
625
+ const result = partition(numbers, 2);
626
+
627
+ expect(result).toStrictEqual([[1, 2], [3, 4], [5]]);
628
+ });
629
+
630
+ test('should work with chunk size < 2 (returns empty)', () => {
631
+ const numbers = [1, 2, 3];
632
+ const result = partition(numbers, 1);
633
+
634
+ // According to docs, returns empty array if chunkSize < 2
635
+ expect(result).toStrictEqual([]);
636
+ });
637
+
638
+ test('should work with chunk size larger than array', () => {
639
+ const numbers = [1, 2];
640
+ const result = partition(numbers, 5);
641
+
642
+ expect(result).toStrictEqual([[1, 2]]);
643
+ });
644
+
645
+ test('partition should work with empty array', () => {
646
+ const empty: readonly number[] = [];
647
+ const result = partition(empty, 2);
648
+
649
+ expect(result).toStrictEqual([]);
650
+ });
651
+ });
652
+
653
+ describe('concat', () => {
654
+ const xs = [1, 2, 3] as const;
655
+ const ys = [4, 5] as const;
656
+ const result = concat(xs, ys);
657
+
658
+ expectType<typeof result, readonly [1, 2, 3, 4, 5]>('=');
659
+
660
+ test('case 1', () => {
661
+ expect(result).toStrictEqual([1, 2, 3, 4, 5]);
662
+ });
663
+
664
+ // testArrayEquality({
665
+ // testName: 'concat 2 arrays',
666
+ // target: concat([1, 2, 3], [4, 5, 6]),
667
+ // toBe: [1, 2, 3, 4, 5, 6],
668
+ // });
669
+
670
+ // testArrayEquality({
671
+ // testName: 'concat 2 arrays',
672
+ // target: concat([1, 2, 3], []),
673
+ // toBe: [1, 2, 3],
674
+ // });
675
+
676
+ // testArrayEquality({
677
+ // testName: 'concat 2 arrays',
678
+ // target: concat([], [4, 5, 6]),
679
+ // toBe: [4, 5, 6],
680
+ // });
681
+
682
+ // testArrayEquality({
683
+ // testName: 'concat 2 arrays',
684
+ // target: concat([], []),
685
+ // toBe: [],
686
+ // });
687
+
688
+ // testArrayEquality({
689
+ // testName: 'concat 2 arrays',
690
+ // target: concat(['1', '2', '3'], [4, 5, 6]),
691
+ // toBe: ['1', '2', '3', 4, 5, 6],
692
+ // });
693
+ });
694
+
695
+ describe('groupBy', () => {
696
+ const xs = [
697
+ { x: 1, y: 1 },
698
+ { x: 2, y: 1 },
699
+ { x: 3, y: 1 },
700
+ { x: 1, y: 2 },
701
+ { x: 2, y: 2 },
702
+ { x: 1, y: 3 },
703
+ ] as const;
704
+
705
+ const result = groupBy(xs, (a) => a.x);
706
+
707
+ expectType<
708
+ typeof result,
709
+ IMap<
710
+ 1 | 2 | 3,
711
+ readonly (
712
+ | Readonly<{ x: 1; y: 1 }>
713
+ | Readonly<{ x: 1; y: 2 }>
714
+ | Readonly<{ x: 1; y: 3 }>
715
+ | Readonly<{ x: 2; y: 1 }>
716
+ | Readonly<{ x: 2; y: 2 }>
717
+ | Readonly<{ x: 3; y: 1 }>
718
+ )[]
719
+ >
720
+ >('=');
721
+
722
+ test('case 1', () => {
723
+ expect(result).toStrictEqual(
724
+ IMap.create<
725
+ 1 | 2 | 3,
726
+ readonly (
727
+ | Readonly<{ x: 1; y: 1 }>
728
+ | Readonly<{ x: 1; y: 2 }>
729
+ | Readonly<{ x: 1; y: 3 }>
730
+ | Readonly<{ x: 2; y: 1 }>
731
+ | Readonly<{ x: 2; y: 2 }>
732
+ | Readonly<{ x: 3; y: 1 }>
733
+ )[]
734
+ >([
735
+ [
736
+ 1,
737
+ [
738
+ { x: 1, y: 1 },
739
+ { x: 1, y: 2 },
740
+ { x: 1, y: 3 },
741
+ ],
742
+ ],
743
+ [
744
+ 2,
745
+ [
746
+ { x: 2, y: 1 },
747
+ { x: 2, y: 2 },
748
+ ],
749
+ ],
750
+ [3, [{ x: 3, y: 1 }]],
751
+ ]),
752
+ );
753
+ });
754
+
755
+ test('should group elements by key', () => {
756
+ const array = [
757
+ { type: 'fruit', name: 'apple' },
758
+ { type: 'vegetable', name: 'carrot' },
759
+ { type: 'fruit', name: 'banana' },
760
+ ];
761
+ const grouped = groupBy(array, (item) => item.type);
762
+
763
+ expect(grouped.size).toBe(2);
764
+ const fruits = grouped.get('fruit');
765
+ const vegetables = grouped.get('vegetable');
766
+
767
+ expect(Optional.isSome(fruits)).toBe(true);
768
+ expect(Optional.isSome(vegetables)).toBe(true);
769
+
770
+ if (Optional.isSome(fruits)) {
771
+ expect(fruits.value).toHaveLength(2);
772
+ expect(fruits.value[0]?.name).toBe('apple');
773
+ expect(fruits.value[1]?.name).toBe('banana');
774
+ }
775
+
776
+ if (Optional.isSome(vegetables)) {
777
+ expect(vegetables.value).toHaveLength(1);
778
+ expect(vegetables.value[0]?.name).toBe('carrot');
779
+ }
780
+ });
781
+
782
+ test('should work with numeric keys', () => {
783
+ const numbers = [1, 2, 3, 4, 5, 6];
784
+ const grouped = groupBy(numbers, (n) => n % 2);
785
+
786
+ expect(grouped.size).toBe(2);
787
+ const evens = grouped.get(0);
788
+ const odds = grouped.get(1);
789
+
790
+ if (Optional.isSome(evens)) {
791
+ expect(evens.value).toStrictEqual([2, 4, 6]);
792
+ }
793
+
794
+ if (Optional.isSome(odds)) {
795
+ expect(odds.value).toStrictEqual([1, 3, 5]);
796
+ }
797
+ });
798
+
799
+ test('should work with empty array', () => {
800
+ const empty: readonly number[] = [];
801
+ const grouped = groupBy(empty, (n) => n % 2);
802
+ expect(grouped.size).toBe(0);
803
+ });
804
+
805
+ test('should handle all elements in same group', () => {
806
+ const array = [1, 2, 3, 4];
807
+ const grouped = groupBy(array, () => 'all');
808
+
809
+ expect(grouped.size).toBe(1);
810
+ const all = grouped.get('all');
811
+
812
+ if (Optional.isSome(all)) {
813
+ expect(all.value).toStrictEqual([1, 2, 3, 4]);
814
+ }
815
+ });
816
+ });
817
+
818
+ describe('zip', () => {
819
+ {
820
+ const xs = [1, 2, 3] as const;
821
+ const ys = [4, 5, 6] as const;
822
+ const zipped = zip(xs, ys);
823
+
824
+ expectType<
825
+ typeof zipped,
826
+ readonly [readonly [1, 4], readonly [2, 5], readonly [3, 6]]
827
+ >('=');
828
+
829
+ test('case 1', () => {
830
+ expect(zipped).toStrictEqual([
831
+ [1, 4],
832
+ [2, 5],
833
+ [3, 6],
834
+ ]);
835
+ });
836
+ }
837
+ {
838
+ const xs: readonly number[] = [1, 2, 3];
839
+ const ys: readonly number[] = [4];
840
+ const zipped = zip(xs, ys);
841
+
842
+ expectType<typeof zipped, readonly (readonly [number, number])[]>('=');
843
+
844
+ test('case 2', () => {
845
+ expect(zipped).toStrictEqual([[1, 4]]);
846
+ });
847
+ }
848
+ {
849
+ const xs = [1] as const;
850
+ const ys: readonly number[] = [4, 5, 6];
851
+ const zipped = zip(xs, ys);
852
+
853
+ expectType<typeof zipped, readonly [readonly [1, number]]>('=');
854
+
855
+ test('case 3', () => {
856
+ expect(zipped).toStrictEqual([[1, 4]]);
857
+ });
858
+ }
859
+
860
+ // testArrayEquality({
861
+ // testName: 'zip',
862
+ // target: zip([0, 1, 2, 3, 4], [5, 6, 7, 8, 9]),
863
+ // toBe: [
864
+ // [0, 5],
865
+ // [1, 6],
866
+ // [2, 7],
867
+ // [3, 8],
868
+ // [4, 9],
869
+ // ],
870
+ // });
871
+
872
+ // testArrayEquality({
873
+ // testName: 'zipArrays 2 arrays',
874
+ // target: zipArrays([0, 1, 2, 3, 4], [5, 6, 7, 8, 9]),
875
+ // toBe: [
876
+ // [0, 5],
877
+ // [1, 6],
878
+ // [2, 7],
879
+ // [3, 8],
880
+ // [4, 9],
881
+ // ],
882
+ // });
883
+
884
+ // testArrayEquality({
885
+ // testName: 'zipArrays 3 arrays',
886
+ // target: zipArrays(
887
+ // [0, 1, 2, 3, 4],
888
+ // [5, 6, 7, 8, 9, 999, 999],
889
+ // [10, 11, 12, 13, 14, 999]
890
+ // ),
891
+ // toBe: [
892
+ // [0, 5, 10],
893
+ // [1, 6, 11],
894
+ // [2, 7, 12],
895
+ // [3, 8, 13],
896
+ // [4, 9, 14],
897
+ // ],
898
+ // });
899
+
900
+ test('should zip two arrays', () => {
901
+ const arr1 = [1, 2, 3];
902
+ const arr2 = ['a', 'b', 'c'];
903
+ const result = zip(arr1, arr2);
904
+ expect(result).toStrictEqual([
905
+ [1, 'a'],
906
+ [2, 'b'],
907
+ [3, 'c'],
908
+ ]);
909
+ });
910
+
911
+ test('should handle arrays of different lengths', () => {
912
+ const arr1 = [1, 2, 3, 4];
913
+ const arr2 = ['a', 'b'];
914
+ const result = zip(arr1, arr2);
915
+ expect(result).toStrictEqual([
916
+ [1, 'a'],
917
+ [2, 'b'],
918
+ ]);
919
+ });
920
+
921
+ test('should work with empty arrays', () => {
922
+ const arr1: readonly number[] = [];
923
+ const arr2: readonly string[] = [];
924
+ const result = zip(arr1, arr2);
925
+ expect(result).toStrictEqual([]);
926
+ });
927
+
928
+ test('should handle one empty array', () => {
929
+ const arr1 = [1, 2, 3];
930
+ const arr2: readonly string[] = [];
931
+ const result = zip(arr1, arr2);
932
+ expect(result).toStrictEqual([]);
933
+ });
934
+ });
1162
935
  });