The Range Class
Relevant source files
The following files were used as context for generating this wiki page:
The Range class is a core component of the node-semver library, responsible for parsing, representing, and testing semantic version ranges. A range consists of one or more "comparator sets" joined by the || (logical OR) operator. Each comparator set is satisfied by the intersection (logical AND) of the individual comparators it contains.
This class enables complex version matching logic, supporting advanced syntax such as hyphen ranges (1.2.3 - 2.3.4), Tilde ranges (~1.2.3), Caret ranges (^1.2.3), and X-Ranges (1.2.x). It serves as the underlying engine for high-level functions like satisfies(), maxSatisfying(), and minVersion().
Sources: classes/range.js:6-103, README.md:95-120, semver.js:770-802
Architecture and Internal Structure
The Range class transforms a raw range string into a structured 2D array known as a set. This set represents a Disjunctive Normal Form (DNF) where the outer array elements are OR-ed together, and the inner array elements (Comparators) are AND-ed together.
Class Composition
The diagram shows the relationship between Range and Comparator. A Range is composed of multiple Comparator objects organized into sets.
Sources: classes/range.js:6-103, semver.js:770-810
Key Properties
| Property | Type | Description |
|---|---|---|
raw | String | The original range string, trimmed and with collapsed whitespace. |
set | Array<Array<Comparator>> | A 2D array where this.set[i] is a list of comparators that must all be satisfied. |
options | Object | Configuration object containing loose and includePrerelease flags. |
formatted | String | A cached, canonical string representation of the parsed range. |
Sources: classes/range.js:7-60, semver.js:771-802
Range Parsing Logic
The parsing process involves several stages of "desugaring" advanced syntax into primitive comparators (<, <=, >, >=, =).
The Parsing Workflow
The flowchart illustrates how a raw range string is processed into a normalized set of comparators.
Sources: classes/range.js:33-100, semver.js:812-843
Memoization and Caching
To optimize performance on a "hot path," Range uses a memoization strategy. Parsing results for a specific string and option combination are stored in an internal LRU cache. The cache key is generated by combining bit-flags for loose and includePrerelease with the range string.
Sources: classes/range.js:106-114, classes/range.js:192-193
Advanced Syntax Desugaring
The Range class internally converts advanced syntax into standard comparators using specific transformation rules.
Hyphen Ranges
Hyphen ranges like X.Y.Z - A.B.C specify an inclusive set.
1.2.3 - 2.3.4desugars to>=1.2.3 <=2.3.4.- If partial versions are used (e.g.,
1.2 - 2), the range expands to cover the implied versions:1.2 - 2becomes>=1.2.0 <3.0.0-0.
Sources: README.md:144-156, classes/range.js:462-491
Tilde and Caret Ranges
- Tilde (
~): Allows patch-level changes if a minor version is specified; otherwise, allows minor-level changes.~1.2.3becomes>=1.2.3 <1.3.0-0. - Caret (
^): Allows changes that do not modify the leftmost non-zero digit.^1.2.3becomes>=1.2.3 <2.0.0-0, while^0.2.3becomes>=0.2.3 <0.3.0-0.
Sources: README.md:173-231, classes/range.js:255-364
X-Ranges
Characters like x, X, or * are used as placeholders for numeric values.
1.2.xis interpreted as>=1.2.0 <1.3.0-0.1.xis interpreted as>=1.0.0 <2.0.0-0.
Sources: README.md:158-171, classes/range.js:366-444
Validation and Testing
Version Satisfaction
The test(version) method determines if a specific version satisfies the range. A version satisfies the range if it satisfies every comparator in at least one of the comparator sets.
The logic ensures that prerelease versions are excluded unless the range explicitly opts into them or shares the same [major, minor, patch] tuple with a comparator.
Sources: classes/range.js:168-190, classes/range.js:493-524, README.md:122-142
Range Intersection
The intersects(range, options) method checks if there is any possible version that could satisfy both ranges. It iterates through the sets of both ranges to find a pair of sets where every comparator in the first set intersects with every comparator in the second set.
Sources: classes/range.js:148-166, semver.js:845-859, test/index.js:636-670
Implementation Details
Configuration Options
The Range constructor and its methods accept an options object that modifies parsing and matching behavior.
| Option | Type | Default | Description |
|---|---|---|---|
loose | Boolean | false | If true, accepts non-compliant semver strings (e.g., v1.2). |
includePrerelease | Boolean | false | If true, prerelease versions can satisfy ranges without matching tuples. |
Sources: semver.js:770-780, classes/range.js:7-10, README.md:261-270
Example Implementation
// From classes/range.js:115-132
get range () {
if (this.formatted === undefined) {
this.formatted = ''
for (let i = 0; i < this.set.length; i++) {
if (i > 0) {
this.formatted += '||'
}
const comps = this.set[i]
for (let k = 0; k < comps.length; k++) {
if (k > 0) {
this.formatted += ' '
}
this.formatted += comps[k].toString().trim()
}
}
}
return this.formatted
}
The range getter lazily constructs and caches the canonical string representation of the range.
Sources: classes/range.js:115-132
Summary
The Range class provides a robust mechanism for handling semantic version constraints. By decomposing complex strings into simplified comparator sets, it provides a consistent API for version matching, intersection testing, and canonical formatting. Its use of caching and optimized regex handling ensures it remains performant even when processing large numbers of version checks.
Sources: classes/range.js:6-60, README.md:95-120