line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
package SemVer; |
2
|
|
|
|
|
|
|
|
3
|
2
|
|
|
2
|
|
141967
|
use 5.008001; |
|
2
|
|
|
|
|
16
|
|
4
|
2
|
|
|
2
|
|
10
|
use strict; |
|
2
|
|
|
|
|
5
|
|
|
2
|
|
|
|
|
46
|
|
5
|
2
|
|
|
2
|
|
865
|
use version 0.82; |
|
2
|
|
|
|
|
3887
|
|
|
2
|
|
|
|
|
15
|
|
6
|
2
|
|
|
2
|
|
162
|
use Scalar::Util (); |
|
2
|
|
|
|
|
5
|
|
|
2
|
|
|
|
|
53
|
|
7
|
|
|
|
|
|
|
|
8
|
|
|
|
|
|
|
use overload ( |
9
|
2
|
|
|
|
|
22
|
'""' => 'stringify', |
10
|
|
|
|
|
|
|
'<=>' => 'vcmp', |
11
|
|
|
|
|
|
|
'cmp' => 'vcmp', |
12
|
|
|
|
|
|
|
'bool' => 'vbool', |
13
|
2
|
|
|
2
|
|
2358
|
); |
|
2
|
|
|
|
|
1838
|
|
14
|
|
|
|
|
|
|
|
15
|
|
|
|
|
|
|
our @ISA = qw(version); |
16
|
|
|
|
|
|
|
our $VERSION = '0.10.0'; # For Module::Build |
17
|
|
|
|
|
|
|
|
18
|
56
|
|
|
56
|
|
277
|
sub _die { require Carp; Carp::croak(@_) } |
|
56
|
|
|
|
|
5747
|
|
19
|
|
|
|
|
|
|
|
20
|
|
|
|
|
|
|
# Prevent version.pm from mucking with our internals. |
21
|
|
|
|
2
|
|
|
sub import {} |
22
|
|
|
|
|
|
|
|
23
|
|
|
|
|
|
|
sub new { |
24
|
1061
|
|
|
1061
|
1
|
99085
|
my ($class, $ival) = @_; |
25
|
|
|
|
|
|
|
|
26
|
|
|
|
|
|
|
# Handle vstring. |
27
|
1061
|
100
|
|
|
|
2913
|
return $class->SUPER::new($ival) if Scalar::Util::isvstring($ival); |
28
|
|
|
|
|
|
|
|
29
|
|
|
|
|
|
|
# Let version handle cloning. |
30
|
1056
|
100
|
|
|
|
1451
|
if (eval { $ival->isa('version') }) { |
|
1056
|
|
|
|
|
4322
|
|
31
|
597
|
|
|
|
|
3316
|
my $self = $class->SUPER::new($ival); |
32
|
597
|
|
|
|
|
1414
|
$self->{extra} = $ival->{extra}; |
33
|
597
|
|
|
|
|
937
|
$self->{patch} = $ival->{patch}; |
34
|
597
|
|
|
|
|
836
|
$self->{prerelease} = $ival->{prerelease}; |
35
|
597
|
|
|
|
|
1724
|
return $self; |
36
|
|
|
|
|
|
|
} |
37
|
|
|
|
|
|
|
|
38
|
|
|
|
|
|
|
# Regex taken from https://semver.org/#is-there-a-suggested-regular-expression-regex-to-check-a-semver-string. |
39
|
459
|
|
|
|
|
3598
|
my ($major, $minor, $patch, $prerelease, $meta) = ( |
40
|
|
|
|
|
|
|
$ival =~ /^v?(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-((?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\.(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\+([0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*))?$/ |
41
|
|
|
|
|
|
|
); |
42
|
459
|
100
|
|
|
|
1188
|
_die qq{Invalid semantic version string format: "$ival"} |
43
|
|
|
|
|
|
|
unless defined $major; |
44
|
|
|
|
|
|
|
|
45
|
411
|
|
|
|
|
2878
|
return _init($class->SUPER::new("$major.$minor.$patch"), $prerelease, $meta); |
46
|
|
|
|
|
|
|
} |
47
|
|
|
|
|
|
|
|
48
|
|
|
|
|
|
|
sub _init { |
49
|
623
|
|
|
623
|
|
1225
|
my ($self, $pre, $meta) = @_; |
50
|
623
|
100
|
|
|
|
1132
|
if (defined $pre) { |
51
|
250
|
|
|
|
|
698
|
$self->{extra} = "-$pre"; |
52
|
250
|
|
|
|
|
323
|
@{$self->{prerelease}} = split /[.]/, $pre; |
|
250
|
|
|
|
|
830
|
|
53
|
|
|
|
|
|
|
} |
54
|
623
|
100
|
|
|
|
1172
|
if (defined $meta) { |
55
|
33
|
|
|
|
|
83
|
$self->{extra} .= "+$meta"; |
56
|
33
|
|
|
|
|
45
|
@{$self->{patch}} = split /[.]/, $meta; |
|
33
|
|
|
|
|
98
|
|
57
|
|
|
|
|
|
|
} |
58
|
|
|
|
|
|
|
|
59
|
623
|
|
|
|
|
2179
|
return $self; |
60
|
|
|
|
|
|
|
} |
61
|
|
|
|
|
|
|
|
62
|
|
|
|
|
|
|
$VERSION = __PACKAGE__->new($VERSION); # For ourselves. |
63
|
|
|
|
|
|
|
|
64
|
|
|
|
|
|
|
sub _lenient { |
65
|
798
|
|
|
798
|
|
1494
|
my ($class, $ctor, $ival) = @_; |
66
|
|
|
|
|
|
|
return $class->new($ival) if Scalar::Util::isvstring($ival) |
67
|
798
|
100
|
100
|
|
|
2587
|
or eval { $ival->isa('version') }; |
|
795
|
|
|
|
|
4748
|
|
68
|
|
|
|
|
|
|
|
69
|
|
|
|
|
|
|
# Use official regex for prerelease and meta, use more lenient version num matching and whitespace. |
70
|
219
|
|
|
|
|
1628
|
my ($v, $prerelease, $meta) = ( |
71
|
|
|
|
|
|
|
$ival =~ /^[[:space:]]* |
72
|
|
|
|
|
|
|
v?([\d_]+(?:\.[\d_]+(?:\.[\d_]+)?)?) |
73
|
|
|
|
|
|
|
(?:-((?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\.(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\+([0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*))? |
74
|
|
|
|
|
|
|
[[:space:]]*$/x |
75
|
|
|
|
|
|
|
); |
76
|
|
|
|
|
|
|
|
77
|
219
|
100
|
|
|
|
563
|
_die qq{Invalid semantic version string format: "$ival"} |
78
|
|
|
|
|
|
|
unless defined $v; |
79
|
|
|
|
|
|
|
|
80
|
212
|
100
|
100
|
|
|
811
|
$v += 0 if $v && $v =~ s/_//g; # ignore underscores. |
81
|
212
|
|
|
|
|
862
|
my $code = $class->can("SUPER::$ctor"); |
82
|
212
|
|
|
|
|
1376
|
return _init($code->($class, $v), $prerelease, $meta); |
83
|
|
|
|
|
|
|
} |
84
|
|
|
|
|
|
|
|
85
|
|
|
|
|
|
|
sub declare { |
86
|
710
|
|
|
710
|
1
|
10840
|
shift->_lenient('declare', @_); |
87
|
|
|
|
|
|
|
} |
88
|
|
|
|
|
|
|
|
89
|
|
|
|
|
|
|
sub parse { |
90
|
88
|
|
|
88
|
1
|
5313
|
shift->_lenient('parse', @_); |
91
|
|
|
|
|
|
|
} |
92
|
|
|
|
|
|
|
|
93
|
|
|
|
|
|
|
sub stringify { |
94
|
1361
|
|
|
1361
|
1
|
2577
|
my $self = shift; |
95
|
1361
|
|
|
|
|
4240
|
my $str = $self->SUPER::stringify; |
96
|
|
|
|
|
|
|
# This is purely for SemVers constructed from version objects. |
97
|
1361
|
100
|
|
|
|
3645
|
$str += 0 if $str =~ s/_//g; # ignore underscores. |
98
|
1361
|
|
50
|
|
|
8765
|
return $str . ($self->{dash} || '') . ($self->{extra} || ''); |
|
|
|
100
|
|
|
|
|
99
|
|
|
|
|
|
|
} |
100
|
|
|
|
|
|
|
|
101
|
|
|
|
|
|
|
sub normal { |
102
|
125
|
|
|
125
|
1
|
210
|
my $self = shift; |
103
|
125
|
|
|
|
|
912
|
(my $norm = $self->SUPER::normal) =~ s/^v//; |
104
|
125
|
|
|
|
|
290
|
$norm =~ s/_/./g; |
105
|
125
|
|
100
|
|
|
788
|
return $norm . ($self->{extra} || ''); |
106
|
|
|
|
|
|
|
} |
107
|
|
|
|
|
|
|
|
108
|
1
|
|
|
1
|
1
|
3
|
sub numify { _die 'Semantic versions cannot be numified'; } |
109
|
12
|
|
|
12
|
1
|
6795
|
sub is_alpha { !!shift->{extra} } |
110
|
|
|
|
|
|
|
sub vbool { |
111
|
103
|
|
|
103
|
1
|
7976
|
my $self = shift; |
112
|
103
|
|
|
|
|
222
|
return version::vcmp($self, $self->new("0.0.0"), 1); |
113
|
|
|
|
|
|
|
} |
114
|
|
|
|
|
|
|
|
115
|
|
|
|
|
|
|
# Sort Ordering: |
116
|
|
|
|
|
|
|
# Precedence refers to how versions are compared to each other when ordered. Precedence MUST be calculated by |
117
|
|
|
|
|
|
|
# separating the version into major, minor, patch and pre-release identifiers in that order (Build metadata does not figure into precedence). |
118
|
|
|
|
|
|
|
# Precedence is determined by the first difference when comparing each of these identifiers from left to right as follows: |
119
|
|
|
|
|
|
|
# 1. Major, minor, and patch versions are always compared numerically. Example: 1.0.0 < 2.0.0 < 2.1.0 < 2.1.1. |
120
|
|
|
|
|
|
|
# 2. When major, minor, and patch are equal, a pre-release version has lower precedence than a normal version. |
121
|
|
|
|
|
|
|
# Example: 1.0.0-alpha < 1.0.0. |
122
|
|
|
|
|
|
|
# 3. Precedence for two pre-release versions with the same major, minor, and patch version MUST be determined by |
123
|
|
|
|
|
|
|
# comparing each dot separated identifier from left to right until a difference is found as follows: |
124
|
|
|
|
|
|
|
# 3.a. identifiers consisting of only digits are compared numerically and identifiers with letters or hyphens are |
125
|
|
|
|
|
|
|
# compared lexically in ASCII sort order. |
126
|
|
|
|
|
|
|
# 3.b. Numeric identifiers always have lower precedence than non-numeric identifiers. |
127
|
|
|
|
|
|
|
# 3.c. A larger set of pre-release fields has a higher precedence than a smaller set, if all of the preceding identifiers are equal. |
128
|
|
|
|
|
|
|
# Example: 1.0.0-alpha < 1.0.0-alpha.1 < 1.0.0-alpha.beta < 1.0.0-beta < 1.0.0-beta.2 < 1.0.0-beta.11 < 1.0.0-rc.1 < 1.0.0. |
129
|
|
|
|
|
|
|
sub vcmp { |
130
|
610
|
|
|
610
|
1
|
68838
|
my $left = shift; |
131
|
610
|
|
|
|
|
1830
|
my $right = ref($left)->declare(shift); |
132
|
|
|
|
|
|
|
|
133
|
|
|
|
|
|
|
# Reverse? |
134
|
610
|
100
|
|
|
|
1700
|
($left, $right) = shift() ? ($right, $left): ($left, $right); |
135
|
|
|
|
|
|
|
|
136
|
|
|
|
|
|
|
# Major and minor win. - case 1. |
137
|
610
|
100
|
|
|
|
2226
|
if (my $ret = $left->SUPER::vcmp($right, 0)) { |
138
|
138
|
|
|
|
|
1547
|
return $ret; |
139
|
|
|
|
|
|
|
} else { #cases 2, 3 |
140
|
472
|
|
|
|
|
657
|
my $lenLeft = 0; |
141
|
472
|
|
|
|
|
625
|
my $lenRight = 0; |
142
|
472
|
100
|
|
|
|
1039
|
if (defined $left->{prerelease}) { |
143
|
215
|
|
|
|
|
271
|
$lenLeft = scalar(@{$left->{prerelease}}); |
|
215
|
|
|
|
|
378
|
|
144
|
|
|
|
|
|
|
} |
145
|
472
|
100
|
|
|
|
888
|
if (defined $right->{prerelease}) { |
146
|
206
|
|
|
|
|
235
|
$lenRight = scalar(@{$right->{prerelease}}); |
|
206
|
|
|
|
|
303
|
|
147
|
|
|
|
|
|
|
} |
148
|
472
|
|
|
|
|
818
|
my $lenMin = ($lenLeft, $lenRight)[$lenLeft > $lenRight]; |
149
|
472
|
100
|
|
|
|
851
|
if ( $lenLeft == 0) { |
150
|
257
|
100
|
|
|
|
384
|
if ($lenRight == 0) { |
151
|
243
|
|
|
|
|
2627
|
return 0; # Neither LEFT nor RIGHT have prerelease identifiers - versions are equal |
152
|
|
|
|
|
|
|
} else { |
153
|
|
|
|
|
|
|
# Case 2: When major, minor, and patch are equal, a pre-release version has lower precedence than a normal version. |
154
|
14
|
|
|
|
|
149
|
return 1; # Only RIGHT has prelease - not LEFT -> LEFT wins |
155
|
|
|
|
|
|
|
} |
156
|
|
|
|
|
|
|
} else { |
157
|
215
|
100
|
|
|
|
404
|
if ($lenRight == 0) { |
158
|
|
|
|
|
|
|
# Case 2: When major, minor, and patch are equal, a pre-release version has lower precedence than a normal version. |
159
|
23
|
|
|
|
|
272
|
return -1; # Only LEFT has prelease identifiers - not RIGHT -> RIGHT wins |
160
|
|
|
|
|
|
|
} else { |
161
|
|
|
|
|
|
|
# LEFT and RIGHT have prelease identifiers - compare each part separately |
162
|
192
|
|
|
|
|
398
|
for (my $i = 0; $i < $lenMin; $i++) { |
163
|
225
|
|
|
|
|
622
|
my $isNumLeft = Scalar::Util::looks_like_number($left->{prerelease}->[$i]); |
164
|
225
|
|
|
|
|
446
|
my $isNumRight = Scalar::Util::looks_like_number($right->{prerelease}->[$i]); |
165
|
|
|
|
|
|
|
# Case 3.b: Numeric identifiers always have lower precedence than non-numeric identifiers |
166
|
225
|
50
|
66
|
|
|
1052
|
if (!$isNumLeft && $isNumRight) { |
|
|
100
|
100
|
|
|
|
|
|
|
100
|
66
|
|
|
|
|
167
|
0
|
|
|
|
|
0
|
return 1; # LEFT identifier is Non-numeric - RIGHT identifier is numeric -> LEFT wins |
168
|
|
|
|
|
|
|
} elsif ($isNumLeft && !$isNumRight) { |
169
|
1
|
|
|
|
|
27
|
return -1; # LEFT identifier is numeric - RIGHT identifier is non-numeric -> RIGHT wins |
170
|
|
|
|
|
|
|
} elsif ($isNumLeft && $isNumRight) { |
171
|
|
|
|
|
|
|
# Case 3.a.1: identifiers consisting of only digits are compared numerically |
172
|
32
|
100
|
|
|
|
76
|
if ($left->{prerelease}->[$i] == $right->{prerelease}->[$i] ) { |
|
|
50
|
|
|
|
|
|
173
|
26
|
|
|
|
|
53
|
next; # LEFT identifier and RIGHT identifier are equal - step to next part |
174
|
|
|
|
|
|
|
} elsif ($left->{prerelease}->[$i] > $right->{prerelease}->[$i] ) { |
175
|
0
|
|
|
|
|
0
|
return 1; # LEFT identifier is bigger than RIGHT identifier -> LEFT wins |
176
|
|
|
|
|
|
|
} else { |
177
|
6
|
|
|
|
|
89
|
return -1; return 1; # LEFT identifier is smaller than RIGHT identifier -> RIGHT wins |
|
0
|
|
|
|
|
0
|
|
178
|
|
|
|
|
|
|
} |
179
|
|
|
|
|
|
|
} else { |
180
|
|
|
|
|
|
|
# Case 3.a.2: identifiers with letters or hyphens are compared lexically in ASCII sort order. |
181
|
192
|
100
|
|
|
|
537
|
if (lc $left->{prerelease}->[$i] eq lc $right->{prerelease}->[$i] ) { |
|
|
100
|
|
|
|
|
|
182
|
131
|
|
|
|
|
294
|
next; # LEFT identifier and RIGHT identifier are equal - step to next part |
183
|
|
|
|
|
|
|
} elsif (lc $left->{prerelease}->[$i] gt lc $right->{prerelease}->[$i] ) { |
184
|
10
|
|
|
|
|
123
|
return 1; # LEFT identifier is bigger than RIGHT identifier -> LEFT wins |
185
|
|
|
|
|
|
|
} else { |
186
|
51
|
|
|
|
|
651
|
return -1; return 1; # LEFT identifier is smaller than RIGHT identifier -> RIGHT wins |
|
0
|
|
|
|
|
0
|
|
187
|
|
|
|
|
|
|
} |
188
|
|
|
|
|
|
|
} |
189
|
|
|
|
|
|
|
} |
190
|
|
|
|
|
|
|
# Case 3.c: A larger set of pre-release fields has a higher precedence than a smaller set, if all of the preceding identifiers are equal |
191
|
124
|
50
|
|
|
|
282
|
if ($lenLeft > $lenRight) { |
|
|
100
|
|
|
|
|
|
192
|
0
|
|
|
|
|
0
|
return 1; # All existing identifiers are equal, but LEFT has more identifiers -> LEFT wins |
193
|
|
|
|
|
|
|
} elsif ($lenLeft < $lenRight) { |
194
|
6
|
|
|
|
|
98
|
return -1; # All existing identifiers are equal, but RIGHT has more identifiers -> RIGHT wins |
195
|
|
|
|
|
|
|
} |
196
|
|
|
|
|
|
|
# All identifiers are equal |
197
|
118
|
|
|
|
|
1306
|
return 0; |
198
|
|
|
|
|
|
|
} |
199
|
|
|
|
|
|
|
} |
200
|
|
|
|
|
|
|
} |
201
|
|
|
|
|
|
|
} |
202
|
|
|
|
|
|
|
|
203
|
|
|
|
|
|
|
1; |
204
|
|
|
|
|
|
|
__END__ |