@imranq2/fhirpatientsummary 1.0.8 → 1.0.10
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 +129 -51
- package/dist/index.d.cts +36 -17
- package/dist/index.d.ts +36 -17
- package/dist/index.js +129 -51
- package/package.json +6 -4
package/dist/index.cjs
CHANGED
|
@@ -949,7 +949,7 @@ var AllergyIntoleranceTemplate = class _AllergyIntoleranceTemplate {
|
|
|
949
949
|
}
|
|
950
950
|
}
|
|
951
951
|
}
|
|
952
|
-
let html =
|
|
952
|
+
let html = "";
|
|
953
953
|
html += `
|
|
954
954
|
<div class="ActiveAllergies">
|
|
955
955
|
<h3>Active Allergies and Intolerances</h3>
|
|
@@ -1006,8 +1006,7 @@ var AllergyIntoleranceTemplate = class _AllergyIntoleranceTemplate {
|
|
|
1006
1006
|
html += `
|
|
1007
1007
|
</tbody>
|
|
1008
1008
|
</table>
|
|
1009
|
-
</div
|
|
1010
|
-
</div>`;
|
|
1009
|
+
</div>`;
|
|
1011
1010
|
return html;
|
|
1012
1011
|
}
|
|
1013
1012
|
/**
|
|
@@ -1117,7 +1116,7 @@ var MedicationSummaryTemplate = class _MedicationSummaryTemplate {
|
|
|
1117
1116
|
* @returns HTML string for rendering
|
|
1118
1117
|
*/
|
|
1119
1118
|
static renderMedicationRequests(templateUtilities, medications) {
|
|
1120
|
-
let html =
|
|
1119
|
+
let html = `
|
|
1121
1120
|
<table>
|
|
1122
1121
|
<thead>
|
|
1123
1122
|
<tr>
|
|
@@ -1167,7 +1166,7 @@ var MedicationSummaryTemplate = class _MedicationSummaryTemplate {
|
|
|
1167
1166
|
}
|
|
1168
1167
|
html += `
|
|
1169
1168
|
</tbody>
|
|
1170
|
-
</table
|
|
1169
|
+
</table>`;
|
|
1171
1170
|
return html;
|
|
1172
1171
|
}
|
|
1173
1172
|
/**
|
|
@@ -1177,7 +1176,7 @@ var MedicationSummaryTemplate = class _MedicationSummaryTemplate {
|
|
|
1177
1176
|
* @returns HTML string for rendering
|
|
1178
1177
|
*/
|
|
1179
1178
|
static renderMedicationStatements(templateUtilities, medications) {
|
|
1180
|
-
let html =
|
|
1179
|
+
let html = `
|
|
1181
1180
|
<table>
|
|
1182
1181
|
<thead>
|
|
1183
1182
|
<tr>
|
|
@@ -1221,7 +1220,7 @@ var MedicationSummaryTemplate = class _MedicationSummaryTemplate {
|
|
|
1221
1220
|
}
|
|
1222
1221
|
html += `
|
|
1223
1222
|
</tbody>
|
|
1224
|
-
</table
|
|
1223
|
+
</table>`;
|
|
1225
1224
|
return html;
|
|
1226
1225
|
}
|
|
1227
1226
|
};
|
|
@@ -1247,7 +1246,7 @@ var ImmunizationsTemplate = class _ImmunizationsTemplate {
|
|
|
1247
1246
|
const templateUtilities = new TemplateUtilities(resource);
|
|
1248
1247
|
let html = `
|
|
1249
1248
|
<h5>Immunizations</h5>
|
|
1250
|
-
<table
|
|
1249
|
+
<table>
|
|
1251
1250
|
<thead>
|
|
1252
1251
|
<tr>
|
|
1253
1252
|
<th>Immunization</th>
|
|
@@ -1303,7 +1302,7 @@ var ProblemListTemplate = class _ProblemListTemplate {
|
|
|
1303
1302
|
*/
|
|
1304
1303
|
static generateStaticNarrative(resource, timezone) {
|
|
1305
1304
|
const templateUtilities = new TemplateUtilities(resource);
|
|
1306
|
-
let html =
|
|
1305
|
+
let html = ``;
|
|
1307
1306
|
const activeConditions = [];
|
|
1308
1307
|
const resolvedConditions = [];
|
|
1309
1308
|
if (resource.entry && Array.isArray(resource.entry)) {
|
|
@@ -1379,7 +1378,6 @@ var ProblemListTemplate = class _ProblemListTemplate {
|
|
|
1379
1378
|
</table>
|
|
1380
1379
|
</div>`;
|
|
1381
1380
|
}
|
|
1382
|
-
html += `</div>`;
|
|
1383
1381
|
return html;
|
|
1384
1382
|
}
|
|
1385
1383
|
};
|
|
@@ -1405,7 +1403,7 @@ var VitalSignsTemplate = class _VitalSignsTemplate {
|
|
|
1405
1403
|
const templateUtilities = new TemplateUtilities(resource);
|
|
1406
1404
|
let html = `
|
|
1407
1405
|
<h5>Vital Signs</h5>
|
|
1408
|
-
<table
|
|
1406
|
+
<table>
|
|
1409
1407
|
<thead>
|
|
1410
1408
|
<tr>
|
|
1411
1409
|
<th>Code</th>
|
|
@@ -1464,7 +1462,7 @@ var MedicalDevicesTemplate = class _MedicalDevicesTemplate {
|
|
|
1464
1462
|
const templateUtilities = new TemplateUtilities(resource);
|
|
1465
1463
|
let html = `
|
|
1466
1464
|
<h5>Medical Devices</h5>
|
|
1467
|
-
<table
|
|
1465
|
+
<table>
|
|
1468
1466
|
<thead>
|
|
1469
1467
|
<tr>
|
|
1470
1468
|
<th>Device</th>
|
|
@@ -1557,7 +1555,7 @@ var DiagnosticResultsTemplate = class _DiagnosticResultsTemplate {
|
|
|
1557
1555
|
static renderObservations(templateUtilities, observations, timezone) {
|
|
1558
1556
|
let html = `
|
|
1559
1557
|
<h5>Diagnostic Results: Observations</h5>
|
|
1560
|
-
<table
|
|
1558
|
+
<table>
|
|
1561
1559
|
<thead>
|
|
1562
1560
|
<tr>
|
|
1563
1561
|
<th>Code</th>
|
|
@@ -1597,7 +1595,7 @@ var DiagnosticResultsTemplate = class _DiagnosticResultsTemplate {
|
|
|
1597
1595
|
static renderDiagnosticReports(templateUtilities, reports, timezone) {
|
|
1598
1596
|
let html = `
|
|
1599
1597
|
<h5>Diagnostic Results: Reports</h5>
|
|
1600
|
-
<table
|
|
1598
|
+
<table>
|
|
1601
1599
|
<thead>
|
|
1602
1600
|
<tr>
|
|
1603
1601
|
<th>Report</th>
|
|
@@ -1650,7 +1648,7 @@ var HistoryOfProceduresTemplate = class _HistoryOfProceduresTemplate {
|
|
|
1650
1648
|
const templateUtilities = new TemplateUtilities(resource);
|
|
1651
1649
|
let html = `
|
|
1652
1650
|
<h5>History Of Procedures</h5>
|
|
1653
|
-
<table
|
|
1651
|
+
<table>
|
|
1654
1652
|
<thead>
|
|
1655
1653
|
<tr>
|
|
1656
1654
|
<th>Procedure</th>
|
|
@@ -1701,7 +1699,7 @@ var SocialHistoryTemplate = class _SocialHistoryTemplate {
|
|
|
1701
1699
|
const templateUtilities = new TemplateUtilities(resource);
|
|
1702
1700
|
let html = `
|
|
1703
1701
|
<h5>Social History</h5>
|
|
1704
|
-
<table
|
|
1702
|
+
<table>
|
|
1705
1703
|
<thead>
|
|
1706
1704
|
<tr>
|
|
1707
1705
|
<th>Code</th>
|
|
@@ -1747,7 +1745,7 @@ var PastHistoryOfIllnessTemplate = class {
|
|
|
1747
1745
|
const templateUtilities = new TemplateUtilities(resource);
|
|
1748
1746
|
let html = `
|
|
1749
1747
|
<h5>Past History of Illnesses</h5>
|
|
1750
|
-
<table
|
|
1748
|
+
<table>
|
|
1751
1749
|
<thead>
|
|
1752
1750
|
<tr>
|
|
1753
1751
|
<th>Medical Problems</th>
|
|
@@ -1792,7 +1790,7 @@ var PlanOfCareTemplate = class {
|
|
|
1792
1790
|
const templateUtilities = new TemplateUtilities(resource);
|
|
1793
1791
|
let html = `
|
|
1794
1792
|
<h5>Plan of Care</h5>
|
|
1795
|
-
<table
|
|
1793
|
+
<table>
|
|
1796
1794
|
<thead>
|
|
1797
1795
|
<tr>
|
|
1798
1796
|
<th>Activity</th>
|
|
@@ -1847,7 +1845,7 @@ var FunctionalStatusTemplate = class _FunctionalStatusTemplate {
|
|
|
1847
1845
|
const templateUtilities = new TemplateUtilities(resource);
|
|
1848
1846
|
let html = `
|
|
1849
1847
|
<h5>Functional Status</h5>
|
|
1850
|
-
<table
|
|
1848
|
+
<table>
|
|
1851
1849
|
<thead>
|
|
1852
1850
|
<tr>
|
|
1853
1851
|
<th>Assessment</th>
|
|
@@ -1902,7 +1900,7 @@ var PregnancyTemplate = class _PregnancyTemplate {
|
|
|
1902
1900
|
const templateUtilities = new TemplateUtilities(resource);
|
|
1903
1901
|
let html = `
|
|
1904
1902
|
<h5>Pregnancy</h5>
|
|
1905
|
-
<table
|
|
1903
|
+
<table>
|
|
1906
1904
|
<thead>
|
|
1907
1905
|
<tr>
|
|
1908
1906
|
<th>Code</th>
|
|
@@ -1956,7 +1954,7 @@ var AdvanceDirectivesTemplate = class _AdvanceDirectivesTemplate {
|
|
|
1956
1954
|
const templateUtilities = new TemplateUtilities(resource);
|
|
1957
1955
|
let html = `
|
|
1958
1956
|
<h5>Advance Directives</h5>
|
|
1959
|
-
<table
|
|
1957
|
+
<table>
|
|
1960
1958
|
<thead>
|
|
1961
1959
|
<tr>
|
|
1962
1960
|
<th>Scope</th>
|
|
@@ -2000,7 +1998,7 @@ var FamilyHistoryTemplate = class {
|
|
|
2000
1998
|
const templateUtilities = new TemplateUtilities(resource);
|
|
2001
1999
|
let html = `
|
|
2002
2000
|
<h5>Family History</h5>
|
|
2003
|
-
<table
|
|
2001
|
+
<table>
|
|
2004
2002
|
<thead>
|
|
2005
2003
|
<tr>
|
|
2006
2004
|
<th>Relationship</th>
|
|
@@ -2081,7 +2079,7 @@ var ClinicalImpressionTemplate = class {
|
|
|
2081
2079
|
const templateUtilities = new TemplateUtilities(resource);
|
|
2082
2080
|
let html = `
|
|
2083
2081
|
<h5>Clinical Impressions</h5>
|
|
2084
|
-
<table
|
|
2082
|
+
<table>
|
|
2085
2083
|
<thead>
|
|
2086
2084
|
<tr>
|
|
2087
2085
|
<th>Date</th>
|
|
@@ -2193,15 +2191,42 @@ TypeScriptTemplateMapper.sectionToTemplate = {
|
|
|
2193
2191
|
};
|
|
2194
2192
|
|
|
2195
2193
|
// src/generators/narrative_generator.ts
|
|
2194
|
+
var import_html_minifier_terser = require("html-minifier-terser");
|
|
2195
|
+
var DEFAULT_MINIFY_OPTIONS = {
|
|
2196
|
+
collapseWhitespace: true,
|
|
2197
|
+
conservativeCollapse: true,
|
|
2198
|
+
// Preserves one whitespace
|
|
2199
|
+
removeComments: true,
|
|
2200
|
+
caseSensitive: true,
|
|
2201
|
+
// Important for XML/XHTML
|
|
2202
|
+
minifyCSS: true,
|
|
2203
|
+
minifyJS: false,
|
|
2204
|
+
decodeEntities: true,
|
|
2205
|
+
keepClosingSlash: true,
|
|
2206
|
+
// Important for XML/XHTML
|
|
2207
|
+
removeEmptyAttributes: true
|
|
2208
|
+
};
|
|
2209
|
+
var AGGRESSIVE_MINIFY_OPTIONS = {
|
|
2210
|
+
...DEFAULT_MINIFY_OPTIONS,
|
|
2211
|
+
collapseWhitespace: true,
|
|
2212
|
+
conservativeCollapse: false,
|
|
2213
|
+
// Don't preserve whitespace
|
|
2214
|
+
removeAttributeQuotes: true,
|
|
2215
|
+
removeRedundantAttributes: true,
|
|
2216
|
+
removeEmptyElements: false,
|
|
2217
|
+
// Don't remove empty elements as they may be semantically important
|
|
2218
|
+
removeOptionalTags: true
|
|
2219
|
+
};
|
|
2196
2220
|
var NarrativeGenerator = class {
|
|
2197
2221
|
/**
|
|
2198
2222
|
* Generates narrative HTML content for a section
|
|
2199
2223
|
* @param section - IPS section type
|
|
2200
2224
|
* @param resources - Array of domain resources
|
|
2201
2225
|
* @param timezone - Optional timezone to use for date formatting (e.g., 'America/New_York', 'Europe/London')
|
|
2226
|
+
* @param wrapInXhtml - Whether to wrap the content in XHTML div
|
|
2202
2227
|
* @returns Generated HTML content or undefined if no resources
|
|
2203
2228
|
*/
|
|
2204
|
-
static
|
|
2229
|
+
static async generateNarrativeContentAsync(section, resources, timezone, wrapInXhtml = true) {
|
|
2205
2230
|
if (!resources || resources.length === 0) {
|
|
2206
2231
|
return void 0;
|
|
2207
2232
|
}
|
|
@@ -2213,48 +2238,81 @@ var NarrativeGenerator = class {
|
|
|
2213
2238
|
resource
|
|
2214
2239
|
}))
|
|
2215
2240
|
};
|
|
2216
|
-
|
|
2241
|
+
const content = TypeScriptTemplateMapper.generateNarrative(section, bundle, timezone);
|
|
2242
|
+
if (!content) {
|
|
2243
|
+
return void 0;
|
|
2244
|
+
}
|
|
2245
|
+
if (wrapInXhtml) {
|
|
2246
|
+
return await this.wrapInXhtmlAsync(content);
|
|
2247
|
+
} else {
|
|
2248
|
+
return await this.minifyHtmlAsync(content);
|
|
2249
|
+
}
|
|
2217
2250
|
} catch (error) {
|
|
2218
2251
|
console.error(`Error generating narrative for section ${section}:`, error);
|
|
2219
2252
|
return `<div class="error">Error generating narrative: ${error instanceof Error ? error.message : String(error)}</div>`;
|
|
2220
2253
|
}
|
|
2221
2254
|
}
|
|
2222
2255
|
/**
|
|
2223
|
-
*
|
|
2256
|
+
* Minifies HTML content asynchronously using html-minifier-terser
|
|
2257
|
+
* @param html - HTML content to minify
|
|
2258
|
+
* @param aggressive - Whether to use more aggressive minification
|
|
2259
|
+
* @returns Promise that resolves to minified HTML content
|
|
2260
|
+
*/
|
|
2261
|
+
static async minifyHtmlAsync(html, aggressive = false) {
|
|
2262
|
+
if (!html) return html;
|
|
2263
|
+
try {
|
|
2264
|
+
const options = aggressive ? AGGRESSIVE_MINIFY_OPTIONS : DEFAULT_MINIFY_OPTIONS;
|
|
2265
|
+
return await (0, import_html_minifier_terser.minify)(html, options);
|
|
2266
|
+
} catch (error) {
|
|
2267
|
+
console.warn("HTML minification failed", error);
|
|
2268
|
+
return html;
|
|
2269
|
+
}
|
|
2270
|
+
}
|
|
2271
|
+
/**
|
|
2272
|
+
* Creates a complete FHIR Narrative object asynchronously
|
|
2224
2273
|
* @param content - HTML content
|
|
2225
|
-
* @
|
|
2274
|
+
* @param minify - Whether to minify the HTML content (default: true)
|
|
2275
|
+
* @returns Promise that resolves to a FHIR Narrative object
|
|
2226
2276
|
*/
|
|
2227
|
-
static
|
|
2228
|
-
content = content.replace(/\s+/g, " ").trim();
|
|
2277
|
+
static async createNarrativeAsync(content, minify = true) {
|
|
2229
2278
|
const divMatch = content.match(/^<div[^>]*>(.*?)<\/div>$/);
|
|
2230
2279
|
if (divMatch) {
|
|
2231
2280
|
content = divMatch[1];
|
|
2232
2281
|
}
|
|
2282
|
+
if (minify) {
|
|
2283
|
+
content = await this.minifyHtmlAsync(content);
|
|
2284
|
+
}
|
|
2233
2285
|
return {
|
|
2234
2286
|
status: "generated",
|
|
2235
2287
|
div: `<div xmlns="http://www.w3.org/1999/xhtml">${content}</div>`
|
|
2236
2288
|
};
|
|
2237
2289
|
}
|
|
2238
2290
|
/**
|
|
2239
|
-
* Generates a complete FHIR Narrative object for a section
|
|
2291
|
+
* Generates a complete FHIR Narrative object for a section asynchronously
|
|
2240
2292
|
* @param section - IPS section type
|
|
2241
2293
|
* @param resources - Array of domain resources
|
|
2242
|
-
* @param timezone - Optional timezone to use for date formatting
|
|
2243
|
-
* @
|
|
2294
|
+
* @param timezone - Optional timezone to use for date formatting
|
|
2295
|
+
* @param minify - Whether to minify the HTML content (default: true)
|
|
2296
|
+
* @param wrapInXhtml - Whether to wrap the content in XHTML div
|
|
2297
|
+
* @returns Promise that resolves to a FHIR Narrative object or undefined if no resources
|
|
2244
2298
|
*/
|
|
2245
|
-
static
|
|
2246
|
-
const content = this.
|
|
2299
|
+
static async generateNarrativeAsync(section, resources, timezone, minify = true, wrapInXhtml) {
|
|
2300
|
+
const content = await this.generateNarrativeContentAsync(section, resources, timezone, wrapInXhtml);
|
|
2247
2301
|
if (!content) {
|
|
2248
2302
|
return void 0;
|
|
2249
2303
|
}
|
|
2250
|
-
return this.
|
|
2304
|
+
return await this.createNarrativeAsync(content, minify);
|
|
2251
2305
|
}
|
|
2252
2306
|
/**
|
|
2253
|
-
* Wrap content in XHTML div with FHIR namespace
|
|
2307
|
+
* Wrap content in XHTML div with FHIR namespace asynchronously
|
|
2254
2308
|
* @param content - HTML content to wrap
|
|
2255
|
-
* @
|
|
2309
|
+
* @param minify - Whether to minify the HTML content before wrapping (default: false)
|
|
2310
|
+
* @returns Promise that resolves to XHTML div string
|
|
2256
2311
|
*/
|
|
2257
|
-
static
|
|
2312
|
+
static async wrapInXhtmlAsync(content, minify = false) {
|
|
2313
|
+
if (minify) {
|
|
2314
|
+
content = await this.minifyHtmlAsync(content);
|
|
2315
|
+
}
|
|
2258
2316
|
return `<div xmlns="http://www.w3.org/1999/xhtml">${content}</div>`;
|
|
2259
2317
|
}
|
|
2260
2318
|
};
|
|
@@ -2278,8 +2336,14 @@ var ComprehensiveIPSCompositionBuilder = class {
|
|
|
2278
2336
|
this.patient = patient;
|
|
2279
2337
|
return this;
|
|
2280
2338
|
}
|
|
2281
|
-
|
|
2282
|
-
|
|
2339
|
+
/**
|
|
2340
|
+
* Adds a section to the composition with async HTML minification
|
|
2341
|
+
* @param sectionType - IPS section type
|
|
2342
|
+
* @param resources - Array of domain resources
|
|
2343
|
+
* @param timezone - Optional timezone to use for date formatting
|
|
2344
|
+
* @param options - Optional configuration options
|
|
2345
|
+
*/
|
|
2346
|
+
async addSectionAsync(sectionType, resources, timezone, options) {
|
|
2283
2347
|
const validResources = resources;
|
|
2284
2348
|
for (const resource of validResources) {
|
|
2285
2349
|
this.resources.add(resource);
|
|
@@ -2291,7 +2355,13 @@ var ComprehensiveIPSCompositionBuilder = class {
|
|
|
2291
2355
|
return this;
|
|
2292
2356
|
}
|
|
2293
2357
|
if (sectionType !== "Patient" /* PATIENT */) {
|
|
2294
|
-
const narrative = NarrativeGenerator.
|
|
2358
|
+
const narrative = await NarrativeGenerator.generateNarrativeAsync(
|
|
2359
|
+
sectionType,
|
|
2360
|
+
validResources,
|
|
2361
|
+
timezone,
|
|
2362
|
+
true,
|
|
2363
|
+
false
|
|
2364
|
+
);
|
|
2295
2365
|
const sectionEntry = {
|
|
2296
2366
|
title: IPS_SECTION_DISPLAY_NAMES[sectionType] || sectionType,
|
|
2297
2367
|
code: {
|
|
@@ -2318,9 +2388,9 @@ var ComprehensiveIPSCompositionBuilder = class {
|
|
|
2318
2388
|
/**
|
|
2319
2389
|
* Reads a FHIR Bundle and extracts resources for each section defined in IPSSections.
|
|
2320
2390
|
* @param bundle - FHIR Bundle containing resources
|
|
2321
|
-
* @param timezone - Optional timezone to use for date formatting
|
|
2391
|
+
* @param timezone - Optional timezone to use for date formatting
|
|
2322
2392
|
*/
|
|
2323
|
-
|
|
2393
|
+
async readBundleAsync(bundle, timezone) {
|
|
2324
2394
|
if (!bundle.entry) {
|
|
2325
2395
|
return this;
|
|
2326
2396
|
}
|
|
@@ -2337,7 +2407,9 @@ var ComprehensiveIPSCompositionBuilder = class {
|
|
|
2337
2407
|
resources = resources.filter(customFilter);
|
|
2338
2408
|
}
|
|
2339
2409
|
if (resources.length > 0) {
|
|
2340
|
-
this.
|
|
2410
|
+
await this.addSectionAsync(sectionType, resources, timezone, {
|
|
2411
|
+
isOptional: true
|
|
2412
|
+
});
|
|
2341
2413
|
}
|
|
2342
2414
|
}
|
|
2343
2415
|
return this;
|
|
@@ -2371,7 +2443,7 @@ var ComprehensiveIPSCompositionBuilder = class {
|
|
|
2371
2443
|
* @param baseUrl - Base URL for the FHIR server (e.g., 'https://example.com/fhir')
|
|
2372
2444
|
* @param timezone - Optional timezone to use for date formatting (e.g., 'America/New_York', 'Europe/London')
|
|
2373
2445
|
*/
|
|
2374
|
-
|
|
2446
|
+
async buildBundleAsync(authorOrganizationId, authorOrganizationName, baseUrl, timezone) {
|
|
2375
2447
|
if (baseUrl.endsWith("/")) {
|
|
2376
2448
|
baseUrl = baseUrl.slice(0, -1);
|
|
2377
2449
|
}
|
|
@@ -2400,7 +2472,7 @@ var ComprehensiveIPSCompositionBuilder = class {
|
|
|
2400
2472
|
date: (/* @__PURE__ */ new Date()).toISOString(),
|
|
2401
2473
|
title: "International Patient Summary",
|
|
2402
2474
|
section: this.sections,
|
|
2403
|
-
text: this.
|
|
2475
|
+
text: await this.createCompositionNarrativeAsync(timezone)
|
|
2404
2476
|
};
|
|
2405
2477
|
const bundle = {
|
|
2406
2478
|
resourceType: "Bundle",
|
|
@@ -2445,13 +2517,14 @@ var ComprehensiveIPSCompositionBuilder = class {
|
|
|
2445
2517
|
* @param timezone - Optional timezone to use for date formatting (e.g., 'America/New_York', 'Europe/London')
|
|
2446
2518
|
* @private
|
|
2447
2519
|
*/
|
|
2448
|
-
|
|
2520
|
+
async createCompositionNarrativeAsync(timezone) {
|
|
2449
2521
|
const patient = this.patient;
|
|
2450
2522
|
let fullNarrativeContent = "";
|
|
2451
|
-
const patientNarrative = NarrativeGenerator.
|
|
2523
|
+
const patientNarrative = await NarrativeGenerator.generateNarrativeContentAsync(
|
|
2452
2524
|
"Patient" /* PATIENT */,
|
|
2453
2525
|
[patient],
|
|
2454
|
-
timezone
|
|
2526
|
+
timezone,
|
|
2527
|
+
false
|
|
2455
2528
|
);
|
|
2456
2529
|
fullNarrativeContent = fullNarrativeContent.concat(patientNarrative || "");
|
|
2457
2530
|
for (const sectionType of Object.values(IPSSections)) {
|
|
@@ -2462,13 +2535,18 @@ var ComprehensiveIPSCompositionBuilder = class {
|
|
|
2462
2535
|
const allResources = Array.from(this.resources);
|
|
2463
2536
|
const resources = allResources.filter((r) => resourceTypesForSection.includes(r.resourceType));
|
|
2464
2537
|
if (resources.length > 0) {
|
|
2465
|
-
const sectionNarrative = NarrativeGenerator.
|
|
2538
|
+
const sectionNarrative = await NarrativeGenerator.generateNarrativeContentAsync(
|
|
2539
|
+
sectionType,
|
|
2540
|
+
resources,
|
|
2541
|
+
timezone,
|
|
2542
|
+
false
|
|
2543
|
+
);
|
|
2466
2544
|
fullNarrativeContent = fullNarrativeContent.concat(sectionNarrative || "");
|
|
2467
2545
|
}
|
|
2468
2546
|
}
|
|
2469
2547
|
return {
|
|
2470
2548
|
status: "generated",
|
|
2471
|
-
div: NarrativeGenerator.
|
|
2549
|
+
div: await NarrativeGenerator.wrapInXhtmlAsync(fullNarrativeContent, true)
|
|
2472
2550
|
};
|
|
2473
2551
|
}
|
|
2474
2552
|
};
|
package/dist/index.d.cts
CHANGED
|
@@ -643,16 +643,23 @@ declare class ComprehensiveIPSCompositionBuilder {
|
|
|
643
643
|
* @param patient - FHIR Patient resource to set
|
|
644
644
|
*/
|
|
645
645
|
setPatient(patient: TPatient): this;
|
|
646
|
-
|
|
646
|
+
/**
|
|
647
|
+
* Adds a section to the composition with async HTML minification
|
|
648
|
+
* @param sectionType - IPS section type
|
|
649
|
+
* @param resources - Array of domain resources
|
|
650
|
+
* @param timezone - Optional timezone to use for date formatting
|
|
651
|
+
* @param options - Optional configuration options
|
|
652
|
+
*/
|
|
653
|
+
addSectionAsync<T extends TDomainResource>(sectionType: IPSSections, resources: T[], timezone: string | undefined, options?: {
|
|
647
654
|
isOptional?: boolean;
|
|
648
655
|
customLoincCode?: string;
|
|
649
|
-
}): this
|
|
656
|
+
}): Promise<this>;
|
|
650
657
|
/**
|
|
651
658
|
* Reads a FHIR Bundle and extracts resources for each section defined in IPSSections.
|
|
652
659
|
* @param bundle - FHIR Bundle containing resources
|
|
653
|
-
* @param timezone - Optional timezone to use for date formatting
|
|
660
|
+
* @param timezone - Optional timezone to use for date formatting
|
|
654
661
|
*/
|
|
655
|
-
|
|
662
|
+
readBundleAsync(bundle: TBundle, timezone: string | undefined): Promise<this>;
|
|
656
663
|
/**
|
|
657
664
|
* Builds the final Composition sections, ensuring all mandatory sections are present.
|
|
658
665
|
* @param timezone - Optional timezone to use for date formatting (e.g., 'America/New_York', 'Europe/London')
|
|
@@ -665,13 +672,13 @@ declare class ComprehensiveIPSCompositionBuilder {
|
|
|
665
672
|
* @param baseUrl - Base URL for the FHIR server (e.g., 'https://example.com/fhir')
|
|
666
673
|
* @param timezone - Optional timezone to use for date formatting (e.g., 'America/New_York', 'Europe/London')
|
|
667
674
|
*/
|
|
668
|
-
|
|
675
|
+
buildBundleAsync(authorOrganizationId: string, authorOrganizationName: string, baseUrl: string, timezone: string | undefined): Promise<TBundle>;
|
|
669
676
|
/**
|
|
670
677
|
* Creates a narrative for the composition based on the patient and sections.
|
|
671
678
|
* @param timezone - Optional timezone to use for date formatting (e.g., 'America/New_York', 'Europe/London')
|
|
672
679
|
* @private
|
|
673
680
|
*/
|
|
674
|
-
private
|
|
681
|
+
private createCompositionNarrativeAsync;
|
|
675
682
|
}
|
|
676
683
|
|
|
677
684
|
interface Narrative {
|
|
@@ -688,29 +695,41 @@ declare class NarrativeGenerator {
|
|
|
688
695
|
* @param section - IPS section type
|
|
689
696
|
* @param resources - Array of domain resources
|
|
690
697
|
* @param timezone - Optional timezone to use for date formatting (e.g., 'America/New_York', 'Europe/London')
|
|
698
|
+
* @param wrapInXhtml - Whether to wrap the content in XHTML div
|
|
691
699
|
* @returns Generated HTML content or undefined if no resources
|
|
692
700
|
*/
|
|
693
|
-
static
|
|
701
|
+
static generateNarrativeContentAsync<T extends TDomainResource>(section: IPSSections, resources: T[], timezone: string | undefined, wrapInXhtml?: boolean): Promise<string | undefined>;
|
|
694
702
|
/**
|
|
695
|
-
*
|
|
703
|
+
* Minifies HTML content asynchronously using html-minifier-terser
|
|
704
|
+
* @param html - HTML content to minify
|
|
705
|
+
* @param aggressive - Whether to use more aggressive minification
|
|
706
|
+
* @returns Promise that resolves to minified HTML content
|
|
707
|
+
*/
|
|
708
|
+
static minifyHtmlAsync(html: string, aggressive?: boolean): Promise<string>;
|
|
709
|
+
/**
|
|
710
|
+
* Creates a complete FHIR Narrative object asynchronously
|
|
696
711
|
* @param content - HTML content
|
|
697
|
-
* @
|
|
712
|
+
* @param minify - Whether to minify the HTML content (default: true)
|
|
713
|
+
* @returns Promise that resolves to a FHIR Narrative object
|
|
698
714
|
*/
|
|
699
|
-
static
|
|
715
|
+
static createNarrativeAsync(content: string, minify?: boolean): Promise<Narrative>;
|
|
700
716
|
/**
|
|
701
|
-
* Generates a complete FHIR Narrative object for a section
|
|
717
|
+
* Generates a complete FHIR Narrative object for a section asynchronously
|
|
702
718
|
* @param section - IPS section type
|
|
703
719
|
* @param resources - Array of domain resources
|
|
704
|
-
* @param timezone - Optional timezone to use for date formatting
|
|
705
|
-
* @
|
|
720
|
+
* @param timezone - Optional timezone to use for date formatting
|
|
721
|
+
* @param minify - Whether to minify the HTML content (default: true)
|
|
722
|
+
* @param wrapInXhtml - Whether to wrap the content in XHTML div
|
|
723
|
+
* @returns Promise that resolves to a FHIR Narrative object or undefined if no resources
|
|
706
724
|
*/
|
|
707
|
-
static
|
|
725
|
+
static generateNarrativeAsync<T extends TDomainResource>(section: IPSSections, resources: T[], timezone: string | undefined, minify: boolean | undefined, wrapInXhtml: boolean): Promise<Narrative | undefined>;
|
|
708
726
|
/**
|
|
709
|
-
* Wrap content in XHTML div with FHIR namespace
|
|
727
|
+
* Wrap content in XHTML div with FHIR namespace asynchronously
|
|
710
728
|
* @param content - HTML content to wrap
|
|
711
|
-
* @
|
|
729
|
+
* @param minify - Whether to minify the HTML content before wrapping (default: false)
|
|
730
|
+
* @returns Promise that resolves to XHTML div string
|
|
712
731
|
*/
|
|
713
|
-
static
|
|
732
|
+
static wrapInXhtmlAsync(content: string, minify?: boolean): Promise<string>;
|
|
714
733
|
}
|
|
715
734
|
|
|
716
735
|
declare const myPackage: (taco?: string) => string;
|
package/dist/index.d.ts
CHANGED
|
@@ -643,16 +643,23 @@ declare class ComprehensiveIPSCompositionBuilder {
|
|
|
643
643
|
* @param patient - FHIR Patient resource to set
|
|
644
644
|
*/
|
|
645
645
|
setPatient(patient: TPatient): this;
|
|
646
|
-
|
|
646
|
+
/**
|
|
647
|
+
* Adds a section to the composition with async HTML minification
|
|
648
|
+
* @param sectionType - IPS section type
|
|
649
|
+
* @param resources - Array of domain resources
|
|
650
|
+
* @param timezone - Optional timezone to use for date formatting
|
|
651
|
+
* @param options - Optional configuration options
|
|
652
|
+
*/
|
|
653
|
+
addSectionAsync<T extends TDomainResource>(sectionType: IPSSections, resources: T[], timezone: string | undefined, options?: {
|
|
647
654
|
isOptional?: boolean;
|
|
648
655
|
customLoincCode?: string;
|
|
649
|
-
}): this
|
|
656
|
+
}): Promise<this>;
|
|
650
657
|
/**
|
|
651
658
|
* Reads a FHIR Bundle and extracts resources for each section defined in IPSSections.
|
|
652
659
|
* @param bundle - FHIR Bundle containing resources
|
|
653
|
-
* @param timezone - Optional timezone to use for date formatting
|
|
660
|
+
* @param timezone - Optional timezone to use for date formatting
|
|
654
661
|
*/
|
|
655
|
-
|
|
662
|
+
readBundleAsync(bundle: TBundle, timezone: string | undefined): Promise<this>;
|
|
656
663
|
/**
|
|
657
664
|
* Builds the final Composition sections, ensuring all mandatory sections are present.
|
|
658
665
|
* @param timezone - Optional timezone to use for date formatting (e.g., 'America/New_York', 'Europe/London')
|
|
@@ -665,13 +672,13 @@ declare class ComprehensiveIPSCompositionBuilder {
|
|
|
665
672
|
* @param baseUrl - Base URL for the FHIR server (e.g., 'https://example.com/fhir')
|
|
666
673
|
* @param timezone - Optional timezone to use for date formatting (e.g., 'America/New_York', 'Europe/London')
|
|
667
674
|
*/
|
|
668
|
-
|
|
675
|
+
buildBundleAsync(authorOrganizationId: string, authorOrganizationName: string, baseUrl: string, timezone: string | undefined): Promise<TBundle>;
|
|
669
676
|
/**
|
|
670
677
|
* Creates a narrative for the composition based on the patient and sections.
|
|
671
678
|
* @param timezone - Optional timezone to use for date formatting (e.g., 'America/New_York', 'Europe/London')
|
|
672
679
|
* @private
|
|
673
680
|
*/
|
|
674
|
-
private
|
|
681
|
+
private createCompositionNarrativeAsync;
|
|
675
682
|
}
|
|
676
683
|
|
|
677
684
|
interface Narrative {
|
|
@@ -688,29 +695,41 @@ declare class NarrativeGenerator {
|
|
|
688
695
|
* @param section - IPS section type
|
|
689
696
|
* @param resources - Array of domain resources
|
|
690
697
|
* @param timezone - Optional timezone to use for date formatting (e.g., 'America/New_York', 'Europe/London')
|
|
698
|
+
* @param wrapInXhtml - Whether to wrap the content in XHTML div
|
|
691
699
|
* @returns Generated HTML content or undefined if no resources
|
|
692
700
|
*/
|
|
693
|
-
static
|
|
701
|
+
static generateNarrativeContentAsync<T extends TDomainResource>(section: IPSSections, resources: T[], timezone: string | undefined, wrapInXhtml?: boolean): Promise<string | undefined>;
|
|
694
702
|
/**
|
|
695
|
-
*
|
|
703
|
+
* Minifies HTML content asynchronously using html-minifier-terser
|
|
704
|
+
* @param html - HTML content to minify
|
|
705
|
+
* @param aggressive - Whether to use more aggressive minification
|
|
706
|
+
* @returns Promise that resolves to minified HTML content
|
|
707
|
+
*/
|
|
708
|
+
static minifyHtmlAsync(html: string, aggressive?: boolean): Promise<string>;
|
|
709
|
+
/**
|
|
710
|
+
* Creates a complete FHIR Narrative object asynchronously
|
|
696
711
|
* @param content - HTML content
|
|
697
|
-
* @
|
|
712
|
+
* @param minify - Whether to minify the HTML content (default: true)
|
|
713
|
+
* @returns Promise that resolves to a FHIR Narrative object
|
|
698
714
|
*/
|
|
699
|
-
static
|
|
715
|
+
static createNarrativeAsync(content: string, minify?: boolean): Promise<Narrative>;
|
|
700
716
|
/**
|
|
701
|
-
* Generates a complete FHIR Narrative object for a section
|
|
717
|
+
* Generates a complete FHIR Narrative object for a section asynchronously
|
|
702
718
|
* @param section - IPS section type
|
|
703
719
|
* @param resources - Array of domain resources
|
|
704
|
-
* @param timezone - Optional timezone to use for date formatting
|
|
705
|
-
* @
|
|
720
|
+
* @param timezone - Optional timezone to use for date formatting
|
|
721
|
+
* @param minify - Whether to minify the HTML content (default: true)
|
|
722
|
+
* @param wrapInXhtml - Whether to wrap the content in XHTML div
|
|
723
|
+
* @returns Promise that resolves to a FHIR Narrative object or undefined if no resources
|
|
706
724
|
*/
|
|
707
|
-
static
|
|
725
|
+
static generateNarrativeAsync<T extends TDomainResource>(section: IPSSections, resources: T[], timezone: string | undefined, minify: boolean | undefined, wrapInXhtml: boolean): Promise<Narrative | undefined>;
|
|
708
726
|
/**
|
|
709
|
-
* Wrap content in XHTML div with FHIR namespace
|
|
727
|
+
* Wrap content in XHTML div with FHIR namespace asynchronously
|
|
710
728
|
* @param content - HTML content to wrap
|
|
711
|
-
* @
|
|
729
|
+
* @param minify - Whether to minify the HTML content before wrapping (default: false)
|
|
730
|
+
* @returns Promise that resolves to XHTML div string
|
|
712
731
|
*/
|
|
713
|
-
static
|
|
732
|
+
static wrapInXhtmlAsync(content: string, minify?: boolean): Promise<string>;
|
|
714
733
|
}
|
|
715
734
|
|
|
716
735
|
declare const myPackage: (taco?: string) => string;
|
package/dist/index.js
CHANGED
|
@@ -921,7 +921,7 @@ var AllergyIntoleranceTemplate = class _AllergyIntoleranceTemplate {
|
|
|
921
921
|
}
|
|
922
922
|
}
|
|
923
923
|
}
|
|
924
|
-
let html =
|
|
924
|
+
let html = "";
|
|
925
925
|
html += `
|
|
926
926
|
<div class="ActiveAllergies">
|
|
927
927
|
<h3>Active Allergies and Intolerances</h3>
|
|
@@ -978,8 +978,7 @@ var AllergyIntoleranceTemplate = class _AllergyIntoleranceTemplate {
|
|
|
978
978
|
html += `
|
|
979
979
|
</tbody>
|
|
980
980
|
</table>
|
|
981
|
-
</div
|
|
982
|
-
</div>`;
|
|
981
|
+
</div>`;
|
|
983
982
|
return html;
|
|
984
983
|
}
|
|
985
984
|
/**
|
|
@@ -1089,7 +1088,7 @@ var MedicationSummaryTemplate = class _MedicationSummaryTemplate {
|
|
|
1089
1088
|
* @returns HTML string for rendering
|
|
1090
1089
|
*/
|
|
1091
1090
|
static renderMedicationRequests(templateUtilities, medications) {
|
|
1092
|
-
let html =
|
|
1091
|
+
let html = `
|
|
1093
1092
|
<table>
|
|
1094
1093
|
<thead>
|
|
1095
1094
|
<tr>
|
|
@@ -1139,7 +1138,7 @@ var MedicationSummaryTemplate = class _MedicationSummaryTemplate {
|
|
|
1139
1138
|
}
|
|
1140
1139
|
html += `
|
|
1141
1140
|
</tbody>
|
|
1142
|
-
</table
|
|
1141
|
+
</table>`;
|
|
1143
1142
|
return html;
|
|
1144
1143
|
}
|
|
1145
1144
|
/**
|
|
@@ -1149,7 +1148,7 @@ var MedicationSummaryTemplate = class _MedicationSummaryTemplate {
|
|
|
1149
1148
|
* @returns HTML string for rendering
|
|
1150
1149
|
*/
|
|
1151
1150
|
static renderMedicationStatements(templateUtilities, medications) {
|
|
1152
|
-
let html =
|
|
1151
|
+
let html = `
|
|
1153
1152
|
<table>
|
|
1154
1153
|
<thead>
|
|
1155
1154
|
<tr>
|
|
@@ -1193,7 +1192,7 @@ var MedicationSummaryTemplate = class _MedicationSummaryTemplate {
|
|
|
1193
1192
|
}
|
|
1194
1193
|
html += `
|
|
1195
1194
|
</tbody>
|
|
1196
|
-
</table
|
|
1195
|
+
</table>`;
|
|
1197
1196
|
return html;
|
|
1198
1197
|
}
|
|
1199
1198
|
};
|
|
@@ -1219,7 +1218,7 @@ var ImmunizationsTemplate = class _ImmunizationsTemplate {
|
|
|
1219
1218
|
const templateUtilities = new TemplateUtilities(resource);
|
|
1220
1219
|
let html = `
|
|
1221
1220
|
<h5>Immunizations</h5>
|
|
1222
|
-
<table
|
|
1221
|
+
<table>
|
|
1223
1222
|
<thead>
|
|
1224
1223
|
<tr>
|
|
1225
1224
|
<th>Immunization</th>
|
|
@@ -1275,7 +1274,7 @@ var ProblemListTemplate = class _ProblemListTemplate {
|
|
|
1275
1274
|
*/
|
|
1276
1275
|
static generateStaticNarrative(resource, timezone) {
|
|
1277
1276
|
const templateUtilities = new TemplateUtilities(resource);
|
|
1278
|
-
let html =
|
|
1277
|
+
let html = ``;
|
|
1279
1278
|
const activeConditions = [];
|
|
1280
1279
|
const resolvedConditions = [];
|
|
1281
1280
|
if (resource.entry && Array.isArray(resource.entry)) {
|
|
@@ -1351,7 +1350,6 @@ var ProblemListTemplate = class _ProblemListTemplate {
|
|
|
1351
1350
|
</table>
|
|
1352
1351
|
</div>`;
|
|
1353
1352
|
}
|
|
1354
|
-
html += `</div>`;
|
|
1355
1353
|
return html;
|
|
1356
1354
|
}
|
|
1357
1355
|
};
|
|
@@ -1377,7 +1375,7 @@ var VitalSignsTemplate = class _VitalSignsTemplate {
|
|
|
1377
1375
|
const templateUtilities = new TemplateUtilities(resource);
|
|
1378
1376
|
let html = `
|
|
1379
1377
|
<h5>Vital Signs</h5>
|
|
1380
|
-
<table
|
|
1378
|
+
<table>
|
|
1381
1379
|
<thead>
|
|
1382
1380
|
<tr>
|
|
1383
1381
|
<th>Code</th>
|
|
@@ -1436,7 +1434,7 @@ var MedicalDevicesTemplate = class _MedicalDevicesTemplate {
|
|
|
1436
1434
|
const templateUtilities = new TemplateUtilities(resource);
|
|
1437
1435
|
let html = `
|
|
1438
1436
|
<h5>Medical Devices</h5>
|
|
1439
|
-
<table
|
|
1437
|
+
<table>
|
|
1440
1438
|
<thead>
|
|
1441
1439
|
<tr>
|
|
1442
1440
|
<th>Device</th>
|
|
@@ -1529,7 +1527,7 @@ var DiagnosticResultsTemplate = class _DiagnosticResultsTemplate {
|
|
|
1529
1527
|
static renderObservations(templateUtilities, observations, timezone) {
|
|
1530
1528
|
let html = `
|
|
1531
1529
|
<h5>Diagnostic Results: Observations</h5>
|
|
1532
|
-
<table
|
|
1530
|
+
<table>
|
|
1533
1531
|
<thead>
|
|
1534
1532
|
<tr>
|
|
1535
1533
|
<th>Code</th>
|
|
@@ -1569,7 +1567,7 @@ var DiagnosticResultsTemplate = class _DiagnosticResultsTemplate {
|
|
|
1569
1567
|
static renderDiagnosticReports(templateUtilities, reports, timezone) {
|
|
1570
1568
|
let html = `
|
|
1571
1569
|
<h5>Diagnostic Results: Reports</h5>
|
|
1572
|
-
<table
|
|
1570
|
+
<table>
|
|
1573
1571
|
<thead>
|
|
1574
1572
|
<tr>
|
|
1575
1573
|
<th>Report</th>
|
|
@@ -1622,7 +1620,7 @@ var HistoryOfProceduresTemplate = class _HistoryOfProceduresTemplate {
|
|
|
1622
1620
|
const templateUtilities = new TemplateUtilities(resource);
|
|
1623
1621
|
let html = `
|
|
1624
1622
|
<h5>History Of Procedures</h5>
|
|
1625
|
-
<table
|
|
1623
|
+
<table>
|
|
1626
1624
|
<thead>
|
|
1627
1625
|
<tr>
|
|
1628
1626
|
<th>Procedure</th>
|
|
@@ -1673,7 +1671,7 @@ var SocialHistoryTemplate = class _SocialHistoryTemplate {
|
|
|
1673
1671
|
const templateUtilities = new TemplateUtilities(resource);
|
|
1674
1672
|
let html = `
|
|
1675
1673
|
<h5>Social History</h5>
|
|
1676
|
-
<table
|
|
1674
|
+
<table>
|
|
1677
1675
|
<thead>
|
|
1678
1676
|
<tr>
|
|
1679
1677
|
<th>Code</th>
|
|
@@ -1719,7 +1717,7 @@ var PastHistoryOfIllnessTemplate = class {
|
|
|
1719
1717
|
const templateUtilities = new TemplateUtilities(resource);
|
|
1720
1718
|
let html = `
|
|
1721
1719
|
<h5>Past History of Illnesses</h5>
|
|
1722
|
-
<table
|
|
1720
|
+
<table>
|
|
1723
1721
|
<thead>
|
|
1724
1722
|
<tr>
|
|
1725
1723
|
<th>Medical Problems</th>
|
|
@@ -1764,7 +1762,7 @@ var PlanOfCareTemplate = class {
|
|
|
1764
1762
|
const templateUtilities = new TemplateUtilities(resource);
|
|
1765
1763
|
let html = `
|
|
1766
1764
|
<h5>Plan of Care</h5>
|
|
1767
|
-
<table
|
|
1765
|
+
<table>
|
|
1768
1766
|
<thead>
|
|
1769
1767
|
<tr>
|
|
1770
1768
|
<th>Activity</th>
|
|
@@ -1819,7 +1817,7 @@ var FunctionalStatusTemplate = class _FunctionalStatusTemplate {
|
|
|
1819
1817
|
const templateUtilities = new TemplateUtilities(resource);
|
|
1820
1818
|
let html = `
|
|
1821
1819
|
<h5>Functional Status</h5>
|
|
1822
|
-
<table
|
|
1820
|
+
<table>
|
|
1823
1821
|
<thead>
|
|
1824
1822
|
<tr>
|
|
1825
1823
|
<th>Assessment</th>
|
|
@@ -1874,7 +1872,7 @@ var PregnancyTemplate = class _PregnancyTemplate {
|
|
|
1874
1872
|
const templateUtilities = new TemplateUtilities(resource);
|
|
1875
1873
|
let html = `
|
|
1876
1874
|
<h5>Pregnancy</h5>
|
|
1877
|
-
<table
|
|
1875
|
+
<table>
|
|
1878
1876
|
<thead>
|
|
1879
1877
|
<tr>
|
|
1880
1878
|
<th>Code</th>
|
|
@@ -1928,7 +1926,7 @@ var AdvanceDirectivesTemplate = class _AdvanceDirectivesTemplate {
|
|
|
1928
1926
|
const templateUtilities = new TemplateUtilities(resource);
|
|
1929
1927
|
let html = `
|
|
1930
1928
|
<h5>Advance Directives</h5>
|
|
1931
|
-
<table
|
|
1929
|
+
<table>
|
|
1932
1930
|
<thead>
|
|
1933
1931
|
<tr>
|
|
1934
1932
|
<th>Scope</th>
|
|
@@ -1972,7 +1970,7 @@ var FamilyHistoryTemplate = class {
|
|
|
1972
1970
|
const templateUtilities = new TemplateUtilities(resource);
|
|
1973
1971
|
let html = `
|
|
1974
1972
|
<h5>Family History</h5>
|
|
1975
|
-
<table
|
|
1973
|
+
<table>
|
|
1976
1974
|
<thead>
|
|
1977
1975
|
<tr>
|
|
1978
1976
|
<th>Relationship</th>
|
|
@@ -2053,7 +2051,7 @@ var ClinicalImpressionTemplate = class {
|
|
|
2053
2051
|
const templateUtilities = new TemplateUtilities(resource);
|
|
2054
2052
|
let html = `
|
|
2055
2053
|
<h5>Clinical Impressions</h5>
|
|
2056
|
-
<table
|
|
2054
|
+
<table>
|
|
2057
2055
|
<thead>
|
|
2058
2056
|
<tr>
|
|
2059
2057
|
<th>Date</th>
|
|
@@ -2165,15 +2163,42 @@ TypeScriptTemplateMapper.sectionToTemplate = {
|
|
|
2165
2163
|
};
|
|
2166
2164
|
|
|
2167
2165
|
// src/generators/narrative_generator.ts
|
|
2166
|
+
import { minify as htmlMinify } from "html-minifier-terser";
|
|
2167
|
+
var DEFAULT_MINIFY_OPTIONS = {
|
|
2168
|
+
collapseWhitespace: true,
|
|
2169
|
+
conservativeCollapse: true,
|
|
2170
|
+
// Preserves one whitespace
|
|
2171
|
+
removeComments: true,
|
|
2172
|
+
caseSensitive: true,
|
|
2173
|
+
// Important for XML/XHTML
|
|
2174
|
+
minifyCSS: true,
|
|
2175
|
+
minifyJS: false,
|
|
2176
|
+
decodeEntities: true,
|
|
2177
|
+
keepClosingSlash: true,
|
|
2178
|
+
// Important for XML/XHTML
|
|
2179
|
+
removeEmptyAttributes: true
|
|
2180
|
+
};
|
|
2181
|
+
var AGGRESSIVE_MINIFY_OPTIONS = {
|
|
2182
|
+
...DEFAULT_MINIFY_OPTIONS,
|
|
2183
|
+
collapseWhitespace: true,
|
|
2184
|
+
conservativeCollapse: false,
|
|
2185
|
+
// Don't preserve whitespace
|
|
2186
|
+
removeAttributeQuotes: true,
|
|
2187
|
+
removeRedundantAttributes: true,
|
|
2188
|
+
removeEmptyElements: false,
|
|
2189
|
+
// Don't remove empty elements as they may be semantically important
|
|
2190
|
+
removeOptionalTags: true
|
|
2191
|
+
};
|
|
2168
2192
|
var NarrativeGenerator = class {
|
|
2169
2193
|
/**
|
|
2170
2194
|
* Generates narrative HTML content for a section
|
|
2171
2195
|
* @param section - IPS section type
|
|
2172
2196
|
* @param resources - Array of domain resources
|
|
2173
2197
|
* @param timezone - Optional timezone to use for date formatting (e.g., 'America/New_York', 'Europe/London')
|
|
2198
|
+
* @param wrapInXhtml - Whether to wrap the content in XHTML div
|
|
2174
2199
|
* @returns Generated HTML content or undefined if no resources
|
|
2175
2200
|
*/
|
|
2176
|
-
static
|
|
2201
|
+
static async generateNarrativeContentAsync(section, resources, timezone, wrapInXhtml = true) {
|
|
2177
2202
|
if (!resources || resources.length === 0) {
|
|
2178
2203
|
return void 0;
|
|
2179
2204
|
}
|
|
@@ -2185,48 +2210,81 @@ var NarrativeGenerator = class {
|
|
|
2185
2210
|
resource
|
|
2186
2211
|
}))
|
|
2187
2212
|
};
|
|
2188
|
-
|
|
2213
|
+
const content = TypeScriptTemplateMapper.generateNarrative(section, bundle, timezone);
|
|
2214
|
+
if (!content) {
|
|
2215
|
+
return void 0;
|
|
2216
|
+
}
|
|
2217
|
+
if (wrapInXhtml) {
|
|
2218
|
+
return await this.wrapInXhtmlAsync(content);
|
|
2219
|
+
} else {
|
|
2220
|
+
return await this.minifyHtmlAsync(content);
|
|
2221
|
+
}
|
|
2189
2222
|
} catch (error) {
|
|
2190
2223
|
console.error(`Error generating narrative for section ${section}:`, error);
|
|
2191
2224
|
return `<div class="error">Error generating narrative: ${error instanceof Error ? error.message : String(error)}</div>`;
|
|
2192
2225
|
}
|
|
2193
2226
|
}
|
|
2194
2227
|
/**
|
|
2195
|
-
*
|
|
2228
|
+
* Minifies HTML content asynchronously using html-minifier-terser
|
|
2229
|
+
* @param html - HTML content to minify
|
|
2230
|
+
* @param aggressive - Whether to use more aggressive minification
|
|
2231
|
+
* @returns Promise that resolves to minified HTML content
|
|
2232
|
+
*/
|
|
2233
|
+
static async minifyHtmlAsync(html, aggressive = false) {
|
|
2234
|
+
if (!html) return html;
|
|
2235
|
+
try {
|
|
2236
|
+
const options = aggressive ? AGGRESSIVE_MINIFY_OPTIONS : DEFAULT_MINIFY_OPTIONS;
|
|
2237
|
+
return await htmlMinify(html, options);
|
|
2238
|
+
} catch (error) {
|
|
2239
|
+
console.warn("HTML minification failed", error);
|
|
2240
|
+
return html;
|
|
2241
|
+
}
|
|
2242
|
+
}
|
|
2243
|
+
/**
|
|
2244
|
+
* Creates a complete FHIR Narrative object asynchronously
|
|
2196
2245
|
* @param content - HTML content
|
|
2197
|
-
* @
|
|
2246
|
+
* @param minify - Whether to minify the HTML content (default: true)
|
|
2247
|
+
* @returns Promise that resolves to a FHIR Narrative object
|
|
2198
2248
|
*/
|
|
2199
|
-
static
|
|
2200
|
-
content = content.replace(/\s+/g, " ").trim();
|
|
2249
|
+
static async createNarrativeAsync(content, minify = true) {
|
|
2201
2250
|
const divMatch = content.match(/^<div[^>]*>(.*?)<\/div>$/);
|
|
2202
2251
|
if (divMatch) {
|
|
2203
2252
|
content = divMatch[1];
|
|
2204
2253
|
}
|
|
2254
|
+
if (minify) {
|
|
2255
|
+
content = await this.minifyHtmlAsync(content);
|
|
2256
|
+
}
|
|
2205
2257
|
return {
|
|
2206
2258
|
status: "generated",
|
|
2207
2259
|
div: `<div xmlns="http://www.w3.org/1999/xhtml">${content}</div>`
|
|
2208
2260
|
};
|
|
2209
2261
|
}
|
|
2210
2262
|
/**
|
|
2211
|
-
* Generates a complete FHIR Narrative object for a section
|
|
2263
|
+
* Generates a complete FHIR Narrative object for a section asynchronously
|
|
2212
2264
|
* @param section - IPS section type
|
|
2213
2265
|
* @param resources - Array of domain resources
|
|
2214
|
-
* @param timezone - Optional timezone to use for date formatting
|
|
2215
|
-
* @
|
|
2266
|
+
* @param timezone - Optional timezone to use for date formatting
|
|
2267
|
+
* @param minify - Whether to minify the HTML content (default: true)
|
|
2268
|
+
* @param wrapInXhtml - Whether to wrap the content in XHTML div
|
|
2269
|
+
* @returns Promise that resolves to a FHIR Narrative object or undefined if no resources
|
|
2216
2270
|
*/
|
|
2217
|
-
static
|
|
2218
|
-
const content = this.
|
|
2271
|
+
static async generateNarrativeAsync(section, resources, timezone, minify = true, wrapInXhtml) {
|
|
2272
|
+
const content = await this.generateNarrativeContentAsync(section, resources, timezone, wrapInXhtml);
|
|
2219
2273
|
if (!content) {
|
|
2220
2274
|
return void 0;
|
|
2221
2275
|
}
|
|
2222
|
-
return this.
|
|
2276
|
+
return await this.createNarrativeAsync(content, minify);
|
|
2223
2277
|
}
|
|
2224
2278
|
/**
|
|
2225
|
-
* Wrap content in XHTML div with FHIR namespace
|
|
2279
|
+
* Wrap content in XHTML div with FHIR namespace asynchronously
|
|
2226
2280
|
* @param content - HTML content to wrap
|
|
2227
|
-
* @
|
|
2281
|
+
* @param minify - Whether to minify the HTML content before wrapping (default: false)
|
|
2282
|
+
* @returns Promise that resolves to XHTML div string
|
|
2228
2283
|
*/
|
|
2229
|
-
static
|
|
2284
|
+
static async wrapInXhtmlAsync(content, minify = false) {
|
|
2285
|
+
if (minify) {
|
|
2286
|
+
content = await this.minifyHtmlAsync(content);
|
|
2287
|
+
}
|
|
2230
2288
|
return `<div xmlns="http://www.w3.org/1999/xhtml">${content}</div>`;
|
|
2231
2289
|
}
|
|
2232
2290
|
};
|
|
@@ -2250,8 +2308,14 @@ var ComprehensiveIPSCompositionBuilder = class {
|
|
|
2250
2308
|
this.patient = patient;
|
|
2251
2309
|
return this;
|
|
2252
2310
|
}
|
|
2253
|
-
|
|
2254
|
-
|
|
2311
|
+
/**
|
|
2312
|
+
* Adds a section to the composition with async HTML minification
|
|
2313
|
+
* @param sectionType - IPS section type
|
|
2314
|
+
* @param resources - Array of domain resources
|
|
2315
|
+
* @param timezone - Optional timezone to use for date formatting
|
|
2316
|
+
* @param options - Optional configuration options
|
|
2317
|
+
*/
|
|
2318
|
+
async addSectionAsync(sectionType, resources, timezone, options) {
|
|
2255
2319
|
const validResources = resources;
|
|
2256
2320
|
for (const resource of validResources) {
|
|
2257
2321
|
this.resources.add(resource);
|
|
@@ -2263,7 +2327,13 @@ var ComprehensiveIPSCompositionBuilder = class {
|
|
|
2263
2327
|
return this;
|
|
2264
2328
|
}
|
|
2265
2329
|
if (sectionType !== "Patient" /* PATIENT */) {
|
|
2266
|
-
const narrative = NarrativeGenerator.
|
|
2330
|
+
const narrative = await NarrativeGenerator.generateNarrativeAsync(
|
|
2331
|
+
sectionType,
|
|
2332
|
+
validResources,
|
|
2333
|
+
timezone,
|
|
2334
|
+
true,
|
|
2335
|
+
false
|
|
2336
|
+
);
|
|
2267
2337
|
const sectionEntry = {
|
|
2268
2338
|
title: IPS_SECTION_DISPLAY_NAMES[sectionType] || sectionType,
|
|
2269
2339
|
code: {
|
|
@@ -2290,9 +2360,9 @@ var ComprehensiveIPSCompositionBuilder = class {
|
|
|
2290
2360
|
/**
|
|
2291
2361
|
* Reads a FHIR Bundle and extracts resources for each section defined in IPSSections.
|
|
2292
2362
|
* @param bundle - FHIR Bundle containing resources
|
|
2293
|
-
* @param timezone - Optional timezone to use for date formatting
|
|
2363
|
+
* @param timezone - Optional timezone to use for date formatting
|
|
2294
2364
|
*/
|
|
2295
|
-
|
|
2365
|
+
async readBundleAsync(bundle, timezone) {
|
|
2296
2366
|
if (!bundle.entry) {
|
|
2297
2367
|
return this;
|
|
2298
2368
|
}
|
|
@@ -2309,7 +2379,9 @@ var ComprehensiveIPSCompositionBuilder = class {
|
|
|
2309
2379
|
resources = resources.filter(customFilter);
|
|
2310
2380
|
}
|
|
2311
2381
|
if (resources.length > 0) {
|
|
2312
|
-
this.
|
|
2382
|
+
await this.addSectionAsync(sectionType, resources, timezone, {
|
|
2383
|
+
isOptional: true
|
|
2384
|
+
});
|
|
2313
2385
|
}
|
|
2314
2386
|
}
|
|
2315
2387
|
return this;
|
|
@@ -2343,7 +2415,7 @@ var ComprehensiveIPSCompositionBuilder = class {
|
|
|
2343
2415
|
* @param baseUrl - Base URL for the FHIR server (e.g., 'https://example.com/fhir')
|
|
2344
2416
|
* @param timezone - Optional timezone to use for date formatting (e.g., 'America/New_York', 'Europe/London')
|
|
2345
2417
|
*/
|
|
2346
|
-
|
|
2418
|
+
async buildBundleAsync(authorOrganizationId, authorOrganizationName, baseUrl, timezone) {
|
|
2347
2419
|
if (baseUrl.endsWith("/")) {
|
|
2348
2420
|
baseUrl = baseUrl.slice(0, -1);
|
|
2349
2421
|
}
|
|
@@ -2372,7 +2444,7 @@ var ComprehensiveIPSCompositionBuilder = class {
|
|
|
2372
2444
|
date: (/* @__PURE__ */ new Date()).toISOString(),
|
|
2373
2445
|
title: "International Patient Summary",
|
|
2374
2446
|
section: this.sections,
|
|
2375
|
-
text: this.
|
|
2447
|
+
text: await this.createCompositionNarrativeAsync(timezone)
|
|
2376
2448
|
};
|
|
2377
2449
|
const bundle = {
|
|
2378
2450
|
resourceType: "Bundle",
|
|
@@ -2417,13 +2489,14 @@ var ComprehensiveIPSCompositionBuilder = class {
|
|
|
2417
2489
|
* @param timezone - Optional timezone to use for date formatting (e.g., 'America/New_York', 'Europe/London')
|
|
2418
2490
|
* @private
|
|
2419
2491
|
*/
|
|
2420
|
-
|
|
2492
|
+
async createCompositionNarrativeAsync(timezone) {
|
|
2421
2493
|
const patient = this.patient;
|
|
2422
2494
|
let fullNarrativeContent = "";
|
|
2423
|
-
const patientNarrative = NarrativeGenerator.
|
|
2495
|
+
const patientNarrative = await NarrativeGenerator.generateNarrativeContentAsync(
|
|
2424
2496
|
"Patient" /* PATIENT */,
|
|
2425
2497
|
[patient],
|
|
2426
|
-
timezone
|
|
2498
|
+
timezone,
|
|
2499
|
+
false
|
|
2427
2500
|
);
|
|
2428
2501
|
fullNarrativeContent = fullNarrativeContent.concat(patientNarrative || "");
|
|
2429
2502
|
for (const sectionType of Object.values(IPSSections)) {
|
|
@@ -2434,13 +2507,18 @@ var ComprehensiveIPSCompositionBuilder = class {
|
|
|
2434
2507
|
const allResources = Array.from(this.resources);
|
|
2435
2508
|
const resources = allResources.filter((r) => resourceTypesForSection.includes(r.resourceType));
|
|
2436
2509
|
if (resources.length > 0) {
|
|
2437
|
-
const sectionNarrative = NarrativeGenerator.
|
|
2510
|
+
const sectionNarrative = await NarrativeGenerator.generateNarrativeContentAsync(
|
|
2511
|
+
sectionType,
|
|
2512
|
+
resources,
|
|
2513
|
+
timezone,
|
|
2514
|
+
false
|
|
2515
|
+
);
|
|
2438
2516
|
fullNarrativeContent = fullNarrativeContent.concat(sectionNarrative || "");
|
|
2439
2517
|
}
|
|
2440
2518
|
}
|
|
2441
2519
|
return {
|
|
2442
2520
|
status: "generated",
|
|
2443
|
-
div: NarrativeGenerator.
|
|
2521
|
+
div: await NarrativeGenerator.wrapInXhtmlAsync(fullNarrativeContent, true)
|
|
2444
2522
|
};
|
|
2445
2523
|
}
|
|
2446
2524
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@imranq2/fhirpatientsummary",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.10",
|
|
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",
|
|
@@ -34,9 +34,9 @@
|
|
|
34
34
|
"test:watch": "jest --watch",
|
|
35
35
|
"test": "jest --coverage",
|
|
36
36
|
"typecheck": "tsc --noEmit",
|
|
37
|
-
"check:cjs-import": "node
|
|
38
|
-
"check:esm-import": "node --experimental-vm-modules
|
|
39
|
-
"check:ts-import": "ts-node --project tsconfig.json
|
|
37
|
+
"check:cjs-import": "node tests/build/cjs-import-check.cjs",
|
|
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"
|
|
40
40
|
},
|
|
41
41
|
"repository": {
|
|
42
42
|
"type": "git",
|
|
@@ -67,11 +67,13 @@
|
|
|
67
67
|
},
|
|
68
68
|
"homepage": "https://github.com/icanbwell/fhir-patient-summary#readme",
|
|
69
69
|
"dependencies": {
|
|
70
|
+
"html-minifier-terser": "^7.2.0",
|
|
70
71
|
"luxon": "^3.6.1",
|
|
71
72
|
"turndown": "^7.2.0"
|
|
72
73
|
},
|
|
73
74
|
"devDependencies": {
|
|
74
75
|
"@eslint/js": "^9.29.0",
|
|
76
|
+
"@types/html-minifier-terser": "^7.0.2",
|
|
75
77
|
"@types/jest": "^30.0.0",
|
|
76
78
|
"@types/js-beautify": "^1.14.3",
|
|
77
79
|
"@types/luxon": "^3.6.2",
|