diff --git a/include/version_weaver.h b/include/version_weaver.h index f6cce60..b9e9a1f 100644 --- a/include/version_weaver.h +++ b/include/version_weaver.h @@ -81,6 +81,7 @@ enum parse_error { INVALID_MAJOR, INVALID_MINOR, INVALID_PATCH, + INVALID_PRERELEASE, INVALID_RELEASE_TYPE, }; @@ -95,12 +96,11 @@ enum release_type { MAJOR, MINOR, PATCH, - // TODO: also support - // - PRE_MAJOR - // - PRE_MINOR - // - PRE_PATCH - // - PRE_RELEASE - // - RELEASE + PRE_MAJOR, + PRE_MINOR, + PRE_PATCH, + RELEASE, + PRE_RELEASE, }; // Increment the version according to the provided release type. diff --git a/src/version_weaver.cpp b/src/version_weaver.cpp index 661de80..64c3c70 100644 --- a/src/version_weaver.cpp +++ b/src/version_weaver.cpp @@ -36,8 +36,11 @@ std::string minimum(std::string_view range) { return ""; } std::expected inc(version input, release_type release_type) { + version_weaver::version result; + std::string incremented; switch (release_type) { - case MAJOR: { + case MAJOR: + case PRE_MAJOR: { int major_int; auto [ptr, ec] = std::from_chars(input.major.data(), @@ -46,11 +49,12 @@ std::expected inc(version input, return std::unexpected(parse_error::INVALID_MAJOR); } auto incremented_major_int = major_int + 1; - auto major = std::to_string(incremented_major_int); - auto new_version = version_weaver::version{major, "0", "0"}; - return new_version; + incremented = std::move(std::to_string(incremented_major_int)); + result = version_weaver::version{incremented, "0", "0"}; + break; } - case MINOR: { + case MINOR: + case PRE_MINOR: { int minor_int; auto [ptr, ec] = std::from_chars(input.minor.data(), @@ -59,13 +63,34 @@ std::expected inc(version input, return std::unexpected(parse_error::INVALID_MINOR); } auto incremented_minor_int = minor_int + 1; - return version_weaver::version{ - input.major, std::to_string(incremented_minor_int), "0"}; + incremented = std::move(std::to_string(incremented_minor_int)); + result = version_weaver::version{input.major, incremented, "0"}; + break; } - case PATCH: { - if (input.pre_release) { + case PATCH: + case PRE_PATCH: + case PRE_RELEASE: { + if (input.pre_release.has_value() && release_type == PATCH) { return version_weaver::version{input.major, input.minor, input.patch}; } + if (release_type == PRE_RELEASE && input.pre_release.has_value()) { + // TODO: support non-int pre_releases as well + // (see: + // https://github.com/npm/node-semver/blob/d17aebf8/test/fixtures/increments.js#L22-L36) + auto pre_release_value = input.pre_release.value(); + int prerelease_int; + auto [ptr, ec] = + std::from_chars(pre_release_value.data(), + pre_release_value.data() + pre_release_value.size(), + prerelease_int); + if (ec != std::errc()) { + return std::unexpected(parse_error::INVALID_PRERELEASE); + } + auto incremented_prerelease_int = prerelease_int + 1; + incremented = std::move(std::to_string(incremented_prerelease_int)); + return version_weaver::version{input.major, input.minor, input.patch, + incremented}; + } int patch_int; auto [ptr, ec] = std::from_chars(input.patch.data(), @@ -74,12 +99,26 @@ std::expected inc(version input, return std::unexpected(parse_error::INVALID_PATCH); } auto incremented_patch_int = patch_int + 1; - return version_weaver::version{input.major, input.minor, - std::to_string(incremented_patch_int)}; + incremented = std::move(std::to_string(incremented_patch_int)); + result = version_weaver::version{input.major, input.minor, incremented}; + break; } + case RELEASE: { + if (!input.pre_release.has_value()) { + return std::unexpected(parse_error::INVALID_INPUT); + } + return version_weaver::version{input.major, input.minor, input.patch}; + }; default: return std::unexpected(parse_error::INVALID_RELEASE_TYPE); } + + if (release_type == PRE_MAJOR || release_type == PRE_MINOR || + release_type == PRE_PATCH || release_type == PRE_RELEASE) { + result.pre_release = "0"; + } + + return result; } constexpr inline void trim_whitespace(std::string_view* input) noexcept { diff --git a/tests/basictests.cpp b/tests/basictests.cpp index 9d7a9f6..e1aea0e 100644 --- a/tests/basictests.cpp +++ b/tests/basictests.cpp @@ -229,6 +229,39 @@ std::vector inc_values = { {version_weaver::version{"1", "2", "3", "alpha.0.beta"}, "1.2.3-alpha.0.beta", version_weaver::release_type::PATCH, "1.2.3", version_weaver::version{"1", "2", "3"}}, + {version_weaver::version{"1", "2", "0"}, "1.2.0", + version_weaver::release_type::PRE_MAJOR, "2.0.0-0", + version_weaver::version{"2", "0", "0", "0"}}, + {version_weaver::version{"1", "2", "0"}, "1.2.0", + version_weaver::release_type::PRE_MINOR, "1.3.0-0", + version_weaver::version{"1", "3", "0", "0"}}, + {version_weaver::version{"1", "2", "3", "1"}, "1.2.3-1", + version_weaver::release_type::PRE_MINOR, "1.3.0-0", + version_weaver::version{"1", "3", "0", "0"}}, + {version_weaver::version{"1", "2", "0"}, "1.2.0", + version_weaver::release_type::PRE_PATCH, "1.2.1-0", + version_weaver::version{"1", "2", "1", "0"}}, + {version_weaver::version{"1", "2", "0", "1"}, "1.2.0-1", + version_weaver::release_type::PRE_PATCH, "1.2.1-0", + version_weaver::version{"1", "2", "1", "0"}}, + {version_weaver::version{"1", "0", "0", "1"}, "1.0.0-1", + version_weaver::release_type::RELEASE, "1.0.0", + version_weaver::version{"1", "0", "0"}}, + {version_weaver::version{"1", "2", "0", "1"}, "1.2.0-1", + version_weaver::release_type::RELEASE, "1.2.0", + version_weaver::version{"1", "2", "0"}}, + {version_weaver::version{"1", "2", "3", "1"}, "1.2.3-1", + version_weaver::release_type::RELEASE, "1.2.3", + version_weaver::version{"1", "2", "3"}}, + {version_weaver::version{"1", "2", "3"}, "1.2.3", + version_weaver::release_type::RELEASE, "1.2.3", + std::unexpected(version_weaver::parse_error::INVALID_INPUT)}, + {version_weaver::version{"1", "2", "4"}, "1.2.4", + version_weaver::release_type::PRE_RELEASE, "1.2.5-0", + version_weaver::version{"1", "2", "5", "0"}}, + {version_weaver::version{"1", "2", "3", "0"}, "1.2.3-0", + version_weaver::release_type::PRE_RELEASE, "1.2.3-1", + version_weaver::version{"1", "2", "3", "1"}}, }; TEST(basictests, inc) {