@icure/form 2.1.2 → 2.1.4

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 (61) hide show
  1. package/.yarn/cache/{libphonenumber-js-npm-1.12.34-cd35ce8e26-e4bb10ba42.zip → libphonenumber-js-npm-1.12.38-a5180a8a02-2a2eeb122d.zip} +0 -0
  2. package/.yarn/cache/{lodash-npm-4.17.21-6382451519-eb835a2e51.zip → lodash-npm-4.17.23-50bdb1c01a-7daad39758.zip} +0 -0
  3. package/.yarn/cache/{markdown-it-npm-14.1.0-e337d75bfe-07296b45eb.zip → markdown-it-npm-14.1.1-45c173274d-d6d55865c6.zip} +0 -0
  4. package/.yarn/cache/prosemirror-markdown-npm-1.13.4-1a47b172bd-3306b4eca0.zip +0 -0
  5. package/.yarn/cache/prosemirror-transform-npm-1.11.0-fa260ad6f3-71989931b8.zip +0 -0
  6. package/.yarn/cache/{prosemirror-view-npm-1.41.5-39b37df338-ee47e9091a.zip → prosemirror-view-npm-1.41.6-a9d2feed27-68f6a8bd66.zip} +0 -0
  7. package/.yarn/install-state.gz +0 -0
  8. package/components/common/field.d.ts +14 -2
  9. package/components/common/field.js +95 -2
  10. package/components/common/field.js.map +1 -1
  11. package/components/common/utils.js +11 -1
  12. package/components/common/utils.js.map +1 -1
  13. package/components/icure-button-group/index.js +1 -1
  14. package/components/icure-button-group/index.js.map +1 -1
  15. package/components/icure-form/fields/button-group/checkbox.js +3 -4
  16. package/components/icure-form/fields/button-group/checkbox.js.map +1 -1
  17. package/components/icure-form/fields/button-group/radio-button.js +3 -4
  18. package/components/icure-form/fields/button-group/radio-button.js.map +1 -1
  19. package/components/icure-form/fields/date-picker/date-picker.js +3 -4
  20. package/components/icure-form/fields/date-picker/date-picker.js.map +1 -1
  21. package/components/icure-form/fields/date-picker/date-time-picker.js +3 -4
  22. package/components/icure-form/fields/date-picker/date-time-picker.js.map +1 -1
  23. package/components/icure-form/fields/date-picker/time-picker.js +3 -4
  24. package/components/icure-form/fields/date-picker/time-picker.js.map +1 -1
  25. package/components/icure-form/fields/dropdown/dropdown-field.js +3 -4
  26. package/components/icure-form/fields/dropdown/dropdown-field.js.map +1 -1
  27. package/components/icure-form/fields/measure-field/measure-field.js +3 -4
  28. package/components/icure-form/fields/measure-field/measure-field.js.map +1 -1
  29. package/components/icure-form/fields/number-field/number-field.js +3 -4
  30. package/components/icure-form/fields/number-field/number-field.js.map +1 -1
  31. package/components/icure-form/fields/text-field/text-field.js +3 -4
  32. package/components/icure-form/fields/text-field/text-field.js.map +1 -1
  33. package/components/icure-form/fields/utils/index.d.ts +0 -5
  34. package/components/icure-form/fields/utils/index.js +1 -12
  35. package/components/icure-form/fields/utils/index.js.map +1 -1
  36. package/components/icure-form/index.js +14 -10
  37. package/components/icure-form/index.js.map +1 -1
  38. package/components/icure-form/renderer/form/form.js +10 -8
  39. package/components/icure-form/renderer/form/form.js.map +1 -1
  40. package/components/icure-text-field/index.js +0 -2
  41. package/components/icure-text-field/index.js.map +1 -1
  42. package/components/icure-text-field/schema/measure-schema.js +0 -1
  43. package/components/icure-text-field/schema/measure-schema.js.map +1 -1
  44. package/components/model/index.d.ts +17 -17
  45. package/components/model/index.js +34 -30
  46. package/components/model/index.js.map +1 -1
  47. package/generic/model.d.ts +11 -6
  48. package/generic/model.js.map +1 -1
  49. package/icure/form-values-container.d.ts +33 -21
  50. package/icure/form-values-container.js +325 -154
  51. package/icure/form-values-container.js.map +1 -1
  52. package/icure/icure-utils.js +48 -18
  53. package/icure/icure-utils.js.map +1 -1
  54. package/package.json +1 -1
  55. package/utils/code-utils.js +2 -2
  56. package/utils/code-utils.js.map +1 -1
  57. package/utils/fields-values-provider.d.ts +1 -1
  58. package/utils/fields-values-provider.js +6 -4
  59. package/utils/fields-values-provider.js.map +1 -1
  60. package/.yarn/cache/prosemirror-markdown-npm-1.13.2-6e2f179fd8-ce9fcb3b13.zip +0 -0
  61. package/.yarn/cache/prosemirror-transform-npm-1.10.5-5b3b4f5f61-6f5921e53a.zip +0 -0
@@ -15,10 +15,30 @@ const no_lodash_1 = require("../utils/no-lodash");
15
15
  const icure_utils_1 = require("./icure-utils");
16
16
  const primitive_1 = require("../utils/primitive");
17
17
  const dates_1 = require("../utils/dates");
18
- const uuid_1 = require("uuid");
19
18
  const code_utils_1 = require("../utils/code-utils");
20
- function notify(l, fvc) {
21
- l(fvc);
19
+ let _ordinal = 0;
20
+ function notify(l, fvc, changedKeys, force = false) {
21
+ l(fvc, changedKeys, force);
22
+ }
23
+ function primitiveTypeToString(pt) {
24
+ switch (pt.type) {
25
+ case 'string':
26
+ return pt.value;
27
+ case 'number':
28
+ return pt.value.toString();
29
+ case 'boolean':
30
+ return pt.value.toString();
31
+ case 'measure':
32
+ return pt.value !== undefined ? `${pt.value}${pt.unit ? ' ' + pt.unit : ''}` : '';
33
+ case 'timestamp':
34
+ return new Date(pt.value).toISOString();
35
+ case 'datetime':
36
+ return pt.value.toString();
37
+ case 'compound':
38
+ return Object.entries(pt.value)
39
+ .map(([k, v]) => `${k}: ${primitiveTypeToString(v)}`)
40
+ .join(', ');
41
+ }
22
42
  }
23
43
  /** This class is a bridge between the ICure API and the generic FormValuesContainer interface.
24
44
  * It wraps around a ContactFormValuesContainer and provides a series of services:
@@ -55,8 +75,9 @@ class BridgedFormValuesContainer {
55
75
  * @param language The language in which the values are displayed
56
76
  * @param changeListeners The listeners that will be notified when the values change
57
77
  * @param interpreterContext A map with keys that are the names of the variables and values that are the functions that return the values of the variables
78
+ * @param dependenciesCache
58
79
  */
59
- constructor(responsible, contactFormValuesContainer, interpreter, contact, initialValuesProvider = () => [], dependentValuesProvider = () => [], validatorsProvider = () => [], language = 'en', changeListeners = [], interpreterContext = {}) {
80
+ constructor(responsible, contactFormValuesContainer, interpreter, contact, initialValuesProvider = () => [], dependentValuesProvider = () => [], validatorsProvider = () => [], language = 'en', changeListeners = [], interpreterContext = {}, dependenciesCache = {}) {
60
81
  this.responsible = responsible;
61
82
  this.interpreter = interpreter;
62
83
  this.initialValuesProvider = initialValuesProvider;
@@ -65,25 +86,59 @@ class BridgedFormValuesContainer {
65
86
  this.language = language;
66
87
  this.changeListeners = changeListeners;
67
88
  this.interpreterContext = interpreterContext;
68
- this._id = (0, uuid_1.v4)();
69
- console.log(`Creating bridge FVC (${contactFormValuesContainer.rootForm.formTemplateId}) with ${contactFormValuesContainer.children.length} children [${this._id}]`);
89
+ this.dependenciesCache = dependenciesCache;
90
+ this._id = '';
91
+ this.dependentValuesComputationIteration = undefined;
70
92
  //Before start to broadcast changes, we need to fill in the contactFormValuesContainer with the dependent values
71
93
  this.contactFormValuesContainer = contactFormValuesContainer;
72
- this.mutateAndNotify = (newContactFormValuesContainer) => __awaiter(this, void 0, void 0, function* () {
94
+ this._id = `[${contactFormValuesContainer._id}]`;
95
+ console.log(`+ BFVC ${this._id} created`);
96
+ this.mutateAndNotify = (newContactFormValuesContainer, changedKeys, force = false) => {
97
+ if (this.changeListeners.length === 0) {
98
+ return;
99
+ }
100
+ if (!force && this.contactFormValuesContainer === newContactFormValuesContainer) {
101
+ return;
102
+ }
103
+ this.contactFormValuesContainer.unregisterChangeListener(this.mutateAndNotify);
73
104
  newContactFormValuesContainer.unregisterChangeListener(this.mutateAndNotify);
74
- const newBridgedFormValueContainer = yield new BridgedFormValuesContainer(this.responsible, newContactFormValuesContainer, this.interpreter, this.contact === this.contactFormValuesContainer.currentContact ? newContactFormValuesContainer.currentContact : this.contact, this.initialValuesProvider, this.dependentValuesProvider, this.validatorsProvider, this.language, this.changeListeners, this.interpreterContext).init();
75
- this.changeListeners.forEach((l) => notify(l, newBridgedFormValueContainer));
76
- return newBridgedFormValueContainer;
77
- });
105
+ const newBridgedFormValueContainer = new BridgedFormValuesContainer(this.responsible, newContactFormValuesContainer, this.interpreter, this.contact === this.contactFormValuesContainer.currentContact ? newContactFormValuesContainer.currentContact : this.contact, this.initialValuesProvider, this.dependentValuesProvider, this.validatorsProvider, this.language, this.changeListeners, this.interpreterContext, this.dependenciesCache);
106
+ console.log(`- init started ${newBridgedFormValueContainer._id} with changed keys: ${changedKeys ? changedKeys.join(', ') : 'all'}`);
107
+ const initPromise = newBridgedFormValueContainer.init(changedKeys, this.dependentValuesComputationIteration);
108
+ this.changeListeners.forEach((l) => notify(l, newBridgedFormValueContainer, changedKeys));
109
+ initPromise
110
+ .catch((e) => {
111
+ console.log('Error while initializing new BridgedFormValuesContainer', e);
112
+ })
113
+ .finally(() => {
114
+ console.log(`- init finished ${newBridgedFormValueContainer._id}`);
115
+ });
116
+ };
78
117
  this.contactFormValuesContainer.registerChangeListener(this.mutateAndNotify);
79
118
  this.contact = contact !== null && contact !== void 0 ? contact : contactFormValuesContainer.currentContact;
80
119
  }
120
+ /* init can be called several times on the same instance but the initialisation will only be done once */
81
121
  init() {
82
- return __awaiter(this, void 0, void 0, function* () {
83
- if (this.contactFormValuesContainer.mustBeInitialised()) {
84
- yield this.computeInitialValues();
122
+ return __awaiter(this, arguments, void 0, function* (changedKeys = null, pendingComputationIteration) {
123
+ let changedKeysByInit = [];
124
+ if (pendingComputationIteration) {
125
+ const changes = yield pendingComputationIteration;
126
+ if (changes.length > 0) {
127
+ this.quietlyApplyChangesOnContactFormValueContainer(changes);
128
+ changedKeysByInit = yield this.computeDependentValues([...(changedKeys !== null && changedKeys !== void 0 ? changedKeys : []), ...changes.map(({ metadata }) => metadata.label)], this.contactFormValuesContainer.mustBeInitialised());
129
+ }
130
+ else {
131
+ changedKeysByInit = yield this.computeDependentValues(changedKeys, this.contactFormValuesContainer.mustBeInitialised());
132
+ }
85
133
  }
86
- yield this.computeDependentValues();
134
+ else {
135
+ console.log('Start compute');
136
+ changedKeysByInit = yield this.computeDependentValues(changedKeys, this.contactFormValuesContainer.mustBeInitialised());
137
+ console.log('Finish compute');
138
+ }
139
+ //After all the silent updates, we need a last one that causes a new BridgedFormValuesContainer to be created and broadcasted to the listeners, so that they get the final values with all the dependencies computed
140
+ console.log('Launch refresh');
141
+ this.contactFormValuesContainer.changeListeners.forEach((l) => notify(l, this.contactFormValuesContainer, changedKeysByInit, changedKeysByInit.length > 0));
87
142
  return this;
88
143
  });
89
144
  }
@@ -102,12 +157,10 @@ class BridgedFormValuesContainer {
102
157
  unregisterChangeListener(listener) {
103
158
  this.changeListeners = this.changeListeners.filter((l) => l !== listener);
104
159
  }
105
- getDefaultValue(label) {
106
- return __awaiter(this, void 0, void 0, function* () {
107
- var _a;
108
- const formula = (_a = this.initialValuesProvider(this.contactFormValuesContainer.rootForm.descr, this.contactFormValuesContainer.rootForm.formTemplateId).find(({ metadata }) => metadata.label === label)) === null || _a === void 0 ? void 0 : _a.formula;
109
- return formula ? this.convertRawValue(yield this.compute(formula)) : undefined;
110
- });
160
+ getDefaultValueProvider(label) {
161
+ var _a;
162
+ const formula = (_a = this.initialValuesProvider(this.contactFormValuesContainer.rootForm.descr, this.contactFormValuesContainer.rootForm.formTemplateId).find(({ metadata }) => metadata.label === label)) === null || _a === void 0 ? void 0 : _a.formula;
163
+ return formula ? () => __awaiter(this, void 0, void 0, function* () { return this.convertRawValue(yield this.compute(formula)); }) : undefined;
111
164
  }
112
165
  getValues(revisionsFilter) {
113
166
  return Object.entries(this.contactFormValuesContainer.getValues((id, history) => revisionsFilter(id, history
@@ -193,73 +246,89 @@ class BridgedFormValuesContainer {
193
246
  return undefined;
194
247
  }
195
248
  //This method mutates the BridgedFormValuesContainer but can only be called from the constructor
196
- computeInitialValues() {
249
+ computeDependentValues(changedKeys, computeInitialValues) {
197
250
  return __awaiter(this, void 0, void 0, function* () {
198
- if (this.contactFormValuesContainer.rootForm.formTemplateId) {
199
- yield Promise.all(this.initialValuesProvider(this.contactFormValuesContainer.rootForm.descr, this.contactFormValuesContainer.rootForm.formTemplateId).map((_a) => __awaiter(this, [_a], void 0, function* ({ metadata, revisionsFilter, formula }) {
200
- var _b;
201
- try {
202
- const currentValue = this.getValues(revisionsFilter);
203
- if (!currentValue || !Object.keys(currentValue).length) {
204
- const newValue = this.convertRawValue((yield this.compute(formula)));
205
- if (newValue !== undefined) {
206
- const lng = (_b = this.language) !== null && _b !== void 0 ? _b : 'en';
207
- if (newValue && !newValue.content[lng] && newValue.content['*']) {
208
- newValue.content[lng] = newValue.content['*'];
251
+ const initialValues = (computeInitialValues ? this.initialValuesProvider(this.contactFormValuesContainer.rootForm.descr, this.contactFormValuesContainer.rootForm.formTemplateId) : []).filter(({ revisionsFilter }) => {
252
+ const currentValue = this.getValues(revisionsFilter);
253
+ return !currentValue || !Object.keys(currentValue).length;
254
+ });
255
+ const dependentValues = this.dependentValuesProvider(this.contactFormValuesContainer.rootForm.descr, this.contactFormValuesContainer.rootForm.formTemplateId);
256
+ const iterate = (changedKeys, iterationCount) => __awaiter(this, void 0, void 0, function* () {
257
+ if (this.contactFormValuesContainer.rootForm.formTemplateId) {
258
+ console.log(`% ${iterationCount}, keys: ${changedKeys ? changedKeys.join(', ') : 'all'}`);
259
+ return yield Promise.all(dependentValues.concat(initialValues).map((_a) => __awaiter(this, [_a], void 0, function* ({ metadata, revisionsFilter, formula }) {
260
+ var _b, _c;
261
+ try {
262
+ if (!changedKeys || !this.dependenciesCache[formula] || this.dependenciesCache[formula].some((d) => changedKeys.includes(d))) {
263
+ const currentValue = this.getValues(revisionsFilter);
264
+ try {
265
+ const computationResult = yield this.compute(formula);
266
+ this.dependenciesCache[formula] = [...((_b = this.dependenciesCache[formula]) !== null && _b !== void 0 ? _b : []), ...computationResult.dependencies].filter((d, idx, array) => array.indexOf(d) === idx);
267
+ const newValue = computationResult.value ? this.convertRawValue(computationResult.value) : undefined;
268
+ if (newValue !== undefined || (currentValue != undefined && Object.keys(currentValue).length > 0 && currentValue[Object.keys(currentValue)[0]][0].value)) {
269
+ const lng = (_c = this.language) !== null && _c !== void 0 ? _c : 'en';
270
+ if (newValue && !newValue.content[lng] && newValue.content['*']) {
271
+ newValue.content[lng] = newValue.content['*'];
272
+ }
273
+ if (newValue) {
274
+ delete newValue.content['*'];
275
+ }
276
+ return { serviceId: Object.keys(currentValue !== null && currentValue !== void 0 ? currentValue : {})[0], metadata, language: lng, value: newValue };
277
+ }
209
278
  }
210
- if (newValue) {
211
- delete newValue.content['*'];
279
+ catch (e) {
280
+ console.log(`Error while computing formula : ${formula}`, e);
212
281
  }
213
- setValueOnContactFormValuesContainer(this.contactFormValuesContainer, metadata.label, lng, newValue, undefined, metadata, (fvc) => {
214
- const currentContact = this.contactFormValuesContainer.currentContact;
215
- this.contactFormValuesContainer = fvc;
216
- if (this.contact === currentContact) {
217
- this.contact = fvc.currentContact;
218
- }
219
- });
220
282
  }
221
283
  }
222
- }
223
- catch (e) {
224
- console.log(`Error while computing formula : ${formula}`, e);
225
- }
226
- })));
284
+ catch (e) {
285
+ console.log(`Error while computing formula : ${formula}`, e);
286
+ }
287
+ return null;
288
+ }))).then((results) => {
289
+ return results.filter((r) => !!r);
290
+ });
291
+ }
292
+ else {
293
+ return [];
294
+ }
295
+ });
296
+ let latestKeys = changedKeys;
297
+ const iterationCount = 0;
298
+ const allChangedKeys = [];
299
+ while (true) {
300
+ if (latestKeys != null && latestKeys.length === 0) {
301
+ this.dependentValuesComputationIteration = undefined;
302
+ break;
303
+ }
304
+ const changesPromise = iterate(latestKeys, iterationCount);
305
+ this.dependentValuesComputationIteration = changesPromise;
306
+ const changesResult = yield changesPromise;
307
+ latestKeys = this.quietlyApplyChangesOnContactFormValueContainer(changesResult);
308
+ allChangedKeys.push(...latestKeys);
227
309
  }
310
+ return allChangedKeys;
228
311
  });
229
312
  }
230
- //This method mutates the BridgedFormValuesContainer but can only be called from the constructor
231
- computeDependentValues() {
232
- return __awaiter(this, void 0, void 0, function* () {
233
- if (this.contactFormValuesContainer.rootForm.formTemplateId) {
234
- yield Promise.all(this.dependentValuesProvider(this.contactFormValuesContainer.rootForm.descr, this.contactFormValuesContainer.rootForm.formTemplateId).map((_a) => __awaiter(this, [_a], void 0, function* ({ metadata, revisionsFilter, formula }) {
235
- var _b;
236
- try {
237
- const currentValue = this.getValues(revisionsFilter);
238
- const newValue = this.convertRawValue((yield this.compute(formula)));
239
- if (newValue !== undefined || currentValue != undefined) {
240
- const lng = (_b = this.language) !== null && _b !== void 0 ? _b : 'en';
241
- if (newValue && !newValue.content[lng] && newValue.content['*']) {
242
- newValue.content[lng] = newValue.content['*'];
243
- }
244
- if (newValue) {
245
- delete newValue.content['*'];
246
- }
247
- const interceptor = (fvc) => {
248
- const currentContact = this.contactFormValuesContainer.currentContact;
249
- this.contactFormValuesContainer = fvc;
250
- if (this.contact === currentContact) {
251
- this.contact = fvc.currentContact;
252
- }
253
- };
254
- setValueOnContactFormValuesContainer(this.contactFormValuesContainer, metadata.label, lng, newValue, Object.keys(currentValue !== null && currentValue !== void 0 ? currentValue : {})[0], metadata, interceptor);
255
- }
256
- }
257
- catch (e) {
258
- console.log(`Error while computing formula : ${formula}`, e);
259
- }
260
- })));
313
+ quietlyApplyChangesOnContactFormValueContainer(changes) {
314
+ const allChangedKeys = [];
315
+ const interceptor = (fvc, changedKeys) => {
316
+ const currentContact = this.contactFormValuesContainer.currentContact;
317
+ this.contactFormValuesContainer = fvc;
318
+ if (this.contact === currentContact) {
319
+ this.contact = fvc.currentContact;
320
+ }
321
+ allChangedKeys.push(...(changedKeys !== null && changedKeys !== void 0 ? changedKeys : []));
322
+ };
323
+ changes.forEach(({ serviceId, metadata, language, value }) => {
324
+ try {
325
+ setValueOnContactFormValuesContainer(this.contactFormValuesContainer, metadata.label, language, value !== null && value !== void 0 ? value : undefined, serviceId, metadata, interceptor);
326
+ }
327
+ catch (e) {
328
+ console.log(`Error while applying dependent value change for ${metadata.label} (${serviceId})`, e);
261
329
  }
262
330
  });
331
+ return allChangedKeys;
263
332
  }
264
333
  setValue(label, language, fv, id, metadata) {
265
334
  setValueOnContactFormValuesContainer(this.contactFormValuesContainer, label, language, fv, id, metadata);
@@ -278,9 +347,10 @@ class BridgedFormValuesContainer {
278
347
  getVersionedValuesForKey(key) {
279
348
  return this.getValues((id, history) => { var _a, _b, _c; return (((_b = (_a = history === null || history === void 0 ? void 0 : history[0]) === null || _a === void 0 ? void 0 : _a.value) === null || _b === void 0 ? void 0 : _b.label) && key === history[0].value.label ? [(_c = history === null || history === void 0 ? void 0 : history[0]) === null || _c === void 0 ? void 0 : _c.revision] : []); });
280
349
  }
281
- compute(formula, sandbox) {
350
+ compute(formula) {
282
351
  return __awaiter(this, void 0, void 0, function* () {
283
352
  var _a;
353
+ const dependencies = new Set();
284
354
  // noinspection JSUnusedGlobalSymbols
285
355
  const parseContent = (content, toString = false) => {
286
356
  var _a, _b;
@@ -301,6 +371,7 @@ class BridgedFormValuesContainer {
301
371
  .join(', ');
302
372
  };
303
373
  const log = console.log;
374
+ // noinspection JSUnusedGlobalSymbols
304
375
  const native = {
305
376
  parseInt: parseInt,
306
377
  parseFloat: parseFloat,
@@ -348,42 +419,40 @@ class BridgedFormValuesContainer {
348
419
  if (!!nativeValue) {
349
420
  return nativeValue;
350
421
  }
351
- return key === 'self' ? proxy : this.interpreterContext[key] ? this.interpreterContext[key]() : Object.values(this.getVersionedValuesForKey(key)).map((v) => { var _a; return (_a = v[0]) === null || _a === void 0 ? void 0 : _a.value; });
422
+ if (key === 'self') {
423
+ return proxy;
424
+ }
425
+ else {
426
+ dependencies.add(key.toString());
427
+ return this.interpreterContext[key] ? this.interpreterContext[key]() : Object.values(this.getVersionedValuesForKey(key)).map((v) => { var _a; return (_a = v[0]) === null || _a === void 0 ? void 0 : _a.value; });
428
+ }
352
429
  },
353
430
  });
354
- return (_a = this.interpreter) === null || _a === void 0 ? void 0 : _a.call(this, formula, sandbox !== null && sandbox !== void 0 ? sandbox : proxy);
431
+ return { value: yield ((_a = this.interpreter) === null || _a === void 0 ? void 0 : _a.call(this, formula, proxy)), dependencies: Array.from(dependencies) };
355
432
  });
356
433
  }
357
434
  getChildren() {
358
435
  return __awaiter(this, void 0, void 0, function* () {
359
- const children = yield Promise.all((yield this.contactFormValuesContainer.getChildren()).map((fvc) => new BridgedFormValuesContainer(this.responsible, fvc, this.interpreter, this.contact, this.initialValuesProvider, this.dependentValuesProvider, this.validatorsProvider, this.language, [], this.interpreterContext).init()));
360
- console.log(`${children.length} children found in ${this.contactFormValuesContainer.rootForm.formTemplateId} initialised with `, this.initialValuesProvider);
361
- return children;
436
+ return yield Promise.all((yield this.contactFormValuesContainer.getChildren()).map((fvc) => new BridgedFormValuesContainer(this.responsible, fvc, this.interpreter, this.contact, this.initialValuesProvider, this.dependentValuesProvider, this.validatorsProvider, this.language, [], this.interpreterContext).init()));
362
437
  });
363
438
  }
364
439
  getValidationErrors() {
365
- return __awaiter(this, void 0, void 0, function* () {
366
- if (this.contactFormValuesContainer.rootForm.formTemplateId) {
367
- // noinspection ES6MissingAwait
368
- return yield this.validatorsProvider(this.contactFormValuesContainer.rootForm.descr, this.contactFormValuesContainer.rootForm.formTemplateId).reduce((resPromise_1, _a) => __awaiter(this, [resPromise_1, _a], void 0, function* (resPromise, { metadata, validators }) {
369
- return yield validators.reduce((resPromise_2, _a) => __awaiter(this, [resPromise_2, _a], void 0, function* (resPromise, { validation, message }) {
370
- const res = yield resPromise;
371
- try {
372
- if (!(yield this.compute(validation))) {
373
- res.push([metadata, message]);
374
- }
375
- }
376
- catch (e) {
377
- console.log(`Error while computing validation : ${validation}`, e);
378
- }
379
- return res;
380
- }), resPromise);
381
- }), Promise.resolve([]));
382
- }
383
- else {
384
- return [];
385
- }
386
- });
440
+ if (this.contactFormValuesContainer.rootForm.formTemplateId) {
441
+ return this.validatorsProvider(this.contactFormValuesContainer.rootForm.descr, this.contactFormValuesContainer.rootForm.formTemplateId).flatMap(({ metadata, validators }) => validators.map((_a) => __awaiter(this, [_a], void 0, function* ({ validation, message }) {
442
+ try {
443
+ if (!(yield this.compute(validation))) {
444
+ return [metadata, message];
445
+ }
446
+ }
447
+ catch (e) {
448
+ console.log(`Error while computing validation : ${validation}`, e);
449
+ }
450
+ return null;
451
+ })));
452
+ }
453
+ else {
454
+ return [];
455
+ }
387
456
  }
388
457
  addChild(anchorId, templateId, label) {
389
458
  return __awaiter(this, void 0, void 0, function* () {
@@ -433,17 +502,20 @@ class ContactFormValuesContainer {
433
502
  allForms() {
434
503
  return [this.rootForm].concat(this.children.flatMap((c) => c.allForms()));
435
504
  }
436
- constructor(rootForm, currentContact, contactsHistory, serviceFactory, children, formFactory, formRecycler, changeListeners = [], initialised = true) {
437
- this._id = (0, uuid_1.v4)();
505
+ constructor(rootForm, currentContact, contactsHistory, serviceFactory, children, formFactory, formRecycler, changeListeners = [], anchorId, initialised = true) {
506
+ var _a;
507
+ this._id = '';
438
508
  this._initialised = false;
439
- console.log(`Creating contact FVC (${rootForm.formTemplateId}) with ${children.length} children [${this._id}]`);
509
+ this.rootForm = rootForm;
510
+ this._id = `${((_a = rootForm.formTemplateId) !== null && _a !== void 0 ? _a : '').substring(0, 4)}.${++_ordinal}`;
511
+ console.log(`+ CFVC: ${this._id} with children { ${children.map((c) => c._id).join(', ')} }`);
440
512
  if (contactsHistory.includes(currentContact)) {
441
513
  throw new Error('Illegal argument, the history must not contain the currentContact');
442
514
  }
443
- this.rootForm = rootForm;
444
515
  this.currentContact = currentContact;
445
516
  this.contactsHistory = (0, no_lodash_1.sortedBy)(contactsHistory, 'created', 'desc');
446
517
  this.children = children;
518
+ this.anchorId = anchorId;
447
519
  this.serviceFactory = serviceFactory;
448
520
  this.formFactory = formFactory;
449
521
  this.formRecycler = formRecycler;
@@ -451,7 +523,7 @@ class ContactFormValuesContainer {
451
523
  this._initialised = initialised;
452
524
  this.indexedServices = [this.currentContact].concat(this.contactsHistory).reduce((acc, ctc) => {
453
525
  var _a, _b, _c;
454
- const services = (_c = (_b = (_a = ctc.services) === null || _a === void 0 ? void 0 : _a.filter((s) => { var _a; return (_a = ctc.subContacts) === null || _a === void 0 ? void 0 : _a.some((sc) => { var _a; return sc.formId === this.rootForm.id && ((_a = sc.services) === null || _a === void 0 ? void 0 : _a.some((sss) => sss.serviceId === s.id)); }); })) === null || _b === void 0 ? void 0 : _b.reduce((acc, s) => {
526
+ return ((_c = (_b = (_a = ctc.services) === null || _a === void 0 ? void 0 : _a.filter((s) => { var _a; return (_a = ctc.subContacts) === null || _a === void 0 ? void 0 : _a.some((sc) => { var _a; return sc.formId === this.rootForm.id && ((_a = sc.services) === null || _a === void 0 ? void 0 : _a.some((sss) => sss.serviceId === s.id)); }); })) === null || _b === void 0 ? void 0 : _b.reduce((acc, s) => {
455
527
  var _a, _b;
456
528
  return s.id
457
529
  ? Object.assign(Object.assign({}, acc), { [s.id]: ((_a = acc[s.id]) !== null && _a !== void 0 ? _a : (acc[s.id] = [])).concat({
@@ -459,26 +531,29 @@ class ContactFormValuesContainer {
459
531
  modified: ctc.created,
460
532
  value: s,
461
533
  }) }) : acc;
462
- }, acc)) !== null && _c !== void 0 ? _c : acc;
463
- return services;
534
+ }, acc)) !== null && _c !== void 0 ? _c : acc);
464
535
  }, {});
465
536
  this.synchronise();
466
537
  }
467
538
  synchronise() {
468
539
  this.children.forEach((childFVC) => {
469
- this.registerChildFormValuesContainer(childFVC.synchronise());
540
+ var _a;
541
+ this.registerChildFormValuesContainer(childFVC.synchronise(), (_a = childFVC.anchorId) !== null && _a !== void 0 ? _a : '');
470
542
  });
471
543
  return this;
472
544
  }
473
545
  //Make sure that when a child is changed, a new version of this is created with the updated child
474
- registerChildFormValuesContainer(childFormValueContainer) {
546
+ registerChildFormValuesContainer(childFormValueContainer, anchorId) {
475
547
  childFormValueContainer.changeListeners = [
476
- (newValue) => {
548
+ (newValue, changedKeys, force) => {
549
+ if ((changedKeys === null || changedKeys === void 0 ? void 0 : changedKeys.length) === 0 && !force) {
550
+ return;
551
+ }
477
552
  console.log(`Child ${newValue._id} ${childFormValueContainer.rootForm.formTemplateId} changed, updating parent ${this._id} ${this.rootForm.formTemplateId}`);
478
553
  const newContactFormValuesContainer = new ContactFormValuesContainer(this.rootForm, this.currentContact, this.contactsHistory, this.serviceFactory, this.children.map((c) => {
479
554
  return c.rootForm.id === childFormValueContainer.rootForm.id ? newValue : c;
480
- }), this.formFactory, this.formRecycler);
481
- this.changeListeners.forEach((l) => notify(l, newContactFormValuesContainer));
555
+ }), this.formFactory, this.formRecycler, [], this.anchorId, true);
556
+ this.changeListeners.forEach((l) => notify(l, newContactFormValuesContainer, null));
482
557
  },
483
558
  ];
484
559
  }
@@ -488,8 +563,8 @@ class ContactFormValuesContainer {
488
563
  ? yield Promise.all((yield formChildrenProvider(rootForm.id)).map((f) => __awaiter(this, void 0, void 0, function* () {
489
564
  // eslint-disable-next-line max-len
490
565
  return yield ContactFormValuesContainer.fromFormsHierarchy(f, currentContact, contactsHistory, serviceFactory, formChildrenProvider, formFactory, formRecycler); })))
491
- : [], formFactory, formRecycler, changeListeners, false);
492
- contactFormValuesContainer.children.forEach((childFVC) => contactFormValuesContainer.registerChildFormValuesContainer(childFVC));
566
+ : [], formFactory, formRecycler, changeListeners, rootForm.descr, false);
567
+ contactFormValuesContainer.children.forEach((childFVC) => { var _a; return contactFormValuesContainer.registerChildFormValuesContainer(childFVC, (_a = childFVC.anchorId) !== null && _a !== void 0 ? _a : 'all'); });
493
568
  return contactFormValuesContainer;
494
569
  });
495
570
  }
@@ -513,12 +588,10 @@ class ContactFormValuesContainer {
513
588
  });
514
589
  }
515
590
  getValidationErrors() {
516
- return __awaiter(this, void 0, void 0, function* () {
517
- throw new Error('Validation not supported at contact level');
518
- });
591
+ throw new Error('Validation not supported at contact level');
519
592
  }
520
- getDefaultValue() {
521
- return Promise.resolve(undefined);
593
+ getDefaultValueProvider() {
594
+ return undefined;
522
595
  }
523
596
  getValues(revisionsFilter) {
524
597
  return Object.entries(this.getServicesInHistory(revisionsFilter)).reduce((acc, [id, history]) => history.length
@@ -563,20 +636,20 @@ class ContactFormValuesContainer {
563
636
  meta.valueDate && (newService.valueDate = meta.valueDate);
564
637
  meta.codes && (newService.codes = (0, code_utils_1.normalizeCodes)(meta.codes));
565
638
  meta.tags && (newService.tags = (0, code_utils_1.normalizeCodes)(meta.tags));
566
- const newFormValuesContainer = new ContactFormValuesContainer(this.rootForm, Object.assign(Object.assign({}, this.currentContact), { services: (_a = this.currentContact.services) === null || _a === void 0 ? void 0 : _a.map((s) => (s.id === service.id ? newService : s)) }), this.contactsHistory, this.serviceFactory, this.children, this.formFactory, this.formRecycler, this.changeListeners);
567
- this.changeListeners.forEach((l) => notify(l, newFormValuesContainer));
639
+ const newFormValuesContainer = new ContactFormValuesContainer(this.rootForm, Object.assign(Object.assign({}, this.currentContact), { services: (_a = this.currentContact.services) === null || _a === void 0 ? void 0 : _a.map((s) => (s.id === service.id ? newService : s)) }), this.contactsHistory, this.serviceFactory, this.children, this.formFactory, this.formRecycler, this.changeListeners, this.anchorId, true);
640
+ this.changeListeners.forEach((l) => notify(l, newFormValuesContainer, [meta.label]));
568
641
  }
569
642
  }
570
643
  setValue(label, language, value, id, metadata, changeListenersOverrider) {
571
- var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t, _u, _v;
644
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t, _u, _v, _w;
572
645
  const service = (id && ((_b = (_a = this.getServicesInHistory((sid, history) => (sid === id ? history.map((x) => x.revision) : []))[id]) === null || _a === void 0 ? void 0 : _a[0]) === null || _b === void 0 ? void 0 : _b.value)) || this.serviceFactory(label, id);
573
646
  if (!service.id) {
574
647
  throw new Error('Service id must be defined');
575
648
  }
576
- console.log('Setting value of service', service.id, 'with', value, 'and metadata', metadata);
577
- const newContent = (_c = value === null || value === void 0 ? void 0 : value.content) === null || _c === void 0 ? void 0 : _c[language];
649
+ console.log(`Setting value of service ${service.label} [${service.id}] to ${Object.entries((_c = value === null || value === void 0 ? void 0 : value.content) !== null && _c !== void 0 ? _c : {}).map(([k, c]) => `${k}: ${JSON.stringify((0, icure_utils_1.contentToPrimitiveType)(k, c))}`)} and md`, metadata);
650
+ const newContent = (_d = value === null || value === void 0 ? void 0 : value.content) === null || _d === void 0 ? void 0 : _d[language];
578
651
  const newCodes = (value === null || value === void 0 ? void 0 : value.codes) ? (0, code_utils_1.normalizeCodes)(value.codes) : [];
579
- if (!(0, icure_utils_1.isContentEqual)((_d = service.content) === null || _d === void 0 ? void 0 : _d[language], newContent) || (newCodes && !(0, icure_utils_1.areCodesEqual)(newCodes, (_e = service.codes) !== null && _e !== void 0 ? _e : []))) {
652
+ if (!(0, icure_utils_1.isContentEqual)((_e = service.content) === null || _e === void 0 ? void 0 : _e[language], newContent) || (newCodes && !(0, icure_utils_1.areCodesEqual)(newCodes, (_f = service.codes) !== null && _f !== void 0 ? _f : []))) {
580
653
  const newService = new api_1.Service(Object.assign(Object.assign({}, service), { modified: Date.now() }));
581
654
  const newContents = newContent
582
655
  ? Object.assign(Object.assign({}, (service.content || {})), { [language]: newContent }) : Object.assign({}, (service.content || {}));
@@ -585,8 +658,8 @@ class ContactFormValuesContainer {
585
658
  }
586
659
  let newCurrentContact;
587
660
  if (!Object.entries(newContents).filter(([, cnt]) => cnt !== undefined).length) {
588
- newCurrentContact = Object.assign(Object.assign({}, this.currentContact), { subContacts: ((_f = this.currentContact.subContacts) !== null && _f !== void 0 ? _f : []).some((sc) => sc.formId === this.rootForm.id)
589
- ? ((_g = this.currentContact.subContacts) !== null && _g !== void 0 ? _g : []).map((sc) => {
661
+ newCurrentContact = Object.assign(Object.assign({}, this.currentContact), { subContacts: ((_g = this.currentContact.subContacts) !== null && _g !== void 0 ? _g : []).some((sc) => sc.formId === this.rootForm.id)
662
+ ? ((_h = this.currentContact.subContacts) !== null && _h !== void 0 ? _h : []).map((sc) => {
590
663
  var _a;
591
664
  if (sc.formId === this.rootForm.id) {
592
665
  return Object.assign(Object.assign({}, sc), { services: ((_a = sc.services) !== null && _a !== void 0 ? _a : []).filter((s) => s.serviceId !== service.id).concat([{ serviceId: service.id }]) });
@@ -595,21 +668,21 @@ class ContactFormValuesContainer {
595
668
  return sc;
596
669
  }
597
670
  })
598
- : ((_h = this.currentContact.subContacts) !== null && _h !== void 0 ? _h : []).concat({ formId: this.rootForm.id, services: [{ serviceId: service.id }] }), services: ((_j = this.currentContact.services) !== null && _j !== void 0 ? _j : []).some((s) => s.id === service.id)
599
- ? ((_k = this.currentContact.services) !== null && _k !== void 0 ? _k : []).filter((s) => s.id !== service.id)
600
- : [...((_l = this.currentContact.services) !== null && _l !== void 0 ? _l : [])] });
671
+ : ((_j = this.currentContact.subContacts) !== null && _j !== void 0 ? _j : []).concat({ formId: this.rootForm.id, services: [{ serviceId: service.id }] }), services: ((_k = this.currentContact.services) !== null && _k !== void 0 ? _k : []).some((s) => s.id === service.id)
672
+ ? ((_l = this.currentContact.services) !== null && _l !== void 0 ? _l : []).filter((s) => s.id !== service.id)
673
+ : [...((_m = this.currentContact.services) !== null && _m !== void 0 ? _m : [])] });
601
674
  }
602
675
  else {
603
676
  newService.content = newContents;
604
677
  newService.codes = newCodes;
605
678
  if (metadata) {
606
- newService.responsible = (_m = metadata.responsible) !== null && _m !== void 0 ? _m : newService.responsible;
607
- newService.valueDate = (_o = metadata.valueDate) !== null && _o !== void 0 ? _o : newService.valueDate;
679
+ newService.responsible = (_o = metadata.responsible) !== null && _o !== void 0 ? _o : newService.responsible;
680
+ newService.valueDate = (_p = metadata.valueDate) !== null && _p !== void 0 ? _p : newService.valueDate;
608
681
  newService.tags = metadata.tags ? (0, code_utils_1.normalizeCodes)(metadata.tags) : newService.tags;
609
- newService.label = (_p = metadata.label) !== null && _p !== void 0 ? _p : newService.label;
682
+ newService.label = (_q = metadata.label) !== null && _q !== void 0 ? _q : newService.label;
610
683
  }
611
- newCurrentContact = Object.assign(Object.assign({}, this.currentContact), { subContacts: ((_q = this.currentContact.subContacts) !== null && _q !== void 0 ? _q : []).some((sc) => sc.formId === this.rootForm.id)
612
- ? ((_r = this.currentContact.subContacts) !== null && _r !== void 0 ? _r : []).map((sc) => {
684
+ newCurrentContact = Object.assign(Object.assign({}, this.currentContact), { subContacts: ((_r = this.currentContact.subContacts) !== null && _r !== void 0 ? _r : []).some((sc) => sc.formId === this.rootForm.id)
685
+ ? ((_s = this.currentContact.subContacts) !== null && _s !== void 0 ? _s : []).map((sc) => {
613
686
  var _a;
614
687
  if (sc.formId === this.rootForm.id) {
615
688
  return Object.assign(Object.assign({}, sc), { services: ((_a = sc.services) !== null && _a !== void 0 ? _a : []).filter((s) => s.serviceId !== service.id).concat([{ serviceId: service.id }]) });
@@ -618,12 +691,12 @@ class ContactFormValuesContainer {
618
691
  return sc;
619
692
  }
620
693
  })
621
- : ((_s = this.currentContact.subContacts) !== null && _s !== void 0 ? _s : []).concat({ formId: this.rootForm.id, services: [{ serviceId: service.id }] }), services: ((_t = this.currentContact.services) !== null && _t !== void 0 ? _t : []).some((s) => s.id === service.id)
622
- ? ((_u = this.currentContact.services) !== null && _u !== void 0 ? _u : []).map((s) => (s.id === service.id ? newService : s))
623
- : [...((_v = this.currentContact.services) !== null && _v !== void 0 ? _v : []), newService] });
694
+ : ((_t = this.currentContact.subContacts) !== null && _t !== void 0 ? _t : []).concat({ formId: this.rootForm.id, services: [{ serviceId: service.id }] }), services: ((_u = this.currentContact.services) !== null && _u !== void 0 ? _u : []).some((s) => s.id === service.id)
695
+ ? ((_v = this.currentContact.services) !== null && _v !== void 0 ? _v : []).map((s) => (s.id === service.id ? newService : s))
696
+ : [...((_w = this.currentContact.services) !== null && _w !== void 0 ? _w : []), newService] });
624
697
  }
625
- const newFormValuesContainer = new ContactFormValuesContainer(this.rootForm, newCurrentContact, this.contactsHistory.map((c) => (c === this.currentContact ? newCurrentContact : c)), this.serviceFactory, this.children, this.formFactory, this.formRecycler, this.changeListeners);
626
- changeListenersOverrider ? changeListenersOverrider(newFormValuesContainer) : this.changeListeners.forEach((l) => notify(l, newFormValuesContainer));
698
+ const newFormValuesContainer = new ContactFormValuesContainer(this.rootForm, newCurrentContact, this.contactsHistory.map((c) => (c === this.currentContact ? newCurrentContact : c)), this.serviceFactory, this.children, this.formFactory, this.formRecycler, this.changeListeners, this.anchorId, true);
699
+ changeListenersOverrider ? changeListenersOverrider(newFormValuesContainer, [label]) : this.changeListeners.forEach((l) => notify(l, newFormValuesContainer, [label]));
627
700
  }
628
701
  }
629
702
  delete(serviceId) {
@@ -632,10 +705,35 @@ class ContactFormValuesContainer {
632
705
  if (service) {
633
706
  const newFormValuesContainer = new ContactFormValuesContainer(this.rootForm, Object.assign(Object.assign({}, this.currentContact), { services: (_a = this.currentContact.services) === null || _a === void 0 ? void 0 : _a.map((s) => s.id === serviceId
634
707
  ? new api_1.Service(Object.assign(Object.assign({}, service), { endOfLife: Date.now() }))
635
- : s) }), this.contactsHistory, this.serviceFactory, this.children, this.formFactory, this.formRecycler, this.changeListeners);
636
- this.changeListeners.forEach((l) => notify(l, newFormValuesContainer));
708
+ : s) }), this.contactsHistory, this.serviceFactory, this.children, this.formFactory, this.formRecycler, this.changeListeners, this.anchorId, true);
709
+ this.changeListeners.forEach((l) => { var _a, _b; return notify(l, newFormValuesContainer, [(_b = (_a = service.label) !== null && _a !== void 0 ? _a : service.id) !== null && _b !== void 0 ? _b : ''] /* only the label is going to propagate the changes for the formulas */); });
637
710
  }
638
711
  }
712
+ toMarkdownTable() {
713
+ var _a, _b, _c;
714
+ const tableRows = [];
715
+ for (const [, versions] of Object.entries(this.indexedServices)) {
716
+ if (!versions.length)
717
+ continue;
718
+ const service = versions[0].value;
719
+ const label = (_b = (_a = service.label) !== null && _a !== void 0 ? _a : service.id) !== null && _b !== void 0 ? _b : '';
720
+ const modifiedStr = service.modified ? new Date(service.modified).toISOString() : '';
721
+ const contentParts = [];
722
+ for (const [lng, cnt] of Object.entries((_c = service.content) !== null && _c !== void 0 ? _c : {})) {
723
+ const primitive = (0, icure_utils_1.contentToPrimitiveType)(lng, cnt);
724
+ if (primitive) {
725
+ contentParts.push(primitiveTypeToString(primitive));
726
+ }
727
+ }
728
+ tableRows.push([label, modifiedStr, contentParts.join(', ')]);
729
+ }
730
+ const headers = ['Label', 'Modified', 'Content'];
731
+ const colWidths = headers.map((h, i) => Math.max(h.length, ...tableRows.map((r) => r[i].length)));
732
+ const pad = (s, w) => s + ' '.repeat(w - s.length);
733
+ const formatRow = (cells) => '| ' + cells.map((c, i) => pad(c, colWidths[i])).join(' | ') + ' |';
734
+ const separator = '|' + colWidths.map((w) => '-'.repeat(w + 2)).join('|') + '|';
735
+ return [formatRow(headers), separator, ...tableRows.map(formatRow)].join('\n');
736
+ }
639
737
  compute() {
640
738
  return __awaiter(this, void 0, void 0, function* () {
641
739
  throw new Error('Compute not supported at contact level');
@@ -674,10 +772,12 @@ class ContactFormValuesContainer {
674
772
  if (!parentId)
675
773
  return;
676
774
  const newForm = yield this.formFactory(parentId, anchorId, templateId, label);
677
- const childFVC = new ContactFormValuesContainer(newForm, this.currentContact, this.contactsHistory, this.serviceFactory, [], this.formFactory, this.formRecycler, [], false);
678
- const newContactFormValuesContainer = new ContactFormValuesContainer(this.rootForm, this.currentContact, this.contactsHistory, this.serviceFactory, [...this.children, childFVC], this.formFactory, this.formRecycler, this.changeListeners);
679
- newContactFormValuesContainer.registerChildFormValuesContainer(childFVC);
680
- this.changeListeners.forEach((l) => notify(l, newContactFormValuesContainer));
775
+ const childFVC = new ContactFormValuesContainer(newForm, this.currentContact, this.contactsHistory, this.serviceFactory, [], this.formFactory, this.formRecycler, [], anchorId, false);
776
+ const newContactFormValuesContainer = new ContactFormValuesContainer(this.rootForm, this.currentContact, this.contactsHistory, this.serviceFactory, [...this.children, childFVC], this.formFactory, this.formRecycler, this.changeListeners, this.anchorId, true);
777
+ newContactFormValuesContainer.registerChildFormValuesContainer(childFVC, anchorId);
778
+ this.changeListeners.forEach((l) => {
779
+ notify(l, newContactFormValuesContainer, null);
780
+ });
681
781
  });
682
782
  }
683
783
  getServiceInCurrentContact(id) {
@@ -687,14 +787,85 @@ class ContactFormValuesContainer {
687
787
  }
688
788
  removeChild(container) {
689
789
  return __awaiter(this, void 0, void 0, function* () {
690
- const newContactFormValuesContainer = new ContactFormValuesContainer(this.rootForm, this.currentContact, this.contactsHistory, this.serviceFactory, this.children.filter((c) => c.rootForm.id !== container.rootForm.id), this.formFactory, this.formRecycler, this.changeListeners);
691
- this.changeListeners.forEach((l) => notify(l, newContactFormValuesContainer));
790
+ const newContactFormValuesContainer = new ContactFormValuesContainer(this.rootForm, this.currentContact, this.contactsHistory, this.serviceFactory, this.children.filter((c) => c.rootForm.id !== container.rootForm.id), this.formFactory, this.formRecycler, this.changeListeners, this.anchorId, true);
791
+ this.changeListeners.forEach((l) => { var _a; return notify(l, newContactFormValuesContainer, [`subForms_${(_a = container.anchorId) !== null && _a !== void 0 ? _a : 'all'}`]); });
692
792
  });
693
793
  }
694
794
  }
695
795
  exports.ContactFormValuesContainer = ContactFormValuesContainer;
796
+ // Runtime validation for FieldValue — guards against mistyped data coming from
797
+ // external callers (formulas, SDK bridges, etc.) where the TypeScript types may
798
+ // not match the actual runtime values.
799
+ const validatePrimitiveType = (pt, path) => {
800
+ const v = pt.value;
801
+ switch (pt.type) {
802
+ case 'string':
803
+ if (typeof v !== 'string') {
804
+ throw new Error(`${path}: expected string value, got ${typeof v}`);
805
+ }
806
+ break;
807
+ case 'number':
808
+ if (typeof v !== 'number') {
809
+ throw new Error(`${path}: expected number value, got ${typeof v}`);
810
+ }
811
+ break;
812
+ case 'boolean':
813
+ if (typeof v !== 'boolean') {
814
+ throw new Error(`${path}: expected boolean value, got ${typeof v}`);
815
+ }
816
+ break;
817
+ case 'timestamp':
818
+ if (typeof v !== 'number') {
819
+ throw new Error(`${path}: expected number value for timestamp, got ${typeof v}`);
820
+ }
821
+ break;
822
+ case 'datetime':
823
+ if (typeof v !== 'number') {
824
+ throw new Error(`${path}: expected number value for datetime, got ${typeof v}`);
825
+ }
826
+ break;
827
+ case 'measure': {
828
+ const m = pt;
829
+ if (m.value !== undefined && typeof m.value !== 'number') {
830
+ throw new Error(`${path}: expected number or undefined value for measure, got ${typeof m.value}`);
831
+ }
832
+ if (m.unit !== undefined && typeof m.unit !== 'string') {
833
+ throw new Error(`${path}: expected string or undefined unit for measure, got ${typeof m.unit}`);
834
+ }
835
+ break;
836
+ }
837
+ case 'compound':
838
+ if (typeof v !== 'object' || v === null || Array.isArray(v)) {
839
+ throw new Error(`${path}: expected object value for compound, got ${Array.isArray(v) ? 'array' : typeof v}`);
840
+ }
841
+ for (const [key, subValue] of Object.entries(v)) {
842
+ validatePrimitiveType(subValue, `${path}.compound[${key}]`);
843
+ }
844
+ break;
845
+ default:
846
+ throw new Error(`${path}: unknown PrimitiveType type: ${pt.type}`);
847
+ }
848
+ };
849
+ const validateCode = (code, path) => {
850
+ const id = code.id;
851
+ if (!id || typeof id !== 'string') {
852
+ throw new Error(`${path}: code must have a non-empty string id, got ${JSON.stringify(id)}`);
853
+ }
854
+ };
855
+ const validateFieldValue = (fv, language, label) => {
856
+ const pt = fv.content[language];
857
+ if (pt) {
858
+ validatePrimitiveType(pt, `FieldValue[${label}].content[${language}]`);
859
+ }
860
+ if (fv.codes) {
861
+ fv.codes.forEach((code, i) => validateCode(code, `FieldValue[${label}].codes[${i}]`));
862
+ }
863
+ };
696
864
  const setValueOnContactFormValuesContainer = (cfvc, label, language, fv, id, metadata, changeListenersOverrider) => {
697
865
  var _a, _b;
866
+ if (fv) {
867
+ validateFieldValue(fv, language, label);
868
+ }
698
869
  const value = fv === null || fv === void 0 ? void 0 : fv.content[language];
699
870
  cfvc.setValue(label, language, {
700
871
  id: id,