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,465 +1,555 @@
1
- import DYOToolsComponent from './DTComponent';
2
- import DYOToolsBunch from './DTBunch';
3
- import DYOToolsError from './DTError';
4
- import {
5
- DTAcceptedMetaData,
6
- DTComponentOptions,
7
- DTManagerFilters,
8
- DTManagerItemsType,
9
- DTManagerItemType,
10
- DTManagerOptions,
11
- DTManagerToObject,
12
- DYOFinderConfiguration,
13
- } from '../types';
14
- import DYOFinder from '../libs/DYOFinder';
15
- import { componentManagerDefaultFinderConfiguration, managerDefaultOptions as defaultOptions } from '../constants';
16
- import DYOToolsElement from './DTElement';
17
- import DYOToolsMaster from './DTMaster';
18
-
19
- export default class DYOToolsManager<
20
- IBunchItem extends DYOToolsElement<DTAcceptedMetaData> = DYOToolsElement<DTAcceptedMetaData>,
21
- > extends DYOToolsComponent<DTManagerOptions> {
22
- /**
23
- * Defining component type to "manager".
24
- */
25
- protected _componentType = 'manager';
26
-
27
- /**
28
- * DTBunch instances managed by the Manager.
29
- *
30
- * This property is an object with an entry for each bunch :
31
- * * The key is the bunch _id.
32
- * * The value is an object with :
33
- * * * *scope* : the current affected **scope** of the bunch.
34
- * * * *item* : the DTBunch instance.
35
- */
36
- protected _items: DTManagerItemsType<IBunchItem>;
37
-
38
- /**
39
- * Valid scopes list for bunches.
40
- *
41
- * Each bunch is affected to one scope, in order to facilitate filtering and grouping of bunches.
42
- * A DTManager instance comes with two initial scopes : 'default' and 'virtual'.
43
- */
44
- protected _scopes: string[];
45
-
46
- /**
47
- * Current Library instance for the Manager.
48
- *
49
- * The Library is a special virtual bunch which contains all elements added in bunches.
50
- * The purpose is the guarantee of id uniqueness when transferring elements between bunches.
51
- * It also facilitates searching elements in all Manager bunches.
52
- */
53
- protected _library: DYOToolsBunch<IBunchItem>;
54
-
55
- /**
56
- * Current DYOFinder instance.
57
- *
58
- * This instance offers advanced methods to manipulate items, like searching.
59
- */
60
- protected _finder: DYOFinder;
61
-
62
- /**
63
- * Applying the parent constructor, and execute following process steps :
64
- * * If **key** isn't provided and the property _domain is defined, the _key property has the _domain value.
65
- * * Add *default* and *virtual* as basic _scopes value, and add **scopes**.
66
- * * Create the Library instance, and add **elements** into it.
67
- * * Initialize *DYOFinder* with **getFinderConfiguration** method.
68
- *
69
- * @param key
70
- * @param elements Array of DTElement instance to add into the Manager Library. Default empty array.
71
- * @param scopes Array of custom scopes for the Manager. Default empty array.
72
- * @param options Specific options configuration for the instance. Default empty object.
73
- */
74
- constructor(key?: string, elements: IBunchItem[] = [], scopes: string[] = [], options: Partial<DTManagerOptions> = {}) {
75
- super(key, { ...defaultOptions, ...options });
76
- // Use default _domain as _key
77
- this._key = !key ? (this.getDomain() || this._id) : key;
78
-
79
- this._items = {};
80
- this._scopes = [
81
- 'default',
82
- 'virtual',
83
- ...scopes,
84
- ];
85
- this._library = new DYOToolsBunch('library', elements, { virtualContainer: true });
86
- this._library.setContext(this);
87
-
88
- this._finder = new DYOFinder(this, this.getFinderConfiguration());
89
- }
90
-
91
- /**
92
- * Returns DYOFinder configuration for standard DTManager instance.
93
- *
94
- * This method can be overridden to extend the configuration.
95
- *
96
- * @returns DYOFinderConfiguration standard configuration.
97
- */
98
- getFinderConfiguration(): DYOFinderConfiguration {
99
- return componentManagerDefaultFinderConfiguration;
100
- }
101
-
102
- /**
103
- * Getter for _library property.
104
- */
105
- getLibrary(): DYOToolsBunch<IBunchItem> {
106
- return this._library;
107
- }
108
-
109
- /**
110
- * Getter for _scopes property.
111
- */
112
- getScopes(): string[] {
113
- return this._scopes;
114
- }
115
-
116
- /**
117
- * Define if a scope name is a valid scope into the Manager.
118
- *
119
- * @param scope scope name.
120
- * @returns boolean if the scope is valid or not.
121
- */
122
- isValidScope(scope: string): boolean {
123
- return this._scopes.includes(scope);
124
- }
125
-
126
- /**
127
- * Add a DTBunch **item** into _items Manager property.
128
- *
129
- * The adding process has the following specifications :
130
- * * If the added item has the same _id than existing item, an error occurred (depending on **errors** option).
131
- * * The bunch item is automatically added to a scope depending on its virtual context :
132
- * * * *default* if the bunch option **virtualContainer** is false.
133
- * * * *virtual* if the bunch option **virtualContainer** is true.
134
- * * An optional parameter **targetScope** can be passed to force the scope affectation.
135
- * An error occurred if the affection doesn't conform to the following restrictions :
136
- * * * Virtual context bunch must be affected to the 'virtual' scope.
137
- * * * Not virtual context bunch must be affected to the 'default' scope, or any scope other than the 'virtual' one.
138
- * * All elements of the added bunch item are added to the Manager Library, only if the element doesn't already exist
139
- * into the Library.
140
- * * The Manager instance becomes the new context of the added item.
141
- * * The added item format follows the type DTManagerItemsType.
142
- * @see DTManagerItemsType
143
- *
144
- * @param item A DTBunch instance to add into the Manager.
145
- * @param targetScope Optional scope for affectation.
146
- */
147
- add(item: DYOToolsBunch<IBunchItem>, targetScope?: string): void {
148
- // Id conflict
149
- if (Object.keys(this._items).includes(item.getId())) {
150
- this.triggerError(new DYOToolsError(
151
- 'id_conflict',
152
- 'Bunch with same id already exists in the manager',
153
- this,
154
- item,
155
- ));
156
- return;
157
- }
158
-
159
- // Define scope validity
160
- const { virtualContainer } = item.getOptions();
161
- let scope;
162
- if (!targetScope) {
163
- scope = virtualContainer ? 'virtual' : 'default';
164
- } else {
165
- const { code: errorCode, message: errorMessage } = this.getErrorDataForScope(targetScope, virtualContainer);
166
-
167
- if (errorCode && errorMessage) {
168
- this.triggerError(new DYOToolsError(errorCode, errorMessage, this, item));
169
- return;
170
- }
171
- scope = targetScope;
172
- }
173
-
174
- // Update Library with non-existing new Elements
175
- if (item.getAll().length) {
176
- item.getAll().forEach((element: IBunchItem) => {
177
- if (!this._library.get(element.getId())) {
178
- this._library.add(element);
179
- }
180
- });
181
- }
182
-
183
- // Update context
184
- // Bunch
185
- item.setContext<DYOToolsManager<IBunchItem>>(this);
186
- const oldContext = item.getContext();
187
- if (oldContext && oldContext.getComponentType() === 'manager') {
188
- (oldContext as DYOToolsManager<IBunchItem>).remove(item.getId());
189
- }
190
-
191
- // Elements children
192
- item.getAll().forEach((element) => {
193
- element.setContext<DYOToolsManager<IBunchItem>>(this);
194
- });
195
-
196
- // Add the new item
197
- this._items[item.getId()] = {
198
- scope,
199
- item,
200
- };
201
- }
202
-
203
- /**
204
- * Add each bunch of an array **items** into _items Manager property.
205
- *
206
- * @see [add](#add) method for adding specifications.
207
- * @param items An array of DTBunch instances to add into the Manager.
208
- * @param targetScope Optional scope for affectation (all added items are affected).
209
- */
210
- addMany(items: DYOToolsBunch<IBunchItem>[], targetScope?: string): void {
211
- const previousItems = { ...this._items };
212
- const { errors }: DTComponentOptions = this._options;
213
-
214
- try {
215
- items.forEach((item: DYOToolsBunch<IBunchItem>) => {
216
- this.add(item, targetScope);
217
- });
218
- } catch (err: unknown) {
219
- this._items = previousItems;
220
- if (!errors) {
221
- throw err;
222
- }
223
- }
224
- }
225
-
226
- /**
227
- * Move a bunch item to a new scope.
228
- *
229
- * Note : an error occurred (depending on **errors** option) if the bunch id doesn't exist into the Manager.
230
- *
231
- * @see [add](#add) method for restrictions into the scope affectation.
232
- * @param bunchId _id property of the bunch to move.
233
- * @param targetScope new scope of the bunch.
234
- */
235
- moveToScope(bunchId: string, targetScope: string): void {
236
- if (!Object.keys(this._items).includes(bunchId)) {
237
- this.triggerError(new DYOToolsError(
238
- 'invalid_id',
239
- 'Bunch id provided doesn\'t exist in the manager',
240
- this,
241
- ));
242
- return;
243
- }
244
-
245
- const bunch = this._items[bunchId].item;
246
-
247
- const { virtualContainer } = bunch.getOptions();
248
- const { code: errorCode, message: errorMessage } = this.getErrorDataForScope(targetScope, virtualContainer);
249
- if (errorCode && errorMessage) {
250
- this.triggerError(new DYOToolsError(errorCode, errorMessage, this, bunch));
251
- return;
252
- }
253
-
254
- this._items[bunchId].scope = targetScope;
255
- }
256
-
257
- /**
258
- * Return one DTBunch instance included in the _items property by id.
259
- *
260
- * @param id bunch id to return.
261
- * @returns DYOToolsBunch instance that corresponds to the id provided, or undefined if not found.
262
- */
263
- get(id: string): DYOToolsBunch<IBunchItem> | undefined {
264
- return this._items[id]?.item ?? undefined;
265
- }
266
-
267
- /**
268
- * Return all DTBunch instance managed into the Manager.
269
- *
270
- * @param scope Optional parameter **scope** to return only bunches which are affected to a specific scope.
271
- * @returns DYOToolsBunch array.
272
- */
273
- getAll(scope?: string): DYOToolsBunch<IBunchItem>[] {
274
- const finalItems = [];
275
- Object.values(this._items).forEach((item: DTManagerItemType<IBunchItem>) => {
276
- if (!scope || item.scope === scope) {
277
- finalItems.push(item.item);
278
- }
279
- });
280
-
281
- return finalItems;
282
- }
283
-
284
- /**
285
- * Return the current affected scope of a bunch depending on its id.
286
- *
287
- * @param id bunch id to return.
288
- * @returns Current scope affected to the bunch, or undefined if the bunch doesn't exist.
289
- */
290
- getScope(id: string): string | undefined {
291
- return this._items[id] && this._items[id].scope;
292
- }
293
-
294
- /**
295
- * Returns Master component from context, or undefined.
296
- */
297
- getMaster(): DYOToolsMaster | undefined {
298
- return this.getContext<DYOToolsMaster>('master');
299
- }
300
-
301
- /**
302
- * Remove one bunch into the _items property of the Manager, depending on its id.
303
- *
304
- * If option **libraryDeletion** is *true*, the method performs also a deletion of removed bunch elements
305
- * in the Manager Library.
306
- *
307
- * @param id bunch id to remove.
308
- */
309
- remove(id: string): void {
310
- this.removeMany([id]);
311
- }
312
-
313
- /**
314
- * Remove many bunches into the _items property of the Manager, depending on their ids.
315
- *
316
- * If option **libraryDeletion** is *true*, the method performs also a deletion of removed bunch elements
317
- * in the Manager Library.
318
- *
319
- * @param ids Array of bunch ids to remove.
320
- * @param options Optional Manager option configuration object to apply only for this method execution. Options are not
321
- * saved in current _options property. Available Options are : **libraryDeletion** and **errors**.
322
- */
323
- removeMany(ids: string[], options: Partial<DTManagerOptions> = {}): void {
324
- const { libraryDeletion } = { ...this._options, ...options };
325
-
326
- ids.forEach((id: string) => {
327
- if (this._items[id]) {
328
- this._items[id].item.getAll().forEach((item: IBunchItem) => {
329
- if (libraryDeletion) {
330
- this._library.remove(item.getId());
331
- }
332
- item.removeContext();
333
- });
334
-
335
- this._items[id].item.removeContext();
336
- delete this._items[id];
337
- }
338
- });
339
- }
340
-
341
- /**
342
- * Remove all bunches into the _items property of the Manager.
343
- *
344
- * If option **libraryDeletion** is *true*, the method performs also a deletion of removed bunch elements
345
- * in the Manager Library.
346
- */
347
- removeAll(): void {
348
- this.removeMany(Object.keys(this._items));
349
- }
350
-
351
- /**
352
- * Return an array of DTBunch from _items property filtered with a **filters** argument.
353
- *
354
- * This method use the DYOFinder instance **execute** method.
355
- *
356
- * Search filters can be applied on following bunch properties :
357
- * * **id** : property _id. Basic operators only.
358
- * * **key** : property _key. Basic operators only.
359
- * * **scope** : affected scope name. Basic operators only.
360
- * * **owner** : property _id of current _owner instance. Basic operators only.
361
- * * **meta** : each meta Key of _meta property. Extended operators can be used.
362
- *
363
- * Examples of **filters** argument :
364
- * * { key: { $eq: "key_1" } } : Return all DTBunch instances into _items with *key_1* as _key property.
365
- * * { scope: { $in: ["default", "scope_1"] } } : Return all DTBunch instances into _items affected to scopes
366
- * "default" or "scope_1".
367
- * * { key: { $ne: "key_1" }, meta: { score: { $gte: 50, $lte: 100 } } } : Return all DTBunch instance into _items
368
- * with _key property different from *key_1*, and meta key *score* value from _meta property between 50 and 100.
369
- *
370
- * @param filters Filters Object. The format is :
371
- * { [property_1] : { [operator_1] : filter_value, [operator_2] : filter_value_2, ... }, [property_2] : { ... }, ... }
372
- *
373
- * For **meta**, you have to pass the meta key before the operator :
374
- * { meta: { [meta_key1] : { [operator_1] : filter_value_1, ... }, [meta_key2] : { ... }, ... }, ... }
375
- * @returns Array of DTBunch instance corresponding to the filters. Empty if no filter or invalid ones are passed.
376
- * @see DYOFinder
377
- */
378
- find(filters: Partial<DTManagerFilters>): DYOToolsBunch<IBunchItem>[] {
379
- return this._finder.execute<DYOToolsBunch<IBunchItem>>(filters);
380
- }
381
-
382
- /**
383
- * Remove all items into the Manager Library, and add items from all bunches instance managed by the Manager.
384
- *
385
- * This method is useful to guarantee that the Library contains all bunches items, especially after many complex
386
- * operations.
387
- */
388
- reloadLibrary(): void {
389
- this._library.removeAll();
390
-
391
- Object.values(this._items).forEach((item: DTManagerItemType<IBunchItem>) => {
392
- item.item.getAll().forEach((element: IBunchItem) => {
393
- if (!this._library.get(element.getId())) {
394
- this._library.add(element);
395
- }
396
- });
397
- });
398
- }
399
-
400
- /**
401
- * Return JSON Object representation of the Manager instance.
402
- *
403
- * JSON Object returned has the following structure :
404
- * * **id** : _id property of the Manager.
405
- * * **key** : _key property of the Manager.
406
- * * **type** : _componentType property of the Manager.
407
- * * **items** : Array of JSON Object representation for each DTBunch instance in _items property of the Manager.
408
- *
409
- * @returns JSON Object representation of the Manager.
410
- */
411
- toObject(): DTManagerToObject {
412
- const objectManager: DTManagerToObject = {
413
- id: this._id,
414
- key: this._key,
415
- type: this._componentType,
416
- items: [],
417
- };
418
-
419
- Object.keys(this._items).forEach((bunchId: string) => {
420
- objectManager.items.push({
421
- scope: this._items[bunchId].scope,
422
- ...this._items[bunchId].item.toObject(),
423
- });
424
- });
425
-
426
- return objectManager;
427
- }
428
-
429
- /**
430
- * Return String representation of the Manager instance.
431
- *
432
- * @returns String representation of the Manager.
433
- */
434
- toString(): string {
435
- const libraryLabel = `Library: ${this._library.getAll().length}`;
436
- const domainLabel = this._domain ? ` ${this._domain}` : '';
437
-
438
- return `Component${domainLabel} ${this._key} - Type: Manager - ${libraryLabel} - Items: ${Object.keys(this._items).length}`;
439
- }
440
-
441
- /**
442
- * Get error data for scope affectation. Used in method which performs scope affectation.
443
- *
444
- * @param targetScope scope name to check for affectation.
445
- * @param virtualContainer boolean if the bunch to affect has **virtualContainer** option enabled or not. Default *false*.
446
- * @returns An Object with error code and message.
447
- */
448
- private getErrorDataForScope(targetScope: string, virtualContainer = false): { code: string, message: string } {
449
- const response = { code: '', message: '' };
450
- if (!this.isValidScope(targetScope)) {
451
- response.code = 'invalid_scope';
452
- response.message = "Scope provided doesn't exist in the manager";
453
- }
454
- if (virtualContainer && targetScope !== 'virtual') {
455
- response.code = 'forbidden_scope';
456
- response.message = 'Scope provided cannot be associated to a virtual bunch';
457
- }
458
- if (!virtualContainer && targetScope === 'virtual') {
459
- response.code = 'forbidden_virtual_scope';
460
- response.message = 'Virtual Scope provided cannot be associated to a physical bunch';
461
- }
462
-
463
- return response;
464
- }
465
- }
1
+ import DTComponent from './DTComponent';
2
+ import DTBunch from './DTBunch';
3
+ import DTError from './DTError';
4
+ import {
5
+ DIXObject,
6
+ DTAcceptedMetaData,
7
+ DTComponentOptions,
8
+ DTManagerFilters,
9
+ DTManagerItemsType,
10
+ DTManagerItemType,
11
+ DTManagerOptions,
12
+ DTManagerToObject,
13
+ DYOFinderConfiguration,
14
+ } from '../types';
15
+ import DYOFinder from '../libs/DYOFinder';
16
+ import { componentManagerDefaultFinderConfiguration, managerDefaultOptions as defaultOptions } from '../constants';
17
+ import DTElement from './DTElement';
18
+ import DTMaster from './DTMaster';
19
+ import DTDIXModule from '../libs/dix/DIXModule.module';
20
+
21
+ export default class DTManager<
22
+ IBunchItem extends DTElement<DTAcceptedMetaData> = DTElement<DTAcceptedMetaData>,
23
+ > extends DTComponent<DTManagerOptions> {
24
+ /**
25
+ * Defining component type to "manager".
26
+ */
27
+ protected _componentType = 'manager';
28
+
29
+ /**
30
+ * DTBunch instances managed by the Manager.
31
+ *
32
+ * This property is an object with an entry for each bunch :
33
+ * * The key is the bunch _id.
34
+ * * The value is an object with :
35
+ * * * *scope* : the current affected **scope** of the bunch.
36
+ * * * *item* : the DTBunch instance.
37
+ */
38
+ protected _items: DTManagerItemsType<IBunchItem>;
39
+
40
+ /**
41
+ * Valid scopes list for bunches.
42
+ *
43
+ * Each bunch is affected to one scope, in order to facilitate filtering and grouping of bunches.
44
+ * A DTManager instance comes with two initial scopes : 'default' and 'virtual'.
45
+ */
46
+ protected _scopes: string[];
47
+
48
+ /**
49
+ * Current Library instance for the Manager.
50
+ *
51
+ * The Library is a special virtual bunch which contains all elements added in bunches.
52
+ * The purpose is the guarantee of id uniqueness when transferring elements between bunches.
53
+ * It also facilitates searching elements in all Manager bunches.
54
+ */
55
+ protected _library: DTBunch<IBunchItem>;
56
+
57
+ /**
58
+ * Current DYOFinder instance.
59
+ *
60
+ * This instance offers advanced methods to manipulate items, like searching.
61
+ */
62
+ protected _finder: DYOFinder;
63
+
64
+ /**
65
+ * Applying the parent constructor, and execute following process steps :
66
+ * * If **key** isn't provided and the property _domain is defined, the _key property has the _domain value.
67
+ * * Add *default* and *virtual* as basic _scopes value, and add **scopes**.
68
+ * * Create the Library instance, and add **elements** into it.
69
+ * * Initialize *DYOFinder* with **getFinderConfiguration** method.
70
+ *
71
+ * @param key
72
+ * @param elements Array of DTElement instance to add into the Manager Library. Default empty array.
73
+ * @param scopes Array of custom scopes for the Manager. Default empty array.
74
+ * @param options Specific options configuration for the instance. Default empty object.
75
+ */
76
+ constructor(key?: string, elements: IBunchItem[] = [], scopes: string[] = [], options: Partial<DTManagerOptions> = {}) {
77
+ super(key, { ...defaultOptions, ...options });
78
+
79
+ this._items = {};
80
+ this._scopes = [
81
+ 'default',
82
+ 'virtual',
83
+ ...scopes,
84
+ ];
85
+ this._library = new DTBunch('library', elements, { virtualContainer: true });
86
+ this._library.setContext(this);
87
+
88
+ this._finder = new DYOFinder(this, this.getFinderConfiguration());
89
+ }
90
+
91
+ /**
92
+ * Returns DYOFinder configuration for standard DTManager instance.
93
+ *
94
+ * This method can be overridden to extend the configuration.
95
+ *
96
+ * @returns DYOFinderConfiguration standard configuration.
97
+ */
98
+ getFinderConfiguration(): DYOFinderConfiguration {
99
+ return componentManagerDefaultFinderConfiguration;
100
+ }
101
+
102
+ /**
103
+ * Getter for _library property.
104
+ */
105
+ getLibrary(): DTBunch<IBunchItem> {
106
+ return this._library;
107
+ }
108
+
109
+ /**
110
+ * Getter for _scopes property.
111
+ */
112
+ getScopes(): string[] {
113
+ return this._scopes;
114
+ }
115
+
116
+ /**
117
+ * Define if a scope name is a valid scope into the Manager.
118
+ *
119
+ * @param scope scope name.
120
+ * @returns boolean if the scope is valid or not.
121
+ */
122
+ isValidScope(scope: string): boolean {
123
+ return this._scopes.includes(scope);
124
+ }
125
+
126
+ /**
127
+ * Add a DTBunch **item** into _items Manager property.
128
+ *
129
+ * The adding process has the following specifications :
130
+ * * If the added item has the same _id than existing item, an error occurred (depending on **errors** option).
131
+ * * The bunch item is automatically added to a scope depending on its virtual context :
132
+ * * * *default* if the bunch option **virtualContainer** is false.
133
+ * * * *virtual* if the bunch option **virtualContainer** is true.
134
+ * * An optional parameter **targetScope** can be passed to force the scope affectation.
135
+ * An error occurred if the affection doesn't conform to the following restrictions :
136
+ * * * Virtual context bunch must be affected to the 'virtual' scope.
137
+ * * * Not virtual context bunch must be affected to the 'default' scope, or any scope other than the 'virtual' one.
138
+ * * All elements of the added bunch item are added to the Manager Library, only if the element doesn't already exist
139
+ * into the Library.
140
+ * * The Manager instance becomes the new context of the added item.
141
+ * * The added item format follows the type DTManagerItemsType.
142
+ * @see DTManagerItemsType
143
+ *
144
+ * @param item A DTBunch instance to add into the Manager.
145
+ * @param targetScope Optional scope for affectation.
146
+ */
147
+ add(item: DTBunch<IBunchItem>, targetScope?: string): void {
148
+ // Id conflict
149
+ if (Object.keys(this._items).includes(item.getId())) {
150
+ this.triggerError(new DTError(
151
+ 'id_conflict',
152
+ 'Bunch with same id already exists in the manager',
153
+ this,
154
+ item,
155
+ ));
156
+ return;
157
+ }
158
+
159
+ // Define scope validity
160
+ const { virtualContainer } = item.getOptions();
161
+ let scope;
162
+ if (!targetScope) {
163
+ scope = virtualContainer ? 'virtual' : 'default';
164
+ } else {
165
+ const { code: errorCode, message: errorMessage } = this.getErrorDataForScope(targetScope, virtualContainer);
166
+
167
+ if (errorCode && errorMessage) {
168
+ this.triggerError(new DTError(errorCode, errorMessage, this, item));
169
+ return;
170
+ }
171
+ scope = targetScope;
172
+ }
173
+
174
+ // Update Library with non-existing new Elements
175
+ if (item.getAll().length) {
176
+ item.getAll().forEach((element: IBunchItem) => {
177
+ if (!this._library.get(element.getId())) {
178
+ this._library.add(element);
179
+ }
180
+ });
181
+ }
182
+
183
+ // Update context
184
+ // Bunch
185
+ const oldContext = item.getContext();
186
+ if (oldContext && oldContext.getComponentType() === 'manager') {
187
+ (oldContext as DTManager<IBunchItem>).remove(item.getId());
188
+ }
189
+ item.setContext<DTManager<IBunchItem>>(this);
190
+
191
+ // Elements children
192
+ item.getAll().forEach((element) => {
193
+ element.setContext<DTManager<IBunchItem>>(this);
194
+ });
195
+
196
+ // Add the new item
197
+ this._items[item.getId()] = {
198
+ scope,
199
+ item,
200
+ };
201
+ }
202
+
203
+ /**
204
+ * Add each bunch of an array **items** into _items Manager property.
205
+ *
206
+ * @see [add](#add) method for adding specifications.
207
+ * @param items An array of DTBunch instances to add into the Manager.
208
+ * @param targetScope Optional scope for affectation (all added items are affected).
209
+ */
210
+ addMany(items: DTBunch<IBunchItem>[], targetScope?: string): void {
211
+ const previousItems = { ...this._items };
212
+ const { errors }: DTComponentOptions = this._options;
213
+
214
+ try {
215
+ items.forEach((item: DTBunch<IBunchItem>) => {
216
+ this.add(item, targetScope);
217
+ });
218
+ } catch (err: unknown) {
219
+ this._items = previousItems;
220
+ if (!errors) {
221
+ throw err;
222
+ }
223
+ }
224
+ }
225
+
226
+ /**
227
+ * Move a bunch item to a new scope.
228
+ *
229
+ * Note : an error occurred (depending on **errors** option) if the bunch id doesn't exist into the Manager.
230
+ *
231
+ * @see [add](#add) method for restrictions into the scope affectation.
232
+ * @param bunchId _id property of the bunch to move.
233
+ * @param targetScope new scope of the bunch.
234
+ */
235
+ moveToScope(bunchId: string, targetScope: string): void {
236
+ if (!Object.keys(this._items).includes(bunchId)) {
237
+ this.triggerError(new DTError(
238
+ 'invalid_id',
239
+ 'Bunch id provided doesn\'t exist in the manager',
240
+ this,
241
+ ));
242
+ return;
243
+ }
244
+
245
+ const bunch = this._items[bunchId].item;
246
+
247
+ const { virtualContainer } = bunch.getOptions();
248
+ const { code: errorCode, message: errorMessage } = this.getErrorDataForScope(targetScope, virtualContainer);
249
+ if (errorCode && errorMessage) {
250
+ this.triggerError(new DTError(errorCode, errorMessage, this, bunch));
251
+ return;
252
+ }
253
+
254
+ this._items[bunchId].scope = targetScope;
255
+ }
256
+
257
+ /**
258
+ * Return one DTBunch instance included in the _items property by id.
259
+ *
260
+ * @param id bunch id to return.
261
+ * @returns DYOToolsBunch instance that corresponds to the id provided, or undefined if not found.
262
+ */
263
+ get(id: string): DTBunch<IBunchItem> | undefined {
264
+ return this._items[id]?.item ?? undefined;
265
+ }
266
+
267
+ /**
268
+ * Return all DTBunch instance managed into the Manager.
269
+ *
270
+ * @param scope Optional parameter **scope** to return only bunches which are affected to a specific scope.
271
+ * @returns DYOToolsBunch array.
272
+ */
273
+ getAll(scope?: string): DTBunch<IBunchItem>[] {
274
+ const finalItems = [];
275
+ Object.values(this._items).forEach((item: DTManagerItemType<IBunchItem>) => {
276
+ if (!scope || item.scope === scope) {
277
+ finalItems.push(item.item);
278
+ }
279
+ });
280
+
281
+ return finalItems;
282
+ }
283
+
284
+ /**
285
+ * Return the current affected scope of a bunch depending on its id.
286
+ *
287
+ * @param id bunch id to return.
288
+ * @returns Current scope affected to the bunch, or undefined if the bunch doesn't exist.
289
+ */
290
+ getScope(id: string): string | undefined {
291
+ return this._items[id] && this._items[id].scope;
292
+ }
293
+
294
+ /**
295
+ * Returns Master component from context, or undefined.
296
+ */
297
+ getMaster(): DTMaster | undefined {
298
+ return this.getContext<DTMaster>('master');
299
+ }
300
+
301
+ /**
302
+ * Remove one bunch into the _items property of the Manager, depending on its id.
303
+ *
304
+ * If option **libraryDeletion** is *true*, the method performs also a deletion of removed bunch elements
305
+ * in the Manager Library.
306
+ *
307
+ * @param id bunch id to remove.
308
+ */
309
+ remove(id: string): void {
310
+ this.removeMany([id]);
311
+ }
312
+
313
+ /**
314
+ * Remove many bunches into the _items property of the Manager, depending on their ids.
315
+ *
316
+ * If option **libraryDeletion** is *true*, the method performs also a deletion of removed bunch elements
317
+ * in the Manager Library.
318
+ *
319
+ * @param ids Array of bunch ids to remove.
320
+ * @param options Optional Manager option configuration object to apply only for this method execution. Options are not
321
+ * saved in current _options property. Available Options are : **libraryDeletion** and **errors**.
322
+ */
323
+ removeMany(ids: string[], options: Partial<DTManagerOptions> = {}): void {
324
+ const { libraryDeletion } = { ...this._options, ...options };
325
+
326
+ ids.forEach((id: string) => {
327
+ if (this._items[id]) {
328
+ this._items[id].item.getAll().forEach((item: IBunchItem) => {
329
+ if (libraryDeletion) {
330
+ this._library.remove(item.getId());
331
+ }
332
+ item.removeContainer();
333
+ });
334
+
335
+ this._items[id].item.removeContext();
336
+ delete this._items[id];
337
+ }
338
+ });
339
+ }
340
+
341
+ /**
342
+ * Remove all bunches into the _items property of the Manager.
343
+ *
344
+ * If option **libraryDeletion** is *true*, the method performs also a deletion of removed bunch elements
345
+ * in the Manager Library.
346
+ */
347
+ removeAll(): void {
348
+ this.removeMany(Object.keys(this._items));
349
+ }
350
+
351
+ /**
352
+ * Return an array of DTBunch from _items property filtered with a **filters** argument.
353
+ *
354
+ * This method use the DYOFinder instance **execute** method.
355
+ *
356
+ * Search filters can be applied on following bunch properties :
357
+ * * **id** : property _id. Basic operators only.
358
+ * * **key** : property _key. Basic operators only.
359
+ * * **scope** : affected scope name. Basic operators only.
360
+ * * **owner** : property _id of current _owner instance. Basic operators only.
361
+ * * **meta** : each meta Key of _meta property. Extended operators can be used.
362
+ *
363
+ * Examples of **filters** argument :
364
+ * * { key: { $eq: "key_1" } } : Return all DTBunch instances into _items with *key_1* as _key property.
365
+ * * { scope: { $in: ["default", "scope_1"] } } : Return all DTBunch instances into _items affected to scopes
366
+ * "default" or "scope_1".
367
+ * * { key: { $ne: "key_1" }, meta: { score: { $gte: 50, $lte: 100 } } } : Return all DTBunch instance into _items
368
+ * with _key property different from *key_1*, and meta key *score* value from _meta property between 50 and 100.
369
+ *
370
+ * @param filters Filters Object. The format is :
371
+ * { [property_1] : { [operator_1] : filter_value, [operator_2] : filter_value_2, ... }, [property_2] : { ... }, ... }
372
+ *
373
+ * For **meta**, you have to pass the meta key before the operator :
374
+ * { meta: { [meta_key1] : { [operator_1] : filter_value_1, ... }, [meta_key2] : { ... }, ... }, ... }
375
+ * @returns Array of DTBunch instance corresponding to the filters. Empty if no filter or invalid ones are passed.
376
+ * @see DYOFinder
377
+ */
378
+ find(filters: Partial<DTManagerFilters>): DTBunch<IBunchItem>[] {
379
+ return this._finder.execute<DTBunch<IBunchItem>>(filters);
380
+ }
381
+
382
+ /**
383
+ * Remove all items into the Manager Library, and add items from all bunches instance managed by the Manager.
384
+ *
385
+ * This method is useful to guarantee that the Library contains all bunches items, especially after many complex
386
+ * operations.
387
+ */
388
+ reloadLibrary(): void {
389
+ this._library.removeAll();
390
+
391
+ Object.values(this._items).forEach((item: DTManagerItemType<IBunchItem>) => {
392
+ item.item.getAll().forEach((element: IBunchItem) => {
393
+ if (!this._library.get(element.getId())) {
394
+ this._library.add(element);
395
+ }
396
+ });
397
+ });
398
+ }
399
+
400
+ /**
401
+ * Return JSON Object representation of the Manager instance.
402
+ *
403
+ * JSON Object returned has the following structure :
404
+ * * **id** : _id property of the Manager.
405
+ * * **key** : _key property of the Manager.
406
+ * * **type** : _componentType property of the Manager.
407
+ * * **items** : Array of JSON Object representation for each DTBunch instance in _items property of the Manager.
408
+ *
409
+ * @returns JSON Object representation of the Manager.
410
+ */
411
+ toObject(): DTManagerToObject {
412
+ const objectManager: DTManagerToObject = {
413
+ id: this._id,
414
+ key: this._key,
415
+ type: this._componentType,
416
+ items: [],
417
+ };
418
+
419
+ Object.keys(this._items).forEach((bunchId: string) => {
420
+ objectManager.items.push({
421
+ scope: this._items[bunchId].scope,
422
+ ...this._items[bunchId].item.toObject(),
423
+ });
424
+ });
425
+
426
+ return objectManager;
427
+ }
428
+
429
+ /**
430
+ * Return String representation of the Manager instance.
431
+ *
432
+ * @returns String representation of the Manager.
433
+ */
434
+ toString(): string {
435
+ const libraryLabel = `Library: ${this._library.getAll().length}`;
436
+ const domainLabel = this._domain ? ` ${this._domain}` : '';
437
+
438
+ return `Component${domainLabel} ${this._key} - Type: Manager - ${libraryLabel} - Items: ${Object.keys(this._items).length}`;
439
+ }
440
+
441
+ /**
442
+ * Get error data for scope affectation. Used in method which performs scope affectation.
443
+ *
444
+ * @param targetScope scope name to check for affectation.
445
+ * @param virtualContainer boolean if the bunch to affect has **virtualContainer** option enabled or not. Default *false*.
446
+ * @returns An Object with error code and message.
447
+ */
448
+ private getErrorDataForScope(targetScope: string, virtualContainer = false): { code: string, message: string } {
449
+ const response = { code: '', message: '' };
450
+ if (!this.isValidScope(targetScope)) {
451
+ response.code = 'invalid_scope';
452
+ response.message = "Scope provided doesn't exist in the manager";
453
+ }
454
+ if (virtualContainer && targetScope !== 'virtual') {
455
+ response.code = 'forbidden_scope';
456
+ response.message = 'Scope provided cannot be associated to a virtual bunch';
457
+ }
458
+ if (!virtualContainer && targetScope === 'virtual') {
459
+ response.code = 'forbidden_virtual_scope';
460
+ response.message = 'Virtual Scope provided cannot be associated to a physical bunch';
461
+ }
462
+
463
+ return response;
464
+ }
465
+
466
+ /**
467
+ * Return DIX Object representation of the DTManager instance.
468
+ *
469
+ * @returns DIX Object representation of the DTManager.
470
+ */
471
+ toDIXObject(): Record<string, DIXObject> {
472
+ const parentDixObject = super.toDIXObject();
473
+ const dixObject: DIXObject = {
474
+ ...parentDixObject[this._id],
475
+ items: Object.keys(this._items),
476
+ library: this._library.getId(),
477
+ };
478
+
479
+ // Library Dix Object
480
+ // Empty string for options because not relevant
481
+ const libraryDix: DIXObject = {
482
+ ...this._library.toDIXObject()[this._library.getId()],
483
+ options: '',
484
+ };
485
+
486
+ // Add Scopes
487
+ // Only non default scopes
488
+ const scopesForDix = this._scopes.filter((sc) => !['default', 'virtual'].includes(sc));
489
+ if (scopesForDix.length > 0) {
490
+ dixObject.scopes = scopesForDix;
491
+ }
492
+
493
+ const finalDix = {
494
+ [this._id]: dixObject,
495
+ ...this._library.toDIXObject(),
496
+ [this._library.getId()]: libraryDix,
497
+ };
498
+
499
+ Object.values(this._items).forEach((item) => {
500
+ const itemDix = item.item.toDIXObject();
501
+ itemDix[item.item.getId()].scope = item.scope;
502
+
503
+ Object.assign(finalDix, {
504
+ ...itemDix,
505
+ });
506
+ });
507
+
508
+ return finalDix;
509
+ }
510
+
511
+ /**
512
+ * Update the DTManager instance with a DIX Object.
513
+ *
514
+ * @param dix DIX Object to use for updating.
515
+ */
516
+ updateFromDix(dix: Record<string, DIXObject>): void {
517
+ const dixObject = dix[this._id];
518
+ const dixModule = this.getMaster()?.getModule('dix') as DTDIXModule;
519
+
520
+ if (dixObject && dixModule?.isEnabled()) {
521
+ // Synchronize Library
522
+ if (dixObject.library) {
523
+ this._library = new DTBunch('library', [], { virtualContainer: true, syncId: dixObject.library });
524
+ this._library.setContext(this);
525
+ this._library.updateFromDix(dix);
526
+ }
527
+
528
+ // Synchronize Bunches
529
+ if (dixObject.items) {
530
+ // Remove items
531
+ this.getAll().forEach((it) => {
532
+ if (!dixObject.items.includes(it.getId())) {
533
+ this.remove(it.getId());
534
+ }
535
+ });
536
+
537
+ // Add and update existing items
538
+ dixObject.items.forEach((itemId) => {
539
+ if (this.get(itemId)) {
540
+ this.get(itemId).updateFromDix(dix);
541
+ } else {
542
+ const newBunch = dixModule.syncNewItem(itemId, dix) as DTBunch<IBunchItem>;
543
+ this.add(newBunch);
544
+ newBunch.updateFromDix(dix);
545
+ }
546
+ // Move to scope
547
+ const bunchDixObject = dix[itemId];
548
+ if (bunchDixObject) {
549
+ this.moveToScope(itemId, bunchDixObject.scope);
550
+ }
551
+ });
552
+ }
553
+ }
554
+ }
555
+ }