Skip to content

feat(nodeenv): accept npm-style semver ranges in --node - #393

Merged
ekalinin merged 4 commits into
masterfrom
feat/node-version-ranges
Aug 14, 2026
Merged

feat(nodeenv): accept npm-style semver ranges in --node#393
ekalinin merged 4 commits into
masterfrom
feat/node-version-ranges

Conversation

@ekalinin

Copy link
Copy Markdown
Owner

Closes #152.

--node currently accepts only an exact version or one of system / latest / lts. Getting "the newest 22.x" meant calling nodeenv --list, parsing it and sorting the result by hand.

This adds npm-style semver ranges, resolved to the highest matching release:

nodeenv --node=22          # -> 22.23.2
nodeenv --node=21.7        # -> 21.7.3
nodeenv --node=4.x         # -> 4.9.1
nodeenv --node="^4.3.1"    # -> 4.9.1
nodeenv --node="~20.11"    # -> 20.11.1
nodeenv --node=">=20 <22"  # -> 21.7.3
nodeenv --node="8 || 10"   # -> 10.24.1
nodeenv --node="4 - 6"     # -> 6.17.1

Ranges work in .node-version files too, since that file feeds the same option.

Notes

No new dependencies. install_requires stays empty, so the range parser is implemented in the module rather than pulling in packaging or semver.

Exact versions still make no network request. 22.11.0 is detected up front and passed through untouched, keeping offline installs and current latency intact.

Unparseable strings are passed through, not rejected. Nightly and custom-mirror versions such as 23.0.0-nightly20240101abcdef are not valid semver, so erroring on them would be a regression. The change is strictly additive: anything that works today still works.

Partial comparators follow npm. >4.3 means >=4.4.0, not >4.3.0 - zero-padding would let >4.3 match 4.3.2. ^ follows the leftmost-non-zero rule, including the ^0.4.3 -> <0.5.0 and ^0.0.3 -> <0.0.4 cases, since 0.x versions are still supported.

Platform builds are respected. The musl/riscv64 filter in _get_last_node_version() is extracted into _has_platform_build() and reused by the resolver, so a musl host cannot resolve to a release that ships no build for it and then fail at download time.

A range that parses but matches nothing logs an error and exits 1.

Tests

62 new unit tests covering the parser, the matcher, resolution against the existing nodejs_index.json fixture, the platform filter, and main() dispatch (including assertions that exact/system/unparseable inputs make no urlopen call). Full suite: 192 passed, flake8 clean.

Verified end to end against nodejs.org: --node '^22.11' resolves to 22.23.2, installs, and node --version reports v22.23.2.

@ekalinin
ekalinin force-pushed the feat/node-version-ranges branch from 39dc049 to 13ccc0b Compare August 14, 2026 18:30
@ekalinin
ekalinin merged commit bb12812 into master Aug 14, 2026
38 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Request: Allow version ranges

1 participant