Skip to main content
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.71.2.82.5.31.3.9,但不匹配版本 1.2.61.1.0

比较器可以通过空白字符连接形成一个 比较器集合,满足该集合的版本必须满足所有包含的比较器的交集

版本范围由一个或多个通过 || 连接的比较器集合组成。只有满足至少一个 || 分隔的比较器集合中每个比较器的版本,才匹配该范围。

例如,范围 >=1.2.7 <1.3.0 可以匹配版本 1.2.71.2.81.2.99,但不匹配版本 1.2.61.3.01.1.0

范围 1.2.7 || >=1.2.9 <2.0.0 可匹配版本 1.2.71.2.91.4.6, 但不匹配版本 1.2.82.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.0
  • 1.2.3 - 2 等同于 >=1.2.3 <3.0.0

X 范围 1.2.x 1.X 1.2.* *

Xx* 可用作 [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.0
  • 1 等价于 1.x.x,即 >=1.0.0 <2.0.0
  • 1.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.40.3.0 之间可能引入破坏性变更的情况,这很常见。但它假定 0.2.40.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

缺失 minorpatch 值时,默认补零,但即使主版本为零,仍允许该部分灵活变化。

  • ^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.92.0.0 之间有空隙, 版本 1.2.10 既不大于范围(因为 2.0.1 满足,且更大),也不小于范围(因为 1.2.8 满足,且更小), 同时也不满足该范围。

如果您想判断版本是否满足某个范围,请使用 satisfies 函数。

添加到您的项目 Jump to heading

deno add jsr:@std/semver

查看 @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,短横线)表达兼容性窗口。
  • 对预发布版本保持明确;范围匹配默认排除预发布版本,除非包括它们。

你找到了你需要的东西吗?

编辑此页面
隐私政策