fhirsmith 0.4.2 → 0.5.0
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/CHANGELOG.md +12 -0
- package/README.md +1 -1
- package/library/cron-utilities.js +136 -0
- package/library/html-server.js +13 -29
- package/library/html.js +3 -8
- package/library/languages.js +160 -37
- package/library/package-manager.js +48 -1
- package/library/utilities.js +100 -19
- package/package.json +2 -2
- package/packages/package-crawler.js +6 -1
- package/packages/packages.js +38 -54
- package/publisher/publisher.js +19 -27
- package/registry/api.js +11 -10
- package/registry/crawler.js +31 -29
- package/registry/model.js +5 -26
- package/registry/registry.js +32 -41
- package/server.js +53 -5
- package/shl/shl.js +0 -18
- package/static/assets/js/statuspage.js +1 -9
- package/stats.js +39 -1
- package/token/token.js +14 -9
- package/translations/Messages.properties +2 -1
- package/tx/README.md +17 -6
- package/tx/cs/cs-api.js +19 -1
- package/tx/cs/cs-base.js +77 -0
- package/tx/cs/cs-country.js +46 -0
- package/tx/cs/cs-cpt.js +9 -5
- package/tx/cs/cs-cs.js +27 -13
- package/tx/cs/cs-lang.js +60 -22
- package/tx/cs/cs-loinc.js +69 -98
- package/tx/cs/cs-mimetypes.js +4 -0
- package/tx/cs/cs-ndc.js +6 -0
- package/tx/cs/cs-omop.js +16 -15
- package/tx/cs/cs-rxnorm.js +23 -1
- package/tx/cs/cs-snomed.js +283 -40
- package/tx/cs/cs-ucum.js +90 -70
- package/tx/importers/import-sct.module.js +371 -35
- package/tx/importers/readme.md +117 -7
- package/tx/library/bundle.js +5 -0
- package/tx/library/capabilitystatement.js +3 -142
- package/tx/library/codesystem.js +19 -173
- package/tx/library/conceptmap.js +4 -218
- package/tx/library/designations.js +14 -1
- package/tx/library/extensions.js +7 -0
- package/tx/library/namingsystem.js +3 -89
- package/tx/library/operation-outcome.js +8 -3
- package/tx/library/parameters.js +3 -2
- package/tx/library/renderer.js +10 -6
- package/tx/library/terminologycapabilities.js +3 -243
- package/tx/library/valueset.js +3 -235
- package/tx/library.js +100 -13
- package/tx/operation-context.js +23 -4
- package/tx/params.js +35 -38
- package/tx/provider.js +6 -5
- package/tx/sct/expressions.js +12 -3
- package/tx/tx-html.js +80 -89
- package/tx/tx.fhir.org.yml +6 -5
- package/tx/tx.js +163 -13
- package/tx/vs/vs-database.js +56 -39
- package/tx/vs/vs-package.js +21 -2
- package/tx/vs/vs-vsac.js +175 -39
- package/tx/workers/batch-validate.js +2 -0
- package/tx/workers/batch.js +2 -0
- package/tx/workers/expand.js +132 -112
- package/tx/workers/lookup.js +33 -14
- package/tx/workers/metadata.js +2 -2
- package/tx/workers/read.js +3 -2
- package/tx/workers/related.js +574 -0
- package/tx/workers/search.js +46 -9
- package/tx/workers/subsumes.js +13 -3
- package/tx/workers/translate.js +7 -3
- package/tx/workers/validate.js +258 -285
- package/tx/workers/worker.js +43 -39
- package/tx/xml/bundle-xml.js +237 -0
- package/tx/xml/xml-base.js +215 -64
- package/tx/xversion/xv-bundle.js +71 -0
- package/tx/xversion/xv-capabiliityStatement.js +137 -0
- package/tx/xversion/xv-codesystem.js +169 -0
- package/tx/xversion/xv-conceptmap.js +224 -0
- package/tx/xversion/xv-namingsystem.js +88 -0
- package/tx/xversion/xv-operationoutcome.js +27 -0
- package/tx/xversion/xv-parameters.js +87 -0
- package/tx/xversion/xv-resource.js +45 -0
- package/tx/xversion/xv-terminologyCapabilities.js +214 -0
- package/tx/xversion/xv-valueset.js +234 -0
- package/utilities/dev-proxy-server.js +126 -0
- package/utilities/explode-results.js +58 -0
- package/utilities/split-by-system.js +198 -0
- package/utilities/vsac-cs-fetcher.js +0 -0
- package/{windows-install.js → utilities/windows-install.js} +2 -0
- package/vcl/vcl.js +0 -18
- package/xig/xig.js +108 -99
package/tx/tx-html.js
CHANGED
|
@@ -8,6 +8,7 @@ const path = require('path');
|
|
|
8
8
|
const htmlServer = require('../library/html-server');
|
|
9
9
|
const Logger = require('../library/logger');
|
|
10
10
|
const packageJson = require("../package.json");
|
|
11
|
+
const escape = require('escape-html');
|
|
11
12
|
|
|
12
13
|
const txHtmlLog = Logger.getInstance().child({ module: 'tx-html' });
|
|
13
14
|
|
|
@@ -62,28 +63,6 @@ class TxHtmlRenderer {
|
|
|
62
63
|
this.liquid = liquid;
|
|
63
64
|
}
|
|
64
65
|
|
|
65
|
-
/**
|
|
66
|
-
* Escape HTML special characters
|
|
67
|
-
*/
|
|
68
|
-
escapeHtml(text) {
|
|
69
|
-
if (text === null || text === undefined) {
|
|
70
|
-
return '';
|
|
71
|
-
}
|
|
72
|
-
if (typeof text !== 'string') {
|
|
73
|
-
return String(text);
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
const map = {
|
|
77
|
-
'&': '&',
|
|
78
|
-
'<': '<',
|
|
79
|
-
'>': '>',
|
|
80
|
-
'"': '"',
|
|
81
|
-
"'": '''
|
|
82
|
-
};
|
|
83
|
-
|
|
84
|
-
return text.replace(/[&<>"']/g, m => map[m]);
|
|
85
|
-
}
|
|
86
|
-
|
|
87
66
|
/**
|
|
88
67
|
* Render a page with the TX template
|
|
89
68
|
*/
|
|
@@ -102,8 +81,20 @@ class TxHtmlRenderer {
|
|
|
102
81
|
* Check if request accepts HTML
|
|
103
82
|
*/
|
|
104
83
|
acceptsHtml(req) {
|
|
105
|
-
|
|
106
|
-
|
|
84
|
+
let _fmt = req.query._format || req.query.format || req.body?._format;
|
|
85
|
+
if (_fmt && typeof _fmt !== 'string') {
|
|
86
|
+
_fmt = null;
|
|
87
|
+
}
|
|
88
|
+
if (_fmt && _fmt == 'html') {
|
|
89
|
+
return true;
|
|
90
|
+
}
|
|
91
|
+
if (!_fmt) {
|
|
92
|
+
_fmt = req.headers.accept || '';
|
|
93
|
+
}
|
|
94
|
+
if (typeof _fmt !== 'string') {
|
|
95
|
+
return false;
|
|
96
|
+
}
|
|
97
|
+
return _fmt.includes('text/html');
|
|
107
98
|
}
|
|
108
99
|
|
|
109
100
|
/**
|
|
@@ -146,7 +137,7 @@ class TxHtmlRenderer {
|
|
|
146
137
|
|
|
147
138
|
// eslint-disable-next-line no-unused-vars
|
|
148
139
|
async buildSearchForm(req, mode, params) {
|
|
149
|
-
const html = await this.liquid.renderFile('search-form', { baseUrl:
|
|
140
|
+
const html = await this.liquid.renderFile('search-form', { baseUrl: escape(req.baseUrl) });
|
|
150
141
|
return html;
|
|
151
142
|
}
|
|
152
143
|
|
|
@@ -178,8 +169,8 @@ class TxHtmlRenderer {
|
|
|
178
169
|
|
|
179
170
|
html += '<table class="grid">';
|
|
180
171
|
html += '<tr>';
|
|
181
|
-
html += `<td><strong>FHIR Version:</strong> ${
|
|
182
|
-
html += `<td><strong>Uptime:</strong> ${
|
|
172
|
+
html += `<td><strong>FHIR Version:</strong> ${escape(provider.getFhirVersion())}</td>`;
|
|
173
|
+
html += `<td><strong>Uptime:</strong> ${escape(uptimeStr)}</td>`;
|
|
183
174
|
html += `<td><strong>Request Count:</strong> ${provider.requestCount}</td>`;
|
|
184
175
|
html += '</tr>';
|
|
185
176
|
html += '<tr>';
|
|
@@ -227,7 +218,7 @@ class TxHtmlRenderer {
|
|
|
227
218
|
const sorted = [...provider.contentSources].sort();
|
|
228
219
|
html += '<ul>';
|
|
229
220
|
for (const source of sorted) {
|
|
230
|
-
html += `<li>${
|
|
221
|
+
html += `<li>${escape(source)}</li>`;
|
|
231
222
|
}
|
|
232
223
|
html += '</ul>';
|
|
233
224
|
} else {
|
|
@@ -255,9 +246,9 @@ class TxHtmlRenderer {
|
|
|
255
246
|
|
|
256
247
|
for (const factory of uniqueFactories) {
|
|
257
248
|
html += '<tr>';
|
|
258
|
-
html += `<td>${
|
|
259
|
-
html += `<td>${
|
|
260
|
-
html += `<td>${
|
|
249
|
+
html += `<td>${escape(factory.name())}</td>`;
|
|
250
|
+
html += `<td>${escape(factory.system())}</td>`;
|
|
251
|
+
html += `<td>${escape(factory.version() || '-')}</td>`;
|
|
261
252
|
html += `<td>${factory.useCount ? factory.useCount() : '-'}</td>`;
|
|
262
253
|
html += '</tr>';
|
|
263
254
|
}
|
|
@@ -329,7 +320,7 @@ class TxHtmlRenderer {
|
|
|
329
320
|
html += `<button type="button" class="btn btn-sm btn-outline-secondary" onclick="toggleJsonSource('${resourceId}')">`;
|
|
330
321
|
html += 'Show JSON Source</button>';
|
|
331
322
|
html += `<div id="${resourceId}" class="json-content" style="display: none; margin-top: 10px;">`;
|
|
332
|
-
html += `<pre>${
|
|
323
|
+
html += `<pre>${escape(JSON.stringify(json, null, 2))}</pre>`;
|
|
333
324
|
html += '</div>';
|
|
334
325
|
html += '</div>';
|
|
335
326
|
|
|
@@ -341,7 +332,7 @@ class TxHtmlRenderer {
|
|
|
341
332
|
*/
|
|
342
333
|
async renderParameter(param) {
|
|
343
334
|
let html = '<tr>';
|
|
344
|
-
html += `<td>${
|
|
335
|
+
html += `<td>${escape(param.name || '')}</td>`;
|
|
345
336
|
html += '<td>';
|
|
346
337
|
html += await this.renderParameterValue(param);
|
|
347
338
|
html += '</td>';
|
|
@@ -358,7 +349,7 @@ class TxHtmlRenderer {
|
|
|
358
349
|
let html = '<ul>';
|
|
359
350
|
for (const part of param.part) {
|
|
360
351
|
html += '<li>';
|
|
361
|
-
html += `<strong>${
|
|
352
|
+
html += `<strong>${escape(part.name || '')}:</strong> `;
|
|
362
353
|
html += await this.renderParameterValue(part);
|
|
363
354
|
html += '</li>';
|
|
364
355
|
}
|
|
@@ -393,40 +384,40 @@ class TxHtmlRenderer {
|
|
|
393
384
|
|
|
394
385
|
// Primitive types
|
|
395
386
|
if (param.valueString !== undefined) {
|
|
396
|
-
return
|
|
387
|
+
return escape(param.valueString);
|
|
397
388
|
}
|
|
398
389
|
if (param.valueBoolean !== undefined) {
|
|
399
390
|
return param.valueBoolean ? 'true' : 'false';
|
|
400
391
|
}
|
|
401
392
|
if (param.valueInteger !== undefined) {
|
|
402
|
-
return
|
|
393
|
+
return escape(String(param.valueInteger));
|
|
403
394
|
}
|
|
404
395
|
if (param.valueDecimal !== undefined) {
|
|
405
|
-
return
|
|
396
|
+
return escape(String(param.valueDecimal));
|
|
406
397
|
}
|
|
407
398
|
if (param.valueUri !== undefined) {
|
|
408
|
-
return
|
|
399
|
+
return escape(param.valueUri);
|
|
409
400
|
}
|
|
410
401
|
if (param.valueUrl !== undefined) {
|
|
411
|
-
return
|
|
402
|
+
return escape(param.valueUrl);
|
|
412
403
|
}
|
|
413
404
|
if (param.valueCanonical !== undefined) {
|
|
414
|
-
return
|
|
405
|
+
return escape(param.valueCanonical);
|
|
415
406
|
}
|
|
416
407
|
if (param.valueCode !== undefined) {
|
|
417
|
-
return `<code>${
|
|
408
|
+
return `<code>${escape(param.valueCode)}</code>`;
|
|
418
409
|
}
|
|
419
410
|
if (param.valueDate !== undefined) {
|
|
420
|
-
return
|
|
411
|
+
return escape(param.valueDate);
|
|
421
412
|
}
|
|
422
413
|
if (param.valueDateTime !== undefined) {
|
|
423
|
-
return
|
|
414
|
+
return escape(param.valueDateTime);
|
|
424
415
|
}
|
|
425
416
|
if (param.valueTime !== undefined) {
|
|
426
|
-
return
|
|
417
|
+
return escape(param.valueTime);
|
|
427
418
|
}
|
|
428
419
|
if (param.valueInstant !== undefined) {
|
|
429
|
-
return
|
|
420
|
+
return escape(param.valueInstant);
|
|
430
421
|
}
|
|
431
422
|
|
|
432
423
|
return '<em>(empty)</em>';
|
|
@@ -440,16 +431,16 @@ class TxHtmlRenderer {
|
|
|
440
431
|
|
|
441
432
|
let parts = [];
|
|
442
433
|
if (coding.system) {
|
|
443
|
-
parts.push(
|
|
434
|
+
parts.push(escape(coding.system));
|
|
444
435
|
}
|
|
445
436
|
if (coding.code) {
|
|
446
|
-
parts.push(`<code>${
|
|
437
|
+
parts.push(`<code>${escape(coding.code)}</code>`);
|
|
447
438
|
}
|
|
448
439
|
if (coding.display) {
|
|
449
|
-
parts.push(`"${
|
|
440
|
+
parts.push(`"${escape(coding.display)}"`);
|
|
450
441
|
}
|
|
451
442
|
if (coding.version) {
|
|
452
|
-
parts.push(`(version: ${
|
|
443
|
+
parts.push(`(version: ${escape(coding.version)})`);
|
|
453
444
|
}
|
|
454
445
|
|
|
455
446
|
return parts.join(' | ') || '<em>(empty coding)</em>';
|
|
@@ -464,7 +455,7 @@ class TxHtmlRenderer {
|
|
|
464
455
|
let html = '';
|
|
465
456
|
|
|
466
457
|
if (cc.text) {
|
|
467
|
-
html += `<strong>${
|
|
458
|
+
html += `<strong>${escape(cc.text)}</strong>`;
|
|
468
459
|
}
|
|
469
460
|
|
|
470
461
|
if (cc.coding && Array.isArray(cc.coding) && cc.coding.length > 0) {
|
|
@@ -488,18 +479,18 @@ class TxHtmlRenderer {
|
|
|
488
479
|
let html = '';
|
|
489
480
|
|
|
490
481
|
if (qty.comparator) {
|
|
491
|
-
html +=
|
|
482
|
+
html += escape(qty.comparator) + ' ';
|
|
492
483
|
}
|
|
493
484
|
if (qty.value !== undefined) {
|
|
494
|
-
html +=
|
|
485
|
+
html += escape(String(qty.value));
|
|
495
486
|
}
|
|
496
487
|
if (qty.unit) {
|
|
497
|
-
html += ' ' +
|
|
488
|
+
html += ' ' + escape(qty.unit);
|
|
498
489
|
} else if (qty.code) {
|
|
499
|
-
html += ' ' +
|
|
490
|
+
html += ' ' + escape(qty.code);
|
|
500
491
|
}
|
|
501
492
|
if (qty.system) {
|
|
502
|
-
html += ` <small>(${
|
|
493
|
+
html += ` <small>(${escape(qty.system)})</small>`;
|
|
503
494
|
}
|
|
504
495
|
|
|
505
496
|
return html || '<em>(empty Quantity)</em>';
|
|
@@ -514,19 +505,19 @@ class TxHtmlRenderer {
|
|
|
514
505
|
let html = '';
|
|
515
506
|
|
|
516
507
|
if (att.title) {
|
|
517
|
-
html += `<strong>${
|
|
508
|
+
html += `<strong>${escape(att.title)}</strong><br/>`;
|
|
518
509
|
}
|
|
519
510
|
if (att.contentType) {
|
|
520
|
-
html += `Content-Type: ${
|
|
511
|
+
html += `Content-Type: ${escape(att.contentType)}<br/>`;
|
|
521
512
|
}
|
|
522
513
|
if (att.url) {
|
|
523
|
-
html += `URL: <a href="${
|
|
514
|
+
html += `URL: <a href="${escape(att.url)}">${escape(att.url)}</a><br/>`;
|
|
524
515
|
}
|
|
525
516
|
if (att.size !== undefined) {
|
|
526
|
-
html += `Size: ${
|
|
517
|
+
html += `Size: ${escape(String(att.size))} bytes<br/>`;
|
|
527
518
|
}
|
|
528
519
|
if (att.language) {
|
|
529
|
-
html += `Language: ${
|
|
520
|
+
html += `Language: ${escape(att.language)}<br/>`;
|
|
530
521
|
}
|
|
531
522
|
if (att.data) {
|
|
532
523
|
html += `<small>(base64 data present, ${att.data.length} chars)</small>`;
|
|
@@ -544,16 +535,16 @@ class TxHtmlRenderer {
|
|
|
544
535
|
let parts = [];
|
|
545
536
|
|
|
546
537
|
if (id.use) {
|
|
547
|
-
parts.push(`[${
|
|
538
|
+
parts.push(`[${escape(id.use)}]`);
|
|
548
539
|
}
|
|
549
540
|
if (id.type && id.type.text) {
|
|
550
|
-
parts.push(
|
|
541
|
+
parts.push(escape(id.type.text));
|
|
551
542
|
}
|
|
552
543
|
if (id.system) {
|
|
553
|
-
parts.push(
|
|
544
|
+
parts.push(escape(id.system));
|
|
554
545
|
}
|
|
555
546
|
if (id.value) {
|
|
556
|
-
parts.push(`<strong>${
|
|
547
|
+
parts.push(`<strong>${escape(id.value)}</strong>`);
|
|
557
548
|
}
|
|
558
549
|
if (id.period) {
|
|
559
550
|
parts.push(this.renderPeriod(id.period));
|
|
@@ -571,11 +562,11 @@ class TxHtmlRenderer {
|
|
|
571
562
|
let html = '';
|
|
572
563
|
|
|
573
564
|
if (period.start && period.end) {
|
|
574
|
-
html = `${
|
|
565
|
+
html = `${escape(period.start)} to ${escape(period.end)}`;
|
|
575
566
|
} else if (period.start) {
|
|
576
|
-
html = `from ${
|
|
567
|
+
html = `from ${escape(period.start)}`;
|
|
577
568
|
} else if (period.end) {
|
|
578
|
-
html = `until ${
|
|
569
|
+
html = `until ${escape(period.end)}`;
|
|
579
570
|
}
|
|
580
571
|
|
|
581
572
|
return html || '<em>(empty Period)</em>';
|
|
@@ -590,7 +581,7 @@ class TxHtmlRenderer {
|
|
|
590
581
|
if (!inBundle) {
|
|
591
582
|
html += await this.liquid.renderFile('codesystem-operations', {
|
|
592
583
|
opsId: this.generateResourceId(),
|
|
593
|
-
url:
|
|
584
|
+
url: escape(json.url || '')
|
|
594
585
|
});
|
|
595
586
|
}
|
|
596
587
|
|
|
@@ -608,7 +599,7 @@ class TxHtmlRenderer {
|
|
|
608
599
|
opsId: this.generateResourceId(),
|
|
609
600
|
vcSystemId: this.generateResourceId(),
|
|
610
601
|
inferSystemId: this.generateResourceId(),
|
|
611
|
-
url:
|
|
602
|
+
url: escape(json.url || '')
|
|
612
603
|
});
|
|
613
604
|
}
|
|
614
605
|
|
|
@@ -665,9 +656,9 @@ class TxHtmlRenderer {
|
|
|
665
656
|
}
|
|
666
657
|
|
|
667
658
|
html += '">';
|
|
668
|
-
html += `<strong>${
|
|
669
|
-
html += `[${
|
|
670
|
-
html +=
|
|
659
|
+
html += `<strong>${escape(issue.severity || 'unknown')}:</strong> `;
|
|
660
|
+
html += `[${escape(issue.code || 'unknown')}] `;
|
|
661
|
+
html += escape(issue.diagnostics || issue.details?.text || 'No details');
|
|
671
662
|
html += '</div>';
|
|
672
663
|
}
|
|
673
664
|
}
|
|
@@ -741,18 +732,18 @@ class TxHtmlRenderer {
|
|
|
741
732
|
const params = resourceType === 'CodeSystem' ? CODESYSTEM_PARAMS : SEARCH_PARAMS;
|
|
742
733
|
|
|
743
734
|
let html = '<div class="alert alert-info">Enter search criteria:</div>';
|
|
744
|
-
html += `<form method="get" action="${
|
|
735
|
+
html += `<form method="get" action="${escape(req.baseUrl)}/${escape(resourceType)}">`;
|
|
745
736
|
html += '<div class="row">';
|
|
746
737
|
|
|
747
738
|
// Build form fields
|
|
748
739
|
for (const param of params) {
|
|
749
740
|
html += '<div class="col-md-4 mb-3">';
|
|
750
|
-
html += `<label for="${param.name}" class="form-label">${
|
|
741
|
+
html += `<label for="${param.name}" class="form-label">${escape(param.label)}</label>`;
|
|
751
742
|
|
|
752
743
|
if (param.type === 'select') {
|
|
753
744
|
html += `<select name="${param.name}" id="${param.name}" class="form-select">`;
|
|
754
745
|
for (const opt of param.options) {
|
|
755
|
-
html += `<option value="${
|
|
746
|
+
html += `<option value="${escape(opt)}">${escape(opt || '(any)')}</option>`;
|
|
756
747
|
}
|
|
757
748
|
html += '</select>';
|
|
758
749
|
} else {
|
|
@@ -770,7 +761,7 @@ class TxHtmlRenderer {
|
|
|
770
761
|
html += '<label for="_sort" class="form-label">Sort By</label>';
|
|
771
762
|
html += '<select name="_sort" id="_sort" class="form-select">';
|
|
772
763
|
for (const opt of SORT_OPTIONS) {
|
|
773
|
-
html += `<option value="${
|
|
764
|
+
html += `<option value="${escape(opt)}">${escape(opt || '(default)')}</option>`;
|
|
774
765
|
}
|
|
775
766
|
html += '</select>';
|
|
776
767
|
html += '</div>';
|
|
@@ -781,8 +772,8 @@ class TxHtmlRenderer {
|
|
|
781
772
|
html += '<label class="form-label">Elements to include:</label><br/>';
|
|
782
773
|
for (const elem of ELEMENT_OPTIONS) {
|
|
783
774
|
html += `<div class="form-check form-check-inline">`;
|
|
784
|
-
html += `<input type="checkbox" name="_elements" value="${
|
|
785
|
-
html += `<label for="elem_${elem}" class="form-check-label">${
|
|
775
|
+
html += `<input type="checkbox" name="_elements" value="${escape(elem)}" id="elem_${elem}" class="form-check-input"/>`;
|
|
776
|
+
html += `<label for="elem_${elem}" class="form-check-label">${escape(elem)}</label>`;
|
|
786
777
|
html += '</div>';
|
|
787
778
|
}
|
|
788
779
|
html += '</div>';
|
|
@@ -827,7 +818,7 @@ class TxHtmlRenderer {
|
|
|
827
818
|
html += '<th>ID</th>';
|
|
828
819
|
for (const elem of elements) {
|
|
829
820
|
if (elem !== 'id') {
|
|
830
|
-
html += `<th>${
|
|
821
|
+
html += `<th>${escape(elem)}</th>`;
|
|
831
822
|
}
|
|
832
823
|
}
|
|
833
824
|
html += '</tr></thead>';
|
|
@@ -842,13 +833,13 @@ class TxHtmlRenderer {
|
|
|
842
833
|
// ID column with link
|
|
843
834
|
const id = resource.id || '';
|
|
844
835
|
const resourceType = resource.resourceType || '';
|
|
845
|
-
html += `<td><a href="${
|
|
836
|
+
html += `<td><a href="${escape(req.baseUrl)}/${escape(resourceType)}/${escape(id)}">${escape(id)}</a></td>`;
|
|
846
837
|
|
|
847
838
|
// Other element columns
|
|
848
839
|
for (const elem of elements) {
|
|
849
840
|
if (elem !== 'id') {
|
|
850
841
|
const value = resource[elem];
|
|
851
|
-
html += `<td>${
|
|
842
|
+
html += `<td>${escape(this.formatValue(value))}</td>`;
|
|
852
843
|
}
|
|
853
844
|
}
|
|
854
845
|
|
|
@@ -879,7 +870,7 @@ class TxHtmlRenderer {
|
|
|
879
870
|
html += '<div class="card mb-3">';
|
|
880
871
|
html += '<div class="card-header">Bundle Summary</div>';
|
|
881
872
|
html += '<div class="card-body">';
|
|
882
|
-
html += `<p><strong>Type:</strong> ${
|
|
873
|
+
html += `<p><strong>Type:</strong> ${escape(json.type)}</p>`;
|
|
883
874
|
html += `<p><strong>Total:</strong> ${total}</p>`;
|
|
884
875
|
html += '</div>';
|
|
885
876
|
html += '</div>';
|
|
@@ -890,10 +881,10 @@ class TxHtmlRenderer {
|
|
|
890
881
|
|
|
891
882
|
if (entry.resource) {
|
|
892
883
|
const resource = entry.resource;
|
|
893
|
-
html += `<h4>${
|
|
884
|
+
html += `<h4>${escape(resource.resourceType)}/${escape(resource.id || 'unknown')}</h4>`;
|
|
894
885
|
|
|
895
886
|
if (entry.fullUrl) {
|
|
896
|
-
html += `<p><small><a href="${
|
|
887
|
+
html += `<p><small><a href="${escape(entry.fullUrl)}">${escape(entry.fullUrl)}</a></small></p>`;
|
|
897
888
|
}
|
|
898
889
|
|
|
899
890
|
// Render the resource
|
|
@@ -925,9 +916,9 @@ class TxHtmlRenderer {
|
|
|
925
916
|
const label = rel.charAt(0).toUpperCase() + rel.slice(1);
|
|
926
917
|
|
|
927
918
|
if (isDisabled) {
|
|
928
|
-
html += `<li class="page-item active"><span class="page-link">${
|
|
919
|
+
html += `<li class="page-item active"><span class="page-link">${escape(label)}</span></li>`;
|
|
929
920
|
} else {
|
|
930
|
-
html += `<li class="page-item"><a class="page-link" href="${
|
|
921
|
+
html += `<li class="page-item"><a class="page-link" href="${escape(link.url)}">${escape(label)}</a></li>`;
|
|
931
922
|
}
|
|
932
923
|
}
|
|
933
924
|
}
|
|
@@ -943,7 +934,7 @@ class TxHtmlRenderer {
|
|
|
943
934
|
let html = '<div class="card mb-3">';
|
|
944
935
|
html += '<div class="card-header">Bundle</div>';
|
|
945
936
|
html += '<div class="card-body">';
|
|
946
|
-
html += `<p><strong>Type:</strong> ${
|
|
937
|
+
html += `<p><strong>Type:</strong> ${escape(json.type)}</p>`;
|
|
947
938
|
html += `<p><strong>Total:</strong> ${json.total || 'N/A'}</p>`;
|
|
948
939
|
html += '</div>';
|
|
949
940
|
html += '</div>';
|
|
@@ -953,7 +944,7 @@ class TxHtmlRenderer {
|
|
|
953
944
|
html += '<h4>Links</h4>';
|
|
954
945
|
html += '<ul>';
|
|
955
946
|
for (const link of json.link) {
|
|
956
|
-
html += `<li><strong>${
|
|
947
|
+
html += `<li><strong>${escape(link.relation)}:</strong> <a href="${escape(link.url)}">${escape(link.url)}</a></li>`;
|
|
957
948
|
}
|
|
958
949
|
html += '</ul>';
|
|
959
950
|
}
|
|
@@ -1038,7 +1029,7 @@ class TxHtmlRenderer {
|
|
|
1038
1029
|
html += `<button type="button" class="btn btn-sm btn-outline-secondary" onclick="toggleJsonSource('${resourceId}')">`;
|
|
1039
1030
|
html += 'Show JSON Source</button>';
|
|
1040
1031
|
html += `<div id="${resourceId}" class="json-content" style="display: none; margin-top: 10px;">`;
|
|
1041
|
-
html += `<pre>${
|
|
1032
|
+
html += `<pre>${escape(JSON.stringify(json, null, 2))}</pre>`;
|
|
1042
1033
|
html += '</div>';
|
|
1043
1034
|
html += '</div>';
|
|
1044
1035
|
|
package/tx/tx.fhir.org.yml
CHANGED
|
@@ -10,12 +10,13 @@ sources:
|
|
|
10
10
|
- internal:usstates
|
|
11
11
|
- internal:hgvs
|
|
12
12
|
- ucum:tx/data/ucum-essence.xml
|
|
13
|
-
- loinc:loinc-2.
|
|
13
|
+
- loinc:loinc-2.77-a.db
|
|
14
|
+
- loinc!:loinc-2.81-b.db
|
|
14
15
|
- rxnorm:rxnorm_02032025-a.db
|
|
15
16
|
- ndc:ndc-20211101.db
|
|
16
17
|
- unii:unii_20240622.db
|
|
17
|
-
- snomed!:sct_intl_20250201.cache
|
|
18
18
|
- snomed:sct_intl_20240201.cache
|
|
19
|
+
- snomed!:sct_intl_20250201.cache
|
|
19
20
|
- snomed:sct_se_20231130.cache
|
|
20
21
|
- snomed:sct_au_20230731.cache
|
|
21
22
|
- snomed:sct_be_20231115.cache
|
|
@@ -24,16 +25,16 @@ sources:
|
|
|
24
25
|
- snomed:sct_ips_20241216.cache
|
|
25
26
|
- snomed:sct_nl_20240930.cache
|
|
26
27
|
- snomed:sct_uk_20230412.cache
|
|
27
|
-
- snomed:sct_us_20250901.cache
|
|
28
28
|
- snomed:sct_us_20230301.cache
|
|
29
|
+
- snomed:sct_us_20250901.cache
|
|
29
30
|
- snomed:sct_test_20250814.cache
|
|
30
|
-
- cpt:cpt-2023-fragment-0.1.db
|
|
31
|
+
- cpt:CodeSystem-cpt.db|cpt-2023-fragment-0.1.db
|
|
31
32
|
- omop:omop_v20250227.db
|
|
32
33
|
- npm:hl7.terminology
|
|
33
34
|
- npm:fhir.tx.support.r4
|
|
34
35
|
- npm:ihe.formatcode.fhir
|
|
35
36
|
- npm:fhir.dicom
|
|
36
37
|
- npm:hl7.fhir.us.core
|
|
37
|
-
- npm:us.nlm.vsac
|
|
38
38
|
- npm:us.cdc.phinvads
|
|
39
39
|
- npm:hl7.fhir.uv.sdc
|
|
40
|
+
- internal:vsac
|