@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.
- package/lib/components/FormComponents/BooleanItem/BooleanField.d.ts +1 -0
- package/lib/components/FormComponents/BooleanItem/BooleanField.js +20 -17
- package/lib/components/FormComponents/BooleanItem/BooleanField.js.map +1 -1
- package/lib/components/FormComponents/BooleanItem/BooleanItem.js +6 -3
- package/lib/components/FormComponents/BooleanItem/BooleanItem.js.map +1 -1
- package/lib/components/FormComponents/ChoiceItems/ChoiceRadioAnswerOptionFields.d.ts +1 -0
- package/lib/components/FormComponents/ChoiceItems/ChoiceRadioAnswerOptionFields.js +15 -7
- package/lib/components/FormComponents/ChoiceItems/ChoiceRadioAnswerOptionFields.js.map +1 -1
- package/lib/components/FormComponents/ChoiceItems/ChoiceRadioAnswerOptionItem.js +5 -2
- package/lib/components/FormComponents/ChoiceItems/ChoiceRadioAnswerOptionItem.js.map +1 -1
- package/lib/components/FormComponents/ChoiceItems/ChoiceRadioAnswerOptionView.d.ts +1 -0
- package/lib/components/FormComponents/ChoiceItems/ChoiceRadioAnswerOptionView.js +3 -3
- package/lib/components/FormComponents/ChoiceItems/ChoiceRadioAnswerOptionView.js.map +1 -1
- package/lib/components/FormComponents/ChoiceItems/ChoiceRadioAnswerValueSetFields.d.ts +1 -0
- package/lib/components/FormComponents/ChoiceItems/ChoiceRadioAnswerValueSetFields.js +14 -7
- package/lib/components/FormComponents/ChoiceItems/ChoiceRadioAnswerValueSetFields.js.map +1 -1
- package/lib/components/FormComponents/ChoiceItems/ChoiceRadioAnswerValueSetItem.js +6 -3
- package/lib/components/FormComponents/ChoiceItems/ChoiceRadioAnswerValueSetItem.js.map +1 -1
- package/lib/components/FormComponents/ChoiceItems/ChoiceSelectAnswerOptionFields.d.ts +1 -0
- package/lib/components/FormComponents/ChoiceItems/ChoiceSelectAnswerOptionFields.js +7 -5
- package/lib/components/FormComponents/ChoiceItems/ChoiceSelectAnswerOptionFields.js.map +1 -1
- package/lib/components/FormComponents/ChoiceItems/ChoiceSelectAnswerOptionItem.js +4 -1
- package/lib/components/FormComponents/ChoiceItems/ChoiceSelectAnswerOptionItem.js.map +1 -1
- package/lib/components/FormComponents/ChoiceItems/ChoiceSelectAnswerOptionView.d.ts +1 -0
- package/lib/components/FormComponents/ChoiceItems/ChoiceSelectAnswerOptionView.js +3 -3
- package/lib/components/FormComponents/ChoiceItems/ChoiceSelectAnswerOptionView.js.map +1 -1
- package/lib/components/FormComponents/DecimalItem/DecimalItem.js +1 -1
- package/lib/components/FormComponents/DecimalItem/DecimalItem.js.map +1 -1
- package/lib/components/FormComponents/IntegerItem/IntegerItem.js +1 -1
- package/lib/components/FormComponents/IntegerItem/IntegerItem.js.map +1 -1
- package/lib/components/FormComponents/QuantityItem/QuantityItem.js +1 -1
- package/lib/components/FormComponents/QuantityItem/QuantityItem.js.map +1 -1
- package/lib/components/FormComponents/StringItem/StringItem.js +1 -1
- package/lib/components/FormComponents/StringItem/StringItem.js.map +1 -1
- package/lib/components/FormComponents/TextItem/TextItem.js +1 -1
- package/lib/components/FormComponents/TextItem/TextItem.js.map +1 -1
- package/lib/components/FormComponents/UrlItem/UrlItem.js +1 -1
- package/lib/components/FormComponents/UrlItem/UrlItem.js.map +1 -1
- package/lib/components/Renderer/BaseRenderer.js +6 -4
- package/lib/components/Renderer/BaseRenderer.js.map +1 -1
- package/lib/components/Renderer/FormBodyTabbed.js +1 -1
- package/lib/components/Renderer/FormBodyTabbed.js.map +1 -1
- package/lib/hooks/useValidationFeedback.js +33 -2
- package/lib/hooks/useValidationFeedback.js.map +1 -1
- package/lib/interfaces/questionnaireStore.interface.d.ts +2 -0
- package/lib/interfaces/targetConstraint.interface.d.ts +30 -0
- package/lib/interfaces/targetConstraint.interface.js +2 -0
- package/lib/interfaces/targetConstraint.interface.js.map +1 -0
- package/lib/stores/questionnaireResponseStore.d.ts +8 -2
- package/lib/stores/questionnaireResponseStore.js +15 -16
- package/lib/stores/questionnaireResponseStore.js.map +1 -1
- package/lib/stores/questionnaireStore.d.ts +7 -0
- package/lib/stores/questionnaireStore.js +22 -8
- package/lib/stores/questionnaireStore.js.map +1 -1
- package/lib/utils/calculatedExpression.d.ts +3 -2
- package/lib/utils/calculatedExpression.js +2 -2
- package/lib/utils/calculatedExpression.js.map +1 -1
- package/lib/utils/enableWhenExpression.d.ts +4 -3
- package/lib/utils/enableWhenExpression.js +4 -4
- package/lib/utils/enableWhenExpression.js.map +1 -1
- package/lib/utils/fhirpath.d.ts +8 -3
- package/lib/utils/fhirpath.js +27 -8
- package/lib/utils/fhirpath.js.map +1 -1
- package/lib/utils/initialise.d.ts +6 -2
- package/lib/utils/initialise.js +16 -4
- package/lib/utils/initialise.js.map +1 -1
- package/lib/utils/itemControl.d.ts +1 -0
- package/lib/utils/itemControl.js +11 -0
- package/lib/utils/itemControl.js.map +1 -1
- package/lib/utils/manageForm.js +2 -0
- package/lib/utils/manageForm.js.map +1 -1
- package/lib/utils/questionnaireStoreUtils/createQuestionaireModel.js +4 -0
- package/lib/utils/questionnaireStoreUtils/createQuestionaireModel.js.map +1 -1
- package/lib/utils/questionnaireStoreUtils/extractTargetConstraint.d.ts +4 -0
- package/lib/utils/questionnaireStoreUtils/extractTargetConstraint.js +39 -0
- package/lib/utils/questionnaireStoreUtils/extractTargetConstraint.js.map +1 -0
- package/lib/utils/targetConstraint.d.ts +23 -0
- package/lib/utils/targetConstraint.js +179 -0
- package/lib/utils/targetConstraint.js.map +1 -0
- package/lib/utils/validate.d.ts +73 -0
- package/lib/utils/validate.js +742 -0
- package/lib/utils/validate.js.map +1 -0
- package/lib/utils/validateQuestionnaire.d.ts +40 -40
- package/lib/utils/validateQuestionnaire.js +1 -0
- package/lib/utils/validateQuestionnaire.js.map +1 -1
- package/lib/utils/validateQuestionnaireResponse.d.ts +71 -0
- package/lib/utils/validateQuestionnaireResponse.js +710 -0
- package/lib/utils/validateQuestionnaireResponse.js.map +1 -0
- package/lib/utils/validateTargetConstraint.d.ts +1 -0
- package/lib/utils/validateTargetConstraint.js +34 -0
- package/lib/utils/validateTargetConstraint.js.map +1 -0
- package/package.json +1 -1
- package/src/components/FormComponents/BooleanItem/BooleanField.tsx +82 -73
- package/src/components/FormComponents/BooleanItem/BooleanItem.tsx +7 -0
- package/src/components/FormComponents/ChoiceItems/ChoiceRadioAnswerOptionFields.tsx +43 -18
- package/src/components/FormComponents/ChoiceItems/ChoiceRadioAnswerOptionItem.tsx +6 -0
- package/src/components/FormComponents/ChoiceItems/ChoiceRadioAnswerOptionView.tsx +4 -0
- package/src/components/FormComponents/ChoiceItems/ChoiceRadioAnswerValueSetFields.tsx +35 -17
- package/src/components/FormComponents/ChoiceItems/ChoiceRadioAnswerValueSetItem.tsx +8 -2
- package/src/components/FormComponents/ChoiceItems/ChoiceSelectAnswerOptionFields.tsx +41 -34
- package/src/components/FormComponents/ChoiceItems/ChoiceSelectAnswerOptionItem.tsx +5 -0
- package/src/components/FormComponents/ChoiceItems/ChoiceSelectAnswerOptionView.tsx +4 -0
- package/src/components/FormComponents/DecimalItem/DecimalItem.tsx +2 -1
- package/src/components/FormComponents/IntegerItem/IntegerItem.tsx +2 -1
- package/src/components/FormComponents/QuantityItem/QuantityItem.tsx +2 -1
- package/src/components/FormComponents/StringItem/StringItem.tsx +1 -1
- package/src/components/FormComponents/TextItem/TextItem.tsx +2 -1
- package/src/components/FormComponents/UrlItem/UrlItem.tsx +2 -1
- package/src/components/Renderer/BaseRenderer.tsx +6 -4
- package/src/components/Renderer/FormBodyTabbed.tsx +1 -1
- package/src/hooks/useValidationFeedback.ts +39 -2
- package/src/interfaces/questionnaireStore.interface.ts +2 -0
- package/src/interfaces/renderProps.interface.ts +1 -0
- package/src/interfaces/targetConstraint.interface.ts +36 -0
- package/src/stores/questionnaireResponseStore.ts +25 -18
- package/src/stores/questionnaireStore.ts +31 -5
- package/src/utils/calculatedExpression.ts +4 -4
- package/src/utils/enableWhenExpression.ts +8 -7
- package/src/utils/fhirpath.ts +57 -9
- package/src/utils/initialise.ts +23 -6
- package/src/utils/itemControl.ts +15 -0
- package/src/utils/manageForm.ts +3 -0
- package/src/utils/questionnaireStoreUtils/createQuestionaireModel.ts +6 -0
- package/src/utils/questionnaireStoreUtils/extractTargetConstraint.ts +71 -0
- package/src/utils/targetConstraint.ts +243 -0
- package/src/utils/{validateQuestionnaire.ts → validate.ts} +138 -58
|
@@ -50,6 +50,8 @@ import { insertCompleteAnswerOptionsIntoQuestionnaire } from '../utils/questionn
|
|
|
50
50
|
import type { InitialExpression } from '../interfaces/initialExpression.interface';
|
|
51
51
|
import type { QItemOverrideComponentProps, SdcUiOverrideComponentProps } from '../interfaces';
|
|
52
52
|
import type { ComponentType } from 'react';
|
|
53
|
+
import type { TargetConstraint } from '../interfaces/targetConstraint.interface';
|
|
54
|
+
import { readTargetConstraintLocationLinkIds } from '../utils/targetConstraint';
|
|
53
55
|
|
|
54
56
|
/**
|
|
55
57
|
* QuestionnaireStore properties and methods
|
|
@@ -65,6 +67,8 @@ import type { ComponentType } from 'react';
|
|
|
65
67
|
* @property currentPageIndex - Index of the current page
|
|
66
68
|
* @property variables - Questionnaire variables object containing FHIRPath and x-fhir-query variables
|
|
67
69
|
* @property launchContexts - Key-value pair of launch contexts `Record<launch context name, launch context properties>`
|
|
70
|
+
* @property targetConstraints - Key-value pair of target constraints `Record<target constraint key, target constraint properties>`
|
|
71
|
+
* @property targetConstraintLinkIds - Key-value pair of linkIds against target constraint key(s) `Record<linkId, target constraint keys>`
|
|
68
72
|
* @property enableWhenItems - EnableWhenItems object containing enableWhen items and their linked questions
|
|
69
73
|
* @property enableWhenLinkedQuestions - Key-value pair of linked questions to enableWhen items `Record<linkId, linkIds of linked questions>`
|
|
70
74
|
* @property enableWhenIsActivated - Flag to turn enableWhen checks on/off
|
|
@@ -109,6 +113,8 @@ export interface QuestionnaireStoreType {
|
|
|
109
113
|
currentPageIndex: number;
|
|
110
114
|
variables: Variables;
|
|
111
115
|
launchContexts: Record<string, LaunchContext>;
|
|
116
|
+
targetConstraints: Record<string, TargetConstraint>;
|
|
117
|
+
targetConstraintLinkIds: Record<string, string[]>;
|
|
112
118
|
enableWhenItems: EnableWhenItems;
|
|
113
119
|
enableWhenLinkedQuestions: Record<string, string[]>;
|
|
114
120
|
enableWhenIsActivated: boolean;
|
|
@@ -183,6 +189,8 @@ export const questionnaireStore = createStore<QuestionnaireStoreType>()((set, ge
|
|
|
183
189
|
currentPageIndex: 0,
|
|
184
190
|
variables: { fhirPathVariables: {}, xFhirQueryVariables: {} },
|
|
185
191
|
launchContexts: {},
|
|
192
|
+
targetConstraints: {},
|
|
193
|
+
targetConstraintLinkIds: {},
|
|
186
194
|
calculatedExpressions: {},
|
|
187
195
|
initialExpressions: {},
|
|
188
196
|
enableWhenExpressions: { singleExpressions: {}, repeatExpressions: {} },
|
|
@@ -229,6 +237,7 @@ export const questionnaireStore = createStore<QuestionnaireStoreType>()((set, ge
|
|
|
229
237
|
|
|
230
238
|
// Initialise form with questionnaire response and properties in questionnaire model
|
|
231
239
|
const {
|
|
240
|
+
initialTargetConstraints,
|
|
232
241
|
initialEnableWhenItems,
|
|
233
242
|
initialEnableWhenLinkedQuestions,
|
|
234
243
|
initialEnableWhenExpressions,
|
|
@@ -239,10 +248,11 @@ export const questionnaireStore = createStore<QuestionnaireStoreType>()((set, ge
|
|
|
239
248
|
fhirPathTerminologyCache: updatedFhirPathTerminologyCache
|
|
240
249
|
} = await initialiseFormFromResponse({
|
|
241
250
|
questionnaireResponse,
|
|
251
|
+
targetConstraints: questionnaireModel.targetConstraints,
|
|
242
252
|
enableWhenItems: questionnaireModel.enableWhenItems,
|
|
243
253
|
enableWhenExpressions: questionnaireModel.enableWhenExpressions,
|
|
244
254
|
calculatedExpressions: questionnaireModel.calculatedExpressions,
|
|
245
|
-
|
|
255
|
+
variables: questionnaireModel.variables,
|
|
246
256
|
tabs: questionnaireModel.tabs,
|
|
247
257
|
pages: questionnaireModel.pages,
|
|
248
258
|
fhirPathContext: fhirPathContext,
|
|
@@ -250,6 +260,12 @@ export const questionnaireStore = createStore<QuestionnaireStoreType>()((set, ge
|
|
|
250
260
|
terminologyServerUrl: terminologyServerUrl
|
|
251
261
|
});
|
|
252
262
|
|
|
263
|
+
// Read target constraint locations
|
|
264
|
+
const targetConstraintLinkIds = readTargetConstraintLocationLinkIds(
|
|
265
|
+
questionnaire,
|
|
266
|
+
initialTargetConstraints
|
|
267
|
+
);
|
|
268
|
+
|
|
253
269
|
set({
|
|
254
270
|
sourceQuestionnaire: questionnaire,
|
|
255
271
|
itemTypes: questionnaireModel.itemTypes,
|
|
@@ -260,6 +276,8 @@ export const questionnaireStore = createStore<QuestionnaireStoreType>()((set, ge
|
|
|
260
276
|
currentPageIndex: firstVisiblePage,
|
|
261
277
|
variables: questionnaireModel.variables,
|
|
262
278
|
launchContexts: questionnaireModel.launchContexts,
|
|
279
|
+
targetConstraints: initialTargetConstraints,
|
|
280
|
+
targetConstraintLinkIds: targetConstraintLinkIds,
|
|
263
281
|
enableWhenItems: initialEnableWhenItems,
|
|
264
282
|
enableWhenLinkedQuestions: initialEnableWhenLinkedQuestions,
|
|
265
283
|
enableWhenExpressions: initialEnableWhenExpressions,
|
|
@@ -286,6 +304,8 @@ export const questionnaireStore = createStore<QuestionnaireStoreType>()((set, ge
|
|
|
286
304
|
currentPageIndex: 0,
|
|
287
305
|
variables: { fhirPathVariables: {}, xFhirQueryVariables: {} },
|
|
288
306
|
launchContexts: {},
|
|
307
|
+
targetConstraints: {},
|
|
308
|
+
targetConstraintLinkIds: {},
|
|
289
309
|
enableWhenItems: { singleItems: {}, repeatItems: {} },
|
|
290
310
|
enableWhenLinkedQuestions: {},
|
|
291
311
|
enableWhenExpressions: { singleExpressions: {}, repeatExpressions: {} },
|
|
@@ -364,7 +384,7 @@ export const questionnaireStore = createStore<QuestionnaireStoreType>()((set, ge
|
|
|
364
384
|
await mutateRepeatEnableWhenExpressionInstances({
|
|
365
385
|
questionnaireResponse: questionnaireResponseStore.getState().updatableResponse,
|
|
366
386
|
questionnaireResponseItemMap: questionnaireResponseStore.getState().updatableResponseItems,
|
|
367
|
-
|
|
387
|
+
variables: get().variables,
|
|
368
388
|
existingFhirPathContext: get().fhirPathContext,
|
|
369
389
|
fhirPathTerminologyCache: get().fhirPathTerminologyCache,
|
|
370
390
|
enableWhenExpressions: enableWhenExpressions,
|
|
@@ -387,6 +407,7 @@ export const questionnaireStore = createStore<QuestionnaireStoreType>()((set, ge
|
|
|
387
407
|
const updatedResponseItemMap = createQuestionnaireResponseItemMap(updatedResponse);
|
|
388
408
|
const {
|
|
389
409
|
isUpdated,
|
|
410
|
+
updatedTargetConstraints,
|
|
390
411
|
updatedEnableWhenExpressions,
|
|
391
412
|
updatedCalculatedExpressions,
|
|
392
413
|
updatedFhirPathContext,
|
|
@@ -394,9 +415,10 @@ export const questionnaireStore = createStore<QuestionnaireStoreType>()((set, ge
|
|
|
394
415
|
} = await evaluateUpdatedExpressions({
|
|
395
416
|
updatedResponse,
|
|
396
417
|
updatedResponseItemMap,
|
|
418
|
+
targetConstraints: get().targetConstraints,
|
|
397
419
|
enableWhenExpressions: get().enableWhenExpressions,
|
|
398
420
|
calculatedExpressions: get().calculatedExpressions,
|
|
399
|
-
|
|
421
|
+
variables: get().variables,
|
|
400
422
|
existingFhirPathContext: get().fhirPathContext,
|
|
401
423
|
fhirPathTerminologyCache: get().fhirPathTerminologyCache,
|
|
402
424
|
terminologyServerUrl: terminologyServerStore.getState().url
|
|
@@ -404,6 +426,7 @@ export const questionnaireStore = createStore<QuestionnaireStoreType>()((set, ge
|
|
|
404
426
|
|
|
405
427
|
if (isUpdated) {
|
|
406
428
|
set(() => ({
|
|
429
|
+
targetConstraints: updatedTargetConstraints,
|
|
407
430
|
enableWhenExpressions: updatedEnableWhenExpressions,
|
|
408
431
|
calculatedExpressions: updatedCalculatedExpressions,
|
|
409
432
|
fhirPathContext: updatedFhirPathContext,
|
|
@@ -436,7 +459,7 @@ export const questionnaireStore = createStore<QuestionnaireStoreType>()((set, ge
|
|
|
436
459
|
initialResponse: populatedResponse,
|
|
437
460
|
initialResponseItemMap: initialResponseItemMap,
|
|
438
461
|
calculatedExpressions: get().calculatedExpressions,
|
|
439
|
-
|
|
462
|
+
variables: get().variables,
|
|
440
463
|
existingFhirPathContext: get().fhirPathContext,
|
|
441
464
|
fhirPathTerminologyCache: get().fhirPathTerminologyCache,
|
|
442
465
|
terminologyServerUrl: terminologyServerStore.getState().url
|
|
@@ -453,6 +476,7 @@ export const questionnaireStore = createStore<QuestionnaireStoreType>()((set, ge
|
|
|
453
476
|
);
|
|
454
477
|
|
|
455
478
|
const {
|
|
479
|
+
initialTargetConstraints,
|
|
456
480
|
initialEnableWhenItems,
|
|
457
481
|
initialEnableWhenLinkedQuestions,
|
|
458
482
|
initialEnableWhenExpressions,
|
|
@@ -460,10 +484,11 @@ export const questionnaireStore = createStore<QuestionnaireStoreType>()((set, ge
|
|
|
460
484
|
firstVisiblePage
|
|
461
485
|
} = await initialiseFormFromResponse({
|
|
462
486
|
questionnaireResponse: updatedResponse,
|
|
487
|
+
targetConstraints: get().targetConstraints,
|
|
463
488
|
enableWhenItems: get().enableWhenItems,
|
|
464
489
|
enableWhenExpressions: get().enableWhenExpressions,
|
|
465
490
|
calculatedExpressions: initialCalculatedExpressions,
|
|
466
|
-
|
|
491
|
+
variables: get().variables,
|
|
467
492
|
tabs: get().tabs,
|
|
468
493
|
pages: get().pages,
|
|
469
494
|
fhirPathContext: updatedFhirPathContext,
|
|
@@ -474,6 +499,7 @@ export const questionnaireStore = createStore<QuestionnaireStoreType>()((set, ge
|
|
|
474
499
|
fhirPathTerminologyCache = evaluateInitialCalculatedExpressionsResult.fhirPathTerminologyCache;
|
|
475
500
|
|
|
476
501
|
set(() => ({
|
|
502
|
+
targetConstraints: initialTargetConstraints,
|
|
477
503
|
enableWhenItems: initialEnableWhenItems,
|
|
478
504
|
enableWhenLinkedQuestions: initialEnableWhenLinkedQuestions,
|
|
479
505
|
enableWhenExpressions: initialEnableWhenExpressions,
|
|
@@ -19,7 +19,6 @@ import type { CalculatedExpression } from '../interfaces/calculatedExpression.in
|
|
|
19
19
|
import fhirpath from 'fhirpath';
|
|
20
20
|
import fhirpath_r4_model from 'fhirpath/fhir-context/r4';
|
|
21
21
|
import type {
|
|
22
|
-
Expression,
|
|
23
22
|
Questionnaire,
|
|
24
23
|
QuestionnaireItem,
|
|
25
24
|
QuestionnaireItemAnswerOption,
|
|
@@ -34,12 +33,13 @@ import { updateQrItemsInGroup } from './qrItem';
|
|
|
34
33
|
import dayjs from 'dayjs';
|
|
35
34
|
import { updateQuestionnaireResponse } from './genericRecursive';
|
|
36
35
|
import isEqual from 'lodash.isequal';
|
|
36
|
+
import type { Variables } from '../interfaces';
|
|
37
37
|
|
|
38
38
|
interface EvaluateInitialCalculatedExpressionsParams {
|
|
39
39
|
initialResponse: QuestionnaireResponse;
|
|
40
40
|
initialResponseItemMap: Record<string, QuestionnaireResponseItem[]>;
|
|
41
41
|
calculatedExpressions: Record<string, CalculatedExpression[]>;
|
|
42
|
-
|
|
42
|
+
variables: Variables;
|
|
43
43
|
existingFhirPathContext: Record<string, any>;
|
|
44
44
|
fhirPathTerminologyCache: Record<string, any>;
|
|
45
45
|
terminologyServerUrl: string;
|
|
@@ -56,7 +56,7 @@ export async function evaluateInitialCalculatedExpressions(
|
|
|
56
56
|
initialResponse,
|
|
57
57
|
initialResponseItemMap,
|
|
58
58
|
calculatedExpressions,
|
|
59
|
-
|
|
59
|
+
variables,
|
|
60
60
|
existingFhirPathContext,
|
|
61
61
|
terminologyServerUrl
|
|
62
62
|
} = params;
|
|
@@ -81,7 +81,7 @@ export async function evaluateInitialCalculatedExpressions(
|
|
|
81
81
|
const fhirPathEvalResult = await createFhirPathContext(
|
|
82
82
|
initialResponse,
|
|
83
83
|
initialResponseItemMap,
|
|
84
|
-
|
|
84
|
+
variables,
|
|
85
85
|
existingFhirPathContext,
|
|
86
86
|
fhirPathTerminologyCache,
|
|
87
87
|
terminologyServerUrl
|
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
* limitations under the License.
|
|
16
16
|
*/
|
|
17
17
|
|
|
18
|
-
import type {
|
|
18
|
+
import type { QuestionnaireResponse, QuestionnaireResponseItem } from 'fhir/r4';
|
|
19
19
|
import { createFhirPathContext, handleFhirPathResult } from './fhirpath';
|
|
20
20
|
import fhirpath from 'fhirpath';
|
|
21
21
|
import fhirpath_r4_model from 'fhirpath/fhir-context/r4';
|
|
@@ -24,12 +24,13 @@ import type {
|
|
|
24
24
|
EnableWhenRepeatExpression,
|
|
25
25
|
EnableWhenSingleExpression
|
|
26
26
|
} from '../interfaces/enableWhen.interface';
|
|
27
|
+
import type { Variables } from '../interfaces';
|
|
27
28
|
|
|
28
29
|
interface EvaluateInitialEnableWhenExpressionsParams {
|
|
29
30
|
initialResponse: QuestionnaireResponse;
|
|
30
31
|
initialResponseItemMap: Record<string, QuestionnaireResponseItem[]>;
|
|
31
32
|
enableWhenExpressions: EnableWhenExpressions;
|
|
32
|
-
|
|
33
|
+
variables: Variables;
|
|
33
34
|
existingFhirPathContext: Record<string, any>;
|
|
34
35
|
fhirPathTerminologyCache: Record<string, any>;
|
|
35
36
|
terminologyServerUrl: string;
|
|
@@ -46,7 +47,7 @@ export async function evaluateInitialEnableWhenExpressions(
|
|
|
46
47
|
initialResponse,
|
|
47
48
|
initialResponseItemMap,
|
|
48
49
|
enableWhenExpressions,
|
|
49
|
-
|
|
50
|
+
variables,
|
|
50
51
|
existingFhirPathContext,
|
|
51
52
|
terminologyServerUrl
|
|
52
53
|
} = params;
|
|
@@ -58,7 +59,7 @@ export async function evaluateInitialEnableWhenExpressions(
|
|
|
58
59
|
const fhirPathEvalResult = await createFhirPathContext(
|
|
59
60
|
initialResponse,
|
|
60
61
|
initialResponseItemMap,
|
|
61
|
-
|
|
62
|
+
variables,
|
|
62
63
|
existingFhirPathContext,
|
|
63
64
|
fhirPathTerminologyCache,
|
|
64
65
|
terminologyServerUrl
|
|
@@ -325,7 +326,7 @@ export async function evaluateEnableWhenExpressions(
|
|
|
325
326
|
interface MutateRepeatEnableWhenExpressionInstancesParams {
|
|
326
327
|
questionnaireResponse: QuestionnaireResponse;
|
|
327
328
|
questionnaireResponseItemMap: Record<string, QuestionnaireResponseItem[]>;
|
|
328
|
-
|
|
329
|
+
variables: Variables;
|
|
329
330
|
existingFhirPathContext: Record<string, any>;
|
|
330
331
|
fhirPathTerminologyCache: Record<string, any>;
|
|
331
332
|
enableWhenExpressions: EnableWhenExpressions;
|
|
@@ -341,7 +342,7 @@ export async function mutateRepeatEnableWhenExpressionInstances(
|
|
|
341
342
|
const {
|
|
342
343
|
questionnaireResponse,
|
|
343
344
|
questionnaireResponseItemMap,
|
|
344
|
-
|
|
345
|
+
variables,
|
|
345
346
|
fhirPathTerminologyCache,
|
|
346
347
|
existingFhirPathContext,
|
|
347
348
|
enableWhenExpressions,
|
|
@@ -356,7 +357,7 @@ export async function mutateRepeatEnableWhenExpressionInstances(
|
|
|
356
357
|
const fhirPathEvalResult = await createFhirPathContext(
|
|
357
358
|
questionnaireResponse,
|
|
358
359
|
questionnaireResponseItemMap,
|
|
359
|
-
|
|
360
|
+
variables,
|
|
360
361
|
existingFhirPathContext,
|
|
361
362
|
fhirPathTerminologyCache,
|
|
362
363
|
terminologyServerUrl
|
package/src/utils/fhirpath.ts
CHANGED
|
@@ -22,13 +22,17 @@ import type { CalculatedExpression } from '../interfaces/calculatedExpression.in
|
|
|
22
22
|
import type { EnableWhenExpressions } from '../interfaces/enableWhen.interface';
|
|
23
23
|
import { evaluateEnableWhenExpressions } from './enableWhenExpression';
|
|
24
24
|
import { evaluateCalculatedExpressions } from './calculatedExpression';
|
|
25
|
+
import { evaluateTargetConstraints } from './targetConstraint';
|
|
26
|
+
import type { TargetConstraint } from '../interfaces/targetConstraint.interface';
|
|
27
|
+
import type { Variables, VariableXFhirQuery } from '../interfaces';
|
|
25
28
|
|
|
26
29
|
interface EvaluateUpdatedExpressionsParams {
|
|
27
30
|
updatedResponse: QuestionnaireResponse;
|
|
28
31
|
updatedResponseItemMap: Record<string, QuestionnaireResponseItem[]>;
|
|
32
|
+
targetConstraints: Record<string, TargetConstraint>;
|
|
29
33
|
calculatedExpressions: Record<string, CalculatedExpression[]>;
|
|
30
34
|
enableWhenExpressions: EnableWhenExpressions;
|
|
31
|
-
|
|
35
|
+
variables: Variables;
|
|
32
36
|
existingFhirPathContext: Record<string, any>;
|
|
33
37
|
fhirPathTerminologyCache: Record<string, any>;
|
|
34
38
|
terminologyServerUrl: string;
|
|
@@ -38,6 +42,7 @@ export async function evaluateUpdatedExpressions(
|
|
|
38
42
|
params: EvaluateUpdatedExpressionsParams
|
|
39
43
|
): Promise<{
|
|
40
44
|
isUpdated: boolean;
|
|
45
|
+
updatedTargetConstraints: Record<string, TargetConstraint>;
|
|
41
46
|
updatedEnableWhenExpressions: EnableWhenExpressions;
|
|
42
47
|
updatedCalculatedExpressions: Record<string, CalculatedExpression[]>;
|
|
43
48
|
updatedFhirPathContext: Record<string, any>;
|
|
@@ -46,9 +51,10 @@ export async function evaluateUpdatedExpressions(
|
|
|
46
51
|
const {
|
|
47
52
|
updatedResponse,
|
|
48
53
|
updatedResponseItemMap,
|
|
54
|
+
targetConstraints,
|
|
49
55
|
enableWhenExpressions,
|
|
50
56
|
calculatedExpressions,
|
|
51
|
-
|
|
57
|
+
variables,
|
|
52
58
|
existingFhirPathContext,
|
|
53
59
|
terminologyServerUrl
|
|
54
60
|
} = params;
|
|
@@ -57,9 +63,10 @@ export async function evaluateUpdatedExpressions(
|
|
|
57
63
|
const noExpressionsToBeUpdated =
|
|
58
64
|
Object.keys(enableWhenExpressions).length === 0 &&
|
|
59
65
|
Object.keys(calculatedExpressions).length === 0;
|
|
60
|
-
if (noExpressionsToBeUpdated
|
|
66
|
+
if (noExpressionsToBeUpdated) {
|
|
61
67
|
return {
|
|
62
68
|
isUpdated: false,
|
|
69
|
+
updatedTargetConstraints: targetConstraints,
|
|
63
70
|
updatedEnableWhenExpressions: enableWhenExpressions,
|
|
64
71
|
updatedCalculatedExpressions: calculatedExpressions,
|
|
65
72
|
updatedFhirPathContext: existingFhirPathContext,
|
|
@@ -70,7 +77,7 @@ export async function evaluateUpdatedExpressions(
|
|
|
70
77
|
const fhirPathEvalResult = await createFhirPathContext(
|
|
71
78
|
updatedResponse,
|
|
72
79
|
updatedResponseItemMap,
|
|
73
|
-
|
|
80
|
+
variables,
|
|
74
81
|
existingFhirPathContext,
|
|
75
82
|
fhirPathTerminologyCache,
|
|
76
83
|
terminologyServerUrl
|
|
@@ -79,6 +86,14 @@ export async function evaluateUpdatedExpressions(
|
|
|
79
86
|
const updatedFhirPathContext = fhirPathEvalResult.fhirPathContext;
|
|
80
87
|
fhirPathTerminologyCache = fhirPathEvalResult.fhirPathTerminologyCache;
|
|
81
88
|
|
|
89
|
+
// Update targetConstraints
|
|
90
|
+
const { targetConstraintsIsUpdated, updatedTargetConstraints } = await evaluateTargetConstraints(
|
|
91
|
+
updatedFhirPathContext,
|
|
92
|
+
fhirPathTerminologyCache,
|
|
93
|
+
targetConstraints,
|
|
94
|
+
terminologyServerUrl
|
|
95
|
+
);
|
|
96
|
+
|
|
82
97
|
// Update enableWhenExpressions
|
|
83
98
|
const { enableWhenExpsIsUpdated, updatedEnableWhenExpressions } =
|
|
84
99
|
await evaluateEnableWhenExpressions(
|
|
@@ -97,10 +112,12 @@ export async function evaluateUpdatedExpressions(
|
|
|
97
112
|
terminologyServerUrl
|
|
98
113
|
);
|
|
99
114
|
|
|
100
|
-
const isUpdated =
|
|
115
|
+
const isUpdated =
|
|
116
|
+
enableWhenExpsIsUpdated || calculatedExpsIsUpdated || targetConstraintsIsUpdated;
|
|
101
117
|
|
|
102
118
|
return {
|
|
103
119
|
isUpdated,
|
|
120
|
+
updatedTargetConstraints,
|
|
104
121
|
updatedEnableWhenExpressions,
|
|
105
122
|
updatedCalculatedExpressions,
|
|
106
123
|
updatedFhirPathContext,
|
|
@@ -111,7 +128,7 @@ export async function evaluateUpdatedExpressions(
|
|
|
111
128
|
export async function createFhirPathContext(
|
|
112
129
|
questionnaireResponse: QuestionnaireResponse,
|
|
113
130
|
questionnaireResponseItemMap: Record<string, QuestionnaireResponseItem[]>,
|
|
114
|
-
|
|
131
|
+
variables: Variables,
|
|
115
132
|
existingFhirPathContext: Record<string, any>,
|
|
116
133
|
fhirPathTerminologyCache: Record<string, any>,
|
|
117
134
|
terminologyServerUrl: string
|
|
@@ -119,6 +136,9 @@ export async function createFhirPathContext(
|
|
|
119
136
|
fhirPathContext: Record<string, any>;
|
|
120
137
|
fhirPathTerminologyCache: Record<string, any>;
|
|
121
138
|
}> {
|
|
139
|
+
const { fhirPathVariables: variablesFhirPath, xFhirQueryVariables: variablesXFhirQuery } =
|
|
140
|
+
variables;
|
|
141
|
+
|
|
122
142
|
// Add latest resource to fhirPathContext
|
|
123
143
|
let fhirPathContext: Record<string, any> = {
|
|
124
144
|
...existingFhirPathContext,
|
|
@@ -126,6 +146,12 @@ export async function createFhirPathContext(
|
|
|
126
146
|
rootResource: questionnaireResponse
|
|
127
147
|
};
|
|
128
148
|
|
|
149
|
+
// Add empty x-fhir-query variables to fhirPathContext to prevent false-positive warnings
|
|
150
|
+
fhirPathContext = addEmptyXFhirQueryVariablesToFhirPathContext(
|
|
151
|
+
fhirPathContext,
|
|
152
|
+
variablesXFhirQuery
|
|
153
|
+
);
|
|
154
|
+
|
|
129
155
|
// Evaluate resource-level variables
|
|
130
156
|
const fhirPathEvalResult = await evaluateQuestionnaireLevelVariables(
|
|
131
157
|
questionnaireResponse,
|
|
@@ -155,13 +181,32 @@ export async function createFhirPathContext(
|
|
|
155
181
|
}
|
|
156
182
|
|
|
157
183
|
// Items don't exist in questionnaireResponseItemMap, but we still have to add them into the fhirPathContext as empty arrays
|
|
184
|
+
const qrItemMapIsEmpty = Object.keys(questionnaireResponseItemMap).length === 0;
|
|
158
185
|
for (const linkId in variablesFhirPath) {
|
|
159
|
-
fhirPathContext = addEmptyLinkIdVariables(
|
|
186
|
+
fhirPathContext = addEmptyLinkIdVariables(
|
|
187
|
+
linkId,
|
|
188
|
+
variablesFhirPath,
|
|
189
|
+
fhirPathContext,
|
|
190
|
+
qrItemMapIsEmpty
|
|
191
|
+
);
|
|
160
192
|
}
|
|
161
193
|
|
|
162
194
|
return { fhirPathContext, fhirPathTerminologyCache };
|
|
163
195
|
}
|
|
164
196
|
|
|
197
|
+
export function addEmptyXFhirQueryVariablesToFhirPathContext(
|
|
198
|
+
fhirPathContext: Record<string, any>,
|
|
199
|
+
variablesXFhirQuery: Record<string, VariableXFhirQuery>
|
|
200
|
+
) {
|
|
201
|
+
for (const variableName in variablesXFhirQuery) {
|
|
202
|
+
if (!fhirPathContext[variableName]) {
|
|
203
|
+
fhirPathContext[variableName] = [];
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
return fhirPathContext;
|
|
208
|
+
}
|
|
209
|
+
|
|
165
210
|
export async function evaluateLinkIdVariables(
|
|
166
211
|
item: QuestionnaireResponseItem,
|
|
167
212
|
variablesFhirPath: Record<string, Expression[]>,
|
|
@@ -213,7 +258,8 @@ export async function evaluateLinkIdVariables(
|
|
|
213
258
|
export function addEmptyLinkIdVariables(
|
|
214
259
|
linkId: string,
|
|
215
260
|
variablesFhirPath: Record<string, Expression[]>,
|
|
216
|
-
fhirPathContext: Record<string, any
|
|
261
|
+
fhirPathContext: Record<string, any>,
|
|
262
|
+
qrItemMapIsEmpty: boolean
|
|
217
263
|
) {
|
|
218
264
|
const linkIdVariables = variablesFhirPath[linkId];
|
|
219
265
|
if (!linkIdVariables || linkIdVariables.length === 0) {
|
|
@@ -222,7 +268,9 @@ export function addEmptyLinkIdVariables(
|
|
|
222
268
|
|
|
223
269
|
for (const variable of linkIdVariables) {
|
|
224
270
|
if (variable.expression && variable.name) {
|
|
225
|
-
|
|
271
|
+
// If the variable is not evaluated, add it as an empty array
|
|
272
|
+
// Also, when questionnaireResponseItemMap is empty, no items exist in the questionnaireResponse, therefore no variables are evaluated
|
|
273
|
+
if (fhirPathContext[`${variable.name}`] === undefined || qrItemMapIsEmpty) {
|
|
226
274
|
fhirPathContext[`${variable.name}`] = [];
|
|
227
275
|
}
|
|
228
276
|
}
|
package/src/utils/initialise.ts
CHANGED
|
@@ -19,7 +19,6 @@ import { evaluateInitialEnableWhenExpressions } from './enableWhenExpression';
|
|
|
19
19
|
import { getFirstVisibleTab } from './tabs';
|
|
20
20
|
import { getFirstVisiblePage } from './page';
|
|
21
21
|
import type {
|
|
22
|
-
Expression,
|
|
23
22
|
Questionnaire,
|
|
24
23
|
QuestionnaireItem,
|
|
25
24
|
QuestionnaireItemInitial,
|
|
@@ -36,6 +35,9 @@ import { evaluateInitialCalculatedExpressions } from './calculatedExpression';
|
|
|
36
35
|
import { createQuestionnaireResponseItemMap } from './questionnaireResponseStoreUtils/updatableResponseItems';
|
|
37
36
|
import { readQuestionnaireResponse } from './genericRecursive';
|
|
38
37
|
import { getQrItemsIndex, mapQItemsIndex } from './mapItem';
|
|
38
|
+
import type { TargetConstraint } from '../interfaces/targetConstraint.interface';
|
|
39
|
+
import { evaluateInitialTargetConstraints } from './targetConstraint';
|
|
40
|
+
import type { Variables } from '../interfaces';
|
|
39
41
|
|
|
40
42
|
/**
|
|
41
43
|
* Initialise a questionnaireResponse from a given questionnaire
|
|
@@ -311,10 +313,11 @@ function createNewRepeatGroupQuestionnaireResponseItem(
|
|
|
311
313
|
|
|
312
314
|
export interface initialFormFromResponseParams {
|
|
313
315
|
questionnaireResponse: QuestionnaireResponse;
|
|
316
|
+
targetConstraints: Record<string, TargetConstraint>;
|
|
314
317
|
enableWhenItems: EnableWhenItems;
|
|
315
318
|
enableWhenExpressions: EnableWhenExpressions;
|
|
316
319
|
calculatedExpressions: Record<string, CalculatedExpression[]>;
|
|
317
|
-
|
|
320
|
+
variables: Variables;
|
|
318
321
|
tabs: Tabs;
|
|
319
322
|
pages: Pages;
|
|
320
323
|
fhirPathContext: Record<string, any>;
|
|
@@ -323,6 +326,7 @@ export interface initialFormFromResponseParams {
|
|
|
323
326
|
}
|
|
324
327
|
|
|
325
328
|
export async function initialiseFormFromResponse(params: initialFormFromResponseParams): Promise<{
|
|
329
|
+
initialTargetConstraints: Record<string, TargetConstraint>;
|
|
326
330
|
initialEnableWhenItems: EnableWhenItems;
|
|
327
331
|
initialEnableWhenLinkedQuestions: Record<string, string[]>;
|
|
328
332
|
initialEnableWhenExpressions: EnableWhenExpressions;
|
|
@@ -334,10 +338,11 @@ export async function initialiseFormFromResponse(params: initialFormFromResponse
|
|
|
334
338
|
}> {
|
|
335
339
|
const {
|
|
336
340
|
questionnaireResponse,
|
|
341
|
+
targetConstraints,
|
|
337
342
|
enableWhenItems,
|
|
338
343
|
enableWhenExpressions,
|
|
339
344
|
calculatedExpressions,
|
|
340
|
-
|
|
345
|
+
variables,
|
|
341
346
|
tabs,
|
|
342
347
|
pages,
|
|
343
348
|
fhirPathContext,
|
|
@@ -353,24 +358,35 @@ export async function initialiseFormFromResponse(params: initialFormFromResponse
|
|
|
353
358
|
questionnaireResponse
|
|
354
359
|
);
|
|
355
360
|
|
|
361
|
+
const evaluateInitialTargetConstraintsResult = await evaluateInitialTargetConstraints({
|
|
362
|
+
initialResponse: questionnaireResponse,
|
|
363
|
+
initialResponseItemMap: initialResponseItemMap,
|
|
364
|
+
targetConstraints: targetConstraints,
|
|
365
|
+
variables: variables,
|
|
366
|
+
existingFhirPathContext: fhirPathContext,
|
|
367
|
+
fhirPathTerminologyCache: fhirPathTerminologyCache,
|
|
368
|
+
terminologyServerUrl
|
|
369
|
+
});
|
|
370
|
+
const { initialTargetConstraints } = evaluateInitialTargetConstraintsResult;
|
|
371
|
+
fhirPathTerminologyCache = evaluateInitialTargetConstraintsResult.fhirPathTerminologyCache;
|
|
372
|
+
|
|
356
373
|
const evaluateInitialEnableWhenExpressionsResult = await evaluateInitialEnableWhenExpressions({
|
|
357
374
|
initialResponse: questionnaireResponse,
|
|
358
375
|
initialResponseItemMap: initialResponseItemMap,
|
|
359
376
|
enableWhenExpressions: enableWhenExpressions,
|
|
360
|
-
|
|
377
|
+
variables: variables,
|
|
361
378
|
existingFhirPathContext: fhirPathContext,
|
|
362
379
|
fhirPathTerminologyCache: fhirPathTerminologyCache,
|
|
363
380
|
terminologyServerUrl: terminologyServerUrl
|
|
364
381
|
});
|
|
365
382
|
const { initialEnableWhenExpressions } = evaluateInitialEnableWhenExpressionsResult;
|
|
366
|
-
updatedFhirPathContext = evaluateInitialEnableWhenExpressionsResult.updatedFhirPathContext;
|
|
367
383
|
fhirPathTerminologyCache = evaluateInitialEnableWhenExpressionsResult.fhirPathTerminologyCache;
|
|
368
384
|
|
|
369
385
|
const evaluateInitialCalculatedExpressionsResult = await evaluateInitialCalculatedExpressions({
|
|
370
386
|
initialResponse: questionnaireResponse,
|
|
371
387
|
initialResponseItemMap: initialResponseItemMap,
|
|
372
388
|
calculatedExpressions: calculatedExpressions,
|
|
373
|
-
|
|
389
|
+
variables: variables,
|
|
374
390
|
existingFhirPathContext: fhirPathContext,
|
|
375
391
|
fhirPathTerminologyCache: fhirPathTerminologyCache,
|
|
376
392
|
terminologyServerUrl
|
|
@@ -389,6 +405,7 @@ export async function initialiseFormFromResponse(params: initialFormFromResponse
|
|
|
389
405
|
: 0;
|
|
390
406
|
|
|
391
407
|
return {
|
|
408
|
+
initialTargetConstraints,
|
|
392
409
|
initialEnableWhenItems: initialisedItems,
|
|
393
410
|
initialEnableWhenLinkedQuestions: linkedQuestions,
|
|
394
411
|
initialEnableWhenExpressions,
|
package/src/utils/itemControl.ts
CHANGED
|
@@ -471,6 +471,21 @@ export function getMaxValueFeedback(qItem: QuestionnaireItem) {
|
|
|
471
471
|
return null;
|
|
472
472
|
}
|
|
473
473
|
|
|
474
|
+
export function getRequiredFeedback(qItem: QuestionnaireItem) {
|
|
475
|
+
const itemControl = qItem.extension?.find(
|
|
476
|
+
(extension: Extension) =>
|
|
477
|
+
extension.url === 'https://smartforms.csiro.au/ig/StructureDefinition/required-feedback'
|
|
478
|
+
);
|
|
479
|
+
if (itemControl) {
|
|
480
|
+
const extensionString = itemControl.valueString;
|
|
481
|
+
if (extensionString) {
|
|
482
|
+
return extensionString;
|
|
483
|
+
}
|
|
484
|
+
}
|
|
485
|
+
|
|
486
|
+
return null;
|
|
487
|
+
}
|
|
488
|
+
|
|
474
489
|
/**
|
|
475
490
|
* Check if the item has a sdc-questionnaire-minQuantity and minQuantity extension
|
|
476
491
|
* @author Janardhan Vignarajan
|
package/src/utils/manageForm.ts
CHANGED
|
@@ -65,6 +65,9 @@ export async function buildForm(
|
|
|
65
65
|
questionnaireResponseStore.getState().buildSourceResponse(initialisedQuestionnaireResponse);
|
|
66
66
|
await questionnaireStore.getState().updatePopulatedProperties(initialisedQuestionnaireResponse);
|
|
67
67
|
|
|
68
|
+
// Adding another call to buildSourceResponse so invalidItems is truly updated - not great, but a cheap fix
|
|
69
|
+
questionnaireResponseStore.getState().buildSourceResponse(initialisedQuestionnaireResponse);
|
|
70
|
+
|
|
68
71
|
if (readOnly) {
|
|
69
72
|
questionnaireStore.getState().setFormAsReadOnly(readOnly);
|
|
70
73
|
}
|
|
@@ -31,6 +31,8 @@ import { resolveValueSets } from './resolveValueSets';
|
|
|
31
31
|
import { addAdditionalVariables } from './addAdditionalVariables';
|
|
32
32
|
import { getLinkIdPreferredTerminologyServerTuples, getLinkIdTypeTuples } from '../qItem';
|
|
33
33
|
import { addDisplayToAnswerOptions, addDisplayToProcessedCodings } from './addDisplayToCodings';
|
|
34
|
+
import type { TargetConstraint } from '../../interfaces/targetConstraint.interface';
|
|
35
|
+
import { extractTargetConstraints } from './extractTargetConstraint';
|
|
34
36
|
|
|
35
37
|
export async function createQuestionnaireModel(
|
|
36
38
|
questionnaire: Questionnaire,
|
|
@@ -49,6 +51,8 @@ export async function createQuestionnaireModel(
|
|
|
49
51
|
const pages: Pages = extractPages(questionnaire);
|
|
50
52
|
|
|
51
53
|
const launchContexts: Record<string, LaunchContext> = extractLaunchContexts(questionnaire);
|
|
54
|
+
const targetConstraints: Record<string, TargetConstraint> =
|
|
55
|
+
extractTargetConstraints(questionnaire);
|
|
52
56
|
|
|
53
57
|
let variables: Variables = extractQuestionnaireLevelVariables(questionnaire);
|
|
54
58
|
variables = addAdditionalVariables(variables, additionalVariables);
|
|
@@ -109,6 +113,7 @@ export async function createQuestionnaireModel(
|
|
|
109
113
|
pages,
|
|
110
114
|
variables,
|
|
111
115
|
launchContexts,
|
|
116
|
+
targetConstraints,
|
|
112
117
|
enableWhenItems,
|
|
113
118
|
enableWhenExpressions,
|
|
114
119
|
calculatedExpressions,
|
|
@@ -130,6 +135,7 @@ function createEmptyModel(): QuestionnaireModel {
|
|
|
130
135
|
pages: {},
|
|
131
136
|
variables: { fhirPathVariables: {}, xFhirQueryVariables: {} },
|
|
132
137
|
launchContexts: {},
|
|
138
|
+
targetConstraints: {},
|
|
133
139
|
calculatedExpressions: {},
|
|
134
140
|
initialExpressions: {},
|
|
135
141
|
enableWhenExpressions: { singleExpressions: {}, repeatExpressions: {} },
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import type { Extension, Questionnaire } from 'fhir/r4';
|
|
2
|
+
import type {
|
|
3
|
+
TargetConstraint,
|
|
4
|
+
TargetConstraintExpression,
|
|
5
|
+
TargetConstraintHuman,
|
|
6
|
+
TargetConstraintKey,
|
|
7
|
+
TargetConstraintLocation,
|
|
8
|
+
TargetConstraintSeverity
|
|
9
|
+
} from '../../interfaces/targetConstraint.interface';
|
|
10
|
+
|
|
11
|
+
export function constructTargetConstraint(extension: Extension): TargetConstraint | null {
|
|
12
|
+
const targetConstraintUrl = extension.url;
|
|
13
|
+
const targetConstraintKey = extension.extension?.find(
|
|
14
|
+
(ext) => ext.url === 'key' && typeof ext.valueId === 'string'
|
|
15
|
+
) as TargetConstraintKey | undefined;
|
|
16
|
+
|
|
17
|
+
const targetConstraintSeverity = extension.extension?.find(
|
|
18
|
+
(ext) =>
|
|
19
|
+
ext.url === 'severity' &&
|
|
20
|
+
ext.valueCode &&
|
|
21
|
+
(ext.valueCode === 'error' || ext.valueCode === 'warning')
|
|
22
|
+
) as TargetConstraintSeverity | undefined;
|
|
23
|
+
|
|
24
|
+
const targetConstraintExpression = extension.extension?.find(
|
|
25
|
+
(ext) => ext.url === 'expression' && ext.valueExpression
|
|
26
|
+
) as TargetConstraintExpression | undefined;
|
|
27
|
+
|
|
28
|
+
const targetConstraintHuman = extension.extension?.find(
|
|
29
|
+
(ext) => ext.url === 'human' && ext.valueString
|
|
30
|
+
) as TargetConstraintHuman | undefined;
|
|
31
|
+
|
|
32
|
+
const hasTargetConstraintLocation = extension.extension?.find(
|
|
33
|
+
(ext) => ext.url === 'location' && ext.valueString
|
|
34
|
+
) as TargetConstraintLocation | undefined;
|
|
35
|
+
|
|
36
|
+
if (
|
|
37
|
+
targetConstraintUrl === 'http://hl7.org/fhir/StructureDefinition/targetConstraint' &&
|
|
38
|
+
targetConstraintKey &&
|
|
39
|
+
targetConstraintSeverity &&
|
|
40
|
+
targetConstraintExpression &&
|
|
41
|
+
targetConstraintHuman
|
|
42
|
+
) {
|
|
43
|
+
return {
|
|
44
|
+
key: targetConstraintKey.valueId,
|
|
45
|
+
severityCode: targetConstraintSeverity.valueCode,
|
|
46
|
+
valueExpression: targetConstraintExpression.valueExpression,
|
|
47
|
+
human: targetConstraintHuman.valueString,
|
|
48
|
+
location: hasTargetConstraintLocation?.valueString
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
return null;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
export function extractTargetConstraints(
|
|
56
|
+
questionnaire: Questionnaire
|
|
57
|
+
): Record<string, TargetConstraint> {
|
|
58
|
+
if (!questionnaire.extension || questionnaire.extension.length === 0) {
|
|
59
|
+
return {};
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
const targetConstraints: Record<string, TargetConstraint> = {};
|
|
63
|
+
for (const ext of questionnaire.extension) {
|
|
64
|
+
const targetConstraint = constructTargetConstraint(ext);
|
|
65
|
+
if (targetConstraint?.key) {
|
|
66
|
+
targetConstraints[targetConstraint?.key] = targetConstraint;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
return targetConstraints;
|
|
71
|
+
}
|