Skip to content

ddn.util.semver

The ddn.util.semver module provides a full-featured Semantic Versioning (SemVer) implementation according to the semver.org specification. It includes parsing, comparison, stringification, and manipulation utilities.

Overview

Semantic Versioning is a versioning scheme that conveys meaning about the underlying changes in a release. A semantic version consists of three numeric components (MAJOR.MINOR.PATCH) with optional pre-release and build metadata identifiers.

This module provides the SemVer struct for representing and working with semantic versions in D applications.

Key Features

  • Full SemVer 2.0.0 Compliance: Implements the complete semver.org specification
  • Version Parsing: Parse version strings into structured SemVer objects
  • Version Comparison: Compare versions according to semver precedence rules
  • Pre-release Support: Handle pre-release identifiers like alpha, beta, rc.1
  • Build Metadata: Support for build metadata identifiers (ignored in comparisons)
  • String Conversion: Convert SemVer objects back to canonical string format
  • Sorting: Sort collections of versions using built-in comparison operators

Basic Usage

import ddn.util.semver;

void main() {
    // Parse a version string
    auto v = SemVer.parse("1.2.3-alpha.1+build.5");

    assert(v.major == 1);
    assert(v.minor == 2);
    assert(v.patch == 3);
    assert(v.prerelease == ["alpha", "1"]);
    assert(v.build == ["build", "5"]);

    // Convert back to string
    assert(v.toString() == "1.2.3-alpha.1+build.5");
}

Creating SemVer Objects

You can create SemVer objects either by parsing a string or by using the constructor:

import ddn.util.semver;

// Parse from string
auto v1 = SemVer.parse("2.0.0");

// Create directly with constructor
auto v2 = SemVer(2, 0, 0);  // 2.0.0
auto v3 = SemVer(1, 0, 0, ["beta"]);  // 1.0.0-beta
auto v4 = SemVer(1, 0, 0, ["rc", "1"], ["build", "123"]);  // 1.0.0-rc.1+build.123

Version Comparison

Versions are compared according to semver precedence rules:

  1. Major, minor, and patch versions are compared numerically
  2. Pre-release versions have lower precedence than normal versions
  3. Pre-release identifiers are compared left-to-right
  4. Build metadata is ignored for precedence
import ddn.util.semver;

auto v1 = SemVer.parse("1.0.0");
auto v2 = SemVer.parse("1.0.0-alpha");
auto v3 = SemVer.parse("1.0.0-alpha.1");
auto v4 = SemVer.parse("1.0.0-beta");
auto v5 = SemVer.parse("2.0.0");

// Pre-release < release
assert(v2 < v1);

// Numeric comparison of pre-release identifiers
assert(v2 < v3);

// Alphabetic comparison: alpha < beta
assert(v3 < v4);

// Major version comparison
assert(v1 < v5);

// Using compare() method
assert(v1.compare(v5) == -1);  // v1 < v5
assert(v1.compare(v1) == 0);   // equal
assert(v5.compare(v1) == 1);   // v5 > v1

Sorting Versions

The SemVer struct implements comparison operators, making it easy to sort collections:

import ddn.util.semver;
import std.algorithm : sort;
import std.array : array;

string[] versionStrings = [
    "2.0.0",
    "1.0.0-alpha",
    "1.0.0",
    "1.0.0-beta",
    "0.1.0",
    "2.0.0-rc.1"
];

// Parse and sort
auto versions = versionStrings
    .map!(s => SemVer.parse(s))
    .array;

versions.sort();

// Result order:
// 0.1.0
// 1.0.0-alpha
// 1.0.0-beta
// 1.0.0
// 2.0.0-rc.1
// 2.0.0

Checking Version Properties

import ddn.util.semver;

auto v1 = SemVer.parse("1.0.0-alpha");
auto v2 = SemVer.parse("1.0.0+build.123");
auto v3 = SemVer.parse("1.0.0");

// Check if pre-release
assert(v1.isPrerelease());
assert(!v3.isPrerelease());

// Check if has build metadata
assert(v2.hasBuild());
assert(!v3.hasBuild());

Error Handling

Invalid version strings throw a SemVerParseException:

import ddn.util.semver;

try {
    auto v = SemVer.parse("1.2");  // Invalid: missing patch version
} catch (SemVerParseException e) {
    // Handle invalid version string
    writeln("Invalid version: ", e.msg);
}

Version String Format

A valid semantic version string follows this format:

MAJOR.MINOR.PATCH[-PRERELEASE][+BUILD]

Where:

  • MAJOR, MINOR, PATCH: Non-negative integers without leading zeros
  • PRERELEASE: Dot-separated identifiers (alphanumeric and hyphens)
  • BUILD: Dot-separated identifiers (alphanumeric and hyphens)

Examples of valid versions:

  • 1.0.0
  • 1.0.0-alpha
  • 1.0.0-alpha.1
  • 1.0.0-0.3.7
  • 1.0.0+20130313144700
  • 1.0.0-beta+exp.sha.5114f85

When to Use

Use this module when you need to:

  • Parse and validate semantic version strings
  • Compare software versions for compatibility checks
  • Sort releases or dependencies by version
  • Implement version constraints or ranges
  • Display version information in a standardized format