1
1
#include " version_weaver.h"
2
+ #include < algorithm>
3
+ #include < cctype>
2
4
namespace version_weaver {
3
- bool validate (std::string_view version) {
4
- return std::holds_alternative<Version>(parse (version));
5
- }
5
+ bool validate (std::string_view version) { return bool (parse (version)); }
6
6
7
7
bool gt (std::string_view version1, std::string_view version2) { return true ; }
8
8
bool lt (std::string_view version1, std::string_view version2) { return true ; }
@@ -13,66 +13,81 @@ std::string coerce(std::string_view version) { return ""; }
13
13
std::string minimum (std::string_view range) { return " " ; }
14
14
std::string clean (std::string_view range) { return " " ; }
15
15
16
- std::variant<Version, ParseError> parse (std::string_view input) {
16
+ inline std::string_view trim_whitespace (std::string_view input) noexcept {
17
+ while (!input.empty () && std::isspace (input.front ())) {
18
+ input.remove_prefix (1 );
19
+ }
20
+ while (!input.empty () && std::isspace (input.back ())) {
21
+ input.remove_suffix (1 );
22
+ }
23
+ return input;
24
+ }
25
+
26
+ std::expected<Version, ParseError> parse (std::string_view input) {
17
27
if (input.size () > MAX_VERSION_LENGTH) {
18
- return ParseError::VERSION_LARGER_THAN_MAX_LENGTH;
28
+ return std::unexpected ( ParseError::VERSION_LARGER_THAN_MAX_LENGTH) ;
19
29
}
20
30
21
- std::string_view input_copy = input;
22
- // TODO: Trim leading and trailing whitespace
31
+ std::string_view input_copy = trim_whitespace (input);
23
32
24
33
auto dot_iterator = input_copy.find (' .' );
25
34
if (dot_iterator == std::string_view::npos) {
26
35
// Only major exists. No minor or patch.
27
- return ParseError::INVALID_INPUT;
36
+ return std::unexpected ( ParseError::INVALID_INPUT) ;
28
37
}
29
38
Version version;
30
39
auto major = input_copy.substr (0 , dot_iterator);
31
40
32
41
if (major.empty () || major.front () == ' 0' ) {
33
42
// Version components can not have leading zeroes.
34
- return ParseError::INVALID_INPUT;
43
+ return std::unexpected ( ParseError::INVALID_INPUT) ;
35
44
}
36
45
version.major = major;
37
46
input_copy = input_copy.substr (dot_iterator + 1 );
38
47
dot_iterator = input_copy.find (' .' );
39
48
if (dot_iterator == std::string_view::npos) {
40
49
// Only major and minor exists. No patch.
41
- return ParseError::INVALID_INPUT;
50
+ return std::unexpected ( ParseError::INVALID_INPUT) ;
42
51
}
43
52
44
53
auto minor = input_copy.substr (0 , dot_iterator);
45
- if (minor.empty () || minor.front () == ' 0' ) {
54
+ if (minor.empty () || ( minor.front () == ' 0' && minor. size () > 1 ) ) {
46
55
// Version components can not have leading zeroes.
47
- return ParseError::INVALID_INPUT;
56
+ return std::unexpected ( ParseError::INVALID_INPUT) ;
48
57
}
49
58
version.minor = minor;
50
59
input_copy = input_copy.substr (dot_iterator + 1 );
51
- dot_iterator = input_copy.find (' .' );
52
- if (dot_iterator == std::string_view::npos) {
53
- // Only major, minor and patch exists.
54
- return ParseError::INVALID_INPUT;
55
- }
56
-
57
- auto patch = input_copy.substr (0 , dot_iterator);
58
- if (patch.empty () || patch.front () == ' 0' ) {
59
- // Version components can not have leading zeroes.
60
- return ParseError::INVALID_INPUT;
60
+ dot_iterator = input_copy.find_first_of (" -+" );
61
+ auto patch = (dot_iterator == std::string_view::npos)
62
+ ? input_copy
63
+ : input_copy.substr (0 , dot_iterator);
64
+ if (patch.empty () || (patch.front () == ' 0' && patch.size () > 1 )) {
65
+ return std::unexpected (ParseError::INVALID_INPUT);
61
66
}
62
67
version.patch = patch;
68
+ if (dot_iterator == std::string_view::npos) {
69
+ return version;
70
+ }
71
+ bool is_pre_release = input_copy[dot_iterator] == ' -' ;
63
72
input_copy = input_copy.substr (dot_iterator + 1 );
64
-
65
- auto pre_release_iterator = input_copy.find (' -' );
66
- if (pre_release_iterator != std::string_view::npos) {
67
- version.pre_release = input_copy.substr (0 , pre_release_iterator);
68
- input_copy = input_copy.substr (pre_release_iterator + 1 );
69
- if (input_copy.find (' .' ) != std::string_view::npos) {
70
- // Build metadata exists.
71
- auto build_iterator = input_copy.find (' .' );
72
- version.build = input_copy.substr (0 , build_iterator);
73
+ if (is_pre_release) {
74
+ dot_iterator = input_copy.find (' +' );
75
+ auto prerelease = (dot_iterator == std::string_view::npos)
76
+ ? input_copy
77
+ : input_copy.substr (0 , dot_iterator);
78
+ if (prerelease.empty ()) {
79
+ return std::unexpected (ParseError::INVALID_INPUT);
80
+ }
81
+ version.pre_release = prerelease;
82
+ if (dot_iterator == std::string_view::npos) {
83
+ return version;
73
84
}
85
+ input_copy = input_copy.substr (dot_iterator + 1 );
74
86
}
75
-
87
+ if (input_copy.empty ()) {
88
+ return std::unexpected (ParseError::INVALID_INPUT);
89
+ }
90
+ version.build = input_copy;
76
91
return version;
77
92
}
78
93
} // namespace version_weaver
0 commit comments