CODE-0002 · claude-opus-4-8 (xhigh)
import re

# Semantic Versioning 2.0.0 grammar, compiled once.
#
# A numeric identifier in a prerelease is one of:
#   - "0"
#   - a non-zero digit followed by zero or more digits
# (i.e. a non-negative integer with no leading zeros).
#
# An alphanumeric identifier in a prerelease is any [0-9A-Za-z-] string that
# contains at least one non-digit (a letter or a hyphen). If an identifier is
# all digits it is treated as numeric and must obey the no-leading-zero rule.
#
# Build metadata identifiers are any non-empty [0-9A-Za-z-] string with no
# leading-zero restriction.

_NUM = r"0|[1-9]\d*"  # non-negative integer, no leading zeros

_SEMVER_RE = re.compile(
    r"^"
    r"(?P<major>0|[1-9]\d*)"
    r"\.(?P<minor>0|[1-9]\d*)"
    r"\.(?P<patch>0|[1-9]\d*)"
    r"(?:-(?P<prerelease>"
    r"(?:0|[1-9]\d*|\d*[A-Za-z-][0-9A-Za-z-]*)"
    r"(?:\.(?:0|[1-9]\d*|\d*[A-Za-z-][0-9A-Za-z-]*))*"
    r"))?"
    r"(?:\+(?P<build>"
    r"[0-9A-Za-z-]+"
    r"(?:\.[0-9A-Za-z-]+)*"
    r"))?"
    r"$"
)


def parse_semver(s):
    """Parse a Semantic Versioning 2.0.0 string.

    Returns a dict with keys "major", "minor", "patch" (ints), "prerelease"
    (str or None) and "build" (str or None) on success, or None if ``s`` is
    not a valid SemVer version (including when ``s`` is not a string).
    """
    if not isinstance(s, str):
        return None

    match = _SEMVER_RE.match(s)
    if match is None:
        return None

    return {
        "major": int(match.group("major")),
        "minor": int(match.group("minor")),
        "patch": int(match.group("patch")),
        "prerelease": match.group("prerelease"),
        "build": match.group("build"),
    }