Crate nextver

source ·
Expand description

§nextver

A library for parsing and incrementing arbitrarily-formatted versions.

Instead of conforming to a specific versioning scheme, this library allows you to define your own version format, parse version strings against it, and increment versions according to semantic and/or calendar rules.

Also comes with a CLI.

§Examples

Below, the text in < and > brackets is a specifier. See what they mean here.

Quickly get a next version:

use nextver::prelude::*;

let next = Sem::next_version_string(
  "<MAJOR>.<MINOR>.<PATCH>",  // format string
  "1.2.3",                    // current version string
  SemLevel::Minor             // the specifier to increment
)?;
assert_eq!(next, "1.3.0");
use nextver::prelude::*;

let date = Date::utc_now();  // assume today is 2024-02-23

let next = CalSem::next_version_string(
  "<YYYY>.<0M>-<PATCH>",  // format string
  "2023.12-42",           // current version string
  date,                   // the date to update to
  CalSemLevel::Patch      // the specifier to increment if no calendar update
)?;
assert_eq!(next, "2024.02-0");

Or, break down the steps for reusability and comparisons:

use nextver::prelude::*;

let date = Date::utc_now();  // assume today is 2024-02-23

let format = CalSem::new_format("<YYYY>.<MM>.<PATCH>")?;
let cur = format.new_version("2023.12.42")?;
let next = cur.next(date, CalSemLevel::Patch)?;
assert_eq!(next.to_string(), "2024.2.0");
// the next version will be compare as greater than the current
assert!(next > cur);

§API Overview

nextver is built around three main concepts: Schemes, formats, and versions.

  • Schemes dictate the kinds of values allowed in versions and the rules for incrementing them. (See the table below.) They are modeled by the Scheme trait and implemented by the the following structs:

    • Sem: A semantic versioning scheme. It is similar to SemVer.
    • CalSem: A calendar-semantic versioning scheme. It is similar to CalVer, but with an explicitly-required semantic part(s).
    • Cal: A calendar versioning scheme. Its like CalSem but without semantic specifiers. (This scheme is less useful in practice because there is no way to increment a version twice within the same period of its least significant specifier.)
  • Formats define the structure of a version string. They are modeled by the Format struct. They contains a sequence of specifier and literal text tokens. For example, <MAJOR>.<MINOR>.<PATCH> is a format string that can be turned into a Format object.

  • Versions are like Formats, but with actual values instead of specifiers. They represent a a point in a project’s development. These are modeled by the Version struct. They can be incremented to new versions and compared amongst each other.

§Format String Syntax

Use any sequence of specifiers (listed below) and literal text in a format string. Specifiers are bracketed with < and >. Literal text is anything else (also see escaping).

§Table

In the “Example” column below, we reference a major of 1, minor of 2, patch of 3 and a date of 2001-02-03 (which is in the 4th week).

SpecifierExampleSemCalSemCalParse WidthMin. Format WidthDescription
<MAJOR>1>=1-The major part of a version
<MINOR>2>=1-The minor part of a version
<PATCH>3>=1-The patch part of a version
<YYYY>2001>=1-Full year, years less than 1 BCE are unsupported (0 refers to 1 BCE)
<YY>1>=1-Year minus 2000. For now, has same effect as year % 100, but the year 2100 will be 100, and so on
<0Y>01>=22Same as YY but zero-padded
<MM>11 or 2-Month of year (112)
<0M>0122Same as MM but zero-padded
<WW>41 or 2-Week of the year (053), week 1 starts with the first Sunday in that year.
<0W>0422Same as WW but zero-padded
<DD>31 or 2-Day of the month (131)
<0D>0322Same as DD but zero-padded

Specifiers are case-sensitive. For example, <major> or <yYyY> are not a valid specifiers.

§Parse Width

The parse width comes into play when reading an existing version string. It is the number of characters a specifier can consume. Some specifiers are flexible in this regard, while others are not. For example, <YYYY> can consume 1 to an infinite number of characters, while <0M> can only consume 2 characters.

When the parse width is variable, the specifier is currently implemented to consume as few characters as possible (non-greedy). Therefore, exercise caution when using adjacent specifiers that have this quality. For an unsurprising parse, use a literal separator between them.

use nextver::prelude::*;

// Let's say I have a version values of major=111, minor=222, patch=333
let (major, minor, patch) = (111, 222, 333);

// And, my format string contains no separators between the specifiers
let format_str = "<MAJOR><MINOR><PATCH>";
let version_str = format!("{}{}{}", major, minor, patch);

// There is no clear way to parse this because the starts and ends of specifiers are ambiguous.
// So, nextver is going to interpret: major=1, minor=1, patch=1222333, despite our intentions
let next_str = Sem::next_version_string(format_str, &version_str, SemLevel::Minor)?;

// thus, the next version is: major=1, minor=2, patch=0
assert_eq!("120", next_str);

§Minimum Format Width

The format width is the minimum number of characters the specifier value will be formatted to with zero-padding. Values with fewer characters than this number will be zero-padded to meet this width, and values with more characters will be left as-is. (In the table above, a - value means no zero padding applied.)

Take, for example, the <0Y> specifier that has a format width of 2. Given a year, it may be formatted as follows:

  • 200101, zero-padded to meet the format width
  • 201010, as-is formatting
  • 2100100, as-is formatting

§Escaping Brackets

If you want to use a literal < in your format, escape it as <<.

> must not be escaped.

use nextver::prelude::*;

// double `<<` in format string (and single closing `>` because it must not be escaped)
let format_str = "<MAJOR>-<<some literal text>";
// single `<` in version string
let version_str = "1-<some literal text>";
let format = Sem::new_format(format_str)?;
let version = format.new_version(version_str)?;

assert_eq!(&version.to_string(), version_str);

§Prelude

nextver provides a prelude module for convenience. It contains everything needed to interact with the library.

Use it with:

use nextver::prelude::*;

§CLI

This crate provides a CLI that can be used to do some API functions straight from the command line.

§Installation

cargo install nextver

§Usage

nextver --help

Modules§

  • A convenience module appropriate for glob imports (use nextver::prelude::*;).

Structs§

  • Scheme for formats that have only calendar specifiers, such as <YYYY>.<MM>.<DD>.
  • Scheme for formats that have both calendar and semantic specifiers, such as <YYYY>.<MM>.<PATCH>.
  • Ways to specify a date.
  • A Format describes the structure of a version, comprised of specifiers and literal text.
  • Scheme for formats that have only semantic specifiers, such as <MAJOR>.<MINOR>.<PATCH>.
  • A Version object represents a specific point in a project’s development, comprised of values and literal text. It’s structure is defined by a Format. Versions can be displayed (to_string()), incremented (next()), and compared (partial_cmp()).

Enums§

Traits§

  • A trait for versioning schemes, which dictate the kinds of specifiers/values allowed in formats/versions and the rules for incrementing them.