Grammar

Build a library from the grammar.

Formal Backus–Naur forms for versions, ranges and comparators. Each is downloadable as a .bnf file, and mirrored by the reference semantic-versions parser. A regular expression is also available for quick validation.

Versions

A valid version is a version core with optional pre-release and build labels.

<valid semver> ::= <version core>
                 | <version core> "-" <pre-release>
                 | <version core> "+" <build>
                 | <version core> "-" <pre-release> "+" <build>

<version core> ::= <major> "." <minor> "." <patch>

<major> ::= <numeric identifier>
<minor> ::= <numeric identifier>
<patch> ::= <numeric identifier>

<pre-release> ::= <dot-separated pre-release identifiers>

<dot-separated pre-release identifiers> ::= <pre-release identifier>
                                          | <pre-release identifier> "." <dot-separated pre-release identifiers>

<build> ::= <dot-separated build identifiers>

<dot-separated build identifiers> ::= <build identifier>
                                    | <build identifier> "." <dot-separated build identifiers>

<pre-release identifier> ::= <alphanumeric identifier>
                           | <numeric identifier>

<build identifier> ::= <alphanumeric identifier>
                     | <digits>

<numeric identifier> ::= "0"
                       | <positive digit>
                       | <positive digit> <digits>

<positive digit> ::= "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9"

The full leaf definitions (identifier characters, letters, digits) are in the downloadable file.

References & context

A version rarely travels alone. A reference pairs a version (or a range) with the context it belongs to: the identity of a package, module, image, crate or service. The context is optional and, when present, is separated from the version by @. An ecosystem qualifies a context with a source (source:name), so the same grammar names artifacts anywhere: npm:react@18.2.0, pypi:flask@3.0.0, gem:rails@7.1.3, golang:golang.org/x/text@0.14.0. A context never contains whitespace and a version never contains @, so the split is unambiguous.

<reference>       ::= <valid semver>
                  | <context> "@" <valid semver>

<range reference> ::= <range set>
                  | <context> "@" <range set>

<context>         ::= <name>
                  | <source> ":" <name>

<source>          ::= <lowercase letter> ( <lowercase letter> | <digit> | "-" ) *

<name>            ::= <name path>
                  | "@" <name path>                ; scoped, e.g. @scope/pkg

<name path>       ::= <name segment> ( "/" <name segment> ) *

<name segment>    ::= <name character> +

<name character>  ::= <letter> | <digit> | "-" | "." | "_"

Context is identity, not precedence: it never changes how versions order. It scopes a range to a Contextual Set, so npm:react@^1.2.3 admits only versions of npm:react.

Ranges

A range-set is one or more comparator sets joined by ||. Hyphen, x-range, tilde, caret and approximate forms desugar to primitive comparators.

<range set>    ::= <range> ( <logical or> <range> ) *

<logical or>   ::= ( " " ) * "||" ( " " ) *

<range>        ::= <hyphen>
                 | <simple> ( " " <simple> ) *
                 | ""

<hyphen>       ::= <partial> " - " <partial>

<simple>       ::= <primitive>
                 | <partial>
                 | <tilde>
                 | <caret>

<primitive>    ::= <operator> <partial>

<operator>     ::= "<" | ">" | ">=" | "<=" | "="

<tilde>        ::= "~" [ ">" ] <partial>

<caret>        ::= "^" <partial>

<partial>      ::= <xr> [ "." <xr> [ "." <xr> <qualifier> ? ] ]

<xr>           ::= "x" | "X" | "*" | <numeric identifier>

<qualifier>    ::= ( "-" <pre-release> ) ? ( "+" <build> ) ?

Comparators

A comparator is an operator and a version; a comparator set is the intersection of whitespace-joined comparators.

<comparator set> ::= <comparator> ( <whitespace> <comparator> ) *

<comparator>     ::= <operator> <partial>
                   | <partial>

<operator>       ::= "<" | ">" | ">=" | "<=" | "="

<whitespace>     ::= ( " " ) +

<partial>        ::= <xr> [ "." <xr> [ "." <xr> <qualifier> ? ] ]

<xr>             ::= "x" | "X" | "*" | <numeric identifier>

<qualifier>      ::= ( "-" <pre-release> ) ? ( "+" <build> ) ?

Reference parser

The semantic-versions package implements this grammar. It exposes Version, Range, satisfies, compare, valid, validRange and the usual comparison helpers, and is the engine behind the range selector.

semantic-versions
import { Range, satisfies, validRange } from "semantic-versions"

validRange("~>1.2")            // ">=1.2.0 <1.3.0-0"
satisfies("1.4.0", "^1.2.3")  // true
new Range("1.2.7 || >=1.2.9 <2.0.0").test("1.4.6")  // true