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
package/tx/cs/cs-ucum.js
ADDED
|
@@ -0,0 +1,514 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* UCUM CodeSystem Provider
|
|
3
|
+
* Implementation of CodeSystemProvider for UCUM (Unified Code for Units of Measure)
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
const { CodeSystemProvider, FilterExecutionContext, CodeSystemFactoryProvider} = require('./cs-api');
|
|
7
|
+
const { CodeSystem } = require("../library/codesystem");
|
|
8
|
+
const ValueSet = require("../library/valueset");
|
|
9
|
+
const assert = require('assert');
|
|
10
|
+
const {UcumService} = require("../library/ucum-service");
|
|
11
|
+
const {validateArrayParameter} = require("../../library/utilities");
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* UCUM provider context for concepts
|
|
15
|
+
*/
|
|
16
|
+
class UcumContext {
|
|
17
|
+
constructor(code) {
|
|
18
|
+
assert(typeof code === 'string', 'code must be string');
|
|
19
|
+
this.code = code;
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Filter context for UCUM canonical unit filters
|
|
25
|
+
*/
|
|
26
|
+
class UcumFilterContext {
|
|
27
|
+
constructor(canonical = '') {
|
|
28
|
+
this.canonical = canonical;
|
|
29
|
+
this.cursor = -1; // Used for iteration
|
|
30
|
+
this.filters = [];
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* UCUM CodeSystem Provider
|
|
36
|
+
* Provides validation and lookup for UCUM unit expressions
|
|
37
|
+
*/
|
|
38
|
+
class UcumCodeSystemProvider extends CodeSystemProvider {
|
|
39
|
+
constructor(opContext, supplements, ucumService, commonUnits = null) {
|
|
40
|
+
super(opContext, supplements);
|
|
41
|
+
assert(ucumService != null && ucumService instanceof UcumService, 'ucumService must be a UcumService');
|
|
42
|
+
assert(!commonUnits || commonUnits instanceof ValueSet, 'if provided, commonUnits must be a ValueSet');
|
|
43
|
+
|
|
44
|
+
this.ucumService = ucumService;
|
|
45
|
+
this.commonUnits = commonUnits; // ValueSet for common units
|
|
46
|
+
this.commonUnitList = null;
|
|
47
|
+
|
|
48
|
+
this._setupCommonUnits();
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
_setupCommonUnits() {
|
|
52
|
+
if (this.commonUnits) {
|
|
53
|
+
// Extract concept list from common units ValueSet
|
|
54
|
+
// This would depend on your ValueSet implementation
|
|
55
|
+
// For now, assuming it has a getConcepts() method
|
|
56
|
+
// if (typeof this.commonUnits.getConcepts === 'function') {
|
|
57
|
+
// this.commonUnitList = this.commonUnits.getConcepts();
|
|
58
|
+
// }
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
// ========== Metadata Methods ==========
|
|
63
|
+
|
|
64
|
+
system() {
|
|
65
|
+
return 'http://unitsofmeasure.org'; // UCUM URI
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
version() {
|
|
69
|
+
return this.ucumService.ucumIdentification().version;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
description() {
|
|
73
|
+
return 'Unified Code for Units of Measure (UCUM)';
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
name() {
|
|
77
|
+
return 'UCUM';
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
totalCount() {
|
|
81
|
+
return -1; // Unbounded due to grammar
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
hasParents() {
|
|
85
|
+
return false; // No hierarchy in UCUM
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
contentMode() {
|
|
89
|
+
return 'complete';
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
expandLimitation() {
|
|
93
|
+
return 0; // No limitation
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
specialEnumeration() {
|
|
97
|
+
// Return URL of common units if available
|
|
98
|
+
return this.commonUnits ? this.commonUnits.url || null : null;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
hasAnyDisplays(languages) {
|
|
102
|
+
const langs = this._ensureLanguages(languages);
|
|
103
|
+
if (this._hasAnySupplementDisplays(langs)) {
|
|
104
|
+
return true;
|
|
105
|
+
}
|
|
106
|
+
return langs.isEnglishOrNothing();
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
listFeatures() {
|
|
110
|
+
return [
|
|
111
|
+
{
|
|
112
|
+
feature: `rest.Codesystem:${this.system()}.filter`,
|
|
113
|
+
value: 'canonical:equals'
|
|
114
|
+
}
|
|
115
|
+
];
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
// ========== Code Information Methods ==========
|
|
119
|
+
|
|
120
|
+
async code(code) {
|
|
121
|
+
|
|
122
|
+
const ctxt = await this.#ensureContext(code);
|
|
123
|
+
return ctxt.code;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
async display(code) {
|
|
127
|
+
|
|
128
|
+
const ctxt = await this.#ensureContext(code);
|
|
129
|
+
|
|
130
|
+
if (this.opContext.langs.isEnglishOrNothing()) {
|
|
131
|
+
// Check for common units display first
|
|
132
|
+
if (this.commonUnitList) {
|
|
133
|
+
for (const concept of this.commonUnitList) {
|
|
134
|
+
if (concept.code === ctxt.code && concept.display) {
|
|
135
|
+
return concept.display.trim();
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
// Check supplements
|
|
141
|
+
const supplementDisplay = this._displayFromSupplements(ctxt.code);
|
|
142
|
+
if (supplementDisplay) {
|
|
143
|
+
return supplementDisplay;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
// Default to analysis
|
|
147
|
+
return this.ucumService.analyse(ctxt.code);
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
// Non-English languages - check supplements first
|
|
151
|
+
const supplementDisplay = this._displayFromSupplements(ctxt.code);
|
|
152
|
+
if (supplementDisplay) {
|
|
153
|
+
return supplementDisplay;
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
// Fall back to analysis
|
|
157
|
+
return this.ucumService.analyse(ctxt.code);
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
async definition(code) {
|
|
161
|
+
|
|
162
|
+
await this.#ensureContext(code);
|
|
163
|
+
return null; // UCUM doesn't provide definitions
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
async isAbstract(code) {
|
|
167
|
+
|
|
168
|
+
await this.#ensureContext(code);
|
|
169
|
+
return false; // UCUM codes are not abstract
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
async isInactive(code) {
|
|
173
|
+
|
|
174
|
+
await this.#ensureContext(code);
|
|
175
|
+
return false; // We don't track inactive UCUM codes
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
async isDeprecated(code) {
|
|
179
|
+
|
|
180
|
+
await this.#ensureContext(code);
|
|
181
|
+
return false; // We don't track deprecated UCUM codes
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
async designations(code, displays) {
|
|
185
|
+
|
|
186
|
+
const ctxt = await this.#ensureContext(code);
|
|
187
|
+
|
|
188
|
+
// Primary display (analysis)
|
|
189
|
+
const analysis = this.ucumService.analyse(ctxt.code);
|
|
190
|
+
displays.addDesignation(true, 'active', 'en', CodeSystem.makeUseForDisplay(), analysis);
|
|
191
|
+
|
|
192
|
+
// Common unit display if available
|
|
193
|
+
if (this.commonUnitList) {
|
|
194
|
+
for (const concept of this.commonUnitList) {
|
|
195
|
+
if (concept.code === ctxt.code && concept.display) {
|
|
196
|
+
const display = concept.display.trim();
|
|
197
|
+
if (display !== analysis) {
|
|
198
|
+
displays.addDesignation(false, 'active', 'en', CodeSystem.makeUseForDisplay(), display);
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
// Add supplement designations
|
|
205
|
+
this._listSupplementDesignations(ctxt.code, displays);
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
async #ensureContext(code) {
|
|
209
|
+
if (!code) {
|
|
210
|
+
return code;
|
|
211
|
+
}
|
|
212
|
+
if (typeof code === 'string') {
|
|
213
|
+
const result = await this.locate(code);
|
|
214
|
+
if (!result.context) {
|
|
215
|
+
throw new Error(result.message);
|
|
216
|
+
} else {
|
|
217
|
+
return result.context;
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
if (code instanceof UcumContext) {
|
|
221
|
+
return code;
|
|
222
|
+
}
|
|
223
|
+
throw new Error("Unknown Type at #ensureContext: " + (typeof code));
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
// ========== Lookup Methods ==========
|
|
227
|
+
|
|
228
|
+
async locate(code) {
|
|
229
|
+
|
|
230
|
+
assert(!code || typeof code === 'string', 'code must be string');
|
|
231
|
+
|
|
232
|
+
if (!code) {
|
|
233
|
+
return { context: null, message: 'Empty code' };
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
const validationResult = this.ucumService.validate(code);
|
|
237
|
+
if (!validationResult) {
|
|
238
|
+
return { context: new UcumContext(code), message: null };
|
|
239
|
+
} else {
|
|
240
|
+
return { context: null, message: validationResult };
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
// ========== Filter Methods ==========
|
|
245
|
+
|
|
246
|
+
async doesFilter(prop, op, value) {
|
|
247
|
+
|
|
248
|
+
assert(prop != null && typeof prop === 'string', 'prop must be a non-null string');
|
|
249
|
+
assert(op != null && typeof op === 'string', 'op must be a non-null string');
|
|
250
|
+
assert(value != null && typeof value === 'string', 'value must be a non-null string');
|
|
251
|
+
|
|
252
|
+
// Support canonical unit filters
|
|
253
|
+
return (prop === 'canonical' && op === 'equals');
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
async searchFilter(filterContext, filter, sort) {
|
|
257
|
+
|
|
258
|
+
assert(filterContext && filterContext instanceof FilterExecutionContext, 'filterContext must be a FilterExecutionContext');
|
|
259
|
+
assert(filter && typeof filter === 'string', 'filter must be a non-null string');
|
|
260
|
+
assert(typeof sort === 'boolean', 'sort must be a boolean');
|
|
261
|
+
|
|
262
|
+
throw new Error('Search filter not implemented for UCUM');
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
async specialFilter(filterContext, filter, sort) {
|
|
266
|
+
|
|
267
|
+
assert(filterContext && filterContext instanceof FilterExecutionContext, 'filterContext must be a FilterExecutionContext');
|
|
268
|
+
assert(filter && typeof filter === 'string', 'filter must be a non-null string');
|
|
269
|
+
assert(typeof sort === 'boolean', 'sort must be a boolean');
|
|
270
|
+
|
|
271
|
+
throw new Error('Special filter not presently implemented for UCUM');
|
|
272
|
+
// const ucumFilter = new UcumFilterContext('');
|
|
273
|
+
// filterContext.filters.push(ucumFilter);
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
async filter(filterContext, prop, op, value) {
|
|
277
|
+
|
|
278
|
+
assert(filterContext && filterContext instanceof FilterExecutionContext, 'filterContext must be a FilterExecutionContext');
|
|
279
|
+
assert(prop != null && typeof prop === 'string', 'prop must be a non-null string');
|
|
280
|
+
assert(op != null && typeof op === 'string', 'op must be a non-null string');
|
|
281
|
+
assert(value != null && typeof value === 'string', 'value must be a non-null string');
|
|
282
|
+
|
|
283
|
+
if (prop !== 'canonical') {
|
|
284
|
+
throw new Error(`Unsupported filter property: ${prop}`);
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
if (op !== 'equals') {
|
|
288
|
+
throw new Error(`Unsupported filter operator for canonical: ${op}`);
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
const ucumFilter = new UcumFilterContext(value);
|
|
292
|
+
filterContext.filters.push(ucumFilter);
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
async executeFilters(filterContext) {
|
|
296
|
+
|
|
297
|
+
assert(filterContext && filterContext instanceof FilterExecutionContext, 'filterContext must be a FilterExecutionContext');
|
|
298
|
+
return filterContext.filters;
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
async filterSize(filterContext, set) {
|
|
302
|
+
|
|
303
|
+
assert(filterContext && filterContext instanceof FilterExecutionContext, 'filterContext must be a FilterExecutionContext');
|
|
304
|
+
assert(set && set instanceof UcumFilterContext, 'set must be a UcumFilterContext');
|
|
305
|
+
|
|
306
|
+
if (!set.canonical && this.commonUnitList) {
|
|
307
|
+
return this.commonUnitList.length;
|
|
308
|
+
}
|
|
309
|
+
throw new Error('UCUM filter sets cannot be sized as they are based on a grammar');
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
async filtersNotClosed(filterContext) {
|
|
313
|
+
|
|
314
|
+
assert(filterContext && filterContext instanceof FilterExecutionContext, 'filterContext must be a FilterExecutionContext');
|
|
315
|
+
return true; // Grammar-based system is not closed
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
async filterMore(filterContext, set) {
|
|
319
|
+
|
|
320
|
+
assert(filterContext && filterContext instanceof FilterExecutionContext, 'filterContext must be a FilterExecutionContext');
|
|
321
|
+
assert(set && set instanceof UcumFilterContext, 'set must be a UcumFilterContext');
|
|
322
|
+
|
|
323
|
+
if (!set.canonical && this.commonUnitList) {
|
|
324
|
+
// Iterating common units
|
|
325
|
+
set.cursor++;
|
|
326
|
+
return set.cursor < this.commonUnitList.length;
|
|
327
|
+
}
|
|
328
|
+
throw new Error('UCUM filter sets cannot be iterated as they are based on a grammar');
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
async filterConcept(filterContext, set) {
|
|
332
|
+
|
|
333
|
+
assert(filterContext && filterContext instanceof FilterExecutionContext, 'filterContext must be a FilterExecutionContext');
|
|
334
|
+
assert(set && set instanceof UcumFilterContext, 'set must be a UcumFilterContext');
|
|
335
|
+
|
|
336
|
+
if (!set.canonical && this.commonUnitList) {
|
|
337
|
+
// Return current common unit
|
|
338
|
+
const concept = this.commonUnitList[set.cursor];
|
|
339
|
+
return new UcumContext(concept.code);
|
|
340
|
+
}
|
|
341
|
+
throw new Error('UCUM filter sets cannot be iterated as they are based on a grammar');
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
async filterLocate(filterContext, set, code) {
|
|
345
|
+
|
|
346
|
+
assert(filterContext && filterContext instanceof FilterExecutionContext, 'filterContext must be a FilterExecutionContext');
|
|
347
|
+
assert(set && set instanceof UcumFilterContext, 'set must be a UcumFilterContext');
|
|
348
|
+
assert(typeof code === 'string', 'code must be non-null string');
|
|
349
|
+
|
|
350
|
+
// Validate the code first
|
|
351
|
+
const validationResult = this.ucumService.validate(code);
|
|
352
|
+
if (validationResult) {
|
|
353
|
+
return `Invalid UCUM code: ${validationResult}`;
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
if (!set.canonical) {
|
|
357
|
+
// Special enumeration case - check if in common units
|
|
358
|
+
if (this.commonUnitList) {
|
|
359
|
+
const found = this.commonUnitList.find(concept => concept.code === code);
|
|
360
|
+
if (found) {
|
|
361
|
+
return new UcumContext(code);
|
|
362
|
+
} else {
|
|
363
|
+
return `Code ${code} is not in the common units enumeration`;
|
|
364
|
+
}
|
|
365
|
+
}
|
|
366
|
+
return new UcumContext(code); // Valid code
|
|
367
|
+
} else {
|
|
368
|
+
// Check canonical units
|
|
369
|
+
try {
|
|
370
|
+
const canonical = this.ucumService.getCanonicalUnits(code);
|
|
371
|
+
if (canonical === set.canonical) {
|
|
372
|
+
return new UcumContext(code);
|
|
373
|
+
} else {
|
|
374
|
+
return `Code ${code} has canonical form ${canonical}, not ${set.canonical} as required`;
|
|
375
|
+
}
|
|
376
|
+
} catch (error) {
|
|
377
|
+
return `Error getting canonical form for ${code}: ${error.message}`;
|
|
378
|
+
}
|
|
379
|
+
}
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
async filterCheck(filterContext, set, concept) {
|
|
383
|
+
|
|
384
|
+
assert(filterContext && filterContext instanceof FilterExecutionContext, 'filterContext must be a FilterExecutionContext');
|
|
385
|
+
assert(set && set instanceof UcumFilterContext, 'set must be a UcumFilterContext');
|
|
386
|
+
|
|
387
|
+
const ctxt = await this.#ensureContext(concept);
|
|
388
|
+
|
|
389
|
+
if (!set.canonical) {
|
|
390
|
+
// Special enumeration case
|
|
391
|
+
if (this.commonUnitList) {
|
|
392
|
+
return this.commonUnitList.some(c => c.code === ctxt.code);
|
|
393
|
+
}
|
|
394
|
+
return true; // All valid codes are included
|
|
395
|
+
} else {
|
|
396
|
+
// Check canonical units
|
|
397
|
+
try {
|
|
398
|
+
const canonical = this.ucumService.getCanonicalUnits(ctxt.code);
|
|
399
|
+
return canonical === set.canonical;
|
|
400
|
+
} catch (error) {
|
|
401
|
+
return false;
|
|
402
|
+
}
|
|
403
|
+
}
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
|
|
407
|
+
// ========== Not Iterator Methods: Cannot iterate UCUM codes ==========
|
|
408
|
+
|
|
409
|
+
// ========== Additional Methods ==========
|
|
410
|
+
|
|
411
|
+
async sameConcept(a, b) {
|
|
412
|
+
|
|
413
|
+
const codeA = await this.#ensureContext(a);
|
|
414
|
+
const codeB = await this.#ensureContext(b);
|
|
415
|
+
return codeA === codeB;
|
|
416
|
+
}
|
|
417
|
+
|
|
418
|
+
async subsumesTest(codeA, codeB) {
|
|
419
|
+
|
|
420
|
+
await this.#ensureContext(codeA);
|
|
421
|
+
await this.#ensureContext(codeB);
|
|
422
|
+
return 'not-subsumed'; // No subsumption in UCUM
|
|
423
|
+
}
|
|
424
|
+
|
|
425
|
+
async extendLookup(ctxt, props, params) {
|
|
426
|
+
validateArrayParameter(props, 'props', String);
|
|
427
|
+
validateArrayParameter(params, 'params', Object);
|
|
428
|
+
|
|
429
|
+
|
|
430
|
+
if (props.includes('canonical')) {
|
|
431
|
+
try {
|
|
432
|
+
const canonical = this.ucumService.getCanonicalUnits(ctxt.code);
|
|
433
|
+
// Add canonical property to params - implementation depends on your Parameters class
|
|
434
|
+
if (params && typeof params.addProperty === 'function') {
|
|
435
|
+
params.addProperty('canonical', canonical);
|
|
436
|
+
}
|
|
437
|
+
} catch (error) {
|
|
438
|
+
// Ignore errors in canonical form calculation
|
|
439
|
+
}
|
|
440
|
+
}
|
|
441
|
+
}
|
|
442
|
+
|
|
443
|
+
versionAlgorithm() {
|
|
444
|
+
return 'natural';
|
|
445
|
+
}
|
|
446
|
+
|
|
447
|
+
|
|
448
|
+
isNotClosed() {
|
|
449
|
+
return true;
|
|
450
|
+
}
|
|
451
|
+
}
|
|
452
|
+
|
|
453
|
+
/**
|
|
454
|
+
* Factory for creating UCUM CodeSystem providers
|
|
455
|
+
*/
|
|
456
|
+
class UcumCodeSystemFactory extends CodeSystemFactoryProvider {
|
|
457
|
+
constructor(i18n, ucumService, commonUnits = null) {
|
|
458
|
+
super(i18n);
|
|
459
|
+
assert(ucumService != null && ucumService instanceof UcumService, 'ucumService must be a UcumService');
|
|
460
|
+
assert(!commonUnits || commonUnits instanceof ValueSet, 'if provided, commonUnits must be a ValueSet');
|
|
461
|
+
this.ucumService = ucumService;
|
|
462
|
+
this.commonUnits = commonUnits;
|
|
463
|
+
this.uses = 0;
|
|
464
|
+
}
|
|
465
|
+
|
|
466
|
+
system() {
|
|
467
|
+
return 'http://unitsofmeasure.org'; // UCUM URI
|
|
468
|
+
}
|
|
469
|
+
|
|
470
|
+
version() {
|
|
471
|
+
return this.ucumService.ucumIdentification().getVersion();
|
|
472
|
+
}
|
|
473
|
+
|
|
474
|
+
// eslint-disable-next-line no-unused-vars
|
|
475
|
+
async buildKnownValueSet(url, version) {
|
|
476
|
+
return null;
|
|
477
|
+
}
|
|
478
|
+
|
|
479
|
+
defaultVersion() {
|
|
480
|
+
if (this.ucumService && typeof this.ucumService.ucumIdentification === 'function') {
|
|
481
|
+
const versionDetails = this.ucumService.ucumIdentification();
|
|
482
|
+
return versionDetails ? versionDetails.getVersion() : '';
|
|
483
|
+
}
|
|
484
|
+
return '';
|
|
485
|
+
}
|
|
486
|
+
|
|
487
|
+
build(opContext, supplements) {
|
|
488
|
+
this.recordUse();
|
|
489
|
+
return new UcumCodeSystemProvider(opContext, supplements, this.ucumService, this.commonUnits);
|
|
490
|
+
}
|
|
491
|
+
|
|
492
|
+
useCount() {
|
|
493
|
+
return this.uses;
|
|
494
|
+
}
|
|
495
|
+
|
|
496
|
+
recordUse() {
|
|
497
|
+
this.uses++;
|
|
498
|
+
}
|
|
499
|
+
|
|
500
|
+
name() {
|
|
501
|
+
return 'UCUM';
|
|
502
|
+
}
|
|
503
|
+
|
|
504
|
+
id() {
|
|
505
|
+
return "ucum";
|
|
506
|
+
}
|
|
507
|
+
}
|
|
508
|
+
|
|
509
|
+
module.exports = {
|
|
510
|
+
UcumCodeSystemProvider,
|
|
511
|
+
UcumCodeSystemFactory,
|
|
512
|
+
UcumContext,
|
|
513
|
+
UcumFilterContext
|
|
514
|
+
};
|