dyo-tools 0.3.0 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (208) hide show
  1. package/.c8rc.json +4 -4
  2. package/.eslintignore +1 -1
  3. package/.eslintrc.json +47 -47
  4. package/Makefile +34 -34
  5. package/dist/constants.d.ts +1 -0
  6. package/dist/constants.d.ts.map +1 -0
  7. package/dist/constants.js +24 -20
  8. package/dist/constants.js.map +1 -1
  9. package/dist/core/DTAction.d.ts +6 -4
  10. package/dist/core/DTAction.d.ts.map +1 -0
  11. package/dist/core/DTAction.js +3 -6
  12. package/dist/core/DTAction.js.map +1 -1
  13. package/dist/core/DTBunch.d.ts +8 -5
  14. package/dist/core/DTBunch.d.ts.map +1 -0
  15. package/dist/core/DTBunch.js +54 -20
  16. package/dist/core/DTBunch.js.map +1 -1
  17. package/dist/core/DTComponent.d.ts +13 -10
  18. package/dist/core/DTComponent.d.ts.map +1 -0
  19. package/dist/core/DTComponent.js +23 -10
  20. package/dist/core/DTComponent.js.map +1 -1
  21. package/dist/core/DTComponentPhysical.d.ts +11 -7
  22. package/dist/core/DTComponentPhysical.d.ts.map +1 -0
  23. package/dist/core/DTComponentPhysical.js +21 -6
  24. package/dist/core/DTComponentPhysical.js.map +1 -1
  25. package/dist/core/DTComponentWithMeta.d.ts +6 -3
  26. package/dist/core/DTComponentWithMeta.d.ts.map +1 -0
  27. package/dist/core/DTComponentWithMeta.js +21 -7
  28. package/dist/core/DTComponentWithMeta.js.map +1 -1
  29. package/dist/core/DTElement.d.ts +10 -8
  30. package/dist/core/DTElement.d.ts.map +1 -0
  31. package/dist/core/DTElement.js +8 -9
  32. package/dist/core/DTElement.js.map +1 -1
  33. package/dist/core/DTError.d.ts +8 -7
  34. package/dist/core/DTError.d.ts.map +1 -0
  35. package/dist/core/DTError.js +1 -5
  36. package/dist/core/DTError.js.map +1 -1
  37. package/dist/core/DTManager.d.ts +17 -14
  38. package/dist/core/DTManager.d.ts.map +1 -0
  39. package/dist/core/DTManager.js +84 -26
  40. package/dist/core/DTManager.js.map +1 -1
  41. package/dist/core/DTMaster.d.ts +19 -16
  42. package/dist/core/DTMaster.d.ts.map +1 -0
  43. package/dist/core/DTMaster.js +48 -31
  44. package/dist/core/DTMaster.js.map +1 -1
  45. package/dist/core/DTModule.d.ts +8 -5
  46. package/dist/core/DTModule.d.ts.map +1 -0
  47. package/dist/core/DTModule.js +6 -6
  48. package/dist/core/DTModule.js.map +1 -1
  49. package/dist/index.d.ts +1 -0
  50. package/dist/index.d.ts.map +1 -0
  51. package/dist/index.js +12 -28
  52. package/dist/index.js.map +1 -1
  53. package/dist/libs/DYOFinder.d.ts +1 -0
  54. package/dist/libs/DYOFinder.d.ts.map +1 -0
  55. package/dist/libs/DYOFinder.js +10 -14
  56. package/dist/libs/DYOFinder.js.map +1 -1
  57. package/dist/libs/dix/DIXModule.module.d.ts +8 -0
  58. package/dist/libs/dix/DIXModule.module.d.ts.map +1 -0
  59. package/dist/libs/dix/DIXModule.module.js +73 -0
  60. package/dist/libs/player/DTPlayer.element.d.ts +3 -2
  61. package/dist/libs/player/DTPlayer.element.d.ts.map +1 -0
  62. package/dist/libs/player/DTPlayer.element.js +2 -6
  63. package/dist/libs/player/DTPlayer.element.js.map +1 -1
  64. package/dist/libs/player/DTPlayer.manager.d.ts +8 -7
  65. package/dist/libs/player/DTPlayer.manager.d.ts.map +1 -0
  66. package/dist/libs/player/DTPlayer.manager.js +13 -20
  67. package/dist/libs/player/DTPlayer.manager.js.map +1 -1
  68. package/dist/tsconfig.dev.tsbuildinfo +1 -0
  69. package/dist/tsconfig.tsbuildinfo +1 -1
  70. package/dist/types/core.d.ts +40 -12
  71. package/dist/types/core.d.ts.map +1 -0
  72. package/dist/types/core.js +2 -6
  73. package/dist/types/core.js.map +1 -1
  74. package/dist/types/index.d.ts +1 -0
  75. package/dist/types/index.d.ts.map +1 -0
  76. package/dist/types/index.js +2 -19
  77. package/dist/types/index.js.map +1 -1
  78. package/dist/types/player.d.ts +1 -1
  79. package/dist/types/player.d.ts.map +1 -0
  80. package/dist/types/player.js +1 -3
  81. package/docs/assets/main.js +59 -59
  82. package/docs/assets/style.css +1414 -1414
  83. package/integration/data/components/DTHero.ts +42 -0
  84. package/integration/data/components/DTHeroManager.ts +11 -0
  85. package/integration/data/components/DTHeroPlayZone.ts +6 -0
  86. package/integration/data/components/DTHeroPlayerHand.ts +11 -0
  87. package/integration/data/components/index.ts +5 -0
  88. package/integration/data/in/heroIn.helper.ts +8 -0
  89. package/integration/data/in/playerIn.helper.ts +13 -0
  90. package/integration/data/out/heroOut.helper.ts +48 -0
  91. package/integration/endings/synchronisation.ending.ts +25 -0
  92. package/integration/scenes/drawCard.scene.ts +31 -0
  93. package/integration/scenes/empty.scene.ts +6 -0
  94. package/integration/scenes/playCard.scene.ts +23 -0
  95. package/integration/scenes/playerLeave.scene.ts +33 -0
  96. package/integration/stages/baseDix.stage.ts +137 -0
  97. package/integration/stages/syncDix.stage.ts +36 -0
  98. package/integration/tests/scenario1.spec.ts +55 -0
  99. package/integration/types/index.ts +24 -0
  100. package/jest-integration.config.ts +25 -0
  101. package/jest.config.ts +26 -0
  102. package/package.json +31 -19
  103. package/src/constants.ts +87 -85
  104. package/src/core/DTAction.ts +54 -52
  105. package/src/core/DTBunch.ts +531 -467
  106. package/src/core/DTComponent.ts +258 -225
  107. package/src/core/DTComponentPhysical.ts +88 -53
  108. package/src/core/DTComponentWithMeta.ts +98 -65
  109. package/src/core/DTElement.ts +111 -102
  110. package/src/core/DTError.ts +78 -78
  111. package/src/core/DTManager.ts +555 -465
  112. package/src/core/DTMaster.ts +366 -318
  113. package/src/core/DTModule.ts +96 -90
  114. package/src/libs/dix/DIXModule.module.ts +98 -0
  115. package/src/libs/player/DTPlayer.element.ts +9 -9
  116. package/src/libs/player/DTPlayer.manager.ts +70 -84
  117. package/src/types/core.ts +204 -169
  118. package/src/types/player.ts +5 -6
  119. package/test/core/DTAction.double.ts +12 -28
  120. package/test/core/DTAction.spec.ts +8 -16
  121. package/test/core/DTBunch.double.ts +49 -135
  122. package/test/core/DTBunch.spec.ts +163 -238
  123. package/test/core/DTComponent.double.ts +17 -2
  124. package/test/core/DTComponent.spec.ts +6 -4
  125. package/test/core/DTComponentPhysical.double.ts +29 -43
  126. package/test/core/DTComponentPhysical.spec.ts +22 -19
  127. package/test/core/DTComponentWithMeta.double.ts +38 -31
  128. package/test/core/DTComponentWithMeta.spec.ts +23 -18
  129. package/test/core/DTElement.double.ts +32 -53
  130. package/test/core/DTElement.spec.ts +15 -38
  131. package/test/core/DTError.double.ts +18 -53
  132. package/test/core/DTError.spec.ts +21 -32
  133. package/test/core/DTManager.double.ts +74 -141
  134. package/test/core/DTManager.spec.ts +289 -380
  135. package/test/core/DTMaster.double.ts +56 -80
  136. package/test/core/DTMaster.spec.ts +185 -232
  137. package/test/core/DTModule.double.ts +12 -25
  138. package/test/core/DTModule.spec.ts +14 -28
  139. package/test/core/copy.spec.ts +9 -30
  140. package/tsconfig.dev.json +5 -8
  141. package/tsconfig.json +5 -8
  142. package/cucumber-report.html +0 -48
  143. package/docs/assets/navigation.js +0 -1
  144. package/docs/classes/core_DTAction.DYOToolsAction.html +0 -89
  145. package/docs/classes/core_DTBunch.DYOToolsBunch.html +0 -254
  146. package/docs/classes/core_DTComponent.DYOToolsComponent.html +0 -76
  147. package/docs/classes/core_DTComponentPhysical.DYOToolsComponentPhysical.html +0 -110
  148. package/docs/classes/core_DTComponentWithMeta.DYOToolsComponentWithMeta.html +0 -96
  149. package/docs/classes/core_DTElement.DYOToolsElement.html +0 -135
  150. package/docs/classes/core_DTError.DYOToolsError.html +0 -37
  151. package/docs/classes/core_DTManager.DYOToolsManager.html +0 -237
  152. package/docs/classes/core_DTMaster.DYOToolsMaster.html +0 -150
  153. package/docs/classes/core_DTModule.DYOToolsModule.html +0 -92
  154. package/docs/classes/libs_DYOFinder.DYOFinder.html +0 -34
  155. package/docs/classes/libs_player_DTPlayer_element.DYOToolsPlayer.html +0 -134
  156. package/docs/classes/libs_player_DTPlayer_manager.DYOToolsPlayerManager.html +0 -243
  157. package/docs/enums/types_core.FilterOperatorType.html +0 -10
  158. package/docs/hierarchy.html +0 -1
  159. package/docs/interfaces/types_core.DTBunchFilters.html +0 -6
  160. package/docs/interfaces/types_core.DTBunchOptions.html +0 -19
  161. package/docs/interfaces/types_core.DTBunchToObject.html +0 -7
  162. package/docs/interfaces/types_core.DTComponentOptions.html +0 -5
  163. package/docs/interfaces/types_core.DTComponentToObject.html +0 -4
  164. package/docs/interfaces/types_core.DTElementToObject.html +0 -7
  165. package/docs/interfaces/types_core.DTManagerFilters.html +0 -6
  166. package/docs/interfaces/types_core.DTManagerOptions.html +0 -8
  167. package/docs/interfaces/types_core.DTManagerToObject.html +0 -5
  168. package/docs/interfaces/types_core.DTMasterToObject.html +0 -8
  169. package/docs/interfaces/types_core.DTModuleToObject.html +0 -6
  170. package/docs/interfaces/types_core.DYOFinderConfigurationPropDefault.html +0 -4
  171. package/docs/interfaces/types_core.DYOFinderConfigurationPropObjectSearch.html +0 -4
  172. package/docs/interfaces/types_core.DYOFinderFilterOperatorAdvanced.html +0 -5
  173. package/docs/interfaces/types_core.DYOFinderFilterOperatorBase.html +0 -5
  174. package/docs/interfaces/types_player.DTPlayerManagerSimpleConfiguration.html +0 -3
  175. package/docs/modules/constants.html +0 -6
  176. package/docs/modules/core_DTAction.html +0 -2
  177. package/docs/modules/core_DTBunch.html +0 -2
  178. package/docs/modules/core_DTComponent.html +0 -2
  179. package/docs/modules/core_DTComponentPhysical.html +0 -2
  180. package/docs/modules/core_DTComponentWithMeta.html +0 -2
  181. package/docs/modules/core_DTElement.html +0 -2
  182. package/docs/modules/core_DTError.html +0 -2
  183. package/docs/modules/core_DTManager.html +0 -2
  184. package/docs/modules/core_DTMaster.html +0 -2
  185. package/docs/modules/core_DTModule.html +0 -2
  186. package/docs/modules/libs_DYOFinder.html +0 -2
  187. package/docs/modules/libs_player_DTPlayer_element.html +0 -2
  188. package/docs/modules/libs_player_DTPlayer_manager.html +0 -2
  189. package/docs/modules/types.html +0 -29
  190. package/docs/modules/types_core.html +0 -28
  191. package/docs/modules/types_player.html +0 -2
  192. package/docs/types/types_core.DTAcceptedMetaData.html +0 -2
  193. package/docs/types/types_core.DTManagerItemType.html +0 -1
  194. package/docs/types/types_core.DTManagerItemsType.html +0 -2
  195. package/docs/types/types_core.DYOFinderComponentType.html +0 -1
  196. package/docs/types/types_core.DYOFinderConfiguration.html +0 -2
  197. package/docs/types/types_core.DYOFinderConfigurationProp.html +0 -1
  198. package/docs/types/types_core.DYOFinderFilterOperator.html +0 -1
  199. package/docs/types/types_core.DYOFinderFilterOperatorArgument.html +0 -1
  200. package/docs/types/types_core.DYOFinderFilters.html +0 -1
  201. package/docs/types/types_core.StandardPrimitiveType.html +0 -2
  202. package/docs/types/types_core.StandardPrimitiveTypeWithArray.html +0 -1
  203. package/docs/variables/constants.bunchDefaultOptions.html +0 -2
  204. package/docs/variables/constants.componentBunchDefaultFinderConfiguration.html +0 -1
  205. package/docs/variables/constants.componentManagerDefaultFinderConfiguration.html +0 -1
  206. package/docs/variables/constants.componentPhysicalDefaultFinderConfiguration.html +0 -1
  207. package/docs/variables/constants.managerDefaultOptions.html +0 -2
  208. package/jest.config.js +0 -6
@@ -1,467 +1,531 @@
1
- import DYOToolsElement from './DTElement';
2
- import DYOToolsManager from './DTManager';
3
- import {
4
- DTAcceptedMetaData, DTBunchFilters, DTBunchOptions, DTBunchToObject, DYOFinderConfiguration,
5
- } from '../types';
6
- import DYOToolsError from './DTError';
7
- import DYOToolsComponentPhysical from './DTComponentPhysical';
8
- import { bunchDefaultOptions as defaultOptions, componentBunchDefaultFinderConfiguration } from '../constants';
9
- import DYOFinder from '../libs/DYOFinder';
10
-
11
- export default class DYOToolsBunch<
12
- IBunchItem extends DYOToolsElement<DTAcceptedMetaData> = DYOToolsElement<DTAcceptedMetaData>,
13
- IComponentMeta extends DTAcceptedMetaData = DTAcceptedMetaData,
14
- > extends DYOToolsComponentPhysical<IComponentMeta, DTBunchOptions> {
15
- /**
16
- * Defining component type to "bunch".
17
- */
18
- protected _componentType = 'bunch';
19
-
20
- /**
21
- * Ordered Array of DTElement instance managed by the bunch.
22
- */
23
- protected _items: IBunchItem[];
24
-
25
- /**
26
- * Current DYOFinder instance.
27
- *
28
- * This instance offers advanced methods to manipulate items, like searching.
29
- */
30
- protected _finder: DYOFinder;
31
-
32
- /**
33
- * Applying the parent constructor, and execute following process steps :
34
- * * Add **items** to the bunch instance (using adding specifications).
35
- * * Merge specific **options** configuration with default in _options.
36
- * * Initialize *DYOFinder* with **getFinderConfiguration** method.
37
- *
38
- * @see [addAtIndex](#addAtIndex) method for adding specifications.
39
- * @param key
40
- * @param items Array of DTElement instance to add. Default empty array.
41
- * @param options Specific options configuration for the instance. Default empty object.
42
- */
43
- constructor(key?: string, items: IBunchItem[] = [], options: Partial<DTBunchOptions> = {}) {
44
- super(key, { ...defaultOptions, ...options });
45
-
46
- this._items = [];
47
- if (items && items.length > 0) {
48
- this.addMany(items);
49
- }
50
-
51
- this._finder = new DYOFinder(this, this.getFinderConfiguration());
52
- }
53
-
54
- /**
55
- * Returns DYOFinder configuration for standard DTBunch instance.
56
- *
57
- * This method can be overridden to extend the configuration.
58
- *
59
- * @returns DYOFinderConfiguration standard configuration.
60
- */
61
- getFinderConfiguration(): DYOFinderConfiguration {
62
- return componentBunchDefaultFinderConfiguration;
63
- }
64
-
65
- /**
66
- * Setter for _owner property.
67
- *
68
- * If **inheritOwner** is *true*, apply new **owner** to each item.
69
- */
70
- setOwner(value: string): void {
71
- super.setOwner(value);
72
-
73
- // Update owner elements
74
- const { inheritOwner } = this._options;
75
- if (inheritOwner) {
76
- this._items.forEach((item) => { item.setOwner(this.getOwner()); });
77
- }
78
- }
79
-
80
- /**
81
- * Remove the current owner of bunch.
82
- *
83
- * If **inheritOwner** is *true*, remove current owner to each item.
84
- */
85
- removeOwner(): void {
86
- super.removeOwner();
87
-
88
- // Update owner elements
89
- const { inheritOwner } = this._options;
90
- if (inheritOwner) {
91
- this._items.forEach((item) => { item.removeOwner(); });
92
- }
93
- }
94
-
95
- /**
96
- * Add an element **item** as the last element into _items property array.
97
- *
98
- * @see [addAtIndex](#addAtIndex) method for adding specifications.
99
- * @param item A DTElement instance to add into the bunch.
100
- * @param options Optional Bunch option configuration object to apply only for this method execution. Options are not
101
- * saved in current _options property. Available Options are : **uniqueKey**, **inheritOwner**, **replaceIndex**
102
- * and **errors**.
103
- */
104
- add(item: IBunchItem, options: Partial<Omit<DTBunchOptions, 'virtualContainer'>> = {}): void {
105
- this.addAtIndex(item, this._items.length, options);
106
- }
107
-
108
- /**
109
- * Add an element **item** at specified **index** into _items property array.
110
- *
111
- * The adding process has the following specifications :
112
- * * If the added item has the same _id than existing item, an error occurred (depending on **errors** option).
113
- * * Option **uniqueKey** = *true*. If the added item has the same _key than existing item,
114
- * an error occurred (depending on **errors** option).
115
- * * Option **inheritOwner** = *true*. When the new item is added, its owner is replaced by the current bunch owner.
116
- * * Option **virtualContainer** = *false*. When the new item is added, its container is replaced by the current bunch
117
- * instance. The item is removed from the old container.
118
- * * If an item already exists at the specified index, the new item is added at the index, and following items are
119
- * automatically affected at next indexes. If **replaceIndex** option is *true*, the new item replaces the former one
120
- * at the index instead.
121
- * * If the bunch has a parent **Manager**, the added item is also added to the **Manager library**, only if this one
122
- * doesn't already exist in the library.
123
- *
124
- * @param item A DTElement instance to add into the bunch.
125
- * @param index Index value where the item might be added. Must be a number between 0 and the current _items length.
126
- * If not, the provided argument is automatically changed to 0 or current _items length.
127
- * @param options Optional Bunch option configuration object to apply only for this method execution. Options are not
128
- * saved in current _options property. Available Options are : **uniqueKey**, **inheritOwner**, **replaceIndex**
129
- * and **errors**.
130
- */
131
- addAtIndex(item: IBunchItem, index: number, options: Partial<Omit<DTBunchOptions, ''>> = {}): void {
132
- const {
133
- uniqueKey, replaceIndex, inheritOwner, virtualContainer,
134
- }: Partial<DTBunchOptions> = { ...this._options, ...options };
135
- let hasError = false;
136
- let finalIndex = index;
137
-
138
- // Handle ID conflicts
139
- const existingItem = this.get(item.getId());
140
- if (existingItem) {
141
- hasError = true;
142
- this.triggerError(new DYOToolsError(
143
- 'id_conflict',
144
- 'Element with same id already exists in the bunch',
145
- this,
146
- item,
147
- ));
148
- }
149
-
150
- // Handle Key conflicts
151
- if (uniqueKey && !hasError) {
152
- const existingItemByKey = this.find({ key: { $eq: item.getKey() } });
153
- if (existingItemByKey) {
154
- hasError = true;
155
- this.triggerError(new DYOToolsError(
156
- 'key_conflict',
157
- 'Element with same key already exists in the bunch',
158
- this,
159
- item,
160
- ));
161
- }
162
- }
163
-
164
- if (!hasError) {
165
- // Update indexes if out of limits
166
- if (index < 0) {
167
- finalIndex = 0;
168
- }
169
- if (index > this._items.length) {
170
- finalIndex = this._items.length;
171
- }
172
-
173
- // Update Context with manager
174
- if (this._context) {
175
- item.setContext(this._context);
176
- }
177
-
178
- if (!virtualContainer) {
179
- const oldContainer = item.getContainer();
180
- if (oldContainer && oldContainer.getComponentType() === 'bunch') {
181
- (oldContainer as DYOToolsBunch<IBunchItem, DTAcceptedMetaData>).remove(item.getId());
182
- }
183
- item.setContainer(this);
184
- }
185
-
186
- // Update Owner
187
- if (inheritOwner) {
188
- item.setOwner(this._owner);
189
- }
190
-
191
- // Update Manager library
192
- if (this.getContext('manager')) {
193
- const manager: DYOToolsManager<IBunchItem> = this.getContext('manager') as DYOToolsManager<IBunchItem>;
194
- if (!manager.getLibrary().get(item.getId())) {
195
- manager.getLibrary().add(item);
196
- }
197
- }
198
-
199
- // Add the new Item
200
- if (replaceIndex) {
201
- this._items[finalIndex] = item;
202
- } else {
203
- const arrayPart1 = this._items.slice(0, finalIndex);
204
- const arrayPart2 = this._items.slice(finalIndex);
205
-
206
- this._items = [...arrayPart1, item, ...arrayPart2];
207
- }
208
- }
209
- }
210
-
211
- /**
212
- * Add each element of an array **items** at the end of the _items property array.
213
- *
214
- * @see [addAtIndex](#addAtIndex) method for adding specifications.
215
- * @param items An array of DTElement instances to add into the bunch.
216
- * @param options Optional Bunch option configuration object to apply only for this method execution. Options are not
217
- * saved in current _options property. Available Options are : **uniqueKey**, **inheritOwner**, **replaceIndex**
218
- * and **errors**.
219
- */
220
- addMany(items: IBunchItem[], options: Partial<Omit<DTBunchOptions, 'virtualContainer'>> = {}): void {
221
- this.addManyAtIndex(items, this._items.length, options);
222
- }
223
-
224
- /**
225
- * Add each element of an array **items** at specified **index** into _items property array.
226
- * The first element is added at provided **index** argument, and each next element at next indexes, following adding
227
- * specifications.
228
- *
229
- * @see [addAtIndex](#addAtIndex) method for adding specifications.
230
- * @param items An array of DTElement instances to add into the bunch.
231
- * @param index Index value where the item might be added. Must be a number between 0 and the current _items length.
232
- * If not, the provided argument is automatically changed to 0 or current _items length.
233
- * @param options Optional Bunch option configuration object to apply only for this method execution. Options are not
234
- * saved in current _options property. Available Options are : **uniqueKey**, **inheritOwner**, **replaceIndex**
235
- * and **errors**.
236
- */
237
- addManyAtIndex(items: IBunchItem[], index: number, options: Partial<Omit<DTBunchOptions, 'virtualContainer'>> = {}): void {
238
- const previousItems = this._items;
239
- const { errors }: Partial<DTBunchOptions> = { ...this._options, ...options };
240
- let currentIndex = index;
241
-
242
- if (index < 0) {
243
- currentIndex = 0;
244
- }
245
-
246
- try {
247
- for (const item of items) {
248
- this.addAtIndex(item, currentIndex, options);
249
- currentIndex += 1;
250
- }
251
- } catch (exception) {
252
- if (!errors) {
253
- this._items = previousItems;
254
- throw exception;
255
- }
256
- }
257
- }
258
-
259
- /**
260
- * Return one DTElement instance included in the _items property by index or id.
261
- *
262
- * * If a Number is provided, return the DTElement instance at the corresponding index into _items.
263
- * * If a String is provided, return the DTElement instance with the corresponding _id property into _items.
264
- *
265
- * @param index Number index value or String _id value.
266
- * @returns DTElement instance that corresponds to index or id provided, or undefined if not found.
267
- */
268
- get(index: string | number): IBunchItem | undefined {
269
- if (typeof index === 'number') {
270
- return this._items[index];
271
- }
272
- const itemFiltered = this._items.filter((item: IBunchItem) => item.getId() === index);
273
- return itemFiltered.length > 0 ? itemFiltered[0] : undefined;
274
- }
275
-
276
- /**
277
- * Return all DTElement instance managed by the Bunch.
278
- *
279
- * @returns DTElement array corresponding to current _items property.
280
- */
281
- getAll(): IBunchItem[] {
282
- return this._items;
283
- }
284
-
285
- /**
286
- * Return current index of a DTElement instance into _items property by _id.
287
- *
288
- * @param id String _id value of the DTElement instance.
289
- * @returns Current index number into _items, or -1 if not found.
290
- */
291
- indexOf(id: string): number {
292
- let indexOfItem = -1;
293
- for (let i = 0; i < this._items.length; i += 1) {
294
- if (this._items[i].getId() === id) {
295
- indexOfItem = i;
296
- break;
297
- }
298
- }
299
- return indexOfItem;
300
- }
301
-
302
- /**
303
- * Remove a DTElement instance into the _items property by index or id.
304
- *
305
- * * If a Number is provided, remove the DTElement instance at the corresponding index into _items.
306
- * * If a String is provided, remove the DTElement instance with the corresponding _id property into _items.
307
- *
308
- * Note : Remove also affectation to the current container of the removed item
309
- * (only if Option **virtualContainer** is *false*).
310
- *
311
- * @param index Number index value or String _id value.
312
- */
313
- remove(index: string | number): void {
314
- if (typeof index === 'number') {
315
- this.removeMany([index as number]);
316
- } else {
317
- this.removeMany([index as string]);
318
- }
319
- }
320
-
321
- /**
322
- * Remove multiple DTElement instances into the _items property by index or id. An array of indexes or ids to remove
323
- * must be provided.
324
- *
325
- * * If a Number Array is provided, remove DTElement instances at corresponding indexes into _items.
326
- * * If a String Array is provided, remove DTElement instances with corresponding _id properties into _items.
327
- *
328
- * Note : Remove also affectation to the current container of removed items
329
- * (only if Option **virtualContainer** is *false*).
330
- *
331
- * @param indexes Number Array index values or String Array _id values.
332
- */
333
- removeMany(indexes: string[] | number[]): void {
334
- const { virtualContainer } = this._options;
335
- const newItems = [];
336
- for (let i = 0; i < this._items.length; i += 1) {
337
- if (typeof indexes[0] === 'number') {
338
- if (!(indexes as number[]).includes(i)) {
339
- newItems.push(this._items[i]);
340
- } else if (!virtualContainer) {
341
- this._items[i].removeContainer();
342
- }
343
- } else if (!(indexes as string[]).includes(this._items[i].getId())) {
344
- newItems.push(this._items[i]);
345
- } else if (!virtualContainer) {
346
- this._items[i].removeContainer();
347
- }
348
- }
349
-
350
- this._items = newItems;
351
- }
352
-
353
- /**
354
- * Remove all DTElement instances into the _items property.
355
- *
356
- * Note : Remove also affectation to the current container of removed items
357
- * (only if Option **virtualContainer** is *false*).
358
- */
359
- removeAll(): void {
360
- const keysToRemove: number[] = this._items.map((item, index) => index);
361
- this.removeMany(keysToRemove);
362
- }
363
-
364
- /**
365
- * Return an array of DTElement from _items property filtered with a **filters** argument.
366
- *
367
- * This method use the DYOFinder instance **execute** method.
368
- *
369
- * Search filters can be applied on following DTElement properties :
370
- * * **id** : property _id. Basic operators only.
371
- * * **key** : property _key. Basic operators only.
372
- * * **container** : property _id of current _container instance. Basic operators only.
373
- * * **owner** : property _owner. Basic operators only.
374
- * * **meta** : each meta Key of _meta property. Extended operators can be used.
375
- *
376
- * Examples of **filters** argument :
377
- * * { key: { $eq: "key_1" } } : Return all DTElement instance into _items with *key_1* as _key property.
378
- * * { context: { $in: [null, "bunch_1"] } } : Return all DTElement instance into _items having no context or a
379
- * bunch context with *bunch_1* as _id property.
380
- * * { key: { $ne: "key_1" }, meta: { score: { $gte: 50, $lte: 100 } } } : Return all DTElement instance into _items
381
- * with _key property different than *key_1*, and meta key *score* value from _meta property between 50 and 100.
382
- *
383
- * @param filters Filters Object. The format is :
384
- * { [property_1] : { [operator_1] : filter_value, [operator_2] : filter_value_2, ... }, [property_2] : { ... }, ... }
385
- *
386
- * For **meta**, you have to pass the meta key before the operator :
387
- * { meta: { [meta_key1] : { [operator_1] : filter_value_1, ... }, [meta_key2] : { ... }, ... }, ... }
388
- * @returns Array of DTElement instance corresponding to the filters. Empty if no filter or invalid ones are passed.
389
- * @see DYOFinder
390
- */
391
- find(filters: Partial<DTBunchFilters>): IBunchItem[] {
392
- return this._finder.execute<IBunchItem>(filters);
393
- }
394
-
395
- /**
396
- * Create and return a new DTBunch instance by applying from current instance :
397
- * - Copy _key property
398
- * - Copy _meta property
399
- * - Copy _globalOptions property
400
- * - Make a copy of each element in _items, and add it into _items of the copied Bunch.
401
- *
402
- * @returns New DTBunch instance copied.
403
- */
404
- copy(): DYOToolsBunch<IBunchItem, IComponentMeta> {
405
- let copyItems;
406
- if (this._options.virtualContainer) {
407
- copyItems = this._items;
408
- } else {
409
- copyItems = this._items.length === 0 ? [] : this._items.map((item) => item.copy() as IBunchItem);
410
- }
411
-
412
- const copyBunch = new DYOToolsBunch<IBunchItem, IComponentMeta>(this._key, copyItems, this._options);
413
- copyBunch.setManyMeta({ ...this.getManyMeta() });
414
-
415
- return copyBunch;
416
- }
417
-
418
- /**
419
- * Return JSON Object representation of the Bunch instance.
420
- *
421
- * JSON Object returned has the following structure :
422
- * * **id** : _id property of the Bunch.
423
- * * **key** : _key property of the Bunch.
424
- * * **type** : _componentType property of the Bunch.
425
- * * **items** : Array of JSON Object representation for each DTElement instance in _items property of the Bunch.
426
- * * **owner** : String current value of _owner property of the Bunch (only if defined).
427
- * * **meta** : JSON Object of all current metadata in _meta property of the Bunch (only if not empty).
428
- *
429
- * @returns JSON Object representation of the Bunch.
430
- */
431
- toObject(): DTBunchToObject<IComponentMeta> {
432
- const objectBunch: DTBunchToObject<IComponentMeta> = {
433
- id: this._id,
434
- key: this._key,
435
- type: this._componentType,
436
- items: [],
437
- };
438
-
439
- if (this._items.length) {
440
- objectBunch.items = this._items.map((item) => item.toObject());
441
- }
442
-
443
- if (this._owner) {
444
- objectBunch.owner = this._owner.toString();
445
- }
446
-
447
- if (this._meta && Object.keys(this._meta).length > 0) {
448
- objectBunch.meta = { ...this.getManyMeta() };
449
- }
450
-
451
- return objectBunch;
452
- }
453
-
454
- /**
455
- * Return String representation of the Bunch instance.
456
- *
457
- * @returns String representation of the Bunch.
458
- */
459
- toString(): string {
460
- let ownerKey = '';
461
- if (this._owner) {
462
- ownerKey = ` - Owner: ${this._owner}`;
463
- }
464
-
465
- return `Component ${this._key} - Type: Bunch${ownerKey} - Items: ${this._items.length}`;
466
- }
467
- }
1
+ import DTElement from './DTElement';
2
+ import DTManager from './DTManager';
3
+ import {
4
+ DIXObject,
5
+ DTAcceptedMetaData,
6
+ DTBunchFilters,
7
+ DTBunchOptions,
8
+ DTBunchToObject,
9
+ DYOFinderConfiguration,
10
+ } from '../types';
11
+ import DTError from './DTError';
12
+ import DTComponentPhysical from './DTComponentPhysical';
13
+ import { bunchDefaultOptions as defaultOptions, componentBunchDefaultFinderConfiguration } from '../constants';
14
+ import DYOFinder from '../libs/DYOFinder';
15
+ import DTDIXModule from '../libs/dix/DIXModule.module';
16
+
17
+ export default class DTBunch<
18
+ IBunchItem extends DTElement<DTAcceptedMetaData> = DTElement<DTAcceptedMetaData>,
19
+ IComponentMeta extends DTAcceptedMetaData = DTAcceptedMetaData,
20
+ > extends DTComponentPhysical<IComponentMeta, DTBunchOptions> {
21
+ /**
22
+ * Defining component type to "bunch".
23
+ */
24
+ protected _componentType = 'bunch';
25
+
26
+ /**
27
+ * Ordered Array of DTElement instance managed by the bunch.
28
+ */
29
+ protected _items: IBunchItem[];
30
+
31
+ /**
32
+ * Current DYOFinder instance.
33
+ *
34
+ * This instance offers advanced methods to manipulate items, like searching.
35
+ */
36
+ protected _finder: DYOFinder;
37
+
38
+ /**
39
+ * Applying the parent constructor, and execute following process steps :
40
+ * * Add **items** to the bunch instance (using adding specifications).
41
+ * * Merge specific **options** configuration with default in _options.
42
+ * * Initialize *DYOFinder* with **getFinderConfiguration** method.
43
+ *
44
+ * @see [addAtIndex](#addAtIndex) method for adding specifications.
45
+ * @param key
46
+ * @param items Array of DTElement instance to add. Default empty array.
47
+ * @param options Specific options configuration for the instance. Default empty object.
48
+ */
49
+ constructor(key?: string, items: IBunchItem[] = [], options: Partial<DTBunchOptions> = {}) {
50
+ super(key, { ...defaultOptions, ...options });
51
+
52
+ this._items = [];
53
+ if (items && items.length > 0) {
54
+ this.addMany(items);
55
+ }
56
+
57
+ this._finder = new DYOFinder(this, this.getFinderConfiguration());
58
+ }
59
+
60
+ /**
61
+ * Returns DYOFinder configuration for standard DTBunch instance.
62
+ *
63
+ * This method can be overridden to extend the configuration.
64
+ *
65
+ * @returns DYOFinderConfiguration standard configuration.
66
+ */
67
+ getFinderConfiguration(): DYOFinderConfiguration {
68
+ return componentBunchDefaultFinderConfiguration;
69
+ }
70
+
71
+ /**
72
+ * Setter for _owner property.
73
+ *
74
+ * If **inheritOwner** is *true*, apply new **owner** to each item.
75
+ */
76
+ setOwner(value: string): void {
77
+ super.setOwner(value);
78
+
79
+ // Update owner elements
80
+ const { inheritOwner } = this._options;
81
+ if (inheritOwner) {
82
+ this._items.forEach((item) => { item.setOwner(this.getOwner()); });
83
+ }
84
+ }
85
+
86
+ /**
87
+ * Remove the current owner of bunch.
88
+ *
89
+ * If **inheritOwner** is *true*, remove current owner to each item.
90
+ */
91
+ removeOwner(): void {
92
+ super.removeOwner();
93
+
94
+ // Update owner elements
95
+ const { inheritOwner } = this._options;
96
+ if (inheritOwner) {
97
+ this._items.forEach((item) => { item.removeOwner(); });
98
+ }
99
+ }
100
+
101
+ /**
102
+ * Add an element **item** as the last element into _items property array.
103
+ *
104
+ * @see [addAtIndex](#addAtIndex) method for adding specifications.
105
+ * @param item A DTElement instance to add into the bunch.
106
+ * @param options Optional Bunch option configuration object to apply only for this method execution. Options are not
107
+ * saved in current _options property. Available Options are : **uniqueKey**, **inheritOwner**, **replaceIndex**
108
+ * and **errors**.
109
+ */
110
+ add(item: IBunchItem, options: Partial<Omit<DTBunchOptions, 'virtualContainer'>> = {}): void {
111
+ this.addAtIndex(item, this._items.length, options);
112
+ }
113
+
114
+ /**
115
+ * Add an element **item** at specified **index** into _items property array.
116
+ *
117
+ * The adding process has the following specifications :
118
+ * * If the added item has the same _id than existing item, an error occurred (depending on **errors** option).
119
+ * * Option **uniqueKey** = *true*. If the added item has the same _key than existing item,
120
+ * an error occurred (depending on **errors** option).
121
+ * * Option **inheritOwner** = *true*. When the new item is added, its owner is replaced by the current bunch owner.
122
+ * * Option **virtualContainer** = *false*. When the new item is added, its container is replaced by the current bunch
123
+ * instance. The item is removed from the old container.
124
+ * * If an item already exists at the specified index, the new item is added at the index, and following items are
125
+ * automatically affected at next indexes. If **replaceIndex** option is *true*, the new item replaces the former one
126
+ * at the index instead.
127
+ * * If the bunch has a parent **Manager**, the added item is also added to the **Manager library**, only if this one
128
+ * doesn't already exist in the library.
129
+ *
130
+ * @param item A DTElement instance to add into the bunch.
131
+ * @param index Index value where the item might be added. Must be a number between 0 and the current _items length.
132
+ * If not, the provided argument is automatically changed to 0 or current _items length.
133
+ * @param options Optional Bunch option configuration object to apply only for this method execution. Options are not
134
+ * saved in current _options property. Available Options are : **uniqueKey**, **inheritOwner**, **replaceIndex**
135
+ * and **errors**.
136
+ */
137
+ addAtIndex(item: IBunchItem, index: number, options: Partial<Omit<DTBunchOptions, ''>> = {}): void {
138
+ const {
139
+ uniqueKey, replaceIndex, inheritOwner, virtualContainer,
140
+ }: Partial<DTBunchOptions> = { ...this._options, ...options };
141
+ let hasError = false;
142
+ let finalIndex = index;
143
+
144
+ // Handle ID conflicts
145
+ const existingItem = this.get(item.getId());
146
+ if (existingItem) {
147
+ hasError = true;
148
+ this.triggerError(new DTError(
149
+ 'id_conflict',
150
+ 'Element with same id already exists in the bunch',
151
+ this,
152
+ item,
153
+ ));
154
+ }
155
+
156
+ // Handle Key conflicts
157
+ if (uniqueKey && !hasError) {
158
+ const existingItemByKey = this.find({ key: { $eq: item.getKey() } });
159
+ if (existingItemByKey) {
160
+ hasError = true;
161
+ this.triggerError(new DTError(
162
+ 'key_conflict',
163
+ 'Element with same key already exists in the bunch',
164
+ this,
165
+ item,
166
+ ));
167
+ }
168
+ }
169
+
170
+ if (!hasError) {
171
+ // Update indexes if out of limits
172
+ if (index < 0) {
173
+ finalIndex = 0;
174
+ }
175
+ if (index > this._items.length) {
176
+ finalIndex = this._items.length;
177
+ }
178
+
179
+ // Update Context with manager
180
+ if (this._context) {
181
+ item.setContext(this._context);
182
+ }
183
+
184
+ if (!virtualContainer) {
185
+ const oldContainer = item.getContainer();
186
+ if (oldContainer && oldContainer.getComponentType() === 'bunch') {
187
+ (oldContainer as DTBunch<IBunchItem, DTAcceptedMetaData>).remove(item.getId());
188
+ }
189
+ item.setContainer(this);
190
+ }
191
+
192
+ // Update Owner
193
+ if (inheritOwner) {
194
+ item.setOwner(this._owner);
195
+ }
196
+
197
+ // Update Manager library
198
+ if (this.getContext('manager')) {
199
+ const manager: DTManager<IBunchItem> = this.getContext('manager') as DTManager<IBunchItem>;
200
+ if (manager.getLibrary().getId() !== this._id && !manager.getLibrary().get(item.getId())) {
201
+ manager.getLibrary().add(item);
202
+ }
203
+ }
204
+
205
+ // Add the new Item
206
+ if (replaceIndex) {
207
+ this._items[finalIndex] = item;
208
+ } else {
209
+ const arrayPart1 = this._items.slice(0, finalIndex);
210
+ const arrayPart2 = this._items.slice(finalIndex);
211
+
212
+ this._items = [...arrayPart1, item, ...arrayPart2];
213
+ }
214
+ }
215
+ }
216
+
217
+ /**
218
+ * Add each element of an array **items** at the end of the _items property array.
219
+ *
220
+ * @see [addAtIndex](#addAtIndex) method for adding specifications.
221
+ * @param items An array of DTElement instances to add into the bunch.
222
+ * @param options Optional Bunch option configuration object to apply only for this method execution. Options are not
223
+ * saved in current _options property. Available Options are : **uniqueKey**, **inheritOwner**, **replaceIndex**
224
+ * and **errors**.
225
+ */
226
+ addMany(items: IBunchItem[], options: Partial<Omit<DTBunchOptions, 'virtualContainer'>> = {}): void {
227
+ this.addManyAtIndex(items, this._items.length, options);
228
+ }
229
+
230
+ /**
231
+ * Add each element of an array **items** at specified **index** into _items property array.
232
+ * The first element is added at provided **index** argument, and each next element at next indexes, following adding
233
+ * specifications.
234
+ *
235
+ * @see [addAtIndex](#addAtIndex) method for adding specifications.
236
+ * @param items An array of DTElement instances to add into the bunch.
237
+ * @param index Index value where the item might be added. Must be a number between 0 and the current _items length.
238
+ * If not, the provided argument is automatically changed to 0 or current _items length.
239
+ * @param options Optional Bunch option configuration object to apply only for this method execution. Options are not
240
+ * saved in current _options property. Available Options are : **uniqueKey**, **inheritOwner**, **replaceIndex**
241
+ * and **errors**.
242
+ */
243
+ addManyAtIndex(items: IBunchItem[], index: number, options: Partial<Omit<DTBunchOptions, 'virtualContainer'>> = {}): void {
244
+ const previousItems = this._items;
245
+ const { errors }: Partial<DTBunchOptions> = { ...this._options, ...options };
246
+ let currentIndex = index;
247
+
248
+ if (index < 0) {
249
+ currentIndex = 0;
250
+ }
251
+
252
+ try {
253
+ for (const item of items) {
254
+ this.addAtIndex(item, currentIndex, options);
255
+ currentIndex += 1;
256
+ }
257
+ } catch (exception) {
258
+ if (!errors) {
259
+ this._items = previousItems;
260
+ throw exception;
261
+ }
262
+ }
263
+ }
264
+
265
+ /**
266
+ * Return one DTElement instance included in the _items property by index or id.
267
+ *
268
+ * * If a Number is provided, return the DTElement instance at the corresponding index into _items.
269
+ * * If a String is provided, return the DTElement instance with the corresponding _id property into _items.
270
+ *
271
+ * @param index Number index value or String _id value.
272
+ * @returns DTElement instance that corresponds to index or id provided, or undefined if not found.
273
+ */
274
+ get(index: string | number): IBunchItem | undefined {
275
+ if (typeof index === 'number') {
276
+ return this._items[index];
277
+ }
278
+ const itemFiltered = this._items.filter((item: IBunchItem) => item.getId() === index);
279
+ return itemFiltered.length > 0 ? itemFiltered[0] : undefined;
280
+ }
281
+
282
+ /**
283
+ * Return all DTElement instance managed by the Bunch.
284
+ *
285
+ * @returns DTElement array corresponding to current _items property.
286
+ */
287
+ getAll(): IBunchItem[] {
288
+ return this._items;
289
+ }
290
+
291
+ /**
292
+ * Return current index of a DTElement instance into _items property by _id.
293
+ *
294
+ * @param id String _id value of the DTElement instance.
295
+ * @returns Current index number into _items, or -1 if not found.
296
+ */
297
+ indexOf(id: string): number {
298
+ let indexOfItem = -1;
299
+ for (let i = 0; i < this._items.length; i += 1) {
300
+ if (this._items[i].getId() === id) {
301
+ indexOfItem = i;
302
+ break;
303
+ }
304
+ }
305
+ return indexOfItem;
306
+ }
307
+
308
+ /**
309
+ * Remove a DTElement instance into the _items property by index or id.
310
+ *
311
+ * * If a Number is provided, remove the DTElement instance at the corresponding index into _items.
312
+ * * If a String is provided, remove the DTElement instance with the corresponding _id property into _items.
313
+ *
314
+ * Note : Remove also affectation to the current container of the removed item
315
+ * (only if Option **virtualContainer** is *false*).
316
+ *
317
+ * @param index Number index value or String _id value.
318
+ */
319
+ remove(index: string | number): void {
320
+ if (typeof index === 'number') {
321
+ this.removeMany([index as number]);
322
+ } else {
323
+ this.removeMany([index as string]);
324
+ }
325
+ }
326
+
327
+ /**
328
+ * Remove multiple DTElement instances into the _items property by index or id. An array of indexes or ids to remove
329
+ * must be provided.
330
+ *
331
+ * * If a Number Array is provided, remove DTElement instances at corresponding indexes into _items.
332
+ * * If a String Array is provided, remove DTElement instances with corresponding _id properties into _items.
333
+ *
334
+ * Note : Remove also affectation to the current container of removed items
335
+ * (only if Option **virtualContainer** is *false*).
336
+ *
337
+ * @param indexes Number Array index values or String Array _id values.
338
+ */
339
+ removeMany(indexes: string[] | number[]): void {
340
+ const { virtualContainer } = this._options;
341
+ const newItems = [];
342
+ for (let i = 0; i < this._items.length; i += 1) {
343
+ if (typeof indexes[0] === 'number') {
344
+ if (!(indexes as number[]).includes(i)) {
345
+ newItems.push(this._items[i]);
346
+ } else if (!virtualContainer) {
347
+ this._items[i].removeContainer();
348
+ }
349
+ } else if (!(indexes as string[]).includes(this._items[i].getId())) {
350
+ newItems.push(this._items[i]);
351
+ } else if (!virtualContainer) {
352
+ this._items[i].removeContainer();
353
+ }
354
+ }
355
+
356
+ this._items = newItems;
357
+ }
358
+
359
+ /**
360
+ * Remove all DTElement instances into the _items property.
361
+ *
362
+ * Note : Remove also affectation to the current container of removed items
363
+ * (only if Option **virtualContainer** is *false*).
364
+ */
365
+ removeAll(): void {
366
+ const keysToRemove: number[] = this._items.map((item, index) => index);
367
+ this.removeMany(keysToRemove);
368
+ }
369
+
370
+ /**
371
+ * Return an array of DTElement from _items property filtered with a **filters** argument.
372
+ *
373
+ * This method use the DYOFinder instance **execute** method.
374
+ *
375
+ * Search filters can be applied on following DTElement properties :
376
+ * * **id** : property _id. Basic operators only.
377
+ * * **key** : property _key. Basic operators only.
378
+ * * **container** : property _id of current _container instance. Basic operators only.
379
+ * * **owner** : property _owner. Basic operators only.
380
+ * * **meta** : each meta Key of _meta property. Extended operators can be used.
381
+ *
382
+ * Examples of **filters** argument :
383
+ * * { key: { $eq: "key_1" } } : Return all DTElement instance into _items with *key_1* as _key property.
384
+ * * { context: { $in: [null, "bunch_1"] } } : Return all DTElement instance into _items having no context or a
385
+ * bunch context with *bunch_1* as _id property.
386
+ * * { key: { $ne: "key_1" }, meta: { score: { $gte: 50, $lte: 100 } } } : Return all DTElement instance into _items
387
+ * with _key property different than *key_1*, and meta key *score* value from _meta property between 50 and 100.
388
+ *
389
+ * @param filters Filters Object. The format is :
390
+ * { [property_1] : { [operator_1] : filter_value, [operator_2] : filter_value_2, ... }, [property_2] : { ... }, ... }
391
+ *
392
+ * For **meta**, you have to pass the meta key before the operator :
393
+ * { meta: { [meta_key1] : { [operator_1] : filter_value_1, ... }, [meta_key2] : { ... }, ... }, ... }
394
+ * @returns Array of DTElement instance corresponding to the filters. Empty if no filter or invalid ones are passed.
395
+ * @see DYOFinder
396
+ */
397
+ find(filters: Partial<DTBunchFilters>): IBunchItem[] {
398
+ return this._finder.execute<IBunchItem>(filters);
399
+ }
400
+
401
+ /**
402
+ * Create and return a new DTBunch instance by applying from current instance :
403
+ * - Copy _key property
404
+ * - Copy _meta property
405
+ * - Copy _globalOptions property
406
+ * - Make a copy of each element in _items, and add it into _items of the copied Bunch.
407
+ *
408
+ * @returns New DTBunch instance copied.
409
+ */
410
+ copy(): DTBunch<IBunchItem, IComponentMeta> {
411
+ let copyItems;
412
+ if (this._options.virtualContainer) {
413
+ copyItems = this._items;
414
+ } else {
415
+ copyItems = this._items.length === 0 ? [] : this._items.map((item) => item.copy() as IBunchItem);
416
+ }
417
+
418
+ const copyBunch = new DTBunch<IBunchItem, IComponentMeta>(this._key, copyItems, this._options);
419
+ copyBunch.setManyMeta({ ...this.getManyMeta() });
420
+
421
+ return copyBunch;
422
+ }
423
+
424
+ /**
425
+ * Return JSON Object representation of the Bunch instance.
426
+ *
427
+ * JSON Object returned has the following structure :
428
+ * * **id** : _id property of the Bunch.
429
+ * * **key** : _key property of the Bunch.
430
+ * * **type** : _componentType property of the Bunch.
431
+ * * **items** : Array of JSON Object representation for each DTElement instance in _items property of the Bunch.
432
+ * * **owner** : String current value of _owner property of the Bunch (only if defined).
433
+ * * **meta** : JSON Object of all current metadata in _meta property of the Bunch (only if not empty).
434
+ *
435
+ * @returns JSON Object representation of the Bunch.
436
+ */
437
+ toObject(): DTBunchToObject<IComponentMeta> {
438
+ const objectBunch: DTBunchToObject<IComponentMeta> = {
439
+ id: this._id,
440
+ key: this._key,
441
+ type: this._componentType,
442
+ items: [],
443
+ };
444
+
445
+ if (this._items.length) {
446
+ objectBunch.items = this._items.map((item) => item.toObject());
447
+ }
448
+
449
+ if (this._owner) {
450
+ objectBunch.owner = this._owner.toString();
451
+ }
452
+
453
+ if (this._meta && Object.keys(this._meta).length > 0) {
454
+ objectBunch.meta = { ...this.getManyMeta() };
455
+ }
456
+
457
+ return objectBunch;
458
+ }
459
+
460
+ /**
461
+ * Return String representation of the Bunch instance.
462
+ *
463
+ * @returns String representation of the Bunch.
464
+ */
465
+ toString(): string {
466
+ let ownerKey = '';
467
+ if (this._owner) {
468
+ ownerKey = ` - Owner: ${this._owner}`;
469
+ }
470
+
471
+ return `Component ${this._key} - Type: Bunch${ownerKey} - Items: ${this._items.length}`;
472
+ }
473
+
474
+ /**
475
+ * Return DIX Object representation of the DTBunch instance.
476
+ *
477
+ * @returns DIX Object representation of the DTBunch.
478
+ */
479
+ toDIXObject(): Record<string, DIXObject> {
480
+ const parentDixObject = super.toDIXObject();
481
+ const dixObject: DIXObject = {
482
+ ...parentDixObject[this._id],
483
+ items: this._items.map((item) => item.getId()),
484
+ };
485
+
486
+ const finalDix = {
487
+ [this._id]: dixObject,
488
+ };
489
+ this._items.forEach((item) => {
490
+ Object.assign(finalDix, item.toDIXObject());
491
+ });
492
+
493
+ return finalDix;
494
+ }
495
+
496
+ /**
497
+ * Update the DTBunch instance with a DIX Object.
498
+ *
499
+ * @param dix DIX Object to use for updating.
500
+ */
501
+ updateFromDix(dix: Record<string, DIXObject>): void {
502
+ const dixObject = dix[this._id];
503
+ const dixModule = this.getMaster()?.getModule('dix') as DTDIXModule;
504
+
505
+ if (dixObject) {
506
+ // Update data
507
+ super.updateFromDix(dix);
508
+
509
+ // Synchronize Elements
510
+ if (dixObject.items && dixModule?.isEnabled()) {
511
+ // Remove items
512
+ this.getAll().forEach((it) => {
513
+ if (!dixObject.items.includes(it.getId())) {
514
+ this.remove(it.getId());
515
+ }
516
+ });
517
+
518
+ // Add and update existing items
519
+ dixObject.items.forEach((itemId) => {
520
+ if (this.get(itemId)) {
521
+ this.get(itemId).updateFromDix(dix);
522
+ } else {
523
+ const newElement = dixModule.syncNewItem(itemId, dix) as IBunchItem;
524
+ this.add(newElement);
525
+ newElement.updateFromDix(dix);
526
+ }
527
+ });
528
+ }
529
+ }
530
+ }
531
+ }