@imranq2/fhirpatientsummary 1.0.22 → 1.0.23

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (3) hide show
  1. package/dist/index.cjs +180 -124
  2. package/dist/index.js +180 -124
  3. package/package.json +1 -1
package/dist/index.cjs CHANGED
@@ -109,6 +109,14 @@ var BLOOD_PRESSURE_LOINC_CODES = {
109
109
  DIASTOLIC: "8462-4"
110
110
  };
111
111
 
112
+ // src/structures/ips_section_constants.ts
113
+ var VITAL_SIGNS_SUMMARY_COMPONENT_MAP = {
114
+ "Systolic Blood Pressure": "valueRatio.numerator.value",
115
+ "Diastolic Blood Pressure": "valueRatio.denominator.value",
116
+ "Default": "valueString"
117
+ };
118
+ var IPS_SUMMARY_COMPOSITION_TYPE_SYSTEM = "https://fhir.icanbwell.com/4_0_0/CodeSystem/composition/";
119
+
112
120
  // src/structures/ips_section_resource_map.ts
113
121
  var IPSSectionResourceFilters = {
114
122
  // Patient section: only Patient resource
@@ -116,7 +124,7 @@ var IPSSectionResourceFilters = {
116
124
  // Only include allergies
117
125
  ["AllergyIntoleranceSection" /* ALLERGIES */]: (resource) => resource.resourceType === "AllergyIntolerance",
118
126
  // includes MedicationRequest, MedicationStatement. Medication is needed for medication names
119
- ["MedicationSummarySection" /* MEDICATIONS */]: (resource) => ["MedicationRequest", "MedicationStatement", "Medication"].includes(resource.resourceType),
127
+ ["MedicationSummarySection" /* MEDICATIONS */]: (resource) => ["MedicationRequest", "MedicationStatement"].includes(resource.resourceType) && resource.status === "active" || resource.resourceType === "Medication",
120
128
  // Only include active conditions
121
129
  ["ProblemSection" /* PROBLEMS */]: (resource) => resource.resourceType === "Condition" && resource.clinicalStatus?.coding?.some((c) => !["inactive", "resolved"].includes(c.code)),
122
130
  // Only include completed immunizations
@@ -143,10 +151,11 @@ var IPSSectionResourceFilters = {
143
151
  ["AdvanceDirectivesSection" /* ADVANCE_DIRECTIVES */]: (resource) => resource.resourceType === "Consent" && resource.status === "active"
144
152
  };
145
153
  var IPSSectionSummaryCompositionFilter = {
146
- ["AllergyIntoleranceSection" /* ALLERGIES */]: (resource) => resource.resourceType === "Composition" && resource.type?.coding?.some((c) => c.system === "https://fhir.icanbwell.com/4_0_0/CodeSystem/composition/" && c.code === "allergy_summary_document"),
147
- ["VitalSignsSection" /* VITAL_SIGNS */]: (resource) => resource.resourceType === "Composition" && resource.type?.coding?.some((c) => c.system === "https://fhir.icanbwell.com/4_0_0/CodeSystem/composition/" && c.code === "vital_summary_document"),
148
- ["PlanOfCareSection" /* CARE_PLAN */]: (resource) => resource.resourceType === "Composition" && resource.type?.coding?.some((c) => c.system === "https://fhir.icanbwell.com/4_0_0/CodeSystem/composition/" && c.code === "careplan_summary_document"),
149
- ["ImmunizationSection" /* IMMUNIZATIONS */]: (resource) => resource.resourceType === "Composition" && resource.type?.coding?.some((c) => c.system === "https://fhir.icanbwell.com/4_0_0/CodeSystem/composition/" && c.code === "immunization_summary_document")
154
+ ["AllergyIntoleranceSection" /* ALLERGIES */]: (resource) => resource.resourceType === "Composition" && resource.type?.coding?.some((c) => c.system === IPS_SUMMARY_COMPOSITION_TYPE_SYSTEM && c.code === "allergy_summary_document"),
155
+ ["VitalSignsSection" /* VITAL_SIGNS */]: (resource) => resource.resourceType === "Composition" && resource.type?.coding?.some((c) => c.system === IPS_SUMMARY_COMPOSITION_TYPE_SYSTEM && c.code === "vital_summary_document"),
156
+ ["PlanOfCareSection" /* CARE_PLAN */]: (resource) => resource.resourceType === "Composition" && resource.type?.coding?.some((c) => c.system === IPS_SUMMARY_COMPOSITION_TYPE_SYSTEM && c.code === "careplan_summary_document"),
157
+ ["ImmunizationSection" /* IMMUNIZATIONS */]: (resource) => resource.resourceType === "Composition" && resource.type?.coding?.some((c) => c.system === IPS_SUMMARY_COMPOSITION_TYPE_SYSTEM && c.code === "immunization_summary_document"),
158
+ ["MedicationSummarySection" /* MEDICATIONS */]: (resource) => resource.resourceType === "Composition" && resource.type?.coding?.some((c) => c.system === IPS_SUMMARY_COMPOSITION_TYPE_SYSTEM && c.code === "medication_summary_document")
150
159
  };
151
160
  var IPSSectionResourceHelper = class {
152
161
  static getResourceFilterForSection(section) {
@@ -850,9 +859,11 @@ var TemplateUtilities = class {
850
859
  if (dateValue instanceof Date) {
851
860
  dateTime = import_luxon.DateTime.fromJSDate(dateValue);
852
861
  } else if (typeof dateValue === "string") {
853
- dateTime = import_luxon.DateTime.fromISO(dateValue);
854
862
  if (!dateValue.includes("T")) {
855
863
  dateOnly = true;
864
+ dateTime = import_luxon.DateTime.fromISO(dateValue, { zone: "utc" });
865
+ } else {
866
+ dateTime = import_luxon.DateTime.fromISO(dateValue);
856
867
  }
857
868
  } else {
858
869
  dateTime = import_luxon.DateTime.fromISO(String(dateValue));
@@ -954,6 +965,9 @@ var TemplateUtilities = class {
954
965
  }
955
966
  };
956
967
 
968
+ // src/constants.ts
969
+ var ADDRESS_SIMILARITY_THRESHOLD = 70;
970
+
957
971
  // src/narratives/templates/typescript/PatientTemplate.ts
958
972
  var PatientTemplate = class _PatientTemplate {
959
973
  /**
@@ -980,7 +994,6 @@ var PatientTemplate = class _PatientTemplate {
980
994
  <li><strong>Name(s):</strong>${this.renderNames(combinedPatient)}</li>
981
995
  <li><strong>Gender:</strong>${combinedPatient.gender ? this.capitalize(combinedPatient.gender) : ""}</li>
982
996
  <li><strong>Date of Birth:</strong>${combinedPatient.birthDate || ""}</li>
983
- <li><strong>Identifier(s):</strong>${this.renderIdentifiers(combinedPatient)}</li>
984
997
  <li><strong>Telecom:</strong><ul>${this.renderTelecom(combinedPatient)}</ul></li>
985
998
  <li><strong>Address(es):</strong>${this.renderAddresses(combinedPatient)}</li>
986
999
  <li><strong>Marital Status:</strong> ${combinedPatient.maritalStatus?.text || ""}</li>
@@ -1001,7 +1014,6 @@ var PatientTemplate = class _PatientTemplate {
1001
1014
  }
1002
1015
  const combined = patients[0];
1003
1016
  const allNames = [];
1004
- const allIdentifiers = [];
1005
1017
  const allTelecom = [];
1006
1018
  const allAddresses = [];
1007
1019
  const allCommunication = [];
@@ -1009,9 +1021,6 @@ var PatientTemplate = class _PatientTemplate {
1009
1021
  if (patient.name) {
1010
1022
  allNames.push(...patient.name);
1011
1023
  }
1012
- if (patient.identifier) {
1013
- allIdentifiers.push(...patient.identifier);
1014
- }
1015
1024
  if (patient.telecom) {
1016
1025
  allTelecom.push(...patient.telecom);
1017
1026
  }
@@ -1038,7 +1047,6 @@ var PatientTemplate = class _PatientTemplate {
1038
1047
  }
1039
1048
  });
1040
1049
  combined.name = allNames;
1041
- combined.identifier = allIdentifiers;
1042
1050
  combined.telecom = allTelecom;
1043
1051
  combined.address = allAddresses;
1044
1052
  combined.communication = allCommunication;
@@ -1064,21 +1072,6 @@ var PatientTemplate = class _PatientTemplate {
1064
1072
  });
1065
1073
  return Array.from(uniqueNames).map((nameText) => `<ul><li>${nameText}</li></ul>`).join("");
1066
1074
  }
1067
- /**
1068
- * Renders patient identifiers as HTML list items
1069
- * @param patient - Patient resources
1070
- * @returns HTML string of list items
1071
- */
1072
- static renderIdentifiers(patient) {
1073
- if (!patient.identifier || patient.identifier.length === 0) {
1074
- return "";
1075
- }
1076
- return patient.identifier.map((id) => {
1077
- const system = id.system || "";
1078
- const value = id.value || "";
1079
- return `<ul><li>${system}: ${value}</li></ul>`;
1080
- }).join("");
1081
- }
1082
1075
  /**
1083
1076
  * Renders patient telecom information grouped by system
1084
1077
  * @param patient - Patient resources
@@ -1180,7 +1173,89 @@ var PatientTemplate = class _PatientTemplate {
1180
1173
  uniqueAddresses.add(addressText);
1181
1174
  }
1182
1175
  });
1183
- return Array.from(uniqueAddresses).map((addressText) => `<ul><li>${addressText}</li></ul>`).join("");
1176
+ const deduplicatedAddresses = this.deduplicateSimilarAddresses(Array.from(uniqueAddresses));
1177
+ return deduplicatedAddresses.map((addressText) => `<ul><li>${addressText}</li></ul>`).join("");
1178
+ }
1179
+ /**
1180
+ * Calculates the similarity between two strings using Levenshtein distance
1181
+ * Returns a percentage (0-100) indicating how similar the strings are
1182
+ * @param str1 - First string
1183
+ * @param str2 - Second string
1184
+ * @returns Similarity percentage (0-100)
1185
+ */
1186
+ static calculateStringSimilarity(str1, str2) {
1187
+ const longer = str1.length > str2.length ? str1 : str2;
1188
+ const shorter = str1.length > str2.length ? str2 : str1;
1189
+ if (longer.length === 0) {
1190
+ return 100;
1191
+ }
1192
+ const editDistance = this.levenshteinDistance(longer.toLowerCase(), shorter.toLowerCase());
1193
+ return (longer.length - editDistance) / longer.length * 100;
1194
+ }
1195
+ /**
1196
+ * Calculates the Levenshtein distance between two strings
1197
+ * @param str1 - First string
1198
+ * @param str2 - Second string
1199
+ * @returns The Levenshtein distance
1200
+ */
1201
+ static levenshteinDistance(str1, str2) {
1202
+ const matrix = [];
1203
+ for (let i = 0; i <= str2.length; i++) {
1204
+ matrix[i] = [i];
1205
+ }
1206
+ for (let j = 0; j <= str1.length; j++) {
1207
+ matrix[0][j] = j;
1208
+ }
1209
+ for (let i = 1; i <= str2.length; i++) {
1210
+ for (let j = 1; j <= str1.length; j++) {
1211
+ if (str2.charAt(i - 1) === str1.charAt(j - 1)) {
1212
+ matrix[i][j] = matrix[i - 1][j - 1];
1213
+ } else {
1214
+ matrix[i][j] = Math.min(
1215
+ matrix[i - 1][j - 1] + 1,
1216
+ // substitution
1217
+ matrix[i][j - 1] + 1,
1218
+ // insertion
1219
+ matrix[i - 1][j] + 1
1220
+ // deletion
1221
+ );
1222
+ }
1223
+ }
1224
+ }
1225
+ return matrix[str2.length][str1.length];
1226
+ }
1227
+ /**
1228
+ * Deduplicates addresses that are more than ADDRESS_SIMILARITY_THRESHOLD% similar
1229
+ * @param addresses - Array of address strings
1230
+ * @returns Array of deduplicated addresses
1231
+ */
1232
+ static deduplicateSimilarAddresses(addresses) {
1233
+ if (addresses.length <= 1) {
1234
+ return addresses;
1235
+ }
1236
+ const deduplicated = [];
1237
+ const processed = /* @__PURE__ */ new Set();
1238
+ for (let i = 0; i < addresses.length; i++) {
1239
+ if (processed.has(i)) {
1240
+ continue;
1241
+ }
1242
+ let keepAddress = addresses[i];
1243
+ processed.add(i);
1244
+ for (let j = i + 1; j < addresses.length; j++) {
1245
+ if (processed.has(j)) {
1246
+ continue;
1247
+ }
1248
+ const similarity = this.calculateStringSimilarity(addresses[i], addresses[j]);
1249
+ if (similarity > ADDRESS_SIMILARITY_THRESHOLD) {
1250
+ processed.add(j);
1251
+ if (addresses[j].length > keepAddress.length) {
1252
+ keepAddress = addresses[j];
1253
+ }
1254
+ }
1255
+ }
1256
+ deduplicated.push(keepAddress);
1257
+ }
1258
+ return deduplicated;
1184
1259
  }
1185
1260
  /**
1186
1261
  * Renders patient deceased status
@@ -1428,6 +1503,75 @@ var MedicationSummaryTemplate = class _MedicationSummaryTemplate {
1428
1503
  generateNarrative(resources, timezone) {
1429
1504
  return _MedicationSummaryTemplate.generateStaticNarrative(resources, timezone);
1430
1505
  }
1506
+ /**
1507
+ * Generate HTML narrative for Medication resources using summary
1508
+ * @param resources - FHIR Composition resources
1509
+ * @param timezone - Optional timezone to use for date formatting (e.g., 'America/New_York', 'Europe/London')
1510
+ * @returns HTML string for rendering
1511
+ */
1512
+ generateSummaryNarrative(resources, timezone) {
1513
+ const templateUtilities = new TemplateUtilities(resources);
1514
+ let html = `
1515
+ <div>
1516
+ <table>
1517
+ <thead>
1518
+ <tr>
1519
+ <th>Medication</th>
1520
+ <th>Sig</th>
1521
+ <th>Days of Supply</th>
1522
+ <th>Refills</th>
1523
+ <th>Start Date</th>
1524
+ </tr>
1525
+ </thead>
1526
+ <tbody>`;
1527
+ for (const resourceItem of resources) {
1528
+ for (const rowData of resourceItem.section ?? []) {
1529
+ const data = {};
1530
+ for (const columnData of rowData.section ?? []) {
1531
+ switch (columnData.title) {
1532
+ case "Medication Name":
1533
+ data["medication"] = columnData.text?.div ?? "";
1534
+ break;
1535
+ case "Status":
1536
+ data["status"] = columnData.text?.div ?? "";
1537
+ break;
1538
+ case "Prescriber Instruction":
1539
+ data["sig-prescriber"] = columnData.text?.div ?? "";
1540
+ break;
1541
+ case "Pharmacy Instruction":
1542
+ data["sig-pharmacy"] = columnData.text?.div ?? "";
1543
+ break;
1544
+ case "Days Of Supply":
1545
+ data["daysOfSupply"] = columnData.text?.div ?? "";
1546
+ break;
1547
+ case "Refills Remaining":
1548
+ data["refills"] = columnData.text?.div ?? "";
1549
+ break;
1550
+ case "Authored On Date":
1551
+ data["startDate"] = columnData.text?.div ?? "";
1552
+ break;
1553
+ default:
1554
+ break;
1555
+ }
1556
+ }
1557
+ if (data["status"] === "active") {
1558
+ html += `
1559
+ <tr>
1560
+ <td>${data["medication"]}</td>
1561
+ <td>${data["sig-prescriber"] || data["sig-pharmacy"]}</td>
1562
+ <td>${data["daysOfSupply"]}</td>
1563
+ <td>${data["refills"]}</td>
1564
+ <td>${templateUtilities.renderTime(data["startDate"], timezone)}</td>
1565
+ </tr>`;
1566
+ }
1567
+ }
1568
+ }
1569
+ html += `
1570
+ </tbody>
1571
+ </table>
1572
+ </div>`;
1573
+ return html;
1574
+ }
1431
1575
  /**
1432
1576
  * Safely parse a date string and return a valid Date object or null
1433
1577
  * @param dateString - The date string to parse
@@ -1440,55 +1584,6 @@ var MedicationSummaryTemplate = class _MedicationSummaryTemplate {
1440
1584
  const date = new Date(dateString);
1441
1585
  return !isNaN(date.getTime()) ? date : null;
1442
1586
  }
1443
- /**
1444
- * Determine if a MedicationRequest is active
1445
- * @param medicationRequest - The MedicationRequest resource
1446
- * @returns boolean indicating if the medication request is active
1447
- */
1448
- static isActiveMedicationRequest(medicationRequest) {
1449
- const status = medicationRequest.status?.toLowerCase();
1450
- if (status === "active" || status === "unknown") {
1451
- return true;
1452
- }
1453
- if (status === "completed" || status === "cancelled" || status === "stopped" || status === "draft") {
1454
- return false;
1455
- }
1456
- const endDate = medicationRequest.dispenseRequest?.validityPeriod?.end;
1457
- if (!endDate) {
1458
- return true;
1459
- }
1460
- const parsedEndDate = this.parseDate(endDate);
1461
- if (!parsedEndDate) {
1462
- return true;
1463
- }
1464
- return parsedEndDate.getTime() > Date.now();
1465
- }
1466
- /**
1467
- * Determine if a MedicationStatement is active
1468
- * @param medicationStatement - The MedicationStatement resource
1469
- * @returns boolean indicating if the medication statement is active
1470
- */
1471
- static isActiveMedicationStatement(medicationStatement) {
1472
- const status = medicationStatement.status?.toLowerCase();
1473
- if (status === "active" || status === "intended" || status === "unknown") {
1474
- return true;
1475
- }
1476
- if (status === "completed" || status === "stopped" || status === "not-taken") {
1477
- return false;
1478
- }
1479
- let endDate;
1480
- if (medicationStatement.effectivePeriod?.end) {
1481
- endDate = medicationStatement.effectivePeriod.end;
1482
- }
1483
- if (!endDate) {
1484
- return true;
1485
- }
1486
- const parsedEndDate = this.parseDate(endDate);
1487
- if (!parsedEndDate) {
1488
- return true;
1489
- }
1490
- return parsedEndDate.getTime() > Date.now();
1491
- }
1492
1587
  /**
1493
1588
  * Internal static implementation that actually generates the narrative
1494
1589
  * @param resources - FHIR Medication resources
@@ -1502,20 +1597,11 @@ var MedicationSummaryTemplate = class _MedicationSummaryTemplate {
1502
1597
  const medicationRequests = this.getMedicationRequests(templateUtilities, resources);
1503
1598
  const medicationStatements = this.getMedicationStatements(templateUtilities, resources);
1504
1599
  const allActiveMedications = [];
1505
- const allInactiveMedications = [];
1506
1600
  medicationRequests.forEach((mr) => {
1507
- if (this.isActiveMedicationRequest(mr.resource)) {
1508
- allActiveMedications.push({ type: "request", resource: mr.resource, extension: mr.extension });
1509
- } else {
1510
- allInactiveMedications.push({ type: "request", resource: mr.resource, extension: mr.extension });
1511
- }
1601
+ allActiveMedications.push({ type: "request", resource: mr.resource, extension: mr.extension });
1512
1602
  });
1513
1603
  medicationStatements.forEach((ms) => {
1514
- if (this.isActiveMedicationStatement(ms.resource)) {
1515
- allActiveMedications.push({ type: "statement", resource: ms.resource, extension: ms.extension });
1516
- } else {
1517
- allInactiveMedications.push({ type: "statement", resource: ms.resource, extension: ms.extension });
1518
- }
1604
+ allActiveMedications.push({ type: "statement", resource: ms.resource, extension: ms.extension });
1519
1605
  });
1520
1606
  const sortMedications = (medications) => {
1521
1607
  medications.sort((a, b) => {
@@ -1545,11 +1631,7 @@ var MedicationSummaryTemplate = class _MedicationSummaryTemplate {
1545
1631
  };
1546
1632
  if (allActiveMedications.length > 0) {
1547
1633
  sortMedications(allActiveMedications);
1548
- html += this.renderCombinedMedications(templateUtilities, allActiveMedications, true);
1549
- }
1550
- if (allInactiveMedications.length > 0) {
1551
- sortMedications(allInactiveMedications);
1552
- html += this.renderCombinedMedications(templateUtilities, allInactiveMedications, false);
1634
+ html += this.renderCombinedMedications(templateUtilities, allActiveMedications);
1553
1635
  }
1554
1636
  return html;
1555
1637
  }
@@ -1587,12 +1669,10 @@ var MedicationSummaryTemplate = class _MedicationSummaryTemplate {
1587
1669
  * Render HTML table for combined MedicationRequest and MedicationStatement resources
1588
1670
  * @param templateUtilities - Instance of TemplateUtilities for utility functions
1589
1671
  * @param medications - Array of combined medication resources
1590
- * @param sectionTitle - Title for the section
1591
1672
  * @returns HTML string for rendering
1592
1673
  */
1593
- static renderCombinedMedications(templateUtilities, medications, isActiveSection) {
1674
+ static renderCombinedMedications(templateUtilities, medications) {
1594
1675
  let html = `
1595
- <h3>${isActiveSection ? "Active Medications" : "Inactive Medications"}</h3>
1596
1676
  <table>
1597
1677
  <thead>
1598
1678
  <tr>
@@ -1601,9 +1681,7 @@ var MedicationSummaryTemplate = class _MedicationSummaryTemplate {
1601
1681
  <th>Sig</th>
1602
1682
  <th>Dispense Quantity</th>
1603
1683
  <th>Refills</th>
1604
- <th>Start Date</th>${isActiveSection ? "" : `
1605
- <th>End Date</th>`}
1606
- <th>Status</th>
1684
+ <th>Start Date</th>
1607
1685
  </tr>
1608
1686
  </thead>
1609
1687
  <tbody>`;
@@ -1615,12 +1693,9 @@ var MedicationSummaryTemplate = class _MedicationSummaryTemplate {
1615
1693
  let dispenseQuantity = "-";
1616
1694
  let refills = "-";
1617
1695
  let startDate = "-";
1618
- let endDate = "-";
1619
- let status;
1620
1696
  if (medication.type === "request") {
1621
1697
  const mr = medication.resource;
1622
1698
  type = "Request";
1623
- status = mr.status ? String(mr.status) : "-";
1624
1699
  medicationName = templateUtilities.getMedicationName(
1625
1700
  mr.medicationReference || mr.medicationCodeableConcept
1626
1701
  );
@@ -1634,14 +1709,12 @@ var MedicationSummaryTemplate = class _MedicationSummaryTemplate {
1634
1709
  refills = mr.dispenseRequest?.numberOfRepeatsAllowed?.toString() || "-";
1635
1710
  if (mr.dispenseRequest?.validityPeriod) {
1636
1711
  startDate = mr.dispenseRequest.validityPeriod.start || "-";
1637
- endDate = mr.dispenseRequest.validityPeriod.end || "-";
1638
1712
  } else {
1639
1713
  startDate = mr.authoredOn || "-";
1640
1714
  }
1641
1715
  } else {
1642
1716
  const ms = medication.resource;
1643
1717
  type = "Statement";
1644
- status = ms.status ? String(ms.status) : "-";
1645
1718
  medicationName = templateUtilities.getMedicationName(
1646
1719
  ms.medicationReference || ms.medicationCodeableConcept
1647
1720
  );
@@ -1650,7 +1723,6 @@ var MedicationSummaryTemplate = class _MedicationSummaryTemplate {
1650
1723
  startDate = ms.effectiveDateTime;
1651
1724
  } else if (ms.effectivePeriod) {
1652
1725
  startDate = ms.effectivePeriod.start || "-";
1653
- endDate = ms.effectivePeriod.end || "-";
1654
1726
  }
1655
1727
  }
1656
1728
  html += `
@@ -1660,9 +1732,7 @@ var MedicationSummaryTemplate = class _MedicationSummaryTemplate {
1660
1732
  <td>${sig}</td>
1661
1733
  <td>${dispenseQuantity}</td>
1662
1734
  <td>${refills}</td>
1663
- <td>${startDate}</td>${isActiveSection ? "" : `
1664
- <td>${endDate}</td>`}
1665
- <td>${status}</td>
1735
+ <td>${startDate}</td>
1666
1736
  </tr>`;
1667
1737
  }
1668
1738
  html += `
@@ -1803,6 +1873,7 @@ var ProblemListTemplate = class _ProblemListTemplate {
1803
1873
  * @param timezone - Optional timezone to use for date formatting (e.g., 'America/New_York', 'Europe/London')
1804
1874
  * @returns HTML string for rendering
1805
1875
  */
1876
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
1806
1877
  static generateStaticNarrative(resources, timezone) {
1807
1878
  const templateUtilities = new TemplateUtilities(resources);
1808
1879
  let html = ``;
@@ -1819,7 +1890,6 @@ var ProblemListTemplate = class _ProblemListTemplate {
1819
1890
  <th>Problem</th>
1820
1891
  <th>Onset Date</th>
1821
1892
  <th>Recorded Date</th>
1822
- <th>Notes</th>
1823
1893
  </tr>
1824
1894
  </thead>
1825
1895
  <tbody>`;
@@ -1828,7 +1898,6 @@ var ProblemListTemplate = class _ProblemListTemplate {
1828
1898
  <td class="Name">${templateUtilities.codeableConcept(cond.code)}</td>
1829
1899
  <td class="OnsetDate">${templateUtilities.renderDate(cond.onsetDateTime)}</td>
1830
1900
  <td class="RecordedDate">${templateUtilities.renderDate(cond.recordedDate)}</td>
1831
- <td class="Notes">${templateUtilities.renderNotes(cond.note, timezone)}</td>
1832
1901
  </tr>`;
1833
1902
  }
1834
1903
  html += `</tbody>
@@ -1837,13 +1906,6 @@ var ProblemListTemplate = class _ProblemListTemplate {
1837
1906
  }
1838
1907
  };
1839
1908
 
1840
- // src/structures/ips_section_constants.ts
1841
- var VITAL_SIGNS_SUMMARY_COMPONENT_MAP = {
1842
- "Systolic Blood Pressure": "valueRatio.numerator.value",
1843
- "Diastolic Blood Pressure": "valueRatio.denominator.value",
1844
- "Default": "valueString"
1845
- };
1846
-
1847
1909
  // src/narratives/templates/typescript/VitalSignsTemplate.ts
1848
1910
  var VitalSignsTemplate = class _VitalSignsTemplate {
1849
1911
  /**
@@ -2263,6 +2325,7 @@ var PastHistoryOfIllnessTemplate = class {
2263
2325
  * @param timezone - Optional timezone to use for date formatting (e.g., 'America/New_York', 'Europe/London')
2264
2326
  * @returns HTML string for rendering
2265
2327
  */
2328
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
2266
2329
  generateNarrative(resources, timezone) {
2267
2330
  const templateUtilities = new TemplateUtilities(resources);
2268
2331
  let html = ``;
@@ -2280,7 +2343,6 @@ var PastHistoryOfIllnessTemplate = class {
2280
2343
  <th>Onset Date</th>
2281
2344
  <th>Recorded Date</th>
2282
2345
  <th>Resolved Date</th>
2283
- <th>Notes</th>
2284
2346
  </tr>
2285
2347
  </thead>
2286
2348
  <tbody>`;
@@ -2290,7 +2352,6 @@ var PastHistoryOfIllnessTemplate = class {
2290
2352
  <td class="OnsetDate">${templateUtilities.renderDate(cond.onsetDateTime)}</td>
2291
2353
  <td class="RecordedDate">${templateUtilities.renderDate(cond.recordedDate)}</td>
2292
2354
  <td class="ResolvedDate">${templateUtilities.renderDate(cond.abatementDateTime)}</td>
2293
- <td class="Notes">${templateUtilities.renderNotes(cond.note, timezone)}</td>
2294
2355
  </tr>`;
2295
2356
  }
2296
2357
  html += `</tbody>
@@ -2443,7 +2504,6 @@ var FunctionalStatusTemplate = class _FunctionalStatusTemplate {
2443
2504
  <th>Problem</th>
2444
2505
  <th>Onset Date</th>
2445
2506
  <th>Recorded Date</th>
2446
- <th>Notes</th>
2447
2507
  </tr>
2448
2508
  </thead>
2449
2509
  <tbody>`;
@@ -2452,7 +2512,6 @@ var FunctionalStatusTemplate = class _FunctionalStatusTemplate {
2452
2512
  <td class="Name">${templateUtilities.codeableConcept(cond.code)}</td>
2453
2513
  <td class="OnsetDate">${templateUtilities.renderDate(cond.onsetDateTime)}</td>
2454
2514
  <td class="RecordedDate">${templateUtilities.renderDate(cond.recordedDate)}</td>
2455
- <td class="Notes">${templateUtilities.renderNotes(cond.note, timezone, { styled: true, warning: true })}</td>
2456
2515
  </tr>`;
2457
2516
  }
2458
2517
  html += `</tbody>
@@ -2468,7 +2527,6 @@ var FunctionalStatusTemplate = class _FunctionalStatusTemplate {
2468
2527
  <th>Description</th>
2469
2528
  <th>Summary</th>
2470
2529
  <th>Findings</th>
2471
- <th>Notes</th>
2472
2530
  </tr>
2473
2531
  </thead>
2474
2532
  <tbody>`;
@@ -2497,7 +2555,6 @@ var FunctionalStatusTemplate = class _FunctionalStatusTemplate {
2497
2555
  }
2498
2556
  findingsHtml += "</ul>";
2499
2557
  }
2500
- const notes = templateUtilities.renderNotes(impression.note, timezone);
2501
2558
  html += `
2502
2559
  <tr id="${templateUtilities.narrativeLinkId(impression)}">
2503
2560
  <td>${formattedDate}</td>
@@ -2505,7 +2562,6 @@ var FunctionalStatusTemplate = class _FunctionalStatusTemplate {
2505
2562
  <td>${impression.description || ""}</td>
2506
2563
  <td>${impression.summary || ""}</td>
2507
2564
  <td>${findingsHtml}</td>
2508
- <td>${notes}</td>
2509
2565
  </tr>`;
2510
2566
  }
2511
2567
  html += `</tbody>
package/dist/index.js CHANGED
@@ -81,6 +81,14 @@ var BLOOD_PRESSURE_LOINC_CODES = {
81
81
  DIASTOLIC: "8462-4"
82
82
  };
83
83
 
84
+ // src/structures/ips_section_constants.ts
85
+ var VITAL_SIGNS_SUMMARY_COMPONENT_MAP = {
86
+ "Systolic Blood Pressure": "valueRatio.numerator.value",
87
+ "Diastolic Blood Pressure": "valueRatio.denominator.value",
88
+ "Default": "valueString"
89
+ };
90
+ var IPS_SUMMARY_COMPOSITION_TYPE_SYSTEM = "https://fhir.icanbwell.com/4_0_0/CodeSystem/composition/";
91
+
84
92
  // src/structures/ips_section_resource_map.ts
85
93
  var IPSSectionResourceFilters = {
86
94
  // Patient section: only Patient resource
@@ -88,7 +96,7 @@ var IPSSectionResourceFilters = {
88
96
  // Only include allergies
89
97
  ["AllergyIntoleranceSection" /* ALLERGIES */]: (resource) => resource.resourceType === "AllergyIntolerance",
90
98
  // includes MedicationRequest, MedicationStatement. Medication is needed for medication names
91
- ["MedicationSummarySection" /* MEDICATIONS */]: (resource) => ["MedicationRequest", "MedicationStatement", "Medication"].includes(resource.resourceType),
99
+ ["MedicationSummarySection" /* MEDICATIONS */]: (resource) => ["MedicationRequest", "MedicationStatement"].includes(resource.resourceType) && resource.status === "active" || resource.resourceType === "Medication",
92
100
  // Only include active conditions
93
101
  ["ProblemSection" /* PROBLEMS */]: (resource) => resource.resourceType === "Condition" && resource.clinicalStatus?.coding?.some((c) => !["inactive", "resolved"].includes(c.code)),
94
102
  // Only include completed immunizations
@@ -115,10 +123,11 @@ var IPSSectionResourceFilters = {
115
123
  ["AdvanceDirectivesSection" /* ADVANCE_DIRECTIVES */]: (resource) => resource.resourceType === "Consent" && resource.status === "active"
116
124
  };
117
125
  var IPSSectionSummaryCompositionFilter = {
118
- ["AllergyIntoleranceSection" /* ALLERGIES */]: (resource) => resource.resourceType === "Composition" && resource.type?.coding?.some((c) => c.system === "https://fhir.icanbwell.com/4_0_0/CodeSystem/composition/" && c.code === "allergy_summary_document"),
119
- ["VitalSignsSection" /* VITAL_SIGNS */]: (resource) => resource.resourceType === "Composition" && resource.type?.coding?.some((c) => c.system === "https://fhir.icanbwell.com/4_0_0/CodeSystem/composition/" && c.code === "vital_summary_document"),
120
- ["PlanOfCareSection" /* CARE_PLAN */]: (resource) => resource.resourceType === "Composition" && resource.type?.coding?.some((c) => c.system === "https://fhir.icanbwell.com/4_0_0/CodeSystem/composition/" && c.code === "careplan_summary_document"),
121
- ["ImmunizationSection" /* IMMUNIZATIONS */]: (resource) => resource.resourceType === "Composition" && resource.type?.coding?.some((c) => c.system === "https://fhir.icanbwell.com/4_0_0/CodeSystem/composition/" && c.code === "immunization_summary_document")
126
+ ["AllergyIntoleranceSection" /* ALLERGIES */]: (resource) => resource.resourceType === "Composition" && resource.type?.coding?.some((c) => c.system === IPS_SUMMARY_COMPOSITION_TYPE_SYSTEM && c.code === "allergy_summary_document"),
127
+ ["VitalSignsSection" /* VITAL_SIGNS */]: (resource) => resource.resourceType === "Composition" && resource.type?.coding?.some((c) => c.system === IPS_SUMMARY_COMPOSITION_TYPE_SYSTEM && c.code === "vital_summary_document"),
128
+ ["PlanOfCareSection" /* CARE_PLAN */]: (resource) => resource.resourceType === "Composition" && resource.type?.coding?.some((c) => c.system === IPS_SUMMARY_COMPOSITION_TYPE_SYSTEM && c.code === "careplan_summary_document"),
129
+ ["ImmunizationSection" /* IMMUNIZATIONS */]: (resource) => resource.resourceType === "Composition" && resource.type?.coding?.some((c) => c.system === IPS_SUMMARY_COMPOSITION_TYPE_SYSTEM && c.code === "immunization_summary_document"),
130
+ ["MedicationSummarySection" /* MEDICATIONS */]: (resource) => resource.resourceType === "Composition" && resource.type?.coding?.some((c) => c.system === IPS_SUMMARY_COMPOSITION_TYPE_SYSTEM && c.code === "medication_summary_document")
122
131
  };
123
132
  var IPSSectionResourceHelper = class {
124
133
  static getResourceFilterForSection(section) {
@@ -822,9 +831,11 @@ var TemplateUtilities = class {
822
831
  if (dateValue instanceof Date) {
823
832
  dateTime = DateTime.fromJSDate(dateValue);
824
833
  } else if (typeof dateValue === "string") {
825
- dateTime = DateTime.fromISO(dateValue);
826
834
  if (!dateValue.includes("T")) {
827
835
  dateOnly = true;
836
+ dateTime = DateTime.fromISO(dateValue, { zone: "utc" });
837
+ } else {
838
+ dateTime = DateTime.fromISO(dateValue);
828
839
  }
829
840
  } else {
830
841
  dateTime = DateTime.fromISO(String(dateValue));
@@ -926,6 +937,9 @@ var TemplateUtilities = class {
926
937
  }
927
938
  };
928
939
 
940
+ // src/constants.ts
941
+ var ADDRESS_SIMILARITY_THRESHOLD = 70;
942
+
929
943
  // src/narratives/templates/typescript/PatientTemplate.ts
930
944
  var PatientTemplate = class _PatientTemplate {
931
945
  /**
@@ -952,7 +966,6 @@ var PatientTemplate = class _PatientTemplate {
952
966
  <li><strong>Name(s):</strong>${this.renderNames(combinedPatient)}</li>
953
967
  <li><strong>Gender:</strong>${combinedPatient.gender ? this.capitalize(combinedPatient.gender) : ""}</li>
954
968
  <li><strong>Date of Birth:</strong>${combinedPatient.birthDate || ""}</li>
955
- <li><strong>Identifier(s):</strong>${this.renderIdentifiers(combinedPatient)}</li>
956
969
  <li><strong>Telecom:</strong><ul>${this.renderTelecom(combinedPatient)}</ul></li>
957
970
  <li><strong>Address(es):</strong>${this.renderAddresses(combinedPatient)}</li>
958
971
  <li><strong>Marital Status:</strong> ${combinedPatient.maritalStatus?.text || ""}</li>
@@ -973,7 +986,6 @@ var PatientTemplate = class _PatientTemplate {
973
986
  }
974
987
  const combined = patients[0];
975
988
  const allNames = [];
976
- const allIdentifiers = [];
977
989
  const allTelecom = [];
978
990
  const allAddresses = [];
979
991
  const allCommunication = [];
@@ -981,9 +993,6 @@ var PatientTemplate = class _PatientTemplate {
981
993
  if (patient.name) {
982
994
  allNames.push(...patient.name);
983
995
  }
984
- if (patient.identifier) {
985
- allIdentifiers.push(...patient.identifier);
986
- }
987
996
  if (patient.telecom) {
988
997
  allTelecom.push(...patient.telecom);
989
998
  }
@@ -1010,7 +1019,6 @@ var PatientTemplate = class _PatientTemplate {
1010
1019
  }
1011
1020
  });
1012
1021
  combined.name = allNames;
1013
- combined.identifier = allIdentifiers;
1014
1022
  combined.telecom = allTelecom;
1015
1023
  combined.address = allAddresses;
1016
1024
  combined.communication = allCommunication;
@@ -1036,21 +1044,6 @@ var PatientTemplate = class _PatientTemplate {
1036
1044
  });
1037
1045
  return Array.from(uniqueNames).map((nameText) => `<ul><li>${nameText}</li></ul>`).join("");
1038
1046
  }
1039
- /**
1040
- * Renders patient identifiers as HTML list items
1041
- * @param patient - Patient resources
1042
- * @returns HTML string of list items
1043
- */
1044
- static renderIdentifiers(patient) {
1045
- if (!patient.identifier || patient.identifier.length === 0) {
1046
- return "";
1047
- }
1048
- return patient.identifier.map((id) => {
1049
- const system = id.system || "";
1050
- const value = id.value || "";
1051
- return `<ul><li>${system}: ${value}</li></ul>`;
1052
- }).join("");
1053
- }
1054
1047
  /**
1055
1048
  * Renders patient telecom information grouped by system
1056
1049
  * @param patient - Patient resources
@@ -1152,7 +1145,89 @@ var PatientTemplate = class _PatientTemplate {
1152
1145
  uniqueAddresses.add(addressText);
1153
1146
  }
1154
1147
  });
1155
- return Array.from(uniqueAddresses).map((addressText) => `<ul><li>${addressText}</li></ul>`).join("");
1148
+ const deduplicatedAddresses = this.deduplicateSimilarAddresses(Array.from(uniqueAddresses));
1149
+ return deduplicatedAddresses.map((addressText) => `<ul><li>${addressText}</li></ul>`).join("");
1150
+ }
1151
+ /**
1152
+ * Calculates the similarity between two strings using Levenshtein distance
1153
+ * Returns a percentage (0-100) indicating how similar the strings are
1154
+ * @param str1 - First string
1155
+ * @param str2 - Second string
1156
+ * @returns Similarity percentage (0-100)
1157
+ */
1158
+ static calculateStringSimilarity(str1, str2) {
1159
+ const longer = str1.length > str2.length ? str1 : str2;
1160
+ const shorter = str1.length > str2.length ? str2 : str1;
1161
+ if (longer.length === 0) {
1162
+ return 100;
1163
+ }
1164
+ const editDistance = this.levenshteinDistance(longer.toLowerCase(), shorter.toLowerCase());
1165
+ return (longer.length - editDistance) / longer.length * 100;
1166
+ }
1167
+ /**
1168
+ * Calculates the Levenshtein distance between two strings
1169
+ * @param str1 - First string
1170
+ * @param str2 - Second string
1171
+ * @returns The Levenshtein distance
1172
+ */
1173
+ static levenshteinDistance(str1, str2) {
1174
+ const matrix = [];
1175
+ for (let i = 0; i <= str2.length; i++) {
1176
+ matrix[i] = [i];
1177
+ }
1178
+ for (let j = 0; j <= str1.length; j++) {
1179
+ matrix[0][j] = j;
1180
+ }
1181
+ for (let i = 1; i <= str2.length; i++) {
1182
+ for (let j = 1; j <= str1.length; j++) {
1183
+ if (str2.charAt(i - 1) === str1.charAt(j - 1)) {
1184
+ matrix[i][j] = matrix[i - 1][j - 1];
1185
+ } else {
1186
+ matrix[i][j] = Math.min(
1187
+ matrix[i - 1][j - 1] + 1,
1188
+ // substitution
1189
+ matrix[i][j - 1] + 1,
1190
+ // insertion
1191
+ matrix[i - 1][j] + 1
1192
+ // deletion
1193
+ );
1194
+ }
1195
+ }
1196
+ }
1197
+ return matrix[str2.length][str1.length];
1198
+ }
1199
+ /**
1200
+ * Deduplicates addresses that are more than ADDRESS_SIMILARITY_THRESHOLD% similar
1201
+ * @param addresses - Array of address strings
1202
+ * @returns Array of deduplicated addresses
1203
+ */
1204
+ static deduplicateSimilarAddresses(addresses) {
1205
+ if (addresses.length <= 1) {
1206
+ return addresses;
1207
+ }
1208
+ const deduplicated = [];
1209
+ const processed = /* @__PURE__ */ new Set();
1210
+ for (let i = 0; i < addresses.length; i++) {
1211
+ if (processed.has(i)) {
1212
+ continue;
1213
+ }
1214
+ let keepAddress = addresses[i];
1215
+ processed.add(i);
1216
+ for (let j = i + 1; j < addresses.length; j++) {
1217
+ if (processed.has(j)) {
1218
+ continue;
1219
+ }
1220
+ const similarity = this.calculateStringSimilarity(addresses[i], addresses[j]);
1221
+ if (similarity > ADDRESS_SIMILARITY_THRESHOLD) {
1222
+ processed.add(j);
1223
+ if (addresses[j].length > keepAddress.length) {
1224
+ keepAddress = addresses[j];
1225
+ }
1226
+ }
1227
+ }
1228
+ deduplicated.push(keepAddress);
1229
+ }
1230
+ return deduplicated;
1156
1231
  }
1157
1232
  /**
1158
1233
  * Renders patient deceased status
@@ -1400,6 +1475,75 @@ var MedicationSummaryTemplate = class _MedicationSummaryTemplate {
1400
1475
  generateNarrative(resources, timezone) {
1401
1476
  return _MedicationSummaryTemplate.generateStaticNarrative(resources, timezone);
1402
1477
  }
1478
+ /**
1479
+ * Generate HTML narrative for Medication resources using summary
1480
+ * @param resources - FHIR Composition resources
1481
+ * @param timezone - Optional timezone to use for date formatting (e.g., 'America/New_York', 'Europe/London')
1482
+ * @returns HTML string for rendering
1483
+ */
1484
+ generateSummaryNarrative(resources, timezone) {
1485
+ const templateUtilities = new TemplateUtilities(resources);
1486
+ let html = `
1487
+ <div>
1488
+ <table>
1489
+ <thead>
1490
+ <tr>
1491
+ <th>Medication</th>
1492
+ <th>Sig</th>
1493
+ <th>Days of Supply</th>
1494
+ <th>Refills</th>
1495
+ <th>Start Date</th>
1496
+ </tr>
1497
+ </thead>
1498
+ <tbody>`;
1499
+ for (const resourceItem of resources) {
1500
+ for (const rowData of resourceItem.section ?? []) {
1501
+ const data = {};
1502
+ for (const columnData of rowData.section ?? []) {
1503
+ switch (columnData.title) {
1504
+ case "Medication Name":
1505
+ data["medication"] = columnData.text?.div ?? "";
1506
+ break;
1507
+ case "Status":
1508
+ data["status"] = columnData.text?.div ?? "";
1509
+ break;
1510
+ case "Prescriber Instruction":
1511
+ data["sig-prescriber"] = columnData.text?.div ?? "";
1512
+ break;
1513
+ case "Pharmacy Instruction":
1514
+ data["sig-pharmacy"] = columnData.text?.div ?? "";
1515
+ break;
1516
+ case "Days Of Supply":
1517
+ data["daysOfSupply"] = columnData.text?.div ?? "";
1518
+ break;
1519
+ case "Refills Remaining":
1520
+ data["refills"] = columnData.text?.div ?? "";
1521
+ break;
1522
+ case "Authored On Date":
1523
+ data["startDate"] = columnData.text?.div ?? "";
1524
+ break;
1525
+ default:
1526
+ break;
1527
+ }
1528
+ }
1529
+ if (data["status"] === "active") {
1530
+ html += `
1531
+ <tr>
1532
+ <td>${data["medication"]}</td>
1533
+ <td>${data["sig-prescriber"] || data["sig-pharmacy"]}</td>
1534
+ <td>${data["daysOfSupply"]}</td>
1535
+ <td>${data["refills"]}</td>
1536
+ <td>${templateUtilities.renderTime(data["startDate"], timezone)}</td>
1537
+ </tr>`;
1538
+ }
1539
+ }
1540
+ }
1541
+ html += `
1542
+ </tbody>
1543
+ </table>
1544
+ </div>`;
1545
+ return html;
1546
+ }
1403
1547
  /**
1404
1548
  * Safely parse a date string and return a valid Date object or null
1405
1549
  * @param dateString - The date string to parse
@@ -1412,55 +1556,6 @@ var MedicationSummaryTemplate = class _MedicationSummaryTemplate {
1412
1556
  const date = new Date(dateString);
1413
1557
  return !isNaN(date.getTime()) ? date : null;
1414
1558
  }
1415
- /**
1416
- * Determine if a MedicationRequest is active
1417
- * @param medicationRequest - The MedicationRequest resource
1418
- * @returns boolean indicating if the medication request is active
1419
- */
1420
- static isActiveMedicationRequest(medicationRequest) {
1421
- const status = medicationRequest.status?.toLowerCase();
1422
- if (status === "active" || status === "unknown") {
1423
- return true;
1424
- }
1425
- if (status === "completed" || status === "cancelled" || status === "stopped" || status === "draft") {
1426
- return false;
1427
- }
1428
- const endDate = medicationRequest.dispenseRequest?.validityPeriod?.end;
1429
- if (!endDate) {
1430
- return true;
1431
- }
1432
- const parsedEndDate = this.parseDate(endDate);
1433
- if (!parsedEndDate) {
1434
- return true;
1435
- }
1436
- return parsedEndDate.getTime() > Date.now();
1437
- }
1438
- /**
1439
- * Determine if a MedicationStatement is active
1440
- * @param medicationStatement - The MedicationStatement resource
1441
- * @returns boolean indicating if the medication statement is active
1442
- */
1443
- static isActiveMedicationStatement(medicationStatement) {
1444
- const status = medicationStatement.status?.toLowerCase();
1445
- if (status === "active" || status === "intended" || status === "unknown") {
1446
- return true;
1447
- }
1448
- if (status === "completed" || status === "stopped" || status === "not-taken") {
1449
- return false;
1450
- }
1451
- let endDate;
1452
- if (medicationStatement.effectivePeriod?.end) {
1453
- endDate = medicationStatement.effectivePeriod.end;
1454
- }
1455
- if (!endDate) {
1456
- return true;
1457
- }
1458
- const parsedEndDate = this.parseDate(endDate);
1459
- if (!parsedEndDate) {
1460
- return true;
1461
- }
1462
- return parsedEndDate.getTime() > Date.now();
1463
- }
1464
1559
  /**
1465
1560
  * Internal static implementation that actually generates the narrative
1466
1561
  * @param resources - FHIR Medication resources
@@ -1474,20 +1569,11 @@ var MedicationSummaryTemplate = class _MedicationSummaryTemplate {
1474
1569
  const medicationRequests = this.getMedicationRequests(templateUtilities, resources);
1475
1570
  const medicationStatements = this.getMedicationStatements(templateUtilities, resources);
1476
1571
  const allActiveMedications = [];
1477
- const allInactiveMedications = [];
1478
1572
  medicationRequests.forEach((mr) => {
1479
- if (this.isActiveMedicationRequest(mr.resource)) {
1480
- allActiveMedications.push({ type: "request", resource: mr.resource, extension: mr.extension });
1481
- } else {
1482
- allInactiveMedications.push({ type: "request", resource: mr.resource, extension: mr.extension });
1483
- }
1573
+ allActiveMedications.push({ type: "request", resource: mr.resource, extension: mr.extension });
1484
1574
  });
1485
1575
  medicationStatements.forEach((ms) => {
1486
- if (this.isActiveMedicationStatement(ms.resource)) {
1487
- allActiveMedications.push({ type: "statement", resource: ms.resource, extension: ms.extension });
1488
- } else {
1489
- allInactiveMedications.push({ type: "statement", resource: ms.resource, extension: ms.extension });
1490
- }
1576
+ allActiveMedications.push({ type: "statement", resource: ms.resource, extension: ms.extension });
1491
1577
  });
1492
1578
  const sortMedications = (medications) => {
1493
1579
  medications.sort((a, b) => {
@@ -1517,11 +1603,7 @@ var MedicationSummaryTemplate = class _MedicationSummaryTemplate {
1517
1603
  };
1518
1604
  if (allActiveMedications.length > 0) {
1519
1605
  sortMedications(allActiveMedications);
1520
- html += this.renderCombinedMedications(templateUtilities, allActiveMedications, true);
1521
- }
1522
- if (allInactiveMedications.length > 0) {
1523
- sortMedications(allInactiveMedications);
1524
- html += this.renderCombinedMedications(templateUtilities, allInactiveMedications, false);
1606
+ html += this.renderCombinedMedications(templateUtilities, allActiveMedications);
1525
1607
  }
1526
1608
  return html;
1527
1609
  }
@@ -1559,12 +1641,10 @@ var MedicationSummaryTemplate = class _MedicationSummaryTemplate {
1559
1641
  * Render HTML table for combined MedicationRequest and MedicationStatement resources
1560
1642
  * @param templateUtilities - Instance of TemplateUtilities for utility functions
1561
1643
  * @param medications - Array of combined medication resources
1562
- * @param sectionTitle - Title for the section
1563
1644
  * @returns HTML string for rendering
1564
1645
  */
1565
- static renderCombinedMedications(templateUtilities, medications, isActiveSection) {
1646
+ static renderCombinedMedications(templateUtilities, medications) {
1566
1647
  let html = `
1567
- <h3>${isActiveSection ? "Active Medications" : "Inactive Medications"}</h3>
1568
1648
  <table>
1569
1649
  <thead>
1570
1650
  <tr>
@@ -1573,9 +1653,7 @@ var MedicationSummaryTemplate = class _MedicationSummaryTemplate {
1573
1653
  <th>Sig</th>
1574
1654
  <th>Dispense Quantity</th>
1575
1655
  <th>Refills</th>
1576
- <th>Start Date</th>${isActiveSection ? "" : `
1577
- <th>End Date</th>`}
1578
- <th>Status</th>
1656
+ <th>Start Date</th>
1579
1657
  </tr>
1580
1658
  </thead>
1581
1659
  <tbody>`;
@@ -1587,12 +1665,9 @@ var MedicationSummaryTemplate = class _MedicationSummaryTemplate {
1587
1665
  let dispenseQuantity = "-";
1588
1666
  let refills = "-";
1589
1667
  let startDate = "-";
1590
- let endDate = "-";
1591
- let status;
1592
1668
  if (medication.type === "request") {
1593
1669
  const mr = medication.resource;
1594
1670
  type = "Request";
1595
- status = mr.status ? String(mr.status) : "-";
1596
1671
  medicationName = templateUtilities.getMedicationName(
1597
1672
  mr.medicationReference || mr.medicationCodeableConcept
1598
1673
  );
@@ -1606,14 +1681,12 @@ var MedicationSummaryTemplate = class _MedicationSummaryTemplate {
1606
1681
  refills = mr.dispenseRequest?.numberOfRepeatsAllowed?.toString() || "-";
1607
1682
  if (mr.dispenseRequest?.validityPeriod) {
1608
1683
  startDate = mr.dispenseRequest.validityPeriod.start || "-";
1609
- endDate = mr.dispenseRequest.validityPeriod.end || "-";
1610
1684
  } else {
1611
1685
  startDate = mr.authoredOn || "-";
1612
1686
  }
1613
1687
  } else {
1614
1688
  const ms = medication.resource;
1615
1689
  type = "Statement";
1616
- status = ms.status ? String(ms.status) : "-";
1617
1690
  medicationName = templateUtilities.getMedicationName(
1618
1691
  ms.medicationReference || ms.medicationCodeableConcept
1619
1692
  );
@@ -1622,7 +1695,6 @@ var MedicationSummaryTemplate = class _MedicationSummaryTemplate {
1622
1695
  startDate = ms.effectiveDateTime;
1623
1696
  } else if (ms.effectivePeriod) {
1624
1697
  startDate = ms.effectivePeriod.start || "-";
1625
- endDate = ms.effectivePeriod.end || "-";
1626
1698
  }
1627
1699
  }
1628
1700
  html += `
@@ -1632,9 +1704,7 @@ var MedicationSummaryTemplate = class _MedicationSummaryTemplate {
1632
1704
  <td>${sig}</td>
1633
1705
  <td>${dispenseQuantity}</td>
1634
1706
  <td>${refills}</td>
1635
- <td>${startDate}</td>${isActiveSection ? "" : `
1636
- <td>${endDate}</td>`}
1637
- <td>${status}</td>
1707
+ <td>${startDate}</td>
1638
1708
  </tr>`;
1639
1709
  }
1640
1710
  html += `
@@ -1775,6 +1845,7 @@ var ProblemListTemplate = class _ProblemListTemplate {
1775
1845
  * @param timezone - Optional timezone to use for date formatting (e.g., 'America/New_York', 'Europe/London')
1776
1846
  * @returns HTML string for rendering
1777
1847
  */
1848
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
1778
1849
  static generateStaticNarrative(resources, timezone) {
1779
1850
  const templateUtilities = new TemplateUtilities(resources);
1780
1851
  let html = ``;
@@ -1791,7 +1862,6 @@ var ProblemListTemplate = class _ProblemListTemplate {
1791
1862
  <th>Problem</th>
1792
1863
  <th>Onset Date</th>
1793
1864
  <th>Recorded Date</th>
1794
- <th>Notes</th>
1795
1865
  </tr>
1796
1866
  </thead>
1797
1867
  <tbody>`;
@@ -1800,7 +1870,6 @@ var ProblemListTemplate = class _ProblemListTemplate {
1800
1870
  <td class="Name">${templateUtilities.codeableConcept(cond.code)}</td>
1801
1871
  <td class="OnsetDate">${templateUtilities.renderDate(cond.onsetDateTime)}</td>
1802
1872
  <td class="RecordedDate">${templateUtilities.renderDate(cond.recordedDate)}</td>
1803
- <td class="Notes">${templateUtilities.renderNotes(cond.note, timezone)}</td>
1804
1873
  </tr>`;
1805
1874
  }
1806
1875
  html += `</tbody>
@@ -1809,13 +1878,6 @@ var ProblemListTemplate = class _ProblemListTemplate {
1809
1878
  }
1810
1879
  };
1811
1880
 
1812
- // src/structures/ips_section_constants.ts
1813
- var VITAL_SIGNS_SUMMARY_COMPONENT_MAP = {
1814
- "Systolic Blood Pressure": "valueRatio.numerator.value",
1815
- "Diastolic Blood Pressure": "valueRatio.denominator.value",
1816
- "Default": "valueString"
1817
- };
1818
-
1819
1881
  // src/narratives/templates/typescript/VitalSignsTemplate.ts
1820
1882
  var VitalSignsTemplate = class _VitalSignsTemplate {
1821
1883
  /**
@@ -2235,6 +2297,7 @@ var PastHistoryOfIllnessTemplate = class {
2235
2297
  * @param timezone - Optional timezone to use for date formatting (e.g., 'America/New_York', 'Europe/London')
2236
2298
  * @returns HTML string for rendering
2237
2299
  */
2300
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
2238
2301
  generateNarrative(resources, timezone) {
2239
2302
  const templateUtilities = new TemplateUtilities(resources);
2240
2303
  let html = ``;
@@ -2252,7 +2315,6 @@ var PastHistoryOfIllnessTemplate = class {
2252
2315
  <th>Onset Date</th>
2253
2316
  <th>Recorded Date</th>
2254
2317
  <th>Resolved Date</th>
2255
- <th>Notes</th>
2256
2318
  </tr>
2257
2319
  </thead>
2258
2320
  <tbody>`;
@@ -2262,7 +2324,6 @@ var PastHistoryOfIllnessTemplate = class {
2262
2324
  <td class="OnsetDate">${templateUtilities.renderDate(cond.onsetDateTime)}</td>
2263
2325
  <td class="RecordedDate">${templateUtilities.renderDate(cond.recordedDate)}</td>
2264
2326
  <td class="ResolvedDate">${templateUtilities.renderDate(cond.abatementDateTime)}</td>
2265
- <td class="Notes">${templateUtilities.renderNotes(cond.note, timezone)}</td>
2266
2327
  </tr>`;
2267
2328
  }
2268
2329
  html += `</tbody>
@@ -2415,7 +2476,6 @@ var FunctionalStatusTemplate = class _FunctionalStatusTemplate {
2415
2476
  <th>Problem</th>
2416
2477
  <th>Onset Date</th>
2417
2478
  <th>Recorded Date</th>
2418
- <th>Notes</th>
2419
2479
  </tr>
2420
2480
  </thead>
2421
2481
  <tbody>`;
@@ -2424,7 +2484,6 @@ var FunctionalStatusTemplate = class _FunctionalStatusTemplate {
2424
2484
  <td class="Name">${templateUtilities.codeableConcept(cond.code)}</td>
2425
2485
  <td class="OnsetDate">${templateUtilities.renderDate(cond.onsetDateTime)}</td>
2426
2486
  <td class="RecordedDate">${templateUtilities.renderDate(cond.recordedDate)}</td>
2427
- <td class="Notes">${templateUtilities.renderNotes(cond.note, timezone, { styled: true, warning: true })}</td>
2428
2487
  </tr>`;
2429
2488
  }
2430
2489
  html += `</tbody>
@@ -2440,7 +2499,6 @@ var FunctionalStatusTemplate = class _FunctionalStatusTemplate {
2440
2499
  <th>Description</th>
2441
2500
  <th>Summary</th>
2442
2501
  <th>Findings</th>
2443
- <th>Notes</th>
2444
2502
  </tr>
2445
2503
  </thead>
2446
2504
  <tbody>`;
@@ -2469,7 +2527,6 @@ var FunctionalStatusTemplate = class _FunctionalStatusTemplate {
2469
2527
  }
2470
2528
  findingsHtml += "</ul>";
2471
2529
  }
2472
- const notes = templateUtilities.renderNotes(impression.note, timezone);
2473
2530
  html += `
2474
2531
  <tr id="${templateUtilities.narrativeLinkId(impression)}">
2475
2532
  <td>${formattedDate}</td>
@@ -2477,7 +2534,6 @@ var FunctionalStatusTemplate = class _FunctionalStatusTemplate {
2477
2534
  <td>${impression.description || ""}</td>
2478
2535
  <td>${impression.summary || ""}</td>
2479
2536
  <td>${findingsHtml}</td>
2480
- <td>${notes}</td>
2481
2537
  </tr>`;
2482
2538
  }
2483
2539
  html += `</tbody>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@imranq2/fhirpatientsummary",
3
- "version": "1.0.22",
3
+ "version": "1.0.23",
4
4
  "description": "A template for creating npm packages using TypeScript and VSCode",
5
5
  "main": "./dist/index.js",
6
6
  "module": "./dist/index.mjs",