fhirsmith 0.4.2 → 0.5.1
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/CHANGELOG.md +24 -0
- package/README.md +1 -1
- package/library/cron-utilities.js +136 -0
- package/library/html-server.js +13 -29
- package/library/html.js +3 -8
- package/library/languages.js +160 -37
- package/library/package-manager.js +48 -1
- package/library/utilities.js +100 -19
- package/package.json +2 -2
- package/packages/package-crawler.js +6 -1
- package/packages/packages.js +38 -54
- package/publisher/publisher.js +19 -27
- package/registry/api.js +11 -10
- package/registry/crawler.js +31 -29
- package/registry/model.js +5 -26
- package/registry/registry.js +32 -41
- package/server.js +89 -12
- package/shl/shl.js +0 -18
- package/static/assets/js/statuspage.js +1 -9
- package/stats.js +39 -1
- package/token/token.js +14 -9
- package/translations/Messages.properties +2 -1
- package/tx/README.md +17 -6
- package/tx/cs/cs-api.js +19 -1
- package/tx/cs/cs-base.js +77 -0
- package/tx/cs/cs-country.js +46 -0
- package/tx/cs/cs-cpt.js +9 -5
- package/tx/cs/cs-cs.js +27 -13
- package/tx/cs/cs-lang.js +60 -22
- package/tx/cs/cs-loinc.js +69 -98
- package/tx/cs/cs-mimetypes.js +4 -0
- package/tx/cs/cs-ndc.js +6 -0
- package/tx/cs/cs-omop.js +16 -15
- package/tx/cs/cs-rxnorm.js +23 -1
- package/tx/cs/cs-snomed.js +283 -40
- package/tx/cs/cs-ucum.js +90 -70
- package/tx/importers/import-sct.module.js +371 -35
- package/tx/importers/readme.md +117 -7
- package/tx/library/bundle.js +5 -0
- package/tx/library/capabilitystatement.js +3 -142
- package/tx/library/codesystem.js +19 -173
- package/tx/library/conceptmap.js +4 -218
- package/tx/library/designations.js +14 -1
- package/tx/library/extensions.js +7 -0
- package/tx/library/namingsystem.js +3 -89
- package/tx/library/operation-outcome.js +8 -3
- package/tx/library/parameters.js +3 -2
- package/tx/library/renderer.js +10 -6
- package/tx/library/terminologycapabilities.js +3 -243
- package/tx/library/valueset.js +3 -235
- package/tx/library.js +100 -13
- package/tx/operation-context.js +23 -4
- package/tx/params.js +35 -38
- package/tx/provider.js +6 -5
- package/tx/sct/expressions.js +12 -3
- package/tx/tx-html.js +80 -89
- package/tx/tx.fhir.org.yml +6 -5
- package/tx/tx.js +163 -13
- package/tx/vs/vs-database.js +56 -39
- package/tx/vs/vs-package.js +21 -2
- package/tx/vs/vs-vsac.js +175 -39
- package/tx/workers/batch-validate.js +2 -0
- package/tx/workers/batch.js +2 -0
- package/tx/workers/expand.js +132 -112
- package/tx/workers/lookup.js +33 -14
- package/tx/workers/metadata.js +2 -2
- package/tx/workers/read.js +3 -2
- package/tx/workers/related.js +574 -0
- package/tx/workers/search.js +46 -9
- package/tx/workers/subsumes.js +13 -3
- package/tx/workers/translate.js +7 -3
- package/tx/workers/validate.js +258 -285
- package/tx/workers/worker.js +43 -39
- package/tx/xml/bundle-xml.js +237 -0
- package/tx/xml/xml-base.js +215 -64
- package/tx/xversion/xv-bundle.js +71 -0
- package/tx/xversion/xv-capabiliityStatement.js +137 -0
- package/tx/xversion/xv-codesystem.js +169 -0
- package/tx/xversion/xv-conceptmap.js +224 -0
- package/tx/xversion/xv-namingsystem.js +88 -0
- package/tx/xversion/xv-operationoutcome.js +27 -0
- package/tx/xversion/xv-parameters.js +87 -0
- package/tx/xversion/xv-resource.js +45 -0
- package/tx/xversion/xv-terminologyCapabilities.js +214 -0
- package/tx/xversion/xv-valueset.js +234 -0
- package/utilities/dev-proxy-server.js +126 -0
- package/utilities/explode-results.js +58 -0
- package/utilities/split-by-system.js +198 -0
- package/utilities/vsac-cs-fetcher.js +0 -0
- package/{windows-install.js → utilities/windows-install.js} +2 -0
- package/vcl/vcl.js +0 -18
- package/xig/xig.js +241 -230
package/tx/workers/worker.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
const { TerminologyError } = require('../operation-context');
|
|
1
|
+
const { TerminologyError, isDebugging} = require('../operation-context');
|
|
2
2
|
const { CodeSystem } = require('../library/codesystem');
|
|
3
3
|
const ValueSet = require('../library/valueset');
|
|
4
4
|
const {VersionUtilities} = require("../../library/version-utilities");
|
|
@@ -133,9 +133,10 @@ class TerminologyWorker {
|
|
|
133
133
|
* @param {Array<string>} kinds - Allowed content modes
|
|
134
134
|
* @param {OperationOutcome} op - Op for errors
|
|
135
135
|
* * @param {boolean} nullOk - Whether null result is acceptable
|
|
136
|
+
* @param {Set<string>} statedSupplements - Supplements invoked in context
|
|
136
137
|
* @returns {CodeSystemProvider|null} Code system provider or null
|
|
137
138
|
*/
|
|
138
|
-
async findCodeSystem(url, version = '', params, kinds = ['complete'], op, nullOk = false, checkVer = false, noVParams = false) {
|
|
139
|
+
async findCodeSystem(url, version = '', params, kinds = ['complete'], op, nullOk = false, checkVer = false, noVParams = false, statedSupplements = null) {
|
|
139
140
|
if (!url) {
|
|
140
141
|
return null;
|
|
141
142
|
}
|
|
@@ -145,7 +146,7 @@ class TerminologyWorker {
|
|
|
145
146
|
}
|
|
146
147
|
let codeSystemResource = null;
|
|
147
148
|
let provider = null;
|
|
148
|
-
const supplements = this.loadSupplements(url, version);
|
|
149
|
+
const supplements = this.loadSupplements(url, version, statedSupplements);
|
|
149
150
|
|
|
150
151
|
// First check additional resources
|
|
151
152
|
codeSystemResource = this.findInAdditionalResources(url, version, 'CodeSystem', !nullOk);
|
|
@@ -169,13 +170,13 @@ class TerminologyWorker {
|
|
|
169
170
|
|
|
170
171
|
if (!provider && !nullOk) {
|
|
171
172
|
if (!version) {
|
|
172
|
-
throw new Issue("error", "not-found", null, "UNKNOWN_CODESYSTEM_EXP", this.i18n.translate("UNKNOWN_CODESYSTEM_EXP", params.FHTTPLanguages, [url]), "not-found",
|
|
173
|
+
throw new Issue("error", "not-found", null, "UNKNOWN_CODESYSTEM_EXP", this.i18n.translate("UNKNOWN_CODESYSTEM_EXP", params.FHTTPLanguages, [url]), "not-found", 422);
|
|
173
174
|
} else {
|
|
174
175
|
const versions = await this.listVersions(url);
|
|
175
176
|
if (versions.length === 0) {
|
|
176
|
-
throw new Issue("error", "not-found", null, "UNKNOWN_CODESYSTEM_VERSION_EXP_NONE", this.i18n.translate("UNKNOWN_CODESYSTEM_VERSION_EXP_NONE", params.FHTTPLanguages, [url, version]), "not-found",
|
|
177
|
+
throw new Issue("error", "not-found", null, "UNKNOWN_CODESYSTEM_VERSION_EXP_NONE", this.i18n.translate("UNKNOWN_CODESYSTEM_VERSION_EXP_NONE", params.FHTTPLanguages, [url, version]), "not-found", 422);
|
|
177
178
|
} else {
|
|
178
|
-
throw new Issue("error", "not-found", null, "UNKNOWN_CODESYSTEM_VERSION_EXP", this.i18n.translate("UNKNOWN_CODESYSTEM_VERSION_EXP", params.FHTTPLanguages, [url, version, this.presentVersionList(versions)]), "not-found",
|
|
179
|
+
throw new Issue("error", "not-found", null, "UNKNOWN_CODESYSTEM_VERSION_EXP", this.i18n.translate("UNKNOWN_CODESYSTEM_VERSION_EXP", params.FHTTPLanguages, [url, version, this.presentVersionList(versions)]), "not-found", 422);
|
|
179
180
|
}
|
|
180
181
|
}
|
|
181
182
|
}
|
|
@@ -245,9 +246,10 @@ class TerminologyWorker {
|
|
|
245
246
|
* Load supplements for a code system
|
|
246
247
|
* @param {string} url - Code system URL
|
|
247
248
|
* @param {string} version - Code system version
|
|
249
|
+
* @param {Set<string>} statedSupplements - Supplements invoked in context
|
|
248
250
|
* @returns {Array<CodeSystem>} Supplement code systems
|
|
249
251
|
*/
|
|
250
|
-
loadSupplements(url, version = '') {
|
|
252
|
+
loadSupplements(url, version = '', statedSupplements) {
|
|
251
253
|
const supplements = [];
|
|
252
254
|
|
|
253
255
|
if (!this.additionalResources) {
|
|
@@ -265,6 +267,10 @@ class TerminologyWorker {
|
|
|
265
267
|
continue;
|
|
266
268
|
}
|
|
267
269
|
|
|
270
|
+
// we consider either language packs or specified supplements
|
|
271
|
+
if (!(cs.isLangPack() || (statedSupplements && (statedSupplements.has(cs.url) || statedSupplements.has(cs.vurl))))) {
|
|
272
|
+
continue;
|
|
273
|
+
}
|
|
268
274
|
// Handle exact URL match (no version specified in supplements)
|
|
269
275
|
if (supplementsUrl === url) {
|
|
270
276
|
// If we're looking for a specific version, only include if no version in supplements URL
|
|
@@ -298,10 +304,10 @@ class TerminologyWorker {
|
|
|
298
304
|
* @param {CodeSystemProvider} cs - Code system provider
|
|
299
305
|
* @param {Object} src - Source element (for extensions)
|
|
300
306
|
*/
|
|
301
|
-
checkSupplements(cs, src, requiredSupplements) {
|
|
307
|
+
checkSupplements(cs, src, requiredSupplements, usedSupplements = null) {
|
|
302
308
|
// Check for required supplements in extensions
|
|
303
|
-
if (src && src.
|
|
304
|
-
const supplementExtensions = src.
|
|
309
|
+
if (src && src.extension) {
|
|
310
|
+
const supplementExtensions = src.extension.filter(x => x.url == 'http://hl7.org/fhir/StructureDefinition/valueset-supplement');
|
|
305
311
|
for (const ext of supplementExtensions) {
|
|
306
312
|
const supplementUrl = ext.valueString || ext.valueUri;
|
|
307
313
|
if (supplementUrl && !cs.hasSupplement(this.opContext, supplementUrl)) {
|
|
@@ -310,10 +316,12 @@ class TerminologyWorker {
|
|
|
310
316
|
}
|
|
311
317
|
}
|
|
312
318
|
|
|
313
|
-
//
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
319
|
+
// Note required supplements that are satisfied
|
|
320
|
+
if (usedSupplements) {
|
|
321
|
+
for (const s of requiredSupplements) {
|
|
322
|
+
if (cs.hasSupplement(s)) {
|
|
323
|
+
usedSupplements.add(s);
|
|
324
|
+
}
|
|
317
325
|
}
|
|
318
326
|
}
|
|
319
327
|
}
|
|
@@ -456,6 +464,10 @@ class TerminologyWorker {
|
|
|
456
464
|
if (req.method === 'POST' && req.body && req.body.resourceType === 'Parameters') {
|
|
457
465
|
return req.body;
|
|
458
466
|
}
|
|
467
|
+
if (req.method === 'POST' && req.body && req.body.resourceType) {
|
|
468
|
+
let langs = this.languages.parse(req.headers['accept-language']);
|
|
469
|
+
throw new Issue('error', 'invalid', null, 'Wrong_type_for_resource_expected', this.i18n.translate('Wrong_type_for_resource_expected', langs, ["Parameters", req.body.resourceType])).handleAsOO(400);
|
|
470
|
+
}
|
|
459
471
|
|
|
460
472
|
// Convert query params or form body to Parameters
|
|
461
473
|
const source = req.method === 'POST' ? {...req.query, ...req.body} : req.query;
|
|
@@ -480,6 +492,10 @@ class TerminologyWorker {
|
|
|
480
492
|
// Assume it's a complex type like Coding or CodeableConcept
|
|
481
493
|
params.parameter.push(this.buildComplexParameter(name, value));
|
|
482
494
|
}
|
|
495
|
+
} else if (value == 'true') {
|
|
496
|
+
params.parameter.push({name, valueBoolean: true});
|
|
497
|
+
} else if (value == 'false') {
|
|
498
|
+
params.parameter.push({name, valueBoolean: false});
|
|
483
499
|
} else {
|
|
484
500
|
params.parameter.push({name, valueString: String(value)});
|
|
485
501
|
}
|
|
@@ -837,31 +853,6 @@ class TerminologyWorker {
|
|
|
837
853
|
return result;
|
|
838
854
|
}
|
|
839
855
|
|
|
840
|
-
// Note: findParameter, getStringParam, getResourceParam, getCodingParam,
|
|
841
|
-
// and getCodeableConceptParam are inherited from TerminologyWorker base class
|
|
842
|
-
|
|
843
|
-
fixForVersion(resource) {
|
|
844
|
-
if (this.provider.fhirVersion >= 5) {
|
|
845
|
-
return resource;
|
|
846
|
-
}
|
|
847
|
-
let rt = resource.resourceType;
|
|
848
|
-
switch (rt) {
|
|
849
|
-
case "ValueSet": {
|
|
850
|
-
let vs = new ValueSet(resource);
|
|
851
|
-
if (this.provider.fhirVersion == 4) {
|
|
852
|
-
return vs.convertFromR5(resource, "R4");
|
|
853
|
-
} else if (this.provider.fhirVersion == 3) {
|
|
854
|
-
return vs.convertFromR5(resource, "R3");
|
|
855
|
-
} else {
|
|
856
|
-
return resource;
|
|
857
|
-
}
|
|
858
|
-
}
|
|
859
|
-
default:
|
|
860
|
-
return resource;
|
|
861
|
-
}
|
|
862
|
-
}
|
|
863
|
-
|
|
864
|
-
|
|
865
856
|
seeSourceVS(vs, url) {
|
|
866
857
|
let s = url;
|
|
867
858
|
if (vs) {
|
|
@@ -896,6 +887,19 @@ class TerminologyWorker {
|
|
|
896
887
|
const lastItem = items.pop();
|
|
897
888
|
return `${items.join(', ')} and ${lastItem}`;
|
|
898
889
|
}
|
|
890
|
+
|
|
891
|
+
checkNoLockedDate(url, compose) {
|
|
892
|
+
if (compose.lockedDate) {
|
|
893
|
+
throw new Issue("error", "business-rule", null, null, `Cannot process ValueSet ${url} due to the presence of a lockedDate on the compose`);
|
|
894
|
+
}
|
|
895
|
+
return true;
|
|
896
|
+
}
|
|
897
|
+
|
|
898
|
+
debugLog(error) {
|
|
899
|
+
if (isDebugging()) {
|
|
900
|
+
console.log(error);
|
|
901
|
+
}
|
|
902
|
+
}
|
|
899
903
|
}
|
|
900
904
|
|
|
901
905
|
module.exports = {
|
|
@@ -0,0 +1,237 @@
|
|
|
1
|
+
//
|
|
2
|
+
// Bundle XML Serialization
|
|
3
|
+
//
|
|
4
|
+
|
|
5
|
+
const { FhirXmlBase } = require('./xml-base');
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* XML support for FHIR Bundle resources
|
|
9
|
+
*/
|
|
10
|
+
class BundleXML extends FhirXmlBase {
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Element order for Bundle (FHIR requires specific order)
|
|
14
|
+
*/
|
|
15
|
+
static _elementOrder = [
|
|
16
|
+
'id', 'meta', 'implicitRules', 'language',
|
|
17
|
+
'identifier', 'type', 'timestamp', 'total',
|
|
18
|
+
'link', 'entry', 'signature', 'issues'
|
|
19
|
+
];
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Element order for Bundle.entry
|
|
23
|
+
*/
|
|
24
|
+
static _entryElementOrder = [
|
|
25
|
+
'link', 'fullUrl', 'resource', 'search', 'request', 'response'
|
|
26
|
+
];
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Element order for Bundle.link
|
|
30
|
+
*/
|
|
31
|
+
static _linkElementOrder = [
|
|
32
|
+
'relation', 'url'
|
|
33
|
+
];
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Element order for Bundle.entry.search
|
|
37
|
+
*/
|
|
38
|
+
static _searchElementOrder = [
|
|
39
|
+
'mode', 'score'
|
|
40
|
+
];
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Convert Bundle JSON to XML string
|
|
44
|
+
* @param {Object} json - Bundle as JSON
|
|
45
|
+
* @param {number} fhirVersion - FHIR version (3, 4, or 5)
|
|
46
|
+
* @returns {string} XML string
|
|
47
|
+
*/
|
|
48
|
+
static toXml(json, fhirVersion) {
|
|
49
|
+
let content = '';
|
|
50
|
+
const indent = ' ';
|
|
51
|
+
|
|
52
|
+
// Render simple elements first
|
|
53
|
+
for (const key of this._elementOrder) {
|
|
54
|
+
if (json[key] === undefined) continue;
|
|
55
|
+
|
|
56
|
+
if (key === 'link') {
|
|
57
|
+
// Handle link array
|
|
58
|
+
for (const link of json.link || []) {
|
|
59
|
+
content += `${indent}<link>\n`;
|
|
60
|
+
content += this.renderElementsInOrder(link, 2, this._linkElementOrder);
|
|
61
|
+
content += `${indent}</link>\n`;
|
|
62
|
+
}
|
|
63
|
+
} else if (key === 'entry') {
|
|
64
|
+
// Handle entry array with nested resources
|
|
65
|
+
for (const entry of json.entry || []) {
|
|
66
|
+
content += `${indent}<entry>\n`;
|
|
67
|
+
|
|
68
|
+
// fullUrl
|
|
69
|
+
if (entry.fullUrl) {
|
|
70
|
+
content += `${indent}${indent}<fullUrl value="${this.escapeXml(entry.fullUrl)}"/>\n`;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
// resource - needs special handling to embed full resource
|
|
74
|
+
if (entry.resource) {
|
|
75
|
+
content += `${indent}${indent}<resource>\n`;
|
|
76
|
+
content += this.renderResource(entry.resource, 3, fhirVersion);
|
|
77
|
+
content += `${indent}${indent}</resource>\n`;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
// search
|
|
81
|
+
if (entry.search) {
|
|
82
|
+
content += `${indent}${indent}<search>\n`;
|
|
83
|
+
if (entry.search.mode) {
|
|
84
|
+
content += `${indent}${indent}${indent}<mode value="${this.escapeXml(entry.search.mode)}"/>\n`;
|
|
85
|
+
}
|
|
86
|
+
if (entry.search.score !== undefined) {
|
|
87
|
+
content += `${indent}${indent}${indent}<score value="${entry.search.score}"/>\n`;
|
|
88
|
+
}
|
|
89
|
+
content += `${indent}${indent}</search>\n`;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
content += `${indent}</entry>\n`;
|
|
93
|
+
}
|
|
94
|
+
} else if (key === 'total') {
|
|
95
|
+
content += `${indent}<total value="${json.total}"/>\n`;
|
|
96
|
+
} else if (key === 'type') {
|
|
97
|
+
content += `${indent}<type value="${this.escapeXml(json.type)}"/>\n`;
|
|
98
|
+
} else if (key === 'timestamp') {
|
|
99
|
+
content += `${indent}<timestamp value="${this.escapeXml(json.timestamp)}"/>\n`;
|
|
100
|
+
} else if (key === 'id') {
|
|
101
|
+
content += `${indent}<id value="${this.escapeXml(json.id)}"/>\n`;
|
|
102
|
+
} else if (key === 'meta') {
|
|
103
|
+
content += this.renderMeta(json.meta, 1);
|
|
104
|
+
} else {
|
|
105
|
+
// Generic element handling
|
|
106
|
+
content += this.renderElement(key, json[key], 1);
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
return this.wrapInRootElement('Bundle', content);
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
/**
|
|
114
|
+
* Render a nested resource as XML
|
|
115
|
+
*/
|
|
116
|
+
static renderResource(resource, indentLevel, _fhirVersion) {
|
|
117
|
+
void _fhirVersion; // reserved for future version-specific rendering
|
|
118
|
+
|
|
119
|
+
const indent = ' '.repeat(indentLevel);
|
|
120
|
+
const resourceType = resource.resourceType;
|
|
121
|
+
|
|
122
|
+
// For known resource types, delegate to their specific converters
|
|
123
|
+
// For unknown types, render generically
|
|
124
|
+
let innerContent = '';
|
|
125
|
+
|
|
126
|
+
// Get element order based on resource type
|
|
127
|
+
const elementOrder = this.getElementOrderForResource(resourceType);
|
|
128
|
+
|
|
129
|
+
innerContent = this.renderElementsInOrder(resource, indentLevel + 1, elementOrder);
|
|
130
|
+
|
|
131
|
+
return `${indent}<${resourceType} xmlns="http://hl7.org/fhir">\n${innerContent}${indent}</${resourceType}>\n`;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
/**
|
|
135
|
+
* Get element order for a resource type
|
|
136
|
+
*/
|
|
137
|
+
static getElementOrderForResource(resourceType) {
|
|
138
|
+
// Common elements that most resources have
|
|
139
|
+
const commonElements = [
|
|
140
|
+
'id', 'meta', 'implicitRules', 'language', 'text', 'contained',
|
|
141
|
+
'extension', 'modifierExtension'
|
|
142
|
+
];
|
|
143
|
+
|
|
144
|
+
switch (resourceType) {
|
|
145
|
+
case 'CodeSystem':
|
|
146
|
+
return [
|
|
147
|
+
...commonElements,
|
|
148
|
+
'url', 'identifier', 'version', 'versionAlgorithmString', 'versionAlgorithmCoding',
|
|
149
|
+
'name', 'title', 'status', 'experimental', 'date', 'publisher',
|
|
150
|
+
'contact', 'description', 'useContext', 'jurisdiction', 'purpose', 'copyright',
|
|
151
|
+
'copyrightLabel', 'approvalDate', 'lastReviewDate',
|
|
152
|
+
'caseSensitive', 'valueSet', 'hierarchyMeaning', 'compositional',
|
|
153
|
+
'versionNeeded', 'content', 'supplements', 'count', 'filter', 'property', 'concept'
|
|
154
|
+
];
|
|
155
|
+
case 'ValueSet':
|
|
156
|
+
return [
|
|
157
|
+
...commonElements,
|
|
158
|
+
'url', 'identifier', 'version', 'versionAlgorithmString', 'versionAlgorithmCoding',
|
|
159
|
+
'name', 'title', 'status', 'experimental', 'date', 'publisher',
|
|
160
|
+
'contact', 'description', 'useContext', 'jurisdiction', 'purpose', 'copyright',
|
|
161
|
+
'copyrightLabel', 'approvalDate', 'lastReviewDate', 'effectivePeriod',
|
|
162
|
+
'immutable', 'compose', 'expansion'
|
|
163
|
+
];
|
|
164
|
+
case 'ConceptMap':
|
|
165
|
+
return [
|
|
166
|
+
...commonElements,
|
|
167
|
+
'url', 'identifier', 'version', 'name', 'title', 'status', 'experimental',
|
|
168
|
+
'date', 'publisher', 'contact', 'description', 'useContext', 'jurisdiction',
|
|
169
|
+
'purpose', 'copyright', 'sourceUri', 'sourceCanonical', 'targetUri', 'targetCanonical',
|
|
170
|
+
'group'
|
|
171
|
+
];
|
|
172
|
+
default:
|
|
173
|
+
// Return common elements plus all other keys from the resource
|
|
174
|
+
return commonElements;
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
/**
|
|
179
|
+
* Render meta element
|
|
180
|
+
*/
|
|
181
|
+
static renderMeta(meta, indentLevel) {
|
|
182
|
+
if (!meta) return '';
|
|
183
|
+
const indent = ' '.repeat(indentLevel);
|
|
184
|
+
let content = `${indent}<meta>\n`;
|
|
185
|
+
|
|
186
|
+
if (meta.versionId) {
|
|
187
|
+
content += `${indent} <versionId value="${this.escapeXml(meta.versionId)}"/>\n`;
|
|
188
|
+
}
|
|
189
|
+
if (meta.lastUpdated) {
|
|
190
|
+
content += `${indent} <lastUpdated value="${this.escapeXml(meta.lastUpdated)}"/>\n`;
|
|
191
|
+
}
|
|
192
|
+
if (meta.source) {
|
|
193
|
+
content += `${indent} <source value="${this.escapeXml(meta.source)}"/>\n`;
|
|
194
|
+
}
|
|
195
|
+
for (const profile of meta.profile || []) {
|
|
196
|
+
content += `${indent} <profile value="${this.escapeXml(profile)}"/>\n`;
|
|
197
|
+
}
|
|
198
|
+
for (const security of meta.security || []) {
|
|
199
|
+
content += this.renderCoding(security, indentLevel + 1, 'security');
|
|
200
|
+
}
|
|
201
|
+
for (const tag of meta.tag || []) {
|
|
202
|
+
content += this.renderCoding(tag, indentLevel + 1, 'tag');
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
content += `${indent}</meta>\n`;
|
|
206
|
+
return content;
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
/**
|
|
210
|
+
* Render a Coding element
|
|
211
|
+
*/
|
|
212
|
+
static renderCoding(coding, indentLevel, elementName) {
|
|
213
|
+
const indent = ' '.repeat(indentLevel);
|
|
214
|
+
let content = `${indent}<${elementName}>\n`;
|
|
215
|
+
|
|
216
|
+
if (coding.system) {
|
|
217
|
+
content += `${indent} <system value="${this.escapeXml(coding.system)}"/>\n`;
|
|
218
|
+
}
|
|
219
|
+
if (coding.version) {
|
|
220
|
+
content += `${indent} <version value="${this.escapeXml(coding.version)}"/>\n`;
|
|
221
|
+
}
|
|
222
|
+
if (coding.code) {
|
|
223
|
+
content += `${indent} <code value="${this.escapeXml(coding.code)}"/>\n`;
|
|
224
|
+
}
|
|
225
|
+
if (coding.display) {
|
|
226
|
+
content += `${indent} <display value="${this.escapeXml(coding.display)}"/>\n`;
|
|
227
|
+
}
|
|
228
|
+
if (coding.userSelected !== undefined) {
|
|
229
|
+
content += `${indent} <userSelected value="${coding.userSelected}"/>\n`;
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
content += `${indent}</${elementName}>\n`;
|
|
233
|
+
return content;
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
module.exports = { BundleXML };
|