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.
- package/ACCESSIBILITY.md +119 -0
- package/CHANGELOG.md +190 -9
- package/CONFIGURATION.md +305 -0
- package/LICENSE +29 -0
- package/README.md +29 -122
- package/cluster.js +1220 -0
- package/cluster.md +707 -0
- package/config-template.json +77 -8
- package/extension-tracker/extension-tracker-template.html +5 -8
- package/extension-tracker/extension-tracker.js +0 -2
- package/folder/folder.js +7 -6
- package/ips/analysis.js +560 -0
- package/ips/ips-template.html +5 -8
- package/ips/ips.js +331 -33
- package/ips/jurisdictions.js +65 -0
- package/ips/nationality.js +120 -0
- package/ips/pipeline.js +131 -17
- package/ips/presenter.js +1 -1
- package/ips/profile-editor.js +283 -4
- package/ips/readme.md +170 -20
- package/ips/render.js +769 -109
- package/ips/scripts.js +46 -0
- package/ips/store.js +123 -11
- package/ips/structure.js +247 -0
- package/ips/terminology.js +1 -1
- package/library/body-limit.js +22 -0
- package/library/cache-generation.js +15 -0
- package/library/cgroup-memory.js +133 -1
- package/library/cluster-counts.js +121 -0
- package/library/cluster-events.js +153 -0
- package/library/cluster-metrics.js +193 -0
- package/library/cluster-status.js +468 -0
- package/library/config-reader.js +96 -0
- package/library/daily-report.js +100 -2
- package/library/html-server.js +27 -1
- package/library/i18nsupport.js +23 -1
- package/library/keep-alive.js +18 -0
- package/library/languages.js +17 -3
- package/library/logger.js +31 -0
- package/library/memory-guard.js +428 -0
- package/library/native-memory.js +52 -0
- package/library/npm-audit.js +51 -25
- package/library/openapi-doc.js +7 -5
- package/library/package-manager.js +8 -0
- package/library/role.js +197 -0
- package/library/server-credentials.js +169 -0
- package/library/sqlite-utilities.js +59 -0
- package/library/ssrf-guard.js +100 -0
- package/library/static-response-stats.js +16 -0
- package/library/version-utilities.js +50 -0
- package/library/worker-count.js +192 -0
- package/nginx.md +30 -11
- package/npmprojector/indexer.js +18 -10
- package/package.json +11 -8
- package/packages/feed-check-page.js +117 -0
- package/packages/feed-check.js +279 -0
- package/packages/npm-check.js +57 -3
- package/packages/npm-signing.js +219 -0
- package/packages/openapi.yaml +207 -1
- package/packages/package-crawler.js +322 -41
- package/packages/packages-template.html +6 -8
- package/packages/packages.js +604 -57
- package/packages/readme.md +113 -1
- package/publisher/publisher-template.html +2 -5
- package/publisher/publisher.js +121 -110
- package/publisher/readme.md +75 -0
- package/registry/api.js +179 -1
- package/registry/crawler.js +86 -108
- package/registry/documentation/api.md +68 -2
- package/registry/documentation/configuration.md +34 -0
- package/registry/documentation/internals.md +4 -1
- package/registry/documentation/readme.md +3 -2
- package/registry/model.js +8 -0
- package/registry/openapi.yaml +84 -0
- package/registry/registry-template.html +5 -8
- package/registry/registry.js +58 -6
- package/root-bare-template.html +7 -4
- package/root-template.html +5 -8
- package/server.js +398 -198
- package/shl/shl.js +38 -37
- package/static/a11y/a11y-check.js +832 -0
- package/static/a11y/axe.min.js +12 -0
- package/static/assets/css/bootstrap-fhir.css +15 -15
- package/static/assets/images/flags/au.svg +18 -0
- package/static/assets/images/flags/unknown.svg +11 -0
- package/static/assets/images/flags/us.svg +63 -0
- package/static/assets/images/icon_audit.png +0 -0
- package/static/assets/images/icon_clinical.png +0 -0
- package/static/assets/images/icon_document.png +0 -0
- package/static/assets/images/icon_external.png +0 -0
- package/static/assets/images/icon_medication.png +0 -0
- package/static/assets/images/icon_organization.png +0 -0
- package/static/assets/images/icon_other.png +0 -0
- package/static/assets/images/icon_person.png +0 -0
- package/static/assets/images/icon_section.png +0 -0
- package/stats-db.js +45 -0
- package/stats.js +197 -10
- package/testing/testing-template.html +5 -8
- package/token/nginx_passport_setup.md +1 -1
- package/token/security_guide.md +1 -1
- package/token/token-template.html +2 -5
- package/token/token.js +40 -36
- package/translations/Messages.properties +19 -0
- package/tx/README.md +158 -4
- package/tx/closure/closure-store.js +126 -3
- package/tx/cm/cm-database.js +69 -57
- package/tx/cm/cm-package.js +50 -16
- package/tx/cs/cs-api.js +284 -19
- package/tx/cs/cs-api.md +41 -4
- package/tx/cs/cs-areacode.js +1 -1
- package/tx/cs/cs-country.js +17 -5
- package/tx/cs/cs-cpt.js +33 -16
- package/tx/cs/cs-cs.js +199 -24
- package/tx/cs/cs-currency.js +1 -1
- package/tx/cs/cs-icd11.js +21 -13
- package/tx/cs/cs-icf.js +22 -3
- package/tx/cs/cs-lang.js +2 -2
- package/tx/cs/cs-loinc.js +193 -67
- package/tx/cs/cs-mimetypes.js +12 -2
- package/tx/cs/cs-ndc.js +40 -25
- package/tx/cs/cs-omop.js +54 -29
- package/tx/cs/cs-rxnorm.js +300 -196
- package/tx/cs/cs-snomed.js +861 -95
- package/tx/cs/cs-ucum.js +14 -4
- package/tx/cs/cs-unii.js +18 -14
- package/tx/cs/cs-virtual.js +210 -0
- package/tx/ecosystem-resolver.js +413 -0
- package/tx/html/cluster-dash-metrics.liquid +26 -0
- package/tx/html/cluster-home-metrics.liquid +31 -0
- package/tx/html/cluster-metrics-script.liquid +251 -0
- package/tx/html/codesystem-operations.liquid +3 -3
- package/tx/html/ecl-panel.liquid +1 -1
- package/tx/html/external-metrics.liquid +17 -0
- package/tx/html/operations-form.liquid +17 -17
- package/tx/html/search-form.liquid +11 -11
- package/tx/html/status-line.liquid +58 -0
- package/tx/html/status-panel.liquid +140 -0
- package/tx/html/status-tasks.liquid +25 -0
- package/tx/html/tx-template.html +2 -5
- package/tx/importers/atc-to-fhir.js +17 -16
- package/tx/importers/export-icd11-codesystem.js +3 -2
- package/tx/importers/import-icd11.js +4 -3
- package/tx/importers/import-loinc.module.js +118 -56
- package/tx/importers/import-ndc.module.js +56 -44
- package/tx/importers/import-rxnorm.module.js +118 -79
- package/tx/importers/import-sct.module.js +125 -61
- package/tx/importers/import-unii.module.js +37 -36
- package/tx/importers/subset-loinc.module.js +49 -48
- package/tx/importers/subset-rxnorm.module.js +29 -28
- package/tx/importers/terminal.js +18 -0
- package/tx/importers/tx-import-base.js +13 -12
- package/tx/importers/tx-import-settings.js +5 -4
- package/tx/importers/tx-import.js +53 -52
- package/tx/library/canonical-resource.js +49 -0
- package/tx/library/codesystem.js +94 -5
- package/tx/library/designations.js +45 -2
- package/tx/library/extensions.js +13 -7
- package/tx/library/implicit-valuesets.js +66 -0
- package/tx/library/renderer.js +77 -21
- package/tx/library/sqlite-utilities.js +2 -0
- package/tx/library/tho-precedence.js +40 -0
- package/tx/library/ucum-parsers.js +11 -1
- package/tx/library/wait-for-cache.js +43 -0
- package/tx/library.js +321 -22
- package/tx/openapi-operations.js +6 -4
- package/tx/operation-context.js +460 -99
- package/tx/params.js +25 -0
- package/tx/problems.js +3 -5
- package/tx/provider.js +314 -67
- package/tx/resource-cache-sqlite.js +1050 -0
- package/tx/sct/documentation.md +45 -21
- package/tx/sct/ecl.js +81 -17
- package/tx/sct/editions.js +39 -0
- package/tx/sct/expressions.js +10 -1
- package/tx/sct/load-config.js +107 -0
- package/tx/sct/mmap.js +109 -0
- package/tx/sct/structures.js +175 -15
- package/tx/sct/text-index.js +5 -1
- package/tx/syndication/syndication-feed.js +2 -2
- package/tx/tx-html.js +44 -8
- package/tx/tx.fhir.org.yml +8 -8
- package/tx/tx.js +282 -80
- package/tx/usage-tracker.js +39 -11
- package/tx/vs/vs-api.js +19 -0
- package/tx/vs/vs-database.js +386 -62
- package/tx/vs/vs-package.js +44 -17
- package/tx/vs/vs-vsac.js +649 -101
- package/tx/workers/batch-validate.js +37 -10
- package/tx/workers/batch.js +6 -1
- package/tx/workers/cache-control.js +15 -4
- package/tx/workers/closure.js +156 -13
- package/tx/workers/compare.js +8 -5
- package/tx/workers/expand.js +1173 -289
- package/tx/workers/metadata.js +35 -0
- package/tx/workers/search.js +53 -1
- package/tx/workers/supplement-filters.js +145 -0
- package/tx/workers/translate.js +169 -4
- package/tx/workers/validate.js +223 -119
- package/tx/workers/worker.js +123 -31
- package/tx/xversion/xv-valueset.js +7 -4
- package/utilities/submit-test-report.js +3 -1
- package/utilities/tx-stress-test.js +482 -0
- package/vcl/readme.md +37 -0
- package/vcl/vcl-parser.js +15 -0
- package/xig/readme.md +52 -0
- package/xig/xig-template.html +5 -8
- package/xig/xig.js +238 -422
- package/changelog-template.md +0 -22
- package/registry/test-runner.js +0 -237
- package/release.sh +0 -80
- package/test-scripts/repro-re2-wasm-leak.js +0 -34
- package/tsconfig.eslint.json +0 -9
- package/tx/html/dash-metrics.liquid +0 -147
- 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
|
-
|
|
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
|
-
|
|
452
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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 };
|