@imranq2/fhirpatientsummary 1.0.21 → 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.
- package/dist/index.cjs +189 -126
- package/dist/index.js +189 -126
- package/package.json +21 -20
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"
|
|
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,15 +151,21 @@ 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 ===
|
|
147
|
-
["VitalSignsSection" /* VITAL_SIGNS */]: (resource) => resource.resourceType === "Composition" && resource.type?.coding?.some((c) => c.system ===
|
|
148
|
-
["PlanOfCareSection" /* CARE_PLAN */]: (resource) => resource.resourceType === "Composition" && resource.type?.coding?.some((c) => c.system ===
|
|
149
|
-
["ImmunizationSection" /* IMMUNIZATIONS */]: (resource) => resource.resourceType === "Composition" && resource.type?.coding?.some((c) => c.system ===
|
|
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) {
|
|
153
162
|
return IPSSectionResourceFilters[section];
|
|
154
163
|
}
|
|
164
|
+
static getSectionResources(section, resources) {
|
|
165
|
+
const filter = IPSSectionResourceFilters[section];
|
|
166
|
+
if (!filter) return [];
|
|
167
|
+
return resources.filter(filter);
|
|
168
|
+
}
|
|
155
169
|
static getSummaryCompositionFilterForSection(section) {
|
|
156
170
|
return IPSSectionSummaryCompositionFilter[section];
|
|
157
171
|
}
|
|
@@ -331,7 +345,7 @@ var TemplateUtilities = class {
|
|
|
331
345
|
* @returns Formatted date string (date only, no time component)
|
|
332
346
|
*/
|
|
333
347
|
renderDate(date) {
|
|
334
|
-
return this.formatDateTime(date,
|
|
348
|
+
return this.formatDateTime(date, "UTC", true);
|
|
335
349
|
}
|
|
336
350
|
/**
|
|
337
351
|
* Renders a recorded date
|
|
@@ -845,9 +859,11 @@ var TemplateUtilities = class {
|
|
|
845
859
|
if (dateValue instanceof Date) {
|
|
846
860
|
dateTime = import_luxon.DateTime.fromJSDate(dateValue);
|
|
847
861
|
} else if (typeof dateValue === "string") {
|
|
848
|
-
dateTime = import_luxon.DateTime.fromISO(dateValue);
|
|
849
862
|
if (!dateValue.includes("T")) {
|
|
850
863
|
dateOnly = true;
|
|
864
|
+
dateTime = import_luxon.DateTime.fromISO(dateValue, { zone: "utc" });
|
|
865
|
+
} else {
|
|
866
|
+
dateTime = import_luxon.DateTime.fromISO(dateValue);
|
|
851
867
|
}
|
|
852
868
|
} else {
|
|
853
869
|
dateTime = import_luxon.DateTime.fromISO(String(dateValue));
|
|
@@ -855,7 +871,9 @@ var TemplateUtilities = class {
|
|
|
855
871
|
if (!dateTime.isValid) {
|
|
856
872
|
return String(dateValue);
|
|
857
873
|
}
|
|
858
|
-
if (
|
|
874
|
+
if (dateOnly) {
|
|
875
|
+
dateTime = dateTime.toUTC();
|
|
876
|
+
} else if (timezone) {
|
|
859
877
|
dateTime = dateTime.toUTC().setZone(timezone);
|
|
860
878
|
}
|
|
861
879
|
const formatOptions = dateOnly ? { year: "numeric", month: "2-digit", day: "2-digit" } : {
|
|
@@ -947,6 +965,9 @@ var TemplateUtilities = class {
|
|
|
947
965
|
}
|
|
948
966
|
};
|
|
949
967
|
|
|
968
|
+
// src/constants.ts
|
|
969
|
+
var ADDRESS_SIMILARITY_THRESHOLD = 70;
|
|
970
|
+
|
|
950
971
|
// src/narratives/templates/typescript/PatientTemplate.ts
|
|
951
972
|
var PatientTemplate = class _PatientTemplate {
|
|
952
973
|
/**
|
|
@@ -973,7 +994,6 @@ var PatientTemplate = class _PatientTemplate {
|
|
|
973
994
|
<li><strong>Name(s):</strong>${this.renderNames(combinedPatient)}</li>
|
|
974
995
|
<li><strong>Gender:</strong>${combinedPatient.gender ? this.capitalize(combinedPatient.gender) : ""}</li>
|
|
975
996
|
<li><strong>Date of Birth:</strong>${combinedPatient.birthDate || ""}</li>
|
|
976
|
-
<li><strong>Identifier(s):</strong>${this.renderIdentifiers(combinedPatient)}</li>
|
|
977
997
|
<li><strong>Telecom:</strong><ul>${this.renderTelecom(combinedPatient)}</ul></li>
|
|
978
998
|
<li><strong>Address(es):</strong>${this.renderAddresses(combinedPatient)}</li>
|
|
979
999
|
<li><strong>Marital Status:</strong> ${combinedPatient.maritalStatus?.text || ""}</li>
|
|
@@ -994,7 +1014,6 @@ var PatientTemplate = class _PatientTemplate {
|
|
|
994
1014
|
}
|
|
995
1015
|
const combined = patients[0];
|
|
996
1016
|
const allNames = [];
|
|
997
|
-
const allIdentifiers = [];
|
|
998
1017
|
const allTelecom = [];
|
|
999
1018
|
const allAddresses = [];
|
|
1000
1019
|
const allCommunication = [];
|
|
@@ -1002,9 +1021,6 @@ var PatientTemplate = class _PatientTemplate {
|
|
|
1002
1021
|
if (patient.name) {
|
|
1003
1022
|
allNames.push(...patient.name);
|
|
1004
1023
|
}
|
|
1005
|
-
if (patient.identifier) {
|
|
1006
|
-
allIdentifiers.push(...patient.identifier);
|
|
1007
|
-
}
|
|
1008
1024
|
if (patient.telecom) {
|
|
1009
1025
|
allTelecom.push(...patient.telecom);
|
|
1010
1026
|
}
|
|
@@ -1031,7 +1047,6 @@ var PatientTemplate = class _PatientTemplate {
|
|
|
1031
1047
|
}
|
|
1032
1048
|
});
|
|
1033
1049
|
combined.name = allNames;
|
|
1034
|
-
combined.identifier = allIdentifiers;
|
|
1035
1050
|
combined.telecom = allTelecom;
|
|
1036
1051
|
combined.address = allAddresses;
|
|
1037
1052
|
combined.communication = allCommunication;
|
|
@@ -1057,21 +1072,6 @@ var PatientTemplate = class _PatientTemplate {
|
|
|
1057
1072
|
});
|
|
1058
1073
|
return Array.from(uniqueNames).map((nameText) => `<ul><li>${nameText}</li></ul>`).join("");
|
|
1059
1074
|
}
|
|
1060
|
-
/**
|
|
1061
|
-
* Renders patient identifiers as HTML list items
|
|
1062
|
-
* @param patient - Patient resources
|
|
1063
|
-
* @returns HTML string of list items
|
|
1064
|
-
*/
|
|
1065
|
-
static renderIdentifiers(patient) {
|
|
1066
|
-
if (!patient.identifier || patient.identifier.length === 0) {
|
|
1067
|
-
return "";
|
|
1068
|
-
}
|
|
1069
|
-
return patient.identifier.map((id) => {
|
|
1070
|
-
const system = id.system || "";
|
|
1071
|
-
const value = id.value || "";
|
|
1072
|
-
return `<ul><li>${system}: ${value}</li></ul>`;
|
|
1073
|
-
}).join("");
|
|
1074
|
-
}
|
|
1075
1075
|
/**
|
|
1076
1076
|
* Renders patient telecom information grouped by system
|
|
1077
1077
|
* @param patient - Patient resources
|
|
@@ -1173,7 +1173,89 @@ var PatientTemplate = class _PatientTemplate {
|
|
|
1173
1173
|
uniqueAddresses.add(addressText);
|
|
1174
1174
|
}
|
|
1175
1175
|
});
|
|
1176
|
-
|
|
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;
|
|
1177
1259
|
}
|
|
1178
1260
|
/**
|
|
1179
1261
|
* Renders patient deceased status
|
|
@@ -1421,6 +1503,75 @@ var MedicationSummaryTemplate = class _MedicationSummaryTemplate {
|
|
|
1421
1503
|
generateNarrative(resources, timezone) {
|
|
1422
1504
|
return _MedicationSummaryTemplate.generateStaticNarrative(resources, timezone);
|
|
1423
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
|
+
}
|
|
1424
1575
|
/**
|
|
1425
1576
|
* Safely parse a date string and return a valid Date object or null
|
|
1426
1577
|
* @param dateString - The date string to parse
|
|
@@ -1433,55 +1584,6 @@ var MedicationSummaryTemplate = class _MedicationSummaryTemplate {
|
|
|
1433
1584
|
const date = new Date(dateString);
|
|
1434
1585
|
return !isNaN(date.getTime()) ? date : null;
|
|
1435
1586
|
}
|
|
1436
|
-
/**
|
|
1437
|
-
* Determine if a MedicationRequest is active
|
|
1438
|
-
* @param medicationRequest - The MedicationRequest resource
|
|
1439
|
-
* @returns boolean indicating if the medication request is active
|
|
1440
|
-
*/
|
|
1441
|
-
static isActiveMedicationRequest(medicationRequest) {
|
|
1442
|
-
const status = medicationRequest.status?.toLowerCase();
|
|
1443
|
-
if (status === "active" || status === "unknown") {
|
|
1444
|
-
return true;
|
|
1445
|
-
}
|
|
1446
|
-
if (status === "completed" || status === "cancelled" || status === "stopped" || status === "draft") {
|
|
1447
|
-
return false;
|
|
1448
|
-
}
|
|
1449
|
-
const endDate = medicationRequest.dispenseRequest?.validityPeriod?.end;
|
|
1450
|
-
if (!endDate) {
|
|
1451
|
-
return true;
|
|
1452
|
-
}
|
|
1453
|
-
const parsedEndDate = this.parseDate(endDate);
|
|
1454
|
-
if (!parsedEndDate) {
|
|
1455
|
-
return true;
|
|
1456
|
-
}
|
|
1457
|
-
return parsedEndDate.getTime() > Date.now();
|
|
1458
|
-
}
|
|
1459
|
-
/**
|
|
1460
|
-
* Determine if a MedicationStatement is active
|
|
1461
|
-
* @param medicationStatement - The MedicationStatement resource
|
|
1462
|
-
* @returns boolean indicating if the medication statement is active
|
|
1463
|
-
*/
|
|
1464
|
-
static isActiveMedicationStatement(medicationStatement) {
|
|
1465
|
-
const status = medicationStatement.status?.toLowerCase();
|
|
1466
|
-
if (status === "active" || status === "intended" || status === "unknown") {
|
|
1467
|
-
return true;
|
|
1468
|
-
}
|
|
1469
|
-
if (status === "completed" || status === "stopped" || status === "not-taken") {
|
|
1470
|
-
return false;
|
|
1471
|
-
}
|
|
1472
|
-
let endDate;
|
|
1473
|
-
if (medicationStatement.effectivePeriod?.end) {
|
|
1474
|
-
endDate = medicationStatement.effectivePeriod.end;
|
|
1475
|
-
}
|
|
1476
|
-
if (!endDate) {
|
|
1477
|
-
return true;
|
|
1478
|
-
}
|
|
1479
|
-
const parsedEndDate = this.parseDate(endDate);
|
|
1480
|
-
if (!parsedEndDate) {
|
|
1481
|
-
return true;
|
|
1482
|
-
}
|
|
1483
|
-
return parsedEndDate.getTime() > Date.now();
|
|
1484
|
-
}
|
|
1485
1587
|
/**
|
|
1486
1588
|
* Internal static implementation that actually generates the narrative
|
|
1487
1589
|
* @param resources - FHIR Medication resources
|
|
@@ -1495,20 +1597,11 @@ var MedicationSummaryTemplate = class _MedicationSummaryTemplate {
|
|
|
1495
1597
|
const medicationRequests = this.getMedicationRequests(templateUtilities, resources);
|
|
1496
1598
|
const medicationStatements = this.getMedicationStatements(templateUtilities, resources);
|
|
1497
1599
|
const allActiveMedications = [];
|
|
1498
|
-
const allInactiveMedications = [];
|
|
1499
1600
|
medicationRequests.forEach((mr) => {
|
|
1500
|
-
|
|
1501
|
-
allActiveMedications.push({ type: "request", resource: mr.resource, extension: mr.extension });
|
|
1502
|
-
} else {
|
|
1503
|
-
allInactiveMedications.push({ type: "request", resource: mr.resource, extension: mr.extension });
|
|
1504
|
-
}
|
|
1601
|
+
allActiveMedications.push({ type: "request", resource: mr.resource, extension: mr.extension });
|
|
1505
1602
|
});
|
|
1506
1603
|
medicationStatements.forEach((ms) => {
|
|
1507
|
-
|
|
1508
|
-
allActiveMedications.push({ type: "statement", resource: ms.resource, extension: ms.extension });
|
|
1509
|
-
} else {
|
|
1510
|
-
allInactiveMedications.push({ type: "statement", resource: ms.resource, extension: ms.extension });
|
|
1511
|
-
}
|
|
1604
|
+
allActiveMedications.push({ type: "statement", resource: ms.resource, extension: ms.extension });
|
|
1512
1605
|
});
|
|
1513
1606
|
const sortMedications = (medications) => {
|
|
1514
1607
|
medications.sort((a, b) => {
|
|
@@ -1538,11 +1631,7 @@ var MedicationSummaryTemplate = class _MedicationSummaryTemplate {
|
|
|
1538
1631
|
};
|
|
1539
1632
|
if (allActiveMedications.length > 0) {
|
|
1540
1633
|
sortMedications(allActiveMedications);
|
|
1541
|
-
html += this.renderCombinedMedications(templateUtilities, allActiveMedications
|
|
1542
|
-
}
|
|
1543
|
-
if (allInactiveMedications.length > 0) {
|
|
1544
|
-
sortMedications(allInactiveMedications);
|
|
1545
|
-
html += this.renderCombinedMedications(templateUtilities, allInactiveMedications, false);
|
|
1634
|
+
html += this.renderCombinedMedications(templateUtilities, allActiveMedications);
|
|
1546
1635
|
}
|
|
1547
1636
|
return html;
|
|
1548
1637
|
}
|
|
@@ -1580,12 +1669,10 @@ var MedicationSummaryTemplate = class _MedicationSummaryTemplate {
|
|
|
1580
1669
|
* Render HTML table for combined MedicationRequest and MedicationStatement resources
|
|
1581
1670
|
* @param templateUtilities - Instance of TemplateUtilities for utility functions
|
|
1582
1671
|
* @param medications - Array of combined medication resources
|
|
1583
|
-
* @param sectionTitle - Title for the section
|
|
1584
1672
|
* @returns HTML string for rendering
|
|
1585
1673
|
*/
|
|
1586
|
-
static renderCombinedMedications(templateUtilities, medications
|
|
1674
|
+
static renderCombinedMedications(templateUtilities, medications) {
|
|
1587
1675
|
let html = `
|
|
1588
|
-
<h3>${isActiveSection ? "Active Medications" : "Inactive Medications"}</h3>
|
|
1589
1676
|
<table>
|
|
1590
1677
|
<thead>
|
|
1591
1678
|
<tr>
|
|
@@ -1594,9 +1681,7 @@ var MedicationSummaryTemplate = class _MedicationSummaryTemplate {
|
|
|
1594
1681
|
<th>Sig</th>
|
|
1595
1682
|
<th>Dispense Quantity</th>
|
|
1596
1683
|
<th>Refills</th>
|
|
1597
|
-
<th>Start Date</th
|
|
1598
|
-
<th>End Date</th>`}
|
|
1599
|
-
<th>Status</th>
|
|
1684
|
+
<th>Start Date</th>
|
|
1600
1685
|
</tr>
|
|
1601
1686
|
</thead>
|
|
1602
1687
|
<tbody>`;
|
|
@@ -1608,12 +1693,9 @@ var MedicationSummaryTemplate = class _MedicationSummaryTemplate {
|
|
|
1608
1693
|
let dispenseQuantity = "-";
|
|
1609
1694
|
let refills = "-";
|
|
1610
1695
|
let startDate = "-";
|
|
1611
|
-
let endDate = "-";
|
|
1612
|
-
let status;
|
|
1613
1696
|
if (medication.type === "request") {
|
|
1614
1697
|
const mr = medication.resource;
|
|
1615
1698
|
type = "Request";
|
|
1616
|
-
status = mr.status ? String(mr.status) : "-";
|
|
1617
1699
|
medicationName = templateUtilities.getMedicationName(
|
|
1618
1700
|
mr.medicationReference || mr.medicationCodeableConcept
|
|
1619
1701
|
);
|
|
@@ -1627,14 +1709,12 @@ var MedicationSummaryTemplate = class _MedicationSummaryTemplate {
|
|
|
1627
1709
|
refills = mr.dispenseRequest?.numberOfRepeatsAllowed?.toString() || "-";
|
|
1628
1710
|
if (mr.dispenseRequest?.validityPeriod) {
|
|
1629
1711
|
startDate = mr.dispenseRequest.validityPeriod.start || "-";
|
|
1630
|
-
endDate = mr.dispenseRequest.validityPeriod.end || "-";
|
|
1631
1712
|
} else {
|
|
1632
1713
|
startDate = mr.authoredOn || "-";
|
|
1633
1714
|
}
|
|
1634
1715
|
} else {
|
|
1635
1716
|
const ms = medication.resource;
|
|
1636
1717
|
type = "Statement";
|
|
1637
|
-
status = ms.status ? String(ms.status) : "-";
|
|
1638
1718
|
medicationName = templateUtilities.getMedicationName(
|
|
1639
1719
|
ms.medicationReference || ms.medicationCodeableConcept
|
|
1640
1720
|
);
|
|
@@ -1643,7 +1723,6 @@ var MedicationSummaryTemplate = class _MedicationSummaryTemplate {
|
|
|
1643
1723
|
startDate = ms.effectiveDateTime;
|
|
1644
1724
|
} else if (ms.effectivePeriod) {
|
|
1645
1725
|
startDate = ms.effectivePeriod.start || "-";
|
|
1646
|
-
endDate = ms.effectivePeriod.end || "-";
|
|
1647
1726
|
}
|
|
1648
1727
|
}
|
|
1649
1728
|
html += `
|
|
@@ -1653,9 +1732,7 @@ var MedicationSummaryTemplate = class _MedicationSummaryTemplate {
|
|
|
1653
1732
|
<td>${sig}</td>
|
|
1654
1733
|
<td>${dispenseQuantity}</td>
|
|
1655
1734
|
<td>${refills}</td>
|
|
1656
|
-
<td>${startDate}</td
|
|
1657
|
-
<td>${endDate}</td>`}
|
|
1658
|
-
<td>${status}</td>
|
|
1735
|
+
<td>${startDate}</td>
|
|
1659
1736
|
</tr>`;
|
|
1660
1737
|
}
|
|
1661
1738
|
html += `
|
|
@@ -1796,6 +1873,7 @@ var ProblemListTemplate = class _ProblemListTemplate {
|
|
|
1796
1873
|
* @param timezone - Optional timezone to use for date formatting (e.g., 'America/New_York', 'Europe/London')
|
|
1797
1874
|
* @returns HTML string for rendering
|
|
1798
1875
|
*/
|
|
1876
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
1799
1877
|
static generateStaticNarrative(resources, timezone) {
|
|
1800
1878
|
const templateUtilities = new TemplateUtilities(resources);
|
|
1801
1879
|
let html = ``;
|
|
@@ -1812,7 +1890,6 @@ var ProblemListTemplate = class _ProblemListTemplate {
|
|
|
1812
1890
|
<th>Problem</th>
|
|
1813
1891
|
<th>Onset Date</th>
|
|
1814
1892
|
<th>Recorded Date</th>
|
|
1815
|
-
<th>Notes</th>
|
|
1816
1893
|
</tr>
|
|
1817
1894
|
</thead>
|
|
1818
1895
|
<tbody>`;
|
|
@@ -1821,7 +1898,6 @@ var ProblemListTemplate = class _ProblemListTemplate {
|
|
|
1821
1898
|
<td class="Name">${templateUtilities.codeableConcept(cond.code)}</td>
|
|
1822
1899
|
<td class="OnsetDate">${templateUtilities.renderDate(cond.onsetDateTime)}</td>
|
|
1823
1900
|
<td class="RecordedDate">${templateUtilities.renderDate(cond.recordedDate)}</td>
|
|
1824
|
-
<td class="Notes">${templateUtilities.renderNotes(cond.note, timezone)}</td>
|
|
1825
1901
|
</tr>`;
|
|
1826
1902
|
}
|
|
1827
1903
|
html += `</tbody>
|
|
@@ -1830,13 +1906,6 @@ var ProblemListTemplate = class _ProblemListTemplate {
|
|
|
1830
1906
|
}
|
|
1831
1907
|
};
|
|
1832
1908
|
|
|
1833
|
-
// src/structures/ips_section_constants.ts
|
|
1834
|
-
var VITAL_SIGNS_SUMMARY_COMPONENT_MAP = {
|
|
1835
|
-
"Systolic Blood Pressure": "valueRatio.numerator.value",
|
|
1836
|
-
"Diastolic Blood Pressure": "valueRatio.denominator.value",
|
|
1837
|
-
"Default": "valueString"
|
|
1838
|
-
};
|
|
1839
|
-
|
|
1840
1909
|
// src/narratives/templates/typescript/VitalSignsTemplate.ts
|
|
1841
1910
|
var VitalSignsTemplate = class _VitalSignsTemplate {
|
|
1842
1911
|
/**
|
|
@@ -2256,6 +2325,7 @@ var PastHistoryOfIllnessTemplate = class {
|
|
|
2256
2325
|
* @param timezone - Optional timezone to use for date formatting (e.g., 'America/New_York', 'Europe/London')
|
|
2257
2326
|
* @returns HTML string for rendering
|
|
2258
2327
|
*/
|
|
2328
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
2259
2329
|
generateNarrative(resources, timezone) {
|
|
2260
2330
|
const templateUtilities = new TemplateUtilities(resources);
|
|
2261
2331
|
let html = ``;
|
|
@@ -2273,7 +2343,6 @@ var PastHistoryOfIllnessTemplate = class {
|
|
|
2273
2343
|
<th>Onset Date</th>
|
|
2274
2344
|
<th>Recorded Date</th>
|
|
2275
2345
|
<th>Resolved Date</th>
|
|
2276
|
-
<th>Notes</th>
|
|
2277
2346
|
</tr>
|
|
2278
2347
|
</thead>
|
|
2279
2348
|
<tbody>`;
|
|
@@ -2283,7 +2352,6 @@ var PastHistoryOfIllnessTemplate = class {
|
|
|
2283
2352
|
<td class="OnsetDate">${templateUtilities.renderDate(cond.onsetDateTime)}</td>
|
|
2284
2353
|
<td class="RecordedDate">${templateUtilities.renderDate(cond.recordedDate)}</td>
|
|
2285
2354
|
<td class="ResolvedDate">${templateUtilities.renderDate(cond.abatementDateTime)}</td>
|
|
2286
|
-
<td class="Notes">${templateUtilities.renderNotes(cond.note, timezone)}</td>
|
|
2287
2355
|
</tr>`;
|
|
2288
2356
|
}
|
|
2289
2357
|
html += `</tbody>
|
|
@@ -2436,7 +2504,6 @@ var FunctionalStatusTemplate = class _FunctionalStatusTemplate {
|
|
|
2436
2504
|
<th>Problem</th>
|
|
2437
2505
|
<th>Onset Date</th>
|
|
2438
2506
|
<th>Recorded Date</th>
|
|
2439
|
-
<th>Notes</th>
|
|
2440
2507
|
</tr>
|
|
2441
2508
|
</thead>
|
|
2442
2509
|
<tbody>`;
|
|
@@ -2445,7 +2512,6 @@ var FunctionalStatusTemplate = class _FunctionalStatusTemplate {
|
|
|
2445
2512
|
<td class="Name">${templateUtilities.codeableConcept(cond.code)}</td>
|
|
2446
2513
|
<td class="OnsetDate">${templateUtilities.renderDate(cond.onsetDateTime)}</td>
|
|
2447
2514
|
<td class="RecordedDate">${templateUtilities.renderDate(cond.recordedDate)}</td>
|
|
2448
|
-
<td class="Notes">${templateUtilities.renderNotes(cond.note, timezone, { styled: true, warning: true })}</td>
|
|
2449
2515
|
</tr>`;
|
|
2450
2516
|
}
|
|
2451
2517
|
html += `</tbody>
|
|
@@ -2461,7 +2527,6 @@ var FunctionalStatusTemplate = class _FunctionalStatusTemplate {
|
|
|
2461
2527
|
<th>Description</th>
|
|
2462
2528
|
<th>Summary</th>
|
|
2463
2529
|
<th>Findings</th>
|
|
2464
|
-
<th>Notes</th>
|
|
2465
2530
|
</tr>
|
|
2466
2531
|
</thead>
|
|
2467
2532
|
<tbody>`;
|
|
@@ -2490,7 +2555,6 @@ var FunctionalStatusTemplate = class _FunctionalStatusTemplate {
|
|
|
2490
2555
|
}
|
|
2491
2556
|
findingsHtml += "</ul>";
|
|
2492
2557
|
}
|
|
2493
|
-
const notes = templateUtilities.renderNotes(impression.note, timezone);
|
|
2494
2558
|
html += `
|
|
2495
2559
|
<tr id="${templateUtilities.narrativeLinkId(impression)}">
|
|
2496
2560
|
<td>${formattedDate}</td>
|
|
@@ -2498,7 +2562,6 @@ var FunctionalStatusTemplate = class _FunctionalStatusTemplate {
|
|
|
2498
2562
|
<td>${impression.description || ""}</td>
|
|
2499
2563
|
<td>${impression.summary || ""}</td>
|
|
2500
2564
|
<td>${findingsHtml}</td>
|
|
2501
|
-
<td>${notes}</td>
|
|
2502
2565
|
</tr>`;
|
|
2503
2566
|
}
|
|
2504
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"
|
|
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,15 +123,21 @@ 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 ===
|
|
119
|
-
["VitalSignsSection" /* VITAL_SIGNS */]: (resource) => resource.resourceType === "Composition" && resource.type?.coding?.some((c) => c.system ===
|
|
120
|
-
["PlanOfCareSection" /* CARE_PLAN */]: (resource) => resource.resourceType === "Composition" && resource.type?.coding?.some((c) => c.system ===
|
|
121
|
-
["ImmunizationSection" /* IMMUNIZATIONS */]: (resource) => resource.resourceType === "Composition" && resource.type?.coding?.some((c) => c.system ===
|
|
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) {
|
|
125
134
|
return IPSSectionResourceFilters[section];
|
|
126
135
|
}
|
|
136
|
+
static getSectionResources(section, resources) {
|
|
137
|
+
const filter = IPSSectionResourceFilters[section];
|
|
138
|
+
if (!filter) return [];
|
|
139
|
+
return resources.filter(filter);
|
|
140
|
+
}
|
|
127
141
|
static getSummaryCompositionFilterForSection(section) {
|
|
128
142
|
return IPSSectionSummaryCompositionFilter[section];
|
|
129
143
|
}
|
|
@@ -303,7 +317,7 @@ var TemplateUtilities = class {
|
|
|
303
317
|
* @returns Formatted date string (date only, no time component)
|
|
304
318
|
*/
|
|
305
319
|
renderDate(date) {
|
|
306
|
-
return this.formatDateTime(date,
|
|
320
|
+
return this.formatDateTime(date, "UTC", true);
|
|
307
321
|
}
|
|
308
322
|
/**
|
|
309
323
|
* Renders a recorded date
|
|
@@ -817,9 +831,11 @@ var TemplateUtilities = class {
|
|
|
817
831
|
if (dateValue instanceof Date) {
|
|
818
832
|
dateTime = DateTime.fromJSDate(dateValue);
|
|
819
833
|
} else if (typeof dateValue === "string") {
|
|
820
|
-
dateTime = DateTime.fromISO(dateValue);
|
|
821
834
|
if (!dateValue.includes("T")) {
|
|
822
835
|
dateOnly = true;
|
|
836
|
+
dateTime = DateTime.fromISO(dateValue, { zone: "utc" });
|
|
837
|
+
} else {
|
|
838
|
+
dateTime = DateTime.fromISO(dateValue);
|
|
823
839
|
}
|
|
824
840
|
} else {
|
|
825
841
|
dateTime = DateTime.fromISO(String(dateValue));
|
|
@@ -827,7 +843,9 @@ var TemplateUtilities = class {
|
|
|
827
843
|
if (!dateTime.isValid) {
|
|
828
844
|
return String(dateValue);
|
|
829
845
|
}
|
|
830
|
-
if (
|
|
846
|
+
if (dateOnly) {
|
|
847
|
+
dateTime = dateTime.toUTC();
|
|
848
|
+
} else if (timezone) {
|
|
831
849
|
dateTime = dateTime.toUTC().setZone(timezone);
|
|
832
850
|
}
|
|
833
851
|
const formatOptions = dateOnly ? { year: "numeric", month: "2-digit", day: "2-digit" } : {
|
|
@@ -919,6 +937,9 @@ var TemplateUtilities = class {
|
|
|
919
937
|
}
|
|
920
938
|
};
|
|
921
939
|
|
|
940
|
+
// src/constants.ts
|
|
941
|
+
var ADDRESS_SIMILARITY_THRESHOLD = 70;
|
|
942
|
+
|
|
922
943
|
// src/narratives/templates/typescript/PatientTemplate.ts
|
|
923
944
|
var PatientTemplate = class _PatientTemplate {
|
|
924
945
|
/**
|
|
@@ -945,7 +966,6 @@ var PatientTemplate = class _PatientTemplate {
|
|
|
945
966
|
<li><strong>Name(s):</strong>${this.renderNames(combinedPatient)}</li>
|
|
946
967
|
<li><strong>Gender:</strong>${combinedPatient.gender ? this.capitalize(combinedPatient.gender) : ""}</li>
|
|
947
968
|
<li><strong>Date of Birth:</strong>${combinedPatient.birthDate || ""}</li>
|
|
948
|
-
<li><strong>Identifier(s):</strong>${this.renderIdentifiers(combinedPatient)}</li>
|
|
949
969
|
<li><strong>Telecom:</strong><ul>${this.renderTelecom(combinedPatient)}</ul></li>
|
|
950
970
|
<li><strong>Address(es):</strong>${this.renderAddresses(combinedPatient)}</li>
|
|
951
971
|
<li><strong>Marital Status:</strong> ${combinedPatient.maritalStatus?.text || ""}</li>
|
|
@@ -966,7 +986,6 @@ var PatientTemplate = class _PatientTemplate {
|
|
|
966
986
|
}
|
|
967
987
|
const combined = patients[0];
|
|
968
988
|
const allNames = [];
|
|
969
|
-
const allIdentifiers = [];
|
|
970
989
|
const allTelecom = [];
|
|
971
990
|
const allAddresses = [];
|
|
972
991
|
const allCommunication = [];
|
|
@@ -974,9 +993,6 @@ var PatientTemplate = class _PatientTemplate {
|
|
|
974
993
|
if (patient.name) {
|
|
975
994
|
allNames.push(...patient.name);
|
|
976
995
|
}
|
|
977
|
-
if (patient.identifier) {
|
|
978
|
-
allIdentifiers.push(...patient.identifier);
|
|
979
|
-
}
|
|
980
996
|
if (patient.telecom) {
|
|
981
997
|
allTelecom.push(...patient.telecom);
|
|
982
998
|
}
|
|
@@ -1003,7 +1019,6 @@ var PatientTemplate = class _PatientTemplate {
|
|
|
1003
1019
|
}
|
|
1004
1020
|
});
|
|
1005
1021
|
combined.name = allNames;
|
|
1006
|
-
combined.identifier = allIdentifiers;
|
|
1007
1022
|
combined.telecom = allTelecom;
|
|
1008
1023
|
combined.address = allAddresses;
|
|
1009
1024
|
combined.communication = allCommunication;
|
|
@@ -1029,21 +1044,6 @@ var PatientTemplate = class _PatientTemplate {
|
|
|
1029
1044
|
});
|
|
1030
1045
|
return Array.from(uniqueNames).map((nameText) => `<ul><li>${nameText}</li></ul>`).join("");
|
|
1031
1046
|
}
|
|
1032
|
-
/**
|
|
1033
|
-
* Renders patient identifiers as HTML list items
|
|
1034
|
-
* @param patient - Patient resources
|
|
1035
|
-
* @returns HTML string of list items
|
|
1036
|
-
*/
|
|
1037
|
-
static renderIdentifiers(patient) {
|
|
1038
|
-
if (!patient.identifier || patient.identifier.length === 0) {
|
|
1039
|
-
return "";
|
|
1040
|
-
}
|
|
1041
|
-
return patient.identifier.map((id) => {
|
|
1042
|
-
const system = id.system || "";
|
|
1043
|
-
const value = id.value || "";
|
|
1044
|
-
return `<ul><li>${system}: ${value}</li></ul>`;
|
|
1045
|
-
}).join("");
|
|
1046
|
-
}
|
|
1047
1047
|
/**
|
|
1048
1048
|
* Renders patient telecom information grouped by system
|
|
1049
1049
|
* @param patient - Patient resources
|
|
@@ -1145,7 +1145,89 @@ var PatientTemplate = class _PatientTemplate {
|
|
|
1145
1145
|
uniqueAddresses.add(addressText);
|
|
1146
1146
|
}
|
|
1147
1147
|
});
|
|
1148
|
-
|
|
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;
|
|
1149
1231
|
}
|
|
1150
1232
|
/**
|
|
1151
1233
|
* Renders patient deceased status
|
|
@@ -1393,6 +1475,75 @@ var MedicationSummaryTemplate = class _MedicationSummaryTemplate {
|
|
|
1393
1475
|
generateNarrative(resources, timezone) {
|
|
1394
1476
|
return _MedicationSummaryTemplate.generateStaticNarrative(resources, timezone);
|
|
1395
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
|
+
}
|
|
1396
1547
|
/**
|
|
1397
1548
|
* Safely parse a date string and return a valid Date object or null
|
|
1398
1549
|
* @param dateString - The date string to parse
|
|
@@ -1405,55 +1556,6 @@ var MedicationSummaryTemplate = class _MedicationSummaryTemplate {
|
|
|
1405
1556
|
const date = new Date(dateString);
|
|
1406
1557
|
return !isNaN(date.getTime()) ? date : null;
|
|
1407
1558
|
}
|
|
1408
|
-
/**
|
|
1409
|
-
* Determine if a MedicationRequest is active
|
|
1410
|
-
* @param medicationRequest - The MedicationRequest resource
|
|
1411
|
-
* @returns boolean indicating if the medication request is active
|
|
1412
|
-
*/
|
|
1413
|
-
static isActiveMedicationRequest(medicationRequest) {
|
|
1414
|
-
const status = medicationRequest.status?.toLowerCase();
|
|
1415
|
-
if (status === "active" || status === "unknown") {
|
|
1416
|
-
return true;
|
|
1417
|
-
}
|
|
1418
|
-
if (status === "completed" || status === "cancelled" || status === "stopped" || status === "draft") {
|
|
1419
|
-
return false;
|
|
1420
|
-
}
|
|
1421
|
-
const endDate = medicationRequest.dispenseRequest?.validityPeriod?.end;
|
|
1422
|
-
if (!endDate) {
|
|
1423
|
-
return true;
|
|
1424
|
-
}
|
|
1425
|
-
const parsedEndDate = this.parseDate(endDate);
|
|
1426
|
-
if (!parsedEndDate) {
|
|
1427
|
-
return true;
|
|
1428
|
-
}
|
|
1429
|
-
return parsedEndDate.getTime() > Date.now();
|
|
1430
|
-
}
|
|
1431
|
-
/**
|
|
1432
|
-
* Determine if a MedicationStatement is active
|
|
1433
|
-
* @param medicationStatement - The MedicationStatement resource
|
|
1434
|
-
* @returns boolean indicating if the medication statement is active
|
|
1435
|
-
*/
|
|
1436
|
-
static isActiveMedicationStatement(medicationStatement) {
|
|
1437
|
-
const status = medicationStatement.status?.toLowerCase();
|
|
1438
|
-
if (status === "active" || status === "intended" || status === "unknown") {
|
|
1439
|
-
return true;
|
|
1440
|
-
}
|
|
1441
|
-
if (status === "completed" || status === "stopped" || status === "not-taken") {
|
|
1442
|
-
return false;
|
|
1443
|
-
}
|
|
1444
|
-
let endDate;
|
|
1445
|
-
if (medicationStatement.effectivePeriod?.end) {
|
|
1446
|
-
endDate = medicationStatement.effectivePeriod.end;
|
|
1447
|
-
}
|
|
1448
|
-
if (!endDate) {
|
|
1449
|
-
return true;
|
|
1450
|
-
}
|
|
1451
|
-
const parsedEndDate = this.parseDate(endDate);
|
|
1452
|
-
if (!parsedEndDate) {
|
|
1453
|
-
return true;
|
|
1454
|
-
}
|
|
1455
|
-
return parsedEndDate.getTime() > Date.now();
|
|
1456
|
-
}
|
|
1457
1559
|
/**
|
|
1458
1560
|
* Internal static implementation that actually generates the narrative
|
|
1459
1561
|
* @param resources - FHIR Medication resources
|
|
@@ -1467,20 +1569,11 @@ var MedicationSummaryTemplate = class _MedicationSummaryTemplate {
|
|
|
1467
1569
|
const medicationRequests = this.getMedicationRequests(templateUtilities, resources);
|
|
1468
1570
|
const medicationStatements = this.getMedicationStatements(templateUtilities, resources);
|
|
1469
1571
|
const allActiveMedications = [];
|
|
1470
|
-
const allInactiveMedications = [];
|
|
1471
1572
|
medicationRequests.forEach((mr) => {
|
|
1472
|
-
|
|
1473
|
-
allActiveMedications.push({ type: "request", resource: mr.resource, extension: mr.extension });
|
|
1474
|
-
} else {
|
|
1475
|
-
allInactiveMedications.push({ type: "request", resource: mr.resource, extension: mr.extension });
|
|
1476
|
-
}
|
|
1573
|
+
allActiveMedications.push({ type: "request", resource: mr.resource, extension: mr.extension });
|
|
1477
1574
|
});
|
|
1478
1575
|
medicationStatements.forEach((ms) => {
|
|
1479
|
-
|
|
1480
|
-
allActiveMedications.push({ type: "statement", resource: ms.resource, extension: ms.extension });
|
|
1481
|
-
} else {
|
|
1482
|
-
allInactiveMedications.push({ type: "statement", resource: ms.resource, extension: ms.extension });
|
|
1483
|
-
}
|
|
1576
|
+
allActiveMedications.push({ type: "statement", resource: ms.resource, extension: ms.extension });
|
|
1484
1577
|
});
|
|
1485
1578
|
const sortMedications = (medications) => {
|
|
1486
1579
|
medications.sort((a, b) => {
|
|
@@ -1510,11 +1603,7 @@ var MedicationSummaryTemplate = class _MedicationSummaryTemplate {
|
|
|
1510
1603
|
};
|
|
1511
1604
|
if (allActiveMedications.length > 0) {
|
|
1512
1605
|
sortMedications(allActiveMedications);
|
|
1513
|
-
html += this.renderCombinedMedications(templateUtilities, allActiveMedications
|
|
1514
|
-
}
|
|
1515
|
-
if (allInactiveMedications.length > 0) {
|
|
1516
|
-
sortMedications(allInactiveMedications);
|
|
1517
|
-
html += this.renderCombinedMedications(templateUtilities, allInactiveMedications, false);
|
|
1606
|
+
html += this.renderCombinedMedications(templateUtilities, allActiveMedications);
|
|
1518
1607
|
}
|
|
1519
1608
|
return html;
|
|
1520
1609
|
}
|
|
@@ -1552,12 +1641,10 @@ var MedicationSummaryTemplate = class _MedicationSummaryTemplate {
|
|
|
1552
1641
|
* Render HTML table for combined MedicationRequest and MedicationStatement resources
|
|
1553
1642
|
* @param templateUtilities - Instance of TemplateUtilities for utility functions
|
|
1554
1643
|
* @param medications - Array of combined medication resources
|
|
1555
|
-
* @param sectionTitle - Title for the section
|
|
1556
1644
|
* @returns HTML string for rendering
|
|
1557
1645
|
*/
|
|
1558
|
-
static renderCombinedMedications(templateUtilities, medications
|
|
1646
|
+
static renderCombinedMedications(templateUtilities, medications) {
|
|
1559
1647
|
let html = `
|
|
1560
|
-
<h3>${isActiveSection ? "Active Medications" : "Inactive Medications"}</h3>
|
|
1561
1648
|
<table>
|
|
1562
1649
|
<thead>
|
|
1563
1650
|
<tr>
|
|
@@ -1566,9 +1653,7 @@ var MedicationSummaryTemplate = class _MedicationSummaryTemplate {
|
|
|
1566
1653
|
<th>Sig</th>
|
|
1567
1654
|
<th>Dispense Quantity</th>
|
|
1568
1655
|
<th>Refills</th>
|
|
1569
|
-
<th>Start Date</th
|
|
1570
|
-
<th>End Date</th>`}
|
|
1571
|
-
<th>Status</th>
|
|
1656
|
+
<th>Start Date</th>
|
|
1572
1657
|
</tr>
|
|
1573
1658
|
</thead>
|
|
1574
1659
|
<tbody>`;
|
|
@@ -1580,12 +1665,9 @@ var MedicationSummaryTemplate = class _MedicationSummaryTemplate {
|
|
|
1580
1665
|
let dispenseQuantity = "-";
|
|
1581
1666
|
let refills = "-";
|
|
1582
1667
|
let startDate = "-";
|
|
1583
|
-
let endDate = "-";
|
|
1584
|
-
let status;
|
|
1585
1668
|
if (medication.type === "request") {
|
|
1586
1669
|
const mr = medication.resource;
|
|
1587
1670
|
type = "Request";
|
|
1588
|
-
status = mr.status ? String(mr.status) : "-";
|
|
1589
1671
|
medicationName = templateUtilities.getMedicationName(
|
|
1590
1672
|
mr.medicationReference || mr.medicationCodeableConcept
|
|
1591
1673
|
);
|
|
@@ -1599,14 +1681,12 @@ var MedicationSummaryTemplate = class _MedicationSummaryTemplate {
|
|
|
1599
1681
|
refills = mr.dispenseRequest?.numberOfRepeatsAllowed?.toString() || "-";
|
|
1600
1682
|
if (mr.dispenseRequest?.validityPeriod) {
|
|
1601
1683
|
startDate = mr.dispenseRequest.validityPeriod.start || "-";
|
|
1602
|
-
endDate = mr.dispenseRequest.validityPeriod.end || "-";
|
|
1603
1684
|
} else {
|
|
1604
1685
|
startDate = mr.authoredOn || "-";
|
|
1605
1686
|
}
|
|
1606
1687
|
} else {
|
|
1607
1688
|
const ms = medication.resource;
|
|
1608
1689
|
type = "Statement";
|
|
1609
|
-
status = ms.status ? String(ms.status) : "-";
|
|
1610
1690
|
medicationName = templateUtilities.getMedicationName(
|
|
1611
1691
|
ms.medicationReference || ms.medicationCodeableConcept
|
|
1612
1692
|
);
|
|
@@ -1615,7 +1695,6 @@ var MedicationSummaryTemplate = class _MedicationSummaryTemplate {
|
|
|
1615
1695
|
startDate = ms.effectiveDateTime;
|
|
1616
1696
|
} else if (ms.effectivePeriod) {
|
|
1617
1697
|
startDate = ms.effectivePeriod.start || "-";
|
|
1618
|
-
endDate = ms.effectivePeriod.end || "-";
|
|
1619
1698
|
}
|
|
1620
1699
|
}
|
|
1621
1700
|
html += `
|
|
@@ -1625,9 +1704,7 @@ var MedicationSummaryTemplate = class _MedicationSummaryTemplate {
|
|
|
1625
1704
|
<td>${sig}</td>
|
|
1626
1705
|
<td>${dispenseQuantity}</td>
|
|
1627
1706
|
<td>${refills}</td>
|
|
1628
|
-
<td>${startDate}</td
|
|
1629
|
-
<td>${endDate}</td>`}
|
|
1630
|
-
<td>${status}</td>
|
|
1707
|
+
<td>${startDate}</td>
|
|
1631
1708
|
</tr>`;
|
|
1632
1709
|
}
|
|
1633
1710
|
html += `
|
|
@@ -1768,6 +1845,7 @@ var ProblemListTemplate = class _ProblemListTemplate {
|
|
|
1768
1845
|
* @param timezone - Optional timezone to use for date formatting (e.g., 'America/New_York', 'Europe/London')
|
|
1769
1846
|
* @returns HTML string for rendering
|
|
1770
1847
|
*/
|
|
1848
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
1771
1849
|
static generateStaticNarrative(resources, timezone) {
|
|
1772
1850
|
const templateUtilities = new TemplateUtilities(resources);
|
|
1773
1851
|
let html = ``;
|
|
@@ -1784,7 +1862,6 @@ var ProblemListTemplate = class _ProblemListTemplate {
|
|
|
1784
1862
|
<th>Problem</th>
|
|
1785
1863
|
<th>Onset Date</th>
|
|
1786
1864
|
<th>Recorded Date</th>
|
|
1787
|
-
<th>Notes</th>
|
|
1788
1865
|
</tr>
|
|
1789
1866
|
</thead>
|
|
1790
1867
|
<tbody>`;
|
|
@@ -1793,7 +1870,6 @@ var ProblemListTemplate = class _ProblemListTemplate {
|
|
|
1793
1870
|
<td class="Name">${templateUtilities.codeableConcept(cond.code)}</td>
|
|
1794
1871
|
<td class="OnsetDate">${templateUtilities.renderDate(cond.onsetDateTime)}</td>
|
|
1795
1872
|
<td class="RecordedDate">${templateUtilities.renderDate(cond.recordedDate)}</td>
|
|
1796
|
-
<td class="Notes">${templateUtilities.renderNotes(cond.note, timezone)}</td>
|
|
1797
1873
|
</tr>`;
|
|
1798
1874
|
}
|
|
1799
1875
|
html += `</tbody>
|
|
@@ -1802,13 +1878,6 @@ var ProblemListTemplate = class _ProblemListTemplate {
|
|
|
1802
1878
|
}
|
|
1803
1879
|
};
|
|
1804
1880
|
|
|
1805
|
-
// src/structures/ips_section_constants.ts
|
|
1806
|
-
var VITAL_SIGNS_SUMMARY_COMPONENT_MAP = {
|
|
1807
|
-
"Systolic Blood Pressure": "valueRatio.numerator.value",
|
|
1808
|
-
"Diastolic Blood Pressure": "valueRatio.denominator.value",
|
|
1809
|
-
"Default": "valueString"
|
|
1810
|
-
};
|
|
1811
|
-
|
|
1812
1881
|
// src/narratives/templates/typescript/VitalSignsTemplate.ts
|
|
1813
1882
|
var VitalSignsTemplate = class _VitalSignsTemplate {
|
|
1814
1883
|
/**
|
|
@@ -2228,6 +2297,7 @@ var PastHistoryOfIllnessTemplate = class {
|
|
|
2228
2297
|
* @param timezone - Optional timezone to use for date formatting (e.g., 'America/New_York', 'Europe/London')
|
|
2229
2298
|
* @returns HTML string for rendering
|
|
2230
2299
|
*/
|
|
2300
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
2231
2301
|
generateNarrative(resources, timezone) {
|
|
2232
2302
|
const templateUtilities = new TemplateUtilities(resources);
|
|
2233
2303
|
let html = ``;
|
|
@@ -2245,7 +2315,6 @@ var PastHistoryOfIllnessTemplate = class {
|
|
|
2245
2315
|
<th>Onset Date</th>
|
|
2246
2316
|
<th>Recorded Date</th>
|
|
2247
2317
|
<th>Resolved Date</th>
|
|
2248
|
-
<th>Notes</th>
|
|
2249
2318
|
</tr>
|
|
2250
2319
|
</thead>
|
|
2251
2320
|
<tbody>`;
|
|
@@ -2255,7 +2324,6 @@ var PastHistoryOfIllnessTemplate = class {
|
|
|
2255
2324
|
<td class="OnsetDate">${templateUtilities.renderDate(cond.onsetDateTime)}</td>
|
|
2256
2325
|
<td class="RecordedDate">${templateUtilities.renderDate(cond.recordedDate)}</td>
|
|
2257
2326
|
<td class="ResolvedDate">${templateUtilities.renderDate(cond.abatementDateTime)}</td>
|
|
2258
|
-
<td class="Notes">${templateUtilities.renderNotes(cond.note, timezone)}</td>
|
|
2259
2327
|
</tr>`;
|
|
2260
2328
|
}
|
|
2261
2329
|
html += `</tbody>
|
|
@@ -2408,7 +2476,6 @@ var FunctionalStatusTemplate = class _FunctionalStatusTemplate {
|
|
|
2408
2476
|
<th>Problem</th>
|
|
2409
2477
|
<th>Onset Date</th>
|
|
2410
2478
|
<th>Recorded Date</th>
|
|
2411
|
-
<th>Notes</th>
|
|
2412
2479
|
</tr>
|
|
2413
2480
|
</thead>
|
|
2414
2481
|
<tbody>`;
|
|
@@ -2417,7 +2484,6 @@ var FunctionalStatusTemplate = class _FunctionalStatusTemplate {
|
|
|
2417
2484
|
<td class="Name">${templateUtilities.codeableConcept(cond.code)}</td>
|
|
2418
2485
|
<td class="OnsetDate">${templateUtilities.renderDate(cond.onsetDateTime)}</td>
|
|
2419
2486
|
<td class="RecordedDate">${templateUtilities.renderDate(cond.recordedDate)}</td>
|
|
2420
|
-
<td class="Notes">${templateUtilities.renderNotes(cond.note, timezone, { styled: true, warning: true })}</td>
|
|
2421
2487
|
</tr>`;
|
|
2422
2488
|
}
|
|
2423
2489
|
html += `</tbody>
|
|
@@ -2433,7 +2499,6 @@ var FunctionalStatusTemplate = class _FunctionalStatusTemplate {
|
|
|
2433
2499
|
<th>Description</th>
|
|
2434
2500
|
<th>Summary</th>
|
|
2435
2501
|
<th>Findings</th>
|
|
2436
|
-
<th>Notes</th>
|
|
2437
2502
|
</tr>
|
|
2438
2503
|
</thead>
|
|
2439
2504
|
<tbody>`;
|
|
@@ -2462,7 +2527,6 @@ var FunctionalStatusTemplate = class _FunctionalStatusTemplate {
|
|
|
2462
2527
|
}
|
|
2463
2528
|
findingsHtml += "</ul>";
|
|
2464
2529
|
}
|
|
2465
|
-
const notes = templateUtilities.renderNotes(impression.note, timezone);
|
|
2466
2530
|
html += `
|
|
2467
2531
|
<tr id="${templateUtilities.narrativeLinkId(impression)}">
|
|
2468
2532
|
<td>${formattedDate}</td>
|
|
@@ -2470,7 +2534,6 @@ var FunctionalStatusTemplate = class _FunctionalStatusTemplate {
|
|
|
2470
2534
|
<td>${impression.description || ""}</td>
|
|
2471
2535
|
<td>${impression.summary || ""}</td>
|
|
2472
2536
|
<td>${findingsHtml}</td>
|
|
2473
|
-
<td>${notes}</td>
|
|
2474
2537
|
</tr>`;
|
|
2475
2538
|
}
|
|
2476
2539
|
html += `</tbody>
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@imranq2/fhirpatientsummary",
|
|
3
|
-
"version": "1.0.
|
|
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",
|
|
@@ -28,7 +28,7 @@
|
|
|
28
28
|
"prebuild": "npm run clean:dist",
|
|
29
29
|
"pretest": "npm run clean:coverage",
|
|
30
30
|
"cm": "cz",
|
|
31
|
-
"lint": "eslint ./src/ --ext .ts --fix",
|
|
31
|
+
"lint": "eslint ./src/ ./tests/ --ext .ts --fix",
|
|
32
32
|
"prepare": "husky",
|
|
33
33
|
"semantic-release": "semantic-release",
|
|
34
34
|
"test:watch": "jest --watch",
|
|
@@ -36,7 +36,8 @@
|
|
|
36
36
|
"typecheck": "tsc --noEmit",
|
|
37
37
|
"check:cjs-import": "node tests/build/cjs-import-check.cjs",
|
|
38
38
|
"check:esm-import": "node --experimental-vm-modules tests/build/esm-import-check.mjs",
|
|
39
|
-
"check:ts-import": "ts-node --project tsconfig.json tests/build/ts-import-check.ts"
|
|
39
|
+
"check:ts-import": "ts-node --project tsconfig.json tests/build/ts-import-check.ts",
|
|
40
|
+
"split:bundle": "node tests/full_record/split_bundle.cjs"
|
|
40
41
|
},
|
|
41
42
|
"repository": {
|
|
42
43
|
"type": "git",
|
|
@@ -68,34 +69,34 @@
|
|
|
68
69
|
"homepage": "https://github.com/icanbwell/fhir-patient-summary#readme",
|
|
69
70
|
"dependencies": {
|
|
70
71
|
"html-minifier-terser": "^7.2.0",
|
|
71
|
-
"luxon": "^3.
|
|
72
|
-
"turndown": "^7.2.
|
|
72
|
+
"luxon": "^3.7.2",
|
|
73
|
+
"turndown": "^7.2.2"
|
|
73
74
|
},
|
|
74
75
|
"devDependencies": {
|
|
75
|
-
"@eslint/js": "^9.
|
|
76
|
+
"@eslint/js": "^9.39.1",
|
|
76
77
|
"@types/html-minifier-terser": "^7.0.2",
|
|
77
78
|
"@types/jest": "^30.0.0",
|
|
78
79
|
"@types/js-beautify": "^1.14.3",
|
|
79
|
-
"@types/luxon": "^3.
|
|
80
|
-
"@types/node": "^24.
|
|
81
|
-
"@types/turndown": "^5.0.
|
|
80
|
+
"@types/luxon": "^3.7.1",
|
|
81
|
+
"@types/node": "^24.10.1",
|
|
82
|
+
"@types/turndown": "^5.0.6",
|
|
82
83
|
"commitizen": "^4.3.1",
|
|
83
|
-
"conventional-changelog-conventionalcommits": "^
|
|
84
|
-
"eslint": "^9.
|
|
85
|
-
"eslint-config-prettier": "^10.1.
|
|
84
|
+
"conventional-changelog-conventionalcommits": "^9.1.0",
|
|
85
|
+
"eslint": "^9.39.1",
|
|
86
|
+
"eslint-config-prettier": "^10.1.8",
|
|
86
87
|
"eslint-plugin-node": "^11.1.0",
|
|
87
|
-
"eslint-plugin-prettier": "^5.5.
|
|
88
|
+
"eslint-plugin-prettier": "^5.5.4",
|
|
88
89
|
"husky": "^9.1.7",
|
|
89
|
-
"jest": "^30.
|
|
90
|
+
"jest": "^30.2.0",
|
|
90
91
|
"js-beautify": "^1.15.4",
|
|
91
|
-
"lint-staged": "^16.
|
|
92
|
-
"prettier": "^3.
|
|
93
|
-
"semantic-release": "^
|
|
94
|
-
"ts-jest": "^29.4.
|
|
92
|
+
"lint-staged": "^16.2.7",
|
|
93
|
+
"prettier": "^3.7.4",
|
|
94
|
+
"semantic-release": "^25.0.2",
|
|
95
|
+
"ts-jest": "^29.4.6",
|
|
95
96
|
"ts-node": "^10.9.2",
|
|
96
97
|
"tsup": "8.5.1",
|
|
97
|
-
"typescript": "^5.
|
|
98
|
-
"typescript-eslint": "^8.
|
|
98
|
+
"typescript": "^5.9.3",
|
|
99
|
+
"typescript-eslint": "^8.48.1"
|
|
99
100
|
},
|
|
100
101
|
"lint-staged": {
|
|
101
102
|
"src/**/*.{ts,js}": "eslint --cache --cache-location .eslintcache --fix",
|