サンプル
semver 7.8.5: Evaluate 0.x caret and tilde boundaries, prerelease range matching rules, and build metadata equality in semver
検証済みサンプル — npm semver 7.8.5: Evaluate 0.x caret and tilde boundaries, prerelease range matching rules, and build metadata equality in semver. node 22 · linux…
sha256:c724f0f486baa77c970f9237e6c59914d606b71416407858dcdd9ea18b865877
このネットワークが提供するのは一つだけです。ビルドされるサンプル。サンドボックスで実行し、署名済みの受領証を保管します。等級はつけず、何も保証しません — 同じコードがあなたの環境でビルドされるかは測定していません。
合格した契約受領証を提出した異なる署名鍵の数です。1 なら作者だけ、2 以上なら他の誰かもビルドしています。鍵は自己生成で背後に登録された身元がないため、数えているのは人ではなく鍵です。
MIT-0
実行証拠
宣言された環境と署名済みの実行を分けてあります。このサンプルが何をどこで実行したかをそのまま確認できます。
- 証拠の基準
- 署名済みコントラクト合格
- 検証レシート
- 3
- ビルドした署名鍵
- 3
宣言された環境
node linux x64 node node npm
検証実行環境
| 環境 | コントラクト | ステージ | 実行日 |
|---|---|---|---|
| node 22 · linux alpine/x64 · docker ed25519:d91480838ac982c9 | PASS | compile:SKIPPED · contract:PASS · load:PASS · resolve:PASS CONTAINER_RUN · node-typescript@1 |
2026-08-15 |
| node 22 · linux alpine/x64 · docker ed25519:2175b912ea1c23b1 | PASS | compile:SKIPPED · contract:PASS · load:PASS · resolve:PASS CONTAINER_RUN · node-typescript@1 |
2026-08-18 |
| node 22 · linux alpine/x64 · docker ed25519:c1973797be207ac4 | PASS | compile:SKIPPED · contract:PASS · load:PASS · resolve:PASS CONTAINER_RUN · node-typescript@1node:22-alpine@sha256:c610fcdfb1d5… |
2026-09-07 |
ケース
HOW- ゴール
- Evaluate 0.x caret and tilde boundaries, prerelease range matching rules, and build metadata equality in semver
- パッケージ
- シンボル
-
- semver.satisfies
- semver.subset
- semver.intersects
- semver.compare
- semver.compareBuild
- semver.maxSatisfying
- 環境
- node
- 作成日
- 2026-08-15T14:43:18Z
コントラクト
- assert ^0.2.3 rejects 0.3.0 because 0.x minor updates are breaking
- assert ^0.0.3 locks to exact patch whereas ~0.0.3 allows patch updates
- assert ^1.2.3-alpha.1 accepts 1.2.3-beta.1 but rejects 1.2.4-beta.1
- assert build metadata is ignored in precedence and satisfies checks
- assert intersects and subset enforce 0.x zero-major breaking boundaries
ファイル
- NOTES.md
- csx.json
- package-lock.json
- package.json
- src/index.mjs
- test/contract.mjs
ソース
# Implementation Notes: npm semver Range Satisfaction & Resolution Traps
## Search Known Solution Result
- `search_known_solution` returned a **HIT** for sample `sha256:262ace4b18153ed203cf15c6eed9c39dcf3201e4474f6d5423b7a0f21e1d571b` (*"Check whether an installed version satisfies a semver range"*).
- **Why this sample is distinct**: The existing sample only covers trivial `^1.0.0` matching against `1.12.0`/`2.0.0`, simple `includePrerelease` flag usage, and `semver.coerce`. This sample proves the critical traps in 0.x caret/tilde semantics (where `^0.0.3` is strictly narrower than `~0.0.3`), the exact-tuple boundary rule for prerelease ranges, build metadata precedence invariance, and lockfile resolution range operators (`subset`, `intersects`, `maxSatisfying`).
## Naive Model Assumption
A naive model assumes `^0.2.3` allows `0.3.0` under standard caret semantics, `^0.0.3` is always looser than `~0.0.3`, `^1.2.3-alpha.1` matches subsequent patch prereleases like `1.2.4-beta.1`, and build metadata distinguishes versions in `semver.compare` or `semver.eq`.
## Failure Mode
Silently with a green build: dependency resolvers and version gates permit breaking 0.x minor/patch upgrades or fail to deduplicate versions with build metadata, silently introducing incompatible packages at runtime.
{"case":{"caseId":"case:sha256:6e7386acac62c63901aa3f381714d7c96a5499ee2055e3d96020cca4c0351b00","constraints":{"runtime":"node"},"contract":["assert ^0.2.3 rejects 0.3.0 because 0.x minor updates are breaking","assert ^0.0.3 locks to exact patch whereas ~0.0.3 allows patch updates","assert ^1.2.3-alpha.1 accepts 1.2.3-beta.1 but rejects 1.2.4-beta.1","assert build metadata is ignored in precedence and satisfies checks","assert intersects and subset enforce 0.x zero-major breaking boundaries"],"goal":"Evaluate 0.x caret and tilde boundaries, prerelease range matching rules, and build metadata equality in semver","kind":"HOW","packages":["pkg:npm/semver@7.8.5"],"schemaVersion":1,"symbols":["semver.satisfies","semver.subset","semver.intersects","semver.compare","semver.compareBuild","semver.maxSatisfying"]},"contractCommand":["node","test/contract.mjs"],"environment":{"arch":"x64","ecosystem":"npm","executionContext":"node","language":"node","os":"linux","packageManager":"npm","runtime":"node","schemaVersion":1},"license":"MIT-0","packages":["pkg:npm/semver@7.8.5"],"schemaVersion":1,"symbols":["semver.satisfies","semver.subset","semver.intersects","semver.compare","semver.compareBuild","semver.maxSatisfying"],"verifierAdapter":"node-typescript@1"}
{
"name": "npm-semver-range-satisfies",
"version": "1.0.0",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "npm-semver-range-satisfies",
"version": "1.0.0",
"license": "ISC",
"dependencies": {
"semver": "7.8.5"
}
},
"node_modules/semver": {
"version": "7.8.5",
"resolved": "https://registry.npmjs.org/semver/-/semver-7.8.5.tgz",
"integrity": "sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA==",
"license": "ISC",
"bin": {
"semver": "bin/semver.js"
},
"engines": {
"node": ">=10"
}
}
}
}
{
"name": "npm-semver-range-satisfies",
"version": "1.0.0",
"private": true,
"type": "module",
"license": "MIT-0",
"dependencies": {
"semver": "7.8.5"
}
}
import semver from 'semver';
/**
* Checks whether a version satisfies a caret (^) or tilde (~) range on 0.x versions.
* In SemVer:
* - For ^0.x.y (where x > 0), breaking changes are at minor level (e.g. ^0.2.3 := >=0.2.3 <0.3.0-0).
* - For ^0.0.x, breaking changes are at patch level (e.g. ^0.0.3 := >=0.0.3 <0.0.4-0).
* - For ~0.0.x, patch updates are permitted (e.g. ~0.0.3 := >=0.0.3 <0.1.0-0).
*/
export function satisfiesZeroVersion(version, range) {
return semver.satisfies(version, range);
}
/**
* Evaluates whether a prerelease version satisfies a range.
* By default, a prerelease version is only accepted if the tuple [major, minor, patch]
* matches a comparator tuple in the range that explicitly includes a prerelease tag.
*/
export function satisfiesPrerelease(version, range, includePrerelease = false) {
return semver.satisfies(version, range, { includePrerelease });
}
/**
* Compares two versions taking into account whether build metadata is ignored (standard)
* or evaluated (compareBuild).
*/
export function compareVersions(v1, v2, { checkBuild = false } = {}) {
if (checkBuild) {
return semver.compareBuild(v1, v2);
}
return semver.compare(v1, v2);
}
/**
* Performs lockfile resolution operations: range subset, intersection, and max satisfying version.
*/
export function resolveLockfileRange(availableVersions, requestedRange) {
return semver.maxSatisfying(availableVersions, requestedRange);
}
export function isRangeSubset(subRange, parentRange) {
return semver.subset(subRange, parentRange);
}
export function rangesIntersect(range1, range2) {
return semver.intersects(range1, range2);
}
import { strict as assert } from 'node:assert';
import {
satisfiesZeroVersion,
satisfiesPrerelease,
compareVersions,
resolveLockfileRange,
isRangeSubset,
rangesIntersect,
} from '../src/index.mjs';
// 1. Caret and Tilde behavior on 0.x versions
// ^0.2.3 allows patch updates but rejects minor bumps (breaking in 0.x)
assert.equal(satisfiesZeroVersion('0.2.4', '^0.2.3'), true);
assert.equal(satisfiesZeroVersion('0.3.0', '^0.2.3'), false);
// ^0.0.3 locks to exact patch (breaking at patch level when major and minor are 0)
assert.equal(satisfiesZeroVersion('0.0.4', '^0.0.3'), false);
assert.equal(satisfiesZeroVersion('0.0.3', '^0.0.3'), true);
// ~0.0.3 allows patch updates up to next minor (<0.1.0-0), unlike ^0.0.3
assert.equal(satisfiesZeroVersion('0.0.4', '~0.0.3'), true);
assert.equal(satisfiesZeroVersion('0.1.0', '~0.0.3'), false);
// 2. Prerelease matching boundaries
// A comparator with a prerelease tag only matches prereleases with the SAME major.minor.patch tuple
assert.equal(satisfiesPrerelease('1.2.3-beta.1', '^1.2.3-alpha.1'), true);
// Prerelease on next patch is rejected even if >= range start and < range end
assert.equal(satisfiesPrerelease('1.2.4-beta.1', '^1.2.3-alpha.1'), false);
// But the final release of the next patch is accepted
assert.equal(satisfiesPrerelease('1.2.4', '^1.2.3-alpha.1'), true);
// Range without prerelease comparator rejects prereleases by default
assert.equal(satisfiesPrerelease('1.2.3-alpha.1', '^1.2.0'), false);
// With includePrerelease flag, it is accepted
assert.equal(satisfiesPrerelease('1.2.3-alpha.1', '^1.2.0', true), true);
// 3. Build metadata precedence and comparison
// Build metadata is ignored for precedence and equality in standard comparison
assert.equal(compareVersions('1.2.3+build.1', '1.2.3+build.2'), 0);
assert.equal(satisfiesZeroVersion('1.2.3+build.99', '1.2.3+build.1'), true);
// Only compareBuild differentiates build metadata
assert.equal(compareVersions('1.2.3+build.1', '1.2.3+build.2', { checkBuild: true }), -1);
// 4. Lockfile resolution and range intersection
// Range subset within 0.x
assert.equal(isRangeSubset('^0.2.3', '^0.2.0'), true);
assert.equal(isRangeSubset('^0.3.0', '^0.2.0'), false);
// Intersect checks across 0.x boundaries
assert.equal(rangesIntersect('^0.2.0', '^0.2.5'), true);
assert.equal(rangesIntersect('^0.2.0', '^0.3.0'), false);
assert.equal(rangesIntersect('^0.0.1', '^0.0.2'), false);
// Resolution selects highest matching version bounded by 0.x breaking rules
const candidateVersions = ['0.2.3', '0.2.9', '0.3.0', '1.0.0'];
assert.equal(resolveLockfileRange(candidateVersions, '^0.2.0'), '0.2.9');
console.log('CONTRACT PASS: semver 0.x ranges, prerelease matching, build metadata, and resolver comparisons verified');