fhirsmith 0.8.0 → 0.8.3
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 +41 -0
- package/README.md +9 -5
- package/package.json +1 -1
- package/packages/package-crawler.js +1 -1
- package/publisher/publisher.js +257 -218
- package/root-bare-template.html +0 -3
- package/security.md +3 -0
- package/server.js +29 -24
- package/shl/readme.md +27 -0
- package/shl/shl.js +2 -8
- package/stats.js +1 -1
- package/tx/cs/cs-api.js +8 -4
- package/tx/cs/cs-omop.js +5 -3
- package/tx/cs/cs-rxnorm.js +4 -6
- package/tx/cs/cs-snomed.js +113 -1
- package/tx/data/cpt-fragment.db +0 -0
- package/tx/data/cs-de.json +186 -0
- package/tx/data/cs-extensions.json +92 -0
- package/tx/data/cs-simple.json +130 -0
- package/tx/data/cs-supplement.json +78 -0
- package/tx/data/lang.dat +49180 -0
- package/tx/data/languages.csv +191 -0
- package/tx/data/loinc-subset.txt +75 -0
- package/tx/data/omop-fragment.db +0 -0
- package/tx/data/readme.md +43 -0
- package/tx/data/regions.csv +273 -0
- package/tx/data/rxnorm-subset.txt +22 -0
- package/tx/data/snomed-subset.txt +47 -0
- package/tx/data/ucum-essence.xml +2059 -0
- package/tx/library/conceptmap.js +26 -0
- package/tx/library/extensions.js +4 -3
- package/tx/params.js +2 -2
- package/tx/provider.js +4 -1
- package/tx/sct/structures.js +1 -1
- package/tx/workers/expand.js +10 -10
- package/tx/workers/related.js +2 -2
- package/tx/workers/translate.js +184 -20
- package/tx/workers/validate.js +10 -10
- package/tx/xversion/xv-parameters.js +54 -1
package/root-bare-template.html
CHANGED
|
@@ -9,9 +9,6 @@
|
|
|
9
9
|
<meta content="http://hl7.org/fhir" name="author"/>
|
|
10
10
|
<meta charset="utf-8" http-equiv="X-UA-Compatible" content="IE=edge" />
|
|
11
11
|
|
|
12
|
-
<link rel="stylesheet" href="/fhir.css"/>
|
|
13
|
-
|
|
14
|
-
|
|
15
12
|
<!-- Bootstrap core CSS -->
|
|
16
13
|
<link rel="stylesheet" href="/assets/css/bootstrap.css"/>
|
|
17
14
|
<link rel="stylesheet" href="/assets/css/bootstrap-fhir.css"/>
|
package/security.md
CHANGED
package/server.js
CHANGED
|
@@ -11,6 +11,7 @@ const express = require('express');
|
|
|
11
11
|
const path = require('path');
|
|
12
12
|
const fs = require('fs');
|
|
13
13
|
const os = require('os');
|
|
14
|
+
const v8 = require('v8');
|
|
14
15
|
const folders = require('./library/folder-setup'); // <-- ADD: load early
|
|
15
16
|
const { statSync, readdirSync } = require('fs');
|
|
16
17
|
const escape = require('escape-html');
|
|
@@ -41,8 +42,8 @@ serverLog.info(`Data directory: ${folders.dataDir()}`);
|
|
|
41
42
|
serverLog.info(`========================================`);
|
|
42
43
|
|
|
43
44
|
const activeModules = config.modules ? Object.keys(config.modules)
|
|
44
|
-
|
|
45
|
-
|
|
45
|
+
.filter(mod => config.modules[mod].enabled)
|
|
46
|
+
.join(', ') : [];
|
|
46
47
|
serverLog.info(`Loaded Configuration. Active modules = ${activeModules}`);
|
|
47
48
|
|
|
48
49
|
// Import modules
|
|
@@ -541,20 +542,21 @@ app.get('/dashboard', async (req, res) => {
|
|
|
541
542
|
|
|
542
543
|
// Memory usage
|
|
543
544
|
const memUsage = process.memoryUsage();
|
|
544
|
-
const
|
|
545
|
-
const
|
|
546
|
-
const
|
|
547
|
-
const
|
|
545
|
+
const heapStats = v8.getHeapStatistics();
|
|
546
|
+
const nodeMemPCT = (memUsage.heapUsed * 100) / heapStats.heap_size_limit; // % of Node.js memory limit used
|
|
547
|
+
const totalMemBytes = os.totalmem();
|
|
548
|
+
const freeMemBytes = os.freemem();
|
|
549
|
+
const sysMemPCT = ((totalMemBytes - freeMemBytes) * 100) / totalMemBytes; // % of system memory used
|
|
548
550
|
const fstats = fs.statfsSync(folders.logsDir());
|
|
549
|
-
const diskPCT = (fstats.bavail * 100) / fstats.blocks;
|
|
551
|
+
const diskPCT = 100 - ((fstats.bavail * 100) / fstats.blocks); // % of disk used
|
|
550
552
|
|
|
551
|
-
let content = '';
|
|
552
|
-
content += '<table
|
|
553
|
+
let content = '<style>table.grid{margin-bottom:10px;border:1px solid black;margin-right:auto}table.grid th,table.grid td{border:1px solid silver;padding:3px 7px 2px;font-size:12px;line-height:1.4em;font-family:verdana;vertical-align:top}table.grid th{font-weight:bold}table.grid td{font-weight:normal}</style>';
|
|
554
|
+
content += '<table class="grid">';
|
|
553
555
|
content += '<tr>';
|
|
554
556
|
content += `<td><strong>Uptime:</strong> ${escape(uptimeStr)}</td>`;
|
|
555
557
|
content += `<td><strong>Request Count:</strong> ${stats.requestCount} (static: ${stats.staticRequestCount})</td>`;
|
|
556
|
-
content += `<td style="background-color:${pctColor(
|
|
557
|
-
content += `<td style="background-color:${pctColor(
|
|
558
|
+
content += `<td style="background-color:${pctColor(nodeMemPCT)}"><strong>Node Memory:</strong> ${nodeMemPCT.toFixed(0)}%</td>`;
|
|
559
|
+
content += `<td style="background-color:${pctColor(sysMemPCT)}"><strong>System Memory:</strong> ${sysMemPCT.toFixed(0)}%</td>`;
|
|
558
560
|
content += `<td style="background-color:${pctColor(diskPCT)}"><strong>Disk:</strong> ${diskPCT.toFixed(0)}%</td>`;
|
|
559
561
|
content += '</tr>';
|
|
560
562
|
content += '</table>';
|
|
@@ -590,9 +592,12 @@ app.get('/dashboard', async (req, res) => {
|
|
|
590
592
|
});
|
|
591
593
|
|
|
592
594
|
function pctColor(pct) {
|
|
593
|
-
|
|
594
|
-
const
|
|
595
|
-
|
|
595
|
+
// Gradient from green (#deffe0) at 0% to red (#ffd3d1) at 100%
|
|
596
|
+
const t = Math.max(0, Math.min(100, pct)) / 100;
|
|
597
|
+
const r = Math.round(222 + 33 * t); // 222 -> 255
|
|
598
|
+
const g = Math.round(255 - 44 * t); // 255 -> 211
|
|
599
|
+
const b = Math.round(224 - 15 * t); // 224 -> 209
|
|
600
|
+
return `rgb(${r}, ${g}, ${b})`;
|
|
596
601
|
}
|
|
597
602
|
|
|
598
603
|
// Health check endpoint
|
|
@@ -659,10 +664,10 @@ function getLogStats() {
|
|
|
659
664
|
const limitInfo = `${maxFiles} files × ${maxSize} each`;
|
|
660
665
|
|
|
661
666
|
return '<tr>'
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
667
|
+
+ `<td><strong>Existing Logs:</strong> ${files.length} (${sizeMB} MB)</td>`
|
|
668
|
+
+ `<td><strong>Retention Policy:</strong> ${limitInfo}</td>`
|
|
669
|
+
+ diskInfo
|
|
670
|
+
+ '</tr>';
|
|
666
671
|
} catch (e) {
|
|
667
672
|
return `<tr><td colspan="3"><strong>Logs:</strong> unable to read (${e.message})</td></tr>`;
|
|
668
673
|
}
|
|
@@ -793,12 +798,12 @@ async function serveFhirsmithHome(req, res) {
|
|
|
793
798
|
endpoints: {
|
|
794
799
|
health: '/health',
|
|
795
800
|
...Object.fromEntries(
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
801
|
+
Object.keys(enabledModules)
|
|
802
|
+
.filter(m => m !== 'tx')
|
|
803
|
+
.map(m => [
|
|
804
|
+
m,
|
|
805
|
+
m === 'vcl' ? '/VCL' : `/${m}`
|
|
806
|
+
])
|
|
802
807
|
),
|
|
803
808
|
// Add TX endpoints separately
|
|
804
809
|
...(enabledModules.tx ? {
|
package/shl/readme.md
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
To generate a certificate:
|
|
2
|
+
|
|
3
|
+
```shell
|
|
4
|
+
# Generate EC P-256 private key
|
|
5
|
+
openssl ecparam -name prime256v1 -genkey -noout -out private-key.pem
|
|
6
|
+
|
|
7
|
+
# Extract the public key / self-signed cert
|
|
8
|
+
openssl req -new -x509 -key private-key.pem -out public-key.pem -days 3650 \
|
|
9
|
+
-subj "/CN=fhirsmith-shl"
|
|
10
|
+
|
|
11
|
+
node -e "
|
|
12
|
+
const crypto = require('crypto');
|
|
13
|
+
const fs = require('fs');
|
|
14
|
+
const key = crypto.createPrivateKey(fs.readFileSync('private-key.pem'));
|
|
15
|
+
const jwk = key.export({format:'jwk'});
|
|
16
|
+
const thumbprint = crypto.createHash('sha256')
|
|
17
|
+
.update(JSON.stringify({crv:jwk.crv,kty:jwk.kty,x:jwk.x,y:jwk.y}))
|
|
18
|
+
.digest('base64url');
|
|
19
|
+
console.log('kid: '+thumbprint);
|
|
20
|
+
"
|
|
21
|
+
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
Config:
|
|
25
|
+
|
|
26
|
+
All files will be in {data}/shl. the file paths in the config are relative to
|
|
27
|
+
that location
|
package/shl/shl.js
CHANGED
|
@@ -396,14 +396,8 @@ class SHLModule {
|
|
|
396
396
|
|
|
397
397
|
loadCertificates() {
|
|
398
398
|
try {
|
|
399
|
-
const certPath =
|
|
400
|
-
const keyPath =
|
|
401
|
-
|
|
402
|
-
// Validate paths to prevent directory traversal
|
|
403
|
-
if (!certPath.startsWith(path.resolve(__dirname)) ||
|
|
404
|
-
!keyPath.startsWith(path.resolve(__dirname))) {
|
|
405
|
-
throw new Error('Certificate paths outside allowed directory');
|
|
406
|
-
}
|
|
399
|
+
const certPath = folders.filePath('shl', this.config.certificates.certFile);
|
|
400
|
+
const keyPath = folders.filePath('shl', this.config.certificates.keyFile);
|
|
407
401
|
|
|
408
402
|
const certPem = fs.readFileSync(certPath, 'utf8');
|
|
409
403
|
const keyPem = fs.readFileSync(keyPath, 'utf8');
|
package/stats.js
CHANGED
|
@@ -118,7 +118,7 @@ class ServerStats {
|
|
|
118
118
|
if (this.taskMap.size == 0) {
|
|
119
119
|
return "";
|
|
120
120
|
}
|
|
121
|
-
let html = '<table class="grid">';
|
|
121
|
+
let html = '<table class="grid" >';
|
|
122
122
|
html += "<tr><th>Background Task</th><th>Status</th><th>Frequency</th><th>Last Seen</th></tr>";
|
|
123
123
|
for (let m of this.taskMap.keys()) {
|
|
124
124
|
let mm = this.taskMap.get(m);
|
package/tx/cs/cs-api.js
CHANGED
|
@@ -673,11 +673,13 @@ class CodeSystemProvider {
|
|
|
673
673
|
/**
|
|
674
674
|
* register the concept maps that are implicitly defined as part of the code system
|
|
675
675
|
*
|
|
676
|
+
* @param {ConceptMap} map the map (this will have been returned from findImplicitConceptMap)
|
|
676
677
|
* @param {Coding} coding the coding to translate
|
|
677
|
-
* @param {String} target
|
|
678
|
-
* @
|
|
678
|
+
* @param {String} target the target code system
|
|
679
|
+
* @param {boolean} reverse - if the translation is being run backwards
|
|
680
|
+
* @returns {CodeTranslation[]} the list of translations, each CodeTranslation has map, code, system, version, display, and relationship
|
|
679
681
|
*/
|
|
680
|
-
async getTranslations(coding, target) { return null;}
|
|
682
|
+
async getTranslations(map, coding, target, reverse) { return null;}
|
|
681
683
|
|
|
682
684
|
// ==== Parameter checking methods =========
|
|
683
685
|
_ensureLanguages(param) {
|
|
@@ -853,7 +855,7 @@ class CodeSystemFactoryProvider {
|
|
|
853
855
|
}
|
|
854
856
|
|
|
855
857
|
/**
|
|
856
|
-
* see
|
|
858
|
+
* see comments for registerSupplements()
|
|
857
859
|
*
|
|
858
860
|
* @param {CodeSystem} supplement - the supplement to flesh out
|
|
859
861
|
* @returns void
|
|
@@ -865,6 +867,8 @@ class CodeSystemFactoryProvider {
|
|
|
865
867
|
/**
|
|
866
868
|
* build and return a known concept map from the URL, if there is one.
|
|
867
869
|
*
|
|
870
|
+
* the conceptmap is never visible to a user; if it has an implicitSource, then
|
|
871
|
+
* provider.getTranslations will be called when it's actually used
|
|
868
872
|
* @param url
|
|
869
873
|
* @param version
|
|
870
874
|
* @returns {ConceptMap}
|
package/tx/cs/cs-omop.js
CHANGED
|
@@ -660,8 +660,10 @@ class OMOPServices extends BaseCSServices {
|
|
|
660
660
|
}
|
|
661
661
|
|
|
662
662
|
// Translation support
|
|
663
|
-
async getTranslations(coding, target) {
|
|
664
|
-
|
|
663
|
+
async getTranslations(map, coding, target) {
|
|
664
|
+
if (map == null) {
|
|
665
|
+
return;
|
|
666
|
+
}
|
|
665
667
|
|
|
666
668
|
const vocabId = getVocabId(target);
|
|
667
669
|
if (vocabId === -1) {
|
|
@@ -680,7 +682,7 @@ class OMOPServices extends BaseCSServices {
|
|
|
680
682
|
reject(err);
|
|
681
683
|
} else {
|
|
682
684
|
const translations = rows.map(row => ({
|
|
683
|
-
|
|
685
|
+
system: target,
|
|
684
686
|
code: row.concept_code,
|
|
685
687
|
display: row.concept_name,
|
|
686
688
|
relationship: 'equivalent',
|
package/tx/cs/cs-rxnorm.js
CHANGED
|
@@ -395,24 +395,24 @@ class RxNormServices extends CodeSystemProvider {
|
|
|
395
395
|
} else if (this.rels.includes(prop)) {
|
|
396
396
|
if (value.startsWith('CUI:')) {
|
|
397
397
|
const cui = value.substring(4);
|
|
398
|
-
sql = `AND (${this.getCodeField()} IN (SELECT ${this.getCodeField()} FROM rxnconso WHERE RXCUI IN (SELECT
|
|
398
|
+
sql = `AND (${this.getCodeField()} IN (SELECT ${this.getCodeField()} FROM rxnconso WHERE RXCUI IN (SELECT RXCUI2 FROM rxnrel WHERE REL = $rel AND RXCUI1 = $cui2)))`;
|
|
399
399
|
params.rel = this.#sqlWrapString(prop);
|
|
400
400
|
params.cui2 = this.#sqlWrapString(cui);
|
|
401
401
|
} else if (value.startsWith('AUI:')) {
|
|
402
402
|
const aui = value.substring(4);
|
|
403
|
-
sql = `AND (${this.getCodeField()} IN (SELECT ${this.getCodeField()} FROM rxnconso WHERE RXAUI IN (SELECT
|
|
403
|
+
sql = `AND (${this.getCodeField()} IN (SELECT ${this.getCodeField()} FROM rxnconso WHERE RXAUI IN (SELECT RXAUI2 FROM rxnrel WHERE REL = $rel AND RXAUI1 = $aui2)))`;
|
|
404
404
|
params.rel = this.#sqlWrapString(prop);
|
|
405
405
|
params.aui2 = this.#sqlWrapString(aui);
|
|
406
406
|
}
|
|
407
407
|
} else if (this.reltypes.includes(prop)) {
|
|
408
408
|
if (value.startsWith('CUI:')) {
|
|
409
409
|
const cui = value.substring(4);
|
|
410
|
-
sql = `AND (${this.getCodeField()} IN (SELECT ${this.getCodeField()} FROM rxnconso WHERE RXCUI IN (SELECT
|
|
410
|
+
sql = `AND (${this.getCodeField()} IN (SELECT ${this.getCodeField()} FROM rxnconso WHERE RXCUI IN (SELECT RXCUI2 FROM rxnrel WHERE RELA = $rela AND RXCUI1 = $cui2)))`;
|
|
411
411
|
params.rela = this.#sqlWrapString(prop);
|
|
412
412
|
params.cui2 = this.#sqlWrapString(cui);
|
|
413
413
|
} else if (value.startsWith('AUI:')) {
|
|
414
414
|
const aui = value.substring(4);
|
|
415
|
-
sql = `AND (${this.getCodeField()} IN (SELECT ${this.getCodeField()} FROM rxnconso WHERE RXAUI IN (SELECT
|
|
415
|
+
sql = `AND (${this.getCodeField()} IN (SELECT ${this.getCodeField()} FROM rxnconso WHERE RXAUI IN (SELECT RXAUI2 FROM rxnrel WHERE RELA = $rela AND RXAUI1 = $aui2)))`;
|
|
416
416
|
params.rela = this.#sqlWrapString(prop);
|
|
417
417
|
params.aui2 = this.#sqlWrapString(aui);
|
|
418
418
|
}
|
|
@@ -498,8 +498,6 @@ class RxNormServices extends CodeSystemProvider {
|
|
|
498
498
|
}
|
|
499
499
|
|
|
500
500
|
async filterSize(filterContext, set) {
|
|
501
|
-
|
|
502
|
-
|
|
503
501
|
if (!set.executed) {
|
|
504
502
|
await this.#executeFilter(set);
|
|
505
503
|
}
|
package/tx/cs/cs-snomed.js
CHANGED
|
@@ -12,6 +12,7 @@ const {
|
|
|
12
12
|
const {DesignationUse} = require("../library/designations");
|
|
13
13
|
const {BaseCSServices} = require("./cs-base");
|
|
14
14
|
const {formatDateMMDDYYYY} = require("../../library/utilities");
|
|
15
|
+
const {ConceptMap} = require("../library/conceptmap");
|
|
15
16
|
|
|
16
17
|
// Context kinds matching Pascal enum
|
|
17
18
|
const SnomedProviderContextKind = {
|
|
@@ -1213,6 +1214,64 @@ class SnomedProvider extends BaseCSServices {
|
|
|
1213
1214
|
(cd.use.code === '900000000000013009' || cd.use.code === '900000000000003001');
|
|
1214
1215
|
}
|
|
1215
1216
|
|
|
1217
|
+
async getTranslations(map, coding, target, reverse) {
|
|
1218
|
+
if (!map || (target && target !== this.system()) || reverse) {
|
|
1219
|
+
return [];
|
|
1220
|
+
}
|
|
1221
|
+
let ref = this.sct.concepts.findConcept(map.id);
|
|
1222
|
+
if (!ref.found) {
|
|
1223
|
+
return [];
|
|
1224
|
+
}
|
|
1225
|
+
let rref = this.sct.refSetIndex.getRefSetByConcept(ref.index);
|
|
1226
|
+
if (rref == -1) {
|
|
1227
|
+
return [];
|
|
1228
|
+
}
|
|
1229
|
+
let refSetRecord = this.sct.refSetIndex.getReferenceSet(rref);
|
|
1230
|
+
let members = this.sct.refSetMembers.getMembers(refSetRecord.membersByRef);
|
|
1231
|
+
let srcConcept = this.sct.concepts.findConcept(coding.code);
|
|
1232
|
+
if (!srcConcept.found) {
|
|
1233
|
+
return [];
|
|
1234
|
+
}
|
|
1235
|
+
|
|
1236
|
+
let result = [];
|
|
1237
|
+
let L = 0;
|
|
1238
|
+
let H = members.length - 1;
|
|
1239
|
+
while (L <= H) {
|
|
1240
|
+
const I = Math.floor((L + H) / 2);
|
|
1241
|
+
const ref = members[I].ref;
|
|
1242
|
+
if (ref < srcConcept.index) {
|
|
1243
|
+
L = I + 1;
|
|
1244
|
+
} else if (ref > srcConcept.index) {
|
|
1245
|
+
H = I - 1;
|
|
1246
|
+
} else {
|
|
1247
|
+
// Found — but scan left for first match in case of duplicates
|
|
1248
|
+
let first = I;
|
|
1249
|
+
while (first > 0 && members[first - 1].ref === srcConcept.index) {
|
|
1250
|
+
first--;
|
|
1251
|
+
}
|
|
1252
|
+
// Process all matching members
|
|
1253
|
+
for (let i = first; i < members.length && members[i].ref === srcConcept.index; i++) {
|
|
1254
|
+
let values = this.sct.refs.getReferences(members[i].values);
|
|
1255
|
+
if (values && values.length >= 1) {
|
|
1256
|
+
let tgtId = String(this.sct.concepts.getConceptId(values[0]));
|
|
1257
|
+
let ct = {
|
|
1258
|
+
map: map.vurl,
|
|
1259
|
+
code: tgtId,
|
|
1260
|
+
system: this.system(),
|
|
1261
|
+
version : this.version(),
|
|
1262
|
+
display: await this.display(tgtId),
|
|
1263
|
+
relationship: map.jsonObj.relationship
|
|
1264
|
+
}
|
|
1265
|
+
result.push(ct);
|
|
1266
|
+
}
|
|
1267
|
+
}
|
|
1268
|
+
break;
|
|
1269
|
+
}
|
|
1270
|
+
}
|
|
1271
|
+
|
|
1272
|
+
return result;
|
|
1273
|
+
}
|
|
1274
|
+
|
|
1216
1275
|
}
|
|
1217
1276
|
|
|
1218
1277
|
/**
|
|
@@ -1339,7 +1398,7 @@ class SnomedServicesFactory extends CodeSystemFactoryProvider {
|
|
|
1339
1398
|
return null;
|
|
1340
1399
|
}
|
|
1341
1400
|
let rref = this.snomedServices.refSetIndex.getRefSetByConcept(ref.index);
|
|
1342
|
-
if (rref ==
|
|
1401
|
+
if (rref == -1) {
|
|
1343
1402
|
return null;
|
|
1344
1403
|
}
|
|
1345
1404
|
return {
|
|
@@ -1448,6 +1507,59 @@ class SnomedServicesFactory extends CodeSystemFactoryProvider {
|
|
|
1448
1507
|
|
|
1449
1508
|
return edition + ' ' + formatDateMMDDYYYY(match[2].substring(4, 6) + match[2].substring(6, 8) + match[2].substring(0, 4));
|
|
1450
1509
|
}
|
|
1510
|
+
|
|
1511
|
+
async findImplicitConceptMap(url, version) {
|
|
1512
|
+
if (version && (version !== this.version())) {
|
|
1513
|
+
return null;
|
|
1514
|
+
}
|
|
1515
|
+
if (!url || !url.startsWith(this.system()+"?fhir_cm=")) {
|
|
1516
|
+
return null;
|
|
1517
|
+
}
|
|
1518
|
+
let id = url.substring(url.indexOf("=")+1);
|
|
1519
|
+
if (['900000000000523009', '900000000000526001', '900000000000527005', '900000000000530003'].includes(id)) {
|
|
1520
|
+
let name = '';
|
|
1521
|
+
let relationship = '';
|
|
1522
|
+
switch (id) {
|
|
1523
|
+
case '900000000000523009':
|
|
1524
|
+
name = 'POSSIBLY EQUIVALENT TO';
|
|
1525
|
+
relationship = 'inexact';
|
|
1526
|
+
break;
|
|
1527
|
+
case '900000000000526001':
|
|
1528
|
+
name = 'REPLACED BY';
|
|
1529
|
+
relationship = 'equivalent';
|
|
1530
|
+
break;
|
|
1531
|
+
case '900000000000527005':
|
|
1532
|
+
name = 'SAME AS';
|
|
1533
|
+
relationship = 'equal';
|
|
1534
|
+
break;
|
|
1535
|
+
case '900000000000530003':
|
|
1536
|
+
name = 'ALTERNATIVE';
|
|
1537
|
+
relationship = 'inexact';
|
|
1538
|
+
break;
|
|
1539
|
+
}
|
|
1540
|
+
let cm = {
|
|
1541
|
+
resourceType: 'ConceptMap',
|
|
1542
|
+
internalSource : this,
|
|
1543
|
+
relationship: relationship,
|
|
1544
|
+
id : id,
|
|
1545
|
+
url: `${this.system}?fhir_cm=${id}`,
|
|
1546
|
+
version: this.version(),
|
|
1547
|
+
name: `SNOMED CT ${name} Concept Map`,
|
|
1548
|
+
description: `The concept map implicitly defined by the ${name} Association Reference Set`,
|
|
1549
|
+
copyright: 'This value set includes content from SNOMED CT, which is copyright © 2002+ International Health Terminology Standards Development Organisation (SNOMED International), and distributed by agreement between SNOMED International and HL7',
|
|
1550
|
+
status: 'active',
|
|
1551
|
+
sourceUri: `${this.system}?fhir_vs`,
|
|
1552
|
+
targetUri: `${this.system}?fhir_vs`,
|
|
1553
|
+
group: [{
|
|
1554
|
+
source: 'http://snomed.info/sct',
|
|
1555
|
+
target: 'http://snomed.info/sct'
|
|
1556
|
+
}]
|
|
1557
|
+
}
|
|
1558
|
+
return new ConceptMap(cm);
|
|
1559
|
+
} else {
|
|
1560
|
+
return null;
|
|
1561
|
+
}
|
|
1562
|
+
}
|
|
1451
1563
|
}
|
|
1452
1564
|
|
|
1453
1565
|
function getEditionName(edition) {
|
|
Binary file
|
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
{
|
|
2
|
+
"resourceType" : "CodeSystem",
|
|
3
|
+
"language" : "de",
|
|
4
|
+
"id" : "de-multi",
|
|
5
|
+
"url" : "http://hl7.org/fhir/test/CodeSystem/de-multi",
|
|
6
|
+
"name" : "TestCodeSystemMultiLangDE",
|
|
7
|
+
"title" : "Testcodesystem mit mehreren Sprachen",
|
|
8
|
+
"title:en" : "Test Code System with Multiple Languages",
|
|
9
|
+
"_title" : {
|
|
10
|
+
"extension" : [{
|
|
11
|
+
"url" : "http://hl7.org/fhir/StructureDefinition/translation",
|
|
12
|
+
"extension" : [{
|
|
13
|
+
"url" : "lang",
|
|
14
|
+
"valueCode" : "en"
|
|
15
|
+
},{
|
|
16
|
+
"url" : "content",
|
|
17
|
+
"valueString" : "Test Code System with Multiple Languages"
|
|
18
|
+
}]
|
|
19
|
+
}]
|
|
20
|
+
},
|
|
21
|
+
"status" : "active",
|
|
22
|
+
"experimental" : false,
|
|
23
|
+
"date" : "2023-04-01",
|
|
24
|
+
"publisher" : "FHIR Project",
|
|
25
|
+
"caseSensitive" : true,
|
|
26
|
+
"content" : "complete",
|
|
27
|
+
"concept" : [{
|
|
28
|
+
"code" : "code1",
|
|
29
|
+
"display" : "Anzeige 1",
|
|
30
|
+
"definition" : "Mein erster Code",
|
|
31
|
+
"definition:en" : "My first code",
|
|
32
|
+
"_definition" : {
|
|
33
|
+
"extension" : [{
|
|
34
|
+
"url" : "http://hl7.org/fhir/StructureDefinition/translation",
|
|
35
|
+
"extension" : [{
|
|
36
|
+
"url" : "lang",
|
|
37
|
+
"valueCode" : "en"
|
|
38
|
+
},{
|
|
39
|
+
"url" : "content",
|
|
40
|
+
"valueString" : "My first code"
|
|
41
|
+
}]
|
|
42
|
+
}]
|
|
43
|
+
},
|
|
44
|
+
"designation" : [{
|
|
45
|
+
"language" : "en",
|
|
46
|
+
"value" : "Display 1"
|
|
47
|
+
}]
|
|
48
|
+
},
|
|
49
|
+
{
|
|
50
|
+
"code" : "code2",
|
|
51
|
+
"display" : "Anzeige 2",
|
|
52
|
+
"definition" : "Mein zweiter Code, mit Kindern",
|
|
53
|
+
"definition:en" : "My second code, with children",
|
|
54
|
+
"_definition" : {
|
|
55
|
+
"extension" : [{
|
|
56
|
+
"url" : "http://hl7.org/fhir/StructureDefinition/translation",
|
|
57
|
+
"extension" : [{
|
|
58
|
+
"url" : "lang",
|
|
59
|
+
"valueCode" : "en"
|
|
60
|
+
},{
|
|
61
|
+
"url" : "content",
|
|
62
|
+
"valueString" : "My second code, with children"
|
|
63
|
+
}]
|
|
64
|
+
}]
|
|
65
|
+
},
|
|
66
|
+
"designation" : [{
|
|
67
|
+
"language" : "de-CH",
|
|
68
|
+
"value" : "Anzeige 2"
|
|
69
|
+
},{
|
|
70
|
+
"language" : "es",
|
|
71
|
+
"value" : "Mostrar 2"
|
|
72
|
+
},{
|
|
73
|
+
"language" : "en",
|
|
74
|
+
"value" : "Display 2"
|
|
75
|
+
}],
|
|
76
|
+
"concept" : [{
|
|
77
|
+
"code" : "code2a",
|
|
78
|
+
"display" : "Anzeige 2a",
|
|
79
|
+
"definition" : "Mein erster Second-Level-Code",
|
|
80
|
+
"definition:en" : "My first second level code",
|
|
81
|
+
"_definition" : {
|
|
82
|
+
"extension" : [{
|
|
83
|
+
"url" : "http://hl7.org/fhir/StructureDefinition/translation",
|
|
84
|
+
"extension" : [{
|
|
85
|
+
"url" : "lang",
|
|
86
|
+
"valueCode" : "en"
|
|
87
|
+
},{
|
|
88
|
+
"url" : "content",
|
|
89
|
+
"valueString" : "My first second level code"
|
|
90
|
+
}]
|
|
91
|
+
}]
|
|
92
|
+
},
|
|
93
|
+
"designation" : [{
|
|
94
|
+
"language" : "en",
|
|
95
|
+
"value" : "Display 2a"
|
|
96
|
+
},{
|
|
97
|
+
"language" : "es",
|
|
98
|
+
"value" : "Mostrar 2a"
|
|
99
|
+
}],
|
|
100
|
+
"concept" : [{
|
|
101
|
+
"code" : "code2aI",
|
|
102
|
+
"display" : "Anzeige 2aI",
|
|
103
|
+
"definition" : "Mein erster Third-Level-Code",
|
|
104
|
+
"definition:en" : "My first third level code",
|
|
105
|
+
"_definition" : {
|
|
106
|
+
"extension" : [{
|
|
107
|
+
"url" : "http://hl7.org/fhir/StructureDefinition/translation",
|
|
108
|
+
"extension" : [{
|
|
109
|
+
"url" : "lang",
|
|
110
|
+
"valueCode" : "en"
|
|
111
|
+
},{
|
|
112
|
+
"url" : "content",
|
|
113
|
+
"valueString" : "My first third level code"
|
|
114
|
+
}]
|
|
115
|
+
}]
|
|
116
|
+
},
|
|
117
|
+
"designation" : [{
|
|
118
|
+
"language" : "es",
|
|
119
|
+
"value" : "Mostrar 2aI"
|
|
120
|
+
}]
|
|
121
|
+
},
|
|
122
|
+
{
|
|
123
|
+
"code" : "code2aII",
|
|
124
|
+
"display" : "Anzeige 2aII",
|
|
125
|
+
"definition" : "Mein zweiter Third-Level-Code",
|
|
126
|
+
"definition:en" : "My second third level code",
|
|
127
|
+
"_definition" : {
|
|
128
|
+
"extension" : [{
|
|
129
|
+
"url" : "http://hl7.org/fhir/StructureDefinition/translation",
|
|
130
|
+
"extension" : [{
|
|
131
|
+
"url" : "lang",
|
|
132
|
+
"valueCode" : "en"
|
|
133
|
+
},{
|
|
134
|
+
"url" : "content",
|
|
135
|
+
"valueString" : "My second third level code"
|
|
136
|
+
}]
|
|
137
|
+
}]
|
|
138
|
+
}
|
|
139
|
+
}]
|
|
140
|
+
},
|
|
141
|
+
{
|
|
142
|
+
"code" : "code2b",
|
|
143
|
+
"display" : "Anzeige 2b",
|
|
144
|
+
"definition" : "Mein zweiter Second-Level-Code",
|
|
145
|
+
"definition:en" : "My second second level code",
|
|
146
|
+
"_definition" : {
|
|
147
|
+
"extension" : [{
|
|
148
|
+
"url" : "http://hl7.org/fhir/StructureDefinition/translation",
|
|
149
|
+
"extension" : [{
|
|
150
|
+
"url" : "lang",
|
|
151
|
+
"valueCode" : "en"
|
|
152
|
+
},{
|
|
153
|
+
"url" : "content",
|
|
154
|
+
"valueString" : "My second second level code"
|
|
155
|
+
}]
|
|
156
|
+
}]
|
|
157
|
+
},
|
|
158
|
+
"designation" : [{
|
|
159
|
+
"language" : "en",
|
|
160
|
+
"value" : "Display 2b"
|
|
161
|
+
}]
|
|
162
|
+
}]
|
|
163
|
+
},
|
|
164
|
+
{
|
|
165
|
+
"code" : "code3",
|
|
166
|
+
"display" : "Anzeige 3",
|
|
167
|
+
"definition" : "Mein Third-Level-Code",
|
|
168
|
+
"definition:en" : "My Third Level Code",
|
|
169
|
+
"_definition" : {
|
|
170
|
+
"extension" : [{
|
|
171
|
+
"url" : "http://hl7.org/fhir/StructureDefinition/translation",
|
|
172
|
+
"extension" : [{
|
|
173
|
+
"url" : "lang",
|
|
174
|
+
"valueCode" : "en"
|
|
175
|
+
},{
|
|
176
|
+
"url" : "content",
|
|
177
|
+
"valueString" : "My Third Level Code"
|
|
178
|
+
}]
|
|
179
|
+
}]
|
|
180
|
+
},
|
|
181
|
+
"designation" : [{
|
|
182
|
+
"language" : "en",
|
|
183
|
+
"value" : "Display 3"
|
|
184
|
+
}]
|
|
185
|
+
}]
|
|
186
|
+
}
|