Range Subsets
Relevant source files
The following files were used as context for generating this wiki page:
The Range Subsets feature provides the logic necessary to determine if one semantic version range is a subset of another. A range sub is considered a subset of dom (the domain or superset) if every version that satisfies sub also satisfies dom. This is a critical utility for dependency resolution, allowing the system to determine if a narrower version constraint is safely contained within a broader one.
The implementation handles complex ranges (those containing || OR-operators) by breaking them down into "simple ranges" (sets of comparators that must all be satisfied) and performing logical comparisons between these sets. It accounts for various edge cases including prerelease tags, the "ANY" comparator (*), and null sets.
Sources: ranges/subset.js:1-45, test/ranges/subset.js:5-10
Core Logic and Architecture
The subset determination follows a hierarchical approach, delegating complex range comparisons to simple range comparisons, and finally to individual comparator analysis.
Complex Range Comparison
A complex range r1 || r2 || ... is a subset of R1 || R2 || ... if every simple range in the first set is either a null set or is a subset of at least one simple range in the second set.
The diagram above illustrates how the algorithm iterates through OR-separated groups to validate the subset relationship.
Sources: ranges/subset.js:47-75, classes/range.js:34-45
Simple Range Comparison (simpleSubset)
The simpleSubset function handles the logic for a single set of AND-ed comparators. It identifies the bounds of the subset by calculating the "highest" Greater-Than (gt) and "lowest" Less-Than (lt) constraints.
Key steps in simpleSubset logic:
- Normalization: If the range is
ANY(*), it is normalized to>=0.0.0(or>=0.0.0-0ifincludePrereleaseis enabled). - Equality Constraints: If the subset contains multiple different
=comparators, it is considered a null set (subset of everything). - Boundary Analysis: It compares the
gtandltof the subset against all comparators in the domain. - Prerelease Handling: If the subset contains a prerelease version, the domain must contain a comparator with the same
[major, minor, patch]tuple and a prerelease tag to be considered a subset, unlessincludePrereleaseis explicitly toggled.
Sources: ranges/subset.js:80-200, ranges/subset.js:210-234
Comparator Boundary Functions
To determine the effective boundaries of a range, the system uses helper functions to track the most restrictive constraints.
| Function | Logic | Purpose |
|---|---|---|
higherGT | Returns the higher of two > or >= comparators. If versions are equal, > is higher than >=. | Determines the effective lower bound of a range. |
lowerLT | Returns the lower of two < or <= comparators. If versions are equal, < is lower than <=. | Determines the effective upper bound of a range. |
Sources: ranges/subset.js:210-234
Boundary Comparison Flow
When evaluating a Greater-Than constraint, the system must ensure the subset's boundary is more restrictive (higher) than the domain's boundary.
Sources: ranges/subset.js:154-175
Prerelease Edge Cases
Prerelease handling is a significant part of the subset logic. By default, a range like ^1.2.3-pre.0 is not a subset of 1.x because 1.x does not explicitly opt into prereleases for the 1.2.3 tuple.
- Explicit Inclusion: If
includePrerelease: trueis passed in options, many restrictions are lifted. - Null Set Exception:
<1.2.3-0is treated as functionally equivalent to<1.2.3for subset purposes. - Tuple Matching: If a subset boundary has a prerelease, the domain must have a comparator that specifically targets that
[major, minor, patch]tuple with a prerelease.
Sources: test/ranges/subset.js:15-35, ranges/subset.js:145-152
API Definition
The subset functionality is exported as a function that accepts two range strings (or objects) and an optional configuration.
subset(sub, dom, [options])
| Parameter | Type | Description |
|---|---|---|
sub | String | Range | The potential subset range. |
dom | String | Range | The potential domain (superset) range. |
options | Object | Configuration options (e.g., loose, includePrerelease). |
Returns: Boolean - true if sub is a subset of dom.
Sources: index.js:46, ranges/subset.js:47, test/ranges/subset.js:105-115
Conclusion
The Range Subsets module provides a robust logical engine for comparing SemVer ranges. By deconstructing complex OR-ranges into simple comparator sets and strictly enforcing boundary and prerelease rules, it ensures that subset relationships are determined with high technical accuracy. This allows developers to verify if specific version requirements satisfy broader architectural constraints within the project.