fhirsmith 0.9.0 → 0.9.1
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 +20 -0
- package/package.json +1 -1
- package/root-bare-template.html +58 -9775
- package/translations/Messages.properties +2 -2
- package/tx/cs/cs-cs.js +32 -5
- package/tx/library/extensions.js +7 -1
- package/tx/library/renderer.js +11 -2
- package/tx/vs/vs-vsac.js +2 -1
- package/tx/workers/validate.js +1 -1
- package/tx/xversion/xv-valueset.js +28 -8
|
@@ -1298,7 +1298,7 @@ VIEWDEFINITION_SHOULD_HAVE_NAME = No name provided. A name is required in many c
|
|
|
1298
1298
|
VIEWDEFINITION_TYPE_MISMATCH = The path expression ''{0}'' does not return a value of the type ''{1}'' - found ''{2}''{3}
|
|
1299
1299
|
VIEWDEFINITION_UNABLE_TO_TYPE = Unable to determine a type (found ''{0}''){1}
|
|
1300
1300
|
VIEWDEFINITION_UNKNOWN_RESOURCE = The name ''{0}'' is not a valid resource{1}
|
|
1301
|
-
VS_EXP_FILTER_UNK = ValueSet ''{0}'' Filter by property ''{1}'' and op ''{2}'' is not supported yet
|
|
1301
|
+
VS_EXP_FILTER_UNK = ValueSet ''{0}'' Filter by property ''{1}'' and op ''{2}'' is not supported (yet?)
|
|
1302
1302
|
VS_EXP_IMPORT_CS = Cannot include value set ''{0}'' because it''s actually a code system
|
|
1303
1303
|
VS_EXP_IMPORT_CS_PINNED = Cannot include value set ''{0}'' version ''{1}'' because it''s actually a code system
|
|
1304
1304
|
VS_EXP_IMPORT_CS_PINNED_X = Cannot exclude value set ''{0}'' version ''{1}'' because it''s actually a code system
|
|
@@ -1400,7 +1400,7 @@ TEXT_LINK_NO_DATA = No data element was found in the textLink extension
|
|
|
1400
1400
|
TEXT_LINK_SELECTOR_INVALID = The textLink selector ''{0}'' is invalid: {1}
|
|
1401
1401
|
SD_CONTEXT_SHOULD_ELEMENT_NOT_FOUND = The element {0} is not valid
|
|
1402
1402
|
SD_CONTEXT_SHOULD_ELEMENT_NOT_FOUND_VER = The element {0} is not valid in version {1}
|
|
1403
|
-
FILTER_NOT_UNDERSTOOD = The filter "{0} {1} {2}"
|
|
1403
|
+
FILTER_NOT_UNDERSTOOD = The filter "{0} {1} {2}" is not understood or supported
|
|
1404
1404
|
XHTML_CONTROL_NO_SOURCE = The xhtml node at ''{0}'' does not have a class attribute to indicate its source (boilerplate, generated, or original) and this is required by the profile {1}
|
|
1405
1405
|
XHTML_XHTML_MIXED_LANG = The xhtml has some language sections ({0}), and also has content that is not in a language section
|
|
1406
1406
|
XHTML_CONTROL_NO_LANGS = The xhtml has some language sections ({0}), but language sections are prohibited in this context by the profile {1}
|
package/tx/cs/cs-cs.js
CHANGED
|
@@ -1224,7 +1224,7 @@ class FhirCodeSystemProvider extends BaseCSServices {
|
|
|
1224
1224
|
|
|
1225
1225
|
// Handle concept/code hierarchy filters
|
|
1226
1226
|
if ((prop === 'concept' || prop === 'code')) {
|
|
1227
|
-
results = await this._handleConceptFilter(filterContext, op, value);
|
|
1227
|
+
results = await this._handleConceptFilter(filterContext, prop, op, value);
|
|
1228
1228
|
}
|
|
1229
1229
|
|
|
1230
1230
|
// Handle child existence filter
|
|
@@ -1248,7 +1248,8 @@ class FhirCodeSystemProvider extends BaseCSServices {
|
|
|
1248
1248
|
}
|
|
1249
1249
|
|
|
1250
1250
|
if (!results) {
|
|
1251
|
-
throw new
|
|
1251
|
+
throw new Issue('error', 'exception', null, 'FILTER_NOT_UNDERSTOOD',
|
|
1252
|
+
this.opContext.i18n.translate('FILTER_NOT_UNDERSTOOD', this.opContext.langs, [prop, op, value]), 'vs-invalid', 422);
|
|
1252
1253
|
}
|
|
1253
1254
|
// Add to filter context
|
|
1254
1255
|
if (!filterContext.filters) {
|
|
@@ -1267,15 +1268,17 @@ class FhirCodeSystemProvider extends BaseCSServices {
|
|
|
1267
1268
|
* @returns {Promise<FhirCodeSystemProviderFilterContext>} Filter results
|
|
1268
1269
|
* @private
|
|
1269
1270
|
*/
|
|
1270
|
-
async _handleConceptFilter(filterContext, op, value) {
|
|
1271
|
+
async _handleConceptFilter(filterContext, prop, op, value) {
|
|
1271
1272
|
const results = new FhirCodeSystemProviderFilterContext();
|
|
1272
1273
|
|
|
1273
1274
|
if (op === 'is-a' || op === 'descendent-of') {
|
|
1274
1275
|
// Find all descendants of the specified code
|
|
1275
1276
|
const includeRoot = (op === 'is-a');
|
|
1276
1277
|
await this._addDescendants(results, value, includeRoot);
|
|
1277
|
-
}
|
|
1278
|
-
|
|
1278
|
+
} else if (op === 'child-of') {
|
|
1279
|
+
// Find all descendants of the specified code
|
|
1280
|
+
await this._addChildren(results, value);
|
|
1281
|
+
} else if (op === 'is-not-a') {
|
|
1279
1282
|
// Find all concepts that are NOT descendants of the specified code
|
|
1280
1283
|
const excludeDescendants = this.codeSystem.getDescendants(value);
|
|
1281
1284
|
const excludeSet = new Set([value, ...excludeDescendants]);
|
|
@@ -1323,6 +1326,9 @@ class FhirCodeSystemProvider extends BaseCSServices {
|
|
|
1323
1326
|
} catch (error) {
|
|
1324
1327
|
throw new Issue('error', 'exception', null, 'INVALID_REGEX', this.opContext.i18n.translate('INVALID_REGEX', this.opContext.langs, [value, error.message]), 'vs-invalid', 422);
|
|
1325
1328
|
}
|
|
1329
|
+
} else {
|
|
1330
|
+
throw new Issue('error', 'exception', null, 'FILTER_NOT_UNDERSTOOD',
|
|
1331
|
+
this.opContext.i18n.translate('FILTER_NOT_UNDERSTOOD', this.opContext.langs, [prop, op, value]), 'vs-invalid', 422);
|
|
1326
1332
|
}
|
|
1327
1333
|
|
|
1328
1334
|
return results;
|
|
@@ -1353,6 +1359,27 @@ class FhirCodeSystemProvider extends BaseCSServices {
|
|
|
1353
1359
|
}
|
|
1354
1360
|
}
|
|
1355
1361
|
|
|
1362
|
+
/**
|
|
1363
|
+
* Add immediate children of a code to the results
|
|
1364
|
+
* @param {FhirCodeSystemProviderFilterContext} results - Results to add to
|
|
1365
|
+
* @param {string} ancestorCode - The parent code
|
|
1366
|
+
* @private
|
|
1367
|
+
*/
|
|
1368
|
+
async _addChildren(results, parentCode) {
|
|
1369
|
+
const concept = this.codeSystem.getConceptByCode(parentCode);
|
|
1370
|
+
if (concept) {
|
|
1371
|
+
const descendants = this.codeSystem.getChildren(parentCode);
|
|
1372
|
+
for (const code of descendants) {
|
|
1373
|
+
if (code !== parentCode) { // should not be
|
|
1374
|
+
const concept = this.codeSystem.getConceptByCode(code);
|
|
1375
|
+
if (concept) {
|
|
1376
|
+
results.add(concept, 0);
|
|
1377
|
+
}
|
|
1378
|
+
}
|
|
1379
|
+
}
|
|
1380
|
+
}
|
|
1381
|
+
}
|
|
1382
|
+
|
|
1356
1383
|
/**
|
|
1357
1384
|
* Handle child exists filter
|
|
1358
1385
|
* @param {FilterExecutionContext} filterContext - Filter context
|
package/tx/library/extensions.js
CHANGED
|
@@ -56,7 +56,13 @@ const Extensions = {
|
|
|
56
56
|
if (!resource) {
|
|
57
57
|
return undefined;
|
|
58
58
|
}
|
|
59
|
-
|
|
59
|
+
let extensions = Array.isArray(resource) ? resource : (resource.extension || []);
|
|
60
|
+
for (let ext of extensions || []) {
|
|
61
|
+
if (ext.url === url) {
|
|
62
|
+
return getValuePrimitive(ext);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
extensions = Array.isArray(resource) ? resource : (resource.modifierExtension || []);
|
|
60
66
|
for (let ext of extensions || []) {
|
|
61
67
|
if (ext.url === url) {
|
|
62
68
|
return getValuePrimitive(ext);
|
package/tx/library/renderer.js
CHANGED
|
@@ -466,14 +466,15 @@ class Renderer {
|
|
|
466
466
|
li.tx(" "+ this.translate('VALUE_SET_WHERE')+" ");
|
|
467
467
|
li.startCommaList("and");
|
|
468
468
|
for (let f of inc.filter) {
|
|
469
|
-
|
|
469
|
+
let op = this.readFilterOp(f);
|
|
470
|
+
if (op == 'exists') {
|
|
470
471
|
if (f.value == "true") {
|
|
471
472
|
li.commaItem(f.property+" "+ this.translate('VALUE_SET_EXISTS'));
|
|
472
473
|
} else {
|
|
473
474
|
li.commaItem(f.property+" "+ this.translate('VALUE_SET_DOESNT_EXIST'));
|
|
474
475
|
}
|
|
475
476
|
} else {
|
|
476
|
-
li.commaItem(f.property + " " +
|
|
477
|
+
li.commaItem(f.property + " " + op + " ");
|
|
477
478
|
const loc = this.linkResolver ? await this.linkResolver.resolveCode(this.opContext, inc.system, inc.version, f.value) : null;
|
|
478
479
|
if (loc) {
|
|
479
480
|
li.ah(loc.link).tx(loc.description);
|
|
@@ -2243,6 +2244,14 @@ class Renderer {
|
|
|
2243
2244
|
return defn+' = ' + value;
|
|
2244
2245
|
}
|
|
2245
2246
|
}
|
|
2247
|
+
|
|
2248
|
+
readFilterOp(f) {
|
|
2249
|
+
if (f._op) {
|
|
2250
|
+
return Extensions.readString(f._op, 'http://hl7.org/fhir/5.0/StructureDefinition/extension-ValueSet.compose.include.filter.op');
|
|
2251
|
+
} else {
|
|
2252
|
+
return f.op;
|
|
2253
|
+
}
|
|
2254
|
+
}
|
|
2246
2255
|
}
|
|
2247
2256
|
|
|
2248
2257
|
module.exports = { Renderer };
|
package/tx/vs/vs-vsac.js
CHANGED
|
@@ -17,6 +17,7 @@ class VSACValueSetProvider extends AbstractValueSetProvider {
|
|
|
17
17
|
* @param {string} config.cacheFolder - Local folder for cached database
|
|
18
18
|
* @param {number} [config.refreshIntervalHours=24] - Hours between refresh scans
|
|
19
19
|
* @param {string} [config.baseUrl='http://cts.nlm.nih.gov/fhir'] - Base URL for VSAC FHIR server
|
|
20
|
+
* @param {number} [config.timeoutMs=120000] - HTTP request timeout in milliseconds
|
|
20
21
|
*/
|
|
21
22
|
constructor(config, stats) {
|
|
22
23
|
super();
|
|
@@ -43,7 +44,7 @@ class VSACValueSetProvider extends AbstractValueSetProvider {
|
|
|
43
44
|
const authString = Buffer.from(`apikey:${this.apiKey}`).toString('base64');
|
|
44
45
|
this.httpClient = axios.create({
|
|
45
46
|
baseURL: this.baseUrl,
|
|
46
|
-
timeout:
|
|
47
|
+
timeout: config.timeoutMs || 120000,
|
|
47
48
|
headers: {
|
|
48
49
|
'Accept': 'application/fhir+json',
|
|
49
50
|
'User-Agent': 'FHIR-ValueSet-Provider/1.0',
|
package/tx/workers/validate.js
CHANGED
|
@@ -839,7 +839,7 @@ class ValueSetChecker {
|
|
|
839
839
|
} else {
|
|
840
840
|
bAdd = !unknownSystems.has(system + '|' + version);
|
|
841
841
|
if (bAdd) {
|
|
842
|
-
let vl = await this.listVersions(system);
|
|
842
|
+
let vl = await this.worker.listVersions(system);
|
|
843
843
|
if (vl.length == 0) {
|
|
844
844
|
mid = 'UNKNOWN_CODESYSTEM_VERSION_NONE';
|
|
845
845
|
vn = system;
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
const {VersionUtilities} = require("../../library/version-utilities");
|
|
2
2
|
const {getValueName} = require("../../library/utilities");
|
|
3
|
+
const {Extensions} = require("../library/extensions");
|
|
3
4
|
|
|
4
5
|
/**
|
|
5
6
|
* Converts input ValueSet to R5 format (modifies input object for performance)
|
|
@@ -13,6 +14,12 @@ function valueSetToR5(jsonObj, sourceVersion) {
|
|
|
13
14
|
if (VersionUtilities.isR5Ver(sourceVersion)) {
|
|
14
15
|
return jsonObj; // No conversion needed
|
|
15
16
|
}
|
|
17
|
+
for (const inc of jsonObj.compose.include || []) {
|
|
18
|
+
valueSetIncludeToR5(inc);
|
|
19
|
+
}
|
|
20
|
+
for (const inc of jsonObj.compose.exclude || []) {
|
|
21
|
+
valueSetIncludeToR5(inc);
|
|
22
|
+
}
|
|
16
23
|
if (VersionUtilities.isR4Ver(sourceVersion)) {
|
|
17
24
|
return jsonObj; // No conversion needed
|
|
18
25
|
}
|
|
@@ -26,6 +33,19 @@ function valueSetToR5(jsonObj, sourceVersion) {
|
|
|
26
33
|
throw new Error(`Unsupported FHIR version: ${sourceVersion}`);
|
|
27
34
|
}
|
|
28
35
|
|
|
36
|
+
function valueSetIncludeToR5(inc) {
|
|
37
|
+
for (const filter of inc.filter || []) {
|
|
38
|
+
if (filter._op) {
|
|
39
|
+
let code = Extensions.readString(filter._op, 'http://hl7.org/fhir/5.0/StructureDefinition/extension-ValueSet.compose.include.filter.op');
|
|
40
|
+
if (code) {
|
|
41
|
+
filter.op = code;
|
|
42
|
+
delete filter._op;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
|
|
29
49
|
/**
|
|
30
50
|
* Converts R5 ValueSet to target version format (clones object first)
|
|
31
51
|
* @param {Object} r5Obj - The R5 format ValueSet object
|
|
@@ -70,8 +90,8 @@ function valueSetR5ToR4(r5Obj) {
|
|
|
70
90
|
if (include.filter && Array.isArray(include.filter)) {
|
|
71
91
|
include.filter = include.filter.map(filter => {
|
|
72
92
|
if (filter.op && isR5OnlyFilterOperator(filter.op)) {
|
|
73
|
-
|
|
74
|
-
|
|
93
|
+
filter._op = { "extension": "http://hl7.org/fhir/5.0/StructureDefinition/extension-ValueSet.compose.include.filter.op", "valueCode": filter.op}
|
|
94
|
+
delete filter.op;
|
|
75
95
|
}
|
|
76
96
|
return filter;
|
|
77
97
|
}).filter(filter => filter !== null);
|
|
@@ -85,8 +105,8 @@ function valueSetR5ToR4(r5Obj) {
|
|
|
85
105
|
if (exclude.filter && Array.isArray(exclude.filter)) {
|
|
86
106
|
exclude.filter = exclude.filter.map(filter => {
|
|
87
107
|
if (filter.op && isR5OnlyFilterOperator(filter.op)) {
|
|
88
|
-
|
|
89
|
-
|
|
108
|
+
filter._op = { "extension": "http://hl7.org/fhir/5.0/StructureDefinition/extension-ValueSet.compose.include.filter.op", "valueCode": filter.op}
|
|
109
|
+
delete filter.op;
|
|
90
110
|
}
|
|
91
111
|
return filter;
|
|
92
112
|
}).filter(filter => filter !== null);
|
|
@@ -135,8 +155,8 @@ function valueSetR5ToR3(r5Obj) {
|
|
|
135
155
|
if (include.filter && Array.isArray(include.filter)) {
|
|
136
156
|
include.filter = include.filter.map(filter => {
|
|
137
157
|
if (filter.op && !isR3CompatibleFilterOperator(filter.op)) {
|
|
138
|
-
|
|
139
|
-
|
|
158
|
+
filter._op = { "extension": "http://hl7.org/fhir/5.0/StructureDefinition/extension-ValueSet.compose.include.filter.op", "valueCode": filter.op}
|
|
159
|
+
delete filter.op;
|
|
140
160
|
}
|
|
141
161
|
return filter;
|
|
142
162
|
}).filter(filter => filter !== null);
|
|
@@ -150,8 +170,8 @@ function valueSetR5ToR3(r5Obj) {
|
|
|
150
170
|
if (exclude.filter && Array.isArray(exclude.filter)) {
|
|
151
171
|
exclude.filter = exclude.filter.map(filter => {
|
|
152
172
|
if (filter.op && !isR3CompatibleFilterOperator(filter.op)) {
|
|
153
|
-
|
|
154
|
-
|
|
173
|
+
filter._op = { "extension": "http://hl7.org/fhir/5.0/StructureDefinition/extension-ValueSet.compose.include.filter.op", "valueCode": filter.op}
|
|
174
|
+
delete filter.op;
|
|
155
175
|
}
|
|
156
176
|
return filter;
|
|
157
177
|
}).filter(filter => filter !== null);
|