Private/Join-VersionRange.ps1
|
function Join-VersionRange { <# .SYNOPSIS Intersect several version constraints into a single NuGet range string. .DESCRIPTION When a lock is resolved, one package can be constrained by several parents (and by the DependencyFile itself). Each DependencyScript only understands a single Version string, so the constraints are intersected here first. Empty strings and 'latest' impose no constraint. Exact versions must agree with each other and satisfy every range. Ranges are intersected bound by bound: the highest lower bound and lowest upper bound win, and when bounds tie the exclusive one is kept because it is stricter. Equal inclusive bounds collapse to an exact version. Returns 'latest', an exact version, or a NuGet range string. Writes a non-terminating error and returns nothing when the constraints conflict or one of them cannot be parsed. .PARAMETER Range The constraints to intersect: 'latest', exact versions, or NuGet ranges. .EXAMPLE Join-VersionRange -Range '[1.0,3.0)', '[2.0,)' Returns '[2.0,3.0)'. .EXAMPLE Join-VersionRange -Range '2.5.0', '[2.0,3.0)' Returns '2.5.0' because the exact version lies inside the range. #> [CmdletBinding()] [OutputType([string])] param( [AllowEmptyString()] [AllowNull()] [string[]]$Range ) $constraints = @($Range | Where-Object { -not [string]::IsNullOrEmpty($_) -and $_ -ne 'latest' }) if ($constraints.Count -eq 0) { return 'latest' } $parsed = foreach ($constraint in $constraints) { $bounds = ConvertFrom-VersionRange -Version $constraint if (-not $bounds) { return } $bounds } $exacts = @($parsed | Where-Object IsExact) $ranges = @($parsed | Where-Object { -not $_.IsExact }) if ($exacts.Count -gt 0) { $exact = $exacts[0].Exact foreach ($other in $exacts) { if (-not (Test-VersionEquality -ReferenceVersion $exact -DifferenceVersion $other.Exact)) { Write-Error "Version constraints conflict: exact versions [$exact] and [$($other.Exact)] both required" return } } foreach ($constraint in $constraints) { if (-not (Test-VersionInRange -Version $exact -Required $constraint)) { Write-Error "Version constraints conflict: exact version [$exact] does not satisfy [$constraint]" return } } return $exact } $min = $null $minInclusive = $true $max = $null $maxInclusive = $true foreach ($bounds in $ranges) { if ($null -ne $bounds.Min) { $cmp = if ($null -eq $min) { 1 } else { Compare-Version -ReferenceVersion $bounds.Min -DifferenceVersion $min } if ($cmp -gt 0) { $min = $bounds.Min $minInclusive = $bounds.MinInclusive } elseif ($cmp -eq 0 -and -not $bounds.MinInclusive) { $minInclusive = $false } } if ($null -ne $bounds.Max) { $cmp = if ($null -eq $max) { -1 } else { Compare-Version -ReferenceVersion $bounds.Max -DifferenceVersion $max } if ($cmp -lt 0) { $max = $bounds.Max $maxInclusive = $bounds.MaxInclusive } elseif ($cmp -eq 0 -and -not $bounds.MaxInclusive) { $maxInclusive = $false } } } if ($null -ne $min -and $null -ne $max) { $cmp = Compare-Version -ReferenceVersion $min -DifferenceVersion $max if ($cmp -gt 0 -or ($cmp -eq 0 -and -not ($minInclusive -and $maxInclusive))) { Write-Error "Version constraints conflict: no version satisfies all of [$($constraints -join '], [')]" return } if ($cmp -eq 0) { return $min } } $open = if ($null -ne $min -and $minInclusive) { '[' } else { '(' } $close = if ($null -ne $max -and $maxInclusive) { ']' } else { ')' } "$open$min,$max$close" } |