@aehrc/smart-forms-renderer 0.23.0 → 0.23.2
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/GroupItem/GroupItem.styles.d.ts +1 -1
- package/lib/components/FormComponents/ItemParts/ItemLabelText.js +7 -1
- package/lib/components/FormComponents/ItemParts/ItemLabelText.js.map +1 -1
- package/lib/components/FormComponents/SingleItem/SingleItem.js +3 -2
- package/lib/components/FormComponents/SingleItem/SingleItem.js.map +1 -1
- package/lib/hooks/useDecimalCalculatedExpression.js +6 -2
- package/lib/hooks/useDecimalCalculatedExpression.js.map +1 -1
- package/lib/hooks/useDisplayCalculatedExpression.d.ts +3 -0
- package/lib/hooks/useDisplayCalculatedExpression.js +33 -0
- package/lib/hooks/useDisplayCalculatedExpression.js.map +1 -0
- package/lib/hooks/useIntegerCalculatedExpression.js +6 -2
- package/lib/hooks/useIntegerCalculatedExpression.js.map +1 -1
- package/lib/hooks/useStringCalculatedExpression.js +13 -5
- package/lib/hooks/useStringCalculatedExpression.js.map +1 -1
- package/lib/hooks/useValueSetCodings.js +1 -1
- package/lib/hooks/useValueSetCodings.js.map +1 -1
- package/lib/interfaces/calculatedExpression.interface.d.ts +1 -0
- package/lib/interfaces/questionnaireStore.interface.d.ts +1 -1
- package/lib/stores/questionnaireStore.d.ts +2 -2
- package/lib/utils/calculatedExpression.d.ts +5 -5
- package/lib/utils/calculatedExpression.js +43 -29
- package/lib/utils/calculatedExpression.js.map +1 -1
- package/lib/utils/fhirpath.d.ts +2 -2
- package/lib/utils/getExpressionsFromItem.d.ts +20 -0
- package/lib/utils/getExpressionsFromItem.js +90 -0
- package/lib/utils/getExpressionsFromItem.js.map +1 -0
- package/lib/utils/initialise.d.ts +2 -2
- package/lib/utils/itemControl.d.ts +1 -7
- package/lib/utils/itemControl.js +0 -20
- package/lib/utils/itemControl.js.map +1 -1
- package/lib/utils/questionnaireStoreUtils/extractOtherExtensions.d.ts +2 -14
- package/lib/utils/questionnaireStoreUtils/extractOtherExtensions.js +6 -46
- package/lib/utils/questionnaireStoreUtils/extractOtherExtensions.js.map +1 -1
- package/lib/utils/removeEmptyAnswers.js +3 -0
- package/lib/utils/removeEmptyAnswers.js.map +1 -1
- package/package.json +1 -1
- package/src/components/FormComponents/ItemParts/ItemLabelText.tsx +12 -1
- package/src/components/FormComponents/SingleItem/SingleItem.tsx +3 -2
- package/src/hooks/useDecimalCalculatedExpression.ts +8 -2
- package/src/hooks/useDisplayCalculatedExpression.ts +40 -0
- package/src/hooks/useIntegerCalculatedExpression.ts +8 -2
- package/src/hooks/useStringCalculatedExpression.ts +19 -5
- package/src/hooks/useValueSetCodings.ts +1 -1
- package/src/interfaces/calculatedExpression.interface.ts +1 -0
- package/src/interfaces/questionnaireStore.interface.ts +1 -1
- package/src/stores/questionnaireStore.ts +1 -1
- package/src/utils/calculatedExpression.ts +76 -60
- package/src/utils/fhirpath.ts +2 -2
- package/src/utils/getExpressionsFromItem.ts +96 -0
- package/src/utils/initialise.ts +2 -2
- package/src/utils/itemControl.ts +1 -21
- package/src/utils/questionnaireStoreUtils/extractOtherExtensions.ts +13 -50
- package/src/utils/removeEmptyAnswers.ts +4 -0
|
@@ -37,7 +37,7 @@ import dayjs from 'dayjs';
|
|
|
37
37
|
|
|
38
38
|
interface EvaluateInitialCalculatedExpressionsParams {
|
|
39
39
|
initialResponse: QuestionnaireResponse;
|
|
40
|
-
calculatedExpressions: Record<string, CalculatedExpression>;
|
|
40
|
+
calculatedExpressions: Record<string, CalculatedExpression[]>;
|
|
41
41
|
variablesFhirPath: Record<string, Expression[]>;
|
|
42
42
|
existingFhirPathContext: Record<string, any>;
|
|
43
43
|
}
|
|
@@ -45,7 +45,7 @@ interface EvaluateInitialCalculatedExpressionsParams {
|
|
|
45
45
|
export function evaluateInitialCalculatedExpressions(
|
|
46
46
|
params: EvaluateInitialCalculatedExpressionsParams
|
|
47
47
|
): {
|
|
48
|
-
initialCalculatedExpressions: Record<string, CalculatedExpression>;
|
|
48
|
+
initialCalculatedExpressions: Record<string, CalculatedExpression[]>;
|
|
49
49
|
updatedFhirPathContext: Record<string, any>;
|
|
50
50
|
} {
|
|
51
51
|
const { initialResponse, calculatedExpressions, variablesFhirPath, existingFhirPathContext } =
|
|
@@ -62,7 +62,7 @@ export function evaluateInitialCalculatedExpressions(
|
|
|
62
62
|
};
|
|
63
63
|
}
|
|
64
64
|
|
|
65
|
-
const initialCalculatedExpressions: Record<string, CalculatedExpression> = {
|
|
65
|
+
const initialCalculatedExpressions: Record<string, CalculatedExpression[]> = {
|
|
66
66
|
...calculatedExpressions
|
|
67
67
|
};
|
|
68
68
|
const updatedFhirPathContext = createFhirPathContext(
|
|
@@ -72,23 +72,26 @@ export function evaluateInitialCalculatedExpressions(
|
|
|
72
72
|
);
|
|
73
73
|
|
|
74
74
|
for (const linkId in initialCalculatedExpressions) {
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
75
|
+
const itemCalcExpressions = calculatedExpressions[linkId];
|
|
76
|
+
|
|
77
|
+
for (const calcExpression of itemCalcExpressions) {
|
|
78
|
+
try {
|
|
79
|
+
const result = fhirpath.evaluate(
|
|
80
|
+
{},
|
|
81
|
+
calcExpression.expression,
|
|
82
|
+
updatedFhirPathContext,
|
|
83
|
+
fhirpath_r4_model
|
|
84
|
+
);
|
|
82
85
|
|
|
83
|
-
|
|
84
|
-
|
|
86
|
+
if (!_isEqual(calcExpression.value, result[0])) {
|
|
87
|
+
calcExpression.value = result[0];
|
|
88
|
+
}
|
|
89
|
+
} catch (e) {
|
|
90
|
+
console.warn(e.message, `LinkId: ${linkId}\nExpression: ${calcExpression.expression}`);
|
|
85
91
|
}
|
|
86
|
-
} catch (e) {
|
|
87
|
-
console.warn(
|
|
88
|
-
e.message,
|
|
89
|
-
`LinkId: ${linkId}\nExpression: ${calculatedExpressions[linkId].expression}`
|
|
90
|
-
);
|
|
91
92
|
}
|
|
93
|
+
|
|
94
|
+
initialCalculatedExpressions[linkId] = itemCalcExpressions;
|
|
92
95
|
}
|
|
93
96
|
|
|
94
97
|
return {
|
|
@@ -99,37 +102,40 @@ export function evaluateInitialCalculatedExpressions(
|
|
|
99
102
|
|
|
100
103
|
export function evaluateCalculatedExpressions(
|
|
101
104
|
fhirPathContext: Record<string, any>,
|
|
102
|
-
calculatedExpressions: Record<string, CalculatedExpression>
|
|
105
|
+
calculatedExpressions: Record<string, CalculatedExpression[]>
|
|
103
106
|
): {
|
|
104
107
|
calculatedExpsIsUpdated: boolean;
|
|
105
|
-
updatedCalculatedExpressions: Record<string, CalculatedExpression>;
|
|
108
|
+
updatedCalculatedExpressions: Record<string, CalculatedExpression[]>;
|
|
106
109
|
} {
|
|
107
|
-
const updatedCalculatedExpressions: Record<string, CalculatedExpression> = {
|
|
110
|
+
const updatedCalculatedExpressions: Record<string, CalculatedExpression[]> = {
|
|
108
111
|
...calculatedExpressions
|
|
109
112
|
};
|
|
110
113
|
|
|
111
114
|
let isUpdated = false;
|
|
112
115
|
for (const linkId in calculatedExpressions) {
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
116
|
+
const itemCalcExpressions = calculatedExpressions[linkId];
|
|
117
|
+
|
|
118
|
+
for (const calcExpression of itemCalcExpressions) {
|
|
119
|
+
try {
|
|
120
|
+
const result = fhirpath.evaluate(
|
|
121
|
+
{},
|
|
122
|
+
calcExpression.expression,
|
|
123
|
+
fhirPathContext,
|
|
124
|
+
fhirpath_r4_model
|
|
125
|
+
);
|
|
120
126
|
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
127
|
+
if (result.length > 0) {
|
|
128
|
+
if (!_isEqual(calcExpression.value, result[0])) {
|
|
129
|
+
isUpdated = true;
|
|
130
|
+
calcExpression.value = result[0];
|
|
131
|
+
}
|
|
125
132
|
}
|
|
133
|
+
} catch (e) {
|
|
134
|
+
console.warn(e.message, `LinkId: ${linkId}\nExpression: ${calcExpression.expression}`);
|
|
126
135
|
}
|
|
127
|
-
} catch (e) {
|
|
128
|
-
console.warn(
|
|
129
|
-
e.message,
|
|
130
|
-
`LinkId: ${linkId}\nExpression: ${calculatedExpressions[linkId].expression}`
|
|
131
|
-
);
|
|
132
136
|
}
|
|
137
|
+
|
|
138
|
+
updatedCalculatedExpressions[linkId] = itemCalcExpressions;
|
|
133
139
|
}
|
|
134
140
|
|
|
135
141
|
return {
|
|
@@ -141,17 +147,8 @@ export function evaluateCalculatedExpressions(
|
|
|
141
147
|
export function initialiseCalculatedExpressionValues(
|
|
142
148
|
questionnaire: Questionnaire,
|
|
143
149
|
populatedResponse: QuestionnaireResponse,
|
|
144
|
-
calculatedExpressions: Record<string, CalculatedExpression>
|
|
150
|
+
calculatedExpressions: Record<string, CalculatedExpression[]>
|
|
145
151
|
): QuestionnaireResponse {
|
|
146
|
-
const calculatedExpressionsWithValues = Object.keys(calculatedExpressions)
|
|
147
|
-
.filter((key) => calculatedExpressions[key].value !== undefined)
|
|
148
|
-
.reduce(
|
|
149
|
-
(mapping: Record<string, CalculatedExpression>, key: string) => (
|
|
150
|
-
(mapping[key] = calculatedExpressions[key]), mapping
|
|
151
|
-
),
|
|
152
|
-
{}
|
|
153
|
-
);
|
|
154
|
-
|
|
155
152
|
if (
|
|
156
153
|
!questionnaire.item ||
|
|
157
154
|
questionnaire.item.length === 0 ||
|
|
@@ -161,6 +158,19 @@ export function initialiseCalculatedExpressionValues(
|
|
|
161
158
|
return populatedResponse;
|
|
162
159
|
}
|
|
163
160
|
|
|
161
|
+
// Filter calculated expressions, only preserve key-value pairs with values
|
|
162
|
+
const calculatedExpressionsWithValues: Record<string, CalculatedExpression[]> = {};
|
|
163
|
+
for (const linkId in calculatedExpressions) {
|
|
164
|
+
const itemCalcExpressionsWithValues = calculatedExpressions[linkId].filter(
|
|
165
|
+
(calcExpression) => calcExpression.value !== undefined
|
|
166
|
+
);
|
|
167
|
+
|
|
168
|
+
if (itemCalcExpressionsWithValues.length > 0) {
|
|
169
|
+
calculatedExpressionsWithValues[linkId] = itemCalcExpressionsWithValues;
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
// Populate calculated expression values into QR
|
|
164
174
|
const topLevelQrItems: QuestionnaireResponseItem[] = [];
|
|
165
175
|
for (const [index, topLevelQItem] of questionnaire.item.entries()) {
|
|
166
176
|
const populatedTopLevelQrItem = populatedResponse.item[index] ?? {
|
|
@@ -193,7 +203,7 @@ export function initialiseCalculatedExpressionValues(
|
|
|
193
203
|
function initialiseItemCalculatedExpressionValueRecursive(
|
|
194
204
|
qItem: QuestionnaireItem,
|
|
195
205
|
qrItem: QuestionnaireResponseItem | undefined,
|
|
196
|
-
calculatedExpressions: Record<string, CalculatedExpression>
|
|
206
|
+
calculatedExpressions: Record<string, CalculatedExpression[]>
|
|
197
207
|
): QuestionnaireResponseItem[] | QuestionnaireResponseItem | null {
|
|
198
208
|
const childQItems = qItem.item;
|
|
199
209
|
if (childQItems && childQItems.length > 0) {
|
|
@@ -245,16 +255,27 @@ function initialiseItemCalculatedExpressionValueRecursive(
|
|
|
245
255
|
return constructSingleItem(qItem, calculatedExpressions);
|
|
246
256
|
}
|
|
247
257
|
|
|
258
|
+
function getCalculatedExpressionAnswer(
|
|
259
|
+
qItem: QuestionnaireItem,
|
|
260
|
+
calculatedExpressions: Record<string, CalculatedExpression[]>
|
|
261
|
+
): QuestionnaireResponseItemAnswer | undefined {
|
|
262
|
+
const calcExpressionFromItem = calculatedExpressions[qItem.linkId]?.find(
|
|
263
|
+
(calcExpression) => calcExpression.from === 'item'
|
|
264
|
+
);
|
|
265
|
+
|
|
266
|
+
if (calcExpressionFromItem && calcExpressionFromItem.value) {
|
|
267
|
+
return parseValueToAnswer(qItem, calcExpressionFromItem.value);
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
return;
|
|
271
|
+
}
|
|
272
|
+
|
|
248
273
|
function constructGroupItem(
|
|
249
274
|
qItem: QuestionnaireItem,
|
|
250
275
|
qrItem: QuestionnaireResponseItem | undefined,
|
|
251
|
-
calculatedExpressions: Record<string, CalculatedExpression>
|
|
276
|
+
calculatedExpressions: Record<string, CalculatedExpression[]>
|
|
252
277
|
): QuestionnaireResponseItem | null {
|
|
253
|
-
const
|
|
254
|
-
let calculatedExpressionAnswer: QuestionnaireResponseItemAnswer | undefined;
|
|
255
|
-
if (itemCalculatedExpression && itemCalculatedExpression.value) {
|
|
256
|
-
calculatedExpressionAnswer = parseValueToAnswer(qItem, itemCalculatedExpression.value);
|
|
257
|
-
}
|
|
278
|
+
const calculatedExpressionAnswer = getCalculatedExpressionAnswer(qItem, calculatedExpressions);
|
|
258
279
|
|
|
259
280
|
// If group item has an existing answer, do not overwrite it with calculated expression value
|
|
260
281
|
if (qrItem?.answer && qrItem?.answer.length > 0) {
|
|
@@ -281,14 +302,9 @@ function constructGroupItem(
|
|
|
281
302
|
|
|
282
303
|
function constructSingleItem(
|
|
283
304
|
qItem: QuestionnaireItem,
|
|
284
|
-
calculatedExpressions: Record<string, CalculatedExpression>
|
|
305
|
+
calculatedExpressions: Record<string, CalculatedExpression[]>
|
|
285
306
|
): QuestionnaireResponseItem | null {
|
|
286
|
-
const
|
|
287
|
-
let calculatedExpressionAnswer: QuestionnaireResponseItemAnswer | undefined;
|
|
288
|
-
if (itemCalculatedExpression && itemCalculatedExpression.value) {
|
|
289
|
-
calculatedExpressionAnswer = parseValueToAnswer(qItem, itemCalculatedExpression.value);
|
|
290
|
-
}
|
|
291
|
-
|
|
307
|
+
const calculatedExpressionAnswer = getCalculatedExpressionAnswer(qItem, calculatedExpressions);
|
|
292
308
|
if (!calculatedExpressionAnswer) {
|
|
293
309
|
return null;
|
|
294
310
|
}
|
package/src/utils/fhirpath.ts
CHANGED
|
@@ -25,7 +25,7 @@ import { evaluateCalculatedExpressions } from './calculatedExpression';
|
|
|
25
25
|
|
|
26
26
|
interface EvaluateUpdatedExpressionsParams {
|
|
27
27
|
updatedResponse: QuestionnaireResponse;
|
|
28
|
-
calculatedExpressions: Record<string, CalculatedExpression>;
|
|
28
|
+
calculatedExpressions: Record<string, CalculatedExpression[]>;
|
|
29
29
|
enableWhenExpressions: EnableWhenExpressions;
|
|
30
30
|
variablesFhirPath: Record<string, Expression[]>;
|
|
31
31
|
existingFhirPathContext: Record<string, any>;
|
|
@@ -34,7 +34,7 @@ interface EvaluateUpdatedExpressionsParams {
|
|
|
34
34
|
export function evaluateUpdatedExpressions(params: EvaluateUpdatedExpressionsParams): {
|
|
35
35
|
isUpdated: boolean;
|
|
36
36
|
updatedEnableWhenExpressions: EnableWhenExpressions;
|
|
37
|
-
updatedCalculatedExpressions: Record<string, CalculatedExpression>;
|
|
37
|
+
updatedCalculatedExpressions: Record<string, CalculatedExpression[]>;
|
|
38
38
|
updatedFhirPathContext: Record<string, any>;
|
|
39
39
|
} {
|
|
40
40
|
const {
|
|
@@ -0,0 +1,96 @@
|
|
|
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 { Expression, Extension, QuestionnaireItem } from 'fhir/r4';
|
|
19
|
+
import type { CalculatedExpression } from '../interfaces/calculatedExpression.interface';
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Get enableWhenExpression.valueExpression if its present in item
|
|
23
|
+
*
|
|
24
|
+
* @author Sean Fong
|
|
25
|
+
*/
|
|
26
|
+
export function getEnableWhenExpression(qItem: QuestionnaireItem): Expression | null {
|
|
27
|
+
const enableWhenExpression = qItem.extension?.find(
|
|
28
|
+
(extension: Extension) =>
|
|
29
|
+
extension.url ===
|
|
30
|
+
'http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-questionnaire-enableWhenExpression' &&
|
|
31
|
+
extension.valueExpression?.language === 'text/fhirpath'
|
|
32
|
+
);
|
|
33
|
+
|
|
34
|
+
if (enableWhenExpression?.valueExpression) {
|
|
35
|
+
return enableWhenExpression.valueExpression;
|
|
36
|
+
}
|
|
37
|
+
return null;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Get calculatedExpression.valueExpression if its present in item or item._text
|
|
42
|
+
*
|
|
43
|
+
* @author Sean Fong
|
|
44
|
+
*/
|
|
45
|
+
export function getCalculatedExpressions(qItem: QuestionnaireItem): CalculatedExpression[] {
|
|
46
|
+
const calculatedExpressionsInItem = findCalculatedExpressionsInExtensions(qItem.extension ?? [])
|
|
47
|
+
.map(
|
|
48
|
+
(calculatedExpression): CalculatedExpression => ({
|
|
49
|
+
expression: calculatedExpression.valueExpression?.expression ?? '',
|
|
50
|
+
from: 'item'
|
|
51
|
+
})
|
|
52
|
+
)
|
|
53
|
+
.filter((calculatedExpression) => calculatedExpression.expression !== '');
|
|
54
|
+
|
|
55
|
+
const calculatedExpressionsInText = findCalculatedExpressionsInExtensions(
|
|
56
|
+
qItem._text?.extension ?? []
|
|
57
|
+
)
|
|
58
|
+
.map(
|
|
59
|
+
(calculatedExpression): CalculatedExpression => ({
|
|
60
|
+
expression: calculatedExpression.valueExpression?.expression ?? '',
|
|
61
|
+
from: 'item._text'
|
|
62
|
+
})
|
|
63
|
+
)
|
|
64
|
+
.filter((calculatedExpression) => calculatedExpression.expression !== '');
|
|
65
|
+
|
|
66
|
+
return [...calculatedExpressionsInItem, ...calculatedExpressionsInText];
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
function findCalculatedExpressionsInExtensions(extensions: Extension[]): Extension[] {
|
|
70
|
+
return extensions.filter(
|
|
71
|
+
(extension) =>
|
|
72
|
+
extension.url ===
|
|
73
|
+
'http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-questionnaire-calculatedExpression' &&
|
|
74
|
+
extension.valueExpression?.language === 'text/fhirpath'
|
|
75
|
+
);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* Get answerExpression.valueExpression if its present in item
|
|
80
|
+
*
|
|
81
|
+
* @author Sean Fong
|
|
82
|
+
*/
|
|
83
|
+
export function getAnswerExpression(qItem: QuestionnaireItem): Expression | null {
|
|
84
|
+
const itemControl = qItem.extension?.find(
|
|
85
|
+
(extension: Extension) =>
|
|
86
|
+
extension.url ===
|
|
87
|
+
'http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-questionnaire-answerExpression' &&
|
|
88
|
+
extension.valueExpression?.language === 'text/fhirpath'
|
|
89
|
+
);
|
|
90
|
+
if (itemControl) {
|
|
91
|
+
if (itemControl.valueExpression) {
|
|
92
|
+
return itemControl.valueExpression;
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
return null;
|
|
96
|
+
}
|
package/src/utils/initialise.ts
CHANGED
|
@@ -316,7 +316,7 @@ export interface initialFormFromResponseParams {
|
|
|
316
316
|
questionnaireResponse: QuestionnaireResponse;
|
|
317
317
|
enableWhenItems: EnableWhenItems;
|
|
318
318
|
enableWhenExpressions: EnableWhenExpressions;
|
|
319
|
-
calculatedExpressions: Record<string, CalculatedExpression>;
|
|
319
|
+
calculatedExpressions: Record<string, CalculatedExpression[]>;
|
|
320
320
|
variablesFhirPath: Record<string, Expression[]>;
|
|
321
321
|
tabs: Tabs;
|
|
322
322
|
fhirPathContext: Record<string, any>;
|
|
@@ -326,7 +326,7 @@ export function initialiseFormFromResponse(params: initialFormFromResponseParams
|
|
|
326
326
|
initialEnableWhenItems: EnableWhenItems;
|
|
327
327
|
initialEnableWhenLinkedQuestions: Record<string, string[]>;
|
|
328
328
|
initialEnableWhenExpressions: EnableWhenExpressions;
|
|
329
|
-
initialCalculatedExpressions: Record<string, CalculatedExpression>;
|
|
329
|
+
initialCalculatedExpressions: Record<string, CalculatedExpression[]>;
|
|
330
330
|
firstVisibleTab: number;
|
|
331
331
|
updatedFhirPathContext: Record<string, any>;
|
|
332
332
|
} {
|
package/src/utils/itemControl.ts
CHANGED
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
* limitations under the License.
|
|
16
16
|
*/
|
|
17
17
|
|
|
18
|
-
import type { Coding,
|
|
18
|
+
import type { Coding, Extension, QuestionnaireItem } from 'fhir/r4';
|
|
19
19
|
import type { RegexValidation } from '../interfaces/regex.interface';
|
|
20
20
|
import { structuredDataCapture } from 'fhir-sdc-helpers';
|
|
21
21
|
|
|
@@ -101,26 +101,6 @@ export function hasHiddenExtension(qItem: QuestionnaireItem): boolean {
|
|
|
101
101
|
return false;
|
|
102
102
|
}
|
|
103
103
|
|
|
104
|
-
/**
|
|
105
|
-
* Check if an answerExpression extension is present
|
|
106
|
-
*
|
|
107
|
-
* @author Sean Fong
|
|
108
|
-
*/
|
|
109
|
-
export function getAnswerExpression(qItem: QuestionnaireItem): Expression | null {
|
|
110
|
-
const itemControl = qItem.extension?.find(
|
|
111
|
-
(extension: Extension) =>
|
|
112
|
-
extension.url ===
|
|
113
|
-
'http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-questionnaire-answerExpression' &&
|
|
114
|
-
extension.valueExpression?.language === 'text/fhirpath'
|
|
115
|
-
);
|
|
116
|
-
if (itemControl) {
|
|
117
|
-
if (itemControl.valueExpression) {
|
|
118
|
-
return itemControl.valueExpression;
|
|
119
|
-
}
|
|
120
|
-
}
|
|
121
|
-
return null;
|
|
122
|
-
}
|
|
123
|
-
|
|
124
104
|
/**
|
|
125
105
|
* Check if the extension has url for items that use open label
|
|
126
106
|
*
|
|
@@ -17,7 +17,6 @@
|
|
|
17
17
|
|
|
18
18
|
import type {
|
|
19
19
|
Expression,
|
|
20
|
-
Extension,
|
|
21
20
|
Questionnaire,
|
|
22
21
|
QuestionnaireItem,
|
|
23
22
|
QuestionnaireItemEnableWhen
|
|
@@ -35,7 +34,6 @@ import type {
|
|
|
35
34
|
} from '../../interfaces';
|
|
36
35
|
import type { AnswerExpression } from '../../interfaces/answerExpression.interface';
|
|
37
36
|
import type { ValueSetPromise } from '../../interfaces/valueSet.interface';
|
|
38
|
-
import { getAnswerExpression } from '../itemControl';
|
|
39
37
|
import { getTerminologyServerUrl, getValueSetPromise } from '../valueSet';
|
|
40
38
|
import type { Variables } from '../../interfaces/variables.interface';
|
|
41
39
|
import { getFhirPathVariables, getXFhirQueryVariables } from './extractVariables';
|
|
@@ -44,12 +42,17 @@ import { checkItemIsEnabledRepeat } from '../enableWhen';
|
|
|
44
42
|
import cloneDeep from 'lodash.clonedeep';
|
|
45
43
|
import { emptyResponse } from '../emptyResource';
|
|
46
44
|
import { evaluateEnableWhenRepeatExpressionInstance } from '../enableWhenExpression';
|
|
45
|
+
import {
|
|
46
|
+
getAnswerExpression,
|
|
47
|
+
getCalculatedExpressions,
|
|
48
|
+
getEnableWhenExpression
|
|
49
|
+
} from '../getExpressionsFromItem';
|
|
47
50
|
|
|
48
51
|
interface ReturnParamsRecursive {
|
|
49
52
|
variables: Variables;
|
|
50
53
|
enableWhenItems: EnableWhenItems;
|
|
51
54
|
enableWhenExpressions: EnableWhenExpressions;
|
|
52
|
-
calculatedExpressions: Record<string, CalculatedExpression>;
|
|
55
|
+
calculatedExpressions: Record<string, CalculatedExpression[]>;
|
|
53
56
|
answerExpressions: Record<string, AnswerExpression>;
|
|
54
57
|
valueSetPromises: Record<string, ValueSetPromise>;
|
|
55
58
|
}
|
|
@@ -65,7 +68,7 @@ export function extractOtherExtensions(
|
|
|
65
68
|
singleExpressions: {},
|
|
66
69
|
repeatExpressions: {}
|
|
67
70
|
};
|
|
68
|
-
const calculatedExpressions: Record<string, CalculatedExpression> = {};
|
|
71
|
+
const calculatedExpressions: Record<string, CalculatedExpression[]> = {};
|
|
69
72
|
const answerExpressions: Record<string, AnswerExpression> = {};
|
|
70
73
|
|
|
71
74
|
if (!questionnaire.item || questionnaire.item.length === 0) {
|
|
@@ -114,7 +117,7 @@ interface extractExtensionsFromItemRecursiveParams {
|
|
|
114
117
|
variables: Variables;
|
|
115
118
|
enableWhenItems: EnableWhenItems;
|
|
116
119
|
enableWhenExpressions: EnableWhenExpressions;
|
|
117
|
-
calculatedExpressions: Record<string, CalculatedExpression>;
|
|
120
|
+
calculatedExpressions: Record<string, CalculatedExpression[]>;
|
|
118
121
|
answerExpressions: Record<string, AnswerExpression>;
|
|
119
122
|
valueSetPromises: Record<string, ValueSetPromise>;
|
|
120
123
|
defaultTerminologyServerUrl: string;
|
|
@@ -184,13 +187,13 @@ function extractExtensionsFromItemRecursive(
|
|
|
184
187
|
}
|
|
185
188
|
}
|
|
186
189
|
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
};
|
|
190
|
+
// Get calculatedExpressions
|
|
191
|
+
const calculatedExpressionsOfItem = getCalculatedExpressions(item);
|
|
192
|
+
if (calculatedExpressionsOfItem.length > 0) {
|
|
193
|
+
calculatedExpressions[item.linkId] = calculatedExpressionsOfItem;
|
|
192
194
|
}
|
|
193
195
|
|
|
196
|
+
// Get answerExpressions
|
|
194
197
|
const answerExpression = getAnswerExpression(item);
|
|
195
198
|
if (answerExpression) {
|
|
196
199
|
answerExpressions[item.linkId] = {
|
|
@@ -417,43 +420,3 @@ function initialiseEnableWhenExpression(
|
|
|
417
420
|
}
|
|
418
421
|
};
|
|
419
422
|
}
|
|
420
|
-
|
|
421
|
-
/**
|
|
422
|
-
* Check if an enableWhenExpression extension is present
|
|
423
|
-
*
|
|
424
|
-
* @author Sean Fong
|
|
425
|
-
*/
|
|
426
|
-
export function getEnableWhenExpression(qItem: QuestionnaireItem): Expression | null {
|
|
427
|
-
const itemControl = qItem.extension?.find(
|
|
428
|
-
(extension: Extension) =>
|
|
429
|
-
extension.url ===
|
|
430
|
-
'http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-questionnaire-enableWhenExpression' &&
|
|
431
|
-
extension.valueExpression?.language === 'text/fhirpath'
|
|
432
|
-
);
|
|
433
|
-
if (itemControl) {
|
|
434
|
-
if (itemControl.valueExpression) {
|
|
435
|
-
return itemControl.valueExpression;
|
|
436
|
-
}
|
|
437
|
-
}
|
|
438
|
-
return null;
|
|
439
|
-
}
|
|
440
|
-
|
|
441
|
-
/**
|
|
442
|
-
* Check if an calculatedExpression extension is present
|
|
443
|
-
*
|
|
444
|
-
* @author Sean Fong
|
|
445
|
-
*/
|
|
446
|
-
export function getCalculatedExpression(qItem: QuestionnaireItem): Expression | null {
|
|
447
|
-
const itemControl = qItem.extension?.find(
|
|
448
|
-
(extension: Extension) =>
|
|
449
|
-
extension.url ===
|
|
450
|
-
'http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-questionnaire-calculatedExpression' &&
|
|
451
|
-
extension.valueExpression?.language === 'text/fhirpath'
|
|
452
|
-
);
|
|
453
|
-
if (itemControl) {
|
|
454
|
-
if (itemControl.valueExpression) {
|
|
455
|
-
return itemControl.valueExpression;
|
|
456
|
-
}
|
|
457
|
-
}
|
|
458
|
-
return null;
|
|
459
|
-
}
|