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.
Files changed (277) hide show
  1. package/CHANGELOG.md +42 -0
  2. package/FHIRsmith.png +0 -0
  3. package/README.md +277 -0
  4. package/config-template.json +144 -0
  5. package/library/folder-setup.js +58 -0
  6. package/library/html-server.js +166 -0
  7. package/library/html.js +835 -0
  8. package/library/i18nsupport.js +259 -0
  9. package/library/languages.js +779 -0
  10. package/library/logger-telnet.js +205 -0
  11. package/library/logger.js +279 -0
  12. package/library/package-manager.js +876 -0
  13. package/library/utilities.js +196 -0
  14. package/library/version-utilities.js +1056 -0
  15. package/npmprojector/config-example.json +13 -0
  16. package/npmprojector/indexer.js +394 -0
  17. package/npmprojector/npmprojector.js +395 -0
  18. package/npmprojector/readme.md +174 -0
  19. package/npmprojector/watcher.js +335 -0
  20. package/package.json +119 -0
  21. package/packages/package-crawler.js +846 -0
  22. package/packages/packages-template.html +126 -0
  23. package/packages/packages.js +2838 -0
  24. package/passwords.ini +2 -0
  25. package/publisher/publisher-template.html +208 -0
  26. package/publisher/publisher.js +2167 -0
  27. package/publisher/task-draft.js +458 -0
  28. package/registry/api.js +735 -0
  29. package/registry/crawler.js +637 -0
  30. package/registry/model.js +513 -0
  31. package/registry/readme.md +243 -0
  32. package/registry/registry-data.json +121015 -0
  33. package/registry/registry-template.html +126 -0
  34. package/registry/registry.js +1395 -0
  35. package/registry/test-runner.js +237 -0
  36. package/root-template.html +124 -0
  37. package/server.js +524 -0
  38. package/shl/private-key.pem +5 -0
  39. package/shl/public-key.pem +18 -0
  40. package/shl/shl.js +1125 -0
  41. package/shl/vhl.js +69 -0
  42. package/static/FHIRsmith128.png +0 -0
  43. package/static/FHIRsmith16.png +0 -0
  44. package/static/FHIRsmith32.png +0 -0
  45. package/static/FHIRsmith64.png +0 -0
  46. package/static/assets/css/bootstrap-fhir.css +5302 -0
  47. package/static/assets/css/bootstrap-glyphicons.css +2 -0
  48. package/static/assets/css/bootstrap.css +4097 -0
  49. package/static/assets/css/jquery-ui.css +523 -0
  50. package/static/assets/css/jquery-ui.structure.css +863 -0
  51. package/static/assets/css/jquery-ui.structure.min.css +5 -0
  52. package/static/assets/css/jquery-ui.theme.css +439 -0
  53. package/static/assets/css/jquery-ui.theme.min.css +5 -0
  54. package/static/assets/css/jquery.ui.all.css +7 -0
  55. package/static/assets/css/modules.css +18 -0
  56. package/static/assets/css/project.css +367 -0
  57. package/static/assets/css/pygments-manni.css +66 -0
  58. package/static/assets/css/tags.css +74 -0
  59. package/static/assets/css/xml.css +2 -0
  60. package/static/assets/fonts/glyphiconshalflings-regular.eot +0 -0
  61. package/static/assets/fonts/glyphiconshalflings-regular.otf +0 -0
  62. package/static/assets/fonts/glyphiconshalflings-regular.svg +175 -0
  63. package/static/assets/fonts/glyphiconshalflings-regular.ttf +0 -0
  64. package/static/assets/fonts/glyphiconshalflings-regular.woff +0 -0
  65. package/static/assets/ico/apple-touch-icon-114-precomposed.png +0 -0
  66. package/static/assets/ico/apple-touch-icon-144-precomposed.png +0 -0
  67. package/static/assets/ico/apple-touch-icon-57-precomposed.png +0 -0
  68. package/static/assets/ico/apple-touch-icon-72-precomposed.png +0 -0
  69. package/static/assets/ico/favicon.ico +0 -0
  70. package/static/assets/ico/favicon.png +0 -0
  71. package/static/assets/images/fhir-logo-www.png +0 -0
  72. package/static/assets/images/fhir-logo.png +0 -0
  73. package/static/assets/images/hl7-logo.png +0 -0
  74. package/static/assets/images/logo_ansinew.jpg +0 -0
  75. package/static/assets/images/search.png +0 -0
  76. package/static/assets/images/stripe.png +0 -0
  77. package/static/assets/images/target.png +0 -0
  78. package/static/assets/images/tx-registry-root.gif +0 -0
  79. package/static/assets/images/tx-registry.png +0 -0
  80. package/static/assets/images/tx-server.png +0 -0
  81. package/static/assets/images/tx-version.png +0 -0
  82. package/static/assets/js/bootstrap.min.js +6 -0
  83. package/static/assets/js/fhir-gw.js +259 -0
  84. package/static/assets/js/fhir.js +2 -0
  85. package/static/assets/js/html5shiv.js +8 -0
  86. package/static/assets/js/jcookie.js +96 -0
  87. package/static/assets/js/jquery-ui.min.js +6 -0
  88. package/static/assets/js/jquery.js +10716 -0
  89. package/static/assets/js/jquery.min.js +2 -0
  90. package/static/assets/js/jquery.ui.core.js +314 -0
  91. package/static/assets/js/jquery.ui.draggable.js +825 -0
  92. package/static/assets/js/jquery.ui.mouse.js +162 -0
  93. package/static/assets/js/jquery.ui.resizable.js +842 -0
  94. package/static/assets/js/jquery.ui.widget.js +268 -0
  95. package/static/assets/js/json2.js +487 -0
  96. package/static/assets/js/jtip.js +97 -0
  97. package/static/assets/js/respond.min.js +6 -0
  98. package/static/assets/js/statuspage.js +70 -0
  99. package/static/assets/js/xml.js +2 -0
  100. package/static/dist/js/bootstrap.js +1964 -0
  101. package/static/favicon.png +0 -0
  102. package/static/fhir.css +626 -0
  103. package/static/icon-fhir-16.png +0 -0
  104. package/static/images/ui-bg_diagonals-thick_18_b81900_40x40.png +0 -0
  105. package/static/images/ui-bg_diagonals-thick_20_666666_40x40.png +0 -0
  106. package/static/images/ui-bg_flat_10_000000_40x100.png +0 -0
  107. package/static/images/ui-bg_glass_100_f6f6f6_1x400.png +0 -0
  108. package/static/images/ui-bg_glass_100_fdf5ce_1x400.png +0 -0
  109. package/static/images/ui-bg_glass_65_ffffff_1x400.png +0 -0
  110. package/static/images/ui-bg_gloss-wave_35_f6a828_500x100.png +0 -0
  111. package/static/images/ui-bg_highlight-soft_100_eeeeee_1x100.png +0 -0
  112. package/static/images/ui-bg_highlight-soft_75_ffe45c_1x100.png +0 -0
  113. package/static/images/ui-icons_222222_256x240.png +0 -0
  114. package/static/images/ui-icons_228ef1_256x240.png +0 -0
  115. package/static/images/ui-icons_ef8c08_256x240.png +0 -0
  116. package/static/images/ui-icons_ffd27a_256x240.png +0 -0
  117. package/static/images/ui-icons_ffffff_256x240.png +0 -0
  118. package/static/js/jquery.effects.blind.js +49 -0
  119. package/static/js/jquery.effects.bounce.js +78 -0
  120. package/static/js/jquery.effects.clip.js +54 -0
  121. package/static/js/jquery.effects.core.js +763 -0
  122. package/static/js/jquery.effects.drop.js +50 -0
  123. package/static/js/jquery.effects.explode.js +79 -0
  124. package/static/js/jquery.effects.fade.js +32 -0
  125. package/static/js/jquery.effects.fold.js +56 -0
  126. package/static/js/jquery.effects.highlight.js +50 -0
  127. package/static/js/jquery.effects.pulsate.js +51 -0
  128. package/static/js/jquery.effects.scale.js +178 -0
  129. package/static/js/jquery.effects.shake.js +57 -0
  130. package/static/js/jquery.effects.slide.js +50 -0
  131. package/static/js/jquery.effects.transfer.js +45 -0
  132. package/static/js/jquery.ui.accordion.js +611 -0
  133. package/static/js/jquery.ui.autocomplete.js +612 -0
  134. package/static/js/jquery.ui.button.js +416 -0
  135. package/static/js/jquery.ui.datepicker.js +1823 -0
  136. package/static/js/jquery.ui.dialog.js +878 -0
  137. package/static/js/jquery.ui.droppable.js +296 -0
  138. package/static/js/jquery.ui.position.js +252 -0
  139. package/static/js/jquery.ui.progressbar.js +109 -0
  140. package/static/js/jquery.ui.selectable.js +266 -0
  141. package/static/js/jquery.ui.slider.js +666 -0
  142. package/static/js/jquery.ui.sortable.js +1077 -0
  143. package/static/js/jquery.ui.tabs.js +758 -0
  144. package/stats.js +80 -0
  145. package/test-cache/vsac/vsac-valuesets.db +0 -0
  146. package/token/nginx_passport_setup.md +383 -0
  147. package/token/security_guide.md +294 -0
  148. package/token/token-template.html +330 -0
  149. package/token/token.js +1300 -0
  150. package/translations/Messages.properties +1510 -0
  151. package/translations/Messages_ar.properties +1399 -0
  152. package/translations/Messages_de.properties +836 -0
  153. package/translations/Messages_es.properties +737 -0
  154. package/translations/Messages_fr.properties +1 -0
  155. package/translations/Messages_ja.properties +893 -0
  156. package/translations/Messages_nl.properties +1357 -0
  157. package/translations/Messages_pt.properties +1302 -0
  158. package/translations/Messages_ru.properties +1 -0
  159. package/translations/Messages_uz.properties +1 -0
  160. package/translations/Messages_zh.properties +1 -0
  161. package/translations/rendering-phrases.properties +1128 -0
  162. package/translations/rendering-phrases_ar.properties +1091 -0
  163. package/translations/rendering-phrases_de.properties +6 -0
  164. package/translations/rendering-phrases_es.properties +6 -0
  165. package/translations/rendering-phrases_fr.properties +624 -0
  166. package/translations/rendering-phrases_ja.properties +21 -0
  167. package/translations/rendering-phrases_nl.properties +970 -0
  168. package/translations/rendering-phrases_pt.properties +1020 -0
  169. package/translations/rendering-phrases_ru.properties +1094 -0
  170. package/translations/rendering-phrases_uz.properties +1 -0
  171. package/translations/rendering-phrases_zh.properties +1 -0
  172. package/tx/README.md +418 -0
  173. package/tx/cm/cm-api.js +110 -0
  174. package/tx/cm/cm-database.js +735 -0
  175. package/tx/cm/cm-package.js +325 -0
  176. package/tx/cs/cs-api.js +789 -0
  177. package/tx/cs/cs-areacode.js +615 -0
  178. package/tx/cs/cs-country.js +1110 -0
  179. package/tx/cs/cs-cpt.js +785 -0
  180. package/tx/cs/cs-cs.js +1579 -0
  181. package/tx/cs/cs-currency.js +539 -0
  182. package/tx/cs/cs-db.js +1321 -0
  183. package/tx/cs/cs-hgvs.js +329 -0
  184. package/tx/cs/cs-lang.js +465 -0
  185. package/tx/cs/cs-loinc.js +1485 -0
  186. package/tx/cs/cs-mimetypes.js +238 -0
  187. package/tx/cs/cs-ndc.js +704 -0
  188. package/tx/cs/cs-omop.js +1025 -0
  189. package/tx/cs/cs-provider-api.js +43 -0
  190. package/tx/cs/cs-provider-list.js +37 -0
  191. package/tx/cs/cs-rxnorm.js +808 -0
  192. package/tx/cs/cs-snomed.js +1102 -0
  193. package/tx/cs/cs-ucum.js +514 -0
  194. package/tx/cs/cs-unii.js +271 -0
  195. package/tx/cs/cs-uri.js +218 -0
  196. package/tx/cs/cs-usstates.js +305 -0
  197. package/tx/dev.fhir.org.yml +14 -0
  198. package/tx/fixtures/test-cases-setup.json +18 -0
  199. package/tx/fixtures/test-cases.yml +16 -0
  200. package/tx/html/codesystem-operations.liquid +25 -0
  201. package/tx/html/home-metrics.liquid +247 -0
  202. package/tx/html/operations-form.liquid +148 -0
  203. package/tx/html/search-form.liquid +62 -0
  204. package/tx/html/tx-template.html +133 -0
  205. package/tx/html/valueset-operations.liquid +54 -0
  206. package/tx/importers/atc-to-fhir.js +316 -0
  207. package/tx/importers/import-loinc.module.js +1536 -0
  208. package/tx/importers/import-ndc.module.js +1088 -0
  209. package/tx/importers/import-rxnorm.module.js +898 -0
  210. package/tx/importers/import-sct.module.js +2457 -0
  211. package/tx/importers/import-unii.module.js +601 -0
  212. package/tx/importers/readme.md +453 -0
  213. package/tx/importers/subset-loinc.module.js +1081 -0
  214. package/tx/importers/subset-rxnorm.module.js +938 -0
  215. package/tx/importers/tx-import-base.js +351 -0
  216. package/tx/importers/tx-import-settings.js +310 -0
  217. package/tx/importers/tx-import.js +357 -0
  218. package/tx/library/canonical-resource.js +88 -0
  219. package/tx/library/capabilitystatement.js +292 -0
  220. package/tx/library/codesystem.js +774 -0
  221. package/tx/library/conceptmap.js +568 -0
  222. package/tx/library/designations.js +932 -0
  223. package/tx/library/errors.js +77 -0
  224. package/tx/library/extensions.js +117 -0
  225. package/tx/library/namingsystem.js +322 -0
  226. package/tx/library/operation-outcome.js +127 -0
  227. package/tx/library/parameters.js +105 -0
  228. package/tx/library/renderer.js +1559 -0
  229. package/tx/library/terminologycapabilities.js +418 -0
  230. package/tx/library/ucum-parsers.js +1029 -0
  231. package/tx/library/ucum-service.js +370 -0
  232. package/tx/library/ucum-types.js +1099 -0
  233. package/tx/library/valueset.js +543 -0
  234. package/tx/library.js +676 -0
  235. package/tx/ocl/cm-ocl.js +106 -0
  236. package/tx/ocl/cs-ocl.js +39 -0
  237. package/tx/ocl/vs-ocl.js +105 -0
  238. package/tx/operation-context.js +568 -0
  239. package/tx/params.js +613 -0
  240. package/tx/provider.js +403 -0
  241. package/tx/sct/ecl.js +1560 -0
  242. package/tx/sct/expressions.js +2077 -0
  243. package/tx/sct/structures.js +1396 -0
  244. package/tx/tx-html.js +1063 -0
  245. package/tx/tx.fhir.org.yml +39 -0
  246. package/tx/tx.js +927 -0
  247. package/tx/vs/vs-api.js +112 -0
  248. package/tx/vs/vs-database.js +786 -0
  249. package/tx/vs/vs-package.js +358 -0
  250. package/tx/vs/vs-vsac.js +366 -0
  251. package/tx/workers/batch-validate.js +129 -0
  252. package/tx/workers/batch.js +361 -0
  253. package/tx/workers/closure.js +32 -0
  254. package/tx/workers/expand.js +1845 -0
  255. package/tx/workers/lookup.js +407 -0
  256. package/tx/workers/metadata.js +467 -0
  257. package/tx/workers/operations.js +34 -0
  258. package/tx/workers/read.js +164 -0
  259. package/tx/workers/search.js +384 -0
  260. package/tx/workers/subsumes.js +334 -0
  261. package/tx/workers/translate.js +492 -0
  262. package/tx/workers/validate.js +2504 -0
  263. package/tx/workers/worker.js +904 -0
  264. package/tx/xml/capabilitystatement-xml.js +63 -0
  265. package/tx/xml/codesystem-xml.js +62 -0
  266. package/tx/xml/conceptmap-xml.js +65 -0
  267. package/tx/xml/namingsystem-xml.js +65 -0
  268. package/tx/xml/operationoutcome-xml.js +127 -0
  269. package/tx/xml/parameters-xml.js +312 -0
  270. package/tx/xml/terminologycapabilities-xml.js +64 -0
  271. package/tx/xml/valueset-xml.js +64 -0
  272. package/tx/xml/xml-base.js +603 -0
  273. package/vcl/vcl-parser.js +1098 -0
  274. package/vcl/vcl.js +253 -0
  275. package/windows-install.js +19 -0
  276. package/xig/xig-template.html +124 -0
  277. package/xig/xig.js +3049 -0
@@ -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
+ };