Skip to content

Commit 2daa9c7

Browse files
authored
add validate function (#1)
* add validate function * apply fixes * add include variant
1 parent 507a530 commit 2daa9c7

File tree

3 files changed

+113
-1
lines changed

3 files changed

+113
-1
lines changed

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
build
2+
cmake-build-debug

include/version_weaver.h

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,60 @@
11
#ifndef VERSION_WEAVER_H
22
#define VERSION_WEAVER_H
3+
#include <optional>
34
#include <string_view>
45
#include <string>
6+
#include <variant>
57

68
namespace version_weaver {
9+
10+
// https://semver.org/#does-semver-have-a-size-limit-on-the-version-string
11+
static constexpr size_t MAX_VERSION_LENGTH = 256;
12+
713
bool validate(std::string_view version);
814
bool gt(std::string_view version1, std::string_view version2);
915
bool lt(std::string_view version1, std::string_view version2);
1016
bool satisfies(std::string_view version, std::string_view range);
1117
std::string coerce(std::string_view version);
1218
std::string minimum(std::string_view range);
1319
std::string clean(std::string_view range);
20+
21+
// A normal version number MUST take the form X.Y.Z where X, Y, and Z are
22+
// non-negative integers, and MUST NOT contain leading zeroes.
23+
// X is the major version, Y is the minor version, and Z is the patch version.
24+
// Each element MUST increase numerically.
25+
// For instance: 1.9.0 -> 1.10.0 -> 1.11.0.
26+
struct Version {
27+
28+
std::string_view major;
29+
std::string_view minor;
30+
std::string_view patch;
31+
32+
// A pre-release version MAY be denoted by appending a hyphen and a series
33+
// of dot separated identifiers immediately following the patch version.
34+
// - Identifiers MUST comprise only ASCII alphanumerics and hyphens [0-9A-Za-z-].
35+
// - Identifiers MUST NOT be empty.
36+
// - Numeric identifiers MUST NOT include leading zeroes.
37+
//
38+
// Examples: 1.0.0-alpha, 1.0.0-alpha.1, 1.0.0-0.3.7, 1.0.0-x.7.z.92, 1.0.0-x-y-z.--.
39+
std::optional<std::string_view> pre_release;
40+
41+
// Build metadata MAY be denoted by appending a plus sign and a series of dot
42+
// separated identifiers immediately following the patch or pre-release version.
43+
// - Identifiers MUST comprise only ASCII alphanumerics and hyphens [0-9A-Za-z-].
44+
// - Identifiers MUST NOT be empty.
45+
// Build metadata MUST be ignored when determining version precedence.
46+
// Thus two versions that differ only in the build metadata, have the same precedence.
47+
//
48+
// Examples: 1.0.0-alpha+001, 1.0.0+20130313144700, 1.0.0-beta+exp.sha.5114f85, 1.0.0+21AF26D3----117B344092BD.
49+
std::optional<std::string_view> build;
50+
};
51+
52+
enum ParseError {
53+
VERSION_LARGER_THAN_MAX_LENGTH,
54+
INVALID_INPUT,
55+
};
56+
57+
std::variant<Version, ParseError> parse(std::string_view version);
1458
}
1559

1660
#endif // VERSION_WEAVER_H

src/version_weaver.cpp

Lines changed: 67 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,76 @@
11
#include "version_weaver.h"
22
namespace version_weaver {
3-
bool validate(std::string_view version) { return true; }
3+
bool validate(std::string_view version) {
4+
return std::holds_alternative<Version>(parse(version));
5+
}
6+
47
bool gt(std::string_view version1, std::string_view version2) { return true; }
58
bool lt(std::string_view version1, std::string_view version2) { return true; }
69
bool satisfies(std::string_view version, std::string_view range) { return true; }
710
std::string coerce(std::string_view version) { return ""; }
811
std::string minimum(std::string_view range) { return ""; }
912
std::string clean(std::string_view range) { return ""; }
13+
14+
std::variant<Version, ParseError> parse(std::string_view input) {
15+
if (input.size() > MAX_VERSION_LENGTH) {
16+
return ParseError::VERSION_LARGER_THAN_MAX_LENGTH;
17+
}
18+
19+
std::string_view input_copy = input;
20+
// TODO: Trim leading and trailing whitespace
21+
22+
auto dot_iterator = input_copy.find('.');
23+
if (dot_iterator == std::string_view::npos) {
24+
// Only major exists. No minor or patch.
25+
return ParseError::INVALID_INPUT;
26+
}
27+
Version version;
28+
auto major = input_copy.substr(0, dot_iterator);
29+
30+
if (major.empty() || major.front() == '0') {
31+
// Version components can not have leading zeroes.
32+
return ParseError::INVALID_INPUT;
33+
}
34+
version.major = major;
35+
input_copy = input_copy.substr(dot_iterator + 1);
36+
dot_iterator = input_copy.find('.');
37+
if (dot_iterator == std::string_view::npos) {
38+
// Only major and minor exists. No patch.
39+
return ParseError::INVALID_INPUT;
40+
}
41+
42+
auto minor = input_copy.substr(0, dot_iterator);
43+
if (minor.empty() || minor.front() == '0') {
44+
// Version components can not have leading zeroes.
45+
return ParseError::INVALID_INPUT;
46+
}
47+
version.minor = minor;
48+
input_copy = input_copy.substr(dot_iterator + 1);
49+
dot_iterator = input_copy.find('.');
50+
if (dot_iterator == std::string_view::npos) {
51+
// Only major, minor and patch exists.
52+
return ParseError::INVALID_INPUT;
53+
}
54+
55+
auto patch = input_copy.substr(0, dot_iterator);
56+
if (patch.empty() || patch.front() == '0') {
57+
// Version components can not have leading zeroes.
58+
return ParseError::INVALID_INPUT;
59+
}
60+
version.patch = patch;
61+
input_copy = input_copy.substr(dot_iterator + 1);
62+
63+
auto pre_release_iterator = input_copy.find('-');
64+
if (pre_release_iterator != std::string_view::npos) {
65+
version.pre_release = input_copy.substr(0, pre_release_iterator);
66+
input_copy = input_copy.substr(pre_release_iterator + 1);
67+
if (input_copy.find('.') != std::string_view::npos) {
68+
// Build metadata exists.
69+
auto build_iterator = input_copy.find('.');
70+
version.build = input_copy.substr(0, build_iterator);
71+
}
72+
}
73+
74+
return version;
75+
}
1076
}

0 commit comments

Comments
 (0)