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-icd11.js CHANGED
@@ -22,6 +22,7 @@ const { ICD11Expression, parseExpression, axisLabel } = require('./icd11-express
22
22
  const { Issue } = require('../library/operation-outcome');
23
23
  const { DesignationUse } = require('../library/designations');
24
24
  const assert = require('assert');
25
+ const { guarded } = require('../library/sqlite-utilities');
25
26
 
26
27
  // WHO's own vocabulary for the kinds of text an entity carries, used as designation.use.
27
28
  const SCHEMA_NS = 'http://id.who.int/icd/schema';
@@ -100,10 +101,7 @@ class ICD11Services extends BaseCSServices {
100
101
  }
101
102
 
102
103
  close() {
103
- if (this.db) {
104
- this.db.close();
105
- this.db = null;
106
- }
104
+ this.closeDb();
107
105
  }
108
106
 
109
107
  // -- small promise wrappers, so no query below carries callback boilerplate -----------
@@ -116,7 +114,7 @@ class ICD11Services extends BaseCSServices {
116
114
 
117
115
  #all(sql, params = []) {
118
116
  return new Promise((resolve, reject) => {
119
- this.db.all(sql, params, (err, rows) => err ? reject(err) : resolve(rows || []));
117
+ this.db.all(sql, params, guarded(reject, (err, rows) => err ? reject(err) : resolve(rows || [])));
120
118
  });
121
119
  }
122
120
 
@@ -993,12 +991,22 @@ class ICD11ServicesFactory extends CodeSystemFactoryProvider {
993
991
 
994
992
  id() { return `icd11-${this.systemCode}`; }
995
993
 
994
+ /**
995
+ * The WHO browser page for the concept, as the ICD-API gives it (browserUrl, kept in the
996
+ * database: https://icd.who.int/browse/2026-01/mms/en#257068234). A postcoordinated
997
+ * expression links to its stem.
998
+ */
999
+ codeLink(context) {
1000
+ const concept = context && context.tokens ? context.tokens[0]?.concept : context;
1001
+ return concept && concept.browserUrl ? concept.browserUrl : undefined;
1002
+ }
1003
+
996
1004
  async load() {
997
1005
  if (this._loaded) return;
998
1006
  const db = new sqlite3.Database(this.dbPath, sqlite3.OPEN_READONLY);
999
1007
  try {
1000
1008
  const get = (sql, p) => new Promise((res, rej) =>
1001
- db.get(sql, p, (e, r) => e ? rej(e) : res(r)));
1009
+ db.get(sql, p, guarded(rej, (e, r) => e ? rej(e) : res(r))));
1002
1010
  const sys = await get('SELECT * FROM system WHERE code = ?', [this.systemCode]);
1003
1011
  if (!sys) {
1004
1012
  throw new Error(`ICD-11 database ${this.dbPath} has no '${this.systemCode}' code system`);
@@ -1007,7 +1015,7 @@ class ICD11ServicesFactory extends CodeSystemFactoryProvider {
1007
1015
  const langs = await get("SELECT value FROM meta WHERE key = 'languages'", []);
1008
1016
  // per-language titles; a database built before system_title existed has none
1009
1017
  const all = (sql, p) => new Promise((res, rej) =>
1010
- db.all(sql, p, (e, r) => e ? rej(e) : res(r || [])));
1018
+ db.all(sql, p, guarded(rej, (e, r) => e ? rej(e) : res(r || []))));
1011
1019
  const titles = {};
1012
1020
  const hasTitles = await get(
1013
1021
  "SELECT 1 x FROM sqlite_master WHERE type = 'table' AND name = 'system_title'", []);
@@ -1054,8 +1062,8 @@ class ICD11ServicesFactory extends CodeSystemFactoryProvider {
1054
1062
 
1055
1063
  const db = new sqlite3.Database(this.dbPath, sqlite3.OPEN_READONLY);
1056
1064
  try {
1057
- const get = (sql, p) => new Promise((res, rej) => db.get(sql, p, (e, r) => e ? rej(e) : res(r)));
1058
- const all = (sql, p) => new Promise((res, rej) => db.all(sql, p, (e, r) => e ? rej(e) : res(r || [])));
1065
+ const get = (sql, p) => new Promise((res, rej) => db.get(sql, p, guarded(rej, (e, r) => e ? rej(e) : res(r))));
1066
+ const all = (sql, p) => new Promise((res, rej) => db.all(sql, p, guarded(rej, (e, r) => e ? rej(e) : res(r || []))));
1059
1067
  const scale = await get(
1060
1068
  `SELECT ps.id, ps.axis, ps.axis_name, ps.required, ps.allow_multiple,
1061
1069
  c.entity_id, c.code AS stem_code, c.uri AS stem_uri
@@ -1100,14 +1108,14 @@ class ICD11ServicesFactory extends CodeSystemFactoryProvider {
1100
1108
  /** Which code systems a given database holds, so the library can register one each. */
1101
1109
  static listSystems(dbPath) {
1102
1110
  return new Promise((resolve, reject) => {
1103
- const db = new sqlite3.Database(dbPath, sqlite3.OPEN_READONLY, (err) => {
1111
+ const db = new sqlite3.Database(dbPath, sqlite3.OPEN_READONLY, guarded(reject, (err) => {
1104
1112
  if (err) { reject(new Error(`cannot open ICD-11 database ${dbPath}: ${err.message}`)); return; }
1105
- db.all('SELECT code, url, version, title FROM system ORDER BY code', (e, rows) => {
1113
+ db.all('SELECT code, url, version, title FROM system ORDER BY code', guarded(reject, (e, rows) => {
1106
1114
  db.close();
1107
1115
  if (e) reject(new Error(`${dbPath} is not an ICD-11 database: ${e.message}`));
1108
1116
  else resolve(rows || []);
1109
- });
1110
- });
1117
+ }));
1118
+ }));
1111
1119
  });
1112
1120
  }
1113
1121
  }
package/tx/cs/cs-icf.js CHANGED
@@ -195,9 +195,23 @@ class IcfCodeSystemProvider extends FhirCodeSystemProvider {
195
195
  return ctxt instanceof IcfQualifiedContext ? ctxt.qualifiedCode : super.code(ctxt);
196
196
  }
197
197
 
198
- /** The category's display, then the qualifiers' displays, leaving out any 8 (not specified). */
198
+ /**
199
+ * A qualified code's display is the one an extension-codes supplement in scope gives it, if one
200
+ * does. Otherwise it is generated: the category's display, then the qualifiers' displays, leaving
201
+ * out any 8 (not specified).
202
+ */
199
203
  async display(context) {
200
204
  const ctxt = await this.#resolve(context);
205
+ if (ctxt instanceof IcfQualifiedContext) {
206
+ const ext = this._extensionCodeDisplay(ctxt.qualifiedCode);
207
+ if (ext) {
208
+ return ext;
209
+ }
210
+ }
211
+ return this.#generatedDisplay(ctxt);
212
+ }
213
+
214
+ async #generatedDisplay(ctxt) {
201
215
  const display = await super.display(ctxt);
202
216
  if (!(ctxt instanceof IcfQualifiedContext)) {
203
217
  return display;
@@ -207,14 +221,19 @@ class IcfCodeSystemProvider extends FhirCodeSystemProvider {
207
221
  return parts.length > 0 ? display + ': ' + parts.join(', ') : display;
208
222
  }
209
223
 
210
- /** A qualified code has one designation: its display. The category's translations do not describe it. */
224
+ /**
225
+ * A qualified code's designations: the display an extension-codes supplement in scope gives it
226
+ * (first, so it is the preferred display), and its generated display, which stays a valid one. The
227
+ * category's translations do not describe it.
228
+ */
211
229
  async designations(context, displays) {
212
230
  const ctxt = await this.#resolve(context);
213
231
  if (!(ctxt instanceof IcfQualifiedContext)) {
214
232
  return super.designations(ctxt, displays);
215
233
  }
234
+ this._listSupplementDesignations(ctxt.qualifiedCode, displays, true);
216
235
  const lang = this.defaultLanguage ? this.defaultLanguage.toString() : null;
217
- displays.addDesignation(true, 'active', lang, CodeSystem.makeUseForDisplay(), await this.display(ctxt));
236
+ displays.addDesignation(true, 'active', lang, CodeSystem.makeUseForDisplay(), await this.#generatedDisplay(ctxt));
218
237
  }
219
238
 
220
239
  /**
package/tx/cs/cs-lang.js CHANGED
@@ -75,7 +75,7 @@ class IETFLanguageCodeFilter {
75
75
  }
76
76
 
77
77
  /** Why a code did not match, for the caller. @returns {string} */
78
- describe(code, _lang) {
78
+ describe(code) {
79
79
  const action = this.status ? 'does not contain' : 'contains';
80
80
  const requirement = this.status ? 'required' : 'not allowed';
81
81
  return `The language code ${code} ${action} a ${this.component}, and it is ${requirement}`;
@@ -101,7 +101,7 @@ class IETFLanguageEqualityFilter {
101
101
  return value.toLowerCase() === this.value.toLowerCase();
102
102
  }
103
103
 
104
- describe(code, _lang) {
104
+ describe(code) {
105
105
  return `The language code ${code} does not have a ${this.component} of '${this.value}'`;
106
106
  }
107
107
  }