Range Intersections
Relevant source files
The following files were used as context for generating this wiki page:
The Range Intersections feature provides the logic necessary to determine if two SemVer ranges or comparators share at least one possible version in common. This is a critical component for dependency resolution, ensuring that multiple version constraints can be satisfied simultaneously.
Intersection logic is implemented across the Range and Comparator classes, as well as via a top-level utility function. The system evaluates intersections by breaking complex ranges down into their constituent parts—individual comparator sets—and verifying if any combination of these sets can overlap.
Core Logic and Architecture
The intersection logic follows a hierarchical approach:
- Range Level: A Range consists of one or more "comparator sets" (joined by
||). Two ranges intersect if any set from the first range intersects any set from the second range. - Set Level: A comparator set is a group of individual comparators (joined by whitespace/AND). Two sets intersect if every individual comparator in the first set intersects every individual comparator in the second set.
- Comparator Level: The fundamental unit of intersection, comparing two specific constraints (e.g.,
>=1.0.0and<2.0.0).
High-Level Range Intersection Flow
This diagram illustrates how the system evaluates whether two complex ranges intersect.
Sources: classes/range.js:142-160, semver.js:1195-1210
Comparator Intersection
The Comparator.intersects method determines if two individual constraints overlap. It handles various scenarios including same-direction constraints, opposite directions, and exact version matches.
Intersection Scenarios
| Scenario | Logic Description | Result |
|---|---|---|
| Exact Version | If one comparator has an empty operator (e.g., 1.2.3), it tests if that version satisfies the other comparator's range. | Boolean |
| Same Direction | Both comparators are increasing (>, >=) or both are decreasing (<, <=). | Always True |
| Same Version | Both point to the same version and use inclusive operators (e.g., >=1.0.0 and <=1.0.0). | True |
| Opposite (Overlapping) | Constraints like >1.0.0 and <2.0.0 where the start is less than the end. | True |
| Opposite (Gapped) | Constraints like <=1.0.0 and >=2.0.0 where no overlap exists. | False |
Sources: semver.js:1118-1153, test/index.js:614-645
Implementation Logic for Comparators
The logic evaluates specific mathematical relationships between the two comparators:
Sources: semver.js:1135-1152
Satisfiability
A critical prerequisite for range intersection is "satisfiability." A range set like >2.0.0 <1.0.0 is technically a "null set" because no version can ever satisfy it. The isSatisfiable helper ensures that only logically possible sets are used in intersection comparisons.
A set is considered satisfiable if every comparator within that set intersects with every other comparator in the same set.
const isSatisfiable = (comparators, options) => {
let result = true
const remainingComparators = comparators.slice()
let testComparator = remainingComparators.pop()
while (result && remainingComparators.length) {
result = remainingComparators.every((otherComparator) => {
return testComparator.intersects(otherComparator, options)
})
testComparator = remainingComparators.pop()
}
return result
}
Sources: classes/range.js:188-202
Key Functions and Methods
| Function/Method | Location | Description |
|---|---|---|
intersects(r1, r2, options) | index.js, ranges/intersects.js | Top-level utility function to check if two ranges overlap. |
Range.prototype.intersects(range, options) | classes/range.js | Instance method to check intersection with another Range object. |
Comparator.prototype.intersects(comp, options) | semver.js | Instance method to check intersection with another Comparator object. |
isSatisfiable(comparators, options) | classes/range.js | Internal helper to verify if a set of comparators has a non-empty intersection. |
Sources: index.js:47, classes/range.js:142, semver.js:1118, semver.js:1404
Usage and Testing
Testing for intersections involves verifying both simple comparators and complex, multi-set ranges.
Range Intersection Test Example
Tests ensure that ranges with multiple sets (joined by ||) are handled correctly. For instance, the range 1.3.0 || <1.0.0 >2.0.0 is checked against itself and other ranges to verify consistency.
Sources: test/index.js:662-670, test/ranges/intersects.js:28-41
Null Set Handling
If a range evaluation results in an impossible constraint (a null set), it is represented as <0.0.0-0. In intersection logic, a null set is technically a subset of everything but generally fails standard intersection checks unless specifically matched.
Sources: classes/range.js:174, test/ranges/subset.js:10
Conclusion
The Range Intersection system in node-semver utilizes a recursive-style logic that decomposes ranges into comparator sets and individual comparators. By ensuring that at least one combination of these components overlaps and is internally satisfiable, the system provides a robust mechanism for detecting version compatibility across disparate constraints.