@icure/form 2.1.2 → 2.1.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.
Files changed (57) 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-form/fields/button-group/checkbox.js +3 -4
  14. package/components/icure-form/fields/button-group/checkbox.js.map +1 -1
  15. package/components/icure-form/fields/button-group/radio-button.js +3 -4
  16. package/components/icure-form/fields/button-group/radio-button.js.map +1 -1
  17. package/components/icure-form/fields/date-picker/date-picker.js +3 -4
  18. package/components/icure-form/fields/date-picker/date-picker.js.map +1 -1
  19. package/components/icure-form/fields/date-picker/date-time-picker.js +3 -4
  20. package/components/icure-form/fields/date-picker/date-time-picker.js.map +1 -1
  21. package/components/icure-form/fields/date-picker/time-picker.js +3 -4
  22. package/components/icure-form/fields/date-picker/time-picker.js.map +1 -1
  23. package/components/icure-form/fields/dropdown/dropdown-field.js +3 -4
  24. package/components/icure-form/fields/dropdown/dropdown-field.js.map +1 -1
  25. package/components/icure-form/fields/measure-field/measure-field.js +3 -4
  26. package/components/icure-form/fields/measure-field/measure-field.js.map +1 -1
  27. package/components/icure-form/fields/number-field/number-field.js +3 -4
  28. package/components/icure-form/fields/number-field/number-field.js.map +1 -1
  29. package/components/icure-form/fields/text-field/text-field.js +3 -4
  30. package/components/icure-form/fields/text-field/text-field.js.map +1 -1
  31. package/components/icure-form/fields/utils/index.d.ts +0 -5
  32. package/components/icure-form/fields/utils/index.js +1 -12
  33. package/components/icure-form/fields/utils/index.js.map +1 -1
  34. package/components/icure-form/index.js +14 -10
  35. package/components/icure-form/index.js.map +1 -1
  36. package/components/icure-form/renderer/form/form.js +7 -5
  37. package/components/icure-form/renderer/form/form.js.map +1 -1
  38. package/components/icure-text-field/index.js +0 -2
  39. package/components/icure-text-field/index.js.map +1 -1
  40. package/components/icure-text-field/schema/measure-schema.js +0 -1
  41. package/components/icure-text-field/schema/measure-schema.js.map +1 -1
  42. package/components/model/index.d.ts +16 -16
  43. package/components/model/index.js +34 -30
  44. package/components/model/index.js.map +1 -1
  45. package/generic/model.d.ts +11 -6
  46. package/generic/model.js.map +1 -1
  47. package/icure/form-values-container.d.ts +26 -20
  48. package/icure/form-values-container.js +316 -123
  49. package/icure/form-values-container.js.map +1 -1
  50. package/icure/icure-utils.js +48 -18
  51. package/icure/icure-utils.js.map +1 -1
  52. package/package.json +1 -1
  53. package/utils/fields-values-provider.d.ts +1 -1
  54. package/utils/fields-values-provider.js +6 -4
  55. package/utils/fields-values-provider.js.map +1 -1
  56. package/.yarn/cache/prosemirror-markdown-npm-1.13.2-6e2f179fd8-ce9fcb3b13.zip +0 -0
  57. 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,54 @@ 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
+ const initPromise = newBridgedFormValueContainer.init(changedKeys, this.dependentValuesComputationIteration);
107
+ this.changeListeners.forEach((l) => notify(l, newBridgedFormValueContainer, changedKeys));
108
+ initPromise.catch((e) => {
109
+ console.log('Error while initializing new BridgedFormValuesContainer', e);
110
+ });
111
+ };
78
112
  this.contactFormValuesContainer.registerChangeListener(this.mutateAndNotify);
79
113
  this.contact = contact !== null && contact !== void 0 ? contact : contactFormValuesContainer.currentContact;
80
114
  }
115
+ /* init can be called several times on the same instance but the initialisation will only be done once */
81
116
  init() {
82
- return __awaiter(this, void 0, void 0, function* () {
117
+ return __awaiter(this, arguments, void 0, function* (changedKeys = null, pendingComputationIteration) {
83
118
  if (this.contactFormValuesContainer.mustBeInitialised()) {
84
119
  yield this.computeInitialValues();
85
120
  }
86
- yield this.computeDependentValues();
121
+ let changedKeysByInit = [];
122
+ if (pendingComputationIteration) {
123
+ const changes = yield pendingComputationIteration;
124
+ if (changes.length > 0) {
125
+ this.quietlyApplyChangesOnContactFormValueContainer(changes);
126
+ changedKeysByInit = yield this.computeDependentValues([...(changedKeys !== null && changedKeys !== void 0 ? changedKeys : []), ...changes.map(([, metadata]) => metadata.label)]);
127
+ }
128
+ else {
129
+ changedKeysByInit = yield this.computeDependentValues(changedKeys);
130
+ }
131
+ }
132
+ else {
133
+ changedKeysByInit = yield this.computeDependentValues(changedKeys);
134
+ }
135
+ //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
136
+ this.contactFormValuesContainer.changeListeners.forEach((l) => notify(l, this.contactFormValuesContainer, changedKeysByInit, changedKeysByInit.length > 0));
87
137
  return this;
88
138
  });
89
139
  }
@@ -102,12 +152,10 @@ class BridgedFormValuesContainer {
102
152
  unregisterChangeListener(listener) {
103
153
  this.changeListeners = this.changeListeners.filter((l) => l !== listener);
104
154
  }
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
- });
155
+ getDefaultValueProvider(label) {
156
+ var _a;
157
+ 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;
158
+ return formula ? () => __awaiter(this, void 0, void 0, function* () { return this.convertRawValue(yield this.compute(formula)); }) : undefined;
111
159
  }
112
160
  getValues(revisionsFilter) {
113
161
  return Object.entries(this.contactFormValuesContainer.getValues((id, history) => revisionsFilter(id, history
@@ -201,7 +249,8 @@ class BridgedFormValuesContainer {
201
249
  try {
202
250
  const currentValue = this.getValues(revisionsFilter);
203
251
  if (!currentValue || !Object.keys(currentValue).length) {
204
- const newValue = this.convertRawValue((yield this.compute(formula)));
252
+ const computedValue = (yield this.compute(formula)).value;
253
+ const newValue = computedValue ? this.convertRawValue(computedValue) : undefined;
205
254
  if (newValue !== undefined) {
206
255
  const lng = (_b = this.language) !== null && _b !== void 0 ? _b : 'en';
207
256
  if (newValue && !newValue.content[lng] && newValue.content['*']) {
@@ -228,38 +277,80 @@ class BridgedFormValuesContainer {
228
277
  });
229
278
  }
230
279
  //This method mutates the BridgedFormValuesContainer but can only be called from the constructor
231
- computeDependentValues() {
280
+ computeDependentValues(changedKeys) {
232
281
  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;
282
+ const iterate = (changedKeys, iterationCount) => __awaiter(this, void 0, void 0, function* () {
283
+ if (this.contactFormValuesContainer.rootForm.formTemplateId) {
284
+ console.log(`% ${iterationCount}, keys: ${changedKeys ? changedKeys.join(', ') : 'all'}`);
285
+ return yield Promise.all(this.dependentValuesProvider(this.contactFormValuesContainer.rootForm.descr, this.contactFormValuesContainer.rootForm.formTemplateId).map((_a) => __awaiter(this, [_a], void 0, function* ({ metadata, revisionsFilter, formula }) {
286
+ var _b, _c;
287
+ try {
288
+ if (!changedKeys || !this.dependenciesCache[formula] || this.dependenciesCache[formula].some((d) => changedKeys.includes(d))) {
289
+ const currentValue = this.getValues(revisionsFilter);
290
+ try {
291
+ const computationResult = yield this.compute(formula);
292
+ this.dependenciesCache[formula] = [...((_b = this.dependenciesCache[formula]) !== null && _b !== void 0 ? _b : []), ...computationResult.dependencies].filter((d, idx, array) => array.indexOf(d) === idx);
293
+ const newValue = computationResult.value ? this.convertRawValue(computationResult.value) : undefined;
294
+ if (newValue !== undefined || (currentValue != undefined && Object.keys(currentValue).length > 0 && currentValue[Object.keys(currentValue)[0]][0].value)) {
295
+ const lng = (_c = this.language) !== null && _c !== void 0 ? _c : 'en';
296
+ if (newValue && !newValue.content[lng] && newValue.content['*']) {
297
+ newValue.content[lng] = newValue.content['*'];
298
+ }
299
+ if (newValue) {
300
+ delete newValue.content['*'];
301
+ }
302
+ return [Object.keys(currentValue !== null && currentValue !== void 0 ? currentValue : {})[0], metadata, lng, newValue];
303
+ }
304
+ }
305
+ catch (e) {
306
+ console.log(`Error while computing formula : ${formula}`, e);
252
307
  }
253
- };
254
- setValueOnContactFormValuesContainer(this.contactFormValuesContainer, metadata.label, lng, newValue, Object.keys(currentValue !== null && currentValue !== void 0 ? currentValue : {})[0], metadata, interceptor);
308
+ }
255
309
  }
256
- }
257
- catch (e) {
258
- console.log(`Error while computing formula : ${formula}`, e);
259
- }
260
- })));
310
+ catch (e) {
311
+ console.log(`Error while computing formula : ${formula}`, e);
312
+ }
313
+ return null;
314
+ }))).then((results) => results.filter((r) => !!r));
315
+ }
316
+ else {
317
+ return [];
318
+ }
319
+ });
320
+ let latestKeys = changedKeys;
321
+ let iterationCount = 0;
322
+ const allChangedKeys = [];
323
+ while (true) {
324
+ if (latestKeys != null && latestKeys.length === 0) {
325
+ this.dependentValuesComputationIteration = undefined;
326
+ break;
327
+ }
328
+ const changes = yield (this.dependentValuesComputationIteration = iterate(latestKeys, iterationCount++));
329
+ latestKeys = this.quietlyApplyChangesOnContactFormValueContainer(changes);
330
+ allChangedKeys.push(...latestKeys);
331
+ }
332
+ return allChangedKeys;
333
+ });
334
+ }
335
+ quietlyApplyChangesOnContactFormValueContainer(changes) {
336
+ const allChangedKeys = [];
337
+ const interceptor = (fvc, changedKeys) => {
338
+ const currentContact = this.contactFormValuesContainer.currentContact;
339
+ this.contactFormValuesContainer = fvc;
340
+ if (this.contact === currentContact) {
341
+ this.contact = fvc.currentContact;
342
+ }
343
+ allChangedKeys.push(...(changedKeys !== null && changedKeys !== void 0 ? changedKeys : []));
344
+ };
345
+ changes.forEach(([id, metadata, language, newValue]) => {
346
+ try {
347
+ setValueOnContactFormValuesContainer(this.contactFormValuesContainer, metadata.label, language, newValue !== null && newValue !== void 0 ? newValue : undefined, id, metadata, interceptor);
348
+ }
349
+ catch (e) {
350
+ console.log(`Error while applying dependent value change for ${metadata.label} (${id})`, e);
261
351
  }
262
352
  });
353
+ return allChangedKeys;
263
354
  }
264
355
  setValue(label, language, fv, id, metadata) {
265
356
  setValueOnContactFormValuesContainer(this.contactFormValuesContainer, label, language, fv, id, metadata);
@@ -278,9 +369,10 @@ class BridgedFormValuesContainer {
278
369
  getVersionedValuesForKey(key) {
279
370
  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
371
  }
281
- compute(formula, sandbox) {
372
+ compute(formula) {
282
373
  return __awaiter(this, void 0, void 0, function* () {
283
374
  var _a;
375
+ const dependencies = new Set();
284
376
  // noinspection JSUnusedGlobalSymbols
285
377
  const parseContent = (content, toString = false) => {
286
378
  var _a, _b;
@@ -301,6 +393,7 @@ class BridgedFormValuesContainer {
301
393
  .join(', ');
302
394
  };
303
395
  const log = console.log;
396
+ // noinspection JSUnusedGlobalSymbols
304
397
  const native = {
305
398
  parseInt: parseInt,
306
399
  parseFloat: parseFloat,
@@ -348,42 +441,40 @@ class BridgedFormValuesContainer {
348
441
  if (!!nativeValue) {
349
442
  return nativeValue;
350
443
  }
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; });
444
+ if (key === 'self') {
445
+ return proxy;
446
+ }
447
+ else {
448
+ dependencies.add(key.toString());
449
+ 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; });
450
+ }
352
451
  },
353
452
  });
354
- return (_a = this.interpreter) === null || _a === void 0 ? void 0 : _a.call(this, formula, sandbox !== null && sandbox !== void 0 ? sandbox : proxy);
453
+ return { value: yield ((_a = this.interpreter) === null || _a === void 0 ? void 0 : _a.call(this, formula, proxy)), dependencies: Array.from(dependencies) };
355
454
  });
356
455
  }
357
456
  getChildren() {
358
457
  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;
458
+ 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
459
  });
363
460
  }
364
461
  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
- });
462
+ if (this.contactFormValuesContainer.rootForm.formTemplateId) {
463
+ 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 }) {
464
+ try {
465
+ if (!(yield this.compute(validation))) {
466
+ return [metadata, message];
467
+ }
468
+ }
469
+ catch (e) {
470
+ console.log(`Error while computing validation : ${validation}`, e);
471
+ }
472
+ return null;
473
+ })));
474
+ }
475
+ else {
476
+ return [];
477
+ }
387
478
  }
388
479
  addChild(anchorId, templateId, label) {
389
480
  return __awaiter(this, void 0, void 0, function* () {
@@ -433,17 +524,20 @@ class ContactFormValuesContainer {
433
524
  allForms() {
434
525
  return [this.rootForm].concat(this.children.flatMap((c) => c.allForms()));
435
526
  }
436
- constructor(rootForm, currentContact, contactsHistory, serviceFactory, children, formFactory, formRecycler, changeListeners = [], initialised = true) {
437
- this._id = (0, uuid_1.v4)();
527
+ constructor(rootForm, currentContact, contactsHistory, serviceFactory, children, formFactory, formRecycler, changeListeners = [], anchorId, initialised = true) {
528
+ var _a;
529
+ this._id = '';
438
530
  this._initialised = false;
439
- console.log(`Creating contact FVC (${rootForm.formTemplateId}) with ${children.length} children [${this._id}]`);
531
+ this.rootForm = rootForm;
532
+ this._id = `${((_a = rootForm.formTemplateId) !== null && _a !== void 0 ? _a : '').substring(0, 4)}.${++_ordinal}`;
533
+ console.log(`+ CFVC: ${this._id} with children { ${children.map((c) => c._id).join(', ')} }`);
440
534
  if (contactsHistory.includes(currentContact)) {
441
535
  throw new Error('Illegal argument, the history must not contain the currentContact');
442
536
  }
443
- this.rootForm = rootForm;
444
537
  this.currentContact = currentContact;
445
538
  this.contactsHistory = (0, no_lodash_1.sortedBy)(contactsHistory, 'created', 'desc');
446
539
  this.children = children;
540
+ this.anchorId = anchorId;
447
541
  this.serviceFactory = serviceFactory;
448
542
  this.formFactory = formFactory;
449
543
  this.formRecycler = formRecycler;
@@ -451,7 +545,7 @@ class ContactFormValuesContainer {
451
545
  this._initialised = initialised;
452
546
  this.indexedServices = [this.currentContact].concat(this.contactsHistory).reduce((acc, ctc) => {
453
547
  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) => {
548
+ 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
549
  var _a, _b;
456
550
  return s.id
457
551
  ? Object.assign(Object.assign({}, acc), { [s.id]: ((_a = acc[s.id]) !== null && _a !== void 0 ? _a : (acc[s.id] = [])).concat({
@@ -459,26 +553,29 @@ class ContactFormValuesContainer {
459
553
  modified: ctc.created,
460
554
  value: s,
461
555
  }) }) : acc;
462
- }, acc)) !== null && _c !== void 0 ? _c : acc;
463
- return services;
556
+ }, acc)) !== null && _c !== void 0 ? _c : acc);
464
557
  }, {});
465
558
  this.synchronise();
466
559
  }
467
560
  synchronise() {
468
561
  this.children.forEach((childFVC) => {
469
- this.registerChildFormValuesContainer(childFVC.synchronise());
562
+ var _a;
563
+ this.registerChildFormValuesContainer(childFVC.synchronise(), (_a = childFVC.anchorId) !== null && _a !== void 0 ? _a : '');
470
564
  });
471
565
  return this;
472
566
  }
473
567
  //Make sure that when a child is changed, a new version of this is created with the updated child
474
- registerChildFormValuesContainer(childFormValueContainer) {
568
+ registerChildFormValuesContainer(childFormValueContainer, anchorId) {
475
569
  childFormValueContainer.changeListeners = [
476
- (newValue) => {
570
+ (newValue, changedKeys, force) => {
571
+ if ((changedKeys === null || changedKeys === void 0 ? void 0 : changedKeys.length) === 0 && !force) {
572
+ return;
573
+ }
477
574
  console.log(`Child ${newValue._id} ${childFormValueContainer.rootForm.formTemplateId} changed, updating parent ${this._id} ${this.rootForm.formTemplateId}`);
478
575
  const newContactFormValuesContainer = new ContactFormValuesContainer(this.rootForm, this.currentContact, this.contactsHistory, this.serviceFactory, this.children.map((c) => {
479
576
  return c.rootForm.id === childFormValueContainer.rootForm.id ? newValue : c;
480
- }), this.formFactory, this.formRecycler);
481
- this.changeListeners.forEach((l) => notify(l, newContactFormValuesContainer));
577
+ }), this.formFactory, this.formRecycler, [], this.anchorId, true);
578
+ this.changeListeners.forEach((l) => notify(l, newContactFormValuesContainer, null));
482
579
  },
483
580
  ];
484
581
  }
@@ -488,8 +585,8 @@ class ContactFormValuesContainer {
488
585
  ? yield Promise.all((yield formChildrenProvider(rootForm.id)).map((f) => __awaiter(this, void 0, void 0, function* () {
489
586
  // eslint-disable-next-line max-len
490
587
  return yield ContactFormValuesContainer.fromFormsHierarchy(f, currentContact, contactsHistory, serviceFactory, formChildrenProvider, formFactory, formRecycler); })))
491
- : [], formFactory, formRecycler, changeListeners, false);
492
- contactFormValuesContainer.children.forEach((childFVC) => contactFormValuesContainer.registerChildFormValuesContainer(childFVC));
588
+ : [], formFactory, formRecycler, changeListeners, rootForm.descr, false);
589
+ contactFormValuesContainer.children.forEach((childFVC) => { var _a; return contactFormValuesContainer.registerChildFormValuesContainer(childFVC, (_a = childFVC.anchorId) !== null && _a !== void 0 ? _a : 'all'); });
493
590
  return contactFormValuesContainer;
494
591
  });
495
592
  }
@@ -513,12 +610,10 @@ class ContactFormValuesContainer {
513
610
  });
514
611
  }
515
612
  getValidationErrors() {
516
- return __awaiter(this, void 0, void 0, function* () {
517
- throw new Error('Validation not supported at contact level');
518
- });
613
+ throw new Error('Validation not supported at contact level');
519
614
  }
520
- getDefaultValue() {
521
- return Promise.resolve(undefined);
615
+ getDefaultValueProvider() {
616
+ return undefined;
522
617
  }
523
618
  getValues(revisionsFilter) {
524
619
  return Object.entries(this.getServicesInHistory(revisionsFilter)).reduce((acc, [id, history]) => history.length
@@ -563,20 +658,20 @@ class ContactFormValuesContainer {
563
658
  meta.valueDate && (newService.valueDate = meta.valueDate);
564
659
  meta.codes && (newService.codes = (0, code_utils_1.normalizeCodes)(meta.codes));
565
660
  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));
661
+ 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);
662
+ this.changeListeners.forEach((l) => notify(l, newFormValuesContainer, [meta.label]));
568
663
  }
569
664
  }
570
665
  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;
666
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t, _u, _v, _w;
572
667
  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
668
  if (!service.id) {
574
669
  throw new Error('Service id must be defined');
575
670
  }
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];
671
+ 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);
672
+ const newContent = (_d = value === null || value === void 0 ? void 0 : value.content) === null || _d === void 0 ? void 0 : _d[language];
578
673
  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 : []))) {
674
+ 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
675
  const newService = new api_1.Service(Object.assign(Object.assign({}, service), { modified: Date.now() }));
581
676
  const newContents = newContent
582
677
  ? Object.assign(Object.assign({}, (service.content || {})), { [language]: newContent }) : Object.assign({}, (service.content || {}));
@@ -585,8 +680,8 @@ class ContactFormValuesContainer {
585
680
  }
586
681
  let newCurrentContact;
587
682
  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) => {
683
+ newCurrentContact = Object.assign(Object.assign({}, this.currentContact), { subContacts: ((_g = this.currentContact.subContacts) !== null && _g !== void 0 ? _g : []).some((sc) => sc.formId === this.rootForm.id)
684
+ ? ((_h = this.currentContact.subContacts) !== null && _h !== void 0 ? _h : []).map((sc) => {
590
685
  var _a;
591
686
  if (sc.formId === this.rootForm.id) {
592
687
  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 +690,21 @@ class ContactFormValuesContainer {
595
690
  return sc;
596
691
  }
597
692
  })
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 : [])] });
693
+ : ((_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)
694
+ ? ((_l = this.currentContact.services) !== null && _l !== void 0 ? _l : []).filter((s) => s.id !== service.id)
695
+ : [...((_m = this.currentContact.services) !== null && _m !== void 0 ? _m : [])] });
601
696
  }
602
697
  else {
603
698
  newService.content = newContents;
604
699
  newService.codes = newCodes;
605
700
  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;
701
+ newService.responsible = (_o = metadata.responsible) !== null && _o !== void 0 ? _o : newService.responsible;
702
+ newService.valueDate = (_p = metadata.valueDate) !== null && _p !== void 0 ? _p : newService.valueDate;
608
703
  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;
704
+ newService.label = (_q = metadata.label) !== null && _q !== void 0 ? _q : newService.label;
610
705
  }
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) => {
706
+ newCurrentContact = Object.assign(Object.assign({}, this.currentContact), { subContacts: ((_r = this.currentContact.subContacts) !== null && _r !== void 0 ? _r : []).some((sc) => sc.formId === this.rootForm.id)
707
+ ? ((_s = this.currentContact.subContacts) !== null && _s !== void 0 ? _s : []).map((sc) => {
613
708
  var _a;
614
709
  if (sc.formId === this.rootForm.id) {
615
710
  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 +713,12 @@ class ContactFormValuesContainer {
618
713
  return sc;
619
714
  }
620
715
  })
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] });
716
+ : ((_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)
717
+ ? ((_v = this.currentContact.services) !== null && _v !== void 0 ? _v : []).map((s) => (s.id === service.id ? newService : s))
718
+ : [...((_w = this.currentContact.services) !== null && _w !== void 0 ? _w : []), newService] });
624
719
  }
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));
720
+ 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);
721
+ changeListenersOverrider ? changeListenersOverrider(newFormValuesContainer, [label]) : this.changeListeners.forEach((l) => notify(l, newFormValuesContainer, [label]));
627
722
  }
628
723
  }
629
724
  delete(serviceId) {
@@ -632,10 +727,35 @@ class ContactFormValuesContainer {
632
727
  if (service) {
633
728
  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
729
  ? 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));
730
+ : s) }), this.contactsHistory, this.serviceFactory, this.children, this.formFactory, this.formRecycler, this.changeListeners, this.anchorId, true);
731
+ 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
732
  }
638
733
  }
734
+ toMarkdownTable() {
735
+ var _a, _b, _c;
736
+ const tableRows = [];
737
+ for (const [, versions] of Object.entries(this.indexedServices)) {
738
+ if (!versions.length)
739
+ continue;
740
+ const service = versions[0].value;
741
+ const label = (_b = (_a = service.label) !== null && _a !== void 0 ? _a : service.id) !== null && _b !== void 0 ? _b : '';
742
+ const modifiedStr = service.modified ? new Date(service.modified).toISOString() : '';
743
+ const contentParts = [];
744
+ for (const [lng, cnt] of Object.entries((_c = service.content) !== null && _c !== void 0 ? _c : {})) {
745
+ const primitive = (0, icure_utils_1.contentToPrimitiveType)(lng, cnt);
746
+ if (primitive) {
747
+ contentParts.push(primitiveTypeToString(primitive));
748
+ }
749
+ }
750
+ tableRows.push([label, modifiedStr, contentParts.join(', ')]);
751
+ }
752
+ const headers = ['Label', 'Modified', 'Content'];
753
+ const colWidths = headers.map((h, i) => Math.max(h.length, ...tableRows.map((r) => r[i].length)));
754
+ const pad = (s, w) => s + ' '.repeat(w - s.length);
755
+ const formatRow = (cells) => '| ' + cells.map((c, i) => pad(c, colWidths[i])).join(' | ') + ' |';
756
+ const separator = '|' + colWidths.map((w) => '-'.repeat(w + 2)).join('|') + '|';
757
+ return [formatRow(headers), separator, ...tableRows.map(formatRow)].join('\n');
758
+ }
639
759
  compute() {
640
760
  return __awaiter(this, void 0, void 0, function* () {
641
761
  throw new Error('Compute not supported at contact level');
@@ -674,10 +794,12 @@ class ContactFormValuesContainer {
674
794
  if (!parentId)
675
795
  return;
676
796
  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));
797
+ const childFVC = new ContactFormValuesContainer(newForm, this.currentContact, this.contactsHistory, this.serviceFactory, [], this.formFactory, this.formRecycler, [], anchorId, false);
798
+ const newContactFormValuesContainer = new ContactFormValuesContainer(this.rootForm, this.currentContact, this.contactsHistory, this.serviceFactory, [...this.children, childFVC], this.formFactory, this.formRecycler, this.changeListeners, this.anchorId, true);
799
+ newContactFormValuesContainer.registerChildFormValuesContainer(childFVC, anchorId);
800
+ this.changeListeners.forEach((l) => {
801
+ notify(l, newContactFormValuesContainer, null);
802
+ });
681
803
  });
682
804
  }
683
805
  getServiceInCurrentContact(id) {
@@ -687,14 +809,85 @@ class ContactFormValuesContainer {
687
809
  }
688
810
  removeChild(container) {
689
811
  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));
812
+ 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);
813
+ this.changeListeners.forEach((l) => { var _a; return notify(l, newContactFormValuesContainer, [`subForms_${(_a = container.anchorId) !== null && _a !== void 0 ? _a : 'all'}`]); });
692
814
  });
693
815
  }
694
816
  }
695
817
  exports.ContactFormValuesContainer = ContactFormValuesContainer;
818
+ // Runtime validation for FieldValue — guards against mistyped data coming from
819
+ // external callers (formulas, SDK bridges, etc.) where the TypeScript types may
820
+ // not match the actual runtime values.
821
+ const validatePrimitiveType = (pt, path) => {
822
+ const v = pt.value;
823
+ switch (pt.type) {
824
+ case 'string':
825
+ if (typeof v !== 'string') {
826
+ throw new Error(`${path}: expected string value, got ${typeof v}`);
827
+ }
828
+ break;
829
+ case 'number':
830
+ if (typeof v !== 'number') {
831
+ throw new Error(`${path}: expected number value, got ${typeof v}`);
832
+ }
833
+ break;
834
+ case 'boolean':
835
+ if (typeof v !== 'boolean') {
836
+ throw new Error(`${path}: expected boolean value, got ${typeof v}`);
837
+ }
838
+ break;
839
+ case 'timestamp':
840
+ if (typeof v !== 'number') {
841
+ throw new Error(`${path}: expected number value for timestamp, got ${typeof v}`);
842
+ }
843
+ break;
844
+ case 'datetime':
845
+ if (typeof v !== 'number') {
846
+ throw new Error(`${path}: expected number value for datetime, got ${typeof v}`);
847
+ }
848
+ break;
849
+ case 'measure': {
850
+ const m = pt;
851
+ if (m.value !== undefined && typeof m.value !== 'number') {
852
+ throw new Error(`${path}: expected number or undefined value for measure, got ${typeof m.value}`);
853
+ }
854
+ if (m.unit !== undefined && typeof m.unit !== 'string') {
855
+ throw new Error(`${path}: expected string or undefined unit for measure, got ${typeof m.unit}`);
856
+ }
857
+ break;
858
+ }
859
+ case 'compound':
860
+ if (typeof v !== 'object' || v === null || Array.isArray(v)) {
861
+ throw new Error(`${path}: expected object value for compound, got ${Array.isArray(v) ? 'array' : typeof v}`);
862
+ }
863
+ for (const [key, subValue] of Object.entries(v)) {
864
+ validatePrimitiveType(subValue, `${path}.compound[${key}]`);
865
+ }
866
+ break;
867
+ default:
868
+ throw new Error(`${path}: unknown PrimitiveType type: ${pt.type}`);
869
+ }
870
+ };
871
+ const validateCode = (code, path) => {
872
+ const id = code.id;
873
+ if (!id || typeof id !== 'string') {
874
+ throw new Error(`${path}: code must have a non-empty string id, got ${JSON.stringify(id)}`);
875
+ }
876
+ };
877
+ const validateFieldValue = (fv, language, label) => {
878
+ const pt = fv.content[language];
879
+ if (pt) {
880
+ validatePrimitiveType(pt, `FieldValue[${label}].content[${language}]`);
881
+ }
882
+ if (fv.codes) {
883
+ fv.codes.forEach((code, i) => validateCode(code, `FieldValue[${label}].codes[${i}]`));
884
+ }
885
+ };
696
886
  const setValueOnContactFormValuesContainer = (cfvc, label, language, fv, id, metadata, changeListenersOverrider) => {
697
887
  var _a, _b;
888
+ if (fv) {
889
+ validateFieldValue(fv, language, label);
890
+ }
698
891
  const value = fv === null || fv === void 0 ? void 0 : fv.content[language];
699
892
  cfvc.setValue(label, language, {
700
893
  id: id,