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,1845 @@
1
+ //
2
+ // Expand Worker - Handles ValueSet $expand operation
3
+ //
4
+ // GET /ValueSet/{id}/$expand
5
+ // GET /ValueSet/$expand?url=...&version=...
6
+ // POST /ValueSet/$expand (form body or Parameters with url)
7
+ // POST /ValueSet/$expand (body is ValueSet resource)
8
+ // POST /ValueSet/$expand (body is Parameters with valueSet parameter)
9
+ //
10
+
11
+ const { TerminologyWorker } = require('./worker');
12
+ const {TxParameters} = require("../params");
13
+ const {Designations, SearchFilterText} = require("../library/designations");
14
+ const {Extensions} = require("../library/extensions");
15
+ const {getValuePrimitive, getValueName} = require("../../library/utilities");
16
+ const {div} = require("../../library/html");
17
+ const {Issue, OperationOutcome} = require("../library/operation-outcome");
18
+ const crypto = require('crypto');
19
+ const ValueSet = require("../library/valueset");
20
+ const {VersionUtilities} = require("../../library/version-utilities");
21
+
22
+ // Expansion limits (from Pascal constants)
23
+ const UPPER_LIMIT_NO_TEXT = 1000;
24
+ const UPPER_LIMIT_TEXT = 1000;
25
+ const INTERNAL_LIMIT = 10000;
26
+ const EXPANSION_DEAD_TIME_SECS = 30;
27
+ const CACHE_WHEN_DEBUGGING = false;
28
+
29
+ /**
30
+ * Total status for expansion
31
+ */
32
+ const TotalStatus = {
33
+ Uninitialized: 'uninitialized',
34
+ Set: 'set',
35
+ Off: 'off'
36
+ };
37
+
38
+ /**
39
+ * Wraps an already-expanded ValueSet for fast code lookups
40
+ * Used when importing ValueSets during expansion
41
+ */
42
+ class ImportedValueSet {
43
+ /**
44
+ * @param {Object} valueSet - Expanded ValueSet resource
45
+ */
46
+ constructor(valueSet) {
47
+ this.valueSet = valueSet;
48
+ this.url = valueSet.url || '';
49
+ this.version = valueSet.version || '';
50
+
51
+ /** @type {Map<string, Object>} Maps system|code -> contains entry */
52
+ this.codeMap = new Map();
53
+
54
+ /** @type {Set<string>} Set of systems in this ValueSet */
55
+ this.systems = new Set();
56
+
57
+ this._buildCodeMap();
58
+ }
59
+
60
+ /**
61
+ * Build the code lookup map from the expansion
62
+ * @private
63
+ */
64
+ _buildCodeMap() {
65
+ if (!this.valueSet.expansion || !this.valueSet.expansion.contains) {
66
+ return;
67
+ }
68
+
69
+ this._indexContains(this.valueSet.expansion.contains);
70
+ }
71
+
72
+ /**
73
+ * Recursively index contains entries
74
+ * @private
75
+ */
76
+ _indexContains(contains) {
77
+ for (const entry of contains) {
78
+ if (entry.system && entry.code) {
79
+ const key = this._makeKey(entry.system, entry.code);
80
+ this.codeMap.set(key, entry);
81
+ this.systems.add(entry.system);
82
+ }
83
+
84
+ // Handle nested contains (hierarchy)
85
+ if (entry.contains && entry.contains.length > 0) {
86
+ this._indexContains(entry.contains);
87
+ }
88
+ }
89
+ }
90
+
91
+ /**
92
+ * Make a lookup key from system and code
93
+ * @private
94
+ */
95
+ _makeKey(system, code) {
96
+ return `${system}\x00${code}`;
97
+ }
98
+
99
+ /**
100
+ * Check if this ValueSet contains a specific code
101
+ * @param {string} system - Code system URL
102
+ * @param {string} code - Code value
103
+ * @returns {boolean}
104
+ */
105
+ hasCode(system, code) {
106
+ return this.codeMap.has(this._makeKey(system, code));
107
+ }
108
+
109
+ /**
110
+ * Get a contains entry for a specific code
111
+ * @param {string} system - Code system URL
112
+ * @param {string} code - Code value
113
+ * @returns {Object|null}
114
+ */
115
+ getCode(system, code) {
116
+ return this.codeMap.get(this._makeKey(system, code)) || null;
117
+ }
118
+
119
+ /**
120
+ * Check if this ValueSet contains any codes from a system
121
+ * @param {string} system - Code system URL
122
+ * @returns {boolean}
123
+ */
124
+ hasSystem(system) {
125
+ return this.systems.has(system);
126
+ }
127
+
128
+ /**
129
+ * Get total number of codes
130
+ * @returns {number}
131
+ */
132
+ get count() {
133
+ return this.codeMap.size;
134
+ }
135
+
136
+ /**
137
+ * Iterate over all codes
138
+ * @yields {{system: string, code: string, entry: Object}}
139
+ */
140
+ *codes() {
141
+ for (const entry of this.codeMap.values()) {
142
+ yield {
143
+ system: entry.system,
144
+ code: entry.code,
145
+ entry
146
+ };
147
+ }
148
+ }
149
+ }
150
+
151
+ /**
152
+ * Special filter context for ValueSet import optimization
153
+ * When a ValueSet can be used as a filter instead of full expansion
154
+ */
155
+ class ValueSetFilterContext {
156
+ /**
157
+ * @param {ImportedValueSet} importedVs - The imported ValueSet
158
+ */
159
+ constructor(importedVs) {
160
+ this.importedVs = importedVs;
161
+ this.type = 'valueset';
162
+ }
163
+
164
+ /**
165
+ * Check if a code passes this filter
166
+ * @param {string} system - Code system URL
167
+ * @param {string} code - Code value
168
+ * @returns {boolean}
169
+ */
170
+ passesFilter(system, code) {
171
+ return this.importedVs.hasCode(system, code);
172
+ }
173
+ }
174
+
175
+ /**
176
+ * Special filter context for empty filter (nothing matches)
177
+ */
178
+ class EmptyFilterContext {
179
+ constructor() {
180
+ this.type = 'empty';
181
+ }
182
+
183
+ passesFilter() {
184
+ return false;
185
+ }
186
+ }
187
+
188
+ class ValueSetCounter {
189
+ constructor() {
190
+ this.count = 0;
191
+ }
192
+
193
+ increment() {
194
+ this.count++;
195
+ }
196
+ }
197
+
198
+ class ValueSetExpander {
199
+ worker;
200
+ params;
201
+ excluded = new Set();
202
+ hasExclusions = false;
203
+
204
+ constructor(worker, params) {
205
+ this.worker = worker;
206
+ this.params = params;
207
+
208
+ this.csCounter = new Map();
209
+ }
210
+
211
+ addDefinedCode(cs, system, c, imports, parent, excludeInactive, srcURL) {
212
+ this.worker.deadCheck('addDefinedCode');
213
+ let n = null;
214
+ if (!this.params.excludeNotForUI || !cs.isAbstract(c)) {
215
+ const cds = new Designations(this.worker.opContext.i18n.languageDefinitions);
216
+ this.listDisplays(cds, c);
217
+ n = this.includeCode(null, parent, system, '', c.code, cs.isAbstract(c), cs.isInactive(c), cs.isDeprecated(c), cs.codeStatus(c), cds, c.definition, c.itemWeight,
218
+ null, imports, c.getAllExtensionsW(), null, c.properties, null, excludeInactive, srcURL);
219
+ }
220
+ for (let i = 0; i < c.concept.length; i++) {
221
+ this.worker.deadCheck('addDefinedCode');
222
+ this.addDefinedCode(cs, system, c.concept[i], imports, n, excludeInactive, srcURL);
223
+ }
224
+ }
225
+
226
+ async listDisplaysFromProvider(displays, cs, context) {
227
+ await cs.designations(context, displays);
228
+ displays.source = cs;
229
+ }
230
+
231
+ listDisplaysFromConcept(displays, concept) {
232
+ for (const ccd of concept.designations || []) {
233
+ displays.addDesignation(ccd);
234
+ }
235
+ }
236
+
237
+ listDisplaysFromIncludeConcept(displays, concept, vs) {
238
+ if (concept.display) {
239
+ if (!VersionUtilities.isR4Plus(this.worker.provider.getFhirVersion())) {
240
+ displays.clear();
241
+ }
242
+ let lang = vs.language ? this.worker.languages.parse(vs.language) : null;
243
+ displays.addDesignation(true, "active", lang, null, concept.display);
244
+ }
245
+ for (const cd of concept.designation || []) {
246
+ displays.addDesignationFromConcept(cd);
247
+ }
248
+ }
249
+ canonical(system, version) {
250
+ if (!version) {
251
+ return system;
252
+ } else {
253
+ return system + '|' + version;
254
+ }
255
+ }
256
+
257
+ passesImport(imp, system, code) {
258
+ imp.buildMap();
259
+ return imp.hasCode(system, code);
260
+ }
261
+
262
+ passesImports(imports, system, code, offset) {
263
+ if (imports == null) {
264
+ return true;
265
+ }
266
+ for (let i = offset; i < imports.length; i++) {
267
+ if (!this.passesImport(imports[i], system, code)) {
268
+ return false;
269
+ }
270
+ }
271
+ return true;
272
+ }
273
+
274
+ useDesignation(cd) {
275
+ if (!this.params.hasDesignations) {
276
+ return true;
277
+ }
278
+ for (const s of this.params.designations) {
279
+ const [l, r] = s.split('|');
280
+ if (cd.use != null && cd.use.system === l && cd.use.code === r) {
281
+ return true;
282
+ }
283
+ if (cd.language != null && l === 'urn:ietf:bcp:47' && r === cd.language.code) {
284
+ return true;
285
+ }
286
+ }
287
+ return false;
288
+ }
289
+
290
+ isValidating() {
291
+ return false;
292
+ }
293
+
294
+ opName() {
295
+ return 'expansion';
296
+ }
297
+
298
+ redundantDisplay(n, lang, use, value) {
299
+ if (!((lang == null) && (!this.valueSet.language)) || ((lang) && lang.code.startsWith(this.valueSet.language))) {
300
+ return false;
301
+ } else if (!((use == null) || (use.code === 'display'))) {
302
+ return false;
303
+ } else {
304
+ return value.asString === n.display;
305
+ }
306
+ }
307
+
308
+ includeCode(cs, parent, system, version, code, isAbstract, isInactive, deprecated, status, displays, definition, itemWeight, expansion, imports, csExtList, vsExtList, csProps, expProps, excludeInactive, srcURL) {
309
+ let result = null;
310
+ this.worker.deadCheck('processCode');
311
+
312
+ if (!this.passesImports(imports, system, code, 0)) {
313
+ return null;
314
+ }
315
+ if (isInactive && excludeInactive) {
316
+ return null;
317
+ }
318
+ if (this.isExcluded(system, version, code)) {
319
+ return null;
320
+ }
321
+
322
+ if (cs != null && cs.expandLimitation > 0) {
323
+ let cnt = this.csCounter.get(cs.system);
324
+ if (cnt == null) {
325
+ cnt = new ValueSetCounter();
326
+ this.csCounter.set(cs.system, cnt);
327
+ }
328
+ cnt.increment();
329
+ if (cnt.count > cs.expandLimitation) {
330
+ return null;
331
+ }
332
+ }
333
+
334
+ if (this.limitCount > 0 && this.fullList.length >= this.limitCount && !this.hasExclusions) {
335
+ if (this.count > -1 && this.offset > -1 && this.count + this.offset > 0 && this.fullList.length >= this.count + this.offset) {
336
+ throw new Issue('information', 'informational', null, null, null, null).setFinished();
337
+ } else {
338
+ if (!srcURL) {
339
+ srcURL = '??';
340
+ }
341
+ throw new Issue("error", "too-costly", null, 'VALUESET_TOO_COSTLY', this.worker.i18n.translate('VALUESET_TOO_COSTLY', this.params.httpLanguages, [srcURL, '>' + this.limitCount]), null, 400).withDiagnostics(this.worker.opContext.diagnostics());
342
+ }
343
+ }
344
+
345
+ if (expansion) {
346
+ const s = this.canonical(system, version);
347
+ this.addParamUri(expansion, 'used-codesystem', s);
348
+ if (cs != null) {
349
+ const ts = cs.listSupplements();
350
+ for (const vs of ts) {
351
+ this.addParamUri(expansion, 'used-supplement', vs);
352
+ }
353
+ }
354
+ }
355
+
356
+ const s = this.keyS(system, version, code);
357
+
358
+ if (!this.map.has(s)) {
359
+ const n = {};
360
+ n.system = system;
361
+ n.code = code;
362
+ if (this.doingVersion) {
363
+ n.version = version;
364
+ }
365
+ if (isAbstract) {
366
+ n.abstract = isAbstract;
367
+ }
368
+ if (isInactive) {
369
+ n.inactive = true;
370
+ }
371
+
372
+ if (status && status.toLowerCase() !== 'active') {
373
+ this.defineProperty(expansion, n, 'http://hl7.org/fhir/concept-properties#status', 'status', "valueCode", status);
374
+ } else if (deprecated) {
375
+ this.defineProperty(expansion, n, 'http://hl7.org/fhir/concept-properties#status', 'status', "valueCode", 'deprecated');
376
+ }
377
+
378
+ if (Extensions.has(csExtList, 'http://hl7.org/fhir/StructureDefinition/codesystem-label')) {
379
+ this.defineProperty(expansion, n, 'http://hl7.org/fhir/concept-properties#label', 'label', "valueString", Extensions.readString(csExtList, 'http://hl7.org/fhir/StructureDefinition/codesystem-label'));
380
+ }
381
+ if (Extensions.has(vsExtList, 'http://hl7.org/fhir/StructureDefinition/valueset-label')) {
382
+ this.defineProperty(expansion, n, 'http://hl7.org/fhir/concept-properties#label', 'label', "valueString", Extensions.readString(vsExtList, 'http://hl7.org/fhir/StructureDefinition/valueset-label'));
383
+ }
384
+
385
+ if (Extensions.has(csExtList, 'http://hl7.org/fhir/StructureDefinition/codesystem-conceptOrder')) {
386
+ this.defineProperty(expansion, n, 'http://hl7.org/fhir/concept-properties#order', 'order', "valueDecimal", Extensions.readNumber(csExtList, 'http://hl7.org/fhir/StructureDefinition/codesystem-conceptOrder', undefined));
387
+ }
388
+ if (Extensions.has(vsExtList, 'http://hl7.org/fhir/StructureDefinition/valueset-conceptOrder')) {
389
+ this.defineProperty(expansion, n, 'http://hl7.org/fhir/concept-properties#order', 'order', "valueDecimal", Extensions.readNumber(vsExtList, 'http://hl7.org/fhir/StructureDefinition/valueset-conceptOrder', undefined));
390
+ }
391
+
392
+ if (Extensions.has(csExtList, 'http://hl7.org/fhir/StructureDefinition/itemWeight')) {
393
+ this.defineProperty(expansion, n, 'http://hl7.org/fhir/concept-properties#itemWeight', 'weight', "valueDecimal", Extensions.readNumber(csExtList, 'http://hl7.org/fhir/StructureDefinition/itemWeight', undefined));
394
+ }
395
+ if (Extensions.has(vsExtList, 'http://hl7.org/fhir/StructureDefinition/itemWeight')) {
396
+ this.defineProperty(expansion, n, 'http://hl7.org/fhir/concept-properties#itemWeight', 'weight', "valueDecimal", Extensions.readNumber(vsExtList, 'http://hl7.org/fhir/StructureDefinition/itemWeight', undefined));
397
+ }
398
+
399
+ if (csExtList != null) {
400
+ for (const ext of csExtList) {
401
+ if (['http://hl7.org/fhir/StructureDefinition/coding-sctdescid', 'http://hl7.org/fhir/StructureDefinition/rendering-style',
402
+ 'http://hl7.org/fhir/StructureDefinition/rendering-xhtml', 'http://hl7.org/fhir/StructureDefinition/codesystem-alternate'].includes(ext.url)) {
403
+ if (!n.extension) {n.extension = []}
404
+ n.extension.push(ext);
405
+ }
406
+ if (['http://hl7.org/fhir/StructureDefinition/structuredefinition-standards-status'].includes(ext.url)) {
407
+ this.defineProperty(expansion, n, 'http://hl7.org/fhir/concept-properties#status', 'status', "valueCode", getValuePrimitive(ext));
408
+ }
409
+ }
410
+ }
411
+
412
+ if (vsExtList != null) {
413
+ for (const ext of vsExtList || []) {
414
+ if (['http://hl7.org/fhir/StructureDefinition/valueset-supplement', 'http://hl7.org/fhir/StructureDefinition/valueset-deprecated',
415
+ 'http://hl7.org/fhir/StructureDefinition/structuredefinition-standards-status',
416
+ 'http://hl7.org/fhir/StructureDefinition/valueset-concept-definition', 'http://hl7.org/fhir/StructureDefinition/coding-sctdescid',
417
+ 'http://hl7.org/fhir/StructureDefinition/rendering-style', 'http://hl7.org/fhir/StructureDefinition/rendering-xhtml'].includes(ext.url)) {
418
+ if (!n.extension) {n.extension = []}
419
+ n.extension.push(ext);
420
+ }
421
+ }
422
+ }
423
+
424
+ // display and designations
425
+ const pref = displays.preferredDesignation(this.params.workingLanguages());
426
+ if (pref && pref.value) {
427
+ n.display = pref.value;
428
+ }
429
+
430
+ if (this.params.includeDesignations) {
431
+ for (const t of displays.designations) {
432
+ if (t !== pref && this.useDesignation(t) && t.value != null && !this.redundantDisplay(n, t.language, t.use, t.value)) {
433
+ if (!n.designation) {
434
+ n.designation = [];
435
+ }
436
+ n.designation.push(t.asObject());
437
+ }
438
+ }
439
+ }
440
+
441
+ for (const pn of this.params.properties) {
442
+ if (pn === 'definition') {
443
+ if (definition) {
444
+ this.defineProperty(expansion, n, 'http://hl7.org/fhir/concept-properties#definition', pn, "valueString", definition);
445
+ }
446
+ } else if (csProps != null && cs != null) {
447
+ for (const cp of csProps) {
448
+ if (cp.code === pn) {
449
+ let vn = getValueName(cp);
450
+ let v = cp[vn];
451
+ this.defineProperty(expansion, n, this.getPropUrl(cs, pn), pn, vn, v);
452
+ }
453
+ }
454
+ }
455
+ }
456
+
457
+ if (!this.map.has(s)) {
458
+ this.fullList.push(n);
459
+ this.map.set(s, n);
460
+ if (parent != null) {
461
+ if (!parent.contains) {
462
+ parent.contains = [];
463
+ }
464
+ parent.contains.push(n);
465
+ } else {
466
+ this.rootList.push(n);
467
+ }
468
+ } else {
469
+ this.canBeHierarchy = false;
470
+ }
471
+ result = n;
472
+ }
473
+ return result;
474
+ }
475
+
476
+ excludeCode(cs, system, version, code, expansion, imports, srcURL) {
477
+ this.worker.deadCheck('excludeCode');
478
+ if (!this.passesImports(imports, system, code, 0)) {
479
+ return;
480
+ }
481
+
482
+ if (this.limitCount > 0 && this.fullList.length >= this.limitCount && !this.hasExclusions) {
483
+ if (this.count > -1 && this.offset > -1 && this.count + this.offset > 0 && this.fullList.length >= this.count + this.offset) {
484
+ throw new Issue('information', 'informational', null, null, null, null).setFinished();
485
+ } else {
486
+ if (!srcURL) {
487
+ srcURL = '??';
488
+ }
489
+ throw new Issue("error", "too-costly", null, 'VALUESET_TOO_COSTLY', this.worker.i18n.translate('VALUESET_TOO_COSTLY', this.params.httpLanguages, [srcURL, '>' + this.limitCount]), null, 400).withDiagnostics(this.worker.opContext.diagnostics());
490
+ }
491
+ }
492
+
493
+ if (expansion) {
494
+ const s = this.canonical(system, version);
495
+ this.addParamUri(expansion, 'used-codesystem', s);
496
+ if (cs) {
497
+ const ts= cs.listSupplements();
498
+ for (const vs of ts) {
499
+ this.addParamUri(expansion, 'used-supplement', vs);
500
+ }
501
+ }
502
+ }
503
+
504
+ this.excluded.add(system + '|' + version + '#' + code);
505
+ }
506
+
507
+ async checkCanExpandValueset(uri, version) {
508
+ const vs = await this.worker.findValueSet(uri, version);
509
+ if (vs == null) {
510
+ if (!version && uri.includes('|')) {
511
+ version = uri.substring(uri.indexOf('|') + 1);
512
+ uri = uri.substring(0, uri.indexOf('|'));
513
+ }
514
+ if (!version) {
515
+ throw new Issue('error', 'not-found', null, 'VS_EXP_IMPORT_UNK', this.worker.i18n.translate('VS_EXP_IMPORT_UNK', this.params.httpLanguages, [uri]), 'unknown', 400);
516
+ } else {
517
+ throw new Issue('error', 'not-found', null, 'VS_EXP_IMPORT_UNK_PINNED', this.worker.i18n.translate('VS_EXP_IMPORT_UNK_PINNED', this.params.httpLanguages, [uri, version]), 'not-found', 400);
518
+ }
519
+ } else {
520
+ this.worker.seeSourceVS(vs, uri);
521
+ }
522
+ }
523
+
524
+ async expandValueSet(uri, version, filter, notClosed) {
525
+
526
+ let vs = await this.worker.findValueSet(uri, version);
527
+ if (!vs) {
528
+ if (version) {
529
+ throw new Issue('error', 'not-found', null, 'VS_EXP_IMPORT_UNK_PINNED', this.worker.i18n.translate('VS_EXP_IMPORT_UNK_PINNED', this.params.httpLanguages, [uri, version]), "not-found", 400);
530
+ } else if (uri.includes('|')) {
531
+ throw new Issue('error', 'not-found', null, 'VS_EXP_IMPORT_UNK_PINNED', this.worker.i18n.translate('VS_EXP_IMPORT_UNK_PINNED', this.params.httpLanguages, [uri.substring(0, uri.indexOf("|")), uri.substring(uri.indexOf("|")+1)]), "not-found", 400);
532
+ } else {
533
+ throw new Issue('error', 'not-found', null, 'VS_EXP_IMPORT_UNK', this.worker.i18n.translate('VS_EXP_IMPORT_UNK', this.params.httpLanguages, [uri]), "not-found", 400);
534
+ }
535
+ }
536
+ let worker = new ExpandWorker(this.worker.opContext, this.worker.log, this.worker.provider, this.worker.languages, this.worker.i18n);
537
+ worker.additionalResources = this.worker.additionalResources;
538
+ let expander = new ValueSetExpander(worker, this.params);
539
+ let result = await expander.expand(vs, filter, false);
540
+ if (result == null) {
541
+ throw new Issue('error', 'not-found', null, 'VS_EXP_IMPORT_UNK', this.worker.i18n.translate('VS_EXP_IMPORT_UNK', this.params.httpLanguages, [uri]), 'unknown');
542
+ }
543
+ if (Extensions.has(result.expansion, 'http://hl7.org/fhir/params/questionnaire-extensions#closed')) {
544
+ notClosed.value = true;
545
+ }
546
+ return result;
547
+ }
548
+
549
+ async importValueSet(vs, expansion, imports, offset) {
550
+ this.canBeHierarchy = false;
551
+ for (let p of vs.expansion.parameter) {
552
+ let vn = getValueName(p);
553
+ let v = getValuePrimitive(p);
554
+ this.addParam(expansion, p.name, vn, v);
555
+ }
556
+ this.checkResourceCanonicalStatus(expansion, vs, this.valueSet);
557
+
558
+ for (const c of vs.expansion.contains || []) {
559
+ this.worker.deadCheck('importValueSet');
560
+ await this.importValueSetItem(null, c, imports, offset);
561
+ }
562
+ }
563
+
564
+ async importValueSetItem(p, c, imports, offset) {
565
+ this.worker.deadCheck('importValueSetItem');
566
+ const s = this.keyC(c);
567
+ if (this.passesImports(imports, c.system, c.code, offset) && !this.map.has(s)) {
568
+ this.fullList.push(c);
569
+ if (p != null) {
570
+ if (!p.contains) {p.contains = [] }
571
+ p.contains.push(c);
572
+ } else {
573
+ this.rootList.push(c);
574
+ }
575
+ this.map.set(s, c);
576
+ }
577
+ for (const cc of c.contains || []) {
578
+ this.worker.deadCheck('importValueSetItem');
579
+ await this.importValueSetItem(c, cc, imports, offset);
580
+ }
581
+ }
582
+
583
+ excludeValueSet(vs, expansion, imports, offset) {
584
+ for (const c of vs.expansion.contains) {
585
+ this.worker.deadCheck('excludeValueSet');
586
+ const s = this.keyC(c);
587
+ if (this.passesImports(imports, c.system, c.code, offset) && this.map.has(s)) {
588
+ const idx = this.fullList.indexOf(this.map.get(s));
589
+ if (idx >= 0) {
590
+ this.fullList.splice(idx, 1);
591
+ }
592
+ this.map.delete(s);
593
+ }
594
+ }
595
+ }
596
+
597
+ async checkSource(cset, exp, filter, srcURL, ts) {
598
+ this.worker.deadCheck('checkSource');
599
+ Extensions.checkNoModifiers(cset, 'ValueSetExpander.checkSource', 'set');
600
+ let imp = false;
601
+ for (const u of cset.valueSet || []) {
602
+ this.worker.deadCheck('checkSource');
603
+ const s = this.worker.pinValueSet(u);
604
+ await this.checkCanExpandValueset(s, '');
605
+ imp = true;
606
+ }
607
+
608
+ if (ts.has(cset.system)) {
609
+ const v = ts.get(cset.system);
610
+ if (v !== cset.version) {
611
+ this.doingVersion = true;
612
+ }
613
+ } else {
614
+ ts.set(cset.system, cset.version);
615
+ }
616
+
617
+ if (cset.system) {
618
+ const cs = await this.worker.findCodeSystem(cset.system, cset.version, this.params, ['complete', 'fragment'], false, true, true, null);
619
+ this.worker.seeSourceProvider(cs, cset.system);
620
+ if (cs == null) {
621
+ // nothing
622
+ } else {
623
+ if (cs.contentMode() !== 'complete') {
624
+ if (cs.contentMode() === 'not-present') {
625
+ throw new Issue('error', 'business-rule', null, null, 'The code system definition for ' + cset.system + ' has no content, so this expansion cannot be performed', 'invalid');
626
+ } else if (cs.contentMode() === 'supplement') {
627
+ throw new Issue('error', 'business-rule', null, null, 'The code system definition for ' + cset.system + ' defines a supplement, so this expansion cannot be performed', 'invalid');
628
+ } else if (this.params.incompleteOK) {
629
+ exp.addParamUri(cs.contentMode, cs.system + '|' + cs.version);
630
+ } else {
631
+ throw new Issue('error', 'business-rule', null, null, 'The code system definition for ' + cset.system + ' is a ' + cs.contentMode + ', so this expansion is not permitted unless the expansion parameter "incomplete-ok" has a value of "true"', 'invalid');
632
+ }
633
+ }
634
+
635
+ if (!cset.concept && !cset.filter) {
636
+ if (cs.specialEnumeration() && this.params.limitedExpansion) {
637
+ this.checkCanExpandValueSet(cs.specialEnumeration(), '');
638
+ } else if (filter.isNull) {
639
+ if (cs.isNotClosed()) {
640
+ if (cs.specialEnumeration()) {
641
+ throw new Issue("error", "too-costly", null, null, 'The code System "' + cs.system() + '" has a grammar, and cannot be enumerated directly. If an incomplete expansion is requested, a limited enumeration will be returned', null, 400).withDiagnostics(this.worker.opContext.diagnostics());
642
+ } else {
643
+ throw new Issue("error", "too-costly", null, null, 'The code System "' + cs.system() + '" has a grammar, and cannot be enumerated directly', null, 400).withDiagnostics(this.worker.opContext.diagnostics());
644
+ }
645
+ }
646
+
647
+ if (!imp && this.limitCount > 0 && cs.totalCount > this.limitCount && !this.params.limitedExpansion) {
648
+ throw new Issue("error", "too-costly", null, 'VALUESET_TOO_COSTLY', this.worker.i18n.translate('VALUESET_TOO_COSTLY', this.params.httpLanguages, [srcURL, '>' + this.limitCount]), null, 400).withDiagnostics(this.worker.opContext.diagnostics());
649
+ }
650
+ }
651
+ }
652
+ }
653
+ }
654
+ }
655
+
656
+ async includeCodes(cset, path, vsSrc, filter, expansion, excludeInactive, notClosed) {
657
+ this.worker.deadCheck('processCodes#1');
658
+ const valueSets = [];
659
+
660
+ Extensions.checkNoModifiers(cset, 'ValueSetExpander.processCodes', 'set');
661
+
662
+ if (cset.valueSet || cset.concept || (cset.filter || []).length > 1) {
663
+ this.canBeHierarchy = false;
664
+ }
665
+
666
+ if (!cset.system) {
667
+ for (const u of cset.valueSet) {
668
+ this.worker.deadCheck('processCodes#2');
669
+ const s = this.worker.pinValueSet(u);
670
+ this.worker.opContext.log('import value set ' + s);
671
+ const ivs = new ImportedValueSet(await this.expandValueSet(s, '', filter, notClosed));
672
+ this.checkResourceCanonicalStatus(expansion, ivs.valueSet, this.valueSet);
673
+ this.addParamUri(expansion, 'used-valueset', this.worker.makeVurl(ivs.valueSet));
674
+ valueSets.push(ivs);
675
+ }
676
+ await this.importValueSet(valueSets[0].valueSet, expansion, valueSets, 1);
677
+ } else {
678
+ const filters = [];
679
+ const prep = null;
680
+ const cs = await this.worker.findCodeSystem(cset.system, cset.version, this.params, ['complete', 'fragment'], false, false, true, null);
681
+
682
+ if (cs == null) {
683
+ // nothing
684
+ } else {
685
+
686
+ this.worker.checkSupplements(cs, cset, this.requiredSupplements);
687
+ this.checkProviderCanonicalStatus(expansion, cs, this.valueSet);
688
+ const sv = this.canonical(await cs.system(), await cs.version());
689
+ this.addParamUri(expansion, 'used-codesystem', sv);
690
+
691
+ for (const u of cset.valueSet || []) {
692
+ this.worker.deadCheck('processCodes#3');
693
+ const s = this.pinValueSet(u);
694
+ let f = null;
695
+ this.opContext.log('import2 value set ' + s);
696
+ const vs = this.onGetValueSet(this, s, '');
697
+ if (vs != null) {
698
+ f = this.makeFilterForValueSet(cs, vs);
699
+ }
700
+ if (f != null) {
701
+ filters.push(f);
702
+ } else {
703
+ valueSets.push(new ImportedValueSet(await this.expandValueSet(s, '', filter, notClosed)));
704
+ }
705
+ }
706
+
707
+ if (!cset.concept && !cset.filter) {
708
+ if (cs.specialEnumeration() && this.params.limitedExpansion && filters.length === 0) {
709
+ this.worker.opContext.log('import special value set ' + cs.specialEnumeration());
710
+ const base = await this.expandValueSet(cs.specialEnumeration(), '', filter, notClosed);
711
+ Extensions.addBoolean(expansion, 'http://hl7.org/fhir/StructureDefinition/valueset-toocostly', true);
712
+ await this.importValueSet(base, expansion, valueSets, 0);
713
+ notClosed.value = true;
714
+ } else if (filter.isNull) {
715
+ this.worker.opContext.log('add whole code system');
716
+ if (cs.isNotClosed()) {
717
+ if (cs.specialEnumeration()) {
718
+ throw new Issue("error", "too-costly", null, null, 'The code System "' + cs.system() + '" has a grammar, and cannot be enumerated directly. If an incomplete expansion is requested, a limited enumeration will be returned', null, 400).withDiagnostics(this.worker.opContext.diagnostics());
719
+
720
+ } else {
721
+ throw new Issue("error", "too-costly", null, null, 'The code System "' + cs.system() + '" has a grammar, and cannot be enumerated directly', null, 400).withDiagnostics(this.worker.opContext.diagnostics());
722
+ }
723
+ }
724
+
725
+ const iter = await cs.iterator(null);
726
+ if (valueSets.length === 0 && this.limitCount > 0 && (iter && iter.total > this.limitCount) && !this.params.limitedExpansion && this.offset < 0) {
727
+ throw new Issue("error", "too-costly", null, 'VALUESET_TOO_COSTLY', this.worker.i18n.translate('VALUESET_TOO_COSTLY', this.params.httpLanguages, [vsSrc.vurl, '>' + this.limitCount]), null, 400).withDiagnostics(this.worker.opContext.diagnostics());
728
+
729
+ }
730
+ let tcount = 0;
731
+ let c = await cs.nextContext(iter);
732
+ while (c) {
733
+ this.worker.deadCheck('processCodes#3a');
734
+ if (await this.passesFilters(cs, c, prep, filters, 0)) {
735
+ tcount += await this.includeCodeAndDescendants(cs, c, expansion, valueSets, null, excludeInactive, vsSrc.vurl);
736
+ }
737
+ c = await cs.nextContext(iter);
738
+ }
739
+ this.addToTotal(tcount);
740
+ } else {
741
+ this.worker.opContext.log('prepare filters');
742
+ this.noTotal();
743
+ if (cs.isNotClosed(filter)) {
744
+ notClosed.value = true;
745
+ }
746
+ const prep = await cs.getPrepContext(true);
747
+ const ctxt = await cs.searchFilter(filter, prep, false);
748
+ await cs.prepare(prep);
749
+ this.worker.opContext.log('iterate filters');
750
+ while (await cs.filterMore(ctxt)) {
751
+ this.worker.deadCheck('processCodes#4');
752
+ const c = await cs.filterConcept(ctxt);
753
+ if (await this.passesFilters(cs, c, prep, filters, 0)) {
754
+ const cds = new Designations(this.worker.i18n.languageDefinitions);
755
+ await this.listDisplaysFromProvider(cds, cs, c);
756
+ await this.includeCode(cs, null, await cs.system(), await cs.version(), await cs.code(c), await cs.isAbstract(c), await cs.isInactive(c), await cs.deprecated(c), await cs.getCodeStatus(c),
757
+ cds, await cs.definition(c), await cs.itemWeight(c), expansion, valueSets, await cs.getExtensions(c), null, await cs.getProperties(c), null, excludeInactive, vsSrc.url);
758
+ }
759
+ }
760
+ this.worker.opContext.log('iterate filters done');
761
+ }
762
+ }
763
+
764
+ if (cset.concept) {
765
+ this.worker.opContext.log('iterate concepts');
766
+ const cds = new Designations(this.worker.i18n.languageDefinitions);
767
+ let tcount = 0;
768
+ for (const cc of cset.concept) {
769
+ this.worker.deadCheck('processCodes#3');
770
+ cds.clear();
771
+ Extensions.checkNoModifiers(cc, 'ValueSetExpander.processCodes', 'set concept reference');
772
+ const cctxt = await cs.locate(cc.code, this.allAltCodes);
773
+ if (cctxt && cctxt.context && (!this.params.activeOnly || !await cs.isInactive(cctxt.context)) && await this.passesFilters(cs, cctxt.context, prep, filters, 0)) {
774
+ await this.listDisplaysFromProvider(cds, cs, cctxt.context);
775
+ this.listDisplaysFromIncludeConcept(cds, cc, vsSrc);
776
+ if (filter.passesDesignations(cds) || filter.passes(cc.code)) {
777
+ tcount++;
778
+ let ov = Extensions.readString(cc, 'http://hl7.org/fhir/StructureDefinition/itemWeight');
779
+ if (!ov) {
780
+ ov = await cs.itemWeight(cctxt.context);
781
+ }
782
+ await this.includeCode(cs, null, cs.system(), cs.version(), cc.code, await cs.isAbstract(cctxt.context), await cs.isInactive(cctxt.context), await cs.isDeprecated(cctxt.context), await cs.getStatus(cctxt.context), cds,
783
+ await cs.definition(cctxt.context), ov, expansion, valueSets, await cs.extensions(cctxt.context), cc.extension, await cs.properties(cctxt.context), null, excludeInactive, vsSrc.url);
784
+ }
785
+ }
786
+ }
787
+ this.addToTotal(tcount);
788
+ this.worker.opContext.log('iterate concepts done');
789
+ }
790
+
791
+ if (cset.filter) {
792
+ this.worker.opContext.log('prepare filters');
793
+ const fcl = cset.filter;
794
+ const prep = await cs.getPrepContext(true);
795
+ if (!filter.isNull) {
796
+ await cs.searchFilter(filter, prep, true);
797
+ }
798
+
799
+ if (cs.specialEnumeration()) {
800
+ await cs.specialFilter(prep, true);
801
+ Extensions.addBoolean(expansion, 'http://hl7.org/fhir/StructureDefinition/valueset-toocostly', true);
802
+ notClosed.value = true;
803
+ }
804
+
805
+ for (let i = 0; i < fcl.length; i++) {
806
+ this.worker.deadCheck('processCodes#4a');
807
+ const fc = fcl[i];
808
+ if (!fc.value) {
809
+ throw new Issue('error', 'invalid', path+".filter["+i+"]", 'UNABLE_TO_HANDLE_SYSTEM_FILTER_WITH_NO_VALUE', this.worker.i18n.translate('UNABLE_TO_HANDLE_SYSTEM_FILTER_WITH_NO_VALUE', this.params.httpLanguages, [cs.system(), fc.property, fc.op]), 'vs-invalid', 400);
810
+ }
811
+ Extensions.checkNoModifiers(fc, 'ValueSetExpander.processCodes', 'filter');
812
+ await cs.filter(prep, fc.property, fc.op, fc.value);
813
+ }
814
+
815
+ const fset = await cs.executeFilters(prep);
816
+ if (await cs.filtersNotClosed(prep)) {
817
+ notClosed.value = true;
818
+ }
819
+ if (fset.length === 1 && !excludeInactive && !this.params.activeOnly) {
820
+ this.addToTotal(await cs.filterSize(prep, fset[0]));
821
+ }
822
+
823
+ // let count = 0;
824
+ this.worker.opContext.log('iterate filters');
825
+ while (await cs.filterMore(prep, fset[0])) {
826
+ this.worker.deadCheck('processCodes#5');
827
+ const c = await cs.filterConcept(prep, fset[0]);
828
+ const ok = (!this.params.activeOnly || !await cs.isInactive(c)) && (await this.passesFilters(cs, c, prep, fset, 1));
829
+ if (ok) {
830
+ // count++;
831
+ const cds = new Designations(this.worker.i18n.languageDefinitions);
832
+ if (this.passesImports(valueSets, cs.system(), await cs.code(c), 0)) {
833
+ await this.listDisplaysFromProvider(cds, cs, c);
834
+ let parent = null;
835
+ if (cs.hasParents()) {
836
+ parent = this.map.get(this.keyS(cs.system(), cs.version(), await cs.parent(c)));
837
+ } else {
838
+ this.canBeHierarchy = false;
839
+ }
840
+ await this.includeCode(cs, parent, await cs.system(), await cs.version(), await cs.code(c), await cs.isAbstract(c), await cs.isInactive(c),
841
+ await cs.isDeprecated(c), await cs.getStatus(c), cds, await cs.definition(c), await cs.itemWeight(c),
842
+ expansion, null, await cs.extensions(c), null, await cs.properties(c), null, excludeInactive, vsSrc.url);
843
+
844
+ }
845
+ }
846
+ }
847
+ this.worker.opContext.log('iterate filters done');
848
+ }
849
+
850
+ }
851
+ }
852
+ }
853
+
854
+ async passesFilters(cs, c, prep, filters, offset) {
855
+ for (let j = offset; j < filters.length; j++) {
856
+ const f = filters[j];
857
+ // if (f instanceof SpecialProviderFilterContextNothing) {
858
+ // return false;
859
+ // } else if (f instanceof SpecialProviderFilterContextConcepts) {
860
+ // let ok = false;
861
+ // for (const t of f.list) {
862
+ // if (cs.sameContext(t, c)) {
863
+ // ok = true;
864
+ // }
865
+ // }
866
+ // if (!ok) return false;
867
+ // } else {
868
+ let ok = await cs.filterCheck(prep, f, c);
869
+ if (ok != true) {
870
+ return false;
871
+ }
872
+ // }
873
+ }
874
+ return true;
875
+ }
876
+
877
+ async excludeCodes(cset, path, vsSrc, filter, expansion, excludeInactive, notClosed) {
878
+ this.worker.deadCheck('processCodes#1');
879
+ const valueSets = [];
880
+
881
+ Extensions.checkNoModifiers(cset, 'ValueSetExpander.processCodes', 'set');
882
+
883
+ if (cset.valueSet || cset.concept || (cset.filter || []).length > 1) {
884
+ this.canBeHierarchy = false;
885
+ }
886
+
887
+ if (!cset.system) {
888
+ if (cset.valueSet) {
889
+ this.noTotal();
890
+ for (const u of cset.valueSet) {
891
+ const s = this.worker.pinValueSet(u);
892
+ this.worker.deadCheck('processCodes#2');
893
+ const ivs = new ImportedValueSet(await this.expandValueSet(s, '', filter, notClosed));
894
+ this.checkResourceCanonicalStatus(expansion, ivs.valueSet, this.valueSet);
895
+ this.addParamUri(expansion, 'used-valueset', ivs.valueSet.vurl);
896
+ valueSets.push(ivs);
897
+ }
898
+ this.excludeValueSet(valueSets[0].valueSet, expansion, valueSets, 1);
899
+ }
900
+ } else {
901
+ const filters = [];
902
+ const prep = null;
903
+ const cs = await this.worker.findCodeSystem(cset.system, cset.version, this.params, ['complete', 'fragment'], false, true, true, null);
904
+
905
+ this.worker.checkSupplements(cs, cset, this.requiredSupplements);
906
+ this.checkResourceCanonicalStatus(expansion, cs, this.valueSet);
907
+ const sv = this.canonical(await cs.system(), await cs.version());
908
+ this.addParamUri(expansion, 'used-codesystem', sv);
909
+
910
+ for (const u of cset.valueSet || []) {
911
+ const s = this.pinValueSet(u);
912
+ this.worker.deadCheck('processCodes#3');
913
+ let f = null;
914
+ const vs = this.onGetValueSet(this, s, '');
915
+ if (vs != null) {
916
+ f = this.makeFilterForValueSet(cs, vs);
917
+ }
918
+ if (f != null) {
919
+ filters.push(f);
920
+ } else {
921
+ valueSets.push(new ImportedValueSet(await this.expandValueSet(s, '', filter, notClosed)));
922
+ }
923
+ }
924
+
925
+ if (!cset.concept && !cset.filter) {
926
+ this.opContext.log('handle system');
927
+ if (cs.specialEnumeration() && this.params.limitedExpansion && filters.length === 0) {
928
+ const base = await this.expandValueSet(cs.specialEnumeration(), '', filter, notClosed);
929
+ Extensions.addBoolean(expansion, 'http://hl7.org/fhir/StructureDefinition/valueset-toocostly', true);
930
+ this.excludeValueSet(base, expansion, valueSets, 0);
931
+ notClosed.value = true;
932
+ } else if (filter.isNull) {
933
+ if (cs.isNotClosed(filter)) {
934
+ if (cs.specialEnumeration()) {
935
+ throw new Issue("error", "too-costly", null, null, 'The code System "' + cs.system() + '" has a grammar, and cannot be enumerated directly. If an incomplete expansion is requested, a limited enumeration will be returned', null, 400).withDiagnostics(this.worker.opContext.diagnostics());
936
+ } else {
937
+ throw new Issue("error", "too-costly", null, null, 'The code System "' + cs.system + '" has a grammar, and cannot be enumerated directly', null, 400).withDiagnostics(this.worker.opContext.diagnostics());
938
+ }
939
+ }
940
+
941
+ const iter = await cs.getIterator(null);
942
+ if (valueSets.length === 0 && this.limitCount > 0 && iter.count > this.limitCount && !this.params.limitedExpansion) {
943
+ throw new Issue("error", "too-costly", null, 'VALUESET_TOO_COSTLY', this.worker.i18n.translate('VALUESET_TOO_COSTLY', this.params.httpLanguages, [vsSrc.url, '>' + this.limitCount]), null, 400).withDiagnostics(this.worker.opContext.diagnostics());
944
+ }
945
+ while (iter.more()) {
946
+ this.worker.deadCheck('processCodes#3a');
947
+ const c = await cs.getNextContext(iter);
948
+ if (await this.passesFilters(cs, c, prep, filters, 0)) {
949
+ await this.excludeCodeAndDescendants(cs, c, expansion, valueSets, excludeInactive, vsSrc.url);
950
+ }
951
+ }
952
+ } else {
953
+ this.noTotal();
954
+ if (cs.isNotClosed(filter)) {
955
+ notClosed.value = true;
956
+ }
957
+ const prep = await cs.getPrepContext(true);
958
+ const ctxt = await cs.searchFilter(filter, prep, false);
959
+ await cs.prepare(prep);
960
+ while (await cs.filterMore(ctxt)) {
961
+ this.worker.deadCheck('processCodes#4');
962
+ const c = await cs.filterConcept(ctxt);
963
+ if (await this.passesFilters(cs, c, prep, filters, 0)) {
964
+ this.excludeCode(cs, await cs.system(), await cs.version(), await cs.code(c), expansion, valueSets, vsSrc.url);
965
+ }
966
+ }
967
+ }
968
+ }
969
+
970
+ if (cset.concept) {
971
+ this.worker.opContext.log('iterate concepts');
972
+ const cds = new Designations(this.worker.i18n.languageDefinitions);
973
+ for (const cc of cset.concept) {
974
+ this.worker.deadCheck('processCodes#3');
975
+ cds.clear();
976
+ Extensions.checkNoModifiers(cc, 'ValueSetExpander.processCodes', 'set concept reference');
977
+ const cctxt = await cs.locate(cc.code, this.allAltCodes);
978
+ if (cctxt && cctxt.context && (!this.params.activeOnly || !await cs.isInactive(cctxt)) && await this.passesFilters(cs, cctxt, prep, filters, 0)) {
979
+ if (filter.passesDesignations(cds) || filter.passes(cc.code)) {
980
+ let ov = Extensions.readString(cc, 'http://hl7.org/fhir/StructureDefinition/itemWeight');
981
+ if (!ov) {
982
+ ov = await cs.itemWeight(cctxt.context);
983
+ }
984
+ this.excludeCode(cs, await cs.system(), await cs.version(), cc.code, expansion, valueSets, vsSrc.url);
985
+ }
986
+ }
987
+ }
988
+ }
989
+
990
+ if (cset.filter) {
991
+ this.worker.opContext.log('prep filters');
992
+ const prep = await cs.getPrepContext(true);
993
+ if (!filter.isNull) {
994
+ await cs.searchFilter(filter, prep, true);
995
+ }
996
+
997
+ if (cs.specialEnumeration()) {
998
+ await cs.specialFilter(prep, true);
999
+ Extensions.addBoolean(expansion, 'http://hl7.org/fhir/StructureDefinition/valueset-toocostly', true);
1000
+ notClosed.value = true;
1001
+ }
1002
+
1003
+ for (let fc of cset.filter) {
1004
+ this.worker.deadCheck('processCodes#4a');
1005
+ Extensions.checkNoModifiers(fc, 'ValueSetExpander.processCodes', 'filter');
1006
+ await cs.filter(prep, fc.property, fc.op, fc.value);
1007
+ }
1008
+
1009
+ this.worker.opContext.log('iterate filters');
1010
+ const fset = await cs.executeFilters(prep);
1011
+ if (await cs.filtersNotClosed(prep)) {
1012
+ notClosed.value = true;
1013
+ }
1014
+ //let count = 0;
1015
+ while (await cs.filterMore(prep, fset[0])) {
1016
+ this.worker.deadCheck('processCodes#5');
1017
+ const c = await cs.filterConcept(prep, fset[0]);
1018
+ const ok = (!this.params.activeOnly || !await cs.isInactive(c)) && (await this.passesFilters(cs, c, prep, fset, 1));
1019
+ if (ok) {
1020
+ //count++;
1021
+ if (this.passesImports(valueSets, await cs.system(), await cs.code(c), 0)) {
1022
+ this.excludeCode(cs, await cs.system(), await cs.version(), await cs.code(c), expansion, null, vsSrc.url);
1023
+ }
1024
+ }
1025
+ }
1026
+ this.worker.opContext.log('iterate filters finished');
1027
+ }
1028
+ }
1029
+ }
1030
+
1031
+ async includeCodeAndDescendants(cs, context, expansion, imports, parent, excludeInactive, srcUrl) {
1032
+ let result = 0;
1033
+ this.worker.deadCheck('processCodeAndDescendants');
1034
+
1035
+ if (expansion) {
1036
+ const vs = this.canonical(await cs.system(), await cs.version());
1037
+ this.addParamUri(expansion, 'used-codesystem', vs);
1038
+ const ts = cs.listSupplements();
1039
+ for (const v of ts) {
1040
+ this.worker.deadCheck('processCodeAndDescendants');
1041
+ this.addParamUri(expansion, 'used-supplement', v);
1042
+ }
1043
+ }
1044
+
1045
+ let n = null;
1046
+ if ((!this.params.excludeNotForUI || !await cs.isAbstract(context)) && (!this.params.activeOnly || !await cs.isInactive(context))) {
1047
+ const cds = new Designations(this.worker.i18n.languageDefinitions);
1048
+ await this.listDisplaysFromProvider(cds, cs, context);
1049
+ const t = await this.includeCode(cs, parent, await cs.system(), await cs.version(), context.code, await cs.isAbstract(context), await cs.isInactive(context), await cs.isDeprecated(context), await cs.getStatus(context), cds, await cs.definition(context),
1050
+ await cs.itemWeight(context), expansion, imports, await cs.extensions(context), null, await cs.properties(context), null, excludeInactive, srcUrl);
1051
+ if (t != null) {
1052
+ result++;
1053
+ }
1054
+ if (n == null) {
1055
+ n = t;
1056
+ }
1057
+ } else {
1058
+ n = parent;
1059
+ }
1060
+
1061
+ const iter = await cs.iterator(context);
1062
+ if (iter) {
1063
+ let c = await cs.nextContext(iter);
1064
+ while (c) {
1065
+ this.worker.deadCheck('processCodeAndDescendants#3');
1066
+ result += await this.includeCodeAndDescendants(cs, c, expansion, imports, n, excludeInactive, srcUrl);
1067
+ c = await cs.nextContext(iter);
1068
+ }
1069
+ }
1070
+ return result;
1071
+ }
1072
+
1073
+ async excludeCodeAndDescendants(cs, context, expansion, imports, excludeInactive, srcUrl) {
1074
+ this.worker.deadCheck('processCodeAndDescendants');
1075
+
1076
+ if (expansion) {
1077
+ const vs = this.canonical(await cs.system(), await cs.version());
1078
+ this.addParamUri(expansion, 'used-codesystem', vs);
1079
+ const ts= cs.listSupplements();
1080
+ for (const v of ts) {
1081
+ this.worker.deadCheck('processCodeAndDescendants');
1082
+ this.addParamUri(expansion, 'used-supplement', v);
1083
+ }
1084
+ }
1085
+
1086
+ if ((!this.params.excludeNotForUI || !await cs.isAbstract(context)) && (!this.params.activeOnly || !await cs.isInactive(context))) {
1087
+ const cds = new Designations(this.worker.i18n.languageDefinitions);
1088
+ await this.listDisplaysFromProvider(cds, cs, context);
1089
+ for (const code of await cs.listCodes(context, this.params.altCodeRules)) {
1090
+ this.worker.deadCheck('processCodeAndDescendants#2');
1091
+ this.excludeCode(cs, await cs.system(), await cs.version(), code, expansion, imports, srcUrl);
1092
+ }
1093
+ }
1094
+
1095
+ const iter = await cs.getIterator(context);
1096
+ while (iter.more()) {
1097
+ this.worker.deadCheck('processCodeAndDescendants#3');
1098
+ const c = await cs.getNextContext(iter);
1099
+ await this.excludeCodeAndDescendants(cs, c, expansion, imports, excludeInactive, srcUrl);
1100
+ }
1101
+ }
1102
+
1103
+ async handleCompose(source, filter, expansion, notClosed) {
1104
+ this.worker.opContext.log('compose #1');
1105
+
1106
+ const ts = new Map();
1107
+ for (const c of source.jsonObj.compose.include || []) {
1108
+ this.worker.deadCheck('handleCompose#2');
1109
+ await this.checkSource(c, expansion, filter, source.url, ts);
1110
+ }
1111
+ for (const c of source.jsonObj.compose.exclude || []) {
1112
+ this.worker.deadCheck('handleCompose#3');
1113
+ this.hasExclusions = true;
1114
+ await this.checkSource(c, expansion, filter, source.url, ts);
1115
+ }
1116
+
1117
+ this.worker.opContext.log('compose #2');
1118
+
1119
+ let i = 0;
1120
+ for (const c of source.jsonObj.compose.exclude || []) {
1121
+ this.worker.deadCheck('handleCompose#4');
1122
+ await this.excludeCodes(c, "ValueSet.compose.exclude["+i+"]", source, filter, expansion, this.excludeInactives(source), notClosed);
1123
+ }
1124
+
1125
+ i = 0;
1126
+ for (const c of source.jsonObj.compose.include || []) {
1127
+ this.worker.deadCheck('handleCompose#5');
1128
+ await this.includeCodes(c, "ValueSet.compose.include["+i+"]", source, filter, expansion, this.excludeInactives(source), notClosed);
1129
+ i++;
1130
+ }
1131
+ }
1132
+
1133
+ excludeInactives(source) {
1134
+ return source.jsonObj.compose && source.jsonObj.compose.inactive != undefined && !source.jsonObj.compose.inactive;
1135
+ }
1136
+
1137
+ async expand(source, filter, noCacheThisOne) {
1138
+ this.noCacheThisOne = noCacheThisOne;
1139
+ this.totalStatus = 'uninitialised';
1140
+ this.total = 0;
1141
+
1142
+ Extensions.checkNoImplicitRules(source,'ValueSetExpander.Expand', 'ValueSet');
1143
+ Extensions.checkNoModifiers(source,'ValueSetExpander.Expand', 'ValueSet');
1144
+ this.worker.seeValueSet(source, this.params);
1145
+ this.valueSet = source;
1146
+
1147
+ const result = structuredClone(source.jsonObj);
1148
+ result.id = '';
1149
+ let table = null;
1150
+ let div_ = null;
1151
+
1152
+ if (!this.params.includeDefinition) {
1153
+ result.purpose = undefined;
1154
+ result.compose = undefined;
1155
+ result.description = undefined;
1156
+ result.contactList = undefined;
1157
+ result.copyright = undefined;
1158
+ result.publisher = undefined;
1159
+ result.extension = undefined;
1160
+ result.text = undefined;
1161
+ }
1162
+
1163
+ this.requiredSupplements = [];
1164
+ for (const ext of Extensions.list(source.jsonObj, 'http://hl7.org/fhir/StructureDefinition/valueset-supplement')) {
1165
+ this.requiredSupplements.push(getValuePrimitive(ext));
1166
+ }
1167
+
1168
+ if (result.expansion) {
1169
+ return result; // just return the expansion
1170
+ }
1171
+
1172
+ if (this.params.generateNarrative) {
1173
+ div_ = div();
1174
+ table = div_.table("grid");
1175
+ } else {
1176
+ result.text = undefined;
1177
+ }
1178
+
1179
+ this.map = new Map();
1180
+ this.rootList = [];
1181
+ this.fullList = [];
1182
+ this.canBeHierarchy = !this.params.excludeNested;
1183
+
1184
+ this.limitCount = INTERNAL_LIMIT;
1185
+ if (this.params.limit <= 0) {
1186
+ if (!filter.isNull) {
1187
+ this.limitCount = UPPER_LIMIT_TEXT;
1188
+ } else {
1189
+ this.limitCount = UPPER_LIMIT_NO_TEXT;
1190
+ }
1191
+ }
1192
+ this.offset = this.params.offset;
1193
+ this.count = this.params.count;
1194
+
1195
+ if (this.params.offset > 0) {
1196
+ this.canBeHierarchy = false;
1197
+ }
1198
+
1199
+ const exp = {};
1200
+ exp.timestamp = new Date().toISOString();
1201
+ exp.identifier = 'urn:uuid:' + crypto.randomUUID();
1202
+ result.expansion = exp;
1203
+
1204
+ if (!filter.isNull) {
1205
+ this.addParamStr(exp, 'filter', filter.filter);
1206
+ }
1207
+
1208
+ if (this.params.hasLimitedExpansion) {
1209
+ this.addParamBool(exp, 'limitedExpansion', this.params.limitedExpansion);
1210
+ }
1211
+ if (this.params.DisplayLanguages) {
1212
+ this.addParamCode(exp, 'displayLanguage', this.params.DisplayLanguages.asString(true));
1213
+ } else if (this.params.HTTPLanguages) {
1214
+ this.addParamCode(exp, 'displayLanguage', this.params.HTTPLanguages.asString(true));
1215
+ }
1216
+ if (this.params.designations) {
1217
+ for (const s of this.params.designations) {
1218
+ this.addParamStr(exp, 'designation', s);
1219
+ }
1220
+ }
1221
+ if (this.params.hasExcludeNested) {
1222
+ this.addParamBool(exp, 'excludeNested', this.params.excludeNested);
1223
+ }
1224
+ if (this.params.hasActiveOnly) {
1225
+ this.addParamBool(exp, 'activeOnly', this.params.activeOnly);
1226
+ }
1227
+ if (this.params.hasIncludeDesignations) {
1228
+ this.addParamBool(exp, 'includeDesignations', this.params.includeDesignations);
1229
+ }
1230
+ if (this.params.hasIncludeDefinition) {
1231
+ this.addParamBool(exp, 'includeDefinition', this.params.includeDefinition);
1232
+ }
1233
+ if (this.params.hasExcludeNotForUI) {
1234
+ this.addParamBool(exp, 'excludeNotForUI', this.params.excludeNotForUI);
1235
+ }
1236
+ if (this.params.hasExcludePostCoordinated) {
1237
+ this.addParamBool(exp, 'excludePostCoordinated', this.params.excludePostCoordinated);
1238
+ }
1239
+
1240
+ this.checkResourceCanonicalStatus(exp, source, source);
1241
+
1242
+ if (this.offset > -1) {
1243
+ this.addParamInt(exp,'offset', this.offset);
1244
+ exp.offset = this.offset;
1245
+ }
1246
+ if (this.count > -1) {
1247
+ this.addParamInt(exp, 'count', this.count);
1248
+ }
1249
+ if (this.count > 0 && this.offset === -1) {
1250
+ this.offset = 0;
1251
+ }
1252
+
1253
+ this.worker.opContext.log('start working');
1254
+ this.worker.deadCheck('expand');
1255
+
1256
+ let notClosed = { value : false};
1257
+
1258
+ try {
1259
+ if (source.jsonObj.compose && Extensions.checkNoModifiers(source.jsonObj.compose, 'ValueSetExpander.Expand', 'compose')) {
1260
+ await this.handleCompose(source, filter, exp, notClosed);
1261
+ }
1262
+
1263
+ if (this.requiredSupplements.length > 0) {
1264
+ throw new Issue('error', 'not-found', null, 'VALUESET_SUPPLEMENT_MISSING', this.worker.opContext.i18n.translatePlural(this.requiredSupplements.length, 'VALUESET_SUPPLEMENT_MISSING', this.params.httpLanguages, [this.requiredSupplements.join(', ')]), 'not-found', 400);
1265
+ }
1266
+ } catch (e) {
1267
+ if (e instanceof Issue) {
1268
+ if (e.finished) {
1269
+ // nothing - we're just trapping this
1270
+ if (this.totalStatus === 'uninitialised') {
1271
+ this.totalStatus = 'off';
1272
+ } else if (e.toocostly) {
1273
+ if (this.params.limitedExpansion) {
1274
+ Extensions.addBoolean(exp, 'http://hl7.org/fhir/StructureDefinition/valueset-toocostly', 'value', true);
1275
+ if (table != null) {
1276
+ div_.p().style('color: Maroon').tx(e.message);
1277
+ }
1278
+ } else {
1279
+ throw e;
1280
+ }
1281
+ } else {
1282
+ // nothing- swallow it
1283
+ }
1284
+ } else {
1285
+ throw e;
1286
+ }
1287
+ } else {
1288
+ throw e;
1289
+ }
1290
+ }
1291
+
1292
+ this.worker.opContext.log('finish up');
1293
+
1294
+ let list;
1295
+ if (notClosed.value) {
1296
+ Extensions.addBoolean(exp, 'http://hl7.org/fhir/StructureDefinition/valueset-unclosed', true);
1297
+ list = this.fullList;
1298
+ for (const c of this.fullList) {
1299
+ c.contains = undefined;
1300
+ }
1301
+ if (table != null) {
1302
+ div_.addTag('p').setAttribute('style', 'color: Navy').tx('Because of the way that this value set is defined, not all the possible codes can be listed in advance');
1303
+ }
1304
+ } else {
1305
+ if (this.totalStatus === 'off' || this.total === -1) {
1306
+ this.canBeHierarchy = false;
1307
+ } else if (this.total > 0) {
1308
+ exp.total = this.total;
1309
+ } else {
1310
+ exp.total = this.fullList.length;
1311
+ }
1312
+
1313
+ if (this.canBeHierarchy && (this.count <= 0 || this.count > this.fullList.length)) {
1314
+ list = this.rootList;
1315
+ } else {
1316
+ list = this.fullList;
1317
+ for (const c of this.fullList) {
1318
+ c.contains = undefined;
1319
+ }
1320
+ }
1321
+ }
1322
+
1323
+ if (this.offset + this.count < 0 && this.fullList.length > this.limit) {
1324
+ this.log.log('Operation took too long @ expand (' + this.constructor.name + ')');
1325
+ throw new Issue("error", "too-costly", null, 'VALUESET_TOO_COSTLY', this.worker.i18n.translate('VALUESET_TOO_COSTLY', this.params.httpLanguages, [source.vurl, '>' + this.limit]), null, 400).withDiagnostics(this.worker.opContext.diagnostics());
1326
+ } else {
1327
+ let t = 0;
1328
+ let o = 0;
1329
+ for (let i = 0; i < list.length; i++) {
1330
+ this.worker.deadCheck('expand#1');
1331
+ const c = list[i];
1332
+ if (this.map.has(this.keyC(c))) {
1333
+ o++;
1334
+ if (o > this.offset && (this.count <= 0 || t < this.count)) {
1335
+ t++;
1336
+ if (!exp.contains) {
1337
+ exp.contains = [];
1338
+ }
1339
+ exp.contains.push(c);
1340
+ if (table != null) {
1341
+ const tr = table.tr();
1342
+ tr.td().tx(c.system);
1343
+ tr.td().tx(c.code);
1344
+ tr.td().tx(c.display);
1345
+ }
1346
+ }
1347
+ }
1348
+ }
1349
+ }
1350
+
1351
+ for (const s of this.worker.foundParameters) {
1352
+ const [l, r] = s.split('=');
1353
+ if (r != source.vurl) {
1354
+ this.addParamUri(exp, l, r);
1355
+ }
1356
+ }
1357
+
1358
+ return result;
1359
+ }
1360
+
1361
+ checkResourceCanonicalStatus(exp, resource, source) {
1362
+ if (resource.jsonObj) {
1363
+ resource = resource.jsonObj;
1364
+ }
1365
+ this.checkCanonicalStatus(exp, this.worker.makeVurl(resource), resource.status, Extensions.readString(resource, 'http://hl7.org/fhir/StructureDefinition/structuredefinition-standards-status'), resource.experimental, source);
1366
+ }
1367
+
1368
+ checkProviderCanonicalStatus(exp, cs, source) {
1369
+ let status = cs.status();
1370
+ this.checkCanonicalStatus(exp, cs.vurl(), status.status, status.standardsStatus, status.experimental, source);
1371
+ }
1372
+
1373
+ checkCanonicalStatus(exp, vurl, status, standardsStatus, experimental, source) {
1374
+ if (standardsStatus == 'deprecated') {
1375
+ this.addParamUri(exp, 'warning-deprecated', vurl);
1376
+ } else if (standardsStatus == 'withdrawn') {
1377
+ this.addParamUri(exp, 'warning-withdrawn', vurl);
1378
+ } else if (status == 'retired') {
1379
+ this.addParamUri(exp, 'warning-retired', vurl);
1380
+ } else if (experimental && !source.experimental) {
1381
+ this.addParamUri(exp, 'warning-experimental', vurl)
1382
+ } else if (((status == 'draft') || (standardsStatus == 'draft')) &&
1383
+ !((source.status == 'draft') || (Extensions.readString(source, 'http://hl7.org/fhir/StructureDefinition/structuredefinition-standards-status') == 'draft'))) {
1384
+ this.addParamUri(exp, 'warning-draft', vurl)
1385
+ }
1386
+ }
1387
+
1388
+ addParamStr(exp, name, value) {
1389
+ if (!this.hasParam(exp, name, value)) {
1390
+ if (!exp.parameter) {
1391
+ exp.parameter = [];
1392
+ }
1393
+ exp.parameter.push({name: name, valueString: value});
1394
+ }
1395
+ }
1396
+
1397
+ addParamBool(exp, name, value) {
1398
+ if (!this.hasParam(exp, name, value)) {
1399
+ if (!exp.parameter) {
1400
+ exp.parameter = [];
1401
+ }
1402
+ exp.parameter.push({name: name, valueBoolean: value});
1403
+ }
1404
+ }
1405
+
1406
+ addParamCode(exp, name, value) {
1407
+ if (!this.hasParam(exp, name, value)) {
1408
+ if (!exp.parameter) {
1409
+ exp.parameter = [];
1410
+ }
1411
+ exp.parameter.push({name: name, valueCode: value});
1412
+ }
1413
+ }
1414
+
1415
+ addParamInt(exp, name, value) {
1416
+ if (!this.hasParam(exp, name, value)) {
1417
+ if (!exp.parameter) {
1418
+ exp.parameter = [];
1419
+ }
1420
+ exp.parameter.push({name: name, valueInteger: value});
1421
+ }
1422
+ }
1423
+
1424
+ addParamUri(exp, name, value) {
1425
+ if (!this.hasParam(exp, name, value)) {
1426
+ if (!exp.parameter) {
1427
+ exp.parameter = [];
1428
+ }
1429
+ exp.parameter.push({name: name, valueUri: value});
1430
+ }
1431
+ }
1432
+
1433
+ addParam(exp, name, valueName, value) {
1434
+ if (!this.hasParam(exp, name, value)) {
1435
+ if (!exp.parameter) {
1436
+ exp.parameter = [];
1437
+ }
1438
+ let p = {name: name}
1439
+ exp.parameter.push(p);
1440
+ p[valueName] = value;
1441
+ }
1442
+ }
1443
+
1444
+
1445
+ hasParam(exp, name, value) {
1446
+ return (exp.parameter || []).find((ex => ex.name == name && getValuePrimitive(ex) == value));
1447
+ }
1448
+
1449
+ isExcluded(system, version, code) {
1450
+ return this.excluded.has(system+'|'+version+'#'+code);
1451
+ }
1452
+
1453
+ keyS(system, version, code) {
1454
+ return system+"~"+(this.doingVersion ? version+"~" : "")+code;
1455
+ }
1456
+
1457
+ keyC(contains) {
1458
+ return this.keyS(contains.system, contains.version, contains.code);
1459
+ }
1460
+
1461
+ defineProperty(expansion, contains, url, code, valueName, value) {
1462
+ if (value === undefined || value == null) {
1463
+ return;
1464
+ }
1465
+ if (!expansion.property) {
1466
+ expansion.property = [];
1467
+ }
1468
+ let pd = expansion.property.find(t1 => t1.uri == url || t1.code == code);
1469
+ if (!pd) {
1470
+ pd = {};
1471
+ expansion.property.push(pd);
1472
+ pd.uri = url;
1473
+ pd.code = code;
1474
+ } else if (!pd.uri) {
1475
+ pd.uri = url
1476
+ }
1477
+ if (pd.uri != url) {
1478
+ throw new Error('URL mismatch on expansion: ' + pd.uri + ' vs ' + url + ' for code ' + code);
1479
+ } else {
1480
+ code = pd.code;
1481
+ }
1482
+
1483
+ if (!contains.property) {
1484
+ contains.property = [];
1485
+ }
1486
+ let pdv = contains.property.find(t2 => t2.code == code);
1487
+ if (!pdv) {
1488
+ pdv = {};
1489
+ contains.property.push(pdv);
1490
+ pdv.code = code;
1491
+ }
1492
+ pdv[valueName] = value;
1493
+ }
1494
+
1495
+ addToTotal(t) {
1496
+ if (this.total > -1 && this.totalStatus != "off") {
1497
+ this.total = this.total + t;
1498
+ this.totalStatus = 'set';
1499
+ }
1500
+ }
1501
+
1502
+ noTotal() {
1503
+ this.total = -1;
1504
+ this.totalStatus = 'off';
1505
+ }
1506
+
1507
+ getPropUrl(cs, pn) {
1508
+ for (let p of cs.propertyDefinitions()) {
1509
+ if (pn == p.code) {
1510
+ return p.uri;
1511
+ }
1512
+ }
1513
+ return undefined;
1514
+ }
1515
+
1516
+
1517
+ }
1518
+
1519
+ class ExpandWorker extends TerminologyWorker {
1520
+ /**
1521
+ * @param {OperationContext} opContext - Operation context
1522
+ * @param {Logger} log - Logger instance
1523
+ * @param {Provider} provider - Provider for code systems and resources
1524
+ * @param {LanguageDefinitions} languages - Language definitions
1525
+ * @param {I18nSupport} i18n - Internationalization support
1526
+ */
1527
+ constructor(opContext, log, provider, languages, i18n) {
1528
+ super(opContext, log, provider, languages, i18n);
1529
+ }
1530
+
1531
+ /**
1532
+ * Get operation name
1533
+ * @returns {string}
1534
+ */
1535
+ opName() {
1536
+ return 'expand';
1537
+ }
1538
+
1539
+ /**
1540
+ * Handle a type-level $expand request
1541
+ * GET/POST /ValueSet/$expand
1542
+ * @param {express.Request} req - Express request
1543
+ * @param {express.Response} res - Express response
1544
+ */
1545
+ async handle(req, res) {
1546
+ try {
1547
+ await this.handleTypeLevelExpand(req, res);
1548
+ } catch (error) {
1549
+ req.logInfo = this.usedSources.join("|")+" - error"+(error.msgId ? " "+error.msgId : "");
1550
+ this.log.error(error);
1551
+ const statusCode = error.statusCode || 500;
1552
+ if (error instanceof Issue) {
1553
+ let oo = new OperationOutcome();
1554
+ oo.addIssue(error);
1555
+ return res.status(error.statusCode || 500).json(this.fixForVersion(oo.jsonObj));
1556
+ } else {
1557
+ const issueCode = error.issueCode || 'exception';
1558
+ return res.status(statusCode).json(this.fixForVersion({
1559
+ resourceType: 'OperationOutcome',
1560
+ issue: [{
1561
+ severity: 'error',
1562
+ code: issueCode,
1563
+ details: {
1564
+ text: error.message
1565
+ },
1566
+ diagnostics: error.message
1567
+ }]
1568
+ }));
1569
+ }
1570
+ }
1571
+ }
1572
+
1573
+ /**
1574
+ * Handle an instance-level $expand request
1575
+ * GET/POST /ValueSet/{id}/$expand
1576
+ * @param {express.Request} req - Express request
1577
+ * @param {express.Response} res - Express response
1578
+ */
1579
+ async handleInstance(req, res) {
1580
+ try {
1581
+ await this.handleInstanceLevelExpand(req, res);
1582
+ } catch (error) {
1583
+ req.logInfo = this.usedSources.join("|")+" - error"+(error.msgId ? " "+error.msgId : "");
1584
+ this.log.error(error);
1585
+ const statusCode = error.statusCode || 500;
1586
+ const issueCode = error.issueCode || 'exception';
1587
+ return res.status(statusCode).json(this.fixForVersion({
1588
+ resourceType: 'OperationOutcome',
1589
+ issue: [{
1590
+ severity: 'error',
1591
+ code: issueCode,
1592
+ details: {
1593
+ text : error.message
1594
+ },
1595
+ diagnostics: error.message
1596
+ }]
1597
+ }));
1598
+ }
1599
+ }
1600
+
1601
+ /**
1602
+ * Handle type-level expand: /ValueSet/$expand
1603
+ * ValueSet identified by url, or provided directly in body
1604
+ */
1605
+ async handleTypeLevelExpand(req, res) {
1606
+ this.deadCheck('expand-type-level');
1607
+
1608
+ // Determine how the request is structured
1609
+ let valueSet = null;
1610
+ let params = null;
1611
+
1612
+ if (req.method === 'POST' && req.body) {
1613
+ if (req.body.resourceType === 'ValueSet') {
1614
+ // Body is directly a ValueSet resource
1615
+ valueSet = new ValueSet(req.body);
1616
+ params = this.queryToParameters(req.query);
1617
+ this.seeSourceVS(valueSet);
1618
+
1619
+ } else if (req.body.resourceType === 'Parameters') {
1620
+ // Body is a Parameters resource
1621
+ params = req.body;
1622
+
1623
+ // Check for valueSet parameter
1624
+ const valueSetParam = this.findParameter(params, 'valueSet');
1625
+ if (valueSetParam && valueSetParam.resource) {
1626
+ valueSet = new ValueSet(valueSetParam.resource);
1627
+ this.seeSourceVS(valueSet);
1628
+ }
1629
+
1630
+ } else {
1631
+ // Assume form body - convert to Parameters
1632
+ params = this.formToParameters(req.body, req.query);
1633
+ }
1634
+ } else {
1635
+ // GET request - convert query to Parameters
1636
+ params = this.queryToParameters(req.query);
1637
+ }
1638
+ this.addHttpParams(req, params);
1639
+
1640
+ // Check for context parameter - not supported yet
1641
+ const contextParam = this.findParameter(params, 'context');
1642
+ if (contextParam) {
1643
+ return res.status(400).json(this.operationOutcome('error', 'not-supported',
1644
+ 'The context parameter is not yet supported'));
1645
+ }
1646
+
1647
+ // Handle tx-resource and cache-id parameters
1648
+ this.setupAdditionalResources(params);
1649
+ const logExtraOutput = this.findParameter(params, 'logExtraOutput');
1650
+
1651
+ let txp = new TxParameters(this.opContext.i18n.languageDefinitions, this.opContext.i18n, false);
1652
+ txp.readParams(params);
1653
+
1654
+ // If no valueSet yet, try to find by url
1655
+ if (!valueSet) {
1656
+ const urlParam = this.findParameter(params, 'url');
1657
+ const versionParam = this.findParameter(params, 'valueSetVersion');
1658
+
1659
+ if (!urlParam) {
1660
+ return res.status(400).json(this.operationOutcome('error', 'invalid',
1661
+ 'Must provide either a ValueSet resource or a url parameter'));
1662
+ }
1663
+
1664
+ const url = this.getParameterValue(urlParam);
1665
+ const version = versionParam ? this.getParameterValue(versionParam) : null;
1666
+
1667
+ valueSet = await this.findValueSet(url, version);
1668
+ this.seeSourceVS(valueSet, url);
1669
+ if (!valueSet) {
1670
+ return res.status(404).json(this.operationOutcome('error', 'not-found',
1671
+ version ? `ValueSet not found: ${url} version ${version}` : `ValueSet not found: ${url}`));
1672
+ }
1673
+ }
1674
+
1675
+ // Perform the expansion
1676
+ const result = await this.doExpand(valueSet, txp, logExtraOutput);
1677
+ req.logInfo = this.usedSources.join("|")+txp.logInfo();
1678
+ return res.json(this.fixForVersion(result));
1679
+ }
1680
+
1681
+ /**
1682
+ * Handle instance-level expand: /ValueSet/{id}/$expand
1683
+ * ValueSet identified by resource ID
1684
+ */
1685
+ async handleInstanceLevelExpand(req, res) {
1686
+ this.deadCheck('expand-instance-level');
1687
+
1688
+ const { id } = req.params;
1689
+
1690
+ // Find the ValueSet by ID
1691
+ const valueSet = await this.provider.getValueSetById(this.opContext, id);
1692
+
1693
+ if (!valueSet) {
1694
+ return res.status(404).json(this.operationOutcome('error', 'not-found',
1695
+ `ValueSet/${id} not found`));
1696
+ }
1697
+
1698
+ // Parse parameters
1699
+ let params;
1700
+ if (req.method === 'POST' && req.body) {
1701
+ if (req.body.resourceType === 'Parameters') {
1702
+ params = req.body;
1703
+ } else {
1704
+ // Form body
1705
+ params = this.formToParameters(req.body, req.query);
1706
+ }
1707
+ } else {
1708
+ params = this.queryToParameters(req.query);
1709
+ }
1710
+
1711
+ // Check for context parameter - not supported yet
1712
+ const contextParam = this.findParameter(params, 'context');
1713
+ if (contextParam) {
1714
+ return res.status(400).json(this.operationOutcome('error', 'not-supported',
1715
+ 'The context parameter is not yet supported'));
1716
+ }
1717
+
1718
+ // Handle tx-resource and cache-id parameters
1719
+ this.setupAdditionalResources(params);
1720
+ const logExtraOutput = this.findParameter(params, 'logExtraOutput');
1721
+
1722
+ let txp = new TxParameters(this.opContext.i18n.languageDefinitions, this.opContext.i18n, false);
1723
+ txp.readParams(params);
1724
+
1725
+ // Perform the expansion
1726
+ const result = await this.doExpand(valueSet, txp, logExtraOutput);
1727
+ req.logInfo = this.usedSources.join("|")+txp.logInfo();
1728
+ return res.json(this.fixForVersion(result));
1729
+ }
1730
+
1731
+ // Note: setupAdditionalResources, queryToParameters, formToParameters,
1732
+ // findParameter, getParameterValue, and wrapRawResource are inherited
1733
+ // from TerminologyWorker base class
1734
+
1735
+ /**
1736
+ * Perform the actual expansion operation
1737
+ * Uses expansion cache for expensive operations
1738
+ * @param {Object} valueSet - ValueSet resource to expand
1739
+ * @param {Object} params - Parameters resource with expansion options
1740
+ * @returns {Object} Expanded ValueSet resource
1741
+ */
1742
+ async doExpand(valueSet, params, logExtraOutput) {
1743
+ this.deadCheck('doExpand');
1744
+
1745
+ const expansionCache = this.opContext.expansionCache;
1746
+ // Compute cache key (only if caching is available and not debugging)
1747
+ let cacheKey = null;
1748
+ if (expansionCache && (CACHE_WHEN_DEBUGGING || !this.opContext.debugging)) {
1749
+ cacheKey = expansionCache.computeKey(valueSet, params, this.additionalResources);
1750
+
1751
+ // Check for cached expansion
1752
+ const cached = expansionCache.get(cacheKey);
1753
+ if (cached) {
1754
+ this.log.debug('Using cached expansion');
1755
+ return cached;
1756
+ }
1757
+ }
1758
+
1759
+ // Perform the actual expansion
1760
+ const startTime = performance.now();
1761
+ const result = await this.performExpansion(valueSet, params, logExtraOutput);
1762
+ const durationMs = performance.now() - startTime;
1763
+
1764
+ // Cache if it took long enough (and not debugging)
1765
+ if (cacheKey && expansionCache && (CACHE_WHEN_DEBUGGING || !this.opContext.debugging)) {
1766
+ const wasCached = expansionCache.set(cacheKey, result, durationMs);
1767
+ if (wasCached) {
1768
+ this.log.debug(`Cached expansion (took ${Math.round(durationMs)}ms)`);
1769
+ }
1770
+ }
1771
+
1772
+ return result;
1773
+ }
1774
+
1775
+ /**
1776
+ * Perform the actual expansion logic
1777
+ * @param {Object} valueSet - ValueSet resource to expand
1778
+ * @param {Object} params - Parameters resource with expansion options
1779
+ * @returns {Object} Expanded ValueSet resource
1780
+ */
1781
+ async performExpansion(valueSet, params, logExtraOutput) {
1782
+ this.deadCheck('performExpansion');
1783
+
1784
+ // Store params for worker methods
1785
+ this.params = params;
1786
+
1787
+ if (params.limit < -1) {
1788
+ params.limit = -1;
1789
+ } else if (params.limit > UPPER_LIMIT_TEXT) {
1790
+ params.limit = UPPER_LIMIT_TEXT; // can't ask for more than this externally, though you can internally
1791
+ }
1792
+
1793
+ const filter = new SearchFilterText(params.filter);
1794
+ //txResources = processAdditionalResources(context, manager, nil, params);
1795
+ // Create expander and run expansion
1796
+ const expander = new ValueSetExpander(this, params);
1797
+ expander.logExtraOutput = logExtraOutput;
1798
+ return await expander.expand(valueSet, filter);
1799
+ }
1800
+
1801
+ /**
1802
+ * Generate a UUID
1803
+ * @returns {string} UUID
1804
+ */
1805
+ generateUuid() {
1806
+ return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
1807
+ const r = Math.random() * 16 | 0;
1808
+ const v = c === 'x' ? r : (r & 0x3 | 0x8);
1809
+ return v.toString(16);
1810
+ });
1811
+ }
1812
+
1813
+ /**
1814
+ * Build an OperationOutcome
1815
+ * @param {string} severity - error, warning, information
1816
+ * @param {string} code - Issue code
1817
+ * @param {string} message - Diagnostic message
1818
+ * @returns {Object} OperationOutcome resource
1819
+ */
1820
+ operationOutcome(severity, code, message) {
1821
+ return {
1822
+ resourceType: 'OperationOutcome',
1823
+ issue: [{
1824
+ severity,
1825
+ code,
1826
+ diagnostics: message
1827
+ }]
1828
+ };
1829
+ }
1830
+
1831
+ }
1832
+
1833
+ module.exports = {
1834
+ ExpandWorker,
1835
+ ValueSetExpander,
1836
+ ValueSetCounter,
1837
+ ImportedValueSet,
1838
+ ValueSetFilterContext,
1839
+ EmptyFilterContext,
1840
+ TotalStatus,
1841
+ UPPER_LIMIT_NO_TEXT,
1842
+ UPPER_LIMIT_TEXT,
1843
+ INTERNAL_LIMIT,
1844
+ EXPANSION_DEAD_TIME_SECS
1845
+ };