fhirsmith 0.5.5 → 0.6.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 +30 -0
- package/library/html-server.js +2 -1
- package/library/package-manager.js +37 -32
- package/library/utilities.js +10 -1
- package/package.json +1 -1
- package/packages/package-crawler.js +103 -46
- package/packages/packages.js +14 -7
- package/publisher/publisher.js +15 -3
- package/registry/api.js +173 -191
- package/registry/crawler.js +72 -58
- package/registry/model.js +14 -8
- package/registry/registry.js +2 -0
- package/root-template.html +1 -0
- package/server.js +109 -45
- package/tx/cs/cs-api.js +22 -1
- package/tx/cs/cs-base.js +1 -0
- package/tx/cs/cs-loinc.js +1 -1
- package/tx/cs/cs-rxnorm.js +9 -2
- package/tx/cs/cs-snomed.js +17 -2
- package/tx/html/codesystem-operations.liquid +17 -24
- package/tx/html/valueset-operations.liquid +46 -52
- package/tx/library/codesystem.js +6 -1
- package/tx/library/renderer.js +99 -22
- package/tx/library.js +18 -3
- package/tx/provider.js +4 -2
- package/tx/sct/expressions.js +20 -9
- package/tx/tx-html.js +143 -50
- package/tx/tx.js +2 -2
- package/tx/workers/expand.js +62 -10
- package/tx/workers/metadata.js +10 -3
- package/tx/workers/search.js +5 -2
- package/tx/workers/validate.js +4 -3
- package/tx/workers/worker.js +1 -1
- package/tx/xversion/xv-terminologyCapabilities.js +21 -1
- package/utilities/icd9cm-parser.js +313 -0
|
@@ -1,25 +1,18 @@
|
|
|
1
|
-
<div class="
|
|
2
|
-
<
|
|
3
|
-
<
|
|
1
|
+
<div class="operation-form" style="margin-bottom: 15px;">
|
|
2
|
+
<strong>Lookup</strong>
|
|
3
|
+
<form method="get" action="$lookup" style="display: inline-block; margin-left: 10px;">
|
|
4
|
+
<input type="hidden" name="system" value="{{ url }}"/>
|
|
5
|
+
<input type="text" name="code" placeholder="Code" required size="20"/>
|
|
6
|
+
<button type="submit" class="btn btn-sm btn-primary">Lookup</button>
|
|
7
|
+
</form>
|
|
8
|
+
</div>
|
|
4
9
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
<div class="operation-form" style="margin-bottom: 15px;">
|
|
15
|
-
<strong>Subsumes</strong>
|
|
16
|
-
<form method="get" action="$subsumes" style="display: inline-block; margin-left: 10px;">
|
|
17
|
-
<input type="hidden" name="system" value="{{ url }}"/>
|
|
18
|
-
<input type="text" name="codeA" placeholder="Code A" required size="15"/>
|
|
19
|
-
<input type="text" name="codeB" placeholder="Code B" required size="15"/>
|
|
20
|
-
<button type="submit" class="btn btn-sm btn-primary">Subsumes</button>
|
|
21
|
-
</form>
|
|
22
|
-
</div>
|
|
23
|
-
|
|
24
|
-
</div>
|
|
25
|
-
</div>
|
|
10
|
+
<div class="operation-form" style="margin-bottom: 15px;">
|
|
11
|
+
<strong>Subsumes</strong>
|
|
12
|
+
<form method="get" action="$subsumes" style="display: inline-block; margin-left: 10px;">
|
|
13
|
+
<input type="hidden" name="system" value="{{ url }}"/>
|
|
14
|
+
<input type="text" name="codeA" placeholder="Code A" required size="15"/>
|
|
15
|
+
<input type="text" name="codeB" placeholder="Code B" required size="15"/>
|
|
16
|
+
<button type="submit" class="btn btn-sm btn-primary">Subsumes</button>
|
|
17
|
+
</form>
|
|
18
|
+
</div>
|
|
@@ -1,54 +1,48 @@
|
|
|
1
|
-
<div class="operations" style="margin-top: 20px;">
|
|
2
|
-
<button type="button" class="btn btn-sm btn-outline-secondary" onclick="toggleOperations('{{ opsId }}')">Show Operations</button>
|
|
3
|
-
<div id="{{ opsId }}" style="display: none; margin-top: 10px;">
|
|
4
1
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
2
|
+
<div class="operation-form" style="margin-bottom: 15px;">
|
|
3
|
+
<strong>Expand</strong>
|
|
4
|
+
<form method="get" action="$expand" style="margin-left: 10px; margin-top: 5px;">
|
|
5
|
+
<input type="hidden" name="url" value="{{ url }}"/>
|
|
6
|
+
<table class="grid" cellpadding="0" cellspacing="0">
|
|
7
|
+
<tr>
|
|
8
|
+
<td>Filter: <input type="text" name="filter" size="20"/></td>
|
|
9
|
+
<td>Language: <input type="text" name="displayLanguage" size="10"/></td>
|
|
10
|
+
</tr>
|
|
11
|
+
<tr>
|
|
12
|
+
<td colspan="2">
|
|
13
|
+
<input type="checkbox" name="includeDesignations" id="expand_desig" value="true"/>
|
|
14
|
+
<label for="expand_desig">Include Designations</label>
|
|
15
|
+
<input type="checkbox" name="activeOnly" id="expand_active" value="true"/>
|
|
16
|
+
<label for="expand_active">Active Only</label>
|
|
17
|
+
</td>
|
|
18
|
+
</tr>
|
|
19
|
+
</table>
|
|
20
|
+
<button type="submit" class="btn btn-sm btn-primary">Expand</button>
|
|
21
|
+
</form>
|
|
22
|
+
</div>
|
|
26
23
|
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
</div>
|
|
54
|
-
</div>
|
|
24
|
+
<div class="operation-form" style="margin-bottom: 15px;">
|
|
25
|
+
<strong>Validate Code (ValueSet)</strong>
|
|
26
|
+
<form method="get" action="$validate-code" style="margin-left: 10px; margin-top: 5px;">
|
|
27
|
+
<input type="hidden" name="url" value="{{ url }}"/>
|
|
28
|
+
<input type="hidden" name="inferSystem" id="{{ inferSystemId }}" value="true"/>
|
|
29
|
+
<table class="grid" cellpadding="0" cellspacing="0">
|
|
30
|
+
<tr>
|
|
31
|
+
<td>System: <input type="text" name="system" id="{{ vcSystemId }}" size="30" onchange="updateInferSystem('{{ vcSystemId }}', '{{ inferSystemId }}')"/></td>
|
|
32
|
+
<td>Version: <input type="text" name="version" size="10"/></td>
|
|
33
|
+
</tr>
|
|
34
|
+
<tr>
|
|
35
|
+
<td>Code: <input type="text" name="code" size="20" required/></td>
|
|
36
|
+
<td>Display: <input type="text" name="display" size="20"/></td>
|
|
37
|
+
</tr>
|
|
38
|
+
<tr>
|
|
39
|
+
<td>Language: <input type="text" name="displayLanguage" size="10"/></td>
|
|
40
|
+
<td>
|
|
41
|
+
<input type="checkbox" name="abstract" value="true"/>
|
|
42
|
+
<label>Abstract</label>
|
|
43
|
+
</td>
|
|
44
|
+
</tr>
|
|
45
|
+
</table>
|
|
46
|
+
<button type="submit" class="btn btn-sm btn-primary">Validate Code</button>
|
|
47
|
+
</form>
|
|
48
|
+
</div>
|
package/tx/library/codesystem.js
CHANGED
|
@@ -33,7 +33,12 @@ class CodeSystem extends CanonicalResource {
|
|
|
33
33
|
// Convert to R5 format internally (modifies input for performance)
|
|
34
34
|
this.jsonObj = codeSystemToR5(this.jsonObj, fhirVersion);
|
|
35
35
|
if (!noMaps) {
|
|
36
|
-
|
|
36
|
+
try {
|
|
37
|
+
this.validate();
|
|
38
|
+
} catch (e) {
|
|
39
|
+
const id = this.jsonObj?.url ? `${this.jsonObj.url}|${this.jsonObj.version || ''}` : this.jsonObj?.name || 'unknown';
|
|
40
|
+
throw new Error(`${e.message} (in ${id})`);
|
|
41
|
+
}
|
|
37
42
|
this.buildMaps();
|
|
38
43
|
}
|
|
39
44
|
}
|
package/tx/library/renderer.js
CHANGED
|
@@ -22,18 +22,17 @@ class Renderer {
|
|
|
22
22
|
displayCoded(...args) {
|
|
23
23
|
if (args.length === 1) {
|
|
24
24
|
const arg = args[0];
|
|
25
|
-
if (arg
|
|
25
|
+
if (arg instanceof CodeSystemProvider) {
|
|
26
|
+
return arg.system() + "|" + arg.version();
|
|
27
|
+
} else if (arg.system !== undefined && arg.version !== undefined && arg.code !== undefined && arg.display !== undefined) {
|
|
26
28
|
// It's a Coding
|
|
27
29
|
return this.displayCodedCoding(arg);
|
|
28
30
|
} else if (arg.coding !== undefined || arg.text) {
|
|
29
31
|
// It's a CodeableConcept
|
|
30
32
|
return this.displayCodedCodeableConcept(arg);
|
|
31
|
-
} else if (arg.
|
|
33
|
+
} else if (arg.system !== undefined && arg.version !== undefined) {
|
|
32
34
|
// It's a CodeSystemProvider
|
|
33
35
|
return this.displayCodedProvider(arg);
|
|
34
|
-
} else if (arg instanceof CodeSystemProvider) {
|
|
35
|
-
let cs = arg;
|
|
36
|
-
return cs.system() + "|" + cs.version();
|
|
37
36
|
}
|
|
38
37
|
} else if (args.length === 2) {
|
|
39
38
|
return this.displayCodedSystemVersion(args[0], args[1]);
|
|
@@ -46,7 +45,7 @@ class Renderer {
|
|
|
46
45
|
}
|
|
47
46
|
|
|
48
47
|
displayCodedProvider(system) {
|
|
49
|
-
let result = system.
|
|
48
|
+
let result = system.system + '|' + system.version;
|
|
50
49
|
if (system.sourcePackage) {
|
|
51
50
|
result = result + ' (from ' + system.sourcePackage + ')';
|
|
52
51
|
}
|
|
@@ -70,7 +69,7 @@ class Renderer {
|
|
|
70
69
|
}
|
|
71
70
|
|
|
72
71
|
displayCodedCoding(code) {
|
|
73
|
-
return this.displayCodedSystemVersionCodeDisplay(code.
|
|
72
|
+
return this.displayCodedSystemVersionCodeDisplay(code.system, code.version, code.code, code.display);
|
|
74
73
|
}
|
|
75
74
|
|
|
76
75
|
displayCodedCodeableConcept(code) {
|
|
@@ -90,12 +89,12 @@ class Renderer {
|
|
|
90
89
|
|
|
91
90
|
displayValueSetInclude(inc) {
|
|
92
91
|
let result;
|
|
93
|
-
if (inc.
|
|
94
|
-
result = '(' + inc.
|
|
95
|
-
if (inc.
|
|
92
|
+
if (inc.system) {
|
|
93
|
+
result = '(' + inc.system + ')';
|
|
94
|
+
if (inc.concept) {
|
|
96
95
|
result = result + '(';
|
|
97
96
|
let first = true;
|
|
98
|
-
for (const cc of inc.
|
|
97
|
+
for (const cc of inc.concept) {
|
|
99
98
|
if (first) {
|
|
100
99
|
first = false;
|
|
101
100
|
} else {
|
|
@@ -105,23 +104,23 @@ class Renderer {
|
|
|
105
104
|
}
|
|
106
105
|
result = result + ')';
|
|
107
106
|
}
|
|
108
|
-
if (inc.
|
|
107
|
+
if (inc.filter) {
|
|
109
108
|
result = result + '(';
|
|
110
109
|
let first = true;
|
|
111
|
-
for (const ci of inc.
|
|
110
|
+
for (const ci of inc.filter) {
|
|
112
111
|
if (first) {
|
|
113
112
|
first = false;
|
|
114
113
|
} else {
|
|
115
114
|
result = result + ',';
|
|
116
115
|
}
|
|
117
|
-
result = result + ci.
|
|
116
|
+
result = result + ci.property + ci.op + ci.value;
|
|
118
117
|
}
|
|
119
118
|
result = result + ')';
|
|
120
119
|
}
|
|
121
120
|
} else {
|
|
122
121
|
result = '(';
|
|
123
122
|
let first = true;
|
|
124
|
-
for (const s of inc.
|
|
123
|
+
for (const s of inc.valueSet || []) {
|
|
125
124
|
if (first) {
|
|
126
125
|
first = false;
|
|
127
126
|
} else {
|
|
@@ -148,6 +147,7 @@ class Renderer {
|
|
|
148
147
|
this.renderProperty(tbl, 'GENERAL_TITLE', res.title);
|
|
149
148
|
this.renderProperty(tbl, 'GENERAL_STATUS', res.status);
|
|
150
149
|
this.renderPropertyMD(tbl, 'GENERAL_DEFINITION', res.description);
|
|
150
|
+
this.renderPropertyMD(tbl, 'GENERAL_PURPOSE', res.purpose);
|
|
151
151
|
this.renderProperty(tbl, 'CANON_REND_PUBLISHER', res.publisher);
|
|
152
152
|
this.renderProperty(tbl, 'CANON_REND_COMMITTEE', Extensions.readString(res, 'http://hl7.org/fhir/StructureDefinition/structuredefinition-wg'));
|
|
153
153
|
this.renderProperty(tbl, 'GENERAL_COPYRIGHT', res.copyright);
|
|
@@ -340,7 +340,7 @@ class Renderer {
|
|
|
340
340
|
}
|
|
341
341
|
if (vs.expansion) {
|
|
342
342
|
div_.h2().tx("Expansion");
|
|
343
|
-
await this.renderExpansion(div_
|
|
343
|
+
await this.renderExpansion(div_, vs, tbl);
|
|
344
344
|
}
|
|
345
345
|
|
|
346
346
|
return div_.toString();
|
|
@@ -420,7 +420,7 @@ class Renderer {
|
|
|
420
420
|
li.tx(this.translate('VALUE_SET_ALL_CODES_DEF')+" ");
|
|
421
421
|
await this.renderLink(li,inc.system+(inc.version ? "|"+inc.version : ""));
|
|
422
422
|
} else if (inc.concept) {
|
|
423
|
-
li.tx(this.translate('VALUE_SET_THESE_CODES_DEF'));
|
|
423
|
+
li.tx(this.translate('VALUE_SET_THESE_CODES_DEF')+" ");
|
|
424
424
|
await this.renderLink(li,inc.system+(inc.version ? "|"+inc.version : ""));
|
|
425
425
|
li.tx(":");
|
|
426
426
|
const ul = li.ul();
|
|
@@ -899,18 +899,45 @@ class Renderer {
|
|
|
899
899
|
return count;
|
|
900
900
|
}
|
|
901
901
|
|
|
902
|
+
async renderVSExpansion(vs, showProps) {
|
|
903
|
+
let div_ = div();
|
|
904
|
+
let tbl;
|
|
905
|
+
if (showProps) {
|
|
906
|
+
div_.h2().tx("Expansion Properties");
|
|
907
|
+
tbl = div_.table("grid");
|
|
908
|
+
} else {
|
|
909
|
+
tbl = div(); // dummy
|
|
910
|
+
}
|
|
911
|
+
await this.renderExpansion(div_.table("grid"), vs, tbl);
|
|
912
|
+
return div_.toString();
|
|
913
|
+
}
|
|
914
|
+
|
|
902
915
|
async renderExpansion(x, vs, tbl) {
|
|
903
916
|
this.renderProperty(tbl, 'Expansion Identifier', vs.expansion.identifier);
|
|
904
917
|
this.renderProperty(tbl, 'Expansion Timestamp', vs.expansion.timestamp);
|
|
905
918
|
this.renderProperty(tbl, 'Expansion Total', vs.expansion.total);
|
|
906
919
|
this.renderProperty(tbl, 'Expansion Offset', vs.expansion.offset);
|
|
920
|
+
const warnings = [];
|
|
921
|
+
const warningNames = new Set(['deprecated', 'withdrawn', 'retired', 'experimental', 'draft']);
|
|
922
|
+
const useds = [];
|
|
923
|
+
const usedNames = new Set(['codesystem', 'valueset', 'supplement']);
|
|
907
924
|
for (let p of vs.expansion.parameter || []) {
|
|
908
|
-
if
|
|
925
|
+
if (p.name.startsWith('warning-') && warningNames.has(p.name.substring(8))) {
|
|
926
|
+
warnings.push(p);
|
|
927
|
+
} else if (p.name.startsWith('used-') && usedNames.has(p.name.substring(5))) {
|
|
928
|
+
useds.push(p);
|
|
929
|
+
} else if( getValueName(p) === 'valueUri' || getValueName(p) === 'valueCanonical') {
|
|
909
930
|
await this.renderPropertyLink(tbl, "Parameter: " + p.name, getValuePrimitive(p));
|
|
910
931
|
} else {
|
|
911
932
|
this.renderProperty(tbl, "Parameter: " + p.name, getValuePrimitive(p));
|
|
912
933
|
}
|
|
913
934
|
}
|
|
935
|
+
if (useds.length > 0) {
|
|
936
|
+
await this.renderUsed(x, useds);
|
|
937
|
+
}
|
|
938
|
+
if (warnings.length > 0) {
|
|
939
|
+
await this.renderWarnings(x, warnings);
|
|
940
|
+
}
|
|
914
941
|
|
|
915
942
|
if (!vs.expansion.contains || vs.expansion.contains.length === 0) {
|
|
916
943
|
x.para().i().tx('No concepts in expansion');
|
|
@@ -936,10 +963,10 @@ class Renderer {
|
|
|
936
963
|
}
|
|
937
964
|
headerRow.th().tx(this.translate('TX_DISPLAY'));
|
|
938
965
|
if (columnInfo.hasAbstract) {
|
|
939
|
-
headerRow.th().tx('Abstract');
|
|
966
|
+
headerRow.th().tx(this.translate('Abstract'));
|
|
940
967
|
}
|
|
941
968
|
if (columnInfo.hasInactive) {
|
|
942
|
-
headerRow.th().tx('
|
|
969
|
+
headerRow.th().tx(this.translate('VALUE_SET_INACTIVE'));
|
|
943
970
|
}
|
|
944
971
|
|
|
945
972
|
// Property columns (from expansion.property definitions)
|
|
@@ -1118,12 +1145,12 @@ class Renderer {
|
|
|
1118
1145
|
|
|
1119
1146
|
// Abstract column
|
|
1120
1147
|
if (columnInfo.hasAbstract) {
|
|
1121
|
-
tr.td().tx(contains.abstract === true ? '
|
|
1148
|
+
tr.td().tx(contains.abstract === true ? 'abstract' : '');
|
|
1122
1149
|
}
|
|
1123
1150
|
|
|
1124
1151
|
// Inactive column
|
|
1125
1152
|
if (columnInfo.hasInactive) {
|
|
1126
|
-
tr.td().tx(contains.inactive === true ? '
|
|
1153
|
+
tr.td().tx(contains.inactive === true ? this.translate('VALUE_SET_INACT') : '');
|
|
1127
1154
|
}
|
|
1128
1155
|
|
|
1129
1156
|
// Property columns
|
|
@@ -1557,12 +1584,62 @@ class Renderer {
|
|
|
1557
1584
|
// No versions specified
|
|
1558
1585
|
await this.renderLink(li, cs.uri);
|
|
1559
1586
|
}
|
|
1587
|
+
let content = cs.content || Extensions.readString(cs, "http://hl7.org/fhir/4.0/StructureDefinition/extension-TerminologyCapabilities.codeSystem.content");
|
|
1588
|
+
if (content && content != "complete") {
|
|
1589
|
+
li.tx(" (" + content + ")");
|
|
1590
|
+
}
|
|
1560
1591
|
}
|
|
1561
1592
|
}
|
|
1562
1593
|
}
|
|
1563
1594
|
|
|
1564
1595
|
return div_.toString();
|
|
1565
1596
|
}
|
|
1597
|
+
|
|
1598
|
+
async renderWarnings(x, warnings) {
|
|
1599
|
+
await this.renderWarningsForStatus(x, 'deprecated', warnings);
|
|
1600
|
+
await this.renderWarningsForStatus(x, 'withdrawn', warnings);
|
|
1601
|
+
await this.renderWarningsForStatus(x, 'retired', warnings);
|
|
1602
|
+
await this.renderWarningsForStatus(x, 'experimental', warnings);
|
|
1603
|
+
await this.renderWarningsForStatus(x, 'draft', warnings);
|
|
1604
|
+
}
|
|
1605
|
+
|
|
1606
|
+
async renderWarningsForStatus(x, name, warnings) {
|
|
1607
|
+
const wl = warnings.filter(item => item.name == 'warning-'+name);
|
|
1608
|
+
if (wl && wl.length > 0) {
|
|
1609
|
+
x.para().tx(`This ValueSet depends on the following ${name} ValueSets: `);
|
|
1610
|
+
let ul = x.ul();
|
|
1611
|
+
for (const w of wl) {
|
|
1612
|
+
const linkinfo = await this.linkResolver.resolveURL(this.opContext, getValuePrimitive(w));
|
|
1613
|
+
if (linkinfo) {
|
|
1614
|
+
ul.li().ah(linkinfo.link).tx(linkinfo.description);
|
|
1615
|
+
} else {
|
|
1616
|
+
ul.li().code().tx(getValuePrimitive(w));
|
|
1617
|
+
}
|
|
1618
|
+
}
|
|
1619
|
+
}
|
|
1620
|
+
}
|
|
1621
|
+
|
|
1622
|
+
async renderUsed(x, list) {
|
|
1623
|
+
x.para().tx(`This ValueSet depends on the following items:`);
|
|
1624
|
+
let ul = x.ul();
|
|
1625
|
+
await this.renderUsedForType(ul, 'codesystem', 'CodeSystem', list);
|
|
1626
|
+
await this.renderUsedForType(ul, 'valueset', 'ValueSet', list);
|
|
1627
|
+
await this.renderUsedForType(ul, 'supplement', 'Supplement', list);
|
|
1628
|
+
}
|
|
1629
|
+
|
|
1630
|
+
async renderUsedForType(ul, name, title, list) {
|
|
1631
|
+
const wl = list.filter(item => item.name == 'used-' + name);
|
|
1632
|
+
for (const w of wl) {
|
|
1633
|
+
const li = ul.li();
|
|
1634
|
+
li.tx(title+": ");
|
|
1635
|
+
const linkinfo = await this.linkResolver.resolveURL(this.opContext, getValuePrimitive(w));
|
|
1636
|
+
if (linkinfo) {
|
|
1637
|
+
li.ah(linkinfo.link).tx(linkinfo.description);
|
|
1638
|
+
} else {
|
|
1639
|
+
li.code().tx(getValuePrimitive(w));
|
|
1640
|
+
}
|
|
1641
|
+
}
|
|
1642
|
+
}
|
|
1566
1643
|
}
|
|
1567
1644
|
|
|
1568
1645
|
module.exports = { Renderer };
|
package/tx/library.js
CHANGED
|
@@ -158,7 +158,12 @@ class Library {
|
|
|
158
158
|
this.log.info('Fetching Data from '+this.baseUrl);
|
|
159
159
|
|
|
160
160
|
for (const source of config.sources) {
|
|
161
|
-
|
|
161
|
+
try {
|
|
162
|
+
await this.processSource(source, this.packageManager, "fetch");
|
|
163
|
+
} catch (error) {
|
|
164
|
+
console.error(`Failed to fetch source '${source}': ${error.message}`);
|
|
165
|
+
throw error;
|
|
166
|
+
}
|
|
162
167
|
}
|
|
163
168
|
|
|
164
169
|
this.log.info("Downloaded "+((this.totalDownloaded + this.packageManager.totalDownloaded)/ 1024)+" kB");
|
|
@@ -167,13 +172,23 @@ class Library {
|
|
|
167
172
|
this.#logSystemHeader();
|
|
168
173
|
|
|
169
174
|
for (const source of config.sources) {
|
|
170
|
-
|
|
175
|
+
try {
|
|
176
|
+
await this.processSource(source, this.packageManager, "cs");
|
|
177
|
+
} catch (error) {
|
|
178
|
+
console.error(`Failed to load code systems from '${source}': ${error.message}`);
|
|
179
|
+
throw error;
|
|
180
|
+
}
|
|
171
181
|
}
|
|
172
182
|
this.log.info('Loading Packages');
|
|
173
183
|
this.#logPackagesHeader();
|
|
174
184
|
|
|
175
185
|
for (const source of config.sources) {
|
|
176
|
-
|
|
186
|
+
try {
|
|
187
|
+
await this.processSource(source, this.packageManager, "npm");
|
|
188
|
+
} catch (error) {
|
|
189
|
+
console.error(`Failed to load package '${source}': ${error.message}`);
|
|
190
|
+
throw error;
|
|
191
|
+
}
|
|
177
192
|
}
|
|
178
193
|
|
|
179
194
|
const endMemory = process.memoryUsage();
|
package/tx/provider.js
CHANGED
|
@@ -153,6 +153,7 @@ class Provider {
|
|
|
153
153
|
}
|
|
154
154
|
|
|
155
155
|
getCodeSystemById(opContext, id) {
|
|
156
|
+
|
|
156
157
|
// Search through codeSystems map for matching id
|
|
157
158
|
for (const cs of this.codeSystems.values()) {
|
|
158
159
|
if (opContext) opContext.deadCheck('getCodeSystemById');
|
|
@@ -318,9 +319,10 @@ class Provider {
|
|
|
318
319
|
factory = this.codeSystemFactories.get(vurlMM);
|
|
319
320
|
}
|
|
320
321
|
if (factory != null) {
|
|
322
|
+
let vdesc = version == null ? "" : factory.describeVersion(version);
|
|
321
323
|
return {
|
|
322
|
-
link: this.path+"/CodeSystem/"+factory.id(),
|
|
323
|
-
description: factory.
|
|
324
|
+
link: this.path+"/CodeSystem/x-"+factory.id(),
|
|
325
|
+
description: factory.nameBase()+' '+vdesc
|
|
324
326
|
};
|
|
325
327
|
}
|
|
326
328
|
let cs = this.codeSystems.get(vurl);
|
package/tx/sct/expressions.js
CHANGED
|
@@ -1469,7 +1469,7 @@ class SnomedExpressionServices {
|
|
|
1469
1469
|
/**
|
|
1470
1470
|
* Validate concept reference
|
|
1471
1471
|
*/
|
|
1472
|
-
checkConcept(concept,
|
|
1472
|
+
checkConcept(concept, limits) {
|
|
1473
1473
|
if (concept.code) {
|
|
1474
1474
|
const conceptId = BigInt(concept.code);
|
|
1475
1475
|
const result = this.concepts.findConcept(conceptId);
|
|
@@ -1480,13 +1480,24 @@ class SnomedExpressionServices {
|
|
|
1480
1480
|
throw new Error(`Concept ${concept.code} not found`);
|
|
1481
1481
|
}
|
|
1482
1482
|
}
|
|
1483
|
-
if (
|
|
1484
|
-
// if a limit is specified, then the concept has to be a specialization of
|
|
1485
|
-
let
|
|
1486
|
-
|
|
1487
|
-
|
|
1488
|
-
|
|
1489
|
-
|
|
1483
|
+
if (limits && concept.reference) {
|
|
1484
|
+
// if a limit is specified, then the concept has to be a specialization of one of them.
|
|
1485
|
+
let ok = false;
|
|
1486
|
+
for (const limit of limits) {
|
|
1487
|
+
let parentRef = this.concepts.findConcept(limit);
|
|
1488
|
+
let descendentsRef = this.concepts.getAllDesc(parentRef.index);
|
|
1489
|
+
const descendants = this.refs.getReferences(descendentsRef);
|
|
1490
|
+
if (descendants && descendants.includes(concept.reference)) {
|
|
1491
|
+
ok = true;
|
|
1492
|
+
break;
|
|
1493
|
+
}
|
|
1494
|
+
}
|
|
1495
|
+
if (!ok) {
|
|
1496
|
+
if (limits.length == 1) {
|
|
1497
|
+
throw new Error(`Concept ${concept.code} is not valid in this context (must be a ${limits[0]})`);
|
|
1498
|
+
} else {
|
|
1499
|
+
throw new Error(`Concept ${concept.code} is not valid in this context (must be a descendent of one of ${limits})`);
|
|
1500
|
+
}
|
|
1490
1501
|
}
|
|
1491
1502
|
}
|
|
1492
1503
|
|
|
@@ -1615,7 +1626,7 @@ class SnomedExpressionServices {
|
|
|
1615
1626
|
* Validate refinement
|
|
1616
1627
|
*/
|
|
1617
1628
|
checkRefinement(refinement) {
|
|
1618
|
-
this.checkConcept(refinement.name, '410662002');
|
|
1629
|
+
this.checkConcept(refinement.name, ['410662002', '106237007']);
|
|
1619
1630
|
this.checkExpression(refinement.value);
|
|
1620
1631
|
}
|
|
1621
1632
|
|