@aehrc/smart-forms-renderer 1.0.0-alpha.21 → 1.0.0-alpha.23

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 (126) hide show
  1. package/lib/components/FormComponents/BooleanItem/BooleanField.d.ts +1 -0
  2. package/lib/components/FormComponents/BooleanItem/BooleanField.js +20 -17
  3. package/lib/components/FormComponents/BooleanItem/BooleanField.js.map +1 -1
  4. package/lib/components/FormComponents/BooleanItem/BooleanItem.js +6 -3
  5. package/lib/components/FormComponents/BooleanItem/BooleanItem.js.map +1 -1
  6. package/lib/components/FormComponents/ChoiceItems/ChoiceRadioAnswerOptionFields.d.ts +1 -0
  7. package/lib/components/FormComponents/ChoiceItems/ChoiceRadioAnswerOptionFields.js +15 -7
  8. package/lib/components/FormComponents/ChoiceItems/ChoiceRadioAnswerOptionFields.js.map +1 -1
  9. package/lib/components/FormComponents/ChoiceItems/ChoiceRadioAnswerOptionItem.js +5 -2
  10. package/lib/components/FormComponents/ChoiceItems/ChoiceRadioAnswerOptionItem.js.map +1 -1
  11. package/lib/components/FormComponents/ChoiceItems/ChoiceRadioAnswerOptionView.d.ts +1 -0
  12. package/lib/components/FormComponents/ChoiceItems/ChoiceRadioAnswerOptionView.js +3 -3
  13. package/lib/components/FormComponents/ChoiceItems/ChoiceRadioAnswerOptionView.js.map +1 -1
  14. package/lib/components/FormComponents/ChoiceItems/ChoiceRadioAnswerValueSetFields.d.ts +1 -0
  15. package/lib/components/FormComponents/ChoiceItems/ChoiceRadioAnswerValueSetFields.js +14 -7
  16. package/lib/components/FormComponents/ChoiceItems/ChoiceRadioAnswerValueSetFields.js.map +1 -1
  17. package/lib/components/FormComponents/ChoiceItems/ChoiceRadioAnswerValueSetItem.js +6 -3
  18. package/lib/components/FormComponents/ChoiceItems/ChoiceRadioAnswerValueSetItem.js.map +1 -1
  19. package/lib/components/FormComponents/ChoiceItems/ChoiceSelectAnswerOptionFields.d.ts +1 -0
  20. package/lib/components/FormComponents/ChoiceItems/ChoiceSelectAnswerOptionFields.js +7 -5
  21. package/lib/components/FormComponents/ChoiceItems/ChoiceSelectAnswerOptionFields.js.map +1 -1
  22. package/lib/components/FormComponents/ChoiceItems/ChoiceSelectAnswerOptionItem.js +4 -1
  23. package/lib/components/FormComponents/ChoiceItems/ChoiceSelectAnswerOptionItem.js.map +1 -1
  24. package/lib/components/FormComponents/ChoiceItems/ChoiceSelectAnswerOptionView.d.ts +1 -0
  25. package/lib/components/FormComponents/ChoiceItems/ChoiceSelectAnswerOptionView.js +3 -3
  26. package/lib/components/FormComponents/ChoiceItems/ChoiceSelectAnswerOptionView.js.map +1 -1
  27. package/lib/components/FormComponents/DecimalItem/DecimalItem.js +1 -1
  28. package/lib/components/FormComponents/DecimalItem/DecimalItem.js.map +1 -1
  29. package/lib/components/FormComponents/IntegerItem/IntegerItem.js +1 -1
  30. package/lib/components/FormComponents/IntegerItem/IntegerItem.js.map +1 -1
  31. package/lib/components/FormComponents/QuantityItem/QuantityItem.js +1 -1
  32. package/lib/components/FormComponents/QuantityItem/QuantityItem.js.map +1 -1
  33. package/lib/components/FormComponents/StringItem/StringItem.js +1 -1
  34. package/lib/components/FormComponents/StringItem/StringItem.js.map +1 -1
  35. package/lib/components/FormComponents/TextItem/TextItem.js +1 -1
  36. package/lib/components/FormComponents/TextItem/TextItem.js.map +1 -1
  37. package/lib/components/FormComponents/UrlItem/UrlItem.js +1 -1
  38. package/lib/components/FormComponents/UrlItem/UrlItem.js.map +1 -1
  39. package/lib/components/Renderer/BaseRenderer.js +6 -4
  40. package/lib/components/Renderer/BaseRenderer.js.map +1 -1
  41. package/lib/components/Renderer/FormBodyTabbed.js +1 -1
  42. package/lib/components/Renderer/FormBodyTabbed.js.map +1 -1
  43. package/lib/hooks/useValidationFeedback.js +33 -2
  44. package/lib/hooks/useValidationFeedback.js.map +1 -1
  45. package/lib/interfaces/questionnaireStore.interface.d.ts +2 -0
  46. package/lib/interfaces/targetConstraint.interface.d.ts +30 -0
  47. package/lib/interfaces/targetConstraint.interface.js +2 -0
  48. package/lib/interfaces/targetConstraint.interface.js.map +1 -0
  49. package/lib/stores/questionnaireResponseStore.d.ts +8 -2
  50. package/lib/stores/questionnaireResponseStore.js +15 -16
  51. package/lib/stores/questionnaireResponseStore.js.map +1 -1
  52. package/lib/stores/questionnaireStore.d.ts +7 -0
  53. package/lib/stores/questionnaireStore.js +22 -8
  54. package/lib/stores/questionnaireStore.js.map +1 -1
  55. package/lib/utils/calculatedExpression.d.ts +3 -2
  56. package/lib/utils/calculatedExpression.js +2 -2
  57. package/lib/utils/calculatedExpression.js.map +1 -1
  58. package/lib/utils/enableWhenExpression.d.ts +4 -3
  59. package/lib/utils/enableWhenExpression.js +4 -4
  60. package/lib/utils/enableWhenExpression.js.map +1 -1
  61. package/lib/utils/fhirpath.d.ts +8 -3
  62. package/lib/utils/fhirpath.js +27 -8
  63. package/lib/utils/fhirpath.js.map +1 -1
  64. package/lib/utils/initialise.d.ts +6 -2
  65. package/lib/utils/initialise.js +16 -4
  66. package/lib/utils/initialise.js.map +1 -1
  67. package/lib/utils/itemControl.d.ts +1 -0
  68. package/lib/utils/itemControl.js +11 -0
  69. package/lib/utils/itemControl.js.map +1 -1
  70. package/lib/utils/manageForm.js +2 -0
  71. package/lib/utils/manageForm.js.map +1 -1
  72. package/lib/utils/questionnaireStoreUtils/createQuestionaireModel.js +4 -0
  73. package/lib/utils/questionnaireStoreUtils/createQuestionaireModel.js.map +1 -1
  74. package/lib/utils/questionnaireStoreUtils/extractTargetConstraint.d.ts +4 -0
  75. package/lib/utils/questionnaireStoreUtils/extractTargetConstraint.js +39 -0
  76. package/lib/utils/questionnaireStoreUtils/extractTargetConstraint.js.map +1 -0
  77. package/lib/utils/targetConstraint.d.ts +23 -0
  78. package/lib/utils/targetConstraint.js +179 -0
  79. package/lib/utils/targetConstraint.js.map +1 -0
  80. package/lib/utils/validate.d.ts +73 -0
  81. package/lib/utils/validate.js +742 -0
  82. package/lib/utils/validate.js.map +1 -0
  83. package/lib/utils/validateQuestionnaire.d.ts +40 -40
  84. package/lib/utils/validateQuestionnaire.js +1 -0
  85. package/lib/utils/validateQuestionnaire.js.map +1 -1
  86. package/lib/utils/validateQuestionnaireResponse.d.ts +71 -0
  87. package/lib/utils/validateQuestionnaireResponse.js +710 -0
  88. package/lib/utils/validateQuestionnaireResponse.js.map +1 -0
  89. package/lib/utils/validateTargetConstraint.d.ts +1 -0
  90. package/lib/utils/validateTargetConstraint.js +34 -0
  91. package/lib/utils/validateTargetConstraint.js.map +1 -0
  92. package/package.json +1 -1
  93. package/src/components/FormComponents/BooleanItem/BooleanField.tsx +82 -73
  94. package/src/components/FormComponents/BooleanItem/BooleanItem.tsx +7 -0
  95. package/src/components/FormComponents/ChoiceItems/ChoiceRadioAnswerOptionFields.tsx +43 -18
  96. package/src/components/FormComponents/ChoiceItems/ChoiceRadioAnswerOptionItem.tsx +6 -0
  97. package/src/components/FormComponents/ChoiceItems/ChoiceRadioAnswerOptionView.tsx +4 -0
  98. package/src/components/FormComponents/ChoiceItems/ChoiceRadioAnswerValueSetFields.tsx +35 -17
  99. package/src/components/FormComponents/ChoiceItems/ChoiceRadioAnswerValueSetItem.tsx +8 -2
  100. package/src/components/FormComponents/ChoiceItems/ChoiceSelectAnswerOptionFields.tsx +41 -34
  101. package/src/components/FormComponents/ChoiceItems/ChoiceSelectAnswerOptionItem.tsx +5 -0
  102. package/src/components/FormComponents/ChoiceItems/ChoiceSelectAnswerOptionView.tsx +4 -0
  103. package/src/components/FormComponents/DecimalItem/DecimalItem.tsx +2 -1
  104. package/src/components/FormComponents/IntegerItem/IntegerItem.tsx +2 -1
  105. package/src/components/FormComponents/QuantityItem/QuantityItem.tsx +2 -1
  106. package/src/components/FormComponents/StringItem/StringItem.tsx +1 -1
  107. package/src/components/FormComponents/TextItem/TextItem.tsx +2 -1
  108. package/src/components/FormComponents/UrlItem/UrlItem.tsx +2 -1
  109. package/src/components/Renderer/BaseRenderer.tsx +6 -4
  110. package/src/components/Renderer/FormBodyTabbed.tsx +1 -1
  111. package/src/hooks/useValidationFeedback.ts +39 -2
  112. package/src/interfaces/questionnaireStore.interface.ts +2 -0
  113. package/src/interfaces/renderProps.interface.ts +1 -0
  114. package/src/interfaces/targetConstraint.interface.ts +36 -0
  115. package/src/stores/questionnaireResponseStore.ts +25 -18
  116. package/src/stores/questionnaireStore.ts +31 -5
  117. package/src/utils/calculatedExpression.ts +4 -4
  118. package/src/utils/enableWhenExpression.ts +8 -7
  119. package/src/utils/fhirpath.ts +57 -9
  120. package/src/utils/initialise.ts +23 -6
  121. package/src/utils/itemControl.ts +15 -0
  122. package/src/utils/manageForm.ts +3 -0
  123. package/src/utils/questionnaireStoreUtils/createQuestionaireModel.ts +6 -0
  124. package/src/utils/questionnaireStoreUtils/extractTargetConstraint.ts +71 -0
  125. package/src/utils/targetConstraint.ts +243 -0
  126. package/src/utils/{validateQuestionnaire.ts → validate.ts} +138 -58
@@ -0,0 +1,710 @@
1
+ /*
2
+ * Copyright 2024 Commonwealth Scientific and Industrial Research
3
+ * Organisation (CSIRO) ABN 41 687 119 230.
4
+ *
5
+ * Licensed under the Apache License, Version 2.0 (the "License");
6
+ * you may not use this file except in compliance with the License.
7
+ * You may obtain a copy of the License at
8
+ *
9
+ * http://www.apache.org/licenses/LICENSE-2.0
10
+ *
11
+ * Unless required by applicable law or agreed to in writing, software
12
+ * distributed under the License is distributed on an "AS IS" BASIS,
13
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ * See the License for the specific language governing permissions and
15
+ * limitations under the License.
16
+ */
17
+ import { getQrItemsIndex, mapQItemsIndex } from './mapItem';
18
+ import { isHiddenByEnableWhen } from './qItem';
19
+ import { getDecimalPrecision, getMaxQuantityValue, getMaxValue, getMinQuantityValue, getMinValue, getRegexString, getRegexValidation, getShortText } from './itemControl';
20
+ import { structuredDataCapture } from 'fhir-sdc-helpers';
21
+ import { parseDecimalStringToFloat } from './parseInputs';
22
+ import dayjs from 'dayjs';
23
+ import { questionnaireStore } from '../stores';
24
+ export var ValidationResult;
25
+ (function (ValidationResult) {
26
+ ValidationResult["unknown"] = "unknown";
27
+ ValidationResult["questionnaireNotFound"] = "questionnaireNotFound";
28
+ ValidationResult["questionnaireInactive"] = "questionnaireInactive";
29
+ ValidationResult["questionnaireDraft"] = "questionnaireDraft";
30
+ ValidationResult["questionnaireRetired"] = "questionnaireRetired";
31
+ ValidationResult["invalidLinkId"] = "invalidLinkId";
32
+ ValidationResult["invalidType"] = "invalidType";
33
+ ValidationResult["invalidAnswerType"] = "invalidAnswerType";
34
+ ValidationResult["invalidAnswerOption"] = "invalidAnswerOption";
35
+ ValidationResult["exclusiveAnswerOption"] = "exclusiveAnswerOption";
36
+ ValidationResult["invalidUrlValue"] = "invalidUrlValue";
37
+ ValidationResult["groupShouldNotHaveAnswers"] = "groupShouldNotHaveAnswers";
38
+ ValidationResult["required"] = "required";
39
+ ValidationResult["invariant"] = "invariant";
40
+ ValidationResult["invariantExecution"] = "invariantExecution";
41
+ ValidationResult["repeats"] = "repeats";
42
+ ValidationResult["minCount"] = "minCount";
43
+ ValidationResult["maxCount"] = "maxCount";
44
+ ValidationResult["minValue"] = "minValue";
45
+ ValidationResult["maxValue"] = "maxValue";
46
+ ValidationResult["maxDecimalPlaces"] = "maxDecimalPlaces";
47
+ ValidationResult["minLength"] = "minLength";
48
+ ValidationResult["maxLength"] = "maxLength";
49
+ ValidationResult["invalidNewLine"] = "invalidNewLine";
50
+ ValidationResult["invalidCoding"] = "invalidCoding";
51
+ ValidationResult["tsError"] = "tsError";
52
+ ValidationResult["maxAttachmentSize"] = "maxAttachmentSize";
53
+ ValidationResult["attachmentSizeInconsistent"] = "attachmentSizeInconsistent";
54
+ ValidationResult["invalidAttachmentType"] = "invalidAttachmentType";
55
+ ValidationResult["displayAnswer"] = "displayAnswer";
56
+ ValidationResult["regex"] = "regex";
57
+ ValidationResult["regexTimeout"] = "regexTimeout";
58
+ ValidationResult["invalidRefValue"] = "invalidRefValue";
59
+ ValidationResult["invalidRefResourceType"] = "invalidRefResourceType";
60
+ ValidationResult["invalidRefResourceTypeRestriction"] = "invalidRefResourceTypeRestriction";
61
+ ValidationResult["minValueIncompatUnits"] = "minValueIncompatUnits";
62
+ ValidationResult["maxValueIncompatUnits"] = "maxValueIncompatUnits";
63
+ ValidationResult["invalidUnit"] = "invalidUnit";
64
+ ValidationResult["invalidUnitValueSet"] = "invalidUnitValueSet";
65
+ ValidationResult["minQuantityValue"] = "minQuantityValue";
66
+ ValidationResult["maxQuantityValue"] = "maxQuantityValue"; // Maximum Quantity value constraint violated
67
+ })(ValidationResult || (ValidationResult = {}));
68
+ /**
69
+ * Recursively go through the questionnaireResponse and check for un-filled required qItems
70
+ * At the moment item.required for group items are not checked
71
+ *
72
+ * @author Sean Fong
73
+ */
74
+ export function validateQuestionnaireResponse(params) {
75
+ var _a;
76
+ const { questionnaire, questionnaireResponse } = params;
77
+ const enableWhenIsActivated = questionnaireStore.getState().enableWhenIsActivated;
78
+ const enableWhenItems = questionnaireStore.getState().enableWhenItems;
79
+ const enableWhenExpressions = questionnaireStore.getState().enableWhenExpressions;
80
+ if (!questionnaire.item || questionnaire.item.length === 0) {
81
+ return {};
82
+ }
83
+ if (!questionnaireResponse.item || questionnaireResponse.item.length === 0) {
84
+ questionnaireResponse.item = [];
85
+ }
86
+ const qItemsIndexMap = mapQItemsIndex(questionnaire);
87
+ const topLevelQRItemsByIndex = getQrItemsIndex(questionnaire.item, questionnaireResponse.item, qItemsIndexMap);
88
+ const invalidItems = {};
89
+ let qrItemIndex = 0;
90
+ for (const [index, topLevelQItem] of questionnaire.item.entries()) {
91
+ let repeatGroupInstances = null;
92
+ let topLevelQRItem = (_a = topLevelQRItemsByIndex[index]) !== null && _a !== void 0 ? _a : {
93
+ linkId: topLevelQItem.linkId,
94
+ text: topLevelQItem.text
95
+ };
96
+ // topLevelQRItem being an array means this item is a repeat group
97
+ const isRepeatGroup = Array.isArray(topLevelQRItem);
98
+ if (Array.isArray(topLevelQRItem)) {
99
+ repeatGroupInstances = topLevelQRItem.length;
100
+ topLevelQRItem = {
101
+ linkId: topLevelQItem.linkId,
102
+ text: topLevelQItem.text,
103
+ item: topLevelQRItem
104
+ };
105
+ }
106
+ const locationExpression = `QuestionnaireResponse.item`;
107
+ validateItemRecursive({
108
+ qItem: topLevelQItem,
109
+ qrItem: topLevelQRItem,
110
+ qrItemIndex,
111
+ locationExpression,
112
+ invalidItems,
113
+ enableWhenIsActivated,
114
+ enableWhenItems,
115
+ enableWhenExpressions,
116
+ isRepeatGroupInstance: false
117
+ });
118
+ // Increment qrItemIndex
119
+ // If it's a repeat group, increment by the number of instances so qrItemIndex is correct once we reach the next item
120
+ if (isRepeatGroup && typeof repeatGroupInstances === 'number') {
121
+ qrItemIndex += repeatGroupInstances;
122
+ }
123
+ else {
124
+ qrItemIndex++;
125
+ }
126
+ }
127
+ return invalidItems;
128
+ }
129
+ function validateItemRecursive(params) {
130
+ var _a, _b, _c, _d;
131
+ const { qItem, qrItem, qrItemIndex, invalidItems, enableWhenIsActivated, enableWhenItems, enableWhenExpressions, isRepeatGroupInstance } = params;
132
+ let { locationExpression } = params;
133
+ // If item is hidden by enableWhen, skip validation
134
+ if (isHiddenByEnableWhen({
135
+ linkId: qItem.linkId,
136
+ enableWhenIsActivated,
137
+ enableWhenItems,
138
+ enableWhenExpressions
139
+ })) {
140
+ return;
141
+ }
142
+ // Validate repeat groups
143
+ if (qItem.type === 'group' && qItem.repeats) {
144
+ if (!isRepeatGroupInstance) {
145
+ validateRepeatGroupRecursive({
146
+ qItem,
147
+ qrItem,
148
+ qrItemIndex,
149
+ locationExpression,
150
+ invalidItems,
151
+ enableWhenIsActivated,
152
+ enableWhenItems,
153
+ enableWhenExpressions,
154
+ isRepeatGroupInstance: false
155
+ });
156
+ return;
157
+ }
158
+ }
159
+ locationExpression = `${locationExpression}[${qrItemIndex}]`;
160
+ // Recursively validate groups with child items
161
+ const childQItems = qItem.item;
162
+ if (childQItems && childQItems.length > 0) {
163
+ const childQrItems = (_a = qrItem === null || qrItem === void 0 ? void 0 : qrItem.item) !== null && _a !== void 0 ? _a : [];
164
+ const indexMap = mapQItemsIndex(qItem);
165
+ const qrItemsByIndex = getQrItemsIndex(childQItems, childQrItems, indexMap);
166
+ // Check if group is required and has no answers
167
+ if (qItem.type === 'group' && qItem.required) {
168
+ if (!qrItem.item || ((_b = qrItem.item) === null || _b === void 0 ? void 0 : _b.length) === 0) {
169
+ invalidItems[qItem.linkId] = createValidationOperationOutcome(ValidationResult.required, qItem, qrItem, null, locationExpression, (_c = invalidItems[qItem.linkId]) === null || _c === void 0 ? void 0 : _c.issue);
170
+ }
171
+ }
172
+ // Loop through child items
173
+ for (const [index, childQItem] of childQItems.entries()) {
174
+ const childLocationExpression = `${locationExpression}.item`;
175
+ let childQRItem = (_d = qrItemsByIndex[index]) !== null && _d !== void 0 ? _d : {
176
+ linkId: childQItem.linkId,
177
+ text: childQItem.text
178
+ };
179
+ if (Array.isArray(childQRItem)) {
180
+ childQRItem = {
181
+ linkId: childQItem.linkId,
182
+ text: childQItem.text,
183
+ item: childQRItem
184
+ };
185
+ }
186
+ validateItemRecursive({
187
+ qItem: childQItem,
188
+ qrItem: childQRItem,
189
+ qrItemIndex: index,
190
+ locationExpression: childLocationExpression,
191
+ invalidItems: invalidItems,
192
+ enableWhenIsActivated,
193
+ enableWhenItems,
194
+ enableWhenExpressions,
195
+ isRepeatGroupInstance: false
196
+ });
197
+ }
198
+ }
199
+ // Stop checking if the item is a group, we have checked previously
200
+ if (qItem.type === 'group') {
201
+ return;
202
+ }
203
+ // Validate the item, note that this can be either a group or a non-group
204
+ validateSingleItem(qItem, qrItem, invalidItems, locationExpression);
205
+ }
206
+ function validateRepeatGroupRecursive(params) {
207
+ var _a;
208
+ const { qItem, qrItem, qrItemIndex, locationExpression, invalidItems, enableWhenIsActivated, enableWhenItems, enableWhenExpressions } = params;
209
+ if (!qItem.item || qItem.item.length === 0 || !qrItem.item || qrItem.item.length === 0) {
210
+ return;
211
+ }
212
+ // Get repeat group answers
213
+ const repeatGroupAnswers = (_a = qrItem.item) !== null && _a !== void 0 ? _a : [];
214
+ for (const [index, repeatGroupAnswer] of repeatGroupAnswers.entries()) {
215
+ // Because the item is a repeat group and might have multiple answer instances, we need to increment the qItemIndex by the instanceIndex
216
+ const updatedQrItemIndex = qrItemIndex + index;
217
+ validateItemRecursive({
218
+ qItem: qItem,
219
+ qrItem: repeatGroupAnswer,
220
+ qrItemIndex: updatedQrItemIndex,
221
+ locationExpression: locationExpression,
222
+ invalidItems: invalidItems,
223
+ enableWhenIsActivated,
224
+ enableWhenItems,
225
+ enableWhenExpressions,
226
+ isRepeatGroupInstance: true
227
+ });
228
+ }
229
+ }
230
+ function validateSingleItem(qItem, qrItem, invalidItems, locationExpression) {
231
+ var _a, _b;
232
+ // Validate item.required first before every other validation check
233
+ if (qItem.type !== 'display') {
234
+ if (qItem.required && !qrItem.answer) {
235
+ invalidItems[qItem.linkId] = createValidationOperationOutcome(ValidationResult.required, qItem, qrItem, null, locationExpression, (_a = invalidItems[qItem.linkId]) === null || _a === void 0 ? void 0 : _a.issue);
236
+ return invalidItems;
237
+ }
238
+ }
239
+ // Validate regex, maxLength and minLength, maxQuantity and minQuantity
240
+ if (qrItem.answer) {
241
+ for (const [i, answer] of qrItem.answer.entries()) {
242
+ // Your code here, you can use 'index' and 'answer' as needed
243
+ if (answer.valueString ||
244
+ answer.valueInteger ||
245
+ answer.valueDecimal ||
246
+ answer.valueUri ||
247
+ answer.valueQuantity) {
248
+ const invalidInputType = getInputInvalidType({
249
+ qItem,
250
+ input: getInputInString(answer),
251
+ regexValidation: getRegexValidation(qItem),
252
+ minLength: structuredDataCapture.getMinLength(qItem),
253
+ maxLength: qItem.maxLength,
254
+ maxDecimalPlaces: structuredDataCapture.getMaxDecimalPlaces(qItem),
255
+ minValue: getMinValue(qItem),
256
+ maxValue: getMaxValue(qItem),
257
+ minQuantityValue: getMinQuantityValue(qItem),
258
+ maxQuantityValue: getMaxQuantityValue(qItem)
259
+ });
260
+ if (invalidInputType) {
261
+ invalidItems[qItem.linkId] = createValidationOperationOutcome(invalidInputType, qItem, qrItem, i, locationExpression, (_b = invalidItems[qItem.linkId]) === null || _b === void 0 ? void 0 : _b.issue);
262
+ } // if not invalid input types found
263
+ else {
264
+ //do nothing
265
+ }
266
+ }
267
+ }
268
+ }
269
+ return invalidItems;
270
+ }
271
+ function getInputInString(answer) {
272
+ if (!answer) {
273
+ return '';
274
+ }
275
+ if (answer.valueString) {
276
+ return answer.valueString;
277
+ }
278
+ else if (answer.valueInteger) {
279
+ return answer.valueInteger.toString();
280
+ }
281
+ else if (answer.valueDecimal) {
282
+ return answer.valueDecimal.toString();
283
+ }
284
+ else if (answer.valueUri) {
285
+ return answer.valueUri;
286
+ }
287
+ else if (answer.valueQuantity && answer.valueQuantity.value) {
288
+ // return the valueQuantity as string
289
+ return answer.valueQuantity.value.toString();
290
+ }
291
+ return '';
292
+ }
293
+ export function getInputInvalidType(getInputInvalidTypeParams) {
294
+ var _a, _b;
295
+ const { qItem, input, regexValidation, minLength, maxLength, maxDecimalPlaces, minValue, maxValue, minQuantityValue, maxQuantityValue } = getInputInvalidTypeParams;
296
+ if (input) {
297
+ if (regexValidation && !regexValidation.expression.test(input)) {
298
+ return ValidationResult.regex;
299
+ }
300
+ if (minLength !== undefined && input.length < minLength) {
301
+ return ValidationResult.minLength;
302
+ }
303
+ if (maxLength !== undefined && input.length > maxLength) {
304
+ return ValidationResult.maxLength;
305
+ }
306
+ if (maxDecimalPlaces !== undefined) {
307
+ const decimalPlaces = (_b = (_a = input.split('.')[1]) === null || _a === void 0 ? void 0 : _a.length) !== null && _b !== void 0 ? _b : 0;
308
+ if (decimalPlaces > maxDecimalPlaces) {
309
+ return ValidationResult.maxDecimalPlaces;
310
+ }
311
+ }
312
+ if (minValue !== undefined) {
313
+ const minValueError = checkMinValue(qItem, input, minValue);
314
+ if (minValueError !== null) {
315
+ return ValidationResult.minValue;
316
+ }
317
+ }
318
+ if (maxValue !== undefined) {
319
+ const maxValueError = checkMaxValue(qItem, input, maxValue);
320
+ if (maxValueError !== null) {
321
+ return ValidationResult.maxValue;
322
+ }
323
+ }
324
+ // if minQuantityValue exists then check the value and validate
325
+ if (minQuantityValue !== undefined) {
326
+ const minQuantityValueError = checkMinQuantityValue(qItem, input, minQuantityValue);
327
+ if (minQuantityValueError !== null) {
328
+ return ValidationResult.minQuantityValue;
329
+ }
330
+ else {
331
+ // No error, do nothing
332
+ }
333
+ }
334
+ // if maxQuantityValue exists then check the value and validate
335
+ if (maxQuantityValue !== undefined) {
336
+ const maxQuantityValueError = checkMaxQuantityValue(qItem, input, maxQuantityValue);
337
+ if (maxQuantityValueError !== null) {
338
+ return ValidationResult.maxQuantityValue;
339
+ }
340
+ else {
341
+ // No error, do nothing
342
+ }
343
+ }
344
+ }
345
+ return null;
346
+ }
347
+ function checkMinValue(qItem, input, minValue) {
348
+ switch (qItem.type) {
349
+ case 'integer':
350
+ if (typeof minValue === 'number') {
351
+ if (parseInt(input) < minValue) {
352
+ return ValidationResult.minValue;
353
+ }
354
+ }
355
+ break;
356
+ case 'decimal': {
357
+ const precision = getDecimalPrecision(qItem);
358
+ const decimalValue = precision
359
+ ? parseDecimalStringToFloat(input, precision)
360
+ : parseFloat(input);
361
+ if (typeof minValue === 'number') {
362
+ if (decimalValue < minValue) {
363
+ return ValidationResult.minValue;
364
+ }
365
+ }
366
+ break;
367
+ }
368
+ case 'date':
369
+ if (typeof minValue === 'string') {
370
+ if (new Date(input) < new Date(minValue)) {
371
+ return ValidationResult.minValue;
372
+ }
373
+ }
374
+ break;
375
+ case 'dateTime':
376
+ if (typeof minValue === 'string') {
377
+ if (dayjs(input).isBefore(dayjs(minValue))) {
378
+ return ValidationResult.minValue;
379
+ }
380
+ }
381
+ break;
382
+ default:
383
+ return null;
384
+ }
385
+ return null;
386
+ }
387
+ function checkMaxValue(qItem, input, maxValue) {
388
+ switch (qItem.type) {
389
+ case 'integer':
390
+ if (typeof maxValue === 'number') {
391
+ if (parseInt(input) > maxValue) {
392
+ return ValidationResult.maxValue;
393
+ }
394
+ }
395
+ break;
396
+ case 'decimal': {
397
+ const precision = getDecimalPrecision(qItem);
398
+ const decimalValue = precision
399
+ ? parseDecimalStringToFloat(input, precision)
400
+ : parseFloat(input);
401
+ if (typeof maxValue === 'number') {
402
+ if (decimalValue > maxValue) {
403
+ return ValidationResult.maxValue;
404
+ }
405
+ }
406
+ break;
407
+ }
408
+ case 'date':
409
+ if (typeof maxValue === 'string') {
410
+ if (new Date(input) > new Date(maxValue)) {
411
+ return ValidationResult.maxValue;
412
+ }
413
+ }
414
+ break;
415
+ case 'dateTime':
416
+ if (typeof maxValue === 'string') {
417
+ if (dayjs(input).isAfter(dayjs(maxValue))) {
418
+ return ValidationResult.maxValue;
419
+ }
420
+ }
421
+ break;
422
+ default:
423
+ return null;
424
+ }
425
+ return null;
426
+ }
427
+ /**
428
+ * Checks for Minimum Quantity Value and returns the validation results
429
+ *
430
+ * @param {QuestionnaireItem} qItem
431
+ * @param {string} input
432
+ * @param {number} minQuantityValue
433
+ * @return {*} {(ValidationResult.minQuantityValue | null)}
434
+ */
435
+ function checkMinQuantityValue(qItem, input, minQuantityValue) {
436
+ switch (qItem.type) {
437
+ case 'quantity': {
438
+ const precision = getDecimalPrecision(qItem);
439
+ const decimalValue = precision
440
+ ? parseDecimalStringToFloat(input, precision)
441
+ : parseFloat(input);
442
+ if (decimalValue < minQuantityValue) {
443
+ return ValidationResult.minQuantityValue;
444
+ }
445
+ break;
446
+ }
447
+ default:
448
+ return null;
449
+ }
450
+ return null;
451
+ }
452
+ /**
453
+ * Checks for Maxmim Quantity Value and returns the validation results
454
+ *
455
+ * @param {QuestionnaireItem} qItem
456
+ * @param {string} input
457
+ * @param {number} maxQuantityValue
458
+ * @return {*} {(ValidationResult.maxQuantityValue | null)}
459
+ */
460
+ function checkMaxQuantityValue(qItem, input, maxQuantityValue) {
461
+ switch (qItem.type) {
462
+ case 'quantity': {
463
+ const precision = getDecimalPrecision(qItem);
464
+ const decimalValue = precision
465
+ ? parseDecimalStringToFloat(input, precision)
466
+ : parseFloat(input);
467
+ if (decimalValue > maxQuantityValue) {
468
+ return ValidationResult.maxQuantityValue;
469
+ }
470
+ break;
471
+ }
472
+ default:
473
+ return null;
474
+ }
475
+ return null;
476
+ }
477
+ export function createValidationOperationOutcome(error, qItem, qrItem, answerIndex, locationExpression, existingOperationOutcomeIssues = []) {
478
+ return {
479
+ resourceType: 'OperationOutcome',
480
+ issue: existingOperationOutcomeIssues.concat(createValidationOperationOutcomeIssue(error, qItem, qrItem, answerIndex, locationExpression))
481
+ };
482
+ }
483
+ function createValidationOperationOutcomeIssue(error, qItem, qrItem, answerIndex, locationExpression, severity = 'error', humanReadable) {
484
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o;
485
+ const errorCodeSystem = 'http://fhir.forms-lab.com/CodeSystem/errors';
486
+ let detailsText = '';
487
+ let fieldDisplayText = '';
488
+ if (qItem && qrItem) {
489
+ fieldDisplayText =
490
+ (_d = (_c = (_b = (_a = qrItem === null || qrItem === void 0 ? void 0 : qrItem.text) !== null && _a !== void 0 ? _a : getShortText(qItem)) !== null && _b !== void 0 ? _b : qItem === null || qItem === void 0 ? void 0 : qItem.text) !== null && _c !== void 0 ? _c : qItem.linkId) !== null && _d !== void 0 ? _d : qrItem.linkId;
491
+ }
492
+ else {
493
+ fieldDisplayText = 'Unknown item';
494
+ }
495
+ if (!fieldDisplayText && fieldDisplayText.endsWith(':')) {
496
+ fieldDisplayText = fieldDisplayText.substring(0, fieldDisplayText.length - 1);
497
+ }
498
+ answerIndex = answerIndex !== null && answerIndex !== void 0 ? answerIndex : 0;
499
+ // create operationOutcomeIssue based on error
500
+ switch (error) {
501
+ case ValidationResult.required: {
502
+ if ((qItem === null || qItem === void 0 ? void 0 : qItem.type) === 'group') {
503
+ detailsText = `${fieldDisplayText}: Mandatory group does not have answer(s)`;
504
+ }
505
+ else {
506
+ detailsText = `${fieldDisplayText}: Mandatory field does not have an answer`;
507
+ }
508
+ return {
509
+ severity: severity,
510
+ code: 'required',
511
+ expression: [locationExpression],
512
+ details: {
513
+ coding: [
514
+ {
515
+ system: errorCodeSystem,
516
+ code: error,
517
+ display: 'Required'
518
+ }
519
+ ],
520
+ text: detailsText
521
+ }
522
+ };
523
+ }
524
+ case ValidationResult.regex: {
525
+ detailsText = `${fieldDisplayText}: The value '${getInputInString((_e = qrItem === null || qrItem === void 0 ? void 0 : qrItem.answer) === null || _e === void 0 ? void 0 : _e[answerIndex])}' does not match the defined format.`;
526
+ if (qItem && structuredDataCapture.getEntryFormat(qItem)) {
527
+ detailsText += ` ${structuredDataCapture.getEntryFormat(qItem)}`;
528
+ }
529
+ return {
530
+ severity: severity,
531
+ code: 'invalid',
532
+ expression: [locationExpression],
533
+ details: {
534
+ coding: [
535
+ {
536
+ system: errorCodeSystem,
537
+ code: error,
538
+ display: 'Invalid format'
539
+ }
540
+ ],
541
+ text: detailsText
542
+ },
543
+ diagnostics: qItem ? ((_f = getRegexString(qItem)) !== null && _f !== void 0 ? _f : undefined) : undefined
544
+ };
545
+ }
546
+ case ValidationResult.minLength: {
547
+ detailsText = `${fieldDisplayText}: Expected the minimum value ${qItem ? structuredDataCapture.getMinLength(qItem) : undefined} characters, received '${getInputInString((_g = qrItem === null || qrItem === void 0 ? void 0 : qrItem.answer) === null || _g === void 0 ? void 0 : _g[answerIndex])}'`;
548
+ return {
549
+ severity: severity,
550
+ code: 'business-rule',
551
+ expression: [locationExpression],
552
+ details: {
553
+ coding: [
554
+ {
555
+ system: errorCodeSystem,
556
+ code: error,
557
+ display: 'Too short'
558
+ }
559
+ ],
560
+ text: detailsText
561
+ }
562
+ };
563
+ }
564
+ case ValidationResult.maxLength: {
565
+ detailsText = `${fieldDisplayText}: Exceeded maximum of ${qItem === null || qItem === void 0 ? void 0 : qItem.maxLength} characters, received '${getInputInString((_h = qrItem === null || qrItem === void 0 ? void 0 : qrItem.answer) === null || _h === void 0 ? void 0 : _h[answerIndex])}'`;
566
+ return {
567
+ severity: severity,
568
+ code: 'business-rule',
569
+ expression: [locationExpression],
570
+ details: {
571
+ coding: [
572
+ {
573
+ system: errorCodeSystem,
574
+ code: error,
575
+ display: 'Too long'
576
+ }
577
+ ],
578
+ text: detailsText
579
+ }
580
+ };
581
+ }
582
+ case ValidationResult.maxDecimalPlaces: {
583
+ detailsText = `${fieldDisplayText}: Exceeded maximum decimal places ${qItem ? structuredDataCapture.getMaxDecimalPlaces(qItem) : undefined}, received '${getInputInString((_j = qrItem === null || qrItem === void 0 ? void 0 : qrItem.answer) === null || _j === void 0 ? void 0 : _j[answerIndex])}'`;
584
+ return {
585
+ severity: severity,
586
+ code: 'business-rule',
587
+ expression: [locationExpression],
588
+ details: {
589
+ coding: [
590
+ {
591
+ system: errorCodeSystem,
592
+ code: error,
593
+ display: 'Too precise'
594
+ }
595
+ ],
596
+ text: detailsText
597
+ }
598
+ };
599
+ }
600
+ case ValidationResult.minValue: {
601
+ detailsText = `${fieldDisplayText}: Expected the minimum value ${qItem ? getMinValue(qItem) : undefined}, received '${getInputInString((_k = qrItem === null || qrItem === void 0 ? void 0 : qrItem.answer) === null || _k === void 0 ? void 0 : _k[answerIndex])}'`;
602
+ return {
603
+ severity: severity,
604
+ code: 'business-rule',
605
+ expression: [locationExpression],
606
+ details: {
607
+ coding: [
608
+ {
609
+ system: errorCodeSystem,
610
+ code: error,
611
+ display: 'Too small'
612
+ }
613
+ ],
614
+ text: detailsText
615
+ }
616
+ };
617
+ }
618
+ case ValidationResult.maxValue: {
619
+ detailsText = `${fieldDisplayText}: Exceeded the maximum value ${qItem ? getMaxValue(qItem) : undefined}, received '${getInputInString((_l = qrItem === null || qrItem === void 0 ? void 0 : qrItem.answer) === null || _l === void 0 ? void 0 : _l[answerIndex])}'`;
620
+ return {
621
+ severity: severity,
622
+ code: 'business-rule',
623
+ expression: [locationExpression],
624
+ details: {
625
+ coding: [
626
+ {
627
+ system: errorCodeSystem,
628
+ code: error,
629
+ display: 'Too big'
630
+ }
631
+ ],
632
+ text: detailsText
633
+ }
634
+ };
635
+ }
636
+ // Validation result error handling for min quantity extension
637
+ case ValidationResult.minQuantityValue: {
638
+ detailsText = `${fieldDisplayText}: Expected the minimum value ${qItem ? getMinQuantityValue(qItem) : undefined}, received '${getInputInString((_m = qrItem === null || qrItem === void 0 ? void 0 : qrItem.answer) === null || _m === void 0 ? void 0 : _m[answerIndex])}'`;
639
+ return {
640
+ severity: severity,
641
+ code: 'business-rule',
642
+ expression: [locationExpression],
643
+ details: {
644
+ coding: [
645
+ {
646
+ system: errorCodeSystem,
647
+ code: error,
648
+ display: 'Too small'
649
+ }
650
+ ],
651
+ text: detailsText
652
+ }
653
+ };
654
+ }
655
+ // Validation result error handling for max quantity extension
656
+ case ValidationResult.maxQuantityValue: {
657
+ detailsText = `${fieldDisplayText}: Exceeded the maximum value ${qItem ? getMaxQuantityValue(qItem) : undefined}, received '${getInputInString((_o = qrItem === null || qrItem === void 0 ? void 0 : qrItem.answer) === null || _o === void 0 ? void 0 : _o[answerIndex])}'`;
658
+ return {
659
+ severity: severity,
660
+ code: 'business-rule',
661
+ expression: [locationExpression],
662
+ details: {
663
+ coding: [
664
+ {
665
+ system: errorCodeSystem,
666
+ code: error,
667
+ display: 'Too big'
668
+ }
669
+ ],
670
+ text: detailsText
671
+ }
672
+ };
673
+ }
674
+ case ValidationResult.invariant: {
675
+ return {
676
+ severity: severity,
677
+ code: 'business-rule',
678
+ expression: [locationExpression],
679
+ details: {
680
+ coding: [
681
+ {
682
+ system: errorCodeSystem,
683
+ code: error,
684
+ display: humanReadable
685
+ }
686
+ ],
687
+ text: humanReadable
688
+ }
689
+ };
690
+ }
691
+ // mark unknown issues as fatal
692
+ default: {
693
+ return {
694
+ severity: 'error',
695
+ code: 'unknown',
696
+ expression: [locationExpression],
697
+ details: {
698
+ coding: [
699
+ {
700
+ system: errorCodeSystem,
701
+ code: 'unknown',
702
+ display: 'Unknown'
703
+ }
704
+ ]
705
+ }
706
+ };
707
+ }
708
+ }
709
+ }
710
+ //# sourceMappingURL=validateQuestionnaireResponse.js.map