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"),
}