sdc-qrf 0.3.1 → 0.3.3

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 (59) hide show
  1. package/lib/components.js +30 -10
  2. package/lib/components.js.map +1 -1
  3. package/lib/converter/extensions.d.ts +21 -1
  4. package/lib/converter/extensions.js +92 -0
  5. package/lib/converter/extensions.js.map +1 -1
  6. package/lib/converter/fceToFhir/questionnaire/processItems.js +17 -11
  7. package/lib/converter/fceToFhir/questionnaire/processItems.js.map +1 -1
  8. package/lib/converter/fceToFhir/questionnaireResponse/processAnswers.js +2 -0
  9. package/lib/converter/fceToFhir/questionnaireResponse/processAnswers.js.map +1 -1
  10. package/lib/converter/fceToFhir/questionnaireResponse/processReference.js +6 -2
  11. package/lib/converter/fceToFhir/questionnaireResponse/processReference.js.map +1 -1
  12. package/lib/converter/fhirToFce/questionnaire/processItems.js +18 -9
  13. package/lib/converter/fhirToFce/questionnaire/processItems.js.map +1 -1
  14. package/lib/converter/fhirToFce/questionnaireResponse/processAnswers.js +3 -0
  15. package/lib/converter/fhirToFce/questionnaireResponse/processAnswers.js.map +1 -1
  16. package/lib/converter/fhirToFce/questionnaireResponse/processMeta.js +4 -0
  17. package/lib/converter/fhirToFce/questionnaireResponse/processMeta.js.map +1 -1
  18. package/lib/converter/fhirToFce/questionnaireResponse/processReference.js +4 -1
  19. package/lib/converter/fhirToFce/questionnaireResponse/processReference.js.map +1 -1
  20. package/lib/converter/fhirToFce/utils.js +1 -2
  21. package/lib/converter/fhirToFce/utils.js.map +1 -1
  22. package/lib/converter/index.js +4 -4
  23. package/lib/converter/index.js.map +1 -1
  24. package/lib/utils.d.ts +2 -1
  25. package/lib/utils.js +20 -10
  26. package/lib/utils.js.map +1 -1
  27. package/package.json +1 -1
  28. package/src/components.tsx +65 -17
  29. package/src/converter/__tests__/resources/questionnaire_response_fce/allergies_inprogress.json +4 -0
  30. package/src/converter/__tests__/resources/questionnaire_response_fce/cardiology.json +4 -0
  31. package/src/converter/__tests__/resources/questionnaire_response_fce/few_answers.json +4 -0
  32. package/src/converter/__tests__/resources/questionnaire_response_fce/gad_7.json +4 -0
  33. package/src/converter/__tests__/resources/questionnaire_response_fce/immunization.json +4 -0
  34. package/src/converter/__tests__/resources/questionnaire_response_fce/medication.json +4 -0
  35. package/src/converter/__tests__/resources/questionnaire_response_fce/phq_2_phq_9.json +4 -0
  36. package/src/converter/__tests__/resources/questionnaire_response_fce/physicalexam.json +4 -0
  37. package/src/converter/__tests__/resources/questionnaire_response_fce/review_of_systems.json +4 -0
  38. package/src/converter/__tests__/resources/questionnaire_response_fce/vitals.json +4 -0
  39. package/src/converter/__tests__/resources/questionnaire_response_fhir/allergies_inprogress.json +3 -0
  40. package/src/converter/__tests__/resources/questionnaire_response_fhir/cardiology.json +3 -0
  41. package/src/converter/__tests__/resources/questionnaire_response_fhir/few_answers.json +3 -0
  42. package/src/converter/__tests__/resources/questionnaire_response_fhir/gad_7.json +3 -0
  43. package/src/converter/__tests__/resources/questionnaire_response_fhir/immunization.json +3 -0
  44. package/src/converter/__tests__/resources/questionnaire_response_fhir/medication.json +3 -0
  45. package/src/converter/__tests__/resources/questionnaire_response_fhir/phq_2_phq_9.json +3 -0
  46. package/src/converter/__tests__/resources/questionnaire_response_fhir/physicalexam.json +3 -0
  47. package/src/converter/__tests__/resources/questionnaire_response_fhir/review_of_systems.json +3 -0
  48. package/src/converter/__tests__/resources/questionnaire_response_fhir/vitals.json +3 -0
  49. package/src/converter/extensions.ts +92 -0
  50. package/src/converter/fceToFhir/questionnaire/processItems.ts +14 -11
  51. package/src/converter/fceToFhir/questionnaireResponse/processAnswers.ts +2 -0
  52. package/src/converter/fceToFhir/questionnaireResponse/processReference.ts +9 -2
  53. package/src/converter/fhirToFce/questionnaire/processItems.ts +18 -5
  54. package/src/converter/fhirToFce/questionnaireResponse/processAnswers.ts +3 -0
  55. package/src/converter/fhirToFce/questionnaireResponse/processMeta.ts +4 -0
  56. package/src/converter/fhirToFce/questionnaireResponse/processReference.ts +4 -1
  57. package/src/converter/fhirToFce/utils.ts +1 -2
  58. package/src/converter/index.ts +4 -5
  59. package/src/utils.ts +42 -23
@@ -7,7 +7,26 @@ export enum ExtensionIdentifier {
7
7
  ItemControl = 'http://hl7.org/fhir/StructureDefinition/questionnaire-itemControl',
8
8
  SliderStepValue = 'http://hl7.org/fhir/StructureDefinition/questionnaire-sliderStepValue',
9
9
  Unit = 'http://hl7.org/fhir/StructureDefinition/questionnaire-unit',
10
+ UnitOption = 'http://hl7.org/fhir/StructureDefinition/questionnaire-unitOption',
10
11
  ReferenceResource = 'http://hl7.org/fhir/StructureDefinition/questionnaire-referenceResource',
12
+ EntryFormat = 'http://hl7.org/fhir/StructureDefinition/entryFormat',
13
+ ColumnSize = 'http://aidbox.io/questionnaire-itemColumnSize',
14
+ ItemMedia = 'http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-questionnaire-itemMedia',
15
+ Regex = 'http://hl7.org/fhir/StructureDefinition/regex',
16
+ ObservationExtract = 'http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-questionnaire-observationExtract',
17
+ ObservationLinkPeriod = 'http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-questionnaire-observationLinkPeriod',
18
+ MinValue = 'http://hl7.org/fhir/StructureDefinition/minValue',
19
+ MaxValue = 'http://hl7.org/fhir/StructureDefinition/maxValue',
20
+ MinQuantity = 'http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-questionnaire-minQuantity',
21
+ MaxQuantity = 'http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-questionnaire-maxQuantity',
22
+ ShowOrdinalValue = 'http://aidbox.io/questionnaire-showOrdinalValue',
23
+ PreferredTerminologyServer = 'http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-questionnaire-preferredTerminologyServer',
24
+ OpenLabel = 'http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-questionnaire-openLabel',
25
+ BackgroundImage = 'http://aidbox.io/questionnaire-backgroundImage',
26
+ Language = 'http://hl7.org/fhir/StructureDefinition/language',
27
+ ChoiceOrientation = 'http://hl7.org/fhir/StructureDefinition/questionnaire-choiceOrientation',
28
+ InlineChoiceDirection = 'https://beda.software/fhir-emr-questionnaire/inline-choice-direction',
29
+ ChoiceColumns = 'http://aidbox.io/fhir/StructureDefinition/questionnaire-choiceColumns',
11
30
 
12
31
  ItemPopulationContext = 'http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-questionnaire-itemPopulationContext',
13
32
  InitialExpression = 'http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-questionnaire-initialExpression',
@@ -22,6 +41,7 @@ export enum ExtensionIdentifier {
22
41
  HelpText = 'https://beda.software/fhir-emr-questionnaire/help-text',
23
42
  StopLabel = 'https://beda.software/fhir-emr-questionnaire/slider-stop-label',
24
43
  Macro = 'https://beda.software/fhir-emr-questionnaire/macro',
44
+ RowsNumber = 'https://beda.software/fhir-emr-questionnaire/rows-number',
25
45
  }
26
46
 
27
47
  export type ExtensionTransformer = {
@@ -52,9 +72,18 @@ export const extensionTransformers: ExtensionTransformer = {
52
72
  [ExtensionIdentifier.SliderStepValue]: {
53
73
  path: { extension: 'valueInteger', questionnaire: 'sliderStepValue' },
54
74
  },
75
+ [ExtensionIdentifier.EntryFormat]: {
76
+ path: { extension: 'valueString', questionnaire: 'entryFormat' },
77
+ },
55
78
  [ExtensionIdentifier.Unit]: {
56
79
  path: { extension: 'valueCoding', questionnaire: 'unit' },
57
80
  },
81
+ [ExtensionIdentifier.UnitOption]: {
82
+ path: { extension: 'valueCoding', questionnaire: 'unitOption' },
83
+ },
84
+ [ExtensionIdentifier.RowsNumber]: {
85
+ path: { extension: 'valueInteger', questionnaire: 'rowsNumber' },
86
+ },
58
87
  [ExtensionIdentifier.ReferenceResource]: {
59
88
  transform: {
60
89
  fromExtension: (extension) => {
@@ -74,6 +103,69 @@ export const extensionTransformers: ExtensionTransformer = {
74
103
  },
75
104
  },
76
105
  },
106
+ [ExtensionIdentifier.ColumnSize]: {
107
+ path: { extension: 'valueInteger', questionnaire: 'columnSize' },
108
+ },
109
+ [ExtensionIdentifier.ItemMedia]: {
110
+ path: { extension: 'valueAttachment', questionnaire: 'itemMedia' },
111
+ },
112
+ [ExtensionIdentifier.Regex]: {
113
+ path: { extension: 'valueString', questionnaire: 'regex' },
114
+ },
115
+ [ExtensionIdentifier.ObservationExtract]: {
116
+ path: { extension: 'valueBoolean', questionnaire: 'observationExtract' },
117
+ },
118
+ [ExtensionIdentifier.ObservationLinkPeriod]: {
119
+ path: { extension: 'valueDuration', questionnaire: 'observationLinkPeriod' },
120
+ },
121
+ [ExtensionIdentifier.MinValue]: {
122
+ transform: {
123
+ fromExtension: (extension) => ({ minValue: extension }),
124
+ toExtension: (item) => item.minValue,
125
+ },
126
+ },
127
+ [ExtensionIdentifier.MaxValue]: {
128
+ transform: {
129
+ fromExtension: (extension) => ({ maxValue: extension }),
130
+ toExtension: (item) => item.maxValue,
131
+ },
132
+ },
133
+ [ExtensionIdentifier.MinQuantity]: {
134
+ transform: {
135
+ fromExtension: (extension) => ({ minQuantity: extension }),
136
+ toExtension: (item) => item.minQuantity,
137
+ },
138
+ },
139
+ [ExtensionIdentifier.MaxQuantity]: {
140
+ transform: {
141
+ fromExtension: (extension) => ({ maxQuantity: extension }),
142
+ toExtension: (item) => item.maxQuantity,
143
+ },
144
+ },
145
+ [ExtensionIdentifier.ShowOrdinalValue]: {
146
+ path: { extension: 'valueBoolean', questionnaire: 'showOrdinalValue' },
147
+ },
148
+ [ExtensionIdentifier.PreferredTerminologyServer]: {
149
+ path: { extension: 'valueUri', questionnaire: 'preferredTerminologyServer' },
150
+ },
151
+ [ExtensionIdentifier.OpenLabel]: {
152
+ path: { extension: 'valueString', questionnaire: 'openLabel' },
153
+ },
154
+ [ExtensionIdentifier.BackgroundImage]: {
155
+ path: { extension: 'valueAttachment', questionnaire: 'backgroundImage' },
156
+ },
157
+ [ExtensionIdentifier.Language]: {
158
+ path: { extension: 'valueCoding', questionnaire: 'language' },
159
+ },
160
+ [ExtensionIdentifier.ChoiceOrientation]: {
161
+ path: { extension: 'valueCode', questionnaire: 'choiceOrientation' },
162
+ },
163
+ [ExtensionIdentifier.InlineChoiceDirection]: {
164
+ path: { extension: 'valueString', questionnaire: 'choiceOrientation' },
165
+ },
166
+ [ExtensionIdentifier.ChoiceColumns]: {
167
+ path: { extension: 'valueInteger', questionnaire: 'choiceColumns' },
168
+ },
77
169
 
78
170
  [ExtensionIdentifier.ItemPopulationContext]: {
79
171
  path: { extension: 'valueExpression', questionnaire: 'itemPopulationContext' },
@@ -5,6 +5,7 @@ import {
5
5
  QuestionnaireItemAnswerOption as FHIRQuestionnaireItemAnswerOption,
6
6
  QuestionnaireItemInitial as FHIRQuestionnaireItemInitial,
7
7
  } from 'fhir/r4b';
8
+ import _ from 'lodash';
8
9
 
9
10
  import {
10
11
  QuestionnaireItem as FCEQuestionnaireItem,
@@ -14,11 +15,7 @@ import {
14
15
  QuestionnaireItemInitial as FCEQuestionnaireItemInitial,
15
16
  } from 'shared/src/contrib/aidbox';
16
17
 
17
- import {
18
- convertFromFHIRExtension,
19
- convertToFHIRExtension,
20
- toFHIRReference,
21
- } from '../../../converter';
18
+ import { convertFromFHIRExtension, convertToFHIRExtension, toFHIRReference } from '../..';
22
19
 
23
20
  export function processItems(items: FCEQuestionnaireItem[]): FHIRQuestionnaireItem[] {
24
21
  return items.map((item) => {
@@ -29,6 +26,7 @@ export function processItems(items: FCEQuestionnaireItem[]): FHIRQuestionnaireIt
29
26
  .filter((ext): ext is Partial<FCEQuestionnaireItem> => ext !== undefined)
30
27
  .flatMap(Object.keys);
31
28
  for (const field of fieldsToOmit) {
29
+ //@ts-ignore
32
30
  delete item[field];
33
31
  }
34
32
  item.extension = extensions.sort();
@@ -78,6 +76,7 @@ const convertEnableWhen = (
78
76
  answerType: string,
79
77
  result: FHIRQuestionnaireItemEnableWhen,
80
78
  ) => {
79
+ //@ts-ignore
81
80
  if (answer[answerType] !== undefined) {
82
81
  switch (answerType) {
83
82
  case 'boolean':
@@ -124,22 +123,26 @@ function processAnswerOption(
124
123
 
125
124
  const fhirOption: FHIRQuestionnaireItemAnswerOption = { ...commonOptions };
126
125
 
127
- if (value?.Coding) {
126
+ if (!value) {
127
+ return fhirOption;
128
+ }
129
+
130
+ if (value.Coding) {
128
131
  fhirOption.valueCoding = value.Coding;
129
132
  }
130
- if (value?.string) {
133
+ if (value.string) {
131
134
  fhirOption.valueString = value.string;
132
135
  }
133
- if (value?.Reference) {
136
+ if (value.Reference) {
134
137
  fhirOption.valueReference = toFHIRReference(value.Reference);
135
138
  }
136
- if (value?.date) {
139
+ if (value.date) {
137
140
  fhirOption.valueDate = value.date;
138
141
  }
139
- if (value?.integer) {
142
+ if (_.isNumber(value.integer)) {
140
143
  fhirOption.valueInteger = value.integer;
141
144
  }
142
- if (value?.time) {
145
+ if (value.time) {
143
146
  fhirOption.valueTime = value.time;
144
147
  }
145
148
 
@@ -39,8 +39,10 @@ function processAnswer(
39
39
  };
40
40
  for (const key in valueMappings) {
41
41
  if (key in value) {
42
+ //@ts-ignore
42
43
  const newKey = valueMappings[key];
43
44
  if (newKey) {
45
+ //@ts-ignore
44
46
  fhirAnswerItem[newKey] = value[key];
45
47
  }
46
48
  break;
@@ -3,9 +3,9 @@ import { QuestionnaireResponse as FHIRQuestionnaireResponse } from 'fhir/r4b';
3
3
  import { QuestionnaireResponse as FCEQuestionnaireResponse } from 'shared/src/contrib/aidbox';
4
4
 
5
5
  export function processReference(fceQR: FCEQuestionnaireResponse): FHIRQuestionnaireResponse {
6
- const { encounter, source, ...commonProprties } = fceQR;
6
+ const { encounter, source, subject, ...commonProperties } = fceQR;
7
7
  const fhirQuestionnaireResponse: FHIRQuestionnaireResponse =
8
- commonProprties as FHIRQuestionnaireResponse;
8
+ commonProperties as FHIRQuestionnaireResponse;
9
9
  if (encounter && encounter.resourceType && encounter.id) {
10
10
  const { id, resourceType, ...encounterProperties } = encounter;
11
11
  fhirQuestionnaireResponse.encounter = {
@@ -20,5 +20,12 @@ export function processReference(fceQR: FCEQuestionnaireResponse): FHIRQuestionn
20
20
  ...sourceProperties,
21
21
  };
22
22
  }
23
+ if (subject && subject.resourceType && subject.id) {
24
+ const { id, resourceType, ...subjectProperties } = subject;
25
+ fhirQuestionnaireResponse.subject = {
26
+ reference: `${resourceType}/${id}`,
27
+ ...subjectProperties,
28
+ };
29
+ }
23
30
  return fhirQuestionnaireResponse;
24
31
  }
@@ -5,6 +5,7 @@ import {
5
5
  QuestionnaireItemAnswerOption as FHIRQuestionnaireItemAnswerOption,
6
6
  QuestionnaireItemInitial as FHIRQuestionnaireItemInitial,
7
7
  } from 'fhir/r4b';
8
+ import _ from 'lodash';
8
9
 
9
10
  import {
10
11
  QuestionnaireItem as FCEQuestionnaireItem,
@@ -12,10 +13,11 @@ import {
12
13
  QuestionnaireItemEnableWhenAnswer as FCEQuestionnaireItemEnableWhenAnswer,
13
14
  QuestionnaireItemAnswerOption as FCEQuestionnaireItemAnswerOption,
14
15
  QuestionnaireItemInitial as FCEQuestionnaireItemInitial,
16
+ Coding as FCECoding,
15
17
  } from 'shared/src/contrib/aidbox';
16
18
 
17
19
  import { convertFromFHIRExtension, findExtension, fromFHIRReference } from '../../../converter';
18
- import { ExtensionIdentifier } from '../../../converter/extensions';
20
+ import { ExtensionIdentifier } from '../../extensions';
19
21
 
20
22
  export function processItems(fhirQuestionnaire: FHIRQuestionnaire) {
21
23
  return fhirQuestionnaire.item?.map(convertItemProperties);
@@ -37,9 +39,20 @@ function convertItemProperties(item: FHIRQuestionnaireItem): FCEQuestionnaireIte
37
39
  function getUpdatedPropertiesFromItem(item: FHIRQuestionnaireItem) {
38
40
  let updatedProperties: FCEQuestionnaireItem = { linkId: item.linkId, type: item.type };
39
41
 
40
- for (const identifer in ExtensionIdentifier) {
41
- const identifierURI = ExtensionIdentifier[identifer];
42
- const extension = findExtension(item, identifierURI);
42
+ for (const identifier of Object.values(ExtensionIdentifier)) {
43
+ if (identifier === ExtensionIdentifier.UnitOption) {
44
+ const unitOptions =
45
+ item.extension?.filter((ext) => ext.url === ExtensionIdentifier.UnitOption) || [];
46
+ if (unitOptions.length > 0) {
47
+ const unitOption = unitOptions.map(
48
+ (ext) => convertFromFHIRExtension(ext)?.unitOption,
49
+ ) as FCECoding[];
50
+ updatedProperties = { ...updatedProperties, unitOption };
51
+ }
52
+ continue;
53
+ }
54
+
55
+ const extension = findExtension(item, identifier);
43
56
  if (extension !== undefined) {
44
57
  updatedProperties = {
45
58
  ...updatedProperties,
@@ -141,7 +154,7 @@ function processItemOption(
141
154
  },
142
155
  };
143
156
  }
144
- if (option.valueInteger) {
157
+ if (_.isNumber(option.valueInteger)) {
145
158
  return {
146
159
  value: {
147
160
  integer: option.valueInteger,
@@ -44,8 +44,11 @@ function processAnswer(
44
44
 
45
45
  for (const key in valueHandlers) {
46
46
  if (key in fceAnswer) {
47
+ //@ts-ignore
47
48
  const value = fceAnswer[key];
49
+ //@ts-ignore
48
50
  delete fceAnswer[key];
51
+ //@ts-ignore
49
52
  fceAnswer.value = valueHandlers[key]?.(value);
50
53
  }
51
54
  }
@@ -9,6 +9,10 @@ export function processMeta(meta: FHIRMeta): FCEMeta {
9
9
  const fceMeta: FCEMeta = { ...commonMeta };
10
10
  if (extension) {
11
11
  fceMeta.createdAt = extractExtension(extension, 'ex:createdAt');
12
+ const filteredExtension = extension.filter((value) => value.url !== 'ex:createdAt');
13
+ if (filteredExtension?.length > 0) {
14
+ fceMeta.extension = filteredExtension;
15
+ }
12
16
  }
13
17
  return fceMeta;
14
18
  }
@@ -7,7 +7,7 @@ import { fromFHIRReference } from '../../../converter';
7
7
  export function processReference(
8
8
  fhirQuestionnaireResponse: FHIRQuestionnaireResponse,
9
9
  ): FCEQuestionnaireResponse {
10
- const { encounter, source, ...commonProperties } = fhirQuestionnaireResponse;
10
+ const { encounter, source, subject, ...commonProperties } = fhirQuestionnaireResponse;
11
11
  const fceQuestionnaireResponse: FCEQuestionnaireResponse =
12
12
  commonProperties as FCEQuestionnaireResponse;
13
13
  if (encounter?.reference) {
@@ -16,5 +16,8 @@ export function processReference(
16
16
  if (source?.reference) {
17
17
  fceQuestionnaireResponse.source = fromFHIRReference(source);
18
18
  }
19
+ if (subject?.reference) {
20
+ fceQuestionnaireResponse.subject = fromFHIRReference(subject);
21
+ }
19
22
  return fceQuestionnaireResponse;
20
23
  }
@@ -13,8 +13,7 @@ export function checkFhirQuestionnaireProfile(fhirQuestionnaire: FHIRQuestionnai
13
13
 
14
14
  export function trimUndefined(e: any) {
15
15
  for (const prop in e) {
16
- // eslint-disable-next-line no-prototype-builtins
17
- if (e.hasOwnProperty(prop)) {
16
+ if (Object.prototype.hasOwnProperty.call(e, prop)) {
18
17
  const val = e[prop];
19
18
  if (val === undefined) {
20
19
  delete e[prop];
@@ -31,9 +31,8 @@ export function convertFromFHIRExtension(
31
31
 
32
32
  export function convertToFHIRExtension(item: FCEQuestionnaireItem): FHIRExtension[] {
33
33
  const extensions: FHIRExtension[] = [];
34
- for (const identifer in ExtensionIdentifier) {
35
- const transformer =
36
- extensionTransformers[ExtensionIdentifier[identifer] as ExtensionIdentifier];
34
+ Object.values(ExtensionIdentifier).forEach((identifier) => {
35
+ const transformer = extensionTransformers[identifier];
37
36
  if ('transform' in transformer) {
38
37
  const extension = transformer.transform.toExtension(item);
39
38
  if (extension !== undefined) {
@@ -44,12 +43,12 @@ export function convertToFHIRExtension(item: FCEQuestionnaireItem): FHIRExtensio
44
43
  if (extensionValue !== undefined) {
45
44
  const extension: FHIRExtension = {
46
45
  [transformer.path.extension]: extensionValue,
47
- url: ExtensionIdentifier[identifer],
46
+ url: identifier,
48
47
  };
49
48
  extensions.push(extension);
50
49
  }
51
50
  }
52
- }
51
+ });
53
52
  return extensions;
54
53
  }
55
54
 
package/src/utils.ts CHANGED
@@ -5,6 +5,7 @@ import isPlainObject from 'lodash/isPlainObject';
5
5
  import queryString from 'query-string';
6
6
 
7
7
  import {
8
+ Extension,
8
9
  Questionnaire,
9
10
  QuestionnaireItem,
10
11
  QuestionnaireItemInitial,
@@ -110,15 +111,25 @@ export function calcContext(
110
111
  qrItem: QuestionnaireResponseItem,
111
112
  ): ItemContext {
112
113
  // TODO: add root variable support
113
- return {
114
- ...(variables || []).reduce(
115
- (acc, curVariable) => ({
116
- ...acc,
117
- [curVariable.name!]: fhirpath.evaluate(qrItem || {}, curVariable.expression!, acc),
118
- }),
119
- { ...initialContext, context: qrItem, qitem: qItem },
120
- ),
121
- };
114
+ try {
115
+ return {
116
+ ...(variables || []).reduce(
117
+ (acc, curVariable) => ({
118
+ ...acc,
119
+ [curVariable.name!]: fhirpath.evaluate(
120
+ qrItem || {},
121
+ curVariable.expression!,
122
+ acc,
123
+ ),
124
+ }),
125
+ { ...initialContext, context: qrItem, qitem: qItem },
126
+ ),
127
+ };
128
+ } catch (err: unknown) {
129
+ throw Error(
130
+ `FHIRPath expression evaluation failure for "variable" in ${qItem.linkId}: ${err}`,
131
+ );
132
+ }
122
133
  }
123
134
 
124
135
  export function compareValue(firstAnswerValue: AnswerValue, secondAnswerValue: AnswerValue) {
@@ -501,21 +512,25 @@ function isQuestionEnabled(args: IsQuestionEnabledArgs) {
501
512
  }
502
513
 
503
514
  if (enableWhenExpression && enableWhenExpression.language === 'text/fhirpath') {
504
- const expressionResult = fhirpath.evaluate(
505
- args.context.resource,
506
- enableWhenExpression.expression!,
507
- args.context ?? {},
508
- )[0];
509
-
510
- if (typeof expressionResult !== 'boolean') {
511
- throw Error(`
512
- linkId: ${args.qItem.linkId}
513
- Expression result: ${expressionResult}
514
- The result of enableWhenExpression is not a boolean value
515
- `);
516
- }
515
+ try {
516
+ const expressionResult = fhirpath.evaluate(
517
+ args.context.resource,
518
+ enableWhenExpression.expression!,
519
+ args.context ?? {},
520
+ )[0];
521
+
522
+ if (typeof expressionResult !== 'boolean') {
523
+ throw Error(
524
+ `The result of enableWhenExpression is not a boolean value. Expression result: ${expressionResult}`,
525
+ );
526
+ }
517
527
 
518
- return expressionResult;
528
+ return expressionResult;
529
+ } catch (err: unknown) {
530
+ throw Error(
531
+ `FHIRPath expression evaluation failure for "enableWhenExpression" in ${args.qItem.linkId}: ${err}`,
532
+ );
533
+ }
519
534
  }
520
535
 
521
536
  const iterFn = enableBehavior === 'any' ? _.some : _.every;
@@ -749,3 +764,7 @@ export function isValueEmpty(value: any) {
749
764
 
750
765
  return _.isFinite(value) || _.isBoolean(value) ? false : _.isEmpty(value);
751
766
  }
767
+
768
+ export function findExtensionByUrl(url: string, extensionList?: Extension[]) {
769
+ return extensionList?.find((extension) => extension.url === url) || null;
770
+ }