@aehrc/smart-forms-renderer 0.25.2 → 0.26.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.
- package/lib/components/FormComponents/BooleanItem/BooleanItem.js +6 -1
- package/lib/components/FormComponents/BooleanItem/BooleanItem.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/ChoiceRadioAnswerValueSetItem.js +5 -2
- package/lib/components/FormComponents/ChoiceItems/ChoiceRadioAnswerValueSetItem.js.map +1 -1
- package/lib/components/FormComponents/ChoiceItems/ChoiceSelectAnswerOptionItem.js +5 -2
- package/lib/components/FormComponents/ChoiceItems/ChoiceSelectAnswerOptionItem.js.map +1 -1
- package/lib/components/FormComponents/ChoiceItems/ChoiceSelectAnswerValueSetItem.js +5 -2
- package/lib/components/FormComponents/ChoiceItems/ChoiceSelectAnswerValueSetItem.js.map +1 -1
- package/lib/components/FormComponents/DecimalItem/DecimalItem.js +9 -3
- package/lib/components/FormComponents/DecimalItem/DecimalItem.js.map +1 -1
- package/lib/components/FormComponents/IntegerItem/IntegerItem.js +7 -3
- package/lib/components/FormComponents/IntegerItem/IntegerItem.js.map +1 -1
- package/lib/components/FormComponents/StringItem/StringItem.js +7 -3
- package/lib/components/FormComponents/StringItem/StringItem.js.map +1 -1
- package/lib/components/FormComponents/TextItem/TextItem.js +7 -3
- package/lib/components/FormComponents/TextItem/TextItem.js.map +1 -1
- package/lib/components/Renderer/BaseRenderer.js +3 -3
- package/lib/components/Renderer/BaseRenderer.js.map +1 -1
- package/lib/hooks/useBooleanCalculatedExpression.d.ts +5 -4
- package/lib/hooks/useBooleanCalculatedExpression.js +12 -7
- package/lib/hooks/useBooleanCalculatedExpression.js.map +1 -1
- package/lib/hooks/useCodingCalculatedExpression.d.ts +4 -3
- package/lib/hooks/useCodingCalculatedExpression.js +14 -7
- package/lib/hooks/useCodingCalculatedExpression.js.map +1 -1
- package/lib/hooks/useDecimalCalculatedExpression.d.ts +3 -3
- package/lib/hooks/useDecimalCalculatedExpression.js +11 -7
- package/lib/hooks/useDecimalCalculatedExpression.js.map +1 -1
- package/lib/hooks/useDisplayCalculatedExpression.js +8 -1
- package/lib/hooks/useDisplayCalculatedExpression.js.map +1 -1
- package/lib/hooks/useIntegerCalculatedExpression.d.ts +3 -3
- package/lib/hooks/useIntegerCalculatedExpression.js +11 -7
- package/lib/hooks/useIntegerCalculatedExpression.js.map +1 -1
- package/lib/hooks/useStringCalculatedExpression.d.ts +3 -3
- package/lib/hooks/useStringCalculatedExpression.js +12 -7
- package/lib/hooks/useStringCalculatedExpression.js.map +1 -1
- package/lib/interfaces/calculatedExpression.interface.d.ts +1 -1
- package/lib/stores/questionnaireResponseStore.d.ts +3 -1
- package/lib/stores/questionnaireResponseStore.js +9 -1
- package/lib/stores/questionnaireResponseStore.js.map +1 -1
- package/lib/stores/questionnaireStore.d.ts +6 -2
- package/lib/stores/questionnaireStore.js +13 -2
- package/lib/stores/questionnaireStore.js.map +1 -1
- package/lib/utils/calculatedExpression.d.ts +2 -1
- package/lib/utils/calculatedExpression.js +14 -8
- package/lib/utils/calculatedExpression.js.map +1 -1
- package/lib/utils/enableWhenExpression.d.ts +3 -2
- package/lib/utils/enableWhenExpression.js +15 -5
- package/lib/utils/enableWhenExpression.js.map +1 -1
- package/lib/utils/fhirpath.d.ts +5 -4
- package/lib/utils/fhirpath.js +45 -33
- package/lib/utils/fhirpath.js.map +1 -1
- package/lib/utils/index.d.ts +1 -0
- package/lib/utils/index.js +1 -0
- package/lib/utils/index.js.map +1 -1
- package/lib/utils/initialise.js +5 -2
- package/lib/utils/initialise.js.map +1 -1
- package/lib/utils/parseInputs.js +1 -1
- package/lib/utils/parseInputs.js.map +1 -1
- package/package.json +2 -1
- package/src/components/FormComponents/BooleanItem/BooleanItem.tsx +9 -1
- package/src/components/FormComponents/ChoiceItems/ChoiceRadioAnswerOptionItem.tsx +5 -2
- package/src/components/FormComponents/ChoiceItems/ChoiceRadioAnswerValueSetItem.tsx +5 -2
- package/src/components/FormComponents/ChoiceItems/ChoiceSelectAnswerOptionItem.tsx +5 -2
- package/src/components/FormComponents/ChoiceItems/ChoiceSelectAnswerValueSetItem.tsx +5 -2
- package/src/components/FormComponents/DecimalItem/DecimalItem.tsx +14 -3
- package/src/components/FormComponents/IntegerItem/IntegerItem.tsx +10 -3
- package/src/components/FormComponents/StringItem/StringItem.tsx +10 -3
- package/src/components/FormComponents/TextItem/TextItem.tsx +10 -3
- package/src/components/Renderer/BaseRenderer.tsx +3 -3
- package/src/hooks/useBooleanCalculatedExpression.ts +19 -12
- package/src/hooks/useCodingCalculatedExpression.ts +18 -8
- package/src/hooks/useDecimalCalculatedExpression.ts +26 -17
- package/src/hooks/useDisplayCalculatedExpression.ts +12 -1
- package/src/hooks/useIntegerCalculatedExpression.ts +18 -13
- package/src/hooks/useStringCalculatedExpression.ts +16 -13
- package/src/interfaces/calculatedExpression.interface.ts +1 -1
- package/src/stores/questionnaireResponseStore.ts +16 -2
- package/src/stores/questionnaireStore.ts +22 -2
- package/src/utils/calculatedExpression.ts +24 -10
- package/src/utils/enableWhenExpression.ts +22 -9
- package/src/utils/fhirpath.ts +62 -41
- package/src/utils/index.ts +1 -0
- package/src/utils/initialise.ts +5 -2
- package/src/utils/parseInputs.ts +1 -1
- package/src/utils/questionnaireResponseStoreUtils/updatableResponseItems.ts +62 -0
package/src/utils/fhirpath.ts
CHANGED
|
@@ -25,6 +25,7 @@ import { evaluateCalculatedExpressions } from './calculatedExpression';
|
|
|
25
25
|
|
|
26
26
|
interface EvaluateUpdatedExpressionsParams {
|
|
27
27
|
updatedResponse: QuestionnaireResponse;
|
|
28
|
+
updatedResponseItemMap: Record<string, QuestionnaireResponseItem[]>;
|
|
28
29
|
calculatedExpressions: Record<string, CalculatedExpression[]>;
|
|
29
30
|
enableWhenExpressions: EnableWhenExpressions;
|
|
30
31
|
variablesFhirPath: Record<string, Expression[]>;
|
|
@@ -39,6 +40,7 @@ export function evaluateUpdatedExpressions(params: EvaluateUpdatedExpressionsPar
|
|
|
39
40
|
} {
|
|
40
41
|
const {
|
|
41
42
|
updatedResponse,
|
|
43
|
+
updatedResponseItemMap,
|
|
42
44
|
enableWhenExpressions,
|
|
43
45
|
calculatedExpressions,
|
|
44
46
|
variablesFhirPath,
|
|
@@ -59,8 +61,8 @@ export function evaluateUpdatedExpressions(params: EvaluateUpdatedExpressionsPar
|
|
|
59
61
|
|
|
60
62
|
const updatedFhirPathContext = createFhirPathContext(
|
|
61
63
|
updatedResponse,
|
|
62
|
-
|
|
63
|
-
|
|
64
|
+
updatedResponseItemMap,
|
|
65
|
+
variablesFhirPath
|
|
64
66
|
);
|
|
65
67
|
|
|
66
68
|
// Update enableWhenExpressions
|
|
@@ -87,58 +89,52 @@ export function evaluateUpdatedExpressions(params: EvaluateUpdatedExpressionsPar
|
|
|
87
89
|
|
|
88
90
|
export function createFhirPathContext(
|
|
89
91
|
questionnaireResponse: QuestionnaireResponse,
|
|
90
|
-
|
|
91
|
-
|
|
92
|
+
questionnaireResponseItemMap: Record<string, QuestionnaireResponseItem[]>,
|
|
93
|
+
variablesFhirPath: Record<string, Expression[]>
|
|
92
94
|
): Record<string, any> {
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
fhirPathContext = { ...fhirPathContext, ...existingFhirPathContext };
|
|
95
|
+
if (!questionnaireResponse.item) {
|
|
96
|
+
return {};
|
|
96
97
|
}
|
|
97
98
|
|
|
98
99
|
// Add latest resource to fhirPathContext
|
|
99
|
-
fhirPathContext = {
|
|
100
|
-
|
|
101
|
-
if (!questionnaireResponse.item || questionnaireResponse.item.length === 0) {
|
|
102
|
-
return fhirPathContext;
|
|
103
|
-
}
|
|
100
|
+
let fhirPathContext: Record<string, any> = { resource: questionnaireResponse };
|
|
104
101
|
|
|
105
|
-
|
|
102
|
+
// Evaluate resource-level variables
|
|
103
|
+
fhirPathContext = evaluateQuestionnaireLevelVariables(
|
|
104
|
+
questionnaireResponse,
|
|
105
|
+
variablesFhirPath,
|
|
106
|
+
fhirPathContext
|
|
107
|
+
);
|
|
106
108
|
|
|
107
|
-
|
|
108
|
-
|
|
109
|
+
// Add variables of items that exist in questionnaireResponseItemMap into fhirPathContext
|
|
110
|
+
for (const linkId in questionnaireResponseItemMap) {
|
|
111
|
+
// For non-repeat groups, the same linkId will have only one item
|
|
112
|
+
// For repeat groups, the same linkId will have multiple items
|
|
113
|
+
for (const qrItem of questionnaireResponseItemMap[linkId]) {
|
|
114
|
+
fhirPathContext = evaluateLinkIdVariables(qrItem, variablesFhirPath, fhirPathContext);
|
|
115
|
+
}
|
|
109
116
|
}
|
|
110
117
|
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
export function evaluateFhirPathRecursive(
|
|
115
|
-
item: QuestionnaireResponseItem,
|
|
116
|
-
variablesFhirPath: Record<string, Expression[]>,
|
|
117
|
-
fhirPathContext: Record<string, any>
|
|
118
|
-
) {
|
|
119
|
-
const items = item.item;
|
|
120
|
-
if (items && items.length > 0) {
|
|
121
|
-
// iterate through items of item recursively
|
|
122
|
-
for (const childItem of items) {
|
|
123
|
-
evaluateFhirPathRecursive(childItem, variablesFhirPath, fhirPathContext);
|
|
124
|
-
}
|
|
118
|
+
// Items don't exist in questionnaireResponseItemMap, but we still have to add them into the fhirPathContext as empty arrays
|
|
119
|
+
for (const linkId in variablesFhirPath) {
|
|
120
|
+
fhirPathContext = addEmptyLinkIdVariables(linkId, variablesFhirPath, fhirPathContext);
|
|
125
121
|
}
|
|
126
122
|
|
|
127
|
-
|
|
123
|
+
return fhirPathContext;
|
|
128
124
|
}
|
|
129
125
|
|
|
130
|
-
export function
|
|
126
|
+
export function evaluateLinkIdVariables(
|
|
131
127
|
item: QuestionnaireResponseItem,
|
|
132
128
|
variablesFhirPath: Record<string, Expression[]>,
|
|
133
129
|
fhirPathContext: Record<string, any>
|
|
134
130
|
) {
|
|
135
|
-
const
|
|
136
|
-
if (!
|
|
137
|
-
return;
|
|
131
|
+
const linkIdVariables = variablesFhirPath[item.linkId];
|
|
132
|
+
if (!linkIdVariables || linkIdVariables.length === 0) {
|
|
133
|
+
return fhirPathContext;
|
|
138
134
|
}
|
|
139
135
|
|
|
140
|
-
|
|
141
|
-
if (variable.expression) {
|
|
136
|
+
for (const variable of linkIdVariables) {
|
|
137
|
+
if (variable.expression && variable.name) {
|
|
142
138
|
try {
|
|
143
139
|
fhirPathContext[`${variable.name}`] = fhirpath.evaluate(
|
|
144
140
|
item,
|
|
@@ -153,20 +149,43 @@ export function evaluateItemFhirPath(
|
|
|
153
149
|
console.warn(e.message, `LinkId: ${item.linkId}\nExpression: ${variable.expression}`);
|
|
154
150
|
}
|
|
155
151
|
}
|
|
156
|
-
}
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
return fhirPathContext;
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
export function addEmptyLinkIdVariables(
|
|
158
|
+
linkId: string,
|
|
159
|
+
variablesFhirPath: Record<string, Expression[]>,
|
|
160
|
+
fhirPathContext: Record<string, any>
|
|
161
|
+
) {
|
|
162
|
+
const linkIdVariables = variablesFhirPath[linkId];
|
|
163
|
+
if (!linkIdVariables || linkIdVariables.length === 0) {
|
|
164
|
+
return fhirPathContext;
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
for (const variable of linkIdVariables) {
|
|
168
|
+
if (variable.expression && variable.name) {
|
|
169
|
+
if (fhirPathContext[`${variable.name}`] === undefined) {
|
|
170
|
+
fhirPathContext[`${variable.name}`] = [];
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
return fhirPathContext;
|
|
157
176
|
}
|
|
158
177
|
|
|
159
|
-
export function
|
|
178
|
+
export function evaluateQuestionnaireLevelVariables(
|
|
160
179
|
resource: QuestionnaireResponse,
|
|
161
180
|
variablesFhirPath: Record<string, Expression[]>,
|
|
162
181
|
fhirPathContext: Record<string, any>
|
|
163
182
|
) {
|
|
164
183
|
const questionnaireLevelVariables = variablesFhirPath['QuestionnaireLevel'];
|
|
165
184
|
if (!questionnaireLevelVariables || questionnaireLevelVariables.length === 0) {
|
|
166
|
-
return;
|
|
185
|
+
return fhirPathContext;
|
|
167
186
|
}
|
|
168
187
|
|
|
169
|
-
|
|
188
|
+
for (const variable of questionnaireLevelVariables) {
|
|
170
189
|
if (variable.expression) {
|
|
171
190
|
try {
|
|
172
191
|
fhirPathContext[`${variable.name}`] = fhirpath.evaluate(
|
|
@@ -182,5 +201,7 @@ export function evaluateResourceLevelFhirPath(
|
|
|
182
201
|
console.warn(e.message, `Questionnaire-level\nExpression: ${variable.expression}`);
|
|
183
202
|
}
|
|
184
203
|
}
|
|
185
|
-
}
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
return fhirPathContext;
|
|
186
207
|
}
|
package/src/utils/index.ts
CHANGED
package/src/utils/initialise.ts
CHANGED
|
@@ -31,6 +31,7 @@ import type { Tabs } from '../interfaces/tab.interface';
|
|
|
31
31
|
import { assignPopulatedAnswersToEnableWhen } from './enableWhen';
|
|
32
32
|
import type { CalculatedExpression } from '../interfaces/calculatedExpression.interface';
|
|
33
33
|
import { evaluateInitialCalculatedExpressions } from './calculatedExpression';
|
|
34
|
+
import { createQuestionnaireResponseItemMap } from './questionnaireResponseStoreUtils/updatableResponseItems';
|
|
34
35
|
|
|
35
36
|
/**
|
|
36
37
|
* Initialise a conformant questionnaireResponse from a given questionnaire
|
|
@@ -345,6 +346,7 @@ export function initialiseFormFromResponse(params: initialFormFromResponseParams
|
|
|
345
346
|
variablesFhirPath,
|
|
346
347
|
tabs
|
|
347
348
|
} = params;
|
|
349
|
+
const initialResponseItemMap = createQuestionnaireResponseItemMap(questionnaireResponse);
|
|
348
350
|
let updatedFhirPathContext = params.fhirPathContext;
|
|
349
351
|
|
|
350
352
|
const { initialisedItems, linkedQuestions } = assignPopulatedAnswersToEnableWhen(
|
|
@@ -354,15 +356,16 @@ export function initialiseFormFromResponse(params: initialFormFromResponseParams
|
|
|
354
356
|
|
|
355
357
|
const evaluateInitialEnableWhenExpressionsResult = evaluateInitialEnableWhenExpressions({
|
|
356
358
|
initialResponse: questionnaireResponse,
|
|
359
|
+
initialResponseItemMap: initialResponseItemMap,
|
|
357
360
|
enableWhenExpressions: enableWhenExpressions,
|
|
358
|
-
variablesFhirPath: variablesFhirPath
|
|
359
|
-
existingFhirPathContext: updatedFhirPathContext
|
|
361
|
+
variablesFhirPath: variablesFhirPath
|
|
360
362
|
});
|
|
361
363
|
const { initialEnableWhenExpressions } = evaluateInitialEnableWhenExpressionsResult;
|
|
362
364
|
updatedFhirPathContext = evaluateInitialEnableWhenExpressionsResult.updatedFhirPathContext;
|
|
363
365
|
|
|
364
366
|
const evaluateInitialCalculatedExpressionsResult = evaluateInitialCalculatedExpressions({
|
|
365
367
|
initialResponse: questionnaireResponse,
|
|
368
|
+
initialResponseItemMap: initialResponseItemMap,
|
|
366
369
|
calculatedExpressions: calculatedExpressions,
|
|
367
370
|
variablesFhirPath: variablesFhirPath,
|
|
368
371
|
existingFhirPathContext: updatedFhirPathContext
|
package/src/utils/parseInputs.ts
CHANGED
|
@@ -59,7 +59,7 @@ export function parseDecimalStringWithPrecision(input: string, precision: number
|
|
|
59
59
|
|
|
60
60
|
// truncate decimal digits based on precision
|
|
61
61
|
const parsedDecimalPoint = input.indexOf('.');
|
|
62
|
-
if (precision && parsedDecimalPoint !== -1) {
|
|
62
|
+
if (typeof precision === 'number' && parsedDecimalPoint !== -1) {
|
|
63
63
|
parsedInput = parsedInput.substring(0, parsedDecimalPoint + precision + 1);
|
|
64
64
|
}
|
|
65
65
|
|
|
@@ -0,0 +1,62 @@
|
|
|
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
|
+
|
|
18
|
+
import type { QuestionnaireResponse, QuestionnaireResponseItem } from 'fhir/r4';
|
|
19
|
+
|
|
20
|
+
export function createQuestionnaireResponseItemMap(
|
|
21
|
+
questionnaireResponse: QuestionnaireResponse
|
|
22
|
+
): Record<string, QuestionnaireResponseItem[]> {
|
|
23
|
+
if (!questionnaireResponse.item) {
|
|
24
|
+
return {};
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
const questionnaireResponseItemMap: Record<string, QuestionnaireResponseItem[]> = {};
|
|
28
|
+
for (const topLevelQRItem of questionnaireResponse.item) {
|
|
29
|
+
fillQuestionnaireResponseItemMapRecursive(topLevelQRItem, questionnaireResponseItemMap);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
return questionnaireResponseItemMap;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
function fillQuestionnaireResponseItemMapRecursive(
|
|
36
|
+
qrItem: QuestionnaireResponseItem,
|
|
37
|
+
questionnaireResponseItemMap: Record<string, QuestionnaireResponseItem[]>
|
|
38
|
+
) {
|
|
39
|
+
const qrItems = qrItem.item;
|
|
40
|
+
if (qrItems && qrItems.length > 0) {
|
|
41
|
+
// iterate through items of item recursively
|
|
42
|
+
for (const childQRItem of qrItems) {
|
|
43
|
+
fillQuestionnaireResponseItemMapRecursive(childQRItem, questionnaireResponseItemMap);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
fillQuestionnaireResponseItemMap(qrItem, questionnaireResponseItemMap);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
function fillQuestionnaireResponseItemMap(
|
|
51
|
+
qrItem: QuestionnaireResponseItem,
|
|
52
|
+
questionnaireResponseItemMap: Record<string, QuestionnaireResponseItem[]>
|
|
53
|
+
) {
|
|
54
|
+
// linkId already exists in questionnaireResponseItemMap, it would be a repeat group
|
|
55
|
+
if (qrItem.linkId in questionnaireResponseItemMap) {
|
|
56
|
+
questionnaireResponseItemMap[qrItem.linkId].push(qrItem);
|
|
57
|
+
}
|
|
58
|
+
// Add item to questionnaireResponseItemMap
|
|
59
|
+
else {
|
|
60
|
+
questionnaireResponseItemMap[qrItem.linkId] = [qrItem];
|
|
61
|
+
}
|
|
62
|
+
}
|