fhirsmith 0.5.6 → 0.7.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 (78) hide show
  1. package/CHANGELOG.md +38 -0
  2. package/README.md +2 -0
  3. package/configurations/projector.json +21 -0
  4. package/configurations/readme.md +5 -0
  5. package/library/html-server.js +2 -1
  6. package/library/package-manager.js +37 -34
  7. package/library/utilities.js +10 -1
  8. package/library/version-utilities.js +85 -0
  9. package/package.json +1 -1
  10. package/packages/package-crawler.js +144 -52
  11. package/packages/packages.js +15 -7
  12. package/publisher/publisher.js +15 -3
  13. package/registry/api.js +173 -191
  14. package/registry/crawler.js +100 -65
  15. package/registry/model.js +14 -8
  16. package/registry/registry.js +5 -0
  17. package/root-template.html +1 -0
  18. package/server.js +113 -45
  19. package/tx/README.md +4 -4
  20. package/tx/cs/cs-api.js +18 -1
  21. package/tx/cs/cs-base.js +1 -0
  22. package/tx/cs/cs-loinc.js +5 -2
  23. package/tx/cs/cs-provider-api.js +25 -1
  24. package/tx/cs/cs-provider-list.js +2 -2
  25. package/tx/cs/cs-rxnorm.js +9 -2
  26. package/tx/cs/cs-snomed.js +17 -2
  27. package/tx/html/codesystem-operations.liquid +17 -24
  28. package/tx/html/valueset-operations.liquid +46 -52
  29. package/tx/library/canonical-resource.js +6 -1
  30. package/tx/library/codesystem.js +6 -1
  31. package/tx/library/renderer.js +81 -7
  32. package/tx/library.js +145 -13
  33. package/tx/ocl/README.md +236 -0
  34. package/tx/ocl/cache/cache-paths.cjs +32 -0
  35. package/tx/ocl/cache/cache-paths.js +2 -0
  36. package/tx/ocl/cache/cache-utils.cjs +43 -0
  37. package/tx/ocl/cache/cache-utils.js +2 -0
  38. package/tx/ocl/cm-ocl.cjs +531 -0
  39. package/tx/ocl/cm-ocl.js +1 -105
  40. package/tx/ocl/cs-ocl.cjs +1779 -0
  41. package/tx/ocl/cs-ocl.js +1 -38
  42. package/tx/ocl/fingerprint/fingerprint.cjs +67 -0
  43. package/tx/ocl/fingerprint/fingerprint.js +2 -0
  44. package/tx/ocl/http/client.cjs +31 -0
  45. package/tx/ocl/http/client.js +2 -0
  46. package/tx/ocl/http/pagination.cjs +98 -0
  47. package/tx/ocl/http/pagination.js +2 -0
  48. package/tx/ocl/jobs/background-queue.cjs +200 -0
  49. package/tx/ocl/jobs/background-queue.js +2 -0
  50. package/tx/ocl/mappers/concept-mapper.cjs +66 -0
  51. package/tx/ocl/mappers/concept-mapper.js +2 -0
  52. package/tx/ocl/model/concept-filter-context.cjs +51 -0
  53. package/tx/ocl/model/concept-filter-context.js +2 -0
  54. package/tx/ocl/shared/constants.cjs +15 -0
  55. package/tx/ocl/shared/constants.js +2 -0
  56. package/tx/ocl/shared/patches.cjs +224 -0
  57. package/tx/ocl/shared/patches.js +2 -0
  58. package/tx/ocl/vs-ocl.cjs +1848 -0
  59. package/tx/ocl/vs-ocl.js +1 -104
  60. package/tx/operation-context.js +8 -1
  61. package/tx/params.js +24 -3
  62. package/tx/provider.js +51 -2
  63. package/tx/sct/expressions.js +20 -9
  64. package/tx/tx-html.js +144 -51
  65. package/tx/tx.js +10 -2
  66. package/tx/vs/vs-vsac.js +4 -3
  67. package/tx/workers/batch-validate.js +3 -2
  68. package/tx/workers/batch.js +3 -2
  69. package/tx/workers/expand.js +125 -18
  70. package/tx/workers/lookup.js +5 -4
  71. package/tx/workers/read.js +2 -1
  72. package/tx/workers/related.js +3 -2
  73. package/tx/workers/search.js +6 -8
  74. package/tx/workers/subsumes.js +3 -2
  75. package/tx/workers/translate.js +4 -3
  76. package/tx/workers/validate.js +132 -40
  77. package/tx/workers/worker.js +1 -7
  78. package/tx/xversion/xv-terminologyCapabilities.js +1 -1
package/tx/cs/cs-api.js CHANGED
@@ -774,12 +774,19 @@ class CodeSystemFactoryProvider {
774
774
  }
775
775
 
776
776
  /**
777
- * @returns {string} uri for the code system
777
+ * @returns {string} name for the code system
778
778
  */
779
779
  name() {
780
780
  throw new Error("Must override");
781
781
  }
782
782
 
783
+ /**
784
+ * @returns {string} name for the code system, without version information
785
+ */
786
+ nameBase() {
787
+ return this.name();
788
+ }
789
+
783
790
  /**
784
791
  * @returns {string} version for the code system
785
792
  */
@@ -796,6 +803,16 @@ class CodeSystemFactoryProvider {
796
803
  }
797
804
  return ver;
798
805
  }
806
+
807
+ /**
808
+ * the version parameter might not be the same as version() once
809
+ * all matching rules are done
810
+ * @param version
811
+ */
812
+ describeVersion(version) {
813
+ return "v"+version;
814
+ }
815
+
799
816
  /**
800
817
  * @returns {number} how many times the factory has been asked to construct a provider
801
818
  */
package/tx/cs/cs-base.js CHANGED
@@ -72,6 +72,7 @@ class BaseCSServices extends CodeSystemProvider {
72
72
  };
73
73
  }
74
74
 
75
+
75
76
  module.exports = {
76
77
  BaseCSServices
77
78
  };
package/tx/cs/cs-loinc.js CHANGED
@@ -203,9 +203,12 @@ class LoincServices extends BaseCSServices {
203
203
  // Use language-aware display logic
204
204
  if (this.opContext.langs && !this.opContext.langs.isEnglishOrNothing()) {
205
205
  const displays = await this.#getDisplaysForContext(ctxt, this.opContext.langs);
206
+ const requestedLanguages = Array.isArray(this.opContext.langs.languages)
207
+ ? this.opContext.langs.languages
208
+ : (Array.isArray(this.opContext.langs.langs) ? this.opContext.langs.langs : []);
206
209
 
207
210
  // Try to find exact language match
208
- for (const lang of this.opContext.langs.langs) {
211
+ for (const lang of requestedLanguages) {
209
212
  for (const display of displays) {
210
213
  if (lang.matches(display.language, true)) {
211
214
  return display.value;
@@ -214,7 +217,7 @@ class LoincServices extends BaseCSServices {
214
217
  }
215
218
 
216
219
  // Try partial language match
217
- for (const lang of this.opContext.langs.langs) {
220
+ for (const lang of requestedLanguages) {
218
221
  for (const display of displays) {
219
222
  if (lang.matches(display.language, false)) {
220
223
  return display.value;
@@ -20,7 +20,13 @@ class AbstractCodeSystemProvider {
20
20
  }
21
21
 
22
22
  /**
23
- * Returns the list of CodeSystems this provider provides
23
+ * Returns the list of CodeSystems this provider provides. This is called once at start up.
24
+ * The code systems should be fully loaded; lazy loading code systems is not considered good
25
+ * for engineering.
26
+ *
27
+ *
28
+ * Note that unlike value sets, which are accessed from the provider on the fly, code systems
29
+ * are all preloaded into the kernel (e.g. provider) at start up
24
30
  *
25
31
  * @param {string} fhirVersion - The FHIRVersion in scope - if relevant (there's always a stated version, though R5 is always used)
26
32
  * @param {string} context - The client's stated context - if provided.
@@ -32,6 +38,24 @@ class AbstractCodeSystemProvider {
32
38
  throw new Error('listCodeSystems must be implemented by AbstractCodeSystemProvider subclass');
33
39
  }
34
40
 
41
+ /**
42
+ * This is called once a minute to update the code system list that the provider maintains.
43
+ *
44
+ * return an object that has three Map<String, CodeSystem>: {added, changed, deleted}
45
+ *
46
+ * these use the same key as the
47
+ *
48
+ * code systems are identified by url and version
49
+ *
50
+ * @param fhirVersion
51
+ * @param context
52
+ * @returns {Promise<null>}
53
+ */
54
+ // eslint-disable-next-line no-unused-vars
55
+ async getCodeSystemChanges(fhirVersion, context){
56
+ return null;
57
+ }
58
+
35
59
  async close() {
36
60
 
37
61
  }
@@ -7,7 +7,7 @@ class ListCodeSystemProvider extends AbstractCodeSystemProvider {
7
7
  /**
8
8
  * {Map<String, CodeSystem>} A list of code system factories that contains all the preloaded native code systems
9
9
  */
10
- codeSystems = new Map();
10
+ codeSystems = [];
11
11
 
12
12
  /**
13
13
  * ensure that the ids on the code systems are unique, if they are
@@ -17,7 +17,7 @@ class ListCodeSystemProvider extends AbstractCodeSystemProvider {
17
17
  */
18
18
  // eslint-disable-next-line no-unused-vars
19
19
  assignIds(ids) {
20
- for (const cs of this.codeSystems.values()) {
20
+ for (const cs of this.codeSystems) {
21
21
  if (!cs.id || ids.has("CodeSystem/"+cs.id)) {
22
22
  cs.id = ""+ids.size;
23
23
  }
@@ -3,7 +3,7 @@ const assert = require('assert');
3
3
  const { CodeSystem } = require('../library/codesystem');
4
4
  const { CodeSystemProvider, CodeSystemFactoryProvider } = require('./cs-api');
5
5
  const {Designations} = require("../library/designations");
6
- const {validateArrayParameter} = require("../../library/utilities");
6
+ const {validateArrayParameter, formatDateMMDDYYYY} = require("../../library/utilities");
7
7
 
8
8
  // Context for RxNorm concepts
9
9
  class RxNormConcept {
@@ -806,9 +806,16 @@ class RxNormTypeServicesFactory extends CodeSystemFactoryProvider {
806
806
  }
807
807
 
808
808
  id() {
809
- return this.name();
809
+ return this.name()+"-"+this.version();
810
810
  }
811
811
 
812
+ describeVersion(version) {
813
+ try {
814
+ return formatDateMMDDYYYY(version);
815
+ } catch (error) {
816
+ return "v" + version;
817
+ }
818
+ }
812
819
  }
813
820
 
814
821
  // Specific RxNorm implementation
@@ -11,6 +11,7 @@ const {
11
11
  } = require('../sct/expressions');
12
12
  const {DesignationUse} = require("../library/designations");
13
13
  const {BaseCSServices} = require("./cs-base");
14
+ const {formatDateMMDDYYYY} = require("../../library/utilities");
14
15
 
15
16
  // Context kinds matching Pascal enum
16
17
  const SnomedProviderContextKind = {
@@ -1262,11 +1263,25 @@ class SnomedServicesFactory extends CodeSystemFactoryProvider {
1262
1263
  return `SCT ${getEditionCode(this._sharedData.edition)}`;
1263
1264
  }
1264
1265
 
1266
+ nameBase() {
1267
+ return `SCT`;
1268
+ }
1269
+
1265
1270
  id() {
1266
- return "SCT"+this.version();
1271
+ const match = this.version().match(/^http:\/\/snomed\.info\/sct\/(\d+)(?:\/version\/(\d{8}))?$/);
1272
+ return "SCT-"+match[1]+"-"+match[2];
1267
1273
  }
1268
- }
1269
1274
 
1275
+ describeVersion(version) {
1276
+ const match = version.match(/^http:\/\/snomed\.info\/sct\/(\d+)(?:\/version\/(\d{8}))?$/);
1277
+ if (!match) return version;
1278
+
1279
+ const edition = getEditionName(match[1]);
1280
+ if (!match[2]) return edition;
1281
+
1282
+ return edition + ' ' + formatDateMMDDYYYY(match[2].substring(4, 6) + match[2].substring(6, 8) + match[2].substring(0, 4));
1283
+ }
1284
+ }
1270
1285
 
1271
1286
  function getEditionName(edition) {
1272
1287
  const editionMap = {
@@ -1,25 +1,18 @@
1
- <div class="operations" style="margin-top: 20px;">
2
- <button type="button" class="btn btn-sm btn-outline-secondary" onclick="toggleOperations('{{ opsId }}')">Show Operations</button>
3
- <div id="{{ opsId }}" style="display: none; margin-top: 10px;">
1
+ <div class="operation-form" style="margin-bottom: 15px;">
2
+ <strong>Lookup</strong>
3
+ <form method="get" action="$lookup" style="display: inline-block; margin-left: 10px;">
4
+ <input type="hidden" name="system" value="{{ url }}"/>
5
+ <input type="text" name="code" placeholder="Code" required size="20"/>
6
+ <button type="submit" class="btn btn-sm btn-primary">Lookup</button>
7
+ </form>
8
+ </div>
4
9
 
5
- <div class="operation-form" style="margin-bottom: 15px;">
6
- <strong>Lookup</strong>
7
- <form method="get" action="$lookup" style="display: inline-block; margin-left: 10px;">
8
- <input type="hidden" name="system" value="{{ url }}"/>
9
- <input type="text" name="code" placeholder="Code" required size="20"/>
10
- <button type="submit" class="btn btn-sm btn-primary">Lookup</button>
11
- </form>
12
- </div>
13
-
14
- <div class="operation-form" style="margin-bottom: 15px;">
15
- <strong>Subsumes</strong>
16
- <form method="get" action="$subsumes" style="display: inline-block; margin-left: 10px;">
17
- <input type="hidden" name="system" value="{{ url }}"/>
18
- <input type="text" name="codeA" placeholder="Code A" required size="15"/>
19
- <input type="text" name="codeB" placeholder="Code B" required size="15"/>
20
- <button type="submit" class="btn btn-sm btn-primary">Subsumes</button>
21
- </form>
22
- </div>
23
-
24
- </div>
25
- </div>
10
+ <div class="operation-form" style="margin-bottom: 15px;">
11
+ <strong>Subsumes</strong>
12
+ <form method="get" action="$subsumes" style="display: inline-block; margin-left: 10px;">
13
+ <input type="hidden" name="system" value="{{ url }}"/>
14
+ <input type="text" name="codeA" placeholder="Code A" required size="15"/>
15
+ <input type="text" name="codeB" placeholder="Code B" required size="15"/>
16
+ <button type="submit" class="btn btn-sm btn-primary">Subsumes</button>
17
+ </form>
18
+ </div>
@@ -1,54 +1,48 @@
1
- <div class="operations" style="margin-top: 20px;">
2
- <button type="button" class="btn btn-sm btn-outline-secondary" onclick="toggleOperations('{{ opsId }}')">Show Operations</button>
3
- <div id="{{ opsId }}" style="display: none; margin-top: 10px;">
4
1
 
5
- <div class="operation-form" style="margin-bottom: 15px;">
6
- <strong>Expand</strong>
7
- <form method="get" action="$expand" style="margin-left: 10px; margin-top: 5px;">
8
- <input type="hidden" name="url" value="{{ url }}"/>
9
- <table class="grid" cellpadding="0" cellspacing="0">
10
- <tr>
11
- <td>Filter: <input type="text" name="filter" size="20"/></td>
12
- <td>Language: <input type="text" name="displayLanguage" size="10"/></td>
13
- </tr>
14
- <tr>
15
- <td colspan="2">
16
- <input type="checkbox" name="includeDesignations" id="expand_desig" value="true"/>
17
- <label for="expand_desig">Include Designations</label>
18
- <input type="checkbox" name="activeOnly" id="expand_active" value="true"/>
19
- <label for="expand_active">Active Only</label>
20
- </td>
21
- </tr>
22
- </table>
23
- <button type="submit" class="btn btn-sm btn-primary">Expand</button>
24
- </form>
25
- </div>
2
+ <div class="operation-form" style="margin-bottom: 15px;">
3
+ <strong>Expand</strong>
4
+ <form method="get" action="$expand" style="margin-left: 10px; margin-top: 5px;">
5
+ <input type="hidden" name="url" value="{{ url }}"/>
6
+ <table class="grid" cellpadding="0" cellspacing="0">
7
+ <tr>
8
+ <td>Filter: <input type="text" name="filter" size="20"/></td>
9
+ <td>Language: <input type="text" name="displayLanguage" size="10"/></td>
10
+ </tr>
11
+ <tr>
12
+ <td colspan="2">
13
+ <input type="checkbox" name="includeDesignations" id="expand_desig" value="true"/>
14
+ <label for="expand_desig">Include Designations</label>
15
+ <input type="checkbox" name="activeOnly" id="expand_active" value="true"/>
16
+ <label for="expand_active">Active Only</label>
17
+ </td>
18
+ </tr>
19
+ </table>
20
+ <button type="submit" class="btn btn-sm btn-primary">Expand</button>
21
+ </form>
22
+ </div>
26
23
 
27
- <div class="operation-form" style="margin-bottom: 15px;">
28
- <strong>Validate Code (ValueSet)</strong>
29
- <form method="get" action="$validate-code" style="margin-left: 10px; margin-top: 5px;">
30
- <input type="hidden" name="url" value="{{ url }}"/>
31
- <input type="hidden" name="inferSystem" id="{{ inferSystemId }}" value="true"/>
32
- <table class="grid" cellpadding="0" cellspacing="0">
33
- <tr>
34
- <td>System: <input type="text" name="system" id="{{ vcSystemId }}" size="30" onchange="updateInferSystem('{{ vcSystemId }}', '{{ inferSystemId }}')"/></td>
35
- <td>Version: <input type="text" name="version" size="10"/></td>
36
- </tr>
37
- <tr>
38
- <td>Code: <input type="text" name="code" size="20" required/></td>
39
- <td>Display: <input type="text" name="display" size="20"/></td>
40
- </tr>
41
- <tr>
42
- <td>Language: <input type="text" name="displayLanguage" size="10"/></td>
43
- <td>
44
- <input type="checkbox" name="abstract" value="true"/>
45
- <label>Abstract</label>
46
- </td>
47
- </tr>
48
- </table>
49
- <button type="submit" class="btn btn-sm btn-primary">Validate Code</button>
50
- </form>
51
- </div>
52
-
53
- </div>
54
- </div>
24
+ <div class="operation-form" style="margin-bottom: 15px;">
25
+ <strong>Validate Code (ValueSet)</strong>
26
+ <form method="get" action="$validate-code" style="margin-left: 10px; margin-top: 5px;">
27
+ <input type="hidden" name="url" value="{{ url }}"/>
28
+ <input type="hidden" name="inferSystem" id="{{ inferSystemId }}" value="true"/>
29
+ <table class="grid" cellpadding="0" cellspacing="0">
30
+ <tr>
31
+ <td>System: <input type="text" name="system" id="{{ vcSystemId }}" size="30" onchange="updateInferSystem('{{ vcSystemId }}', '{{ inferSystemId }}')"/></td>
32
+ <td>Version: <input type="text" name="version" size="10"/></td>
33
+ </tr>
34
+ <tr>
35
+ <td>Code: <input type="text" name="code" size="20" required/></td>
36
+ <td>Display: <input type="text" name="display" size="20"/></td>
37
+ </tr>
38
+ <tr>
39
+ <td>Language: <input type="text" name="displayLanguage" size="10"/></td>
40
+ <td>
41
+ <input type="checkbox" name="abstract" value="true"/>
42
+ <label>Abstract</label>
43
+ </td>
44
+ </tr>
45
+ </table>
46
+ <button type="submit" class="btn btn-sm btn-primary">Validate Code</button>
47
+ </form>
48
+ </div>
@@ -111,7 +111,12 @@ class CanonicalResource {
111
111
  const fmt = this.versionAlgorithm() || other.versionAlgorithm() || this.guessVersionAlgorithmFromVersion(this.version);
112
112
  switch (fmt) {
113
113
  case 'semver':
114
- return VersionUtilities.isThisOrLater(other.version, this.version, VersionPrecision.PATCH);
114
+ try {
115
+ return VersionUtilities.isThisOrLater(other.version, this.version, VersionPrecision.PATCH);
116
+ } catch (error) {
117
+ // other is not semver. Not much we can do
118
+ return false;
119
+ }
115
120
  case 'date':
116
121
  return this.dateIsMoreRecent(this.version, other.version);
117
122
  case 'integer':
@@ -33,7 +33,12 @@ class CodeSystem extends CanonicalResource {
33
33
  // Convert to R5 format internally (modifies input for performance)
34
34
  this.jsonObj = codeSystemToR5(this.jsonObj, fhirVersion);
35
35
  if (!noMaps) {
36
- this.validate();
36
+ try {
37
+ this.validate();
38
+ } catch (e) {
39
+ const id = this.jsonObj?.url ? `${this.jsonObj.url}|${this.jsonObj.version || ''}` : this.jsonObj?.name || 'unknown';
40
+ throw new Error(`${e.message} (in ${id})`);
41
+ }
37
42
  this.buildMaps();
38
43
  }
39
44
  }
@@ -147,6 +147,7 @@ class Renderer {
147
147
  this.renderProperty(tbl, 'GENERAL_TITLE', res.title);
148
148
  this.renderProperty(tbl, 'GENERAL_STATUS', res.status);
149
149
  this.renderPropertyMD(tbl, 'GENERAL_DEFINITION', res.description);
150
+ this.renderPropertyMD(tbl, 'GENERAL_PURPOSE', res.purpose);
150
151
  this.renderProperty(tbl, 'CANON_REND_PUBLISHER', res.publisher);
151
152
  this.renderProperty(tbl, 'CANON_REND_COMMITTEE', Extensions.readString(res, 'http://hl7.org/fhir/StructureDefinition/structuredefinition-wg'));
152
153
  this.renderProperty(tbl, 'GENERAL_COPYRIGHT', res.copyright);
@@ -339,7 +340,7 @@ class Renderer {
339
340
  }
340
341
  if (vs.expansion) {
341
342
  div_.h2().tx("Expansion");
342
- await this.renderExpansion(div_.table("grid"), vs, tbl);
343
+ await this.renderExpansion(div_, vs, tbl);
343
344
  }
344
345
 
345
346
  return div_.toString();
@@ -419,7 +420,7 @@ class Renderer {
419
420
  li.tx(this.translate('VALUE_SET_ALL_CODES_DEF')+" ");
420
421
  await this.renderLink(li,inc.system+(inc.version ? "|"+inc.version : ""));
421
422
  } else if (inc.concept) {
422
- li.tx(this.translate('VALUE_SET_THESE_CODES_DEF'));
423
+ li.tx(this.translate('VALUE_SET_THESE_CODES_DEF')+" ");
423
424
  await this.renderLink(li,inc.system+(inc.version ? "|"+inc.version : ""));
424
425
  li.tx(":");
425
426
  const ul = li.ul();
@@ -898,18 +899,45 @@ class Renderer {
898
899
  return count;
899
900
  }
900
901
 
902
+ async renderVSExpansion(vs, showProps) {
903
+ let div_ = div();
904
+ let tbl;
905
+ if (showProps) {
906
+ div_.h2().tx("Expansion Properties");
907
+ tbl = div_.table("grid");
908
+ } else {
909
+ tbl = div(); // dummy
910
+ }
911
+ await this.renderExpansion(div_.table("grid"), vs, tbl);
912
+ return div_.toString();
913
+ }
914
+
901
915
  async renderExpansion(x, vs, tbl) {
902
916
  this.renderProperty(tbl, 'Expansion Identifier', vs.expansion.identifier);
903
917
  this.renderProperty(tbl, 'Expansion Timestamp', vs.expansion.timestamp);
904
918
  this.renderProperty(tbl, 'Expansion Total', vs.expansion.total);
905
919
  this.renderProperty(tbl, 'Expansion Offset', vs.expansion.offset);
920
+ const warnings = [];
921
+ const warningNames = new Set(['deprecated', 'withdrawn', 'retired', 'experimental', 'draft']);
922
+ const useds = [];
923
+ const usedNames = new Set(['codesystem', 'valueset', 'supplement']);
906
924
  for (let p of vs.expansion.parameter || []) {
907
- if( getValueName(p) === 'valueUri' || getValueName(p) === 'valueCanonical') {
925
+ if (p.name.startsWith('warning-') && warningNames.has(p.name.substring(8))) {
926
+ warnings.push(p);
927
+ } else if (p.name.startsWith('used-') && usedNames.has(p.name.substring(5))) {
928
+ useds.push(p);
929
+ } else if( getValueName(p) === 'valueUri' || getValueName(p) === 'valueCanonical') {
908
930
  await this.renderPropertyLink(tbl, "Parameter: " + p.name, getValuePrimitive(p));
909
931
  } else {
910
932
  this.renderProperty(tbl, "Parameter: " + p.name, getValuePrimitive(p));
911
933
  }
912
934
  }
935
+ if (useds.length > 0) {
936
+ await this.renderUsed(x, useds);
937
+ }
938
+ if (warnings.length > 0) {
939
+ await this.renderWarnings(x, warnings);
940
+ }
913
941
 
914
942
  if (!vs.expansion.contains || vs.expansion.contains.length === 0) {
915
943
  x.para().i().tx('No concepts in expansion');
@@ -935,10 +963,10 @@ class Renderer {
935
963
  }
936
964
  headerRow.th().tx(this.translate('TX_DISPLAY'));
937
965
  if (columnInfo.hasAbstract) {
938
- headerRow.th().tx('Abstract');
966
+ headerRow.th().tx(this.translate('Abstract'));
939
967
  }
940
968
  if (columnInfo.hasInactive) {
941
- headerRow.th().tx('Inactive');
969
+ headerRow.th().tx(this.translate('VALUE_SET_INACTIVE'));
942
970
  }
943
971
 
944
972
  // Property columns (from expansion.property definitions)
@@ -1117,12 +1145,12 @@ class Renderer {
1117
1145
 
1118
1146
  // Abstract column
1119
1147
  if (columnInfo.hasAbstract) {
1120
- tr.td().tx(contains.abstract === true ? 'true' : '');
1148
+ tr.td().tx(contains.abstract === true ? 'abstract' : '');
1121
1149
  }
1122
1150
 
1123
1151
  // Inactive column
1124
1152
  if (columnInfo.hasInactive) {
1125
- tr.td().tx(contains.inactive === true ? 'true' : '');
1153
+ tr.td().tx(contains.inactive === true ? this.translate('VALUE_SET_INACT') : '');
1126
1154
  }
1127
1155
 
1128
1156
  // Property columns
@@ -1566,6 +1594,52 @@ class Renderer {
1566
1594
 
1567
1595
  return div_.toString();
1568
1596
  }
1597
+
1598
+ async renderWarnings(x, warnings) {
1599
+ await this.renderWarningsForStatus(x, 'deprecated', warnings);
1600
+ await this.renderWarningsForStatus(x, 'withdrawn', warnings);
1601
+ await this.renderWarningsForStatus(x, 'retired', warnings);
1602
+ await this.renderWarningsForStatus(x, 'experimental', warnings);
1603
+ await this.renderWarningsForStatus(x, 'draft', warnings);
1604
+ }
1605
+
1606
+ async renderWarningsForStatus(x, name, warnings) {
1607
+ const wl = warnings.filter(item => item.name == 'warning-'+name);
1608
+ if (wl && wl.length > 0) {
1609
+ x.para().tx(`This ValueSet depends on the following ${name} ValueSets: `);
1610
+ let ul = x.ul();
1611
+ for (const w of wl) {
1612
+ const linkinfo = await this.linkResolver.resolveURL(this.opContext, getValuePrimitive(w));
1613
+ if (linkinfo) {
1614
+ ul.li().ah(linkinfo.link).tx(linkinfo.description);
1615
+ } else {
1616
+ ul.li().code().tx(getValuePrimitive(w));
1617
+ }
1618
+ }
1619
+ }
1620
+ }
1621
+
1622
+ async renderUsed(x, list) {
1623
+ x.para().tx(`This ValueSet depends on the following items:`);
1624
+ let ul = x.ul();
1625
+ await this.renderUsedForType(ul, 'codesystem', 'CodeSystem', list);
1626
+ await this.renderUsedForType(ul, 'valueset', 'ValueSet', list);
1627
+ await this.renderUsedForType(ul, 'supplement', 'Supplement', list);
1628
+ }
1629
+
1630
+ async renderUsedForType(ul, name, title, list) {
1631
+ const wl = list.filter(item => item.name == 'used-' + name);
1632
+ for (const w of wl) {
1633
+ const li = ul.li();
1634
+ li.tx(title+": ");
1635
+ const linkinfo = await this.linkResolver.resolveURL(this.opContext, getValuePrimitive(w));
1636
+ if (linkinfo) {
1637
+ li.ah(linkinfo.link).tx(linkinfo.description);
1638
+ } else {
1639
+ li.code().tx(getValuePrimitive(w));
1640
+ }
1641
+ }
1642
+ }
1569
1643
  }
1570
1644
 
1571
1645
  module.exports = { Renderer };