@imranq2/fhirpatientsummary 1.0.32 → 1.0.34

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.js CHANGED
@@ -161,6 +161,8 @@ var IPSSectionResourceFilters = {
161
161
  };
162
162
  var IPSSectionSummaryCompositionFilter = {
163
163
  ["AllergyIntoleranceSection" /* ALLERGIES */]: (resource) => resource.resourceType === "Composition" && resource.type?.coding?.some((c) => codingMatches(c, "allergy_summary_document", IPS_SUMMARY_COMPOSITION_TYPE_SYSTEM)),
164
+ ["ProblemSection" /* PROBLEMS */]: (resource) => resource.resourceType === "Composition" && resource.type?.coding?.some((c) => codingMatches(c, "condition_summary_document", IPS_SUMMARY_COMPOSITION_TYPE_SYSTEM)),
165
+ ["HistoryOfPastIllnessSection" /* MEDICAL_HISTORY */]: (resource) => resource.resourceType === "Composition" && resource.type?.coding?.some((c) => codingMatches(c, "condition_summary_document", IPS_SUMMARY_COMPOSITION_TYPE_SYSTEM)),
164
166
  ["VitalSignsSection" /* VITAL_SIGNS */]: (resource) => resource.resourceType === "Composition" && resource.type?.coding?.some((c) => codingMatches(c, "vital_summary_document", IPS_SUMMARY_COMPOSITION_TYPE_SYSTEM)),
165
167
  ["PlanOfCareSection" /* CARE_PLAN */]: (resource) => resource.resourceType === "Composition" && resource.type?.coding?.some((c) => codingMatches(c, "careplan_summary_document", IPS_SUMMARY_COMPOSITION_TYPE_SYSTEM)),
166
168
  ["ImmunizationSection" /* IMMUNIZATIONS */]: (resource) => resource.resourceType === "Composition" && resource.type?.coding?.some((c) => codingMatches(c, "immunization_summary_document", IPS_SUMMARY_COMPOSITION_TYPE_SYSTEM)),
@@ -169,7 +171,8 @@ var IPSSectionSummaryCompositionFilter = {
169
171
  ["HistoryOfProceduresSection" /* PROCEDURES */]: (resource) => resource.resourceType === "Composition" && resource.type?.coding?.some((c) => codingMatches(c, "procedure_summary_document", IPS_SUMMARY_COMPOSITION_TYPE_SYSTEM))
170
172
  };
171
173
  var IPSSectionSummaryIPSCompositionFilter = {
172
- ["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")
174
+ ["Patient" /* PATIENT */]: (resource) => resource.resourceType === "Composition" && resource.type?.coding?.some((c) => codingMatches(c, "ips_patient_summary_document", IPS_SUMMARY_COMPOSITION_TYPE_SYSTEM)),
175
+ ["VitalSignsSection" /* VITAL_SIGNS */]: (resource) => resource.resourceType === "Composition" && resource.type?.coding?.some((c) => codingMatches(c, "ips_vital_summary_document", IPS_SUMMARY_COMPOSITION_TYPE_SYSTEM))
173
176
  };
174
177
  var IPSSectionResourceHelper = class {
175
178
  static getResourceFilterForSection(section) {
@@ -181,10 +184,16 @@ var IPSSectionResourceHelper = class {
181
184
  return resources.filter(filter);
182
185
  }
183
186
  static getSummaryCompositionFilterForSection(section) {
184
- return IPSSectionSummaryCompositionFilter[section];
187
+ const sectionCompositionEnabled = process.env.SUMMARY_COMPOSITION_SECTIONS ? process.env.SUMMARY_COMPOSITION_SECTIONS.split(",").some(
188
+ (s) => s.trim().toLowerCase() === section.toString().toLowerCase() || s.trim().toLowerCase() === "all"
189
+ ) : false;
190
+ return sectionCompositionEnabled ? IPSSectionSummaryCompositionFilter[section] : void 0;
185
191
  }
186
192
  static getSummaryIPSCompositionFilterForSection(section) {
187
- return IPSSectionSummaryIPSCompositionFilter[section];
193
+ const sectionIPSCompositionEnabled = process.env.SUMMARY_IPS_COMPOSITION_SECTIONS ? process.env.SUMMARY_IPS_COMPOSITION_SECTIONS.split(",").some(
194
+ (s) => s.trim().toLowerCase() === section.toString().toLowerCase() || s.trim().toLowerCase() === "all"
195
+ ) : false;
196
+ return sectionIPSCompositionEnabled ? IPSSectionSummaryIPSCompositionFilter[section] : void 0;
188
197
  }
189
198
  };
190
199
  function codingMatches(coding, code, system) {
@@ -884,18 +893,6 @@ var TemplateUtilities = class {
884
893
  }
885
894
  return "";
886
895
  }
887
- /**
888
- * Returns the owner tag from the resource meta.security array.
889
- * @param resource - FHIR resource with meta tag
890
- * @returns The owner code if found, otherwise undefined
891
- */
892
- getOwnerTag(resource) {
893
- if (!resource?.meta?.security) return "";
894
- const ownerEntry = resource.meta.security.find(
895
- (sec) => sec.system === "https://www.icanbwell.com/owner" && !!sec.code
896
- );
897
- return ownerEntry?.code;
898
- }
899
896
  /**
900
897
  * Public method to render plain text as HTML, escaping special characters and replacing newlines with <br />.
901
898
  * This method should be used whenever displaying user-supplied or FHIR resource text in HTML to prevent XSS vulnerabilities
@@ -916,6 +913,17 @@ var TemplateUtilities = class {
916
913
  }
917
914
  return text.charAt(0).toUpperCase() + text.slice(1);
918
915
  }
916
+ renderListSectionData(sectionData) {
917
+ if (!sectionData || !Array.isArray(sectionData) || sectionData.length === 0) {
918
+ return "";
919
+ }
920
+ const items = [];
921
+ for (const section of sectionData) {
922
+ items.push(this.renderTextAsHtml(section.text?.div || ""));
923
+ }
924
+ const listString = Array.from(items).map((item) => `<li>${item}</li>`).join("");
925
+ return `<ul>${listString}</ul>`;
926
+ }
919
927
  /**
920
928
  * Renders note elements from a FHIR resource in a standardized format
921
929
  * Can render as simple comma-separated text or as styled HTML with timestamps
@@ -1403,6 +1411,60 @@ var PatientTemplate = class _PatientTemplate {
1403
1411
  generateNarrative(resources, timezone) {
1404
1412
  return _PatientTemplate.generateStaticNarrative(resources, timezone);
1405
1413
  }
1414
+ /**
1415
+ * Generate HTML narrative for Patient resources using summary
1416
+ * @param resources - FHIR Composition resources
1417
+ * @param timezone - Optional timezone to use for date formatting (e.g., 'America/New_York', 'Europe/London')
1418
+ * @returns HTML string for rendering
1419
+ */
1420
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
1421
+ generateSummaryNarrative(resources, timezone) {
1422
+ const templateUtilities = new TemplateUtilities(resources);
1423
+ const compositionResources = resources[0];
1424
+ const data = {};
1425
+ for (const rowData of compositionResources.section ?? []) {
1426
+ for (const columnData of rowData.section ?? []) {
1427
+ switch (columnData.title) {
1428
+ case "Name":
1429
+ case "Address":
1430
+ case "Communication":
1431
+ data[columnData.title] = templateUtilities.renderListSectionData(columnData.section ?? []);
1432
+ break;
1433
+ case "Telecom": {
1434
+ const telecomStringParts = [];
1435
+ for (const telecomData of columnData.section ?? []) {
1436
+ const telecomSystem = telecomData?.title;
1437
+ const telecomValue = templateUtilities.renderListSectionData(telecomData.section ?? []);
1438
+ if (telecomSystem && telecomValue) {
1439
+ telecomStringParts.push(`<li><strong>${telecomSystem}:</strong>${telecomValue}</li>`);
1440
+ }
1441
+ }
1442
+ data["Telecom"] = `<ul>${telecomStringParts.join("")}</ul>`;
1443
+ break;
1444
+ }
1445
+ default:
1446
+ if (columnData.title) {
1447
+ data[columnData.title] = templateUtilities.renderTextAsHtml(columnData.text?.div ?? "");
1448
+ }
1449
+ break;
1450
+ }
1451
+ }
1452
+ }
1453
+ let html = `<p>This section merges all Patient resources into a single combined patient record, preferring non-empty values for each field.</p>`;
1454
+ html += `<div>
1455
+ <ul>
1456
+ <li><strong>Name(s):</strong>${data["Name"] || ""}</li>
1457
+ <li><strong>Gender:</strong>${data["Gender"] || ""}</li>
1458
+ <li><strong>Date of Birth:</strong>${data["Date of Birth"] || ""}</li>
1459
+ <li><strong>Telecom:</strong>${data["Telecom"] || ""}</li>
1460
+ <li><strong>Address(es):</strong>${data["Address"] || ""}</li>
1461
+ ${data["Marital Status"] ? `<li><strong>Marital Status:</strong>${data["Marital Status"]}</li>` : ""}
1462
+ ${data["Deceased"] ? `<li><strong>Deceased:</strong>${data["Deceased"]}</li>` : ""}
1463
+ <li><strong>Language(s):</strong>${data["Communication"] || ""}</li>
1464
+ </ul>
1465
+ </div>`;
1466
+ return html;
1467
+ }
1406
1468
  /**
1407
1469
  * Internal static implementation that actually generates the narrative
1408
1470
  * @param resources - FHIR Patient resources
@@ -1413,6 +1475,7 @@ var PatientTemplate = class _PatientTemplate {
1413
1475
  static generateStaticNarrative(resources, timezone) {
1414
1476
  const templateUtilities = new TemplateUtilities(resources);
1415
1477
  const combinedPatient = this.combinePatients(resources);
1478
+ const deceasedText = this.renderDeceased(combinedPatient);
1416
1479
  let html = `<p>This section merges all Patient resources into a single combined patient record, preferring non-empty values for each field.</p>`;
1417
1480
  html += `<div>
1418
1481
  <ul>
@@ -1421,8 +1484,8 @@ var PatientTemplate = class _PatientTemplate {
1421
1484
  <li><strong>Date of Birth:</strong>${combinedPatient.birthDate || ""}</li>
1422
1485
  <li><strong>Telecom:</strong><ul>${this.renderTelecom(combinedPatient)}</ul></li>
1423
1486
  <li><strong>Address(es):</strong>${this.renderAddresses(combinedPatient)}</li>
1424
- <li><strong>Marital Status:</strong> ${combinedPatient.maritalStatus?.text || ""}</li>
1425
- <li><strong>Deceased:</strong>${this.renderDeceased(combinedPatient)}</li>
1487
+ ${combinedPatient.maritalStatus?.text ? `<li><strong>Marital Status:</strong> ${combinedPatient.maritalStatus.text}</li>` : ""}
1488
+ ${deceasedText ? `<li><strong>Deceased:</strong>${deceasedText}</li>` : ""}
1426
1489
  <li><strong>Language(s):</strong>${this.renderCommunication(templateUtilities, combinedPatient)}</li>
1427
1490
  </ul>
1428
1491
  </div>`;
@@ -1496,7 +1559,8 @@ var PatientTemplate = class _PatientTemplate {
1496
1559
  }
1497
1560
  }
1498
1561
  });
1499
- return Array.from(uniqueNames).map((nameText) => `<ul><li>${nameText}</li></ul>`).join("");
1562
+ const namesHtml = Array.from(uniqueNames).map((nameText) => `<li>${nameText}</li>`).join("");
1563
+ return `<ul>${namesHtml}</ul>`;
1500
1564
  }
1501
1565
  /**
1502
1566
  * Renders patient telecom information grouped by system
@@ -1600,7 +1664,8 @@ var PatientTemplate = class _PatientTemplate {
1600
1664
  }
1601
1665
  });
1602
1666
  const deduplicatedAddresses = this.deduplicateSimilarAddresses(Array.from(uniqueAddresses));
1603
- return deduplicatedAddresses.map((addressText) => `<ul><li>${addressText}</li></ul>`).join("");
1667
+ const addressesHtml = deduplicatedAddresses.map((addressText) => `<li>${addressText}</li>`).join("");
1668
+ return `<ul>${addressesHtml}</ul>`;
1604
1669
  }
1605
1670
  /**
1606
1671
  * Calculates the similarity between two strings using Levenshtein distance
@@ -1718,7 +1783,8 @@ var PatientTemplate = class _PatientTemplate {
1718
1783
  uniqueLanguages.add(language);
1719
1784
  }
1720
1785
  });
1721
- return Array.from(uniqueLanguages).map((language) => `<ul><li>${language}${preferredLanguages.has(language) ? " (preferred)" : ""}</li></ul>`).join("");
1786
+ const languagesHtml = Array.from(uniqueLanguages).map((language) => `<li>${language}${preferredLanguages.has(language) ? " (preferred)" : ""}</li>`).join("");
1787
+ return `<ul>${languagesHtml}</ul>`;
1722
1788
  }
1723
1789
  /**
1724
1790
  * Capitalizes first letter of a string
@@ -1762,7 +1828,6 @@ var AllergyIntoleranceTemplate = class _AllergyIntoleranceTemplate {
1762
1828
  <th>Code (System)</th>
1763
1829
  <th>Criticality</th>
1764
1830
  <th>Recorded Date</th>
1765
- <th>Source</th>
1766
1831
  </tr>
1767
1832
  </thead>
1768
1833
  <tbody>`;
@@ -1782,13 +1847,13 @@ var AllergyIntoleranceTemplate = class _AllergyIntoleranceTemplate {
1782
1847
  case "Recorded Date":
1783
1848
  data["recordedDate"] = templateUtilities.renderTextAsHtml(columnData.text?.div ?? "");
1784
1849
  break;
1785
- case "Source":
1786
- data["source"] = templateUtilities.renderTextAsHtml(columnData.text?.div ?? "");
1787
- break;
1788
1850
  default:
1789
1851
  break;
1790
1852
  }
1791
1853
  }
1854
+ if (data["allergen"]?.toLowerCase() === "unknown") {
1855
+ continue;
1856
+ }
1792
1857
  isSummaryCreated = true;
1793
1858
  html += `
1794
1859
  <tr>
@@ -1796,7 +1861,6 @@ var AllergyIntoleranceTemplate = class _AllergyIntoleranceTemplate {
1796
1861
  <td>${data["codeSystem"] ?? ""}</td>
1797
1862
  <td>${data["criticality"] ?? ""}</td>
1798
1863
  <td>${templateUtilities.renderTime(data["recordedDate"], timezone) ?? ""}</td>
1799
- <td>${data["source"] ?? ""}</td>
1800
1864
  </tr>`;
1801
1865
  }
1802
1866
  }
@@ -1850,7 +1914,6 @@ var AllergyIntoleranceTemplate = class _AllergyIntoleranceTemplate {
1850
1914
  <th>Reaction</th>
1851
1915
  <th>Onset Date</th>
1852
1916
  <th>Comments</th>
1853
- <th>Source</th>
1854
1917
  </tr>
1855
1918
  </thead>
1856
1919
  <tbody>`;
@@ -1880,7 +1943,6 @@ var AllergyIntoleranceTemplate = class _AllergyIntoleranceTemplate {
1880
1943
  <th>Onset Date</th>
1881
1944
  <th>Comments</th>
1882
1945
  <th>Resolved Date</th>
1883
- <th>Source</th>
1884
1946
  </tr>
1885
1947
  </thead>
1886
1948
  <tbody>`;
@@ -1909,16 +1971,19 @@ var AllergyIntoleranceTemplate = class _AllergyIntoleranceTemplate {
1909
1971
  static generateAllergyRows(allergies, templateUtilities, timezone, includeResolved = false) {
1910
1972
  let html = "";
1911
1973
  for (const allergy of allergies) {
1974
+ const allergenName = templateUtilities.codeableConceptDisplay(allergy.code);
1975
+ if (allergenName?.toLowerCase() === "unknown") {
1976
+ continue;
1977
+ }
1912
1978
  html += `
1913
1979
  <tr>
1914
- <td class="Name"><span class="AllergenName">${templateUtilities.capitalizeFirstLetter(templateUtilities.renderTextAsHtml(templateUtilities.codeableConceptDisplay(allergy.code)))}</span></td>
1980
+ <td class="Name"><span class="AllergenName">${templateUtilities.capitalizeFirstLetter(templateUtilities.renderTextAsHtml(allergenName))}</span></td>
1915
1981
  <td class="Status">${templateUtilities.renderTextAsHtml(templateUtilities.codeableConceptDisplay(allergy.clinicalStatus)) || ""}</td>
1916
1982
  <td class="CodeSystem">${templateUtilities.codeableConceptCoding(allergy.code)}</td>
1917
1983
  <td class="Category">${templateUtilities.renderTextAsHtml(templateUtilities.safeConcat(allergy.category)) || ""}</td>
1918
1984
  <td class="Reaction">${templateUtilities.renderTextAsHtml(templateUtilities.concatReactionManifestation(allergy.reaction)) || ""}</td>
1919
1985
  <td class="OnsetDate">${templateUtilities.renderTextAsHtml(templateUtilities.renderTime(allergy.onsetDateTime, timezone)) || ""}</td>
1920
- <td class="Comments">${templateUtilities.renderNotes(allergy.note, timezone, { styled: true, warning: true })}</td>
1921
- <td class="Source">${templateUtilities.getOwnerTag(allergy)}</td>`;
1986
+ <td class="Comments">${templateUtilities.renderNotes(allergy.note, timezone, { styled: true, warning: true })}</td>`;
1922
1987
  if (includeResolved) {
1923
1988
  let endDate = "";
1924
1989
  if (allergy.extension && Array.isArray(allergy.extension)) {
@@ -1973,9 +2038,7 @@ var MedicationSummaryTemplate = class _MedicationSummaryTemplate {
1973
2038
  <th>Status</th>
1974
2039
  <th>Sig</th>
1975
2040
  <th>Days of Supply</th>
1976
- <th>Refills</th>
1977
2041
  <th>Start Date</th>
1978
- <th>Source</th>
1979
2042
  </tr>
1980
2043
  </thead>
1981
2044
  <tbody>`;
@@ -2001,15 +2064,9 @@ var MedicationSummaryTemplate = class _MedicationSummaryTemplate {
2001
2064
  case "Days Of Supply":
2002
2065
  data["daysOfSupply"] = templateUtilities.renderTextAsHtml(columnData.text?.div ?? "");
2003
2066
  break;
2004
- case "Refills Remaining":
2005
- data["refills"] = templateUtilities.renderTextAsHtml(columnData.text?.div ?? "");
2006
- break;
2007
2067
  case "Authored On Date":
2008
2068
  data["startDate"] = templateUtilities.renderTextAsHtml(columnData.text?.div ?? "");
2009
2069
  break;
2010
- case "Source":
2011
- data["source"] = templateUtilities.renderTextAsHtml(columnData.text?.div ?? "");
2012
- break;
2013
2070
  default:
2014
2071
  break;
2015
2072
  }
@@ -2025,6 +2082,9 @@ var MedicationSummaryTemplate = class _MedicationSummaryTemplate {
2025
2082
  skippedMedications++;
2026
2083
  }
2027
2084
  if (data["status"] === "active" || startDateObj && startDateObj >= twoYearsAgo) {
2085
+ if (data["medication"]?.toLowerCase() === "unknown") {
2086
+ continue;
2087
+ }
2028
2088
  isSummaryCreated = true;
2029
2089
  html += `
2030
2090
  <tr>
@@ -2033,9 +2093,7 @@ var MedicationSummaryTemplate = class _MedicationSummaryTemplate {
2033
2093
  <td>${templateUtilities.renderTextAsHtml(data["status"])}</td>
2034
2094
  <td>${templateUtilities.renderTextAsHtml(data["sig-prescriber"] || data["sig-pharmacy"])}</td>
2035
2095
  <td>${templateUtilities.renderTextAsHtml(data["daysOfSupply"])}</td>
2036
- <td>${templateUtilities.renderTextAsHtml(data["refills"])}</td>
2037
2096
  <td>${templateUtilities.renderTime(data["startDate"], timezone)}</td>
2038
- <td>${templateUtilities.renderTextAsHtml(data["source"])}</td>
2039
2097
  </tr>`;
2040
2098
  }
2041
2099
  }
@@ -2160,9 +2218,7 @@ var MedicationSummaryTemplate = class _MedicationSummaryTemplate {
2160
2218
  <th>Code (System)</th>
2161
2219
  <th>Sig</th>
2162
2220
  <th>Dispense Quantity</th>
2163
- <th>Refills</th>
2164
2221
  <th>Start Date</th>
2165
- <th>Source</th>
2166
2222
  </tr>
2167
2223
  </thead>
2168
2224
  <tbody>`;
@@ -2171,7 +2227,6 @@ var MedicationSummaryTemplate = class _MedicationSummaryTemplate {
2171
2227
  let medicationName;
2172
2228
  let sig;
2173
2229
  let dispenseQuantity = "";
2174
- let refills = "";
2175
2230
  let startDate = "";
2176
2231
  let codeSystemDisplay = "";
2177
2232
  if (medication.type === "request") {
@@ -2187,7 +2242,6 @@ var MedicationSummaryTemplate = class _MedicationSummaryTemplate {
2187
2242
  dispenseQuantity = `${quantity.value} ${quantity.unit || quantity.code || ""}`.trim();
2188
2243
  }
2189
2244
  }
2190
- refills = mr.dispenseRequest?.numberOfRepeatsAllowed?.toString() || "";
2191
2245
  if (mr.dispenseRequest?.validityPeriod) {
2192
2246
  startDate = mr.dispenseRequest.validityPeriod.start || "";
2193
2247
  } else {
@@ -2212,6 +2266,9 @@ var MedicationSummaryTemplate = class _MedicationSummaryTemplate {
2212
2266
  codeSystemDisplay = templateUtilities.codeableConceptCoding(ms.medicationCodeableConcept);
2213
2267
  }
2214
2268
  }
2269
+ if (medicationName?.toLowerCase() === "unknown") {
2270
+ continue;
2271
+ }
2215
2272
  html += `
2216
2273
  <tr>
2217
2274
  <td>${type}</td>
@@ -2219,9 +2276,7 @@ var MedicationSummaryTemplate = class _MedicationSummaryTemplate {
2219
2276
  <td>${codeSystemDisplay}</td>
2220
2277
  <td>${sig}</td>
2221
2278
  <td>${dispenseQuantity}</td>
2222
- <td>${refills}</td>
2223
2279
  <td>${startDate}</td>
2224
- <td>${templateUtilities.getOwnerTag(medication.resource)}</td>
2225
2280
  </tr>`;
2226
2281
  }
2227
2282
  html += `
@@ -2266,7 +2321,6 @@ var ImmunizationsTemplate = class _ImmunizationsTemplate {
2266
2321
  <th>Code (System)</th>
2267
2322
  <th>Status</th>
2268
2323
  <th>Date</th>
2269
- <th>Source</th>
2270
2324
  </tr>
2271
2325
  </thead>
2272
2326
  <tbody>`;
@@ -2286,14 +2340,14 @@ var ImmunizationsTemplate = class _ImmunizationsTemplate {
2286
2340
  case "occurrenceDateTime":
2287
2341
  data["occurrenceDateTime"] = templateUtilities.renderTextAsHtml(columnData.text?.div ?? "");
2288
2342
  break;
2289
- case "Source":
2290
- data["source"] = templateUtilities.renderTextAsHtml(columnData.text?.div ?? "");
2291
- break;
2292
2343
  default:
2293
2344
  break;
2294
2345
  }
2295
2346
  }
2296
2347
  if (data["status"] === "completed") {
2348
+ if (data["immunization"]?.toLowerCase() === "unknown") {
2349
+ continue;
2350
+ }
2297
2351
  isSummaryCreated = true;
2298
2352
  html += `
2299
2353
  <tr>
@@ -2301,7 +2355,6 @@ var ImmunizationsTemplate = class _ImmunizationsTemplate {
2301
2355
  <td>${data["codeSystem"] ?? ""}</td>
2302
2356
  <td>${data["status"] ?? ""}</td>
2303
2357
  <td>${templateUtilities.renderTime(data["occurrenceDateTime"], timezone) ?? ""}</td>
2304
- <td>${data["source"] ?? ""}</td>
2305
2358
  </tr>`;
2306
2359
  }
2307
2360
  }
@@ -2332,7 +2385,6 @@ var ImmunizationsTemplate = class _ImmunizationsTemplate {
2332
2385
  <th>Lot Number</th>
2333
2386
  <th>Comments</th>
2334
2387
  <th>Date</th>
2335
- <th>Source</th>
2336
2388
  </tr>
2337
2389
  </thead>
2338
2390
  <tbody>`;
@@ -2340,9 +2392,13 @@ var ImmunizationsTemplate = class _ImmunizationsTemplate {
2340
2392
  if (immunizations.length > 0) {
2341
2393
  for (const resourceItem of immunizations) {
2342
2394
  const imm = resourceItem;
2395
+ const immunizationName = templateUtilities.codeableConceptDisplay(imm.vaccineCode);
2396
+ if (immunizationName?.toLowerCase() === "unknown") {
2397
+ continue;
2398
+ }
2343
2399
  html += `
2344
2400
  <tr>
2345
- <td>${templateUtilities.capitalizeFirstLetter(templateUtilities.renderTextAsHtml(templateUtilities.codeableConceptDisplay(imm.vaccineCode)))}</td>
2401
+ <td>${templateUtilities.capitalizeFirstLetter(templateUtilities.renderTextAsHtml(immunizationName))}</td>
2346
2402
  <td>${templateUtilities.codeableConceptCoding(imm.vaccineCode)}</td>
2347
2403
  <td>${imm.status || ""}</td>
2348
2404
  <td>${templateUtilities.concatDoseNumber(imm.protocolApplied)}</td>
@@ -2350,7 +2406,6 @@ var ImmunizationsTemplate = class _ImmunizationsTemplate {
2350
2406
  <td>${imm.lotNumber || ""}</td>
2351
2407
  <td>${templateUtilities.renderNotes(imm.note, timezone)}</td>
2352
2408
  <td>${templateUtilities.renderTime(imm.occurrenceDateTime, timezone)}</td>
2353
- <td>${templateUtilities.getOwnerTag(imm)}</td>
2354
2409
  </tr>`;
2355
2410
  }
2356
2411
  }
@@ -2372,6 +2427,59 @@ var ProblemListTemplate = class _ProblemListTemplate {
2372
2427
  generateNarrative(resources, timezone) {
2373
2428
  return _ProblemListTemplate.generateStaticNarrative(resources, timezone);
2374
2429
  }
2430
+ /**
2431
+ * Generate HTML narrative for Condition resources using summary
2432
+ * @param resources - FHIR Composition resources
2433
+ * @param timezone - Optional timezone to use for date formatting (e.g., 'America/New_York', 'Europe/London')
2434
+ * @returns HTML string for rendering
2435
+ */
2436
+ generateSummaryNarrative(resources, timezone) {
2437
+ const templateUtilities = new TemplateUtilities(resources);
2438
+ let isSummaryCreated = false;
2439
+ let html = `<p>This list includes patient problems, sorted by recorded date (most recent first)</p>
2440
+ <div>
2441
+ <table>
2442
+ <thead>
2443
+ <tr>
2444
+ <th>Problem</th>
2445
+ <th>Code (System)</th>
2446
+ <th>Is Chronic</th>
2447
+ <th>Onset Date</th>
2448
+ <th>Last Confirmed Date</th>
2449
+ </tr>
2450
+ </thead>
2451
+ <tbody>`;
2452
+ for (const resourceItem of resources) {
2453
+ for (const rowData of resourceItem.section ?? []) {
2454
+ const sectionCodeableConcept = rowData.code;
2455
+ const data = {};
2456
+ for (const columnData of rowData.section ?? []) {
2457
+ if (columnData.title) {
2458
+ data[columnData.title] = templateUtilities.renderTextAsHtml(columnData.text?.div ?? "");
2459
+ }
2460
+ }
2461
+ if (data["Condition Name"]?.toLowerCase() === "unknown") {
2462
+ continue;
2463
+ }
2464
+ if (data["Status"] === "active") {
2465
+ isSummaryCreated = true;
2466
+ html += `
2467
+ <tr>
2468
+ <td>${templateUtilities.capitalizeFirstLetter(data["Condition Name"] ?? "")}</td>
2469
+ <td>${templateUtilities.codeableConceptCoding(sectionCodeableConcept)}</td>
2470
+ <td>${data["Is Chronic"] ?? ""}</td>
2471
+ <td>${templateUtilities.renderTime(data["Onset Date"], timezone) ?? ""}</td>
2472
+ <td>${templateUtilities.renderTime(data["Last Confirmed Date"], timezone) ?? ""}</td>
2473
+ </tr>`;
2474
+ }
2475
+ }
2476
+ }
2477
+ html += `
2478
+ </tbody>
2479
+ </table>
2480
+ </div>`;
2481
+ return isSummaryCreated ? html : void 0;
2482
+ }
2375
2483
  /**
2376
2484
  * Internal static implementation that actually generates the narrative
2377
2485
  * @param resources - FHIR Condition resources
@@ -2400,7 +2508,6 @@ var ProblemListTemplate = class _ProblemListTemplate {
2400
2508
  <th>Code (System)</th>
2401
2509
  <th>Onset Date</th>
2402
2510
  <th>Recorded Date</th>
2403
- <th>Source</th>
2404
2511
  </tr>
2405
2512
  </thead>
2406
2513
  <tbody>`;
@@ -2411,13 +2518,15 @@ var ProblemListTemplate = class _ProblemListTemplate {
2411
2518
  if (codeAndSystem && seenCodeAndSystems.has(codeAndSystem)) {
2412
2519
  continue;
2413
2520
  }
2521
+ if (conditionDisplay?.toLowerCase() === "unknown") {
2522
+ continue;
2523
+ }
2414
2524
  seenCodeAndSystems.add(codeAndSystem);
2415
2525
  html += `<tr>
2416
2526
  <td class="Name">${templateUtilities.capitalizeFirstLetter(conditionDisplay)}</td>
2417
2527
  <td class="CodeSystem">${codeAndSystem}</td>
2418
2528
  <td class="OnsetDate">${templateUtilities.renderDate(cond.onsetDateTime)}</td>
2419
2529
  <td class="RecordedDate">${templateUtilities.renderDate(cond.recordedDate)}</td>
2420
- <td class="Source">${templateUtilities.getOwnerTag(cond)}</td>
2421
2530
  </tr>`;
2422
2531
  }
2423
2532
  html += `</tbody>
@@ -2457,7 +2566,6 @@ var VitalSignsTemplate = class _VitalSignsTemplate {
2457
2566
  <th>Code (System)</th>
2458
2567
  <th>Result</th>
2459
2568
  <th>Date</th>
2460
- <th>Source</th>
2461
2569
  </tr>
2462
2570
  </thead>
2463
2571
  <tbody>`;
@@ -2490,6 +2598,9 @@ var VitalSignsTemplate = class _VitalSignsTemplate {
2490
2598
  data[columnTitle] = templateUtilities.renderTextAsHtml(columnData.text?.div ?? "");
2491
2599
  }
2492
2600
  }
2601
+ if (data["Vital Name"]?.toLowerCase() === "unknown") {
2602
+ continue;
2603
+ }
2493
2604
  isSummaryCreated = true;
2494
2605
  html += `
2495
2606
  <tr>
@@ -2497,7 +2608,6 @@ var VitalSignsTemplate = class _VitalSignsTemplate {
2497
2608
  <td>${data["codeSystem"] ?? ""}</td>
2498
2609
  <td>${templateUtilities.extractObservationSummaryValue(data, timezone) ?? ""}</td>
2499
2610
  <td>${templateUtilities.extractObservationSummaryEffectiveTime(data, timezone) ?? ""}</td>
2500
- <td>${data["Source"] ?? ""}</td>
2501
2611
  </tr>`;
2502
2612
  }
2503
2613
  }
@@ -2535,14 +2645,17 @@ var VitalSignsTemplate = class _VitalSignsTemplate {
2535
2645
  <th>Component(s)</th>
2536
2646
  <th>Comments</th>
2537
2647
  <th>Date</th>
2538
- <th>Source</th>
2539
2648
  </tr>
2540
2649
  </thead>
2541
2650
  <tbody>`;
2542
2651
  for (const obs of observations) {
2652
+ const vitalName = templateUtilities.codeableConceptDisplay(obs.code, "display");
2653
+ if (vitalName?.toLowerCase() === "unknown") {
2654
+ continue;
2655
+ }
2543
2656
  html += `
2544
2657
  <tr>
2545
- <td>${templateUtilities.capitalizeFirstLetter(templateUtilities.renderTextAsHtml(templateUtilities.codeableConceptDisplay(obs.code, "display")))}</td>
2658
+ <td>${templateUtilities.capitalizeFirstLetter(templateUtilities.renderTextAsHtml(vitalName))}</td>
2546
2659
  <td>${templateUtilities.codeableConceptCoding(obs.code)}</td>
2547
2660
  <td>${templateUtilities.extractObservationValue(obs)}</td>
2548
2661
  <td>${templateUtilities.extractObservationValueUnit(obs)}</td>
@@ -2550,7 +2663,6 @@ var VitalSignsTemplate = class _VitalSignsTemplate {
2550
2663
  <td>${templateUtilities.renderComponent(obs.component)}</td>
2551
2664
  <td>${templateUtilities.renderNotes(obs.note, timezone)}</td>
2552
2665
  <td>${obs.effectiveDateTime ? templateUtilities.renderTime(obs.effectiveDateTime, timezone) : obs.effectivePeriod ? templateUtilities.renderPeriod(obs.effectivePeriod, timezone) : ""}</td>
2553
- <td>${templateUtilities.getOwnerTag(obs)}</td>
2554
2666
  </tr>`;
2555
2667
  }
2556
2668
  html += `
@@ -2597,10 +2709,14 @@ var MedicalDevicesTemplate = class _MedicalDevicesTemplate {
2597
2709
  });
2598
2710
  let isDeviceAdded = false;
2599
2711
  for (const dus of deviceStatements) {
2712
+ const deviceName = templateUtilities.renderTextAsHtml(templateUtilities.renderDevice(dus.device));
2713
+ if (deviceName?.toLowerCase() === "unknown") {
2714
+ continue;
2715
+ }
2600
2716
  isDeviceAdded = true;
2601
2717
  html += `
2602
2718
  <tr>
2603
- <td>${templateUtilities.capitalizeFirstLetter(templateUtilities.renderTextAsHtml(templateUtilities.renderDevice(dus.device)))}</td>
2719
+ <td>${templateUtilities.capitalizeFirstLetter(deviceName)}</td>
2604
2720
  <td>${templateUtilities.renderTextAsHtml(dus.status || "")}</td>
2605
2721
  <td>${templateUtilities.renderNotes(dus.note, timezone)}</td>
2606
2722
  <td>${templateUtilities.renderTextAsHtml(templateUtilities.renderRecorded(dus.recordedOn, timezone))}</td>
@@ -2974,7 +3090,6 @@ var DiagnosticResultsTemplate = class _DiagnosticResultsTemplate {
2974
3090
  <th>Result</th>
2975
3091
  <th>Reference Range</th>
2976
3092
  <th>Date</th>
2977
- <th>Source</th>
2978
3093
  </tr>
2979
3094
  </thead>
2980
3095
  <tbody>`;
@@ -2988,7 +3103,6 @@ var DiagnosticResultsTemplate = class _DiagnosticResultsTemplate {
2988
3103
  <th>Report</th>
2989
3104
  <th>Performer</th>
2990
3105
  <th>Issued</th>
2991
- <th>Source</th>
2992
3106
  </tr>
2993
3107
  </thead>
2994
3108
  <tbody>`;
@@ -3035,8 +3149,6 @@ var DiagnosticResultsTemplate = class _DiagnosticResultsTemplate {
3035
3149
  case "Status":
3036
3150
  data["status"] = templateUtilities.renderTextAsHtml(columnData.text?.div ?? "");
3037
3151
  break;
3038
- case "Source":
3039
- data["source"] = templateUtilities.renderTextAsHtml(columnData.text?.div ?? "");
3040
3152
  break;
3041
3153
  default:
3042
3154
  break;
@@ -3062,6 +3174,9 @@ var DiagnosticResultsTemplate = class _DiagnosticResultsTemplate {
3062
3174
  for (const component of components) {
3063
3175
  const componentCode = `${groupName}${component["code"] ?? ""}`;
3064
3176
  if (componentCode && !observationAdded.has(componentCode)) {
3177
+ if (component["code"]?.toLowerCase() === "unknown") {
3178
+ continue;
3179
+ }
3065
3180
  observationAdded.add(componentCode);
3066
3181
  this.formatSummaryObservationData(component);
3067
3182
  observationhtml += `
@@ -3071,7 +3186,6 @@ var DiagnosticResultsTemplate = class _DiagnosticResultsTemplate {
3071
3186
  <td>${templateUtilities.renderTextAsHtml(component["formattedValue"]) ?? ""}</td>
3072
3187
  <td>${templateUtilities.renderTextAsHtml(component["referenceRange"])?.trim() ?? ""}</td>
3073
3188
  <td>${date ?? ""}</td>
3074
- <td>${data["source"] ?? ""}</td>
3075
3189
  </tr>`;
3076
3190
  }
3077
3191
  }
@@ -3079,6 +3193,9 @@ var DiagnosticResultsTemplate = class _DiagnosticResultsTemplate {
3079
3193
  if (obsDate && obsDate >= twoYearsAgo) {
3080
3194
  const code = data["code"] ?? "";
3081
3195
  if (code && !observationAdded.has(code)) {
3196
+ if (code.toLowerCase() === "unknown") {
3197
+ continue;
3198
+ }
3082
3199
  observationAdded.add(code);
3083
3200
  this.formatSummaryObservationData(data);
3084
3201
  observationhtml += `
@@ -3088,7 +3205,6 @@ var DiagnosticResultsTemplate = class _DiagnosticResultsTemplate {
3088
3205
  <td>${templateUtilities.renderTextAsHtml(data["formattedValue"]) ?? ""}</td>
3089
3206
  <td>${templateUtilities.renderTextAsHtml(data["referenceRange"])?.trim() ?? ""}</td>
3090
3207
  <td>${date ?? ""}</td>
3091
- <td>${data["source"] ?? ""}</td>
3092
3208
  </tr>`;
3093
3209
  }
3094
3210
  }
@@ -3101,13 +3217,15 @@ var DiagnosticResultsTemplate = class _DiagnosticResultsTemplate {
3101
3217
  if (data["status"] === "final" && issuedDate && issuedDate >= twoYearsAgo) {
3102
3218
  const reportName = data["report"] ?? "";
3103
3219
  if (reportName && !diagnosticReportAdded.has(reportName)) {
3220
+ if (reportName.toLowerCase() === "unknown") {
3221
+ continue;
3222
+ }
3104
3223
  diagnosticReportAdded.add(reportName);
3105
3224
  diagnosticReporthtml += `
3106
3225
  <tr>
3107
3226
  <td>${templateUtilities.capitalizeFirstLetter(data["report"] ?? "")}</td>
3108
3227
  <td>${data["performer"] ?? ""}</td>
3109
3228
  <td>${templateUtilities.renderTime(data["issued"], timezone) ?? ""}</td>
3110
- <td>${data["source"] ?? ""}</td>
3111
3229
  </tr>`;
3112
3230
  }
3113
3231
  }
@@ -3292,7 +3410,6 @@ var DiagnosticResultsTemplate = class _DiagnosticResultsTemplate {
3292
3410
  <th>Result</th>
3293
3411
  <th>Reference Range</th>
3294
3412
  <th>Date</th>
3295
- <th>Source</th>
3296
3413
  </tr>
3297
3414
  </thead>
3298
3415
  <tbody>`;
@@ -3301,6 +3418,9 @@ var DiagnosticResultsTemplate = class _DiagnosticResultsTemplate {
3301
3418
  const obsCodeDisplay = templateUtilities.renderTextAsHtml(templateUtilities.codeableConceptDisplay(obs.code));
3302
3419
  const obsCodeAndSystem = templateUtilities.codeableConceptCoding(obs.code);
3303
3420
  if (!observationAdded.has(obsCodeDisplay) && !observationAdded.has(obsCodeAndSystem)) {
3421
+ if (obsCodeDisplay?.toLowerCase() === "unknown") {
3422
+ continue;
3423
+ }
3304
3424
  observationAdded.add(obsCodeDisplay);
3305
3425
  observationAdded.add(obsCodeAndSystem);
3306
3426
  html += `
@@ -3310,7 +3430,6 @@ var DiagnosticResultsTemplate = class _DiagnosticResultsTemplate {
3310
3430
  <td>${templateUtilities.extractObservationValue(obs)}</td>
3311
3431
  <td>${templateUtilities.concatReferenceRange(obs.referenceRange)}</td>
3312
3432
  <td>${obs.effectiveDateTime ? templateUtilities.renderTime(obs.effectiveDateTime, timezone) : obs.effectivePeriod ? templateUtilities.renderPeriod(obs.effectivePeriod, timezone) : ""}</td>
3313
- <td>${templateUtilities.getOwnerTag(obs)}</td>
3314
3433
  </tr>`;
3315
3434
  }
3316
3435
  }
@@ -3337,7 +3456,6 @@ var DiagnosticResultsTemplate = class _DiagnosticResultsTemplate {
3337
3456
  <th>Category</th>
3338
3457
  <th>Result</th>
3339
3458
  <th>Issued</th>
3340
- <th>Source</th>
3341
3459
  </tr>
3342
3460
  </thead>
3343
3461
  <tbody>`;
@@ -3346,6 +3464,9 @@ var DiagnosticResultsTemplate = class _DiagnosticResultsTemplate {
3346
3464
  const reportName = templateUtilities.renderTextAsHtml(templateUtilities.codeableConceptDisplay(report.code));
3347
3465
  const codeAndSystem = templateUtilities.codeableConceptCoding(report.code);
3348
3466
  if (!diagnosticReportAdded.has(reportName) && !diagnosticReportAdded.has(codeAndSystem)) {
3467
+ if (reportName?.toLowerCase() === "unknown") {
3468
+ continue;
3469
+ }
3349
3470
  diagnosticReportAdded.add(reportName);
3350
3471
  diagnosticReportAdded.add(codeAndSystem);
3351
3472
  let resultCount = "";
@@ -3359,7 +3480,6 @@ var DiagnosticResultsTemplate = class _DiagnosticResultsTemplate {
3359
3480
  <td>${templateUtilities.firstFromCodeableConceptList(report.category)}</td>
3360
3481
  <td>${resultCount}</td>
3361
3482
  <td>${report.issued ? templateUtilities.renderTime(report.issued, timezone) : ""}</td>
3362
- <td>${templateUtilities.getOwnerTag(report)}</td>
3363
3483
  </tr>`;
3364
3484
  }
3365
3485
  }
@@ -3426,7 +3546,6 @@ var HistoryOfProceduresTemplate = class _HistoryOfProceduresTemplate {
3426
3546
  <th>Code (System)</th>
3427
3547
  <th>Performer</th>
3428
3548
  <th>Date</th>
3429
- <th>Source</th>
3430
3549
  </tr>
3431
3550
  </thead>
3432
3551
  <tbody>`;
@@ -3446,13 +3565,14 @@ var HistoryOfProceduresTemplate = class _HistoryOfProceduresTemplate {
3446
3565
  case "Performed Date":
3447
3566
  data["date"] = columnData.text?.div ?? "";
3448
3567
  break;
3449
- case "Source":
3450
- data["source"] = templateUtilities.renderTextAsHtml(columnData.text?.div ?? "");
3451
3568
  break;
3452
3569
  default:
3453
3570
  break;
3454
3571
  }
3455
3572
  }
3573
+ if (data["procedure"]?.toLowerCase() === "unknown") {
3574
+ continue;
3575
+ }
3456
3576
  isSummaryCreated = true;
3457
3577
  html += `
3458
3578
  <tr>
@@ -3460,7 +3580,6 @@ var HistoryOfProceduresTemplate = class _HistoryOfProceduresTemplate {
3460
3580
  <td>${data["codeSystem"] ?? ""}</td>
3461
3581
  <td>${data["performer"] ?? ""}</td>
3462
3582
  <td>${templateUtilities.renderTime(data["date"], timezone) ?? ""}</td>
3463
- <td>${data["source"] ?? ""}</td>
3464
3583
  </tr>`;
3465
3584
  }
3466
3585
  }
@@ -3488,19 +3607,21 @@ var HistoryOfProceduresTemplate = class _HistoryOfProceduresTemplate {
3488
3607
  <th>Code (System)</th>
3489
3608
  <th>Comments</th>
3490
3609
  <th>Date</th>
3491
- <th>Source</th>
3492
3610
  </tr>
3493
3611
  </thead>
3494
3612
  <tbody>`;
3495
3613
  for (const resourceItem of resources) {
3496
3614
  const proc = resourceItem;
3615
+ const procedureName = templateUtilities.codeableConceptDisplay(proc.code, "display");
3616
+ if (procedureName?.toLowerCase() === "unknown") {
3617
+ continue;
3618
+ }
3497
3619
  html += `
3498
3620
  <tr>
3499
- <td>${templateUtilities.capitalizeFirstLetter(templateUtilities.renderTextAsHtml(templateUtilities.codeableConceptDisplay(proc.code, "display")))}</td>
3621
+ <td>${templateUtilities.capitalizeFirstLetter(templateUtilities.renderTextAsHtml(procedureName))}</td>
3500
3622
  <td>${templateUtilities.codeableConceptCoding(proc.code)}</td>
3501
3623
  <td>${templateUtilities.renderNotes(proc.note, timezone)}</td>
3502
3624
  <td>${templateUtilities.renderTime(proc.performedDateTime || proc.performedPeriod?.start, timezone)}</td>
3503
- <td>${templateUtilities.getOwnerTag(proc)}</td>
3504
3625
  </tr>`;
3505
3626
  }
3506
3627
  html += `
@@ -3547,7 +3668,6 @@ var SocialHistoryTemplate = class _SocialHistoryTemplate {
3547
3668
  <th>Unit</th>
3548
3669
  <th>Comments</th>
3549
3670
  <th>Date</th>
3550
- <th>Source</th>
3551
3671
  </tr>
3552
3672
  </thead>
3553
3673
  <tbody>`;
@@ -3555,6 +3675,9 @@ var SocialHistoryTemplate = class _SocialHistoryTemplate {
3555
3675
  for (const obs of observations) {
3556
3676
  const obsName = templateUtilities.renderTextAsHtml(templateUtilities.codeableConceptDisplay(obs.code));
3557
3677
  if (!addedObservations.has(obsName)) {
3678
+ if (obsName?.toLowerCase() === "unknown") {
3679
+ continue;
3680
+ }
3558
3681
  addedObservations.add(obsName);
3559
3682
  html += `
3560
3683
  <tr>
@@ -3564,7 +3687,6 @@ var SocialHistoryTemplate = class _SocialHistoryTemplate {
3564
3687
  <td>${templateUtilities.extractObservationValueUnit(obs)}</td>
3565
3688
  <td>${templateUtilities.renderNotes(obs.note, timezone)}</td>
3566
3689
  <td>${obs.effectiveDateTime ? templateUtilities.renderTime(obs.effectiveDateTime, timezone) : obs.effectivePeriod ? templateUtilities.renderPeriod(obs.effectivePeriod, timezone) : ""}</td>
3567
- <td>${templateUtilities.getOwnerTag(obs)}</td>
3568
3690
  </tr>`;
3569
3691
  }
3570
3692
  }
@@ -3615,7 +3737,6 @@ var PastHistoryOfIllnessTemplate = class {
3615
3737
  <th>Onset Date</th>
3616
3738
  <th>Recorded Date</th>
3617
3739
  <th>Resolved Date</th>
3618
- <th>Source</th>
3619
3740
  </tr>
3620
3741
  </thead>
3621
3742
  <tbody>`;
@@ -3623,6 +3744,9 @@ var PastHistoryOfIllnessTemplate = class {
3623
3744
  for (const cond of filteredConditions) {
3624
3745
  const conditionCode = templateUtilities.renderTextAsHtml(templateUtilities.codeableConceptDisplay(cond.code));
3625
3746
  if (!addedConditionCodes.has(conditionCode)) {
3747
+ if (conditionCode?.toLowerCase() === "unknown") {
3748
+ continue;
3749
+ }
3626
3750
  addedConditionCodes.add(conditionCode);
3627
3751
  html += `<tr>
3628
3752
  <td class="Name">${templateUtilities.capitalizeFirstLetter(conditionCode)}</td>
@@ -3630,7 +3754,6 @@ var PastHistoryOfIllnessTemplate = class {
3630
3754
  <td class="OnsetDate">${templateUtilities.renderDate(cond.onsetDateTime)}</td>
3631
3755
  <td class="RecordedDate">${templateUtilities.renderDate(cond.recordedDate)}</td>
3632
3756
  <td class="ResolvedDate">${templateUtilities.renderDate(cond.abatementDateTime)}</td>
3633
- <td class="Source">${templateUtilities.getOwnerTag(cond)}</td>
3634
3757
  </tr>`;
3635
3758
  }
3636
3759
  }
@@ -3642,6 +3765,73 @@ var PastHistoryOfIllnessTemplate = class {
3642
3765
  }
3643
3766
  return html;
3644
3767
  }
3768
+ /**
3769
+ * Generate HTML narrative for Condition resources using summary
3770
+ * @param resources - FHIR Composition resources
3771
+ * @param timezone - Optional timezone to use for date formatting (e.g., 'America/New_York', 'Europe/London')
3772
+ * @returns HTML string for rendering
3773
+ */
3774
+ generateSummaryNarrative(resources, timezone, now) {
3775
+ const templateUtilities = new TemplateUtilities(resources);
3776
+ let isSummaryCreated = false;
3777
+ const currentDate = now || /* @__PURE__ */ new Date();
3778
+ const fiveYearsAgo = new Date(currentDate);
3779
+ fiveYearsAgo.setFullYear(currentDate.getFullYear() - 5);
3780
+ let skippedConditions = 0;
3781
+ let html = `<p>This list includes past problems for the patient with a recorded date within the last 5 years, sorted by recorded date (most recent first).</p>
3782
+ <div>
3783
+ <table>
3784
+ <thead>
3785
+ <tr>
3786
+ <th>Problem</th>
3787
+ <th>Code (System)</th>
3788
+ <th>Is Chronic</th>
3789
+ <th>Onset Date</th>
3790
+ <th>Last Confirmed Date</th>
3791
+ <th>Resolved Date</th>
3792
+ </tr>
3793
+ </thead>
3794
+ <tbody>`;
3795
+ for (const resourceItem of resources) {
3796
+ for (const rowData of resourceItem.section ?? []) {
3797
+ const sectionCodeableConcept = rowData.code;
3798
+ const data = {};
3799
+ for (const columnData of rowData.section ?? []) {
3800
+ if (columnData.title) {
3801
+ data[columnData.title] = templateUtilities.renderTextAsHtml(columnData.text?.div ?? "");
3802
+ }
3803
+ }
3804
+ if (data["Condition Name"]?.toLowerCase() === "unknown") {
3805
+ continue;
3806
+ }
3807
+ if (data["Status"] === "inactive") {
3808
+ if (data["Last Confirmed Date"] && new Date(data["Last Confirmed Date"]) < fiveYearsAgo) {
3809
+ skippedConditions++;
3810
+ continue;
3811
+ }
3812
+ isSummaryCreated = true;
3813
+ html += `
3814
+ <tr>
3815
+ <td>${templateUtilities.capitalizeFirstLetter(data["Condition Name"] ?? "")}</td>
3816
+ <td>${templateUtilities.codeableConceptCoding(sectionCodeableConcept)}</td>
3817
+ <td>${data["Is Chronic"] ?? ""}</td>
3818
+ <td>${templateUtilities.renderTime(data["Onset Date"], timezone) ?? ""}</td>
3819
+ <td>${templateUtilities.renderTime(data["Last Confirmed Date"], timezone) ?? ""}</td>
3820
+ <td>${templateUtilities.renderTime(data["Resolved Date"], timezone) ?? ""}</td>
3821
+ </tr>`;
3822
+ }
3823
+ }
3824
+ }
3825
+ html += `
3826
+ </tbody>
3827
+ </table>`;
3828
+ if (skippedConditions > 0) {
3829
+ html += `
3830
+ <p><em>${skippedConditions} additional past illnesses older than 5 years ago are present</em></p>`;
3831
+ }
3832
+ html += `</div>`;
3833
+ return isSummaryCreated ? html : void 0;
3834
+ }
3645
3835
  };
3646
3836
 
3647
3837
  // src/narratives/templates/typescript/PlanOfCareTemplate.ts
@@ -3671,19 +3861,21 @@ var PlanOfCareTemplate = class {
3671
3861
  <th>Comments</th>
3672
3862
  <th>Planned Start</th>
3673
3863
  <th>Planned End</th>
3674
- <th>Source</th>
3675
3864
  </tr>
3676
3865
  </thead>
3677
3866
  <tbody>`;
3678
3867
  for (const cp of carePlans) {
3868
+ const carePlanName = cp.description || cp.title || "";
3869
+ if (carePlanName.toLowerCase() === "unknown") {
3870
+ continue;
3871
+ }
3679
3872
  html += `
3680
3873
  <tr>
3681
- <td>${templateUtilities.capitalizeFirstLetter(cp.description || cp.title || "")}</td>
3874
+ <td>${templateUtilities.capitalizeFirstLetter(carePlanName)}</td>
3682
3875
  <td>${cp.intent || ""}</td>
3683
3876
  <td>${templateUtilities.concat(cp.note, "text")}</td>
3684
3877
  <td>${cp.period?.start ? templateUtilities.renderTime(cp.period?.start, timezone) : ""}</td>
3685
3878
  <td>${cp.period?.end ? templateUtilities.renderTime(cp.period?.end, timezone) : ""}</td>
3686
- <td>${templateUtilities.getOwnerTag(cp)}</td>
3687
3879
  </tr>`;
3688
3880
  }
3689
3881
  html += `
@@ -3711,7 +3903,6 @@ var PlanOfCareTemplate = class {
3711
3903
  <th>Created</th>
3712
3904
  <th>Planned Start</th>
3713
3905
  <th>Planned End</th>
3714
- <th>Source</th>
3715
3906
  </tr>
3716
3907
  </thead>
3717
3908
  <tbody>`;
@@ -3726,6 +3917,9 @@ var PlanOfCareTemplate = class {
3726
3917
  if (data["status"] !== "active") {
3727
3918
  continue;
3728
3919
  }
3920
+ if (data["CarePlan Name"]?.toLowerCase() === "unknown") {
3921
+ continue;
3922
+ }
3729
3923
  isSummaryCreated = true;
3730
3924
  html += `
3731
3925
  <tr>
@@ -3733,7 +3927,6 @@ var PlanOfCareTemplate = class {
3733
3927
  <td>${templateUtilities.renderTime(data["created"], timezone) ?? ""}</td>
3734
3928
  <td>${templateUtilities.renderTime(data["period.start"], timezone) ?? ""}</td>
3735
3929
  <td>${templateUtilities.renderTime(data["period.end"], timezone) ?? ""}</td>
3736
- <td>${data["source"] ?? ""}</td>
3737
3930
  </tr>`;
3738
3931
  }
3739
3932
  }
@@ -3790,6 +3983,9 @@ var FunctionalStatusTemplate = class _FunctionalStatusTemplate {
3790
3983
  for (const obs of functionalObservations) {
3791
3984
  const observation = obs;
3792
3985
  const obsName = templateUtilities.codeableConceptDisplay(observation.code);
3986
+ if (obsName?.toLowerCase() === "unknown") {
3987
+ continue;
3988
+ }
3793
3989
  const value = templateUtilities.extractObservationValue(observation);
3794
3990
  const date = observation.effectiveDateTime ? templateUtilities.renderDate(observation.effectiveDateTime) : observation.issued ? templateUtilities.renderDate(observation.issued) : "";
3795
3991
  const interpretation = observation.interpretation ? templateUtilities.codeableConceptDisplay(observation.interpretation[0]) : "";
@@ -3897,18 +4093,19 @@ var PregnancyTemplate = class _PregnancyTemplate {
3897
4093
  <th>Code (System)</th>
3898
4094
  <th>Comments</th>
3899
4095
  <th>Date</th>
3900
- <th>Source</th>
3901
4096
  </tr>
3902
4097
  </thead>
3903
4098
  <tbody>`;
3904
- function renderRow({ result, comments, date, codeSystem, owner }) {
4099
+ function renderRow({ result, comments, date, codeSystem }) {
4100
+ if (result?.toLowerCase() === "unknown") {
4101
+ return;
4102
+ }
3905
4103
  html += `
3906
4104
  <tr>
3907
4105
  <td class="Result">${templateUtilities.capitalizeFirstLetter(result)}</td>
3908
4106
  <td class="CodeSystem">${codeSystem}</td>
3909
4107
  <td class="Comments">${comments}</td>
3910
4108
  <td class="Date">${date}</td>
3911
- <td class="Source">${owner}</td>
3912
4109
  </tr>`;
3913
4110
  }
3914
4111
  const rowResources = [];
@@ -3962,8 +4159,7 @@ var PregnancyTemplate = class _PregnancyTemplate {
3962
4159
  const rowKey = `${result}|${codeSystem}`;
3963
4160
  if (!addedRows.has(rowKey)) {
3964
4161
  addedRows.add(rowKey);
3965
- const owner = templateUtilities.getOwnerTag(resource);
3966
- renderRow({ result, comments, date: dateStr, codeSystem, owner });
4162
+ renderRow({ result, comments, date: dateStr, codeSystem });
3967
4163
  }
3968
4164
  }
3969
4165
  html += `
@@ -4010,11 +4206,17 @@ var AdvanceDirectivesTemplate = class _AdvanceDirectivesTemplate {
4010
4206
  </tr>
4011
4207
  </thead>
4012
4208
  <tbody>`;
4209
+ let isConsentAdded = false;
4013
4210
  for (const resourceItem of resources) {
4014
4211
  const consent = resourceItem;
4212
+ const consentScope = templateUtilities.capitalizeFirstLetter(templateUtilities.renderTextAsHtml(templateUtilities.codeableConceptDisplay(consent.scope, "display")));
4213
+ if (!consentScope || consentScope.toLowerCase() === "unknown") {
4214
+ continue;
4215
+ }
4216
+ isConsentAdded = true;
4015
4217
  html += `
4016
4218
  <tr>
4017
- <td>${templateUtilities.capitalizeFirstLetter(templateUtilities.renderTextAsHtml(templateUtilities.codeableConceptDisplay(consent.scope, "display")))}</td>
4219
+ <td>${consentScope}</td>
4018
4220
  <td>${consent.status || ""}</td>
4019
4221
  <td>${consent.provision?.action ? templateUtilities.concatCodeableConcept(consent.provision.action) : ""}</td>
4020
4222
  <td>${consent.dateTime || ""}</td>
@@ -4023,7 +4225,7 @@ var AdvanceDirectivesTemplate = class _AdvanceDirectivesTemplate {
4023
4225
  html += `
4024
4226
  </tbody>
4025
4227
  </table>`;
4026
- return html;
4228
+ return isConsentAdded ? html : void 0;
4027
4229
  }
4028
4230
  };
4029
4231
 
@@ -4218,6 +4420,10 @@ var ComprehensiveIPSCompositionBuilder = class {
4218
4420
  * @param validResources - Array of domain resources
4219
4421
  */
4220
4422
  addSectionAsync(narrative, sectionType, validResources) {
4423
+ if (sectionType === "Patient" /* PATIENT */) {
4424
+ this.patientSummary = narrative;
4425
+ return this;
4426
+ }
4221
4427
  const sectionEntry = {
4222
4428
  title: IPS_SECTION_DISPLAY_NAMES[sectionType] || sectionType,
4223
4429
  code: {
@@ -4247,26 +4453,24 @@ var ComprehensiveIPSCompositionBuilder = class {
4247
4453
  for (const resource of validResources) {
4248
4454
  this.resources.add(resource);
4249
4455
  }
4250
- if (sectionType !== "Patient" /* PATIENT */) {
4251
- let narrative = void 0;
4252
- if (validResources.length > 0) {
4253
- narrative = await NarrativeGenerator.generateNarrativeAsync(
4254
- sectionType,
4255
- validResources,
4256
- timezone,
4257
- true
4258
- );
4259
- }
4260
- if (!narrative && sectionType in IPSMandatorySections) {
4261
- narrative = await NarrativeGenerator.createNarrativeAsync(
4262
- IPSMissingMandatorySectionContent[sectionType]
4263
- );
4264
- }
4265
- if (!narrative) {
4266
- return this;
4267
- }
4268
- this.addSectionAsync(narrative, sectionType, validResources);
4456
+ let narrative = void 0;
4457
+ if (validResources.length > 0) {
4458
+ narrative = await NarrativeGenerator.generateNarrativeAsync(
4459
+ sectionType,
4460
+ validResources,
4461
+ timezone,
4462
+ true
4463
+ );
4464
+ }
4465
+ if (!narrative && sectionType in IPSMandatorySections) {
4466
+ narrative = await NarrativeGenerator.createNarrativeAsync(
4467
+ IPSMissingMandatorySectionContent[sectionType]
4468
+ );
4469
+ }
4470
+ if (!narrative) {
4471
+ return this;
4269
4472
  }
4473
+ this.addSectionAsync(narrative, sectionType, validResources);
4270
4474
  return this;
4271
4475
  }
4272
4476
  async makeSectionFromSummaryAsync(sectionType, summaryCompositions, resources, timezone) {
@@ -4304,17 +4508,18 @@ var ComprehensiveIPSCompositionBuilder = class {
4304
4508
  * @param timezone - Optional timezone to use for date formatting
4305
4509
  * @param useSummaryCompositions - Whether to use summary compositions (default: false)
4306
4510
  */
4307
- async readBundleAsync(bundle, timezone, useSummaryCompositions = false) {
4511
+ async readBundleAsync(bundle, timezone, useSummaryCompositions = false, consoleLogger = console) {
4308
4512
  if (!bundle.entry) {
4309
4513
  return this;
4310
4514
  }
4311
4515
  const patientEntries = [];
4312
4516
  const resources = [];
4313
4517
  bundle.entry.forEach((e) => {
4314
- if (e.resource?.resourceType === "Patient") {
4315
- patientEntries.push(e.resource);
4316
- this.resources.add(e.resource);
4317
- } else if (e.resource) {
4518
+ if (e.resource) {
4519
+ if (e.resource.resourceType === "Patient") {
4520
+ patientEntries.push(e.resource);
4521
+ this.resources.add(e.resource);
4522
+ }
4318
4523
  resources.push(e.resource);
4319
4524
  }
4320
4525
  });
@@ -4323,23 +4528,20 @@ var ComprehensiveIPSCompositionBuilder = class {
4323
4528
  }
4324
4529
  this.patients = patientEntries;
4325
4530
  for (const sectionType of Object.values(IPSSections)) {
4326
- if (sectionType === "Patient" /* PATIENT */) {
4327
- continue;
4328
- }
4329
4531
  const summaryIPSCompositionFilter = useSummaryCompositions ? IPSSectionResourceHelper.getSummaryIPSCompositionFilterForSection(sectionType) : void 0;
4330
4532
  const sectionIPSSummary = summaryIPSCompositionFilter ? resources.filter((resource) => summaryIPSCompositionFilter(resource)) : [];
4331
4533
  if (sectionIPSSummary.length > 0) {
4332
- console.log(`Using IPS summary composition for section: ${sectionType}`);
4534
+ consoleLogger.info(`Using IPS summary composition for section: ${sectionType}`);
4333
4535
  await this.makeSectionFromSummaryAsync(sectionType, sectionIPSSummary, resources, timezone);
4334
4536
  continue;
4335
4537
  }
4336
4538
  const summaryCompositionFilter = useSummaryCompositions ? IPSSectionResourceHelper.getSummaryCompositionFilterForSection(sectionType) : void 0;
4337
4539
  const sectionSummary = summaryCompositionFilter ? resources.filter((resource) => summaryCompositionFilter(resource)) : [];
4338
4540
  if (sectionSummary.length > 0) {
4339
- console.log(`Using summary composition for section: ${sectionType}`);
4541
+ consoleLogger.info(`Using summary composition for section: ${sectionType}`);
4340
4542
  await this.makeSectionFromSummaryAsync(sectionType, sectionSummary, resources, timezone);
4341
4543
  } else {
4342
- console.log(`Using individual resources for section: ${sectionType}`);
4544
+ consoleLogger.info(`Using individual resources for section: ${sectionType}`);
4343
4545
  const sectionFilter = IPSSectionResourceHelper.getResourceFilterForSection(sectionType);
4344
4546
  const sectionResources = resources.filter((resource) => sectionFilter(resource));
4345
4547
  await this.makeSectionAsync(sectionType, sectionResources, timezone);
@@ -4363,6 +4565,9 @@ var ComprehensiveIPSCompositionBuilder = class {
4363
4565
  if (!this.patients) {
4364
4566
  throw new Error("Patient resource must be set before building the bundle");
4365
4567
  }
4568
+ if (!this.patientSummary) {
4569
+ throw new Error("Patient summary narrative must be set before building the bundle");
4570
+ }
4366
4571
  const primaryPatientId = patientId ?? this.patients[0].id;
4367
4572
  const composition = {
4368
4573
  id: `Composition-${primaryPatientId}`,
@@ -4386,14 +4591,7 @@ var ComprehensiveIPSCompositionBuilder = class {
4386
4591
  date: (now || /* @__PURE__ */ new Date()).toISOString(),
4387
4592
  title: "International Patient Summary",
4388
4593
  section: this.sections,
4389
- text: await NarrativeGenerator.generateNarrativeAsync(
4390
- "Patient" /* PATIENT */,
4391
- this.patients,
4392
- timezone,
4393
- true,
4394
- false,
4395
- now
4396
- )
4594
+ text: this.patientSummary
4397
4595
  };
4398
4596
  const bundle = {
4399
4597
  resourceType: "Bundle",