Skip to content

Commit 5b57c76

Browse files
committed
Clarify node-semver vs. semver references
node-semver is a range notation, while semver is a version string syntax. Signed-off-by: Philippe Ombredanne <pombredanne@nexb.com>
1 parent 2522a26 commit 5b57c76

1 file changed

Lines changed: 56 additions & 39 deletions

File tree

VERSION-RANGE-SPEC.rst

Lines changed: 56 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -56,15 +56,19 @@ vulnerability databases like `VulnerableCode
5656
To better understand the problem, here are some of the notations and conventions
5757
in use:
5858

59-
- Rubygems strongly suggest using semver but does not enforce it
59+
- ``semver`` https://semver.org/ is a popular specification to structure version
60+
strings, but does not provide a way to express version ranges.
61+
62+
- Rubygems strongly suggest using ``semver`` for version but does not enforce it.
63+
It use its own notation for version ranges.
6064
https://guides.rubygems.org/patterns/#semantic-versioning
6165

6266
- node-semver ranges are used in npms https://github.com/npm/node-semver#ranges
63-
with semantics specific to semver and node and npm.
67+
with their own range semantics that are specific to ``semver`` and npm.
6468

65-
- Dart pub versioning scheme is similar to node-semver and the documentation at
66-
https://dart.dev/tools/pub/versioning provides a comprehensive coverage of the
67-
topic of versioning. But version resolution is using its own algorithm.
69+
- Dart pub versioning scheme is similar to ``node-semver`` and the documentation
70+
at https://dart.dev/tools/pub/versioning provides a comprehensive coverage of
71+
the topic of versioning. Version resolution is using its own algorithm.
6872

6973
- Python uses its own version ranges notation https://www.python.org/dev/peps/pep-0440/
7074

@@ -74,21 +78,24 @@ in use:
7478
- RPM distros use their own range notation
7579
https://rpm-software-management.github.io/rpm/manual/dependencies.html
7680

77-
- Perl CPAN define its own version range notation similar to this specification:
81+
- Perl CPAN define its own version range notation similar to this specification
7882
https://metacpan.org/pod/CPAN::Meta::Spec#Version-Ranges
7983

8084
- Apache Maven and NuGet use math intervals notation
8185
https://en.wikipedia.org/wiki/Interval_(mathematics)
86+
8287
- Apache Maven http://maven.apache.org/enforcer/enforcer-rules/versionRanges.html
8388
- NuGet https://docs.microsoft.com/en-us/nuget/concepts/package-versioning#version-ranges
8489

90+
- gradle uses Apache Maven notation with extensions
91+
https://docs.gradle.org/current/userguide/single_versions.html
92+
8593
- Gentoo and Alpine Linux use comparison operators similar to this specification:
8694
- Gentoo https://wiki.gentoo.org/wiki/Version_specifier
8795
- Alpine linux https://gitlab.alpinelinux.org/alpine/apk-tools/-/blob/master/src/version.c
8896

89-
- Arch Linux https://wiki.archlinux.org/title/PKGBUILD#Dependencies use a
90-
simplified notation for its PKGBUILD depends array with comparison operators
91-
similar to this specification.
97+
- Arch Linux https://wiki.archlinux.org/title/PKGBUILD#Dependencies use its
98+
own simplified notation for its PKGBUILD depends array.
9299

93100
- Go modules https://golang.org/ref/mod#versions use semver versions with
94101
specific version resolution algorithms.
@@ -103,16 +110,16 @@ in use:
103110
a daily feed.
104111

105112
Note that there is a closely related problem as the way two versions are compared
106-
as equal, lesser or greater is often complex.
113+
as equal, lesser or greater is often complex:
107114

108-
Each package ecosystem may have evolved its own peculiar version comparison
109-
procedure.
115+
- Each package ecosystem may have evolved its own peculiar version comparison
116+
procedure.
110117

111-
For instance, semver is a prominent specification in this domain but this is
112-
just one of the many ways to structure a version string.
118+
- For instance, semver is a prominent specification in this domain but this is
119+
just one of the many ways to structure a version string.
113120

114-
Debian, RPM, PyPI, Rubygems, and Composer have their own subtly different
115-
approach on how to determine which version is greater or lesser.
121+
- Debian, RPM, PyPI, Rubygems, and Composer have their own subtly different
122+
approach on how to determine which version is greater or lesser.
116123

117124

118125
Solution
@@ -121,11 +128,11 @@ Solution
121128
A solution to the many version range syntaxes is to design a new notation to
122129
unify them all with:
123130

124-
- a mostly universal and minimalist notation to express the version range
125-
notations from many different package types and ecosystems.
131+
- a mostly universal and minimalist, compact notation to express version ranges
132+
from many different package types and ecosystems.
126133

127134
- the package type-specific definitions to normalize existing range expressions
128-
to this common notation .
135+
to this common notation.
129136

130137
- the designation of which algorithm or procedure to use when comparing two
131138
versions such that it is possible to resolve if a version is within or
@@ -145,9 +152,9 @@ URI-scheme with this syntax::
145152

146153
For example to define a set of versions that contains either version ``1.2.3``,
147154
or any versions greater than or equal to ``2.0.0`` but less than ``5.0.0`` using
148-
the `semver` versioning scheme, the version range specifier will be::
155+
the ``node-semver`` versioning scheme, the version range specifier will be::
149156

150-
vers:semver/1.2.3,>=2.0.0&<5.0.0
157+
vers:node-semver/1.2.3,>=2.0.0&<5.0.0
151158

152159
Each ``<version-constraint>`` in the comma-separated list is either a simple
153160
constraint such as::
@@ -173,7 +180,7 @@ for a future formal registration for this URI-scheme at the IANA registry.
173180
``<versioning-scheme>``
174181
------------------------
175182

176-
The ``<versioning-scheme>`` (such as ``semver``,
183+
The ``<versioning-scheme>`` (such as ``node-semver``,
177184
``debian``, etc.) determines:
178185

179186
- the specific notation and conventions used for a version string encoded in
@@ -368,7 +375,7 @@ Notes and caveats
368375
~~~~~~~~~~~~~~~~~~~
369376

370377
- Comparing versions from two different versioning schemes is unspecified. Even
371-
though there may be some similarities between the `semver` version of an npm
378+
though there may be some similarities between the ``semver`` version of an npm
372379
and the `debian` version of its Debian packaging, these similarities are
373380
specific to each versioning scheme. Tools may report an error in these
374381
cases.
@@ -394,12 +401,15 @@ scheme and package type.
394401
The version comparison routine of rmpvercmp is also used by archlinux Pacman.
395402

396403
- ``rubygems``: Rubygems https://guides.rubygems.org/patterns/#semantic-versioning
397-
which is almost but not exactly semver.
404+
which is almost but not exactly ``node-semver``.
398405

399-
- ``semver``: node-semver as used for npm https://github.com/npm/node-semver#ranges
400-
It is also used by Rust: https://doc.rust-lang.org/cargo/reference/specifying-dependencies.html
401-
and several other package types. `composer` may need its own scheme as this is
402-
not strictly semver.
406+
- ``node-semver``: node-semver is based on semver and is used for npm
407+
https://github.com/npm/node-semver#ranges
408+
A similar scheme is used by Rust https://doc.rust-lang.org/cargo/reference/specifying-dependencies.html
409+
and several other package types that use ``semver``. But most of these related
410+
schemes are not strictly the same as what is implemented in ``node-semver``.
411+
For instance PHP ``composer`` may need its own scheme as this is not strictly
412+
``node-semver``.
403413

404414
- ``python``: Python https://www.python.org/dev/peps/pep-0440/
405415

@@ -417,12 +427,13 @@ scheme and package type.
417427
- ``gentoo``: Gentoo https://wiki.gentoo.org/wiki/Version_specifier
418428

419429
- ``alpine``: Alpine linux https://gitlab.alpinelinux.org/alpine/apk-tools/-/blob/master/src/version.c
420-
(which might be using Gentoo conventions)
430+
which is using Gentoo-like conventions.
421431

422432
- ``generic``: a generic version comparison algorithm (which is TBD, likely a
423433
split on punctuation and dealing with digit vs. strings comparisons, like is
424434
done in libversion)
425435

436+
TODO: add Rust, composer and archlinux
426437

427438

428439
Implementations
@@ -493,14 +504,16 @@ specified in ``vers`` and found in other notations.
493504
Why not use node-semver ranges?
494505
###############################
495506

496-
https://github.com/npm/node-semver#ranges
507+
- https://github.com/npm/node-semver#ranges
497508

498-
The node semver is very similar to this spec (this is also an OR of ANDs) but it
499-
has a few practical issues:
509+
The node-semver spec is similar to this spec but is an AND of ORs with a few
510+
issues:
500511

501-
- The space means "AND" and significant whitespace in a single string makes
502-
normalization more complicated and may be a source of confusion or errors. The
503-
explicit ampersand used as "AND" operator specified here improves clarity.
512+
- The space means "AND", therefore whitespaces are significant. Having
513+
significant whitespaces in string makes normalization more complicated and may
514+
be a source of confusion if you remove the spaces from the string. Using an
515+
ampersand as an "AND" operator in ``vers`` makes this explicit and avoids any
516+
ambiguity.
504517

505518
- There is no negation "!=" operator meaning that some version constraints are
506519
difficult to express and require combining < and > comparators. For instance
@@ -510,14 +523,18 @@ has a few practical issues:
510523
- The advanced range syntax has grown to be rather complex using hyphen, stars,
511524
carets and tilde constructs are all tied to the JavaScript and npm ways of
512525
handling versions in their specific ecosystem and furthermore are bound to the
513-
semver semantics. These are not readily reusable elsewhere. And these multiple
514-
comparators and modifiers make the grammar and parsing more complex.
526+
semver semantics and the npm implementation. These are not readily reusable
527+
elsewhere. And these multiple comparators and modifiers make the grammar and
528+
parsing more complex.
529+
530+
Notations that are directly derived from node-semver as used in Rust and PHP
531+
Composer have the same issues.
515532

516533

517534
Why not use Python pep-0440 ranges?
518535
#####################################
519536

520-
https://www.python.org/dev/peps/pep-0440/#version-specifiers
537+
- https://www.python.org/dev/peps/pep-0440/#version-specifiers
521538

522539
The Python pep-0440 "Version Identification and Dependency Specification"
523540
provides a comprehensive specification for Python package versioning and a
@@ -542,7 +559,7 @@ only in the Python ecosystem.
542559
Why not use Rubygems requirements notation?
543560
##############################################################
544561

545-
https://guides.rubygems.org/patterns/#declaring-dependencies
562+
- https://guides.rubygems.org/patterns/#declaring-dependencies
546563

547564
The rubygems specification suggests but does not enforce using semver. It is
548565
similar to this spec's operators with the addition of the "~>" aka. pessimistic

0 commit comments

Comments
 (0)