@imranq2/fhirpatientsummary 1.0.17 → 1.0.19
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/README.md +6 -6
- package/dist/index.cjs +331 -29
- package/dist/index.d.cts +69 -4
- package/dist/index.d.ts +69 -4
- package/dist/index.js +331 -29
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -18,7 +18,7 @@ npm install
|
|
|
18
18
|
|
|
19
19
|
You can use the `ComprehensiveIPSCompositionBuilder` in your TypeScript or JavaScript project to generate an IPS-compliant FHIR Bundle. The builder supports both fluent section addition and a convenient `read_bundle()` method to extract all supported sections from a FHIR Bundle.
|
|
20
20
|
|
|
21
|
-
### Example: Using setPatient and
|
|
21
|
+
### Example: Using setPatient and makeSectionAsync
|
|
22
22
|
|
|
23
23
|
```typescript
|
|
24
24
|
import { ComprehensiveIPSCompositionBuilder } from './src/generators/fhir_summary_generator';
|
|
@@ -26,10 +26,10 @@ import { IPSSections } from './src/structures/ips_sections';
|
|
|
26
26
|
|
|
27
27
|
const builder = new ComprehensiveIPSCompositionBuilder()
|
|
28
28
|
.setPatient(patientResource)
|
|
29
|
-
.
|
|
30
|
-
.
|
|
31
|
-
.
|
|
32
|
-
.
|
|
29
|
+
.makeSectionAsync(IPSSections.ALLERGIES, allergiesArray, 'America/New_York')
|
|
30
|
+
.makeSectionAsync(IPSSections.MEDICATIONS, medicationsArray, 'America/New_York')
|
|
31
|
+
.makeSectionAsync(IPSSections.PROBLEMS, problemsArray, 'America/New_York')
|
|
32
|
+
.makeSectionAsync(IPSSections.IMMUNIZATIONS, immunizationsArray, 'America/New_York');
|
|
33
33
|
|
|
34
34
|
const bundle = builder.build_bundle(
|
|
35
35
|
'example-organization',
|
|
@@ -61,7 +61,7 @@ console.log(JSON.stringify(bundle, null, 2));
|
|
|
61
61
|
```
|
|
62
62
|
|
|
63
63
|
- Use `setPatient(patientResource)` to set the patient.
|
|
64
|
-
- Use `
|
|
64
|
+
- Use `makeSectionAsync(sectionType, resources, timezone)` to add each IPS section, or use `read_bundle(fhirBundle, timezone)` to extract all supported sections from a FHIR Bundle.
|
|
65
65
|
- Use `build_bundle` to generate the final FHIR Bundle.
|
|
66
66
|
|
|
67
67
|
## Running Tests
|
package/dist/index.cjs
CHANGED
|
@@ -142,10 +142,17 @@ var IPSSectionResourceFilters = {
|
|
|
142
142
|
// Only include active advance directives (Consent resources)
|
|
143
143
|
["AdvanceDirectivesSection" /* ADVANCE_DIRECTIVES */]: (resource) => resource.resourceType === "Consent" && resource.status === "active"
|
|
144
144
|
};
|
|
145
|
+
var IPSSectionSummaryCompositionFilter = {
|
|
146
|
+
["AllergyIntoleranceSection" /* ALLERGIES */]: (resource) => resource.resourceType === "Composition" && resource.type?.coding?.some((c) => c.system === "https://fhir.icanbwell.com/4_0_0/CodeSystem/composition/" && c.code === "allergy_summary_document"),
|
|
147
|
+
["VitalSignsSection" /* VITAL_SIGNS */]: (resource) => resource.resourceType === "Composition" && resource.type?.coding?.some((c) => c.system === "https://fhir.icanbwell.com/4_0_0/CodeSystem/composition/" && c.code === "vital_summary_document")
|
|
148
|
+
};
|
|
145
149
|
var IPSSectionResourceHelper = class {
|
|
146
150
|
static getResourceFilterForSection(section) {
|
|
147
151
|
return IPSSectionResourceFilters[section];
|
|
148
152
|
}
|
|
153
|
+
static getSummaryCompositionFilterForSection(section) {
|
|
154
|
+
return IPSSectionSummaryCompositionFilter[section];
|
|
155
|
+
}
|
|
149
156
|
};
|
|
150
157
|
|
|
151
158
|
// src/narratives/templates/typescript/TemplateUtilities.ts
|
|
@@ -595,6 +602,137 @@ var TemplateUtilities = class {
|
|
|
595
602
|
}
|
|
596
603
|
return status;
|
|
597
604
|
}
|
|
605
|
+
extractObservationSummaryValue(data, timezone) {
|
|
606
|
+
if (data["valueQuantity.value"] !== void 0) {
|
|
607
|
+
const value = data["valueQuantity.value"];
|
|
608
|
+
const unit = data["valueQuantity.unit"];
|
|
609
|
+
return unit ? `${value} ${unit}` : `${value}`;
|
|
610
|
+
}
|
|
611
|
+
if (data["valueCodeableConcept.text"] !== void 0) {
|
|
612
|
+
return data["valueCodeableConcept.text"];
|
|
613
|
+
}
|
|
614
|
+
if (data["valueCodeableConcept.coding.display"] !== void 0) {
|
|
615
|
+
return data["valueCodeableConcept.coding.display"];
|
|
616
|
+
}
|
|
617
|
+
if (data["valueString"] !== void 0) {
|
|
618
|
+
return data["valueString"];
|
|
619
|
+
}
|
|
620
|
+
if (data["valueBoolean"] !== void 0) {
|
|
621
|
+
return String(data["valueBoolean"]);
|
|
622
|
+
}
|
|
623
|
+
if (data["valueInteger"] !== void 0) {
|
|
624
|
+
return String(data["valueInteger"]);
|
|
625
|
+
}
|
|
626
|
+
if (data["valueDateTime"] !== void 0) {
|
|
627
|
+
return this.renderTime(data["valueDateTime"], timezone);
|
|
628
|
+
}
|
|
629
|
+
if (data["valuePeriod.start"] !== void 0 || data["valuePeriod.end"] !== void 0) {
|
|
630
|
+
const start = this.renderTime(data["valuePeriod.start"], timezone);
|
|
631
|
+
const end = this.renderTime(data["valuePeriod.end"], timezone);
|
|
632
|
+
if (start && end) {
|
|
633
|
+
return `${start} - ${end}`;
|
|
634
|
+
} else if (start) {
|
|
635
|
+
return `${start}`;
|
|
636
|
+
} else if (end) {
|
|
637
|
+
return `${end}`;
|
|
638
|
+
}
|
|
639
|
+
}
|
|
640
|
+
if (data["valueTime"] !== void 0) {
|
|
641
|
+
return this.renderTime(data["valueTime"], timezone);
|
|
642
|
+
}
|
|
643
|
+
if (data["valueSampledData.origin.value"] !== void 0 || data["valueSampledData.origin.unit"] !== void 0) {
|
|
644
|
+
const originValue = data["valueSampledData.origin.value"];
|
|
645
|
+
const originUnit = data["valueSampledData.origin.unit"];
|
|
646
|
+
let result = "";
|
|
647
|
+
if (originValue !== void 0 && originUnit !== void 0) {
|
|
648
|
+
result = `${originValue} ${originUnit}`;
|
|
649
|
+
} else if (originValue !== void 0) {
|
|
650
|
+
result = `${originValue}`;
|
|
651
|
+
} else if (originUnit !== void 0) {
|
|
652
|
+
result = `${originUnit}`;
|
|
653
|
+
}
|
|
654
|
+
const period = data["valueSampledData.period"];
|
|
655
|
+
const factor = data["valueSampledData.factor"];
|
|
656
|
+
const lowerLimit = data["valueSampledData.lowerLimit"];
|
|
657
|
+
const upperLimit = data["valueSampledData.upperLimit"];
|
|
658
|
+
const sampledData = data["valueSampledData.data"];
|
|
659
|
+
const extras = [];
|
|
660
|
+
if (period !== void 0) extras.push(`period: ${period}`);
|
|
661
|
+
if (factor !== void 0) extras.push(`factor: ${factor}`);
|
|
662
|
+
if (lowerLimit !== void 0) extras.push(`lowerLimit: ${lowerLimit}`);
|
|
663
|
+
if (upperLimit !== void 0) extras.push(`upperLimit: ${upperLimit}`);
|
|
664
|
+
if (sampledData !== void 0) extras.push(`data: ${sampledData}`);
|
|
665
|
+
if (extras.length > 0) {
|
|
666
|
+
result += ` (${extras.join(", ")})`;
|
|
667
|
+
}
|
|
668
|
+
return result;
|
|
669
|
+
}
|
|
670
|
+
if (data["valueRange.low.value"] !== void 0 || data["valueRange.high.value"] !== void 0) {
|
|
671
|
+
let referenceRange = "";
|
|
672
|
+
if (data["valueRange.low.value"] !== void 0) {
|
|
673
|
+
referenceRange += `${data["valueRange.low.value"]}`;
|
|
674
|
+
if (data["valueRange.low.unit"] !== void 0) {
|
|
675
|
+
referenceRange += ` ${data["valueRange.low.unit"]}`;
|
|
676
|
+
}
|
|
677
|
+
referenceRange = referenceRange.trim();
|
|
678
|
+
if (data["valueRange.high.value"] !== void 0) {
|
|
679
|
+
referenceRange += " - ";
|
|
680
|
+
}
|
|
681
|
+
}
|
|
682
|
+
if (data["valueRange.high.value"] !== void 0) {
|
|
683
|
+
referenceRange += `${data["valueRange.high.value"]}`;
|
|
684
|
+
if (data["valueRange.high.unit"] !== void 0) {
|
|
685
|
+
referenceRange += ` ${data["valueRange.high.unit"]}`;
|
|
686
|
+
}
|
|
687
|
+
}
|
|
688
|
+
return referenceRange.trim();
|
|
689
|
+
}
|
|
690
|
+
if (data["valueRatio.numerator.value"] !== void 0 || data["valueRatio.denominator.value"] !== void 0) {
|
|
691
|
+
let ratio = "";
|
|
692
|
+
if (data["valueRatio.numerator.value"] !== void 0) {
|
|
693
|
+
ratio += `${data["valueRatio.numerator.value"]}`;
|
|
694
|
+
if (data["valueRatio.numerator.unit"] !== void 0) {
|
|
695
|
+
ratio += ` ${data["valueRatio.numerator.unit"]}`;
|
|
696
|
+
}
|
|
697
|
+
}
|
|
698
|
+
if (data["valueRatio.denominator.value"] !== void 0) {
|
|
699
|
+
ratio += " / ";
|
|
700
|
+
ratio += `${data["valueRatio.denominator.value"]}`;
|
|
701
|
+
if (data["valueRatio.denominator.unit"] !== void 0) {
|
|
702
|
+
ratio += ` ${data["valueRatio.denominator.unit"]}`;
|
|
703
|
+
}
|
|
704
|
+
}
|
|
705
|
+
return ratio.trim();
|
|
706
|
+
}
|
|
707
|
+
return "";
|
|
708
|
+
}
|
|
709
|
+
extractObservationSummaryReferenceRange(data) {
|
|
710
|
+
let referenceRange = "";
|
|
711
|
+
if (data["referenceRange.low.value"]) {
|
|
712
|
+
referenceRange += `${data["referenceRange.low.value"]} ${data["referenceRange.low.unit"]}`;
|
|
713
|
+
referenceRange.trim();
|
|
714
|
+
if (data["referenceRange.high.value"]) {
|
|
715
|
+
referenceRange += " - ";
|
|
716
|
+
}
|
|
717
|
+
}
|
|
718
|
+
if (data["referenceRange.high.value"]) {
|
|
719
|
+
referenceRange += `${data["referenceRange.high.value"]} ${data["referenceRange.high.unit"]}`;
|
|
720
|
+
}
|
|
721
|
+
return referenceRange.trim();
|
|
722
|
+
}
|
|
723
|
+
extractObservationSummaryEffectiveTime(data, timezone) {
|
|
724
|
+
if (data["effectiveDateTime"]) {
|
|
725
|
+
return this.renderTime(data["effectiveDateTime"], timezone);
|
|
726
|
+
}
|
|
727
|
+
let effectiveTimePeriod = "";
|
|
728
|
+
if (data["effectivePeriod.start"]) {
|
|
729
|
+
effectiveTimePeriod += this.renderTime(data["effectivePeriod.start"], timezone);
|
|
730
|
+
}
|
|
731
|
+
if (data["effectivePeriod.end"]) {
|
|
732
|
+
effectiveTimePeriod += ` - ${this.renderTime(data["effectivePeriod.end"], timezone)}`;
|
|
733
|
+
}
|
|
734
|
+
return effectiveTimePeriod.trim();
|
|
735
|
+
}
|
|
598
736
|
formatQuantityValue(quantity) {
|
|
599
737
|
if (!quantity) return "";
|
|
600
738
|
const parts = [];
|
|
@@ -1094,6 +1232,57 @@ var AllergyIntoleranceTemplate = class _AllergyIntoleranceTemplate {
|
|
|
1094
1232
|
generateNarrative(resources, timezone) {
|
|
1095
1233
|
return _AllergyIntoleranceTemplate.generateStaticNarrative(resources, timezone);
|
|
1096
1234
|
}
|
|
1235
|
+
/**
|
|
1236
|
+
* Generate HTML narrative for AllergyIntolerance resources using summary
|
|
1237
|
+
* @param resources - FHIR Composition resources
|
|
1238
|
+
* @param timezone - Optional timezone to use for date formatting (e.g., 'America/New_York', 'Europe/London')
|
|
1239
|
+
* @returns HTML string for rendering
|
|
1240
|
+
*/
|
|
1241
|
+
generateSummaryNarrative(resources, timezone) {
|
|
1242
|
+
const templateUtilities = new TemplateUtilities(resources);
|
|
1243
|
+
let html = `
|
|
1244
|
+
<div>
|
|
1245
|
+
<table>
|
|
1246
|
+
<thead>
|
|
1247
|
+
<tr>
|
|
1248
|
+
<th>Allergen</th>
|
|
1249
|
+
<th>Criticality</th>
|
|
1250
|
+
<th>Recorded Date</th>
|
|
1251
|
+
</tr>
|
|
1252
|
+
</thead>
|
|
1253
|
+
<tbody>`;
|
|
1254
|
+
for (const resourceItem of resources) {
|
|
1255
|
+
for (const rowData of resourceItem.section ?? []) {
|
|
1256
|
+
const data = {};
|
|
1257
|
+
for (const columnData of rowData.section ?? []) {
|
|
1258
|
+
switch (columnData.title) {
|
|
1259
|
+
case "Allergen Name":
|
|
1260
|
+
data["allergen"] = columnData.text?.div ?? "";
|
|
1261
|
+
break;
|
|
1262
|
+
case "Criticality":
|
|
1263
|
+
data["criticality"] = columnData.text?.div ?? "";
|
|
1264
|
+
break;
|
|
1265
|
+
case "Recorded Date":
|
|
1266
|
+
data["recordedDate"] = columnData.text?.div ?? "";
|
|
1267
|
+
break;
|
|
1268
|
+
default:
|
|
1269
|
+
break;
|
|
1270
|
+
}
|
|
1271
|
+
}
|
|
1272
|
+
html += `
|
|
1273
|
+
<tr>
|
|
1274
|
+
<td>${data["allergen"] ?? "-"}</td>
|
|
1275
|
+
<td>${data["criticality"] ?? "-"}</td>
|
|
1276
|
+
<td>${templateUtilities.renderTime(data["recordedDate"], timezone) ?? "-"}</td>
|
|
1277
|
+
</tr>`;
|
|
1278
|
+
}
|
|
1279
|
+
}
|
|
1280
|
+
html += `
|
|
1281
|
+
</tbody>
|
|
1282
|
+
</table>
|
|
1283
|
+
</div>`;
|
|
1284
|
+
return html;
|
|
1285
|
+
}
|
|
1097
1286
|
/**
|
|
1098
1287
|
* Internal static implementation that actually generates the narrative
|
|
1099
1288
|
* @param resources - FHIR resources array containing AllergyIntolerance resources
|
|
@@ -1586,6 +1775,13 @@ var ProblemListTemplate = class _ProblemListTemplate {
|
|
|
1586
1775
|
}
|
|
1587
1776
|
};
|
|
1588
1777
|
|
|
1778
|
+
// src/structures/ips_section_constants.ts
|
|
1779
|
+
var VITAL_SIGNS_SUMMARY_COMPONENT_MAP = {
|
|
1780
|
+
"Systolic Blood Pressure": "valueRatio.numerator.value",
|
|
1781
|
+
"Diastolic Blood Pressure": "valueRatio.denominator.value",
|
|
1782
|
+
"Default": "valueString"
|
|
1783
|
+
};
|
|
1784
|
+
|
|
1589
1785
|
// src/narratives/templates/typescript/VitalSignsTemplate.ts
|
|
1590
1786
|
var VitalSignsTemplate = class _VitalSignsTemplate {
|
|
1591
1787
|
/**
|
|
@@ -1597,6 +1793,68 @@ var VitalSignsTemplate = class _VitalSignsTemplate {
|
|
|
1597
1793
|
generateNarrative(resources, timezone) {
|
|
1598
1794
|
return _VitalSignsTemplate.generateStaticNarrative(resources, timezone);
|
|
1599
1795
|
}
|
|
1796
|
+
/**
|
|
1797
|
+
* Generate HTML narrative for vital signs using summary
|
|
1798
|
+
* @param resources - FHIR Composition resources
|
|
1799
|
+
* @param timezone - Optional timezone to use for date formatting (e.g., 'America/New_York', 'Europe/London')
|
|
1800
|
+
* @returns HTML string for rendering
|
|
1801
|
+
*/
|
|
1802
|
+
generateSummaryNarrative(resources, timezone) {
|
|
1803
|
+
const templateUtilities = new TemplateUtilities(resources);
|
|
1804
|
+
let html = `
|
|
1805
|
+
<div>
|
|
1806
|
+
<table>
|
|
1807
|
+
<thead>
|
|
1808
|
+
<tr>
|
|
1809
|
+
<th>Vital Name</th>
|
|
1810
|
+
<th>Result</th>
|
|
1811
|
+
<th>Reference Range</th>
|
|
1812
|
+
<th>Date</th>
|
|
1813
|
+
</tr>
|
|
1814
|
+
</thead>
|
|
1815
|
+
<tbody>`;
|
|
1816
|
+
for (const resourceItem of resources) {
|
|
1817
|
+
for (const rowData of resourceItem.section ?? []) {
|
|
1818
|
+
const data = {};
|
|
1819
|
+
for (const columnData of rowData.section ?? []) {
|
|
1820
|
+
const columnTitle = columnData.title;
|
|
1821
|
+
if (columnTitle) {
|
|
1822
|
+
if (Object.keys(VITAL_SIGNS_SUMMARY_COMPONENT_MAP).includes(
|
|
1823
|
+
columnTitle
|
|
1824
|
+
)) {
|
|
1825
|
+
const vitalData = {};
|
|
1826
|
+
for (const component of columnData.section?.[0]?.section ?? []) {
|
|
1827
|
+
if (component.title) {
|
|
1828
|
+
vitalData[component.title] = component.text?.div ?? "";
|
|
1829
|
+
}
|
|
1830
|
+
}
|
|
1831
|
+
const vitalValue = templateUtilities.extractObservationSummaryValue(
|
|
1832
|
+
vitalData,
|
|
1833
|
+
timezone
|
|
1834
|
+
);
|
|
1835
|
+
if (vitalValue) {
|
|
1836
|
+
const dataKey = VITAL_SIGNS_SUMMARY_COMPONENT_MAP[columnTitle] ?? VITAL_SIGNS_SUMMARY_COMPONENT_MAP["Default"];
|
|
1837
|
+
data[dataKey] = vitalValue;
|
|
1838
|
+
}
|
|
1839
|
+
}
|
|
1840
|
+
data[columnTitle] = columnData.text?.div ?? "";
|
|
1841
|
+
}
|
|
1842
|
+
}
|
|
1843
|
+
html += `
|
|
1844
|
+
<tr>
|
|
1845
|
+
<td>${data["Vital Name"] ?? "-"}</td>
|
|
1846
|
+
<td>${templateUtilities.extractObservationSummaryValue(data, timezone) ?? "-"}</td>
|
|
1847
|
+
<td>${templateUtilities.extractObservationSummaryReferenceRange(data) ?? "-"}</td>
|
|
1848
|
+
<td>${templateUtilities.extractObservationSummaryEffectiveTime(data, timezone) ?? "-"}</td>
|
|
1849
|
+
</tr>`;
|
|
1850
|
+
}
|
|
1851
|
+
}
|
|
1852
|
+
html += `
|
|
1853
|
+
</tbody>
|
|
1854
|
+
</table>
|
|
1855
|
+
</div>`;
|
|
1856
|
+
return html;
|
|
1857
|
+
}
|
|
1600
1858
|
/**
|
|
1601
1859
|
* Internal static implementation that actually generates the narrative
|
|
1602
1860
|
* @param resources - FHIR Observation resources
|
|
@@ -1615,7 +1873,7 @@ var VitalSignsTemplate = class _VitalSignsTemplate {
|
|
|
1615
1873
|
<table>
|
|
1616
1874
|
<thead>
|
|
1617
1875
|
<tr>
|
|
1618
|
-
<th>
|
|
1876
|
+
<th>Vital Name</th>
|
|
1619
1877
|
<th>Result</th>
|
|
1620
1878
|
<th>Unit</th>
|
|
1621
1879
|
<th>Interpretation</th>
|
|
@@ -2260,14 +2518,18 @@ var TypeScriptTemplateMapper = class {
|
|
|
2260
2518
|
* @param section - The IPS section
|
|
2261
2519
|
* @param resources - FHIR resources
|
|
2262
2520
|
* @param timezone - Optional timezone to use for date formatting (e.g., 'America/New_York', 'Europe/London')
|
|
2521
|
+
* @param useSectionSummary - Whether to use the section summary for narrative generation
|
|
2263
2522
|
* @returns HTML string for rendering
|
|
2264
2523
|
*/
|
|
2265
|
-
static generateNarrative(section, resources, timezone) {
|
|
2524
|
+
static generateNarrative(section, resources, timezone, useSectionSummary = false) {
|
|
2266
2525
|
const templateClass = this.sectionToTemplate[section];
|
|
2267
2526
|
if (!templateClass) {
|
|
2268
2527
|
throw new Error(`No template found for section: ${section}`);
|
|
2269
2528
|
}
|
|
2270
|
-
return templateClass.
|
|
2529
|
+
return useSectionSummary ? templateClass.generateSummaryNarrative(
|
|
2530
|
+
resources,
|
|
2531
|
+
timezone
|
|
2532
|
+
) : templateClass.generateNarrative(resources, timezone);
|
|
2271
2533
|
}
|
|
2272
2534
|
};
|
|
2273
2535
|
// Map of section types to their template classes
|
|
@@ -2323,14 +2585,15 @@ var NarrativeGenerator = class {
|
|
|
2323
2585
|
* @param section - IPS section type
|
|
2324
2586
|
* @param resources - Array of domain resources
|
|
2325
2587
|
* @param timezone - Optional timezone to use for date formatting (e.g., 'America/New_York', 'Europe/London')
|
|
2588
|
+
* @param useSectionSummary - Whether to use section summary for narrative generation (default: false)
|
|
2326
2589
|
* @returns Generated HTML content or undefined if no resources
|
|
2327
2590
|
*/
|
|
2328
|
-
static async generateNarrativeContentAsync(section, resources, timezone) {
|
|
2591
|
+
static async generateNarrativeContentAsync(section, resources, timezone, useSectionSummary = false) {
|
|
2329
2592
|
if (!resources || resources.length === 0) {
|
|
2330
2593
|
return void 0;
|
|
2331
2594
|
}
|
|
2332
2595
|
try {
|
|
2333
|
-
const content = TypeScriptTemplateMapper.generateNarrative(section, resources, timezone);
|
|
2596
|
+
const content = TypeScriptTemplateMapper.generateNarrative(section, resources, timezone, useSectionSummary);
|
|
2334
2597
|
if (!content) {
|
|
2335
2598
|
return void 0;
|
|
2336
2599
|
}
|
|
@@ -2381,10 +2644,11 @@ var NarrativeGenerator = class {
|
|
|
2381
2644
|
* @param resources - Array of domain resources
|
|
2382
2645
|
* @param timezone - Optional timezone to use for date formatting
|
|
2383
2646
|
* @param minify - Whether to minify the HTML content (default: true)
|
|
2647
|
+
* @param useSectionSummary - Whether to use section summary for narrative generation (default: false)
|
|
2384
2648
|
* @returns Promise that resolves to a FHIR Narrative object or undefined if no resources
|
|
2385
2649
|
*/
|
|
2386
|
-
static async generateNarrativeAsync(section, resources, timezone, minify = true) {
|
|
2387
|
-
const content = await this.generateNarrativeContentAsync(section, resources, timezone);
|
|
2650
|
+
static async generateNarrativeAsync(section, resources, timezone, minify = true, useSectionSummary = false) {
|
|
2651
|
+
const content = await this.generateNarrativeContentAsync(section, resources, timezone, useSectionSummary);
|
|
2388
2652
|
if (!content) {
|
|
2389
2653
|
return void 0;
|
|
2390
2654
|
}
|
|
@@ -2429,11 +2693,37 @@ var ComprehensiveIPSCompositionBuilder = class {
|
|
|
2429
2693
|
}
|
|
2430
2694
|
/**
|
|
2431
2695
|
* Adds a section to the composition with async HTML minification
|
|
2696
|
+
* @param narrative - Narrative content for the section
|
|
2697
|
+
* @param sectionType - IPS section type
|
|
2698
|
+
* @param validResources - Array of domain resources
|
|
2699
|
+
*/
|
|
2700
|
+
addSectionAsync(narrative, sectionType, validResources) {
|
|
2701
|
+
const sectionEntry = {
|
|
2702
|
+
title: IPS_SECTION_DISPLAY_NAMES[sectionType] || sectionType,
|
|
2703
|
+
code: {
|
|
2704
|
+
coding: [{
|
|
2705
|
+
system: "http://loinc.org",
|
|
2706
|
+
code: IPS_SECTION_LOINC_CODES[sectionType],
|
|
2707
|
+
display: IPS_SECTION_DISPLAY_NAMES[sectionType] || sectionType
|
|
2708
|
+
}],
|
|
2709
|
+
text: IPS_SECTION_DISPLAY_NAMES[sectionType] || sectionType
|
|
2710
|
+
},
|
|
2711
|
+
text: narrative,
|
|
2712
|
+
entry: validResources.map((resource) => ({
|
|
2713
|
+
reference: `${resource.resourceType}/${resource.id}`,
|
|
2714
|
+
display: resource.resourceType
|
|
2715
|
+
}))
|
|
2716
|
+
};
|
|
2717
|
+
this.sections.push(sectionEntry);
|
|
2718
|
+
return this;
|
|
2719
|
+
}
|
|
2720
|
+
/**
|
|
2721
|
+
* Make and adds a section to the composition with async HTML minification
|
|
2432
2722
|
* @param sectionType - IPS section type
|
|
2433
2723
|
* @param validResources - Array of domain resources
|
|
2434
2724
|
* @param timezone - Optional timezone to use for date formatting
|
|
2435
2725
|
*/
|
|
2436
|
-
async
|
|
2726
|
+
async makeSectionAsync(sectionType, validResources, timezone) {
|
|
2437
2727
|
for (const resource of validResources) {
|
|
2438
2728
|
this.resources.add(resource);
|
|
2439
2729
|
}
|
|
@@ -2453,32 +2743,38 @@ var ComprehensiveIPSCompositionBuilder = class {
|
|
|
2453
2743
|
} else {
|
|
2454
2744
|
return this;
|
|
2455
2745
|
}
|
|
2456
|
-
|
|
2457
|
-
title: IPS_SECTION_DISPLAY_NAMES[sectionType] || sectionType,
|
|
2458
|
-
code: {
|
|
2459
|
-
coding: [{
|
|
2460
|
-
system: "http://loinc.org",
|
|
2461
|
-
code: IPS_SECTION_LOINC_CODES[sectionType],
|
|
2462
|
-
display: IPS_SECTION_DISPLAY_NAMES[sectionType] || sectionType
|
|
2463
|
-
}],
|
|
2464
|
-
text: IPS_SECTION_DISPLAY_NAMES[sectionType] || sectionType
|
|
2465
|
-
},
|
|
2466
|
-
text: narrative,
|
|
2467
|
-
entry: validResources.map((resource) => ({
|
|
2468
|
-
reference: `${resource.resourceType}/${resource.id}`,
|
|
2469
|
-
display: resource.resourceType
|
|
2470
|
-
}))
|
|
2471
|
-
};
|
|
2472
|
-
this.sections.push(sectionEntry);
|
|
2746
|
+
this.addSectionAsync(narrative, sectionType, validResources);
|
|
2473
2747
|
}
|
|
2474
2748
|
return this;
|
|
2475
2749
|
}
|
|
2750
|
+
async makeSectionFromSummaryAsync(sectionType, summaryCompositions, resources, timezone) {
|
|
2751
|
+
const sectionResources = [];
|
|
2752
|
+
for (const summaryComposition of summaryCompositions) {
|
|
2753
|
+
const resourceEntries = summaryComposition?.section?.flatMap((sec) => sec.entry || []) ?? [];
|
|
2754
|
+
resources.forEach((resource) => {
|
|
2755
|
+
if (resourceEntries?.some((entry) => entry.reference === `${resource.resourceType}/${resource.id}`)) {
|
|
2756
|
+
this.resources.add(resource);
|
|
2757
|
+
sectionResources.push(resource);
|
|
2758
|
+
}
|
|
2759
|
+
});
|
|
2760
|
+
}
|
|
2761
|
+
const narrative = await NarrativeGenerator.generateNarrativeAsync(
|
|
2762
|
+
sectionType,
|
|
2763
|
+
summaryCompositions,
|
|
2764
|
+
timezone,
|
|
2765
|
+
true,
|
|
2766
|
+
true
|
|
2767
|
+
);
|
|
2768
|
+
this.addSectionAsync(narrative, sectionType, sectionResources);
|
|
2769
|
+
return this;
|
|
2770
|
+
}
|
|
2476
2771
|
/**
|
|
2477
2772
|
* Reads a FHIR Bundle and extracts resources for each section defined in IPSSections.
|
|
2478
2773
|
* @param bundle - FHIR Bundle containing resources
|
|
2479
2774
|
* @param timezone - Optional timezone to use for date formatting
|
|
2775
|
+
* @param useSummaryCompositions - Whether to use summary compositions (default: false)
|
|
2480
2776
|
*/
|
|
2481
|
-
async readBundleAsync(bundle, timezone) {
|
|
2777
|
+
async readBundleAsync(bundle, timezone, useSummaryCompositions = false) {
|
|
2482
2778
|
if (!bundle.entry) {
|
|
2483
2779
|
return this;
|
|
2484
2780
|
}
|
|
@@ -2500,9 +2796,15 @@ var ComprehensiveIPSCompositionBuilder = class {
|
|
|
2500
2796
|
if (sectionType === "Patient" /* PATIENT */) {
|
|
2501
2797
|
continue;
|
|
2502
2798
|
}
|
|
2503
|
-
const
|
|
2504
|
-
const
|
|
2505
|
-
|
|
2799
|
+
const summaryCompositionFilter = useSummaryCompositions ? IPSSectionResourceHelper.getSummaryCompositionFilterForSection(sectionType) : void 0;
|
|
2800
|
+
const sectionSummary = summaryCompositionFilter ? resources.filter((resource) => summaryCompositionFilter(resource)) : [];
|
|
2801
|
+
if (sectionSummary.length > 0) {
|
|
2802
|
+
await this.makeSectionFromSummaryAsync(sectionType, sectionSummary, resources, timezone);
|
|
2803
|
+
} else {
|
|
2804
|
+
const sectionFilter = IPSSectionResourceHelper.getResourceFilterForSection(sectionType);
|
|
2805
|
+
const sectionResources = resources.filter((resource) => sectionFilter(resource));
|
|
2806
|
+
await this.makeSectionAsync(sectionType, sectionResources, timezone);
|
|
2807
|
+
}
|
|
2506
2808
|
}
|
|
2507
2809
|
return this;
|
|
2508
2810
|
}
|
package/dist/index.d.cts
CHANGED
|
@@ -630,6 +630,60 @@ type TBundle = {
|
|
|
630
630
|
signature?: TSignature;
|
|
631
631
|
};
|
|
632
632
|
|
|
633
|
+
type TCompositionAttester = {
|
|
634
|
+
id?: string;
|
|
635
|
+
extension?: TExtension[];
|
|
636
|
+
modifierExtension?: TExtension[];
|
|
637
|
+
mode: string;
|
|
638
|
+
time?: TDateTime;
|
|
639
|
+
party?: TReference;
|
|
640
|
+
};
|
|
641
|
+
|
|
642
|
+
type TCompositionRelatesTo = {
|
|
643
|
+
id?: string;
|
|
644
|
+
extension?: TExtension[];
|
|
645
|
+
modifierExtension?: TExtension[];
|
|
646
|
+
code: string;
|
|
647
|
+
targetIdentifier?: TIdentifier;
|
|
648
|
+
targetReference?: TReference;
|
|
649
|
+
};
|
|
650
|
+
|
|
651
|
+
type TCompositionEvent = {
|
|
652
|
+
id?: string;
|
|
653
|
+
extension?: TExtension[];
|
|
654
|
+
modifierExtension?: TExtension[];
|
|
655
|
+
code?: TCodeableConcept[];
|
|
656
|
+
period?: TPeriod;
|
|
657
|
+
detail?: TReference[];
|
|
658
|
+
};
|
|
659
|
+
|
|
660
|
+
type TComposition = {
|
|
661
|
+
resourceType?: string;
|
|
662
|
+
id?: string;
|
|
663
|
+
meta?: TMeta;
|
|
664
|
+
implicitRules?: TUri;
|
|
665
|
+
language?: string;
|
|
666
|
+
text?: TNarrative;
|
|
667
|
+
contained?: TResourceContainer[];
|
|
668
|
+
extension?: TExtension[];
|
|
669
|
+
modifierExtension?: TExtension[];
|
|
670
|
+
identifier?: TIdentifier;
|
|
671
|
+
status: string;
|
|
672
|
+
type: TCodeableConcept;
|
|
673
|
+
category?: TCodeableConcept[];
|
|
674
|
+
subject?: TReference;
|
|
675
|
+
encounter?: TReference;
|
|
676
|
+
date: TDateTime;
|
|
677
|
+
author: TReference[];
|
|
678
|
+
title: string;
|
|
679
|
+
confidentiality?: string;
|
|
680
|
+
attester?: TCompositionAttester[];
|
|
681
|
+
custodian?: TReference;
|
|
682
|
+
relatesTo?: TCompositionRelatesTo[];
|
|
683
|
+
event?: TCompositionEvent[];
|
|
684
|
+
section?: TCompositionSection[];
|
|
685
|
+
};
|
|
686
|
+
|
|
633
687
|
declare class ComprehensiveIPSCompositionBuilder {
|
|
634
688
|
private patients;
|
|
635
689
|
private sections;
|
|
@@ -642,17 +696,26 @@ declare class ComprehensiveIPSCompositionBuilder {
|
|
|
642
696
|
setPatient(patients: TPatient | TPatient[]): this;
|
|
643
697
|
/**
|
|
644
698
|
* Adds a section to the composition with async HTML minification
|
|
699
|
+
* @param narrative - Narrative content for the section
|
|
700
|
+
* @param sectionType - IPS section type
|
|
701
|
+
* @param validResources - Array of domain resources
|
|
702
|
+
*/
|
|
703
|
+
addSectionAsync<T extends TDomainResource>(narrative: TNarrative, sectionType: IPSSections, validResources: T[]): this;
|
|
704
|
+
/**
|
|
705
|
+
* Make and adds a section to the composition with async HTML minification
|
|
645
706
|
* @param sectionType - IPS section type
|
|
646
707
|
* @param validResources - Array of domain resources
|
|
647
708
|
* @param timezone - Optional timezone to use for date formatting
|
|
648
709
|
*/
|
|
649
|
-
|
|
710
|
+
makeSectionAsync<T extends TDomainResource>(sectionType: IPSSections, validResources: T[], timezone: string | undefined): Promise<this>;
|
|
711
|
+
makeSectionFromSummaryAsync(sectionType: IPSSections, summaryCompositions: TComposition[], resources: TDomainResource[], timezone: string | undefined): Promise<this>;
|
|
650
712
|
/**
|
|
651
713
|
* Reads a FHIR Bundle and extracts resources for each section defined in IPSSections.
|
|
652
714
|
* @param bundle - FHIR Bundle containing resources
|
|
653
715
|
* @param timezone - Optional timezone to use for date formatting
|
|
716
|
+
* @param useSummaryCompositions - Whether to use summary compositions (default: false)
|
|
654
717
|
*/
|
|
655
|
-
readBundleAsync(bundle: TBundle, timezone: string | undefined): Promise<this>;
|
|
718
|
+
readBundleAsync(bundle: TBundle, timezone: string | undefined, useSummaryCompositions?: boolean): Promise<this>;
|
|
656
719
|
/**
|
|
657
720
|
* Builds a complete FHIR Bundle containing the Composition and all resources.
|
|
658
721
|
* @param authorOrganizationId - ID of the authoring organization (e.g., hospital or clinic)
|
|
@@ -683,9 +746,10 @@ declare class NarrativeGenerator {
|
|
|
683
746
|
* @param section - IPS section type
|
|
684
747
|
* @param resources - Array of domain resources
|
|
685
748
|
* @param timezone - Optional timezone to use for date formatting (e.g., 'America/New_York', 'Europe/London')
|
|
749
|
+
* @param useSectionSummary - Whether to use section summary for narrative generation (default: false)
|
|
686
750
|
* @returns Generated HTML content or undefined if no resources
|
|
687
751
|
*/
|
|
688
|
-
static generateNarrativeContentAsync<T extends TDomainResource>(section: IPSSections, resources: T[], timezone: string | undefined): Promise<string | undefined>;
|
|
752
|
+
static generateNarrativeContentAsync<T extends TDomainResource>(section: IPSSections, resources: T[], timezone: string | undefined, useSectionSummary?: boolean): Promise<string | undefined>;
|
|
689
753
|
/**
|
|
690
754
|
* Minifies HTML content asynchronously using html-minifier-terser
|
|
691
755
|
* @param html - HTML content to minify
|
|
@@ -706,9 +770,10 @@ declare class NarrativeGenerator {
|
|
|
706
770
|
* @param resources - Array of domain resources
|
|
707
771
|
* @param timezone - Optional timezone to use for date formatting
|
|
708
772
|
* @param minify - Whether to minify the HTML content (default: true)
|
|
773
|
+
* @param useSectionSummary - Whether to use section summary for narrative generation (default: false)
|
|
709
774
|
* @returns Promise that resolves to a FHIR Narrative object or undefined if no resources
|
|
710
775
|
*/
|
|
711
|
-
static generateNarrativeAsync<T extends TDomainResource>(section: IPSSections, resources: T[], timezone: string | undefined, minify?: boolean): Promise<Narrative | undefined>;
|
|
776
|
+
static generateNarrativeAsync<T extends TDomainResource>(section: IPSSections, resources: T[], timezone: string | undefined, minify?: boolean, useSectionSummary?: boolean): Promise<Narrative | undefined>;
|
|
712
777
|
}
|
|
713
778
|
|
|
714
779
|
declare const myPackage: (taco?: string) => string;
|
package/dist/index.d.ts
CHANGED
|
@@ -630,6 +630,60 @@ type TBundle = {
|
|
|
630
630
|
signature?: TSignature;
|
|
631
631
|
};
|
|
632
632
|
|
|
633
|
+
type TCompositionAttester = {
|
|
634
|
+
id?: string;
|
|
635
|
+
extension?: TExtension[];
|
|
636
|
+
modifierExtension?: TExtension[];
|
|
637
|
+
mode: string;
|
|
638
|
+
time?: TDateTime;
|
|
639
|
+
party?: TReference;
|
|
640
|
+
};
|
|
641
|
+
|
|
642
|
+
type TCompositionRelatesTo = {
|
|
643
|
+
id?: string;
|
|
644
|
+
extension?: TExtension[];
|
|
645
|
+
modifierExtension?: TExtension[];
|
|
646
|
+
code: string;
|
|
647
|
+
targetIdentifier?: TIdentifier;
|
|
648
|
+
targetReference?: TReference;
|
|
649
|
+
};
|
|
650
|
+
|
|
651
|
+
type TCompositionEvent = {
|
|
652
|
+
id?: string;
|
|
653
|
+
extension?: TExtension[];
|
|
654
|
+
modifierExtension?: TExtension[];
|
|
655
|
+
code?: TCodeableConcept[];
|
|
656
|
+
period?: TPeriod;
|
|
657
|
+
detail?: TReference[];
|
|
658
|
+
};
|
|
659
|
+
|
|
660
|
+
type TComposition = {
|
|
661
|
+
resourceType?: string;
|
|
662
|
+
id?: string;
|
|
663
|
+
meta?: TMeta;
|
|
664
|
+
implicitRules?: TUri;
|
|
665
|
+
language?: string;
|
|
666
|
+
text?: TNarrative;
|
|
667
|
+
contained?: TResourceContainer[];
|
|
668
|
+
extension?: TExtension[];
|
|
669
|
+
modifierExtension?: TExtension[];
|
|
670
|
+
identifier?: TIdentifier;
|
|
671
|
+
status: string;
|
|
672
|
+
type: TCodeableConcept;
|
|
673
|
+
category?: TCodeableConcept[];
|
|
674
|
+
subject?: TReference;
|
|
675
|
+
encounter?: TReference;
|
|
676
|
+
date: TDateTime;
|
|
677
|
+
author: TReference[];
|
|
678
|
+
title: string;
|
|
679
|
+
confidentiality?: string;
|
|
680
|
+
attester?: TCompositionAttester[];
|
|
681
|
+
custodian?: TReference;
|
|
682
|
+
relatesTo?: TCompositionRelatesTo[];
|
|
683
|
+
event?: TCompositionEvent[];
|
|
684
|
+
section?: TCompositionSection[];
|
|
685
|
+
};
|
|
686
|
+
|
|
633
687
|
declare class ComprehensiveIPSCompositionBuilder {
|
|
634
688
|
private patients;
|
|
635
689
|
private sections;
|
|
@@ -642,17 +696,26 @@ declare class ComprehensiveIPSCompositionBuilder {
|
|
|
642
696
|
setPatient(patients: TPatient | TPatient[]): this;
|
|
643
697
|
/**
|
|
644
698
|
* Adds a section to the composition with async HTML minification
|
|
699
|
+
* @param narrative - Narrative content for the section
|
|
700
|
+
* @param sectionType - IPS section type
|
|
701
|
+
* @param validResources - Array of domain resources
|
|
702
|
+
*/
|
|
703
|
+
addSectionAsync<T extends TDomainResource>(narrative: TNarrative, sectionType: IPSSections, validResources: T[]): this;
|
|
704
|
+
/**
|
|
705
|
+
* Make and adds a section to the composition with async HTML minification
|
|
645
706
|
* @param sectionType - IPS section type
|
|
646
707
|
* @param validResources - Array of domain resources
|
|
647
708
|
* @param timezone - Optional timezone to use for date formatting
|
|
648
709
|
*/
|
|
649
|
-
|
|
710
|
+
makeSectionAsync<T extends TDomainResource>(sectionType: IPSSections, validResources: T[], timezone: string | undefined): Promise<this>;
|
|
711
|
+
makeSectionFromSummaryAsync(sectionType: IPSSections, summaryCompositions: TComposition[], resources: TDomainResource[], timezone: string | undefined): Promise<this>;
|
|
650
712
|
/**
|
|
651
713
|
* Reads a FHIR Bundle and extracts resources for each section defined in IPSSections.
|
|
652
714
|
* @param bundle - FHIR Bundle containing resources
|
|
653
715
|
* @param timezone - Optional timezone to use for date formatting
|
|
716
|
+
* @param useSummaryCompositions - Whether to use summary compositions (default: false)
|
|
654
717
|
*/
|
|
655
|
-
readBundleAsync(bundle: TBundle, timezone: string | undefined): Promise<this>;
|
|
718
|
+
readBundleAsync(bundle: TBundle, timezone: string | undefined, useSummaryCompositions?: boolean): Promise<this>;
|
|
656
719
|
/**
|
|
657
720
|
* Builds a complete FHIR Bundle containing the Composition and all resources.
|
|
658
721
|
* @param authorOrganizationId - ID of the authoring organization (e.g., hospital or clinic)
|
|
@@ -683,9 +746,10 @@ declare class NarrativeGenerator {
|
|
|
683
746
|
* @param section - IPS section type
|
|
684
747
|
* @param resources - Array of domain resources
|
|
685
748
|
* @param timezone - Optional timezone to use for date formatting (e.g., 'America/New_York', 'Europe/London')
|
|
749
|
+
* @param useSectionSummary - Whether to use section summary for narrative generation (default: false)
|
|
686
750
|
* @returns Generated HTML content or undefined if no resources
|
|
687
751
|
*/
|
|
688
|
-
static generateNarrativeContentAsync<T extends TDomainResource>(section: IPSSections, resources: T[], timezone: string | undefined): Promise<string | undefined>;
|
|
752
|
+
static generateNarrativeContentAsync<T extends TDomainResource>(section: IPSSections, resources: T[], timezone: string | undefined, useSectionSummary?: boolean): Promise<string | undefined>;
|
|
689
753
|
/**
|
|
690
754
|
* Minifies HTML content asynchronously using html-minifier-terser
|
|
691
755
|
* @param html - HTML content to minify
|
|
@@ -706,9 +770,10 @@ declare class NarrativeGenerator {
|
|
|
706
770
|
* @param resources - Array of domain resources
|
|
707
771
|
* @param timezone - Optional timezone to use for date formatting
|
|
708
772
|
* @param minify - Whether to minify the HTML content (default: true)
|
|
773
|
+
* @param useSectionSummary - Whether to use section summary for narrative generation (default: false)
|
|
709
774
|
* @returns Promise that resolves to a FHIR Narrative object or undefined if no resources
|
|
710
775
|
*/
|
|
711
|
-
static generateNarrativeAsync<T extends TDomainResource>(section: IPSSections, resources: T[], timezone: string | undefined, minify?: boolean): Promise<Narrative | undefined>;
|
|
776
|
+
static generateNarrativeAsync<T extends TDomainResource>(section: IPSSections, resources: T[], timezone: string | undefined, minify?: boolean, useSectionSummary?: boolean): Promise<Narrative | undefined>;
|
|
712
777
|
}
|
|
713
778
|
|
|
714
779
|
declare const myPackage: (taco?: string) => string;
|
package/dist/index.js
CHANGED
|
@@ -114,10 +114,17 @@ var IPSSectionResourceFilters = {
|
|
|
114
114
|
// Only include active advance directives (Consent resources)
|
|
115
115
|
["AdvanceDirectivesSection" /* ADVANCE_DIRECTIVES */]: (resource) => resource.resourceType === "Consent" && resource.status === "active"
|
|
116
116
|
};
|
|
117
|
+
var IPSSectionSummaryCompositionFilter = {
|
|
118
|
+
["AllergyIntoleranceSection" /* ALLERGIES */]: (resource) => resource.resourceType === "Composition" && resource.type?.coding?.some((c) => c.system === "https://fhir.icanbwell.com/4_0_0/CodeSystem/composition/" && c.code === "allergy_summary_document"),
|
|
119
|
+
["VitalSignsSection" /* VITAL_SIGNS */]: (resource) => resource.resourceType === "Composition" && resource.type?.coding?.some((c) => c.system === "https://fhir.icanbwell.com/4_0_0/CodeSystem/composition/" && c.code === "vital_summary_document")
|
|
120
|
+
};
|
|
117
121
|
var IPSSectionResourceHelper = class {
|
|
118
122
|
static getResourceFilterForSection(section) {
|
|
119
123
|
return IPSSectionResourceFilters[section];
|
|
120
124
|
}
|
|
125
|
+
static getSummaryCompositionFilterForSection(section) {
|
|
126
|
+
return IPSSectionSummaryCompositionFilter[section];
|
|
127
|
+
}
|
|
121
128
|
};
|
|
122
129
|
|
|
123
130
|
// src/narratives/templates/typescript/TemplateUtilities.ts
|
|
@@ -567,6 +574,137 @@ var TemplateUtilities = class {
|
|
|
567
574
|
}
|
|
568
575
|
return status;
|
|
569
576
|
}
|
|
577
|
+
extractObservationSummaryValue(data, timezone) {
|
|
578
|
+
if (data["valueQuantity.value"] !== void 0) {
|
|
579
|
+
const value = data["valueQuantity.value"];
|
|
580
|
+
const unit = data["valueQuantity.unit"];
|
|
581
|
+
return unit ? `${value} ${unit}` : `${value}`;
|
|
582
|
+
}
|
|
583
|
+
if (data["valueCodeableConcept.text"] !== void 0) {
|
|
584
|
+
return data["valueCodeableConcept.text"];
|
|
585
|
+
}
|
|
586
|
+
if (data["valueCodeableConcept.coding.display"] !== void 0) {
|
|
587
|
+
return data["valueCodeableConcept.coding.display"];
|
|
588
|
+
}
|
|
589
|
+
if (data["valueString"] !== void 0) {
|
|
590
|
+
return data["valueString"];
|
|
591
|
+
}
|
|
592
|
+
if (data["valueBoolean"] !== void 0) {
|
|
593
|
+
return String(data["valueBoolean"]);
|
|
594
|
+
}
|
|
595
|
+
if (data["valueInteger"] !== void 0) {
|
|
596
|
+
return String(data["valueInteger"]);
|
|
597
|
+
}
|
|
598
|
+
if (data["valueDateTime"] !== void 0) {
|
|
599
|
+
return this.renderTime(data["valueDateTime"], timezone);
|
|
600
|
+
}
|
|
601
|
+
if (data["valuePeriod.start"] !== void 0 || data["valuePeriod.end"] !== void 0) {
|
|
602
|
+
const start = this.renderTime(data["valuePeriod.start"], timezone);
|
|
603
|
+
const end = this.renderTime(data["valuePeriod.end"], timezone);
|
|
604
|
+
if (start && end) {
|
|
605
|
+
return `${start} - ${end}`;
|
|
606
|
+
} else if (start) {
|
|
607
|
+
return `${start}`;
|
|
608
|
+
} else if (end) {
|
|
609
|
+
return `${end}`;
|
|
610
|
+
}
|
|
611
|
+
}
|
|
612
|
+
if (data["valueTime"] !== void 0) {
|
|
613
|
+
return this.renderTime(data["valueTime"], timezone);
|
|
614
|
+
}
|
|
615
|
+
if (data["valueSampledData.origin.value"] !== void 0 || data["valueSampledData.origin.unit"] !== void 0) {
|
|
616
|
+
const originValue = data["valueSampledData.origin.value"];
|
|
617
|
+
const originUnit = data["valueSampledData.origin.unit"];
|
|
618
|
+
let result = "";
|
|
619
|
+
if (originValue !== void 0 && originUnit !== void 0) {
|
|
620
|
+
result = `${originValue} ${originUnit}`;
|
|
621
|
+
} else if (originValue !== void 0) {
|
|
622
|
+
result = `${originValue}`;
|
|
623
|
+
} else if (originUnit !== void 0) {
|
|
624
|
+
result = `${originUnit}`;
|
|
625
|
+
}
|
|
626
|
+
const period = data["valueSampledData.period"];
|
|
627
|
+
const factor = data["valueSampledData.factor"];
|
|
628
|
+
const lowerLimit = data["valueSampledData.lowerLimit"];
|
|
629
|
+
const upperLimit = data["valueSampledData.upperLimit"];
|
|
630
|
+
const sampledData = data["valueSampledData.data"];
|
|
631
|
+
const extras = [];
|
|
632
|
+
if (period !== void 0) extras.push(`period: ${period}`);
|
|
633
|
+
if (factor !== void 0) extras.push(`factor: ${factor}`);
|
|
634
|
+
if (lowerLimit !== void 0) extras.push(`lowerLimit: ${lowerLimit}`);
|
|
635
|
+
if (upperLimit !== void 0) extras.push(`upperLimit: ${upperLimit}`);
|
|
636
|
+
if (sampledData !== void 0) extras.push(`data: ${sampledData}`);
|
|
637
|
+
if (extras.length > 0) {
|
|
638
|
+
result += ` (${extras.join(", ")})`;
|
|
639
|
+
}
|
|
640
|
+
return result;
|
|
641
|
+
}
|
|
642
|
+
if (data["valueRange.low.value"] !== void 0 || data["valueRange.high.value"] !== void 0) {
|
|
643
|
+
let referenceRange = "";
|
|
644
|
+
if (data["valueRange.low.value"] !== void 0) {
|
|
645
|
+
referenceRange += `${data["valueRange.low.value"]}`;
|
|
646
|
+
if (data["valueRange.low.unit"] !== void 0) {
|
|
647
|
+
referenceRange += ` ${data["valueRange.low.unit"]}`;
|
|
648
|
+
}
|
|
649
|
+
referenceRange = referenceRange.trim();
|
|
650
|
+
if (data["valueRange.high.value"] !== void 0) {
|
|
651
|
+
referenceRange += " - ";
|
|
652
|
+
}
|
|
653
|
+
}
|
|
654
|
+
if (data["valueRange.high.value"] !== void 0) {
|
|
655
|
+
referenceRange += `${data["valueRange.high.value"]}`;
|
|
656
|
+
if (data["valueRange.high.unit"] !== void 0) {
|
|
657
|
+
referenceRange += ` ${data["valueRange.high.unit"]}`;
|
|
658
|
+
}
|
|
659
|
+
}
|
|
660
|
+
return referenceRange.trim();
|
|
661
|
+
}
|
|
662
|
+
if (data["valueRatio.numerator.value"] !== void 0 || data["valueRatio.denominator.value"] !== void 0) {
|
|
663
|
+
let ratio = "";
|
|
664
|
+
if (data["valueRatio.numerator.value"] !== void 0) {
|
|
665
|
+
ratio += `${data["valueRatio.numerator.value"]}`;
|
|
666
|
+
if (data["valueRatio.numerator.unit"] !== void 0) {
|
|
667
|
+
ratio += ` ${data["valueRatio.numerator.unit"]}`;
|
|
668
|
+
}
|
|
669
|
+
}
|
|
670
|
+
if (data["valueRatio.denominator.value"] !== void 0) {
|
|
671
|
+
ratio += " / ";
|
|
672
|
+
ratio += `${data["valueRatio.denominator.value"]}`;
|
|
673
|
+
if (data["valueRatio.denominator.unit"] !== void 0) {
|
|
674
|
+
ratio += ` ${data["valueRatio.denominator.unit"]}`;
|
|
675
|
+
}
|
|
676
|
+
}
|
|
677
|
+
return ratio.trim();
|
|
678
|
+
}
|
|
679
|
+
return "";
|
|
680
|
+
}
|
|
681
|
+
extractObservationSummaryReferenceRange(data) {
|
|
682
|
+
let referenceRange = "";
|
|
683
|
+
if (data["referenceRange.low.value"]) {
|
|
684
|
+
referenceRange += `${data["referenceRange.low.value"]} ${data["referenceRange.low.unit"]}`;
|
|
685
|
+
referenceRange.trim();
|
|
686
|
+
if (data["referenceRange.high.value"]) {
|
|
687
|
+
referenceRange += " - ";
|
|
688
|
+
}
|
|
689
|
+
}
|
|
690
|
+
if (data["referenceRange.high.value"]) {
|
|
691
|
+
referenceRange += `${data["referenceRange.high.value"]} ${data["referenceRange.high.unit"]}`;
|
|
692
|
+
}
|
|
693
|
+
return referenceRange.trim();
|
|
694
|
+
}
|
|
695
|
+
extractObservationSummaryEffectiveTime(data, timezone) {
|
|
696
|
+
if (data["effectiveDateTime"]) {
|
|
697
|
+
return this.renderTime(data["effectiveDateTime"], timezone);
|
|
698
|
+
}
|
|
699
|
+
let effectiveTimePeriod = "";
|
|
700
|
+
if (data["effectivePeriod.start"]) {
|
|
701
|
+
effectiveTimePeriod += this.renderTime(data["effectivePeriod.start"], timezone);
|
|
702
|
+
}
|
|
703
|
+
if (data["effectivePeriod.end"]) {
|
|
704
|
+
effectiveTimePeriod += ` - ${this.renderTime(data["effectivePeriod.end"], timezone)}`;
|
|
705
|
+
}
|
|
706
|
+
return effectiveTimePeriod.trim();
|
|
707
|
+
}
|
|
570
708
|
formatQuantityValue(quantity) {
|
|
571
709
|
if (!quantity) return "";
|
|
572
710
|
const parts = [];
|
|
@@ -1066,6 +1204,57 @@ var AllergyIntoleranceTemplate = class _AllergyIntoleranceTemplate {
|
|
|
1066
1204
|
generateNarrative(resources, timezone) {
|
|
1067
1205
|
return _AllergyIntoleranceTemplate.generateStaticNarrative(resources, timezone);
|
|
1068
1206
|
}
|
|
1207
|
+
/**
|
|
1208
|
+
* Generate HTML narrative for AllergyIntolerance resources using summary
|
|
1209
|
+
* @param resources - FHIR Composition resources
|
|
1210
|
+
* @param timezone - Optional timezone to use for date formatting (e.g., 'America/New_York', 'Europe/London')
|
|
1211
|
+
* @returns HTML string for rendering
|
|
1212
|
+
*/
|
|
1213
|
+
generateSummaryNarrative(resources, timezone) {
|
|
1214
|
+
const templateUtilities = new TemplateUtilities(resources);
|
|
1215
|
+
let html = `
|
|
1216
|
+
<div>
|
|
1217
|
+
<table>
|
|
1218
|
+
<thead>
|
|
1219
|
+
<tr>
|
|
1220
|
+
<th>Allergen</th>
|
|
1221
|
+
<th>Criticality</th>
|
|
1222
|
+
<th>Recorded Date</th>
|
|
1223
|
+
</tr>
|
|
1224
|
+
</thead>
|
|
1225
|
+
<tbody>`;
|
|
1226
|
+
for (const resourceItem of resources) {
|
|
1227
|
+
for (const rowData of resourceItem.section ?? []) {
|
|
1228
|
+
const data = {};
|
|
1229
|
+
for (const columnData of rowData.section ?? []) {
|
|
1230
|
+
switch (columnData.title) {
|
|
1231
|
+
case "Allergen Name":
|
|
1232
|
+
data["allergen"] = columnData.text?.div ?? "";
|
|
1233
|
+
break;
|
|
1234
|
+
case "Criticality":
|
|
1235
|
+
data["criticality"] = columnData.text?.div ?? "";
|
|
1236
|
+
break;
|
|
1237
|
+
case "Recorded Date":
|
|
1238
|
+
data["recordedDate"] = columnData.text?.div ?? "";
|
|
1239
|
+
break;
|
|
1240
|
+
default:
|
|
1241
|
+
break;
|
|
1242
|
+
}
|
|
1243
|
+
}
|
|
1244
|
+
html += `
|
|
1245
|
+
<tr>
|
|
1246
|
+
<td>${data["allergen"] ?? "-"}</td>
|
|
1247
|
+
<td>${data["criticality"] ?? "-"}</td>
|
|
1248
|
+
<td>${templateUtilities.renderTime(data["recordedDate"], timezone) ?? "-"}</td>
|
|
1249
|
+
</tr>`;
|
|
1250
|
+
}
|
|
1251
|
+
}
|
|
1252
|
+
html += `
|
|
1253
|
+
</tbody>
|
|
1254
|
+
</table>
|
|
1255
|
+
</div>`;
|
|
1256
|
+
return html;
|
|
1257
|
+
}
|
|
1069
1258
|
/**
|
|
1070
1259
|
* Internal static implementation that actually generates the narrative
|
|
1071
1260
|
* @param resources - FHIR resources array containing AllergyIntolerance resources
|
|
@@ -1558,6 +1747,13 @@ var ProblemListTemplate = class _ProblemListTemplate {
|
|
|
1558
1747
|
}
|
|
1559
1748
|
};
|
|
1560
1749
|
|
|
1750
|
+
// src/structures/ips_section_constants.ts
|
|
1751
|
+
var VITAL_SIGNS_SUMMARY_COMPONENT_MAP = {
|
|
1752
|
+
"Systolic Blood Pressure": "valueRatio.numerator.value",
|
|
1753
|
+
"Diastolic Blood Pressure": "valueRatio.denominator.value",
|
|
1754
|
+
"Default": "valueString"
|
|
1755
|
+
};
|
|
1756
|
+
|
|
1561
1757
|
// src/narratives/templates/typescript/VitalSignsTemplate.ts
|
|
1562
1758
|
var VitalSignsTemplate = class _VitalSignsTemplate {
|
|
1563
1759
|
/**
|
|
@@ -1569,6 +1765,68 @@ var VitalSignsTemplate = class _VitalSignsTemplate {
|
|
|
1569
1765
|
generateNarrative(resources, timezone) {
|
|
1570
1766
|
return _VitalSignsTemplate.generateStaticNarrative(resources, timezone);
|
|
1571
1767
|
}
|
|
1768
|
+
/**
|
|
1769
|
+
* Generate HTML narrative for vital signs using summary
|
|
1770
|
+
* @param resources - FHIR Composition resources
|
|
1771
|
+
* @param timezone - Optional timezone to use for date formatting (e.g., 'America/New_York', 'Europe/London')
|
|
1772
|
+
* @returns HTML string for rendering
|
|
1773
|
+
*/
|
|
1774
|
+
generateSummaryNarrative(resources, timezone) {
|
|
1775
|
+
const templateUtilities = new TemplateUtilities(resources);
|
|
1776
|
+
let html = `
|
|
1777
|
+
<div>
|
|
1778
|
+
<table>
|
|
1779
|
+
<thead>
|
|
1780
|
+
<tr>
|
|
1781
|
+
<th>Vital Name</th>
|
|
1782
|
+
<th>Result</th>
|
|
1783
|
+
<th>Reference Range</th>
|
|
1784
|
+
<th>Date</th>
|
|
1785
|
+
</tr>
|
|
1786
|
+
</thead>
|
|
1787
|
+
<tbody>`;
|
|
1788
|
+
for (const resourceItem of resources) {
|
|
1789
|
+
for (const rowData of resourceItem.section ?? []) {
|
|
1790
|
+
const data = {};
|
|
1791
|
+
for (const columnData of rowData.section ?? []) {
|
|
1792
|
+
const columnTitle = columnData.title;
|
|
1793
|
+
if (columnTitle) {
|
|
1794
|
+
if (Object.keys(VITAL_SIGNS_SUMMARY_COMPONENT_MAP).includes(
|
|
1795
|
+
columnTitle
|
|
1796
|
+
)) {
|
|
1797
|
+
const vitalData = {};
|
|
1798
|
+
for (const component of columnData.section?.[0]?.section ?? []) {
|
|
1799
|
+
if (component.title) {
|
|
1800
|
+
vitalData[component.title] = component.text?.div ?? "";
|
|
1801
|
+
}
|
|
1802
|
+
}
|
|
1803
|
+
const vitalValue = templateUtilities.extractObservationSummaryValue(
|
|
1804
|
+
vitalData,
|
|
1805
|
+
timezone
|
|
1806
|
+
);
|
|
1807
|
+
if (vitalValue) {
|
|
1808
|
+
const dataKey = VITAL_SIGNS_SUMMARY_COMPONENT_MAP[columnTitle] ?? VITAL_SIGNS_SUMMARY_COMPONENT_MAP["Default"];
|
|
1809
|
+
data[dataKey] = vitalValue;
|
|
1810
|
+
}
|
|
1811
|
+
}
|
|
1812
|
+
data[columnTitle] = columnData.text?.div ?? "";
|
|
1813
|
+
}
|
|
1814
|
+
}
|
|
1815
|
+
html += `
|
|
1816
|
+
<tr>
|
|
1817
|
+
<td>${data["Vital Name"] ?? "-"}</td>
|
|
1818
|
+
<td>${templateUtilities.extractObservationSummaryValue(data, timezone) ?? "-"}</td>
|
|
1819
|
+
<td>${templateUtilities.extractObservationSummaryReferenceRange(data) ?? "-"}</td>
|
|
1820
|
+
<td>${templateUtilities.extractObservationSummaryEffectiveTime(data, timezone) ?? "-"}</td>
|
|
1821
|
+
</tr>`;
|
|
1822
|
+
}
|
|
1823
|
+
}
|
|
1824
|
+
html += `
|
|
1825
|
+
</tbody>
|
|
1826
|
+
</table>
|
|
1827
|
+
</div>`;
|
|
1828
|
+
return html;
|
|
1829
|
+
}
|
|
1572
1830
|
/**
|
|
1573
1831
|
* Internal static implementation that actually generates the narrative
|
|
1574
1832
|
* @param resources - FHIR Observation resources
|
|
@@ -1587,7 +1845,7 @@ var VitalSignsTemplate = class _VitalSignsTemplate {
|
|
|
1587
1845
|
<table>
|
|
1588
1846
|
<thead>
|
|
1589
1847
|
<tr>
|
|
1590
|
-
<th>
|
|
1848
|
+
<th>Vital Name</th>
|
|
1591
1849
|
<th>Result</th>
|
|
1592
1850
|
<th>Unit</th>
|
|
1593
1851
|
<th>Interpretation</th>
|
|
@@ -2232,14 +2490,18 @@ var TypeScriptTemplateMapper = class {
|
|
|
2232
2490
|
* @param section - The IPS section
|
|
2233
2491
|
* @param resources - FHIR resources
|
|
2234
2492
|
* @param timezone - Optional timezone to use for date formatting (e.g., 'America/New_York', 'Europe/London')
|
|
2493
|
+
* @param useSectionSummary - Whether to use the section summary for narrative generation
|
|
2235
2494
|
* @returns HTML string for rendering
|
|
2236
2495
|
*/
|
|
2237
|
-
static generateNarrative(section, resources, timezone) {
|
|
2496
|
+
static generateNarrative(section, resources, timezone, useSectionSummary = false) {
|
|
2238
2497
|
const templateClass = this.sectionToTemplate[section];
|
|
2239
2498
|
if (!templateClass) {
|
|
2240
2499
|
throw new Error(`No template found for section: ${section}`);
|
|
2241
2500
|
}
|
|
2242
|
-
return templateClass.
|
|
2501
|
+
return useSectionSummary ? templateClass.generateSummaryNarrative(
|
|
2502
|
+
resources,
|
|
2503
|
+
timezone
|
|
2504
|
+
) : templateClass.generateNarrative(resources, timezone);
|
|
2243
2505
|
}
|
|
2244
2506
|
};
|
|
2245
2507
|
// Map of section types to their template classes
|
|
@@ -2295,14 +2557,15 @@ var NarrativeGenerator = class {
|
|
|
2295
2557
|
* @param section - IPS section type
|
|
2296
2558
|
* @param resources - Array of domain resources
|
|
2297
2559
|
* @param timezone - Optional timezone to use for date formatting (e.g., 'America/New_York', 'Europe/London')
|
|
2560
|
+
* @param useSectionSummary - Whether to use section summary for narrative generation (default: false)
|
|
2298
2561
|
* @returns Generated HTML content or undefined if no resources
|
|
2299
2562
|
*/
|
|
2300
|
-
static async generateNarrativeContentAsync(section, resources, timezone) {
|
|
2563
|
+
static async generateNarrativeContentAsync(section, resources, timezone, useSectionSummary = false) {
|
|
2301
2564
|
if (!resources || resources.length === 0) {
|
|
2302
2565
|
return void 0;
|
|
2303
2566
|
}
|
|
2304
2567
|
try {
|
|
2305
|
-
const content = TypeScriptTemplateMapper.generateNarrative(section, resources, timezone);
|
|
2568
|
+
const content = TypeScriptTemplateMapper.generateNarrative(section, resources, timezone, useSectionSummary);
|
|
2306
2569
|
if (!content) {
|
|
2307
2570
|
return void 0;
|
|
2308
2571
|
}
|
|
@@ -2353,10 +2616,11 @@ var NarrativeGenerator = class {
|
|
|
2353
2616
|
* @param resources - Array of domain resources
|
|
2354
2617
|
* @param timezone - Optional timezone to use for date formatting
|
|
2355
2618
|
* @param minify - Whether to minify the HTML content (default: true)
|
|
2619
|
+
* @param useSectionSummary - Whether to use section summary for narrative generation (default: false)
|
|
2356
2620
|
* @returns Promise that resolves to a FHIR Narrative object or undefined if no resources
|
|
2357
2621
|
*/
|
|
2358
|
-
static async generateNarrativeAsync(section, resources, timezone, minify = true) {
|
|
2359
|
-
const content = await this.generateNarrativeContentAsync(section, resources, timezone);
|
|
2622
|
+
static async generateNarrativeAsync(section, resources, timezone, minify = true, useSectionSummary = false) {
|
|
2623
|
+
const content = await this.generateNarrativeContentAsync(section, resources, timezone, useSectionSummary);
|
|
2360
2624
|
if (!content) {
|
|
2361
2625
|
return void 0;
|
|
2362
2626
|
}
|
|
@@ -2401,11 +2665,37 @@ var ComprehensiveIPSCompositionBuilder = class {
|
|
|
2401
2665
|
}
|
|
2402
2666
|
/**
|
|
2403
2667
|
* Adds a section to the composition with async HTML minification
|
|
2668
|
+
* @param narrative - Narrative content for the section
|
|
2669
|
+
* @param sectionType - IPS section type
|
|
2670
|
+
* @param validResources - Array of domain resources
|
|
2671
|
+
*/
|
|
2672
|
+
addSectionAsync(narrative, sectionType, validResources) {
|
|
2673
|
+
const sectionEntry = {
|
|
2674
|
+
title: IPS_SECTION_DISPLAY_NAMES[sectionType] || sectionType,
|
|
2675
|
+
code: {
|
|
2676
|
+
coding: [{
|
|
2677
|
+
system: "http://loinc.org",
|
|
2678
|
+
code: IPS_SECTION_LOINC_CODES[sectionType],
|
|
2679
|
+
display: IPS_SECTION_DISPLAY_NAMES[sectionType] || sectionType
|
|
2680
|
+
}],
|
|
2681
|
+
text: IPS_SECTION_DISPLAY_NAMES[sectionType] || sectionType
|
|
2682
|
+
},
|
|
2683
|
+
text: narrative,
|
|
2684
|
+
entry: validResources.map((resource) => ({
|
|
2685
|
+
reference: `${resource.resourceType}/${resource.id}`,
|
|
2686
|
+
display: resource.resourceType
|
|
2687
|
+
}))
|
|
2688
|
+
};
|
|
2689
|
+
this.sections.push(sectionEntry);
|
|
2690
|
+
return this;
|
|
2691
|
+
}
|
|
2692
|
+
/**
|
|
2693
|
+
* Make and adds a section to the composition with async HTML minification
|
|
2404
2694
|
* @param sectionType - IPS section type
|
|
2405
2695
|
* @param validResources - Array of domain resources
|
|
2406
2696
|
* @param timezone - Optional timezone to use for date formatting
|
|
2407
2697
|
*/
|
|
2408
|
-
async
|
|
2698
|
+
async makeSectionAsync(sectionType, validResources, timezone) {
|
|
2409
2699
|
for (const resource of validResources) {
|
|
2410
2700
|
this.resources.add(resource);
|
|
2411
2701
|
}
|
|
@@ -2425,32 +2715,38 @@ var ComprehensiveIPSCompositionBuilder = class {
|
|
|
2425
2715
|
} else {
|
|
2426
2716
|
return this;
|
|
2427
2717
|
}
|
|
2428
|
-
|
|
2429
|
-
title: IPS_SECTION_DISPLAY_NAMES[sectionType] || sectionType,
|
|
2430
|
-
code: {
|
|
2431
|
-
coding: [{
|
|
2432
|
-
system: "http://loinc.org",
|
|
2433
|
-
code: IPS_SECTION_LOINC_CODES[sectionType],
|
|
2434
|
-
display: IPS_SECTION_DISPLAY_NAMES[sectionType] || sectionType
|
|
2435
|
-
}],
|
|
2436
|
-
text: IPS_SECTION_DISPLAY_NAMES[sectionType] || sectionType
|
|
2437
|
-
},
|
|
2438
|
-
text: narrative,
|
|
2439
|
-
entry: validResources.map((resource) => ({
|
|
2440
|
-
reference: `${resource.resourceType}/${resource.id}`,
|
|
2441
|
-
display: resource.resourceType
|
|
2442
|
-
}))
|
|
2443
|
-
};
|
|
2444
|
-
this.sections.push(sectionEntry);
|
|
2718
|
+
this.addSectionAsync(narrative, sectionType, validResources);
|
|
2445
2719
|
}
|
|
2446
2720
|
return this;
|
|
2447
2721
|
}
|
|
2722
|
+
async makeSectionFromSummaryAsync(sectionType, summaryCompositions, resources, timezone) {
|
|
2723
|
+
const sectionResources = [];
|
|
2724
|
+
for (const summaryComposition of summaryCompositions) {
|
|
2725
|
+
const resourceEntries = summaryComposition?.section?.flatMap((sec) => sec.entry || []) ?? [];
|
|
2726
|
+
resources.forEach((resource) => {
|
|
2727
|
+
if (resourceEntries?.some((entry) => entry.reference === `${resource.resourceType}/${resource.id}`)) {
|
|
2728
|
+
this.resources.add(resource);
|
|
2729
|
+
sectionResources.push(resource);
|
|
2730
|
+
}
|
|
2731
|
+
});
|
|
2732
|
+
}
|
|
2733
|
+
const narrative = await NarrativeGenerator.generateNarrativeAsync(
|
|
2734
|
+
sectionType,
|
|
2735
|
+
summaryCompositions,
|
|
2736
|
+
timezone,
|
|
2737
|
+
true,
|
|
2738
|
+
true
|
|
2739
|
+
);
|
|
2740
|
+
this.addSectionAsync(narrative, sectionType, sectionResources);
|
|
2741
|
+
return this;
|
|
2742
|
+
}
|
|
2448
2743
|
/**
|
|
2449
2744
|
* Reads a FHIR Bundle and extracts resources for each section defined in IPSSections.
|
|
2450
2745
|
* @param bundle - FHIR Bundle containing resources
|
|
2451
2746
|
* @param timezone - Optional timezone to use for date formatting
|
|
2747
|
+
* @param useSummaryCompositions - Whether to use summary compositions (default: false)
|
|
2452
2748
|
*/
|
|
2453
|
-
async readBundleAsync(bundle, timezone) {
|
|
2749
|
+
async readBundleAsync(bundle, timezone, useSummaryCompositions = false) {
|
|
2454
2750
|
if (!bundle.entry) {
|
|
2455
2751
|
return this;
|
|
2456
2752
|
}
|
|
@@ -2472,9 +2768,15 @@ var ComprehensiveIPSCompositionBuilder = class {
|
|
|
2472
2768
|
if (sectionType === "Patient" /* PATIENT */) {
|
|
2473
2769
|
continue;
|
|
2474
2770
|
}
|
|
2475
|
-
const
|
|
2476
|
-
const
|
|
2477
|
-
|
|
2771
|
+
const summaryCompositionFilter = useSummaryCompositions ? IPSSectionResourceHelper.getSummaryCompositionFilterForSection(sectionType) : void 0;
|
|
2772
|
+
const sectionSummary = summaryCompositionFilter ? resources.filter((resource) => summaryCompositionFilter(resource)) : [];
|
|
2773
|
+
if (sectionSummary.length > 0) {
|
|
2774
|
+
await this.makeSectionFromSummaryAsync(sectionType, sectionSummary, resources, timezone);
|
|
2775
|
+
} else {
|
|
2776
|
+
const sectionFilter = IPSSectionResourceHelper.getResourceFilterForSection(sectionType);
|
|
2777
|
+
const sectionResources = resources.filter((resource) => sectionFilter(resource));
|
|
2778
|
+
await this.makeSectionAsync(sectionType, sectionResources, timezone);
|
|
2779
|
+
}
|
|
2478
2780
|
}
|
|
2479
2781
|
return this;
|
|
2480
2782
|
}
|