On this page
@std/semver
概览 Jump to heading
语义版本解析器。
直接改编自 semver。
import { format, greaterThan, lessThan, parse, parseRange } from "@std/semver";
import { assertEquals } from "@std/assert";
const semver = parse("1.2.3");
assertEquals(semver, {
major: 1,
minor: 2,
patch: 3,
prerelease: [],
build: [],
});
assertEquals(format(semver), "1.2.3");
const range = parseRange("1.x || >=2.5.0 || 5.0.0 - 7.2.3");
const s0 = parse("1.2.3");
const s1 = parse("9.8.7");
assertEquals(greaterThan(s0, s1), false);
assertEquals(lessThan(s0, s1), true);
版本
“版本”依据 v2.0.0 规范描述,详情见
https://semver.org。
前导的 "=" 或 "v" 字符会被剥离并忽略。
格式
语义版本可格式化为字符串,默认格式为 full。下图展示了各种格式选项。
full
┌───┴───┐
release │
┌───┴───┐ │
primary │ │
┌─┴─┐ │ │
1.2.3-pre.1+b.1
│ │ │ └─┬─┘ └┬┘
│ │ │ │ └── build
│ │ │ └─────── pre
│ │ └─────────── patch
│ └───────────── minor
└─────────────── major
版本范围
版本 Range 是一组 Comparator,用于指定满足该范围的版本。
Comparator 由一个 Operator 和一个
SemVer 组成。基本的 操作符 集合如下:
<小于<=小于或等于>大于>=大于或等于=等于。如果未指定操作符,则默认等于,因此该操作符是可选的,但可以包含。
例如,比较器 >=1.2.7 可以匹配版本 1.2.7、1.2.8、
2.5.3 和 1.3.9,但不匹配版本 1.2.6 或 1.1.0。
比较器可以通过空白字符连接形成一个 比较器集合,满足该集合的版本必须满足所有包含的比较器的交集。
版本范围由一个或多个通过 || 连接的比较器集合组成。只有满足至少一个
|| 分隔的比较器集合中每个比较器的版本,才匹配该范围。
例如,范围 >=1.2.7 <1.3.0 可以匹配版本 1.2.7、
1.2.8 和 1.2.99,但不匹配版本 1.2.6、1.3.0 或 1.1.0。
范围 1.2.7 || >=1.2.9 <2.0.0 可匹配版本 1.2.7、1.2.9 和 1.4.6,
但不匹配版本 1.2.8 或 2.0.0。
预发布标签
如果一个版本包含预发布标签(例如 1.2.3-alpha.3),则只有当同一个
[major, minor, patch] 元组至少有一个比较器也带有预发布标签时,该版本才可满足比较器集合。
例如,范围 >1.2.3-alpha.3 可匹配版本
1.2.3-alpha.7,但不会匹配 3.4.5-alpha.9,即使按照 SemVer 排序规则
3.4.5-alpha.9 技术上比 1.2.3-alpha.3 更大。该范围只接受位于 1.2.3 版本的预发布标签。
版本 3.4.5 会满足该范围,因为它没有预发布标记,且比 1.2.3-alpha.7 更高。
这种行为有两个原因。首先,预发布版本通常更新频繁,且可能包含因作者设计而尚未公开的重大变更,因此默认从范围匹配语义中排除。
其次,选择使用预发布版本的用户明确表示其意图使用特定的 alpha/beta/rc 版本。通过包含范围中的预发布标签,用户表示已知风险。然而,不应默认用户也已选择承担下一个预发布版本集的类似风险。
预发布标识符
increment 方法接受额外的 identifier 字符串参数,用作预发布标识符附加值:
import { increment, parse } from "@std/semver";
import { assertEquals } from "@std/assert";
assertEquals(
increment(parse("1.2.3"), "prerelease", { prerelease: "alpha" }),
parse("1.2.4-alpha.0"),
);
构建元数据
构建元数据是以 . 分隔的字母数字字符串。解析版本时,保持在 SemVer 实例的 build: string[] 字段中。
增量操作时,可通过额外参数设置 SemVer 实例的构建元数据。
高级范围语法
高级范围语法可确定性地转换为基本比较器。
高级范围可通过空白字符或 || 与基本比较器同样方式组合。
短横范围 X.Y.Z - A.B.C
指定包含区间。
1.2.3 - 2.3.4等同于>=1.2.3 <=2.3.4
如果起始版本为部分版本,则缺失部分均补零。
1.2 - 2.3.4等同于>=1.2.0 <=2.3.4
如果结束版本为部分版本,则接受所有以该部分元组开头的版本,但不接受比该元组更大的版本。
1.2.3 - 2.3等同于>=1.2.3 <2.4.01.2.3 - 2等同于>=1.2.3 <3.0.0
X 范围 1.2.x 1.X 1.2.* *
X、x 或 * 可用作 [major, minor, patch] 元组中的数字占位符。
*等同于>=0.0.0(任意版本满足)1.x等同于>=1.0.0 <2.0.0(匹配主版本)1.2.x等同于>=1.2.0 <1.3.0(匹配主版本和次版本)
部分版本范围视为 X 范围,因此特殊字符实际上是可选的。
""(空字符串)等价于*,即>=0.0.01等价于1.x.x,即>=1.0.0 <2.0.01.2等价于1.2.x,即>=1.2.0 <1.3.0
波浪符范围 ~1.2.3 ~1.2 ~1
如果比较器指定了次版本,则允许修订版本修改;否则允许次版本修改。
~1.2.3等同于>=1.2.3 <1.(2+1).0,即>=1.2.3 <1.3.0~1.2等同于>=1.2.0 <1.(2+1).0,即>=1.2.0 <1.3.0(同1.2.x)~1等同于>=1.0.0 <(1+1).0.0,即>=1.0.0 <2.0.0(同1.x)~0.2.3等同于>=0.2.3 <0.(2+1).0,即>=0.2.3 <0.3.0~0.2等同于>=0.2.0 <0.(2+1).0,即>=0.2.0 <0.3.0(同0.2.x)~0等同于>=0.0.0 <(0+1).0.0,即>=0.0.0 <1.0.0(同0.x)~1.2.3-beta.2等同于>=1.2.3-beta.2 <1.3.0。注意,1.2.3版本范围内的预发布版本只要大于或等于beta.2都会被允许,例如1.2.3-beta.4。但是1.2.4-beta.2不被允许,因为它属于不同的[major, minor, patch]元组的预发布版本。
插入符范围 ^1.2.3 ^0.2.5 ^0.0.4
允许不修改 [major, minor, patch] 元组中最左边非零元素的更改。换言之,对于版本 1.0.0 及以上,允许次版本和修订版本更新;对于版本 0.X >= 0.1.0,允许修订版本更新;而对版本 0.0.X 则不允许任何更新。
许多作者将 0.x 版本视为 x 是主要“破坏性变更”指标。
插入符范围适合作者在 0.2.4 到 0.3.0 之间可能引入破坏性变更的情况,这很常见。但它假定 0.2.4 到 0.2.5 之间不会有破坏性变更,只允许可认为是添加且非破坏的变更,符合公认实践。
^1.2.3等同于>=1.2.3 <2.0.0^0.2.3等同于>=0.2.3 <0.3.0^0.0.3等同于>=0.0.3 <0.0.4^1.2.3-beta.2等同于>=1.2.3-beta.2 <2.0.0。注意,1.2.3版本范围内的预发布版本只要大于或等于beta.2都会被允许,例如1.2.3-beta.4。但1.2.4-beta.2不被允许,因为它属于不同的[major, minor, patch]元组预发布版本。^0.0.3-beta等同于>=0.0.3-beta <0.0.4。该范围仅允许0.0.3版本的预发布,只要它们大于或等于beta,例如0.0.3-pr.2会被允许。
解析插入符范围时,缺失的 patch 值默认为 0,但即使主版本和次版本均为 0,该部分仍允许灵活变化。
^1.2.x等同于>=1.2.0 <2.0.0^0.0.x等同于>=0.0.0 <0.1.0^0.0等同于>=0.0.0 <0.1.0
缺失 minor 和 patch 值时,默认补零,但即使主版本为零,仍允许该部分灵活变化。
^1.x等同于>=1.0.0 <2.0.0^0.x等同于>=0.0.0 <1.0.0
范围语法
综上所述,为方便解析器作者,以下是范围的巴科斯-诺尔范式(BNF):
range-set ::= range ( logical-or range ) *
logical-or ::= ( " " ) * "||" ( " " ) *
range ::= hyphen | simple ( " " simple ) * | ""
hyphen ::= partial " - " partial
simple ::= primitive | partial | tilde | caret
primitive ::= ( "<" | ">" | ">=" | "<=" | "=" ) partial
partial ::= xr ( "." xr ( "." xr qualifier ? )? )?
xr ::= "x" | "X" | "*" | nr
nr ::= "0" | ["1"-"9"] ( ["0"-"9"] ) *
tilde ::= "~" partial
caret ::= "^" partial
qualifier ::= ( "-" pre )? ( "+" build )?
pre ::= parts
build ::= parts
parts ::= part ( "." part ) *
part ::= nr | [-0-9A-Za-z]+
注意,由于范围可能非连续,一个版本可能既不大于范围,也不小于范围,且不满足范围!例如,范围
1.2 <1.2.9 || >2.0.0 会在 1.2.9 到 2.0.0 之间有空隙,
版本 1.2.10 既不大于范围(因为 2.0.1 满足,且更大),也不小于范围(因为 1.2.8 满足,且更小),
同时也不满足该范围。
如果您想判断版本是否满足某个范围,请使用 satisfies 函数。
添加到您的项目 Jump to heading
deno add jsr:@std/semver
为什么使用 @std/semver? Jump to heading
正确比较、排序和检测版本范围—避免临时字符串比较。
示例 Jump to heading
import { parse, parseRange, satisfies } from "@std/semver";
const v = parse("1.2.3");
const r = parseRange("^1.2.0");
console.log(satisfies(v, r)); // true
小贴士 Jump to heading
- 使用版本范围(
^、~、x,短横线)表达兼容性窗口。 - 对预发布版本保持明确;范围匹配默认排除预发布版本,除非包括它们。