@hkdigital/lib-core 0.3.9 → 0.3.11

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 (428) hide show
  1. package/README.md +149 -149
  2. package/dist/assets/autospuiten/car-paint-picker.d.ts +7 -7
  3. package/dist/assets/autospuiten/car-paint-picker.js +41 -41
  4. package/dist/assets/autospuiten/labels.js +7 -7
  5. package/dist/classes/data/IterableTree.d.ts +15 -24
  6. package/dist/classes/data/IterableTree.js +242 -243
  7. package/dist/classes/data/Selector.js +190 -190
  8. package/dist/classes/data/index.js +2 -2
  9. package/dist/classes/data/typedef.d.ts +8 -0
  10. package/dist/classes/data/typedef.js +9 -0
  11. package/dist/classes/event-emitter/EventEmitter.js +273 -275
  12. package/dist/classes/event-emitter/index.js +2 -2
  13. package/dist/classes/index.js +4 -4
  14. package/dist/classes/promise/HkPromise.d.ts +18 -17
  15. package/dist/classes/promise/HkPromise.js +384 -377
  16. package/dist/classes/promise/index.js +1 -1
  17. package/dist/classes/stores/SubscribersCount.js +107 -107
  18. package/dist/classes/stores/index.js +1 -1
  19. package/dist/classes/streams/LogTransformStream.js +19 -19
  20. package/dist/classes/streams/ServerEventsStore.d.ts +2 -3
  21. package/dist/classes/streams/ServerEventsStore.js +111 -110
  22. package/dist/classes/streams/TimeStampSource.js +26 -26
  23. package/dist/classes/streams/index.js +3 -3
  24. package/dist/classes/svelte/finite-state-machine/FiniteStateMachine.svelte.js +133 -133
  25. package/dist/classes/svelte/finite-state-machine/index.js +1 -1
  26. package/dist/classes/svelte/index.d.ts +0 -8
  27. package/dist/classes/svelte/index.js +11 -14
  28. package/dist/classes/svelte/loading-state-machine/LoadingStateMachine.svelte.js +109 -109
  29. package/dist/classes/svelte/loading-state-machine/constants.js +16 -16
  30. package/dist/classes/svelte/loading-state-machine/index.js +3 -3
  31. package/dist/config/README.md +196 -0
  32. package/dist/config/{imagetools-config.js → generators/imagetools.js} +189 -189
  33. package/dist/config/generators/vite.d.ts +47 -0
  34. package/dist/config/generators/vite.js +142 -0
  35. package/dist/config/imagetools.d.ts +72 -72
  36. package/dist/config/vite.d.ts +1 -0
  37. package/dist/config/vite.js +5 -0
  38. package/dist/constants/bases/index.js +13 -13
  39. package/dist/constants/http/headers.js +6 -6
  40. package/dist/constants/http/index.js +2 -2
  41. package/dist/constants/http/methods.js +14 -14
  42. package/dist/constants/index.js +6 -6
  43. package/dist/constants/mime/application.js +5 -5
  44. package/dist/constants/mime/audio.js +13 -13
  45. package/dist/constants/mime/image.js +3 -3
  46. package/dist/constants/mime/index.js +4 -4
  47. package/dist/constants/mime/text.js +2 -2
  48. package/dist/constants/regexp/README.md +95 -0
  49. package/dist/constants/regexp/index.d.ts +1 -1
  50. package/dist/constants/regexp/index.js +31 -31
  51. package/dist/constants/regexp/inspiratie.js__ +95 -95
  52. package/dist/constants/regexp/text.d.ts +3 -3
  53. package/dist/constants/regexp/text.js +49 -49
  54. package/dist/constants/regexp/url.d.ts +1 -0
  55. package/dist/constants/regexp/url.js +3 -0
  56. package/dist/constants/regexp/user.d.ts +0 -1
  57. package/dist/constants/regexp/user.js +29 -33
  58. package/dist/constants/states/drag.js +6 -6
  59. package/dist/constants/states/drop.js +6 -6
  60. package/dist/constants/states/index.js +4 -4
  61. package/dist/constants/states/input.js +11 -11
  62. package/dist/constants/states/submit.js +4 -4
  63. package/dist/constants/time/index.js +28 -28
  64. package/dist/css/utilities.css +43 -43
  65. package/dist/design/README.md +405 -0
  66. package/dist/design/{design-config.js → config/design-config.js} +73 -73
  67. package/dist/{util/design-system/tailwind.js → design/generators/index.js} +288 -288
  68. package/dist/design/index.d.ts +8 -0
  69. package/dist/design/index.js +97 -0
  70. package/dist/{util/design-system → design/plugins}/skeleton.js +208 -208
  71. package/dist/design/tailwind-theme-extend.js +158 -158
  72. package/dist/design/themes/README.md +103 -0
  73. package/dist/{themes → design/themes}/hkdev/components/blocks/text-block.css +34 -34
  74. package/dist/{themes → design/themes}/hkdev/components/boxes/game-box.css +11 -11
  75. package/dist/{themes → design/themes}/hkdev/components/buttons/button-icon-steeze.css +22 -22
  76. package/dist/{themes → design/themes}/hkdev/components/buttons/button-text.css +32 -32
  77. package/dist/{themes → design/themes}/hkdev/components/buttons/button.css +146 -146
  78. package/dist/{themes → design/themes}/hkdev/components/buttons/skip-button.css +5 -5
  79. package/dist/{themes → design/themes}/hkdev/components/drag-drop/draggable.css +73 -73
  80. package/dist/{themes → design/themes}/hkdev/components/drag-drop/drop-zone.css +58 -58
  81. package/dist/{themes → design/themes}/hkdev/components/icons/icon-steeze.css +15 -15
  82. package/dist/{themes → design/themes}/hkdev/components/inputs/text-input.css +102 -102
  83. package/dist/{themes → design/themes}/hkdev/components/panels/panel.css +25 -25
  84. package/dist/{themes → design/themes}/hkdev/components/rows/panel-grid-row.css +4 -4
  85. package/dist/{themes → design/themes}/hkdev/components/rows/panel-row-2.css +5 -5
  86. package/dist/{themes → design/themes}/hkdev/components.css +29 -29
  87. package/dist/design/themes/hkdev/debug.css +2 -0
  88. package/dist/{themes → design/themes}/hkdev/global/layout.css +32 -32
  89. package/dist/{themes → design/themes}/hkdev/global/on-colors.css +32 -32
  90. package/dist/{themes → design/themes}/hkdev/globals.css +3 -3
  91. package/dist/{themes → design/themes}/hkdev/responsive.css +12 -12
  92. package/dist/{themes → design/themes}/hkdev/theme-ext.js +12 -12
  93. package/dist/{themes → design/themes}/hkdev/theme.css +218 -218
  94. package/dist/{util/design-system/css → design/utils}/clamp.js +66 -66
  95. package/dist/{util/design-system/css/root-design-vars.d.ts → design/utils/root-vars.d.ts} +2 -2
  96. package/dist/{util/design-system/css/root-design-vars.js → design/utils/root-vars.js} +102 -102
  97. package/dist/{util/design-system/layout → design/utils}/scaling.js +228 -228
  98. package/dist/{util/design-system/components → design/utils}/states.js +22 -22
  99. package/dist/errors/api.js +9 -9
  100. package/dist/errors/generic.js +20 -20
  101. package/dist/errors/http.js +16 -16
  102. package/dist/errors/index.d.ts +1 -0
  103. package/dist/errors/index.js +5 -4
  104. package/dist/errors/jwt.js +5 -5
  105. package/dist/errors/promise.d.ts +27 -0
  106. package/dist/errors/promise.js +26 -0
  107. package/dist/logging/index.js +7 -7
  108. package/dist/logging/internal/adapters/console.js +114 -114
  109. package/dist/logging/internal/adapters/index.js +2 -2
  110. package/dist/logging/internal/adapters/pino.d.ts +1 -0
  111. package/dist/logging/internal/adapters/pino.js +142 -115
  112. package/dist/logging/internal/adapters/typedef.d.ts +24 -0
  113. package/dist/logging/internal/adapters/typedef.js +10 -0
  114. package/dist/logging/internal/factories/client.js +21 -21
  115. package/dist/logging/internal/factories/server.js +22 -22
  116. package/dist/logging/internal/factories/universal.js +22 -22
  117. package/dist/logging/internal/unified-logger/Logger.js +217 -217
  118. package/dist/logging/internal/unified-logger/constants.js +22 -22
  119. package/dist/logging/internal/unified-logger/index.js +6 -6
  120. package/dist/logging/internal/unified-logger/typedef.js +17 -17
  121. package/dist/network/README.md +173 -0
  122. package/dist/{classes → network}/cache/IndexedDbCache.js +1407 -1407
  123. package/dist/{classes → network}/cache/MemoryResponseCache.js +138 -138
  124. package/dist/{classes → network}/cache/index.js +5 -5
  125. package/dist/{classes → network}/cache/typedef.js +41 -41
  126. package/dist/network/cache.d.ts +3 -0
  127. package/dist/network/cache.js +4 -0
  128. package/dist/{util → network}/http/caching.js +261 -263
  129. package/dist/{util → network}/http/errors.js +97 -97
  130. package/dist/{util → network}/http/headers.js +75 -75
  131. package/dist/{util → network}/http/http-request.js +578 -578
  132. package/dist/{util → network}/http/index.js +22 -22
  133. package/dist/{util → network}/http/json-request.js +224 -224
  134. package/dist/{util → network}/http/mocks.js +65 -65
  135. package/dist/{util → network}/http/response.js +318 -318
  136. package/dist/{util → network}/http/typedef.js +93 -93
  137. package/dist/{util → network}/http/url.js +52 -52
  138. package/dist/network/http.d.ts +6 -0
  139. package/dist/network/http.js +6 -0
  140. package/dist/network/loaders/README.md +255 -0
  141. package/dist/{classes/svelte → network/loaders}/audio/AudioLoader.svelte.d.ts +1 -1
  142. package/dist/{classes/svelte → network/loaders}/audio/AudioLoader.svelte.js +58 -58
  143. package/dist/{classes/svelte → network/loaders}/audio/AudioScene.svelte.js +324 -324
  144. package/dist/{classes/svelte → network/loaders}/audio/mocks.js +35 -35
  145. package/dist/network/loaders/audio.d.ts +2 -0
  146. package/dist/network/loaders/audio.js +2 -0
  147. package/dist/{classes/svelte → network/loaders}/image/ImageLoader.svelte.d.ts +3 -6
  148. package/dist/{classes/svelte → network/loaders}/image/ImageLoader.svelte.js +44 -45
  149. package/dist/{classes/svelte → network/loaders}/image/ImageScene.svelte.d.ts +5 -7
  150. package/dist/{classes/svelte → network/loaders}/image/ImageScene.svelte.js +248 -249
  151. package/dist/{classes/svelte → network/loaders}/image/ImageVariantsLoader.svelte.d.ts +4 -4
  152. package/dist/{classes/svelte → network/loaders}/image/ImageVariantsLoader.svelte.js +150 -152
  153. package/dist/{classes/svelte → network/loaders}/image/index.js +4 -4
  154. package/dist/{classes/svelte → network/loaders}/image/mocks.js +35 -35
  155. package/dist/{classes/svelte → network/loaders}/image/typedef.js +8 -8
  156. package/dist/{util/image → network/loaders/image/utils}/index.d.ts +2 -2
  157. package/dist/{util/image → network/loaders/image/utils}/index.js +86 -86
  158. package/dist/network/loaders/image.d.ts +5 -0
  159. package/dist/network/loaders/image.js +8 -0
  160. package/dist/{typedef/image.js → network/loaders/typedef.js} +38 -38
  161. package/dist/network/loaders.d.ts +2 -0
  162. package/dist/network/loaders.js +2 -0
  163. package/dist/{classes/svelte/network-loader → network/states}/NetworkLoader.svelte.d.ts +1 -1
  164. package/dist/{classes/svelte/network-loader → network/states}/NetworkLoader.svelte.js +338 -338
  165. package/dist/{classes/svelte/network-loader → network/states}/constants.js +3 -3
  166. package/dist/{classes/svelte/network-loader → network/states}/index.js +3 -3
  167. package/dist/{classes/svelte/network-loader → network/states}/mocks.js +30 -30
  168. package/dist/{classes/svelte/network-loader → network/states}/typedef.js +8 -8
  169. package/dist/network/typedef.d.ts +4 -0
  170. package/dist/network/typedef.js +10 -0
  171. package/dist/services/index.js +1 -1
  172. package/dist/services/internal/index.js +8 -8
  173. package/dist/services/internal/service-base/ServiceBase.js +462 -462
  174. package/dist/services/internal/service-base/constants.js +110 -110
  175. package/dist/services/internal/service-base/index.js +3 -3
  176. package/dist/services/internal/service-base/typedef.js +101 -101
  177. package/dist/services/internal/service-manager/ServiceManager.d.ts +2 -35
  178. package/dist/services/internal/service-manager/ServiceManager.js +608 -614
  179. package/dist/services/internal/service-manager/constants.js +6 -6
  180. package/dist/services/internal/service-manager/typedef.js +90 -90
  181. package/dist/states/index.js +1 -1
  182. package/dist/states/navigation.svelte.js +55 -55
  183. package/dist/stores/index.js +1 -1
  184. package/dist/stores/theme.js +80 -80
  185. package/dist/typedef/context.js +6 -6
  186. package/dist/typedef/drag.js +25 -25
  187. package/dist/typedef/drop.js +12 -12
  188. package/dist/typedef/index.d.ts +0 -1
  189. package/dist/typedef/index.js +4 -4
  190. package/dist/{components → ui/components}/button-group/ButtonGroup.svelte +82 -82
  191. package/dist/{components → ui/components}/button-group/typedef.js +10 -10
  192. package/dist/{components → ui/components}/compare-left-right/CompareLeftRight.svelte +179 -179
  193. package/dist/{components → ui/components}/compare-left-right/index.js +1 -1
  194. package/dist/{components → ui/components}/game-box/GameBox.svelte +577 -577
  195. package/dist/{components → ui/components}/game-box/gamebox.util.js +83 -83
  196. package/dist/ui/components/hk-app-layout/HkAppLayout.state.svelte.d.ts +6 -0
  197. package/dist/{components → ui/components}/hk-app-layout/HkAppLayout.state.svelte.js +25 -25
  198. package/dist/{components → ui/components}/hk-app-layout/HkAppLayout.svelte +251 -251
  199. package/dist/{components → ui/components}/image-box/ImageBox.svelte +210 -210
  200. package/dist/{components → ui/components}/image-box/ImageBox.svelte.d.ts +6 -6
  201. package/dist/ui/components/image-box/index.js +5 -0
  202. package/dist/{components → ui/components}/image-box/typedef.js +32 -32
  203. package/dist/{components → ui/components}/index.js +23 -23
  204. package/dist/{components → ui/components}/presenter/ImageSlide.svelte +64 -64
  205. package/dist/{components → ui/components}/presenter/ImageSlide.svelte.d.ts +2 -2
  206. package/dist/{components → ui/components}/presenter/Presenter.state.svelte.d.ts +1 -1
  207. package/dist/{components → ui/components}/presenter/Presenter.state.svelte.js +638 -638
  208. package/dist/{components → ui/components}/presenter/Presenter.svelte +142 -142
  209. package/dist/{components → ui/components}/presenter/constants.js +7 -7
  210. package/dist/{components → ui/components}/presenter/index.js +10 -10
  211. package/dist/{components → ui/components}/presenter/typedef.js +106 -106
  212. package/dist/{components → ui/components}/presenter/util.js +210 -210
  213. package/dist/{components → ui/components}/virtual-viewport/VirtualViewport.svelte +196 -196
  214. package/dist/{primitives → ui/primitives}/area/HkArea.svelte +49 -49
  215. package/dist/{primitives → ui/primitives}/area/HkGridArea.svelte +77 -77
  216. package/dist/{primitives → ui/primitives}/area/index.js +2 -2
  217. package/dist/{primitives → ui/primitives}/buttons/button/Button.svelte +82 -82
  218. package/dist/{primitives → ui/primitives}/buttons/button/Button.svelte.d.ts +1 -1
  219. package/dist/{primitives → ui/primitives}/buttons/button-icon-steeze/SteezeIconButton.svelte +30 -30
  220. package/dist/{primitives → ui/primitives}/buttons/button-text/TextButton.svelte +21 -21
  221. package/dist/{primitives → ui/primitives}/buttons/index.js +3 -3
  222. package/dist/{primitives → ui/primitives}/debug/debug-panel-design-scaling/DebugPanelDesignScaling.svelte +146 -146
  223. package/dist/{primitives → ui/primitives}/debug/index.js +1 -1
  224. package/dist/{primitives → ui/primitives}/drag-drop/DragController.js +44 -44
  225. package/dist/{primitives → ui/primitives}/drag-drop/DragDropContext.svelte +111 -111
  226. package/dist/{primitives → ui/primitives}/drag-drop/DragDropContext.svelte.d.ts +1 -1
  227. package/dist/{primitives → ui/primitives}/drag-drop/Draggable.svelte +519 -519
  228. package/dist/{primitives → ui/primitives}/drag-drop/Draggable.svelte.d.ts +1 -1
  229. package/dist/{primitives → ui/primitives}/drag-drop/DropZone.svelte +258 -258
  230. package/dist/{primitives → ui/primitives}/drag-drop/DropZone.svelte.d.ts +3 -3
  231. package/dist/{primitives → ui/primitives}/drag-drop/DropZoneArea.svelte +119 -119
  232. package/dist/{primitives → ui/primitives}/drag-drop/DropZoneArea.svelte.d.ts +3 -3
  233. package/dist/{primitives → ui/primitives}/drag-drop/DropZoneList.svelte +125 -125
  234. package/dist/{primitives → ui/primitives}/drag-drop/DropZoneList.svelte.d.ts +3 -3
  235. package/dist/{primitives → ui/primitives}/drag-drop/actions.js +26 -26
  236. package/dist/{primitives → ui/primitives}/drag-drop/drag-state.svelte.d.ts +11 -11
  237. package/dist/{primitives → ui/primitives}/drag-drop/drag-state.svelte.js +322 -322
  238. package/dist/{primitives → ui/primitives}/drag-drop/index.js +7 -7
  239. package/dist/{primitives → ui/primitives}/drag-drop/util.js +85 -85
  240. package/dist/{primitives → ui/primitives}/hkdev/blocks/TextBlock.svelte +46 -46
  241. package/dist/{primitives → ui/primitives}/hkdev/buttons/CheckButton.svelte +62 -62
  242. package/dist/{primitives → ui/primitives}/icons/HkIcon.svelte +86 -86
  243. package/dist/{primitives → ui/primitives}/icons/HkTabIcon.svelte +116 -116
  244. package/dist/{primitives → ui/primitives}/icons/SteezeIcon.svelte +97 -97
  245. package/dist/{primitives → ui/primitives}/icons/index.js +6 -6
  246. package/dist/{primitives → ui/primitives}/icons/typedef.js +16 -16
  247. package/dist/{primitives → ui/primitives}/index.js +2 -2
  248. package/dist/{primitives → ui/primitives}/inputs/index.js +1 -1
  249. package/dist/{primitives → ui/primitives}/inputs/text-input/TextInput.svelte +223 -223
  250. package/dist/{primitives → ui/primitives}/inputs/text-input/assets/IconInvalid.svelte +14 -14
  251. package/dist/{primitives → ui/primitives}/inputs/text-input/assets/IconValid.svelte +12 -12
  252. package/dist/{primitives → ui/primitives}/layout/grid-layers/GridLayers.svelte +63 -63
  253. package/dist/{primitives → ui/primitives}/layout/grid-layers/util.js +74 -74
  254. package/dist/{primitives → ui/primitives}/layout/index.js +1 -1
  255. package/dist/{primitives → ui/primitives}/panels/index.js +1 -1
  256. package/dist/{primitives → ui/primitives}/panels/panel/Panel.svelte +43 -43
  257. package/dist/{primitives → ui/primitives}/rows/index.js +3 -3
  258. package/dist/{primitives → ui/primitives}/rows/panel-grid-row/PanelGridRow.svelte +104 -104
  259. package/dist/{primitives → ui/primitives}/rows/panel-row-2/PanelRow2.svelte +40 -40
  260. package/dist/{primitives → ui/primitives}/tab-bar/HkTabBar.state.svelte.d.ts +3 -3
  261. package/dist/{primitives → ui/primitives}/tab-bar/HkTabBar.state.svelte.js +149 -149
  262. package/dist/{primitives → ui/primitives}/tab-bar/HkTabBar.svelte +74 -74
  263. package/dist/{primitives → ui/primitives}/tab-bar/HkTabBarSelector.state.svelte.d.ts +3 -3
  264. package/dist/{primitives → ui/primitives}/tab-bar/HkTabBarSelector.state.svelte.js +93 -93
  265. package/dist/{primitives → ui/primitives}/tab-bar/HkTabBarSelector.svelte +49 -49
  266. package/dist/{primitives → ui/primitives}/tab-bar/index.js +17 -17
  267. package/dist/{primitives → ui/primitives}/tab-bar/typedef.js +11 -11
  268. package/dist/util/array/index.js +436 -436
  269. package/dist/util/bases/base58.js +262 -262
  270. package/dist/util/bases/index.js +1 -1
  271. package/dist/util/compare/index.js +247 -247
  272. package/dist/util/css/css-vars.js +83 -83
  273. package/dist/util/css/index.js +1 -1
  274. package/dist/util/env/index.js +9 -9
  275. package/dist/util/exceptions/index.js +23 -23
  276. package/dist/util/expect/arrays.js +47 -47
  277. package/dist/util/expect/index.js +259 -259
  278. package/dist/util/expect/primitives.js +55 -55
  279. package/dist/util/expect/url.d.ts +6 -6
  280. package/dist/util/expect/url.js +60 -60
  281. package/dist/util/function/index.js +218 -218
  282. package/dist/util/geo/index.js +26 -26
  283. package/dist/util/index.d.ts +3 -1
  284. package/dist/util/index.js +7 -3
  285. package/dist/util/is/index.d.ts +15 -14
  286. package/dist/util/is/index.js +147 -140
  287. package/dist/util/iterate/index.d.ts +37 -69
  288. package/dist/util/iterate/index.js +204 -234
  289. package/dist/util/object/index.d.ts +38 -57
  290. package/dist/util/object/index.js +1345 -1361
  291. package/dist/util/singleton/index.js +97 -97
  292. package/dist/util/string/array-path.js +75 -75
  293. package/dist/util/string/convert.js +54 -54
  294. package/dist/util/string/fs.js +226 -226
  295. package/dist/util/string/index.js +5 -5
  296. package/dist/util/string/interpolate.js +61 -61
  297. package/dist/util/string/pad.js +10 -10
  298. package/dist/util/svelte/index.js +4 -4
  299. package/dist/util/svelte/loading/loading-tracker.svelte.js +108 -108
  300. package/dist/util/svelte/observe/index.js +49 -49
  301. package/dist/util/svelte/state-context/index.js +117 -117
  302. package/dist/util/svelte/wait/index.js +38 -38
  303. package/dist/util/sveltekit/index.js +1 -1
  304. package/dist/util/sveltekit/route-folders/index.js +101 -101
  305. package/dist/util/time/index.js +328 -323
  306. package/dist/util/unique/index.js +231 -249
  307. package/dist/valibot/README.md +50 -0
  308. package/dist/valibot/index.d.ts +4 -4
  309. package/dist/valibot/index.js +8 -9
  310. package/dist/valibot/{url.d.ts → parsers/url.d.ts} +13 -5
  311. package/dist/valibot/{url.js → parsers/url.js} +111 -95
  312. package/dist/valibot/{user.js → parsers/user.js} +23 -23
  313. package/dist/valibot/parsers.d.ts +2 -0
  314. package/dist/valibot/parsers.js +4 -0
  315. package/package.json +131 -133
  316. package/dist/components/hk-app-layout/HkAppLayout.state.svelte.d.ts +0 -6
  317. package/dist/components/image-box/index.js +0 -5
  318. package/dist/constants/regexp/web.d.ts +0 -1
  319. package/dist/constants/regexp/web.js +0 -3
  320. package/dist/primitives/inputs/text-input/TestTextInput.svelte__ +0 -102
  321. package/dist/primitives/inputs/text-input/TextInput.svelte___ +0 -83
  322. package/dist/primitives/layout/grid-layers/GridLayers.svelte__heightFrom__ +0 -372
  323. package/dist/schemas/index.d.ts +0 -1
  324. package/dist/schemas/index.js +0 -1
  325. package/dist/schemas/validate-url.d.ts +0 -30
  326. package/dist/schemas/validate-url.js +0 -180
  327. package/dist/themes/hkdev/debug.css +0 -2
  328. package/dist/themes/index.d.ts +0 -1
  329. package/dist/themes/index.js +0 -1
  330. package/dist/util/design-system/index.d.ts +0 -5
  331. package/dist/util/design-system/index.js +0 -5
  332. package/dist/util/http/test-data__/content-length-test-hkdigital-small.V4HfZyBQ.avif +0 -0
  333. package/dist/valibot/date.js__ +0 -10
  334. package/dist/zod/all.d.ts +0 -6
  335. package/dist/zod/all.js +0 -33
  336. package/dist/zod/generic.d.ts +0 -6
  337. package/dist/zod/generic.js +0 -11
  338. package/dist/zod/javascript.d.ts +0 -8
  339. package/dist/zod/javascript.js +0 -32
  340. package/dist/zod/user.d.ts +0 -9
  341. package/dist/zod/user.js +0 -16
  342. package/dist/zod/web.d.ts +0 -21
  343. package/dist/zod/web.js +0 -52
  344. /package/dist/config/{imagetools-config.d.ts → generators/imagetools.d.ts} +0 -0
  345. /package/dist/design/{design-config.d.ts → config/design-config.d.ts} +0 -0
  346. /package/dist/{util/design-system/tailwind.d.ts → design/generators/index.d.ts} +0 -0
  347. /package/dist/{util/design-system → design/plugins}/skeleton.d.ts +0 -0
  348. /package/dist/{themes → design/themes}/hkdev/theme-ext.d.ts +0 -0
  349. /package/dist/{util/design-system/css → design/utils}/clamp.d.ts +0 -0
  350. /package/dist/{util/design-system/layout → design/utils}/scaling.d.ts +0 -0
  351. /package/dist/{util/design-system/components → design/utils}/states.d.ts +0 -0
  352. /package/dist/{classes → network}/cache/IndexedDbCache.d.ts +0 -0
  353. /package/dist/{classes → network}/cache/MemoryResponseCache.d.ts +0 -0
  354. /package/dist/{classes → network}/cache/index.d.ts +0 -0
  355. /package/dist/{classes → network}/cache/typedef.d.ts +0 -0
  356. /package/dist/{util → network}/http/caching.d.ts +0 -0
  357. /package/dist/{util → network}/http/errors.d.ts +0 -0
  358. /package/dist/{util → network}/http/headers.d.ts +0 -0
  359. /package/dist/{util → network}/http/http-request.d.ts +0 -0
  360. /package/dist/{util → network}/http/index.d.ts +0 -0
  361. /package/dist/{util → network}/http/json-request.d.ts +0 -0
  362. /package/dist/{util → network}/http/mocks.d.ts +0 -0
  363. /package/dist/{util → network}/http/response.d.ts +0 -0
  364. /package/dist/{util → network}/http/typedef.d.ts +0 -0
  365. /package/dist/{util → network}/http/url.d.ts +0 -0
  366. /package/dist/{classes/svelte → network/loaders}/audio/AudioScene.svelte.d.ts +0 -0
  367. /package/dist/{classes/svelte → network/loaders}/audio/mocks.d.ts +0 -0
  368. /package/dist/{classes/svelte → network/loaders}/image/index.d.ts +0 -0
  369. /package/dist/{classes/svelte → network/loaders}/image/mocks.d.ts +0 -0
  370. /package/dist/{classes/svelte → network/loaders}/image/typedef.d.ts +0 -0
  371. /package/dist/{typedef/image.d.ts → network/loaders/typedef.d.ts} +0 -0
  372. /package/dist/{classes/svelte/network-loader → network/states}/constants.d.ts +0 -0
  373. /package/dist/{classes/svelte/network-loader → network/states}/index.d.ts +0 -0
  374. /package/dist/{classes/svelte/network-loader → network/states}/mocks.d.ts +0 -0
  375. /package/dist/{classes/svelte/network-loader → network/states}/typedef.d.ts +0 -0
  376. /package/dist/{components → ui/components}/button-group/ButtonGroup.svelte.d.ts +0 -0
  377. /package/dist/{components → ui/components}/button-group/typedef.d.ts +0 -0
  378. /package/dist/{components → ui/components}/compare-left-right/CompareLeftRight.svelte.d.ts +0 -0
  379. /package/dist/{components → ui/components}/compare-left-right/index.d.ts +0 -0
  380. /package/dist/{components → ui/components}/game-box/GameBox.svelte.d.ts +0 -0
  381. /package/dist/{components → ui/components}/game-box/gamebox.util.d.ts +0 -0
  382. /package/dist/{components → ui/components}/hk-app-layout/HkAppLayout.svelte.d.ts +0 -0
  383. /package/dist/{components → ui/components}/image-box/index.d.ts +0 -0
  384. /package/dist/{components → ui/components}/image-box/typedef.d.ts +0 -0
  385. /package/dist/{components → ui/components}/index.d.ts +0 -0
  386. /package/dist/{components → ui/components}/presenter/Presenter.svelte.d.ts +0 -0
  387. /package/dist/{components → ui/components}/presenter/constants.d.ts +0 -0
  388. /package/dist/{components → ui/components}/presenter/index.d.ts +0 -0
  389. /package/dist/{components → ui/components}/presenter/typedef.d.ts +0 -0
  390. /package/dist/{components → ui/components}/presenter/util.d.ts +0 -0
  391. /package/dist/{components → ui/components}/virtual-viewport/VirtualViewport.svelte.d.ts +0 -0
  392. /package/dist/{primitives → ui/primitives}/area/HkArea.svelte.d.ts +0 -0
  393. /package/dist/{primitives → ui/primitives}/area/HkGridArea.svelte.d.ts +0 -0
  394. /package/dist/{primitives → ui/primitives}/area/index.d.ts +0 -0
  395. /package/dist/{primitives → ui/primitives}/buttons/button-icon-steeze/SteezeIconButton.svelte.d.ts +0 -0
  396. /package/dist/{primitives → ui/primitives}/buttons/button-text/TextButton.svelte.d.ts +0 -0
  397. /package/dist/{primitives → ui/primitives}/buttons/index.d.ts +0 -0
  398. /package/dist/{primitives → ui/primitives}/debug/debug-panel-design-scaling/DebugPanelDesignScaling.svelte.d.ts +0 -0
  399. /package/dist/{primitives → ui/primitives}/debug/index.d.ts +0 -0
  400. /package/dist/{primitives → ui/primitives}/drag-drop/DragController.d.ts +0 -0
  401. /package/dist/{primitives → ui/primitives}/drag-drop/actions.d.ts +0 -0
  402. /package/dist/{primitives → ui/primitives}/drag-drop/index.d.ts +0 -0
  403. /package/dist/{primitives → ui/primitives}/drag-drop/util.d.ts +0 -0
  404. /package/dist/{primitives → ui/primitives}/hkdev/blocks/TextBlock.svelte.d.ts +0 -0
  405. /package/dist/{primitives → ui/primitives}/hkdev/buttons/CheckButton.svelte.d.ts +0 -0
  406. /package/dist/{primitives → ui/primitives}/icons/HkIcon.svelte.d.ts +0 -0
  407. /package/dist/{primitives → ui/primitives}/icons/HkTabIcon.svelte.d.ts +0 -0
  408. /package/dist/{primitives → ui/primitives}/icons/SteezeIcon.svelte.d.ts +0 -0
  409. /package/dist/{primitives → ui/primitives}/icons/index.d.ts +0 -0
  410. /package/dist/{primitives → ui/primitives}/icons/typedef.d.ts +0 -0
  411. /package/dist/{primitives → ui/primitives}/index.d.ts +0 -0
  412. /package/dist/{primitives → ui/primitives}/inputs/index.d.ts +0 -0
  413. /package/dist/{primitives → ui/primitives}/inputs/text-input/TextInput.svelte.d.ts +0 -0
  414. /package/dist/{primitives → ui/primitives}/inputs/text-input/assets/IconInvalid.svelte.d.ts +0 -0
  415. /package/dist/{primitives → ui/primitives}/inputs/text-input/assets/IconValid.svelte.d.ts +0 -0
  416. /package/dist/{primitives → ui/primitives}/layout/grid-layers/GridLayers.svelte.d.ts +0 -0
  417. /package/dist/{primitives → ui/primitives}/layout/grid-layers/util.d.ts +0 -0
  418. /package/dist/{primitives → ui/primitives}/layout/index.d.ts +0 -0
  419. /package/dist/{primitives → ui/primitives}/panels/index.d.ts +0 -0
  420. /package/dist/{primitives → ui/primitives}/panels/panel/Panel.svelte.d.ts +0 -0
  421. /package/dist/{primitives → ui/primitives}/rows/index.d.ts +0 -0
  422. /package/dist/{primitives → ui/primitives}/rows/panel-grid-row/PanelGridRow.svelte.d.ts +0 -0
  423. /package/dist/{primitives → ui/primitives}/rows/panel-row-2/PanelRow2.svelte.d.ts +0 -0
  424. /package/dist/{primitives → ui/primitives}/tab-bar/HkTabBar.svelte.d.ts +0 -0
  425. /package/dist/{primitives → ui/primitives}/tab-bar/HkTabBarSelector.svelte.d.ts +0 -0
  426. /package/dist/{primitives → ui/primitives}/tab-bar/index.d.ts +0 -0
  427. /package/dist/{primitives → ui/primitives}/tab-bar/typedef.d.ts +0 -0
  428. /package/dist/valibot/{user.d.ts → parsers/user.d.ts} +0 -0
@@ -1,1361 +1,1345 @@
1
- /* ------------------------------------------------------------------ Imports */
2
-
3
- import * as expect from '../expect/index.js';
4
-
5
- import { equals } from '../compare/index.js';
6
-
7
- import { toArrayPath } from '../array/index.js';
8
-
9
- import { toStringPath } from '../string/index.js';
10
-
11
- import { isIterable } from '../is/index.js';
12
-
13
- import { iterateObjectPaths, iterateObjectEntries } from '../iterate/index.js';
14
-
15
- // ------------------------------------------------------------------- Internals
16
-
17
- const PATH_SEPARATOR = '.';
18
-
19
- /**
20
- * Create a human friendly string representation of an array path
21
- * - Allows for removal of the last part of the array part
22
- *
23
- * @param {string[]} arr - Array path to join
24
- * @param {number} [lastIndex]
25
- * If specified, only parts up and including the last index will
26
- * be joined
27
- *
28
- * @returns {string} path as string
29
- */
30
- function display_array_path(arr, lastIndex) {
31
- return arr.slice(0, lastIndex).join(PATH_SEPARATOR);
32
- }
33
-
34
- const object_to_string = Object.prototype.toString;
35
- const has_own_property = Object.prototype.hasOwnProperty;
36
-
37
- /* ------------------------------------------------------------------ Exports */
38
-
39
- export { PATH_SEPARATOR };
40
-
41
- // -----------------------------------------------------------------------------
42
-
43
- /**
44
- * Returns true
45
- * - if the object has no (iterable) key value pairs
46
- * - if the object is an empty array
47
- *
48
- * @param {object} obj
49
- *
50
- * @return {boolean}
51
- * true if the object has no key value pairs or the supplied object
52
- * is `falsey`
53
- */
54
- export function isEmpty(obj) {
55
- if (!obj) {
56
- // object is null or other falsey value
57
- return true;
58
- }
59
-
60
- expect.object(obj);
61
-
62
- if (/*obj instanceof Array && */ 0 === obj.length) {
63
- return true;
64
- }
65
-
66
- for (const key in obj) {
67
- return false;
68
- }
69
-
70
- return true;
71
- }
72
-
73
- // -----------------------------------------------------------------------------
74
-
75
- /**
76
- * Get the number of (iterable) key value pairs in the specified object
77
- *
78
- * @param {object} obj
79
- *
80
- * @return {number} number of iterable key value pairs
81
- */
82
- export function objectSize(obj) {
83
- expect.object(obj);
84
-
85
- let count = 0;
86
-
87
- // eslint-disable-next-line no-unused-vars
88
- for (const _key in obj) {
89
- count = count + 1;
90
- }
91
-
92
- return count;
93
- }
94
-
95
- // -----------------------------------------------------------------------------
96
-
97
- /**
98
- * Returns a shallow copy of the object without the properties that
99
- * have the value [null] or [undefined]
100
- *
101
- * @param {object} obj
102
- *
103
- * @param {string[]} [onlyKeys]
104
- * If specified, only the specified keys will be exported
105
- *
106
- * @returns {object} new object without the null properties
107
- */
108
- export function exportNotNull(obj, onlyKeys) {
109
- expect.object(obj);
110
-
111
- // if( onlyKeys )
112
- // {
113
- // expect.array( onlyKeys );
114
- // }
115
-
116
- const newObj = {};
117
-
118
- const onlyKeysSet = onlyKeys ? new Set(onlyKeys) : null;
119
-
120
- for (const key in obj) {
121
- const value = obj[key];
122
-
123
- if (value !== null && value !== undefined) {
124
- if (onlyKeysSet && !onlyKeysSet.has(key)) {
125
- continue;
126
- }
127
-
128
- newObj[key] = value;
129
- }
130
- } // end for
131
-
132
- return newObj;
133
- }
134
-
135
- // -----------------------------------------------------------------------------
136
-
137
- /**
138
- * Returns a shallow copy of the object without the properties that
139
- * are `private`
140
- * - Private properties are properties that start with an underscore
141
- * `_`.
142
- *
143
- * @param {object} obj
144
- *
145
- * @param {string[]} [keepKeys]
146
- * If specified, the sprecified private keys will be exported (e.g. `_id`)
147
- *
148
- * @returns {object} new object without the null properties
149
- */
150
- export function exportNotPrivate(obj, keepKeys) {
151
- expect.object(obj);
152
-
153
- const newObj = {};
154
-
155
- const keepKeysSet = keepKeys ? new Set(keepKeys) : null;
156
-
157
- for (const key in obj) {
158
- const value = obj[key];
159
-
160
- if (!key.startsWith('_')) {
161
- newObj[key] = value;
162
- } else if (keepKeysSet && keepKeysSet.has(key)) {
163
- //
164
- // Add key to keep as read only property
165
- //
166
- Object.defineProperty(newObj, key, {
167
- value,
168
- writable: false,
169
- enumerable: true
170
- });
171
- }
172
- } // end for
173
-
174
- return newObj;
175
- }
176
-
177
- // -----------------------------------------------------------------------------
178
-
179
- // export function removeNull()
180
-
181
- // -----------------------------------------------------------------------------
182
-
183
- /**
184
- * Keep only the specified keys in the object
185
- * - deletes all other key-value pairs in the object
186
- *
187
- * @param {object} obj
188
- * @param {string[]|Set} keys
189
- * @param {boolean} [removeNullAndUndefined=true]
190
- *
191
- * @returns {object} object that only contains the specified keys
192
- */
193
- export function keep(obj, keys, removeNullAndUndefined = true) {
194
- expect.object(obj);
195
- expect.arrayOrSet(keys);
196
-
197
- const keep = keys instanceof Set ? keys : new Set(keys);
198
-
199
- for (const key in obj) {
200
- if (!keep.has(key)) {
201
- delete obj[key];
202
- continue;
203
- }
204
-
205
- const value = obj[key];
206
-
207
- if (removeNullAndUndefined) {
208
- if (value === null || value === undefined) {
209
- delete obj[key];
210
- }
211
- }
212
- } // end for
213
-
214
- return obj;
215
- }
216
-
217
- // -----------------------------------------------------------------------------
218
-
219
- /**
220
- * Freezes an object recursively
221
- * - Allows non-objects to be passed as input parameter (non-objects are
222
- * immutable by default).
223
- *
224
- * @param {any} value
225
- *
226
- * @returns {any}
227
- * recursively frozen object or original input value if a non-object was
228
- * supplied as input parameter
229
- */
230
- export function deepFreeze(value, _found) {
231
- if (!(value instanceof Object)) {
232
- return value;
233
- }
234
-
235
- if (!_found) {
236
- _found = new Set();
237
- } else if (_found.has(value)) {
238
- // Using recursion -> no need to return value
239
- return;
240
- }
241
-
242
- _found.add(value);
243
-
244
- Object.freeze(value);
245
-
246
- for (const key in value) {
247
- const childObj = value[key];
248
-
249
- if (childObj instanceof Object) {
250
- // Recurse into child objects
251
- deepFreeze(childObj, _found);
252
- }
253
- } // end for
254
-
255
- return value;
256
- }
257
-
258
- // -----------------------------------------------------------------------------
259
-
260
- /**
261
- * Set a value in an object using a path and value pair.
262
- * - Automatically creates parent objects
263
- *
264
- * @param {object} obj - Object to set the value in
265
- * @param {string|Array} path - Dot separated string path or array path
266
- * @param {any} value - value to set
267
- *
268
- * @returns {boolean} true if the value was changed
269
- */
270
- export function objectSet(obj, path, value) {
271
- expect.object(obj);
272
-
273
- const arrPath = toArrayPath(path);
274
-
275
- if (arguments.length < 3) {
276
- throw new Error('Missing or invalid parameter [value]');
277
- }
278
-
279
- let parentNode;
280
- const lastKey = arrPath[arrPath.length - 1];
281
-
282
- if (value !== undefined) {
283
- parentNode = _ensureParent(obj, arrPath);
284
- } else {
285
- //
286
- // value is undefined -> delete node
287
- //
288
- parentNode = _getParent(obj, arrPath);
289
-
290
- if (Array.isArray(parentNode)) {
291
- const keyAsInt = parseInt(lastKey, 10);
292
-
293
- if (Number.isNaN(keyAsInt)) {
294
- throw new Error(
295
- 'Cannot delete property [' +
296
- arrPath.join(PATH_SEPARATOR) +
297
- '] ' +
298
- 'from data node of type [Array]'
299
- );
300
- }
301
-
302
- if (keyAsInt < parentNode.length) {
303
- parentNode.splice(keyAsInt, 1);
304
- return true;
305
- }
306
-
307
- return false;
308
- } else if (parentNode) {
309
- if (lastKey in parentNode) {
310
- delete parentNode[lastKey];
311
- return true;
312
- }
313
- return false;
314
- }
315
- }
316
-
317
- // -- Set value
318
-
319
- const existingValue = parentNode[lastKey];
320
-
321
- if (!equals(value, existingValue)) {
322
- parentNode[lastKey] = value;
323
-
324
- return true;
325
- }
326
-
327
- return false;
328
- }
329
-
330
- // -----------------------------------------------------------------------------
331
-
332
- /**
333
- * Removes a value at the specified object path from the object.
334
- * - All parent objects that remain empty will be removed too (recursively)
335
- *
336
- * @param {object} obj - Object to set the value in
337
- * @param {string|Array} path - Dot separated string path or array path
338
- * @param {any} value - value to set
339
- */
340
- export function deletePath(obj, path) {
341
- expect.object(obj);
342
-
343
- const arrPath = toArrayPath(path);
344
-
345
- const n = arrPath.length;
346
- const n_1 = n - 1;
347
-
348
- if (!n) {
349
- // Path is empty ""
350
- return;
351
- }
352
-
353
- const lastKey = arrPath[n_1];
354
-
355
- if (1 === n) {
356
- // Path consist of a single key
357
- delete obj[lastKey];
358
- return;
359
- }
360
-
361
- // path is longer than a single key >>
362
-
363
- // -- Get parent objects
364
-
365
- const parents = [];
366
-
367
- let current = obj;
368
-
369
- let endValueFound = true;
370
-
371
- for (let j = 0; j < n; j = j + 1) {
372
- if (!(current instanceof Object)) {
373
- break;
374
- }
375
-
376
- parents.push(current);
377
-
378
- const key = arrPath[j];
379
-
380
- // console.log(
381
- // {
382
- // current,
383
- // key,
384
- // next: current[ key ]
385
- // } );
386
-
387
- if (!(key in current)) {
388
- // child not found -> no more parents
389
- endValueFound = false;
390
- break;
391
- }
392
-
393
- current = current[key];
394
- }
395
-
396
- // console.log( "parents", parents );
397
-
398
- // -- Delete value from direct parent
399
-
400
- const n_parents = parents.length - 1;
401
-
402
- if (endValueFound) {
403
- const lastParent = parents[n_parents];
404
-
405
- if (!Array.isArray(lastParent)) {
406
- delete lastParent[lastKey];
407
- } else {
408
- lastParent.splice(parseInt(lastKey, 10), 1);
409
- }
410
- }
411
-
412
- // -- Remove empty parents
413
-
414
- for (let j = n_parents - 1; j >= 0; j = j - 1) {
415
- const parent = parents[j];
416
- const key = arrPath[j];
417
- const child = parent[key];
418
-
419
- let childIsEmpty = false;
420
-
421
- if (Array.isArray(child)) {
422
- // Child is array
423
- if (0 === child.length) {
424
- childIsEmpty = true;
425
- }
426
- } else {
427
- // Child is object
428
- if (0 === Object.keys(child).length) {
429
- childIsEmpty = true;
430
- }
431
- }
432
-
433
- if (!childIsEmpty) {
434
- // done
435
- break;
436
- }
437
-
438
- // Remove empty child from parent
439
-
440
- if (!Array.isArray(parent)) {
441
- delete parent[key];
442
- break;
443
- } else {
444
- parent.splice(parseInt(key, 10), 1);
445
- }
446
- } // end for
447
- }
448
-
449
- // -----------------------------------------------------------------------------
450
-
451
- /**
452
- * Get a value from an object using a path
453
- * - Returns a default value if not found, with is [undefined] by default
454
- *
455
- * @param {object} obj - Object to get the value from
456
- * @param {string|Array} path - Dot separated string path or array path
457
- *
458
- * @param {any} [defaultValue=undefined]
459
- * Value to return if the value does not exist
460
- *
461
- * @return {any} value found at path, defaultValue or undefined
462
- */
463
- export function objectGet(obj, path, defaultValue) {
464
- expect.object(obj);
465
-
466
- const arrPath = toArrayPath(path);
467
-
468
- if (!path.length || (1 === path.length && !path[0].length)) {
469
- // "" or [""]
470
- return obj;
471
- }
472
-
473
- const parentNode = _getParent(obj, arrPath);
474
-
475
- if (!parentNode) {
476
- return defaultValue; // @note may be undefined
477
- }
478
-
479
- const lastKey = arrPath[arrPath.length - 1];
480
-
481
- const value = parentNode[lastKey];
482
-
483
- if (value === undefined) {
484
- return defaultValue; // @note may be undefined
485
- }
486
-
487
- return value;
488
- }
489
-
490
- // -----------------------------------------------------------------------------
491
-
492
- /**
493
- * Get a value from an object using a path
494
- * - Throws an exception if the path does not exist or the value is undefined
495
- *
496
- * @param {object} obj - Object to get the value from
497
- * @param {string|Array} path - Dot separated string path or array path
498
- *
499
- * @param {function} [parseFn]
500
- * Optional parser function that checks and converts the value
501
- *
502
- * @throws No value found at path
503
- * @throws Invalid value
504
- *
505
- * @return {any} value found at path
506
- */
507
- export function objectGetWithThrow(obj, path, parseFn) {
508
- let value = objectGet(obj, path);
509
-
510
- if (parseFn) {
511
- const { value: parsedValue, error } = parseFn(value);
512
-
513
- if (error) {
514
- throw new Error(`Invalid value found at path [${toStringPath(path)}]`, { cause: error });
515
- }
516
-
517
- value = parsedValue;
518
- }
519
-
520
- if (value === undefined) {
521
- throw new Error(`No value found at path [${toStringPath(path)}]`);
522
- }
523
-
524
- return value;
525
- }
526
-
527
- // -----------------------------------------------------------------------------
528
-
529
- // DEV >>>>
530
-
531
- /**
532
- * Get an iterator that returns the value of a path for each item (object)
533
- * in the list of objects
534
- *
535
- * @param {object[]} arr - Array of objects
536
- * @param {string|string[]} path - Dot separated string path or array path
537
- *
538
- * @param {object} [options] - options
539
- *
540
- * DEPRECEATED >>> NOT COMPATIBLE WITH LIGHTWEIGHT ITERATOR
541
- * @param {object} [options.unique=false] - Only return unique values
542
- *
543
- * @param {any} [options.defaultValue]
544
- * Value to return if the value does not exist
545
- *
546
- * @returns {Iterator<mixed>} value at the specified path for each item
547
- */
548
- // export function values( arr, path, options )
549
- // {
550
- // if( !Array.isArray(arr) )
551
- // {
552
- // throw new Error("Missing or invalid parameter [arr] (expected Array)");
553
- // }
554
-
555
- // if( typeof path !== "string" && !Array.isArray(path) )
556
- // {
557
- // throw new Error(
558
- // "Missing or invalid parameter [path] (expected string or Array");
559
- // }
560
-
561
- // options = Object.assign(
562
- // {
563
- // unique: false,
564
- // defaultValue: undefined
565
- // },
566
- // options );
567
-
568
- // if( options.unique )
569
- // {
570
- // // Keep track of all values to prevent duplicates
571
- // }
572
-
573
- // throw new Error("NOT IMPLEMENTED YET");
574
- // }
575
-
576
- // <<< DEV
577
-
578
- // -----------------------------------------------------------------------------
579
-
580
- /**
581
- * Returns a list of differences between the object before and the object
582
- * after the changes.
583
- * - By default, the function returns changes for added, updated and removed
584
- * properties
585
- *
586
- * @param {object} objBefore
587
- * @param {object} objAfter
588
- *
589
- * @param {object} options
590
- * @param {boolean} [options.ignoreAdd=false]
591
- * @param {boolean} [options.ignoreUpdate=false]
592
- * @param {boolean} [options.ignoreDelete=false]
593
- *
594
- * @param {boolean} [options.ignorePrivate=true]
595
- * Ignore properties that start with an underscore e.g. _id or _updatedAt
596
- *
597
- * @param {boolean} [options.deleteValue=null]
598
- *
599
- * @returns {array}
600
- * List of changes between the object before and object after
601
- */
602
- export function objectDiff(objBefore, objAfter, options = {}, _recursion) {
603
- const changes = [];
604
-
605
- const ignoreAdd = undefined === options.ignoreAdd ? false : options.ignoreAdd;
606
-
607
- const ignoreUpdate = undefined === options.ignoreUpdate ? false : options.ignoreUpdate;
608
-
609
- const ignoreDelete = undefined === options.ignoreDelete ? false : options.ignoreDelete;
610
-
611
- const ignorePrivate = undefined === options.ignorePrivate ? true : options.ignorePrivate;
612
-
613
- let deleteValue = null;
614
-
615
- if ('deletevalue' in options) {
616
- // Might be [undefined]
617
- deleteValue = options.deleteValue;
618
- }
619
-
620
- objBefore = objBefore || {};
621
-
622
- for (const key in objAfter) {
623
- if (ignorePrivate && key.startsWith('_')) {
624
- continue;
625
- }
626
-
627
- const newValue = objAfter[key];
628
-
629
- if (deleteValue !== newValue) {
630
- const previousValue = objBefore[key];
631
-
632
- if (newValue === previousValue) {
633
- // No change
634
- continue;
635
- }
636
-
637
- if (previousValue instanceof Object && newValue instanceof Object) {
638
- // TODO: _recursion
639
-
640
- const diff = objectDiff(newValue, previousValue, options, _recursion);
641
-
642
- if (0 === diff.length) {
643
- // No change
644
- continue;
645
- }
646
- }
647
-
648
- if (undefined !== previousValue) {
649
- if (!ignoreUpdate) {
650
- // update property value
651
- changes.push({ path: key, set: newValue });
652
- }
653
- } else if (!ignoreAdd) {
654
- // add property
655
- changes.push({ path: key, set: newValue });
656
- }
657
- } else if (!ignoreDelete) {
658
- // newValue === deleteValue && ignoreDelete=true
659
- changes.push({ path: key, unset: 1 });
660
- }
661
- } // end for
662
-
663
- return changes;
664
- }
665
-
666
- // -----------------------------------------------------------------------------
667
-
668
- /**
669
- * Applies a list of differences to the input object
670
- * - A list of changes can be generated by e.g. objectDiff
671
- *
672
- * @param {object} obj
673
- * @param {object[]} changes
674
- *
675
- * @param {object} options
676
- * @param {boolean} [options.ignoreAdd=false]
677
- * @param {boolean} [options.ignoreUpdate=false]
678
- * @param {boolean} [options.ignoreDelete=false]
679
- *
680
- * @param {boolean} [options.ignorePrivate=true]
681
- * Ignore properties that start with an underscore e.g. _id or _updatedAt
682
- */
683
- export function patchObject(obj, changes, options = {}) {
684
- expect.object(obj);
685
- expect.array(changes);
686
-
687
- const ignoreAdd = undefined === options.ignoreAdd ? false : options.ignoreAdd;
688
-
689
- const ignoreUpdate = undefined === options.ignoreUpdate ? false : options.ignoreUpdate;
690
-
691
- const ignoreDelete = undefined === options.ignoreDelete ? false : options.ignoreDelete;
692
-
693
- const ignorePrivate = undefined === options.ignorePrivate ? true : options.ignorePrivate;
694
-
695
- for (let j = 0, n = changes.length; j < n; j = j + 1) {
696
- const change = changes[j];
697
-
698
- const path = change.path;
699
-
700
- // FIXME: recursion
701
-
702
- if (ignorePrivate && path.startsWith('_')) {
703
- continue;
704
- }
705
-
706
- if ('unset' in change) {
707
- if (ignoreDelete) {
708
- continue;
709
- }
710
-
711
- // console.log( "DELETE", change );
712
- objectSet(obj, path, undefined); // undefined deletes property
713
- continue;
714
- }
715
-
716
- const newValue = change.set;
717
-
718
- if (undefined === newValue) {
719
- //logError("Invalid [change]", ignoreDelete, change);
720
- throw new Error(`Cannot set value [${path}=undefined]`);
721
- }
722
-
723
- if (ignoreAdd && Object._get(obj, path) === undefined) {
724
- // Ignore add
725
- continue;
726
- } else if (ignoreUpdate && objectGet(obj, path) !== undefined) {
727
- // Ignore update
728
- continue;
729
- }
730
-
731
- // Set new value
732
- objectSet(obj, path, newValue);
733
- } // end for
734
- }
735
-
736
- // -----------------------------------------------------------------------------
737
-
738
- /**
739
- * Extend the target object with methods and properties from the source
740
- * property object
741
- * - The target object will be extended by inserting the source property
742
- * object into it's property chain
743
-
744
- * - If the current target's prototype is not the same as the source
745
- * prototype, the source prototype will be cloned
746
- *
747
- * @param {object} target - Target object
748
- * @param {object} source
749
- * object to append to the target's prototype chain. The object and it's
750
- * prototype objects are cloned first
751
- */
752
- export function extend(target, source) {
753
- expect.objectNoFunction(target);
754
-
755
- if (Object.isFrozen(target)) {
756
- throw new Error('Invalid parameter [target] (object is immutable)');
757
- }
758
-
759
- expect.objectNoFunction(source);
760
-
761
- // let sourceProto = source.prototype;
762
-
763
- let targetProto = Object.getPrototypeOf(target);
764
-
765
- if (targetProto === Object.prototype || Object.isFrozen(targetProto)) {
766
- // FIXME: || Object.isFrozen(targetProto) should not be necessary!
767
-
768
- targetProto = target;
769
- }
770
-
771
- {
772
- let obj = source;
773
-
774
- while (obj && obj !== Object.prototype) {
775
- const next = Object.getPrototypeOf(obj);
776
-
777
- copyOwnProperties(obj, targetProto);
778
-
779
- obj = next;
780
- }
781
- }
782
-
783
- return;
784
- }
785
-
786
- // -----------------------------------------------------------------------------
787
-
788
- /**
789
- * Get a list of property names of the specified object
790
- *
791
- * @param {object} obj
792
- *
793
- * @returns {string[]} List of property names
794
- */
795
- export function getPrototypeNames(obj) {
796
- expect.object(obj);
797
-
798
- let proto = obj.prototype || obj;
799
-
800
- const names = [];
801
-
802
- while (proto) {
803
- // console.log( proto );
804
-
805
- names.push(proto.constructor.name);
806
-
807
- proto = Object.getPrototypeOf(proto);
808
- }
809
-
810
- return names;
811
- }
812
-
813
- // -----------------------------------------------------------------------------
814
-
815
- /**
816
- * Get a tree of values from an object
817
- * - Can returns default values if one or multiple values were not found
818
- *
819
- * @param {object} obj - Object to get the value from
820
- * @param {object} tree
821
- * Tree that contains the object paths to get.
822
- *
823
- * e.g. { path: 1 }
824
- * { some: { path: { to: 1 }, otherPath: { to: 1 } } }
825
- * { "some.path.to": 1, "some.otherPath.to": 1 }
826
- * { someArray.0.name: 1 }
827
- *
828
- * @param {object} [options]
829
- * @param {object} [options.shallowLeaves=false]
830
- * If set to true, the values of the leaves of the tree will be converted
831
- * to shallow objects if the leaves are nested objects.
832
- *
833
- * @return {object}
834
- * nested object with the values that were found or defaultValues
835
- */
836
- export function getTree(obj, tree, options) {
837
- expect.object(obj);
838
- expect.object(tree);
839
-
840
- let shallowLeaves = false;
841
-
842
- if (options instanceof Object && options.shallowLeaves) {
843
- shallowLeaves = true;
844
- }
845
-
846
- const it = iterateObjectPaths(tree, { walkArrays: true });
847
-
848
- const result = {};
849
-
850
- for (let arrPath of it) {
851
- // console.log( { arrPath } );
852
-
853
- if (1 === arrPath.length && arrPath[0].includes(PATH_SEPARATOR)) {
854
- // Convert "short path syntax" to array path
855
- arrPath = arrPath[0].split(PATH_SEPARATOR);
856
- }
857
-
858
- // -- Get value from object at current path
859
-
860
- const leaveValue = objectGet(obj, arrPath);
861
-
862
- // -- Set value in result object at current path
863
-
864
- if (!shallowLeaves || !(leaveValue instanceof Object)) {
865
- // option: shallowLeaves=false OR value is not an object
866
- // -> no need to convert leaves to shallow objects
867
- objectSet(result, arrPath, leaveValue);
868
- } else {
869
- // Set shallow leave value instead of nested object
870
-
871
- const shallowLeaveValue = shallowClone(leaveValue);
872
- objectSet(result, arrPath, shallowLeaveValue);
873
- }
874
- } // end for
875
-
876
- return result;
877
- }
878
-
879
- // -----------------------------------------------------------------------------
880
-
881
- /**
882
- * Deep clone an object or any kind of other variable
883
- * - Recursively clone all nested properties
884
- * - Properties in the prototype chain are cloned too, but all copied into a
885
- * single prototype object
886
- * - This method works on objects, but also on any other JS variable type
887
- * - If a value cannot be cloned, a reference is returned. o.a. for
888
- * - Error objects
889
- * - Browser objects
890
- * - Functions
891
- *
892
- * @param {any} objectToBeCloned - Variable to clone
893
- *
894
- * @returns {any} cloned output
895
- */
896
- export function clone(objectToBeCloned, _seenObjects) {
897
- // const startTime = Date.now();
898
-
899
- // -- Return references for all variables that are not objects
900
-
901
- if (!(objectToBeCloned instanceof Object)) {
902
- return objectToBeCloned;
903
- }
904
-
905
- // --- Check if variable has already been cloned before
906
-
907
- if (!_seenObjects) {
908
- _seenObjects = { originals: [], clones: [] };
909
- } else {
910
- const originals = _seenObjects.originals;
911
-
912
- if (originals.length > 0) {
913
- const foundIndex = originals.indexOf(objectToBeCloned);
914
-
915
- if (-1 !== foundIndex) {
916
- //console.log("(recursion) return
917
- //from [_seenObjects]", _seenObjects.clones, foundIndex);
918
- return _seenObjects.clones[foundIndex];
919
- }
920
- }
921
- }
922
-
923
- // -- Handle array (like) objects
924
-
925
- const typeString = object_to_string.call(objectToBeCloned);
926
-
927
- if (Array.isArray(objectToBeCloned) || '[object Arguments]' === typeString) {
928
- const objectClone = [];
929
-
930
- for (let j = 0, n = objectToBeCloned.length; j < n; j = j + 1) {
931
- objectClone[j] = clone(objectToBeCloned[j], _seenObjects);
932
- }
933
-
934
- _seenObjects.originals.push(objectToBeCloned);
935
- _seenObjects.clones.push(objectClone);
936
-
937
- return objectClone;
938
- }
939
-
940
- // -- Handle not clonable objects
941
-
942
- if ('[object Object]' !== typeString || objectToBeCloned instanceof Error) {
943
- // Functions, Browser objects, ...
944
- // - Not clonable -> return reference
945
- // - No need to add to _seenObjects
946
- return objectToBeCloned;
947
- }
948
-
949
- // -- Handle special objects
950
- {
951
- // Filter out special objects.
952
- const Constructor = objectToBeCloned.constructor;
953
-
954
- let objectClone;
955
-
956
- switch (Constructor) {
957
- case RegExp:
958
- objectClone = new Constructor(objectToBeCloned);
959
- break;
960
-
961
- case Date:
962
- objectClone = new Constructor(objectToBeCloned.getTime());
963
- break;
964
-
965
- // TODO: other special objects ...
966
- }
967
-
968
- if (objectClone) {
969
- _seenObjects.originals.push(objectToBeCloned);
970
- _seenObjects.clones.push(objectClone);
971
-
972
- return objectClone;
973
- }
974
-
975
- if (objectToBeCloned.hkDoNotClone) {
976
- // Not clonable flag was set -> return reference
977
- // TODO: Other objects that should not be cloned?
978
- return objectToBeCloned;
979
- }
980
- }
981
-
982
- // -- Create new object and clone properties
983
-
984
- // objectClone = new Constructor();
985
- // const prototypeClone = Object.create(null);
986
-
987
- const prototypeClone = {};
988
- const objectClone = Object.create(prototypeClone);
989
-
990
- // Already push object to _seenObjects
991
- // (objectClone will still change as properties are being cloned)
992
- _seenObjects.originals.push(objectToBeCloned);
993
- _seenObjects.clones.push(objectClone);
994
-
995
- for (const prop in objectToBeCloned) {
996
- if (has_own_property.call(objectToBeCloned, prop)) {
997
- // Own property -> clone into object
998
- objectClone[prop] = clone(objectToBeCloned[prop], _seenObjects);
999
- } else {
1000
- // Inherited property -> clone into prototype
1001
-
1002
- // @warning
1003
- // known issue: all inherited properties are copied into the
1004
- // same prototype object!
1005
-
1006
- prototypeClone[prop] = clone(objectToBeCloned[prop], _seenObjects);
1007
- }
1008
- }
1009
-
1010
- return objectClone;
1011
- }
1012
-
1013
- // -----------------------------------------------------------------------------
1014
-
1015
- /**
1016
- * Set a read only property in an object
1017
- *
1018
- * @param {object} obj - Object to set the read only property in
1019
- * @param {string} propertyName - Name of the property to set
1020
- * @param {any} value - Value to set
1021
- */
1022
- export function setReadOnlyProperty(obj, propertyName, value) {
1023
- expect.object(obj);
1024
-
1025
- expect.string(propertyName);
1026
-
1027
- // expect.defined(value);
1028
-
1029
- Object.defineProperty(obj, propertyName, {
1030
- value,
1031
- writable: false,
1032
- enumerable: true
1033
- });
1034
- }
1035
-
1036
- // -----------------------------------------------------------------------------
1037
-
1038
- /**
1039
- * Returns a clone of a (nested) object that has a maximum depth
1040
- *
1041
- * @param {object|array} obj
1042
- *
1043
- * @returns {object|array} shallow object or array
1044
- */
1045
- export function shallowClone(objectOrArray) {
1046
- expect.object(objectOrArray);
1047
-
1048
- if (Array.isArray(objectOrArray)) {
1049
- // obj is an array
1050
-
1051
- let isShallow = true;
1052
-
1053
- for (let j = 0, n = objectOrArray.length; j < n; j = j + 1) {
1054
- const value = objectOrArray[j];
1055
-
1056
- if (value instanceof Object) {
1057
- isShallow = false;
1058
- break;
1059
- }
1060
- } // end for
1061
-
1062
- if (isShallow) {
1063
- // objectOrArray is already shallow -> nothing to do
1064
- return objectOrArray;
1065
- }
1066
-
1067
- const outputArray = [];
1068
-
1069
- for (let j = 0, n = objectOrArray.length; j < n; j = j + 1) {
1070
- const value = objectOrArray[j];
1071
-
1072
- if (!(value instanceof Object)) {
1073
- outputArray.push(value);
1074
- }
1075
- // else {
1076
- // //outputArray.push( null );
1077
- // // outputArray.push( $removed );
1078
- // }
1079
- } // end for
1080
-
1081
- return outputArray;
1082
- } else {
1083
- // obj is a not an array
1084
-
1085
- let isShallow = true;
1086
-
1087
- for (const key in objectOrArray) {
1088
- const value = objectOrArray[key];
1089
-
1090
- if (value instanceof Object) {
1091
- isShallow = false;
1092
- break;
1093
- }
1094
- // else {
1095
- // // outputObj[ key ] = null;
1096
- // // outputObj[ key ] = $removed;
1097
- // }
1098
- } // end for
1099
-
1100
- if (isShallow) {
1101
- // objectOrArray is already shallow -> nothing to do
1102
- return objectOrArray;
1103
- }
1104
-
1105
- const outputObj = {};
1106
-
1107
- for (const key in objectOrArray) {
1108
- const value = objectOrArray[key];
1109
-
1110
- if (!(value instanceof Object)) {
1111
- outputObj[key] = value;
1112
- }
1113
- // else {
1114
- // // outputObj[ key ] = null;
1115
- // // outputObj[ key ] = $removed;
1116
- // }
1117
- } // end for
1118
-
1119
- return outputObj;
1120
- }
1121
- }
1122
-
1123
- // -----------------------------------------------------------------------------
1124
-
1125
- /**
1126
- * Update an object
1127
- * - Sets the path-value pairs from the updateData in the object
1128
- * - Existing values will be overwritten
1129
- * - Existing intermediate values (objects, arrays) will be overwritten too
1130
- * (if updateData is an object, not an iterable)
1131
- *
1132
- * @param {object} [obj] - Input object
1133
- *
1134
- * @param {object|iterable} updateData - Data to update
1135
- *
1136
- * Note that if using path-value pairs, the order of the pairs is relevant:
1137
- * {
1138
- * "some": {},
1139
- * "some.path": {},
1140
- * "some.path.to": 2,
1141
- * }
1142
- *
1143
- * @returns {object} updated object
1144
- */
1145
- export function updateObject(obj = null, updateData = null, options) {
1146
- // -- Check parameter [obj]
1147
-
1148
- expect.object(obj);
1149
-
1150
- expect.object(updateData);
1151
-
1152
- // -- Update cloned object
1153
-
1154
- let pathValuePairs;
1155
-
1156
- if (!isIterable(updateData)) {
1157
- // Convert updateData to path-value pairs (iterable)
1158
-
1159
- const walkArrays = options && options.replaceArrays ? true : false;
1160
-
1161
- pathValuePairs = iterateObjectEntries(updateData, {
1162
- expandPathKeys: true,
1163
- outputIntermediateNodes: true,
1164
- walkArrays
1165
- });
1166
-
1167
- // pathValuePairs = Array.from( pathValuePairs );
1168
- // console.log( "CHECK", { updateData, pathValuePairs } );
1169
- } else {
1170
- // Iterable -> assume iterable of path-value pairs
1171
- pathValuePairs = updateData;
1172
- }
1173
-
1174
- for (const [arrPath, value] of pathValuePairs) {
1175
- // console.log( "updateObject:set", arrPath, value );
1176
- objectSet(obj, arrPath, value);
1177
- }
1178
-
1179
- return obj;
1180
- }
1181
-
1182
- // -----------------------------------------------------------------------------
1183
-
1184
- /**
1185
- * Copy own properties from an object to another object if they do not
1186
- * exist yet.
1187
- *
1188
- * @param {object} from - Object ot copy properties from
1189
- * @param {object} to - Object to copy properties to
1190
- */
1191
- export function copyOwnProperties(from, to) {
1192
- const propertyNames = Object.getOwnPropertyNames(from);
1193
-
1194
- const nProperties = propertyNames.length;
1195
-
1196
- if (!nProperties) {
1197
- return;
1198
- }
1199
-
1200
- const firstIsConstructor = 'constructor' === propertyNames[0] ? true : false;
1201
-
1202
- if (1 === nProperties && firstIsConstructor) {
1203
- return;
1204
- }
1205
-
1206
- const startAt = firstIsConstructor ? 1 : 0;
1207
-
1208
- // console.log("propertyNames", from, propertyNames, startAt);
1209
-
1210
- for (let j = startAt; j < nProperties; j = j + 1) {
1211
- const key = propertyNames[j];
1212
-
1213
- const descriptor = Object.getOwnPropertyDescriptor(from, key);
1214
-
1215
- const targetDescriptor = Object.getOwnPropertyDescriptor(to, key);
1216
-
1217
- // Not needed, we copy an instance
1218
- // descriptor.value = clone( descriptor.value );
1219
-
1220
- if (!targetDescriptor) {
1221
- // Property does not yet exist
1222
- Object.defineProperty(to, key, descriptor);
1223
- }
1224
- } // end for
1225
-
1226
- // >>> FIXME? TODO? copy Symbols too? <<<
1227
- }
1228
-
1229
- // -----------------------------------------------------------------------------
1230
-
1231
- /**
1232
- * Convert string with dot separated values to a list of values
1233
- * - Accepts that the supplied path is already an array path
1234
- *
1235
- * @param {string|string[]} path
1236
- *
1237
- * @returns {string[]} list of path values
1238
- */
1239
- export function ensureArrayPath(path) {
1240
- if (typeof path === 'string') {
1241
- return path.split(PATH_SEPARATOR);
1242
- } else if (Array.isArray(path)) {
1243
- // Nothing to do
1244
- return path;
1245
- } else {
1246
- throw new Error('Missing or invalid parameter [path] (expected string or array)');
1247
- }
1248
- }
1249
-
1250
- /* ----------------------------------------------------- Internal methods */
1251
-
1252
- // -----------------------------------------------------------------------------
1253
-
1254
- /**
1255
- * Create all parent objects on the object path if they do not yet exist yet
1256
- * - This method will throw an exception if there is a non-object node in
1257
- * the path
1258
- *
1259
- * @param {object} obj
1260
- * Object to create the parent objects in
1261
- *
1262
- * @param {string[]} arrPath
1263
- * The path that specified which parent oobjects to create
1264
- *
1265
- * @returns {object} the input object with the created object properties
1266
- */
1267
- export function _ensureParent(obj, arrPath) {
1268
- // console.log("_ensureParent (1)", { obj, arrPath } );
1269
-
1270
- let current = obj;
1271
- let prev = current;
1272
-
1273
- for (let j = 0, n_1 = arrPath.length - 1; j < n_1; j = j + 1) {
1274
- const key = arrPath[j];
1275
-
1276
- current = current[key];
1277
-
1278
- if (current === undefined || current === null) {
1279
- current = prev[key] = {};
1280
- prev = current;
1281
- continue;
1282
- }
1283
-
1284
- const nextKey = arrPath[j + 1];
1285
-
1286
- // Check
1287
- // Check if current is an object
1288
- // If current is an array, check if the nextKey can be set on a array
1289
-
1290
- if (current instanceof Object) {
1291
- if (Array.isArray(current) && j < n_1) {
1292
- const nextKeyAsInt = parseInt(nextKey, 10);
1293
-
1294
- if (Number.isNaN(nextKeyAsInt)) {
1295
- // console.log("CHECK", { obj, arrPath, j, current, nextKey } );
1296
- throw new Error(`Cannot set property [${nextKey}] ` + 'on data node of type [Array]');
1297
- }
1298
- }
1299
- } else {
1300
- // console.log( { current, prev, key, arrPath, j } );
1301
-
1302
- throw new Error(
1303
- `Cannot set property [${nextKey}] from ` +
1304
- `path [${display_array_path(arrPath)}] on data node that is not ` +
1305
- 'an object or an array'
1306
- );
1307
- }
1308
-
1309
- prev = current;
1310
- } // end for
1311
-
1312
- return current;
1313
- }
1314
-
1315
- // -----------------------------------------------------------------------------
1316
-
1317
- /**
1318
- * Get parent object at the specified path
1319
- *
1320
- * @param {object} obj - Object to work in
1321
- * @param {string[]} arrPath - Path to get the parent object for
1322
- *
1323
- * @returns {object|array|null} parent object or null if not found
1324
- */
1325
- export function _getParent(obj, arrPath) {
1326
- let current = obj;
1327
-
1328
- for (let j = 0, n_1 = arrPath.length - 1; j < n_1; j = j + 1) {
1329
- let key = arrPath[j];
1330
-
1331
- current = current[key];
1332
-
1333
- if (typeof current === 'undefined') {
1334
- return null;
1335
- }
1336
-
1337
- if (current instanceof Object) {
1338
- if (Array.isArray(current) && j < n_1 - 1) {
1339
- // node is an array
1340
- // -> use next part of the array path as (numerical) array index
1341
-
1342
- key = arrPath[j + 1];
1343
- const keyAsInt = parseInt(key, 10);
1344
-
1345
- if (Number.isNaN(keyAsInt)) {
1346
- throw new Error(
1347
- `Cannot get property [${display_array_path(arrPath, j)}]` +
1348
- 'from data node of type [Array]'
1349
- );
1350
- }
1351
- }
1352
- } else {
1353
- throw new Error(
1354
- `Cannot get property [${display_array_path(arrPath, j)}]` +
1355
- 'from a data node that is not an object or an array'
1356
- );
1357
- }
1358
- } // end for
1359
-
1360
- return current;
1361
- }
1
+ /* ------------------------------------------------------------------ Imports */
2
+
3
+ import * as expect from '../expect/index.js';
4
+
5
+ import { equals } from '../compare/index.js';
6
+
7
+ import { toArrayPath } from '../array/index.js';
8
+
9
+ import { toStringPath } from '../string/index.js';
10
+
11
+ import * as is from '../is/index.js';
12
+
13
+ import { iterateObjectPaths, iterateObjectEntries } from '../iterate/index.js';
14
+
15
+ // ------------------------------------------------------------------- Internals
16
+
17
+ const PATH_SEPARATOR = '.';
18
+
19
+ /**
20
+ * Create a human friendly string representation of an array path
21
+ * - Allows for removal of the last part of the array part
22
+ *
23
+ * @param {string[]} arr - Array path to join
24
+ * @param {number} [lastIndex]
25
+ * If specified, only parts up and including the last index will
26
+ * be joined
27
+ *
28
+ * @returns {string} path as string
29
+ */
30
+ function display_array_path(arr, lastIndex) {
31
+ return arr.slice(0, lastIndex).join(PATH_SEPARATOR);
32
+ }
33
+
34
+ const object_to_string = Object.prototype.toString;
35
+ const has_own_property = Object.prototype.hasOwnProperty;
36
+
37
+ /* ------------------------------------------------------------------ Exports */
38
+
39
+ export { PATH_SEPARATOR };
40
+
41
+ // -----------------------------------------------------------------------------
42
+
43
+ /**
44
+ * Returns true
45
+ * - if the object has no enumerable key value pairs
46
+ * - if the object is an empty array
47
+ *
48
+ * @param {object} obj
49
+ *
50
+ * @return {boolean}
51
+ * true if the object has no key value pairs or the supplied object
52
+ * is falsy
53
+ */
54
+ export function isEmpty(obj) {
55
+ if (!obj) {
56
+ // object is null or other falsy value
57
+ return true;
58
+ }
59
+
60
+ expect.object(obj);
61
+
62
+ return Object.keys(obj).length === 0;
63
+ }
64
+
65
+ // -----------------------------------------------------------------------------
66
+
67
+ /**
68
+ * Get the number of enumerable key value pairs in the specified object
69
+ *
70
+ * @param {object} obj
71
+ *
72
+ * @return {number} number of enumerable key value pairs
73
+ */
74
+ export function size(obj) {
75
+ expect.object(obj);
76
+
77
+ return Object.keys(obj).length;
78
+ }
79
+
80
+ // -----------------------------------------------------------------------------
81
+
82
+ /**
83
+ * Returns a shallow copy of the object without the properties that
84
+ * have the value [null] or [undefined]
85
+ *
86
+ * @param {object} obj
87
+ *
88
+ * @param {string[]} [onlyKeys]
89
+ * If specified, only the specified keys will be exported
90
+ *
91
+ * @returns {object} new object without the null properties
92
+ */
93
+ export function exportNotNull(obj, onlyKeys) {
94
+ expect.object(obj);
95
+
96
+ const onlyKeysSet = onlyKeys ? new Set(onlyKeys) : null;
97
+
98
+ return Object.fromEntries(
99
+ Object.entries(obj).filter(([key, value]) => {
100
+ if (value === null || value === undefined) return false;
101
+ return !onlyKeysSet || onlyKeysSet.has(key);
102
+ })
103
+ );
104
+ }
105
+
106
+ // -----------------------------------------------------------------------------
107
+
108
+ /**
109
+ * Create a shallow copy of the object's public properties. Properties that
110
+ * start with an underscore are considered 'internal' properties and are not
111
+ * exported.
112
+ * - This method can e.g. be used to export a data object without it's
113
+ * 'internal' properties
114
+ *
115
+ * @param {object} obj
116
+ *
117
+ * @param {string[]} [keepKeys]
118
+ * If specified, the specified private keys will be exported (e.g. `_id`)
119
+ *
120
+ * @returns {object} new object without properties that start with an underscore
121
+ */
122
+ export function exportPublic(obj, keepKeys) {
123
+ expect.object(obj);
124
+
125
+ const newObj = {};
126
+
127
+ const keepKeysSet = keepKeys ? new Set(keepKeys) : null;
128
+
129
+ for (const key in obj) {
130
+ const value = obj[key];
131
+
132
+ if (!key.startsWith('_')) {
133
+ newObj[key] = value;
134
+ } else if (keepKeysSet && keepKeysSet.has(key)) {
135
+ //
136
+ // Add key to keep as read only property
137
+ //
138
+ Object.defineProperty(newObj, key, {
139
+ value,
140
+ writable: false,
141
+ enumerable: true
142
+ });
143
+ }
144
+ } // end for
145
+
146
+ return newObj;
147
+ }
148
+
149
+ // -----------------------------------------------------------------------------
150
+
151
+ /**
152
+ * Creates a copy of an object or array that contains only primitive values
153
+ * - Nested objects and arrays are completely removed
154
+ * - Only string, number, boolean, null, undefined values are kept
155
+ *
156
+ * @param {object|array} objectOrArray
157
+ *
158
+ * @returns {object|array} new object or array with only primitive values
159
+ */
160
+ export function exportNotNested(objectOrArray) {
161
+ expect.object(objectOrArray);
162
+
163
+ if (Array.isArray(objectOrArray)) {
164
+ // obj is an array
165
+
166
+ let isShallow = true;
167
+
168
+ for (let j = 0, n = objectOrArray.length; j < n; j = j + 1) {
169
+ const value = objectOrArray[j];
170
+
171
+ if (value instanceof Object) {
172
+ isShallow = false;
173
+ break;
174
+ }
175
+ } // end for
176
+
177
+ if (isShallow) {
178
+ // objectOrArray is already shallow -> nothing to do
179
+ return objectOrArray;
180
+ }
181
+
182
+ const outputArray = [];
183
+
184
+ for (let j = 0, n = objectOrArray.length; j < n; j = j + 1) {
185
+ const value = objectOrArray[j];
186
+
187
+ if (!(value instanceof Object)) {
188
+ outputArray.push(value);
189
+ }
190
+ } // end for
191
+
192
+ return outputArray;
193
+ } else {
194
+ // obj is a not an array
195
+
196
+ let isShallow = true;
197
+
198
+ for (const key in objectOrArray) {
199
+ const value = objectOrArray[key];
200
+
201
+ if (value instanceof Object) {
202
+ isShallow = false;
203
+ break;
204
+ }
205
+ } // end for
206
+
207
+ if (isShallow) {
208
+ // objectOrArray is already shallow -> nothing to do
209
+ return objectOrArray;
210
+ }
211
+
212
+ const outputObj = {};
213
+
214
+ for (const key in objectOrArray) {
215
+ const value = objectOrArray[key];
216
+
217
+ if (!(value instanceof Object)) {
218
+ outputObj[key] = value;
219
+ }
220
+ } // end for
221
+
222
+ return outputObj;
223
+ }
224
+ }
225
+
226
+ // -----------------------------------------------------------------------------
227
+
228
+ // export function removeNull()
229
+
230
+ // -----------------------------------------------------------------------------
231
+
232
+ /**
233
+ * Keep only the specified keys in the object
234
+ * - deletes all other key-value pairs in the object
235
+ *
236
+ * @param {object} obj
237
+ * @param {string[]|Set} keys
238
+ * @param {boolean} [removeNullAndUndefined=true]
239
+ *
240
+ * @returns {object} object that only contains the specified keys
241
+ */
242
+ export function keep(obj, keys, removeNullAndUndefined = true) {
243
+ expect.object(obj);
244
+ expect.arrayOrSet(keys);
245
+
246
+ const keep = keys instanceof Set ? keys : new Set(keys);
247
+
248
+ for (const key in obj) {
249
+ if (!keep.has(key)) {
250
+ delete obj[key];
251
+ continue;
252
+ }
253
+
254
+ const value = obj[key];
255
+
256
+ if (removeNullAndUndefined) {
257
+ if (value === null || value === undefined) {
258
+ delete obj[key];
259
+ }
260
+ }
261
+ } // end for
262
+
263
+ return obj;
264
+ }
265
+
266
+ // -----------------------------------------------------------------------------
267
+
268
+ /**
269
+ * Freezes an object recursively
270
+ * - Allows non-objects to be passed as input parameter (non-objects are
271
+ * immutable by default).
272
+ *
273
+ * @param {any} value
274
+ *
275
+ * @returns {any}
276
+ * recursively frozen object or original input value if a non-object was
277
+ * supplied as input parameter
278
+ */
279
+ export function deepFreeze(value, _found) {
280
+ if (!(value instanceof Object)) {
281
+ return value;
282
+ }
283
+
284
+ if (!_found) {
285
+ _found = new Set();
286
+ } else if (_found.has(value)) {
287
+ // Using recursion -> no need to return value
288
+ return;
289
+ }
290
+
291
+ _found.add(value);
292
+
293
+ Object.freeze(value);
294
+
295
+ for (const key in value) {
296
+ const childObj = value[key];
297
+
298
+ if (childObj instanceof Object) {
299
+ // Recurse into child objects
300
+ deepFreeze(childObj, _found);
301
+ }
302
+ } // end for
303
+
304
+ return value;
305
+ }
306
+
307
+ // -----------------------------------------------------------------------------
308
+
309
+ /**
310
+ * Set a value in an object using a path and value pair.
311
+ * - Automatically creates parent objects
312
+ *
313
+ * @param {object} obj - Object to set the value in
314
+ * @param {string|Array} path - Dot separated string path or array path
315
+ * @param {any} value - value to set
316
+ *
317
+ * @returns {boolean} true if the value was changed
318
+ */
319
+ export function objectSet(obj, path, value) {
320
+ expect.object(obj);
321
+
322
+ const arrPath = toArrayPath(path);
323
+
324
+ if (arguments.length < 3) {
325
+ throw new Error('Missing or invalid parameter [value]');
326
+ }
327
+
328
+ let parentNode;
329
+ const lastKey = arrPath[arrPath.length - 1];
330
+
331
+ if (value !== undefined) {
332
+ parentNode = _ensureParent(obj, arrPath);
333
+ } else {
334
+ //
335
+ // value is undefined -> delete node
336
+ //
337
+ parentNode = _getParent(obj, arrPath);
338
+
339
+ if (Array.isArray(parentNode)) {
340
+ const keyAsInt = parseInt(lastKey, 10);
341
+
342
+ if (Number.isNaN(keyAsInt)) {
343
+ throw new Error(
344
+ 'Cannot delete property [' +
345
+ arrPath.join(PATH_SEPARATOR) +
346
+ '] ' +
347
+ 'from data node of type [Array]'
348
+ );
349
+ }
350
+
351
+ if (keyAsInt < parentNode.length) {
352
+ parentNode.splice(keyAsInt, 1);
353
+ return true;
354
+ }
355
+
356
+ return false;
357
+ } else if (parentNode) {
358
+ if (lastKey in parentNode) {
359
+ delete parentNode[lastKey];
360
+ return true;
361
+ }
362
+ return false;
363
+ }
364
+ }
365
+
366
+ // -- Set value
367
+
368
+ const existingValue = parentNode[lastKey];
369
+
370
+ if (!equals(value, existingValue)) {
371
+ parentNode[lastKey] = value;
372
+
373
+ return true;
374
+ }
375
+
376
+ return false;
377
+ }
378
+
379
+ // -----------------------------------------------------------------------------
380
+
381
+ /**
382
+ * Removes a value at the specified object path from the object.
383
+ * - All parent objects that remain empty will be removed too (recursively)
384
+ *
385
+ * @param {object} obj - Object to set the value in
386
+ * @param {string|Array} path - Dot separated string path or array path
387
+ * @param {any} value - value to set
388
+ */
389
+ export function deletePath(obj, path) {
390
+ expect.object(obj);
391
+
392
+ const arrPath = toArrayPath(path);
393
+
394
+ const n = arrPath.length;
395
+ const n_1 = n - 1;
396
+
397
+ if (!n) {
398
+ // Path is empty ""
399
+ return;
400
+ }
401
+
402
+ const lastKey = arrPath[n_1];
403
+
404
+ if (1 === n) {
405
+ // Path consist of a single key
406
+ delete obj[lastKey];
407
+ return;
408
+ }
409
+
410
+ // path is longer than a single key >>
411
+
412
+ // -- Get parent objects
413
+
414
+ const parents = [];
415
+
416
+ let current = obj;
417
+
418
+ let endValueFound = true;
419
+
420
+ for (let j = 0; j < n; j = j + 1) {
421
+ if (!(current instanceof Object)) {
422
+ break;
423
+ }
424
+
425
+ parents.push(current);
426
+
427
+ const key = arrPath[j];
428
+
429
+ // console.log(
430
+ // {
431
+ // current,
432
+ // key,
433
+ // next: current[ key ]
434
+ // } );
435
+
436
+ if (!(key in current)) {
437
+ // child not found -> no more parents
438
+ endValueFound = false;
439
+ break;
440
+ }
441
+
442
+ current = current[key];
443
+ }
444
+
445
+ // console.log( "parents", parents );
446
+
447
+ // -- Delete value from direct parent
448
+
449
+ const n_parents = parents.length - 1;
450
+
451
+ if (endValueFound) {
452
+ const lastParent = parents[n_parents];
453
+
454
+ if (!Array.isArray(lastParent)) {
455
+ delete lastParent[lastKey];
456
+ } else {
457
+ lastParent.splice(parseInt(lastKey, 10), 1);
458
+ }
459
+ }
460
+
461
+ // -- Remove empty parents
462
+
463
+ for (let j = n_parents - 1; j >= 0; j = j - 1) {
464
+ const parent = parents[j];
465
+ const key = arrPath[j];
466
+ const child = parent[key];
467
+
468
+ let childIsEmpty = false;
469
+
470
+ if (Array.isArray(child)) {
471
+ // Child is array
472
+ if (0 === child.length) {
473
+ childIsEmpty = true;
474
+ }
475
+ } else {
476
+ // Child is object
477
+ if (0 === Object.keys(child).length) {
478
+ childIsEmpty = true;
479
+ }
480
+ }
481
+
482
+ if (!childIsEmpty) {
483
+ // done
484
+ break;
485
+ }
486
+
487
+ // Remove empty child from parent
488
+
489
+ if (!Array.isArray(parent)) {
490
+ delete parent[key];
491
+ break;
492
+ } else {
493
+ parent.splice(parseInt(key, 10), 1);
494
+ }
495
+ } // end for
496
+ }
497
+
498
+ // -----------------------------------------------------------------------------
499
+
500
+ /**
501
+ * Get a value from an object using a path
502
+ * - Returns a default value if not found, with is [undefined] by default
503
+ *
504
+ * @param {object} obj - Object to get the value from
505
+ * @param {string|Array} path - Dot separated string path or array path
506
+ *
507
+ * @param {any} [defaultValue=undefined]
508
+ * Value to return if the value does not exist
509
+ *
510
+ * @return {any} value found at path, defaultValue or undefined
511
+ */
512
+ export function objectGet(obj, path, defaultValue) {
513
+ expect.object(obj);
514
+
515
+ const arrPath = toArrayPath(path);
516
+
517
+ if (!path.length || (1 === path.length && !path[0].length)) {
518
+ // "" or [""]
519
+ return obj;
520
+ }
521
+
522
+ const parentNode = _getParent(obj, arrPath);
523
+
524
+ if (!parentNode) {
525
+ return defaultValue; // @note may be undefined
526
+ }
527
+
528
+ const lastKey = arrPath[arrPath.length - 1];
529
+
530
+ const value = parentNode[lastKey];
531
+
532
+ if (value === undefined) {
533
+ return defaultValue; // @note may be undefined
534
+ }
535
+
536
+ return value;
537
+ }
538
+
539
+ // -----------------------------------------------------------------------------
540
+
541
+ /**
542
+ * Get a value from an object using a path
543
+ * - Throws an exception if the path does not exist or the value is undefined
544
+ *
545
+ * @param {object} obj - Object to get the value from
546
+ * @param {string|Array} path - Dot separated string path or array path
547
+ *
548
+ * @param {function} [parseFn]
549
+ * Optional parser function that checks and converts the value
550
+ *
551
+ * @throws No value found at path
552
+ * @throws Invalid value
553
+ *
554
+ * @return {any} value found at path
555
+ */
556
+ export function objectGetWithThrow(obj, path, parseFn) {
557
+ let value = objectGet(obj, path);
558
+
559
+ if (parseFn) {
560
+ const { value: parsedValue, error } = parseFn(value);
561
+
562
+ if (error) {
563
+ throw new Error(`Invalid value found at path [${toStringPath(path)}]`, {
564
+ cause: error
565
+ });
566
+ }
567
+
568
+ value = parsedValue;
569
+ }
570
+
571
+ if (value === undefined) {
572
+ throw new Error(`No value found at path [${toStringPath(path)}]`);
573
+ }
574
+
575
+ return value;
576
+ }
577
+
578
+ // -----------------------------------------------------------------------------
579
+
580
+ // DEV >>>>
581
+
582
+ /**
583
+ * Get an iterator that returns the value of a path for each item (object)
584
+ * in the list of objects
585
+ *
586
+ * @param {object[]} arr - Array of objects
587
+ * @param {string|string[]} path - Dot separated string path or array path
588
+ *
589
+ * @param {object} [options] - options
590
+ *
591
+ * DEPRECEATED >>> NOT COMPATIBLE WITH LIGHTWEIGHT ITERATOR
592
+ * @param {object} [options.unique=false] - Only return unique values
593
+ *
594
+ * @param {any} [options.defaultValue]
595
+ * Value to return if the value does not exist
596
+ *
597
+ * @returns {Iterator<mixed>} value at the specified path for each item
598
+ */
599
+ // export function values( arr, path, options )
600
+ // {
601
+ // if( !Array.isArray(arr) )
602
+ // {
603
+ // throw new Error("Missing or invalid parameter [arr] (expected Array)");
604
+ // }
605
+
606
+ // if( typeof path !== "string" && !Array.isArray(path) )
607
+ // {
608
+ // throw new Error(
609
+ // "Missing or invalid parameter [path] (expected string or Array");
610
+ // }
611
+
612
+ // options = Object.assign(
613
+ // {
614
+ // unique: false,
615
+ // defaultValue: undefined
616
+ // },
617
+ // options );
618
+
619
+ // if( options.unique )
620
+ // {
621
+ // // Keep track of all values to prevent duplicates
622
+ // }
623
+
624
+ // throw new Error("NOT IMPLEMENTED YET");
625
+ // }
626
+
627
+ // <<< DEV
628
+
629
+ // -----------------------------------------------------------------------------
630
+
631
+ /**
632
+ * Returns a list of differences between the object before and the object
633
+ * after the changes.
634
+ * - By default, the function returns changes for added, updated and removed
635
+ * properties
636
+ *
637
+ * @param {object} objBefore
638
+ * @param {object} objAfter
639
+ *
640
+ * @param {object} options
641
+ * @param {boolean} [options.ignoreAdd=false]
642
+ * @param {boolean} [options.ignoreUpdate=false]
643
+ * @param {boolean} [options.ignoreDelete=false]
644
+ *
645
+ * @param {boolean} [options.ignorePrivate=true]
646
+ * Ignore properties that start with an underscore e.g. _id or _updatedAt
647
+ *
648
+ * @param {boolean} [options.deleteValue=null]
649
+ *
650
+ * @returns {array}
651
+ * List of changes between the object before and object after
652
+ */
653
+ export function objectDiff(objBefore, objAfter, options = {}, _recursion) {
654
+ const changes = [];
655
+
656
+ const ignoreAdd = undefined === options.ignoreAdd ? false : options.ignoreAdd;
657
+
658
+ const ignoreUpdate =
659
+ undefined === options.ignoreUpdate ? false : options.ignoreUpdate;
660
+
661
+ const ignoreDelete =
662
+ undefined === options.ignoreDelete ? false : options.ignoreDelete;
663
+
664
+ const ignorePrivate =
665
+ undefined === options.ignorePrivate ? true : options.ignorePrivate;
666
+
667
+ let deleteValue = null;
668
+
669
+ if ('deletevalue' in options) {
670
+ // Might be [undefined]
671
+ deleteValue = options.deleteValue;
672
+ }
673
+
674
+ objBefore = objBefore || {};
675
+
676
+ for (const key in objAfter) {
677
+ if (ignorePrivate && key.startsWith('_')) {
678
+ continue;
679
+ }
680
+
681
+ const newValue = objAfter[key];
682
+
683
+ if (deleteValue !== newValue) {
684
+ const previousValue = objBefore[key];
685
+
686
+ if (newValue === previousValue) {
687
+ // No change
688
+ continue;
689
+ }
690
+
691
+ if (previousValue instanceof Object && newValue instanceof Object) {
692
+ // TODO: _recursion
693
+
694
+ const diff = objectDiff(newValue, previousValue, options, _recursion);
695
+
696
+ if (0 === diff.length) {
697
+ // No change
698
+ continue;
699
+ }
700
+ }
701
+
702
+ if (undefined !== previousValue) {
703
+ if (!ignoreUpdate) {
704
+ // update property value
705
+ changes.push({ path: key, set: newValue });
706
+ }
707
+ } else if (!ignoreAdd) {
708
+ // add property
709
+ changes.push({ path: key, set: newValue });
710
+ }
711
+ } else if (!ignoreDelete) {
712
+ // newValue === deleteValue && ignoreDelete=true
713
+ changes.push({ path: key, unset: 1 });
714
+ }
715
+ } // end for
716
+
717
+ return changes;
718
+ }
719
+
720
+ // -----------------------------------------------------------------------------
721
+
722
+ /**
723
+ * Applies a list of differences to the input object
724
+ * - A list of changes can be generated by e.g. objectDiff
725
+ *
726
+ * @param {object} obj
727
+ * @param {object[]} changes
728
+ *
729
+ * @param {object} options
730
+ * @param {boolean} [options.ignoreAdd=false]
731
+ * @param {boolean} [options.ignoreUpdate=false]
732
+ * @param {boolean} [options.ignoreDelete=false]
733
+ *
734
+ * @param {boolean} [options.ignorePrivate=true]
735
+ * Ignore properties that start with an underscore e.g. _id or _updatedAt
736
+ */
737
+ export function patchObject(obj, changes, options = {}) {
738
+ expect.object(obj);
739
+ expect.array(changes);
740
+
741
+ const ignoreAdd = undefined === options.ignoreAdd ? false : options.ignoreAdd;
742
+
743
+ const ignoreUpdate =
744
+ undefined === options.ignoreUpdate ? false : options.ignoreUpdate;
745
+
746
+ const ignoreDelete =
747
+ undefined === options.ignoreDelete ? false : options.ignoreDelete;
748
+
749
+ const ignorePrivate =
750
+ undefined === options.ignorePrivate ? true : options.ignorePrivate;
751
+
752
+ for (let j = 0, n = changes.length; j < n; j = j + 1) {
753
+ const change = changes[j];
754
+
755
+ const path = change.path;
756
+
757
+ // FIXME: recursion
758
+
759
+ if (ignorePrivate && path.startsWith('_')) {
760
+ continue;
761
+ }
762
+
763
+ if ('unset' in change) {
764
+ if (ignoreDelete) {
765
+ continue;
766
+ }
767
+
768
+ // console.log( "DELETE", change );
769
+ objectSet(obj, path, undefined); // undefined deletes property
770
+ continue;
771
+ }
772
+
773
+ const newValue = change.set;
774
+
775
+ if (undefined === newValue) {
776
+ //logError("Invalid [change]", ignoreDelete, change);
777
+ throw new Error(`Cannot set value [${path}=undefined]`);
778
+ }
779
+
780
+ if (ignoreAdd && Object._get(obj, path) === undefined) {
781
+ // Ignore add
782
+ continue;
783
+ } else if (ignoreUpdate && objectGet(obj, path) !== undefined) {
784
+ // Ignore update
785
+ continue;
786
+ }
787
+
788
+ // Set new value
789
+ objectSet(obj, path, newValue);
790
+ } // end for
791
+ }
792
+
793
+ // -----------------------------------------------------------------------------
794
+
795
+ /**
796
+ * Extend the target object with methods and properties from the source
797
+ * property object
798
+ * - The target object will be extended by inserting the source property
799
+ * object into it's property chain
800
+
801
+ * - If the current target's prototype is not the same as the source
802
+ * prototype, the source prototype will be cloned
803
+ *
804
+ * @param {object} target - Target object
805
+ * @param {object} source
806
+ * object to append to the target's prototype chain. The object and it's
807
+ * prototype objects are cloned first
808
+ */
809
+ export function extend(target, source) {
810
+ expect.objectNoFunction(target);
811
+
812
+ if (Object.isFrozen(target)) {
813
+ throw new Error('Invalid parameter [target] (object is immutable)');
814
+ }
815
+
816
+ expect.objectNoFunction(source);
817
+
818
+ // let sourceProto = source.prototype;
819
+
820
+ let targetProto = Object.getPrototypeOf(target);
821
+
822
+ if (targetProto === Object.prototype || Object.isFrozen(targetProto)) {
823
+ // FIXME: || Object.isFrozen(targetProto) should not be necessary!
824
+
825
+ targetProto = target;
826
+ }
827
+
828
+ {
829
+ let obj = source;
830
+
831
+ while (obj && obj !== Object.prototype) {
832
+ const next = Object.getPrototypeOf(obj);
833
+
834
+ copyOwnProperties(obj, targetProto);
835
+
836
+ obj = next;
837
+ }
838
+ }
839
+
840
+ return;
841
+ }
842
+
843
+ // -----------------------------------------------------------------------------
844
+
845
+ /**
846
+ * Get a list of property names of the specified object
847
+ *
848
+ * @param {object} obj
849
+ *
850
+ * @returns {string[]} List of property names
851
+ */
852
+ export function getPrototypeNames(obj) {
853
+ expect.object(obj);
854
+
855
+ let proto = obj.prototype || obj;
856
+
857
+ const names = [];
858
+
859
+ while (proto) {
860
+ // console.log( proto );
861
+
862
+ names.push(proto.constructor.name);
863
+
864
+ proto = Object.getPrototypeOf(proto);
865
+ }
866
+
867
+ return names;
868
+ }
869
+
870
+ // -----------------------------------------------------------------------------
871
+
872
+ /**
873
+ * Get a tree of values from an object
874
+ * - Can returns default values if one or multiple values were not found
875
+ *
876
+ * @param {object} obj - Object to get the value from
877
+ * @param {object} tree
878
+ * Tree that contains the object paths to get.
879
+ *
880
+ * e.g. { path: 1 }
881
+ * { some: { path: { to: 1 }, otherPath: { to: 1 } } }
882
+ * { "some.path.to": 1, "some.otherPath.to": 1 }
883
+ * { someArray.0.name: 1 }
884
+ *
885
+ * @param {object} [options]
886
+ * @param {boolean} [options.shallowLeaves=false]
887
+ * If true, when extracted leaf values are objects, they are filtered to
888
+ * contain only primitive properties. Nested objects and arrays within
889
+ * the leaves are removed.
890
+ *
891
+ * Example: { profile: { name: "John", settings: {...} } }
892
+ * becomes: { profile: { name: "John" } }
893
+ *
894
+ * @return {object}
895
+ * nested object with the values that were found or defaultValues
896
+ */
897
+ export function getTree(obj, tree, options) {
898
+ expect.object(obj);
899
+ expect.object(tree);
900
+
901
+ let shallowLeaves = false;
902
+
903
+ if (options instanceof Object && options.shallowLeaves) {
904
+ shallowLeaves = true;
905
+ }
906
+
907
+ const it = iterateObjectPaths(tree, { walkArrays: true });
908
+
909
+ const result = {};
910
+
911
+ for (let arrPath of it) {
912
+ // console.log( { arrPath } );
913
+
914
+ if (1 === arrPath.length && arrPath[0].includes(PATH_SEPARATOR)) {
915
+ // Convert "short path syntax" to array path
916
+ arrPath = arrPath[0].split(PATH_SEPARATOR);
917
+ }
918
+
919
+ // -- Get value from object at current path
920
+
921
+ const leaveValue = objectGet(obj, arrPath);
922
+
923
+ // -- Set value in result object at current path
924
+
925
+ if (!shallowLeaves || !(leaveValue instanceof Object)) {
926
+ // option: shallowLeaves=false OR value is not an object
927
+ // -> no need to convert leaves to shallow objects
928
+ objectSet(result, arrPath, leaveValue);
929
+ } else {
930
+ // Set shallow leave value instead of nested object
931
+
932
+ const shallowLeaveValue = exportNotNested(leaveValue);
933
+ objectSet(result, arrPath, shallowLeaveValue);
934
+ }
935
+ } // end for
936
+
937
+ return result;
938
+ }
939
+
940
+ // -----------------------------------------------------------------------------
941
+
942
+ /**
943
+ * Deep clone an object or any kind of other variable
944
+ *
945
+ * @param {any} objectToBeCloned - Variable to clone
946
+ *
947
+ * @returns {any} cloned output
948
+ */
949
+ export function clone(objectToBeCloned, _seenObjects) {
950
+ if (!_seenObjects) {
951
+ try {
952
+ return structuredClone(objectToBeCloned);
953
+ // eslint-disable-next-line no-unused-vars
954
+ } catch (error) {
955
+ // Fall back to custom implementation for unsupported types
956
+ }
957
+ }
958
+
959
+ // const startTime = Date.now();
960
+
961
+ // -- Return references for all variables that are not objects
962
+
963
+ if (!(objectToBeCloned instanceof Object)) {
964
+ return objectToBeCloned;
965
+ }
966
+
967
+ // --- Check if variable has already been cloned before
968
+
969
+ if (!_seenObjects) {
970
+ _seenObjects = { originals: [], clones: [] };
971
+ } else {
972
+ const originals = _seenObjects.originals;
973
+
974
+ if (originals.length > 0) {
975
+ const foundIndex = originals.indexOf(objectToBeCloned);
976
+
977
+ if (-1 !== foundIndex) {
978
+ //console.log("(recursion) return
979
+ //from [_seenObjects]", _seenObjects.clones, foundIndex);
980
+ return _seenObjects.clones[foundIndex];
981
+ }
982
+ }
983
+ }
984
+
985
+ // -- Handle array (like) objects
986
+
987
+ const typeString = object_to_string.call(objectToBeCloned);
988
+
989
+ if (Array.isArray(objectToBeCloned) || '[object Arguments]' === typeString) {
990
+ const objectClone = [];
991
+
992
+ for (let j = 0, n = objectToBeCloned.length; j < n; j = j + 1) {
993
+ objectClone[j] = clone(objectToBeCloned[j], _seenObjects);
994
+ }
995
+
996
+ _seenObjects.originals.push(objectToBeCloned);
997
+ _seenObjects.clones.push(objectClone);
998
+
999
+ return objectClone;
1000
+ }
1001
+
1002
+ // -- Handle not clonable objects
1003
+
1004
+ if ('[object Object]' !== typeString || objectToBeCloned instanceof Error) {
1005
+ // Functions, Browser objects, ...
1006
+ // - Not clonable -> return reference
1007
+ // - No need to add to _seenObjects
1008
+ return objectToBeCloned;
1009
+ }
1010
+
1011
+ // -- Handle special objects
1012
+ {
1013
+ // Filter out special objects.
1014
+ const Constructor = objectToBeCloned.constructor;
1015
+
1016
+ let objectClone;
1017
+
1018
+ switch (Constructor) {
1019
+ case RegExp:
1020
+ objectClone = new Constructor(objectToBeCloned);
1021
+ break;
1022
+
1023
+ case Date:
1024
+ objectClone = new Constructor(objectToBeCloned.getTime());
1025
+ break;
1026
+
1027
+ // TODO: other special objects ...
1028
+ }
1029
+
1030
+ if (objectClone) {
1031
+ _seenObjects.originals.push(objectToBeCloned);
1032
+ _seenObjects.clones.push(objectClone);
1033
+
1034
+ return objectClone;
1035
+ }
1036
+
1037
+ if (objectToBeCloned.hkDoNotClone) {
1038
+ // Not clonable flag was set -> return reference
1039
+ // TODO: Other objects that should not be cloned?
1040
+ return objectToBeCloned;
1041
+ }
1042
+ }
1043
+
1044
+ // -- Create new object and clone properties
1045
+
1046
+ // objectClone = new Constructor();
1047
+ // const prototypeClone = Object.create(null);
1048
+
1049
+ const prototypeClone = {};
1050
+ const objectClone = Object.create(prototypeClone);
1051
+
1052
+ // Already push object to _seenObjects
1053
+ // (objectClone will still change as properties are being cloned)
1054
+ _seenObjects.originals.push(objectToBeCloned);
1055
+ _seenObjects.clones.push(objectClone);
1056
+
1057
+ for (const prop in objectToBeCloned) {
1058
+ if (has_own_property.call(objectToBeCloned, prop)) {
1059
+ // Own property -> clone into object
1060
+ objectClone[prop] = clone(objectToBeCloned[prop], _seenObjects);
1061
+ } else {
1062
+ // Inherited property -> clone into prototype
1063
+
1064
+ // @warning
1065
+ // known issue: all inherited properties are copied into the
1066
+ // same prototype object!
1067
+
1068
+ prototypeClone[prop] = clone(objectToBeCloned[prop], _seenObjects);
1069
+ }
1070
+ }
1071
+
1072
+ return objectClone;
1073
+ }
1074
+
1075
+ // -----------------------------------------------------------------------------
1076
+
1077
+ /**
1078
+ * Set a read only property in an object
1079
+ *
1080
+ * @param {object} obj - Object to set the read only property in
1081
+ * @param {string} propertyName - Name of the property to set
1082
+ * @param {any} value - Value to set
1083
+ */
1084
+ export function setReadOnlyProperty(obj, propertyName, value) {
1085
+ expect.object(obj);
1086
+
1087
+ expect.string(propertyName);
1088
+
1089
+ // expect.defined(value);
1090
+
1091
+ Object.defineProperty(obj, propertyName, {
1092
+ value,
1093
+ writable: false,
1094
+ enumerable: true
1095
+ });
1096
+ }
1097
+
1098
+ // -----------------------------------------------------------------------------
1099
+
1100
+ // -----------------------------------------------------------------------------
1101
+
1102
+ /**
1103
+ * Update an object
1104
+ * - Sets the path-value pairs from the updateData in the object
1105
+ * - Existing values will be overwritten
1106
+ * - Existing intermediate values (objects, arrays) will be overwritten too
1107
+ * (if updateData is an object, not an iterable)
1108
+ *
1109
+ * @param {object} [obj] - Input object
1110
+ *
1111
+ * @param {object|Iterable} updateData - Data to update
1112
+ *
1113
+ * @param {Object} [options]
1114
+ * @param {boolean} [options.replaceArrays=false]
1115
+ *
1116
+ * Note that if using path-value pairs, the order of the pairs is relevant:
1117
+ * {
1118
+ * "some": {},
1119
+ * "some.path": {},
1120
+ * "some.path.to": 2,
1121
+ * }
1122
+ *
1123
+ * @returns {object} updated object
1124
+ */
1125
+ export function updateObject(obj = null, updateData = null, options) {
1126
+ // -- Check parameter [obj]
1127
+
1128
+ expect.object(obj);
1129
+
1130
+ expect.object(updateData);
1131
+
1132
+ // -- Update cloned object
1133
+
1134
+ let pathValuePairs;
1135
+
1136
+ if (!is.iterable(updateData)) {
1137
+ // Convert updateData to path-value pairs (iterable)
1138
+
1139
+ const walkArrays = options && options.replaceArrays ? true : false;
1140
+
1141
+ pathValuePairs = iterateObjectEntries(updateData, {
1142
+ expandPathKeys: true,
1143
+ outputIntermediateNodes: true,
1144
+ walkArrays
1145
+ });
1146
+
1147
+ // pathValuePairs = Array.from( pathValuePairs );
1148
+ // console.log( "CHECK", { updateData, pathValuePairs } );
1149
+ } else {
1150
+ // Iterable -> assume iterable of path-value pairs
1151
+ pathValuePairs = updateData;
1152
+ }
1153
+
1154
+ for (const [arrPath, value] of pathValuePairs) {
1155
+ // console.log( "updateObject:set", arrPath, value );
1156
+ objectSet(obj, arrPath, value);
1157
+ }
1158
+
1159
+ return obj;
1160
+ }
1161
+
1162
+ // -----------------------------------------------------------------------------
1163
+
1164
+ /**
1165
+ * Copy own properties from an object to another object if they do not
1166
+ * exist yet.
1167
+ *
1168
+ * @param {object} from - Object ot copy properties from
1169
+ * @param {object} to - Object to copy properties to
1170
+ */
1171
+ export function copyOwnProperties(from, to) {
1172
+ const propertyNames = Object.getOwnPropertyNames(from);
1173
+
1174
+ const nProperties = propertyNames.length;
1175
+
1176
+ if (!nProperties) {
1177
+ return;
1178
+ }
1179
+
1180
+ const firstIsConstructor = 'constructor' === propertyNames[0] ? true : false;
1181
+
1182
+ if (1 === nProperties && firstIsConstructor) {
1183
+ return;
1184
+ }
1185
+
1186
+ const startAt = firstIsConstructor ? 1 : 0;
1187
+
1188
+ // console.log("propertyNames", from, propertyNames, startAt);
1189
+
1190
+ for (let j = startAt; j < nProperties; j = j + 1) {
1191
+ const key = propertyNames[j];
1192
+
1193
+ const descriptor = Object.getOwnPropertyDescriptor(from, key);
1194
+
1195
+ const targetDescriptor = Object.getOwnPropertyDescriptor(to, key);
1196
+
1197
+ // Not needed, we copy an instance
1198
+ // descriptor.value = clone( descriptor.value );
1199
+
1200
+ if (!targetDescriptor) {
1201
+ // Property does not yet exist
1202
+ Object.defineProperty(to, key, descriptor);
1203
+ }
1204
+ } // end for
1205
+
1206
+ // >>> FIXME? TODO? copy Symbols too? <<<
1207
+ }
1208
+
1209
+ // -----------------------------------------------------------------------------
1210
+
1211
+ /**
1212
+ * Convert string with dot separated values to a list of values
1213
+ * - Accepts that the supplied path is already an array path
1214
+ *
1215
+ * @param {string|string[]} path
1216
+ *
1217
+ * @returns {string[]} list of path values
1218
+ */
1219
+ export function ensureArrayPath(path) {
1220
+ if (typeof path === 'string') {
1221
+ return path.split(PATH_SEPARATOR);
1222
+ } else if (Array.isArray(path)) {
1223
+ // Nothing to do
1224
+ return path;
1225
+ } else {
1226
+ throw new Error(
1227
+ 'Missing or invalid parameter [path] (expected string or array)'
1228
+ );
1229
+ }
1230
+ }
1231
+
1232
+ /* ----------------------------------------------------- Internal methods */
1233
+
1234
+ // -----------------------------------------------------------------------------
1235
+
1236
+ /**
1237
+ * Create all parent objects on the object path if they do not yet exist yet
1238
+ * - This method will throw an exception if there is a non-object node in
1239
+ * the path
1240
+ *
1241
+ * @param {object} obj
1242
+ * Object to create the parent objects in
1243
+ *
1244
+ * @param {string[]} arrPath
1245
+ * The path that specified which parent objects to create
1246
+ *
1247
+ * @returns {object} the input object with the created object properties
1248
+ */
1249
+ function _ensureParent(obj, arrPath) {
1250
+ // console.log("_ensureParent (1)", { obj, arrPath } );
1251
+
1252
+ let current = obj;
1253
+ let prev = current;
1254
+
1255
+ for (let j = 0, n_1 = arrPath.length - 1; j < n_1; j = j + 1) {
1256
+ const key = arrPath[j];
1257
+
1258
+ current = current[key];
1259
+
1260
+ if (current === undefined || current === null) {
1261
+ current = prev[key] = {};
1262
+ prev = current;
1263
+ continue;
1264
+ }
1265
+
1266
+ const nextKey = arrPath[j + 1];
1267
+
1268
+ // Check
1269
+ // Check if current is an object
1270
+ // If current is an array, check if the nextKey can be set on a array
1271
+
1272
+ if (current instanceof Object) {
1273
+ if (Array.isArray(current) && j < n_1) {
1274
+ const nextKeyAsInt = parseInt(nextKey, 10);
1275
+
1276
+ if (Number.isNaN(nextKeyAsInt)) {
1277
+ // console.log("CHECK", { obj, arrPath, j, current, nextKey } );
1278
+ throw new Error(
1279
+ `Cannot set property [${nextKey}] ` + 'on data node of type [Array]'
1280
+ );
1281
+ }
1282
+ }
1283
+ } else {
1284
+ // console.log( { current, prev, key, arrPath, j } );
1285
+
1286
+ throw new Error(
1287
+ `Cannot set property [${nextKey}] from ` +
1288
+ `path [${display_array_path(arrPath)}] on data node that is not ` +
1289
+ 'an object or an array'
1290
+ );
1291
+ }
1292
+
1293
+ prev = current;
1294
+ } // end for
1295
+
1296
+ return current;
1297
+ }
1298
+
1299
+ // -----------------------------------------------------------------------------
1300
+
1301
+ /**
1302
+ * Get parent object at the specified path
1303
+ *
1304
+ * @param {object} obj - Object to work in
1305
+ * @param {string[]} arrPath - Path to get the parent object for
1306
+ *
1307
+ * @returns {object|array|null} parent object or null if not found
1308
+ */
1309
+ function _getParent(obj, arrPath) {
1310
+ let current = obj;
1311
+
1312
+ for (let j = 0, n_1 = arrPath.length - 1; j < n_1; j = j + 1) {
1313
+ let key = arrPath[j];
1314
+
1315
+ current = current[key];
1316
+
1317
+ if (typeof current === 'undefined') {
1318
+ return null;
1319
+ }
1320
+
1321
+ if (current instanceof Object) {
1322
+ if (Array.isArray(current) && j < n_1 - 1) {
1323
+ // node is an array
1324
+ // -> use next part of the array path as (numerical) array index
1325
+
1326
+ key = arrPath[j + 1];
1327
+ const keyAsInt = parseInt(key, 10);
1328
+
1329
+ if (Number.isNaN(keyAsInt)) {
1330
+ throw new Error(
1331
+ `Cannot get property [${display_array_path(arrPath, j)}]` +
1332
+ 'from data node of type [Array]'
1333
+ );
1334
+ }
1335
+ }
1336
+ } else {
1337
+ throw new Error(
1338
+ `Cannot get property [${display_array_path(arrPath, j)}]` +
1339
+ 'from a data node that is not an object or an array'
1340
+ );
1341
+ }
1342
+ } // end for
1343
+
1344
+ return current;
1345
+ }