@configura/web-api 2.2.0-alpha.1 → 2.2.0-alpha.3
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.
- package/.eslintrc.json +5 -5
- package/LICENSE +201 -201
- package/README.md +1 -1
- package/dist/CatalogueAPI.d.ts +633 -633
- package/dist/CatalogueAPI.js +312 -312
- package/dist/CfgMeasure.d.ts +32 -32
- package/dist/CfgMeasure.js +30 -30
- package/dist/CfgProduct.d.ts +359 -344
- package/dist/CfgProduct.js +1005 -992
- package/dist/CfgReferencePathHelper.d.ts +26 -26
- package/dist/CfgReferencePathHelper.js +26 -26
- package/dist/index.d.ts +24 -24
- package/dist/index.js +24 -24
- package/dist/io/CfgHistoryManager.d.ts +83 -83
- package/dist/io/CfgHistoryManager.js +144 -144
- package/dist/io/CfgHistoryToProdConfConnector.d.ts +21 -21
- package/dist/io/CfgHistoryToProdConfConnector.js +50 -50
- package/dist/io/CfgIOManager.d.ts +53 -53
- package/dist/io/CfgIOManager.js +134 -134
- package/dist/io/CfgIOProdConfConnector.d.ts +54 -54
- package/dist/io/CfgIOProdConfConnector.js +139 -139
- package/dist/io/CfgIOWarningSupplier.d.ts +3 -3
- package/dist/io/CfgIOWarningSupplier.js +1 -1
- package/dist/io/CfgObservableStateManager.d.ts +25 -25
- package/dist/io/CfgObservableStateManager.js +69 -69
- package/dist/io/CfgObservableStateToProdConfConnector.d.ts +15 -15
- package/dist/io/CfgObservableStateToProdConfConnector.js +17 -17
- package/dist/io/CfgWindowEventManager.d.ts +21 -21
- package/dist/io/CfgWindowEventManager.js +38 -38
- package/dist/io/CfgWindowMessageManager.d.ts +40 -40
- package/dist/io/CfgWindowMessageManager.js +91 -91
- package/dist/io/CfgWindowMessageToProdConfConnector.d.ts +17 -17
- package/dist/io/CfgWindowMessageToProdConfConnector.js +19 -19
- package/dist/io/index.d.ts +8 -8
- package/dist/io/index.js +8 -8
- package/dist/material/CfgMaterialMapping.d.ts +7 -7
- package/dist/material/CfgMaterialMapping.js +181 -181
- package/dist/material/CfgMtrlApplication.d.ts +18 -18
- package/dist/material/CfgMtrlApplication.js +43 -43
- package/dist/material/CfgMtrlApplicationSource.d.ts +7 -7
- package/dist/material/CfgMtrlApplicationSource.js +8 -8
- package/dist/material/CfgMtrlSource.d.ts +19 -19
- package/dist/material/CfgMtrlSource.js +40 -40
- package/dist/material/CfgMtrlSourceWithMetaData.d.ts +7 -7
- package/dist/material/CfgMtrlSourceWithMetaData.js +1 -1
- package/dist/productConfiguration/CfgFeature.d.ts +199 -199
- package/dist/productConfiguration/CfgFeature.js +691 -691
- package/dist/productConfiguration/CfgOption.d.ts +160 -160
- package/dist/productConfiguration/CfgOption.js +464 -464
- package/dist/productConfiguration/CfgProductConfiguration.d.ts +136 -129
- package/dist/productConfiguration/CfgProductConfiguration.js +355 -346
- package/dist/productConfiguration/filters.d.ts +17 -17
- package/dist/productConfiguration/filters.js +141 -141
- package/dist/productConfiguration/productParamsGenerator.d.ts +15 -15
- package/dist/productConfiguration/productParamsGenerator.js +65 -65
- package/dist/productConfiguration/utilitiesProductConfiguration.d.ts +17 -17
- package/dist/productConfiguration/utilitiesProductConfiguration.js +89 -87
- package/dist/productLoader.d.ts +33 -33
- package/dist/productLoader.js +49 -49
- package/dist/syncGroups/SyncGroupsApplyMode.d.ts +20 -20
- package/dist/syncGroups/SyncGroupsApplyMode.js +21 -21
- package/dist/syncGroups/SyncGroupsHandler.d.ts +47 -47
- package/dist/syncGroups/SyncGroupsHandler.js +370 -370
- package/dist/syncGroups/SyncGroupsPathHelper.d.ts +26 -26
- package/dist/syncGroups/SyncGroupsPathHelper.js +90 -90
- package/dist/syncGroups/SyncGroupsState.d.ts +39 -39
- package/dist/syncGroups/SyncGroupsState.js +167 -167
- package/dist/syncGroups/SyncGroupsTransaction.d.ts +154 -154
- package/dist/syncGroups/SyncGroupsTransaction.js +589 -589
- package/dist/tasks/TaskHandler.d.ts +77 -77
- package/dist/tasks/TaskHandler.js +276 -276
- package/dist/tasks/formats.d.ts +4 -4
- package/dist/tasks/formats.js +7 -7
- package/dist/tests/testData/collectorForTest.d.ts +73 -73
- package/dist/tests/testData/collectorForTest.js +194 -194
- package/dist/tests/testData/dummyProductForTest.d.ts +4 -4
- package/dist/tests/testData/dummyProductForTest.js +32 -32
- package/dist/tests/testData/testDataAdditionalProductInAdditionalProductInProductForTest.d.ts +11 -11
- package/dist/tests/testData/testDataAdditionalProductInAdditionalProductInProductForTest.js +282 -282
- package/dist/tests/testData/testDataCachedGetProduct.d.ts +5 -5
- package/dist/tests/testData/testDataCachedGetProduct.js +187 -187
- package/dist/tests/testData/testDataCachedPostValidate.d.ts +7 -7
- package/dist/tests/testData/testDataCachedPostValidate.js +185 -185
- package/dist/tests/testData/testDataConstraints.d.ts +3 -3
- package/dist/tests/testData/testDataConstraints.js +174 -174
- package/dist/tests/testData/testDataNoAdditionalProductNoPropagateForTest.d.ts +3 -3
- package/dist/tests/testData/testDataNoAdditionalProductNoPropagateForTest.js +1099 -1099
- package/dist/tests/testData/testDataOptions.d.ts +12 -12
- package/dist/tests/testData/testDataOptions.js +60 -60
- package/dist/tests/testData/testDataProductAggregatedPrice.d.ts +6 -6
- package/dist/tests/testData/testDataProductAggregatedPrice.js +189 -189
- package/dist/tests/testData/testDataUpcharge.d.ts +8 -8
- package/dist/tests/testData/testDataUpcharge.js +121 -121
- package/dist/utilitiesCatalogueData.d.ts +47 -47
- package/dist/utilitiesCatalogueData.js +180 -180
- package/dist/utilitiesCataloguePermission.d.ts +38 -38
- package/dist/utilitiesCataloguePermission.js +79 -79
- package/dist/utilitiesConfiguration.d.ts +28 -28
- package/dist/utilitiesConfiguration.js +200 -200
- package/dist/utilitiesNumericValues.d.ts +24 -24
- package/dist/utilitiesNumericValues.js +114 -114
- package/package.json +3 -3
|
@@ -1,346 +1,355 @@
|
|
|
1
|
-
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
2
|
-
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
3
|
-
return new (P || (P = Promise))(function (resolve, reject) {
|
|
4
|
-
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
5
|
-
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
6
|
-
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
7
|
-
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
8
|
-
});
|
|
9
|
-
};
|
|
10
|
-
import { compareArrays, count, isEqualLength, isLengthUnit, Observable, toError, toLengthUnit, } from "@configura/web-utilities";
|
|
11
|
-
import { CfgProduct } from "../CfgProduct.js";
|
|
12
|
-
import { convertDtoFeatureConfsToSelOptions } from "../utilitiesConfiguration.js";
|
|
13
|
-
import { ProductConfigurationBubbleMode } from "./CfgOption.js";
|
|
14
|
-
import { syncCfgFeatures } from "./utilitiesProductConfiguration.js";
|
|
15
|
-
/**
|
|
16
|
-
* This class is meant to only be used through CfgProductConfiguration. It should never be
|
|
17
|
-
* instantiated on its own. Normally the internal state of this class should never be directly
|
|
18
|
-
* modified. CfgProductConfiguration is the class that should be used and interacted with.
|
|
19
|
-
*/
|
|
20
|
-
export class _CfgProductConfigurationInternal {
|
|
21
|
-
constructor(rawFeatures, parentProduct, rootProduct, _initialRootFeatureRefs) {
|
|
22
|
-
this.parentProduct = parentProduct;
|
|
23
|
-
this.rootProduct = rootProduct;
|
|
24
|
-
this._initialRootFeatureRefs = _initialRootFeatureRefs;
|
|
25
|
-
this.key = "~";
|
|
26
|
-
this._rootFeatureRefs = [];
|
|
27
|
-
this.accumulatedRawFeatures = []; // Flat packed. May be extended in validate calls.
|
|
28
|
-
this._features = [];
|
|
29
|
-
this.changeObservable = new Observable();
|
|
30
|
-
this._notifyAllOfChange = (bubbleMode, committed) => __awaiter(this, void 0, void 0, function* () {
|
|
31
|
-
if (bubbleMode === ProductConfigurationBubbleMode.Stop) {
|
|
32
|
-
return;
|
|
33
|
-
}
|
|
34
|
-
const freshRef = CfgProductConfiguration._makeNewRefFrom(this);
|
|
35
|
-
const parent = this.parentProduct;
|
|
36
|
-
this.changeObservable.notifyAll({
|
|
37
|
-
freshRef,
|
|
38
|
-
committed,
|
|
39
|
-
});
|
|
40
|
-
if (parent === undefined) {
|
|
41
|
-
return;
|
|
42
|
-
}
|
|
43
|
-
yield parent._configurationHasChanged(freshRef, bubbleMode === ProductConfigurationBubbleMode.OneLevel
|
|
44
|
-
? ProductConfigurationBubbleMode.Stop
|
|
45
|
-
: bubbleMode, committed);
|
|
46
|
-
});
|
|
47
|
-
/** Called by child to tell its parent that it has changed. */
|
|
48
|
-
this._childHasChanged = (freshRef, bubbleMode, committed) => __awaiter(this, void 0, void 0, function* () {
|
|
49
|
-
const features = this._features;
|
|
50
|
-
const i = features.findIndex((a) => a.isBackedBySame(freshRef));
|
|
51
|
-
if (i === -1) {
|
|
52
|
-
throw Error("Child feature not found");
|
|
53
|
-
}
|
|
54
|
-
features[i] = freshRef;
|
|
55
|
-
yield this._notifyAllOfChange(bubbleMode, committed);
|
|
56
|
-
});
|
|
57
|
-
this.getDtoConf = (includeExtendedData) => this._features.map((f) => f._internal.getDtoConf(includeExtendedData));
|
|
58
|
-
this.getApiSelection = () => convertDtoFeatureConfsToSelOptions(this.getDtoConf(false), true);
|
|
59
|
-
this.getApiConstrained = () => this._features.map((f) => {
|
|
60
|
-
const next = {};
|
|
61
|
-
f._internal.addForApiConstrained(next);
|
|
62
|
-
return {
|
|
63
|
-
code: "!~!",
|
|
64
|
-
feature: "",
|
|
65
|
-
next,
|
|
66
|
-
};
|
|
67
|
-
});
|
|
68
|
-
/**
|
|
69
|
-
* When used internally the notifications are taken care off by the caller, but if set from
|
|
70
|
-
* outside we want notifications to bubble all the way to the root.
|
|
71
|
-
* This method will not cause validation calls. Data is assumed to already be validated.
|
|
72
|
-
*/
|
|
73
|
-
this.setApiSelection = (selectedOptions, constrOptions, bubbleToRoot) => __awaiter(this, void 0, void 0, function* () {
|
|
74
|
-
const featuresLength = this._features.length;
|
|
75
|
-
const selectedOptionsLength = selectedOptions.length;
|
|
76
|
-
if (featuresLength !== selectedOptionsLength) {
|
|
77
|
-
throw new Error(`Wrong selection count. Features on this configuration: ${featuresLength}. Passed feature count: ${selectedOptionsLength}.`);
|
|
78
|
-
}
|
|
79
|
-
if (constrOptions && featuresLength !== constrOptions.length) {
|
|
80
|
-
throw new Error(`Wrong constraint feature count. Features on this configuration: ${featuresLength}. Passed constraint feature count: ${constrOptions.length}.`);
|
|
81
|
-
}
|
|
82
|
-
const change = (yield Promise.all(this._features.map((f, i) => {
|
|
83
|
-
var _a;
|
|
84
|
-
return f._internal.setApiSelection(selectedOptions[i].next, (_a = (constrOptions !== null && constrOptions !== void 0 ? constrOptions : [])[i]) === null || _a === void 0 ? void 0 : _a.next);
|
|
85
|
-
}))).some((b) => b);
|
|
86
|
-
if (change) {
|
|
87
|
-
yield this._notifyAllOfChange(bubbleToRoot
|
|
88
|
-
? ProductConfigurationBubbleMode.ToRoot
|
|
89
|
-
: ProductConfigurationBubbleMode.OneLevel, true);
|
|
90
|
-
}
|
|
91
|
-
return change;
|
|
92
|
-
});
|
|
93
|
-
this.structureCompare = (other, strictOrder, descriptionMatch) => compareArrays(this.features, other.features, (l, r) => l._internal.structureCompare(r._internal, strictOrder, descriptionMatch), strictOrder);
|
|
94
|
-
/**
|
|
95
|
-
* When used internally the notifications are taken care off by the caller, but if set from
|
|
96
|
-
* outside we want notifications to bubble all the way to the root.
|
|
97
|
-
*/
|
|
98
|
-
this.tryMatchSelection = (other, descriptionMatch = false, // Match on case insensitive description, not code
|
|
99
|
-
validate) => __awaiter(this, void 0, void 0, function* () {
|
|
100
|
-
const thisFeatures = this.features;
|
|
101
|
-
const otherFeatures = other.features;
|
|
102
|
-
const change = (yield Promise.all(otherFeatures.map((otherF) => (() => __awaiter(this, void 0, void 0, function* () {
|
|
103
|
-
if (1 <
|
|
104
|
-
count(otherFeatures, (item) => item._internal.keyMatch(otherF._internal, descriptionMatch))) {
|
|
105
|
-
console.warn("tryMatchSelection will ignore items with same key");
|
|
106
|
-
return false;
|
|
107
|
-
}
|
|
108
|
-
const toSetFeatures = thisFeatures.filter((f) => f._internal.keyMatch(otherF._internal, descriptionMatch));
|
|
109
|
-
if (1 < toSetFeatures.length) {
|
|
110
|
-
console.warn("tryMatchSelection will ignore items with same key");
|
|
111
|
-
return false;
|
|
112
|
-
}
|
|
113
|
-
if (toSetFeatures.length === 0) {
|
|
114
|
-
return false;
|
|
115
|
-
}
|
|
116
|
-
return yield toSetFeatures[0]._internal.tryMatchSelection(otherF._internal, descriptionMatch);
|
|
117
|
-
}))()))).some((b) => b);
|
|
118
|
-
if (change) {
|
|
119
|
-
yield this._notifyAllOfChange(validate
|
|
120
|
-
? ProductConfigurationBubbleMode.Validate
|
|
121
|
-
: ProductConfigurationBubbleMode.OneLevel, true);
|
|
122
|
-
}
|
|
123
|
-
return change;
|
|
124
|
-
});
|
|
125
|
-
/** Only selected features. */
|
|
126
|
-
this._getFeaturesWithCode = (code) => this._features.reduce((agg, feature) => {
|
|
127
|
-
agg.push(...feature._internal._getFeaturesWithCode(code));
|
|
128
|
-
return agg;
|
|
129
|
-
}, []);
|
|
130
|
-
/**
|
|
131
|
-
* Extends the list of loaded potentially used features. Will warn for but ignore duplicates.
|
|
132
|
-
* Returns true if a change happened.
|
|
133
|
-
*/
|
|
134
|
-
this.addRawFeatures = (rawFeatures, warnForDuplicates) => {
|
|
135
|
-
let change = false;
|
|
136
|
-
const accumulatedRawFeatures = this.accumulatedRawFeatures;
|
|
137
|
-
for (const rawFeature of rawFeatures) {
|
|
138
|
-
const code = rawFeature.code;
|
|
139
|
-
if (accumulatedRawFeatures.find((f) => code === f.code)) {
|
|
140
|
-
if (warnForDuplicates) {
|
|
141
|
-
console.warn(`Feature ${code} was already loaded. Will ignore it.`);
|
|
142
|
-
}
|
|
143
|
-
continue;
|
|
144
|
-
}
|
|
145
|
-
accumulatedRawFeatures.push(rawFeature);
|
|
146
|
-
change = true;
|
|
147
|
-
}
|
|
148
|
-
return change;
|
|
149
|
-
};
|
|
150
|
-
this._hasRootFeaturesChanged = false;
|
|
151
|
-
/**
|
|
152
|
-
* Populates _features based on the passed @param rootFeatureRefs .
|
|
153
|
-
* @return true if a change happened.
|
|
154
|
-
*/
|
|
155
|
-
this.populateFeatures = (rootFeatureRefs) => {
|
|
156
|
-
if (compareArrays(this._rootFeatureRefs, rootFeatureRefs, (l, r) => l.code === r.code, true)) {
|
|
157
|
-
return false;
|
|
158
|
-
}
|
|
159
|
-
this._rootFeatureRefs = rootFeatureRefs;
|
|
160
|
-
this._hasRootFeaturesChanged = !compareArrays(this._initialRootFeatureRefs, rootFeatureRefs, (l, r) => l.code === r.code);
|
|
161
|
-
this._features = syncCfgFeatures(rootFeatureRefs, this._features, this.accumulatedRawFeatures, this, this, this.parentProduct, this.rootProduct);
|
|
162
|
-
return true;
|
|
163
|
-
};
|
|
164
|
-
this.setStretchReferenceLength = (measureParamCode, referenceLength, unit) => __awaiter(this, void 0, void 0, function* () {
|
|
165
|
-
if (measureParamCode === "") {
|
|
166
|
-
return false;
|
|
167
|
-
}
|
|
168
|
-
if (referenceLength === undefined) {
|
|
169
|
-
// We assume that referenceLength === undefined shall be ignored.
|
|
170
|
-
// One can add a measureParam to a Feature in Catalogue Creator
|
|
171
|
-
// without actually having any numeric values on the Options.
|
|
172
|
-
// Then this will happen. A previous version of the code assumed
|
|
173
|
-
// undefined meant reset. However, this does not seem consistent
|
|
174
|
-
// with CET.
|
|
175
|
-
return false;
|
|
176
|
-
}
|
|
177
|
-
const stretchReferenceLengthsByMeasureParamCode = this.stretchReferenceLengthsByMeasureParamCode;
|
|
178
|
-
const stretchReferenceLength = stretchReferenceLengthsByMeasureParamCode.get(measureParamCode);
|
|
179
|
-
const referenceLengthWithUnit = {
|
|
180
|
-
length: referenceLength,
|
|
181
|
-
unit,
|
|
182
|
-
};
|
|
183
|
-
if (stretchReferenceLength === undefined) {
|
|
184
|
-
stretchReferenceLengthsByMeasureParamCode.set(measureParamCode, {
|
|
185
|
-
def: undefined,
|
|
186
|
-
current: referenceLengthWithUnit,
|
|
187
|
-
});
|
|
188
|
-
}
|
|
189
|
-
else {
|
|
190
|
-
if (isEqualLength(stretchReferenceLength.current, referenceLengthWithUnit)) {
|
|
191
|
-
return false;
|
|
192
|
-
}
|
|
193
|
-
stretchReferenceLength.current = referenceLengthWithUnit;
|
|
194
|
-
}
|
|
195
|
-
yield this._notifyAllOfChange(ProductConfigurationBubbleMode.ToRoot, false);
|
|
196
|
-
return true;
|
|
197
|
-
});
|
|
198
|
-
/* eslint-disable */
|
|
199
|
-
// Useful debug tool:
|
|
200
|
-
if (false) {
|
|
201
|
-
const dbgName = `conf${parentProduct.refKey || parentProduct.key}`;
|
|
202
|
-
window[dbgName] = this;
|
|
203
|
-
window.conf = this;
|
|
204
|
-
console.log(`Use "window['${dbgName}']" or window.conf to access conf.`);
|
|
205
|
-
}
|
|
206
|
-
/* eslint-enable */
|
|
207
|
-
this.addRawFeatures(rawFeatures, true);
|
|
208
|
-
this.populateFeatures(_initialRootFeatureRefs);
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
const
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
*
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
this.
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
* This method will
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
*
|
|
285
|
-
*
|
|
286
|
-
*
|
|
287
|
-
*
|
|
288
|
-
*
|
|
289
|
-
*
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
this.
|
|
294
|
-
this.
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
*
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
internal
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
.
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
*
|
|
316
|
-
*
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
*
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
1
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
2
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
3
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
4
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
5
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
6
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
7
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
8
|
+
});
|
|
9
|
+
};
|
|
10
|
+
import { compareArrays, count, isEqualLength, isLengthUnit, Observable, toError, toLengthUnit, } from "@configura/web-utilities";
|
|
11
|
+
import { CfgProduct } from "../CfgProduct.js";
|
|
12
|
+
import { convertDtoFeatureConfsToSelOptions } from "../utilitiesConfiguration.js";
|
|
13
|
+
import { ProductConfigurationBubbleMode } from "./CfgOption.js";
|
|
14
|
+
import { syncCfgFeatures } from "./utilitiesProductConfiguration.js";
|
|
15
|
+
/**
|
|
16
|
+
* This class is meant to only be used through CfgProductConfiguration. It should never be
|
|
17
|
+
* instantiated on its own. Normally the internal state of this class should never be directly
|
|
18
|
+
* modified. CfgProductConfiguration is the class that should be used and interacted with.
|
|
19
|
+
*/
|
|
20
|
+
export class _CfgProductConfigurationInternal {
|
|
21
|
+
constructor(rawFeatures, parentProduct, rootProduct, _initialRootFeatureRefs) {
|
|
22
|
+
this.parentProduct = parentProduct;
|
|
23
|
+
this.rootProduct = rootProduct;
|
|
24
|
+
this._initialRootFeatureRefs = _initialRootFeatureRefs;
|
|
25
|
+
this.key = "~";
|
|
26
|
+
this._rootFeatureRefs = [];
|
|
27
|
+
this.accumulatedRawFeatures = []; // Flat packed. May be extended in validate calls.
|
|
28
|
+
this._features = [];
|
|
29
|
+
this.changeObservable = new Observable();
|
|
30
|
+
this._notifyAllOfChange = (bubbleMode, committed) => __awaiter(this, void 0, void 0, function* () {
|
|
31
|
+
if (bubbleMode === ProductConfigurationBubbleMode.Stop) {
|
|
32
|
+
return;
|
|
33
|
+
}
|
|
34
|
+
const freshRef = CfgProductConfiguration._makeNewRefFrom(this);
|
|
35
|
+
const parent = this.parentProduct;
|
|
36
|
+
this.changeObservable.notifyAll({
|
|
37
|
+
freshRef,
|
|
38
|
+
committed,
|
|
39
|
+
});
|
|
40
|
+
if (parent === undefined) {
|
|
41
|
+
return;
|
|
42
|
+
}
|
|
43
|
+
yield parent._configurationHasChanged(freshRef, bubbleMode === ProductConfigurationBubbleMode.OneLevel
|
|
44
|
+
? ProductConfigurationBubbleMode.Stop
|
|
45
|
+
: bubbleMode, committed);
|
|
46
|
+
});
|
|
47
|
+
/** Called by child to tell its parent that it has changed. */
|
|
48
|
+
this._childHasChanged = (freshRef, bubbleMode, committed) => __awaiter(this, void 0, void 0, function* () {
|
|
49
|
+
const features = this._features;
|
|
50
|
+
const i = features.findIndex((a) => a.isBackedBySame(freshRef));
|
|
51
|
+
if (i === -1) {
|
|
52
|
+
throw Error("Child feature not found");
|
|
53
|
+
}
|
|
54
|
+
features[i] = freshRef;
|
|
55
|
+
yield this._notifyAllOfChange(bubbleMode, committed);
|
|
56
|
+
});
|
|
57
|
+
this.getDtoConf = (includeExtendedData) => this._features.map((f) => f._internal.getDtoConf(includeExtendedData));
|
|
58
|
+
this.getApiSelection = () => convertDtoFeatureConfsToSelOptions(this.getDtoConf(false), true);
|
|
59
|
+
this.getApiConstrained = () => this._features.map((f) => {
|
|
60
|
+
const next = {};
|
|
61
|
+
f._internal.addForApiConstrained(next);
|
|
62
|
+
return {
|
|
63
|
+
code: "!~!",
|
|
64
|
+
feature: "",
|
|
65
|
+
next,
|
|
66
|
+
};
|
|
67
|
+
});
|
|
68
|
+
/**
|
|
69
|
+
* When used internally the notifications are taken care off by the caller, but if set from
|
|
70
|
+
* outside we want notifications to bubble all the way to the root.
|
|
71
|
+
* This method will not cause validation calls. Data is assumed to already be validated.
|
|
72
|
+
*/
|
|
73
|
+
this.setApiSelection = (selectedOptions, constrOptions, bubbleToRoot) => __awaiter(this, void 0, void 0, function* () {
|
|
74
|
+
const featuresLength = this._features.length;
|
|
75
|
+
const selectedOptionsLength = selectedOptions.length;
|
|
76
|
+
if (featuresLength !== selectedOptionsLength) {
|
|
77
|
+
throw new Error(`Wrong selection count. Features on this configuration: ${featuresLength}. Passed feature count: ${selectedOptionsLength}.`);
|
|
78
|
+
}
|
|
79
|
+
if (constrOptions && featuresLength !== constrOptions.length) {
|
|
80
|
+
throw new Error(`Wrong constraint feature count. Features on this configuration: ${featuresLength}. Passed constraint feature count: ${constrOptions.length}.`);
|
|
81
|
+
}
|
|
82
|
+
const change = (yield Promise.all(this._features.map((f, i) => {
|
|
83
|
+
var _a;
|
|
84
|
+
return f._internal.setApiSelection(selectedOptions[i].next, (_a = (constrOptions !== null && constrOptions !== void 0 ? constrOptions : [])[i]) === null || _a === void 0 ? void 0 : _a.next);
|
|
85
|
+
}))).some((b) => b);
|
|
86
|
+
if (change) {
|
|
87
|
+
yield this._notifyAllOfChange(bubbleToRoot
|
|
88
|
+
? ProductConfigurationBubbleMode.ToRoot
|
|
89
|
+
: ProductConfigurationBubbleMode.OneLevel, true);
|
|
90
|
+
}
|
|
91
|
+
return change;
|
|
92
|
+
});
|
|
93
|
+
this.structureCompare = (other, strictOrder, descriptionMatch) => compareArrays(this.features, other.features, (l, r) => l._internal.structureCompare(r._internal, strictOrder, descriptionMatch), strictOrder);
|
|
94
|
+
/**
|
|
95
|
+
* When used internally the notifications are taken care off by the caller, but if set from
|
|
96
|
+
* outside we want notifications to bubble all the way to the root.
|
|
97
|
+
*/
|
|
98
|
+
this.tryMatchSelection = (other, descriptionMatch = false, // Match on case insensitive description, not code
|
|
99
|
+
validate) => __awaiter(this, void 0, void 0, function* () {
|
|
100
|
+
const thisFeatures = this.features;
|
|
101
|
+
const otherFeatures = other.features;
|
|
102
|
+
const change = (yield Promise.all(otherFeatures.map((otherF) => (() => __awaiter(this, void 0, void 0, function* () {
|
|
103
|
+
if (1 <
|
|
104
|
+
count(otherFeatures, (item) => item._internal.keyMatch(otherF._internal, descriptionMatch))) {
|
|
105
|
+
console.warn("tryMatchSelection will ignore items with same key");
|
|
106
|
+
return false;
|
|
107
|
+
}
|
|
108
|
+
const toSetFeatures = thisFeatures.filter((f) => f._internal.keyMatch(otherF._internal, descriptionMatch));
|
|
109
|
+
if (1 < toSetFeatures.length) {
|
|
110
|
+
console.warn("tryMatchSelection will ignore items with same key");
|
|
111
|
+
return false;
|
|
112
|
+
}
|
|
113
|
+
if (toSetFeatures.length === 0) {
|
|
114
|
+
return false;
|
|
115
|
+
}
|
|
116
|
+
return yield toSetFeatures[0]._internal.tryMatchSelection(otherF._internal, descriptionMatch);
|
|
117
|
+
}))()))).some((b) => b);
|
|
118
|
+
if (change) {
|
|
119
|
+
yield this._notifyAllOfChange(validate
|
|
120
|
+
? ProductConfigurationBubbleMode.Validate
|
|
121
|
+
: ProductConfigurationBubbleMode.OneLevel, true);
|
|
122
|
+
}
|
|
123
|
+
return change;
|
|
124
|
+
});
|
|
125
|
+
/** Only selected features. */
|
|
126
|
+
this._getFeaturesWithCode = (code) => this._features.reduce((agg, feature) => {
|
|
127
|
+
agg.push(...feature._internal._getFeaturesWithCode(code));
|
|
128
|
+
return agg;
|
|
129
|
+
}, []);
|
|
130
|
+
/**
|
|
131
|
+
* Extends the list of loaded potentially used features. Will warn for but ignore duplicates.
|
|
132
|
+
* Returns true if a change happened.
|
|
133
|
+
*/
|
|
134
|
+
this.addRawFeatures = (rawFeatures, warnForDuplicates) => {
|
|
135
|
+
let change = false;
|
|
136
|
+
const accumulatedRawFeatures = this.accumulatedRawFeatures;
|
|
137
|
+
for (const rawFeature of rawFeatures) {
|
|
138
|
+
const code = rawFeature.code;
|
|
139
|
+
if (accumulatedRawFeatures.find((f) => code === f.code)) {
|
|
140
|
+
if (warnForDuplicates) {
|
|
141
|
+
console.warn(`Feature ${code} was already loaded. Will ignore it.`);
|
|
142
|
+
}
|
|
143
|
+
continue;
|
|
144
|
+
}
|
|
145
|
+
accumulatedRawFeatures.push(rawFeature);
|
|
146
|
+
change = true;
|
|
147
|
+
}
|
|
148
|
+
return change;
|
|
149
|
+
};
|
|
150
|
+
this._hasRootFeaturesChanged = false;
|
|
151
|
+
/**
|
|
152
|
+
* Populates _features based on the passed @param rootFeatureRefs .
|
|
153
|
+
* @return true if a change happened.
|
|
154
|
+
*/
|
|
155
|
+
this.populateFeatures = (rootFeatureRefs) => {
|
|
156
|
+
if (compareArrays(this._rootFeatureRefs, rootFeatureRefs, (l, r) => l.code === r.code, true)) {
|
|
157
|
+
return false;
|
|
158
|
+
}
|
|
159
|
+
this._rootFeatureRefs = rootFeatureRefs;
|
|
160
|
+
this._hasRootFeaturesChanged = !compareArrays(this._initialRootFeatureRefs, rootFeatureRefs, (l, r) => l.code === r.code);
|
|
161
|
+
this._features = syncCfgFeatures(rootFeatureRefs, this._features, this.accumulatedRawFeatures, this, this, this.parentProduct, this.rootProduct);
|
|
162
|
+
return true;
|
|
163
|
+
};
|
|
164
|
+
this.setStretchReferenceLength = (measureParamCode, referenceLength, unit) => __awaiter(this, void 0, void 0, function* () {
|
|
165
|
+
if (measureParamCode === "") {
|
|
166
|
+
return false;
|
|
167
|
+
}
|
|
168
|
+
if (referenceLength === undefined) {
|
|
169
|
+
// We assume that referenceLength === undefined shall be ignored.
|
|
170
|
+
// One can add a measureParam to a Feature in Catalogue Creator
|
|
171
|
+
// without actually having any numeric values on the Options.
|
|
172
|
+
// Then this will happen. A previous version of the code assumed
|
|
173
|
+
// undefined meant reset. However, this does not seem consistent
|
|
174
|
+
// with CET.
|
|
175
|
+
return false;
|
|
176
|
+
}
|
|
177
|
+
const stretchReferenceLengthsByMeasureParamCode = this.stretchReferenceLengthsByMeasureParamCode;
|
|
178
|
+
const stretchReferenceLength = stretchReferenceLengthsByMeasureParamCode.get(measureParamCode);
|
|
179
|
+
const referenceLengthWithUnit = {
|
|
180
|
+
length: referenceLength,
|
|
181
|
+
unit,
|
|
182
|
+
};
|
|
183
|
+
if (stretchReferenceLength === undefined) {
|
|
184
|
+
stretchReferenceLengthsByMeasureParamCode.set(measureParamCode, {
|
|
185
|
+
def: undefined,
|
|
186
|
+
current: referenceLengthWithUnit,
|
|
187
|
+
});
|
|
188
|
+
}
|
|
189
|
+
else {
|
|
190
|
+
if (isEqualLength(stretchReferenceLength.current, referenceLengthWithUnit)) {
|
|
191
|
+
return false;
|
|
192
|
+
}
|
|
193
|
+
stretchReferenceLength.current = referenceLengthWithUnit;
|
|
194
|
+
}
|
|
195
|
+
yield this._notifyAllOfChange(ProductConfigurationBubbleMode.ToRoot, false);
|
|
196
|
+
return true;
|
|
197
|
+
});
|
|
198
|
+
/* eslint-disable */
|
|
199
|
+
// Useful debug tool:
|
|
200
|
+
if (false) {
|
|
201
|
+
const dbgName = `conf${parentProduct.refKey || parentProduct.key}`;
|
|
202
|
+
window[dbgName] = this;
|
|
203
|
+
window.conf = this;
|
|
204
|
+
console.log(`Use "window['${dbgName}']" or window.conf to access conf.`);
|
|
205
|
+
}
|
|
206
|
+
/* eslint-enable */
|
|
207
|
+
this.addRawFeatures(rawFeatures, true);
|
|
208
|
+
this.populateFeatures(_initialRootFeatureRefs);
|
|
209
|
+
}
|
|
210
|
+
static _makeUninitialized(rootFeatureRefs, rawFeatures, // Flat packed. All the features that can currently appear anyplace in the selection tree.
|
|
211
|
+
parentProduct, rootProduct) {
|
|
212
|
+
return new this(rawFeatures, parentProduct, rootProduct, rootFeatureRefs);
|
|
213
|
+
}
|
|
214
|
+
get stretchReferenceLengthsByMeasureParamCode() {
|
|
215
|
+
if (this._stretchReferenceLengthsByMeasureParamCode === undefined) {
|
|
216
|
+
const stretchMap = new Map();
|
|
217
|
+
for (const measurementDefinition of this.parentProduct.measureDefinitions) {
|
|
218
|
+
const { measureParamCode, numericValue } = measurementDefinition;
|
|
219
|
+
if (numericValue === undefined) {
|
|
220
|
+
continue;
|
|
221
|
+
}
|
|
222
|
+
let unit;
|
|
223
|
+
const rawUnit = numericValue.unit;
|
|
224
|
+
if (rawUnit === undefined) {
|
|
225
|
+
unit = this.parentProduct.unit;
|
|
226
|
+
}
|
|
227
|
+
else if (rawUnit === "") {
|
|
228
|
+
unit = this.parentProduct.unit;
|
|
229
|
+
console.warn(`MeasureDefinition unit is empty string for code ${measureParamCode}.`);
|
|
230
|
+
}
|
|
231
|
+
else if (isLengthUnit(rawUnit)) {
|
|
232
|
+
unit = toLengthUnit(rawUnit);
|
|
233
|
+
}
|
|
234
|
+
else {
|
|
235
|
+
console.info(`MeasureDefinition unit is non length: "${rawUnit}" for code ${measureParamCode}. Ignored for stretch.`);
|
|
236
|
+
continue;
|
|
237
|
+
}
|
|
238
|
+
const referenceLength = { length: numericValue.value, unit };
|
|
239
|
+
stretchMap.set(measureParamCode, {
|
|
240
|
+
def: referenceLength,
|
|
241
|
+
current: referenceLength,
|
|
242
|
+
});
|
|
243
|
+
}
|
|
244
|
+
this._stretchReferenceLengthsByMeasureParamCode = stretchMap;
|
|
245
|
+
}
|
|
246
|
+
return this._stretchReferenceLengthsByMeasureParamCode;
|
|
247
|
+
}
|
|
248
|
+
clearStretchMeasurements() {
|
|
249
|
+
this._stretchReferenceLengthsByMeasureParamCode = undefined;
|
|
250
|
+
}
|
|
251
|
+
get rootFeatureRefs() {
|
|
252
|
+
return this._rootFeatureRefs;
|
|
253
|
+
}
|
|
254
|
+
// The root features at the root of the selection tree.
|
|
255
|
+
get features() {
|
|
256
|
+
return this._features;
|
|
257
|
+
}
|
|
258
|
+
/**
|
|
259
|
+
* True if what root Features are used is not the same as at initial load.
|
|
260
|
+
* This means that functional selection has happened.
|
|
261
|
+
*/
|
|
262
|
+
get hasRootFeaturesChanged() {
|
|
263
|
+
return this._hasRootFeaturesChanged;
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
export class CfgProductConfiguration {
|
|
267
|
+
/**
|
|
268
|
+
* Private constructor and make-method because make new ref requires the constructor to take an
|
|
269
|
+
* internal and we don't want those who instantiate CfgProductConfiguration to have to be aware
|
|
270
|
+
* of the internal.
|
|
271
|
+
*/
|
|
272
|
+
constructor(_internal) {
|
|
273
|
+
this._internal = _internal;
|
|
274
|
+
this.isBackedBySame = (other) => this._internal === other._internal;
|
|
275
|
+
this.structureCompare = (other, strictOrder = true, descriptionMatch = false) => this._internal.structureCompare(other._internal, strictOrder, descriptionMatch);
|
|
276
|
+
/**
|
|
277
|
+
* This method will try to match the selection from another product configuration
|
|
278
|
+
* This method does not propagate its selections.
|
|
279
|
+
* This method will cause validation calls.
|
|
280
|
+
*/
|
|
281
|
+
this.tryMatchSelection = (other, descriptionMatch = false // Match on case insensitive description, not code
|
|
282
|
+
) => __awaiter(this, void 0, void 0, function* () { return yield this._internal.tryMatchSelection(other._internal, descriptionMatch, true); });
|
|
283
|
+
/**
|
|
284
|
+
* Set how stretched a certain measure should be measureParamCode is the measure to be
|
|
285
|
+
* stretched referenceLength is a value relative to the initial length of the measure. If the
|
|
286
|
+
* stretch drawn up in Model Lab was from the start let's say 2.4 units from start point to end
|
|
287
|
+
* point a reference value of 4.8 would stretch the start point to end point to double length.
|
|
288
|
+
* This however does not stop things from extending outside start point to end point. So the
|
|
289
|
+
* actual perceived length after stretching might have little to do with the referenceLength.
|
|
290
|
+
* Undefined as referenceLength will clear, that is, make the stretched thing revert to its
|
|
291
|
+
* default state.
|
|
292
|
+
*/
|
|
293
|
+
this.setStretchReferenceLength = (measureParamCode, referenceLength, unit) => this._internal.setStretchReferenceLength(measureParamCode, referenceLength, unit);
|
|
294
|
+
this.listenForChange = (l) => this._internal.changeObservable.listen(l);
|
|
295
|
+
this.stopListenForChange = (l) => this._internal.changeObservable.stopListen(l);
|
|
296
|
+
this.stopAllListenForChange = () => this._internal.changeObservable.stopAllListen();
|
|
297
|
+
}
|
|
298
|
+
/**
|
|
299
|
+
* This method is semi-async. It will immediately give you a reference to the created
|
|
300
|
+
* CfgProductConfiguration, but is not properly initialized until the initDone-callback
|
|
301
|
+
* has been called.
|
|
302
|
+
*/
|
|
303
|
+
static make(initSuccess, initFail, rootFeatureRefs, rawFeatures, // Flat packed. All the features that can currently appear anyplace in the selection tree.
|
|
304
|
+
apiSelection, apiConstraints, parentProduct, rootProduct) {
|
|
305
|
+
const internal = _CfgProductConfigurationInternal._makeUninitialized(rootFeatureRefs, rawFeatures, parentProduct, rootProduct);
|
|
306
|
+
const external = new this(internal);
|
|
307
|
+
// Note the async-callback at the end of the following line. The call is async.
|
|
308
|
+
internal
|
|
309
|
+
.setApiSelection(apiSelection, apiConstraints, false)
|
|
310
|
+
.then(() => initSuccess(external))
|
|
311
|
+
.catch((e) => initFail(toError(e)));
|
|
312
|
+
return external;
|
|
313
|
+
}
|
|
314
|
+
/**
|
|
315
|
+
* Makes an object wrapping the passed object. This is not a clone method, it is a method to
|
|
316
|
+
* make a new outer reference. Like a shallow copy.
|
|
317
|
+
*
|
|
318
|
+
* We use this to help frameworks that are built around using equals to detect change.
|
|
319
|
+
*/
|
|
320
|
+
static _makeNewRefFrom(internal) {
|
|
321
|
+
return new this(internal);
|
|
322
|
+
}
|
|
323
|
+
get parentProduct() {
|
|
324
|
+
return CfgProduct._makeNewRefFrom(this._internal.parentProduct);
|
|
325
|
+
}
|
|
326
|
+
get rootProduct() {
|
|
327
|
+
return CfgProduct._makeNewRefFrom(this._internal.rootProduct);
|
|
328
|
+
}
|
|
329
|
+
get key() {
|
|
330
|
+
return this._internal.key;
|
|
331
|
+
}
|
|
332
|
+
/**
|
|
333
|
+
* Every (unprocessed) feature that is currently loaded for this product. This can be extended
|
|
334
|
+
* by validation calls. What features are actually used is controlled by rootFeatureRefs and what
|
|
335
|
+
* options are selected.
|
|
336
|
+
*/
|
|
337
|
+
get rawFeatures() {
|
|
338
|
+
return this._internal.accumulatedRawFeatures;
|
|
339
|
+
}
|
|
340
|
+
/** What features are used in the root of this. This can change with new validate calls. */
|
|
341
|
+
get rootFeatureRefs() {
|
|
342
|
+
return this._internal.rootFeatureRefs;
|
|
343
|
+
}
|
|
344
|
+
/** The root features at the root of the selection tree. */
|
|
345
|
+
get features() {
|
|
346
|
+
return this._internal.features;
|
|
347
|
+
}
|
|
348
|
+
/**
|
|
349
|
+
* Clears cached stretch measurement map. Called by the parent product when the
|
|
350
|
+
* rawProductData has changed, which may potentially change the measurements.
|
|
351
|
+
*/
|
|
352
|
+
clearStretchMeasurements() {
|
|
353
|
+
this._internal.clearStretchMeasurements();
|
|
354
|
+
}
|
|
355
|
+
}
|