fhirsmith 0.5.4 → 0.5.5

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 CHANGED
@@ -5,9 +5,19 @@ All notable changes to the Health Intersections Node Server will be documented i
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6
6
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
 
8
+ ## [v0.5.5] - 2026-02-26
9
+
10
+ ### Changed
11
+ - Fix loading problem for multiple versions of the same code system
12
+ - Fix url matching in search to be precise
13
+
14
+ ### Tx Conformance Statement
15
+
16
+ FHIRsmith 0.5.5 passed all 1382 HL7 terminology service tests (modes tx.fhir.org,omop,general,snomed, tests v1.9.0, runner v6.8.1)
17
+
8
18
  ## [v0.5.4] - 2026-02-25
9
19
 
10
- This version requires that you delete all package content from the terminology-cache directly
20
+ This version requires that you delete all package content from the terminology-cache directly
11
21
  by hand before running this version.
12
22
 
13
23
  ### Changed
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "fhirsmith",
3
- "version": "0.5.4",
3
+ "version": "0.5.5",
4
4
  "description": "A Node.js server that provides a collection of tools to serve the FHIR ecosystem",
5
5
  "main": "server.js",
6
6
  "engines": {
@@ -1,3 +1,4 @@
1
+ const {VersionUtilities, VersionPrecision} = require("../../library/version-utilities");
1
2
 
2
3
  /**
3
4
  * Base class for metadata resources to provide common interface
@@ -83,6 +84,68 @@ class CanonicalResource {
83
84
  }
84
85
  return this.jsonObj.versionAlgorithmString;
85
86
  }
87
+
88
+ guessVersionAlgorithmFromVersion(version) {
89
+ if (VersionUtilities.isSemVerWithWildcards(version)) {
90
+ return 'semver';
91
+ }
92
+ if (this.appearsToBeDate(version)) {
93
+ return 'date';
94
+ }
95
+ if (this.isAnInteger(version)) {
96
+ return 'integer';
97
+ }
98
+ return 'alpha';
99
+ }
100
+
101
+ /**
102
+ * returns true if this is more recent than other.
103
+ *
104
+ * Uses version if possible, otherwise uses date
105
+ *
106
+ * @param other
107
+ * @returns {boolean}
108
+ */
109
+ isMoreRecent(other) {
110
+ if (this.version && other.version && this.version != other.version) {
111
+ const fmt = this.versionAlgorithm() || other.versionAlgorithm() || this.guessVersionAlgorithmFromVersion(this.version);
112
+ switch (fmt) {
113
+ case 'semver':
114
+ return VersionUtilities.isThisOrLater(other.version, this.version, VersionPrecision.PATCH);
115
+ case 'date':
116
+ return this.dateIsMoreRecent(this.version, other.version);
117
+ case 'integer':
118
+ return parseInt(this.version, 10) > parseInt(other.version, 10);
119
+ case 'alpha': return this.version.localeCompare(other.version) > 0;
120
+ default: return this.version.localeCompare(other.version);
121
+ }
122
+ }
123
+ if (this.date && other.date && this.date != other.date) {
124
+ return this.dateIsMoreRecent(this.date, other.date);
125
+ }
126
+ return false;
127
+ }
128
+
129
+ appearsToBeDate(version) {
130
+ if (!version || typeof version !== 'string') return false;
131
+ // Strip optional time portion (T...) before checking
132
+ const datePart = version.split('T')[0];
133
+ return /^\d{4}-?\d{2}(-?\d{2})?$/.test(datePart);
134
+
135
+ }
136
+
137
+ dateIsMoreRecent(date, date2) {
138
+ return this.normaliseDateString(date) > this.normaliseDateString(date2);
139
+ }
140
+
141
+ normaliseDateString(date) {
142
+ // Strip time portion, then remove dashes so all formats compare uniformly as YYYYMMDD or YYYYMM
143
+ return date.split('T')[0].replace(/-/g, '');
144
+ }
145
+
146
+ isAnInteger(version) {
147
+ return /^\d+$/.test(version);
148
+ }
86
149
  }
87
150
 
88
151
  module.exports = { CanonicalResource };
package/tx/library.js CHANGED
@@ -449,8 +449,13 @@ class Library {
449
449
  for (const resource of resources) {
450
450
  const cs = new CodeSystem(await contentLoader.loadFile(resource, contentLoader.fhirVersion()));
451
451
  cs.sourcePackage = contentLoader.pid();
452
- cp.codeSystems.set(cs.url, cs);
453
- cp.codeSystems.set(cs.vurl, cs);
452
+ const existing = cp.codeSystems.get(cs.url);
453
+ if (!existing || cs.isMoreRecent(existing)) {
454
+ cp.codeSystems.set(cs.url, cs);
455
+ }
456
+ if (cs.version) {
457
+ cp.codeSystems.set(cs.vurl, cs);
458
+ }
454
459
  csc++;
455
460
  }
456
461
  this.codeSystemProviders.push(cp);
package/tx/provider.js CHANGED
@@ -136,8 +136,13 @@ class Provider {
136
136
  for (const resource of resources) {
137
137
  const cs = new CodeSystem(await contentLoader.loadFile(resource, contentLoader.fhirVersion()));
138
138
  cs.sourcePackage = contentLoader.pid();
139
- this.codeSystems.set(cs.url, cs);
140
- this.codeSystems.set(cs.vurl, cs);
139
+ const existing = this.codeSystems.get(cs.url);
140
+ if (!existing || cs.isMoreRecent(existing)) {
141
+ this.codeSystems.set(cs.url, cs);
142
+ }
143
+ if (cs.version) {
144
+ this.codeSystems.set(cs.vurl, cs);
145
+ }
141
146
  }
142
147
  const vs = new PackageValueSetProvider(contentLoader);
143
148
  await vs.initialize();
@@ -177,6 +177,12 @@ class SearchWorker extends TerminologyWorker {
177
177
  isMatch = false;
178
178
  break;
179
179
  }
180
+ } else if (param === 'url') { // exact match
181
+ const propValue = json.url;
182
+ if (propValue != searchValue) {
183
+ isMatch = false;
184
+ break;
185
+ }
180
186
  } else {
181
187
  // Standard partial text match
182
188
  const propValue = json[jsonProp];