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
@@ -8,6 +8,8 @@ const { checkContained } = require('../library/canonical-resource');
8
8
  const { VersionUtilities } = require('../../library/version-utilities');
9
9
  const {validateParameter} = require("../../library/utilities");
10
10
  const { applyIdPrefix, stripIdPrefix } = require('../library/resource-ids');
11
+ const { keepForPinnedReference } = require('../library/tho-precedence');
12
+ const { waitForCache } = require('../library/wait-for-cache');
11
13
 
12
14
  /**
13
15
  * Package-based ValueSet provider using shared database layer
@@ -17,15 +19,19 @@ class PackageValueSetProvider extends AbstractValueSetProvider {
17
19
 
18
20
  /**
19
21
  * @param {PackageContentLoader} packageLoader - Path to the extracted package folder
22
+ * @param {Object} [options]
23
+ * @param {boolean} [options.readOnly] - a tx-worker (cluster.md): the cache is the master's; it
24
+ * is opened read-only, waited for until the master has finished it, and never built or changed
20
25
  */
21
- constructor(packageLoader) {
26
+ constructor(packageLoader, options = {}) {
22
27
  super();
23
28
  validateParameter(packageLoader, "packageLoader", PackageContentLoader);
24
29
  this.packageLoader = packageLoader;
25
30
  // -2: caches from before value sets were checked for active content in their narrative
26
31
  // are rebuilt (see initialize)
27
32
  this.dbPath = path.join(packageLoader.packageFolder, '.valuesets-2.db');
28
- this.database = new ValueSetDatabase(this.dbPath);
33
+ this.readOnly = !!options.readOnly;
34
+ this.database = new ValueSetDatabase(this.dbPath, { readOnly: this.readOnly });
29
35
  this.valueSetMap = new Map();
30
36
  this.initialized = false;
31
37
  this.count = 0;
@@ -48,6 +54,13 @@ class PackageValueSetProvider extends AbstractValueSetProvider {
48
54
  return;
49
55
  }
50
56
  await this.packageLoader.initialize();
57
+ if (this.readOnly) {
58
+ await waitForCache(async () => (await this.database.exists()) && (await this.database.isComplete()),
59
+ `Package ${this.packageLoader.pid ? this.packageLoader.pid() : ''}: value set cache ${this.dbPath}`);
60
+ this.valueSetMap = await this.database.loadAllValueSets(this.sourcePackage());
61
+ this.#finishLoad();
62
+ return;
63
+ }
51
64
  await fs.rm(path.join(this.packageLoader.packageFolder, '.valuesets.db'), { force: true }); // the old cache
52
65
 
53
66
  // A cache is only used once its population finished. One that was cut short
@@ -76,7 +89,10 @@ class PackageValueSetProvider extends AbstractValueSetProvider {
76
89
  await this.#buildDatabase();
77
90
  this.valueSetMap = await this.database.loadAllValueSets(this.sourcePackage());
78
91
  }
92
+ this.#finishLoad();
93
+ }
79
94
 
95
+ #finishLoad() {
80
96
  // Mark each value set as cached as it enters the store: it is retained in
81
97
  // memory for the process lifetime, so its compose.include.filter elements
82
98
  // persist and a provider may memoise resolved filter analysis on them
@@ -267,7 +283,7 @@ class PackageValueSetProvider extends AbstractValueSetProvider {
267
283
 
268
284
  // Only process each ValueSet once (use URL to deduplicate)
269
285
  const vsUrl = json.url;
270
- if (seen.has(vsUrl)) {
286
+ if (seen.has(vsUrl) || this.#excludedUrls.has(vsUrl)) {
271
287
  continue;
272
288
  }
273
289
 
@@ -291,6 +307,13 @@ class PackageValueSetProvider extends AbstractValueSetProvider {
291
307
  isMatch = false;
292
308
  break;
293
309
  }
310
+ } else if (param === 'version') {
311
+ // version-aware matching, on the version as asked for (not lower cased)
312
+ const asked = searchParams.find(sp => sp.name === 'version').value;
313
+ if (!VersionUtilities.versionSearchMatches(asked, json.version, VersionUtilities.versionAlgorithmOf(json))) {
314
+ isMatch = false;
315
+ break;
316
+ }
294
317
  } else if (param === 'jurisdiction') {
295
318
  // Special handling for jurisdiction - array of CodeableConcept
296
319
  if (!this._matchJurisdiction(json.jurisdiction, searchValue)) {
@@ -304,8 +327,9 @@ class PackageValueSetProvider extends AbstractValueSetProvider {
304
327
  break;
305
328
  }
306
329
  } else if (param === 'url') {
307
- const propValue = json[param];
308
- if (!this._matchValueFull(propValue, searchValue)) {
330
+ // a left match, on the url as asked for (not lower cased)
331
+ const asked = searchParams.find(sp => sp.name === 'url').value;
332
+ if (!(json.url || '').startsWith(asked)) {
309
333
  isMatch = false;
310
334
  break;
311
335
  }
@@ -460,35 +484,38 @@ class PackageValueSetProvider extends AbstractValueSetProvider {
460
484
  return this.#excludedUrls.size === 0 ? urls : urls.filter(url => !this.#excludedUrls.has(url));
461
485
  }
462
486
 
463
- // the value sets left out by excludeUrls - by url, and by their own (unprefixed) id
487
+ // the value sets left out by keepPinnedOnly - by url, and by their own (unprefixed) id
464
488
  #excludedUrls = new Set();
465
489
  #excludedIds = new Set();
466
490
 
467
491
  /**
468
- * Leave out the value sets with any of these urls: they can't be fetched, and they aren't
469
- * found by search. The FHIR core package's value sets are left out where hl7.terminology
470
- * provides the same url (see Provider.applyTHOPrecedence). Must be called once the
471
- * provider is initialized - the database is shared, so it isn't changed.
492
+ * The value sets with these urls are hl7.terminology's to provide (see
493
+ * Provider.applyTHOPrecedence): from this (core) package they are only available to a
494
+ * reference that names their version, where THO doesn't provide that version itself. They
495
+ * aren't the default for their url, can't be read by id, aren't found by search or listed.
496
+ * Must be called once the provider is initialized - the database is shared, so it isn't
497
+ * changed.
472
498
  *
473
- * @param {Set<string>} urls
499
+ * @param {Map<string, Set<string>>} thoVersions - url -> the versions hl7.terminology provides
474
500
  */
475
- excludeUrls(urls) {
476
- const excluded = new Set();
501
+ keepPinnedOnly(thoVersions) {
502
+ const affected = new Set();
477
503
  for (const vs of this.valueSetMap.values()) {
478
- if (vs && urls.has(vs.url)) {
479
- excluded.add(vs);
504
+ if (vs && thoVersions.has(vs.url)) {
505
+ affected.add(vs);
480
506
  }
481
507
  }
482
508
  for (const [key, vs] of [...this.valueSetMap]) {
483
- if (excluded.has(vs)) {
509
+ if (affected.has(vs) && !keepForPinnedReference(key, vs, thoVersions.get(vs.url))) {
484
510
  this.valueSetMap.delete(key);
485
511
  }
486
512
  }
487
- for (const vs of excluded) {
513
+ for (const vs of affected) {
488
514
  this.#excludedUrls.add(vs.url);
489
515
  this.#excludedIds.add(stripIdPrefix(vs.id, this.spaceId) ?? vs.id);
490
516
  }
491
517
  }
518
+
492
519
  }
493
520
 
494
521
  module.exports = {