fhirsmith 0.3.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 +42 -0
- package/FHIRsmith.png +0 -0
- package/README.md +277 -0
- package/config-template.json +144 -0
- package/library/folder-setup.js +58 -0
- package/library/html-server.js +166 -0
- package/library/html.js +835 -0
- package/library/i18nsupport.js +259 -0
- package/library/languages.js +779 -0
- package/library/logger-telnet.js +205 -0
- package/library/logger.js +279 -0
- package/library/package-manager.js +876 -0
- package/library/utilities.js +196 -0
- package/library/version-utilities.js +1056 -0
- package/npmprojector/config-example.json +13 -0
- package/npmprojector/indexer.js +394 -0
- package/npmprojector/npmprojector.js +395 -0
- package/npmprojector/readme.md +174 -0
- package/npmprojector/watcher.js +335 -0
- package/package.json +119 -0
- package/packages/package-crawler.js +846 -0
- package/packages/packages-template.html +126 -0
- package/packages/packages.js +2838 -0
- package/passwords.ini +2 -0
- package/publisher/publisher-template.html +208 -0
- package/publisher/publisher.js +2167 -0
- package/publisher/task-draft.js +458 -0
- package/registry/api.js +735 -0
- package/registry/crawler.js +637 -0
- package/registry/model.js +513 -0
- package/registry/readme.md +243 -0
- package/registry/registry-data.json +121015 -0
- package/registry/registry-template.html +126 -0
- package/registry/registry.js +1395 -0
- package/registry/test-runner.js +237 -0
- package/root-template.html +124 -0
- package/server.js +524 -0
- package/shl/private-key.pem +5 -0
- package/shl/public-key.pem +18 -0
- package/shl/shl.js +1125 -0
- package/shl/vhl.js +69 -0
- package/static/FHIRsmith128.png +0 -0
- package/static/FHIRsmith16.png +0 -0
- package/static/FHIRsmith32.png +0 -0
- package/static/FHIRsmith64.png +0 -0
- package/static/assets/css/bootstrap-fhir.css +5302 -0
- package/static/assets/css/bootstrap-glyphicons.css +2 -0
- package/static/assets/css/bootstrap.css +4097 -0
- package/static/assets/css/jquery-ui.css +523 -0
- package/static/assets/css/jquery-ui.structure.css +863 -0
- package/static/assets/css/jquery-ui.structure.min.css +5 -0
- package/static/assets/css/jquery-ui.theme.css +439 -0
- package/static/assets/css/jquery-ui.theme.min.css +5 -0
- package/static/assets/css/jquery.ui.all.css +7 -0
- package/static/assets/css/modules.css +18 -0
- package/static/assets/css/project.css +367 -0
- package/static/assets/css/pygments-manni.css +66 -0
- package/static/assets/css/tags.css +74 -0
- package/static/assets/css/xml.css +2 -0
- package/static/assets/fonts/glyphiconshalflings-regular.eot +0 -0
- package/static/assets/fonts/glyphiconshalflings-regular.otf +0 -0
- package/static/assets/fonts/glyphiconshalflings-regular.svg +175 -0
- package/static/assets/fonts/glyphiconshalflings-regular.ttf +0 -0
- package/static/assets/fonts/glyphiconshalflings-regular.woff +0 -0
- package/static/assets/ico/apple-touch-icon-114-precomposed.png +0 -0
- package/static/assets/ico/apple-touch-icon-144-precomposed.png +0 -0
- package/static/assets/ico/apple-touch-icon-57-precomposed.png +0 -0
- package/static/assets/ico/apple-touch-icon-72-precomposed.png +0 -0
- package/static/assets/ico/favicon.ico +0 -0
- package/static/assets/ico/favicon.png +0 -0
- package/static/assets/images/fhir-logo-www.png +0 -0
- package/static/assets/images/fhir-logo.png +0 -0
- package/static/assets/images/hl7-logo.png +0 -0
- package/static/assets/images/logo_ansinew.jpg +0 -0
- package/static/assets/images/search.png +0 -0
- package/static/assets/images/stripe.png +0 -0
- package/static/assets/images/target.png +0 -0
- package/static/assets/images/tx-registry-root.gif +0 -0
- package/static/assets/images/tx-registry.png +0 -0
- package/static/assets/images/tx-server.png +0 -0
- package/static/assets/images/tx-version.png +0 -0
- package/static/assets/js/bootstrap.min.js +6 -0
- package/static/assets/js/fhir-gw.js +259 -0
- package/static/assets/js/fhir.js +2 -0
- package/static/assets/js/html5shiv.js +8 -0
- package/static/assets/js/jcookie.js +96 -0
- package/static/assets/js/jquery-ui.min.js +6 -0
- package/static/assets/js/jquery.js +10716 -0
- package/static/assets/js/jquery.min.js +2 -0
- package/static/assets/js/jquery.ui.core.js +314 -0
- package/static/assets/js/jquery.ui.draggable.js +825 -0
- package/static/assets/js/jquery.ui.mouse.js +162 -0
- package/static/assets/js/jquery.ui.resizable.js +842 -0
- package/static/assets/js/jquery.ui.widget.js +268 -0
- package/static/assets/js/json2.js +487 -0
- package/static/assets/js/jtip.js +97 -0
- package/static/assets/js/respond.min.js +6 -0
- package/static/assets/js/statuspage.js +70 -0
- package/static/assets/js/xml.js +2 -0
- package/static/dist/js/bootstrap.js +1964 -0
- package/static/favicon.png +0 -0
- package/static/fhir.css +626 -0
- package/static/icon-fhir-16.png +0 -0
- package/static/images/ui-bg_diagonals-thick_18_b81900_40x40.png +0 -0
- package/static/images/ui-bg_diagonals-thick_20_666666_40x40.png +0 -0
- package/static/images/ui-bg_flat_10_000000_40x100.png +0 -0
- package/static/images/ui-bg_glass_100_f6f6f6_1x400.png +0 -0
- package/static/images/ui-bg_glass_100_fdf5ce_1x400.png +0 -0
- package/static/images/ui-bg_glass_65_ffffff_1x400.png +0 -0
- package/static/images/ui-bg_gloss-wave_35_f6a828_500x100.png +0 -0
- package/static/images/ui-bg_highlight-soft_100_eeeeee_1x100.png +0 -0
- package/static/images/ui-bg_highlight-soft_75_ffe45c_1x100.png +0 -0
- package/static/images/ui-icons_222222_256x240.png +0 -0
- package/static/images/ui-icons_228ef1_256x240.png +0 -0
- package/static/images/ui-icons_ef8c08_256x240.png +0 -0
- package/static/images/ui-icons_ffd27a_256x240.png +0 -0
- package/static/images/ui-icons_ffffff_256x240.png +0 -0
- package/static/js/jquery.effects.blind.js +49 -0
- package/static/js/jquery.effects.bounce.js +78 -0
- package/static/js/jquery.effects.clip.js +54 -0
- package/static/js/jquery.effects.core.js +763 -0
- package/static/js/jquery.effects.drop.js +50 -0
- package/static/js/jquery.effects.explode.js +79 -0
- package/static/js/jquery.effects.fade.js +32 -0
- package/static/js/jquery.effects.fold.js +56 -0
- package/static/js/jquery.effects.highlight.js +50 -0
- package/static/js/jquery.effects.pulsate.js +51 -0
- package/static/js/jquery.effects.scale.js +178 -0
- package/static/js/jquery.effects.shake.js +57 -0
- package/static/js/jquery.effects.slide.js +50 -0
- package/static/js/jquery.effects.transfer.js +45 -0
- package/static/js/jquery.ui.accordion.js +611 -0
- package/static/js/jquery.ui.autocomplete.js +612 -0
- package/static/js/jquery.ui.button.js +416 -0
- package/static/js/jquery.ui.datepicker.js +1823 -0
- package/static/js/jquery.ui.dialog.js +878 -0
- package/static/js/jquery.ui.droppable.js +296 -0
- package/static/js/jquery.ui.position.js +252 -0
- package/static/js/jquery.ui.progressbar.js +109 -0
- package/static/js/jquery.ui.selectable.js +266 -0
- package/static/js/jquery.ui.slider.js +666 -0
- package/static/js/jquery.ui.sortable.js +1077 -0
- package/static/js/jquery.ui.tabs.js +758 -0
- package/stats.js +80 -0
- package/test-cache/vsac/vsac-valuesets.db +0 -0
- package/token/nginx_passport_setup.md +383 -0
- package/token/security_guide.md +294 -0
- package/token/token-template.html +330 -0
- package/token/token.js +1300 -0
- package/translations/Messages.properties +1510 -0
- package/translations/Messages_ar.properties +1399 -0
- package/translations/Messages_de.properties +836 -0
- package/translations/Messages_es.properties +737 -0
- package/translations/Messages_fr.properties +1 -0
- package/translations/Messages_ja.properties +893 -0
- package/translations/Messages_nl.properties +1357 -0
- package/translations/Messages_pt.properties +1302 -0
- package/translations/Messages_ru.properties +1 -0
- package/translations/Messages_uz.properties +1 -0
- package/translations/Messages_zh.properties +1 -0
- package/translations/rendering-phrases.properties +1128 -0
- package/translations/rendering-phrases_ar.properties +1091 -0
- package/translations/rendering-phrases_de.properties +6 -0
- package/translations/rendering-phrases_es.properties +6 -0
- package/translations/rendering-phrases_fr.properties +624 -0
- package/translations/rendering-phrases_ja.properties +21 -0
- package/translations/rendering-phrases_nl.properties +970 -0
- package/translations/rendering-phrases_pt.properties +1020 -0
- package/translations/rendering-phrases_ru.properties +1094 -0
- package/translations/rendering-phrases_uz.properties +1 -0
- package/translations/rendering-phrases_zh.properties +1 -0
- package/tx/README.md +418 -0
- package/tx/cm/cm-api.js +110 -0
- package/tx/cm/cm-database.js +735 -0
- package/tx/cm/cm-package.js +325 -0
- package/tx/cs/cs-api.js +789 -0
- package/tx/cs/cs-areacode.js +615 -0
- package/tx/cs/cs-country.js +1110 -0
- package/tx/cs/cs-cpt.js +785 -0
- package/tx/cs/cs-cs.js +1579 -0
- package/tx/cs/cs-currency.js +539 -0
- package/tx/cs/cs-db.js +1321 -0
- package/tx/cs/cs-hgvs.js +329 -0
- package/tx/cs/cs-lang.js +465 -0
- package/tx/cs/cs-loinc.js +1485 -0
- package/tx/cs/cs-mimetypes.js +238 -0
- package/tx/cs/cs-ndc.js +704 -0
- package/tx/cs/cs-omop.js +1025 -0
- package/tx/cs/cs-provider-api.js +43 -0
- package/tx/cs/cs-provider-list.js +37 -0
- package/tx/cs/cs-rxnorm.js +808 -0
- package/tx/cs/cs-snomed.js +1102 -0
- package/tx/cs/cs-ucum.js +514 -0
- package/tx/cs/cs-unii.js +271 -0
- package/tx/cs/cs-uri.js +218 -0
- package/tx/cs/cs-usstates.js +305 -0
- package/tx/dev.fhir.org.yml +14 -0
- package/tx/fixtures/test-cases-setup.json +18 -0
- package/tx/fixtures/test-cases.yml +16 -0
- package/tx/html/codesystem-operations.liquid +25 -0
- package/tx/html/home-metrics.liquid +247 -0
- package/tx/html/operations-form.liquid +148 -0
- package/tx/html/search-form.liquid +62 -0
- package/tx/html/tx-template.html +133 -0
- package/tx/html/valueset-operations.liquid +54 -0
- package/tx/importers/atc-to-fhir.js +316 -0
- package/tx/importers/import-loinc.module.js +1536 -0
- package/tx/importers/import-ndc.module.js +1088 -0
- package/tx/importers/import-rxnorm.module.js +898 -0
- package/tx/importers/import-sct.module.js +2457 -0
- package/tx/importers/import-unii.module.js +601 -0
- package/tx/importers/readme.md +453 -0
- package/tx/importers/subset-loinc.module.js +1081 -0
- package/tx/importers/subset-rxnorm.module.js +938 -0
- package/tx/importers/tx-import-base.js +351 -0
- package/tx/importers/tx-import-settings.js +310 -0
- package/tx/importers/tx-import.js +357 -0
- package/tx/library/canonical-resource.js +88 -0
- package/tx/library/capabilitystatement.js +292 -0
- package/tx/library/codesystem.js +774 -0
- package/tx/library/conceptmap.js +568 -0
- package/tx/library/designations.js +932 -0
- package/tx/library/errors.js +77 -0
- package/tx/library/extensions.js +117 -0
- package/tx/library/namingsystem.js +322 -0
- package/tx/library/operation-outcome.js +127 -0
- package/tx/library/parameters.js +105 -0
- package/tx/library/renderer.js +1559 -0
- package/tx/library/terminologycapabilities.js +418 -0
- package/tx/library/ucum-parsers.js +1029 -0
- package/tx/library/ucum-service.js +370 -0
- package/tx/library/ucum-types.js +1099 -0
- package/tx/library/valueset.js +543 -0
- package/tx/library.js +676 -0
- package/tx/ocl/cm-ocl.js +106 -0
- package/tx/ocl/cs-ocl.js +39 -0
- package/tx/ocl/vs-ocl.js +105 -0
- package/tx/operation-context.js +568 -0
- package/tx/params.js +613 -0
- package/tx/provider.js +403 -0
- package/tx/sct/ecl.js +1560 -0
- package/tx/sct/expressions.js +2077 -0
- package/tx/sct/structures.js +1396 -0
- package/tx/tx-html.js +1063 -0
- package/tx/tx.fhir.org.yml +39 -0
- package/tx/tx.js +927 -0
- package/tx/vs/vs-api.js +112 -0
- package/tx/vs/vs-database.js +786 -0
- package/tx/vs/vs-package.js +358 -0
- package/tx/vs/vs-vsac.js +366 -0
- package/tx/workers/batch-validate.js +129 -0
- package/tx/workers/batch.js +361 -0
- package/tx/workers/closure.js +32 -0
- package/tx/workers/expand.js +1845 -0
- package/tx/workers/lookup.js +407 -0
- package/tx/workers/metadata.js +467 -0
- package/tx/workers/operations.js +34 -0
- package/tx/workers/read.js +164 -0
- package/tx/workers/search.js +384 -0
- package/tx/workers/subsumes.js +334 -0
- package/tx/workers/translate.js +492 -0
- package/tx/workers/validate.js +2504 -0
- package/tx/workers/worker.js +904 -0
- package/tx/xml/capabilitystatement-xml.js +63 -0
- package/tx/xml/codesystem-xml.js +62 -0
- package/tx/xml/conceptmap-xml.js +65 -0
- package/tx/xml/namingsystem-xml.js +65 -0
- package/tx/xml/operationoutcome-xml.js +127 -0
- package/tx/xml/parameters-xml.js +312 -0
- package/tx/xml/terminologycapabilities-xml.js +64 -0
- package/tx/xml/valueset-xml.js +64 -0
- package/tx/xml/xml-base.js +603 -0
- package/vcl/vcl-parser.js +1098 -0
- package/vcl/vcl.js +253 -0
- package/windows-install.js +19 -0
- package/xig/xig-template.html +124 -0
- package/xig/xig.js +3049 -0
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Terminology Errors
|
|
3
|
+
*
|
|
4
|
+
* Custom error classes for terminology operations
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Error thrown when an operation exceeds time or resource limits
|
|
9
|
+
*/
|
|
10
|
+
class TooCostlyError extends Error {
|
|
11
|
+
/**
|
|
12
|
+
* @param {string} message - Error message
|
|
13
|
+
* @param {string} diagnostics - Additional diagnostic information
|
|
14
|
+
*/
|
|
15
|
+
constructor(message, diagnostics = '') {
|
|
16
|
+
super(message);
|
|
17
|
+
this.name = 'TooCostlyError';
|
|
18
|
+
this.diagnostics = diagnostics;
|
|
19
|
+
this.statusCode = 422; // Unprocessable Entity
|
|
20
|
+
this.issueCode = 'too-costly';
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Error thrown for terminology operation failures
|
|
26
|
+
*/
|
|
27
|
+
class TerminologyError extends Error {
|
|
28
|
+
/**
|
|
29
|
+
* @param {string} message - Error message
|
|
30
|
+
* @param {string} issueCode - FHIR issue code (default: 'processing')
|
|
31
|
+
* @param {number} statusCode - HTTP status code (default: 422)
|
|
32
|
+
*/
|
|
33
|
+
constructor(message, issueCode = 'processing', statusCode = 422) {
|
|
34
|
+
super(message);
|
|
35
|
+
this.name = 'TerminologyError';
|
|
36
|
+
this.issueCode = issueCode;
|
|
37
|
+
this.statusCode = statusCode;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Error thrown when a required resource is not found
|
|
43
|
+
*/
|
|
44
|
+
class NotFoundError extends TerminologyError {
|
|
45
|
+
constructor(message) {
|
|
46
|
+
super(message, 'not-found', 404);
|
|
47
|
+
this.name = 'NotFoundError';
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Error thrown for invalid input
|
|
53
|
+
*/
|
|
54
|
+
class InvalidError extends TerminologyError {
|
|
55
|
+
constructor(message) {
|
|
56
|
+
super(message, 'invalid', 400);
|
|
57
|
+
this.name = 'InvalidError';
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Error thrown when an operation is not supported
|
|
63
|
+
*/
|
|
64
|
+
class NotSupportedError extends TerminologyError {
|
|
65
|
+
constructor(message) {
|
|
66
|
+
super(message, 'not-supported', 400);
|
|
67
|
+
this.name = 'NotSupportedError';
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
module.exports = {
|
|
72
|
+
TooCostlyError,
|
|
73
|
+
TerminologyError,
|
|
74
|
+
NotFoundError,
|
|
75
|
+
InvalidError,
|
|
76
|
+
NotSupportedError
|
|
77
|
+
};
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
const {getValuePrimitive} = require("../../library/utilities");
|
|
2
|
+
const {Issue} = require("./operation-outcome");
|
|
3
|
+
|
|
4
|
+
const Extensions = {
|
|
5
|
+
|
|
6
|
+
list(object, url) {
|
|
7
|
+
if (object.extension) {
|
|
8
|
+
let res = [];
|
|
9
|
+
for (let extension of object.extension) {
|
|
10
|
+
if (extension.url === url) {
|
|
11
|
+
res.push(extension);
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
return res;
|
|
15
|
+
} else {
|
|
16
|
+
return [];
|
|
17
|
+
}
|
|
18
|
+
},
|
|
19
|
+
|
|
20
|
+
checkNoImplicitRules(resource, place, name) {
|
|
21
|
+
if (!resource) {
|
|
22
|
+
return;
|
|
23
|
+
}
|
|
24
|
+
if (resource.jsonObj) {
|
|
25
|
+
resource = resource.jsonObj
|
|
26
|
+
}
|
|
27
|
+
if (resource.implicitRules) {
|
|
28
|
+
throw new Issue("error", "business-rule", null, null, 'Cannot process resource "'+name+'" due to the presence of implicit rules @'+place);
|
|
29
|
+
}
|
|
30
|
+
},
|
|
31
|
+
|
|
32
|
+
checkNoModifiers(element, place, name) {
|
|
33
|
+
if (!element) {
|
|
34
|
+
return;
|
|
35
|
+
}
|
|
36
|
+
if (element.jsonObj) {
|
|
37
|
+
element = element.jsonObj
|
|
38
|
+
}
|
|
39
|
+
if (element.modifierExtension) {
|
|
40
|
+
let urls = new Set();
|
|
41
|
+
for (const extension of element.modifierExtension) {
|
|
42
|
+
urls.add(extension.url);
|
|
43
|
+
}
|
|
44
|
+
const urlList = [...urls].join('\', \'');
|
|
45
|
+
if (urls.size > 1) {
|
|
46
|
+
throw new Issue("error", "business-rule", null, null, 'Cannot process resource at "' + name + '" due to the presence of modifier extensions '+urlList);
|
|
47
|
+
} else {
|
|
48
|
+
throw new Issue("error", "business-rule", null, null, 'Cannot process resource at "' + name + '" due to the presence of the modifier extension '+urlList);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
return true;
|
|
52
|
+
},
|
|
53
|
+
|
|
54
|
+
readString(resource, url) {
|
|
55
|
+
if (!resource) {
|
|
56
|
+
return undefined;
|
|
57
|
+
}
|
|
58
|
+
const extensions = Array.isArray(resource) ? resource : (resource.extension || []);
|
|
59
|
+
for (let ext of extensions || []) {
|
|
60
|
+
if (ext.url === url) {
|
|
61
|
+
return getValuePrimitive(ext);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
return null;
|
|
65
|
+
},
|
|
66
|
+
|
|
67
|
+
readNumber(resource, url, defaultValue) {
|
|
68
|
+
if (!resource) {
|
|
69
|
+
return defaultValue;
|
|
70
|
+
}
|
|
71
|
+
const extensions = Array.isArray(resource) ? resource : (resource.extension || []);
|
|
72
|
+
for (let ext of extensions) {
|
|
73
|
+
if (ext.url === url) {
|
|
74
|
+
const value = getValuePrimitive(ext);
|
|
75
|
+
if (typeof value === 'number') {
|
|
76
|
+
return value;
|
|
77
|
+
}
|
|
78
|
+
if (typeof value === 'string') {
|
|
79
|
+
const num = parseFloat(value);
|
|
80
|
+
return isNaN(num) ? defaultValue : num;
|
|
81
|
+
}
|
|
82
|
+
return defaultValue;
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
return defaultValue;
|
|
86
|
+
},
|
|
87
|
+
|
|
88
|
+
readValue(resource, url) {
|
|
89
|
+
if (!resource) {
|
|
90
|
+
return undefined;
|
|
91
|
+
}
|
|
92
|
+
const extensions = Array.isArray(resource) ? resource : (resource.extension || []);
|
|
93
|
+
for (let ext of extensions || []) {
|
|
94
|
+
if (ext.url === url) {
|
|
95
|
+
return ext;
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
return null;
|
|
99
|
+
},
|
|
100
|
+
|
|
101
|
+
has(object, url) {
|
|
102
|
+
if (!object) {
|
|
103
|
+
return undefined;
|
|
104
|
+
}
|
|
105
|
+
const extensions = Array.isArray(object) ? object : (object.extension || []);
|
|
106
|
+
return extensions.find(ex => ex.url === url);
|
|
107
|
+
},
|
|
108
|
+
|
|
109
|
+
addBoolean(exp, url, b) {
|
|
110
|
+
if (!exp.extension) {
|
|
111
|
+
exp.extension = [];
|
|
112
|
+
}
|
|
113
|
+
exp.extension.push({ url : url, valueBoolean : b });
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
module.exports = { Extensions };
|
|
@@ -0,0 +1,322 @@
|
|
|
1
|
+
const {VersionUtilities} = require("../../library/version-utilities");
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Represents a FHIR NamingSystem resource with version conversion support
|
|
5
|
+
* @class
|
|
6
|
+
*/
|
|
7
|
+
class NamingSystem {
|
|
8
|
+
/**
|
|
9
|
+
* The original JSON object (always stored in R5 format internally)
|
|
10
|
+
* @type {Object}
|
|
11
|
+
*/
|
|
12
|
+
jsonObj = null;
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* FHIR version of the loaded NamingSystem
|
|
16
|
+
* @type {string}
|
|
17
|
+
*/
|
|
18
|
+
version = 'R5';
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Static factory method for convenience
|
|
22
|
+
* @param {string} jsonString - JSON string representation of NamingSystem
|
|
23
|
+
* @param {string} [version='R5'] - FHIR version ('R3', 'R4', or 'R5')
|
|
24
|
+
* @returns {NamingSystem} New NamingSystem instance
|
|
25
|
+
*/
|
|
26
|
+
static fromJSON(jsonString, version = 'R5') {
|
|
27
|
+
return new NamingSystem(JSON.parse(jsonString), version);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Creates a new NamingSystem instance
|
|
32
|
+
* @param {Object} jsonObj - The JSON object containing NamingSystem data
|
|
33
|
+
* @param {string} [version='R5'] - FHIR version ('R3', 'R4', or 'R5')
|
|
34
|
+
* @param {string} jsonObj.resourceType - Must be "NamingSystem"
|
|
35
|
+
* @param {string} jsonObj.name - Name for this naming system
|
|
36
|
+
* @param {string} jsonObj.status - Publication status (draft|active|retired|unknown)
|
|
37
|
+
* @param {string} jsonObj.kind - Identifies the purpose of the naming system
|
|
38
|
+
* @param {Object[]} jsonObj.uniqueId - Unique identifiers used for system
|
|
39
|
+
*/
|
|
40
|
+
constructor(jsonObj, version = 'R5') {
|
|
41
|
+
this.version = version;
|
|
42
|
+
// Convert to R5 format internally (modifies input for performance)
|
|
43
|
+
this.jsonObj = this._convertToR5(jsonObj, version);
|
|
44
|
+
this.validate();
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Returns JSON string representation
|
|
49
|
+
* @param {string} [version='R5'] - Target FHIR version ('R3', 'R4', or 'R5')
|
|
50
|
+
* @returns {string} JSON string
|
|
51
|
+
*/
|
|
52
|
+
toJSONString(version = 'R5') {
|
|
53
|
+
const outputObj = this._convertFromR5(this.jsonObj, version);
|
|
54
|
+
return JSON.stringify(outputObj);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Converts input NamingSystem to R5 format (modifies input object for performance)
|
|
59
|
+
* @param {Object} jsonObj - The input NamingSystem object
|
|
60
|
+
* @param {string} version - Source FHIR version
|
|
61
|
+
* @returns {Object} The same object, potentially modified to R5 format
|
|
62
|
+
* @private
|
|
63
|
+
*/
|
|
64
|
+
_convertToR5(jsonObj, version) {
|
|
65
|
+
if (version === 'R5') {
|
|
66
|
+
return jsonObj; // Already R5, no conversion needed
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
if (version === 'R3') {
|
|
70
|
+
// R3 to R5: Remove replacedBy field (we ignore it completely)
|
|
71
|
+
if (jsonObj.replacedBy !== undefined) {
|
|
72
|
+
delete jsonObj.replacedBy;
|
|
73
|
+
}
|
|
74
|
+
return jsonObj;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
if (version === 'R4') {
|
|
78
|
+
// R4 to R5: No structural conversion needed
|
|
79
|
+
// R5 is backward compatible for the structural elements we care about
|
|
80
|
+
return jsonObj;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
throw new Error(`Unsupported FHIR version: ${version}`);
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* Converts R5 NamingSystem to target version format (clones object first)
|
|
88
|
+
* @param {Object} r5Obj - The R5 format NamingSystem object
|
|
89
|
+
* @param {string} targetVersion - Target FHIR version
|
|
90
|
+
* @returns {Object} New object in target version format
|
|
91
|
+
* @private
|
|
92
|
+
*/
|
|
93
|
+
_convertFromR5(r5Obj, targetVersion) {
|
|
94
|
+
if (VersionUtilities.isR5Ver(targetVersion)) {
|
|
95
|
+
return r5Obj; // No conversion needed
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
// Clone the object to avoid modifying the original
|
|
99
|
+
const cloned = JSON.parse(JSON.stringify(r5Obj));
|
|
100
|
+
|
|
101
|
+
if (VersionUtilities.isR4Ver(targetVersion)) {
|
|
102
|
+
return this._convertR5ToR4(cloned);
|
|
103
|
+
} else if (VersionUtilities.isR3Ver(targetVersion)) {
|
|
104
|
+
return this._convertR5ToR3(cloned);
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
throw new Error(`Unsupported target FHIR version: ${targetVersion}`);
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
/**
|
|
111
|
+
* Converts R5 NamingSystem to R4 format
|
|
112
|
+
* @param {Object} r5Obj - Cloned R5 NamingSystem object
|
|
113
|
+
* @returns {Object} R4 format NamingSystem
|
|
114
|
+
* @private
|
|
115
|
+
*/
|
|
116
|
+
_convertR5ToR4(r5Obj) {
|
|
117
|
+
// Remove R5-specific elements that don't exist in R4
|
|
118
|
+
if (r5Obj.versionAlgorithmString) {
|
|
119
|
+
delete r5Obj.versionAlgorithmString;
|
|
120
|
+
}
|
|
121
|
+
if (r5Obj.versionAlgorithmCoding) {
|
|
122
|
+
delete r5Obj.versionAlgorithmCoding;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
return r5Obj;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
/**
|
|
129
|
+
* Converts R5 NamingSystem to R3 format
|
|
130
|
+
* @param {Object} r5Obj - Cloned R5 NamingSystem object
|
|
131
|
+
* @returns {Object} R3 format NamingSystem
|
|
132
|
+
* @private
|
|
133
|
+
*/
|
|
134
|
+
_convertR5ToR3(r5Obj) {
|
|
135
|
+
// First apply R4 conversions
|
|
136
|
+
const r4Obj = this._convertR5ToR4(r5Obj);
|
|
137
|
+
|
|
138
|
+
// R3 doesn't have some R4/R5 fields, but we'll just let them through
|
|
139
|
+
// since most additions are backward compatible in JSON
|
|
140
|
+
|
|
141
|
+
return r4Obj;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
/**
|
|
145
|
+
* Gets the FHIR version this NamingSystem was loaded from
|
|
146
|
+
* @returns {string} FHIR version ('R3', 'R4', or 'R5')
|
|
147
|
+
*/
|
|
148
|
+
getFHIRVersion() {
|
|
149
|
+
return this.version;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
/**
|
|
153
|
+
* Validates that this is a proper NamingSystem resource
|
|
154
|
+
* @throws {Error} If validation fails
|
|
155
|
+
*/
|
|
156
|
+
validate() {
|
|
157
|
+
if (!this.jsonObj || typeof this.jsonObj !== 'object') {
|
|
158
|
+
throw new Error('Invalid NamingSystem: expected object');
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
if (this.jsonObj.resourceType !== 'NamingSystem') {
|
|
162
|
+
throw new Error(`Invalid NamingSystem: resourceType must be "NamingSystem", got "${this.jsonObj.resourceType}"`);
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
if (!this.jsonObj.name || typeof this.jsonObj.name !== 'string') {
|
|
166
|
+
throw new Error('Invalid NamingSystem: name is required and must be a string');
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
if (!this.jsonObj.status || typeof this.jsonObj.status !== 'string') {
|
|
170
|
+
throw new Error('Invalid NamingSystem: status is required and must be a string');
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
const validStatuses = ['draft', 'active', 'retired', 'unknown'];
|
|
174
|
+
if (!validStatuses.includes(this.jsonObj.status)) {
|
|
175
|
+
throw new Error(`Invalid NamingSystem: status must be one of ${validStatuses.join(', ')}, got "${this.jsonObj.status}"`);
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
if (!this.jsonObj.kind || typeof this.jsonObj.kind !== 'string') {
|
|
179
|
+
throw new Error('Invalid NamingSystem: kind is required and must be a string');
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
const validKinds = ['codesystem', 'identifier', 'root'];
|
|
183
|
+
if (!validKinds.includes(this.jsonObj.kind)) {
|
|
184
|
+
throw new Error(`Invalid NamingSystem: kind must be one of ${validKinds.join(', ')}, got "${this.jsonObj.kind}"`);
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
if (!this.jsonObj.uniqueId || !Array.isArray(this.jsonObj.uniqueId)) {
|
|
188
|
+
throw new Error('Invalid NamingSystem: uniqueId is required and must be an array');
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
if (this.jsonObj.uniqueId.length === 0) {
|
|
192
|
+
throw new Error('Invalid NamingSystem: uniqueId array cannot be empty');
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
// Validate individual uniqueId entries
|
|
196
|
+
this.jsonObj.uniqueId.forEach((uid, index) => {
|
|
197
|
+
if (!uid.type || typeof uid.type !== 'string') {
|
|
198
|
+
throw new Error(`Invalid NamingSystem: uniqueId[${index}].type is required and must be a string`);
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
const validTypes = ['oid', 'uuid', 'uri', 'other'];
|
|
202
|
+
if (!validTypes.includes(uid.type)) {
|
|
203
|
+
throw new Error(`Invalid NamingSystem: uniqueId[${index}].type must be one of ${validTypes.join(', ')}, got "${uid.type}"`);
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
if (!uid.value || typeof uid.value !== 'string') {
|
|
207
|
+
throw new Error(`Invalid NamingSystem: uniqueId[${index}].value is required and must be a string`);
|
|
208
|
+
}
|
|
209
|
+
});
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
/**
|
|
213
|
+
* Gets unique identifiers of a specific type
|
|
214
|
+
* @param {string} type - Type of identifier ('oid', 'uuid', 'uri', 'other')
|
|
215
|
+
* @returns {Object[]} Array of uniqueId objects of the specified type
|
|
216
|
+
*/
|
|
217
|
+
getUniqueIdsByType(type) {
|
|
218
|
+
return this.jsonObj.uniqueId.filter(uid => uid.type === type);
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
/**
|
|
222
|
+
* Gets all unique identifier values of a specific type
|
|
223
|
+
* @param {string} type - Type of identifier ('oid', 'uuid', 'uri', 'other')
|
|
224
|
+
* @returns {string[]} Array of identifier values
|
|
225
|
+
*/
|
|
226
|
+
getUniqueIdValues(type) {
|
|
227
|
+
return this.getUniqueIdsByType(type).map(uid => uid.value);
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
/**
|
|
231
|
+
* Checks if the naming system has a unique identifier of a specific type and value
|
|
232
|
+
* @param {string} type - Type of identifier ('oid', 'uuid', 'uri', 'other')
|
|
233
|
+
* @param {string} value - Identifier value to check
|
|
234
|
+
* @returns {boolean} True if the identifier exists
|
|
235
|
+
*/
|
|
236
|
+
hasUniqueId(type, value) {
|
|
237
|
+
return this.jsonObj.uniqueId.some(uid => uid.type === type && uid.value === value);
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
/**
|
|
241
|
+
* Gets the preferred unique identifier (marked as preferred=true)
|
|
242
|
+
* @returns {Object|undefined} Preferred uniqueId object or undefined if none marked as preferred
|
|
243
|
+
*/
|
|
244
|
+
getPreferredUniqueId() {
|
|
245
|
+
return this.jsonObj.uniqueId.find(uid => uid.preferred === true);
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
/**
|
|
249
|
+
* Gets all unique identifiers, optionally filtered by preferred status
|
|
250
|
+
* @param {boolean} [preferredOnly=false] - If true, return only preferred identifiers
|
|
251
|
+
* @returns {Object[]} Array of uniqueId objects
|
|
252
|
+
*/
|
|
253
|
+
getAllUniqueIds(preferredOnly = false) {
|
|
254
|
+
if (preferredOnly) {
|
|
255
|
+
return this.jsonObj.uniqueId.filter(uid => uid.preferred === true);
|
|
256
|
+
}
|
|
257
|
+
return [...this.jsonObj.uniqueId];
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
/**
|
|
261
|
+
* Gets the naming system kind
|
|
262
|
+
* @returns {string} The kind ('codesystem', 'identifier', 'root')
|
|
263
|
+
*/
|
|
264
|
+
getKind() {
|
|
265
|
+
return this.jsonObj.kind;
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
/**
|
|
269
|
+
* Checks if this is a code system naming system
|
|
270
|
+
* @returns {boolean} True if kind is 'codesystem'
|
|
271
|
+
*/
|
|
272
|
+
isCodeSystem() {
|
|
273
|
+
return this.jsonObj.kind === 'codesystem';
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
/**
|
|
277
|
+
* Checks if this is an identifier naming system
|
|
278
|
+
* @returns {boolean} True if kind is 'identifier'
|
|
279
|
+
*/
|
|
280
|
+
isIdentifier() {
|
|
281
|
+
return this.jsonObj.kind === 'identifier';
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
/**
|
|
285
|
+
* Checks if this is a root naming system
|
|
286
|
+
* @returns {boolean} True if kind is 'root'
|
|
287
|
+
*/
|
|
288
|
+
isRoot() {
|
|
289
|
+
return this.jsonObj.kind === 'root';
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
/**
|
|
293
|
+
* Gets usage information if available
|
|
294
|
+
* @returns {string|undefined} Usage information or undefined if not present
|
|
295
|
+
*/
|
|
296
|
+
getUsage() {
|
|
297
|
+
return this.jsonObj.usage;
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
/**
|
|
301
|
+
* Gets basic info about this naming system
|
|
302
|
+
* @returns {Object} Basic information object
|
|
303
|
+
*/
|
|
304
|
+
getInfo() {
|
|
305
|
+
const preferred = this.getPreferredUniqueId();
|
|
306
|
+
return {
|
|
307
|
+
resourceType: this.jsonObj.resourceType,
|
|
308
|
+
name: this.jsonObj.name,
|
|
309
|
+
title: this.jsonObj.title,
|
|
310
|
+
status: this.jsonObj.status,
|
|
311
|
+
kind: this.jsonObj.kind,
|
|
312
|
+
fhirVersion: this.version,
|
|
313
|
+
uniqueIdCount: this.jsonObj.uniqueId.length,
|
|
314
|
+
preferredId: preferred ? `${preferred.type}:${preferred.value}` : null,
|
|
315
|
+
types: [...new Set(this.jsonObj.uniqueId.map(uid => uid.type))],
|
|
316
|
+
usage: this.getUsage()
|
|
317
|
+
};
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
|
|
322
|
+
module.exports = { NamingSystem };
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
const {validateParameter} = require("../../library/utilities");
|
|
2
|
+
|
|
3
|
+
class Issue extends Error {
|
|
4
|
+
level;
|
|
5
|
+
cause;
|
|
6
|
+
path;
|
|
7
|
+
msgId;
|
|
8
|
+
issueCode;
|
|
9
|
+
statusCode;
|
|
10
|
+
isSetForhandleAsOO;
|
|
11
|
+
diagnostics;
|
|
12
|
+
issues = [];
|
|
13
|
+
|
|
14
|
+
constructor (level, cause, path, msgId, message, issueCode = null, statusCode = 500) {
|
|
15
|
+
super(message);
|
|
16
|
+
this.level = level;
|
|
17
|
+
this.cause = cause;
|
|
18
|
+
this.path = path;
|
|
19
|
+
this.message = message;
|
|
20
|
+
this.msgId = msgId;
|
|
21
|
+
this.issueCode = issueCode;
|
|
22
|
+
this.statusCode = statusCode;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
asIssue() {
|
|
26
|
+
let res = {
|
|
27
|
+
severity: this.level,
|
|
28
|
+
code: this.cause,
|
|
29
|
+
details: {
|
|
30
|
+
text: this.message
|
|
31
|
+
},
|
|
32
|
+
location: [ this.path ],
|
|
33
|
+
expression: [ this.path ]
|
|
34
|
+
}
|
|
35
|
+
if (this.issueCode) {
|
|
36
|
+
res.details.coding = [{ system: "http://hl7.org/fhir/tools/CodeSystem/tx-issue-type", code : this.issueCode }];
|
|
37
|
+
}
|
|
38
|
+
if (this.msgId) {
|
|
39
|
+
res.extension = [{ url: "http://hl7.org/fhir/StructureDefinition/operationoutcome-message-id", valueString: this.msgId }];
|
|
40
|
+
}
|
|
41
|
+
if (this.diagnostics) {
|
|
42
|
+
res.diagnostics = this.diagnostics;
|
|
43
|
+
}
|
|
44
|
+
return res;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
handleAsOO(statusCode) {
|
|
48
|
+
this.isSetForhandleAsOO = true;
|
|
49
|
+
this.statusCode = statusCode;
|
|
50
|
+
return this;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
isHandleAsOO() {
|
|
54
|
+
return this.isSetForhandleAsOO;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
setFinished() {
|
|
58
|
+
this.finished = true;
|
|
59
|
+
return this;
|
|
60
|
+
}
|
|
61
|
+
setUnknownSystem(s) {
|
|
62
|
+
this.unknownSystem = s;
|
|
63
|
+
return this;
|
|
64
|
+
}
|
|
65
|
+
addIssue(issue) {
|
|
66
|
+
if (issue) {
|
|
67
|
+
this.issues.push(issue);
|
|
68
|
+
}
|
|
69
|
+
return this;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
withDiagnostics(diagnostics) {
|
|
73
|
+
this.diagnostics = diagnostics;
|
|
74
|
+
return this;
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
class OperationOutcome {
|
|
79
|
+
jsonObj;
|
|
80
|
+
|
|
81
|
+
constructor (jsonObj = null) {
|
|
82
|
+
this.jsonObj = jsonObj ? jsonObj : { "resourceType": "OperationOutcome" };
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
addIssue(newIssue, ifNotDuplicate = false) {
|
|
86
|
+
validateParameter(newIssue, "newIssue", Object);
|
|
87
|
+
if (ifNotDuplicate) {
|
|
88
|
+
for (let iss of this.jsonObj.issue || []) {
|
|
89
|
+
if (iss.details.text === newIssue.message) {
|
|
90
|
+
return false;
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
if (!this.jsonObj.issue) {
|
|
95
|
+
this.jsonObj.issue = [];
|
|
96
|
+
}
|
|
97
|
+
this.jsonObj.issue.push(newIssue.asIssue());
|
|
98
|
+
for (let extra of newIssue.issues) {
|
|
99
|
+
this.addIssue(extra, false);
|
|
100
|
+
}
|
|
101
|
+
return true;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
hasIssues() {
|
|
105
|
+
return this.jsonObj && this.jsonObj.issue;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
hasErrors() {
|
|
109
|
+
for (let iss of this.jsonObj.issue || []) {
|
|
110
|
+
if (iss.severity === 'error') {
|
|
111
|
+
return true;
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
return false;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
listMissedErrors(list) {
|
|
118
|
+
for (let iss of this.jsonObj.issue || []) {
|
|
119
|
+
if (iss.severity === 'error' && iss.details && iss.details.text && !list.find(msg => msg === iss.details.text )) {
|
|
120
|
+
return list.push(iss.details.text);
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
module.exports = { OperationOutcome, Issue };
|