@icure/form 3.0.46 → 3.1.1

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 (68) hide show
  1. package/.yarn/cache/{@babel-runtime-npm-7.28.4-31bc1b0001-934b0a0460.zip → @babel-runtime-npm-7.28.6-f40c99aeef-42d8a868c2.zip} +0 -0
  2. package/.yarn/cache/@lit-labs-ssr-dom-shim-npm-1.5.1-3b3c832bd1-22c404c481.zip +0 -0
  3. package/.yarn/cache/@lit-reactive-element-npm-2.1.2-2c713bebce-e0ed931b9c.zip +0 -0
  4. package/.yarn/cache/{lit-element-npm-4.2.1-b5bc114ced-5925326176.zip → lit-element-npm-4.2.2-70d4af2233-554254b87c.zip} +0 -0
  5. package/.yarn/cache/lit-html-npm-3.3.2-4a3e00215f-7fe23502ca.zip +0 -0
  6. package/.yarn/cache/{lit-npm-3.3.1-8f683c51f1-fb88f1ff80.zip → lit-npm-3.3.2-7dea58471e-2136d4beac.zip} +0 -0
  7. package/.yarn/cache/{markdown-it-npm-14.1.0-e337d75bfe-07296b45eb.zip → markdown-it-npm-14.1.1-45c173274d-d6d55865c6.zip} +0 -0
  8. package/.yarn/cache/prosemirror-markdown-npm-1.13.4-1a47b172bd-3306b4eca0.zip +0 -0
  9. package/.yarn/cache/prosemirror-transform-npm-1.11.0-fa260ad6f3-71989931b8.zip +0 -0
  10. package/.yarn/cache/prosemirror-view-npm-1.41.6-a9d2feed27-68f6a8bd66.zip +0 -0
  11. package/.yarn/install-state.gz +0 -0
  12. package/components/common/field.d.ts +14 -2
  13. package/components/common/field.js +95 -2
  14. package/components/common/field.js.map +1 -1
  15. package/components/common/utils.js +11 -1
  16. package/components/common/utils.js.map +1 -1
  17. package/components/icure-form/fields/button-group/checkbox.js +3 -4
  18. package/components/icure-form/fields/button-group/checkbox.js.map +1 -1
  19. package/components/icure-form/fields/button-group/radio-button.js +3 -4
  20. package/components/icure-form/fields/button-group/radio-button.js.map +1 -1
  21. package/components/icure-form/fields/date-picker/date-picker.js +3 -4
  22. package/components/icure-form/fields/date-picker/date-picker.js.map +1 -1
  23. package/components/icure-form/fields/date-picker/date-time-picker.js +3 -4
  24. package/components/icure-form/fields/date-picker/date-time-picker.js.map +1 -1
  25. package/components/icure-form/fields/date-picker/time-picker.js +3 -4
  26. package/components/icure-form/fields/date-picker/time-picker.js.map +1 -1
  27. package/components/icure-form/fields/dropdown/dropdown-field.js +3 -4
  28. package/components/icure-form/fields/dropdown/dropdown-field.js.map +1 -1
  29. package/components/icure-form/fields/measure-field/measure-field.js +3 -4
  30. package/components/icure-form/fields/measure-field/measure-field.js.map +1 -1
  31. package/components/icure-form/fields/number-field/number-field.js +3 -4
  32. package/components/icure-form/fields/number-field/number-field.js.map +1 -1
  33. package/components/icure-form/fields/text-field/text-field.js +3 -4
  34. package/components/icure-form/fields/text-field/text-field.js.map +1 -1
  35. package/components/icure-form/fields/utils/index.d.ts +0 -5
  36. package/components/icure-form/fields/utils/index.js +0 -8
  37. package/components/icure-form/fields/utils/index.js.map +1 -1
  38. package/components/icure-form/index.js +14 -10
  39. package/components/icure-form/index.js.map +1 -1
  40. package/components/icure-form/renderer/form/form.js +7 -5
  41. package/components/icure-form/renderer/form/form.js.map +1 -1
  42. package/components/icure-text-field/index.js +0 -2
  43. package/components/icure-text-field/index.js.map +1 -1
  44. package/components/icure-text-field/schema/measure-schema.js +0 -1
  45. package/components/icure-text-field/schema/measure-schema.js.map +1 -1
  46. package/components/model/index.d.ts +16 -16
  47. package/components/model/index.js +34 -30
  48. package/components/model/index.js.map +1 -1
  49. package/conversion/icure-convert.d.ts +3 -0
  50. package/conversion/icure-convert.js +161 -0
  51. package/conversion/icure-convert.js.map +1 -0
  52. package/generic/model.d.ts +11 -6
  53. package/generic/model.js.map +1 -1
  54. package/icure/form-values-container.d.ts +27 -21
  55. package/icure/form-values-container.js +318 -125
  56. package/icure/form-values-container.js.map +1 -1
  57. package/icure/icure-utils.js +47 -17
  58. package/icure/icure-utils.js.map +1 -1
  59. package/package.json +1 -1
  60. package/utils/fields-values-provider.d.ts +1 -1
  61. package/utils/fields-values-provider.js +6 -4
  62. package/utils/fields-values-provider.js.map +1 -1
  63. package/.yarn/cache/@lit-labs-ssr-dom-shim-npm-1.4.0-e5ef5fbeba-e267c25576.zip +0 -0
  64. package/.yarn/cache/@lit-reactive-element-npm-2.1.1-3875228c32-b9bbc9c089.zip +0 -0
  65. package/.yarn/cache/lit-html-npm-3.3.1-e3722d4f4a-de07c66945.zip +0 -0
  66. package/.yarn/cache/prosemirror-markdown-npm-1.13.2-6e2f179fd8-ce9fcb3b13.zip +0 -0
  67. package/.yarn/cache/prosemirror-transform-npm-1.10.5-5b3b4f5f61-6f5921e53a.zip +0 -0
  68. package/.yarn/cache/prosemirror-view-npm-1.41.4-cf361fd330-b663b8c6ce.zip +0 -0
@@ -12,10 +12,30 @@ import { sortedBy } from '../utils/no-lodash';
12
12
  import { areCodesEqual, codeStubToCode, contentToPrimitiveType, isContentEqual, primitiveTypeToContent } from './icure-utils';
13
13
  import { parsePrimitive } from '../utils/primitive';
14
14
  import { anyDateToDate, dateToFuzzyDate } from '../utils/dates';
15
- import { v4 as uuidv4 } from 'uuid';
16
15
  import { normalizeCodes } from '../utils/code-utils';
17
- function notify(l, fvc) {
18
- l(fvc);
16
+ let _ordinal = 0;
17
+ function notify(l, fvc, changedKeys, force = false) {
18
+ l(fvc, changedKeys, force);
19
+ }
20
+ function primitiveTypeToString(pt) {
21
+ switch (pt.type) {
22
+ case 'string':
23
+ return pt.value;
24
+ case 'number':
25
+ return pt.value.toString();
26
+ case 'boolean':
27
+ return pt.value.toString();
28
+ case 'measure':
29
+ return pt.value !== undefined ? `${pt.value}${pt.unit ? ' ' + pt.unit : ''}` : '';
30
+ case 'timestamp':
31
+ return new Date(pt.value).toISOString();
32
+ case 'datetime':
33
+ return pt.value.toString();
34
+ case 'compound':
35
+ return Object.entries(pt.value)
36
+ .map(([k, v]) => `${k}: ${primitiveTypeToString(v)}`)
37
+ .join(', ');
38
+ }
19
39
  }
20
40
  /** This class is a bridge between the ICure API and the generic FormValuesContainer interface.
21
41
  * It wraps around a ContactFormValuesContainer and provides a series of services:
@@ -52,8 +72,9 @@ export class BridgedFormValuesContainer {
52
72
  * @param language The language in which the values are displayed
53
73
  * @param changeListeners The listeners that will be notified when the values change
54
74
  * @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
75
+ * @param dependenciesCache
55
76
  */
56
- constructor(responsible, contactFormValuesContainer, interpreter, contact, initialValuesProvider = () => [], dependentValuesProvider = () => [], validatorsProvider = () => [], language = 'en', changeListeners = [], interpreterContext = {}) {
77
+ constructor(responsible, contactFormValuesContainer, interpreter, contact, initialValuesProvider = () => [], dependentValuesProvider = () => [], validatorsProvider = () => [], language = 'en', changeListeners = [], interpreterContext = {}, dependenciesCache = {}) {
57
78
  this.responsible = responsible;
58
79
  this.interpreter = interpreter;
59
80
  this.initialValuesProvider = initialValuesProvider;
@@ -62,25 +83,54 @@ export class BridgedFormValuesContainer {
62
83
  this.language = language;
63
84
  this.changeListeners = changeListeners;
64
85
  this.interpreterContext = interpreterContext;
65
- this._id = uuidv4();
66
- console.log(`Creating bridge FVC (${contactFormValuesContainer.rootForm.formTemplateId}) with ${contactFormValuesContainer.children.length} children [${this._id}]`);
86
+ this.dependenciesCache = dependenciesCache;
87
+ this._id = '';
88
+ this.dependentValuesComputationIteration = undefined;
67
89
  //Before start to broadcast changes, we need to fill in the contactFormValuesContainer with the dependent values
68
90
  this.contactFormValuesContainer = contactFormValuesContainer;
69
- this.mutateAndNotify = (newContactFormValuesContainer) => __awaiter(this, void 0, void 0, function* () {
91
+ this._id = `[${contactFormValuesContainer._id}]`;
92
+ console.log(`+ BFVC ${this._id} created`);
93
+ this.mutateAndNotify = (newContactFormValuesContainer, changedKeys, force = false) => {
94
+ if (this.changeListeners.length === 0) {
95
+ return;
96
+ }
97
+ if (!force && this.contactFormValuesContainer === newContactFormValuesContainer) {
98
+ return;
99
+ }
100
+ this.contactFormValuesContainer.unregisterChangeListener(this.mutateAndNotify);
70
101
  newContactFormValuesContainer.unregisterChangeListener(this.mutateAndNotify);
71
- 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();
72
- this.changeListeners.forEach((l) => notify(l, newBridgedFormValueContainer));
73
- return newBridgedFormValueContainer;
74
- });
102
+ 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);
103
+ const initPromise = newBridgedFormValueContainer.init(changedKeys, this.dependentValuesComputationIteration);
104
+ this.changeListeners.forEach((l) => notify(l, newBridgedFormValueContainer, changedKeys));
105
+ initPromise.catch((e) => {
106
+ console.log('Error while initializing new BridgedFormValuesContainer', e);
107
+ });
108
+ };
75
109
  this.contactFormValuesContainer.registerChangeListener(this.mutateAndNotify);
76
110
  this.contact = contact !== null && contact !== void 0 ? contact : contactFormValuesContainer.currentContact;
77
111
  }
112
+ /* init can be called several times on the same instance but the initialisation will only be done once */
78
113
  init() {
79
- return __awaiter(this, void 0, void 0, function* () {
114
+ return __awaiter(this, arguments, void 0, function* (changedKeys = null, pendingComputationIteration) {
80
115
  if (this.contactFormValuesContainer.mustBeInitialised()) {
81
116
  yield this.computeInitialValues();
82
117
  }
83
- yield this.computeDependentValues();
118
+ let changedKeysByInit = [];
119
+ if (pendingComputationIteration) {
120
+ const changes = yield pendingComputationIteration;
121
+ if (changes.length > 0) {
122
+ this.quietlyApplyChangesOnContactFormValueContainer(changes);
123
+ changedKeysByInit = yield this.computeDependentValues([...(changedKeys !== null && changedKeys !== void 0 ? changedKeys : []), ...changes.map(([, metadata]) => metadata.label)]);
124
+ }
125
+ else {
126
+ changedKeysByInit = yield this.computeDependentValues(changedKeys);
127
+ }
128
+ }
129
+ else {
130
+ changedKeysByInit = yield this.computeDependentValues(changedKeys);
131
+ }
132
+ //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
133
+ this.contactFormValuesContainer.changeListeners.forEach((l) => notify(l, this.contactFormValuesContainer, changedKeysByInit, changedKeysByInit.length > 0));
84
134
  return this;
85
135
  });
86
136
  }
@@ -99,12 +149,10 @@ export class BridgedFormValuesContainer {
99
149
  unregisterChangeListener(listener) {
100
150
  this.changeListeners = this.changeListeners.filter((l) => l !== listener);
101
151
  }
102
- getDefaultValue(label) {
103
- return __awaiter(this, void 0, void 0, function* () {
104
- var _a;
105
- 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;
106
- return formula ? this.convertRawValue(yield this.compute(formula)) : undefined;
107
- });
152
+ getDefaultValueProvider(label) {
153
+ var _a;
154
+ 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;
155
+ return formula ? () => __awaiter(this, void 0, void 0, function* () { return this.convertRawValue(yield this.compute(formula)); }) : undefined;
108
156
  }
109
157
  getValues(revisionsFilter) {
110
158
  return Object.entries(this.contactFormValuesContainer.getValues((id, history) => revisionsFilter(id, history
@@ -198,7 +246,8 @@ export class BridgedFormValuesContainer {
198
246
  try {
199
247
  const currentValue = this.getValues(revisionsFilter);
200
248
  if (!currentValue || !Object.keys(currentValue).length) {
201
- const newValue = this.convertRawValue((yield this.compute(formula)));
249
+ const computedValue = (yield this.compute(formula)).value;
250
+ const newValue = computedValue ? this.convertRawValue(computedValue) : undefined;
202
251
  if (newValue !== undefined) {
203
252
  const lng = (_b = this.language) !== null && _b !== void 0 ? _b : 'en';
204
253
  if (newValue && !newValue.content[lng] && newValue.content['*']) {
@@ -225,38 +274,80 @@ export class BridgedFormValuesContainer {
225
274
  });
226
275
  }
227
276
  //This method mutates the BridgedFormValuesContainer but can only be called from the constructor
228
- computeDependentValues() {
277
+ computeDependentValues(changedKeys) {
229
278
  return __awaiter(this, void 0, void 0, function* () {
230
- if (this.contactFormValuesContainer.rootForm.formTemplateId) {
231
- yield Promise.all(this.dependentValuesProvider(this.contactFormValuesContainer.rootForm.descr, this.contactFormValuesContainer.rootForm.formTemplateId).map((_a) => __awaiter(this, [_a], void 0, function* ({ metadata, revisionsFilter, formula }) {
232
- var _b;
233
- try {
234
- const currentValue = this.getValues(revisionsFilter);
235
- const newValue = this.convertRawValue((yield this.compute(formula)));
236
- if (newValue !== undefined || currentValue != undefined) {
237
- const lng = (_b = this.language) !== null && _b !== void 0 ? _b : 'en';
238
- if (newValue && !newValue.content[lng] && newValue.content['*']) {
239
- newValue.content[lng] = newValue.content['*'];
240
- }
241
- if (newValue) {
242
- delete newValue.content['*'];
243
- }
244
- const interceptor = (fvc) => {
245
- const currentContact = this.contactFormValuesContainer.currentContact;
246
- this.contactFormValuesContainer = fvc;
247
- if (this.contact === currentContact) {
248
- this.contact = fvc.currentContact;
279
+ const iterate = (changedKeys, iterationCount) => __awaiter(this, void 0, void 0, function* () {
280
+ if (this.contactFormValuesContainer.rootForm.formTemplateId) {
281
+ console.log(`% ${iterationCount}, keys: ${changedKeys ? changedKeys.join(', ') : 'all'}`);
282
+ 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 }) {
283
+ var _b, _c;
284
+ try {
285
+ if (!changedKeys || !this.dependenciesCache[formula] || this.dependenciesCache[formula].some((d) => changedKeys.includes(d))) {
286
+ const currentValue = this.getValues(revisionsFilter);
287
+ try {
288
+ const computationResult = yield this.compute(formula);
289
+ this.dependenciesCache[formula] = [...((_b = this.dependenciesCache[formula]) !== null && _b !== void 0 ? _b : []), ...computationResult.dependencies].filter((d, idx, array) => array.indexOf(d) === idx);
290
+ const newValue = computationResult.value ? this.convertRawValue(computationResult.value) : undefined;
291
+ if (newValue !== undefined || (currentValue != undefined && Object.keys(currentValue).length > 0 && currentValue[Object.keys(currentValue)[0]][0].value)) {
292
+ const lng = (_c = this.language) !== null && _c !== void 0 ? _c : 'en';
293
+ if (newValue && !newValue.content[lng] && newValue.content['*']) {
294
+ newValue.content[lng] = newValue.content['*'];
295
+ }
296
+ if (newValue) {
297
+ delete newValue.content['*'];
298
+ }
299
+ return [Object.keys(currentValue !== null && currentValue !== void 0 ? currentValue : {})[0], metadata, lng, newValue];
300
+ }
301
+ }
302
+ catch (e) {
303
+ console.log(`Error while computing formula : ${formula}`, e);
249
304
  }
250
- };
251
- setValueOnContactFormValuesContainer(this.contactFormValuesContainer, metadata.label, lng, newValue, Object.keys(currentValue !== null && currentValue !== void 0 ? currentValue : {})[0], metadata, interceptor);
305
+ }
252
306
  }
253
- }
254
- catch (e) {
255
- console.log(`Error while computing formula : ${formula}`, e);
256
- }
257
- })));
307
+ catch (e) {
308
+ console.log(`Error while computing formula : ${formula}`, e);
309
+ }
310
+ return null;
311
+ }))).then((results) => results.filter((r) => !!r));
312
+ }
313
+ else {
314
+ return [];
315
+ }
316
+ });
317
+ let latestKeys = changedKeys;
318
+ let iterationCount = 0;
319
+ const allChangedKeys = [];
320
+ while (true) {
321
+ if (latestKeys != null && latestKeys.length === 0) {
322
+ this.dependentValuesComputationIteration = undefined;
323
+ break;
324
+ }
325
+ const changes = yield (this.dependentValuesComputationIteration = iterate(latestKeys, iterationCount++));
326
+ latestKeys = this.quietlyApplyChangesOnContactFormValueContainer(changes);
327
+ allChangedKeys.push(...latestKeys);
328
+ }
329
+ return allChangedKeys;
330
+ });
331
+ }
332
+ quietlyApplyChangesOnContactFormValueContainer(changes) {
333
+ const allChangedKeys = [];
334
+ const interceptor = (fvc, changedKeys) => {
335
+ const currentContact = this.contactFormValuesContainer.currentContact;
336
+ this.contactFormValuesContainer = fvc;
337
+ if (this.contact === currentContact) {
338
+ this.contact = fvc.currentContact;
339
+ }
340
+ allChangedKeys.push(...(changedKeys !== null && changedKeys !== void 0 ? changedKeys : []));
341
+ };
342
+ changes.forEach(([id, metadata, language, newValue]) => {
343
+ try {
344
+ setValueOnContactFormValuesContainer(this.contactFormValuesContainer, metadata.label, language, newValue !== null && newValue !== void 0 ? newValue : undefined, id, metadata, interceptor);
345
+ }
346
+ catch (e) {
347
+ console.log(`Error while applying dependent value change for ${metadata.label} (${id})`, e);
258
348
  }
259
349
  });
350
+ return allChangedKeys;
260
351
  }
261
352
  setValue(label, language, fv, id, metadata) {
262
353
  setValueOnContactFormValuesContainer(this.contactFormValuesContainer, label, language, fv, id, metadata);
@@ -276,9 +367,10 @@ export class BridgedFormValuesContainer {
276
367
  getVersionedValuesForKey(key) {
277
368
  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] : []); });
278
369
  }
279
- compute(formula, sandbox) {
370
+ compute(formula) {
280
371
  return __awaiter(this, void 0, void 0, function* () {
281
372
  var _a;
373
+ const dependencies = new Set();
282
374
  // noinspection JSUnusedGlobalSymbols
283
375
  const parseContent = (content, toString = false) => {
284
376
  var _a, _b;
@@ -299,6 +391,7 @@ export class BridgedFormValuesContainer {
299
391
  .join(', ');
300
392
  };
301
393
  const log = console.log;
394
+ // noinspection JSUnusedGlobalSymbols
302
395
  const native = {
303
396
  parseInt: parseInt,
304
397
  parseFloat: parseFloat,
@@ -346,42 +439,40 @@ export class BridgedFormValuesContainer {
346
439
  if (!!nativeValue) {
347
440
  return nativeValue;
348
441
  }
349
- 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; });
442
+ if (key === 'self') {
443
+ return proxy;
444
+ }
445
+ else {
446
+ dependencies.add(key.toString());
447
+ 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; });
448
+ }
350
449
  },
351
450
  });
352
- return (_a = this.interpreter) === null || _a === void 0 ? void 0 : _a.call(this, formula, sandbox !== null && sandbox !== void 0 ? sandbox : proxy);
451
+ return { value: yield ((_a = this.interpreter) === null || _a === void 0 ? void 0 : _a.call(this, formula, proxy)), dependencies: Array.from(dependencies) };
353
452
  });
354
453
  }
355
454
  getChildren() {
356
455
  return __awaiter(this, void 0, void 0, function* () {
357
- 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()));
358
- console.log(`${children.length} children found in ${this.contactFormValuesContainer.rootForm.formTemplateId} initialised with `, this.initialValuesProvider);
359
- return children;
456
+ 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()));
360
457
  });
361
458
  }
362
459
  getValidationErrors() {
363
- return __awaiter(this, void 0, void 0, function* () {
364
- if (this.contactFormValuesContainer.rootForm.formTemplateId) {
365
- // noinspection ES6MissingAwait
366
- 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 }) {
367
- return yield validators.reduce((resPromise_2, _a) => __awaiter(this, [resPromise_2, _a], void 0, function* (resPromise, { validation, message }) {
368
- const res = yield resPromise;
369
- try {
370
- if (!(yield this.compute(validation))) {
371
- res.push([metadata, message]);
372
- }
373
- }
374
- catch (e) {
375
- console.log(`Error while computing validation : ${validation}`, e);
376
- }
377
- return res;
378
- }), resPromise);
379
- }), Promise.resolve([]));
380
- }
381
- else {
382
- return [];
383
- }
384
- });
460
+ if (this.contactFormValuesContainer.rootForm.formTemplateId) {
461
+ 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 }) {
462
+ try {
463
+ if (!(yield this.compute(validation))) {
464
+ return [metadata, message];
465
+ }
466
+ }
467
+ catch (e) {
468
+ console.log(`Error while computing validation : ${validation}`, e);
469
+ }
470
+ return null;
471
+ })));
472
+ }
473
+ else {
474
+ return [];
475
+ }
385
476
  }
386
477
  addChild(anchorId, templateId, label) {
387
478
  return __awaiter(this, void 0, void 0, function* () {
@@ -432,17 +523,20 @@ export class ContactFormValuesContainer {
432
523
  allForms() {
433
524
  return [this.rootForm].concat(this.children.flatMap((c) => c.allForms()));
434
525
  }
435
- constructor(rootForm, currentContact, contactsHistory, serviceFactory, children, formFactory, formRecycler, changeListeners = [], initialised = true) {
436
- this._id = uuidv4();
526
+ constructor(rootForm, currentContact, contactsHistory, serviceFactory, children, formFactory, formRecycler, changeListeners = [], anchorId, initialised = true) {
527
+ var _a;
528
+ this._id = '';
437
529
  this._initialised = false;
438
- console.log(`Creating contact FVC (${rootForm.formTemplateId}) with ${children.length} children [${this._id}]`);
530
+ this.rootForm = rootForm;
531
+ this._id = `${((_a = rootForm.formTemplateId) !== null && _a !== void 0 ? _a : '').substring(0, 4)}.${++_ordinal}`;
532
+ console.log(`+ CFVC: ${this._id} with children { ${children.map((c) => c._id).join(', ')} }`);
439
533
  if (contactsHistory.includes(currentContact)) {
440
534
  throw new Error('Illegal argument, the history must not contain the currentContact');
441
535
  }
442
- this.rootForm = rootForm;
443
536
  this.currentContact = currentContact;
444
537
  this.contactsHistory = sortedBy(contactsHistory, 'created', 'desc');
445
538
  this.children = children;
539
+ this.anchorId = anchorId;
446
540
  this.serviceFactory = serviceFactory;
447
541
  this.formFactory = formFactory;
448
542
  this.formRecycler = formRecycler;
@@ -450,7 +544,7 @@ export class ContactFormValuesContainer {
450
544
  this._initialised = initialised;
451
545
  this.indexedServices = [this.currentContact].concat(this.contactsHistory).reduce((acc, ctc) => {
452
546
  var _a, _b, _c;
453
- 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) => {
547
+ 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) => {
454
548
  var _a, _b;
455
549
  return s.id
456
550
  ? Object.assign(Object.assign({}, acc), { [s.id]: ((_a = acc[s.id]) !== null && _a !== void 0 ? _a : (acc[s.id] = [])).concat({
@@ -458,26 +552,29 @@ export class ContactFormValuesContainer {
458
552
  modified: ctc.created,
459
553
  value: s,
460
554
  }) }) : acc;
461
- }, acc)) !== null && _c !== void 0 ? _c : acc;
462
- return services;
555
+ }, acc)) !== null && _c !== void 0 ? _c : acc);
463
556
  }, {});
464
557
  this.synchronise();
465
558
  }
466
559
  synchronise() {
467
560
  this.children.forEach((childFVC) => {
468
- this.registerChildFormValuesContainer(childFVC.synchronise());
561
+ var _a;
562
+ this.registerChildFormValuesContainer(childFVC.synchronise(), (_a = childFVC.anchorId) !== null && _a !== void 0 ? _a : '');
469
563
  });
470
564
  return this;
471
565
  }
472
566
  //Make sure that when a child is changed, a new version of this is created with the updated child
473
- registerChildFormValuesContainer(childFormValueContainer) {
567
+ registerChildFormValuesContainer(childFormValueContainer, anchorId) {
474
568
  childFormValueContainer.changeListeners = [
475
- (newValue) => {
569
+ (newValue, changedKeys, force) => {
570
+ if ((changedKeys === null || changedKeys === void 0 ? void 0 : changedKeys.length) === 0 && !force) {
571
+ return;
572
+ }
476
573
  console.log(`Child ${newValue._id} ${childFormValueContainer.rootForm.formTemplateId} changed, updating parent ${this._id} ${this.rootForm.formTemplateId}`);
477
574
  const newContactFormValuesContainer = new ContactFormValuesContainer(this.rootForm, this.currentContact, this.contactsHistory, this.serviceFactory, this.children.map((c) => {
478
575
  return c.rootForm.id === childFormValueContainer.rootForm.id ? newValue : c;
479
- }), this.formFactory, this.formRecycler);
480
- this.changeListeners.forEach((l) => notify(l, newContactFormValuesContainer));
576
+ }), this.formFactory, this.formRecycler, [], this.anchorId, true);
577
+ this.changeListeners.forEach((l) => notify(l, newContactFormValuesContainer, null));
481
578
  },
482
579
  ];
483
580
  }
@@ -487,8 +584,8 @@ export class ContactFormValuesContainer {
487
584
  ? yield Promise.all((yield formChildrenProvider(rootForm.id)).map((f) => __awaiter(this, void 0, void 0, function* () {
488
585
  // eslint-disable-next-line max-len
489
586
  return yield ContactFormValuesContainer.fromFormsHierarchy(f, currentContact, contactsHistory, serviceFactory, formChildrenProvider, formFactory, formRecycler); })))
490
- : [], formFactory, formRecycler, changeListeners, false);
491
- contactFormValuesContainer.children.forEach((childFVC) => contactFormValuesContainer.registerChildFormValuesContainer(childFVC));
587
+ : [], formFactory, formRecycler, changeListeners, rootForm.descr, false);
588
+ contactFormValuesContainer.children.forEach((childFVC) => { var _a; return contactFormValuesContainer.registerChildFormValuesContainer(childFVC, (_a = childFVC.anchorId) !== null && _a !== void 0 ? _a : 'all'); });
492
589
  return contactFormValuesContainer;
493
590
  });
494
591
  }
@@ -512,12 +609,10 @@ export class ContactFormValuesContainer {
512
609
  });
513
610
  }
514
611
  getValidationErrors() {
515
- return __awaiter(this, void 0, void 0, function* () {
516
- throw new Error('Validation not supported at contact level');
517
- });
612
+ throw new Error('Validation not supported at contact level');
518
613
  }
519
- getDefaultValue() {
520
- return Promise.resolve(undefined);
614
+ getDefaultValueProvider() {
615
+ return undefined;
521
616
  }
522
617
  getValues(revisionsFilter) {
523
618
  return Object.entries(this.getServicesInHistory(revisionsFilter)).reduce((acc, [id, history]) => history.length
@@ -562,20 +657,20 @@ export class ContactFormValuesContainer {
562
657
  meta.valueDate && (newService.valueDate = meta.valueDate);
563
658
  meta.codes && (newService.codes = normalizeCodes(meta.codes));
564
659
  meta.tags && (newService.tags = normalizeCodes(meta.tags));
565
- const newFormValuesContainer = new ContactFormValuesContainer(this.rootForm, new DecryptedContact(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);
566
- this.changeListeners.forEach((l) => notify(l, newFormValuesContainer));
660
+ const newFormValuesContainer = new ContactFormValuesContainer(this.rootForm, new DecryptedContact(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);
661
+ this.changeListeners.forEach((l) => notify(l, newFormValuesContainer, [meta.label]));
567
662
  }
568
663
  }
569
664
  setValue(label, language, value, id, metadata, changeListenersOverrider) {
570
- var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t, _u, _v;
665
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t, _u, _v, _w;
571
666
  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);
572
667
  if (!service.id) {
573
668
  throw new Error('Service id must be defined');
574
669
  }
575
- console.log('Setting value of service', service.id, 'with', value, 'and metadata', metadata);
576
- const newContent = (_c = value === null || value === void 0 ? void 0 : value.content) === null || _c === void 0 ? void 0 : _c[language];
670
+ 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(contentToPrimitiveType(k, c))}`)} and md`, metadata);
671
+ const newContent = (_d = value === null || value === void 0 ? void 0 : value.content) === null || _d === void 0 ? void 0 : _d[language];
577
672
  const newCodes = (value === null || value === void 0 ? void 0 : value.codes) ? normalizeCodes(value.codes) : [];
578
- if (!isContentEqual((_d = service.content) === null || _d === void 0 ? void 0 : _d[language], newContent) || (newCodes && !areCodesEqual(newCodes, (_e = service.codes) !== null && _e !== void 0 ? _e : []))) {
673
+ if (!isContentEqual((_e = service.content) === null || _e === void 0 ? void 0 : _e[language], newContent) || (newCodes && !areCodesEqual(newCodes, (_f = service.codes) !== null && _f !== void 0 ? _f : []))) {
579
674
  const newService = new DecryptedService(Object.assign(Object.assign({}, service), { modified: Date.now() }));
580
675
  const newContents = newContent
581
676
  ? Object.assign(Object.assign({}, (service.content || {})), { [language]: newContent }) : Object.assign({}, (service.content || {}));
@@ -584,8 +679,8 @@ export class ContactFormValuesContainer {
584
679
  }
585
680
  let newCurrentContact;
586
681
  if (!Object.entries(newContents).filter(([, cnt]) => cnt !== undefined).length) {
587
- newCurrentContact = new DecryptedContact(Object.assign(Object.assign({}, this.currentContact), { subContacts: ((_f = this.currentContact.subContacts) !== null && _f !== void 0 ? _f : []).some((sc) => sc.formId === this.rootForm.id)
588
- ? ((_g = this.currentContact.subContacts) !== null && _g !== void 0 ? _g : []).map((sc) => {
682
+ newCurrentContact = new DecryptedContact(Object.assign(Object.assign({}, this.currentContact), { subContacts: ((_g = this.currentContact.subContacts) !== null && _g !== void 0 ? _g : []).some((sc) => sc.formId === this.rootForm.id)
683
+ ? ((_h = this.currentContact.subContacts) !== null && _h !== void 0 ? _h : []).map((sc) => {
589
684
  var _a;
590
685
  if (sc.formId === this.rootForm.id) {
591
686
  return new DecryptedSubContact(Object.assign(Object.assign({}, sc), { services: ((_a = sc.services) !== null && _a !== void 0 ? _a : []).filter((s) => s.serviceId !== service.id).concat([new ServiceLink({ serviceId: service.id })]) }));
@@ -594,24 +689,24 @@ export class ContactFormValuesContainer {
594
689
  return sc;
595
690
  }
596
691
  })
597
- : ((_h = this.currentContact.subContacts) !== null && _h !== void 0 ? _h : []).concat(new DecryptedSubContact({
692
+ : ((_j = this.currentContact.subContacts) !== null && _j !== void 0 ? _j : []).concat(new DecryptedSubContact({
598
693
  formId: this.rootForm.id,
599
694
  services: [new ServiceLink({ serviceId: service.id })],
600
- })), services: ((_j = this.currentContact.services) !== null && _j !== void 0 ? _j : []).some((s) => s.id === service.id)
601
- ? ((_k = this.currentContact.services) !== null && _k !== void 0 ? _k : []).filter((s) => s.id !== service.id)
602
- : [...((_l = this.currentContact.services) !== null && _l !== void 0 ? _l : [])] }));
695
+ })), services: ((_k = this.currentContact.services) !== null && _k !== void 0 ? _k : []).some((s) => s.id === service.id)
696
+ ? ((_l = this.currentContact.services) !== null && _l !== void 0 ? _l : []).filter((s) => s.id !== service.id)
697
+ : [...((_m = this.currentContact.services) !== null && _m !== void 0 ? _m : [])] }));
603
698
  }
604
699
  else {
605
700
  newService.content = newContents;
606
701
  newService.codes = newCodes;
607
702
  if (metadata) {
608
- newService.responsible = (_m = metadata.responsible) !== null && _m !== void 0 ? _m : newService.responsible;
609
- newService.valueDate = (_o = metadata.valueDate) !== null && _o !== void 0 ? _o : newService.valueDate;
703
+ newService.responsible = (_o = metadata.responsible) !== null && _o !== void 0 ? _o : newService.responsible;
704
+ newService.valueDate = (_p = metadata.valueDate) !== null && _p !== void 0 ? _p : newService.valueDate;
610
705
  newService.tags = metadata.tags ? normalizeCodes(metadata.tags) : newService.tags;
611
- newService.label = (_p = metadata.label) !== null && _p !== void 0 ? _p : newService.label;
706
+ newService.label = (_q = metadata.label) !== null && _q !== void 0 ? _q : newService.label;
612
707
  }
613
- newCurrentContact = new DecryptedContact(Object.assign(Object.assign({}, this.currentContact), { subContacts: ((_q = this.currentContact.subContacts) !== null && _q !== void 0 ? _q : []).some((sc) => sc.formId === this.rootForm.id)
614
- ? ((_r = this.currentContact.subContacts) !== null && _r !== void 0 ? _r : []).map((sc) => {
708
+ newCurrentContact = new DecryptedContact(Object.assign(Object.assign({}, this.currentContact), { subContacts: ((_r = this.currentContact.subContacts) !== null && _r !== void 0 ? _r : []).some((sc) => sc.formId === this.rootForm.id)
709
+ ? ((_s = this.currentContact.subContacts) !== null && _s !== void 0 ? _s : []).map((sc) => {
615
710
  var _a;
616
711
  if (sc.formId === this.rootForm.id) {
617
712
  return new DecryptedSubContact(Object.assign(Object.assign({}, sc), { services: ((_a = sc.services) !== null && _a !== void 0 ? _a : []).filter((s) => s.serviceId !== service.id).concat([new ServiceLink({ serviceId: service.id })]) }));
@@ -620,15 +715,15 @@ export class ContactFormValuesContainer {
620
715
  return sc;
621
716
  }
622
717
  })
623
- : ((_s = this.currentContact.subContacts) !== null && _s !== void 0 ? _s : []).concat(new DecryptedSubContact({
718
+ : ((_t = this.currentContact.subContacts) !== null && _t !== void 0 ? _t : []).concat(new DecryptedSubContact({
624
719
  formId: this.rootForm.id,
625
720
  services: [new ServiceLink({ serviceId: service.id })],
626
- })), services: ((_t = this.currentContact.services) !== null && _t !== void 0 ? _t : []).some((s) => s.id === service.id)
627
- ? ((_u = this.currentContact.services) !== null && _u !== void 0 ? _u : []).map((s) => (s.id === service.id ? newService : s))
628
- : [...((_v = this.currentContact.services) !== null && _v !== void 0 ? _v : []), newService] }));
721
+ })), services: ((_u = this.currentContact.services) !== null && _u !== void 0 ? _u : []).some((s) => s.id === service.id)
722
+ ? ((_v = this.currentContact.services) !== null && _v !== void 0 ? _v : []).map((s) => (s.id === service.id ? newService : s))
723
+ : [...((_w = this.currentContact.services) !== null && _w !== void 0 ? _w : []), newService] }));
629
724
  }
630
- 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);
631
- changeListenersOverrider ? changeListenersOverrider(newFormValuesContainer) : this.changeListeners.forEach((l) => notify(l, newFormValuesContainer));
725
+ 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);
726
+ changeListenersOverrider ? changeListenersOverrider(newFormValuesContainer, [label]) : this.changeListeners.forEach((l) => notify(l, newFormValuesContainer, [label]));
632
727
  }
633
728
  }
634
729
  delete(serviceId) {
@@ -637,10 +732,35 @@ export class ContactFormValuesContainer {
637
732
  if (service) {
638
733
  const newFormValuesContainer = new ContactFormValuesContainer(this.rootForm, new DecryptedContact(Object.assign(Object.assign({}, this.currentContact), { services: (_a = this.currentContact.services) === null || _a === void 0 ? void 0 : _a.map((s) => s.id === serviceId
639
734
  ? new DecryptedService(Object.assign(Object.assign({}, service), { endOfLife: Date.now() }))
640
- : s) })), this.contactsHistory, this.serviceFactory, this.children, this.formFactory, this.formRecycler, this.changeListeners);
641
- this.changeListeners.forEach((l) => notify(l, newFormValuesContainer));
735
+ : s) })), this.contactsHistory, this.serviceFactory, this.children, this.formFactory, this.formRecycler, this.changeListeners, this.anchorId, true);
736
+ this.changeListeners.forEach((l) => { var _a; return notify(l, newFormValuesContainer, [(_a = service.label) !== null && _a !== void 0 ? _a : service.id] /* only the label is going to propagate the changes for the formulas */); });
642
737
  }
643
738
  }
739
+ toMarkdownTable() {
740
+ var _a, _b, _c;
741
+ const tableRows = [];
742
+ for (const [, versions] of Object.entries(this.indexedServices)) {
743
+ if (!versions.length)
744
+ continue;
745
+ const service = versions[0].value;
746
+ const label = (_b = (_a = service.label) !== null && _a !== void 0 ? _a : service.id) !== null && _b !== void 0 ? _b : '';
747
+ const modifiedStr = service.modified ? new Date(service.modified).toISOString() : '';
748
+ const contentParts = [];
749
+ for (const [lng, cnt] of Object.entries((_c = service.content) !== null && _c !== void 0 ? _c : {})) {
750
+ const primitive = contentToPrimitiveType(lng, cnt);
751
+ if (primitive) {
752
+ contentParts.push(primitiveTypeToString(primitive));
753
+ }
754
+ }
755
+ tableRows.push([label, modifiedStr, contentParts.join(', ')]);
756
+ }
757
+ const headers = ['Label', 'Modified', 'Content'];
758
+ const colWidths = headers.map((h, i) => Math.max(h.length, ...tableRows.map((r) => r[i].length)));
759
+ const pad = (s, w) => s + ' '.repeat(w - s.length);
760
+ const formatRow = (cells) => '| ' + cells.map((c, i) => pad(c, colWidths[i])).join(' | ') + ' |';
761
+ const separator = '|' + colWidths.map((w) => '-'.repeat(w + 2)).join('|') + '|';
762
+ return [formatRow(headers), separator, ...tableRows.map(formatRow)].join('\n');
763
+ }
644
764
  compute() {
645
765
  return __awaiter(this, void 0, void 0, function* () {
646
766
  throw new Error('Compute not supported at contact level');
@@ -679,10 +799,12 @@ export class ContactFormValuesContainer {
679
799
  if (!parentId)
680
800
  return;
681
801
  const newForm = yield this.formFactory(parentId, anchorId, templateId, label);
682
- const childFVC = new ContactFormValuesContainer(newForm, this.currentContact, this.contactsHistory, this.serviceFactory, [], this.formFactory, this.formRecycler, [], false);
683
- const newContactFormValuesContainer = new ContactFormValuesContainer(this.rootForm, this.currentContact, this.contactsHistory, this.serviceFactory, [...this.children, childFVC], this.formFactory, this.formRecycler, this.changeListeners);
684
- newContactFormValuesContainer.registerChildFormValuesContainer(childFVC);
685
- this.changeListeners.forEach((l) => notify(l, newContactFormValuesContainer));
802
+ const childFVC = new ContactFormValuesContainer(newForm, this.currentContact, this.contactsHistory, this.serviceFactory, [], this.formFactory, this.formRecycler, [], anchorId, false);
803
+ const newContactFormValuesContainer = new ContactFormValuesContainer(this.rootForm, this.currentContact, this.contactsHistory, this.serviceFactory, [...this.children, childFVC], this.formFactory, this.formRecycler, this.changeListeners, this.anchorId, true);
804
+ newContactFormValuesContainer.registerChildFormValuesContainer(childFVC, anchorId);
805
+ this.changeListeners.forEach((l) => {
806
+ notify(l, newContactFormValuesContainer, null);
807
+ });
686
808
  });
687
809
  }
688
810
  getServiceInCurrentContact(id) {
@@ -692,13 +814,84 @@ export class ContactFormValuesContainer {
692
814
  }
693
815
  removeChild(container) {
694
816
  return __awaiter(this, void 0, void 0, function* () {
695
- 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);
696
- this.changeListeners.forEach((l) => notify(l, newContactFormValuesContainer));
817
+ 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);
818
+ this.changeListeners.forEach((l) => { var _a; return notify(l, newContactFormValuesContainer, [`subForms_${(_a = container.anchorId) !== null && _a !== void 0 ? _a : 'all'}`]); });
697
819
  });
698
820
  }
699
821
  }
822
+ // Runtime validation for FieldValue — guards against mistyped data coming from
823
+ // external callers (formulas, SDK bridges, etc.) where the TypeScript types may
824
+ // not match the actual runtime values.
825
+ const validatePrimitiveType = (pt, path) => {
826
+ const v = pt.value;
827
+ switch (pt.type) {
828
+ case 'string':
829
+ if (typeof v !== 'string') {
830
+ throw new Error(`${path}: expected string value, got ${typeof v}`);
831
+ }
832
+ break;
833
+ case 'number':
834
+ if (typeof v !== 'number') {
835
+ throw new Error(`${path}: expected number value, got ${typeof v}`);
836
+ }
837
+ break;
838
+ case 'boolean':
839
+ if (typeof v !== 'boolean') {
840
+ throw new Error(`${path}: expected boolean value, got ${typeof v}`);
841
+ }
842
+ break;
843
+ case 'timestamp':
844
+ if (typeof v !== 'number') {
845
+ throw new Error(`${path}: expected number value for timestamp, got ${typeof v}`);
846
+ }
847
+ break;
848
+ case 'datetime':
849
+ if (typeof v !== 'number') {
850
+ throw new Error(`${path}: expected number value for datetime, got ${typeof v}`);
851
+ }
852
+ break;
853
+ case 'measure': {
854
+ const m = pt;
855
+ if (m.value !== undefined && typeof m.value !== 'number') {
856
+ throw new Error(`${path}: expected number or undefined value for measure, got ${typeof m.value}`);
857
+ }
858
+ if (m.unit !== undefined && typeof m.unit !== 'string') {
859
+ throw new Error(`${path}: expected string or undefined unit for measure, got ${typeof m.unit}`);
860
+ }
861
+ break;
862
+ }
863
+ case 'compound':
864
+ if (typeof v !== 'object' || v === null || Array.isArray(v)) {
865
+ throw new Error(`${path}: expected object value for compound, got ${Array.isArray(v) ? 'array' : typeof v}`);
866
+ }
867
+ for (const [key, subValue] of Object.entries(v)) {
868
+ validatePrimitiveType(subValue, `${path}.compound[${key}]`);
869
+ }
870
+ break;
871
+ default:
872
+ throw new Error(`${path}: unknown PrimitiveType type: ${pt.type}`);
873
+ }
874
+ };
875
+ const validateCode = (code, path) => {
876
+ const id = code.id;
877
+ if (!id || typeof id !== 'string') {
878
+ throw new Error(`${path}: code must have a non-empty string id, got ${JSON.stringify(id)}`);
879
+ }
880
+ };
881
+ const validateFieldValue = (fv, language, label) => {
882
+ const pt = fv.content[language];
883
+ if (pt) {
884
+ validatePrimitiveType(pt, `FieldValue[${label}].content[${language}]`);
885
+ }
886
+ if (fv.codes) {
887
+ fv.codes.forEach((code, i) => validateCode(code, `FieldValue[${label}].codes[${i}]`));
888
+ }
889
+ };
700
890
  const setValueOnContactFormValuesContainer = (cfvc, label, language, fv, id, metadata, changeListenersOverrider) => {
701
891
  var _a, _b, _c, _d;
892
+ if (fv) {
893
+ validateFieldValue(fv, language, label);
894
+ }
702
895
  const value = fv === null || fv === void 0 ? void 0 : fv.content[language];
703
896
  cfvc.setValue(label, language, new DecryptedService({
704
897
  id: id,