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
package/tx/library.js ADDED
@@ -0,0 +1,676 @@
1
+ const fs = require('fs').promises;
2
+ const path = require('path');
3
+ const yaml = require('yaml'); // npm install yaml
4
+ const { PackageManager, PackageContentLoader } = require('../library/package-manager');
5
+ const { CodeSystem } = require("./library/codesystem");
6
+ const {CountryCodeFactoryProvider} = require("./cs/cs-country");
7
+ const {Iso4217FactoryProvider} = require("./cs/cs-currency");
8
+ const {AreaCodeFactoryProvider} = require("./cs/cs-areacode");
9
+ const {MimeTypeServicesFactory} = require("./cs/cs-mimetypes");
10
+ const {USStateFactoryProvider} = require("./cs/cs-usstates");
11
+ const {HGVSServicesFactory} = require("./cs/cs-hgvs");
12
+ const {UcumCodeSystemFactory} = require("./cs/cs-ucum");
13
+ const {UcumService} = require("./library/ucum-service");
14
+ const {readFileSync} = require("fs");
15
+ const https = require('https');
16
+ const http = require('http');
17
+ const {LoincServicesFactory} = require("./cs/cs-loinc");
18
+ const {RxNormServicesFactory} = require("./cs/cs-rxnorm");
19
+ const {NdcServicesFactory} = require("./cs/cs-ndc");
20
+ const {UniiServicesFactory} = require("./cs/cs-unii");
21
+ const {SnomedServicesFactory} = require("./cs/cs-snomed");
22
+ const {CPTServicesFactory} = require("./cs/cs-cpt");
23
+ const {OMOPServicesFactory} = require("./cs/cs-omop");
24
+ const {PackageValueSetProvider} = require("./vs/vs-package");
25
+ const {PackageConceptMapProvider} = require("./cm/cm-package");
26
+ const {IETFLanguageCodeFactory} = require("./cs/cs-lang");
27
+ const {LanguageDefinitions} = require("../library/languages");
28
+ const {VersionUtilities} = require("../library/version-utilities");
29
+ const {ListCodeSystemProvider} = require("./cs/cs-provider-list");
30
+ const { Provider } = require("./provider");
31
+ const {I18nSupport} = require("../library/i18nsupport");
32
+ const folders = require('../library/folder-setup');
33
+
34
+ /**
35
+ * This class holds all the loaded content ready for processing
36
+ *
37
+ * At the start of every service call, this is turned into a
38
+ * provider structure that holds what's actually in context,
39
+ * based on the stated FHIR version, and the other (optional) context information
40
+ *
41
+ */
42
+ class Library {
43
+ /**
44
+ * {Map<String, CodeSystemFactoryProvider>} A list of code system factories that contains all the preloaded native code systems
45
+ */
46
+ codeSystemFactories;
47
+
48
+ /**
49
+ * {Lisr<AbstractCodeSystemProvider>} A list of preloaded FHIR code systems
50
+ */
51
+ codeSystemProviders;
52
+
53
+ /**
54
+ * {List<AbstractValueSetProvider>} A list of value set providers that know how to provide value sets by request
55
+ */
56
+ valueSetProviders;
57
+
58
+ /**
59
+ * {List<AbstractConceptMapProvider>} A list of value set providers that know how to provide value sets by request
60
+ */
61
+ conceptMapProviders;
62
+
63
+ contentSources = [];
64
+
65
+ baseUrl = null;
66
+ cacheFolder = null;
67
+ startTime = Date.now();
68
+ startMemory = process.memoryUsage();
69
+ lastTime = null;
70
+ totalDownloaded = 0;
71
+
72
+ registerProvider(source, factory, isDefault = false) {
73
+ this.#logSystem(factory.system(), factory.version(), source);
74
+ if (isDefault || !this.codeSystemFactories.has(factory.system())) {
75
+ this.codeSystemFactories.set(factory.system(), factory);
76
+ }
77
+ const ver = factory.version() ?? "";
78
+ this.codeSystemFactories.set(factory.system()+"|"+ver, factory);
79
+ const verMin = factory.getPartialVersion();
80
+ if (verMin) {
81
+ this.codeSystemFactories.set(factory.system()+"|"+verMin, factory);
82
+ }
83
+ }
84
+
85
+ constructor(configFile, log) {
86
+ this.configFile = configFile;
87
+ this.log = log;
88
+ // Only synchronous initialization here
89
+ this.codeSystemFactories = new Map();
90
+ this.codeSystemProviders = [];
91
+ this.valueSetProviders = [];
92
+ this.conceptMapProviders = [];
93
+
94
+ // Create package manager for FHIR packages
95
+ const packageServers = ['https://packages2.fhir.org/packages'];
96
+ this.cacheFolder = folders.subDir('terminology-cache'); // <-- CHANGE
97
+ this.packageManager = new PackageManager(packageServers, this.cacheFolder);
98
+ }
99
+
100
+ #logSystemHeader() {
101
+ let time = "Time".padEnd(6);
102
+ // let memory = " MB".padEnd(6);
103
+ let system = "System".padEnd(50);
104
+ let version = "Version".padEnd(62);
105
+ let source = "Source"
106
+ this.log.info(`${time}${system}${version}${source}`);
107
+ this.lastTime = Date.now();
108
+ // this.lastMemory = process.memoryUsage();
109
+ }
110
+
111
+ #logSystem(url, ver, source) {
112
+ //const mem = process.memoryUsage();
113
+ let time = Math.floor(Date.now() - this.lastTime).toString().padStart(5)+" ";
114
+ let system = url.padEnd(50);
115
+ let version = (ver == null ? "" : ver).padEnd(62);
116
+ this.log.info(`${time}${system}${version}${source}`);
117
+ this.lastTime = Date.now();
118
+ }
119
+
120
+ #logPackagesHeader() {
121
+ let time = "Time".padEnd(6);
122
+ //let memory = " MB".padEnd(6);
123
+ let id = "ID".padEnd(20);
124
+ let ver = "Version".padEnd(20);
125
+ let cs = "CS".padEnd(6);
126
+ let vs = "VS".padEnd(6);
127
+ this.log.info(`${time}${id}${ver}${cs}${vs}`);
128
+ this.lastTime = Date.now();
129
+ }
130
+
131
+ #logPackage(idp, verp, csp, vsp) {
132
+ let time = Math.floor(Date.now() - this.lastTime).toString().padStart(5)+" ";
133
+ let id = idp.padEnd(20);
134
+ let ver = verp.padEnd(20);
135
+ let cs = csp.toString().padEnd(6);
136
+ let vs = vsp.toString().padEnd(6);
137
+ this.log.info(`${time}${id}${ver}${cs}${vs}`);
138
+ this.lastTime = Date.now();
139
+ }
140
+
141
+ async load() {
142
+ this.startTime = Date.now();
143
+ this.languageDefinitions = await LanguageDefinitions.fromFile(path.join(__dirname, '../tx/data/lang.dat'));
144
+ this.i18n = new I18nSupport(path.join(__dirname, '../translations'), this.languageDefinitions);
145
+ await this.i18n.load();
146
+
147
+ // Read and parse YAML configuration
148
+ const yamlPath = this.configFile ? this.configFile : path.join(__dirname, '..', 'tx', 'tx.fhir.org.yml');
149
+ const yamlContent = await fs.readFile(yamlPath, 'utf8');
150
+ const config = yaml.parse(yamlContent);
151
+ this.baseUrl = config.base.url;
152
+
153
+ this.log.info('Fetching Data from '+this.baseUrl);
154
+
155
+ for (const source of config.sources) {
156
+ await this.processSource(source, this.packageManager, "fetch");
157
+ }
158
+
159
+ this.log.info("Downloaded "+((this.totalDownloaded + this.packageManager.totalDownloaded)/ 1024)+" kB");
160
+
161
+ this.log.info('Loading Code Systems');
162
+ this.#logSystemHeader();
163
+
164
+ for (const source of config.sources) {
165
+ await this.processSource(source, this.packageManager, "cs");
166
+ }
167
+ this.log.info('Loading Packages');
168
+ this.#logPackagesHeader();
169
+
170
+ for (const source of config.sources) {
171
+ await this.processSource(source, this.packageManager, "npm");
172
+ }
173
+
174
+ const endMemory = process.memoryUsage();
175
+ const totalTime = Date.now() - this.startTime;
176
+
177
+ const memoryIncrease = {
178
+ rss: endMemory.rss - this.startMemory.rss,
179
+ heapUsed: endMemory.heapUsed - this.startMemory.heapUsed,
180
+ heapTotal: endMemory.heapTotal - this.startMemory.heapTotal,
181
+ external: endMemory.external - this.startMemory.external
182
+ };
183
+
184
+ this.log.info(`Loading Time: ${(totalTime / 1000).toLocaleString()}s`);
185
+ this.log.info(`Memory Used: ${(memoryIncrease.rss / 1024 / 1024).toFixed(2)} MB`);
186
+
187
+ this.assignIds();
188
+ }
189
+
190
+ async processSource(source, packageManager, mode) {
191
+ // Parse the source string
192
+ const colonIndex = source.indexOf(':');
193
+ if (colonIndex === -1) {
194
+ throw new Error(`Invalid source format: ${source}`);
195
+ }
196
+
197
+ let type = source.substring(0, colonIndex);
198
+ const details = source.substring(colonIndex + 1);
199
+
200
+ // Handle special markers (like ! for default)
201
+ let isDefault = false;
202
+ if (type.endsWith('!')) {
203
+ type = type.slice(0, -1);
204
+ isDefault = true;
205
+ }
206
+
207
+ // Switch statement for different source types
208
+ switch (type) {
209
+ case 'internal':
210
+ await this.loadInternal(details, isDefault, mode);
211
+ break;
212
+
213
+ case 'ucum':
214
+ await this.loadUcum(details, isDefault, mode);
215
+ break;
216
+
217
+ case 'loinc':
218
+ await this.loadLoinc(details, isDefault, mode);
219
+ break;
220
+
221
+ case 'rxnorm':
222
+ await this.loadRxnorm(details, isDefault, mode);
223
+ break;
224
+
225
+ case 'ndc':
226
+ await this.loadNdc(details, isDefault, mode);
227
+ break;
228
+
229
+ case 'unii':
230
+ await this.loadUnii(details, isDefault, mode);
231
+ break;
232
+
233
+ case 'snomed':
234
+ await this.loadSnomed(details, isDefault, mode);
235
+ break;
236
+
237
+ case 'cpt':
238
+ await this.loadCpt(details, isDefault, mode);
239
+ break;
240
+
241
+ case 'omop':
242
+ await this.loadOmop(details, isDefault, mode);
243
+ break;
244
+
245
+ case 'npm':
246
+ await this.loadNpm(packageManager, details, isDefault, mode);
247
+ break;
248
+
249
+ default:
250
+ throw new Error(`Unknown source type: ${type}`);
251
+ }
252
+ }
253
+
254
+ async loadInternal(details, isDefault, mode) {
255
+ if (isDefault) {
256
+ throw new Error("Default is not supported for internal code system providers");
257
+ }
258
+ if (mode === "fetch" || mode === "npm") {
259
+ return;
260
+ }
261
+ switch (details) {
262
+ case "country" : {
263
+ const cc = new CountryCodeFactoryProvider(this.i18n);
264
+ await cc.load();
265
+ this.registerProvider('internal', cc);
266
+ break;
267
+ }
268
+ case "lang" : {
269
+ const langs = new IETFLanguageCodeFactory(this.i18n);
270
+ await langs.load();
271
+ this.registerProvider('internal', langs);
272
+ break;
273
+ }
274
+ case "currency" : {
275
+ const curr = new Iso4217FactoryProvider(this.i18n);
276
+ await curr.load();
277
+ this.registerProvider('internal', curr);
278
+ break;
279
+ }
280
+ case "areacode" : {
281
+ const ac = new AreaCodeFactoryProvider(this.i18n);
282
+ await ac.load();
283
+ this.registerProvider('internal', ac);
284
+ break;
285
+ }
286
+ case "mimetypes" : {
287
+ const mime = new MimeTypeServicesFactory(this.i18n);
288
+ await mime.load();
289
+ this.registerProvider('internal', mime);
290
+ break;
291
+ }
292
+ case "usstates" : {
293
+ const uss = new USStateFactoryProvider(this.i18n);
294
+ await uss.load();
295
+ this.registerProvider('internal', uss);
296
+ break;
297
+ }
298
+ case "hgvs" : {
299
+ const hgvs = new HGVSServicesFactory(this.i18n);
300
+ await hgvs.load();
301
+ this.registerProvider('internal', hgvs);
302
+ break;
303
+ }
304
+ default:
305
+ throw new Error("Unknown Internal Provider "+details);
306
+ }
307
+ }
308
+
309
+ async loadUcum(details, isDefault, mode) {
310
+ if (mode === "fetch" || mode === "npm") {
311
+ return;
312
+ }
313
+ const source = path.join(__dirname, '..', details);
314
+
315
+ const ucumEssenceXml = readFileSync(source, 'utf8');
316
+ const ucumService = new UcumService();
317
+ await ucumService.init(ucumEssenceXml);
318
+
319
+ const ucum = new UcumCodeSystemFactory(this.i18n, ucumService);
320
+ await ucum.load();
321
+ this.registerProvider(source, ucum, isDefault);
322
+ }
323
+
324
+ async loadLoinc(details, isDefault, mode) {
325
+ const loincFN = await this.getOrDownloadFile(details);
326
+ if (mode === "fetch" || mode === "npm") {
327
+ return;
328
+ }
329
+
330
+ const loinc = new LoincServicesFactory(this.i18n, loincFN);
331
+ await loinc.load();
332
+ this.registerProvider(loincFN, loinc, isDefault);
333
+ }
334
+
335
+ async loadRxnorm(details, isDefault, mode) {
336
+ const rxNormFN = await this.getOrDownloadFile(details);
337
+ if (mode === "fetch" || mode === "npm") {
338
+ return;
339
+ }
340
+ const rxn = new RxNormServicesFactory(this.i18n, rxNormFN);
341
+ await rxn.load();
342
+ this.registerProvider(rxNormFN, rxn, isDefault);
343
+ }
344
+
345
+ async loadNdc(details, isDefault, mode) {
346
+ const ndcFN = await this.getOrDownloadFile(details);
347
+ if (mode === "fetch" || mode === "npm") {
348
+ return;
349
+ }
350
+ const ndc = new NdcServicesFactory(this.i18n, ndcFN);
351
+ await ndc.load();
352
+ this.registerProvider(ndcFN, ndc, isDefault);
353
+ }
354
+
355
+ async loadUnii(details, isDefault, mode) {
356
+ const uniFN = await this.getOrDownloadFile(details);
357
+ if (mode === "fetch" || mode === "npm") {
358
+ return;
359
+ }
360
+ const unii = new UniiServicesFactory(this.i18n, uniFN);
361
+ await unii.load();
362
+ this.registerProvider(uniFN, unii, isDefault);
363
+ }
364
+
365
+ async loadSnomed(details, isDefault, mode) {
366
+ const sctFN = await this.getOrDownloadFile(details);
367
+ if (mode === "fetch" || mode === "npm") {
368
+ return;
369
+ }
370
+ const sct = new SnomedServicesFactory(this.i18n, sctFN);
371
+ await sct.load();
372
+ this.registerProvider(sctFN, sct, isDefault);
373
+ }
374
+
375
+ async loadCpt(details, isDefault, mode) {
376
+ const cptFN = await this.getOrDownloadFile(details);
377
+ if (mode === "fetch" || mode === "npm") {
378
+ return;
379
+ }
380
+ const cpt = new CPTServicesFactory(this.i18n, cptFN);
381
+ await cpt.load();
382
+ this.registerProvider(cptFN, cpt, isDefault);
383
+ }
384
+
385
+ async loadOmop(details, isDefault, mode) {
386
+ const omopFN = await this.getOrDownloadFile(details);
387
+ if (mode === "fetch" || mode === "npm") {
388
+ return;
389
+ }
390
+ const omop = new OMOPServicesFactory(this.i18n, omopFN);
391
+ await omop.load();
392
+ this.registerProvider(omopFN, omop, isDefault);
393
+ }
394
+
395
+ async loadNpm(packageManager, details, isDefault, mode) {
396
+ // Parse packageId and version from details (e.g., "hl7.terminology.r4#6.0.2")
397
+ let packageId = details;
398
+ let version = null;
399
+ if (details.includes('#')) {
400
+ const parts = details.split('#');
401
+ packageId = parts[0];
402
+ version = parts[1];
403
+ }
404
+ const packagePath = await packageManager.fetch(packageId, version);
405
+ if (mode === "fetch" || mode === "cs") {
406
+ return;
407
+ }
408
+ const fullPackagePath = path.join(this.cacheFolder, packagePath);
409
+ const contentLoader = new PackageContentLoader(fullPackagePath);
410
+ await contentLoader.initialize();
411
+
412
+ this.contentSources.push(contentLoader.id()+"#"+contentLoader.version());
413
+
414
+ let cp = new ListCodeSystemProvider();
415
+ const resources = await contentLoader.getResourcesByType("CodeSystem");
416
+ let csc = 0;
417
+ for (const resource of resources) {
418
+ const cs = new CodeSystem(await contentLoader.loadFile(resource, contentLoader.fhirVersion()));
419
+ cs.sourcePackage = contentLoader.pid();
420
+ cp.codeSystems.set(cs.url, cs);
421
+ cp.codeSystems.set(cs.vurl, cs);
422
+ csc++;
423
+ }
424
+ this.codeSystemProviders.push(cp);
425
+ const vs = new PackageValueSetProvider(contentLoader);
426
+ await vs.initialize();
427
+ this.valueSetProviders.push(vs);
428
+ const cm = new PackageConceptMapProvider(contentLoader);
429
+ await cm.initialize();
430
+ this.conceptMapProviders.push(cm);
431
+
432
+ this.#logPackage(contentLoader.id(), contentLoader.version(), csc, vs.valueSetMap.size);
433
+ }
434
+
435
+ /**
436
+ * Gets a file from local folder or downloads it from URL
437
+ * @param {string} fileName - Name of the file
438
+ * @returns {Promise<string>} Full path to the file
439
+ * @throws {Error} If file cannot be downloaded or accessed
440
+ */
441
+ async getOrDownloadFile(fileName) {
442
+ // Ensure folder exists
443
+ await this.ensureFolderExists(this.cacheFolder);
444
+
445
+ const filePath = path.join(this.cacheFolder, fileName);
446
+
447
+ // Check if file already exists
448
+ if (await this.fileExists(filePath)) {
449
+ return filePath;
450
+ }
451
+
452
+ // File doesn't exist, download it
453
+ this.log.info(`Downloading: ${fileName}`);
454
+
455
+ const downloadUrl = this.baseUrl.endsWith('/') ? this.baseUrl + fileName : this.baseUrl + '/' + fileName;
456
+
457
+ try {
458
+ await this.downloadFile(downloadUrl, filePath);
459
+ return filePath;
460
+ } catch (error) {
461
+ throw new Error(`Failed to download file ${fileName} from ${downloadUrl}: ${error.message}`);
462
+ }
463
+ }
464
+
465
+ /**
466
+ * Check if a file exists
467
+ * @param {string} filePath - Path to check
468
+ * @returns {Promise<boolean>} True if file exists
469
+ */
470
+ async fileExists(filePath) {
471
+ try {
472
+ await fs.access(filePath);
473
+ return true;
474
+ } catch {
475
+ return false;
476
+ }
477
+ }
478
+
479
+ /**
480
+ * Ensure a folder exists, create it if it doesn't
481
+ * @param {string} folderPath - Path to folder
482
+ */
483
+ async ensureFolderExists(folderPath) {
484
+ try {
485
+ await fs.mkdir(folderPath, { recursive: true });
486
+ } catch (error) {
487
+ if (error.code !== 'EEXIST') {
488
+ throw new Error(`Failed to create folder ${folderPath}: ${error.message}`);
489
+ }
490
+ }
491
+ }
492
+
493
+ /**
494
+ * Download a file from URL to local path
495
+ * @param {string} url - URL to download from
496
+ * @param {string} filePath - Local path to save file
497
+ * @returns {Promise<void>}
498
+ */
499
+ async downloadFile(url, filePath) {
500
+ return new Promise((resolve, reject) => {
501
+ const protocol = url.startsWith('https:') ? https : http;
502
+
503
+ const request = protocol.get(url, (response) => {
504
+ // Handle redirects
505
+ if (response.statusCode >= 300 && response.statusCode < 400 && response.headers.location) {
506
+ return this.downloadFile(response.headers.location, filePath)
507
+ .then(resolve)
508
+ .catch(reject);
509
+ }
510
+
511
+ // Check for successful response
512
+ if (response.statusCode !== 200) {
513
+ reject(new Error(`HTTP ${response.statusCode}: ${response.statusMessage}`));
514
+ return;
515
+ }
516
+
517
+ // Create write stream
518
+ const fileStream = require('fs').createWriteStream(filePath);
519
+
520
+ // Handle stream errors
521
+ fileStream.on('error', (error) => {
522
+ reject(new Error(`Failed to write file: ${error.message}`));
523
+ });
524
+
525
+ // Handle download completion
526
+ fileStream.on('finish', () => {
527
+ fileStream.close();
528
+ const statsFs = require('fs').statSync(filePath);
529
+ this.totalDownloaded = this.totalDownloaded + statsFs.size;
530
+ resolve();
531
+ });
532
+
533
+ // Pipe response to file
534
+ response.pipe(fileStream);
535
+
536
+ }).on('error', (error) => {
537
+ reject(new Error(`Download request failed: ${error.message}`));
538
+ });
539
+
540
+ // Set timeout for request
541
+ request.setTimeout(30000, () => {
542
+ request.destroy();
543
+ reject(new Error('Download timeout (30 seconds)'));
544
+ });
545
+ });
546
+ }
547
+
548
+ /**
549
+ * Creates a provider for the specified version , and context.
550
+ *
551
+ * @param {string} fhirVersion - FHIR version (e.g., '4.0.1', '5.0.0')
552
+ * @param {string} context - other information from the client that sets the context
553
+ * @returns {Promise<Provider>} New provider instance with FHIR packages loaded
554
+ */
555
+ async cloneWithFhirVersion(fhirVersion, context, path) {
556
+ // Create new provider instance
557
+ const provider = new Provider();
558
+ provider.i18n = this.i18n;
559
+ provider.codeSystemFactories = new Map(this.codeSystemFactories); // all of them
560
+ provider.codeSystems = new Map();
561
+ provider.valueSetProviders = [];
562
+ provider.conceptMapProviders = [];
563
+ provider.path = path;
564
+ if (VersionUtilities.isR5Ver(fhirVersion)) {
565
+ provider.fhirVersion = 5;
566
+ } else if (VersionUtilities.isR4Ver(fhirVersion)) {
567
+ provider.fhirVersion = 4;
568
+ } else if (VersionUtilities.isR3Ver(fhirVersion)) {
569
+ provider.fhirVersion = 3;
570
+ } else {
571
+ provider.fhirVersion = 6;
572
+ }
573
+
574
+
575
+
576
+ // Load FHIR core packages first
577
+ const fhirPackages = this.#getFhirPackagesForVersion(fhirVersion);
578
+
579
+ this.log.info(`Loading FHIR ${fhirVersion} packages`);
580
+ this.#logPackagesHeader();
581
+
582
+ // Load FHIR packages - these will be added to valueSetProviders first
583
+ for (const packageId of fhirPackages) {
584
+ await provider.loadNpm(this.packageManager, this.cacheFolder, packageId, false, "npm");
585
+ }
586
+
587
+
588
+ for (const cp of this.codeSystemProviders) {
589
+ const csMap = await cp.listCodeSystems(fhirVersion, context);
590
+ for (const [key, value] of csMap) {
591
+ provider.codeSystems.set(key, value);
592
+ }
593
+ }
594
+ // Don't clone valueSetProviders yet - we'll build it with correct order
595
+
596
+ // Copy other properties
597
+ provider.baseUrl = this.baseUrl;
598
+ provider.cacheFolder = this.cacheFolder;
599
+ provider.startTime = this.startTime;
600
+ provider.startMemory = this.startMemory;
601
+ provider.lastTime = this.lastTime;
602
+ provider.lastMemory = this.lastMemory;
603
+ provider.totalDownloaded = this.totalDownloaded;
604
+ provider.contentSources = this.contentSources;
605
+
606
+
607
+ // Now add the existing value set providers after the FHIR core packages
608
+ provider.valueSetProviders.push(...this.valueSetProviders);
609
+ provider.conceptMapProviders.push(...this.conceptMapProviders);
610
+
611
+ return provider;
612
+ }
613
+
614
+ /**
615
+ * Gets the list of FHIR packages for a specific version
616
+ * @param {string} fhirVersion - FHIR version
617
+ * @returns {string} Package Id
618
+ * @private
619
+ */
620
+ #getFhirPackagesForVersion(ver) {
621
+ if (VersionUtilities.isR3Ver(ver)) {
622
+ return ["hl7.fhir.r3.core"];
623
+ }
624
+ if (VersionUtilities.isR4Ver(ver) ||VersionUtilities.isR4BVer(ver)) {
625
+ return ["hl7.fhir.r4.core"];
626
+ }
627
+ if (VersionUtilities.isR5Ver(ver)) {
628
+ return ["hl7.fhir.r5.core"];
629
+ }
630
+ throw new Error(`Unsupported FHIR version: ${ver}. Supported versions: R3, R4, R5`);
631
+ }
632
+
633
+ /**
634
+ * all the loaded resources must have unique IDs for the get operation
635
+ * they must be assigned by the library on loading. providers can either assign
636
+ * ids from the global space at start up, or, if they can provide new resources
637
+ * later in an ongoing fashion, allocate them in their own space
638
+ */
639
+ assignIds() {
640
+ let ids = new Set();
641
+ // these don't have ids - not available directly for (const cs of this.codeSystemFactories) { .. }
642
+ let i = 0;
643
+ for (const cp of this.codeSystemProviders) {
644
+ cp.spaceId = String(++i);
645
+ cp.assignIds(ids);
646
+ }
647
+ i = 0;
648
+ for (const vp of this.valueSetProviders) {
649
+ vp.spaceId = String(++i);
650
+ vp.assignIds(ids);
651
+ }
652
+ i = 0;
653
+ for (const cmp of this.conceptMapProviders) {
654
+ cmp.spaceId = String(++i);
655
+ cmp.assignIds(ids);
656
+ }
657
+
658
+ }
659
+
660
+ async close() {
661
+ for (let csp of this.codeSystemProviders) {
662
+ csp.close();
663
+ }
664
+ for (let csp of this.codeSystemFactories.values()) {
665
+ csp.close();
666
+ }
667
+ for (let vsp of this.valueSetProviders) {
668
+ vsp.close();
669
+ }
670
+ for (let cmp of this.conceptMapProviders) {
671
+ cmp.close();
672
+ }
673
+ }
674
+ }
675
+
676
+ module.exports = { Library };