sdc-qrf 1.0.0-beta.2 → 1.0.0-beta.21

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 (48) hide show
  1. package/dist/converter/extensions.d.ts +9 -2
  2. package/dist/converter/extensions.d.ts.map +1 -1
  3. package/dist/converter/extensions.js +66 -2
  4. package/dist/converter/extensions.js.map +1 -1
  5. package/dist/converter/fhirToFce/questionnaire/processItems.d.ts.map +1 -1
  6. package/dist/converter/fhirToFce/questionnaire/processItems.js +33 -23
  7. package/dist/converter/fhirToFce/questionnaire/processItems.js.map +1 -1
  8. package/dist/converter/index.d.ts.map +1 -1
  9. package/dist/converter/index.js +2 -1
  10. package/dist/converter/index.js.map +1 -1
  11. package/dist/converter/utils.d.ts +1 -2
  12. package/dist/converter/utils.d.ts.map +1 -1
  13. package/dist/converter/utils.js +0 -5
  14. package/dist/converter/utils.js.map +1 -1
  15. package/dist/fce.types.d.ts +13 -1
  16. package/dist/fce.types.d.ts.map +1 -1
  17. package/dist/index.d.ts +1 -1
  18. package/dist/index.d.ts.map +1 -1
  19. package/dist/index.js +6 -2
  20. package/dist/index.js.map +1 -1
  21. package/dist/types.d.ts +1 -1
  22. package/dist/types.d.ts.map +1 -1
  23. package/dist/utils.d.ts +16 -6
  24. package/dist/utils.d.ts.map +1 -1
  25. package/dist/utils.js +42 -26
  26. package/dist/utils.js.map +1 -1
  27. package/package.json +1 -1
  28. package/src/converter/__tests__/fce.test.ts +88 -54
  29. package/src/converter/__tests__/resources/questionnaire_fce/answerOptionsToggleExpression.json +84 -0
  30. package/src/converter/__tests__/resources/questionnaire_fce/mixed-fce-with-extensions.json +26 -0
  31. package/src/converter/__tests__/resources/questionnaire_fce/occurs.json +16 -0
  32. package/src/converter/__tests__/resources/questionnaire_fce/sub-questionnaire.json +22 -0
  33. package/src/converter/__tests__/resources/questionnaire_fce/unknown-extensions.json +58 -0
  34. package/src/converter/__tests__/resources/questionnaire_fce/with-attachment-question.json +17 -0
  35. package/src/converter/__tests__/resources/questionnaire_fhir/answerOptionsToggleExpression.json +96 -0
  36. package/src/converter/__tests__/resources/questionnaire_fhir/mixed-fce-with-extensions.json +27 -0
  37. package/src/converter/__tests__/resources/questionnaire_fhir/occurs.json +24 -0
  38. package/src/converter/__tests__/resources/questionnaire_fhir/sub-questionnaire.json +32 -0
  39. package/src/converter/__tests__/resources/questionnaire_fhir/unknown-extensions.json +62 -0
  40. package/src/converter/__tests__/resources/questionnaire_fhir/with-attachment-question.json +26 -0
  41. package/src/converter/extensions.ts +78 -4
  42. package/src/converter/fhirToFce/questionnaire/processItems.ts +43 -34
  43. package/src/converter/index.ts +3 -1
  44. package/src/converter/utils.ts +1 -5
  45. package/src/fce.types.ts +18 -0
  46. package/src/index.ts +5 -1
  47. package/src/types.ts +2 -1
  48. package/src/utils.ts +79 -43
@@ -0,0 +1,22 @@
1
+ {
2
+ "subjectType": ["Encounter", "Patient"],
3
+ "meta": {
4
+ "profile": ["https://emr-core.beda.software/StructureDefinition/fhir-emr-questionnaire"],
5
+ "lastUpdated": "2023-04-10T03:43:34.792167Z",
6
+ "versionId": "694"
7
+ },
8
+ "name": "SubQuestionnaire",
9
+ "item": [
10
+ {
11
+ "text": "SubQuestionnaire",
12
+ "type": "group",
13
+ "linkId": "sub-questionnaire",
14
+ "subQuestionnaire": "allergies"
15
+ }
16
+ ],
17
+ "assembledFrom": "sub-questionnaire",
18
+ "resourceType": "Questionnaire",
19
+ "status": "active",
20
+ "id": "sub-questionnaire",
21
+ "url": "https://aidbox.emr.beda.software/ui/console#/entities/Questionnaire/sub-questionnaire"
22
+ }
@@ -0,0 +1,58 @@
1
+ {
2
+ "resourceType": "Questionnaire",
3
+ "id": "unknown-extensions",
4
+ "meta": {
5
+ "profile": [
6
+ "https://emr-core.beda.software/StructureDefinition/fhir-emr-questionnaire"
7
+ ]
8
+ },
9
+ "status": "active",
10
+ "item": [
11
+ {
12
+ "type": "string",
13
+ "linkId": "question-1",
14
+ "initialExpression": {
15
+ "language": "text/fhirpath",
16
+ "expression": "'This is known extension'"
17
+ },
18
+ "readOnly": true,
19
+ "_readOnly": {
20
+ "cqfExpression": {
21
+ "language": "text/fhirpath",
22
+ "expression": "{}"
23
+ },
24
+ "extension": [
25
+ {
26
+ "url": "urn:unknown-primitive-extension-1",
27
+ "valueString": "This is unknown primitive extension along with known extension"
28
+ }
29
+ ]
30
+ },
31
+ "extension": [
32
+ {
33
+ "url": "urn:unknown-extension-1",
34
+ "valueString": "This is unknown extension along with known extension"
35
+ }
36
+ ]
37
+ },
38
+ {
39
+ "type": "string",
40
+ "linkId": "question-2",
41
+ "readOnly": true,
42
+ "_readOnly": {
43
+ "extension": [
44
+ {
45
+ "url": "urn:unknown-primitive-extension-2",
46
+ "valueString": "This is single unknown primitive extension"
47
+ }
48
+ ]
49
+ },
50
+ "extension": [
51
+ {
52
+ "url": "urn:unknown-extension-2",
53
+ "valueString": "This is single unknown extension"
54
+ }
55
+ ]
56
+ }
57
+ ]
58
+ }
@@ -0,0 +1,17 @@
1
+ {
2
+ "resourceType": "Questionnaire",
3
+ "name": "with-attachment",
4
+ "status": "active",
5
+ "meta": {
6
+ "profile": ["https://emr-core.beda.software/StructureDefinition/fhir-emr-questionnaire"],
7
+ "lastUpdated": "2023-05-04T01:00:51.328418Z"
8
+ },
9
+ "item": [
10
+ {
11
+ "linkId": "logo-image",
12
+ "type": "attachment",
13
+ "text": "upload something",
14
+ "mimeType": ["image/jpeg", "application/pdf"]
15
+ }
16
+ ]
17
+ }
@@ -0,0 +1,96 @@
1
+ {
2
+ "item": [
3
+ {
4
+ "type": "choice",
5
+ "linkId": "answerOptions",
6
+ "answerOption": [
7
+ {
8
+ "valueCoding": {
9
+ "code": "code-1",
10
+ "display": "display-1"
11
+ }
12
+ },
13
+ {
14
+ "valueCoding": {
15
+ "code": "code-2",
16
+ "display": "display-2"
17
+ }
18
+ },
19
+ {
20
+ "valueCoding": {
21
+ "code": "code-3",
22
+ "display": "display-3"
23
+ }
24
+ },
25
+ {
26
+ "valueCoding": {
27
+ "code": "code-4",
28
+ "display": "display-4"
29
+ }
30
+ }
31
+ ],
32
+ "extension": [
33
+ {
34
+ "url": "http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-questionnaire-answerOptionsToggleExpression",
35
+ "extension": [
36
+ {
37
+ "url": "option",
38
+ "valueCoding": {
39
+ "code": "code-1",
40
+ "display": "display-1"
41
+ }
42
+ },
43
+ {
44
+ "url": "option",
45
+ "valueCoding": {
46
+ "code": "code-2",
47
+ "display": "display-2"
48
+ }
49
+ },
50
+ {
51
+ "url": "expression",
52
+ "valueExpression": {
53
+ "language": "text/fhirpath",
54
+ "expression": "1 = 1"
55
+ }
56
+ }
57
+ ]
58
+ },
59
+ {
60
+ "url": "http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-questionnaire-answerOptionsToggleExpression",
61
+ "extension": [
62
+ {
63
+ "url": "option",
64
+ "valueCoding": {
65
+ "code": "code-3",
66
+ "display": "display-3"
67
+ }
68
+ },
69
+ {
70
+ "url": "option",
71
+ "valueCoding": {
72
+ "code": "code-4",
73
+ "display": "display-4"
74
+ }
75
+ },
76
+ {
77
+ "url": "expression",
78
+ "valueExpression": {
79
+ "language": "text/fhirpath",
80
+ "expression": "1 != 1"
81
+ }
82
+ }
83
+ ]
84
+ }
85
+ ]
86
+ }
87
+ ],
88
+ "meta": {
89
+ "profile": [
90
+ "https://emr-core.beda.software/StructureDefinition/fhir-emr-questionnaire"
91
+ ]
92
+ },
93
+ "status": "active",
94
+ "resourceType": "Questionnaire",
95
+ "id": "answerOptionsToggleExpression"
96
+ }
@@ -0,0 +1,27 @@
1
+ {
2
+ "item": [
3
+ {
4
+ "type": "string",
5
+ "linkId": "question",
6
+ "extension": [
7
+ {
8
+ "url": "http://hl7.org/fhir/StructureDefinition/entryFormat",
9
+ "valueString": "This is FCE"
10
+ },
11
+ {
12
+ "url": "http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-questionnaire-initialExpression",
13
+ "valueExpression": {
14
+ "language": "text/fhirpath",
15
+ "expression": "'This is extension'"
16
+ }
17
+ }
18
+ ]
19
+ }
20
+ ],
21
+ "meta": {
22
+ "profile": ["https://emr-core.beda.software/StructureDefinition/fhir-emr-questionnaire"]
23
+ },
24
+ "status": "active",
25
+ "id": "fce-with-extensions",
26
+ "resourceType": "Questionnaire"
27
+ }
@@ -0,0 +1,24 @@
1
+ {
2
+ "item": [
3
+ {
4
+ "type": "number",
5
+ "linkId": "number",
6
+ "extension": [
7
+ {
8
+ "url": "http://hl7.org/fhir/StructureDefinition/questionnaire-minOccurs",
9
+ "valueInteger": 1
10
+ },
11
+ {
12
+ "url": "http://hl7.org/fhir/StructureDefinition/questionnaire-maxOccurs",
13
+ "valueInteger": 2
14
+ }
15
+ ]
16
+ }
17
+ ],
18
+ "meta": {
19
+ "profile": ["https://emr-core.beda.software/StructureDefinition/fhir-emr-questionnaire"]
20
+ },
21
+ "status": "active",
22
+ "resourceType": "Questionnaire",
23
+ "id": "occurs"
24
+ }
@@ -0,0 +1,32 @@
1
+ {
2
+ "subjectType": ["Encounter", "Patient"],
3
+ "meta": {
4
+ "profile": ["https://emr-core.beda.software/StructureDefinition/fhir-emr-questionnaire"],
5
+ "lastUpdated": "2023-04-10T03:43:34.792167Z",
6
+ "versionId": "694"
7
+ },
8
+ "name": "SubQuestionnaire",
9
+ "item": [
10
+ {
11
+ "text": "SubQuestionnaire",
12
+ "type": "group",
13
+ "extension": [
14
+ {
15
+ "url": "http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-questionnaire-subQuestionnaire",
16
+ "valueCanonical": "allergies"
17
+ }
18
+ ],
19
+ "linkId": "sub-questionnaire"
20
+ }
21
+ ],
22
+ "resourceType": "Questionnaire",
23
+ "extension": [
24
+ {
25
+ "url": "http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-questionnaire-assembledFrom",
26
+ "valueCanonical": "sub-questionnaire"
27
+ }
28
+ ],
29
+ "status": "active",
30
+ "id": "sub-questionnaire",
31
+ "url": "https://aidbox.emr.beda.software/ui/console#/entities/Questionnaire/sub-questionnaire"
32
+ }
@@ -0,0 +1,62 @@
1
+ {
2
+ "item": [
3
+ {
4
+ "type": "string",
5
+ "linkId": "question-1",
6
+ "readOnly": true,
7
+ "_readOnly": {
8
+ "extension": [
9
+ {
10
+ "url": "http://hl7.org/fhir/StructureDefinition/cqf-expression",
11
+ "valueExpression": {
12
+ "language": "text/fhirpath",
13
+ "expression": "{}"
14
+ }
15
+ },
16
+ {
17
+ "url": "urn:unknown-primitive-extension-1",
18
+ "valueString": "This is unknown primitive extension along with known extension"
19
+ }
20
+ ]
21
+ },
22
+ "extension": [
23
+ {
24
+ "url": "http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-questionnaire-initialExpression",
25
+ "valueExpression": {
26
+ "language": "text/fhirpath",
27
+ "expression": "'This is known extension'"
28
+ }
29
+ },
30
+ {
31
+ "url": "urn:unknown-extension-1",
32
+ "valueString": "This is unknown extension along with known extension"
33
+ }
34
+ ]
35
+ },
36
+ {
37
+ "type": "string",
38
+ "linkId": "question-2",
39
+ "readOnly": true,
40
+ "_readOnly": {
41
+ "extension": [
42
+ {
43
+ "url": "urn:unknown-primitive-extension-2",
44
+ "valueString": "This is single unknown primitive extension"
45
+ }
46
+ ]
47
+ },
48
+ "extension": [
49
+ {
50
+ "url": "urn:unknown-extension-2",
51
+ "valueString": "This is single unknown extension"
52
+ }
53
+ ]
54
+ }
55
+ ],
56
+ "meta": {
57
+ "profile": ["https://emr-core.beda.software/StructureDefinition/fhir-emr-questionnaire"]
58
+ },
59
+ "status": "active",
60
+ "id": "unknown-extensions",
61
+ "resourceType": "Questionnaire"
62
+ }
@@ -0,0 +1,26 @@
1
+ {
2
+ "resourceType": "Questionnaire",
3
+ "name": "with-attachment",
4
+ "status": "active",
5
+ "meta": {
6
+ "profile": ["https://emr-core.beda.software/StructureDefinition/fhir-emr-questionnaire"],
7
+ "lastUpdated": "2023-05-04T01:00:51.328418Z"
8
+ },
9
+ "item": [
10
+ {
11
+ "linkId": "logo-image",
12
+ "type": "attachment",
13
+ "text": "upload something",
14
+ "extension": [
15
+ {
16
+ "url": "http://hl7.org/fhir/StructureDefinition/mimeType",
17
+ "valueCode": "image/jpeg"
18
+ },
19
+ {
20
+ "url": "http://hl7.org/fhir/StructureDefinition/mimeType",
21
+ "valueCode": "application/pdf"
22
+ }
23
+ ]
24
+ }
25
+ ]
26
+ }
@@ -1,4 +1,4 @@
1
- import { FCEQuestionnaireItem } from '../fce.types';
1
+ import { FCEQuestionnaireItem, FCEQuestionnaireItemAnswerOptionsToggleExpressionOption } from '../fce.types';
2
2
  import { Extension as FHIRExtension } from 'fhir/r4b';
3
3
 
4
4
  export enum ExtensionIdentifier {
@@ -19,7 +19,8 @@ export enum ExtensionIdentifier {
19
19
  MinQuantity = 'http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-questionnaire-minQuantity',
20
20
  MaxQuantity = 'http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-questionnaire-maxQuantity',
21
21
  ShowOrdinalValue = 'http://aidbox.io/questionnaire-showOrdinalValue',
22
- PreferredTerminologyServer = 'http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-questionnaire-preferredTerminologyServer',
22
+ PreferredTerminologyServerSDC = 'http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-questionnaire-preferredTerminologyServer',
23
+ PreferredTerminologyServer = 'http://hl7.org/fhir/StructureDefinition/preferredTerminologyServer',
23
24
  OpenLabel = 'http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-questionnaire-openLabel',
24
25
  BackgroundImage = 'http://aidbox.io/questionnaire-backgroundImage',
25
26
  Language = 'http://hl7.org/fhir/StructureDefinition/language',
@@ -29,6 +30,7 @@ export enum ExtensionIdentifier {
29
30
 
30
31
  ItemPopulationContext = 'http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-questionnaire-itemPopulationContext',
31
32
  ItemConstraint = 'http://hl7.org/fhir/StructureDefinition/questionnaire-constraint',
33
+ AnswerOptionsToggleExpression = 'http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-questionnaire-answerOptionsToggleExpression',
32
34
  InitialExpression = 'http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-questionnaire-initialExpression',
33
35
  ChoiceColumn = 'http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-questionnaire-choiceColumn',
34
36
  CalculatedExpression = 'http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-questionnaire-calculatedExpression',
@@ -36,6 +38,7 @@ export enum ExtensionIdentifier {
36
38
  AnswerExpression = 'http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-questionnaire-answerExpression',
37
39
  CqfExpression = 'http://hl7.org/fhir/StructureDefinition/cqf-expression',
38
40
  Variable = 'http://hl7.org/fhir/StructureDefinition/variable',
41
+ MimeType = 'http://hl7.org/fhir/StructureDefinition/mimeType',
39
42
 
40
43
  AdjustLastToRight = 'https://emr-core.beda.software/StructureDefinition/adjust-last-to-right',
41
44
  SliderStart = 'https://emr-core.beda.software/StructureDefinition/slider-start',
@@ -44,6 +47,10 @@ export enum ExtensionIdentifier {
44
47
  StopLabel = 'https://emr-core.beda.software/StructureDefinition/slider-stop-label',
45
48
  Macro = 'https://emr-core.beda.software/StructureDefinition/macro',
46
49
  RowsNumber = 'https://emr-core.beda.software/StructureDefinition/rows-number',
50
+ ColsNumber = 'https://emr-core.beda.software/StructureDefinition/cols-number',
51
+ SubQuestionnaire = 'http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-questionnaire-subQuestionnaire',
52
+ MinOccurs = 'http://hl7.org/fhir/StructureDefinition/questionnaire-minOccurs',
53
+ MaxOccurs = 'http://hl7.org/fhir/StructureDefinition/questionnaire-maxOccurs',
47
54
  }
48
55
 
49
56
  export type ExtensionTransformer = {
@@ -85,6 +92,12 @@ export const extensionTransformers: ExtensionTransformer = {
85
92
  [ExtensionIdentifier.RowsNumber]: {
86
93
  path: { extension: 'valueInteger', questionnaire: 'rowsNumber' },
87
94
  },
95
+ [ExtensionIdentifier.ColsNumber]: {
96
+ path: { extension: 'valueInteger', questionnaire: 'colsNumber' },
97
+ },
98
+ [ExtensionIdentifier.SubQuestionnaire]: {
99
+ path: { extension: 'valueCanonical', questionnaire: 'subQuestionnaire' },
100
+ },
88
101
  [ExtensionIdentifier.ReferenceResource]: {
89
102
  transform: {
90
103
  fromExtensions: (extensions) => {
@@ -150,8 +163,11 @@ export const extensionTransformers: ExtensionTransformer = {
150
163
  [ExtensionIdentifier.ShowOrdinalValue]: {
151
164
  path: { extension: 'valueBoolean', questionnaire: 'showOrdinalValue' },
152
165
  },
166
+ [ExtensionIdentifier.PreferredTerminologyServerSDC]: {
167
+ path: { extension: 'valueUrl', questionnaire: 'preferredTerminologyServer' },
168
+ },
153
169
  [ExtensionIdentifier.PreferredTerminologyServer]: {
154
- path: { extension: 'valueUri', questionnaire: 'preferredTerminologyServer' },
170
+ path: { extension: 'valueUrl', questionnaire: 'preferredTerminologyServer' },
155
171
  },
156
172
  [ExtensionIdentifier.OpenLabel]: {
157
173
  path: { extension: 'valueString', questionnaire: 'openLabel' },
@@ -171,7 +187,12 @@ export const extensionTransformers: ExtensionTransformer = {
171
187
  [ExtensionIdentifier.ChoiceColumns]: {
172
188
  path: { extension: 'valueInteger', questionnaire: 'choiceColumns' },
173
189
  },
174
-
190
+ [ExtensionIdentifier.MinOccurs]: {
191
+ path: { extension: 'valueInteger', questionnaire: 'minOccurs' },
192
+ },
193
+ [ExtensionIdentifier.MaxOccurs]: {
194
+ path: { extension: 'valueInteger', questionnaire: 'maxOccurs' },
195
+ },
175
196
  [ExtensionIdentifier.ItemPopulationContext]: {
176
197
  path: { extension: 'valueExpression', questionnaire: 'itemPopulationContext' },
177
198
  },
@@ -226,9 +247,55 @@ export const extensionTransformers: ExtensionTransformer = {
226
247
  },
227
248
  },
228
249
  },
250
+ [ExtensionIdentifier.AnswerOptionsToggleExpression]: {
251
+ transform: {
252
+ fromExtensions: (extensions) => {
253
+ return {
254
+ answerOptionsToggleExpression: extensions.map((extension) => {
255
+ const answerOptionsToggleExpression = extension.extension!;
256
+
257
+ return {
258
+ expression: answerOptionsToggleExpression.find((obj) => obj.url === 'expression')!
259
+ .valueExpression!,
260
+ option: answerOptionsToggleExpression
261
+ .filter((obj) => obj.url === 'option')
262
+ .map(
263
+ (obj) =>
264
+ getExtensionValue(
265
+ obj,
266
+ ) as FCEQuestionnaireItemAnswerOptionsToggleExpressionOption,
267
+ ),
268
+ };
269
+ }),
270
+ };
271
+ },
272
+ toExtensions: (item) => {
273
+ if (item.answerOptionsToggleExpression) {
274
+ return item.answerOptionsToggleExpression.map((answerOptionsToggleExpression) => ({
275
+ url: ExtensionIdentifier.AnswerOptionsToggleExpression,
276
+ extension: [
277
+ ...answerOptionsToggleExpression.option.map((option) => ({
278
+ url: 'option',
279
+ ...option,
280
+ })),
281
+ {
282
+ url: 'expression',
283
+ valueExpression: answerOptionsToggleExpression.expression,
284
+ },
285
+ ],
286
+ }));
287
+ }
288
+
289
+ return [];
290
+ },
291
+ },
292
+ },
229
293
  [ExtensionIdentifier.Variable]: {
230
294
  path: { extension: 'valueExpression', questionnaire: 'variable', isCollection: true },
231
295
  },
296
+ [ExtensionIdentifier.MimeType]: {
297
+ path: { extension: 'valueCode', questionnaire: 'mimeType', isCollection: true },
298
+ },
232
299
  [ExtensionIdentifier.InitialExpression]: {
233
300
  path: { extension: 'valueExpression', questionnaire: 'initialExpression' },
234
301
  },
@@ -301,3 +368,10 @@ export const extensionTransformers: ExtensionTransformer = {
301
368
  path: { extension: 'valueString', questionnaire: 'macro' },
302
369
  },
303
370
  };
371
+
372
+ function getExtensionValue(extension: FHIRExtension) {
373
+ const valueKey = Object.keys(extension).find((key) => key.startsWith('value'))! as keyof FHIRExtension;
374
+ return {
375
+ [valueKey]: extension[valueKey],
376
+ };
377
+ }
@@ -1,10 +1,6 @@
1
- import {
2
- Questionnaire as FHIRQuestionnaire,
3
- QuestionnaireItem as FHIRQuestionnaireItem,
4
- Element as FHIRElement,
5
- } from 'fhir/r4b';
1
+ import { Questionnaire as FHIRQuestionnaire, QuestionnaireItem as FHIRQuestionnaireItem, Extension } from 'fhir/r4b';
6
2
 
7
- import { convertFromFHIRExtension, filterQuestionnaireItemExtensions } from '../..';
3
+ import { convertFromFHIRExtension } from '../..';
8
4
  import { ExtensionIdentifier } from '../../extensions';
9
5
  import { FCEQuestionnaireItem } from '../../../fce.types';
10
6
 
@@ -13,45 +9,58 @@ export function processItems(fhirQuestionnaire: FHIRQuestionnaire) {
13
9
  }
14
10
 
15
11
  function convertItemProperties(item: FHIRQuestionnaireItem): FCEQuestionnaireItem {
16
- const updatedProperties = getUpdatedPropertiesFromItem(item);
17
- const newItem = { ...item, ...updatedProperties };
12
+ const newItem = getUpdatedPropertiesFromItem(item);
18
13
 
19
- newItem.item = item.item?.map((nestedItem) => convertItemProperties(nestedItem));
20
-
21
- if (newItem.extension) {
22
- delete newItem.extension;
14
+ if (item.item) {
15
+ newItem.item = item.item.map((nestedItem) => convertItemProperties(nestedItem));
23
16
  }
24
-
25
17
  return newItem;
26
18
  }
27
19
 
28
20
  function getUpdatedPropertiesFromItem(item: FHIRQuestionnaireItem) {
29
- let updatedProperties: FCEQuestionnaireItem = { linkId: item.linkId, type: item.type };
30
-
31
- for (const identifier of Object.values(ExtensionIdentifier)) {
32
- for (const property of Object.keys(item)) {
33
- const element = item[property as keyof FHIRQuestionnaireItem];
34
- if (property.startsWith('_') && element instanceof Object) {
35
- const primitiveExtensions = (element as FHIRElement)?.extension ?? [];
36
- for (const extension of primitiveExtensions) {
37
- if (extension.url === identifier) {
38
- updatedProperties = {
39
- ...updatedProperties,
40
- ...{ [property]: convertFromFHIRExtension([extension]) },
41
- };
42
- }
43
- }
44
- }
21
+ let newItem: FCEQuestionnaireItem = { ...item };
22
+
23
+ // Primitive extensions
24
+ for (const property of Object.keys(item)) {
25
+ const element = item[property as keyof FHIRQuestionnaireItem];
26
+ if (property.startsWith('_') && element instanceof Object && !Array.isArray(element)) {
27
+ newItem = {
28
+ ...newItem,
29
+ ...{
30
+ [property]: processExtensibleElement(element),
31
+ },
32
+ };
45
33
  }
34
+ }
35
+
36
+ return processExtensibleElement(newItem);
37
+ }
38
+
39
+ function processExtensibleElement<T extends { extension?: Extension[] }>(element: T): T {
40
+ let newElement = { ...element };
41
+ const knownExtensionUrls = Object.values(ExtensionIdentifier) as string[];
42
+
43
+ const allExtensions = element.extension ?? [];
44
+ const knownExtensions = allExtensions.filter((ext) => knownExtensionUrls.includes(ext.url));
45
+ const unknownExtensions = allExtensions.filter((ext) => !knownExtensionUrls.includes(ext.url));
46
46
 
47
- const extensions = filterQuestionnaireItemExtensions(item, identifier);
48
- if (extensions?.length) {
49
- updatedProperties = {
50
- ...updatedProperties,
47
+ if (knownExtensions.length) {
48
+ const uniqueExtensionUrls = new Set(knownExtensions.map((ext) => ext.url));
49
+ for (const extensionUrl of uniqueExtensionUrls) {
50
+ const extensions = knownExtensions.filter((ext) => ext.url === extensionUrl);
51
+
52
+ newElement = {
53
+ ...newElement,
51
54
  ...convertFromFHIRExtension(extensions),
52
55
  };
53
56
  }
54
57
  }
55
58
 
56
- return updatedProperties;
59
+ if (unknownExtensions.length) {
60
+ newElement.extension = unknownExtensions;
61
+ } else {
62
+ delete newElement.extension;
63
+ }
64
+
65
+ return newElement;
57
66
  }
@@ -25,7 +25,8 @@ export function convertFromFHIRExtension(extensions: FHIRExtension[]): Partial<F
25
25
  }
26
26
 
27
27
  export function convertToFHIRExtension(item: FCEQuestionnaireItem): FHIRExtension[] {
28
- const extensions: FHIRExtension[] = [];
28
+ const extensions: FHIRExtension[] = [...(item.extension ?? [])];
29
+
29
30
  Object.values(ExtensionIdentifier).forEach((identifier) => {
30
31
  const transformer = extensionTransformers[identifier];
31
32
  if ('transform' in transformer) {
@@ -44,6 +45,7 @@ export function convertToFHIRExtension(item: FCEQuestionnaireItem): FHIRExtensio
44
45
  }
45
46
  }
46
47
  });
48
+
47
49
  return extensions;
48
50
  }
49
51
 
@@ -1,4 +1,4 @@
1
- import { QuestionnaireItem as FHIRQuestionnaireItem, Meta } from 'fhir/r4b';
1
+ import { Meta } from 'fhir/r4b';
2
2
  import cloneDeep from 'lodash/cloneDeep';
3
3
 
4
4
  function sortExtensionsRecursive(object: any) {
@@ -24,10 +24,6 @@ export function sortExtensionsList(object: any) {
24
24
  return sortExtensionsRecursive(cloneDeep(object));
25
25
  }
26
26
 
27
- export function filterQuestionnaireItemExtensions(item: FHIRQuestionnaireItem, url: string) {
28
- return item.extension?.filter((ext) => ext.url === url);
29
- }
30
-
31
27
  export function extractCreatedAtFromMeta(meta: Meta | undefined) {
32
28
  return meta?.extension?.find((e) => e.url === 'ex:createdAt')?.valueInstant;
33
29
  }