fhirsmith 0.3.0 → 0.5.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 (103) hide show
  1. package/CHANGELOG.md +24 -0
  2. package/README.md +4 -2
  3. package/library/cron-utilities.js +136 -0
  4. package/library/folder-setup.js +6 -0
  5. package/library/html-server.js +13 -29
  6. package/library/html.js +3 -8
  7. package/library/languages.js +160 -37
  8. package/library/package-manager.js +48 -1
  9. package/library/utilities.js +100 -19
  10. package/package.json +2 -2
  11. package/packages/package-crawler.js +6 -1
  12. package/packages/packages.js +38 -54
  13. package/publisher/publisher.js +19 -27
  14. package/registry/api.js +11 -10
  15. package/registry/crawler.js +31 -29
  16. package/registry/model.js +5 -26
  17. package/registry/readme.md +1 -11
  18. package/registry/registry.js +32 -41
  19. package/server.js +53 -5
  20. package/shl/shl.js +0 -18
  21. package/static/assets/js/statuspage.js +1 -9
  22. package/stats.js +39 -1
  23. package/token/token.js +14 -9
  24. package/translations/Messages.properties +2 -1
  25. package/tx/README.md +17 -6
  26. package/tx/cs/cs-api.js +19 -1
  27. package/tx/cs/cs-base.js +77 -0
  28. package/tx/cs/cs-country.js +46 -0
  29. package/tx/cs/cs-cpt.js +9 -5
  30. package/tx/cs/cs-cs.js +27 -13
  31. package/tx/cs/cs-db.js +0 -13
  32. package/tx/cs/cs-lang.js +60 -22
  33. package/tx/cs/cs-loinc.js +69 -98
  34. package/tx/cs/cs-mimetypes.js +4 -0
  35. package/tx/cs/cs-ndc.js +6 -0
  36. package/tx/cs/cs-omop.js +16 -15
  37. package/tx/cs/cs-rxnorm.js +23 -1
  38. package/tx/cs/cs-snomed.js +283 -40
  39. package/tx/cs/cs-ucum.js +90 -70
  40. package/tx/importers/import-sct.module.js +371 -35
  41. package/tx/importers/readme.md +117 -7
  42. package/tx/library/bundle.js +5 -0
  43. package/tx/library/capabilitystatement.js +3 -142
  44. package/tx/library/codesystem.js +19 -173
  45. package/tx/library/conceptmap.js +4 -218
  46. package/tx/library/designations.js +14 -1
  47. package/tx/library/extensions.js +7 -0
  48. package/tx/library/namingsystem.js +3 -89
  49. package/tx/library/operation-outcome.js +8 -3
  50. package/tx/library/parameters.js +3 -2
  51. package/tx/library/renderer.js +10 -6
  52. package/tx/library/terminologycapabilities.js +3 -243
  53. package/tx/library/valueset.js +3 -235
  54. package/tx/library.js +100 -13
  55. package/tx/operation-context.js +23 -4
  56. package/tx/params.js +35 -38
  57. package/tx/provider.js +6 -5
  58. package/tx/sct/expressions.js +12 -3
  59. package/tx/tx-html.js +80 -89
  60. package/tx/tx.fhir.org.yml +6 -5
  61. package/tx/tx.js +163 -13
  62. package/tx/vs/vs-database.js +56 -39
  63. package/tx/vs/vs-package.js +21 -2
  64. package/tx/vs/vs-vsac.js +175 -39
  65. package/tx/workers/batch-validate.js +2 -0
  66. package/tx/workers/batch.js +2 -0
  67. package/tx/workers/expand.js +132 -112
  68. package/tx/workers/lookup.js +33 -14
  69. package/tx/workers/metadata.js +2 -2
  70. package/tx/workers/read.js +3 -2
  71. package/tx/workers/related.js +574 -0
  72. package/tx/workers/search.js +46 -9
  73. package/tx/workers/subsumes.js +13 -3
  74. package/tx/workers/translate.js +7 -3
  75. package/tx/workers/validate.js +258 -285
  76. package/tx/workers/worker.js +43 -39
  77. package/tx/xml/bundle-xml.js +237 -0
  78. package/tx/xml/xml-base.js +215 -64
  79. package/tx/xversion/xv-bundle.js +71 -0
  80. package/tx/xversion/xv-capabiliityStatement.js +137 -0
  81. package/tx/xversion/xv-codesystem.js +169 -0
  82. package/tx/xversion/xv-conceptmap.js +224 -0
  83. package/tx/xversion/xv-namingsystem.js +88 -0
  84. package/tx/xversion/xv-operationoutcome.js +27 -0
  85. package/tx/xversion/xv-parameters.js +87 -0
  86. package/tx/xversion/xv-resource.js +45 -0
  87. package/tx/xversion/xv-terminologyCapabilities.js +214 -0
  88. package/tx/xversion/xv-valueset.js +234 -0
  89. package/utilities/dev-proxy-server.js +126 -0
  90. package/utilities/explode-results.js +58 -0
  91. package/utilities/split-by-system.js +198 -0
  92. package/utilities/vsac-cs-fetcher.js +0 -0
  93. package/{windows-install.js → utilities/windows-install.js} +2 -0
  94. package/vcl/vcl.js +0 -18
  95. package/xig/xig.js +108 -99
  96. package/passwords.ini +0 -2
  97. package/registry/registry-data.json +0 -121015
  98. package/shl/private-key.pem +0 -5
  99. package/shl/public-key.pem +0 -18
  100. package/test-cache/vsac/vsac-valuesets.db +0 -0
  101. package/tx/dev.fhir.org.yml +0 -14
  102. package/tx/fixtures/test-cases-setup.json +0 -18
  103. package/tx/fixtures/test-cases.yml +0 -16
package/stats.js CHANGED
@@ -1,5 +1,6 @@
1
1
  const { monitorEventLoopDelay } = require('perf_hooks');
2
- const {cache} = require("express/lib/application");
2
+ const {Utilities} = require("./library/utilities");
3
+ const escape = require('escape-html');
3
4
 
4
5
  class ServerStats {
5
6
  started = false;
@@ -13,6 +14,7 @@ class ServerStats {
13
14
  startTime = Date.now();
14
15
  timer;
15
16
  cachingModules = [];
17
+ taskMap = new Map();
16
18
 
17
19
  constructor() {
18
20
  this.timer = setInterval(() => {
@@ -73,6 +75,42 @@ class ServerStats {
73
75
  this.requestTime = this.requestTime + tat;
74
76
  }
75
77
 
78
+ addTask(name, frequency) {
79
+ let info = {};
80
+ this.taskMap.set(name, info);
81
+ info.frequency = frequency;
82
+ info.state = "Started";
83
+ }
84
+
85
+ task(name, state) {
86
+ let info = this.taskMap.get(name);
87
+ if (info) {
88
+ info.date = Date.now();
89
+ info.state = state;
90
+ }
91
+ }
92
+
93
+ taskDetails() {
94
+ if (this.taskMap.size == 0) {
95
+ return "";
96
+ }
97
+ let html = '<table class="grid"><tr style="background-color: #EEEEEE"><th colspan="4">Background Tasks</th></tr>';
98
+ html += "<tr><th>Task</th><th>Status</th><th>Frequency</th><th>Last Seen</th></tr>";
99
+ for (let m of this.taskMap.keys()) {
100
+ html += "<tr><td>";
101
+ html += escape(m);
102
+ html += "</td><td>";
103
+ html += escape(this.taskMap.get(m).state);
104
+ html += "</td><td>";
105
+ html += this.taskMap.get(m).frequency;
106
+ html += "</td><td>";
107
+ html += Utilities.formatDuration(this.taskMap.get(m).date, Date.now());
108
+ html += "</td></tr>";
109
+ }
110
+ html += "</table>";
111
+ return html;
112
+ }
113
+
76
114
  finishStats() {
77
115
  clearInterval(this.timer);
78
116
  }
package/token/token.js CHANGED
@@ -19,6 +19,7 @@ const GitHubStrategy = require('passport-github2').Strategy;
19
19
  const rateLimit = require('express-rate-limit');
20
20
  const lusca = require('lusca');
21
21
  const folders = require('../library/folder-setup');
22
+ const escape = require('escape-html');
22
23
 
23
24
 
24
25
  const Logger = require('../library/logger');
@@ -325,6 +326,7 @@ class TokenModule {
325
326
  this.log.info('OAuth strategies configured:', configuredStrategies);
326
327
  }
327
328
 
329
+ // eslint-disable-next-line no-unused-vars
328
330
  async handleOAuthCallback(req, provider, profile, tokens) {
329
331
  const email = this.extractEmail(profile);
330
332
  const name = this.extractName(profile);
@@ -928,6 +930,7 @@ class TokenModule {
928
930
  });
929
931
  }
930
932
 
933
+ // eslint-disable-next-line no-unused-vars
931
934
  async updateKeyLastUsed(keyId, ip = null) {
932
935
  return new Promise((resolve, reject) => {
933
936
  this.db.run(
@@ -1004,6 +1007,7 @@ class TokenModule {
1004
1007
  }
1005
1008
 
1006
1009
  async logSecurityEvent(userId, eventType, ip, userAgent, details) {
1010
+ // eslint-disable-next-line no-unused-vars
1007
1011
  return new Promise((resolve, reject) => {
1008
1012
  this.db.run(
1009
1013
  'INSERT INTO security_log (user_id, event_type, ip_address, user_agent, details) VALUES (?, ?, ?, ?, ?)',
@@ -1020,14 +1024,15 @@ class TokenModule {
1020
1024
  }
1021
1025
 
1022
1026
  // Content builders
1027
+ // eslint-disable-next-line no-unused-vars
1023
1028
  buildDashboardContent(user, apiKeys, usageStats) {
1024
1029
  let content = `
1025
1030
  <div class="row mb-4">
1026
1031
  <div class="col-12">
1027
1032
  <div class="d-flex justify-content-between align-items-center">
1028
1033
  <div>
1029
- <h3>Welcome, ${htmlServer.escapeHtml(user.name)}</h3>
1030
- <p class="text-muted">Email: ${htmlServer.escapeHtml(user.email)} | Provider: ${htmlServer.escapeHtml(user.provider)}</p>
1034
+ <h3>Welcome, ${escape(user.name)}</h3>
1035
+ <p class="text-muted">Email: ${escape(user.email)} | Provider: ${escape(user.provider)}</p>
1031
1036
  </div>
1032
1037
  <form method="POST" action="/token/logout" class="d-inline">
1033
1038
  <button type="submit" class="btn btn-outline-secondary">Logout</button>
@@ -1126,16 +1131,16 @@ class TokenModule {
1126
1131
 
1127
1132
  content += `
1128
1133
  <tr>
1129
- <td><strong>${htmlServer.escapeHtml(key.name)}</strong></td>
1130
- <td><code>${htmlServer.escapeHtml(key.key_prefix)}...</code></td>
1131
- <td><span class="badge bg-secondary">${htmlServer.escapeHtml(scopes)}</span></td>
1134
+ <td><strong>${escape(key.name)}</strong></td>
1135
+ <td><code>${escape(key.key_prefix)}...</code></td>
1136
+ <td><span class="badge bg-secondary">${escape(scopes)}</span></td>
1132
1137
  <td>${new Date(key.created_at).toLocaleDateString()}</td>
1133
1138
  <td>${lastUsed}</td>
1134
1139
  <td>${expires}</td>
1135
1140
  <td><span class="${statusClass}">${status}</span></td>
1136
1141
  <td>
1137
1142
  ${key.is_active ?
1138
- `<button class="btn btn-sm btn-danger" onclick="deleteKey(${key.id}, '${htmlServer.escapeHtml(key.name)}')">Delete</button>` :
1143
+ `<button class="btn btn-sm btn-danger" onclick="deleteKey(${key.id}, '${escape(key.name)}')">Delete</button>` :
1139
1144
  '<span class="text-muted">-</span>'
1140
1145
  }
1141
1146
  </td>
@@ -1176,7 +1181,7 @@ class TokenModule {
1176
1181
 
1177
1182
  content += `
1178
1183
  <div class="alert alert-danger" role="alert">
1179
- <strong>Error:</strong> ${htmlServer.escapeHtml(errorMessage)}
1184
+ <strong>Error:</strong> ${escape(errorMessage)}
1180
1185
  </div>
1181
1186
  `;
1182
1187
  }
@@ -1252,7 +1257,7 @@ class TokenModule {
1252
1257
  <!DOCTYPE html>
1253
1258
  <html lang="en">
1254
1259
  <head>
1255
- <title>${htmlServer.escapeHtml(title)} - FHIR Token Server</title>
1260
+ <title>${escape(title)} - FHIR Token Server</title>
1256
1261
  <meta charset="utf-8">
1257
1262
  <meta name="viewport" content="width=device-width, initial-scale=1">
1258
1263
  <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css" rel="stylesheet">
@@ -1263,7 +1268,7 @@ class TokenModule {
1263
1268
  <nav class="mb-4">
1264
1269
  <a href="/" class="text-decoration-none">← Back to Server Home</a>
1265
1270
  </nav>
1266
- <h1 class="mb-4">${htmlServer.escapeHtml(title)}</h1>
1271
+ <h1 class="mb-4">${escape(title)}</h1>
1267
1272
  ${content}
1268
1273
  </div>
1269
1274
  <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/js/bootstrap.bundle.min.js"></script>
@@ -1312,7 +1312,8 @@ VS_EXP_IMPORT_UNK_PINNED = Unable to find included value set ''{0}'' version ''{
1312
1312
  VS_EXP_IMPORT_UNK_PINNED_X = Unable to find excluded value set ''{0}'' version ''{1}''
1313
1313
  VS_EXP_IMPORT_UNK_X = Unable to find excluded value set ''{0}''
1314
1314
  Wrong_namespace__expected_ = Wrong namespace - expected ''{0}''
1315
- Wrong_type_for_resource = Wrong type for resource
1315
+ Wrong_type_for_resource = Wrong type for resource
1316
+ Wrong_type_for_resource_expected = Wrong type for resource. Expected {0} but found {1}
1316
1317
  TEXT_LINK_DATA_NOT_FOUND = The target of the textLink data reference ''{0}'' was not found in the resource
1317
1318
  TEXT_LINK_DATA_MULTIPLE_MATCHES = Multiple matching targets for the textLink data reference ''{0}'' were found in the resource
1318
1319
  XHTML_URL_DATA_DATA_INVALID = The data should be valid base64 content for a data: URL: {0}
package/tx/README.md CHANGED
@@ -4,12 +4,7 @@ The TX module provides FHIR terminology services for CodeSystem, ValueSet, and C
4
4
 
5
5
  ## Todo
6
6
 
7
- * More work on the HTML interface (external code systems, global functions, render capability statements)
8
- * add more tests for the code system providers - filters, extended lookup, designations and languages
9
- * more refactoring in validate.js and expand.js
10
- * full batch support
11
- * check vsac support
12
- * get tx tests running in pipelines
7
+ * Improve batch support
13
8
 
14
9
  ## Overview
15
10
 
@@ -303,6 +298,22 @@ You can specify a version using the `#` syntax:
303
298
 
304
299
  If no version is specified, the latest released version is fetched.
305
300
 
301
+ #### `url` - FHIR Packages from Direct URLs
302
+
303
+ Loads a FHIR package directly from a tarball URL instead of the FHIR package registry. Useful for packages hosted on CI build servers, branches, or other locations.
304
+
305
+ Use `url/cs` to load only CodeSystem resources from the package (same as `npm/cs`).
306
+
307
+ ```yaml
308
+ # Load a package from a CI build server
309
+ - url:https://example.com/my-package/package.tgz
310
+
311
+ # Load a code-systems-only package from a URL
312
+ - url/cs:https://example.com/my-codesystems/package.tgz
313
+ ```
314
+
315
+ The URL must point to a `.tgz` file in standard FHIR NPM package format. Downloaded packages are cached locally by URL.
316
+
306
317
  ### Default Marker (`!`)
307
318
 
308
319
  When multiple versions of the same code system are loaded, append `!` to mark one as the default:
package/tx/cs/cs-api.js CHANGED
@@ -11,6 +11,11 @@ const {VersionUtilities} = require("../../library/version-utilities");
11
11
 
12
12
  class FilterExecutionContext {
13
13
  filters = [];
14
+ forIterate = false;
15
+
16
+ constructor(forIterate) {
17
+ this.forIterate = forIterate;
18
+ }
14
19
  }
15
20
 
16
21
  class CodeSystemProvider {
@@ -122,6 +127,17 @@ class CodeSystemProvider {
122
127
  isNotClosed() {
123
128
  return false;
124
129
  }
130
+
131
+ /**
132
+ * returns true if the code system is case sensitive when comparing codes.
133
+ * this is true by default
134
+ *
135
+ * @returns {boolean}
136
+ */
137
+ isCaseSensitive() {
138
+ return true;
139
+ }
140
+
125
141
  /**
126
142
  * @param {Languages} languages language specification
127
143
  * @returns {boolean} defined properties for the code system
@@ -489,7 +505,7 @@ class CodeSystemProvider {
489
505
  * @param {boolean} iterate true if the conceptSets that result from this will be iterated, and false if they'll be used to locate a single code
490
506
  * @returns {FilterExecutionContext} filter (or null, it no use for this)
491
507
  * */
492
- async getPrepContext(iterate) { return new FilterExecutionContext(); }
508
+ async getPrepContext(iterate) { return new FilterExecutionContext(iterate); }
493
509
 
494
510
  /**
495
511
  * executes a text search filter (whatever that means) and returns a FilterConceptSet
@@ -662,6 +678,8 @@ class CodeSystemProvider {
662
678
  valueSet() {
663
679
  return null;
664
680
  }
681
+
682
+
665
683
  }
666
684
 
667
685
  class CodeSystemFactoryProvider {
@@ -0,0 +1,77 @@
1
+ const {CodeSystemProvider} = require("./cs-api");
2
+
3
+ class BaseCSServices extends CodeSystemProvider {
4
+
5
+ _addProperty(params, type, name, value, language = null) {
6
+
7
+ const property = {
8
+ name: type,
9
+ part: [
10
+ {name: 'code', valueCode: name},
11
+ {name: 'value', valueString: value}
12
+ ]
13
+ };
14
+
15
+ if (language) {
16
+ property.part.push({name: 'language', valueCode: language});
17
+ }
18
+
19
+ params.push(property);
20
+ }
21
+
22
+
23
+ _addCodeProperty(params, type, name, value, language = null, description = null) {
24
+
25
+ const property = {
26
+ name: type,
27
+ part: [
28
+ {name: 'code', valueCode: name},
29
+ {name: 'value', valueCode: value}
30
+ ]
31
+ };
32
+
33
+ if (language) {
34
+ property.part.push({name: 'language', valueCode: language});
35
+ }
36
+ if (description) {
37
+ property.part.push({name: 'description', valueString: description});
38
+ }
39
+
40
+ params.push(property);
41
+ return property;
42
+ }
43
+
44
+ _addStringProperty(params, type, name, value, language = null) {
45
+
46
+ const property = {
47
+ name: type,
48
+ part: [
49
+ {name: 'code', valueCode: name},
50
+ {name: 'value', valueString: value}
51
+ ]
52
+ };
53
+
54
+ if (language) {
55
+ property.part.push({name: 'language', valueCode: language});
56
+ }
57
+
58
+ params.push(property);
59
+ return property;
60
+ }
61
+
62
+
63
+ // Helper to check if a property should be included
64
+ _hasProp = (props, name, defaultValue = true) => {
65
+ if (!props || props.length === 0) {
66
+ return defaultValue;
67
+ }
68
+ const lowerName = name.toLowerCase();
69
+ return props.some(p =>
70
+ p.toLowerCase() === lowerName || p === '*'
71
+ );
72
+ };
73
+ }
74
+
75
+ module.exports = {
76
+ BaseCSServices
77
+ };
@@ -578,6 +578,52 @@ class CountryCodeFactoryProvider extends CodeSystemFactoryProvider {
578
578
  ['ZM', 'Zambia'],
579
579
  ['ZW', 'Zimbabwe'],
580
580
 
581
+ // ISO 3166-1 User-assigned code elements
582
+ // These codes are reserved for user assignment and will never be used for country names
583
+ // See: https://en.wikipedia.org/wiki/ISO_3166-1_alpha-2#User-assigned_code_elements
584
+ ['AA', 'User-assigned'],
585
+ ['QM', 'User-assigned'],
586
+ ['QN', 'User-assigned'],
587
+ ['QO', 'User-assigned'],
588
+ ['QP', 'User-assigned'],
589
+ ['QQ', 'User-assigned'],
590
+ ['QR', 'User-assigned'],
591
+ ['QS', 'User-assigned'],
592
+ ['QT', 'User-assigned'],
593
+ ['QU', 'User-assigned'],
594
+ ['QV', 'User-assigned'],
595
+ ['QW', 'User-assigned'],
596
+ ['QX', 'User-assigned'],
597
+ ['QY', 'User-assigned'],
598
+ ['QZ', 'User-assigned'],
599
+ ['XA', 'User-assigned'],
600
+ ['XB', 'User-assigned'],
601
+ ['XC', 'User-assigned'],
602
+ ['XD', 'User-assigned'],
603
+ ['XE', 'User-assigned'],
604
+ ['XF', 'User-assigned'],
605
+ ['XG', 'User-assigned'],
606
+ ['XH', 'User-assigned'],
607
+ ['XI', 'User-assigned'],
608
+ ['XJ', 'User-assigned'],
609
+ ['XK', 'Kosovo'],
610
+ ['XL', 'User-assigned'],
611
+ ['XM', 'User-assigned'],
612
+ ['XN', 'User-assigned'],
613
+ ['XO', 'User-assigned'],
614
+ ['XP', 'User-assigned'],
615
+ ['XQ', 'User-assigned'],
616
+ ['XR', 'User-assigned'],
617
+ ['XS', 'User-assigned'],
618
+ ['XT', 'User-assigned'],
619
+ ['XU', 'User-assigned'],
620
+ ['XV', 'User-assigned'],
621
+ ['XW', 'User-assigned'],
622
+ ['XX', 'Unknown'],
623
+ ['XY', 'User-assigned'],
624
+ ['XZ', 'International Waters'],
625
+ ['ZZ', 'Unknown or Invalid Territory'],
626
+
581
627
  // 3-letter codes
582
628
  ['ABW', 'Aruba'],
583
629
  ['AFG', 'Afghanistan'],
package/tx/cs/cs-cpt.js CHANGED
@@ -1,8 +1,9 @@
1
1
  const sqlite3 = require('sqlite3').verbose();
2
2
  const assert = require('assert');
3
3
  const { CodeSystem } = require('../library/codesystem');
4
- const { CodeSystemProvider, FilterExecutionContext, CodeSystemFactoryProvider } = require('./cs-api');
4
+ const { FilterExecutionContext, CodeSystemFactoryProvider } = require('./cs-api');
5
5
  const {validateArrayParameter} = require("../../library/utilities");
6
+ const {BaseCSServices} = require("./cs-base");
6
7
 
7
8
  class CPTConceptDesignation {
8
9
  constructor(kind, value) {
@@ -108,7 +109,7 @@ class CPTPrep extends FilterExecutionContext {
108
109
  }
109
110
  }
110
111
 
111
- class CPTServices extends CodeSystemProvider {
112
+ class CPTServices extends BaseCSServices {
112
113
  constructor(opContext, supplements, db, sharedData) {
113
114
  super(opContext, supplements);
114
115
  this.db = db;
@@ -224,6 +225,9 @@ class CPTServices extends CodeSystemProvider {
224
225
 
225
226
  }
226
227
 
228
+ isNotClosed() {
229
+ return true;
230
+ }
227
231
  async extendLookup(ctxt, props, params) {
228
232
  validateArrayParameter(props, 'props', String);
229
233
  validateArrayParameter(params, 'params', Object);
@@ -255,7 +259,7 @@ class CPTServices extends CodeSystemProvider {
255
259
  }
256
260
  } else if (ctxt instanceof CPTConcept) {
257
261
  // Add designations
258
- if (this.#hasProp(props, 'designation', true)) {
262
+ if (this._hasProp(props, 'designation', true)) {
259
263
  for (const d of ctxt.designations) {
260
264
  this.#addProperty(params, 'designation', d.kind, d.value, 'en');
261
265
  }
@@ -263,7 +267,7 @@ class CPTServices extends CodeSystemProvider {
263
267
 
264
268
  // Add properties
265
269
  for (const p of ctxt.properties) {
266
- if (this.#hasProp(props, p.name, true)) {
270
+ if (this._hasProp(props, p.name, true)) {
267
271
  this.#addProperty(params, 'property', p.name, p.value);
268
272
  }
269
273
  }
@@ -545,7 +549,7 @@ class CPTServices extends CodeSystemProvider {
545
549
  if (concept) {
546
550
  return concept;
547
551
  }
548
- return `Code ${code} is not in the specified filter`;
552
+ return null;
549
553
  }
550
554
 
551
555
  async filterCheck(filterContext, set, concept) {
package/tx/cs/cs-cs.js CHANGED
@@ -1,10 +1,11 @@
1
1
  const { CodeSystem} = require("../library/codesystem");
2
- const { CodeSystemFactoryProvider, CodeSystemProvider, FilterExecutionContext } = require( "./cs-api");
2
+ const { CodeSystemFactoryProvider, FilterExecutionContext } = require( "./cs-api");
3
3
  const { VersionUtilities } = require("../../library/version-utilities");
4
4
  const { Language } = require ("../../library/languages");
5
5
  const { validateOptionalParameter, getValuePrimitive, validateArrayParameter} = require("../../library/utilities");
6
6
  const {Issue} = require("../library/operation-outcome");
7
7
  const {Extensions} = require("../library/extensions");
8
+ const {BaseCSServices} = require("./cs-base");
8
9
 
9
10
  /**
10
11
  * Context class for FHIR CodeSystem provider concepts
@@ -101,7 +102,7 @@ class FhirCodeSystemProviderFilterContext {
101
102
  }
102
103
  }
103
104
 
104
- class FhirCodeSystemProvider extends CodeSystemProvider {
105
+ class FhirCodeSystemProvider extends BaseCSServices {
105
106
  /**
106
107
  * @param {CodeSystem} codeSystem - The primary CodeSystem
107
108
  * @param {CodeSystem[]} supplements - Array of supplement CodeSystems
@@ -385,6 +386,10 @@ class FhirCodeSystemProvider extends CodeSystemProvider {
385
386
  return ctxt ? (ctxt.concept.definition || null) : null;
386
387
  }
387
388
 
389
+ isCaseSensitive() {
390
+ return !this.codeSystem.caseInsensitive();
391
+ }
392
+
388
393
  /**
389
394
  * @param {string|FhirCodeSystemProviderContext} context - Code or context
390
395
  * @returns {Promise<boolean>} If the concept is abstract
@@ -642,6 +647,15 @@ class FhirCodeSystemProvider extends CodeSystemProvider {
642
647
  return extensions.length > 0 ? extensions : null;
643
648
  }
644
649
 
650
+ getPropertyDefinition(cs, code) {
651
+ for (let p of cs.property || []) {
652
+ if (code == p.code) {
653
+ return p;
654
+ }
655
+ }
656
+ return undefined;
657
+ }
658
+
645
659
  /**
646
660
  * @param {string|FhirCodeSystemProviderContext} context - Code or context
647
661
  * @returns {Promise<Object[]|null>} Properties, if any
@@ -656,16 +670,20 @@ class FhirCodeSystemProvider extends CodeSystemProvider {
656
670
  const properties = [];
657
671
 
658
672
  // Add properties from main concept
659
- if (ctxt.concept.property && Array.isArray(ctxt.concept.property)) {
660
- properties.push(...ctxt.concept.property);
673
+ for (let p of ctxt.concept.property || []) {
674
+ let pd = this.getPropertyDefinition(this.codeSystem.jsonObj, p.code);
675
+ properties.push({ ...p, definition: pd });
661
676
  }
662
677
 
663
678
  // Add properties from supplements
664
679
  if (this.supplements) {
665
680
  for (const supplement of this.supplements) {
666
681
  const supplementConcept = supplement.getConceptByCode(ctxt.code);
667
- if (supplementConcept && supplementConcept.property && Array.isArray(supplementConcept.property)) {
668
- properties.push(...supplementConcept.property);
682
+ if (supplementConcept) {
683
+ for (let p of supplementConcept.property || []) {
684
+ let pd = this.getPropertyDefinition(supplement.jsonObj, p.code);
685
+ properties.push({...p, definition: pd});
686
+ }
669
687
  }
670
688
  }
671
689
  }
@@ -886,12 +904,8 @@ class FhirCodeSystemProvider extends CodeSystemProvider {
886
904
  return;
887
905
  }
888
906
 
889
- // Set abstract status
890
- if (!params.find(p => p.name == "abstract") && await this.isAbstract(ctxt)) {
891
- params.push({ name: 'property', part: [ { name: 'code', valueCode: 'abstract' }, { name: 'value', valueBoolean: true } ]});
892
- }
893
907
  // Add properties if requested (or by default)
894
- if (!props || props.length === 0 || props.includes('*') || props.includes('property')) {
908
+ if (this._hasProp(props, 'property', true)) {
895
909
  const properties = await this.properties(ctxt);
896
910
  if (properties) {
897
911
  for (const property of properties) {
@@ -920,7 +934,7 @@ class FhirCodeSystemProvider extends CodeSystemProvider {
920
934
  }
921
935
 
922
936
  // Add parent if requested and exists
923
- if (!props || props.length === 0 || props.includes('*') || props.includes('parent')) {
937
+ if (this._hasProp(props, 'parent', true)) {
924
938
  const parentCode = await this.parent(ctxt);
925
939
  if (parentCode) {
926
940
  let parts = [];
@@ -932,7 +946,7 @@ class FhirCodeSystemProvider extends CodeSystemProvider {
932
946
  }
933
947
 
934
948
  // Add children if requested
935
- if (!props || props.length === 0 || props.includes('*') || props.includes('child')) {
949
+ if (this._hasProp(props, 'child', true)) {
936
950
  const children = this.codeSystem.getChildren(ctxt.code);
937
951
  if (children.length > 0) {
938
952
  for (const childCode of children) {
package/tx/cs/cs-db.js CHANGED
@@ -5,19 +5,6 @@ const { Language, Languages} = require('../../library/languages');
5
5
  const { CodeSystemProvider, CodeSystemFactoryProvider} = require('./cs-api');
6
6
  const { validateOptionalParameter, validateArrayParameter} = require("../../library/utilities");
7
7
 
8
- /**
9
- * SQL Tables:
10
- *
11
- * Metadata: Name, Value
12
- * Concepts: ConceptKey, Code, Display, Definition, Parent
13
- * Closure: ParentKey, ChildKey
14
- * DesignationUses: DesignationUseKey, System, Version, Code, Display
15
- * Languages: LanguageKey, LanguageCode
16
- * Designations: ConceptKey, LanguageKey, DesignationUseKey, Value
17
- * PropertyDefinitions: PropertyDefinitionKey, Code, Uri, Description, Type
18
- * Properties: PropertyKey, PropertyDefinitionKey, Value, System, Version, Display
19
- */
20
-
21
8
  class CachedDesignation {
22
9
  constructor(display, language, use) {
23
10
  this.display = display;