Skip to content

Commit 7fabdef

Browse files
authored
Support pre-release vesions of FHIR (#193)
1 parent d36afd6 commit 7fabdef

8 files changed

Lines changed: 595 additions & 33 deletions

File tree

src/Version/SourceMetadata.php

Lines changed: 87 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,18 @@ class SourceMetadata
3131
private string $_fhirGenerationDate;
3232
private string $_fhirVersion;
3333

34+
/**
35+
* The base version string with any pre-release suffix stripped.
36+
* e.g. 'v6.0.0-ballot4' -> 'v6.0.0'.
37+
* Used for all Semver range comparisons.
38+
*/
39+
private string $_fhirVersionBase;
40+
41+
/**
42+
* The pre-release identifier, if any (e.g. 'ballot4'). Null for GA releases.
43+
*/
44+
private null|string $_fhirPreRelease = null;
45+
3446
public function __construct(string $schemPath)
3547
{
3648
$this->_schemaPath = $schemPath;
@@ -65,14 +77,14 @@ public function getSemanticVersion(bool $trimmed): string
6577
}
6678

6779
/**
68-
* Return the shortenend representation of the FHIR semantic version containing only Manjor.Minor values.
80+
* Return the shortenend representation of the FHIR semantic version containing only Major.Minor values.
6981
*
7082
* @return string
7183
*/
7284
public function getShortVersion(): string
7385
{
7486
$this->_compile();
75-
$v = ltrim($this->_fhirVersion);
87+
$v = ltrim($this->_fhirVersionBase, 'v');
7688
return match (substr_count($v, '.')) {
7789
1 => $v,
7890
2 => substr($v, 0, strrpos($v, '.')),
@@ -82,13 +94,43 @@ public function getShortVersion(): string
8294

8395
/**
8496
* Returns an integer representation of the FHIR semantic version.
97+
* Pre-release suffixes are ignored; the integer is derived from the base
98+
* version only, so 'v6.0.0-ballot4' and 'v6.0.0' produce the same value.
99+
* Use isPreRelease() to distinguish ballot from GA releases.
85100
*
86101
* @return int
87102
*/
88103
public function getVersionInteger(): int
89104
{
90105
$this->_compile();
91-
return intval(sprintf("%'.-08s", str_replace(['v', '.'], '', $this->_fhirVersion)));
106+
return intval(sprintf("%'.-08s", str_replace(['v', '.'], '', $this->_fhirVersionBase)));
107+
}
108+
109+
/**
110+
* Returns the pre-release identifier extracted from the FHIR version string,
111+
* or null if this is a GA release.
112+
*
113+
* e.g. 'v6.0.0-ballot4' -> 'ballot4'
114+
* 'v5.0.0' -> null
115+
*
116+
* @return string|null
117+
*/
118+
public function getPreRelease(): null|string
119+
{
120+
$this->_compile();
121+
return $this->_fhirPreRelease;
122+
}
123+
124+
/**
125+
* Returns true when the FHIR source version carries a pre-release suffix
126+
* (e.g. '-ballot4').
127+
*
128+
* @return bool
129+
*/
130+
public function isPreRelease(): bool
131+
{
132+
$this->_compile();
133+
return null !== $this->_fhirPreRelease;
92134
}
93135

94136
/**
@@ -98,42 +140,59 @@ public function getVersionInteger(): int
98140
*/
99141
public function isDSTU1(): bool
100142
{
101-
return Semver::satisfies($this->getSemanticVersion(false), '< v1.0.0');
143+
return Semver::satisfies($this->_getVersionBase(), '< v1.0.0');
102144
}
103145

104146
public function isDSTU2(): bool
105147
{
106-
$semver = $this->getSemanticVersion(false);
107-
return Semver::satisfies($semver, '>= v1.0.0')
108-
&& Semver::satisfies($semver, '< v3.0.0');
148+
$base = $this->_getVersionBase();
149+
return Semver::satisfies($base, '>= v1.0.0')
150+
&& Semver::satisfies($base, '< v3.0.0');
109151
}
110152

111153
public function isSTU3(): bool
112154
{
113-
$semver = $this->getSemanticVersion(false);
114-
return Semver::satisfies($semver, '>= v3.0.0')
115-
&& Semver::satisfies($semver, '< v4.0.0');
155+
$base = $this->_getVersionBase();
156+
return Semver::satisfies($base, '>= v3.0.0')
157+
&& Semver::satisfies($base, '< v4.0.0');
116158
}
117159

118160
public function isR4(): bool
119161
{
120-
$semver = $this->getSemanticVersion(false);
121-
return Semver::satisfies($semver, '>= v4.0.0')
122-
&& Semver::satisfies($semver, '< v4.3.0');
162+
$base = $this->_getVersionBase();
163+
return Semver::satisfies($base, '>= v4.0.0')
164+
&& Semver::satisfies($base, '< v4.3.0');
123165
}
124166

125167
public function isR4B(): bool
126168
{
127-
$semver = $this->getSemanticVersion(false);
128-
return Semver::satisfies($semver, '>= v4.3.0')
129-
&& Semver::satisfies($semver, '< v5.0.0');
169+
$base = $this->_getVersionBase();
170+
return Semver::satisfies($base, '>= v4.3.0')
171+
&& Semver::satisfies($base, '< v5.0.0');
130172
}
131173

132174
public function isR5(): bool
133175
{
134-
$semver = $this->getSemanticVersion(false);
135-
return Semver::satisfies($semver, '>= v5.0.0')
136-
&& Semver::satisfies($semver, '< v6.0.0');
176+
$base = $this->_getVersionBase();
177+
return Semver::satisfies($base, '>= v5.0.0')
178+
&& Semver::satisfies($base, '< v6.0.0');
179+
}
180+
181+
public function isR6(): bool
182+
{
183+
$base = $this->_getVersionBase();
184+
return Semver::satisfies($base, '>= v6.0.0')
185+
&& Semver::satisfies($base, '< v7.0.0');
186+
}
187+
188+
/**
189+
* Returns the compiled base version (without pre-release suffix) for use
190+
* in Semver range comparisons.
191+
*/
192+
private function _getVersionBase(): string
193+
{
194+
$this->_compile();
195+
return $this->_fhirVersionBase;
137196
}
138197

139198
private function _compile(): void
@@ -180,6 +239,15 @@ private function _compile(): void
180239
$version = trim($version);
181240
if (str_starts_with($version, 'v')) {
182241
$this->_fhirVersion = $version;
242+
// Split off any pre-release suffix (e.g. 'v6.0.0-ballot4').
243+
$dashPos = strpos($version, '-');
244+
if (false !== $dashPos) {
245+
$this->_fhirVersionBase = substr($version, 0, $dashPos);
246+
$this->_fhirPreRelease = substr($version, $dashPos + 1);
247+
} else {
248+
$this->_fhirVersionBase = $version;
249+
$this->_fhirPreRelease = null;
250+
}
183251
} else {
184252
throw new \LogicException(
185253
sprintf(

template/core/class_fhir_version.php

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,21 +38,25 @@ class <?php echo $coreFile; ?> implements \JsonSerializable
3838
public const STU3_MIN_VERSION_INTEGER = 30000000;
3939
public const R4_MIN_VERSION_INTEGER = 40000000;
4040
public const R5_MIN_VERSION_INTEGER = 50000000;
41+
public const R6_MIN_VERSION_INTEGER = 60000000;
4142

4243
private string $_versionName;
4344
private string $_fhirSemanticVersion;
4445
private string $_fhirShortVersion;
4546
private int $_fhirVersionInteger;
47+
private null|string $_fhirPreRelease;
4648

4749
public function __construct(string $versionName,
4850
string $fhirSemanticVersion,
4951
string $fhirShortVersion,
50-
int $fhirVersionInteger)
52+
int $fhirVersionInteger,
53+
null|string $fhirPreRelease = null)
5154
{
5255
$this->_versionName = $versionName;
5356
$this->_fhirSemanticVersion = $fhirSemanticVersion;
5457
$this->_fhirShortVersion = $fhirShortVersion;
5558
$this->_fhirVersionInteger = $fhirVersionInteger;
59+
$this->_fhirPreRelease = $fhirPreRelease;
5660
}
5761

5862
public function getName(): string
@@ -75,13 +79,24 @@ public function getFHIRVersionInteger(): int
7579
return $this->_fhirVersionInteger;
7680
}
7781

82+
public function getFHIRPreRelease(): null|string
83+
{
84+
return $this->_fhirPreRelease;
85+
}
86+
87+
public function isFHIRPreRelease(): bool
88+
{
89+
return null !== $this->_fhirPreRelease;
90+
}
91+
7892
public function jsonSerialize(): \stdClass
7993
{
8094
$out = new \stdClass();
8195
$out->versionName = $this->_versionName;
8296
$out->fhirSemanticVersion = $this->_fhirSemanticVersion;
8397
$out->fhirShortversion = $this->_fhirShortVersion;
8498
$out->fhirVersionInteger = $this->_fhirVersionInteger;
99+
$out->fhirPreRelease = $this->_fhirPreRelease;
85100
return $out;
86101
}
87102

template/core/versions/interface_version.php

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,21 @@ public function getFHIRShortVersion(): string;
8282
*/
8383
public function getFHIRVersionInteger(): int;
8484

85+
/**
86+
* Must return the pre-release identifier from the FHIR version string (e.g. 'ballot4'),
87+
* or null when this is a GA release.
88+
*
89+
* @return null|string
90+
*/
91+
public function getFHIRPreRelease(): null|string;
92+
93+
/**
94+
* Must return true when the FHIR source version is a pre-release (e.g. a ballot build).
95+
*
96+
* @return bool
97+
*/
98+
public function isFHIRPreRelease(): bool;
99+
85100
/**
86101
* Must return the date this FHIR version's source was generated
87102
*

template/tests/core/mock/class_abstract_mock_type.php

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,8 @@ abstract class <?php echo $coreFile; ?> implements <?php echo $typeInterface; ?>
5757

5858
public function __construct(string $name,
5959
string $versionName = self::DEFAULT_MOCK_VERSION_NAME,
60-
string $semanticVersion = self::DEFAULT_MOCK_SEMANTIC_VERSION)
60+
string $semanticVersion = self::DEFAULT_MOCK_SEMANTIC_VERSION,
61+
null|string $preRelease = null)
6162
{
6263
$this->_name = $name;
6364

@@ -69,10 +70,11 @@ public function __construct(string $name,
6970
};
7071

7172
$this->_fhirVersion = new <?php echo $fhirVersion; ?>(
72-
$versionName,
73-
$semanticVersion,
74-
$shortVersion,
75-
intval(sprintf("%'.-08s", str_replace(['v', '.'], '', $semanticVersion))),
73+
versionName: $versionName,
74+
fhirSemanticVersion: $semanticVersion,
75+
fhirShortVersion: $shortVersion,
76+
fhirVersionInteger: intval(sprintf("%'.-08s", str_replace(['v', '.'], '', $semanticVersion))),
77+
fhirPreRelease: $preRelease,
7678
);
7779
}
7880

template/tests/core/mock/class_mock_version.php

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@ class <?php echo $coreFile; ?> implements <?php echo $versionInterface; ?>
5959
public const FHIR_SEMANTIC_VERSION = 'v99.99.99';
6060
public const FHIR_SHORT_VERSION = 'v9.9';
6161
public const FHIR_VERSION_INTEGER = 999999999;
62+
public const FHIR_PRE_RELEASE = null;
6263

6364
private static <?php echo $fhirVersion; ?> $_fhirVersion;
6465
private static <?php echo $versionTypeMapInterface; ?> $_typeMap;
@@ -80,10 +81,11 @@ public static function getFHIRVersion(): <?php echo $fhirVersion; ?>
8081
{
8182
if (!isset(self::$_fhirVersion)) {
8283
self::$_fhirVersion = new <?php echo $fhirVersion; ?>(
83-
self::NAME,
84-
self::FHIR_SEMANTIC_VERSION,
85-
self::FHIR_SHORT_VERSION,
86-
self::FHIR_VERSION_INTEGER,
84+
versionName: self::NAME,
85+
fhirSemanticVersion: self::FHIR_SEMANTIC_VERSION,
86+
fhirShortVersion: self::FHIR_SHORT_VERSION,
87+
fhirVersionInteger: self::FHIR_VERSION_INTEGER,
88+
fhirPreRelease: self::FHIR_PRE_RELEASE,
8789
);
8890
}
8991
return self::$_fhirVersion;
@@ -104,6 +106,16 @@ public function getFHIRVersionInteger(): int
104106
return self::FHIR_VERSION_INTEGER;
105107
}
106108

109+
public function getFHIRPreRelease(): null|string
110+
{
111+
return self::FHIR_PRE_RELEASE;
112+
}
113+
114+
public function isFHIRPreRelease(): bool
115+
{
116+
return null !== self::FHIR_PRE_RELEASE;
117+
}
118+
107119
public function getFHIRGenerationDate(): string
108120
{
109121
throw new \BadMethodCallException('Not implemented');

0 commit comments

Comments
 (0)