@imranq2/fhirpatientsummary 1.0.32 → 1.0.33

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 CHANGED
@@ -197,7 +197,8 @@ var IPSSectionSummaryCompositionFilter = {
197
197
  ["HistoryOfProceduresSection" /* PROCEDURES */]: (resource) => resource.resourceType === "Composition" && resource.type?.coding?.some((c) => codingMatches(c, "procedure_summary_document", IPS_SUMMARY_COMPOSITION_TYPE_SYSTEM))
198
198
  };
199
199
  var IPSSectionSummaryIPSCompositionFilter = {
200
- ["VitalSignsSection" /* VITAL_SIGNS */]: (resource) => resource.resourceType === "Composition" && resource.type?.coding?.some((c) => c.system === IPS_SUMMARY_COMPOSITION_TYPE_SYSTEM && c.code === "ips_vital_summary_document")
200
+ ["Patient" /* PATIENT */]: (resource) => resource.resourceType === "Composition" && resource.type?.coding?.some((c) => codingMatches(c, "ips_patient_summary_document", IPS_SUMMARY_COMPOSITION_TYPE_SYSTEM)),
201
+ ["VitalSignsSection" /* VITAL_SIGNS */]: (resource) => resource.resourceType === "Composition" && resource.type?.coding?.some((c) => codingMatches(c, "ips_vital_summary_document", IPS_SUMMARY_COMPOSITION_TYPE_SYSTEM))
201
202
  };
202
203
  var IPSSectionResourceHelper = class {
203
204
  static getResourceFilterForSection(section) {
@@ -912,18 +913,6 @@ var TemplateUtilities = class {
912
913
  }
913
914
  return "";
914
915
  }
915
- /**
916
- * Returns the owner tag from the resource meta.security array.
917
- * @param resource - FHIR resource with meta tag
918
- * @returns The owner code if found, otherwise undefined
919
- */
920
- getOwnerTag(resource) {
921
- if (!resource?.meta?.security) return "";
922
- const ownerEntry = resource.meta.security.find(
923
- (sec) => sec.system === "https://www.icanbwell.com/owner" && !!sec.code
924
- );
925
- return ownerEntry?.code;
926
- }
927
916
  /**
928
917
  * Public method to render plain text as HTML, escaping special characters and replacing newlines with <br />.
929
918
  * This method should be used whenever displaying user-supplied or FHIR resource text in HTML to prevent XSS vulnerabilities
@@ -944,6 +933,17 @@ var TemplateUtilities = class {
944
933
  }
945
934
  return text.charAt(0).toUpperCase() + text.slice(1);
946
935
  }
936
+ renderListSectionData(sectionData) {
937
+ if (!sectionData || !Array.isArray(sectionData) || sectionData.length === 0) {
938
+ return "";
939
+ }
940
+ const items = [];
941
+ for (const section of sectionData) {
942
+ items.push(this.renderTextAsHtml(section.text?.div || ""));
943
+ }
944
+ const listString = Array.from(items).map((item) => `<li>${item}</li>`).join("");
945
+ return `<ul>${listString}</ul>`;
946
+ }
947
947
  /**
948
948
  * Renders note elements from a FHIR resource in a standardized format
949
949
  * Can render as simple comma-separated text or as styled HTML with timestamps
@@ -1431,6 +1431,60 @@ var PatientTemplate = class _PatientTemplate {
1431
1431
  generateNarrative(resources, timezone) {
1432
1432
  return _PatientTemplate.generateStaticNarrative(resources, timezone);
1433
1433
  }
1434
+ /**
1435
+ * Generate HTML narrative for Patient resources using summary
1436
+ * @param resources - FHIR Composition resources
1437
+ * @param timezone - Optional timezone to use for date formatting (e.g., 'America/New_York', 'Europe/London')
1438
+ * @returns HTML string for rendering
1439
+ */
1440
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
1441
+ generateSummaryNarrative(resources, timezone) {
1442
+ const templateUtilities = new TemplateUtilities(resources);
1443
+ const compositionResources = resources[0];
1444
+ const data = {};
1445
+ for (const rowData of compositionResources.section ?? []) {
1446
+ for (const columnData of rowData.section ?? []) {
1447
+ switch (columnData.title) {
1448
+ case "Name":
1449
+ case "Address":
1450
+ case "Communication":
1451
+ data[columnData.title] = templateUtilities.renderListSectionData(columnData.section ?? []);
1452
+ break;
1453
+ case "Telecom": {
1454
+ const telecomStringParts = [];
1455
+ for (const telecomData of columnData.section ?? []) {
1456
+ const telecomSystem = telecomData?.title;
1457
+ const telecomValue = templateUtilities.renderListSectionData(telecomData.section ?? []);
1458
+ if (telecomSystem && telecomValue) {
1459
+ telecomStringParts.push(`<li><strong>${telecomSystem}:</strong>${telecomValue}</li>`);
1460
+ }
1461
+ }
1462
+ data["Telecom"] = `<ul>${telecomStringParts.join("")}</ul>`;
1463
+ break;
1464
+ }
1465
+ default:
1466
+ if (columnData.title) {
1467
+ data[columnData.title] = templateUtilities.renderTextAsHtml(columnData.text?.div ?? "");
1468
+ }
1469
+ break;
1470
+ }
1471
+ }
1472
+ }
1473
+ let html = `<p>This section merges all Patient resources into a single combined patient record, preferring non-empty values for each field.</p>`;
1474
+ html += `<div>
1475
+ <ul>
1476
+ <li><strong>Name(s):</strong>${data["Name"] || ""}</li>
1477
+ <li><strong>Gender:</strong>${data["Gender"] || ""}</li>
1478
+ <li><strong>Date of Birth:</strong>${data["Date of Birth"] || ""}</li>
1479
+ <li><strong>Telecom:</strong>${data["Telecom"] || ""}</li>
1480
+ <li><strong>Address(es):</strong>${data["Address"] || ""}</li>
1481
+ <li><strong>Marital Status:</strong> ${data["Marital Status"] || ""}</li>
1482
+ <li><strong>Deceased:</strong>${data["Deceased"] || ""}</li>
1483
+ <li><strong>Language(s):</strong>${data["Communication"] || ""}</li>
1484
+ </ul>
1485
+ </div>`;
1486
+ return html;
1487
+ }
1434
1488
  /**
1435
1489
  * Internal static implementation that actually generates the narrative
1436
1490
  * @param resources - FHIR Patient resources
@@ -1524,7 +1578,8 @@ var PatientTemplate = class _PatientTemplate {
1524
1578
  }
1525
1579
  }
1526
1580
  });
1527
- return Array.from(uniqueNames).map((nameText) => `<ul><li>${nameText}</li></ul>`).join("");
1581
+ const namesHtml = Array.from(uniqueNames).map((nameText) => `<li>${nameText}</li>`).join("");
1582
+ return `<ul>${namesHtml}</ul>`;
1528
1583
  }
1529
1584
  /**
1530
1585
  * Renders patient telecom information grouped by system
@@ -1628,7 +1683,8 @@ var PatientTemplate = class _PatientTemplate {
1628
1683
  }
1629
1684
  });
1630
1685
  const deduplicatedAddresses = this.deduplicateSimilarAddresses(Array.from(uniqueAddresses));
1631
- return deduplicatedAddresses.map((addressText) => `<ul><li>${addressText}</li></ul>`).join("");
1686
+ const addressesHtml = deduplicatedAddresses.map((addressText) => `<li>${addressText}</li>`).join("");
1687
+ return `<ul>${addressesHtml}</ul>`;
1632
1688
  }
1633
1689
  /**
1634
1690
  * Calculates the similarity between two strings using Levenshtein distance
@@ -1746,7 +1802,8 @@ var PatientTemplate = class _PatientTemplate {
1746
1802
  uniqueLanguages.add(language);
1747
1803
  }
1748
1804
  });
1749
- return Array.from(uniqueLanguages).map((language) => `<ul><li>${language}${preferredLanguages.has(language) ? " (preferred)" : ""}</li></ul>`).join("");
1805
+ const languagesHtml = Array.from(uniqueLanguages).map((language) => `<li>${language}${preferredLanguages.has(language) ? " (preferred)" : ""}</li>`).join("");
1806
+ return `<ul>${languagesHtml}</ul>`;
1750
1807
  }
1751
1808
  /**
1752
1809
  * Capitalizes first letter of a string
@@ -1790,7 +1847,6 @@ var AllergyIntoleranceTemplate = class _AllergyIntoleranceTemplate {
1790
1847
  <th>Code (System)</th>
1791
1848
  <th>Criticality</th>
1792
1849
  <th>Recorded Date</th>
1793
- <th>Source</th>
1794
1850
  </tr>
1795
1851
  </thead>
1796
1852
  <tbody>`;
@@ -1810,13 +1866,13 @@ var AllergyIntoleranceTemplate = class _AllergyIntoleranceTemplate {
1810
1866
  case "Recorded Date":
1811
1867
  data["recordedDate"] = templateUtilities.renderTextAsHtml(columnData.text?.div ?? "");
1812
1868
  break;
1813
- case "Source":
1814
- data["source"] = templateUtilities.renderTextAsHtml(columnData.text?.div ?? "");
1815
- break;
1816
1869
  default:
1817
1870
  break;
1818
1871
  }
1819
1872
  }
1873
+ if (data["allergen"]?.toLowerCase() === "unknown") {
1874
+ continue;
1875
+ }
1820
1876
  isSummaryCreated = true;
1821
1877
  html += `
1822
1878
  <tr>
@@ -1824,7 +1880,6 @@ var AllergyIntoleranceTemplate = class _AllergyIntoleranceTemplate {
1824
1880
  <td>${data["codeSystem"] ?? ""}</td>
1825
1881
  <td>${data["criticality"] ?? ""}</td>
1826
1882
  <td>${templateUtilities.renderTime(data["recordedDate"], timezone) ?? ""}</td>
1827
- <td>${data["source"] ?? ""}</td>
1828
1883
  </tr>`;
1829
1884
  }
1830
1885
  }
@@ -1878,7 +1933,6 @@ var AllergyIntoleranceTemplate = class _AllergyIntoleranceTemplate {
1878
1933
  <th>Reaction</th>
1879
1934
  <th>Onset Date</th>
1880
1935
  <th>Comments</th>
1881
- <th>Source</th>
1882
1936
  </tr>
1883
1937
  </thead>
1884
1938
  <tbody>`;
@@ -1908,7 +1962,6 @@ var AllergyIntoleranceTemplate = class _AllergyIntoleranceTemplate {
1908
1962
  <th>Onset Date</th>
1909
1963
  <th>Comments</th>
1910
1964
  <th>Resolved Date</th>
1911
- <th>Source</th>
1912
1965
  </tr>
1913
1966
  </thead>
1914
1967
  <tbody>`;
@@ -1937,16 +1990,19 @@ var AllergyIntoleranceTemplate = class _AllergyIntoleranceTemplate {
1937
1990
  static generateAllergyRows(allergies, templateUtilities, timezone, includeResolved = false) {
1938
1991
  let html = "";
1939
1992
  for (const allergy of allergies) {
1993
+ const allergenName = templateUtilities.codeableConceptDisplay(allergy.code);
1994
+ if (allergenName?.toLowerCase() === "unknown") {
1995
+ continue;
1996
+ }
1940
1997
  html += `
1941
1998
  <tr>
1942
- <td class="Name"><span class="AllergenName">${templateUtilities.capitalizeFirstLetter(templateUtilities.renderTextAsHtml(templateUtilities.codeableConceptDisplay(allergy.code)))}</span></td>
1999
+ <td class="Name"><span class="AllergenName">${templateUtilities.capitalizeFirstLetter(templateUtilities.renderTextAsHtml(allergenName))}</span></td>
1943
2000
  <td class="Status">${templateUtilities.renderTextAsHtml(templateUtilities.codeableConceptDisplay(allergy.clinicalStatus)) || ""}</td>
1944
2001
  <td class="CodeSystem">${templateUtilities.codeableConceptCoding(allergy.code)}</td>
1945
2002
  <td class="Category">${templateUtilities.renderTextAsHtml(templateUtilities.safeConcat(allergy.category)) || ""}</td>
1946
2003
  <td class="Reaction">${templateUtilities.renderTextAsHtml(templateUtilities.concatReactionManifestation(allergy.reaction)) || ""}</td>
1947
2004
  <td class="OnsetDate">${templateUtilities.renderTextAsHtml(templateUtilities.renderTime(allergy.onsetDateTime, timezone)) || ""}</td>
1948
- <td class="Comments">${templateUtilities.renderNotes(allergy.note, timezone, { styled: true, warning: true })}</td>
1949
- <td class="Source">${templateUtilities.getOwnerTag(allergy)}</td>`;
2005
+ <td class="Comments">${templateUtilities.renderNotes(allergy.note, timezone, { styled: true, warning: true })}</td>`;
1950
2006
  if (includeResolved) {
1951
2007
  let endDate = "";
1952
2008
  if (allergy.extension && Array.isArray(allergy.extension)) {
@@ -2001,9 +2057,7 @@ var MedicationSummaryTemplate = class _MedicationSummaryTemplate {
2001
2057
  <th>Status</th>
2002
2058
  <th>Sig</th>
2003
2059
  <th>Days of Supply</th>
2004
- <th>Refills</th>
2005
2060
  <th>Start Date</th>
2006
- <th>Source</th>
2007
2061
  </tr>
2008
2062
  </thead>
2009
2063
  <tbody>`;
@@ -2029,15 +2083,9 @@ var MedicationSummaryTemplate = class _MedicationSummaryTemplate {
2029
2083
  case "Days Of Supply":
2030
2084
  data["daysOfSupply"] = templateUtilities.renderTextAsHtml(columnData.text?.div ?? "");
2031
2085
  break;
2032
- case "Refills Remaining":
2033
- data["refills"] = templateUtilities.renderTextAsHtml(columnData.text?.div ?? "");
2034
- break;
2035
2086
  case "Authored On Date":
2036
2087
  data["startDate"] = templateUtilities.renderTextAsHtml(columnData.text?.div ?? "");
2037
2088
  break;
2038
- case "Source":
2039
- data["source"] = templateUtilities.renderTextAsHtml(columnData.text?.div ?? "");
2040
- break;
2041
2089
  default:
2042
2090
  break;
2043
2091
  }
@@ -2053,6 +2101,9 @@ var MedicationSummaryTemplate = class _MedicationSummaryTemplate {
2053
2101
  skippedMedications++;
2054
2102
  }
2055
2103
  if (data["status"] === "active" || startDateObj && startDateObj >= twoYearsAgo) {
2104
+ if (data["medication"]?.toLowerCase() === "unknown") {
2105
+ continue;
2106
+ }
2056
2107
  isSummaryCreated = true;
2057
2108
  html += `
2058
2109
  <tr>
@@ -2061,9 +2112,7 @@ var MedicationSummaryTemplate = class _MedicationSummaryTemplate {
2061
2112
  <td>${templateUtilities.renderTextAsHtml(data["status"])}</td>
2062
2113
  <td>${templateUtilities.renderTextAsHtml(data["sig-prescriber"] || data["sig-pharmacy"])}</td>
2063
2114
  <td>${templateUtilities.renderTextAsHtml(data["daysOfSupply"])}</td>
2064
- <td>${templateUtilities.renderTextAsHtml(data["refills"])}</td>
2065
2115
  <td>${templateUtilities.renderTime(data["startDate"], timezone)}</td>
2066
- <td>${templateUtilities.renderTextAsHtml(data["source"])}</td>
2067
2116
  </tr>`;
2068
2117
  }
2069
2118
  }
@@ -2188,9 +2237,7 @@ var MedicationSummaryTemplate = class _MedicationSummaryTemplate {
2188
2237
  <th>Code (System)</th>
2189
2238
  <th>Sig</th>
2190
2239
  <th>Dispense Quantity</th>
2191
- <th>Refills</th>
2192
2240
  <th>Start Date</th>
2193
- <th>Source</th>
2194
2241
  </tr>
2195
2242
  </thead>
2196
2243
  <tbody>`;
@@ -2199,7 +2246,6 @@ var MedicationSummaryTemplate = class _MedicationSummaryTemplate {
2199
2246
  let medicationName;
2200
2247
  let sig;
2201
2248
  let dispenseQuantity = "";
2202
- let refills = "";
2203
2249
  let startDate = "";
2204
2250
  let codeSystemDisplay = "";
2205
2251
  if (medication.type === "request") {
@@ -2215,7 +2261,6 @@ var MedicationSummaryTemplate = class _MedicationSummaryTemplate {
2215
2261
  dispenseQuantity = `${quantity.value} ${quantity.unit || quantity.code || ""}`.trim();
2216
2262
  }
2217
2263
  }
2218
- refills = mr.dispenseRequest?.numberOfRepeatsAllowed?.toString() || "";
2219
2264
  if (mr.dispenseRequest?.validityPeriod) {
2220
2265
  startDate = mr.dispenseRequest.validityPeriod.start || "";
2221
2266
  } else {
@@ -2240,6 +2285,9 @@ var MedicationSummaryTemplate = class _MedicationSummaryTemplate {
2240
2285
  codeSystemDisplay = templateUtilities.codeableConceptCoding(ms.medicationCodeableConcept);
2241
2286
  }
2242
2287
  }
2288
+ if (medicationName?.toLowerCase() === "unknown") {
2289
+ continue;
2290
+ }
2243
2291
  html += `
2244
2292
  <tr>
2245
2293
  <td>${type}</td>
@@ -2247,9 +2295,7 @@ var MedicationSummaryTemplate = class _MedicationSummaryTemplate {
2247
2295
  <td>${codeSystemDisplay}</td>
2248
2296
  <td>${sig}</td>
2249
2297
  <td>${dispenseQuantity}</td>
2250
- <td>${refills}</td>
2251
2298
  <td>${startDate}</td>
2252
- <td>${templateUtilities.getOwnerTag(medication.resource)}</td>
2253
2299
  </tr>`;
2254
2300
  }
2255
2301
  html += `
@@ -2294,7 +2340,6 @@ var ImmunizationsTemplate = class _ImmunizationsTemplate {
2294
2340
  <th>Code (System)</th>
2295
2341
  <th>Status</th>
2296
2342
  <th>Date</th>
2297
- <th>Source</th>
2298
2343
  </tr>
2299
2344
  </thead>
2300
2345
  <tbody>`;
@@ -2314,14 +2359,14 @@ var ImmunizationsTemplate = class _ImmunizationsTemplate {
2314
2359
  case "occurrenceDateTime":
2315
2360
  data["occurrenceDateTime"] = templateUtilities.renderTextAsHtml(columnData.text?.div ?? "");
2316
2361
  break;
2317
- case "Source":
2318
- data["source"] = templateUtilities.renderTextAsHtml(columnData.text?.div ?? "");
2319
- break;
2320
2362
  default:
2321
2363
  break;
2322
2364
  }
2323
2365
  }
2324
2366
  if (data["status"] === "completed") {
2367
+ if (data["immunization"]?.toLowerCase() === "unknown") {
2368
+ continue;
2369
+ }
2325
2370
  isSummaryCreated = true;
2326
2371
  html += `
2327
2372
  <tr>
@@ -2329,7 +2374,6 @@ var ImmunizationsTemplate = class _ImmunizationsTemplate {
2329
2374
  <td>${data["codeSystem"] ?? ""}</td>
2330
2375
  <td>${data["status"] ?? ""}</td>
2331
2376
  <td>${templateUtilities.renderTime(data["occurrenceDateTime"], timezone) ?? ""}</td>
2332
- <td>${data["source"] ?? ""}</td>
2333
2377
  </tr>`;
2334
2378
  }
2335
2379
  }
@@ -2360,7 +2404,6 @@ var ImmunizationsTemplate = class _ImmunizationsTemplate {
2360
2404
  <th>Lot Number</th>
2361
2405
  <th>Comments</th>
2362
2406
  <th>Date</th>
2363
- <th>Source</th>
2364
2407
  </tr>
2365
2408
  </thead>
2366
2409
  <tbody>`;
@@ -2368,9 +2411,13 @@ var ImmunizationsTemplate = class _ImmunizationsTemplate {
2368
2411
  if (immunizations.length > 0) {
2369
2412
  for (const resourceItem of immunizations) {
2370
2413
  const imm = resourceItem;
2414
+ const immunizationName = templateUtilities.codeableConceptDisplay(imm.vaccineCode);
2415
+ if (immunizationName?.toLowerCase() === "unknown") {
2416
+ continue;
2417
+ }
2371
2418
  html += `
2372
2419
  <tr>
2373
- <td>${templateUtilities.capitalizeFirstLetter(templateUtilities.renderTextAsHtml(templateUtilities.codeableConceptDisplay(imm.vaccineCode)))}</td>
2420
+ <td>${templateUtilities.capitalizeFirstLetter(templateUtilities.renderTextAsHtml(immunizationName))}</td>
2374
2421
  <td>${templateUtilities.codeableConceptCoding(imm.vaccineCode)}</td>
2375
2422
  <td>${imm.status || ""}</td>
2376
2423
  <td>${templateUtilities.concatDoseNumber(imm.protocolApplied)}</td>
@@ -2378,7 +2425,6 @@ var ImmunizationsTemplate = class _ImmunizationsTemplate {
2378
2425
  <td>${imm.lotNumber || ""}</td>
2379
2426
  <td>${templateUtilities.renderNotes(imm.note, timezone)}</td>
2380
2427
  <td>${templateUtilities.renderTime(imm.occurrenceDateTime, timezone)}</td>
2381
- <td>${templateUtilities.getOwnerTag(imm)}</td>
2382
2428
  </tr>`;
2383
2429
  }
2384
2430
  }
@@ -2428,7 +2474,6 @@ var ProblemListTemplate = class _ProblemListTemplate {
2428
2474
  <th>Code (System)</th>
2429
2475
  <th>Onset Date</th>
2430
2476
  <th>Recorded Date</th>
2431
- <th>Source</th>
2432
2477
  </tr>
2433
2478
  </thead>
2434
2479
  <tbody>`;
@@ -2439,13 +2484,15 @@ var ProblemListTemplate = class _ProblemListTemplate {
2439
2484
  if (codeAndSystem && seenCodeAndSystems.has(codeAndSystem)) {
2440
2485
  continue;
2441
2486
  }
2487
+ if (conditionDisplay?.toLowerCase() === "unknown") {
2488
+ continue;
2489
+ }
2442
2490
  seenCodeAndSystems.add(codeAndSystem);
2443
2491
  html += `<tr>
2444
2492
  <td class="Name">${templateUtilities.capitalizeFirstLetter(conditionDisplay)}</td>
2445
2493
  <td class="CodeSystem">${codeAndSystem}</td>
2446
2494
  <td class="OnsetDate">${templateUtilities.renderDate(cond.onsetDateTime)}</td>
2447
2495
  <td class="RecordedDate">${templateUtilities.renderDate(cond.recordedDate)}</td>
2448
- <td class="Source">${templateUtilities.getOwnerTag(cond)}</td>
2449
2496
  </tr>`;
2450
2497
  }
2451
2498
  html += `</tbody>
@@ -2485,7 +2532,6 @@ var VitalSignsTemplate = class _VitalSignsTemplate {
2485
2532
  <th>Code (System)</th>
2486
2533
  <th>Result</th>
2487
2534
  <th>Date</th>
2488
- <th>Source</th>
2489
2535
  </tr>
2490
2536
  </thead>
2491
2537
  <tbody>`;
@@ -2518,6 +2564,9 @@ var VitalSignsTemplate = class _VitalSignsTemplate {
2518
2564
  data[columnTitle] = templateUtilities.renderTextAsHtml(columnData.text?.div ?? "");
2519
2565
  }
2520
2566
  }
2567
+ if (data["Vital Name"]?.toLowerCase() === "unknown") {
2568
+ continue;
2569
+ }
2521
2570
  isSummaryCreated = true;
2522
2571
  html += `
2523
2572
  <tr>
@@ -2525,7 +2574,6 @@ var VitalSignsTemplate = class _VitalSignsTemplate {
2525
2574
  <td>${data["codeSystem"] ?? ""}</td>
2526
2575
  <td>${templateUtilities.extractObservationSummaryValue(data, timezone) ?? ""}</td>
2527
2576
  <td>${templateUtilities.extractObservationSummaryEffectiveTime(data, timezone) ?? ""}</td>
2528
- <td>${data["Source"] ?? ""}</td>
2529
2577
  </tr>`;
2530
2578
  }
2531
2579
  }
@@ -2563,14 +2611,17 @@ var VitalSignsTemplate = class _VitalSignsTemplate {
2563
2611
  <th>Component(s)</th>
2564
2612
  <th>Comments</th>
2565
2613
  <th>Date</th>
2566
- <th>Source</th>
2567
2614
  </tr>
2568
2615
  </thead>
2569
2616
  <tbody>`;
2570
2617
  for (const obs of observations) {
2618
+ const vitalName = templateUtilities.codeableConceptDisplay(obs.code, "display");
2619
+ if (vitalName?.toLowerCase() === "unknown") {
2620
+ continue;
2621
+ }
2571
2622
  html += `
2572
2623
  <tr>
2573
- <td>${templateUtilities.capitalizeFirstLetter(templateUtilities.renderTextAsHtml(templateUtilities.codeableConceptDisplay(obs.code, "display")))}</td>
2624
+ <td>${templateUtilities.capitalizeFirstLetter(templateUtilities.renderTextAsHtml(vitalName))}</td>
2574
2625
  <td>${templateUtilities.codeableConceptCoding(obs.code)}</td>
2575
2626
  <td>${templateUtilities.extractObservationValue(obs)}</td>
2576
2627
  <td>${templateUtilities.extractObservationValueUnit(obs)}</td>
@@ -2578,7 +2629,6 @@ var VitalSignsTemplate = class _VitalSignsTemplate {
2578
2629
  <td>${templateUtilities.renderComponent(obs.component)}</td>
2579
2630
  <td>${templateUtilities.renderNotes(obs.note, timezone)}</td>
2580
2631
  <td>${obs.effectiveDateTime ? templateUtilities.renderTime(obs.effectiveDateTime, timezone) : obs.effectivePeriod ? templateUtilities.renderPeriod(obs.effectivePeriod, timezone) : ""}</td>
2581
- <td>${templateUtilities.getOwnerTag(obs)}</td>
2582
2632
  </tr>`;
2583
2633
  }
2584
2634
  html += `
@@ -2625,10 +2675,14 @@ var MedicalDevicesTemplate = class _MedicalDevicesTemplate {
2625
2675
  });
2626
2676
  let isDeviceAdded = false;
2627
2677
  for (const dus of deviceStatements) {
2678
+ const deviceName = templateUtilities.renderTextAsHtml(templateUtilities.renderDevice(dus.device));
2679
+ if (deviceName?.toLowerCase() === "unknown") {
2680
+ continue;
2681
+ }
2628
2682
  isDeviceAdded = true;
2629
2683
  html += `
2630
2684
  <tr>
2631
- <td>${templateUtilities.capitalizeFirstLetter(templateUtilities.renderTextAsHtml(templateUtilities.renderDevice(dus.device)))}</td>
2685
+ <td>${templateUtilities.capitalizeFirstLetter(deviceName)}</td>
2632
2686
  <td>${templateUtilities.renderTextAsHtml(dus.status || "")}</td>
2633
2687
  <td>${templateUtilities.renderNotes(dus.note, timezone)}</td>
2634
2688
  <td>${templateUtilities.renderTextAsHtml(templateUtilities.renderRecorded(dus.recordedOn, timezone))}</td>
@@ -3002,7 +3056,6 @@ var DiagnosticResultsTemplate = class _DiagnosticResultsTemplate {
3002
3056
  <th>Result</th>
3003
3057
  <th>Reference Range</th>
3004
3058
  <th>Date</th>
3005
- <th>Source</th>
3006
3059
  </tr>
3007
3060
  </thead>
3008
3061
  <tbody>`;
@@ -3016,7 +3069,6 @@ var DiagnosticResultsTemplate = class _DiagnosticResultsTemplate {
3016
3069
  <th>Report</th>
3017
3070
  <th>Performer</th>
3018
3071
  <th>Issued</th>
3019
- <th>Source</th>
3020
3072
  </tr>
3021
3073
  </thead>
3022
3074
  <tbody>`;
@@ -3063,8 +3115,6 @@ var DiagnosticResultsTemplate = class _DiagnosticResultsTemplate {
3063
3115
  case "Status":
3064
3116
  data["status"] = templateUtilities.renderTextAsHtml(columnData.text?.div ?? "");
3065
3117
  break;
3066
- case "Source":
3067
- data["source"] = templateUtilities.renderTextAsHtml(columnData.text?.div ?? "");
3068
3118
  break;
3069
3119
  default:
3070
3120
  break;
@@ -3090,6 +3140,9 @@ var DiagnosticResultsTemplate = class _DiagnosticResultsTemplate {
3090
3140
  for (const component of components) {
3091
3141
  const componentCode = `${groupName}${component["code"] ?? ""}`;
3092
3142
  if (componentCode && !observationAdded.has(componentCode)) {
3143
+ if (component["code"]?.toLowerCase() === "unknown") {
3144
+ continue;
3145
+ }
3093
3146
  observationAdded.add(componentCode);
3094
3147
  this.formatSummaryObservationData(component);
3095
3148
  observationhtml += `
@@ -3099,7 +3152,6 @@ var DiagnosticResultsTemplate = class _DiagnosticResultsTemplate {
3099
3152
  <td>${templateUtilities.renderTextAsHtml(component["formattedValue"]) ?? ""}</td>
3100
3153
  <td>${templateUtilities.renderTextAsHtml(component["referenceRange"])?.trim() ?? ""}</td>
3101
3154
  <td>${date ?? ""}</td>
3102
- <td>${data["source"] ?? ""}</td>
3103
3155
  </tr>`;
3104
3156
  }
3105
3157
  }
@@ -3107,6 +3159,9 @@ var DiagnosticResultsTemplate = class _DiagnosticResultsTemplate {
3107
3159
  if (obsDate && obsDate >= twoYearsAgo) {
3108
3160
  const code = data["code"] ?? "";
3109
3161
  if (code && !observationAdded.has(code)) {
3162
+ if (code.toLowerCase() === "unknown") {
3163
+ continue;
3164
+ }
3110
3165
  observationAdded.add(code);
3111
3166
  this.formatSummaryObservationData(data);
3112
3167
  observationhtml += `
@@ -3116,7 +3171,6 @@ var DiagnosticResultsTemplate = class _DiagnosticResultsTemplate {
3116
3171
  <td>${templateUtilities.renderTextAsHtml(data["formattedValue"]) ?? ""}</td>
3117
3172
  <td>${templateUtilities.renderTextAsHtml(data["referenceRange"])?.trim() ?? ""}</td>
3118
3173
  <td>${date ?? ""}</td>
3119
- <td>${data["source"] ?? ""}</td>
3120
3174
  </tr>`;
3121
3175
  }
3122
3176
  }
@@ -3129,13 +3183,15 @@ var DiagnosticResultsTemplate = class _DiagnosticResultsTemplate {
3129
3183
  if (data["status"] === "final" && issuedDate && issuedDate >= twoYearsAgo) {
3130
3184
  const reportName = data["report"] ?? "";
3131
3185
  if (reportName && !diagnosticReportAdded.has(reportName)) {
3186
+ if (reportName.toLowerCase() === "unknown") {
3187
+ continue;
3188
+ }
3132
3189
  diagnosticReportAdded.add(reportName);
3133
3190
  diagnosticReporthtml += `
3134
3191
  <tr>
3135
3192
  <td>${templateUtilities.capitalizeFirstLetter(data["report"] ?? "")}</td>
3136
3193
  <td>${data["performer"] ?? ""}</td>
3137
3194
  <td>${templateUtilities.renderTime(data["issued"], timezone) ?? ""}</td>
3138
- <td>${data["source"] ?? ""}</td>
3139
3195
  </tr>`;
3140
3196
  }
3141
3197
  }
@@ -3320,7 +3376,6 @@ var DiagnosticResultsTemplate = class _DiagnosticResultsTemplate {
3320
3376
  <th>Result</th>
3321
3377
  <th>Reference Range</th>
3322
3378
  <th>Date</th>
3323
- <th>Source</th>
3324
3379
  </tr>
3325
3380
  </thead>
3326
3381
  <tbody>`;
@@ -3329,6 +3384,9 @@ var DiagnosticResultsTemplate = class _DiagnosticResultsTemplate {
3329
3384
  const obsCodeDisplay = templateUtilities.renderTextAsHtml(templateUtilities.codeableConceptDisplay(obs.code));
3330
3385
  const obsCodeAndSystem = templateUtilities.codeableConceptCoding(obs.code);
3331
3386
  if (!observationAdded.has(obsCodeDisplay) && !observationAdded.has(obsCodeAndSystem)) {
3387
+ if (obsCodeDisplay?.toLowerCase() === "unknown") {
3388
+ continue;
3389
+ }
3332
3390
  observationAdded.add(obsCodeDisplay);
3333
3391
  observationAdded.add(obsCodeAndSystem);
3334
3392
  html += `
@@ -3338,7 +3396,6 @@ var DiagnosticResultsTemplate = class _DiagnosticResultsTemplate {
3338
3396
  <td>${templateUtilities.extractObservationValue(obs)}</td>
3339
3397
  <td>${templateUtilities.concatReferenceRange(obs.referenceRange)}</td>
3340
3398
  <td>${obs.effectiveDateTime ? templateUtilities.renderTime(obs.effectiveDateTime, timezone) : obs.effectivePeriod ? templateUtilities.renderPeriod(obs.effectivePeriod, timezone) : ""}</td>
3341
- <td>${templateUtilities.getOwnerTag(obs)}</td>
3342
3399
  </tr>`;
3343
3400
  }
3344
3401
  }
@@ -3365,7 +3422,6 @@ var DiagnosticResultsTemplate = class _DiagnosticResultsTemplate {
3365
3422
  <th>Category</th>
3366
3423
  <th>Result</th>
3367
3424
  <th>Issued</th>
3368
- <th>Source</th>
3369
3425
  </tr>
3370
3426
  </thead>
3371
3427
  <tbody>`;
@@ -3374,6 +3430,9 @@ var DiagnosticResultsTemplate = class _DiagnosticResultsTemplate {
3374
3430
  const reportName = templateUtilities.renderTextAsHtml(templateUtilities.codeableConceptDisplay(report.code));
3375
3431
  const codeAndSystem = templateUtilities.codeableConceptCoding(report.code);
3376
3432
  if (!diagnosticReportAdded.has(reportName) && !diagnosticReportAdded.has(codeAndSystem)) {
3433
+ if (reportName?.toLowerCase() === "unknown") {
3434
+ continue;
3435
+ }
3377
3436
  diagnosticReportAdded.add(reportName);
3378
3437
  diagnosticReportAdded.add(codeAndSystem);
3379
3438
  let resultCount = "";
@@ -3387,7 +3446,6 @@ var DiagnosticResultsTemplate = class _DiagnosticResultsTemplate {
3387
3446
  <td>${templateUtilities.firstFromCodeableConceptList(report.category)}</td>
3388
3447
  <td>${resultCount}</td>
3389
3448
  <td>${report.issued ? templateUtilities.renderTime(report.issued, timezone) : ""}</td>
3390
- <td>${templateUtilities.getOwnerTag(report)}</td>
3391
3449
  </tr>`;
3392
3450
  }
3393
3451
  }
@@ -3454,7 +3512,6 @@ var HistoryOfProceduresTemplate = class _HistoryOfProceduresTemplate {
3454
3512
  <th>Code (System)</th>
3455
3513
  <th>Performer</th>
3456
3514
  <th>Date</th>
3457
- <th>Source</th>
3458
3515
  </tr>
3459
3516
  </thead>
3460
3517
  <tbody>`;
@@ -3474,13 +3531,14 @@ var HistoryOfProceduresTemplate = class _HistoryOfProceduresTemplate {
3474
3531
  case "Performed Date":
3475
3532
  data["date"] = columnData.text?.div ?? "";
3476
3533
  break;
3477
- case "Source":
3478
- data["source"] = templateUtilities.renderTextAsHtml(columnData.text?.div ?? "");
3479
3534
  break;
3480
3535
  default:
3481
3536
  break;
3482
3537
  }
3483
3538
  }
3539
+ if (data["procedure"]?.toLowerCase() === "unknown") {
3540
+ continue;
3541
+ }
3484
3542
  isSummaryCreated = true;
3485
3543
  html += `
3486
3544
  <tr>
@@ -3488,7 +3546,6 @@ var HistoryOfProceduresTemplate = class _HistoryOfProceduresTemplate {
3488
3546
  <td>${data["codeSystem"] ?? ""}</td>
3489
3547
  <td>${data["performer"] ?? ""}</td>
3490
3548
  <td>${templateUtilities.renderTime(data["date"], timezone) ?? ""}</td>
3491
- <td>${data["source"] ?? ""}</td>
3492
3549
  </tr>`;
3493
3550
  }
3494
3551
  }
@@ -3516,19 +3573,21 @@ var HistoryOfProceduresTemplate = class _HistoryOfProceduresTemplate {
3516
3573
  <th>Code (System)</th>
3517
3574
  <th>Comments</th>
3518
3575
  <th>Date</th>
3519
- <th>Source</th>
3520
3576
  </tr>
3521
3577
  </thead>
3522
3578
  <tbody>`;
3523
3579
  for (const resourceItem of resources) {
3524
3580
  const proc = resourceItem;
3581
+ const procedureName = templateUtilities.codeableConceptDisplay(proc.code, "display");
3582
+ if (procedureName?.toLowerCase() === "unknown") {
3583
+ continue;
3584
+ }
3525
3585
  html += `
3526
3586
  <tr>
3527
- <td>${templateUtilities.capitalizeFirstLetter(templateUtilities.renderTextAsHtml(templateUtilities.codeableConceptDisplay(proc.code, "display")))}</td>
3587
+ <td>${templateUtilities.capitalizeFirstLetter(templateUtilities.renderTextAsHtml(procedureName))}</td>
3528
3588
  <td>${templateUtilities.codeableConceptCoding(proc.code)}</td>
3529
3589
  <td>${templateUtilities.renderNotes(proc.note, timezone)}</td>
3530
3590
  <td>${templateUtilities.renderTime(proc.performedDateTime || proc.performedPeriod?.start, timezone)}</td>
3531
- <td>${templateUtilities.getOwnerTag(proc)}</td>
3532
3591
  </tr>`;
3533
3592
  }
3534
3593
  html += `
@@ -3575,7 +3634,6 @@ var SocialHistoryTemplate = class _SocialHistoryTemplate {
3575
3634
  <th>Unit</th>
3576
3635
  <th>Comments</th>
3577
3636
  <th>Date</th>
3578
- <th>Source</th>
3579
3637
  </tr>
3580
3638
  </thead>
3581
3639
  <tbody>`;
@@ -3583,6 +3641,9 @@ var SocialHistoryTemplate = class _SocialHistoryTemplate {
3583
3641
  for (const obs of observations) {
3584
3642
  const obsName = templateUtilities.renderTextAsHtml(templateUtilities.codeableConceptDisplay(obs.code));
3585
3643
  if (!addedObservations.has(obsName)) {
3644
+ if (obsName?.toLowerCase() === "unknown") {
3645
+ continue;
3646
+ }
3586
3647
  addedObservations.add(obsName);
3587
3648
  html += `
3588
3649
  <tr>
@@ -3592,7 +3653,6 @@ var SocialHistoryTemplate = class _SocialHistoryTemplate {
3592
3653
  <td>${templateUtilities.extractObservationValueUnit(obs)}</td>
3593
3654
  <td>${templateUtilities.renderNotes(obs.note, timezone)}</td>
3594
3655
  <td>${obs.effectiveDateTime ? templateUtilities.renderTime(obs.effectiveDateTime, timezone) : obs.effectivePeriod ? templateUtilities.renderPeriod(obs.effectivePeriod, timezone) : ""}</td>
3595
- <td>${templateUtilities.getOwnerTag(obs)}</td>
3596
3656
  </tr>`;
3597
3657
  }
3598
3658
  }
@@ -3643,7 +3703,6 @@ var PastHistoryOfIllnessTemplate = class {
3643
3703
  <th>Onset Date</th>
3644
3704
  <th>Recorded Date</th>
3645
3705
  <th>Resolved Date</th>
3646
- <th>Source</th>
3647
3706
  </tr>
3648
3707
  </thead>
3649
3708
  <tbody>`;
@@ -3651,6 +3710,9 @@ var PastHistoryOfIllnessTemplate = class {
3651
3710
  for (const cond of filteredConditions) {
3652
3711
  const conditionCode = templateUtilities.renderTextAsHtml(templateUtilities.codeableConceptDisplay(cond.code));
3653
3712
  if (!addedConditionCodes.has(conditionCode)) {
3713
+ if (conditionCode?.toLowerCase() === "unknown") {
3714
+ continue;
3715
+ }
3654
3716
  addedConditionCodes.add(conditionCode);
3655
3717
  html += `<tr>
3656
3718
  <td class="Name">${templateUtilities.capitalizeFirstLetter(conditionCode)}</td>
@@ -3658,7 +3720,6 @@ var PastHistoryOfIllnessTemplate = class {
3658
3720
  <td class="OnsetDate">${templateUtilities.renderDate(cond.onsetDateTime)}</td>
3659
3721
  <td class="RecordedDate">${templateUtilities.renderDate(cond.recordedDate)}</td>
3660
3722
  <td class="ResolvedDate">${templateUtilities.renderDate(cond.abatementDateTime)}</td>
3661
- <td class="Source">${templateUtilities.getOwnerTag(cond)}</td>
3662
3723
  </tr>`;
3663
3724
  }
3664
3725
  }
@@ -3699,19 +3760,21 @@ var PlanOfCareTemplate = class {
3699
3760
  <th>Comments</th>
3700
3761
  <th>Planned Start</th>
3701
3762
  <th>Planned End</th>
3702
- <th>Source</th>
3703
3763
  </tr>
3704
3764
  </thead>
3705
3765
  <tbody>`;
3706
3766
  for (const cp of carePlans) {
3767
+ const carePlanName = cp.description || cp.title || "";
3768
+ if (carePlanName.toLowerCase() === "unknown") {
3769
+ continue;
3770
+ }
3707
3771
  html += `
3708
3772
  <tr>
3709
- <td>${templateUtilities.capitalizeFirstLetter(cp.description || cp.title || "")}</td>
3773
+ <td>${templateUtilities.capitalizeFirstLetter(carePlanName)}</td>
3710
3774
  <td>${cp.intent || ""}</td>
3711
3775
  <td>${templateUtilities.concat(cp.note, "text")}</td>
3712
3776
  <td>${cp.period?.start ? templateUtilities.renderTime(cp.period?.start, timezone) : ""}</td>
3713
3777
  <td>${cp.period?.end ? templateUtilities.renderTime(cp.period?.end, timezone) : ""}</td>
3714
- <td>${templateUtilities.getOwnerTag(cp)}</td>
3715
3778
  </tr>`;
3716
3779
  }
3717
3780
  html += `
@@ -3739,7 +3802,6 @@ var PlanOfCareTemplate = class {
3739
3802
  <th>Created</th>
3740
3803
  <th>Planned Start</th>
3741
3804
  <th>Planned End</th>
3742
- <th>Source</th>
3743
3805
  </tr>
3744
3806
  </thead>
3745
3807
  <tbody>`;
@@ -3754,6 +3816,9 @@ var PlanOfCareTemplate = class {
3754
3816
  if (data["status"] !== "active") {
3755
3817
  continue;
3756
3818
  }
3819
+ if (data["CarePlan Name"]?.toLowerCase() === "unknown") {
3820
+ continue;
3821
+ }
3757
3822
  isSummaryCreated = true;
3758
3823
  html += `
3759
3824
  <tr>
@@ -3761,7 +3826,6 @@ var PlanOfCareTemplate = class {
3761
3826
  <td>${templateUtilities.renderTime(data["created"], timezone) ?? ""}</td>
3762
3827
  <td>${templateUtilities.renderTime(data["period.start"], timezone) ?? ""}</td>
3763
3828
  <td>${templateUtilities.renderTime(data["period.end"], timezone) ?? ""}</td>
3764
- <td>${data["source"] ?? ""}</td>
3765
3829
  </tr>`;
3766
3830
  }
3767
3831
  }
@@ -3818,6 +3882,9 @@ var FunctionalStatusTemplate = class _FunctionalStatusTemplate {
3818
3882
  for (const obs of functionalObservations) {
3819
3883
  const observation = obs;
3820
3884
  const obsName = templateUtilities.codeableConceptDisplay(observation.code);
3885
+ if (obsName?.toLowerCase() === "unknown") {
3886
+ continue;
3887
+ }
3821
3888
  const value = templateUtilities.extractObservationValue(observation);
3822
3889
  const date = observation.effectiveDateTime ? templateUtilities.renderDate(observation.effectiveDateTime) : observation.issued ? templateUtilities.renderDate(observation.issued) : "";
3823
3890
  const interpretation = observation.interpretation ? templateUtilities.codeableConceptDisplay(observation.interpretation[0]) : "";
@@ -3925,18 +3992,19 @@ var PregnancyTemplate = class _PregnancyTemplate {
3925
3992
  <th>Code (System)</th>
3926
3993
  <th>Comments</th>
3927
3994
  <th>Date</th>
3928
- <th>Source</th>
3929
3995
  </tr>
3930
3996
  </thead>
3931
3997
  <tbody>`;
3932
- function renderRow({ result, comments, date, codeSystem, owner }) {
3998
+ function renderRow({ result, comments, date, codeSystem }) {
3999
+ if (result?.toLowerCase() === "unknown") {
4000
+ return;
4001
+ }
3933
4002
  html += `
3934
4003
  <tr>
3935
4004
  <td class="Result">${templateUtilities.capitalizeFirstLetter(result)}</td>
3936
4005
  <td class="CodeSystem">${codeSystem}</td>
3937
4006
  <td class="Comments">${comments}</td>
3938
4007
  <td class="Date">${date}</td>
3939
- <td class="Source">${owner}</td>
3940
4008
  </tr>`;
3941
4009
  }
3942
4010
  const rowResources = [];
@@ -3990,8 +4058,7 @@ var PregnancyTemplate = class _PregnancyTemplate {
3990
4058
  const rowKey = `${result}|${codeSystem}`;
3991
4059
  if (!addedRows.has(rowKey)) {
3992
4060
  addedRows.add(rowKey);
3993
- const owner = templateUtilities.getOwnerTag(resource);
3994
- renderRow({ result, comments, date: dateStr, codeSystem, owner });
4061
+ renderRow({ result, comments, date: dateStr, codeSystem });
3995
4062
  }
3996
4063
  }
3997
4064
  html += `
@@ -4038,11 +4105,17 @@ var AdvanceDirectivesTemplate = class _AdvanceDirectivesTemplate {
4038
4105
  </tr>
4039
4106
  </thead>
4040
4107
  <tbody>`;
4108
+ let isConsentAdded = false;
4041
4109
  for (const resourceItem of resources) {
4042
4110
  const consent = resourceItem;
4111
+ const consentScope = templateUtilities.capitalizeFirstLetter(templateUtilities.renderTextAsHtml(templateUtilities.codeableConceptDisplay(consent.scope, "display")));
4112
+ if (!consentScope || consentScope.toLowerCase() === "unknown") {
4113
+ continue;
4114
+ }
4115
+ isConsentAdded = true;
4043
4116
  html += `
4044
4117
  <tr>
4045
- <td>${templateUtilities.capitalizeFirstLetter(templateUtilities.renderTextAsHtml(templateUtilities.codeableConceptDisplay(consent.scope, "display")))}</td>
4118
+ <td>${consentScope}</td>
4046
4119
  <td>${consent.status || ""}</td>
4047
4120
  <td>${consent.provision?.action ? templateUtilities.concatCodeableConcept(consent.provision.action) : ""}</td>
4048
4121
  <td>${consent.dateTime || ""}</td>
@@ -4051,7 +4124,7 @@ var AdvanceDirectivesTemplate = class _AdvanceDirectivesTemplate {
4051
4124
  html += `
4052
4125
  </tbody>
4053
4126
  </table>`;
4054
- return html;
4127
+ return isConsentAdded ? html : void 0;
4055
4128
  }
4056
4129
  };
4057
4130
 
@@ -4246,6 +4319,10 @@ var ComprehensiveIPSCompositionBuilder = class {
4246
4319
  * @param validResources - Array of domain resources
4247
4320
  */
4248
4321
  addSectionAsync(narrative, sectionType, validResources) {
4322
+ if (sectionType === "Patient" /* PATIENT */) {
4323
+ this.patientSummary = narrative;
4324
+ return this;
4325
+ }
4249
4326
  const sectionEntry = {
4250
4327
  title: IPS_SECTION_DISPLAY_NAMES[sectionType] || sectionType,
4251
4328
  code: {
@@ -4275,26 +4352,24 @@ var ComprehensiveIPSCompositionBuilder = class {
4275
4352
  for (const resource of validResources) {
4276
4353
  this.resources.add(resource);
4277
4354
  }
4278
- if (sectionType !== "Patient" /* PATIENT */) {
4279
- let narrative = void 0;
4280
- if (validResources.length > 0) {
4281
- narrative = await NarrativeGenerator.generateNarrativeAsync(
4282
- sectionType,
4283
- validResources,
4284
- timezone,
4285
- true
4286
- );
4287
- }
4288
- if (!narrative && sectionType in IPSMandatorySections) {
4289
- narrative = await NarrativeGenerator.createNarrativeAsync(
4290
- IPSMissingMandatorySectionContent[sectionType]
4291
- );
4292
- }
4293
- if (!narrative) {
4294
- return this;
4295
- }
4296
- this.addSectionAsync(narrative, sectionType, validResources);
4355
+ let narrative = void 0;
4356
+ if (validResources.length > 0) {
4357
+ narrative = await NarrativeGenerator.generateNarrativeAsync(
4358
+ sectionType,
4359
+ validResources,
4360
+ timezone,
4361
+ true
4362
+ );
4297
4363
  }
4364
+ if (!narrative && sectionType in IPSMandatorySections) {
4365
+ narrative = await NarrativeGenerator.createNarrativeAsync(
4366
+ IPSMissingMandatorySectionContent[sectionType]
4367
+ );
4368
+ }
4369
+ if (!narrative) {
4370
+ return this;
4371
+ }
4372
+ this.addSectionAsync(narrative, sectionType, validResources);
4298
4373
  return this;
4299
4374
  }
4300
4375
  async makeSectionFromSummaryAsync(sectionType, summaryCompositions, resources, timezone) {
@@ -4332,17 +4407,18 @@ var ComprehensiveIPSCompositionBuilder = class {
4332
4407
  * @param timezone - Optional timezone to use for date formatting
4333
4408
  * @param useSummaryCompositions - Whether to use summary compositions (default: false)
4334
4409
  */
4335
- async readBundleAsync(bundle, timezone, useSummaryCompositions = false) {
4410
+ async readBundleAsync(bundle, timezone, useSummaryCompositions = false, consoleLogger = console) {
4336
4411
  if (!bundle.entry) {
4337
4412
  return this;
4338
4413
  }
4339
4414
  const patientEntries = [];
4340
4415
  const resources = [];
4341
4416
  bundle.entry.forEach((e) => {
4342
- if (e.resource?.resourceType === "Patient") {
4343
- patientEntries.push(e.resource);
4344
- this.resources.add(e.resource);
4345
- } else if (e.resource) {
4417
+ if (e.resource) {
4418
+ if (e.resource.resourceType === "Patient") {
4419
+ patientEntries.push(e.resource);
4420
+ this.resources.add(e.resource);
4421
+ }
4346
4422
  resources.push(e.resource);
4347
4423
  }
4348
4424
  });
@@ -4351,23 +4427,20 @@ var ComprehensiveIPSCompositionBuilder = class {
4351
4427
  }
4352
4428
  this.patients = patientEntries;
4353
4429
  for (const sectionType of Object.values(IPSSections)) {
4354
- if (sectionType === "Patient" /* PATIENT */) {
4355
- continue;
4356
- }
4357
4430
  const summaryIPSCompositionFilter = useSummaryCompositions ? IPSSectionResourceHelper.getSummaryIPSCompositionFilterForSection(sectionType) : void 0;
4358
4431
  const sectionIPSSummary = summaryIPSCompositionFilter ? resources.filter((resource) => summaryIPSCompositionFilter(resource)) : [];
4359
4432
  if (sectionIPSSummary.length > 0) {
4360
- console.log(`Using IPS summary composition for section: ${sectionType}`);
4433
+ consoleLogger.info(`Using IPS summary composition for section: ${sectionType}`);
4361
4434
  await this.makeSectionFromSummaryAsync(sectionType, sectionIPSSummary, resources, timezone);
4362
4435
  continue;
4363
4436
  }
4364
4437
  const summaryCompositionFilter = useSummaryCompositions ? IPSSectionResourceHelper.getSummaryCompositionFilterForSection(sectionType) : void 0;
4365
4438
  const sectionSummary = summaryCompositionFilter ? resources.filter((resource) => summaryCompositionFilter(resource)) : [];
4366
4439
  if (sectionSummary.length > 0) {
4367
- console.log(`Using summary composition for section: ${sectionType}`);
4440
+ consoleLogger.info(`Using summary composition for section: ${sectionType}`);
4368
4441
  await this.makeSectionFromSummaryAsync(sectionType, sectionSummary, resources, timezone);
4369
4442
  } else {
4370
- console.log(`Using individual resources for section: ${sectionType}`);
4443
+ consoleLogger.info(`Using individual resources for section: ${sectionType}`);
4371
4444
  const sectionFilter = IPSSectionResourceHelper.getResourceFilterForSection(sectionType);
4372
4445
  const sectionResources = resources.filter((resource) => sectionFilter(resource));
4373
4446
  await this.makeSectionAsync(sectionType, sectionResources, timezone);
@@ -4391,6 +4464,9 @@ var ComprehensiveIPSCompositionBuilder = class {
4391
4464
  if (!this.patients) {
4392
4465
  throw new Error("Patient resource must be set before building the bundle");
4393
4466
  }
4467
+ if (!this.patientSummary) {
4468
+ throw new Error("Patient summary narrative must be set before building the bundle");
4469
+ }
4394
4470
  const primaryPatientId = patientId ?? this.patients[0].id;
4395
4471
  const composition = {
4396
4472
  id: `Composition-${primaryPatientId}`,
@@ -4414,14 +4490,7 @@ var ComprehensiveIPSCompositionBuilder = class {
4414
4490
  date: (now || /* @__PURE__ */ new Date()).toISOString(),
4415
4491
  title: "International Patient Summary",
4416
4492
  section: this.sections,
4417
- text: await NarrativeGenerator.generateNarrativeAsync(
4418
- "Patient" /* PATIENT */,
4419
- this.patients,
4420
- timezone,
4421
- true,
4422
- false,
4423
- now
4424
- )
4493
+ text: this.patientSummary
4425
4494
  };
4426
4495
  const bundle = {
4427
4496
  resourceType: "Bundle",