fhirsmith 0.8.3 → 0.8.5
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 +43 -3
- package/package.json +5 -2
- package/static/assets/js/clipboard-btn.js +31 -0
- package/static/assets/js/clipboard.min.js +7 -0
- package/static/fhir.css +20 -1
- package/static/images/noun_copy to clipboard_1669410.png +0 -0
- package/translations/rendering-phrases.properties +144 -55
- package/tx/cs/cs-api.js +27 -4
- package/tx/cs/cs-base.js +13 -0
- package/tx/cs/cs-snomed.js +91 -10
- package/tx/html/tx-template.html +5 -2
- package/tx/library/codesystem.js +20 -0
- package/tx/library/designations.js +37 -1
- package/tx/library/renderer.js +26 -8
- package/tx/provider.js +30 -0
- package/tx/tx.fhir.org.yml +1 -1
- package/tx/workers/expand.js +19 -12
- package/tx/workers/lookup.js +19 -3
- package/tx/workers/read.js +4 -0
- package/tx/workers/search.js +126 -51
- package/tx/workers/translate.js +3 -3
- package/tx/workers/worker.js +8 -2
- package/tx/xversion/xv-codesystem.js +3 -3
- package/tx/xversion/xv-parameters.js +2 -2
- package/tx/xversion/xv-valueset.js +1 -2
package/tx/cs/cs-snomed.js
CHANGED
|
@@ -355,7 +355,7 @@ class SnomedServices {
|
|
|
355
355
|
return result;
|
|
356
356
|
}
|
|
357
357
|
|
|
358
|
-
|
|
358
|
+
filterChildOf(id = true) {
|
|
359
359
|
const result = new SnomedFilterContext();
|
|
360
360
|
const conceptResult = this.concepts.findConcept(id);
|
|
361
361
|
|
|
@@ -363,12 +363,62 @@ class SnomedServices {
|
|
|
363
363
|
throw new Error(`The SNOMED CT Concept ${id} is not known`);
|
|
364
364
|
}
|
|
365
365
|
|
|
366
|
-
const
|
|
367
|
-
|
|
368
|
-
|
|
366
|
+
const descendants = this.getConceptChildren(conceptResult.index);
|
|
367
|
+
|
|
368
|
+
result.descendants = descendants;
|
|
369
|
+
|
|
370
|
+
return result;
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
|
|
374
|
+
filterGeneralizes(id = true) {
|
|
375
|
+
const result = new SnomedFilterContext();
|
|
376
|
+
const conceptResult = this.concepts.findConcept(id);
|
|
377
|
+
|
|
378
|
+
if (!conceptResult.found) {
|
|
379
|
+
throw new Error(`The SNOMED CT Concept ${id} is not known`);
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
let ancestors = new Set();
|
|
383
|
+
let parents = this.getConceptParents(conceptResult.index);
|
|
384
|
+
let isNew = true;
|
|
385
|
+
while (isNew) {
|
|
386
|
+
isNew = false;
|
|
387
|
+
let np = [];
|
|
388
|
+
for (let parent of parents) {
|
|
389
|
+
if (!ancestors.has(parent)) {
|
|
390
|
+
isNew = true;
|
|
391
|
+
ancestors.add(parent);
|
|
392
|
+
np.push(...this.getConceptParents(parent));
|
|
393
|
+
}
|
|
394
|
+
}
|
|
395
|
+
parents = np;
|
|
369
396
|
}
|
|
370
397
|
|
|
371
|
-
result.
|
|
398
|
+
result.descendants = [...ancestors];
|
|
399
|
+
|
|
400
|
+
return result;
|
|
401
|
+
}
|
|
402
|
+
|
|
403
|
+
|
|
404
|
+
filterIn(idList) {
|
|
405
|
+
const result = new SnomedFilterContext();
|
|
406
|
+
let members = [];
|
|
407
|
+
for (let id of idList.split(',')) {
|
|
408
|
+
const conceptResult = this.concepts.findConcept(id);
|
|
409
|
+
|
|
410
|
+
if (!conceptResult.found) {
|
|
411
|
+
throw new Error(`The SNOMED CT Concept ${id} is not known`);
|
|
412
|
+
}
|
|
413
|
+
|
|
414
|
+
const refSetIndex = this.getConceptRefSet(conceptResult.index, false);
|
|
415
|
+
if (refSetIndex === 0) {
|
|
416
|
+
members.push(conceptResult.index);
|
|
417
|
+
} else {
|
|
418
|
+
members.push(...this.refSetMembers.getMembers(refSetIndex));
|
|
419
|
+
}
|
|
420
|
+
}
|
|
421
|
+
result.members = members;
|
|
372
422
|
return result;
|
|
373
423
|
}
|
|
374
424
|
|
|
@@ -775,6 +825,13 @@ class SnomedProvider extends BaseCSServices {
|
|
|
775
825
|
const ctxt = await this.#ensureContext(context);
|
|
776
826
|
if (ctxt) {
|
|
777
827
|
if (!(ctxt instanceof SnomedExpressionContext) || ctxt.expression?.concepts.length == 1) {
|
|
828
|
+
const time = this.sct.concepts.getConcept(ctxt.getReference()).effectiveTime;
|
|
829
|
+
const pascalEpoch = new Date(1899, 11, 30);
|
|
830
|
+
const date = new Date(pascalEpoch.getTime() + time * 86400000);
|
|
831
|
+
const dateStr = date.toISOString().slice(0, 10);
|
|
832
|
+
this._addDateTimeProperty(params, 'property', 'effectiveTime', dateStr);
|
|
833
|
+
|
|
834
|
+
|
|
778
835
|
const parents = this.sct.getConceptParents(ctxt.getReference());
|
|
779
836
|
for (let parentRef of parents) {
|
|
780
837
|
const code = this.sct.getConceptId(parentRef);
|
|
@@ -792,7 +849,7 @@ class SnomedProvider extends BaseCSServices {
|
|
|
792
849
|
const moduleId = this.sct.concepts.getModuleId(ctxt.getReference());
|
|
793
850
|
if (moduleId) {
|
|
794
851
|
const code = this.sct.getConceptId(moduleId);
|
|
795
|
-
this._addCodeProperty(params, 'property', 'module', code, null,
|
|
852
|
+
this._addCodeProperty(params, 'property', 'module', code, null, this.sct.getDisplayName(moduleId));
|
|
796
853
|
}
|
|
797
854
|
|
|
798
855
|
const relationships = this.sct.getConceptRelationships(ctxt.getReference());
|
|
@@ -838,9 +895,20 @@ class SnomedProvider extends BaseCSServices {
|
|
|
838
895
|
async doesFilter(prop, op, value) {
|
|
839
896
|
if (prop === 'concept') {
|
|
840
897
|
const id = this.sct.stringToIdOrZero(value);
|
|
841
|
-
if (id !== 0n && ['=', 'is-a', 'descendent-of', 'in'].includes(op)) {
|
|
898
|
+
if (id !== 0n && ['=', 'is-a', 'descendent-of', 'in', 'generalizes', 'child-of'].includes(op)) {
|
|
842
899
|
return this.sct.conceptExists(value);
|
|
843
900
|
}
|
|
901
|
+
if (op === 'in' && value.includes(',')) {
|
|
902
|
+
let ok = true;
|
|
903
|
+
for (const idStr of value.split(',')) {
|
|
904
|
+
const id = this.sct.stringToIdOrZero(idStr);
|
|
905
|
+
if (id === 0n) {
|
|
906
|
+
ok = false;
|
|
907
|
+
break;
|
|
908
|
+
}
|
|
909
|
+
}
|
|
910
|
+
return ok;
|
|
911
|
+
}
|
|
844
912
|
}
|
|
845
913
|
if (prop === 'inactive') {
|
|
846
914
|
return op === '=' && ['true', 'false'].includes(value);
|
|
@@ -874,7 +942,7 @@ class SnomedProvider extends BaseCSServices {
|
|
|
874
942
|
|
|
875
943
|
if (prop === 'concept') {
|
|
876
944
|
const id = this.sct.stringToIdOrZero(value);
|
|
877
|
-
if (id === 0n) {
|
|
945
|
+
if (id === 0n && op !== 'in') {
|
|
878
946
|
throw new Error(`Invalid concept ID: ${value}`);
|
|
879
947
|
}
|
|
880
948
|
|
|
@@ -891,8 +959,16 @@ class SnomedProvider extends BaseCSServices {
|
|
|
891
959
|
filterContext.filters.push(this.sct.filterIsA(id, false));
|
|
892
960
|
return null;
|
|
893
961
|
}
|
|
962
|
+
case 'child-of': {
|
|
963
|
+
filterContext.filters.push(this.sct.filterChildOf(id));
|
|
964
|
+
return null;
|
|
965
|
+
}
|
|
966
|
+
case 'generalizes': {
|
|
967
|
+
filterContext.filters.push(this.sct.filterGeneralizes(id, false));
|
|
968
|
+
return null;
|
|
969
|
+
}
|
|
894
970
|
case 'in': {
|
|
895
|
-
filterContext.filters.push(this.sct.filterIn(
|
|
971
|
+
filterContext.filters.push(this.sct.filterIn(value));
|
|
896
972
|
return null;
|
|
897
973
|
}
|
|
898
974
|
default:
|
|
@@ -1121,7 +1197,7 @@ class SnomedProvider extends BaseCSServices {
|
|
|
1121
1197
|
if (set.propProp || set.propValue) {
|
|
1122
1198
|
for (let i = 0; i < this.sct.concepts.count(); i++) {
|
|
1123
1199
|
let concept = this.sct.concepts.getConceptByCount(i);
|
|
1124
|
-
const relationships = this.sct.getConceptRelationships(concept.
|
|
1200
|
+
const relationships = this.sct.getConceptRelationships(concept.index);
|
|
1125
1201
|
for (let relationshipRef of relationships) {
|
|
1126
1202
|
const relationship = this.sct.relationships.getRelationship(relationshipRef);
|
|
1127
1203
|
if (set.propProp === relationship.relType && set.propValue === relationship.target) {
|
|
@@ -1560,6 +1636,11 @@ class SnomedServicesFactory extends CodeSystemFactoryProvider {
|
|
|
1560
1636
|
return null;
|
|
1561
1637
|
}
|
|
1562
1638
|
}
|
|
1639
|
+
|
|
1640
|
+
webSource() {
|
|
1641
|
+
return this.version();
|
|
1642
|
+
}
|
|
1643
|
+
|
|
1563
1644
|
}
|
|
1564
1645
|
|
|
1565
1646
|
function getEditionName(edition) {
|
package/tx/html/tx-template.html
CHANGED
|
@@ -126,9 +126,12 @@
|
|
|
126
126
|
</div>
|
|
127
127
|
|
|
128
128
|
<!-- JS and analytics only. -->
|
|
129
|
-
<script src="/assets/js/respond.min.js"
|
|
130
|
-
<script src="/assets/js/fhir.js"
|
|
129
|
+
<script src="/assets/js/respond.min.js"> </script>
|
|
130
|
+
<script src="/assets/js/fhir.js"> </script>
|
|
131
|
+
<script src="/assets/js/clipboard.min.js"> </script>
|
|
132
|
+
<script src="/assets/js/clipboard-btn.js"> </script>
|
|
131
133
|
|
|
132
134
|
</body>
|
|
133
135
|
|
|
134
136
|
</html>
|
|
137
|
+
|
package/tx/library/codesystem.js
CHANGED
|
@@ -2,6 +2,7 @@ const { Language } = require("../../library/languages");
|
|
|
2
2
|
const {CanonicalResource} = require("./canonical-resource");
|
|
3
3
|
const {codeSystemFromR5, codeSystemToR5} = require("../xversion/xv-codesystem");
|
|
4
4
|
const {getValuePrimitive} = require("../../library/utilities");
|
|
5
|
+
const {VersionUtilities} = require("../../library/version-utilities");
|
|
5
6
|
|
|
6
7
|
const CodeSystemContentMode = Object.freeze({
|
|
7
8
|
Complete: 'complete',
|
|
@@ -614,12 +615,31 @@ class CodeSystem extends CanonicalResource {
|
|
|
614
615
|
}
|
|
615
616
|
|
|
616
617
|
isLangPack() {
|
|
618
|
+
// todo: this is a temporary work around until fhir.tx.support.r4#0.37.0 is released that properly marks this as a language pack
|
|
619
|
+
if (this.jsonObj.url === 'https://terminology.dhp.uz/fhir/CodeSystem/loinc-supplement-uz') {
|
|
620
|
+
return true;
|
|
621
|
+
}
|
|
617
622
|
return (this.jsonObj.extension || []).find(x => x.url == 'http://hl7.org/fhir/StructureDefinition/codesystem-supplement-type' && getValuePrimitive(x) == 'lang-pack');
|
|
618
623
|
}
|
|
619
624
|
|
|
620
625
|
isPropUri(code, uri) {
|
|
621
626
|
return (this.jsonObj.property || []).find(x => x.code == code && x.uri == uri);
|
|
622
627
|
}
|
|
628
|
+
|
|
629
|
+
isSupplementFor(url, version) {
|
|
630
|
+
if (this.jsonObj.content !== 'supplement') {
|
|
631
|
+
return false;
|
|
632
|
+
}
|
|
633
|
+
let suppU = this.jsonObj.supplements;
|
|
634
|
+
if (suppU == url) {
|
|
635
|
+
return true;
|
|
636
|
+
}
|
|
637
|
+
if (suppU.startsWith(url + '|')) {
|
|
638
|
+
let suppV = suppU.substring(suppU.indexOf('|') + 1);
|
|
639
|
+
return VersionUtilities.versionMatchesByAlgorithm(suppV, version, VersionUtilities.guessVersionAlgorithmFromVersion(version));
|
|
640
|
+
}
|
|
641
|
+
return false;
|
|
642
|
+
}
|
|
623
643
|
}
|
|
624
644
|
|
|
625
645
|
module.exports = { CodeSystem, CodeSystemContentMode };
|
|
@@ -404,6 +404,15 @@ class Designations {
|
|
|
404
404
|
// }
|
|
405
405
|
}
|
|
406
406
|
|
|
407
|
+
hasAnyDisplay(value) {
|
|
408
|
+
for (let designation of this.designations) {
|
|
409
|
+
if (designation.value === value) {
|
|
410
|
+
return true;
|
|
411
|
+
}
|
|
412
|
+
}
|
|
413
|
+
return false;
|
|
414
|
+
}
|
|
415
|
+
|
|
407
416
|
/**
|
|
408
417
|
* Check if a display value exists with specified matching criteria
|
|
409
418
|
*/
|
|
@@ -551,7 +560,7 @@ class Designations {
|
|
|
551
560
|
/**
|
|
552
561
|
* Find the preferred designation for given language preferences
|
|
553
562
|
*/
|
|
554
|
-
preferredDesignation(langList = null) {
|
|
563
|
+
preferredDesignation(langList = null, supplements = null) {
|
|
555
564
|
if (this.designations.length === 0) {
|
|
556
565
|
return null;
|
|
557
566
|
}
|
|
@@ -560,24 +569,39 @@ class Designations {
|
|
|
560
569
|
// No language list, prefer base designations
|
|
561
570
|
for (const cd of this.designations) {
|
|
562
571
|
if (this._isPreferred(cd) && cd.isActive()) {
|
|
572
|
+
if (supplements && cd.source) {
|
|
573
|
+
supplements.add(cd.source);
|
|
574
|
+
}
|
|
563
575
|
return cd;
|
|
564
576
|
}
|
|
565
577
|
}
|
|
566
578
|
for (const cd of this.designations) {
|
|
567
579
|
if (this.isDisplay(cd) && cd.isActive()) {
|
|
580
|
+
if (supplements && cd.source) {
|
|
581
|
+
supplements.add(cd.source);
|
|
582
|
+
}
|
|
568
583
|
return cd;
|
|
569
584
|
}
|
|
570
585
|
}
|
|
571
586
|
for (const cd of this.designations) {
|
|
572
587
|
if (this.isDisplay(cd)) {
|
|
588
|
+
if (supplements && cd.source) {
|
|
589
|
+
supplements.add(cd.source);
|
|
590
|
+
}
|
|
573
591
|
return cd;
|
|
574
592
|
}
|
|
575
593
|
}
|
|
576
594
|
for (const cd of this.designations) {
|
|
577
595
|
if (this._isPreferred(cd)) {
|
|
596
|
+
if (supplements && cd.source) {
|
|
597
|
+
supplements.add(cd.source);
|
|
598
|
+
}
|
|
578
599
|
return cd;
|
|
579
600
|
}
|
|
580
601
|
}
|
|
602
|
+
if (supplements && this.designations[0].source) {
|
|
603
|
+
supplements.add(this.designations[0].source);
|
|
604
|
+
}
|
|
581
605
|
return this.designations[0];
|
|
582
606
|
}
|
|
583
607
|
|
|
@@ -589,16 +613,25 @@ class Designations {
|
|
|
589
613
|
for (const matchType of matchTypes) {
|
|
590
614
|
for (const cd of this.designations) {
|
|
591
615
|
if (this._langMatches(lang, cd.language, matchType) && this.isDisplay(cd)) {
|
|
616
|
+
if (supplements && cd.source) {
|
|
617
|
+
supplements.add(cd.source);
|
|
618
|
+
}
|
|
592
619
|
return cd;
|
|
593
620
|
}
|
|
594
621
|
}
|
|
595
622
|
for (const cd of this.designations) {
|
|
596
623
|
if (this._langMatches(lang, cd.language, matchType) && this._isPreferred(cd)) {
|
|
624
|
+
if (supplements && cd.source) {
|
|
625
|
+
supplements.add(cd.source);
|
|
626
|
+
}
|
|
597
627
|
return cd;
|
|
598
628
|
}
|
|
599
629
|
}
|
|
600
630
|
for (const cd of this.designations) {
|
|
601
631
|
if (this._langMatches(lang, cd.language, matchType)) {
|
|
632
|
+
if (supplements && cd.source) {
|
|
633
|
+
supplements.add(cd.source);
|
|
634
|
+
}
|
|
602
635
|
return cd;
|
|
603
636
|
}
|
|
604
637
|
}
|
|
@@ -606,6 +639,9 @@ class Designations {
|
|
|
606
639
|
}
|
|
607
640
|
for (const cd of this.designations) {
|
|
608
641
|
if (!cd.language && this.isDisplay(cd)) {
|
|
642
|
+
if (supplements && cd.source) {
|
|
643
|
+
supplements.add(cd.source);
|
|
644
|
+
}
|
|
609
645
|
return cd;
|
|
610
646
|
}
|
|
611
647
|
}
|
package/tx/library/renderer.js
CHANGED
|
@@ -141,8 +141,8 @@ class Renderer {
|
|
|
141
141
|
this.renderMetadataLastUpdated(res, tbl);
|
|
142
142
|
this.renderMetadataSource(res, tbl);
|
|
143
143
|
this.renderProperty(tbl, 'TEST_PLAN_LANG', res.language);
|
|
144
|
-
this.
|
|
145
|
-
this.
|
|
144
|
+
this.renderPropertyCopy(tbl, 'GENERAL_DEFINING_URL', res.url);
|
|
145
|
+
this.renderPropertyCopy(tbl, 'GENERAL_VER', res.version);
|
|
146
146
|
this.renderProperty(tbl, 'GENERAL_NAME', res.name);
|
|
147
147
|
this.renderProperty(tbl, 'GENERAL_TITLE', res.title);
|
|
148
148
|
this.renderProperty(tbl, 'GENERAL_STATUS', res.status);
|
|
@@ -150,9 +150,10 @@ class Renderer {
|
|
|
150
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
|
-
this.
|
|
153
|
+
this.renderPropertyCopy(tbl, 'GENERAL_COPYRIGHT', res.copyright);
|
|
154
154
|
this.renderProperty(tbl, 'EXT_FMM_LEVEL', Extensions.readString(res, 'http://hl7.org/fhir/StructureDefinition/structuredefinition-fmm'));
|
|
155
155
|
this.renderProperty(tbl, 'PAT_PERIOD', res.effectivePeriod);
|
|
156
|
+
this.renderPropertyLink(tbl, 'WEB_SOURCE', Extensions.readString(res, 'http://hl7.org/fhir/StructureDefinition/web-source'));
|
|
156
157
|
|
|
157
158
|
// capability statement things
|
|
158
159
|
this.renderProperty(tbl, 'Kind', res.kind);
|
|
@@ -253,15 +254,32 @@ class Renderer {
|
|
|
253
254
|
}
|
|
254
255
|
}
|
|
255
256
|
|
|
256
|
-
|
|
257
|
+
renderPropertyCopy(tbl, msgId, value) {
|
|
257
258
|
if (value) {
|
|
258
259
|
let tr = tbl.tr();
|
|
259
260
|
tr.td().b().tx(this.translate(msgId));
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
tr.td().ah(linkinfo.link).tx(linkinfo.description);
|
|
261
|
+
if (value instanceof Object) {
|
|
262
|
+
tr.td().tx("todo");
|
|
263
263
|
} else {
|
|
264
|
-
tr.td()
|
|
264
|
+
let td = tr.td();
|
|
265
|
+
let span = td.span("copy-text");
|
|
266
|
+
span.tx(value);
|
|
267
|
+
let btn = span.button();
|
|
268
|
+
btn.attr("class", "btn-copy");
|
|
269
|
+
btn.attr("data-clipboard-text", value);
|
|
270
|
+
btn.attr("data-original-title", this.translate('GENERAL_COPY'));
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
renderPropertyLink(tbl, msgId, value) {
|
|
276
|
+
if (value) {
|
|
277
|
+
let tr = tbl.tr();
|
|
278
|
+
tr.td().b().tx(this.translate(msgId));
|
|
279
|
+
if (value instanceof Object) {
|
|
280
|
+
tr.td().tx("todo");
|
|
281
|
+
} else {
|
|
282
|
+
tr.td().ah(value).tx(value);
|
|
265
283
|
}
|
|
266
284
|
}
|
|
267
285
|
}
|
package/tx/provider.js
CHANGED
|
@@ -107,6 +107,36 @@ class Provider {
|
|
|
107
107
|
return null;
|
|
108
108
|
}
|
|
109
109
|
|
|
110
|
+
loadSupplements(url, version, statedSupplements) {
|
|
111
|
+
let supplements = new Map();
|
|
112
|
+
for (let csp of this.codeSystemFactories.values()) {
|
|
113
|
+
csp.listSupplements(supplements, url, version, statedSupplements);
|
|
114
|
+
}
|
|
115
|
+
for (let cs of this.codeSystems.values()) {
|
|
116
|
+
if (cs.isSupplementFor(url, version)) {
|
|
117
|
+
if (cs.isLangPack() || this.isStatedSupplement(cs, statedSupplements)) {
|
|
118
|
+
supplements.set(cs.vurl, cs);
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
return [...supplements.values()];
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
isStatedSupplement(cs, statedSupplements) {
|
|
126
|
+
if (statedSupplements == null) {
|
|
127
|
+
return false;
|
|
128
|
+
}
|
|
129
|
+
for (let suppU of statedSupplements) {
|
|
130
|
+
if (suppU === cs.url) {
|
|
131
|
+
return true;
|
|
132
|
+
}
|
|
133
|
+
if (suppU.startsWith(cs.url+"|")) {
|
|
134
|
+
let suppV = suppU.substring(suppU.indexOf('|') + 1);
|
|
135
|
+
return VersionUtilities.versionMatchesByAlgorithm(suppV, cs.version, VersionUtilities.guessVersionAlgorithmFromVersion(cs.version));
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
return false;
|
|
139
|
+
}
|
|
110
140
|
/**
|
|
111
141
|
* Create a code system provider from a CodeSystem resource
|
|
112
142
|
* @param {OperationContext} opContext - The code system resource
|
package/tx/tx.fhir.org.yml
CHANGED
package/tx/workers/expand.js
CHANGED
|
@@ -204,6 +204,7 @@ class ValueSetExpander {
|
|
|
204
204
|
hasExclusions = false;
|
|
205
205
|
requiredSupplements = new Set();
|
|
206
206
|
usedSupplements = new Set();
|
|
207
|
+
reportedSupplements = new Set();
|
|
207
208
|
internalLimit = INTERNAL_DEFAULT_LIMIT;
|
|
208
209
|
externalLimit = EXTERNAL_DEFAULT_LIMIT;
|
|
209
210
|
|
|
@@ -339,9 +340,9 @@ class ValueSetExpander {
|
|
|
339
340
|
const s = this.canonical(system, version);
|
|
340
341
|
this.addParamUri(expansion, 'used-codesystem', s);
|
|
341
342
|
if (cs != null) {
|
|
342
|
-
const ts = cs.listSupplements();
|
|
343
|
+
const ts = cs.listSupplements(false);
|
|
343
344
|
for (const vs of ts) {
|
|
344
|
-
this.
|
|
345
|
+
this.reportedSupplements.add(vs);
|
|
345
346
|
}
|
|
346
347
|
}
|
|
347
348
|
}
|
|
@@ -415,7 +416,7 @@ class ValueSetExpander {
|
|
|
415
416
|
}
|
|
416
417
|
|
|
417
418
|
// display and designations
|
|
418
|
-
const pref = displays.preferredDesignation(this.params.workingLanguages());
|
|
419
|
+
const pref = displays.preferredDesignation(this.params.workingLanguages(), this.reportedSupplements);
|
|
419
420
|
if (pref && pref.value) {
|
|
420
421
|
n.display = pref.value;
|
|
421
422
|
}
|
|
@@ -426,6 +427,9 @@ class ValueSetExpander {
|
|
|
426
427
|
if (!n.designation) {
|
|
427
428
|
n.designation = [];
|
|
428
429
|
}
|
|
430
|
+
if (t.source) {
|
|
431
|
+
this.reportedSupplements.add(t.source);
|
|
432
|
+
}
|
|
429
433
|
n.designation.push(t.asObject());
|
|
430
434
|
}
|
|
431
435
|
}
|
|
@@ -490,9 +494,9 @@ class ValueSetExpander {
|
|
|
490
494
|
const s = this.canonical(system, version);
|
|
491
495
|
this.addParamUri(expansion, 'used-codesystem', s);
|
|
492
496
|
if (cs) {
|
|
493
|
-
const ts= cs.listSupplements();
|
|
497
|
+
const ts= cs.listSupplements(false);
|
|
494
498
|
for (const vs of ts) {
|
|
495
|
-
this.
|
|
499
|
+
this.reportedSupplements.add(vs);
|
|
496
500
|
}
|
|
497
501
|
}
|
|
498
502
|
}
|
|
@@ -813,7 +817,7 @@ class ValueSetExpander {
|
|
|
813
817
|
this.worker.opContext.log('iterate concepts done');
|
|
814
818
|
}
|
|
815
819
|
|
|
816
|
-
if (cset.filter) {
|
|
820
|
+
if (cset.filter && cset.filter.length > 0) {
|
|
817
821
|
this.worker.opContext.log('prepare filters');
|
|
818
822
|
const fcl = cset.filter;
|
|
819
823
|
const prep = await cs.getPrepContext(true);
|
|
@@ -1040,10 +1044,9 @@ class ValueSetExpander {
|
|
|
1040
1044
|
if (expansion) {
|
|
1041
1045
|
const vs = this.canonical(await cs.system(), await cs.version());
|
|
1042
1046
|
this.addParamUri(expansion, 'used-codesystem', vs);
|
|
1043
|
-
const ts = cs.listSupplements();
|
|
1047
|
+
const ts = cs.listSupplements(false);
|
|
1044
1048
|
for (const v of ts) {
|
|
1045
|
-
this.
|
|
1046
|
-
this.addParamUri(expansion, 'used-supplement', v);
|
|
1049
|
+
this.reportedSupplements.add(v);
|
|
1047
1050
|
}
|
|
1048
1051
|
}
|
|
1049
1052
|
|
|
@@ -1081,10 +1084,9 @@ class ValueSetExpander {
|
|
|
1081
1084
|
if (expansion) {
|
|
1082
1085
|
const vs = this.canonical(await cs.system(), await cs.version());
|
|
1083
1086
|
this.addParamUri(expansion, 'used-codesystem', vs);
|
|
1084
|
-
const ts= cs.listSupplements();
|
|
1087
|
+
const ts= cs.listSupplements(false);
|
|
1085
1088
|
for (const v of ts) {
|
|
1086
|
-
this.
|
|
1087
|
-
this.addParamUri(expansion, 'used-supplement', v);
|
|
1089
|
+
this.reportedSupplements.add(v);
|
|
1088
1090
|
}
|
|
1089
1091
|
}
|
|
1090
1092
|
|
|
@@ -1303,6 +1305,11 @@ class ValueSetExpander {
|
|
|
1303
1305
|
}
|
|
1304
1306
|
}
|
|
1305
1307
|
|
|
1308
|
+
const ts = this.reportedSupplements;
|
|
1309
|
+
for (const v of ts) {
|
|
1310
|
+
this.addParamUri(exp, 'used-supplement', v);
|
|
1311
|
+
}
|
|
1312
|
+
|
|
1306
1313
|
this.worker.opContext.log('finish up');
|
|
1307
1314
|
|
|
1308
1315
|
let list;
|
package/tx/workers/lookup.js
CHANGED
|
@@ -149,14 +149,15 @@ class LookupWorker extends TerminologyWorker {
|
|
|
149
149
|
|
|
150
150
|
// check supplements
|
|
151
151
|
const used = new Set();
|
|
152
|
-
|
|
152
|
+
const reported = new Set();
|
|
153
|
+
this.checkSupplements(csProvider, null, txp.supplements, used, reported);
|
|
153
154
|
const unused = new Set([...txp.supplements].filter(s => !used.has(s)));
|
|
154
155
|
if (unused.size > 0) {
|
|
155
156
|
throw new Issue('error', 'not-found', null, 'VALUESET_SUPPLEMENT_MISSING', this.i18n.translatePlural(unused.size, 'VALUESET_SUPPLEMENT_MISSING', txp.HTTPLanguages, [[...unused].join(',')]), 'not-found').handleAsOO(400);
|
|
156
157
|
}
|
|
157
158
|
|
|
158
159
|
// Perform the lookup
|
|
159
|
-
const result = await this.doLookup(csProvider, code, txp);
|
|
160
|
+
const result = await this.doLookup(csProvider, code, txp, reported);
|
|
160
161
|
return res.status(200).json(result);
|
|
161
162
|
} catch (error) {
|
|
162
163
|
this.log.error(error);
|
|
@@ -242,9 +243,10 @@ class LookupWorker extends TerminologyWorker {
|
|
|
242
243
|
* @param {CodeSystemProvider} csProvider - CodeSystem provider
|
|
243
244
|
* @param {string} code - Code to look up
|
|
244
245
|
* @param {Object} params - Parsed parameters
|
|
246
|
+
* @param {Set} reportedSupplements - Set of supplements that are to be reported
|
|
245
247
|
* @returns {Object} Parameters resource with lookup result
|
|
246
248
|
*/
|
|
247
|
-
async doLookup(csProvider, code, params) {
|
|
249
|
+
async doLookup(csProvider, code, params, reportedSupplements) {
|
|
248
250
|
this.deadCheck('doLookup');
|
|
249
251
|
|
|
250
252
|
await this.checkSupplements(csProvider, null, params.supplements);
|
|
@@ -352,6 +354,12 @@ class LookupWorker extends TerminologyWorker {
|
|
|
352
354
|
this.deadCheck('doLookup-designations');
|
|
353
355
|
const designationParts = [];
|
|
354
356
|
|
|
357
|
+
if (designation.supplement) {
|
|
358
|
+
designationParts.push({
|
|
359
|
+
name: 'source',
|
|
360
|
+
valueCanonical: designation.supplement.vurl
|
|
361
|
+
});
|
|
362
|
+
}
|
|
355
363
|
if (designation.language) {
|
|
356
364
|
designationParts.push({
|
|
357
365
|
name: 'language',
|
|
@@ -382,6 +390,14 @@ class LookupWorker extends TerminologyWorker {
|
|
|
382
390
|
// Let the provider add additional properties
|
|
383
391
|
await csProvider.extendLookup(ctxt, params.properties || [], responseParams);
|
|
384
392
|
|
|
393
|
+
if (reportedSupplements) {
|
|
394
|
+
for (const supplement of reportedSupplements) {
|
|
395
|
+
responseParams.push({
|
|
396
|
+
name: 'used-supplement',
|
|
397
|
+
valueCanonical: supplement
|
|
398
|
+
});
|
|
399
|
+
}
|
|
400
|
+
}
|
|
385
401
|
return {
|
|
386
402
|
resourceType: 'Parameters',
|
|
387
403
|
parameter: responseParams
|
package/tx/workers/read.js
CHANGED
|
@@ -90,11 +90,15 @@ class ReadWorker extends TerminologyWorker {
|
|
|
90
90
|
resourceType: "CodeSystem",
|
|
91
91
|
id: "x-" + cs.id(),
|
|
92
92
|
url: cs.system(),
|
|
93
|
+
version: cs.version(),
|
|
93
94
|
name: cs.name(),
|
|
94
95
|
status: "active",
|
|
95
96
|
description: "This is a place holder for the code system which is fully supported through internal means (not by this code system)",
|
|
96
97
|
content: "not-present"
|
|
97
98
|
}
|
|
99
|
+
if (cs.webSource()) {
|
|
100
|
+
json.extension = [{ url: "http://hl7.org/fhir/StructureDefinition/web-source", valueUrl : cs.webSource()}];
|
|
101
|
+
}
|
|
98
102
|
if (cs.version()) {
|
|
99
103
|
json.version = cs.version();
|
|
100
104
|
}
|