Private/AUVersion.ps1
class AUVersion : System.IComparable { [version] $Version [string] $Prerelease [string] $BuildMetadata AUVersion([version] $version, [string] $prerelease, [string] $buildMetadata) { if (!$version) { throw 'Version cannot be null.' } $this.Version = $version $this.Prerelease = $prerelease $this.BuildMetadata = $buildMetadata } AUVersion($input) { if (!$input) { throw 'Input cannot be null.' } $v = [AUVersion]::Parse($input -as [string]) $this.Version = $v.Version $this.Prerelease = $v.Prerelease $this.BuildMetadata = $v.BuildMetadata } static [AUVersion] Parse([string] $input) { return [AUVersion]::Parse($input, $true) } static [AUVersion] Parse([string] $input, [bool] $strict) { if (!$input) { throw 'Version cannot be null.' } $reference = [ref] $null if (![AUVersion]::TryParse($input, $reference, $strict)) { throw "Invalid version: $input." } return $reference.Value } static [bool] TryParse([string] $input, [ref] $result) { return [AUVersion]::TryParse($input, $result, $true) } static [bool] TryParse([string] $input, [ref] $result, [bool] $strict) { $result.Value = [AUVersion] $null if (!$input) { return $false } $pattern = [AUVersion]::GetPattern($strict) if ($input -notmatch $pattern) { return $false } $reference = [ref] $null if (![version]::TryParse($Matches['version'], $reference)) { return $false } $pr = $Matches['prerelease'] $bm = $Matches['buildMetadata'] if ($pr -and !$strict) { $pr = $pr.Replace(' ', '.') } if ($bm -and !$strict) { $bm = $bm.Replace(' ', '.') } # for now, chocolatey does only support SemVer v1 (no dot separated identifiers in pre-release): if ($pr -and $strict -and $pr -like '*.*') { return $false } if ($bm -and $strict -and $bm -like '*.*') { return $false } if ($pr) { $pr = $pr.Replace('.', '') } if ($bm) { $bm = $bm.Replace('.', '') } # $result.Value = [AUVersion]::new($reference.Value, $pr, $bm) return $true } hidden static [string] GetPattern([bool] $strict) { $versionPattern = '(?<version>\d+(?:\.\d+){1,3})' if ($strict) { $identifierPattern = "[0-9A-Za-z-]+(?:\.[0-9A-Za-z-]+)*" return "^$versionPattern(?:-(?<prerelease>$identifierPattern))?(?:\+(?<buildMetadata>$identifierPattern))?`$" } else { $identifierPattern = "[0-9A-Za-z-]+(?:\.[0-9A-Za-z-]+| \d+)*" return "$versionPattern(?:[- ]*(?<prerelease>$identifierPattern))?(?:[+ *](?<buildMetadata>$identifierPattern))?" } } [AUVersion] WithVersion([version] $version) { return [AUVersion]::new($version, $this.Prerelease, $this.BuildMetadata) } [int] CompareTo($obj) { if ($obj -eq $null) { return 1 } if ($obj -isnot [AUVersion]) { throw "AUVersion expected: $($obj.GetType())" } $t = $this.GetParts() $o = $obj.GetParts() for ($i = 0; $i -lt $t.Length -and $i -lt $o.Length; $i++) { if ($t[$i].GetType() -ne $o[$i].GetType()) { $t[$i] = [string] $t[$i] $o[$i] = [string] $o[$i] } if ($t[$i] -gt $o[$i]) { return 1 } if ($t[$i] -lt $o[$i]) { return -1 } } if ($t.Length -eq 1 -and $o.Length -gt 1) { return 1 } if ($o.Length -eq 1 -and $t.Length -gt 1) { return -1 } if ($t.Length -gt $o.Length) { return 1 } if ($t.Length -lt $o.Length) { return -1 } return 0 } [bool] Equals($obj) { return $this.CompareTo($obj) -eq 0 } [int] GetHashCode() { return $this.GetParts().GetHashCode() } [string] ToString() { $result = $this.Version.ToString() if ($this.Prerelease) { $result += "-$($this.Prerelease)" } if ($this.BuildMetadata) { $result += "+$($this.BuildMetadata)" } return $result } [string] ToString([int] $fieldCount) { if ($fieldCount -eq -1) { return $this.Version.ToString() } return $this.Version.ToString($fieldCount) } hidden [object[]] GetParts() { $result = @($this.Version) if ($this.Prerelease) { $this.Prerelease -split '\.' | ForEach-Object { # if identifier is exclusively numeric, cast it to an int if ($_ -match '^[0-9]+$') { $result += [int] $_ } else { $result += $_ } } } return $result } } function ConvertTo-AUVersion($Version) { return [AUVersion] $Version } |