forked from featurevisor/featurevisor-php
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathCompareVersions.php
More file actions
81 lines (63 loc) · 2.14 KB
/
CompareVersions.php
File metadata and controls
81 lines (63 loc) · 2.14 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
<?php
namespace Featurevisor;
class CompareVersions
{
private static $semver = '/^[v^~<>=]*?(\d+)(?:\.([x*]|\d+)(?:\.([x*]|\d+)(?:\.([x*]|\d+))?(?:-([\da-z\-]+(?:\.[\da-z\-]+)*))?(?:\+[\da-z\-]+(?:\.[\da-z\-]+)*)?)?)?$/i';
public static function compare(string $v1, string $v2): int
{
// validate input and split into segments
$n1 = self::validateAndParse($v1);
$n2 = self::validateAndParse($v2);
// pop off the patch
$p1 = array_pop($n1);
$p2 = array_pop($n2);
// validate numbers
$r = self::compareSegments($n1, $n2);
if ($r !== 0) return $r;
// validate pre-release
if ($p1 && $p2) {
return self::compareSegments(explode('.', $p1), explode('.', $p2));
} elseif ($p1 || $p2) {
return $p1 ? -1 : 1;
}
return 0;
}
private static function validateAndParse(string $version): array
{
if (!preg_match(self::$semver, $version, $match)) {
throw new \Exception("Invalid argument not valid semver ('$version' received)");
}
array_shift($match);
return $match;
}
private static function isWildcard(string $s): bool
{
return $s === '*' || $s === 'x' || $s === 'X';
}
private static function forceType($a, $b): array
{
return gettype($a) !== gettype($b) ? [strval($a), strval($b)] : [$a, $b];
}
private static function tryParse(string $v)
{
$n = intval($v);
return is_nan($n) ? $v : $n;
}
private static function compareStrings(string $a, string $b): int
{
if (self::isWildcard($a) || self::isWildcard($b)) return 0;
list($ap, $bp) = self::forceType(self::tryParse($a), self::tryParse($b));
if ($ap > $bp) return 1;
if ($ap < $bp) return -1;
return 0;
}
private static function compareSegments($a, $b): int
{
$maxLength = max(count($a), count($b));
for ($i = 0; $i < $maxLength; $i++) {
$r = self::compareStrings($a[$i] ?? '0', $b[$i] ?? '0');
if ($r !== 0) return $r;
}
return 0;
}
}