fhirsmith 0.18.1 → 1.0.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 (214) hide show
  1. package/ACCESSIBILITY.md +119 -0
  2. package/CHANGELOG.md +190 -9
  3. package/CONFIGURATION.md +305 -0
  4. package/LICENSE +29 -0
  5. package/README.md +29 -122
  6. package/cluster.js +1220 -0
  7. package/cluster.md +707 -0
  8. package/config-template.json +77 -8
  9. package/extension-tracker/extension-tracker-template.html +5 -8
  10. package/extension-tracker/extension-tracker.js +0 -2
  11. package/folder/folder.js +7 -6
  12. package/ips/analysis.js +560 -0
  13. package/ips/ips-template.html +5 -8
  14. package/ips/ips.js +331 -33
  15. package/ips/jurisdictions.js +65 -0
  16. package/ips/nationality.js +120 -0
  17. package/ips/pipeline.js +131 -17
  18. package/ips/presenter.js +1 -1
  19. package/ips/profile-editor.js +283 -4
  20. package/ips/readme.md +170 -20
  21. package/ips/render.js +769 -109
  22. package/ips/scripts.js +46 -0
  23. package/ips/store.js +123 -11
  24. package/ips/structure.js +247 -0
  25. package/ips/terminology.js +1 -1
  26. package/library/body-limit.js +22 -0
  27. package/library/cache-generation.js +15 -0
  28. package/library/cgroup-memory.js +133 -1
  29. package/library/cluster-counts.js +121 -0
  30. package/library/cluster-events.js +153 -0
  31. package/library/cluster-metrics.js +193 -0
  32. package/library/cluster-status.js +468 -0
  33. package/library/config-reader.js +96 -0
  34. package/library/daily-report.js +100 -2
  35. package/library/html-server.js +27 -1
  36. package/library/i18nsupport.js +23 -1
  37. package/library/keep-alive.js +18 -0
  38. package/library/languages.js +17 -3
  39. package/library/logger.js +31 -0
  40. package/library/memory-guard.js +428 -0
  41. package/library/native-memory.js +52 -0
  42. package/library/npm-audit.js +51 -25
  43. package/library/openapi-doc.js +7 -5
  44. package/library/package-manager.js +8 -0
  45. package/library/role.js +197 -0
  46. package/library/server-credentials.js +169 -0
  47. package/library/sqlite-utilities.js +59 -0
  48. package/library/ssrf-guard.js +100 -0
  49. package/library/static-response-stats.js +16 -0
  50. package/library/version-utilities.js +50 -0
  51. package/library/worker-count.js +192 -0
  52. package/nginx.md +30 -11
  53. package/npmprojector/indexer.js +18 -10
  54. package/package.json +11 -8
  55. package/packages/feed-check-page.js +117 -0
  56. package/packages/feed-check.js +279 -0
  57. package/packages/npm-check.js +57 -3
  58. package/packages/npm-signing.js +219 -0
  59. package/packages/openapi.yaml +207 -1
  60. package/packages/package-crawler.js +322 -41
  61. package/packages/packages-template.html +6 -8
  62. package/packages/packages.js +604 -57
  63. package/packages/readme.md +113 -1
  64. package/publisher/publisher-template.html +2 -5
  65. package/publisher/publisher.js +121 -110
  66. package/publisher/readme.md +75 -0
  67. package/registry/api.js +179 -1
  68. package/registry/crawler.js +86 -108
  69. package/registry/documentation/api.md +68 -2
  70. package/registry/documentation/configuration.md +34 -0
  71. package/registry/documentation/internals.md +4 -1
  72. package/registry/documentation/readme.md +3 -2
  73. package/registry/model.js +8 -0
  74. package/registry/openapi.yaml +84 -0
  75. package/registry/registry-template.html +5 -8
  76. package/registry/registry.js +58 -6
  77. package/root-bare-template.html +7 -4
  78. package/root-template.html +5 -8
  79. package/server.js +398 -198
  80. package/shl/shl.js +38 -37
  81. package/static/a11y/a11y-check.js +832 -0
  82. package/static/a11y/axe.min.js +12 -0
  83. package/static/assets/css/bootstrap-fhir.css +15 -15
  84. package/static/assets/images/flags/au.svg +18 -0
  85. package/static/assets/images/flags/unknown.svg +11 -0
  86. package/static/assets/images/flags/us.svg +63 -0
  87. package/static/assets/images/icon_audit.png +0 -0
  88. package/static/assets/images/icon_clinical.png +0 -0
  89. package/static/assets/images/icon_document.png +0 -0
  90. package/static/assets/images/icon_external.png +0 -0
  91. package/static/assets/images/icon_medication.png +0 -0
  92. package/static/assets/images/icon_organization.png +0 -0
  93. package/static/assets/images/icon_other.png +0 -0
  94. package/static/assets/images/icon_person.png +0 -0
  95. package/static/assets/images/icon_section.png +0 -0
  96. package/stats-db.js +45 -0
  97. package/stats.js +197 -10
  98. package/testing/testing-template.html +5 -8
  99. package/token/nginx_passport_setup.md +1 -1
  100. package/token/security_guide.md +1 -1
  101. package/token/token-template.html +2 -5
  102. package/token/token.js +40 -36
  103. package/translations/Messages.properties +19 -0
  104. package/tx/README.md +158 -4
  105. package/tx/closure/closure-store.js +126 -3
  106. package/tx/cm/cm-database.js +69 -57
  107. package/tx/cm/cm-package.js +50 -16
  108. package/tx/cs/cs-api.js +284 -19
  109. package/tx/cs/cs-api.md +41 -4
  110. package/tx/cs/cs-areacode.js +1 -1
  111. package/tx/cs/cs-country.js +17 -5
  112. package/tx/cs/cs-cpt.js +33 -16
  113. package/tx/cs/cs-cs.js +199 -24
  114. package/tx/cs/cs-currency.js +1 -1
  115. package/tx/cs/cs-icd11.js +21 -13
  116. package/tx/cs/cs-icf.js +22 -3
  117. package/tx/cs/cs-lang.js +2 -2
  118. package/tx/cs/cs-loinc.js +193 -67
  119. package/tx/cs/cs-mimetypes.js +12 -2
  120. package/tx/cs/cs-ndc.js +40 -25
  121. package/tx/cs/cs-omop.js +54 -29
  122. package/tx/cs/cs-rxnorm.js +300 -196
  123. package/tx/cs/cs-snomed.js +861 -95
  124. package/tx/cs/cs-ucum.js +14 -4
  125. package/tx/cs/cs-unii.js +18 -14
  126. package/tx/cs/cs-virtual.js +210 -0
  127. package/tx/ecosystem-resolver.js +413 -0
  128. package/tx/html/cluster-dash-metrics.liquid +26 -0
  129. package/tx/html/cluster-home-metrics.liquid +31 -0
  130. package/tx/html/cluster-metrics-script.liquid +251 -0
  131. package/tx/html/codesystem-operations.liquid +3 -3
  132. package/tx/html/ecl-panel.liquid +1 -1
  133. package/tx/html/external-metrics.liquid +17 -0
  134. package/tx/html/operations-form.liquid +17 -17
  135. package/tx/html/search-form.liquid +11 -11
  136. package/tx/html/status-line.liquid +58 -0
  137. package/tx/html/status-panel.liquid +140 -0
  138. package/tx/html/status-tasks.liquid +25 -0
  139. package/tx/html/tx-template.html +2 -5
  140. package/tx/importers/atc-to-fhir.js +17 -16
  141. package/tx/importers/export-icd11-codesystem.js +3 -2
  142. package/tx/importers/import-icd11.js +4 -3
  143. package/tx/importers/import-loinc.module.js +118 -56
  144. package/tx/importers/import-ndc.module.js +56 -44
  145. package/tx/importers/import-rxnorm.module.js +118 -79
  146. package/tx/importers/import-sct.module.js +125 -61
  147. package/tx/importers/import-unii.module.js +37 -36
  148. package/tx/importers/subset-loinc.module.js +49 -48
  149. package/tx/importers/subset-rxnorm.module.js +29 -28
  150. package/tx/importers/terminal.js +18 -0
  151. package/tx/importers/tx-import-base.js +13 -12
  152. package/tx/importers/tx-import-settings.js +5 -4
  153. package/tx/importers/tx-import.js +53 -52
  154. package/tx/library/canonical-resource.js +49 -0
  155. package/tx/library/codesystem.js +94 -5
  156. package/tx/library/designations.js +45 -2
  157. package/tx/library/extensions.js +13 -7
  158. package/tx/library/implicit-valuesets.js +66 -0
  159. package/tx/library/renderer.js +77 -21
  160. package/tx/library/sqlite-utilities.js +2 -0
  161. package/tx/library/tho-precedence.js +40 -0
  162. package/tx/library/ucum-parsers.js +11 -1
  163. package/tx/library/wait-for-cache.js +43 -0
  164. package/tx/library.js +321 -22
  165. package/tx/openapi-operations.js +6 -4
  166. package/tx/operation-context.js +460 -99
  167. package/tx/params.js +25 -0
  168. package/tx/problems.js +3 -5
  169. package/tx/provider.js +314 -67
  170. package/tx/resource-cache-sqlite.js +1050 -0
  171. package/tx/sct/documentation.md +45 -21
  172. package/tx/sct/ecl.js +81 -17
  173. package/tx/sct/editions.js +39 -0
  174. package/tx/sct/expressions.js +10 -1
  175. package/tx/sct/load-config.js +107 -0
  176. package/tx/sct/mmap.js +109 -0
  177. package/tx/sct/structures.js +175 -15
  178. package/tx/sct/text-index.js +5 -1
  179. package/tx/syndication/syndication-feed.js +2 -2
  180. package/tx/tx-html.js +44 -8
  181. package/tx/tx.fhir.org.yml +8 -8
  182. package/tx/tx.js +282 -80
  183. package/tx/usage-tracker.js +39 -11
  184. package/tx/vs/vs-api.js +19 -0
  185. package/tx/vs/vs-database.js +386 -62
  186. package/tx/vs/vs-package.js +44 -17
  187. package/tx/vs/vs-vsac.js +649 -101
  188. package/tx/workers/batch-validate.js +37 -10
  189. package/tx/workers/batch.js +6 -1
  190. package/tx/workers/cache-control.js +15 -4
  191. package/tx/workers/closure.js +156 -13
  192. package/tx/workers/compare.js +8 -5
  193. package/tx/workers/expand.js +1173 -289
  194. package/tx/workers/metadata.js +35 -0
  195. package/tx/workers/search.js +53 -1
  196. package/tx/workers/supplement-filters.js +145 -0
  197. package/tx/workers/translate.js +169 -4
  198. package/tx/workers/validate.js +223 -119
  199. package/tx/workers/worker.js +123 -31
  200. package/tx/xversion/xv-valueset.js +7 -4
  201. package/utilities/submit-test-report.js +3 -1
  202. package/utilities/tx-stress-test.js +482 -0
  203. package/vcl/readme.md +37 -0
  204. package/vcl/vcl-parser.js +15 -0
  205. package/xig/readme.md +52 -0
  206. package/xig/xig-template.html +5 -8
  207. package/xig/xig.js +238 -422
  208. package/changelog-template.md +0 -22
  209. package/registry/test-runner.js +0 -237
  210. package/release.sh +0 -80
  211. package/test-scripts/repro-re2-wasm-leak.js +0 -34
  212. package/tsconfig.eslint.json +0 -9
  213. package/tx/html/dash-metrics.liquid +0 -147
  214. package/tx/html/home-metrics.liquid +0 -225
package/tx/cs/cs-ucum.js CHANGED
@@ -440,17 +440,27 @@ class UcumCodeSystemProvider extends BaseCSServices {
440
440
  return 'not-subsumed';
441
441
  }
442
442
 
443
+ /**
444
+ * The concept's properties for $expand: built by extendLookup, so that an expansion reports
445
+ * the same properties $lookup does (see CodeSystemProvider._propertiesFromLookup)
446
+ */
447
+ async properties(context, names) {
448
+ return this._propertiesFromLookup(context, names);
449
+ }
450
+
443
451
  async extendLookup(ctxt, props, params) {
444
452
  validateArrayParameter(props, 'props', String);
445
453
  validateArrayParameter(params, 'params', Object);
446
454
 
447
455
 
448
- if (this._hasProp(props, 'canonical', true)) {
456
+ // canonical: the unit's canonical form. Only when asked for (by name or *) - $lookup never
457
+ // returned it by default (the old code looked for an addProperty method that params, an
458
+ // array, doesn't have, so it never returned it at all)
459
+ if (this._hasProp(props, 'canonical', false)) {
449
460
  try {
450
461
  const canonical = this.ucumService.getCanonicalUnits(ctxt.code);
451
- // Add canonical property to params - implementation depends on your Parameters class
452
- if (params && typeof params.addProperty === 'function') {
453
- params.addProperty('canonical', canonical);
462
+ if (canonical) {
463
+ this._addStringProperty(params, 'property', 'canonical', canonical);
454
464
  }
455
465
  } catch (error) {
456
466
  // Ignore errors in canonical form calculation
package/tx/cs/cs-unii.js CHANGED
@@ -2,6 +2,7 @@ const sqlite3 = require('sqlite3').verbose();
2
2
  const assert = require('assert');
3
3
  const { CodeSystem } = require('../library/codesystem');
4
4
  const { CodeSystemProvider, CodeSystemFactoryProvider} = require('./cs-api');
5
+ const { guarded } = require('../library/sqlite-utilities');
5
6
 
6
7
  class UniiConcept {
7
8
  constructor(code, display) {
@@ -20,10 +21,7 @@ class UniiServices extends CodeSystemProvider {
20
21
 
21
22
  // Clean up database connection when provider is destroyed
22
23
  close() {
23
- if (this.db) {
24
- this.db.close();
25
- this.db = null;
26
- }
24
+ this.closeDb();
27
25
  }
28
26
 
29
27
  // Metadata methods
@@ -142,19 +140,19 @@ class UniiServices extends CodeSystemProvider {
142
140
  // Database helper methods
143
141
  async #getVersion() {
144
142
  return new Promise((resolve, reject) => {
145
- this.db.get('SELECT Version FROM UniiVersion', (err, row) => {
143
+ this.db.get('SELECT Version FROM UniiVersion', guarded(reject, (err, row) => {
146
144
  if (err) reject(err);
147
145
  else resolve(row ? row.Version : 'unknown');
148
- });
146
+ }));
149
147
  });
150
148
  }
151
149
 
152
150
  async #getTotalCount() {
153
151
  return new Promise((resolve, reject) => {
154
- this.db.get('SELECT COUNT(*) as count FROM Unii', (err, row) => {
152
+ this.db.get('SELECT COUNT(*) as count FROM Unii', guarded(reject, (err, row) => {
155
153
  if (err) reject(err);
156
154
  else resolve(row.count);
157
- });
155
+ }));
158
156
  });
159
157
  }
160
158
 
@@ -166,7 +164,7 @@ class UniiServices extends CodeSystemProvider {
166
164
 
167
165
  return new Promise((resolve, reject) => {
168
166
  // First query: get main concept
169
- this.db.get('SELECT UniiKey, Display FROM Unii WHERE Code = ?', [code], (err, row) => {
167
+ this.db.get('SELECT UniiKey, Display FROM Unii WHERE Code = ?', [code], guarded(reject, (err, row) => {
170
168
  if (err) {
171
169
  return reject(err);
172
170
  }
@@ -179,7 +177,7 @@ class UniiServices extends CodeSystemProvider {
179
177
  const uniiKey = row.UniiKey;
180
178
 
181
179
  // Second query: get all descriptions
182
- this.db.all('SELECT Display FROM UniiDesc WHERE UniiKey = ?', [uniiKey], (err, rows) => {
180
+ this.db.all('SELECT Display FROM UniiDesc WHERE UniiKey = ?', [uniiKey], guarded(reject, (err, rows) => {
183
181
  if (err) return reject(err);
184
182
 
185
183
  // Add unique descriptions to others array
@@ -191,8 +189,8 @@ class UniiServices extends CodeSystemProvider {
191
189
  });
192
190
 
193
191
  resolve({ context: concept, message: undefined });
194
- });
195
- });
192
+ }));
193
+ }));
196
194
  });
197
195
  }
198
196
 
@@ -202,9 +200,14 @@ class UniiServices extends CodeSystemProvider {
202
200
  }
203
201
 
204
202
  class UniiServicesFactory extends CodeSystemFactoryProvider {
205
- constructor(i18n, dbPath) {
203
+ /**
204
+ * @param {Object} [options] - {readOnly: true} in a tx-worker (cluster.md): the file is
205
+ * the master's; this process opens it read-only
206
+ */
207
+ constructor(i18n, dbPath, options = {}) {
206
208
  super(i18n);
207
209
  this.dbPath = dbPath;
210
+ this.readOnly = !!options.readOnly;
208
211
  this.uses = 0;
209
212
  this._version = null;
210
213
  }
@@ -239,7 +242,8 @@ class UniiServicesFactory extends CodeSystemFactoryProvider {
239
242
  build(opContext, supplements) {
240
243
  this.uses++;
241
244
 
242
- return new UniiServices(opContext, supplements, new sqlite3.Database(this.dbPath), this._version);
245
+ const db = this.readOnly ? new sqlite3.Database(this.dbPath, sqlite3.OPEN_READONLY) : new sqlite3.Database(this.dbPath);
246
+ return new UniiServices(opContext, supplements, db, this._version);
243
247
  }
244
248
 
245
249
  // eslint-disable-next-line no-unused-vars
@@ -0,0 +1,210 @@
1
+ const { CodeSystemProvider, FilterExecutionContext } = require('./cs-api');
2
+ const { DesignationUse } = require('../library/designations');
3
+
4
+ /**
5
+ * A code system (and version) that this server doesn't hold, answered by asking another server
6
+ * in the terminology ecosystem that does (see ecosystem-resolver.js, and
7
+ * modules.tx.ecosystem in README.md).
8
+ *
9
+ * This is deliberately minimal: only what $validate-code against a value set needs, and with no
10
+ * regard for performance (every concept is a $lookup, every filter check a $validate-code). Every
11
+ * other method of the code system provider API throws, saying so - the defaults that
12
+ * CodeSystemProvider provides would otherwise give plausible but wrong answers (not abstract, not
13
+ * inactive, no designations...) for a code system that isn't here
14
+ */
15
+ class VirtualCodeSystemProvider extends CodeSystemProvider {
16
+
17
+ /**
18
+ * @param {OperationContext} opContext
19
+ * @param {CodeSystem[]} supplements
20
+ * @param {string} server - the address of the server that has the code system
21
+ * @param {string} system - the code system
22
+ * @param {string} version - the version of the code system on that server (may be null)
23
+ * @param {EcosystemResolver} ecosystem - sends the requests to the server (with its credentials)
24
+ */
25
+ constructor(opContext, supplements, server, system, version, ecosystem) {
26
+ super(opContext, supplements);
27
+ this.ecosystem = ecosystem;
28
+ this.server = server.endsWith('/') ? server.substring(0, server.length - 1) : server;
29
+ this.systemUrl = system;
30
+ this.versionId = version || null;
31
+ for (const name of Object.getOwnPropertyNames(CodeSystemProvider.prototype)) {
32
+ if (name === 'constructor' || name.startsWith('_') || Object.prototype.hasOwnProperty.call(VirtualCodeSystemProvider.prototype, name)) {
33
+ continue;
34
+ }
35
+ const d = Object.getOwnPropertyDescriptor(CodeSystemProvider.prototype, name);
36
+ if (d && typeof d.value === 'function') {
37
+ this[name] = () => { throw this.#notSupported(name); };
38
+ }
39
+ }
40
+ }
41
+
42
+ #notSupported(name) {
43
+ return new Error(`${this.vurl()} is not held on this server, and is provided by ${this.server}, but '${name}' isn't supported for code systems on other servers`);
44
+ }
45
+
46
+ // --- metadata -------------------------------------------------------------------------------
47
+
48
+ system() { return this.systemUrl; }
49
+ version() { return this.versionId; }
50
+ vurl() { return this.systemUrl + (this.versionId ? '|' + this.versionId : ''); }
51
+ name() { return this.vurl(); }
52
+ description() { return this.vurl() + ' (on ' + this.server + ')'; }
53
+ defLang() { return 'en'; }
54
+ contentMode() { return 'complete'; }
55
+ sourcePackage() { return null; }
56
+ status() { return {}; }
57
+ versionNeeded() { return false; }
58
+ versionAlgorithm() { return null; }
59
+ hasSupplement() { return false; }
60
+
61
+ versionIsMoreDetailed(checkVersion, actualVersion) {
62
+ return !!actualVersion && !!checkVersion && actualVersion.startsWith(checkVersion);
63
+ }
64
+
65
+ // --- talking to the other server --------------------------------------------------------------
66
+
67
+ // $lookup and $validate-code: the answers are kept (EcosystemResolver.sendCached), so the
68
+ // same question is only asked once (the validator asks for the same concept several times)
69
+ async #send(url, body) {
70
+ return this.ecosystem.sendCached(this.server, url, body, this.opContext);
71
+ }
72
+
73
+ static #outcomeText(oo) {
74
+ return (oo && oo.issue || []).map(i => (i.details && i.details.text) || i.diagnostics).filter(t => t).join('; ');
75
+ }
76
+
77
+ // --- concepts ---------------------------------------------------------------------------------
78
+
79
+ /**
80
+ * One $lookup on the other server. The context is what it says about the concept
81
+ */
82
+ async locate(code) {
83
+ if (code && typeof code === 'object') {
84
+ return { context: code, message: null };
85
+ }
86
+ let url = this.server + '/CodeSystem/$lookup?system=' + encodeURIComponent(this.systemUrl) + '&code=' + encodeURIComponent(code);
87
+ if (this.versionId) {
88
+ url = url + '&version=' + encodeURIComponent(this.versionId);
89
+ }
90
+ // asking for properties gets only those, so designation too: any designation is a valid
91
+ // display (see designations()), not just the preferred term
92
+ url = url + '&property=inactive&property=notSelectable&property=status&property=designation';
93
+ const { status, json } = await this.#send(url);
94
+ if (status >= 300 || !json || json.resourceType !== 'Parameters') {
95
+ const msg = json && json.resourceType === 'OperationOutcome' ? VirtualCodeSystemProvider.#outcomeText(json) : null;
96
+ return { context: null, message: msg || `Code '${code}' not found on ${this.server}` };
97
+ }
98
+ const ctxt = { code, display: null, inactive: false, abstract: false, status: null, designations: [] };
99
+ for (const p of json.parameter || []) {
100
+ if (p.name === 'display') {
101
+ ctxt.display = p.valueString;
102
+ } else if (p.name === 'abstract') {
103
+ ctxt.abstract = p.valueBoolean === true;
104
+ } else if (p.name === 'inactive') {
105
+ ctxt.inactive = p.valueBoolean === true;
106
+ } else if (p.name === 'designation') {
107
+ const d = {};
108
+ for (const part of p.part || []) {
109
+ if (part.name === 'language') d.language = part.valueCode;
110
+ if (part.name === 'use') d.use = part.valueCoding;
111
+ if (part.name === 'value') d.value = part.valueString;
112
+ }
113
+ if (d.value) {
114
+ ctxt.designations.push(d);
115
+ }
116
+ } else if (p.name === 'property') {
117
+ const pc = (p.part || []).find(x => x.name === 'code');
118
+ const pv = (p.part || []).find(x => x.name === 'value');
119
+ if (pc && pv) {
120
+ if (pc.valueCode === 'inactive' && pv.valueBoolean !== undefined) ctxt.inactive = pv.valueBoolean;
121
+ if (pc.valueCode === 'notSelectable' && pv.valueBoolean !== undefined) ctxt.abstract = pv.valueBoolean;
122
+ if (pc.valueCode === 'status') ctxt.status = pv.valueCode || pv.valueString || null;
123
+ }
124
+ }
125
+ }
126
+ return { context: ctxt, message: null };
127
+ }
128
+
129
+ async code(context) { return typeof context === 'string' ? context : context.code; }
130
+ async display(context) { return (await this.locate(context)).context?.display || null; }
131
+ async isAbstract(context) { return (await this.locate(context)).context?.abstract || false; }
132
+ async isInactive(context) { return (await this.locate(context)).context?.inactive || false; }
133
+ async getStatus(context) {
134
+ const ctxt = (await this.locate(context)).context;
135
+ return ctxt ? (ctxt.status || (ctxt.inactive ? 'inactive' : null)) : null;
136
+ }
137
+ async incompleteValidationMessage() { return null; }
138
+ async classificationCode() { return null; }
139
+ async codeIssues() { return []; }
140
+ async reportedClassificationCode() { return null; }
141
+
142
+ // designations() marks the ones that are displays as it adds them, so no others are
143
+ isDisplay() { return false; }
144
+
145
+ async designations(context, displays) {
146
+ const ctxt = (await this.locate(context)).context;
147
+ if (ctxt) {
148
+ if (ctxt.display) {
149
+ displays.addDesignation(true, 'active', this.defLang(), DesignationUse.DISPLAY, ctxt.display);
150
+ }
151
+ for (const d of ctxt.designations) {
152
+ if (d.value !== ctxt.display) {
153
+ // any designation is a valid display, except a fully specified name
154
+ const fsn = d.use && d.use.code === DesignationUse.FSN.code;
155
+ displays.addDesignation(!fsn, 'active', d.language || '', d.use || null, d.value);
156
+ }
157
+ }
158
+ }
159
+ }
160
+
161
+ // --- filters ----------------------------------------------------------------------------------
162
+ //
163
+ // the filters on an include are collected, and a code is checked against them all at once, by
164
+ // $validate-code on the other server against a value set with just that include
165
+
166
+ async doesFilter() { return true; } // the other server says, when the filter is used
167
+
168
+ async getPrepContext(iterate) {
169
+ return new FilterExecutionContext(iterate);
170
+ }
171
+
172
+ async filter(filterContext, forIteration, prop, op, value) {
173
+ filterContext.filters.push({ property: prop, op, value });
174
+ }
175
+
176
+ async executeFilters(filterContext) {
177
+ return [{ filters: filterContext.filters }];
178
+ }
179
+
180
+ async filterLocate(filterContext, set, code) {
181
+ const include = { system: this.systemUrl, filter: set.filters };
182
+ if (this.versionId) {
183
+ include.version = this.versionId;
184
+ }
185
+ const parameters = { resourceType: 'Parameters', parameter: [
186
+ { name: 'valueSet', resource: { resourceType: 'ValueSet', status: 'active', compose: { include: [include] } } },
187
+ { name: 'system', valueUri: this.systemUrl },
188
+ { name: 'code', valueCode: code }
189
+ ]};
190
+ if (this.versionId) {
191
+ parameters.parameter.push({ name: 'systemVersion', valueString: this.versionId });
192
+ }
193
+ const { status, json } = await this.#send(this.server + '/ValueSet/$validate-code', parameters);
194
+ if (status >= 300 || !json || json.resourceType !== 'Parameters') {
195
+ // the other server couldn't say: that's why the code isn't located, and it's worth reporting
196
+ // (it's passed up to the message, if the code turns out not to be in the value set)
197
+ return `Unable to check '${code}' against the filter ${set.filters.map(f => f.property + ' ' + f.op + ' ' + f.value).join(' and ')} on ${this.server}: ` +
198
+ (json && json.resourceType === 'OperationOutcome' ? VirtualCodeSystemProvider.#outcomeText(json) : 'it returned status ' + status);
199
+ }
200
+ const result = (json.parameter || []).find(p => p.name === 'result');
201
+ if (result && result.valueBoolean === true) {
202
+ const loc = await this.locate(code);
203
+ return loc.context || loc.message;
204
+ }
205
+ // not in the filter: nothing worth saying (the other server's message is about the value set made up here)
206
+ return null;
207
+ }
208
+ }
209
+
210
+ module.exports = { VirtualCodeSystemProvider };