@imranq2/fhirpatientsummary 1.0.26 → 1.0.27
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 +406 -31
- package/dist/index.js +406 -31
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -115,6 +115,8 @@ var VITAL_SIGNS_SUMMARY_COMPONENT_MAP = {
|
|
|
115
115
|
"Diastolic Blood Pressure": "valueRatio.denominator.value",
|
|
116
116
|
"Default": "valueString"
|
|
117
117
|
};
|
|
118
|
+
var RESULT_SUMMARY_OBSERVATION_CATEGORIES = ["laboratory", "Lab", "LAB"];
|
|
119
|
+
var RESULT_SUMMARY_OBSERVATION_DATE_FILTER = 2 * 365 * 24 * 60 * 60 * 1e3;
|
|
118
120
|
var IPS_SUMMARY_COMPOSITION_TYPE_SYSTEM = "https://fhir.icanbwell.com/4_0_0/CodeSystem/composition/";
|
|
119
121
|
|
|
120
122
|
// src/structures/ips_section_resource_map.ts
|
|
@@ -134,7 +136,7 @@ var IPSSectionResourceFilters = {
|
|
|
134
136
|
// Includes DeviceUseStatement. Device is needed for linked device details
|
|
135
137
|
["MedicalDeviceSection" /* MEDICAL_DEVICES */]: (resource) => ["DeviceUseStatement", "Device"].includes(resource.resourceType),
|
|
136
138
|
// Only include finalized diagnostic reports
|
|
137
|
-
["ResultsSection" /* DIAGNOSTIC_REPORTS */]: (resource) =>
|
|
139
|
+
["ResultsSection" /* DIAGNOSTIC_REPORTS */]: (resource) => resource.resourceType === "Observation" && resource.category?.some((cat) => cat.coding?.some((c) => RESULT_SUMMARY_OBSERVATION_CATEGORIES.includes(c.code))),
|
|
138
140
|
// Only include completed procedures
|
|
139
141
|
["HistoryOfProceduresSection" /* PROCEDURES */]: (resource) => resource.resourceType === "Procedure" && resource.status === "completed",
|
|
140
142
|
// Only include social history Observations
|
|
@@ -156,7 +158,7 @@ var IPSSectionSummaryCompositionFilter = {
|
|
|
156
158
|
["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
159
|
["ImmunizationSection" /* IMMUNIZATIONS */]: (resource) => resource.resourceType === "Composition" && resource.type?.coding?.some((c) => c.system === IPS_SUMMARY_COMPOSITION_TYPE_SYSTEM && c.code === "immunization_summary_document"),
|
|
158
160
|
["MedicationSummarySection" /* MEDICATIONS */]: (resource) => resource.resourceType === "Composition" && resource.type?.coding?.some((c) => c.system === IPS_SUMMARY_COMPOSITION_TYPE_SYSTEM && c.code === "medication_summary_document"),
|
|
159
|
-
[
|
|
161
|
+
// [IPSSections.DIAGNOSTIC_REPORTS]: (resource) => resource.resourceType === 'Composition' && resource.type?.coding?.some((c: any) => c.system === IPS_SUMMARY_COMPOSITION_TYPE_SYSTEM && ["lab_summary_document", "diagnosticreportlab_summary_document"].includes(c.code)),
|
|
160
162
|
["HistoryOfProceduresSection" /* PROCEDURES */]: (resource) => resource.resourceType === "Composition" && resource.type?.coding?.some((c) => c.system === IPS_SUMMARY_COMPOSITION_TYPE_SYSTEM && c.code === "procedure_summary_document")
|
|
161
163
|
};
|
|
162
164
|
var IPSSectionResourceHelper = class {
|
|
@@ -620,9 +622,18 @@ var TemplateUtilities = class {
|
|
|
620
622
|
}
|
|
621
623
|
return status;
|
|
622
624
|
}
|
|
625
|
+
formatFloatValue(value) {
|
|
626
|
+
if (typeof value === "number") {
|
|
627
|
+
return value.toFixed(2).replace(/\.?0+$/, "");
|
|
628
|
+
} else if (typeof value === "string" && !isNaN(Number(value))) {
|
|
629
|
+
return parseFloat(value).toFixed(2).replace(/\.?0+$/, "");
|
|
630
|
+
}
|
|
631
|
+
return value;
|
|
632
|
+
}
|
|
623
633
|
extractObservationSummaryValue(data, timezone) {
|
|
624
634
|
if (data["valueQuantity.value"] !== void 0) {
|
|
625
|
-
|
|
635
|
+
let value = data["valueQuantity.value"];
|
|
636
|
+
value = this.formatFloatValue(value);
|
|
626
637
|
const unit = data["valueQuantity.unit"];
|
|
627
638
|
return unit ? `${value} ${unit}` : `${value}`;
|
|
628
639
|
}
|
|
@@ -639,7 +650,9 @@ var TemplateUtilities = class {
|
|
|
639
650
|
return String(data["valueBoolean"]);
|
|
640
651
|
}
|
|
641
652
|
if (data["valueInteger"] !== void 0) {
|
|
642
|
-
|
|
653
|
+
let value = String(data["valueInteger"]);
|
|
654
|
+
value = this.formatFloatValue(value);
|
|
655
|
+
return value;
|
|
643
656
|
}
|
|
644
657
|
if (data["valueDateTime"] !== void 0) {
|
|
645
658
|
return this.renderTime(data["valueDateTime"], timezone);
|
|
@@ -659,7 +672,8 @@ var TemplateUtilities = class {
|
|
|
659
672
|
return this.renderTime(data["valueTime"], timezone);
|
|
660
673
|
}
|
|
661
674
|
if (data["valueSampledData.origin.value"] !== void 0 || data["valueSampledData.origin.unit"] !== void 0) {
|
|
662
|
-
|
|
675
|
+
let originValue = data["valueSampledData.origin.value"];
|
|
676
|
+
originValue = this.formatFloatValue(originValue);
|
|
663
677
|
const originUnit = data["valueSampledData.origin.unit"];
|
|
664
678
|
let result = "";
|
|
665
679
|
if (originValue !== void 0 && originUnit !== void 0) {
|
|
@@ -669,10 +683,10 @@ var TemplateUtilities = class {
|
|
|
669
683
|
} else if (originUnit !== void 0) {
|
|
670
684
|
result = `${originUnit}`;
|
|
671
685
|
}
|
|
672
|
-
const period = data["valueSampledData.period"];
|
|
673
|
-
const factor = data["valueSampledData.factor"];
|
|
674
|
-
const lowerLimit = data["valueSampledData.lowerLimit"];
|
|
675
|
-
const upperLimit = data["valueSampledData.upperLimit"];
|
|
686
|
+
const period = this.formatFloatValue(data["valueSampledData.period"]);
|
|
687
|
+
const factor = this.formatFloatValue(data["valueSampledData.factor"]);
|
|
688
|
+
const lowerLimit = this.formatFloatValue(data["valueSampledData.lowerLimit"]);
|
|
689
|
+
const upperLimit = this.formatFloatValue(data["valueSampledData.upperLimit"]);
|
|
676
690
|
const sampledData = data["valueSampledData.data"];
|
|
677
691
|
const extras = [];
|
|
678
692
|
if (period !== void 0) extras.push(`period: ${period}`);
|
|
@@ -708,14 +722,14 @@ var TemplateUtilities = class {
|
|
|
708
722
|
if (data["valueRatio.numerator.value"] !== void 0 || data["valueRatio.denominator.value"] !== void 0) {
|
|
709
723
|
let ratio = "";
|
|
710
724
|
if (data["valueRatio.numerator.value"] !== void 0) {
|
|
711
|
-
ratio += `${data["valueRatio.numerator.value"]}`;
|
|
725
|
+
ratio += `${this.formatFloatValue(data["valueRatio.numerator.value"])}`;
|
|
712
726
|
if (data["valueRatio.numerator.unit"] !== void 0) {
|
|
713
727
|
ratio += ` ${data["valueRatio.numerator.unit"]}`;
|
|
714
728
|
}
|
|
715
729
|
}
|
|
716
730
|
if (data["valueRatio.denominator.value"] !== void 0) {
|
|
717
731
|
ratio += " / ";
|
|
718
|
-
ratio += `${data["valueRatio.denominator.value"]}`;
|
|
732
|
+
ratio += `${this.formatFloatValue(data["valueRatio.denominator.value"])}`;
|
|
719
733
|
if (data["valueRatio.denominator.unit"] !== void 0) {
|
|
720
734
|
ratio += ` ${data["valueRatio.denominator.unit"]}`;
|
|
721
735
|
}
|
|
@@ -969,6 +983,313 @@ var TemplateUtilities = class {
|
|
|
969
983
|
|
|
970
984
|
// src/constants.ts
|
|
971
985
|
var ADDRESS_SIMILARITY_THRESHOLD = 70;
|
|
986
|
+
var LAB_LOINC_MAP = {
|
|
987
|
+
// METABOLIC PANELS (VERY COMMONLY ORDERED)
|
|
988
|
+
"Basic Metabolic Panel": [
|
|
989
|
+
"24321-2",
|
|
990
|
+
// Basic metabolic 2000 panel - Serum or Plasma
|
|
991
|
+
"51990-0"
|
|
992
|
+
// Basic metabolic 2000 panel - Blood
|
|
993
|
+
],
|
|
994
|
+
"Comprehensive Metabolic Panel": [
|
|
995
|
+
"24323-8"
|
|
996
|
+
// Comprehensive metabolic 2000 panel - Serum or Plasma
|
|
997
|
+
],
|
|
998
|
+
// CBC COMPONENTS
|
|
999
|
+
Hemoglobin: [
|
|
1000
|
+
"718-7"
|
|
1001
|
+
// Hemoglobin [Mass/volume] in Blood
|
|
1002
|
+
],
|
|
1003
|
+
Hematocrit: [
|
|
1004
|
+
"4544-3"
|
|
1005
|
+
// Hematocrit [Volume Fraction] of Blood by Automated count
|
|
1006
|
+
],
|
|
1007
|
+
"White Blood Cell Count": [
|
|
1008
|
+
"6690-2"
|
|
1009
|
+
// Leukocytes [///volume] in Blood by Automated count
|
|
1010
|
+
],
|
|
1011
|
+
"Platelet Count": [
|
|
1012
|
+
"777-3"
|
|
1013
|
+
// Platelets [///volume] in Blood by Automated count
|
|
1014
|
+
],
|
|
1015
|
+
"Complete Blood Count": [
|
|
1016
|
+
"58410-2",
|
|
1017
|
+
// CBC panel - Blood by Automated count
|
|
1018
|
+
"57021-8",
|
|
1019
|
+
// CBC W Auto Differential panel - Blood
|
|
1020
|
+
"69738-3"
|
|
1021
|
+
// CBC W Auto Differential panel - Blood by Automated count
|
|
1022
|
+
],
|
|
1023
|
+
// CHEMISTRY - GLUCOSE
|
|
1024
|
+
Glucose: [
|
|
1025
|
+
"2345-7",
|
|
1026
|
+
// Glucose [Mass/volume] in Serum or Plasma
|
|
1027
|
+
"1558-6",
|
|
1028
|
+
// Fasting glucose [Mass/volume] in Serum or Plasma
|
|
1029
|
+
"2339-0"
|
|
1030
|
+
// Glucose [Mass/volume] in Blood
|
|
1031
|
+
],
|
|
1032
|
+
// RENAL FUNCTION
|
|
1033
|
+
Creatinine: [
|
|
1034
|
+
"2160-0"
|
|
1035
|
+
// Creatinine [Mass/volume] in Serum or Plasma
|
|
1036
|
+
],
|
|
1037
|
+
"Blood Urea Nitrogen": [
|
|
1038
|
+
"3094-0",
|
|
1039
|
+
// Urea nitrogen [Mass/volume] in Serum or Plasma
|
|
1040
|
+
"6299-2"
|
|
1041
|
+
// Urea nitrogen [Mass/volume] in Blood
|
|
1042
|
+
],
|
|
1043
|
+
// ELECTROLYTES
|
|
1044
|
+
Sodium: [
|
|
1045
|
+
"2951-2"
|
|
1046
|
+
// Sodium [Moles/volume] in Serum or Plasma
|
|
1047
|
+
],
|
|
1048
|
+
Potassium: [
|
|
1049
|
+
"2823-3"
|
|
1050
|
+
// Potassium [Moles/volume] in Serum or Plasma
|
|
1051
|
+
],
|
|
1052
|
+
Chloride: [
|
|
1053
|
+
"2075-0"
|
|
1054
|
+
// Chloride [Moles/volume] in Serum or Plasma
|
|
1055
|
+
],
|
|
1056
|
+
Calcium: [
|
|
1057
|
+
"17861-6",
|
|
1058
|
+
// Calcium [Mass/volume] in Serum or Plasma
|
|
1059
|
+
"1994-3"
|
|
1060
|
+
// Calcium.ionized [Moles/volume] in Serum or Plasma
|
|
1061
|
+
],
|
|
1062
|
+
Magnesium: [
|
|
1063
|
+
"19123-9"
|
|
1064
|
+
// Magnesium [Mass/volume] in Serum or Plasma
|
|
1065
|
+
],
|
|
1066
|
+
Phosphate: [
|
|
1067
|
+
"14879-1"
|
|
1068
|
+
// Phosphate [Mass/volume] in Serum or Plasma
|
|
1069
|
+
],
|
|
1070
|
+
// PROTEINS
|
|
1071
|
+
Albumin: [
|
|
1072
|
+
"1751-7"
|
|
1073
|
+
// Albumin [Mass/volume] in Serum or Plasma
|
|
1074
|
+
],
|
|
1075
|
+
"Total Protein": [
|
|
1076
|
+
"2885-2"
|
|
1077
|
+
// Protein [Mass/volume] in Serum or Plasma
|
|
1078
|
+
],
|
|
1079
|
+
// LIVER FUNCTION
|
|
1080
|
+
Bilirubin: [
|
|
1081
|
+
"1975-2",
|
|
1082
|
+
// Bilirubin.total [Mass/volume] in Serum or Plasma
|
|
1083
|
+
"1968-7",
|
|
1084
|
+
// Bilirubin.direct [Mass/volume] in Serum or Plasma
|
|
1085
|
+
"1971-1"
|
|
1086
|
+
// Bilirubin.indirect [Mass/volume] in Serum or Plasma
|
|
1087
|
+
],
|
|
1088
|
+
"Alkaline Phosphatase": [
|
|
1089
|
+
"6768-6"
|
|
1090
|
+
// Alkaline phosphatase [Enzymatic activity/volume] in Serum or Plasma
|
|
1091
|
+
],
|
|
1092
|
+
AST: [
|
|
1093
|
+
"1920-8"
|
|
1094
|
+
// Aspartate aminotransferase [Enzymatic activity/volume] in Serum or Plasma
|
|
1095
|
+
],
|
|
1096
|
+
ALT: [
|
|
1097
|
+
"1742-6"
|
|
1098
|
+
// Alanine aminotransferase [Enzymatic activity/volume] in Serum or Plasma
|
|
1099
|
+
],
|
|
1100
|
+
GGT: [
|
|
1101
|
+
"2324-2"
|
|
1102
|
+
// Gamma glutamyl transferase [Enzymatic activity/volume] in Serum or Plasma
|
|
1103
|
+
],
|
|
1104
|
+
// ENDOCRINE
|
|
1105
|
+
TSH: [
|
|
1106
|
+
"3016-3"
|
|
1107
|
+
// Thyrotropin [Units/volume] in Serum or Plasma
|
|
1108
|
+
],
|
|
1109
|
+
"Free T4": [
|
|
1110
|
+
"3024-7"
|
|
1111
|
+
// Thyroxine (T4) free [Mass/volume] in Serum or Plasma
|
|
1112
|
+
],
|
|
1113
|
+
"Total T4": [
|
|
1114
|
+
"3026-2"
|
|
1115
|
+
// Thyroxine (T4) [Mass/volume] in Serum or Plasma
|
|
1116
|
+
],
|
|
1117
|
+
"Free T3": [
|
|
1118
|
+
"3051-0"
|
|
1119
|
+
// Triiodothyronine (T3) free [Mass/volume] in Serum or Plasma
|
|
1120
|
+
],
|
|
1121
|
+
"Total T3": [
|
|
1122
|
+
"3053-6"
|
|
1123
|
+
// Triiodothyronine (T3) [Mass/volume] in Serum or Plasma
|
|
1124
|
+
],
|
|
1125
|
+
HbA1c: [
|
|
1126
|
+
"4548-4",
|
|
1127
|
+
// Hemoglobin A1c/Hemoglobin.total in Blood
|
|
1128
|
+
"17856-6"
|
|
1129
|
+
// Hemoglobin A1c/Hemoglobin.total in Blood by HPLC
|
|
1130
|
+
],
|
|
1131
|
+
// LIPID PANEL
|
|
1132
|
+
"Lipid Panel": [
|
|
1133
|
+
"24331-1",
|
|
1134
|
+
// Lipid 1996 panel - Serum or Plasma
|
|
1135
|
+
"57698-3"
|
|
1136
|
+
// Lipid panel with direct LDL - Serum or Plasma
|
|
1137
|
+
],
|
|
1138
|
+
"Cholesterol Total": [
|
|
1139
|
+
"2093-3"
|
|
1140
|
+
// Cholesterol [Mass/volume] in Serum or Plasma
|
|
1141
|
+
],
|
|
1142
|
+
"HDL Cholesterol": [
|
|
1143
|
+
"2085-9"
|
|
1144
|
+
// Cholesterol in HDL [Mass/volume] in Serum or Plasma
|
|
1145
|
+
],
|
|
1146
|
+
"LDL Cholesterol": [
|
|
1147
|
+
"13457-7",
|
|
1148
|
+
// Cholesterol in LDL [Mass/volume] in Serum or Plasma by calculation
|
|
1149
|
+
"18262-6"
|
|
1150
|
+
// Cholesterol in LDL [Mass/volume] in Serum or Plasma by Direct assay
|
|
1151
|
+
],
|
|
1152
|
+
Triglycerides: [
|
|
1153
|
+
"2571-8"
|
|
1154
|
+
// Triglyceride [Mass/volume] in Serum or Plasma
|
|
1155
|
+
],
|
|
1156
|
+
// COAGULATION STUDIES (COMMONLY MISSING!)
|
|
1157
|
+
PT: [
|
|
1158
|
+
"5902-2"
|
|
1159
|
+
// Prothrombin time (PT)
|
|
1160
|
+
],
|
|
1161
|
+
INR: [
|
|
1162
|
+
"6301-6"
|
|
1163
|
+
// INR in Platelet poor plasma by Coagulation assay
|
|
1164
|
+
],
|
|
1165
|
+
PTT: [
|
|
1166
|
+
"3173-2",
|
|
1167
|
+
// aPTT in Blood by Coagulation assay
|
|
1168
|
+
"14979-9"
|
|
1169
|
+
// aPTT in Platelet poor plasma by Coagulation assay
|
|
1170
|
+
],
|
|
1171
|
+
Fibrinogen: [
|
|
1172
|
+
"3255-7"
|
|
1173
|
+
// Fibrinogen [Mass/volume] in Platelet poor plasma by Coagulation assay
|
|
1174
|
+
],
|
|
1175
|
+
"D-Dimer": [
|
|
1176
|
+
"48065-7",
|
|
1177
|
+
// D-dimer FEU [Mass/volume] in Platelet poor plasma
|
|
1178
|
+
"48066-5"
|
|
1179
|
+
// D-dimer DDU [Mass/volume] in Platelet poor plasma
|
|
1180
|
+
],
|
|
1181
|
+
// CARDIAC MARKERS (CRITICAL FOR ER!)
|
|
1182
|
+
"Troponin I": [
|
|
1183
|
+
"10839-9",
|
|
1184
|
+
// Troponin I.cardiac [Mass/volume] in Serum or Plasma
|
|
1185
|
+
"42757-5",
|
|
1186
|
+
// Troponin I.cardiac [Mass/volume] in Blood
|
|
1187
|
+
"89579-7"
|
|
1188
|
+
// Troponin I.cardiac [Mass/volume] in Serum or Plasma by High sensitivity method
|
|
1189
|
+
],
|
|
1190
|
+
"Troponin T": [
|
|
1191
|
+
"6598-7",
|
|
1192
|
+
// Troponin T.cardiac [Mass/volume] in Serum or Plasma
|
|
1193
|
+
"48425-3"
|
|
1194
|
+
// Troponin T.cardiac [Mass/volume] in Serum or Plasma by High sensitivity method
|
|
1195
|
+
],
|
|
1196
|
+
BNP: [
|
|
1197
|
+
"30934-4"
|
|
1198
|
+
// BNP [Mass/volume] in Serum or Plasma
|
|
1199
|
+
],
|
|
1200
|
+
"NT-proBNP": [
|
|
1201
|
+
"33762-6"
|
|
1202
|
+
// NT-proBNP [Mass/volume] in Serum or Plasma
|
|
1203
|
+
],
|
|
1204
|
+
"CK-MB": [
|
|
1205
|
+
"13969-1"
|
|
1206
|
+
// Creatine kinase.MB [Mass/volume] in Serum or Plasma
|
|
1207
|
+
],
|
|
1208
|
+
// INFLAMMATORY MARKERS
|
|
1209
|
+
CRP: [
|
|
1210
|
+
"1988-5",
|
|
1211
|
+
// C reactive protein [Mass/volume] in Serum or Plasma
|
|
1212
|
+
"30522-7"
|
|
1213
|
+
// C reactive protein [Mass/volume] in Serum or Plasma by High sensitivity method
|
|
1214
|
+
],
|
|
1215
|
+
ESR: [
|
|
1216
|
+
"30341-2",
|
|
1217
|
+
// Erythrocyte sedimentation rate by Westergren method
|
|
1218
|
+
"4537-7"
|
|
1219
|
+
// Erythrocyte sedimentation rate
|
|
1220
|
+
],
|
|
1221
|
+
// VITAMINS & MINERALS (VERY HIGH VOLUME!)
|
|
1222
|
+
"Vitamin D": [
|
|
1223
|
+
"1990-1",
|
|
1224
|
+
// Vitamin D [Mass/volume] in Serum or Plasma (obsolete, but still used)
|
|
1225
|
+
"14635-7",
|
|
1226
|
+
// 25-Hydroxyvitamin D3 [Mass/volume] in Serum or Plasma
|
|
1227
|
+
"62292-8"
|
|
1228
|
+
// 25-Hydroxyvitamin D2+D3 [Mass/volume] in Serum or Plasma
|
|
1229
|
+
],
|
|
1230
|
+
"Vitamin B12": [
|
|
1231
|
+
"2132-9"
|
|
1232
|
+
// Cobalamin (Vitamin B12) [Mass/volume] in Serum or Plasma
|
|
1233
|
+
],
|
|
1234
|
+
Folate: [
|
|
1235
|
+
"2284-8",
|
|
1236
|
+
// Folate [Mass/volume] in Serum or Plasma
|
|
1237
|
+
"15152-2"
|
|
1238
|
+
// Folate [Mass/volume] in Red Blood Cells
|
|
1239
|
+
],
|
|
1240
|
+
Iron: [
|
|
1241
|
+
"2498-4"
|
|
1242
|
+
// Iron [Mass/volume] in Serum or Plasma
|
|
1243
|
+
],
|
|
1244
|
+
Ferritin: [
|
|
1245
|
+
"2276-4"
|
|
1246
|
+
// Ferritin [Mass/volume] in Serum or Plasma
|
|
1247
|
+
],
|
|
1248
|
+
TIBC: [
|
|
1249
|
+
"2500-7"
|
|
1250
|
+
// Iron binding capacity [Mass/volume] in Serum or Plasma
|
|
1251
|
+
],
|
|
1252
|
+
// OTHER COMMON TESTS
|
|
1253
|
+
PSA: [
|
|
1254
|
+
"2857-1",
|
|
1255
|
+
// Prostate specific Ag [Mass/volume] in Serum or Plasma
|
|
1256
|
+
"10886-0"
|
|
1257
|
+
// Prostate specific Ag Free [Mass/volume] in Serum or Plasma
|
|
1258
|
+
],
|
|
1259
|
+
"Uric Acid": [
|
|
1260
|
+
"3084-1"
|
|
1261
|
+
// Urate [Mass/volume] in Serum or Plasma
|
|
1262
|
+
],
|
|
1263
|
+
LDH: [
|
|
1264
|
+
"2532-0",
|
|
1265
|
+
// Lactate dehydrogenase [Enzymatic activity/volume] in Serum or Plasma
|
|
1266
|
+
"14804-9"
|
|
1267
|
+
// Lactate dehydrogenase [Enzymatic activity/volume] in Serum or Plasma by Lactate to pyruvate reaction
|
|
1268
|
+
],
|
|
1269
|
+
Amylase: [
|
|
1270
|
+
"1798-8"
|
|
1271
|
+
// Amylase [Enzymatic activity/volume] in Serum or Plasma
|
|
1272
|
+
],
|
|
1273
|
+
Lipase: [
|
|
1274
|
+
"3040-3"
|
|
1275
|
+
// Lipase [Enzymatic activity/volume] in Serum or Plasma
|
|
1276
|
+
],
|
|
1277
|
+
hCG: [
|
|
1278
|
+
"21198-7",
|
|
1279
|
+
// Choriogonadotropin.beta subunit [Units/volume] in Serum or Plasma
|
|
1280
|
+
"2118-8",
|
|
1281
|
+
// Choriogonadotropin (pregnancy test) [Presence] in Serum or Plasma
|
|
1282
|
+
"2106-3"
|
|
1283
|
+
// Choriogonadotropin (pregnancy test) [Presence] in Urine
|
|
1284
|
+
],
|
|
1285
|
+
// URINALYSIS
|
|
1286
|
+
Urinalysis: [
|
|
1287
|
+
"24357-6",
|
|
1288
|
+
// Urinalysis macro (dipstick) panel - Urine
|
|
1289
|
+
"24356-8"
|
|
1290
|
+
// Urinalysis complete panel - Urine
|
|
1291
|
+
]
|
|
1292
|
+
};
|
|
972
1293
|
|
|
973
1294
|
// src/narratives/templates/typescript/PatientTemplate.ts
|
|
974
1295
|
var PatientTemplate = class _PatientTemplate {
|
|
@@ -2093,6 +2414,12 @@ var MedicalDevicesTemplate = class _MedicalDevicesTemplate {
|
|
|
2093
2414
|
};
|
|
2094
2415
|
|
|
2095
2416
|
// src/narratives/templates/typescript/DiagnosticResultsTemplate.ts
|
|
2417
|
+
var loincToLabName = {};
|
|
2418
|
+
for (const [labName, loincCodes] of Object.entries(LAB_LOINC_MAP)) {
|
|
2419
|
+
for (const code of loincCodes) {
|
|
2420
|
+
loincToLabName[code] = labName;
|
|
2421
|
+
}
|
|
2422
|
+
}
|
|
2096
2423
|
var DiagnosticResultsTemplate = class _DiagnosticResultsTemplate {
|
|
2097
2424
|
/**
|
|
2098
2425
|
* Generate HTML narrative for Diagnostic Results
|
|
@@ -2519,30 +2846,80 @@ var DiagnosticResultsTemplate = class _DiagnosticResultsTemplate {
|
|
|
2519
2846
|
const observations = this.getObservations(resources);
|
|
2520
2847
|
if (observations.length > 0) {
|
|
2521
2848
|
observations.sort((a, b) => {
|
|
2522
|
-
const dateA =
|
|
2523
|
-
const dateB =
|
|
2524
|
-
return dateA && dateB ?
|
|
2849
|
+
const dateA = this.getObservationDate(a);
|
|
2850
|
+
const dateB = this.getObservationDate(b);
|
|
2851
|
+
return dateA && dateB ? dateB.getTime() - dateA.getTime() : 0;
|
|
2525
2852
|
});
|
|
2853
|
+
this.filterObservationForLoincCodes(observations);
|
|
2526
2854
|
html += this.renderObservations(templateUtilities, observations, timezone);
|
|
2527
2855
|
}
|
|
2528
|
-
|
|
2529
|
-
|
|
2530
|
-
diagnosticReports.
|
|
2531
|
-
|
|
2532
|
-
|
|
2533
|
-
|
|
2534
|
-
|
|
2535
|
-
|
|
2856
|
+
if (process.env.ENABLE_DIAGNOSTIC_REPORTS_IN_SUMMARY === "true") {
|
|
2857
|
+
const diagnosticReports = this.getDiagnosticReports(resources);
|
|
2858
|
+
if (diagnosticReports.length > 0) {
|
|
2859
|
+
diagnosticReports.sort((a, b) => {
|
|
2860
|
+
const dateA = a.issued;
|
|
2861
|
+
const dateB = b.issued;
|
|
2862
|
+
return dateA && dateB ? new Date(dateB).getTime() - new Date(dateA).getTime() : 0;
|
|
2863
|
+
});
|
|
2864
|
+
html += this.renderDiagnosticReports(templateUtilities, diagnosticReports, timezone);
|
|
2865
|
+
}
|
|
2536
2866
|
}
|
|
2537
2867
|
return html;
|
|
2538
2868
|
}
|
|
2869
|
+
static filterObservationForLoincCodes(observations) {
|
|
2870
|
+
const labsAdded = /* @__PURE__ */ new Set();
|
|
2871
|
+
const filteredObservations = [];
|
|
2872
|
+
for (const obs of observations) {
|
|
2873
|
+
const loincCode = this.getObservationLoincCode(obs);
|
|
2874
|
+
if (loincCode && loincToLabName[loincCode]) {
|
|
2875
|
+
const labName = loincToLabName[loincCode];
|
|
2876
|
+
if (!labsAdded.has(labName)) {
|
|
2877
|
+
labsAdded.add(labName);
|
|
2878
|
+
filteredObservations.push(obs);
|
|
2879
|
+
}
|
|
2880
|
+
}
|
|
2881
|
+
}
|
|
2882
|
+
observations.length = 0;
|
|
2883
|
+
observations.push(...filteredObservations);
|
|
2884
|
+
}
|
|
2885
|
+
static getObservationLoincCode(obs) {
|
|
2886
|
+
if (obs.code && obs.code.coding) {
|
|
2887
|
+
for (const coding of obs.code.coding) {
|
|
2888
|
+
if (coding.system && coding.system.toLowerCase().includes("loinc") && coding.code) {
|
|
2889
|
+
return coding.code;
|
|
2890
|
+
}
|
|
2891
|
+
}
|
|
2892
|
+
}
|
|
2893
|
+
return void 0;
|
|
2894
|
+
}
|
|
2895
|
+
static getObservationDate(obs) {
|
|
2896
|
+
let obsDate = void 0;
|
|
2897
|
+
if (obs.effectiveDateTime) {
|
|
2898
|
+
obsDate = new Date(obs.effectiveDateTime);
|
|
2899
|
+
} else if (obs.effectivePeriod) {
|
|
2900
|
+
if (obs.effectivePeriod.start) {
|
|
2901
|
+
obsDate = new Date(obs.effectivePeriod.start);
|
|
2902
|
+
} else if (obs.effectivePeriod.end) {
|
|
2903
|
+
obsDate = new Date(obs.effectivePeriod.end);
|
|
2904
|
+
}
|
|
2905
|
+
}
|
|
2906
|
+
return obsDate;
|
|
2907
|
+
}
|
|
2539
2908
|
/**
|
|
2540
2909
|
* Get all Observation resources from the resource array
|
|
2541
2910
|
* @param resources - FHIR resources array
|
|
2542
2911
|
* @returns Array of Observation resources
|
|
2543
2912
|
*/
|
|
2544
2913
|
static getObservations(resources) {
|
|
2545
|
-
return resources.filter((resourceItem) =>
|
|
2914
|
+
return resources.filter((resourceItem) => {
|
|
2915
|
+
if (resourceItem.resourceType === "Observation") {
|
|
2916
|
+
const obsDate = this.getObservationDate(resourceItem);
|
|
2917
|
+
if (obsDate && obsDate >= new Date(Date.now() - RESULT_SUMMARY_OBSERVATION_DATE_FILTER)) {
|
|
2918
|
+
return true;
|
|
2919
|
+
}
|
|
2920
|
+
}
|
|
2921
|
+
return false;
|
|
2922
|
+
}).map((resourceItem) => resourceItem);
|
|
2546
2923
|
}
|
|
2547
2924
|
/**
|
|
2548
2925
|
* Get all DiagnosticReport resources from the resource array
|
|
@@ -2560,17 +2937,18 @@ var DiagnosticResultsTemplate = class _DiagnosticResultsTemplate {
|
|
|
2560
2937
|
* @returns HTML string for rendering
|
|
2561
2938
|
*/
|
|
2562
2939
|
static renderObservations(templateUtilities, observations, timezone) {
|
|
2563
|
-
let html =
|
|
2564
|
-
|
|
2940
|
+
let html = "";
|
|
2941
|
+
if (process.env.ENABLE_DIAGNOSTIC_REPORTS_IN_SUMMARY === "true") {
|
|
2942
|
+
html += `
|
|
2943
|
+
<h3>Observations</h3>`;
|
|
2944
|
+
}
|
|
2945
|
+
html += `
|
|
2565
2946
|
<table>
|
|
2566
2947
|
<thead>
|
|
2567
2948
|
<tr>
|
|
2568
2949
|
<th>Code</th>
|
|
2569
2950
|
<th>Result</th>
|
|
2570
|
-
<th>Unit</th>
|
|
2571
|
-
<th>Interpretation</th>
|
|
2572
2951
|
<th>Reference Range</th>
|
|
2573
|
-
<th>Comments</th>
|
|
2574
2952
|
<th>Date</th>
|
|
2575
2953
|
</tr>
|
|
2576
2954
|
</thead>
|
|
@@ -2584,10 +2962,7 @@ var DiagnosticResultsTemplate = class _DiagnosticResultsTemplate {
|
|
|
2584
2962
|
<tr id="${templateUtilities.narrativeLinkId(obs)}">
|
|
2585
2963
|
<td>${obsCode}</td>
|
|
2586
2964
|
<td>${templateUtilities.extractObservationValue(obs)}</td>
|
|
2587
|
-
<td>${templateUtilities.extractObservationValueUnit(obs)}</td>
|
|
2588
|
-
<td>${templateUtilities.firstFromCodeableConceptList(obs.interpretation)}</td>
|
|
2589
2965
|
<td>${templateUtilities.concatReferenceRange(obs.referenceRange)}</td>
|
|
2590
|
-
<td>${templateUtilities.renderNotes(obs.note, timezone)}</td>
|
|
2591
2966
|
<td>${obs.effectiveDateTime ? templateUtilities.renderTime(obs.effectiveDateTime, timezone) : obs.effectivePeriod ? templateUtilities.renderPeriod(obs.effectivePeriod, timezone) : ""}</td>
|
|
2592
2967
|
</tr>`;
|
|
2593
2968
|
}
|
package/dist/index.js
CHANGED
|
@@ -87,6 +87,8 @@ var VITAL_SIGNS_SUMMARY_COMPONENT_MAP = {
|
|
|
87
87
|
"Diastolic Blood Pressure": "valueRatio.denominator.value",
|
|
88
88
|
"Default": "valueString"
|
|
89
89
|
};
|
|
90
|
+
var RESULT_SUMMARY_OBSERVATION_CATEGORIES = ["laboratory", "Lab", "LAB"];
|
|
91
|
+
var RESULT_SUMMARY_OBSERVATION_DATE_FILTER = 2 * 365 * 24 * 60 * 60 * 1e3;
|
|
90
92
|
var IPS_SUMMARY_COMPOSITION_TYPE_SYSTEM = "https://fhir.icanbwell.com/4_0_0/CodeSystem/composition/";
|
|
91
93
|
|
|
92
94
|
// src/structures/ips_section_resource_map.ts
|
|
@@ -106,7 +108,7 @@ var IPSSectionResourceFilters = {
|
|
|
106
108
|
// Includes DeviceUseStatement. Device is needed for linked device details
|
|
107
109
|
["MedicalDeviceSection" /* MEDICAL_DEVICES */]: (resource) => ["DeviceUseStatement", "Device"].includes(resource.resourceType),
|
|
108
110
|
// Only include finalized diagnostic reports
|
|
109
|
-
["ResultsSection" /* DIAGNOSTIC_REPORTS */]: (resource) =>
|
|
111
|
+
["ResultsSection" /* DIAGNOSTIC_REPORTS */]: (resource) => resource.resourceType === "Observation" && resource.category?.some((cat) => cat.coding?.some((c) => RESULT_SUMMARY_OBSERVATION_CATEGORIES.includes(c.code))),
|
|
110
112
|
// Only include completed procedures
|
|
111
113
|
["HistoryOfProceduresSection" /* PROCEDURES */]: (resource) => resource.resourceType === "Procedure" && resource.status === "completed",
|
|
112
114
|
// Only include social history Observations
|
|
@@ -128,7 +130,7 @@ var IPSSectionSummaryCompositionFilter = {
|
|
|
128
130
|
["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
131
|
["ImmunizationSection" /* IMMUNIZATIONS */]: (resource) => resource.resourceType === "Composition" && resource.type?.coding?.some((c) => c.system === IPS_SUMMARY_COMPOSITION_TYPE_SYSTEM && c.code === "immunization_summary_document"),
|
|
130
132
|
["MedicationSummarySection" /* MEDICATIONS */]: (resource) => resource.resourceType === "Composition" && resource.type?.coding?.some((c) => c.system === IPS_SUMMARY_COMPOSITION_TYPE_SYSTEM && c.code === "medication_summary_document"),
|
|
131
|
-
[
|
|
133
|
+
// [IPSSections.DIAGNOSTIC_REPORTS]: (resource) => resource.resourceType === 'Composition' && resource.type?.coding?.some((c: any) => c.system === IPS_SUMMARY_COMPOSITION_TYPE_SYSTEM && ["lab_summary_document", "diagnosticreportlab_summary_document"].includes(c.code)),
|
|
132
134
|
["HistoryOfProceduresSection" /* PROCEDURES */]: (resource) => resource.resourceType === "Composition" && resource.type?.coding?.some((c) => c.system === IPS_SUMMARY_COMPOSITION_TYPE_SYSTEM && c.code === "procedure_summary_document")
|
|
133
135
|
};
|
|
134
136
|
var IPSSectionResourceHelper = class {
|
|
@@ -592,9 +594,18 @@ var TemplateUtilities = class {
|
|
|
592
594
|
}
|
|
593
595
|
return status;
|
|
594
596
|
}
|
|
597
|
+
formatFloatValue(value) {
|
|
598
|
+
if (typeof value === "number") {
|
|
599
|
+
return value.toFixed(2).replace(/\.?0+$/, "");
|
|
600
|
+
} else if (typeof value === "string" && !isNaN(Number(value))) {
|
|
601
|
+
return parseFloat(value).toFixed(2).replace(/\.?0+$/, "");
|
|
602
|
+
}
|
|
603
|
+
return value;
|
|
604
|
+
}
|
|
595
605
|
extractObservationSummaryValue(data, timezone) {
|
|
596
606
|
if (data["valueQuantity.value"] !== void 0) {
|
|
597
|
-
|
|
607
|
+
let value = data["valueQuantity.value"];
|
|
608
|
+
value = this.formatFloatValue(value);
|
|
598
609
|
const unit = data["valueQuantity.unit"];
|
|
599
610
|
return unit ? `${value} ${unit}` : `${value}`;
|
|
600
611
|
}
|
|
@@ -611,7 +622,9 @@ var TemplateUtilities = class {
|
|
|
611
622
|
return String(data["valueBoolean"]);
|
|
612
623
|
}
|
|
613
624
|
if (data["valueInteger"] !== void 0) {
|
|
614
|
-
|
|
625
|
+
let value = String(data["valueInteger"]);
|
|
626
|
+
value = this.formatFloatValue(value);
|
|
627
|
+
return value;
|
|
615
628
|
}
|
|
616
629
|
if (data["valueDateTime"] !== void 0) {
|
|
617
630
|
return this.renderTime(data["valueDateTime"], timezone);
|
|
@@ -631,7 +644,8 @@ var TemplateUtilities = class {
|
|
|
631
644
|
return this.renderTime(data["valueTime"], timezone);
|
|
632
645
|
}
|
|
633
646
|
if (data["valueSampledData.origin.value"] !== void 0 || data["valueSampledData.origin.unit"] !== void 0) {
|
|
634
|
-
|
|
647
|
+
let originValue = data["valueSampledData.origin.value"];
|
|
648
|
+
originValue = this.formatFloatValue(originValue);
|
|
635
649
|
const originUnit = data["valueSampledData.origin.unit"];
|
|
636
650
|
let result = "";
|
|
637
651
|
if (originValue !== void 0 && originUnit !== void 0) {
|
|
@@ -641,10 +655,10 @@ var TemplateUtilities = class {
|
|
|
641
655
|
} else if (originUnit !== void 0) {
|
|
642
656
|
result = `${originUnit}`;
|
|
643
657
|
}
|
|
644
|
-
const period = data["valueSampledData.period"];
|
|
645
|
-
const factor = data["valueSampledData.factor"];
|
|
646
|
-
const lowerLimit = data["valueSampledData.lowerLimit"];
|
|
647
|
-
const upperLimit = data["valueSampledData.upperLimit"];
|
|
658
|
+
const period = this.formatFloatValue(data["valueSampledData.period"]);
|
|
659
|
+
const factor = this.formatFloatValue(data["valueSampledData.factor"]);
|
|
660
|
+
const lowerLimit = this.formatFloatValue(data["valueSampledData.lowerLimit"]);
|
|
661
|
+
const upperLimit = this.formatFloatValue(data["valueSampledData.upperLimit"]);
|
|
648
662
|
const sampledData = data["valueSampledData.data"];
|
|
649
663
|
const extras = [];
|
|
650
664
|
if (period !== void 0) extras.push(`period: ${period}`);
|
|
@@ -680,14 +694,14 @@ var TemplateUtilities = class {
|
|
|
680
694
|
if (data["valueRatio.numerator.value"] !== void 0 || data["valueRatio.denominator.value"] !== void 0) {
|
|
681
695
|
let ratio = "";
|
|
682
696
|
if (data["valueRatio.numerator.value"] !== void 0) {
|
|
683
|
-
ratio += `${data["valueRatio.numerator.value"]}`;
|
|
697
|
+
ratio += `${this.formatFloatValue(data["valueRatio.numerator.value"])}`;
|
|
684
698
|
if (data["valueRatio.numerator.unit"] !== void 0) {
|
|
685
699
|
ratio += ` ${data["valueRatio.numerator.unit"]}`;
|
|
686
700
|
}
|
|
687
701
|
}
|
|
688
702
|
if (data["valueRatio.denominator.value"] !== void 0) {
|
|
689
703
|
ratio += " / ";
|
|
690
|
-
ratio += `${data["valueRatio.denominator.value"]}`;
|
|
704
|
+
ratio += `${this.formatFloatValue(data["valueRatio.denominator.value"])}`;
|
|
691
705
|
if (data["valueRatio.denominator.unit"] !== void 0) {
|
|
692
706
|
ratio += ` ${data["valueRatio.denominator.unit"]}`;
|
|
693
707
|
}
|
|
@@ -941,6 +955,313 @@ var TemplateUtilities = class {
|
|
|
941
955
|
|
|
942
956
|
// src/constants.ts
|
|
943
957
|
var ADDRESS_SIMILARITY_THRESHOLD = 70;
|
|
958
|
+
var LAB_LOINC_MAP = {
|
|
959
|
+
// METABOLIC PANELS (VERY COMMONLY ORDERED)
|
|
960
|
+
"Basic Metabolic Panel": [
|
|
961
|
+
"24321-2",
|
|
962
|
+
// Basic metabolic 2000 panel - Serum or Plasma
|
|
963
|
+
"51990-0"
|
|
964
|
+
// Basic metabolic 2000 panel - Blood
|
|
965
|
+
],
|
|
966
|
+
"Comprehensive Metabolic Panel": [
|
|
967
|
+
"24323-8"
|
|
968
|
+
// Comprehensive metabolic 2000 panel - Serum or Plasma
|
|
969
|
+
],
|
|
970
|
+
// CBC COMPONENTS
|
|
971
|
+
Hemoglobin: [
|
|
972
|
+
"718-7"
|
|
973
|
+
// Hemoglobin [Mass/volume] in Blood
|
|
974
|
+
],
|
|
975
|
+
Hematocrit: [
|
|
976
|
+
"4544-3"
|
|
977
|
+
// Hematocrit [Volume Fraction] of Blood by Automated count
|
|
978
|
+
],
|
|
979
|
+
"White Blood Cell Count": [
|
|
980
|
+
"6690-2"
|
|
981
|
+
// Leukocytes [///volume] in Blood by Automated count
|
|
982
|
+
],
|
|
983
|
+
"Platelet Count": [
|
|
984
|
+
"777-3"
|
|
985
|
+
// Platelets [///volume] in Blood by Automated count
|
|
986
|
+
],
|
|
987
|
+
"Complete Blood Count": [
|
|
988
|
+
"58410-2",
|
|
989
|
+
// CBC panel - Blood by Automated count
|
|
990
|
+
"57021-8",
|
|
991
|
+
// CBC W Auto Differential panel - Blood
|
|
992
|
+
"69738-3"
|
|
993
|
+
// CBC W Auto Differential panel - Blood by Automated count
|
|
994
|
+
],
|
|
995
|
+
// CHEMISTRY - GLUCOSE
|
|
996
|
+
Glucose: [
|
|
997
|
+
"2345-7",
|
|
998
|
+
// Glucose [Mass/volume] in Serum or Plasma
|
|
999
|
+
"1558-6",
|
|
1000
|
+
// Fasting glucose [Mass/volume] in Serum or Plasma
|
|
1001
|
+
"2339-0"
|
|
1002
|
+
// Glucose [Mass/volume] in Blood
|
|
1003
|
+
],
|
|
1004
|
+
// RENAL FUNCTION
|
|
1005
|
+
Creatinine: [
|
|
1006
|
+
"2160-0"
|
|
1007
|
+
// Creatinine [Mass/volume] in Serum or Plasma
|
|
1008
|
+
],
|
|
1009
|
+
"Blood Urea Nitrogen": [
|
|
1010
|
+
"3094-0",
|
|
1011
|
+
// Urea nitrogen [Mass/volume] in Serum or Plasma
|
|
1012
|
+
"6299-2"
|
|
1013
|
+
// Urea nitrogen [Mass/volume] in Blood
|
|
1014
|
+
],
|
|
1015
|
+
// ELECTROLYTES
|
|
1016
|
+
Sodium: [
|
|
1017
|
+
"2951-2"
|
|
1018
|
+
// Sodium [Moles/volume] in Serum or Plasma
|
|
1019
|
+
],
|
|
1020
|
+
Potassium: [
|
|
1021
|
+
"2823-3"
|
|
1022
|
+
// Potassium [Moles/volume] in Serum or Plasma
|
|
1023
|
+
],
|
|
1024
|
+
Chloride: [
|
|
1025
|
+
"2075-0"
|
|
1026
|
+
// Chloride [Moles/volume] in Serum or Plasma
|
|
1027
|
+
],
|
|
1028
|
+
Calcium: [
|
|
1029
|
+
"17861-6",
|
|
1030
|
+
// Calcium [Mass/volume] in Serum or Plasma
|
|
1031
|
+
"1994-3"
|
|
1032
|
+
// Calcium.ionized [Moles/volume] in Serum or Plasma
|
|
1033
|
+
],
|
|
1034
|
+
Magnesium: [
|
|
1035
|
+
"19123-9"
|
|
1036
|
+
// Magnesium [Mass/volume] in Serum or Plasma
|
|
1037
|
+
],
|
|
1038
|
+
Phosphate: [
|
|
1039
|
+
"14879-1"
|
|
1040
|
+
// Phosphate [Mass/volume] in Serum or Plasma
|
|
1041
|
+
],
|
|
1042
|
+
// PROTEINS
|
|
1043
|
+
Albumin: [
|
|
1044
|
+
"1751-7"
|
|
1045
|
+
// Albumin [Mass/volume] in Serum or Plasma
|
|
1046
|
+
],
|
|
1047
|
+
"Total Protein": [
|
|
1048
|
+
"2885-2"
|
|
1049
|
+
// Protein [Mass/volume] in Serum or Plasma
|
|
1050
|
+
],
|
|
1051
|
+
// LIVER FUNCTION
|
|
1052
|
+
Bilirubin: [
|
|
1053
|
+
"1975-2",
|
|
1054
|
+
// Bilirubin.total [Mass/volume] in Serum or Plasma
|
|
1055
|
+
"1968-7",
|
|
1056
|
+
// Bilirubin.direct [Mass/volume] in Serum or Plasma
|
|
1057
|
+
"1971-1"
|
|
1058
|
+
// Bilirubin.indirect [Mass/volume] in Serum or Plasma
|
|
1059
|
+
],
|
|
1060
|
+
"Alkaline Phosphatase": [
|
|
1061
|
+
"6768-6"
|
|
1062
|
+
// Alkaline phosphatase [Enzymatic activity/volume] in Serum or Plasma
|
|
1063
|
+
],
|
|
1064
|
+
AST: [
|
|
1065
|
+
"1920-8"
|
|
1066
|
+
// Aspartate aminotransferase [Enzymatic activity/volume] in Serum or Plasma
|
|
1067
|
+
],
|
|
1068
|
+
ALT: [
|
|
1069
|
+
"1742-6"
|
|
1070
|
+
// Alanine aminotransferase [Enzymatic activity/volume] in Serum or Plasma
|
|
1071
|
+
],
|
|
1072
|
+
GGT: [
|
|
1073
|
+
"2324-2"
|
|
1074
|
+
// Gamma glutamyl transferase [Enzymatic activity/volume] in Serum or Plasma
|
|
1075
|
+
],
|
|
1076
|
+
// ENDOCRINE
|
|
1077
|
+
TSH: [
|
|
1078
|
+
"3016-3"
|
|
1079
|
+
// Thyrotropin [Units/volume] in Serum or Plasma
|
|
1080
|
+
],
|
|
1081
|
+
"Free T4": [
|
|
1082
|
+
"3024-7"
|
|
1083
|
+
// Thyroxine (T4) free [Mass/volume] in Serum or Plasma
|
|
1084
|
+
],
|
|
1085
|
+
"Total T4": [
|
|
1086
|
+
"3026-2"
|
|
1087
|
+
// Thyroxine (T4) [Mass/volume] in Serum or Plasma
|
|
1088
|
+
],
|
|
1089
|
+
"Free T3": [
|
|
1090
|
+
"3051-0"
|
|
1091
|
+
// Triiodothyronine (T3) free [Mass/volume] in Serum or Plasma
|
|
1092
|
+
],
|
|
1093
|
+
"Total T3": [
|
|
1094
|
+
"3053-6"
|
|
1095
|
+
// Triiodothyronine (T3) [Mass/volume] in Serum or Plasma
|
|
1096
|
+
],
|
|
1097
|
+
HbA1c: [
|
|
1098
|
+
"4548-4",
|
|
1099
|
+
// Hemoglobin A1c/Hemoglobin.total in Blood
|
|
1100
|
+
"17856-6"
|
|
1101
|
+
// Hemoglobin A1c/Hemoglobin.total in Blood by HPLC
|
|
1102
|
+
],
|
|
1103
|
+
// LIPID PANEL
|
|
1104
|
+
"Lipid Panel": [
|
|
1105
|
+
"24331-1",
|
|
1106
|
+
// Lipid 1996 panel - Serum or Plasma
|
|
1107
|
+
"57698-3"
|
|
1108
|
+
// Lipid panel with direct LDL - Serum or Plasma
|
|
1109
|
+
],
|
|
1110
|
+
"Cholesterol Total": [
|
|
1111
|
+
"2093-3"
|
|
1112
|
+
// Cholesterol [Mass/volume] in Serum or Plasma
|
|
1113
|
+
],
|
|
1114
|
+
"HDL Cholesterol": [
|
|
1115
|
+
"2085-9"
|
|
1116
|
+
// Cholesterol in HDL [Mass/volume] in Serum or Plasma
|
|
1117
|
+
],
|
|
1118
|
+
"LDL Cholesterol": [
|
|
1119
|
+
"13457-7",
|
|
1120
|
+
// Cholesterol in LDL [Mass/volume] in Serum or Plasma by calculation
|
|
1121
|
+
"18262-6"
|
|
1122
|
+
// Cholesterol in LDL [Mass/volume] in Serum or Plasma by Direct assay
|
|
1123
|
+
],
|
|
1124
|
+
Triglycerides: [
|
|
1125
|
+
"2571-8"
|
|
1126
|
+
// Triglyceride [Mass/volume] in Serum or Plasma
|
|
1127
|
+
],
|
|
1128
|
+
// COAGULATION STUDIES (COMMONLY MISSING!)
|
|
1129
|
+
PT: [
|
|
1130
|
+
"5902-2"
|
|
1131
|
+
// Prothrombin time (PT)
|
|
1132
|
+
],
|
|
1133
|
+
INR: [
|
|
1134
|
+
"6301-6"
|
|
1135
|
+
// INR in Platelet poor plasma by Coagulation assay
|
|
1136
|
+
],
|
|
1137
|
+
PTT: [
|
|
1138
|
+
"3173-2",
|
|
1139
|
+
// aPTT in Blood by Coagulation assay
|
|
1140
|
+
"14979-9"
|
|
1141
|
+
// aPTT in Platelet poor plasma by Coagulation assay
|
|
1142
|
+
],
|
|
1143
|
+
Fibrinogen: [
|
|
1144
|
+
"3255-7"
|
|
1145
|
+
// Fibrinogen [Mass/volume] in Platelet poor plasma by Coagulation assay
|
|
1146
|
+
],
|
|
1147
|
+
"D-Dimer": [
|
|
1148
|
+
"48065-7",
|
|
1149
|
+
// D-dimer FEU [Mass/volume] in Platelet poor plasma
|
|
1150
|
+
"48066-5"
|
|
1151
|
+
// D-dimer DDU [Mass/volume] in Platelet poor plasma
|
|
1152
|
+
],
|
|
1153
|
+
// CARDIAC MARKERS (CRITICAL FOR ER!)
|
|
1154
|
+
"Troponin I": [
|
|
1155
|
+
"10839-9",
|
|
1156
|
+
// Troponin I.cardiac [Mass/volume] in Serum or Plasma
|
|
1157
|
+
"42757-5",
|
|
1158
|
+
// Troponin I.cardiac [Mass/volume] in Blood
|
|
1159
|
+
"89579-7"
|
|
1160
|
+
// Troponin I.cardiac [Mass/volume] in Serum or Plasma by High sensitivity method
|
|
1161
|
+
],
|
|
1162
|
+
"Troponin T": [
|
|
1163
|
+
"6598-7",
|
|
1164
|
+
// Troponin T.cardiac [Mass/volume] in Serum or Plasma
|
|
1165
|
+
"48425-3"
|
|
1166
|
+
// Troponin T.cardiac [Mass/volume] in Serum or Plasma by High sensitivity method
|
|
1167
|
+
],
|
|
1168
|
+
BNP: [
|
|
1169
|
+
"30934-4"
|
|
1170
|
+
// BNP [Mass/volume] in Serum or Plasma
|
|
1171
|
+
],
|
|
1172
|
+
"NT-proBNP": [
|
|
1173
|
+
"33762-6"
|
|
1174
|
+
// NT-proBNP [Mass/volume] in Serum or Plasma
|
|
1175
|
+
],
|
|
1176
|
+
"CK-MB": [
|
|
1177
|
+
"13969-1"
|
|
1178
|
+
// Creatine kinase.MB [Mass/volume] in Serum or Plasma
|
|
1179
|
+
],
|
|
1180
|
+
// INFLAMMATORY MARKERS
|
|
1181
|
+
CRP: [
|
|
1182
|
+
"1988-5",
|
|
1183
|
+
// C reactive protein [Mass/volume] in Serum or Plasma
|
|
1184
|
+
"30522-7"
|
|
1185
|
+
// C reactive protein [Mass/volume] in Serum or Plasma by High sensitivity method
|
|
1186
|
+
],
|
|
1187
|
+
ESR: [
|
|
1188
|
+
"30341-2",
|
|
1189
|
+
// Erythrocyte sedimentation rate by Westergren method
|
|
1190
|
+
"4537-7"
|
|
1191
|
+
// Erythrocyte sedimentation rate
|
|
1192
|
+
],
|
|
1193
|
+
// VITAMINS & MINERALS (VERY HIGH VOLUME!)
|
|
1194
|
+
"Vitamin D": [
|
|
1195
|
+
"1990-1",
|
|
1196
|
+
// Vitamin D [Mass/volume] in Serum or Plasma (obsolete, but still used)
|
|
1197
|
+
"14635-7",
|
|
1198
|
+
// 25-Hydroxyvitamin D3 [Mass/volume] in Serum or Plasma
|
|
1199
|
+
"62292-8"
|
|
1200
|
+
// 25-Hydroxyvitamin D2+D3 [Mass/volume] in Serum or Plasma
|
|
1201
|
+
],
|
|
1202
|
+
"Vitamin B12": [
|
|
1203
|
+
"2132-9"
|
|
1204
|
+
// Cobalamin (Vitamin B12) [Mass/volume] in Serum or Plasma
|
|
1205
|
+
],
|
|
1206
|
+
Folate: [
|
|
1207
|
+
"2284-8",
|
|
1208
|
+
// Folate [Mass/volume] in Serum or Plasma
|
|
1209
|
+
"15152-2"
|
|
1210
|
+
// Folate [Mass/volume] in Red Blood Cells
|
|
1211
|
+
],
|
|
1212
|
+
Iron: [
|
|
1213
|
+
"2498-4"
|
|
1214
|
+
// Iron [Mass/volume] in Serum or Plasma
|
|
1215
|
+
],
|
|
1216
|
+
Ferritin: [
|
|
1217
|
+
"2276-4"
|
|
1218
|
+
// Ferritin [Mass/volume] in Serum or Plasma
|
|
1219
|
+
],
|
|
1220
|
+
TIBC: [
|
|
1221
|
+
"2500-7"
|
|
1222
|
+
// Iron binding capacity [Mass/volume] in Serum or Plasma
|
|
1223
|
+
],
|
|
1224
|
+
// OTHER COMMON TESTS
|
|
1225
|
+
PSA: [
|
|
1226
|
+
"2857-1",
|
|
1227
|
+
// Prostate specific Ag [Mass/volume] in Serum or Plasma
|
|
1228
|
+
"10886-0"
|
|
1229
|
+
// Prostate specific Ag Free [Mass/volume] in Serum or Plasma
|
|
1230
|
+
],
|
|
1231
|
+
"Uric Acid": [
|
|
1232
|
+
"3084-1"
|
|
1233
|
+
// Urate [Mass/volume] in Serum or Plasma
|
|
1234
|
+
],
|
|
1235
|
+
LDH: [
|
|
1236
|
+
"2532-0",
|
|
1237
|
+
// Lactate dehydrogenase [Enzymatic activity/volume] in Serum or Plasma
|
|
1238
|
+
"14804-9"
|
|
1239
|
+
// Lactate dehydrogenase [Enzymatic activity/volume] in Serum or Plasma by Lactate to pyruvate reaction
|
|
1240
|
+
],
|
|
1241
|
+
Amylase: [
|
|
1242
|
+
"1798-8"
|
|
1243
|
+
// Amylase [Enzymatic activity/volume] in Serum or Plasma
|
|
1244
|
+
],
|
|
1245
|
+
Lipase: [
|
|
1246
|
+
"3040-3"
|
|
1247
|
+
// Lipase [Enzymatic activity/volume] in Serum or Plasma
|
|
1248
|
+
],
|
|
1249
|
+
hCG: [
|
|
1250
|
+
"21198-7",
|
|
1251
|
+
// Choriogonadotropin.beta subunit [Units/volume] in Serum or Plasma
|
|
1252
|
+
"2118-8",
|
|
1253
|
+
// Choriogonadotropin (pregnancy test) [Presence] in Serum or Plasma
|
|
1254
|
+
"2106-3"
|
|
1255
|
+
// Choriogonadotropin (pregnancy test) [Presence] in Urine
|
|
1256
|
+
],
|
|
1257
|
+
// URINALYSIS
|
|
1258
|
+
Urinalysis: [
|
|
1259
|
+
"24357-6",
|
|
1260
|
+
// Urinalysis macro (dipstick) panel - Urine
|
|
1261
|
+
"24356-8"
|
|
1262
|
+
// Urinalysis complete panel - Urine
|
|
1263
|
+
]
|
|
1264
|
+
};
|
|
944
1265
|
|
|
945
1266
|
// src/narratives/templates/typescript/PatientTemplate.ts
|
|
946
1267
|
var PatientTemplate = class _PatientTemplate {
|
|
@@ -2065,6 +2386,12 @@ var MedicalDevicesTemplate = class _MedicalDevicesTemplate {
|
|
|
2065
2386
|
};
|
|
2066
2387
|
|
|
2067
2388
|
// src/narratives/templates/typescript/DiagnosticResultsTemplate.ts
|
|
2389
|
+
var loincToLabName = {};
|
|
2390
|
+
for (const [labName, loincCodes] of Object.entries(LAB_LOINC_MAP)) {
|
|
2391
|
+
for (const code of loincCodes) {
|
|
2392
|
+
loincToLabName[code] = labName;
|
|
2393
|
+
}
|
|
2394
|
+
}
|
|
2068
2395
|
var DiagnosticResultsTemplate = class _DiagnosticResultsTemplate {
|
|
2069
2396
|
/**
|
|
2070
2397
|
* Generate HTML narrative for Diagnostic Results
|
|
@@ -2491,30 +2818,80 @@ var DiagnosticResultsTemplate = class _DiagnosticResultsTemplate {
|
|
|
2491
2818
|
const observations = this.getObservations(resources);
|
|
2492
2819
|
if (observations.length > 0) {
|
|
2493
2820
|
observations.sort((a, b) => {
|
|
2494
|
-
const dateA =
|
|
2495
|
-
const dateB =
|
|
2496
|
-
return dateA && dateB ?
|
|
2821
|
+
const dateA = this.getObservationDate(a);
|
|
2822
|
+
const dateB = this.getObservationDate(b);
|
|
2823
|
+
return dateA && dateB ? dateB.getTime() - dateA.getTime() : 0;
|
|
2497
2824
|
});
|
|
2825
|
+
this.filterObservationForLoincCodes(observations);
|
|
2498
2826
|
html += this.renderObservations(templateUtilities, observations, timezone);
|
|
2499
2827
|
}
|
|
2500
|
-
|
|
2501
|
-
|
|
2502
|
-
diagnosticReports.
|
|
2503
|
-
|
|
2504
|
-
|
|
2505
|
-
|
|
2506
|
-
|
|
2507
|
-
|
|
2828
|
+
if (process.env.ENABLE_DIAGNOSTIC_REPORTS_IN_SUMMARY === "true") {
|
|
2829
|
+
const diagnosticReports = this.getDiagnosticReports(resources);
|
|
2830
|
+
if (diagnosticReports.length > 0) {
|
|
2831
|
+
diagnosticReports.sort((a, b) => {
|
|
2832
|
+
const dateA = a.issued;
|
|
2833
|
+
const dateB = b.issued;
|
|
2834
|
+
return dateA && dateB ? new Date(dateB).getTime() - new Date(dateA).getTime() : 0;
|
|
2835
|
+
});
|
|
2836
|
+
html += this.renderDiagnosticReports(templateUtilities, diagnosticReports, timezone);
|
|
2837
|
+
}
|
|
2508
2838
|
}
|
|
2509
2839
|
return html;
|
|
2510
2840
|
}
|
|
2841
|
+
static filterObservationForLoincCodes(observations) {
|
|
2842
|
+
const labsAdded = /* @__PURE__ */ new Set();
|
|
2843
|
+
const filteredObservations = [];
|
|
2844
|
+
for (const obs of observations) {
|
|
2845
|
+
const loincCode = this.getObservationLoincCode(obs);
|
|
2846
|
+
if (loincCode && loincToLabName[loincCode]) {
|
|
2847
|
+
const labName = loincToLabName[loincCode];
|
|
2848
|
+
if (!labsAdded.has(labName)) {
|
|
2849
|
+
labsAdded.add(labName);
|
|
2850
|
+
filteredObservations.push(obs);
|
|
2851
|
+
}
|
|
2852
|
+
}
|
|
2853
|
+
}
|
|
2854
|
+
observations.length = 0;
|
|
2855
|
+
observations.push(...filteredObservations);
|
|
2856
|
+
}
|
|
2857
|
+
static getObservationLoincCode(obs) {
|
|
2858
|
+
if (obs.code && obs.code.coding) {
|
|
2859
|
+
for (const coding of obs.code.coding) {
|
|
2860
|
+
if (coding.system && coding.system.toLowerCase().includes("loinc") && coding.code) {
|
|
2861
|
+
return coding.code;
|
|
2862
|
+
}
|
|
2863
|
+
}
|
|
2864
|
+
}
|
|
2865
|
+
return void 0;
|
|
2866
|
+
}
|
|
2867
|
+
static getObservationDate(obs) {
|
|
2868
|
+
let obsDate = void 0;
|
|
2869
|
+
if (obs.effectiveDateTime) {
|
|
2870
|
+
obsDate = new Date(obs.effectiveDateTime);
|
|
2871
|
+
} else if (obs.effectivePeriod) {
|
|
2872
|
+
if (obs.effectivePeriod.start) {
|
|
2873
|
+
obsDate = new Date(obs.effectivePeriod.start);
|
|
2874
|
+
} else if (obs.effectivePeriod.end) {
|
|
2875
|
+
obsDate = new Date(obs.effectivePeriod.end);
|
|
2876
|
+
}
|
|
2877
|
+
}
|
|
2878
|
+
return obsDate;
|
|
2879
|
+
}
|
|
2511
2880
|
/**
|
|
2512
2881
|
* Get all Observation resources from the resource array
|
|
2513
2882
|
* @param resources - FHIR resources array
|
|
2514
2883
|
* @returns Array of Observation resources
|
|
2515
2884
|
*/
|
|
2516
2885
|
static getObservations(resources) {
|
|
2517
|
-
return resources.filter((resourceItem) =>
|
|
2886
|
+
return resources.filter((resourceItem) => {
|
|
2887
|
+
if (resourceItem.resourceType === "Observation") {
|
|
2888
|
+
const obsDate = this.getObservationDate(resourceItem);
|
|
2889
|
+
if (obsDate && obsDate >= new Date(Date.now() - RESULT_SUMMARY_OBSERVATION_DATE_FILTER)) {
|
|
2890
|
+
return true;
|
|
2891
|
+
}
|
|
2892
|
+
}
|
|
2893
|
+
return false;
|
|
2894
|
+
}).map((resourceItem) => resourceItem);
|
|
2518
2895
|
}
|
|
2519
2896
|
/**
|
|
2520
2897
|
* Get all DiagnosticReport resources from the resource array
|
|
@@ -2532,17 +2909,18 @@ var DiagnosticResultsTemplate = class _DiagnosticResultsTemplate {
|
|
|
2532
2909
|
* @returns HTML string for rendering
|
|
2533
2910
|
*/
|
|
2534
2911
|
static renderObservations(templateUtilities, observations, timezone) {
|
|
2535
|
-
let html =
|
|
2536
|
-
|
|
2912
|
+
let html = "";
|
|
2913
|
+
if (process.env.ENABLE_DIAGNOSTIC_REPORTS_IN_SUMMARY === "true") {
|
|
2914
|
+
html += `
|
|
2915
|
+
<h3>Observations</h3>`;
|
|
2916
|
+
}
|
|
2917
|
+
html += `
|
|
2537
2918
|
<table>
|
|
2538
2919
|
<thead>
|
|
2539
2920
|
<tr>
|
|
2540
2921
|
<th>Code</th>
|
|
2541
2922
|
<th>Result</th>
|
|
2542
|
-
<th>Unit</th>
|
|
2543
|
-
<th>Interpretation</th>
|
|
2544
2923
|
<th>Reference Range</th>
|
|
2545
|
-
<th>Comments</th>
|
|
2546
2924
|
<th>Date</th>
|
|
2547
2925
|
</tr>
|
|
2548
2926
|
</thead>
|
|
@@ -2556,10 +2934,7 @@ var DiagnosticResultsTemplate = class _DiagnosticResultsTemplate {
|
|
|
2556
2934
|
<tr id="${templateUtilities.narrativeLinkId(obs)}">
|
|
2557
2935
|
<td>${obsCode}</td>
|
|
2558
2936
|
<td>${templateUtilities.extractObservationValue(obs)}</td>
|
|
2559
|
-
<td>${templateUtilities.extractObservationValueUnit(obs)}</td>
|
|
2560
|
-
<td>${templateUtilities.firstFromCodeableConceptList(obs.interpretation)}</td>
|
|
2561
2937
|
<td>${templateUtilities.concatReferenceRange(obs.referenceRange)}</td>
|
|
2562
|
-
<td>${templateUtilities.renderNotes(obs.note, timezone)}</td>
|
|
2563
2938
|
<td>${obs.effectiveDateTime ? templateUtilities.renderTime(obs.effectiveDateTime, timezone) : obs.effectivePeriod ? templateUtilities.renderPeriod(obs.effectivePeriod, timezone) : ""}</td>
|
|
2564
2939
|
</tr>`;
|
|
2565
2940
|
}
|