@fluixi/utils 1.0.0-alpha.53

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 (354) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +73 -0
  3. package/dist/index.cjs +1 -0
  4. package/dist/index.d.ts +2 -0
  5. package/dist/index.d.ts.map +1 -0
  6. package/dist/index.js +1 -0
  7. package/dist/index.mjs +1 -0
  8. package/dist/lib/array/advanced.cjs +1 -0
  9. package/dist/lib/array/advanced.d.ts +1116 -0
  10. package/dist/lib/array/advanced.d.ts.map +1 -0
  11. package/dist/lib/array/advanced.js +2429 -0
  12. package/dist/lib/array/advanced.mjs +1 -0
  13. package/dist/lib/array/array.cjs +1 -0
  14. package/dist/lib/array/array.d.ts +6 -0
  15. package/dist/lib/array/array.d.ts.map +1 -0
  16. package/dist/lib/array/array.js +31 -0
  17. package/dist/lib/array/array.mjs +1 -0
  18. package/dist/lib/array/index.cjs +1 -0
  19. package/dist/lib/array/index.d.ts +4 -0
  20. package/dist/lib/array/index.d.ts.map +1 -0
  21. package/dist/lib/array/index.js +3 -0
  22. package/dist/lib/array/index.mjs +1 -0
  23. package/dist/lib/array/utils.cjs +1 -0
  24. package/dist/lib/array/utils.d.ts +100 -0
  25. package/dist/lib/array/utils.d.ts.map +1 -0
  26. package/dist/lib/array/utils.js +165 -0
  27. package/dist/lib/array/utils.mjs +1 -0
  28. package/dist/lib/color/color.cjs +1 -0
  29. package/dist/lib/color/color.d.ts +366 -0
  30. package/dist/lib/color/color.d.ts.map +1 -0
  31. package/dist/lib/color/color.js +722 -0
  32. package/dist/lib/color/color.mjs +1 -0
  33. package/dist/lib/color/constants.cjs +1 -0
  34. package/dist/lib/color/constants.d.ts +361 -0
  35. package/dist/lib/color/constants.d.ts.map +1 -0
  36. package/dist/lib/color/constants.js +358 -0
  37. package/dist/lib/color/constants.mjs +1 -0
  38. package/dist/lib/color/conversions.cjs +1 -0
  39. package/dist/lib/color/conversions.d.ts +166 -0
  40. package/dist/lib/color/conversions.d.ts.map +1 -0
  41. package/dist/lib/color/conversions.js +766 -0
  42. package/dist/lib/color/conversions.mjs +1 -0
  43. package/dist/lib/color/helpers.cjs +1 -0
  44. package/dist/lib/color/helpers.d.ts +75 -0
  45. package/dist/lib/color/helpers.d.ts.map +1 -0
  46. package/dist/lib/color/helpers.js +419 -0
  47. package/dist/lib/color/helpers.mjs +1 -0
  48. package/dist/lib/color/index.cjs +1 -0
  49. package/dist/lib/color/index.d.ts +12 -0
  50. package/dist/lib/color/index.d.ts.map +1 -0
  51. package/dist/lib/color/index.js +15 -0
  52. package/dist/lib/color/index.mjs +1 -0
  53. package/dist/lib/color/types.cjs +1 -0
  54. package/dist/lib/color/types.d.ts +179 -0
  55. package/dist/lib/color/types.d.ts.map +1 -0
  56. package/dist/lib/color/types.js +1 -0
  57. package/dist/lib/color/types.mjs +0 -0
  58. package/dist/lib/color/utils.cjs +1 -0
  59. package/dist/lib/color/utils.d.ts +199 -0
  60. package/dist/lib/color/utils.d.ts.map +1 -0
  61. package/dist/lib/color/utils.js +858 -0
  62. package/dist/lib/color/utils.mjs +1 -0
  63. package/dist/lib/compare/comparators.cjs +1 -0
  64. package/dist/lib/compare/comparators.d.ts +65 -0
  65. package/dist/lib/compare/comparators.d.ts.map +1 -0
  66. package/dist/lib/compare/comparators.js +210 -0
  67. package/dist/lib/compare/comparators.mjs +1 -0
  68. package/dist/lib/compare/index.cjs +1 -0
  69. package/dist/lib/compare/index.d.ts +2 -0
  70. package/dist/lib/compare/index.d.ts.map +1 -0
  71. package/dist/lib/compare/index.js +1 -0
  72. package/dist/lib/compare/index.mjs +1 -0
  73. package/dist/lib/crypto/hash.cjs +1 -0
  74. package/dist/lib/crypto/hash.d.ts +6 -0
  75. package/dist/lib/crypto/hash.d.ts.map +1 -0
  76. package/dist/lib/crypto/hash.js +53 -0
  77. package/dist/lib/crypto/hash.mjs +1 -0
  78. package/dist/lib/crypto/index.cjs +1 -0
  79. package/dist/lib/crypto/index.d.ts +2 -0
  80. package/dist/lib/crypto/index.d.ts.map +1 -0
  81. package/dist/lib/crypto/index.js +1 -0
  82. package/dist/lib/crypto/index.mjs +1 -0
  83. package/dist/lib/dom/events.cjs +1 -0
  84. package/dist/lib/dom/events.d.ts +159 -0
  85. package/dist/lib/dom/events.d.ts.map +1 -0
  86. package/dist/lib/dom/events.js +50 -0
  87. package/dist/lib/dom/events.mjs +1 -0
  88. package/dist/lib/dom/index.cjs +1 -0
  89. package/dist/lib/dom/index.d.ts +3 -0
  90. package/dist/lib/dom/index.d.ts.map +1 -0
  91. package/dist/lib/dom/index.js +2 -0
  92. package/dist/lib/dom/index.mjs +1 -0
  93. package/dist/lib/dom/utils.cjs +1 -0
  94. package/dist/lib/dom/utils.d.ts +6 -0
  95. package/dist/lib/dom/utils.d.ts.map +1 -0
  96. package/dist/lib/dom/utils.js +37 -0
  97. package/dist/lib/dom/utils.mjs +1 -0
  98. package/dist/lib/functions/functions.cjs +1 -0
  99. package/dist/lib/functions/functions.d.ts +329 -0
  100. package/dist/lib/functions/functions.d.ts.map +1 -0
  101. package/dist/lib/functions/functions.js +585 -0
  102. package/dist/lib/functions/functions.mjs +1 -0
  103. package/dist/lib/functions/index.cjs +1 -0
  104. package/dist/lib/functions/index.d.ts +3 -0
  105. package/dist/lib/functions/index.d.ts.map +1 -0
  106. package/dist/lib/functions/index.js +1 -0
  107. package/dist/lib/functions/index.mjs +1 -0
  108. package/dist/lib/functions/types.cjs +1 -0
  109. package/dist/lib/functions/types.d.ts +2 -0
  110. package/dist/lib/functions/types.d.ts.map +1 -0
  111. package/dist/lib/functions/types.js +1 -0
  112. package/dist/lib/functions/types.mjs +0 -0
  113. package/dist/lib/helpers.cjs +1 -0
  114. package/dist/lib/helpers.d.ts +13 -0
  115. package/dist/lib/helpers.d.ts.map +1 -0
  116. package/dist/lib/helpers.js +66 -0
  117. package/dist/lib/helpers.mjs +1 -0
  118. package/dist/lib/index.cjs +1 -0
  119. package/dist/lib/index.d.ts +6 -0
  120. package/dist/lib/index.d.ts.map +1 -0
  121. package/dist/lib/index.js +8 -0
  122. package/dist/lib/index.mjs +1 -0
  123. package/dist/lib/maths/constants.cjs +1 -0
  124. package/dist/lib/maths/constants.d.ts +84 -0
  125. package/dist/lib/maths/constants.d.ts.map +1 -0
  126. package/dist/lib/maths/constants.js +79 -0
  127. package/dist/lib/maths/constants.mjs +1 -0
  128. package/dist/lib/maths/fn/advanced.cjs +1 -0
  129. package/dist/lib/maths/fn/advanced.d.ts +149 -0
  130. package/dist/lib/maths/fn/advanced.d.ts.map +1 -0
  131. package/dist/lib/maths/fn/advanced.js +264 -0
  132. package/dist/lib/maths/fn/advanced.mjs +1 -0
  133. package/dist/lib/maths/fn/basic.cjs +1 -0
  134. package/dist/lib/maths/fn/basic.d.ts +182 -0
  135. package/dist/lib/maths/fn/basic.d.ts.map +1 -0
  136. package/dist/lib/maths/fn/basic.js +343 -0
  137. package/dist/lib/maths/fn/basic.mjs +1 -0
  138. package/dist/lib/maths/fn/complex.cjs +1 -0
  139. package/dist/lib/maths/fn/complex.d.ts +153 -0
  140. package/dist/lib/maths/fn/complex.d.ts.map +1 -0
  141. package/dist/lib/maths/fn/complex.js +383 -0
  142. package/dist/lib/maths/fn/complex.mjs +1 -0
  143. package/dist/lib/maths/fn/index.cjs +1 -0
  144. package/dist/lib/maths/fn/index.d.ts +10 -0
  145. package/dist/lib/maths/fn/index.d.ts.map +1 -0
  146. package/dist/lib/maths/fn/index.js +9 -0
  147. package/dist/lib/maths/fn/index.mjs +1 -0
  148. package/dist/lib/maths/fn/trigo.cjs +1 -0
  149. package/dist/lib/maths/fn/trigo.d.ts +147 -0
  150. package/dist/lib/maths/fn/trigo.d.ts.map +1 -0
  151. package/dist/lib/maths/fn/trigo.js +227 -0
  152. package/dist/lib/maths/fn/trigo.mjs +1 -0
  153. package/dist/lib/maths/fn/vector.cjs +1 -0
  154. package/dist/lib/maths/fn/vector.d.ts +512 -0
  155. package/dist/lib/maths/fn/vector.d.ts.map +1 -0
  156. package/dist/lib/maths/fn/vector.js +1136 -0
  157. package/dist/lib/maths/fn/vector.mjs +1 -0
  158. package/dist/lib/maths/formatter.cjs +1 -0
  159. package/dist/lib/maths/formatter.d.ts +35 -0
  160. package/dist/lib/maths/formatter.d.ts.map +1 -0
  161. package/dist/lib/maths/formatter.js +56 -0
  162. package/dist/lib/maths/formatter.mjs +1 -0
  163. package/dist/lib/maths/guards.cjs +1 -0
  164. package/dist/lib/maths/guards.d.ts +166 -0
  165. package/dist/lib/maths/guards.d.ts.map +1 -0
  166. package/dist/lib/maths/guards.js +315 -0
  167. package/dist/lib/maths/guards.mjs +1 -0
  168. package/dist/lib/maths/index.cjs +1 -0
  169. package/dist/lib/maths/index.d.ts +24 -0
  170. package/dist/lib/maths/index.d.ts.map +1 -0
  171. package/dist/lib/maths/index.js +29 -0
  172. package/dist/lib/maths/index.mjs +1 -0
  173. package/dist/lib/maths/parser.cjs +1 -0
  174. package/dist/lib/maths/parser.d.ts +20 -0
  175. package/dist/lib/maths/parser.d.ts.map +1 -0
  176. package/dist/lib/maths/parser.js +78 -0
  177. package/dist/lib/maths/parser.mjs +1 -0
  178. package/dist/lib/maths/random.cjs +1 -0
  179. package/dist/lib/maths/random.d.ts +27 -0
  180. package/dist/lib/maths/random.d.ts.map +1 -0
  181. package/dist/lib/maths/random.js +49 -0
  182. package/dist/lib/maths/random.mjs +1 -0
  183. package/dist/lib/maths/types/advanced.cjs +1 -0
  184. package/dist/lib/maths/types/advanced.d.ts +357 -0
  185. package/dist/lib/maths/types/advanced.d.ts.map +1 -0
  186. package/dist/lib/maths/types/advanced.js +5 -0
  187. package/dist/lib/maths/types/advanced.mjs +0 -0
  188. package/dist/lib/maths/types/basic.cjs +1 -0
  189. package/dist/lib/maths/types/basic.d.ts +95 -0
  190. package/dist/lib/maths/types/basic.d.ts.map +1 -0
  191. package/dist/lib/maths/types/basic.js +5 -0
  192. package/dist/lib/maths/types/basic.mjs +0 -0
  193. package/dist/lib/maths/types/index.cjs +1 -0
  194. package/dist/lib/maths/types/index.d.ts +4 -0
  195. package/dist/lib/maths/types/index.d.ts.map +1 -0
  196. package/dist/lib/maths/types/index.js +3 -0
  197. package/dist/lib/maths/types/index.mjs +0 -0
  198. package/dist/lib/maths/types/negative.cjs +1 -0
  199. package/dist/lib/maths/types/negative.d.ts +51 -0
  200. package/dist/lib/maths/types/negative.d.ts.map +1 -0
  201. package/dist/lib/maths/types/negative.js +5 -0
  202. package/dist/lib/maths/types/negative.mjs +0 -0
  203. package/dist/lib/maths/types/operations.cjs +1 -0
  204. package/dist/lib/maths/types/operations.d.ts +188 -0
  205. package/dist/lib/maths/types/operations.d.ts.map +1 -0
  206. package/dist/lib/maths/types/operations.js +6 -0
  207. package/dist/lib/maths/types/operations.mjs +0 -0
  208. package/dist/lib/object/clone.cjs +1 -0
  209. package/dist/lib/object/clone.d.ts +46 -0
  210. package/dist/lib/object/clone.d.ts.map +1 -0
  211. package/dist/lib/object/clone.js +104 -0
  212. package/dist/lib/object/clone.mjs +1 -0
  213. package/dist/lib/object/diff.cjs +1 -0
  214. package/dist/lib/object/diff.d.ts +203 -0
  215. package/dist/lib/object/diff.d.ts.map +1 -0
  216. package/dist/lib/object/diff.js +805 -0
  217. package/dist/lib/object/diff.mjs +1 -0
  218. package/dist/lib/object/getter-setter.cjs +1 -0
  219. package/dist/lib/object/getter-setter.d.ts +361 -0
  220. package/dist/lib/object/getter-setter.d.ts.map +1 -0
  221. package/dist/lib/object/getter-setter.js +1771 -0
  222. package/dist/lib/object/getter-setter.mjs +1 -0
  223. package/dist/lib/object/index.cjs +6 -0
  224. package/dist/lib/object/index.d.ts +13 -0
  225. package/dist/lib/object/index.d.ts.map +1 -0
  226. package/dist/lib/object/index.js +12 -0
  227. package/dist/lib/object/index.mjs +6 -0
  228. package/dist/lib/object/merge.cjs +1 -0
  229. package/dist/lib/object/merge.d.ts +93 -0
  230. package/dist/lib/object/merge.d.ts.map +1 -0
  231. package/dist/lib/object/merge.js +474 -0
  232. package/dist/lib/object/merge.mjs +1 -0
  233. package/dist/lib/object/object.cjs +1 -0
  234. package/dist/lib/object/object.d.ts +128 -0
  235. package/dist/lib/object/object.d.ts.map +1 -0
  236. package/dist/lib/object/object.js +432 -0
  237. package/dist/lib/object/object.mjs +1 -0
  238. package/dist/lib/object/omit.cjs +1 -0
  239. package/dist/lib/object/omit.d.ts +351 -0
  240. package/dist/lib/object/omit.d.ts.map +1 -0
  241. package/dist/lib/object/omit.js +656 -0
  242. package/dist/lib/object/omit.mjs +1 -0
  243. package/dist/lib/object/reconcile.cjs +1 -0
  244. package/dist/lib/object/reconcile.d.ts +7 -0
  245. package/dist/lib/object/reconcile.d.ts.map +1 -0
  246. package/dist/lib/object/reconcile.js +122 -0
  247. package/dist/lib/object/reconcile.mjs +1 -0
  248. package/dist/lib/object/selector.cjs +1 -0
  249. package/dist/lib/object/selector.d.ts +50 -0
  250. package/dist/lib/object/selector.d.ts.map +1 -0
  251. package/dist/lib/object/selector.js +371 -0
  252. package/dist/lib/object/selector.mjs +1 -0
  253. package/dist/lib/object/sort.cjs +1 -0
  254. package/dist/lib/object/sort.d.ts +149 -0
  255. package/dist/lib/object/sort.d.ts.map +1 -0
  256. package/dist/lib/object/sort.js +298 -0
  257. package/dist/lib/object/sort.mjs +1 -0
  258. package/dist/lib/object/transform.cjs +1 -0
  259. package/dist/lib/object/transform.d.ts +620 -0
  260. package/dist/lib/object/transform.d.ts.map +1 -0
  261. package/dist/lib/object/transform.js +1058 -0
  262. package/dist/lib/object/transform.mjs +1 -0
  263. package/dist/lib/object/types.cjs +1 -0
  264. package/dist/lib/object/types.d.ts +250 -0
  265. package/dist/lib/object/types.d.ts.map +1 -0
  266. package/dist/lib/object/types.js +1 -0
  267. package/dist/lib/object/types.mjs +0 -0
  268. package/dist/lib/object/utils.cjs +6 -0
  269. package/dist/lib/object/utils.d.ts +165 -0
  270. package/dist/lib/object/utils.d.ts.map +1 -0
  271. package/dist/lib/object/utils.js +444 -0
  272. package/dist/lib/object/utils.mjs +6 -0
  273. package/dist/lib/primitive/boolean/boolean.cjs +1 -0
  274. package/dist/lib/primitive/boolean/boolean.d.ts +276 -0
  275. package/dist/lib/primitive/boolean/boolean.d.ts.map +1 -0
  276. package/dist/lib/primitive/boolean/boolean.js +615 -0
  277. package/dist/lib/primitive/boolean/boolean.mjs +1 -0
  278. package/dist/lib/primitive/boolean/index.cjs +1 -0
  279. package/dist/lib/primitive/boolean/index.d.ts +3 -0
  280. package/dist/lib/primitive/boolean/index.d.ts.map +1 -0
  281. package/dist/lib/primitive/boolean/index.js +2 -0
  282. package/dist/lib/primitive/boolean/index.mjs +1 -0
  283. package/dist/lib/primitive/boolean/types.cjs +1 -0
  284. package/dist/lib/primitive/boolean/types.d.ts +14 -0
  285. package/dist/lib/primitive/boolean/types.d.ts.map +1 -0
  286. package/dist/lib/primitive/boolean/types.js +1 -0
  287. package/dist/lib/primitive/boolean/types.mjs +0 -0
  288. package/dist/lib/primitive/date/date.cjs +1 -0
  289. package/dist/lib/primitive/date/date.d.ts +641 -0
  290. package/dist/lib/primitive/date/date.d.ts.map +1 -0
  291. package/dist/lib/primitive/date/date.js +1998 -0
  292. package/dist/lib/primitive/date/date.mjs +1 -0
  293. package/dist/lib/primitive/date/index.cjs +1 -0
  294. package/dist/lib/primitive/date/index.d.ts +3 -0
  295. package/dist/lib/primitive/date/index.d.ts.map +1 -0
  296. package/dist/lib/primitive/date/index.js +2 -0
  297. package/dist/lib/primitive/date/index.mjs +1 -0
  298. package/dist/lib/primitive/date/types.cjs +1 -0
  299. package/dist/lib/primitive/date/types.d.ts +205 -0
  300. package/dist/lib/primitive/date/types.d.ts.map +1 -0
  301. package/dist/lib/primitive/date/types.js +7 -0
  302. package/dist/lib/primitive/date/types.mjs +0 -0
  303. package/dist/lib/primitive/index.cjs +5 -0
  304. package/dist/lib/primitive/index.d.ts +5 -0
  305. package/dist/lib/primitive/index.d.ts.map +1 -0
  306. package/dist/lib/primitive/index.js +4 -0
  307. package/dist/lib/primitive/index.mjs +5 -0
  308. package/dist/lib/primitive/string/index.cjs +5 -0
  309. package/dist/lib/primitive/string/index.d.ts +3 -0
  310. package/dist/lib/primitive/string/index.d.ts.map +1 -0
  311. package/dist/lib/primitive/string/index.js +2 -0
  312. package/dist/lib/primitive/string/index.mjs +5 -0
  313. package/dist/lib/primitive/string/parser-2.cjs +8 -0
  314. package/dist/lib/primitive/string/parser-2.d.ts +17 -0
  315. package/dist/lib/primitive/string/parser-2.d.ts.map +1 -0
  316. package/dist/lib/primitive/string/parser-2.js +656 -0
  317. package/dist/lib/primitive/string/parser-2.mjs +8 -0
  318. package/dist/lib/primitive/string/parser.cjs +3 -0
  319. package/dist/lib/primitive/string/parser.d.ts +9 -0
  320. package/dist/lib/primitive/string/parser.d.ts.map +1 -0
  321. package/dist/lib/primitive/string/parser.js +775 -0
  322. package/dist/lib/primitive/string/parser.mjs +3 -0
  323. package/dist/lib/primitive/string/string.cjs +5 -0
  324. package/dist/lib/primitive/string/string.d.ts +535 -0
  325. package/dist/lib/primitive/string/string.d.ts.map +1 -0
  326. package/dist/lib/primitive/string/string.js +1301 -0
  327. package/dist/lib/primitive/string/string.mjs +5 -0
  328. package/dist/lib/primitive/string/types.cjs +1 -0
  329. package/dist/lib/primitive/string/types.d.ts +318 -0
  330. package/dist/lib/primitive/string/types.d.ts.map +1 -0
  331. package/dist/lib/primitive/string/types.js +5 -0
  332. package/dist/lib/primitive/string/types.mjs +0 -0
  333. package/dist/lib/primitive/types.cjs +1 -0
  334. package/dist/lib/primitive/types.d.ts +27 -0
  335. package/dist/lib/primitive/types.d.ts.map +1 -0
  336. package/dist/lib/primitive/types.js +1 -0
  337. package/dist/lib/primitive/types.mjs +0 -0
  338. package/dist/lib/url/index.cjs +1 -0
  339. package/dist/lib/url/index.d.ts +3 -0
  340. package/dist/lib/url/index.d.ts.map +1 -0
  341. package/dist/lib/url/index.js +2 -0
  342. package/dist/lib/url/index.mjs +1 -0
  343. package/dist/lib/url/parser.cjs +1 -0
  344. package/dist/lib/url/parser.d.ts +216 -0
  345. package/dist/lib/url/parser.d.ts.map +1 -0
  346. package/dist/lib/url/parser.js +488 -0
  347. package/dist/lib/url/parser.mjs +1 -0
  348. package/dist/lib/url/types.cjs +1 -0
  349. package/dist/lib/url/types.d.ts +18 -0
  350. package/dist/lib/url/types.d.ts.map +1 -0
  351. package/dist/lib/url/types.js +1 -0
  352. package/dist/lib/url/types.mjs +0 -0
  353. package/dist/tsconfig.lib.tsbuildinfo +1 -0
  354. package/package.json +150 -0
@@ -0,0 +1,1771 @@
1
+ import { isPrimitive } from '../helpers.js';
2
+ import { deepClone } from './clone.js';
3
+ import { diffObjectDetailed, applyDiff } from './diff.js';
4
+ import { mergeIntoStructure } from './merge.js';
5
+ import { parseSelector, stringifySelector } from './selector.js';
6
+ import { isObject, traverseStructure } from './utils.js';
7
+ /**
8
+ * Gets values from an object while preserving structure
9
+ * @param obj - Source object
10
+ * @param selector - Selector string or array
11
+ * @param options - Selector options
12
+ * @returns Structured object with selected paths
13
+ * @example
14
+ * get({users: [{name: 'Alice'}, {name: 'Bob'}]}, 'users[*].name')
15
+ * // Returns: {users: [{name: 'Alice'}, {name: 'Bob'}]}
16
+ *
17
+ * get({a: {b: 1}, c: {b: 2}}, ['a.b', 'c.b'])
18
+ * // Returns: {a: {b: 1}, c: {b: 2}}
19
+ */
20
+ export function get(obj, selector, options = {}) {
21
+ const { preserveStructure, multiple, throwOnError = false, defaultValue, maxDepth = 20, } = options;
22
+ if (!obj || typeof obj !== 'object') {
23
+ return defaultValue;
24
+ }
25
+ // If no selector provided, return the object
26
+ if (!selector) {
27
+ return obj;
28
+ }
29
+ // console.log('try to get', selector)
30
+ // Handle array of selectors
31
+ if (Array.isArray(selector)) {
32
+ if (preserveStructure) {
33
+ // Return an object with all selected paths
34
+ const result = {};
35
+ for (const sel of selector) {
36
+ const value = get(obj, sel, { ...options, preserveStructure: false });
37
+ if (value !== undefined) {
38
+ // Merge the value into result preserving structure
39
+ mergeIntoStructure(result, sel, value);
40
+ }
41
+ }
42
+ return result;
43
+ }
44
+ else {
45
+ // Return array of values
46
+ return selector.map((sel) => get(obj, sel, { ...options, preserveStructure: false }));
47
+ }
48
+ }
49
+ const segments = parseSelector(selector, { ...options, throwOnError });
50
+ // console.log('segments', segments)
51
+ if (segments.length === 0) {
52
+ return obj;
53
+ }
54
+ if (typeof preserveStructure === 'undefined' || preserveStructure === false) {
55
+ // console.log('p')
56
+ const v = ValueOfKey(obj, selector);
57
+ if (multiple === false && Array.isArray(v)) {
58
+ return v[0];
59
+ }
60
+ if (v === undefined && defaultValue !== undefined) {
61
+ return defaultValue;
62
+ }
63
+ return v;
64
+ }
65
+ // Get structured result
66
+ const result = traverseStructure(obj, segments, 0, maxDepth);
67
+ if (result === undefined && defaultValue !== undefined) {
68
+ return defaultValue;
69
+ }
70
+ return result;
71
+ }
72
+ // Implementation
73
+ export function set(_obj, first, second, third, fourth) {
74
+ // if (params.length === 0) return obj;
75
+ let obj = deepClone(_obj);
76
+ // console.log('set called', {obj, first, second, third, fourth})
77
+ const params = [];
78
+ if (typeof first !== 'undefined')
79
+ params.push(first);
80
+ if (typeof second !== 'undefined')
81
+ params.push(second);
82
+ if (typeof third !== 'undefined')
83
+ params.push(third);
84
+ if (typeof fourth !== 'undefined')
85
+ params.push(fourth);
86
+ if (isPrimitive(obj)) {
87
+ if (typeof first === 'function') {
88
+ return first(obj);
89
+ }
90
+ return first;
91
+ }
92
+ // const [first, second, third, fourth, fifth] = params;
93
+ // Pattern 1 & 2: set(obj, "path", value) or set(obj, "path", updateFunction)
94
+ // console.log('set v', first, second, params.length);
95
+ if (params.length === 1) {
96
+ if (typeof params[0] === 'function') {
97
+ // console.log('callback update', params, obj)
98
+ return updateWithCallBack(obj, params[0]);
99
+ }
100
+ if (Array.isArray(params[0])) {
101
+ // console.log('is array', [...params[0]])
102
+ // if ([...params[0]].some((v) => v.title === 'S / Red / Nike')) throw new Error('stop')
103
+ if (Array.isArray(obj)) {
104
+ // obj = params[0];
105
+ if (first.length === 0) {
106
+ for (let i = 0; i < obj.length; i++) {
107
+ obj.pop();
108
+ }
109
+ }
110
+ else {
111
+ const diff = diffObjectDetailed([...obj], [...params[0]]);
112
+ if (diff.hasChanges) {
113
+ applyDiff(obj, [...params[0]], true);
114
+ }
115
+ return obj;
116
+ }
117
+ }
118
+ // updateWithCallBack(obj, (value) => );
119
+ }
120
+ else if (typeof params[0] === 'object' && !Array.isArray(params[0])) {
121
+ if (typeof obj === 'object' && !Array.isArray(obj)) {
122
+ applyDiff(obj, params[0], true);
123
+ }
124
+ // if (Array.isArray(obj)) {
125
+ // obj.push(params[0]);
126
+ // } else {
127
+ // obj = { ...obj, ...params[0] };
128
+ // }
129
+ // return updateWithCallBack(obj, (value) => ({ ...value, ...params[0] }));
130
+ }
131
+ else {
132
+ obj = params[0];
133
+ }
134
+ return obj;
135
+ // return updateWithCallBack(obj, (value) => params[0]);
136
+ }
137
+ if (Array.isArray(obj)) {
138
+ if (typeof first === 'string' &&
139
+ (isArrayOfString(second) || typeof second === 'string') &&
140
+ params.length === 3) {
141
+ if (Array.isArray(second)) {
142
+ for (let i = 0; i < second.length; i++) {
143
+ setValueAtPath(obj, first, third, second[i]);
144
+ }
145
+ return obj;
146
+ }
147
+ return setValueAtPath(obj, first, third, second);
148
+ }
149
+ if (typeof first === 'string' &&
150
+ typeof second === 'function' &&
151
+ params.length === 2) {
152
+ return setValueAtPath(obj, first, second);
153
+ }
154
+ }
155
+ // if (Array.isArray(obj) && typeof second === 'object') {
156
+ // console.log('items', obj, first, second);
157
+ // }
158
+ if ((typeof first === 'string' || typeof first === 'number') &&
159
+ (params.length === 2 || params.length === 3)) {
160
+ if (isRangeObject(second)) {
161
+ return setValueBetweenRange(obj, first, second, third);
162
+ }
163
+ if (typeof first === 'number') {
164
+ // console.log('setting v', {obj, first, second, third})
165
+ if (typeof third !== 'undefined') {
166
+ return setValueAtPath(obj, `[${first}].${second}`, third);
167
+ }
168
+ else {
169
+ return setValueAtPath(obj, `[${first}]`, second, third);
170
+ }
171
+ }
172
+ // console.log('len 1', params.length);
173
+ if (typeof second === 'number' && typeof third !== 'undefined') {
174
+ return setValueAtIndex(obj, first, second, third);
175
+ }
176
+ if (Array.isArray(second) &&
177
+ second.length > 0 &&
178
+ second.every((s) => typeof s === 'number')) {
179
+ return setValueWithIndices(obj, first, second, third);
180
+ }
181
+ if (typeof third !== 'undefined' && typeof second === 'function') {
182
+ return setValueWithFilter(obj, first, second, third);
183
+ }
184
+ return setValueAtPath(obj, first, second, third);
185
+ }
186
+ // Pattern 3 & 4: set(obj, "path", index, value) or set(obj, "path", index, subPath, value)
187
+ if (typeof first === 'string' && typeof second === 'number') {
188
+ // console.log('len 2', obj, params)
189
+ if (params.length === 3) {
190
+ return setValueAtIndex(obj, first, second, third);
191
+ }
192
+ else if (params.length === 4) {
193
+ return setIndexWithSubPath(obj, first, second, third, fourth);
194
+ }
195
+ }
196
+ // Pattern 5 & 6: set(obj, "path", indices, value) or set(obj, "path", indices, subPath, value)
197
+ if (typeof first === 'string' && Array.isArray(second)) {
198
+ if (params.length === 3) {
199
+ return setValueWithIndices(obj, first, second, third);
200
+ }
201
+ else if (params.length === 4) {
202
+ return setValueWithIndicesWithSubPath(obj, first, second, third, fourth);
203
+ }
204
+ }
205
+ // Pattern 7 & 8: set(obj, "path", range, value) or set(obj, "path", range, subPath, value)
206
+ if (typeof first === 'string' &&
207
+ typeof second === 'object' &&
208
+ !Array.isArray(second) &&
209
+ second !== null) {
210
+ const range = second;
211
+ if ('from' in range || 'to' in range) {
212
+ if (params.length === 3) {
213
+ return setValueBetweenRange(obj, first, range, third);
214
+ }
215
+ else if (params.length === 4) {
216
+ return setValueBetweenRangeWithSubPath(obj, first, range, third, fourth);
217
+ }
218
+ }
219
+ }
220
+ // Pattern 9: set(obj, updateObject)
221
+ if (typeof first === 'object' &&
222
+ !Array.isArray(first) &&
223
+ params.length === 1) {
224
+ return applyDiff(obj, first, true);
225
+ }
226
+ // Pattern 10: set(obj, "path", updateObject)
227
+ if (typeof first === 'string' &&
228
+ typeof second === 'object' &&
229
+ !Array.isArray(second) &&
230
+ params.length === 2) {
231
+ return mergeUpdateAtPath(obj, first, second);
232
+ }
233
+ // console.log('we here', params.length)
234
+ // Pattern 11 & 12: set(obj, "path", filter, value) or set(obj, "path", filter, subPath, value)
235
+ if (typeof first === 'string' && typeof second === 'function') {
236
+ if (params.length === 3) {
237
+ // console.log('set filter')
238
+ return setValueWithFilter(obj, first, second, third);
239
+ }
240
+ else if (params.length === 4) {
241
+ return setValueWithFilterWithSubPath(obj, first, second, third, fourth);
242
+ }
243
+ }
244
+ if (typeof first === 'function' && typeof second === 'string') {
245
+ if (params.length === 3) {
246
+ // console.log('set filter')
247
+ return setArrayValueWithFilter(obj, first, second, third);
248
+ }
249
+ else if (params.length === 4) {
250
+ return setValueWithFilterWithSubPath(obj, second, first, third, fourth);
251
+ }
252
+ }
253
+ // Pattern 13: Array selectors
254
+ // console.log('last pattern', params, _obj)
255
+ if (Array.isArray(first)) {
256
+ if (params.length === 2 &&
257
+ typeof second === 'object' &&
258
+ !Array.isArray(second)) {
259
+ // Array of selectors with update object
260
+ return setValueWithArraySelectors(obj, first, second);
261
+ }
262
+ else if (params.length === 2) {
263
+ // Array of selectors with single value
264
+ return setValueWithArraySelectors(obj, first, second);
265
+ }
266
+ }
267
+ throw new Error(`Invalid set parameters: ${JSON.stringify(params)}`);
268
+ }
269
+ function handleFunctionParams(selector, data, value, isArray = false) {
270
+ const paths = parseSelector(selector);
271
+ // console.log('p', { paths, selector, res: paths[paths.length - 1] });
272
+ if (paths.length === 0)
273
+ return value;
274
+ const isWildcard = paths[paths.length - 1].type === 'wildcard';
275
+ const containWildcard = paths.some((path) => path.type === 'wildcard') && Array.isArray(data);
276
+ let finalValue;
277
+ if (isWildcard ||
278
+ (containWildcard && isArray) ||
279
+ (containWildcard && paths.length === 2)) {
280
+ if (Array.isArray(data)) {
281
+ for (let i = 0; i < data.length; i++) {
282
+ const v = typeof value === 'function'
283
+ ? value(data[i])
284
+ : typeof data[i] === 'object'
285
+ ? applyDiff(data[i], value, true)
286
+ : value;
287
+ if (!finalValue)
288
+ finalValue = [];
289
+ finalValue.push(v);
290
+ }
291
+ }
292
+ }
293
+ if (!isWildcard && !finalValue) {
294
+ finalValue = typeof value === 'function' ? value(data) : value;
295
+ }
296
+ // if (selector === 'person.wife.childs') {
297
+ // console.log('final', { finalValue, data, value });
298
+ // }
299
+ return finalValue;
300
+ }
301
+ /**
302
+ * utility function to check if an object is a range object
303
+ * @param obj - The Object to check
304
+ * @example
305
+ * isRangeObject({ from: 0, to: 10 }); // true
306
+ * isRangeObject({ from: 0, to: 10, by: 1 }); // true
307
+ * isRangeObject({ from: 0, to: 10, by: '1' }); // true
308
+ * isRangeObject({ by: 2 }); // false
309
+ */
310
+ export function isRangeObject(obj) {
311
+ return (typeof obj === 'object' &&
312
+ obj !== null &&
313
+ 'from' in obj &&
314
+ 'to' in obj &&
315
+ typeof obj.from === 'number' &&
316
+ typeof obj.to === 'number' &&
317
+ obj.from < obj.to &&
318
+ obj.from >= 0 &&
319
+ obj.to > 0);
320
+ }
321
+ function isArrayOfString(value) {
322
+ return (Array.isArray(value) && value.every((item) => typeof item === 'string'));
323
+ }
324
+ /**
325
+ * Sets a value at a path
326
+ * @param obj - The Object to set the value at
327
+ * @param selector - The path to set the value at
328
+ * @param value - The value to set
329
+ * @param subPath - The subpath to set the value at
330
+ * @returns The updated object
331
+ * @example
332
+ * setValueAtPath({ a: { b: { c: 1 } } }, 'a.b.c', 2); // { a: { b: { c: 2 } } }
333
+ * setValueAtPath({ a: { b: { c: 1 } } }, 'a.b.c', (prev) => prev + 1); // { a: { b: { c: 2 } } }
334
+ * setValueAtPath({ a: { b: { c: 1 } } }, 'a.b.c', 2, 'd'); // { a: { b: { c: { d: 2 } } } }
335
+ * setValueAtPath({ a: { b: { c: 1 } } }, 'a.b.c', (prev) => prev + 1, 'd'); // { a: { b: { c: { d: 2 } } } }
336
+ */
337
+ export function setValueAtPath(obj, selector, value, subPath) {
338
+ // console.log('set value', selector);
339
+ const paths = parseSelector(selector);
340
+ let target = ValueOfKey(obj, selector, {
341
+ paths,
342
+ createMissing: true,
343
+ });
344
+ // if (selector === 'variantRows') {
345
+ // console.log('set at p', target, value);
346
+ // }
347
+ let get_value;
348
+ if (subPath) {
349
+ if (typeof value === 'function') {
350
+ get_value = get(target, subPath);
351
+ }
352
+ }
353
+ const data = subPath ? get_value : target;
354
+ const finalValue = handleFunctionParams(selector, data, value, Array.isArray(obj));
355
+ // console.log('set value at path', {data, finalValue, selector, obj});
356
+ // if (selector === '[*]') {
357
+ // console.log('finalValue', finalValue, selector);
358
+ // }
359
+ if (subPath) {
360
+ const result = setAtPath(obj, `${selector}.${subPath}`, finalValue, {
361
+ createMissing: true,
362
+ });
363
+ return result;
364
+ }
365
+ else {
366
+ const r = setAtPath(obj, selector, finalValue, { createMissing: true });
367
+ // if (selector === '[*]') {
368
+ // // console.log('r', r);
369
+ // // console.log('r', obj);
370
+ // }
371
+ // console.log('r', obj);
372
+ return r;
373
+ }
374
+ }
375
+ /**
376
+ * Sets value at index
377
+ * @param obj - The Object to set the value at
378
+ * @param selector - The path to set the value at
379
+ * @param index - The index to set the value at
380
+ * @param value - The value to set
381
+ * @returns The updated object
382
+ * @example
383
+ * setValueAtIndex({ a: { b: [1, 2, 3] } }, 'a.b', 1, 4); // { a: { b: [1, 4, 3] } }
384
+ * setValueAtIndex({ a: { b: [1, 2, 3] } }, 'a.b', 1, (prev) => prev + 1); // { a: { b: [1, 3, 3] } }
385
+ * setValueAtIndex({ a: { b: [1, 2, 3] } }, 'a.b', 1, (prev) => prev + 1); // { a: { b: [1, 3, 3] } }
386
+ */
387
+ export function setValueAtIndex(obj, selector, index, value) {
388
+ const target = ValueOfKey(obj, selector, { createMissing: true });
389
+ if (!Array.isArray(target)) {
390
+ throw new Error(`Target at ${selector} is not an array ${index}`);
391
+ }
392
+ const target_copy = structuredClone(target);
393
+ const finalValue = handleFunctionParams(selector, target_copy[index], value);
394
+ // console.log('set value at index', {obj, selector, index, finalValue, value, target_copy});
395
+ if (index < 0) {
396
+ // Negative index counts from end
397
+ const actualIndex = target.length + index;
398
+ if (actualIndex < 0) {
399
+ throw new Error(`Index ${index} is out of bounds`);
400
+ }
401
+ return setAtPath(obj, `${selector}[${actualIndex}]`, finalValue, {
402
+ createMissing: true,
403
+ });
404
+ }
405
+ // console.log('set index', index, `${selector}[${index}]`)
406
+ return setAtPath(obj, `${selector}[${index}]`, finalValue, {
407
+ createMissing: true,
408
+ });
409
+ }
410
+ /**
411
+ * Sets value at index with sub-path
412
+ * @param obj - The object to set the value on
413
+ * @param selector - The selector to set the value at
414
+ * @param index - The index to set the value at
415
+ * @param subPath - The sub-path to set the value at
416
+ * @param value - The value to set
417
+ * @example
418
+ * const obj = { a: [1, 2, 3] };
419
+ * setIndexWithSubPath(obj, 'a', 1, 'b', 4);
420
+ * console.log(obj); // { a: [1, { b: 4 }, 3] }
421
+ */
422
+ const setIndexWithSubPath = (obj, selector, index, subPath, value) => {
423
+ // console.log('sub is fn', {obj, selector, index, subPath, value});
424
+ if (typeof subPath === 'function') {
425
+ return setValueAtPath(obj, `${selector}[${index}]`, subPath);
426
+ }
427
+ if (typeof subPath === 'string') {
428
+ return setValueAtPath(obj, `${selector}[${index}]`, value, subPath);
429
+ }
430
+ return null;
431
+ };
432
+ /**
433
+ * Sets value at multiple indices
434
+ * @param obj - The object to set the value on
435
+ * @param selector - The selector to set the value at
436
+ * @param indices - The indices to set the value at
437
+ * @param value - The value to set
438
+ * @example
439
+ * const obj = { a: [1, 2, 3] };
440
+ * setValueWithIndices(obj, 'a', [1, 2], 4);
441
+ * console.log(obj); // { a: [1, 4, 4] }
442
+ */
443
+ const setValueWithIndices = (obj, selector, indices, value) => {
444
+ const target = ValueOfKey(obj, selector);
445
+ // console.log('setting index', target)
446
+ if (!Array.isArray(target)) {
447
+ throw new Error(`Target at ${selector} is not an array`);
448
+ }
449
+ for (const index of indices) {
450
+ if (typeof index === 'number') {
451
+ setValueAtIndex(obj, selector, index, value);
452
+ }
453
+ else if (typeof index === 'string') {
454
+ setValueAtPath(obj, selector, value, index);
455
+ }
456
+ }
457
+ return obj;
458
+ };
459
+ /**
460
+ * Sets value at multiple indices with sub-path
461
+ * @param obj - The object to set the value on
462
+ * @param selector - The selector to set the value at
463
+ * @param indices - The indices to set the value at
464
+ * @param subPath - The sub-path to set the value at
465
+ * @param value - The value to set
466
+ * @example
467
+ * const obj = { a: [1, 2, 3] };
468
+ * setValueWithIndicesWithSubPath(obj, 'a', [1, 2], 'b', 4);
469
+ * console.log(obj); // { a: [1, { b: 4 }, { b: 4 }] }
470
+ */
471
+ const setValueWithIndicesWithSubPath = (obj, selector, indices, subPath, value) => {
472
+ const updater = (prev) => {
473
+ const newValue = typeof value === 'function'
474
+ ? value(prev ? ValueOfKey(prev, subPath) : undefined)
475
+ : value;
476
+ const result = prev ? { ...prev } : {};
477
+ setAtPath(result, subPath, newValue);
478
+ return result;
479
+ };
480
+ return setValueWithIndices(obj, selector, indices, updater);
481
+ };
482
+ /**
483
+ * Sets value in a range
484
+ * @param obj - The object to set the value on
485
+ * @param selector - The selector to set the value at
486
+ * @param range - The range to set the value in
487
+ * @param value - The value to set
488
+ * @example
489
+ * const obj = { a: [1, 2, 3] };
490
+ * setValueBetweenRange(obj, 'a', { from: 1, to: 2 }, 4);
491
+ * console.log(obj); // { a: [1, 4, 4] }
492
+ */
493
+ export function setValueBetweenRange(obj, selector, range, value) {
494
+ const target = ValueOfKey(obj, selector);
495
+ if (!Array.isArray(target)) {
496
+ throw new Error(`Target at ${selector} is not an array`);
497
+ }
498
+ const from = range.from ?? 0;
499
+ const to = range.to ?? target.length - 1;
500
+ const by = range.by ?? 1;
501
+ const indices = [];
502
+ for (let i = from; i <= to; i += by) {
503
+ if (i >= 0 && i < target.length) {
504
+ indices.push(i);
505
+ }
506
+ }
507
+ return setValueWithIndices(obj, selector, indices, value);
508
+ }
509
+ function getValueFnParams(prev, subPath) {
510
+ return prev ? ValueOfKey(prev, subPath) : undefined;
511
+ }
512
+ /**
513
+ * Sets value in a range with sub-path
514
+ * @param obj - The object to set the value on
515
+ * @param selector - The selector to set the value at
516
+ * @param range - The range to set the value in
517
+ * @param subPath - The sub-path to set the value at
518
+ * @param value - The value to set
519
+ * @example
520
+ * const obj = { a: [1, 2, 3] };
521
+ * setValueBetweenRangeWithSubPath(obj, 'a', { from: 1, to: 2 }, 'b', 4);
522
+ * console.log(obj); // { a: [1, { b: 4 }, { b: 4 }] }
523
+ */
524
+ export const setValueBetweenRangeWithSubPath = (obj, selector, range, subPath, value) => {
525
+ const updater = (prev) => {
526
+ const newValue = typeof value === 'function'
527
+ ? value(prev ? ValueOfKey(prev, subPath) : undefined)
528
+ : value;
529
+ const result = prev ? { ...prev } : {};
530
+ setAtPath(result, subPath, newValue);
531
+ return result;
532
+ };
533
+ return setValueBetweenRange(obj, selector, range, updater);
534
+ };
535
+ /**
536
+ * Casts properties to a given type
537
+ */
538
+ export function castProps(arr, props) {
539
+ return Object.assign(arr, props);
540
+ // return arr as T;
541
+ }
542
+ /**
543
+ * Sets value for filtered items
544
+ * @param obj - The object to modify.
545
+ * @param selector - The selector for the property to modify.
546
+ * @param filterFn - The filter function to apply to the items.
547
+ * @param value - The value to set for the filtered items.
548
+ * @example
549
+ * const arr = [{ id: 1, name: 'John' }, { id: 2, name: 'Jane' }];
550
+ * setValueWithFilter(arr, 'id', id => id === 1, { name: 'John Doe' });
551
+ * console.log(arr); // [{ id: 1, name: 'John Doe' }, { id: 2, name: 'Jane' }]
552
+ */
553
+ export function setValueWithFilter(obj, selector, filterFn, value) {
554
+ const target = ValueOfKey(obj, selector);
555
+ if (!Array.isArray(target)) {
556
+ throw new Error(`Target at ${selector} is not an array`);
557
+ }
558
+ const indices = [];
559
+ const target_copy = [...target];
560
+ target.forEach((item, index) => {
561
+ if (filterFn(item, index)) {
562
+ // console.log('set filter for done', index)
563
+ indices.push(index);
564
+ }
565
+ });
566
+ return setValueWithIndices(obj, selector, indices, value);
567
+ }
568
+ export function setArrayValueWithFilter(obj, filterFn, selector, value) {
569
+ let target = obj;
570
+ // const target = ValueOfKey(obj, selector);
571
+ if (!Array.isArray(target)) {
572
+ throw new Error(`Target at ${selector} is not an array`);
573
+ }
574
+ // return setValueAtPath(obj, selector, value);
575
+ // console.log('updating', selector, value, target)
576
+ const indices = [];
577
+ const target_copy = [...target];
578
+ target.forEach((item, index) => {
579
+ const n = setAtPath(item, selector, value, { createMissing: true });
580
+ item = n;
581
+ // if (filterFn(item, index)) {
582
+ // // console.log('set filter for done', index)
583
+ // indices.push(index);
584
+ // }
585
+ });
586
+ return target;
587
+ // return setValueWithIndices(obj, selector, indices, value);
588
+ }
589
+ /**
590
+ * Sets value for filtered items with sub-path
591
+ * @param obj - The object to modify.
592
+ * @param selector - The selector for the property to modify.
593
+ * @param filterFn - The filter function to apply to the items.
594
+ * @param subPath - The sub-path to modify.
595
+ * @param value - The value to set for the filtered items.
596
+ * @example
597
+ * const arr = [{ id: 1, name: 'John' }, { id: 2, name: 'Jane' }];
598
+ * setValueWithFilterWithSubPath(arr, 'id', id => id === 1, 'name', 'John Doe');
599
+ * console.log(arr); // [{ id: 1, name: 'John Doe' }, { id: 2, name: 'Jane' }]
600
+ */
601
+ export function setValueWithFilterWithSubPath(obj, selector, filterFn, subPath, value) {
602
+ const updater = (prev) => {
603
+ const newValue = typeof value === 'function'
604
+ ? value(prev ? ValueOfKey(prev, subPath) : undefined)
605
+ : value;
606
+ const result = prev ? { ...prev } : {};
607
+ setAtPath(result, subPath, newValue);
608
+ return result;
609
+ };
610
+ return setValueWithFilter(obj, selector, filterFn, updater);
611
+ }
612
+ /**
613
+ * Merge update object at path
614
+ * @param obj - The object to update
615
+ * @param selector - The path to the object to update
616
+ * @param updates - The object to merge with the existing object
617
+ * @example
618
+ * const obj = { a: { b: { c: 1 } } };
619
+ * mergeUpdateAtPath(obj, 'a.b', { c: 2 });
620
+ * console.log(obj); // { a: { b: { c: 2 } } }
621
+ */
622
+ export function mergeUpdateAtPath(obj, selector, updates) {
623
+ const current = ValueOfKey(obj, selector, { createMissing: true });
624
+ const merged = applyDiff(current || {}, updates, true);
625
+ return setAtPath(obj, selector, merged, { createMissing: true });
626
+ }
627
+ /**
628
+ * Set with array selectors
629
+ * @param obj - The object to update
630
+ * @param selectors - The array of paths to update
631
+ * @param value - The value to set for each path
632
+ * @example
633
+ * const obj = { a: { b: { c: 1 } } };
634
+ * setValueWithArraySelectors(obj, ['a.b', 'a.c'], { d: 2 });
635
+ * console.log(obj); // { a: { b: { d: 2 }, c: { d: 2 } } }
636
+ */
637
+ export function setValueWithArraySelectors(obj, selectors, value) {
638
+ if (typeof value === 'object' && !Array.isArray(value) && value !== null) {
639
+ // Update object for multiple selectors
640
+ for (const [path, val] of Object.entries(value)) {
641
+ if (selectors.includes(path)) {
642
+ setAtPath(obj, path, val, { createMissing: true });
643
+ }
644
+ }
645
+ }
646
+ else {
647
+ // Single value for all selectors
648
+ for (const selector of selectors) {
649
+ const finalValue = handleFunctionParams(selector, ValueOfKey(obj, selector), value);
650
+ setAtPath(obj, selector, finalValue, { createMissing: true });
651
+ }
652
+ }
653
+ return obj;
654
+ }
655
+ /**
656
+ * Gets value at path with createMissing option
657
+ * @param obj - The object to get the value from.
658
+ * @param selector - The path to the value.
659
+ * @param options - Options for the operation.
660
+ * @returns The value at the path.
661
+ * @example
662
+ * const a = { b: { c: 1 } };
663
+ * ValueOfKey(a, 'b.c', { createMissing: true });
664
+ * console.log(a); // 1
665
+ */
666
+ export function ValueOfKey(obj, selector, options = {}) {
667
+ const { createMissing = false, add = false, debug = false } = options;
668
+ const segments = parseSelector(selector);
669
+ let current = obj;
670
+ let updateEvenIfNotlast = false;
671
+ let chained_property = '';
672
+ const stringify = selector;
673
+ if (typeof current === 'object' &&
674
+ !Array.isArray(current) &&
675
+ stringify.length > 0) {
676
+ if (current[stringify]) {
677
+ current = current[stringify];
678
+ return current;
679
+ }
680
+ }
681
+ for (let i = 0; i < segments.length; i++) {
682
+ const segment = segments[i];
683
+ const isLast = segments.length > 1 ? i === segments.length - 1 : false;
684
+ if (current === null && !createMissing) {
685
+ return undefined;
686
+ }
687
+ const nextSegment = segments[i + 1];
688
+ switch (segment.type) {
689
+ case 'property':
690
+ if (current && typeof current === 'object') {
691
+ if (Array.isArray(current)) {
692
+ // Handle numeric property as array index
693
+ if (typeof segment.value === 'number') {
694
+ const index = segment.value;
695
+ if (createMissing && index >= current.length) {
696
+ for (let j = current.length; j <= index; j++) {
697
+ current.push(undefined);
698
+ }
699
+ }
700
+ if (createMissing &&
701
+ (current[index] === null || current[index] === undefined) &&
702
+ (!isLast || updateEvenIfNotlast)) {
703
+ if (nextSegment) {
704
+ current[index] =
705
+ nextSegment.type === 'index' ||
706
+ nextSegment.type === 'slice' ||
707
+ nextSegment.type === 'union' ||
708
+ nextSegment.type === 'wildcard'
709
+ ? []
710
+ : {};
711
+ }
712
+ else {
713
+ current[index] = null;
714
+ }
715
+ updateEvenIfNotlast = false;
716
+ }
717
+ current = current[index];
718
+ if (nextSegment) {
719
+ updateEvenIfNotlast = true;
720
+ continue;
721
+ }
722
+ }
723
+ else if (add) {
724
+ current.push({
725
+ [String(segment.value)]: null,
726
+ });
727
+ }
728
+ else {
729
+ current = current.map((item) => item[String(segment.value)]);
730
+ }
731
+ if (nextSegment) {
732
+ continue;
733
+ }
734
+ return filterDefined(current);
735
+ }
736
+ else {
737
+ if (current[chained_property] &&
738
+ chained_property.split('.').length >= 2) {
739
+ current = current[chained_property];
740
+ continue;
741
+ }
742
+ if (createMissing &&
743
+ (current[String(segment.value)] === null ||
744
+ current[String(segment.value)] === undefined) &&
745
+ (!isLast || updateEvenIfNotlast)) {
746
+ if (nextSegment) {
747
+ current[String(segment.value)] =
748
+ nextSegment.type === 'index' ||
749
+ nextSegment.type === 'slice' ||
750
+ nextSegment.type === 'union' ||
751
+ nextSegment.type === 'wildcard'
752
+ ? []
753
+ : {};
754
+ }
755
+ else {
756
+ current[String(segment.value)] = null;
757
+ }
758
+ updateEvenIfNotlast = false;
759
+ current = current[String(segment.value)];
760
+ if (nextSegment) {
761
+ updateEvenIfNotlast = true;
762
+ continue;
763
+ }
764
+ // break;
765
+ }
766
+ if (!current) {
767
+ current = { [String(segment.value)]: null };
768
+ }
769
+ else {
770
+ if (!current[String(segment.value)] && createMissing) {
771
+ current[String(segment.value)] = null;
772
+ }
773
+ // if (
774
+ // selector === 'person.wife.childs' &&
775
+ // segment.value === 'childs'
776
+ // ) {
777
+ // console.log('cp', { current, segment });
778
+ // }
779
+ current = current[String(segment.value)];
780
+ }
781
+ if (nextSegment) {
782
+ continue;
783
+ }
784
+ }
785
+ }
786
+ else if (createMissing) {
787
+ // const nextSegment = segments[i + 1];
788
+ current = {};
789
+ current[String(segment.value)] =
790
+ nextSegment.type === 'index' ||
791
+ nextSegment.type === 'slice' ||
792
+ nextSegment.type === 'union' ||
793
+ nextSegment.type === 'wildcard' ||
794
+ options.type === 'array'
795
+ ? []
796
+ : {};
797
+ current = current[String(segment.value)];
798
+ }
799
+ else {
800
+ return undefined;
801
+ }
802
+ break;
803
+ case 'index':
804
+ case 'wildcard':
805
+ if (Array.isArray(current)) {
806
+ if (segment.type === 'index') {
807
+ const index = segment.value;
808
+ if (index < 0) {
809
+ current = current[current.length - Math.abs(index)];
810
+ continue;
811
+ }
812
+ if (createMissing &&
813
+ (index >= current.length ||
814
+ current[index] == null ||
815
+ current[index] == undefined) &&
816
+ !isLast) {
817
+ for (let j = current.length; j <= index; j++) {
818
+ current.push(undefined);
819
+ }
820
+ if (nextSegment) {
821
+ current[index] =
822
+ nextSegment.type === 'index' ||
823
+ nextSegment.type === 'slice' ||
824
+ nextSegment.type === 'union' ||
825
+ nextSegment.type === 'wildcard'
826
+ ? []
827
+ : {};
828
+ }
829
+ }
830
+ current = current[index];
831
+ // if(!isLast){
832
+ // console.log('not')
833
+ // continue
834
+ // }
835
+ // console.log('index is', current, index, i, nextSegment)
836
+ // if(nextSegment){
837
+ // continue
838
+ // }
839
+ }
840
+ else {
841
+ if (!isLast) {
842
+ continue;
843
+ }
844
+ }
845
+ }
846
+ else if (createMissing) {
847
+ const nextSegment = segments[i + 1];
848
+ current = [];
849
+ const index = segment.value;
850
+ for (let j = 0; j <= index; j++) {
851
+ current.push(undefined);
852
+ }
853
+ current[index] =
854
+ nextSegment.type === 'index' ||
855
+ nextSegment.type === 'slice' ||
856
+ nextSegment.type === 'union' ||
857
+ nextSegment.type === 'wildcard' ||
858
+ options.type === 'array'
859
+ ? []
860
+ : {};
861
+ current = current[index];
862
+ }
863
+ else {
864
+ if (segment.type === 'index' && typeof current === 'object') {
865
+ // Here we need to check if the current is an object and if potentially the segment value is key of the object
866
+ if (current && current[String(segment.value)] !== undefined) {
867
+ current = current[String(segment.value)];
868
+ continue;
869
+ }
870
+ }
871
+ if (typeof current === 'object') {
872
+ const values = Object.values(current);
873
+ current = values;
874
+ continue;
875
+ }
876
+ return undefined;
877
+ }
878
+ break;
879
+ default:
880
+ return undefined;
881
+ }
882
+ }
883
+ return filterDefined(current);
884
+ }
885
+ function filterDefined(obj) {
886
+ if (Array.isArray(obj)) {
887
+ return obj.filter((item) => typeof item !== 'undefined');
888
+ }
889
+ return obj;
890
+ }
891
+ /**
892
+ * Sets value at path (internal)
893
+ */
894
+ export const setAtPath = (obj, selector, value, options = {}) => {
895
+ if (selector === '[*]') {
896
+ return applyDiff(obj, value, true);
897
+ }
898
+ const { createMissing = true } = options;
899
+ const segments = parseSelector(selector);
900
+ if (segments.length === 0) {
901
+ return obj;
902
+ }
903
+ const lastSegment = segments[segments.length - 1];
904
+ let current = obj;
905
+ // Navigate to parent of last segment
906
+ for (let i = 0; i < segments.length - 1; i++) {
907
+ // console.log('i', i)
908
+ const segment = segments[i];
909
+ if (current == null) {
910
+ if (!createMissing)
911
+ return obj;
912
+ throw new Error(`Cannot navigate through null/undefined at segment ${i}`);
913
+ }
914
+ const nextSegment = segments[i + 1];
915
+ // let shoul
916
+ const shouldBeArray = nextSegment.type === 'index' ||
917
+ nextSegment.type === 'slice' ||
918
+ nextSegment.type === 'union' ||
919
+ nextSegment.type === 'wildcard';
920
+ if (segment.type === 'property') {
921
+ // if (selector === '[*].meta.count') {
922
+ // console.log('on property first', { selector, current });
923
+ // }
924
+ // Handle numeric property on array as index
925
+ if (Array.isArray(current) && typeof typeof segment.value === 'number') {
926
+ const index = segment.value;
927
+ if (index < 0) {
928
+ throw new Error(`Negative index ${index} not allowed`);
929
+ }
930
+ if (index >= current.length && createMissing) {
931
+ for (let j = current.length; j <= index; j++) {
932
+ current.push(undefined);
933
+ }
934
+ }
935
+ if ((current[index] === null || current[index] === undefined) &&
936
+ createMissing) {
937
+ current[index] = shouldBeArray ? [] : {};
938
+ }
939
+ current = current[index];
940
+ }
941
+ else {
942
+ if ((current[String(segment.value)] === null ||
943
+ current[String(segment.value)] === undefined) &&
944
+ createMissing) {
945
+ // console.log('not exist', String(segment.value))
946
+ current[String(segment.value)] = shouldBeArray ? [] : {};
947
+ }
948
+ if (typeof current === 'object' && !Array.isArray(current)) {
949
+ current = current[String(segment.value)];
950
+ }
951
+ }
952
+ // console.log('is obj', current, nextSegment)
953
+ // console.log('prop', current)
954
+ if (nextSegment) {
955
+ // console.log('next seg', nextSegment)
956
+ continue;
957
+ }
958
+ break;
959
+ }
960
+ else if (segment.type === 'index' || segment.type === 'wildcard') {
961
+ // console.log('ind', current)
962
+ // if (selector === '[*].meta.count') {
963
+ // console.log('on index or wildcard first', { selector, current });
964
+ // }
965
+ if (!Array.isArray(current)) {
966
+ if (!createMissing)
967
+ return obj;
968
+ current = [];
969
+ }
970
+ if (segment.type === 'index') {
971
+ const index = segment.value;
972
+ if (index < 0) {
973
+ throw new Error(`Negative index ${index} not allowed`);
974
+ }
975
+ // console.log('is index')
976
+ if (index >= current.length && createMissing) {
977
+ // console.log('creating new element')
978
+ for (let j = current.length; j <= index; j++) {
979
+ current.push(undefined);
980
+ }
981
+ }
982
+ if ((current[index] === null || current[index] === undefined) &&
983
+ createMissing) {
984
+ current[index] = shouldBeArray ? [] : undefined;
985
+ }
986
+ current = current[index];
987
+ }
988
+ if (nextSegment) {
989
+ // console.log('next seg', nextSegment)
990
+ continue;
991
+ }
992
+ break;
993
+ }
994
+ else {
995
+ throw new Error(`Invalid segment type for set: ${segment.type}`);
996
+ }
997
+ }
998
+ // if (selector === 'person.wife.childs') {
999
+ // console.log('is array data', { current, value, lastSegment });
1000
+ // }
1001
+ // Set the value
1002
+ switch (lastSegment.type) {
1003
+ case 'property':
1004
+ // Handle numeric property on array as index
1005
+ if (Array.isArray(current) && typeof lastSegment.value === 'number') {
1006
+ const index = lastSegment.value;
1007
+ if (index < 0) {
1008
+ throw new Error(`Negative index ${index} not allowed`);
1009
+ }
1010
+ if (index >= current.length) {
1011
+ for (let j = current.length; j <= index; j++) {
1012
+ current.push(undefined);
1013
+ }
1014
+ }
1015
+ if (Array.isArray(value)) {
1016
+ current[index] = applyDiff(structuredClone(current[index]), value[index], true);
1017
+ }
1018
+ else {
1019
+ current[index] = value;
1020
+ }
1021
+ }
1022
+ else {
1023
+ if (!current)
1024
+ current = {};
1025
+ if (Array.isArray(current)) {
1026
+ const paths = selector.split('.');
1027
+ let ob;
1028
+ if (paths.length >= 2) {
1029
+ paths.shift();
1030
+ // if (Array.isArray(value)) {
1031
+ // }else{
1032
+ // }
1033
+ // if (selector === 'person.wife.childs') {
1034
+ // console.log('is array data', { current, value });
1035
+ // }
1036
+ for (let i = 0; i < current.length; i++) {
1037
+ if (Array.isArray(value)) {
1038
+ ob = fromPath(paths.join('.'), value[i]);
1039
+ current[i] =
1040
+ typeof current[i] === 'object'
1041
+ ? applyDiff(current[i], ob, true)
1042
+ : ob;
1043
+ }
1044
+ else {
1045
+ ob = fromPath(paths.join('.'), value);
1046
+ current[i] =
1047
+ typeof current[i] === 'object'
1048
+ ? applyDiff(current[i], ob, true)
1049
+ : ob;
1050
+ }
1051
+ }
1052
+ }
1053
+ else {
1054
+ ob = {
1055
+ [String(lastSegment.value)]: value,
1056
+ };
1057
+ }
1058
+ }
1059
+ else {
1060
+ // if (selector === 'person.wife.childs') {
1061
+ // console.log('on property', {
1062
+ // current,
1063
+ // lastSegment,
1064
+ // value,
1065
+ // key: String(lastSegment.value),
1066
+ // });
1067
+ // }
1068
+ if (Array.isArray(value) && value.length === 0) {
1069
+ if (typeof current[String(lastSegment.value)] === 'undefined') {
1070
+ current[String(lastSegment.value)] = [];
1071
+ }
1072
+ else {
1073
+ current[String(lastSegment.value)] = [];
1074
+ }
1075
+ }
1076
+ else {
1077
+ current[String(lastSegment.value)] = value;
1078
+ }
1079
+ }
1080
+ }
1081
+ break;
1082
+ case 'index':
1083
+ case 'wildcard':
1084
+ if (!Array.isArray(current)) {
1085
+ throw new Error(`Cannot use index on non-array for final segment`);
1086
+ }
1087
+ // if (selector === '[*].meta.count') {
1088
+ // console.log('on index or Wildcard last', { selector, current });
1089
+ // }
1090
+ const index = lastSegment.value;
1091
+ if (lastSegment.type === 'index') {
1092
+ if (index < 0) {
1093
+ throw new Error(`Negative index ${index} not allowed`);
1094
+ }
1095
+ if (index >= current.length) {
1096
+ for (let j = current.length; j <= index; j++) {
1097
+ current.push(undefined);
1098
+ }
1099
+ }
1100
+ if (Array.isArray(value)) {
1101
+ if (typeof current[index] === typeof value[index]) {
1102
+ try {
1103
+ current[index] = applyDiff(deepClone(current[index]), value[index], true);
1104
+ }
1105
+ catch (e) {
1106
+ // console.log('expected on array', {
1107
+ // selector,
1108
+ // current,
1109
+ // value,
1110
+ // index,
1111
+ // });
1112
+ // console.log('current', current);
1113
+ throw Error('expected on array');
1114
+ }
1115
+ }
1116
+ else {
1117
+ // current[index] = value[index];
1118
+ // setValueAtIndex(current, selector, index, value[index]);
1119
+ current[index] = value;
1120
+ }
1121
+ }
1122
+ else {
1123
+ current[index] = value;
1124
+ }
1125
+ }
1126
+ else if (lastSegment.type === 'wildcard') {
1127
+ if (Array.isArray(value)) {
1128
+ for (let i = 0; i < current.length; i++) {
1129
+ if (typeof current[i] === 'object') {
1130
+ current[i] = applyDiff(current[i], value[i], true);
1131
+ }
1132
+ else {
1133
+ current[i] = value[i];
1134
+ }
1135
+ }
1136
+ }
1137
+ else {
1138
+ for (let i = 0; i < current.length; i++) {
1139
+ if (typeof current[i] === 'object') {
1140
+ current[i] = applyDiff(current[i], value, true);
1141
+ }
1142
+ else {
1143
+ current[i] = value;
1144
+ }
1145
+ }
1146
+ }
1147
+ }
1148
+ break;
1149
+ default:
1150
+ throw new Error(`Invalid final segment type for set: ${lastSegment.type}`);
1151
+ }
1152
+ return obj;
1153
+ };
1154
+ const updateLastKey = (object, value) => {
1155
+ let obj = object ?? {};
1156
+ const keys = Object.keys(obj);
1157
+ let lastKey = keys[keys.length - 1];
1158
+ if (lastKey === undefined) {
1159
+ obj = value;
1160
+ return obj;
1161
+ }
1162
+ while (lastKey !== undefined) {
1163
+ const current = obj[lastKey];
1164
+ if (typeof current !== 'object' || Array.isArray(current)) {
1165
+ if (Array.isArray(current)) {
1166
+ if (current.length === 0) {
1167
+ current.push(value);
1168
+ }
1169
+ else {
1170
+ for (let i = 0; i < current.length; i++) {
1171
+ if (typeof current[i] === 'object' && !Array.isArray(current[i])) {
1172
+ updateLastKey(current[i], value);
1173
+ }
1174
+ else {
1175
+ current[i] = applyDiff(current[i], value, true);
1176
+ }
1177
+ }
1178
+ }
1179
+ }
1180
+ else {
1181
+ obj[lastKey] = value;
1182
+ }
1183
+ break;
1184
+ }
1185
+ const currentKeys = Object.keys(current);
1186
+ const nextKey = currentKeys[currentKeys.length - 1];
1187
+ obj = current;
1188
+ lastKey = nextKey;
1189
+ }
1190
+ };
1191
+ /**
1192
+ * Creates a nested object structure from a path string
1193
+ *
1194
+ * This function generates an object hierarchy based on a path selector and assigns
1195
+ * a value at the deepest level. It builds the structure from the inside out,
1196
+ * handling properties, array indices, wildcards, and other selector types.
1197
+ *
1198
+ * @template T - The expected return type
1199
+ * @param path - The path string describing the structure to create
1200
+ * @param value - The value to place at the end of the path (optional)
1201
+ * @returns The generated object/array structure, or undefined if no segments
1202
+ *
1203
+ * @example
1204
+ * // Simple nested object
1205
+ * fromPath('user.profile.name', 'John')
1206
+ * // Returns: { user: { profile: { name: 'John' } } }
1207
+ *
1208
+ * @example
1209
+ * // Array with specific index
1210
+ * fromPath('users[0].name', 'Alice')
1211
+ * // Returns: { users: [{ name: 'Alice' }] }
1212
+ *
1213
+ * @example
1214
+ * // Array with wildcard
1215
+ * fromPath('items[*].active', true)
1216
+ * // Returns: { items: [true] }
1217
+ *
1218
+ * @example
1219
+ * // Deep nested with arrays
1220
+ * fromPath('company.departments[2].manager.name', 'Bob')
1221
+ * // Returns: { company: { departments: [undefined, undefined, { manager: { name: 'Bob' } }] } }
1222
+ *
1223
+ * @example
1224
+ * // Single property
1225
+ * fromPath('count', 42)
1226
+ * // Returns: { count: 42 }
1227
+ */
1228
+ export const fromPath = (path, value) => {
1229
+ const segments = parseSelector(path);
1230
+ if (segments.length === 0) {
1231
+ return value;
1232
+ }
1233
+ // Build the structure from the end to the beginning
1234
+ let result = value;
1235
+ for (let i = segments.length - 1; i >= 0; i--) {
1236
+ const segment = segments[i];
1237
+ if (segment.type === 'property') {
1238
+ // Create an object with this property
1239
+ result = { [String(segment.value)]: result };
1240
+ }
1241
+ else if (segment.type === 'index') {
1242
+ // Create an array with the value at the specified index
1243
+ const index = parseInt(String(segment.value));
1244
+ const arr = [];
1245
+ arr[index] = result;
1246
+ result = arr;
1247
+ }
1248
+ else if (segment.type === 'wildcard') {
1249
+ // Create an array with one element (or wrap existing value)
1250
+ if (Array.isArray(result)) {
1251
+ // If result is already an array, keep it as is
1252
+ result = result;
1253
+ }
1254
+ else {
1255
+ // Wrap in array
1256
+ result = [result];
1257
+ }
1258
+ }
1259
+ else if (segment.type === 'slice') {
1260
+ // For slices, create an array with the value
1261
+ // The actual slice logic would be handled when reading, not creating
1262
+ if (!Array.isArray(result)) {
1263
+ result = [result];
1264
+ }
1265
+ }
1266
+ else if (segment.type === 'union') {
1267
+ // For union (multiple indices), create an array
1268
+ if (!Array.isArray(result)) {
1269
+ result = [result];
1270
+ }
1271
+ }
1272
+ else if (segment.type === 'filter') {
1273
+ // For filters, create an array
1274
+ if (!Array.isArray(result)) {
1275
+ result = [result];
1276
+ }
1277
+ }
1278
+ else if (segment.type === 'descendant') {
1279
+ // For descendant selectors, wrap in current structure
1280
+ // The actual recursive logic would be handled when reading
1281
+ result = result;
1282
+ }
1283
+ }
1284
+ return result;
1285
+ };
1286
+ /**
1287
+ * Selects values from an object (legacy method, uses get internally)
1288
+ * @deprecated Use get() instead
1289
+ */
1290
+ export const select = (obj, selector, options = {}) => {
1291
+ return get(obj, selector, { ...options, preserveStructure: false });
1292
+ };
1293
+ /**
1294
+ * Checks if a selector matches any value in object
1295
+ * @param obj - Source object
1296
+ * @param selector - Selector string or array
1297
+ * @param options - Selector options
1298
+ * @returns True if selector matches at least one value (or array of booleans for array selector)
1299
+ */
1300
+ export const has = (obj, selector, options = {}) => {
1301
+ // Handle array of selectors
1302
+ if (Array.isArray(selector)) {
1303
+ return selector.map((sel) => has(obj, sel, options));
1304
+ }
1305
+ const result = get(obj, selector, { ...options, preserveStructure: false });
1306
+ if (Array.isArray(result)) {
1307
+ if (result.length > 0) {
1308
+ return result.every((r) => r !== undefined);
1309
+ }
1310
+ return false;
1311
+ }
1312
+ return result !== undefined;
1313
+ };
1314
+ /**
1315
+ * Deletes values from object using selector
1316
+ * @param obj - Target object
1317
+ * @param selector - Selector string or array
1318
+ * @param options - Selector options
1319
+ * @returns True if any values were deleted (or array of booleans for array selector)
1320
+ */
1321
+ export const deletePath = (obj, selector, options = {}) => {
1322
+ const { throwOnError = false } = options;
1323
+ // Handle array of selectors
1324
+ if (Array.isArray(selector)) {
1325
+ return selector.map((sel) => deletePath(obj, sel, options));
1326
+ }
1327
+ const segments = parseSelector(selector, { throwOnError });
1328
+ if (segments.length === 0) {
1329
+ return false;
1330
+ }
1331
+ const lastSegment = segments[segments.length - 1];
1332
+ // For wildcards, we need to find all matching paths and delete them
1333
+ if (segments.some((s) => s.type === 'wildcard' || s.type === 'slice' || s.type === 'union')) {
1334
+ const paths = getPaths(obj, selector, options);
1335
+ let deleted = false;
1336
+ for (const path of paths) {
1337
+ if (deleteSinglePath(obj, path)) {
1338
+ deleted = true;
1339
+ }
1340
+ }
1341
+ return deleted;
1342
+ }
1343
+ // For single path deletion
1344
+ let current = obj;
1345
+ for (let i = 0; i < segments.length - 1; i++) {
1346
+ const segment = segments[i];
1347
+ if (current == null) {
1348
+ return false;
1349
+ }
1350
+ switch (segment.type) {
1351
+ case 'property':
1352
+ current = current[String(segment.value)];
1353
+ break;
1354
+ case 'index':
1355
+ if (!Array.isArray(current))
1356
+ return false;
1357
+ const index = segment.value;
1358
+ if (index < 0 || index >= current.length)
1359
+ return false;
1360
+ current = current[index];
1361
+ break;
1362
+ default:
1363
+ return false;
1364
+ }
1365
+ }
1366
+ if (current == null) {
1367
+ return false;
1368
+ }
1369
+ switch (lastSegment.type) {
1370
+ case 'property':
1371
+ if (String(lastSegment.value) in current) {
1372
+ delete current[String(lastSegment.value)];
1373
+ return true;
1374
+ }
1375
+ break;
1376
+ case 'index':
1377
+ if (!Array.isArray(current))
1378
+ return false;
1379
+ const index = lastSegment.value;
1380
+ if (index >= 0 && index < current.length) {
1381
+ current.splice(index, 1);
1382
+ return true;
1383
+ }
1384
+ break;
1385
+ }
1386
+ return false;
1387
+ };
1388
+ /**
1389
+ * Helper for deleting a single path
1390
+ */
1391
+ const deleteSinglePath = (obj, selector) => {
1392
+ const segments = parseSelector(selector);
1393
+ if (segments.length === 0) {
1394
+ return false;
1395
+ }
1396
+ const lastSegment = segments[segments.length - 1];
1397
+ let current = obj;
1398
+ for (let i = 0; i < segments.length - 1; i++) {
1399
+ const segment = segments[i];
1400
+ if (current == null) {
1401
+ return false;
1402
+ }
1403
+ switch (segment.type) {
1404
+ case 'property':
1405
+ current = current[String(segment.value)];
1406
+ break;
1407
+ case 'index':
1408
+ if (!Array.isArray(current))
1409
+ return false;
1410
+ const index = segment.value;
1411
+ if (index < 0 || index >= current.length)
1412
+ return false;
1413
+ current = current[index];
1414
+ break;
1415
+ default:
1416
+ return false;
1417
+ }
1418
+ }
1419
+ if (current == null) {
1420
+ return false;
1421
+ }
1422
+ switch (lastSegment.type) {
1423
+ case 'property':
1424
+ if (String(lastSegment.value) in current) {
1425
+ delete current[String(lastSegment.value)];
1426
+ return true;
1427
+ }
1428
+ break;
1429
+ case 'index':
1430
+ if (!Array.isArray(current))
1431
+ return false;
1432
+ const index = lastSegment.value;
1433
+ if (index >= 0 && index < current.length) {
1434
+ current.splice(index, 1);
1435
+ return true;
1436
+ }
1437
+ break;
1438
+ }
1439
+ return false;
1440
+ };
1441
+ /**
1442
+ * Gets all matching paths from an object
1443
+ * @param obj - Source object
1444
+ * @param selector - Selector string or array (optional, if not provided returns all paths)
1445
+ * @param options - Selector options
1446
+ * @returns Array of path strings
1447
+ */
1448
+ export const getPaths = (obj, selector, options = {}) => {
1449
+ const { format = 'selector', maxDepth = 20 } = options;
1450
+ // Handle array of selectors
1451
+ if (selector && Array.isArray(selector)) {
1452
+ const allPaths = [];
1453
+ for (const sel of selector) {
1454
+ const paths = getPaths(obj, sel, options);
1455
+ allPaths.push(...paths);
1456
+ }
1457
+ return allPaths;
1458
+ }
1459
+ if (selector) {
1460
+ // Get paths matching the selector
1461
+ const segments = parseSelector(selector, options);
1462
+ const results = traverseWithPaths(obj, segments, 0, maxDepth);
1463
+ return results.map((r) => format === 'selector' ? r.path : r.stringPath);
1464
+ }
1465
+ // Get all paths
1466
+ const allPaths = [];
1467
+ const traverseAll = (current, path = [], stringPath = [], depth = 0) => {
1468
+ if (depth > maxDepth)
1469
+ return;
1470
+ // Add current path
1471
+ if (path.length > 0) {
1472
+ const pathStr = stringifySelector(path);
1473
+ allPaths.push({ path: pathStr, stringPath: stringPath.join('.') });
1474
+ }
1475
+ if (current && typeof current === 'object') {
1476
+ if (Array.isArray(current)) {
1477
+ for (let i = 0; i < current.length; i++) {
1478
+ traverseAll(current[i], [...path, { type: 'index', value: i, raw: `[${i}]` }], [...stringPath, `[${i}]`], depth + 1);
1479
+ }
1480
+ }
1481
+ else {
1482
+ for (const key in current) {
1483
+ if (current.hasOwnProperty(key)) {
1484
+ traverseAll(current[key], [...path, { type: 'property', value: key, raw: key }], [...stringPath, key], depth + 1);
1485
+ }
1486
+ }
1487
+ }
1488
+ }
1489
+ };
1490
+ traverseAll(obj);
1491
+ return allPaths.map((p) => format === 'selector' ? p.path : p.stringPath);
1492
+ };
1493
+ /**
1494
+ * Finds all paths that match a predicate
1495
+ * @param obj - Source object
1496
+ * @param predicate - Function to test each path/value pair
1497
+ * @returns Array of matching path strings
1498
+ * @example
1499
+ * findPaths({a: 1, b: {c: 2}}, (path, value) => value === 2) // ['b.c']
1500
+ */
1501
+ export const findPaths = (obj, predicate) => {
1502
+ const paths = getPaths(obj);
1503
+ return paths.filter((path) => {
1504
+ const value = get(obj, path);
1505
+ return predicate(path, value);
1506
+ });
1507
+ };
1508
+ /**
1509
+ * Flattens an object with array notation in keys
1510
+ * @param obj - Source object
1511
+ * @param separator - Separator for nested keys (default: '.')
1512
+ * @returns Flattened object with array notation
1513
+ * @example
1514
+ * flattenWithArrays({a: [{b: 1}, {b: 2}]}) // {'a[0].b': 1, 'a[1].b': 2}
1515
+ */
1516
+ export const flattenWithArrays = (obj, separator = '.') => {
1517
+ const result = {};
1518
+ const traverse = (current, path = []) => {
1519
+ if (current == null)
1520
+ return;
1521
+ const trav = traverseStructure(current, path, 0, 20);
1522
+ if (trav !== undefined) {
1523
+ result[stringifySelector(path)] = trav;
1524
+ return;
1525
+ }
1526
+ if (Array.isArray(current)) {
1527
+ for (let i = 0; i < current.length; i++) {
1528
+ const newPath = [
1529
+ ...path,
1530
+ { type: 'index', value: i, raw: `[${i}]` },
1531
+ ];
1532
+ traverse(current[i], newPath);
1533
+ }
1534
+ }
1535
+ else if (isObject(current)) {
1536
+ for (const key in current) {
1537
+ if (current.hasOwnProperty(key)) {
1538
+ const newPath = [
1539
+ ...path,
1540
+ { type: 'property', value: key, raw: key },
1541
+ ];
1542
+ traverse(current[key], newPath);
1543
+ }
1544
+ }
1545
+ // Handle symbols
1546
+ const symbols = Object.getOwnPropertySymbols(current);
1547
+ for (const symbol of symbols) {
1548
+ const newPath = [
1549
+ ...path,
1550
+ {
1551
+ type: 'property',
1552
+ value: symbol.toString(),
1553
+ raw: symbol.toString(),
1554
+ },
1555
+ ];
1556
+ traverse(current[symbol], newPath);
1557
+ }
1558
+ }
1559
+ else {
1560
+ // Primitive value - add to result
1561
+ const pathStr = stringifySelector(path);
1562
+ result[pathStr] = current;
1563
+ }
1564
+ };
1565
+ traverse(obj);
1566
+ return result;
1567
+ };
1568
+ /**
1569
+ * Unflattens an object with array notation in keys
1570
+ * @param obj - Source object
1571
+ * @returns Unflattened object
1572
+ * @example
1573
+ * unflattenWithArrays({'a[0].b': 1, 'a[1].b': 2}) // {a: [{b: 1}, {b: 2}]}
1574
+ */
1575
+ export const unflattenWithArrays = (obj) => {
1576
+ const result = {};
1577
+ for (const key in obj) {
1578
+ set(result, key, obj[key]);
1579
+ }
1580
+ return result;
1581
+ };
1582
+ /**
1583
+ * Merges objects with array notation support for paths
1584
+ * @param objects - Objects to merge
1585
+ * @returns Merged object
1586
+ */
1587
+ export const deepMergeWithArrays = (...objects) => {
1588
+ const result = {};
1589
+ for (const obj of objects) {
1590
+ if (!isObject(obj))
1591
+ continue;
1592
+ const flat = flattenWithArrays(obj);
1593
+ for (const path in flat) {
1594
+ set(result, path, flat[path]);
1595
+ }
1596
+ }
1597
+ return result;
1598
+ };
1599
+ /**
1600
+ * Traverse with path tracking
1601
+ * @param current - Current value
1602
+ * @param segments - Selector segments
1603
+ * @param depth - Current depth
1604
+ * @param maxDepth - Maximum depth
1605
+ * @param currentPath - Current path array
1606
+ * @param currentStringPath - Current string path array
1607
+ * @returns Array of values with paths
1608
+ * @example
1609
+ * traverseWithPaths({ a: { b: 1 } }, ['a', 'b'], 0, 2);
1610
+ * // [{ value: 1, path: 'a.b', stringPath: 'a.b' }]
1611
+ */
1612
+ export function traverseWithPaths(current, segments, depth, maxDepth, currentPath = [], currentStringPath = []) {
1613
+ if (depth > maxDepth)
1614
+ return [];
1615
+ if (segments.length === 0)
1616
+ return [
1617
+ {
1618
+ value: current,
1619
+ path: stringifySelector(currentPath),
1620
+ stringPath: currentStringPath.join('.'),
1621
+ },
1622
+ ];
1623
+ const segment = segments[0];
1624
+ const remaining = segments.slice(1);
1625
+ const results = [];
1626
+ // Handle descendant selector
1627
+ if (segment.type === 'descendant') {
1628
+ // Current level
1629
+ results.push(...traverseWithPaths(current, remaining, depth + 1, maxDepth, currentPath, currentStringPath));
1630
+ // Recursive descent
1631
+ if (current && typeof current === 'object') {
1632
+ if (Array.isArray(current)) {
1633
+ for (let i = 0; i < current.length; i++) {
1634
+ results.push(...traverseWithPaths(current[i], segments, // Use same segments for recursion
1635
+ depth + 1, maxDepth, [...currentPath, { type: 'index', value: i, raw: `[${i}]` }], [...currentStringPath, `[${i}]`]));
1636
+ }
1637
+ }
1638
+ else {
1639
+ for (const key in current) {
1640
+ if (current.hasOwnProperty(key)) {
1641
+ results.push(...traverseWithPaths(current[key], segments, depth + 1, maxDepth, [...currentPath, { type: 'property', value: key, raw: key }], [...currentStringPath, key]));
1642
+ }
1643
+ }
1644
+ }
1645
+ }
1646
+ return results;
1647
+ }
1648
+ // Handle other segment types
1649
+ switch (segment.type) {
1650
+ case 'property':
1651
+ if (current &&
1652
+ typeof current === 'object' &&
1653
+ String(segment.value) in current) {
1654
+ const next = current[String(segment.value)];
1655
+ results.push(...traverseWithPaths(next, remaining, depth + 1, maxDepth, [...currentPath, segment], [...currentStringPath, String(segment.value)]));
1656
+ }
1657
+ break;
1658
+ case 'index':
1659
+ if (Array.isArray(current)) {
1660
+ const index = segment.value;
1661
+ if (index >= 0 && index < current.length) {
1662
+ results.push(...traverseWithPaths(current[index], remaining, depth + 1, maxDepth, [...currentPath, segment], [...currentStringPath, `[${index}]`]));
1663
+ }
1664
+ }
1665
+ else if (current && typeof current === 'object') {
1666
+ const key = String(segment.value);
1667
+ if (key in current) {
1668
+ results.push(...traverseWithPaths(current[key], remaining, depth + 1, maxDepth, [...currentPath, { ...segment, type: 'property' }], [...currentStringPath, key]));
1669
+ }
1670
+ }
1671
+ break;
1672
+ case 'wildcard':
1673
+ if (current && typeof current === 'object') {
1674
+ if (Array.isArray(current)) {
1675
+ for (let i = 0; i < current.length; i++) {
1676
+ results.push(...traverseWithPaths(current[i], remaining, depth + 1, maxDepth, [...currentPath, { type: 'index', value: i, raw: `[${i}]` }], [...currentStringPath, `[${i}]`]));
1677
+ }
1678
+ }
1679
+ else {
1680
+ for (const key in current) {
1681
+ if (current.hasOwnProperty(key)) {
1682
+ results.push(...traverseWithPaths(current[key], remaining, depth + 1, maxDepth, [...currentPath, { type: 'property', value: key, raw: key }], [...currentStringPath, key]));
1683
+ }
1684
+ }
1685
+ }
1686
+ }
1687
+ break;
1688
+ case 'slice':
1689
+ if (Array.isArray(current)) {
1690
+ const [start, end] = segment.value;
1691
+ const actualStart = Math.max(0, start);
1692
+ const actualEnd = Math.min(current.length, end === Infinity ? current.length : end);
1693
+ for (let i = actualStart; i < actualEnd; i++) {
1694
+ results.push(...traverseWithPaths(current[i], remaining, depth + 1, maxDepth, [...currentPath, { type: 'index', value: i, raw: `[${i}]` }], [...currentStringPath, `[${i}]`]));
1695
+ }
1696
+ }
1697
+ break;
1698
+ case 'union':
1699
+ if (Array.isArray(current)) {
1700
+ const indices = segment.value;
1701
+ for (const index of indices) {
1702
+ if (index >= 0 && index < current.length) {
1703
+ results.push(...traverseWithPaths(current[index], remaining, depth + 1, maxDepth, [
1704
+ ...currentPath,
1705
+ { type: 'index', value: index, raw: `[${index}]` },
1706
+ ], [...currentStringPath, `[${index}]`]));
1707
+ }
1708
+ }
1709
+ }
1710
+ break;
1711
+ case 'filter':
1712
+ if (Array.isArray(current)) {
1713
+ const filterFn = segment.value;
1714
+ for (let i = 0; i < current.length; i++) {
1715
+ if (filterFn(current[i])) {
1716
+ results.push(...traverseWithPaths(current[i], remaining, depth + 1, maxDepth, [...currentPath, { type: 'index', value: i, raw: `[${i}]` }], [...currentStringPath, `[${i}]`]));
1717
+ }
1718
+ }
1719
+ }
1720
+ break;
1721
+ }
1722
+ return results;
1723
+ }
1724
+ /**
1725
+ * Updates a value at a path using a transformation function
1726
+ * @param obj - Target object
1727
+ * @param path - Path string
1728
+ * @param updater - Function to transform the current value
1729
+ * @returns Modified object
1730
+ * @example
1731
+ * update({a: {b: 1}}, 'a.b', (val) => val + 1) // {a: {b: 2}}
1732
+ * update({items: [{count: 1}]}, 'items[0].count', (count) => count * 2) // {items: [{count: 2}]}
1733
+ */
1734
+ export const update = (obj, path, updater) => {
1735
+ const currentValue = get(obj, path);
1736
+ const newValue = updater(currentValue);
1737
+ return setValueAtPath(obj, path, newValue);
1738
+ };
1739
+ export const updateWithCallBack = (obj, updater) => {
1740
+ const newValue = updater(obj);
1741
+ // console.log('update trigger', obj, path, newValue)
1742
+ // if(typeof newValue === 'number'){
1743
+ // return setAtPath(obj, path, newValue);
1744
+ // }
1745
+ // return setValueAtPath(obj as any, path as any, newValue as any);
1746
+ // console.log('callback update before', Array.isArray(obj) ? [...obj] : {...obj} , newValue);
1747
+ const result = applyDiff(obj, newValue, true);
1748
+ // const result = deepMerge(obj, newValue);
1749
+ // console.log('callback update', {obj, result, updater, newValue})
1750
+ // return obj;
1751
+ return result;
1752
+ };
1753
+ /**
1754
+ * Gets the type of value at a path
1755
+ * @param obj - Source object
1756
+ * @param path - Path string
1757
+ * @returns Type string or undefined
1758
+ * @example
1759
+ * getTypeAtPath({a: [{b: 1}]}, 'a[0].b') // 'number'
1760
+ * getTypeAtPath({a: null}, 'a.b') // undefined
1761
+ */
1762
+ export const getTypeAtPath = (obj, path) => {
1763
+ const value = get(obj, path);
1764
+ if (value === undefined)
1765
+ return undefined;
1766
+ if (value === null)
1767
+ return 'null';
1768
+ if (Array.isArray(value))
1769
+ return 'array';
1770
+ return typeof value;
1771
+ };