@imranq2/fhirpatientsummary 1.0.39 → 1.0.41
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/dist/index.cjs +229 -51
- package/dist/index.d.cts +12 -3
- package/dist/index.d.ts +12 -3
- package/dist/index.js +229 -51
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -229,6 +229,23 @@ var RESULT_SUMMARY_OBSERVATION_DATE_FILTER = 2 * 365 * 24 * 60 * 60 * 1e3;
|
|
|
229
229
|
var IPS_SUMMARY_COMPOSITION_TYPE_SYSTEM = "https://fhir.icanbwell.com/4_0_0/CodeSystem/composition/";
|
|
230
230
|
|
|
231
231
|
// src/structures/ips_section_resource_map.ts
|
|
232
|
+
var IPSSectionResourcesMap = {
|
|
233
|
+
["Patient" /* PATIENT */]: ["Patient"],
|
|
234
|
+
["AllergyIntoleranceSection" /* ALLERGIES */]: ["AllergyIntolerance"],
|
|
235
|
+
["MedicationSummarySection" /* MEDICATIONS */]: ["MedicationRequest", "MedicationStatement", "Medication"],
|
|
236
|
+
["ProblemSection" /* PROBLEMS */]: ["Condition"],
|
|
237
|
+
["ImmunizationSection" /* IMMUNIZATIONS */]: ["Immunization", "Organization"],
|
|
238
|
+
["VitalSignsSection" /* VITAL_SIGNS */]: ["Observation"],
|
|
239
|
+
["MedicalDeviceSection" /* MEDICAL_DEVICES */]: ["DeviceUseStatement", "Device"],
|
|
240
|
+
["ResultsSection" /* DIAGNOSTIC_REPORTS */]: ["DiagnosticReport", "Observation"],
|
|
241
|
+
["HistoryOfProceduresSection" /* PROCEDURES */]: ["Procedure"],
|
|
242
|
+
["SocialHistorySection" /* SOCIAL_HISTORY */]: ["Observation"],
|
|
243
|
+
["HistoryOfPregnancySection" /* PREGNANCY_HISTORY */]: ["Observation", "Patient"],
|
|
244
|
+
["FunctionalStatusSection" /* FUNCTIONAL_STATUS */]: ["Condition", "ClinicalImpression"],
|
|
245
|
+
["HistoryOfPastIllnessSection" /* MEDICAL_HISTORY */]: ["Condition"],
|
|
246
|
+
["PlanOfCareSection" /* CARE_PLAN */]: ["CarePlan"],
|
|
247
|
+
["AdvanceDirectivesSection" /* ADVANCE_DIRECTIVES */]: ["Consent"]
|
|
248
|
+
};
|
|
232
249
|
var IPSSectionResourceFilters = {
|
|
233
250
|
// Patient section: only Patient resource
|
|
234
251
|
["Patient" /* PATIENT */]: (resource) => resource.resourceType === "Patient",
|
|
@@ -251,7 +268,7 @@ var IPSSectionResourceFilters = {
|
|
|
251
268
|
// Only include social history Observations
|
|
252
269
|
["SocialHistorySection" /* SOCIAL_HISTORY */]: (resource) => resource.resourceType === "Observation" && codeableConceptMatches(resource.code, Object.keys(SOCIAL_HISTORY_LOINC_CODES), "http://loinc.org"),
|
|
253
270
|
// Only include pregnancy history Observations or relevant Conditions
|
|
254
|
-
["HistoryOfPregnancySection" /* PREGNANCY_HISTORY */]: (resource) => resource.resourceType === "Observation" && (codeableConceptMatches(resource.code, Object.keys(PREGNANCY_LOINC_CODES.PREGNANCY_STATUS), "http://loinc.org") || codeableConceptMatches(resource.valueCodeableConcept, Object.keys(PREGNANCY_LOINC_CODES.PREGNANCY_OUTCOME), "http://loinc.org") || codingMatches(resource.code?.coding?.[0], PREGNANCY_SNOMED_CODES, "http://snomed.info/sct") || codingMatches(resource.valueCodeableConcept?.coding?.[0], PREGNANCY_SNOMED_CODES, "http://snomed.info/sct")) || resource.resourceType === "
|
|
271
|
+
["HistoryOfPregnancySection" /* PREGNANCY_HISTORY */]: (resource) => resource.resourceType === "Observation" && (codeableConceptMatches(resource.code, Object.keys(PREGNANCY_LOINC_CODES.PREGNANCY_STATUS), "http://loinc.org") || codeableConceptMatches(resource.valueCodeableConcept, Object.keys(PREGNANCY_LOINC_CODES.PREGNANCY_OUTCOME), "http://loinc.org") || codingMatches(resource.code?.coding?.[0], PREGNANCY_SNOMED_CODES, "http://snomed.info/sct") || codingMatches(resource.valueCodeableConcept?.coding?.[0], PREGNANCY_SNOMED_CODES, "http://snomed.info/sct")) || resource.resourceType === "Patient" && resource.gender !== "male",
|
|
255
272
|
// Only include Condition with Functional Status LOINC and SNOMED codes, category code 'problem-list-item', and completed ClinicalImpressions
|
|
256
273
|
["FunctionalStatusSection" /* FUNCTIONAL_STATUS */]: (resource) => resource.resourceType === "Condition" && ((codeableConceptMatches(resource.code, Object.keys(FUNCTIONAL_STATUS_ASSESSMENT_LOINC_CODES), "http://loinc.org") || codeableConceptMatches(resource.code, Object.keys(FUNCTIONAL_STATUS_SNOMED_CODES), "http://snomed.info/sct")) && resource.clinicalStatus?.coding?.some((c) => c.code === "active") && resource.category?.some(
|
|
257
274
|
(cat) => cat.coding?.some((c) => c.code === "problem-list-item")
|
|
@@ -280,7 +297,9 @@ var IPSSectionSummaryIPSCompositionFilter = {
|
|
|
280
297
|
["AdvanceDirectivesSection" /* ADVANCE_DIRECTIVES */]: (resource) => resource.resourceType === "Composition" && resource.type?.coding?.some((c) => codingMatches(c, "ips_advanced_directives_summary_document", IPS_SUMMARY_COMPOSITION_TYPE_SYSTEM)),
|
|
281
298
|
["SocialHistorySection" /* SOCIAL_HISTORY */]: (resource) => resource.resourceType === "Composition" && resource.type?.coding?.some((c) => codingMatches(c, "ips_social_history_summary_document", IPS_SUMMARY_COMPOSITION_TYPE_SYSTEM)),
|
|
282
299
|
["FunctionalStatusSection" /* FUNCTIONAL_STATUS */]: (resource) => resource.resourceType === "Composition" && resource.type?.coding?.some((c) => codingMatches(c, ["ips_functional_status_condition_summary_document", "ips_functional_status_clinical_impression_summary_document"], IPS_SUMMARY_COMPOSITION_TYPE_SYSTEM)),
|
|
283
|
-
["MedicalDeviceSection" /* MEDICAL_DEVICES */]: (resource) => resource.resourceType === "Composition" && resource.type?.coding?.some((c) => codingMatches(c, "ips_medical_device_summary_document", IPS_SUMMARY_COMPOSITION_TYPE_SYSTEM))
|
|
300
|
+
["MedicalDeviceSection" /* MEDICAL_DEVICES */]: (resource) => resource.resourceType === "Composition" && resource.type?.coding?.some((c) => codingMatches(c, "ips_medical_device_summary_document", IPS_SUMMARY_COMPOSITION_TYPE_SYSTEM)),
|
|
301
|
+
["HistoryOfPregnancySection" /* PREGNANCY_HISTORY */]: (resource) => resource.resourceType === "Composition" && resource.type?.coding?.some((c) => codingMatches(c, "ips_pregnancy_history_summary_document", IPS_SUMMARY_COMPOSITION_TYPE_SYSTEM)),
|
|
302
|
+
["ResultsSection" /* DIAGNOSTIC_REPORTS */]: (resource) => resource.resourceType === "Composition" && resource.type?.coding?.some((c) => codingMatches(c, ["ips_diagnosticreportlab_summary_document", "ips_lab_summary_document"], IPS_SUMMARY_COMPOSITION_TYPE_SYSTEM))
|
|
284
303
|
};
|
|
285
304
|
var IPSSectionResourceHelper = class {
|
|
286
305
|
static getResourceFilterForSection(section) {
|
|
@@ -291,6 +310,9 @@ var IPSSectionResourceHelper = class {
|
|
|
291
310
|
if (!filter) return [];
|
|
292
311
|
return resources.filter(filter);
|
|
293
312
|
}
|
|
313
|
+
static getResourceTypesForSection(section) {
|
|
314
|
+
return IPSSectionResourcesMap[section] || [];
|
|
315
|
+
}
|
|
294
316
|
static getSummaryCompositionFilterForSection(section) {
|
|
295
317
|
const sectionCompositionEnabled = process.env.SUMMARY_COMPOSITION_SECTIONS ? process.env.SUMMARY_COMPOSITION_SECTIONS.split(",").some(
|
|
296
318
|
(s) => s.trim().toLowerCase() === section.toString().toLowerCase() || s.trim().toLowerCase() === "all"
|
|
@@ -934,6 +956,57 @@ var TemplateUtilities = class {
|
|
|
934
956
|
}
|
|
935
957
|
return "";
|
|
936
958
|
}
|
|
959
|
+
/**
|
|
960
|
+
* Extracts and formats reference range data including low/high values and age ranges.
|
|
961
|
+
* @param listItems - Array of reference range objects
|
|
962
|
+
* @returns Formatted reference range string
|
|
963
|
+
*/
|
|
964
|
+
extractObservationReferenceRange(listItems) {
|
|
965
|
+
if (!listItems || !Array.isArray(listItems) || listItems.length === 0) {
|
|
966
|
+
return "";
|
|
967
|
+
}
|
|
968
|
+
const referenceRange = listItems[0];
|
|
969
|
+
let result = "";
|
|
970
|
+
const low = referenceRange.low;
|
|
971
|
+
const high = referenceRange.high;
|
|
972
|
+
if (low) {
|
|
973
|
+
if (low.value != void 0 && low.value !== null) {
|
|
974
|
+
result += this.formatFloatValue(low.value);
|
|
975
|
+
if (low.unit) {
|
|
976
|
+
result += ` ${low.unit}`;
|
|
977
|
+
}
|
|
978
|
+
}
|
|
979
|
+
}
|
|
980
|
+
if (high) {
|
|
981
|
+
if (result && (high.value !== void 0 && high.value !== null)) {
|
|
982
|
+
result += " - ";
|
|
983
|
+
}
|
|
984
|
+
result += this.formatFloatValue(high.value);
|
|
985
|
+
if (high.unit) {
|
|
986
|
+
result += ` ${high.unit}`;
|
|
987
|
+
}
|
|
988
|
+
}
|
|
989
|
+
const age = referenceRange.age;
|
|
990
|
+
if (age) {
|
|
991
|
+
const ageParts = [];
|
|
992
|
+
const ageLow = age.low;
|
|
993
|
+
const ageHigh = age.high;
|
|
994
|
+
if (ageLow && ageLow.value != void 0 && ageLow.value !== null) {
|
|
995
|
+
ageParts.push(`${this.formatFloatValue(ageLow.value)}${ageLow.unit ? ` ${ageLow.unit}` : ""}`);
|
|
996
|
+
}
|
|
997
|
+
if (ageHigh && ageHigh.value != void 0 && ageHigh.value !== null) {
|
|
998
|
+
ageParts.push(`${this.formatFloatValue(ageHigh.value)}${ageHigh.unit ? ` ${ageHigh.unit}` : ""}`);
|
|
999
|
+
}
|
|
1000
|
+
if (ageParts.length > 0) {
|
|
1001
|
+
if (result) {
|
|
1002
|
+
result += ` (Age: ${ageParts.join(" - ")})`;
|
|
1003
|
+
} else {
|
|
1004
|
+
result = `Age: ${ageParts.join(" - ")}`;
|
|
1005
|
+
}
|
|
1006
|
+
}
|
|
1007
|
+
}
|
|
1008
|
+
return result;
|
|
1009
|
+
}
|
|
937
1010
|
extractObservationSummaryReferenceRange(data) {
|
|
938
1011
|
let referenceRange = "";
|
|
939
1012
|
if (data["referenceRange.low.value"]) {
|
|
@@ -3664,7 +3737,7 @@ var DiagnosticResultsTemplate = class _DiagnosticResultsTemplate {
|
|
|
3664
3737
|
<td>${templateUtilities.capitalizeFirstLetter(obsCodeDisplay)}</td>
|
|
3665
3738
|
<td>${templateUtilities.codeableConceptCoding(obs.code)}</td>
|
|
3666
3739
|
<td>${templateUtilities.extractObservationValue(obs)}</td>
|
|
3667
|
-
<td>${templateUtilities.
|
|
3740
|
+
<td>${templateUtilities.extractObservationReferenceRange(obs.referenceRange)}</td>
|
|
3668
3741
|
<td>${obs.effectiveDateTime ? templateUtilities.renderTime(obs.effectiveDateTime, timezone) : obs.effectivePeriod ? templateUtilities.renderPeriod(obs.effectivePeriod, timezone) : ""}</td>
|
|
3669
3742
|
<td>${templateUtilities.getOwnerTag(obs)}</td>
|
|
3670
3743
|
</tr>`;
|
|
@@ -4555,6 +4628,67 @@ var PregnancyTemplate = class _PregnancyTemplate {
|
|
|
4555
4628
|
generateNarrative(resources, timezone) {
|
|
4556
4629
|
return _PregnancyTemplate.generateStaticNarrative(resources, timezone);
|
|
4557
4630
|
}
|
|
4631
|
+
/**
|
|
4632
|
+
* Generate HTML narrative for pregnancy using summary
|
|
4633
|
+
* @param resources - FHIR Composition resources
|
|
4634
|
+
* @param timezone - Optional timezone to use for date formatting (e.g., 'America/New_York', 'Europe/London')
|
|
4635
|
+
* @returns HTML string for rendering
|
|
4636
|
+
*/
|
|
4637
|
+
generateSummaryNarrative(resources, timezone) {
|
|
4638
|
+
const templateUtilities = new TemplateUtilities(resources);
|
|
4639
|
+
let isSummaryCreated = false;
|
|
4640
|
+
let html = `<p>This list includes all information about the patient's pregnancy history, sorted by effective date (most recent first).</p>
|
|
4641
|
+
`;
|
|
4642
|
+
html += `
|
|
4643
|
+
<div>
|
|
4644
|
+
<table>
|
|
4645
|
+
<thead>
|
|
4646
|
+
<tr>
|
|
4647
|
+
<th>Result</th>
|
|
4648
|
+
<th>Code (System)</th>
|
|
4649
|
+
<th>Comments</th>
|
|
4650
|
+
<th>Date</th>
|
|
4651
|
+
<th>Source</th>
|
|
4652
|
+
</tr>
|
|
4653
|
+
</thead>
|
|
4654
|
+
<tbody>`;
|
|
4655
|
+
for (const resourceItem of resources) {
|
|
4656
|
+
for (const rowData of resourceItem.section ?? []) {
|
|
4657
|
+
const sectionCodeableConcept = rowData.code;
|
|
4658
|
+
const rowTitle = rowData.title;
|
|
4659
|
+
const data = {};
|
|
4660
|
+
data["codeSystem"] = templateUtilities.codeableConceptCoding(sectionCodeableConcept);
|
|
4661
|
+
for (const columnData of rowData.section ?? []) {
|
|
4662
|
+
const columnTitle = columnData.title;
|
|
4663
|
+
if (columnTitle) {
|
|
4664
|
+
data[columnTitle] = templateUtilities.renderTextAsHtml(columnData.text?.div ?? "");
|
|
4665
|
+
}
|
|
4666
|
+
}
|
|
4667
|
+
if (rowTitle === "Expected Delivery Date") {
|
|
4668
|
+
data["Result"] = "Estimated Delivery Date: " + templateUtilities.renderTextAsHtml(templateUtilities.extractObservationSummaryValue(data, timezone));
|
|
4669
|
+
} else {
|
|
4670
|
+
data["Result"] = data["Pregnancy Result"];
|
|
4671
|
+
}
|
|
4672
|
+
if (data["Result"]?.toLowerCase() === "unknown") {
|
|
4673
|
+
continue;
|
|
4674
|
+
}
|
|
4675
|
+
isSummaryCreated = true;
|
|
4676
|
+
html += `
|
|
4677
|
+
<tr>
|
|
4678
|
+
<td class="Result">${data["Result"] ? templateUtilities.capitalizeFirstLetter(data["Result"]) : ""}</td>
|
|
4679
|
+
<td class="CodeSystem">${data["codeSystem"]}</td>
|
|
4680
|
+
<td class="Comments">${data["Comments"] ?? ""}</td>
|
|
4681
|
+
<td class="Date">${templateUtilities.extractObservationSummaryEffectiveTime(data, timezone) ?? ""}</td>
|
|
4682
|
+
<td class="Source">${data["Source"] ?? ""}</td>
|
|
4683
|
+
</tr>`;
|
|
4684
|
+
}
|
|
4685
|
+
}
|
|
4686
|
+
html += `
|
|
4687
|
+
</tbody>
|
|
4688
|
+
</table>
|
|
4689
|
+
</div>`;
|
|
4690
|
+
return isSummaryCreated ? html : void 0;
|
|
4691
|
+
}
|
|
4558
4692
|
/**
|
|
4559
4693
|
* Internal static implementation that actually generates the narrative
|
|
4560
4694
|
* @param resources - FHIR Observation resources
|
|
@@ -4563,10 +4697,13 @@ var PregnancyTemplate = class _PregnancyTemplate {
|
|
|
4563
4697
|
*/
|
|
4564
4698
|
static generateStaticNarrative(resources, timezone) {
|
|
4565
4699
|
const templateUtilities = new TemplateUtilities(resources);
|
|
4700
|
+
const patients = resources.filter((r) => r.resourceType === "Patient");
|
|
4701
|
+
if (patients.length === 0) {
|
|
4702
|
+
return;
|
|
4703
|
+
}
|
|
4566
4704
|
const pregnancyHistoryFilter = IPSSectionResourceFilters["HistoryOfPregnancySection"];
|
|
4567
4705
|
const filteredResources = pregnancyHistoryFilter ? resources.filter(pregnancyHistoryFilter) : resources;
|
|
4568
4706
|
const observations = filteredResources.filter((r) => r.resourceType === "Observation");
|
|
4569
|
-
const conditions = filteredResources.filter((r) => r.resourceType === "Condition");
|
|
4570
4707
|
const EDD_LOINC = "11778-8";
|
|
4571
4708
|
const pregnancyStatusCodes = Object.keys(PREGNANCY_LOINC_CODES.PREGNANCY_STATUS);
|
|
4572
4709
|
const pregnancyOutcomeCodes = Object.keys(PREGNANCY_LOINC_CODES.PREGNANCY_OUTCOME);
|
|
@@ -4587,10 +4724,10 @@ var PregnancyTemplate = class _PregnancyTemplate {
|
|
|
4587
4724
|
const dateB = b.effectiveDateTime || b.effectivePeriod?.start;
|
|
4588
4725
|
return dateB && dateA ? new Date(dateB).getTime() - new Date(dateA).getTime() : 0;
|
|
4589
4726
|
});
|
|
4590
|
-
if (!pregnancyStatusObs && !eddObs && historyObs.length === 0
|
|
4591
|
-
return
|
|
4727
|
+
if (!pregnancyStatusObs && !eddObs && historyObs.length === 0) {
|
|
4728
|
+
return;
|
|
4592
4729
|
}
|
|
4593
|
-
let html = `<p>This list includes Observation
|
|
4730
|
+
let html = `<p>This list includes Observation resources relevant to pregnancy, sorted by date (most recent first).</p>`;
|
|
4594
4731
|
html += `
|
|
4595
4732
|
<table>
|
|
4596
4733
|
<thead>
|
|
@@ -4629,11 +4766,6 @@ var PregnancyTemplate = class _PregnancyTemplate {
|
|
|
4629
4766
|
const date = obs.effectiveDateTime || obs.effectivePeriod?.start;
|
|
4630
4767
|
rowResources.push({ resource: obs, date, type: "history" });
|
|
4631
4768
|
}
|
|
4632
|
-
for (const cond of conditions) {
|
|
4633
|
-
const condition = cond;
|
|
4634
|
-
const date = condition.onsetDateTime || condition.onsetPeriod?.start;
|
|
4635
|
-
rowResources.push({ resource: condition, date, type: "condition" });
|
|
4636
|
-
}
|
|
4637
4769
|
rowResources.sort((a, b) => {
|
|
4638
4770
|
if (!a.date && !b.date) return 0;
|
|
4639
4771
|
if (!a.date) return 1;
|
|
@@ -4649,7 +4781,7 @@ var PregnancyTemplate = class _PregnancyTemplate {
|
|
|
4649
4781
|
dateStr = date ? templateUtilities.renderTextAsHtml(templateUtilities.renderTime(date, timezone)) : "";
|
|
4650
4782
|
codeSystem = templateUtilities.renderTextAsHtml(templateUtilities.codeableConceptCoding(resource.code));
|
|
4651
4783
|
} else if (type === "edd") {
|
|
4652
|
-
result = "Estimated Delivery Date: " +
|
|
4784
|
+
result = "Estimated Delivery Date: " + (templateUtilities.extractObservationValue(resource) ?? "");
|
|
4653
4785
|
comments = templateUtilities.renderNotes(resource.note, timezone);
|
|
4654
4786
|
dateStr = date ? templateUtilities.renderTextAsHtml(templateUtilities.renderTime(date, timezone)) : "";
|
|
4655
4787
|
codeSystem = templateUtilities.renderTextAsHtml(templateUtilities.codeableConceptCoding(resource.code));
|
|
@@ -4658,11 +4790,6 @@ var PregnancyTemplate = class _PregnancyTemplate {
|
|
|
4658
4790
|
comments = templateUtilities.renderNotes(resource.note, timezone);
|
|
4659
4791
|
dateStr = date ? templateUtilities.renderTextAsHtml(templateUtilities.renderTime(date, timezone)) : "";
|
|
4660
4792
|
codeSystem = templateUtilities.renderTextAsHtml(templateUtilities.codeableConceptCoding(resource.code));
|
|
4661
|
-
} else if (type === "condition") {
|
|
4662
|
-
result = templateUtilities.renderTextAsHtml(templateUtilities.codeableConceptDisplay(resource.code));
|
|
4663
|
-
comments = templateUtilities.renderNotes(resource.note, timezone);
|
|
4664
|
-
dateStr = date ? templateUtilities.renderTextAsHtml(templateUtilities.renderTime(date, timezone)) : "";
|
|
4665
|
-
codeSystem = templateUtilities.renderTextAsHtml(templateUtilities.codeableConceptCoding(resource.code));
|
|
4666
4793
|
}
|
|
4667
4794
|
const rowKey = `${result}|${codeSystem}`;
|
|
4668
4795
|
if (!addedRows.has(rowKey)) {
|
|
@@ -5075,16 +5202,33 @@ var ComprehensiveIPSCompositionBuilder = class {
|
|
|
5075
5202
|
this.addSectionAsync(narrative, sectionType, validResources);
|
|
5076
5203
|
return this;
|
|
5077
5204
|
}
|
|
5078
|
-
async makeSectionFromSummaryAsync(sectionType, summaryCompositions, resources, timezone) {
|
|
5205
|
+
async makeSectionFromSummaryAsync(sectionType, summaryCompositions, resources, timezone, includeSummaryCompositionOnly = false) {
|
|
5079
5206
|
const sectionResources = [];
|
|
5080
5207
|
for (const summaryComposition of summaryCompositions) {
|
|
5081
5208
|
const resourceEntries = summaryComposition?.section?.flatMap((sec) => sec.entry || []) ?? [];
|
|
5082
|
-
|
|
5083
|
-
|
|
5084
|
-
|
|
5085
|
-
|
|
5086
|
-
|
|
5087
|
-
|
|
5209
|
+
if (includeSummaryCompositionOnly) {
|
|
5210
|
+
const addedEntries = /* @__PURE__ */ new Set();
|
|
5211
|
+
resourceEntries.forEach((entry) => {
|
|
5212
|
+
if (entry.reference && !addedEntries.has(entry.reference)) {
|
|
5213
|
+
const reference = entry.reference.split("/");
|
|
5214
|
+
if (reference.length === 2) {
|
|
5215
|
+
const resource = {
|
|
5216
|
+
id: reference[1],
|
|
5217
|
+
resourceType: reference[0]
|
|
5218
|
+
};
|
|
5219
|
+
sectionResources.push(resource);
|
|
5220
|
+
addedEntries.add(entry.reference);
|
|
5221
|
+
}
|
|
5222
|
+
}
|
|
5223
|
+
});
|
|
5224
|
+
} else {
|
|
5225
|
+
resources.forEach((resource) => {
|
|
5226
|
+
if (resourceEntries?.some((entry) => entry.reference === `${resource.resourceType}/${resource.id}`)) {
|
|
5227
|
+
this.resources.add(resource);
|
|
5228
|
+
sectionResources.push(resource);
|
|
5229
|
+
}
|
|
5230
|
+
});
|
|
5231
|
+
}
|
|
5088
5232
|
}
|
|
5089
5233
|
let narrative = await NarrativeGenerator.generateNarrativeAsync(
|
|
5090
5234
|
sectionType,
|
|
@@ -5109,8 +5253,10 @@ var ComprehensiveIPSCompositionBuilder = class {
|
|
|
5109
5253
|
* @param bundle - FHIR Bundle containing resources
|
|
5110
5254
|
* @param timezone - Optional timezone to use for date formatting
|
|
5111
5255
|
* @param useSummaryCompositions - Whether to use summary compositions (default: false)
|
|
5256
|
+
* @param includeSummaryCompositionOnly - Whether to include only summary composition resources (default: false)
|
|
5257
|
+
* @param consoleLogger - Optional console logger for logging (default: console)
|
|
5112
5258
|
*/
|
|
5113
|
-
async readBundleAsync(bundle, timezone, useSummaryCompositions = false, consoleLogger = console) {
|
|
5259
|
+
async readBundleAsync(bundle, timezone, useSummaryCompositions = false, includeSummaryCompositionOnly = false, consoleLogger = console) {
|
|
5114
5260
|
if (!bundle.entry) {
|
|
5115
5261
|
return this;
|
|
5116
5262
|
}
|
|
@@ -5134,14 +5280,14 @@ var ComprehensiveIPSCompositionBuilder = class {
|
|
|
5134
5280
|
const sectionIPSSummary = summaryIPSCompositionFilter ? resources.filter((resource) => summaryIPSCompositionFilter(resource)) : [];
|
|
5135
5281
|
if (sectionIPSSummary.length > 0) {
|
|
5136
5282
|
consoleLogger.info(`Using IPS summary composition for section: ${sectionType}`);
|
|
5137
|
-
await this.makeSectionFromSummaryAsync(sectionType, sectionIPSSummary, resources, timezone);
|
|
5283
|
+
await this.makeSectionFromSummaryAsync(sectionType, sectionIPSSummary, resources, timezone, includeSummaryCompositionOnly);
|
|
5138
5284
|
continue;
|
|
5139
5285
|
}
|
|
5140
5286
|
const summaryCompositionFilter = useSummaryCompositions ? IPSSectionResourceHelper.getSummaryCompositionFilterForSection(sectionType) : void 0;
|
|
5141
5287
|
const sectionSummary = summaryCompositionFilter ? resources.filter((resource) => summaryCompositionFilter(resource)) : [];
|
|
5142
5288
|
if (sectionSummary.length > 0) {
|
|
5143
5289
|
consoleLogger.info(`Using summary composition for section: ${sectionType}`);
|
|
5144
|
-
await this.makeSectionFromSummaryAsync(sectionType, sectionSummary, resources, timezone);
|
|
5290
|
+
await this.makeSectionFromSummaryAsync(sectionType, sectionSummary, resources, timezone, includeSummaryCompositionOnly);
|
|
5145
5291
|
} else {
|
|
5146
5292
|
consoleLogger.info(`Using individual resources for section: ${sectionType}`);
|
|
5147
5293
|
const sectionFilter = IPSSectionResourceHelper.getResourceFilterForSection(sectionType);
|
|
@@ -5157,10 +5303,11 @@ var ComprehensiveIPSCompositionBuilder = class {
|
|
|
5157
5303
|
* @param authorOrganizationName - Name of the authoring organization
|
|
5158
5304
|
* @param baseUrl - Base URL for the FHIR server (e.g., 'https://example.com/fhir')
|
|
5159
5305
|
* @param timezone - Optional timezone to use for date formatting (e.g., 'America/New_York', 'Europe/London')
|
|
5306
|
+
* @param includeSummaryCompositionOnly - Whether to include only summary composition resources (default: false)
|
|
5160
5307
|
* @param patientId - Optional patient ID to use as primary patient for composition reference
|
|
5161
5308
|
* @param now - Optional current date to use for composition date (defaults to new Date())
|
|
5162
5309
|
*/
|
|
5163
|
-
async buildBundleAsync(authorOrganizationId, authorOrganizationName, baseUrl, timezone, patientId, now) {
|
|
5310
|
+
async buildBundleAsync(authorOrganizationId, authorOrganizationName, baseUrl, timezone, includeSummaryCompositionOnly = false, patientId, now) {
|
|
5164
5311
|
if (baseUrl.endsWith("/")) {
|
|
5165
5312
|
baseUrl = baseUrl.slice(0, -1);
|
|
5166
5313
|
}
|
|
@@ -5209,30 +5356,32 @@ var ComprehensiveIPSCompositionBuilder = class {
|
|
|
5209
5356
|
fullUrl: `${baseUrl}/Composition/${composition.id}`,
|
|
5210
5357
|
resource: composition
|
|
5211
5358
|
});
|
|
5212
|
-
|
|
5359
|
+
if (!includeSummaryCompositionOnly) {
|
|
5360
|
+
this.patients.forEach((patient) => {
|
|
5361
|
+
bundle.entry?.push({
|
|
5362
|
+
fullUrl: `${baseUrl}/Patient/${patient.id}`,
|
|
5363
|
+
resource: patient
|
|
5364
|
+
});
|
|
5365
|
+
});
|
|
5366
|
+
this.resources.forEach((resource) => {
|
|
5367
|
+
if (resource.resourceType !== "Patient") {
|
|
5368
|
+
bundle.entry?.push(
|
|
5369
|
+
{
|
|
5370
|
+
fullUrl: `${baseUrl}/${resource.resourceType}/${resource.id}`,
|
|
5371
|
+
resource
|
|
5372
|
+
}
|
|
5373
|
+
);
|
|
5374
|
+
}
|
|
5375
|
+
});
|
|
5213
5376
|
bundle.entry?.push({
|
|
5214
|
-
fullUrl: `${baseUrl}/
|
|
5215
|
-
resource:
|
|
5377
|
+
fullUrl: `${baseUrl}/Organization/${authorOrganizationId}`,
|
|
5378
|
+
resource: {
|
|
5379
|
+
resourceType: "Organization",
|
|
5380
|
+
id: authorOrganizationId,
|
|
5381
|
+
name: authorOrganizationName
|
|
5382
|
+
}
|
|
5216
5383
|
});
|
|
5217
|
-
}
|
|
5218
|
-
this.resources.forEach((resource) => {
|
|
5219
|
-
if (resource.resourceType !== "Patient") {
|
|
5220
|
-
bundle.entry?.push(
|
|
5221
|
-
{
|
|
5222
|
-
fullUrl: `${baseUrl}/${resource.resourceType}/${resource.id}`,
|
|
5223
|
-
resource
|
|
5224
|
-
}
|
|
5225
|
-
);
|
|
5226
|
-
}
|
|
5227
|
-
});
|
|
5228
|
-
bundle.entry?.push({
|
|
5229
|
-
fullUrl: `${baseUrl}/Organization/${authorOrganizationId}`,
|
|
5230
|
-
resource: {
|
|
5231
|
-
resourceType: "Organization",
|
|
5232
|
-
id: authorOrganizationId,
|
|
5233
|
-
name: authorOrganizationName
|
|
5234
|
-
}
|
|
5235
|
-
});
|
|
5384
|
+
}
|
|
5236
5385
|
return bundle;
|
|
5237
5386
|
}
|
|
5238
5387
|
/**
|
|
@@ -5242,6 +5391,35 @@ var ComprehensiveIPSCompositionBuilder = class {
|
|
|
5242
5391
|
getSections() {
|
|
5243
5392
|
return this.sections;
|
|
5244
5393
|
}
|
|
5394
|
+
/**
|
|
5395
|
+
* Identifies remaining resource types that are missing from the composition bundle.
|
|
5396
|
+
* @param bundle - FHIR Bundle containing resources
|
|
5397
|
+
* @returns Array of missing resource type strings
|
|
5398
|
+
*/
|
|
5399
|
+
getRemainingResourcesFromCompositionBundle(bundle) {
|
|
5400
|
+
const resources = [];
|
|
5401
|
+
bundle.entry?.forEach((e) => {
|
|
5402
|
+
if (e.resource) {
|
|
5403
|
+
resources.push(e.resource);
|
|
5404
|
+
}
|
|
5405
|
+
});
|
|
5406
|
+
const remainingResources = /* @__PURE__ */ new Set();
|
|
5407
|
+
for (const sectionType of Object.values(IPSSections)) {
|
|
5408
|
+
const summaryIPSCompositionFilter = IPSSectionResourceHelper.getSummaryIPSCompositionFilterForSection(sectionType);
|
|
5409
|
+
const sectionIPSSummary = summaryIPSCompositionFilter ? resources.filter((resource) => summaryIPSCompositionFilter(resource)) : [];
|
|
5410
|
+
const summaryCompositionFilter = IPSSectionResourceHelper.getSummaryCompositionFilterForSection(sectionType);
|
|
5411
|
+
const sectionSummary = summaryCompositionFilter ? resources.filter((resource) => summaryCompositionFilter(resource)) : [];
|
|
5412
|
+
if (sectionSummary.length === 0 && sectionIPSSummary.length === 0) {
|
|
5413
|
+
const resourcesForSection = IPSSectionResourceHelper.getResourceTypesForSection(sectionType);
|
|
5414
|
+
resourcesForSection.forEach((resourceType) => {
|
|
5415
|
+
if (!remainingResources.has(resourceType) && !resources.some((r) => r.resourceType === resourceType)) {
|
|
5416
|
+
remainingResources.add(resourceType);
|
|
5417
|
+
}
|
|
5418
|
+
});
|
|
5419
|
+
}
|
|
5420
|
+
}
|
|
5421
|
+
return Array.from(remainingResources);
|
|
5422
|
+
}
|
|
5245
5423
|
};
|
|
5246
5424
|
|
|
5247
5425
|
// src/index.ts
|
package/dist/index.d.cts
CHANGED
|
@@ -709,29 +709,38 @@ declare class ComprehensiveIPSCompositionBuilder {
|
|
|
709
709
|
* @param timezone - Optional timezone to use for date formatting
|
|
710
710
|
*/
|
|
711
711
|
makeSectionAsync<T extends TDomainResource>(sectionType: IPSSections, validResources: T[], timezone: string | undefined): Promise<this>;
|
|
712
|
-
makeSectionFromSummaryAsync(sectionType: IPSSections, summaryCompositions: TComposition[], resources: TDomainResource[], timezone: string | undefined): Promise<this>;
|
|
712
|
+
makeSectionFromSummaryAsync(sectionType: IPSSections, summaryCompositions: TComposition[], resources: TDomainResource[], timezone: string | undefined, includeSummaryCompositionOnly?: boolean): Promise<this>;
|
|
713
713
|
/**
|
|
714
714
|
* Reads a FHIR Bundle and extracts resources for each section defined in IPSSections.
|
|
715
715
|
* @param bundle - FHIR Bundle containing resources
|
|
716
716
|
* @param timezone - Optional timezone to use for date formatting
|
|
717
717
|
* @param useSummaryCompositions - Whether to use summary compositions (default: false)
|
|
718
|
+
* @param includeSummaryCompositionOnly - Whether to include only summary composition resources (default: false)
|
|
719
|
+
* @param consoleLogger - Optional console logger for logging (default: console)
|
|
718
720
|
*/
|
|
719
|
-
readBundleAsync(bundle: TBundle, timezone: string | undefined, useSummaryCompositions?: boolean, consoleLogger?: Console): Promise<this>;
|
|
721
|
+
readBundleAsync(bundle: TBundle, timezone: string | undefined, useSummaryCompositions?: boolean, includeSummaryCompositionOnly?: boolean, consoleLogger?: Console): Promise<this>;
|
|
720
722
|
/**
|
|
721
723
|
* Builds a complete FHIR Bundle containing the Composition and all resources.
|
|
722
724
|
* @param authorOrganizationId - ID of the authoring organization (e.g., hospital or clinic)
|
|
723
725
|
* @param authorOrganizationName - Name of the authoring organization
|
|
724
726
|
* @param baseUrl - Base URL for the FHIR server (e.g., 'https://example.com/fhir')
|
|
725
727
|
* @param timezone - Optional timezone to use for date formatting (e.g., 'America/New_York', 'Europe/London')
|
|
728
|
+
* @param includeSummaryCompositionOnly - Whether to include only summary composition resources (default: false)
|
|
726
729
|
* @param patientId - Optional patient ID to use as primary patient for composition reference
|
|
727
730
|
* @param now - Optional current date to use for composition date (defaults to new Date())
|
|
728
731
|
*/
|
|
729
|
-
buildBundleAsync(authorOrganizationId: string, authorOrganizationName: string, baseUrl: string, timezone: string | undefined, patientId?: string, now?: Date): Promise<TBundle>;
|
|
732
|
+
buildBundleAsync(authorOrganizationId: string, authorOrganizationName: string, baseUrl: string, timezone: string | undefined, includeSummaryCompositionOnly?: boolean, patientId?: string, now?: Date): Promise<TBundle>;
|
|
730
733
|
/**
|
|
731
734
|
* Returns the Composition sections without creating a full bundle.
|
|
732
735
|
* @returns Array of TCompositionSection
|
|
733
736
|
*/
|
|
734
737
|
getSections(): TCompositionSection[];
|
|
738
|
+
/**
|
|
739
|
+
* Identifies remaining resource types that are missing from the composition bundle.
|
|
740
|
+
* @param bundle - FHIR Bundle containing resources
|
|
741
|
+
* @returns Array of missing resource type strings
|
|
742
|
+
*/
|
|
743
|
+
getRemainingResourcesFromCompositionBundle(bundle: TBundle): string[];
|
|
735
744
|
}
|
|
736
745
|
|
|
737
746
|
interface Narrative {
|
package/dist/index.d.ts
CHANGED
|
@@ -709,29 +709,38 @@ declare class ComprehensiveIPSCompositionBuilder {
|
|
|
709
709
|
* @param timezone - Optional timezone to use for date formatting
|
|
710
710
|
*/
|
|
711
711
|
makeSectionAsync<T extends TDomainResource>(sectionType: IPSSections, validResources: T[], timezone: string | undefined): Promise<this>;
|
|
712
|
-
makeSectionFromSummaryAsync(sectionType: IPSSections, summaryCompositions: TComposition[], resources: TDomainResource[], timezone: string | undefined): Promise<this>;
|
|
712
|
+
makeSectionFromSummaryAsync(sectionType: IPSSections, summaryCompositions: TComposition[], resources: TDomainResource[], timezone: string | undefined, includeSummaryCompositionOnly?: boolean): Promise<this>;
|
|
713
713
|
/**
|
|
714
714
|
* Reads a FHIR Bundle and extracts resources for each section defined in IPSSections.
|
|
715
715
|
* @param bundle - FHIR Bundle containing resources
|
|
716
716
|
* @param timezone - Optional timezone to use for date formatting
|
|
717
717
|
* @param useSummaryCompositions - Whether to use summary compositions (default: false)
|
|
718
|
+
* @param includeSummaryCompositionOnly - Whether to include only summary composition resources (default: false)
|
|
719
|
+
* @param consoleLogger - Optional console logger for logging (default: console)
|
|
718
720
|
*/
|
|
719
|
-
readBundleAsync(bundle: TBundle, timezone: string | undefined, useSummaryCompositions?: boolean, consoleLogger?: Console): Promise<this>;
|
|
721
|
+
readBundleAsync(bundle: TBundle, timezone: string | undefined, useSummaryCompositions?: boolean, includeSummaryCompositionOnly?: boolean, consoleLogger?: Console): Promise<this>;
|
|
720
722
|
/**
|
|
721
723
|
* Builds a complete FHIR Bundle containing the Composition and all resources.
|
|
722
724
|
* @param authorOrganizationId - ID of the authoring organization (e.g., hospital or clinic)
|
|
723
725
|
* @param authorOrganizationName - Name of the authoring organization
|
|
724
726
|
* @param baseUrl - Base URL for the FHIR server (e.g., 'https://example.com/fhir')
|
|
725
727
|
* @param timezone - Optional timezone to use for date formatting (e.g., 'America/New_York', 'Europe/London')
|
|
728
|
+
* @param includeSummaryCompositionOnly - Whether to include only summary composition resources (default: false)
|
|
726
729
|
* @param patientId - Optional patient ID to use as primary patient for composition reference
|
|
727
730
|
* @param now - Optional current date to use for composition date (defaults to new Date())
|
|
728
731
|
*/
|
|
729
|
-
buildBundleAsync(authorOrganizationId: string, authorOrganizationName: string, baseUrl: string, timezone: string | undefined, patientId?: string, now?: Date): Promise<TBundle>;
|
|
732
|
+
buildBundleAsync(authorOrganizationId: string, authorOrganizationName: string, baseUrl: string, timezone: string | undefined, includeSummaryCompositionOnly?: boolean, patientId?: string, now?: Date): Promise<TBundle>;
|
|
730
733
|
/**
|
|
731
734
|
* Returns the Composition sections without creating a full bundle.
|
|
732
735
|
* @returns Array of TCompositionSection
|
|
733
736
|
*/
|
|
734
737
|
getSections(): TCompositionSection[];
|
|
738
|
+
/**
|
|
739
|
+
* Identifies remaining resource types that are missing from the composition bundle.
|
|
740
|
+
* @param bundle - FHIR Bundle containing resources
|
|
741
|
+
* @returns Array of missing resource type strings
|
|
742
|
+
*/
|
|
743
|
+
getRemainingResourcesFromCompositionBundle(bundle: TBundle): string[];
|
|
735
744
|
}
|
|
736
745
|
|
|
737
746
|
interface Narrative {
|
package/dist/index.js
CHANGED
|
@@ -201,6 +201,23 @@ var RESULT_SUMMARY_OBSERVATION_DATE_FILTER = 2 * 365 * 24 * 60 * 60 * 1e3;
|
|
|
201
201
|
var IPS_SUMMARY_COMPOSITION_TYPE_SYSTEM = "https://fhir.icanbwell.com/4_0_0/CodeSystem/composition/";
|
|
202
202
|
|
|
203
203
|
// src/structures/ips_section_resource_map.ts
|
|
204
|
+
var IPSSectionResourcesMap = {
|
|
205
|
+
["Patient" /* PATIENT */]: ["Patient"],
|
|
206
|
+
["AllergyIntoleranceSection" /* ALLERGIES */]: ["AllergyIntolerance"],
|
|
207
|
+
["MedicationSummarySection" /* MEDICATIONS */]: ["MedicationRequest", "MedicationStatement", "Medication"],
|
|
208
|
+
["ProblemSection" /* PROBLEMS */]: ["Condition"],
|
|
209
|
+
["ImmunizationSection" /* IMMUNIZATIONS */]: ["Immunization", "Organization"],
|
|
210
|
+
["VitalSignsSection" /* VITAL_SIGNS */]: ["Observation"],
|
|
211
|
+
["MedicalDeviceSection" /* MEDICAL_DEVICES */]: ["DeviceUseStatement", "Device"],
|
|
212
|
+
["ResultsSection" /* DIAGNOSTIC_REPORTS */]: ["DiagnosticReport", "Observation"],
|
|
213
|
+
["HistoryOfProceduresSection" /* PROCEDURES */]: ["Procedure"],
|
|
214
|
+
["SocialHistorySection" /* SOCIAL_HISTORY */]: ["Observation"],
|
|
215
|
+
["HistoryOfPregnancySection" /* PREGNANCY_HISTORY */]: ["Observation", "Patient"],
|
|
216
|
+
["FunctionalStatusSection" /* FUNCTIONAL_STATUS */]: ["Condition", "ClinicalImpression"],
|
|
217
|
+
["HistoryOfPastIllnessSection" /* MEDICAL_HISTORY */]: ["Condition"],
|
|
218
|
+
["PlanOfCareSection" /* CARE_PLAN */]: ["CarePlan"],
|
|
219
|
+
["AdvanceDirectivesSection" /* ADVANCE_DIRECTIVES */]: ["Consent"]
|
|
220
|
+
};
|
|
204
221
|
var IPSSectionResourceFilters = {
|
|
205
222
|
// Patient section: only Patient resource
|
|
206
223
|
["Patient" /* PATIENT */]: (resource) => resource.resourceType === "Patient",
|
|
@@ -223,7 +240,7 @@ var IPSSectionResourceFilters = {
|
|
|
223
240
|
// Only include social history Observations
|
|
224
241
|
["SocialHistorySection" /* SOCIAL_HISTORY */]: (resource) => resource.resourceType === "Observation" && codeableConceptMatches(resource.code, Object.keys(SOCIAL_HISTORY_LOINC_CODES), "http://loinc.org"),
|
|
225
242
|
// Only include pregnancy history Observations or relevant Conditions
|
|
226
|
-
["HistoryOfPregnancySection" /* PREGNANCY_HISTORY */]: (resource) => resource.resourceType === "Observation" && (codeableConceptMatches(resource.code, Object.keys(PREGNANCY_LOINC_CODES.PREGNANCY_STATUS), "http://loinc.org") || codeableConceptMatches(resource.valueCodeableConcept, Object.keys(PREGNANCY_LOINC_CODES.PREGNANCY_OUTCOME), "http://loinc.org") || codingMatches(resource.code?.coding?.[0], PREGNANCY_SNOMED_CODES, "http://snomed.info/sct") || codingMatches(resource.valueCodeableConcept?.coding?.[0], PREGNANCY_SNOMED_CODES, "http://snomed.info/sct")) || resource.resourceType === "
|
|
243
|
+
["HistoryOfPregnancySection" /* PREGNANCY_HISTORY */]: (resource) => resource.resourceType === "Observation" && (codeableConceptMatches(resource.code, Object.keys(PREGNANCY_LOINC_CODES.PREGNANCY_STATUS), "http://loinc.org") || codeableConceptMatches(resource.valueCodeableConcept, Object.keys(PREGNANCY_LOINC_CODES.PREGNANCY_OUTCOME), "http://loinc.org") || codingMatches(resource.code?.coding?.[0], PREGNANCY_SNOMED_CODES, "http://snomed.info/sct") || codingMatches(resource.valueCodeableConcept?.coding?.[0], PREGNANCY_SNOMED_CODES, "http://snomed.info/sct")) || resource.resourceType === "Patient" && resource.gender !== "male",
|
|
227
244
|
// Only include Condition with Functional Status LOINC and SNOMED codes, category code 'problem-list-item', and completed ClinicalImpressions
|
|
228
245
|
["FunctionalStatusSection" /* FUNCTIONAL_STATUS */]: (resource) => resource.resourceType === "Condition" && ((codeableConceptMatches(resource.code, Object.keys(FUNCTIONAL_STATUS_ASSESSMENT_LOINC_CODES), "http://loinc.org") || codeableConceptMatches(resource.code, Object.keys(FUNCTIONAL_STATUS_SNOMED_CODES), "http://snomed.info/sct")) && resource.clinicalStatus?.coding?.some((c) => c.code === "active") && resource.category?.some(
|
|
229
246
|
(cat) => cat.coding?.some((c) => c.code === "problem-list-item")
|
|
@@ -252,7 +269,9 @@ var IPSSectionSummaryIPSCompositionFilter = {
|
|
|
252
269
|
["AdvanceDirectivesSection" /* ADVANCE_DIRECTIVES */]: (resource) => resource.resourceType === "Composition" && resource.type?.coding?.some((c) => codingMatches(c, "ips_advanced_directives_summary_document", IPS_SUMMARY_COMPOSITION_TYPE_SYSTEM)),
|
|
253
270
|
["SocialHistorySection" /* SOCIAL_HISTORY */]: (resource) => resource.resourceType === "Composition" && resource.type?.coding?.some((c) => codingMatches(c, "ips_social_history_summary_document", IPS_SUMMARY_COMPOSITION_TYPE_SYSTEM)),
|
|
254
271
|
["FunctionalStatusSection" /* FUNCTIONAL_STATUS */]: (resource) => resource.resourceType === "Composition" && resource.type?.coding?.some((c) => codingMatches(c, ["ips_functional_status_condition_summary_document", "ips_functional_status_clinical_impression_summary_document"], IPS_SUMMARY_COMPOSITION_TYPE_SYSTEM)),
|
|
255
|
-
["MedicalDeviceSection" /* MEDICAL_DEVICES */]: (resource) => resource.resourceType === "Composition" && resource.type?.coding?.some((c) => codingMatches(c, "ips_medical_device_summary_document", IPS_SUMMARY_COMPOSITION_TYPE_SYSTEM))
|
|
272
|
+
["MedicalDeviceSection" /* MEDICAL_DEVICES */]: (resource) => resource.resourceType === "Composition" && resource.type?.coding?.some((c) => codingMatches(c, "ips_medical_device_summary_document", IPS_SUMMARY_COMPOSITION_TYPE_SYSTEM)),
|
|
273
|
+
["HistoryOfPregnancySection" /* PREGNANCY_HISTORY */]: (resource) => resource.resourceType === "Composition" && resource.type?.coding?.some((c) => codingMatches(c, "ips_pregnancy_history_summary_document", IPS_SUMMARY_COMPOSITION_TYPE_SYSTEM)),
|
|
274
|
+
["ResultsSection" /* DIAGNOSTIC_REPORTS */]: (resource) => resource.resourceType === "Composition" && resource.type?.coding?.some((c) => codingMatches(c, ["ips_diagnosticreportlab_summary_document", "ips_lab_summary_document"], IPS_SUMMARY_COMPOSITION_TYPE_SYSTEM))
|
|
256
275
|
};
|
|
257
276
|
var IPSSectionResourceHelper = class {
|
|
258
277
|
static getResourceFilterForSection(section) {
|
|
@@ -263,6 +282,9 @@ var IPSSectionResourceHelper = class {
|
|
|
263
282
|
if (!filter) return [];
|
|
264
283
|
return resources.filter(filter);
|
|
265
284
|
}
|
|
285
|
+
static getResourceTypesForSection(section) {
|
|
286
|
+
return IPSSectionResourcesMap[section] || [];
|
|
287
|
+
}
|
|
266
288
|
static getSummaryCompositionFilterForSection(section) {
|
|
267
289
|
const sectionCompositionEnabled = process.env.SUMMARY_COMPOSITION_SECTIONS ? process.env.SUMMARY_COMPOSITION_SECTIONS.split(",").some(
|
|
268
290
|
(s) => s.trim().toLowerCase() === section.toString().toLowerCase() || s.trim().toLowerCase() === "all"
|
|
@@ -906,6 +928,57 @@ var TemplateUtilities = class {
|
|
|
906
928
|
}
|
|
907
929
|
return "";
|
|
908
930
|
}
|
|
931
|
+
/**
|
|
932
|
+
* Extracts and formats reference range data including low/high values and age ranges.
|
|
933
|
+
* @param listItems - Array of reference range objects
|
|
934
|
+
* @returns Formatted reference range string
|
|
935
|
+
*/
|
|
936
|
+
extractObservationReferenceRange(listItems) {
|
|
937
|
+
if (!listItems || !Array.isArray(listItems) || listItems.length === 0) {
|
|
938
|
+
return "";
|
|
939
|
+
}
|
|
940
|
+
const referenceRange = listItems[0];
|
|
941
|
+
let result = "";
|
|
942
|
+
const low = referenceRange.low;
|
|
943
|
+
const high = referenceRange.high;
|
|
944
|
+
if (low) {
|
|
945
|
+
if (low.value != void 0 && low.value !== null) {
|
|
946
|
+
result += this.formatFloatValue(low.value);
|
|
947
|
+
if (low.unit) {
|
|
948
|
+
result += ` ${low.unit}`;
|
|
949
|
+
}
|
|
950
|
+
}
|
|
951
|
+
}
|
|
952
|
+
if (high) {
|
|
953
|
+
if (result && (high.value !== void 0 && high.value !== null)) {
|
|
954
|
+
result += " - ";
|
|
955
|
+
}
|
|
956
|
+
result += this.formatFloatValue(high.value);
|
|
957
|
+
if (high.unit) {
|
|
958
|
+
result += ` ${high.unit}`;
|
|
959
|
+
}
|
|
960
|
+
}
|
|
961
|
+
const age = referenceRange.age;
|
|
962
|
+
if (age) {
|
|
963
|
+
const ageParts = [];
|
|
964
|
+
const ageLow = age.low;
|
|
965
|
+
const ageHigh = age.high;
|
|
966
|
+
if (ageLow && ageLow.value != void 0 && ageLow.value !== null) {
|
|
967
|
+
ageParts.push(`${this.formatFloatValue(ageLow.value)}${ageLow.unit ? ` ${ageLow.unit}` : ""}`);
|
|
968
|
+
}
|
|
969
|
+
if (ageHigh && ageHigh.value != void 0 && ageHigh.value !== null) {
|
|
970
|
+
ageParts.push(`${this.formatFloatValue(ageHigh.value)}${ageHigh.unit ? ` ${ageHigh.unit}` : ""}`);
|
|
971
|
+
}
|
|
972
|
+
if (ageParts.length > 0) {
|
|
973
|
+
if (result) {
|
|
974
|
+
result += ` (Age: ${ageParts.join(" - ")})`;
|
|
975
|
+
} else {
|
|
976
|
+
result = `Age: ${ageParts.join(" - ")}`;
|
|
977
|
+
}
|
|
978
|
+
}
|
|
979
|
+
}
|
|
980
|
+
return result;
|
|
981
|
+
}
|
|
909
982
|
extractObservationSummaryReferenceRange(data) {
|
|
910
983
|
let referenceRange = "";
|
|
911
984
|
if (data["referenceRange.low.value"]) {
|
|
@@ -3636,7 +3709,7 @@ var DiagnosticResultsTemplate = class _DiagnosticResultsTemplate {
|
|
|
3636
3709
|
<td>${templateUtilities.capitalizeFirstLetter(obsCodeDisplay)}</td>
|
|
3637
3710
|
<td>${templateUtilities.codeableConceptCoding(obs.code)}</td>
|
|
3638
3711
|
<td>${templateUtilities.extractObservationValue(obs)}</td>
|
|
3639
|
-
<td>${templateUtilities.
|
|
3712
|
+
<td>${templateUtilities.extractObservationReferenceRange(obs.referenceRange)}</td>
|
|
3640
3713
|
<td>${obs.effectiveDateTime ? templateUtilities.renderTime(obs.effectiveDateTime, timezone) : obs.effectivePeriod ? templateUtilities.renderPeriod(obs.effectivePeriod, timezone) : ""}</td>
|
|
3641
3714
|
<td>${templateUtilities.getOwnerTag(obs)}</td>
|
|
3642
3715
|
</tr>`;
|
|
@@ -4527,6 +4600,67 @@ var PregnancyTemplate = class _PregnancyTemplate {
|
|
|
4527
4600
|
generateNarrative(resources, timezone) {
|
|
4528
4601
|
return _PregnancyTemplate.generateStaticNarrative(resources, timezone);
|
|
4529
4602
|
}
|
|
4603
|
+
/**
|
|
4604
|
+
* Generate HTML narrative for pregnancy using summary
|
|
4605
|
+
* @param resources - FHIR Composition resources
|
|
4606
|
+
* @param timezone - Optional timezone to use for date formatting (e.g., 'America/New_York', 'Europe/London')
|
|
4607
|
+
* @returns HTML string for rendering
|
|
4608
|
+
*/
|
|
4609
|
+
generateSummaryNarrative(resources, timezone) {
|
|
4610
|
+
const templateUtilities = new TemplateUtilities(resources);
|
|
4611
|
+
let isSummaryCreated = false;
|
|
4612
|
+
let html = `<p>This list includes all information about the patient's pregnancy history, sorted by effective date (most recent first).</p>
|
|
4613
|
+
`;
|
|
4614
|
+
html += `
|
|
4615
|
+
<div>
|
|
4616
|
+
<table>
|
|
4617
|
+
<thead>
|
|
4618
|
+
<tr>
|
|
4619
|
+
<th>Result</th>
|
|
4620
|
+
<th>Code (System)</th>
|
|
4621
|
+
<th>Comments</th>
|
|
4622
|
+
<th>Date</th>
|
|
4623
|
+
<th>Source</th>
|
|
4624
|
+
</tr>
|
|
4625
|
+
</thead>
|
|
4626
|
+
<tbody>`;
|
|
4627
|
+
for (const resourceItem of resources) {
|
|
4628
|
+
for (const rowData of resourceItem.section ?? []) {
|
|
4629
|
+
const sectionCodeableConcept = rowData.code;
|
|
4630
|
+
const rowTitle = rowData.title;
|
|
4631
|
+
const data = {};
|
|
4632
|
+
data["codeSystem"] = templateUtilities.codeableConceptCoding(sectionCodeableConcept);
|
|
4633
|
+
for (const columnData of rowData.section ?? []) {
|
|
4634
|
+
const columnTitle = columnData.title;
|
|
4635
|
+
if (columnTitle) {
|
|
4636
|
+
data[columnTitle] = templateUtilities.renderTextAsHtml(columnData.text?.div ?? "");
|
|
4637
|
+
}
|
|
4638
|
+
}
|
|
4639
|
+
if (rowTitle === "Expected Delivery Date") {
|
|
4640
|
+
data["Result"] = "Estimated Delivery Date: " + templateUtilities.renderTextAsHtml(templateUtilities.extractObservationSummaryValue(data, timezone));
|
|
4641
|
+
} else {
|
|
4642
|
+
data["Result"] = data["Pregnancy Result"];
|
|
4643
|
+
}
|
|
4644
|
+
if (data["Result"]?.toLowerCase() === "unknown") {
|
|
4645
|
+
continue;
|
|
4646
|
+
}
|
|
4647
|
+
isSummaryCreated = true;
|
|
4648
|
+
html += `
|
|
4649
|
+
<tr>
|
|
4650
|
+
<td class="Result">${data["Result"] ? templateUtilities.capitalizeFirstLetter(data["Result"]) : ""}</td>
|
|
4651
|
+
<td class="CodeSystem">${data["codeSystem"]}</td>
|
|
4652
|
+
<td class="Comments">${data["Comments"] ?? ""}</td>
|
|
4653
|
+
<td class="Date">${templateUtilities.extractObservationSummaryEffectiveTime(data, timezone) ?? ""}</td>
|
|
4654
|
+
<td class="Source">${data["Source"] ?? ""}</td>
|
|
4655
|
+
</tr>`;
|
|
4656
|
+
}
|
|
4657
|
+
}
|
|
4658
|
+
html += `
|
|
4659
|
+
</tbody>
|
|
4660
|
+
</table>
|
|
4661
|
+
</div>`;
|
|
4662
|
+
return isSummaryCreated ? html : void 0;
|
|
4663
|
+
}
|
|
4530
4664
|
/**
|
|
4531
4665
|
* Internal static implementation that actually generates the narrative
|
|
4532
4666
|
* @param resources - FHIR Observation resources
|
|
@@ -4535,10 +4669,13 @@ var PregnancyTemplate = class _PregnancyTemplate {
|
|
|
4535
4669
|
*/
|
|
4536
4670
|
static generateStaticNarrative(resources, timezone) {
|
|
4537
4671
|
const templateUtilities = new TemplateUtilities(resources);
|
|
4672
|
+
const patients = resources.filter((r) => r.resourceType === "Patient");
|
|
4673
|
+
if (patients.length === 0) {
|
|
4674
|
+
return;
|
|
4675
|
+
}
|
|
4538
4676
|
const pregnancyHistoryFilter = IPSSectionResourceFilters["HistoryOfPregnancySection"];
|
|
4539
4677
|
const filteredResources = pregnancyHistoryFilter ? resources.filter(pregnancyHistoryFilter) : resources;
|
|
4540
4678
|
const observations = filteredResources.filter((r) => r.resourceType === "Observation");
|
|
4541
|
-
const conditions = filteredResources.filter((r) => r.resourceType === "Condition");
|
|
4542
4679
|
const EDD_LOINC = "11778-8";
|
|
4543
4680
|
const pregnancyStatusCodes = Object.keys(PREGNANCY_LOINC_CODES.PREGNANCY_STATUS);
|
|
4544
4681
|
const pregnancyOutcomeCodes = Object.keys(PREGNANCY_LOINC_CODES.PREGNANCY_OUTCOME);
|
|
@@ -4559,10 +4696,10 @@ var PregnancyTemplate = class _PregnancyTemplate {
|
|
|
4559
4696
|
const dateB = b.effectiveDateTime || b.effectivePeriod?.start;
|
|
4560
4697
|
return dateB && dateA ? new Date(dateB).getTime() - new Date(dateA).getTime() : 0;
|
|
4561
4698
|
});
|
|
4562
|
-
if (!pregnancyStatusObs && !eddObs && historyObs.length === 0
|
|
4563
|
-
return
|
|
4699
|
+
if (!pregnancyStatusObs && !eddObs && historyObs.length === 0) {
|
|
4700
|
+
return;
|
|
4564
4701
|
}
|
|
4565
|
-
let html = `<p>This list includes Observation
|
|
4702
|
+
let html = `<p>This list includes Observation resources relevant to pregnancy, sorted by date (most recent first).</p>`;
|
|
4566
4703
|
html += `
|
|
4567
4704
|
<table>
|
|
4568
4705
|
<thead>
|
|
@@ -4601,11 +4738,6 @@ var PregnancyTemplate = class _PregnancyTemplate {
|
|
|
4601
4738
|
const date = obs.effectiveDateTime || obs.effectivePeriod?.start;
|
|
4602
4739
|
rowResources.push({ resource: obs, date, type: "history" });
|
|
4603
4740
|
}
|
|
4604
|
-
for (const cond of conditions) {
|
|
4605
|
-
const condition = cond;
|
|
4606
|
-
const date = condition.onsetDateTime || condition.onsetPeriod?.start;
|
|
4607
|
-
rowResources.push({ resource: condition, date, type: "condition" });
|
|
4608
|
-
}
|
|
4609
4741
|
rowResources.sort((a, b) => {
|
|
4610
4742
|
if (!a.date && !b.date) return 0;
|
|
4611
4743
|
if (!a.date) return 1;
|
|
@@ -4621,7 +4753,7 @@ var PregnancyTemplate = class _PregnancyTemplate {
|
|
|
4621
4753
|
dateStr = date ? templateUtilities.renderTextAsHtml(templateUtilities.renderTime(date, timezone)) : "";
|
|
4622
4754
|
codeSystem = templateUtilities.renderTextAsHtml(templateUtilities.codeableConceptCoding(resource.code));
|
|
4623
4755
|
} else if (type === "edd") {
|
|
4624
|
-
result = "Estimated Delivery Date: " +
|
|
4756
|
+
result = "Estimated Delivery Date: " + (templateUtilities.extractObservationValue(resource) ?? "");
|
|
4625
4757
|
comments = templateUtilities.renderNotes(resource.note, timezone);
|
|
4626
4758
|
dateStr = date ? templateUtilities.renderTextAsHtml(templateUtilities.renderTime(date, timezone)) : "";
|
|
4627
4759
|
codeSystem = templateUtilities.renderTextAsHtml(templateUtilities.codeableConceptCoding(resource.code));
|
|
@@ -4630,11 +4762,6 @@ var PregnancyTemplate = class _PregnancyTemplate {
|
|
|
4630
4762
|
comments = templateUtilities.renderNotes(resource.note, timezone);
|
|
4631
4763
|
dateStr = date ? templateUtilities.renderTextAsHtml(templateUtilities.renderTime(date, timezone)) : "";
|
|
4632
4764
|
codeSystem = templateUtilities.renderTextAsHtml(templateUtilities.codeableConceptCoding(resource.code));
|
|
4633
|
-
} else if (type === "condition") {
|
|
4634
|
-
result = templateUtilities.renderTextAsHtml(templateUtilities.codeableConceptDisplay(resource.code));
|
|
4635
|
-
comments = templateUtilities.renderNotes(resource.note, timezone);
|
|
4636
|
-
dateStr = date ? templateUtilities.renderTextAsHtml(templateUtilities.renderTime(date, timezone)) : "";
|
|
4637
|
-
codeSystem = templateUtilities.renderTextAsHtml(templateUtilities.codeableConceptCoding(resource.code));
|
|
4638
4765
|
}
|
|
4639
4766
|
const rowKey = `${result}|${codeSystem}`;
|
|
4640
4767
|
if (!addedRows.has(rowKey)) {
|
|
@@ -5047,16 +5174,33 @@ var ComprehensiveIPSCompositionBuilder = class {
|
|
|
5047
5174
|
this.addSectionAsync(narrative, sectionType, validResources);
|
|
5048
5175
|
return this;
|
|
5049
5176
|
}
|
|
5050
|
-
async makeSectionFromSummaryAsync(sectionType, summaryCompositions, resources, timezone) {
|
|
5177
|
+
async makeSectionFromSummaryAsync(sectionType, summaryCompositions, resources, timezone, includeSummaryCompositionOnly = false) {
|
|
5051
5178
|
const sectionResources = [];
|
|
5052
5179
|
for (const summaryComposition of summaryCompositions) {
|
|
5053
5180
|
const resourceEntries = summaryComposition?.section?.flatMap((sec) => sec.entry || []) ?? [];
|
|
5054
|
-
|
|
5055
|
-
|
|
5056
|
-
|
|
5057
|
-
|
|
5058
|
-
|
|
5059
|
-
|
|
5181
|
+
if (includeSummaryCompositionOnly) {
|
|
5182
|
+
const addedEntries = /* @__PURE__ */ new Set();
|
|
5183
|
+
resourceEntries.forEach((entry) => {
|
|
5184
|
+
if (entry.reference && !addedEntries.has(entry.reference)) {
|
|
5185
|
+
const reference = entry.reference.split("/");
|
|
5186
|
+
if (reference.length === 2) {
|
|
5187
|
+
const resource = {
|
|
5188
|
+
id: reference[1],
|
|
5189
|
+
resourceType: reference[0]
|
|
5190
|
+
};
|
|
5191
|
+
sectionResources.push(resource);
|
|
5192
|
+
addedEntries.add(entry.reference);
|
|
5193
|
+
}
|
|
5194
|
+
}
|
|
5195
|
+
});
|
|
5196
|
+
} else {
|
|
5197
|
+
resources.forEach((resource) => {
|
|
5198
|
+
if (resourceEntries?.some((entry) => entry.reference === `${resource.resourceType}/${resource.id}`)) {
|
|
5199
|
+
this.resources.add(resource);
|
|
5200
|
+
sectionResources.push(resource);
|
|
5201
|
+
}
|
|
5202
|
+
});
|
|
5203
|
+
}
|
|
5060
5204
|
}
|
|
5061
5205
|
let narrative = await NarrativeGenerator.generateNarrativeAsync(
|
|
5062
5206
|
sectionType,
|
|
@@ -5081,8 +5225,10 @@ var ComprehensiveIPSCompositionBuilder = class {
|
|
|
5081
5225
|
* @param bundle - FHIR Bundle containing resources
|
|
5082
5226
|
* @param timezone - Optional timezone to use for date formatting
|
|
5083
5227
|
* @param useSummaryCompositions - Whether to use summary compositions (default: false)
|
|
5228
|
+
* @param includeSummaryCompositionOnly - Whether to include only summary composition resources (default: false)
|
|
5229
|
+
* @param consoleLogger - Optional console logger for logging (default: console)
|
|
5084
5230
|
*/
|
|
5085
|
-
async readBundleAsync(bundle, timezone, useSummaryCompositions = false, consoleLogger = console) {
|
|
5231
|
+
async readBundleAsync(bundle, timezone, useSummaryCompositions = false, includeSummaryCompositionOnly = false, consoleLogger = console) {
|
|
5086
5232
|
if (!bundle.entry) {
|
|
5087
5233
|
return this;
|
|
5088
5234
|
}
|
|
@@ -5106,14 +5252,14 @@ var ComprehensiveIPSCompositionBuilder = class {
|
|
|
5106
5252
|
const sectionIPSSummary = summaryIPSCompositionFilter ? resources.filter((resource) => summaryIPSCompositionFilter(resource)) : [];
|
|
5107
5253
|
if (sectionIPSSummary.length > 0) {
|
|
5108
5254
|
consoleLogger.info(`Using IPS summary composition for section: ${sectionType}`);
|
|
5109
|
-
await this.makeSectionFromSummaryAsync(sectionType, sectionIPSSummary, resources, timezone);
|
|
5255
|
+
await this.makeSectionFromSummaryAsync(sectionType, sectionIPSSummary, resources, timezone, includeSummaryCompositionOnly);
|
|
5110
5256
|
continue;
|
|
5111
5257
|
}
|
|
5112
5258
|
const summaryCompositionFilter = useSummaryCompositions ? IPSSectionResourceHelper.getSummaryCompositionFilterForSection(sectionType) : void 0;
|
|
5113
5259
|
const sectionSummary = summaryCompositionFilter ? resources.filter((resource) => summaryCompositionFilter(resource)) : [];
|
|
5114
5260
|
if (sectionSummary.length > 0) {
|
|
5115
5261
|
consoleLogger.info(`Using summary composition for section: ${sectionType}`);
|
|
5116
|
-
await this.makeSectionFromSummaryAsync(sectionType, sectionSummary, resources, timezone);
|
|
5262
|
+
await this.makeSectionFromSummaryAsync(sectionType, sectionSummary, resources, timezone, includeSummaryCompositionOnly);
|
|
5117
5263
|
} else {
|
|
5118
5264
|
consoleLogger.info(`Using individual resources for section: ${sectionType}`);
|
|
5119
5265
|
const sectionFilter = IPSSectionResourceHelper.getResourceFilterForSection(sectionType);
|
|
@@ -5129,10 +5275,11 @@ var ComprehensiveIPSCompositionBuilder = class {
|
|
|
5129
5275
|
* @param authorOrganizationName - Name of the authoring organization
|
|
5130
5276
|
* @param baseUrl - Base URL for the FHIR server (e.g., 'https://example.com/fhir')
|
|
5131
5277
|
* @param timezone - Optional timezone to use for date formatting (e.g., 'America/New_York', 'Europe/London')
|
|
5278
|
+
* @param includeSummaryCompositionOnly - Whether to include only summary composition resources (default: false)
|
|
5132
5279
|
* @param patientId - Optional patient ID to use as primary patient for composition reference
|
|
5133
5280
|
* @param now - Optional current date to use for composition date (defaults to new Date())
|
|
5134
5281
|
*/
|
|
5135
|
-
async buildBundleAsync(authorOrganizationId, authorOrganizationName, baseUrl, timezone, patientId, now) {
|
|
5282
|
+
async buildBundleAsync(authorOrganizationId, authorOrganizationName, baseUrl, timezone, includeSummaryCompositionOnly = false, patientId, now) {
|
|
5136
5283
|
if (baseUrl.endsWith("/")) {
|
|
5137
5284
|
baseUrl = baseUrl.slice(0, -1);
|
|
5138
5285
|
}
|
|
@@ -5181,30 +5328,32 @@ var ComprehensiveIPSCompositionBuilder = class {
|
|
|
5181
5328
|
fullUrl: `${baseUrl}/Composition/${composition.id}`,
|
|
5182
5329
|
resource: composition
|
|
5183
5330
|
});
|
|
5184
|
-
|
|
5331
|
+
if (!includeSummaryCompositionOnly) {
|
|
5332
|
+
this.patients.forEach((patient) => {
|
|
5333
|
+
bundle.entry?.push({
|
|
5334
|
+
fullUrl: `${baseUrl}/Patient/${patient.id}`,
|
|
5335
|
+
resource: patient
|
|
5336
|
+
});
|
|
5337
|
+
});
|
|
5338
|
+
this.resources.forEach((resource) => {
|
|
5339
|
+
if (resource.resourceType !== "Patient") {
|
|
5340
|
+
bundle.entry?.push(
|
|
5341
|
+
{
|
|
5342
|
+
fullUrl: `${baseUrl}/${resource.resourceType}/${resource.id}`,
|
|
5343
|
+
resource
|
|
5344
|
+
}
|
|
5345
|
+
);
|
|
5346
|
+
}
|
|
5347
|
+
});
|
|
5185
5348
|
bundle.entry?.push({
|
|
5186
|
-
fullUrl: `${baseUrl}/
|
|
5187
|
-
resource:
|
|
5349
|
+
fullUrl: `${baseUrl}/Organization/${authorOrganizationId}`,
|
|
5350
|
+
resource: {
|
|
5351
|
+
resourceType: "Organization",
|
|
5352
|
+
id: authorOrganizationId,
|
|
5353
|
+
name: authorOrganizationName
|
|
5354
|
+
}
|
|
5188
5355
|
});
|
|
5189
|
-
}
|
|
5190
|
-
this.resources.forEach((resource) => {
|
|
5191
|
-
if (resource.resourceType !== "Patient") {
|
|
5192
|
-
bundle.entry?.push(
|
|
5193
|
-
{
|
|
5194
|
-
fullUrl: `${baseUrl}/${resource.resourceType}/${resource.id}`,
|
|
5195
|
-
resource
|
|
5196
|
-
}
|
|
5197
|
-
);
|
|
5198
|
-
}
|
|
5199
|
-
});
|
|
5200
|
-
bundle.entry?.push({
|
|
5201
|
-
fullUrl: `${baseUrl}/Organization/${authorOrganizationId}`,
|
|
5202
|
-
resource: {
|
|
5203
|
-
resourceType: "Organization",
|
|
5204
|
-
id: authorOrganizationId,
|
|
5205
|
-
name: authorOrganizationName
|
|
5206
|
-
}
|
|
5207
|
-
});
|
|
5356
|
+
}
|
|
5208
5357
|
return bundle;
|
|
5209
5358
|
}
|
|
5210
5359
|
/**
|
|
@@ -5214,6 +5363,35 @@ var ComprehensiveIPSCompositionBuilder = class {
|
|
|
5214
5363
|
getSections() {
|
|
5215
5364
|
return this.sections;
|
|
5216
5365
|
}
|
|
5366
|
+
/**
|
|
5367
|
+
* Identifies remaining resource types that are missing from the composition bundle.
|
|
5368
|
+
* @param bundle - FHIR Bundle containing resources
|
|
5369
|
+
* @returns Array of missing resource type strings
|
|
5370
|
+
*/
|
|
5371
|
+
getRemainingResourcesFromCompositionBundle(bundle) {
|
|
5372
|
+
const resources = [];
|
|
5373
|
+
bundle.entry?.forEach((e) => {
|
|
5374
|
+
if (e.resource) {
|
|
5375
|
+
resources.push(e.resource);
|
|
5376
|
+
}
|
|
5377
|
+
});
|
|
5378
|
+
const remainingResources = /* @__PURE__ */ new Set();
|
|
5379
|
+
for (const sectionType of Object.values(IPSSections)) {
|
|
5380
|
+
const summaryIPSCompositionFilter = IPSSectionResourceHelper.getSummaryIPSCompositionFilterForSection(sectionType);
|
|
5381
|
+
const sectionIPSSummary = summaryIPSCompositionFilter ? resources.filter((resource) => summaryIPSCompositionFilter(resource)) : [];
|
|
5382
|
+
const summaryCompositionFilter = IPSSectionResourceHelper.getSummaryCompositionFilterForSection(sectionType);
|
|
5383
|
+
const sectionSummary = summaryCompositionFilter ? resources.filter((resource) => summaryCompositionFilter(resource)) : [];
|
|
5384
|
+
if (sectionSummary.length === 0 && sectionIPSSummary.length === 0) {
|
|
5385
|
+
const resourcesForSection = IPSSectionResourceHelper.getResourceTypesForSection(sectionType);
|
|
5386
|
+
resourcesForSection.forEach((resourceType) => {
|
|
5387
|
+
if (!remainingResources.has(resourceType) && !resources.some((r) => r.resourceType === resourceType)) {
|
|
5388
|
+
remainingResources.add(resourceType);
|
|
5389
|
+
}
|
|
5390
|
+
});
|
|
5391
|
+
}
|
|
5392
|
+
}
|
|
5393
|
+
return Array.from(remainingResources);
|
|
5394
|
+
}
|
|
5217
5395
|
};
|
|
5218
5396
|
|
|
5219
5397
|
// src/index.ts
|