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,492 @@
1
+ //
2
+ // Translate Worker - Handles ConceptMap $translate operation
3
+ //
4
+ // GET /ConceptMap/$translate?{params}
5
+ // POST /ConceptMap/$translate
6
+ // GET /ConceptMap/{id}/$translate?{params}
7
+ // POST /ConceptMap/{id}/$translate
8
+ //
9
+
10
+ const { TerminologyWorker } = require('./worker');
11
+ const { TxParameters } = require('../params');
12
+ const { Parameters } = require('../library/parameters');
13
+ const { Issue, OperationOutcome } = require('../library/operation-outcome');
14
+ const {ConceptMap} = require("../library/conceptmap");
15
+
16
+ class TranslateWorker extends TerminologyWorker {
17
+ /**
18
+ * @param {OperationContext} opContext - Operation context
19
+ * @param {Logger} log - Logger instance
20
+ * @param {Provider} provider - Provider for concept maps and resources
21
+ * @param {LanguageDefinitions} languages - Language definitions
22
+ * @param {I18nSupport} i18n - Internationalization support
23
+ */
24
+ constructor(opContext, log, provider, languages, i18n) {
25
+ super(opContext, log, provider, languages, i18n);
26
+ }
27
+
28
+ /**
29
+ * Get operation name
30
+ * @returns {string}
31
+ */
32
+ opName() {
33
+ return 'translate';
34
+ }
35
+
36
+ /**
37
+ * Handle a type-level $translate request
38
+ * GET/POST /ConceptMap/$translate
39
+ * @param {express.Request} req - Express request
40
+ * @param {express.Response} res - Express response
41
+ */
42
+ async handle(req, res) {
43
+ try {
44
+ await this.handleTypeLevelTranslate(req, res);
45
+ } catch (error) {
46
+ this.log.error(error);
47
+ if (error instanceof Issue) {
48
+ const oo = new OperationOutcome();
49
+ oo.addIssue(error);
50
+ return res.status(error.statusCode || 500).json(oo.jsonObj);
51
+ } else {
52
+ return res.status(error.statusCode || 500).json(this.operationOutcome(
53
+ 'error', error.issueCode || 'exception', error.message));
54
+ }
55
+ }
56
+ }
57
+
58
+ /**
59
+ * Handle an instance-level $translate request
60
+ * GET/POST /ConceptMap/{id}/$translate
61
+ * @param {express.Request} req - Express request
62
+ * @param {express.Response} res - Express response
63
+ */
64
+ async handleInstance(req, res) {
65
+ try {
66
+ await this.handleInstanceLevelTranslate(req, res);
67
+ } catch (error) {
68
+ this.log.error(error);
69
+ if (error instanceof Issue) {
70
+ const oo = new OperationOutcome();
71
+ oo.addIssue(error);
72
+ return res.status(error.statusCode || 500).json(oo.jsonObj);
73
+ } else {
74
+ return res.status(error.statusCode || 500).json(this.operationOutcome(
75
+ 'error', error.issueCode || 'exception', error.message));
76
+ }
77
+ }
78
+ }
79
+
80
+ /**
81
+ * Handle type-level translate: /ConceptMap/$translate
82
+ * ConceptMap identified by url+version params or from source/target
83
+ */
84
+ async handleTypeLevelTranslate(req, res) {
85
+ this.deadCheck('translate-type-level');
86
+
87
+ // Handle tx-resource and cache-id parameters from Parameters resource
88
+ if (req.body && req.body.resourceType === 'Parameters') {
89
+ this.setupAdditionalResources(req.body);
90
+ }
91
+
92
+ // Parse parameters from request
93
+ const params = new Parameters(this.buildParameters(req));
94
+ const txp = new TxParameters(this.opContext.i18n.languageDefinitions, this.opContext.i18n);
95
+ txp.readParams(params.jsonObj);
96
+
97
+ // Extract required parameters per FHIR spec
98
+ // url - canonical URL of the concept map (optional for type-level if source/target specified)
99
+ // conceptMapVersion - version of the concept map
100
+ // sourceCode / sourceCoding / sourceCodeableConcept - the code to translate
101
+ // system - system of the code (if sourceCode used)
102
+ // version - version of the code system
103
+ // sourceScope - source value set scope
104
+ // targetScope - target value set scope
105
+ // targetSystem - target code system to translate to
106
+ // dependency - additional dependencies for translation
107
+
108
+ let coding = null;
109
+ let conceptMaps = [];
110
+ let targetScope = null;
111
+ let sourceScope = null;
112
+ let targetSystem = null;
113
+
114
+ // Get the source coding
115
+ if (params.has('sourceCoding')) {
116
+ coding = params.get('sourceCoding');
117
+ } else if (params.has('sourceCodeableConcept')) {
118
+ const cc = params.get('sourceCodeableConcept');
119
+ if (cc.coding && cc.coding.length > 0) {
120
+ coding = cc.coding[0]; // Use first coding
121
+ } else {
122
+ throw new Issue('error', 'invalid', null, null,
123
+ 'sourceCodeableConcept must contain at least one coding', null, 400);
124
+ }
125
+ } else if (params.has('sourceCode')) {
126
+ if (!params.has('sourceSystem')) {
127
+ throw new Issue('error', 'invalid', null, null,
128
+ 'sourceSystem parameter is required when using sourceCode', null, 400);
129
+ }
130
+ coding = {
131
+ system: params.get('sourceSystem'),
132
+ version: params.get('sourceVersion'),
133
+ code: params.get('sourceCode')
134
+ };
135
+ } else {
136
+ throw new Issue('error', 'invalid', null, null,
137
+ 'Must provide sourceCode (with system), sourceCoding, or sourceCodeableConcept', null, 400);
138
+ }
139
+
140
+ // Get the concept map
141
+ if (params.has('url')) {
142
+ const url = params.get('url');
143
+ const cmVersion = params.get('conceptMapVersion');
144
+ let conceptMap = await this.provider.findConceptMap(this.opContext, url, cmVersion);
145
+ if (!conceptMap) {
146
+ const msg = cmVersion
147
+ ? `ConceptMap not found: ${url} version ${cmVersion}`
148
+ : `ConceptMap not found: ${url}`;
149
+ throw new Issue('error', 'not-found', null, null, msg, null, 404);
150
+ } else {
151
+ conceptMaps.push(conceptMap);
152
+ }
153
+ }
154
+
155
+ // Get scope parameters
156
+ if (params.has('sourceScope')) {
157
+ sourceScope = params.get('sourceScope');
158
+ }
159
+ if (params.has('targetScope')) {
160
+ targetScope = params.get('targetScope');
161
+ }
162
+ if (params.has('targetSystem')) {
163
+ targetSystem = params.get('targetSystem');
164
+ }
165
+
166
+ // If no explicit concept map, we need to find one based on source/target
167
+ if (conceptMaps.length == 0) {
168
+ await this.findConceptMapsInAdditionalResources(conceptMaps, coding.system, sourceScope, targetScope, targetSystem);
169
+ await this.provider.findConceptMapForTranslation(this.opContext, conceptMaps, coding.system, sourceScope, targetScope, targetSystem);
170
+ if (conceptMaps.length == 0) {
171
+ throw new Issue('error', 'not-found', null, null, 'No suitable ConceptMaps found for the specified source and target', null, 404);
172
+ }
173
+ }
174
+
175
+ // Perform the translation
176
+ const result = await this.doTranslate(conceptMaps, coding, targetScope, targetSystem, txp);
177
+ return res.status(200).json(result);
178
+ }
179
+
180
+ /**
181
+ * Handle instance-level translate: /ConceptMap/{id}/$translate
182
+ * ConceptMap identified by resource ID
183
+ */
184
+ async handleInstanceLevelTranslate(req, res) {
185
+ this.deadCheck('translate-instance-level');
186
+
187
+ const { id } = req.params;
188
+
189
+ // Find the ConceptMap by ID
190
+ const conceptMap = await this.provider.getConceptMapById(this.opContext, id);
191
+
192
+ if (!conceptMap) {
193
+ throw new Issue('error', 'not-found', null, null,
194
+ `ConceptMap/${id} not found`, null, 404);
195
+ }
196
+
197
+ // Handle tx-resource and cache-id parameters from Parameters resource
198
+ if (req.body && req.body.resourceType === 'Parameters') {
199
+ this.setupAdditionalResources(req.body);
200
+ }
201
+
202
+ // Parse parameters from request
203
+ const params = new Parameters(this.buildParameters(req));
204
+ const txp = new TxParameters(this.opContext.i18n.languageDefinitions, this.opContext.i18n);
205
+ txp.readParams(params.jsonObj);
206
+
207
+ // Get the source coding
208
+ let coding = null;
209
+
210
+ if (params.has('sourceCoding')) {
211
+ coding = params.get('sourceCoding');
212
+ } else if (params.has('sourceCodeableConcept')) {
213
+ const cc = params.get('sourceCodeableConcept');
214
+ if (cc.coding && cc.coding.length > 0) {
215
+ coding = cc.coding[0];
216
+ } else {
217
+ throw new Issue('error', 'invalid', null, null,
218
+ 'sourceCodeableConcept must contain at least one coding', null, 400);
219
+ }
220
+ } else if (params.has('sourceCode')) {
221
+ if (!params.has('system')) {
222
+ throw new Issue('error', 'invalid', null, null,
223
+ 'system parameter is required when using sourceCode', null, 400);
224
+ }
225
+ coding = {
226
+ system: params.get('system'),
227
+ version: params.get('version'),
228
+ code: params.get('sourceCode')
229
+ };
230
+ } else {
231
+ throw new Issue('error', 'invalid', null, null,
232
+ 'Must provide sourceCode (with system), sourceCoding, or sourceCodeableConcept', null, 400);
233
+ }
234
+
235
+ // Get optional scope/target parameters
236
+ const targetScope = params.has('targetScope') ? params.get('targetScope') : null;
237
+ const targetSystem = params.has('targetSystem') ? params.get('targetSystem') : null;
238
+
239
+ let conceptMaps = [];
240
+ conceptMaps.push(conceptMap);
241
+
242
+ // Perform the translation
243
+ const result = await this.doTranslate(conceptMaps, coding, targetScope, targetSystem, params);
244
+ return res.status(200).json(result);
245
+ }
246
+
247
+
248
+ checkCode(op, langList, path, code, system, version, display) {
249
+ let result = false;
250
+ const cp = this.findCodeSystem(system, version, null, ['complete', 'fragment'], true, true, false, null);
251
+ if (cp != null) {
252
+ const lct = cp.locate(this.opContext, code);
253
+ if (op.error('InstanceValidator', 'invalid', path, lct != null, 'Unknown Code (' + system + '#' + code + ')')) {
254
+ result = op.warning('InstanceValidator', 'invalid', path,
255
+ (!display) || (display === cp.display(this.opContext, lct, null)),
256
+ 'Display for ' + system + ' code "' + code + '" should be "' + cp.display(this.opContext, lct, null) + '"');
257
+ }
258
+ }
259
+ return result;
260
+ }
261
+
262
+ translateUsingGroups(cm, coding, targetScope, targetSystem, params, output) {
263
+ let result = false;
264
+ const matches = cm.listTranslations(coding, targetScope, targetSystem);
265
+ if (matches.length > 0) {
266
+ for (let match of matches) {
267
+ const g = match.group;
268
+ const em = match.match;
269
+ for (const map of em.target || []) {
270
+ if (['null', 'equivalent', 'equal', 'wider', 'subsumes', 'narrower', 'specializes', 'inexact'].includes(map.relationship)) {
271
+ result = true;
272
+
273
+ const outcome = {
274
+ system: g.target,
275
+ code: map.code
276
+ };
277
+
278
+ const matchParts = [];
279
+ matchParts.push({
280
+ name: 'concept',
281
+ valueCoding: outcome
282
+ });
283
+ matchParts.push({
284
+ name: 'relationship',
285
+ valueCode: map.relationship
286
+ });
287
+ if (map.comments) {
288
+ matchParts.push({
289
+ name: 'message',
290
+ valueString: map.comments
291
+ });
292
+ }
293
+ for (const prod of map.products || []) {
294
+ const productParts = [];
295
+ productParts.push({
296
+ name: 'element',
297
+ valueString: prod.property
298
+ });
299
+ productParts.push({
300
+ name: 'concept',
301
+ valueCoding: {
302
+ system: prod.system,
303
+ code: prod.value
304
+ }
305
+ });
306
+ matchParts.push({
307
+ name: 'product',
308
+ part: productParts
309
+ });
310
+ }
311
+ output.push({
312
+ name: 'match',
313
+ part: matchParts
314
+ });
315
+ }
316
+ }
317
+ }
318
+ }
319
+ return result;
320
+ }
321
+
322
+ async translateUsingCodeSystem(cm, coding, target, params, output) {
323
+ let result = false;
324
+ const factory = cm.jsonObj.internalSource;
325
+ let prov = await factory.build(this.opContext, []);
326
+
327
+ output.push({
328
+ name: 'used-system',
329
+ valueUri: prov.system() + '|' + prov.version()
330
+ });
331
+
332
+ let translations = await prov.getTranslations(coding, target);
333
+
334
+ if (translations.length > 0) {
335
+ result = true;
336
+
337
+ for (const t of translations) {
338
+ if (t.map) {
339
+ output.push({
340
+ name: 'used-conceptmap',
341
+ valueUri: t.map
342
+ });
343
+ }
344
+
345
+ const outcome = {
346
+ system: t.uri,
347
+ code: t.code,
348
+ version: t.version,
349
+ display: t.display
350
+ };
351
+
352
+ const matchParts = [];
353
+ matchParts.push({
354
+ name: 'concept',
355
+ valueCoding: outcome
356
+ });
357
+ matchParts.push({
358
+ name: 'relationship',
359
+ valueCode: t.relationship
360
+ });
361
+ if (t.message) {
362
+ matchParts.push({
363
+ name: 'message',
364
+ valueString: t.message
365
+ });
366
+ }
367
+ output.push({
368
+ name: 'match',
369
+ part: matchParts
370
+ });
371
+ }
372
+ }
373
+ return result;
374
+ }
375
+
376
+ /**
377
+ * Perform the actual translate operation
378
+ * @param {Object} conceptMap - ConceptMap resource
379
+ * @param {Object} coding - Source coding to translate
380
+ * @param {string} targetScope - Target value set scope (optional)
381
+ * @param {string} targetSystem - Target code system (optional)
382
+ * @param {Parameters} params - Full parameters object
383
+ * @returns {Object} Parameters resource with translate result
384
+ */
385
+ async doTranslate(conceptMaps, coding, targetScope, targetSystem, params) {
386
+ this.deadCheck('doTranslate');
387
+
388
+ const result = [];
389
+
390
+ try {
391
+ let added = false;
392
+ for (const cm of conceptMaps) {
393
+ if (cm.jsonObj.internalSource) {
394
+ added = await this.translateUsingCodeSystem(cm, coding, targetSystem, params, result) || added;
395
+ } else {
396
+ added = this.translateUsingGroups(cm, coding, targetScope, targetSystem, params, result) || added;
397
+ }
398
+ }
399
+ result.push({
400
+ name: 'result',
401
+ valueBoolean: added
402
+ });
403
+ if (!added) {
404
+ result.push({
405
+ name: 'message',
406
+ valueString: 'No translations found'
407
+ });
408
+ }
409
+ } catch (e) {
410
+ result.push({
411
+ name: 'result',
412
+ valueBoolean: false
413
+ });
414
+ result.push({
415
+ name: 'message',
416
+ valueString: e.message
417
+ });
418
+ }
419
+
420
+ return {
421
+ resourceType: 'Parameters',
422
+ parameter: result
423
+ };
424
+ }
425
+
426
+ // eslint-disable-next-line no-unused-vars
427
+ isOkTarget(cm, vs) {
428
+ // if cm.target != null then
429
+ // result := cm.target.url = vs.url
430
+ // else
431
+ return false;
432
+ // todo: or it might be ok to use this value set if it's a subset of the specified one?
433
+ }
434
+
435
+ // isOkSourceWithValueSet(cm, vs, coding) {
436
+ // let result = { found: false, group: null, match: null };
437
+ //
438
+ // if (true /* (vs == null) || ((cm.source != null) && (cm.source.url === vs.url)) */) {
439
+ // for (const g of cm.groups || []) {
440
+ // for (const em of g.elements || []) {
441
+ // if ((g.source === coding.system) && (em.code === coding.code)) {
442
+ // result = {
443
+ // found: true,
444
+ // group: g,
445
+ // match: em
446
+ // };
447
+ // }
448
+ // }
449
+ // }
450
+ // }
451
+ // return result;
452
+ // }
453
+
454
+
455
+ findConceptMap(cm) {
456
+ let msg = '';
457
+ if (cm != null) {
458
+ return { found: true, message: msg };
459
+ } else {
460
+ return { found: false, message: msg };
461
+ }
462
+ }
463
+ /**
464
+ * Build an OperationOutcome
465
+ * @param {string} severity - error, warning, information
466
+ * @param {string} code - Issue code
467
+ * @param {string} message - Diagnostic message
468
+ * @returns {Object} OperationOutcome resource
469
+ */
470
+ operationOutcome(severity, code, message) {
471
+ return {
472
+ resourceType: 'OperationOutcome',
473
+ issue: [{
474
+ severity,
475
+ code,
476
+ diagnostics: message
477
+ }]
478
+ };
479
+ }
480
+
481
+ async findConceptMapsInAdditionalResources(conceptMaps, system, sourceScope, targetScope, targetSystem) {
482
+ for (let res of this.additionalResources || []) {
483
+ if (res instanceof ConceptMap) {
484
+ if (res.providesTranslation(system, sourceScope, targetScope, targetSystem)) {
485
+ conceptMaps.push(res);
486
+ }
487
+ }
488
+ }
489
+ }
490
+ }
491
+
492
+ module.exports = TranslateWorker;