@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,805 @@
1
+ /**
2
+ * @fileoverview Object diff utilities for comparing and tracking changes
3
+ * @description Provides utilities to diff objects and return structured changes
4
+ */
5
+ import { isObject } from './utils.js';
6
+ /**
7
+ * Default equality function using strict equality
8
+ */
9
+ const defaultEqualityFn = (a, b) => a === b;
10
+ /**
11
+ * Deep equality check for arrays
12
+ */
13
+ const deepArrayEqual = (arr1, arr2) => {
14
+ if (arr1.length !== arr2.length)
15
+ return false;
16
+ for (let i = 0; i < arr1.length; i++) {
17
+ if (Array.isArray(arr1[i]) && Array.isArray(arr2[i])) {
18
+ if (!deepArrayEqual(arr1[i], arr2[i]))
19
+ return false;
20
+ }
21
+ else if (isObject(arr1[i]) && isObject(arr2[i])) {
22
+ if (!deepObjectEqual(arr1[i], arr2[i]))
23
+ return false;
24
+ }
25
+ else if (arr1[i] !== arr2[i]) {
26
+ return false;
27
+ }
28
+ }
29
+ return true;
30
+ };
31
+ /**
32
+ * Deep equality check for objects
33
+ */
34
+ const deepObjectEqual = (obj1, obj2) => {
35
+ const keys1 = Object.keys(obj1);
36
+ const keys2 = Object.keys(obj2);
37
+ if (keys1.length !== keys2.length)
38
+ return false;
39
+ for (const key of keys1) {
40
+ if (!(key in obj2))
41
+ return false;
42
+ const val1 = obj1[key];
43
+ const val2 = obj2[key];
44
+ if (Array.isArray(val1) && Array.isArray(val2)) {
45
+ if (!deepArrayEqual(val1, val2))
46
+ return false;
47
+ }
48
+ else if (isObject(val1) && isObject(val2)) {
49
+ if (!deepObjectEqual(val1, val2))
50
+ return false;
51
+ }
52
+ else if (val1 !== val2) {
53
+ return false;
54
+ }
55
+ }
56
+ return true;
57
+ };
58
+ /**
59
+ * Compares two objects and returns only the changed values while preserving the object structure
60
+ *
61
+ * @param oldObj - The original object
62
+ * @param newObj - The new object to compare against
63
+ * @param options - Configuration options for diff behavior
64
+ * @returns Object with the same structure containing only changed values
65
+ *
66
+ * @example
67
+ * ```ts
68
+ * const old = { a: 1, b: { c: 2, d: 3 }, e: 5 };
69
+ * const new = { a: 1, b: { c: 4, d: 3 }, e: 5, f: 6 };
70
+ * const diff = diffObject(old, new);
71
+ * // Returns: { b: { c: 4 }, f: 6 }
72
+ * ```
73
+ *
74
+ * @example
75
+ * ```ts
76
+ * // With arrays
77
+ * const old = { items: [1, 2, 3], meta: { count: 3 } };
78
+ * const new = { items: [1, 2, 4], meta: { count: 4 } };
79
+ * const diff = diffObject(old, new);
80
+ * // Returns: { items: [1, 2, 4], meta: { count: 4 } }
81
+ * ```
82
+ *
83
+ * @example
84
+ * ```ts
85
+ * // Include deleted properties
86
+ * const old = { a: 1, b: 2, c: 3 };
87
+ * const new = { a: 1, c: 4 };
88
+ * const diff = diffObject(old, new, { includeDeleted: true });
89
+ * // Returns: { b: undefined, c: 4 }
90
+ * ```
91
+ */
92
+ export const diffObject = (oldObj, newObj, options = {}) => {
93
+ const { includeDeleted = false, includeAdded = true, deepArrayComparison = true, equalityFn = defaultEqualityFn, preserveStructure = false, } = options;
94
+ // Handle null/undefined cases
95
+ if (oldObj == null && newObj == null) {
96
+ return {};
97
+ }
98
+ if (oldObj == null) {
99
+ return includeAdded ? { ...newObj } : {};
100
+ }
101
+ if (newObj == null) {
102
+ if (includeDeleted) {
103
+ const result = {};
104
+ for (const key in oldObj) {
105
+ result[key] = undefined;
106
+ }
107
+ return result;
108
+ }
109
+ return {};
110
+ }
111
+ // Ensure both are objects
112
+ if (!isObject(oldObj) || !isObject(newObj)) {
113
+ return equalityFn(oldObj, newObj)
114
+ ? {}
115
+ : newObj;
116
+ }
117
+ const result = {};
118
+ const processedKeys = new Set();
119
+ // Process all keys in newObj
120
+ for (const key in newObj) {
121
+ processedKeys.add(key);
122
+ const oldValue = oldObj[key];
123
+ const newValue = newObj[key];
124
+ // Key doesn't exist in old object - it's added
125
+ if (!(key in oldObj)) {
126
+ if (includeAdded) {
127
+ result[key] = newValue;
128
+ }
129
+ continue;
130
+ }
131
+ // Both values are arrays
132
+ if (Array.isArray(oldValue) && Array.isArray(newValue)) {
133
+ if (deepArrayComparison) {
134
+ if (!deepArrayEqual(oldValue, newValue)) {
135
+ result[key] = newValue;
136
+ }
137
+ else if (preserveStructure) {
138
+ result[key] = undefined;
139
+ }
140
+ }
141
+ else {
142
+ if (oldValue !== newValue) {
143
+ result[key] = newValue;
144
+ }
145
+ else if (preserveStructure) {
146
+ result[key] = undefined;
147
+ }
148
+ }
149
+ continue;
150
+ }
151
+ // Both values are objects - recurse
152
+ if (isObject(oldValue) && isObject(newValue)) {
153
+ const nestedDiff = diffObject(oldValue, newValue, options);
154
+ // Only include if there are changes
155
+ if (Object.keys(nestedDiff).length > 0) {
156
+ result[key] = nestedDiff;
157
+ }
158
+ else if (preserveStructure) {
159
+ result[key] = undefined;
160
+ }
161
+ continue;
162
+ }
163
+ // Primitive comparison or type mismatch
164
+ if (!equalityFn(oldValue, newValue)) {
165
+ result[key] = newValue;
166
+ }
167
+ else if (preserveStructure) {
168
+ result[key] = undefined;
169
+ }
170
+ }
171
+ // Process deleted keys (exist in old but not in new)
172
+ if (includeDeleted) {
173
+ for (const key in oldObj) {
174
+ if (!processedKeys.has(key)) {
175
+ result[key] = undefined;
176
+ }
177
+ }
178
+ }
179
+ return result;
180
+ };
181
+ /**
182
+ * Returns detailed diff with metadata about changes for objects and arrays
183
+ *
184
+ * @param oldObj - The original object or array
185
+ * @param newObj - The new object or array to compare against
186
+ * @param options - Configuration options for diff behavior
187
+ * @returns Detailed diff result with metadata including array indices in paths
188
+ *
189
+ * @example
190
+ * ```ts
191
+ * // Object example
192
+ * const old = { a: 1, b: 2, c: 3 };
193
+ * const new = { a: 1, b: 4, d: 5 };
194
+ * const result = diffObjectDetailed(old, new);
195
+ * // {
196
+ * // changes: { b: 4, d: 5 },
197
+ * // added: ['d'],
198
+ * // deleted: ['c'],
199
+ * // modified: ['b'],
200
+ * // hasChanges: true
201
+ * // }
202
+ * ```
203
+ *
204
+ * @example
205
+ * ```ts
206
+ * // Nested array example
207
+ * const old = { items: [{ id: 1, name: 'a' }, { id: 2, name: 'b' }] };
208
+ * const new = { items: [{ id: 1, name: 'x' }, { id: 2, name: 'b' }] };
209
+ * const result = diffObjectDetailed(old, new);
210
+ * // modified: ['items[0].name']
211
+ * ```
212
+ *
213
+ * @example
214
+ * ```ts
215
+ * // Top-level array example
216
+ * const old = [1, 2, 3, 4];
217
+ * const new = [1, 5, 3];
218
+ * const result = diffObjectDetailed(old, new);
219
+ * // {
220
+ * // changes: [1, 5, 3], // Returns the new array with changes
221
+ * // added: [],
222
+ * // deleted: ['[3]'], // Index 3 was removed
223
+ * // modified: ['[1]'], // Index 1 changed from 2 to 5
224
+ * // hasChanges: true
225
+ * // }
226
+ * ```
227
+ *
228
+ * @example
229
+ * ```ts
230
+ * // Array of objects example
231
+ * const old = [{ id: 1, name: 'Alice' }, { id: 2, name: 'Bob' }];
232
+ * const new = [{ id: 1, name: 'Alicia' }, { id: 2, name: 'Bob' }];
233
+ * const result = diffObjectDetailed(old, new);
234
+ * // {
235
+ * // changes: [{ id: 1, name: 'Alicia' }, { id: 2, name: 'Bob' }],
236
+ * // modified: ['[0]'], // First element modified
237
+ * // hasChanges: true
238
+ * // }
239
+ * ```
240
+ */
241
+ export const diffObjectDetailed = (oldObj, newObj, options = {}) => {
242
+ const added = [];
243
+ const deleted = [];
244
+ const modified = [];
245
+ const changes = {};
246
+ const { includeDeleted = false, includeAdded = true, deepArrayComparison = true, equalityFn = defaultEqualityFn, } = options;
247
+ // Handle arrays at the top level
248
+ if (Array.isArray(oldObj) && Array.isArray(newObj)) {
249
+ const maxLength = Math.max(oldObj.length, newObj.length);
250
+ const arrayChanges = [];
251
+ let hasArrayChanges = false;
252
+ for (let i = 0; i < maxLength; i++) {
253
+ const indexPath = `[${i}]`;
254
+ if (i >= oldObj.length) {
255
+ // Added element
256
+ added.push(indexPath);
257
+ arrayChanges[i] = newObj[i];
258
+ hasArrayChanges = true;
259
+ }
260
+ else if (i >= newObj.length) {
261
+ // Deleted element - always track deletions for arrays
262
+ deleted.push(indexPath);
263
+ hasArrayChanges = true;
264
+ // Don't add to arrayChanges - changes array should match newObj length
265
+ }
266
+ else {
267
+ // Compare elements
268
+ const oldElement = oldObj[i];
269
+ const newElement = newObj[i];
270
+ if (isObject(oldElement) && isObject(newElement)) {
271
+ const nestedDiff = diffObjectDetailed(oldElement, newElement, options);
272
+ if (nestedDiff.hasChanges) {
273
+ modified.push(indexPath);
274
+ arrayChanges[i] = newElement;
275
+ hasArrayChanges = true;
276
+ }
277
+ else {
278
+ arrayChanges[i] = oldElement;
279
+ }
280
+ }
281
+ else if (Array.isArray(oldElement) && Array.isArray(newElement)) {
282
+ const nestedDiff = diffObjectDetailed(oldElement, newElement, options);
283
+ if (nestedDiff.hasChanges) {
284
+ modified.push(indexPath);
285
+ arrayChanges[i] = newElement;
286
+ hasArrayChanges = true;
287
+ }
288
+ else {
289
+ arrayChanges[i] = oldElement;
290
+ }
291
+ }
292
+ else if (!equalityFn(oldElement, newElement)) {
293
+ modified.push(indexPath);
294
+ arrayChanges[i] = newElement;
295
+ hasArrayChanges = true;
296
+ }
297
+ else {
298
+ arrayChanges[i] = oldElement;
299
+ }
300
+ }
301
+ }
302
+ // For arrays, always include deletions in changes to trigger store updates
303
+ // The hasChanges flag includes deletions even if includeDeleted is false
304
+ return {
305
+ changes: (hasArrayChanges ? arrayChanges : {}),
306
+ added,
307
+ deleted,
308
+ modified,
309
+ hasChanges: hasArrayChanges || deleted.length > 0,
310
+ };
311
+ }
312
+ // Helper to collect paths with array index support and categorize them
313
+ const collectDetailedPaths = (old, newVal, currentPath = '') => {
314
+ const result = {
315
+ added: [],
316
+ deleted: [],
317
+ modified: [],
318
+ };
319
+ // Handle arrays
320
+ if (Array.isArray(old) && Array.isArray(newVal)) {
321
+ const maxLength = Math.max(old.length, newVal.length);
322
+ for (let i = 0; i < maxLength; i++) {
323
+ const indexPath = currentPath ? `${currentPath}[${i}]` : `[${i}]`;
324
+ if (i >= old.length) {
325
+ // Added element
326
+ result.added.push(indexPath);
327
+ }
328
+ else if (i >= newVal.length) {
329
+ // Deleted element
330
+ result.deleted.push(indexPath);
331
+ }
332
+ else {
333
+ // Compare elements
334
+ const oldElement = old[i];
335
+ const newElement = newVal[i];
336
+ if (isObject(oldElement) && isObject(newElement)) {
337
+ const nested = collectDetailedPaths(oldElement, newElement, indexPath);
338
+ result.added.push(...nested.added);
339
+ result.deleted.push(...nested.deleted);
340
+ result.modified.push(...nested.modified);
341
+ }
342
+ else if (Array.isArray(oldElement) && Array.isArray(newElement)) {
343
+ const nested = collectDetailedPaths(oldElement, newElement, indexPath);
344
+ result.added.push(...nested.added);
345
+ result.deleted.push(...nested.deleted);
346
+ result.modified.push(...nested.modified);
347
+ }
348
+ else if (oldElement !== newElement) {
349
+ result.modified.push(indexPath);
350
+ }
351
+ }
352
+ }
353
+ return result;
354
+ }
355
+ // Handle objects
356
+ if (isObject(old) && isObject(newVal)) {
357
+ const allKeys = new Set([
358
+ ...Object.keys(old || {}),
359
+ ...Object.keys(newVal || {}),
360
+ ]);
361
+ for (const key of allKeys) {
362
+ const oldValue = old?.[key];
363
+ const newValue = newVal?.[key];
364
+ const path = currentPath ? `${currentPath}.${key}` : key;
365
+ if (!(key in (old || {}))) {
366
+ // Added
367
+ result.added.push(path);
368
+ }
369
+ else if (!(key in (newVal || {}))) {
370
+ // Deleted
371
+ result.deleted.push(path);
372
+ }
373
+ else if (Array.isArray(oldValue) && Array.isArray(newValue)) {
374
+ // Compare arrays
375
+ if (!deepArrayEqual(oldValue, newValue)) {
376
+ const nested = collectDetailedPaths(oldValue, newValue, path);
377
+ result.added.push(...nested.added);
378
+ result.deleted.push(...nested.deleted);
379
+ result.modified.push(...nested.modified);
380
+ }
381
+ }
382
+ else if (isObject(oldValue) && isObject(newValue)) {
383
+ // Recurse into objects
384
+ const nested = collectDetailedPaths(oldValue, newValue, path);
385
+ result.added.push(...nested.added);
386
+ result.deleted.push(...nested.deleted);
387
+ result.modified.push(...nested.modified);
388
+ }
389
+ else if (oldValue !== newValue) {
390
+ // Modified
391
+ result.modified.push(path);
392
+ }
393
+ }
394
+ }
395
+ return result;
396
+ };
397
+ // Handle null/undefined cases
398
+ if (oldObj == null && newObj == null) {
399
+ return { changes: {}, added, deleted, modified, hasChanges: false };
400
+ }
401
+ if (oldObj == null) {
402
+ if (includeAdded && newObj) {
403
+ for (const key in newObj) {
404
+ added.push(key);
405
+ changes[key] = newObj[key];
406
+ }
407
+ }
408
+ return {
409
+ changes,
410
+ added,
411
+ deleted,
412
+ modified,
413
+ hasChanges: added.length > 0,
414
+ };
415
+ }
416
+ if (newObj == null) {
417
+ if (includeDeleted) {
418
+ for (const key in oldObj) {
419
+ deleted.push(key);
420
+ changes[key] = undefined;
421
+ }
422
+ }
423
+ return {
424
+ changes,
425
+ added,
426
+ deleted,
427
+ modified,
428
+ hasChanges: deleted.length > 0,
429
+ };
430
+ }
431
+ const processedKeys = new Set();
432
+ // Process all keys in newObj
433
+ for (const key in newObj) {
434
+ processedKeys.add(key);
435
+ const oldValue = oldObj[key];
436
+ const newValue = newObj[key];
437
+ // Key doesn't exist in old object - it's added
438
+ if (!(key in oldObj)) {
439
+ if (includeAdded) {
440
+ added.push(key);
441
+ changes[key] = newValue;
442
+ }
443
+ continue;
444
+ }
445
+ // Check if values are different
446
+ let isDifferent = false;
447
+ if (Array.isArray(oldValue) && Array.isArray(newValue)) {
448
+ isDifferent = deepArrayComparison
449
+ ? !deepArrayEqual(oldValue, newValue)
450
+ : oldValue !== newValue;
451
+ if (isDifferent) {
452
+ const paths = collectDetailedPaths(oldValue, newValue, key);
453
+ added.push(...paths.added);
454
+ deleted.push(...paths.deleted);
455
+ modified.push(...paths.modified);
456
+ changes[key] = newValue;
457
+ }
458
+ }
459
+ else if (isObject(oldValue) && isObject(newValue)) {
460
+ const nestedDiff = diffObject(oldValue, newValue, options);
461
+ isDifferent = Object.keys(nestedDiff).length > 0;
462
+ if (isDifferent) {
463
+ const paths = collectDetailedPaths(oldValue, newValue, key);
464
+ added.push(...paths.added);
465
+ deleted.push(...paths.deleted);
466
+ modified.push(...paths.modified);
467
+ changes[key] = nestedDiff;
468
+ }
469
+ }
470
+ else {
471
+ isDifferent = !equalityFn(oldValue, newValue);
472
+ if (isDifferent) {
473
+ modified.push(key);
474
+ changes[key] = newValue;
475
+ }
476
+ }
477
+ }
478
+ // Process deleted keys - always track them for the store to work correctly
479
+ for (const key in oldObj) {
480
+ if (!processedKeys.has(key)) {
481
+ deleted.push(key);
482
+ // Always include deletions in changes so store signals are triggered
483
+ changes[key] = undefined;
484
+ }
485
+ }
486
+ return {
487
+ changes,
488
+ added,
489
+ deleted,
490
+ modified,
491
+ hasChanges: added.length > 0 || deleted.length > 0 || modified.length > 0,
492
+ };
493
+ };
494
+ /**
495
+ * Checks if two objects have any differences
496
+ *
497
+ * @param oldObj - The original object
498
+ * @param newObj - The new object to compare against
499
+ * @param options - Configuration options for diff behavior
500
+ * @returns True if objects are different
501
+ *
502
+ * @example
503
+ * ```ts
504
+ * hasObjectChanges({ a: 1 }, { a: 1 }) // false
505
+ * hasObjectChanges({ a: 1 }, { a: 2 }) // true
506
+ * ```
507
+ */
508
+ export const hasObjectChanges = (oldObj, newObj, options = {}) => {
509
+ const diff = diffObject(oldObj, newObj, options);
510
+ return Object.keys(diff).length > 0;
511
+ };
512
+ /**
513
+ * Applies a diff object to an original object or array to produce the new object/array
514
+ *
515
+ * @param baseObj - The base object or array to apply changes to
516
+ * @param diff - The diff object or array containing changes
517
+ * @param keepRef - If true, modifies the original object/array instead of creating a copy
518
+ * @returns New object/array with changes applied
519
+ *
520
+ * @example
521
+ * ```ts
522
+ * // Object example
523
+ * const base = { a: 1, b: { c: 2, d: 3 } };
524
+ * const diff = { b: { c: 4 } };
525
+ * const result = applyDiff(base, diff);
526
+ * // Returns: { a: 1, b: { c: 4, d: 3 } }
527
+ * ```
528
+ *
529
+ * @example
530
+ * ```ts
531
+ * // Array example
532
+ * const base = [1, 2, 3, 4];
533
+ * const diff = [10, undefined, 30]; // undefined means no change
534
+ * const result = applyDiff(base, diff);
535
+ * // Returns: [10, 2, 30, 4]
536
+ * ```
537
+ *
538
+ * @example
539
+ * ```ts
540
+ * // Nested array/object example
541
+ * const base = [{ id: 1, name: 'Alice' }, { id: 2, name: 'Bob' }];
542
+ * const diff = [{ name: 'Alicia' }, undefined]; // Change first item's name
543
+ * const result = applyDiff(base, diff);
544
+ * // Returns: [{ id: 1, name: 'Alicia' }, { id: 2, name: 'Bob' }]
545
+ * ```
546
+ */
547
+ function isApplyDiff(value) {
548
+ if (value &&
549
+ (value.diff || value.changes) &&
550
+ (value.modified ||
551
+ value.deleted ||
552
+ value.hasChanges)) {
553
+ return true;
554
+ }
555
+ return false;
556
+ }
557
+ export const applyDiff = (baseObj, option, keepRefParam) => {
558
+ // If option is just a plain object (not ApplyDiff), apply it directly
559
+ if (!isApplyDiff(option)) {
560
+ const diff = option;
561
+ const shouldKeepRef = keepRefParam || false;
562
+ // Handle arrays
563
+ if (Array.isArray(baseObj) && Array.isArray(diff)) {
564
+ const result = shouldKeepRef ? baseObj : [...baseObj];
565
+ // Only adjust length if diff is shorter (deletions)
566
+ if (diff.length < result.length) {
567
+ result.length = diff.length;
568
+ }
569
+ for (let i = 0; i < diff.length; i++) {
570
+ const diffValue = diff[i];
571
+ // undefined means "no change" - keep original value
572
+ if (diffValue === undefined) {
573
+ continue;
574
+ }
575
+ if (isObject(result[i]) && isObject(diffValue)) {
576
+ result[i] = applyDiff(result[i], diffValue, shouldKeepRef);
577
+ }
578
+ else if (Array.isArray(result[i]) && Array.isArray(diffValue)) {
579
+ result[i] = applyDiff(result[i], diffValue, shouldKeepRef);
580
+ }
581
+ else {
582
+ result[i] = diffValue;
583
+ }
584
+ }
585
+ return result;
586
+ }
587
+ // Handle objects
588
+ if (!isObject(baseObj))
589
+ return diff;
590
+ if (!isObject(diff))
591
+ return baseObj;
592
+ const result = shouldKeepRef ? baseObj : { ...baseObj };
593
+ for (const key in diff) {
594
+ const diffValue = diff[key];
595
+ if (diffValue === undefined) {
596
+ delete result[key];
597
+ }
598
+ else if (Array.isArray(result[key]) && Array.isArray(diffValue)) {
599
+ result[key] = applyDiff(result[key], diffValue, shouldKeepRef);
600
+ }
601
+ else if (isObject(result[key]) && isObject(diffValue)) {
602
+ result[key] = applyDiff(result[key], diffValue, shouldKeepRef);
603
+ }
604
+ else {
605
+ result[key] = diffValue;
606
+ }
607
+ }
608
+ return result;
609
+ }
610
+ // ApplyDiff mode - respect added/deleted/modified arrays
611
+ const { diff, added = [], deleted = [], modified = [], changes, keepRef: keepRefOption, } = option;
612
+ const shouldKeepRef = keepRefParam !== undefined ? keepRefParam : keepRefOption;
613
+ const diffToApply = changes || diff;
614
+ if (!diffToApply)
615
+ return baseObj;
616
+ // Create sets for quick lookup
617
+ const addedSet = new Set(added);
618
+ const deletedSet = new Set(deleted);
619
+ const modifiedSet = new Set(modified);
620
+ // Helper to check if a path should be applied
621
+ const shouldApplyPath = (path) => {
622
+ // If no specific paths provided, apply all
623
+ if (added.length === 0 && deleted.length === 0 && modified.length === 0) {
624
+ return true;
625
+ }
626
+ // Check if path or any parent path is in the sets
627
+ const pathParts = path.split(/[.\[\]]+/).filter(Boolean);
628
+ for (let i = 0; i <= pathParts.length; i++) {
629
+ const partialPath = pathParts.slice(0, i).join('.');
630
+ const bracketPath = pathParts
631
+ .slice(0, i)
632
+ .map((p, idx) => (/^\d+$/.test(p) ? `[${p}]` : idx > 0 ? `.${p}` : p))
633
+ .join('');
634
+ if (addedSet.has(partialPath) ||
635
+ addedSet.has(bracketPath) ||
636
+ deletedSet.has(partialPath) ||
637
+ deletedSet.has(bracketPath) ||
638
+ modifiedSet.has(partialPath) ||
639
+ modifiedSet.has(bracketPath)) {
640
+ return true;
641
+ }
642
+ }
643
+ return false;
644
+ };
645
+ // Handle arrays at the top level
646
+ if (Array.isArray(baseObj) && Array.isArray(diffToApply)) {
647
+ const result = shouldKeepRef ? baseObj : [...baseObj];
648
+ // Set the array to the correct length based on diffToApply
649
+ // Since diffObjectDetailed now excludes deleted elements from changes array,
650
+ // the changes array length matches the newObj length
651
+ result.length = diffToApply.length;
652
+ // Apply changes
653
+ for (let i = 0; i < diffToApply.length; i++) {
654
+ const indexPath = `[${i}]`;
655
+ const diffValue = diffToApply[i];
656
+ // undefined in the diff means "no change" - keep the original value
657
+ if (diffValue === undefined) {
658
+ continue;
659
+ }
660
+ // Check if this index should be applied
661
+ if (!shouldApplyPath(indexPath)) {
662
+ continue;
663
+ }
664
+ if (isObject(result[i]) && isObject(diffValue)) {
665
+ result[i] = applyDiff(result[i], diffValue, shouldKeepRef);
666
+ }
667
+ else if (Array.isArray(result[i]) && Array.isArray(diffValue)) {
668
+ result[i] = applyDiff(result[i], diffValue, shouldKeepRef);
669
+ }
670
+ else {
671
+ result[i] = diffValue;
672
+ }
673
+ }
674
+ return result;
675
+ }
676
+ // Handle objects
677
+ if (!isObject(baseObj))
678
+ return diffToApply;
679
+ if (!isObject(diffToApply))
680
+ return baseObj;
681
+ const result = shouldKeepRef ? baseObj : { ...baseObj };
682
+ // Apply deletions
683
+ for (const path of deleted) {
684
+ if (path.includes('.') || path.includes('['))
685
+ continue; // Only handle direct keys
686
+ if (shouldApplyPath(path)) {
687
+ delete result[path];
688
+ }
689
+ }
690
+ // Apply additions and modifications
691
+ for (const key in diffToApply) {
692
+ const diffValue = diffToApply[key];
693
+ // Check if this key should be applied
694
+ if (!shouldApplyPath(key)) {
695
+ continue;
696
+ }
697
+ if (diffValue === undefined) {
698
+ delete result[key];
699
+ }
700
+ else if (Array.isArray(result[key]) && Array.isArray(diffValue)) {
701
+ result[key] = applyDiff(result[key], diffValue, shouldKeepRef);
702
+ }
703
+ else if (isObject(result[key]) && isObject(diffValue)) {
704
+ result[key] = applyDiff(result[key], diffValue, shouldKeepRef);
705
+ }
706
+ else {
707
+ result[key] = diffValue;
708
+ }
709
+ }
710
+ return result;
711
+ };
712
+ /**
713
+ * Gets paths of all changed values with array index notation support
714
+ *
715
+ * @param oldObj - The original object
716
+ * @param newObj - The new object to compare against
717
+ * @param options - Configuration options for diff behavior
718
+ * @returns Array of paths to changed values (e.g., ['a.b[0].name', 'c[1].value'])
719
+ *
720
+ * @example
721
+ * ```ts
722
+ * const old = { a: 1, b: { c: 2, d: 3 } };
723
+ * const new = { a: 1, b: { c: 4, d: 3 }, e: 5 };
724
+ * const paths = getChangedPaths(old, new);
725
+ * // Returns: ['b.c', 'e']
726
+ * ```
727
+ *
728
+ * @example
729
+ * ```ts
730
+ * const old = { items: [{ id: 1, name: 'a' }, { id: 2, name: 'b' }] };
731
+ * const new = { items: [{ id: 1, name: 'x' }, { id: 2, name: 'b' }] };
732
+ * const paths = getChangedPaths(old, new);
733
+ * // Returns: ['items[0].name']
734
+ * ```
735
+ */
736
+ export const getChangedPaths = (oldObj, newObj, options = {}) => {
737
+ const paths = [];
738
+ const collectPaths = (old, newVal, currentPath = '') => {
739
+ if (old === newVal)
740
+ return;
741
+ // Handle arrays with index notation
742
+ if (Array.isArray(old) && Array.isArray(newVal)) {
743
+ const maxLength = Math.max(old.length, newVal.length);
744
+ for (let i = 0; i < maxLength; i++) {
745
+ const indexPath = currentPath ? `${currentPath}[${i}]` : `[${i}]`;
746
+ if (i >= old.length) {
747
+ // Element was added
748
+ paths.push(indexPath);
749
+ }
750
+ else if (i >= newVal.length) {
751
+ // Element was deleted
752
+ paths.push(indexPath);
753
+ }
754
+ else {
755
+ const oldElement = old[i];
756
+ const newElement = newVal[i];
757
+ if (isObject(oldElement) && isObject(newElement)) {
758
+ // Recurse into object elements
759
+ collectPaths(oldElement, newElement, indexPath);
760
+ }
761
+ else if (Array.isArray(oldElement) && Array.isArray(newElement)) {
762
+ // Recurse into nested arrays
763
+ collectPaths(oldElement, newElement, indexPath);
764
+ }
765
+ else if (oldElement !== newElement) {
766
+ // Primitive value changed
767
+ paths.push(indexPath);
768
+ }
769
+ }
770
+ }
771
+ return;
772
+ }
773
+ // Handle non-object/non-array primitives
774
+ if (!isObject(old) || !isObject(newVal)) {
775
+ if (currentPath)
776
+ paths.push(currentPath);
777
+ return;
778
+ }
779
+ // Handle objects
780
+ const allKeys = new Set([
781
+ ...Object.keys(old || {}),
782
+ ...Object.keys(newVal || {}),
783
+ ]);
784
+ for (const key of allKeys) {
785
+ const oldValue = old?.[key];
786
+ const newValue = newVal?.[key];
787
+ const path = currentPath ? `${currentPath}.${key}` : key;
788
+ if (!(key in (old || {})) || !(key in (newVal || {}))) {
789
+ paths.push(path);
790
+ }
791
+ else if (Array.isArray(oldValue) && Array.isArray(newValue)) {
792
+ // Compare arrays with index notation
793
+ collectPaths(oldValue, newValue, path);
794
+ }
795
+ else if (isObject(oldValue) && isObject(newValue)) {
796
+ collectPaths(oldValue, newValue, path);
797
+ }
798
+ else if (oldValue !== newValue) {
799
+ paths.push(path);
800
+ }
801
+ }
802
+ };
803
+ collectPaths(oldObj, newObj);
804
+ return paths;
805
+ };