11#include " version_weaver.h"
2+ #include < algorithm>
3+ #include < cctype>
24namespace 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)); }
66
77bool gt (std::string_view version1, std::string_view version2) { return true ; }
88bool lt (std::string_view version1, std::string_view version2) { return true ; }
@@ -13,66 +13,81 @@ std::string coerce(std::string_view version) { return ""; }
1313std::string minimum (std::string_view range) { return " " ; }
1414std::string clean (std::string_view range) { return " " ; }
1515
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) {
1727 if (input.size () > MAX_VERSION_LENGTH) {
18- return ParseError::VERSION_LARGER_THAN_MAX_LENGTH;
28+ return std::unexpected ( ParseError::VERSION_LARGER_THAN_MAX_LENGTH) ;
1929 }
2030
21- std::string_view input_copy = input;
22- // TODO: Trim leading and trailing whitespace
31+ std::string_view input_copy = trim_whitespace (input);
2332
2433 auto dot_iterator = input_copy.find (' .' );
2534 if (dot_iterator == std::string_view::npos) {
2635 // Only major exists. No minor or patch.
27- return ParseError::INVALID_INPUT;
36+ return std::unexpected ( ParseError::INVALID_INPUT) ;
2837 }
2938 Version version;
3039 auto major = input_copy.substr (0 , dot_iterator);
3140
3241 if (major.empty () || major.front () == ' 0' ) {
3342 // Version components can not have leading zeroes.
34- return ParseError::INVALID_INPUT;
43+ return std::unexpected ( ParseError::INVALID_INPUT) ;
3544 }
3645 version.major = major;
3746 input_copy = input_copy.substr (dot_iterator + 1 );
3847 dot_iterator = input_copy.find (' .' );
3948 if (dot_iterator == std::string_view::npos) {
4049 // Only major and minor exists. No patch.
41- return ParseError::INVALID_INPUT;
50+ return std::unexpected ( ParseError::INVALID_INPUT) ;
4251 }
4352
4453 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 ) ) {
4655 // Version components can not have leading zeroes.
47- return ParseError::INVALID_INPUT;
56+ return std::unexpected ( ParseError::INVALID_INPUT) ;
4857 }
4958 version.minor = minor;
5059 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);
6166 }
6267 version.patch = patch;
68+ if (dot_iterator == std::string_view::npos) {
69+ return version;
70+ }
71+ bool is_pre_release = input_copy[dot_iterator] == ' -' ;
6372 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;
7384 }
85+ input_copy = input_copy.substr (dot_iterator + 1 );
7486 }
75-
87+ if (input_copy.empty ()) {
88+ return std::unexpected (ParseError::INVALID_INPUT);
89+ }
90+ version.build = input_copy;
7691 return version;
7792}
7893} // namespace version_weaver
0 commit comments