Private/Classes.ps1
<# .DESCRIPTION Special private classes for the module. Previously the module used to have a lot of private classes spread across various files, this is an attempt to consolidate them into one file. #> ## Git related classes <# This class converts shorthand git diffs into human readable status #> class GitDiff { [string] $Value GitDiff([char] $Value) { $StatusMap = @{ '?' = 'Untracked' '!' = 'Ignored' 'A' = 'Added' 'C' = 'Copied' 'D' = 'Deleted' 'M' = 'Modified' 'R' = 'Renamed' 'T' = 'Type Changed' 'U' = 'Unmerged' ' ' = 'Unmodified' } if ($StatusMap.ContainsKey($Value)) { $this.Value = $StatusMap[$Value] } else { throw "Invalid git status: '$Value'" } } GitDiff([string] $Value) { $StatusMap = @{ '?' = 'Untracked' '!' = 'Ignored' 'A' = 'Added' 'C' = 'Copied' 'D' = 'Deleted' 'M' = 'Modified' 'R' = 'Renamed' 'T' = 'Type Changed' 'U' = 'Unmerged' ' ' = 'Unmodified' } if ($StatusMap.ContainsKey($Value)) { $this.Value = $StatusMap[$Value] } else { throw "Invalid git status: '$Value'" } } [string] ToString() { return "$($this.Value)" } } <# This class helps us format git status objects #> class GitStatus { [GitDiff]$Staged [GitDiff]$Unstaged [string]$Source hidden [string]$Destination GitStatus([string]$Staged, [string]$Unstaged, [string]$Source, [string]$Destination) { $this.Staged = $Staged $this.Unstaged = $Unstaged $this.Source = $Source $this.Destination = $Destination } GitStatus([pscustomobject]$Status) { if (!$Status.Staged -and !$Status.Unstaged) { throw 'Cannot create GitStatus object without a Staged or Unstaged change' } if (!$Status.Source) { throw 'Cannot create GitStatus object without a Source' } $this.Staged = $Status.Staged $this.Unstaged = $Status.Unstaged $this.Source = $Status.Source $this.Destination = $Status.Destination } GitStatus([hashtable]$Status) { if (!$Status.Staged -and !$Status.Unstaged) { throw 'Cannot create GitStatus object without a Staged or Unstaged change' } if (!$Status.Source) { throw 'Cannot create GitStatus object without a Source' } $this.Staged = $Status.Staged $this.Unstaged = $Status.Unstaged $this.Source = $Status.Source $this.Destination = $Status.Destination } } ## GitHub related classes <# Simple enum for GitHub issue/PR states #> enum GitHubIssueState { Open Closed All } ## Type validation classes <# Simple class to ensure datetime objects are displayed as short dates in output but retain their date time attribute #> class BrownserveShortDate { [datetime]$Date BrownserveShortDate([datetime]$Date) { $this.Date = $Date } BrownserveShortDate([string]$Date) { $this.Date = $Date } [string] ToString() { return "$(Get-Date $this.Date -Format 'yyyy/MM/dd')" } } <# This class helps us to format version history entries from a changelog #> class BrownserveVersionHistory { [semver]$Version [BrownserveShortDate]$ReleaseDate [string]$URL [string[]]$ReleaseNotes [bool]$PreRelease = $false BrownserveVersionHistory([semver]$Version, [datetime]$ReleaseDate, [string]$URL, [string]$ReleaseNotes) { $this.Version = $Version $this.ReleaseDate = $ReleaseDate $this.URL = $URL $this.ReleaseNotes = $ReleaseNotes if ($this.Version.PreReleaseLabel) { $this.PreRelease = $true } } BrownserveVersionHistory([pscustomobject]$VersionHistory) { if (!$VersionHistory.Version) { throw 'Cannot create BrownserveVersionHistory object without a Version' } if (!$VersionHistory.ReleaseDate) { throw 'Cannot create BrownserveVersionHistory object without a ReleaseDate' } if (!$VersionHistory.URL) { throw 'Cannot create BrownserveVersionHistory object without a URL' } if (!$VersionHistory.ReleaseNotes) { throw 'Cannot create BrownserveVersionHistory object without ReleaseNotes' } $this.Version = $VersionHistory.Version $this.ReleaseDate = $VersionHistory.ReleaseDate $this.URL = $VersionHistory.URL $this.ReleaseNotes = $VersionHistory.ReleaseNotes if ($this.Version.PreReleaseLabel) { $this.PreRelease = $true } } BrownserveVersionHistory([hashtable]$VersionHistory) { if (!$VersionHistory.Version) { throw 'Cannot create BrownserveVersionHistory object without a Version' } if (!$VersionHistory.ReleaseDate) { throw 'Cannot create BrownserveVersionHistory object without a ReleaseDate' } if (!$VersionHistory.URL) { throw 'Cannot create BrownserveVersionHistory object without a URL' } if (!$VersionHistory.ReleaseNotes) { throw 'Cannot create BrownserveVersionHistory object without ReleaseNotes' } $this.Version = $VersionHistory.Version $this.ReleaseDate = $VersionHistory.ReleaseDate $this.URL = $VersionHistory.URL $this.ReleaseNotes = $VersionHistory.ReleaseNotes if ($this.Version.PreReleaseLabel) { $this.PreRelease = $true } } [string] ToString() { return "$($this.Version) - $($this.ReleaseDate)" } } <# Class for storing Brownserve Changelog data #> class BrownserveChangelog { [BrownserveVersionHistory[]]$VersionHistory [int]$NewEntryInsertLine [BrownserveVersionHistory]$LatestVersion hidden [string]$ChangelogPath hidden [string[]]$Content BrownserveChangelog([BrownserveVersionHistory[]]$VersionHistory, [int]$NewEntryInsertLine, [string]$ChangelogPath, [string[]]$Content) { $this.VersionHistory = $VersionHistory | Sort-Object -Property ReleaseDate -Descending $this.NewEntryInsertLine = $NewEntryInsertLine $this.LatestVersion = $this.VersionHistory[0] $this.ChangelogPath = $ChangelogPath $this.Content = $Content } BrownserveChangelog([pscustomobject]$Changelog) { if (!$Changelog.VersionHistory) { throw 'Cannot create BrownserveChangelog object without VersionHistory' } if (!$Changelog.NewEntryInsertLine) { throw 'Cannot create BrownserveChangelog object without NewEntryInsertLine' } if (!$Changelog.ChangelogPath) { throw 'Cannot create BrownserveChangelog object without ChangelogPath' } if (!$Changelog.Content) { throw 'Cannot create BrownserveChangelog object without Content' } $this.VersionHistory = $Changelog.VersionHistory | Sort-Object -Property ReleaseDate -Descending $this.NewEntryInsertLine = $Changelog.NewEntryInsertLine $this.LatestVersion = $this.VersionHistory[0] $this.ChangelogPath = $Changelog.ChangelogPath $this.Content = $Changelog.Content } BrownserveChangelog([hashtable]$Changelog) { if (!$Changelog.VersionHistory) { throw 'Cannot create BrownserveChangelog object without VersionHistory' } if (!$Changelog.NewEntryInsertLine) { throw 'Cannot create BrownserveChangelog object without NewEntryInsertLine' } if (!$Changelog.ChangelogPath) { throw 'Cannot create BrownserveChangelog object without ChangelogPath' } if (!$Changelog.Content) { throw 'Cannot create BrownserveChangelog object without Content' } $this.VersionHistory = $Changelog.VersionHistory | Sort-Object -Property ReleaseDate -Descending $this.NewEntryInsertLine = $Changelog.NewEntryInsertLine $this.LatestVersion = $this.VersionHistory[0] $this.ChangelogPath = $Changelog.ChangelogPath $this.Content = $Changelog.Content } } ## IDE related classes <# This class helps us format editorconfig properties #> class EditorConfigProperty { [string]$Name $Value EditorConfigProperty([string]$Name, $Value) { $this.Name = $Name $this.Value = $Value $this.ValidityCheck() } EditorConfigProperty([hashtable]$Property) { $this.Value = $Property.Value $this.Name = $Property.Name $this.ValidityCheck() } EditorConfigProperty([System.Collections.DictionaryEntry]$Property) { $this.Value = $Property.Value $this.Name = $Property.Name $this.ValidityCheck() } [string] ToString() { return ("$($this.Name) = $($this.Value)").ToLower() } hidden ValidityCheck() { # Ensure that the property name is valid as per the editorconfig spec (https://github.com/editorconfig/editorconfig/wiki/EditorConfig-Properties) $ValidPropertyNames = @( 'indent_style', 'indent_size', 'tab_width', 'end_of_line', 'charset', 'trim_trailing_whitespace', 'insert_final_newline', 'max_line_length' ) if ($this.Name -notin $ValidPropertyNames) { throw "Invalid editorconfig property name: '$($this.Name)'" } # Ensure that the property value is valid as per the editorconfig spec switch ($this.Name) { 'indent_style' { $ValidValues = @('tab', 'space') if ($this.Value -notin $ValidValues) { throw "Invalid indent_style value: '$($this.Value)'" } } 'indent_size' { (($this.Value -isnot [int]) -or ($this.Value -isnot [Int64])) { if ($this.Value -ne 'tab') { throw "Invalid indent_size value: '$($this.Value)'" } } } 'tab_width' { (($this.Value -isnot [int]) -or ($this.Value -isnot [Int64])) { throw "Invalid tab_width value: '$($this.Value)'" } } 'end_of_line' { $ValidValues = @('lf', 'cr', 'crlf') if ($this.Value -notin $ValidValues) { throw "Invalid end_of_line value: '$($this.Value)'" } } 'charset' { $ValidValues = @('latin1', 'utf-8', 'utf-8-bom', 'utf-16be', 'utf-16le') if ($this.Value -notin $ValidValues) { throw "Invalid charset value: '$($this.Value)'" } } 'trim_trailing_whitespace' { if ($this.Value -isnot [bool]) { throw "Invalid trim_trailing_whitespace value: '$($this.Value)'" } } 'insert_final_newline' { if ($this.Value -isnot [bool]) { throw "Invalid insert_final_newline value: '$($this.Value)'" } } 'max_line_length' { if (($this.Value -isnot [int]) -or ($this.Value -isnot [Int64])) { if ($this.Value -ne 'off') { throw "Invalid max_line_length value: '$($this.Value)'" } } } } } } <# This class helps us format editorconfig sections #> class EditorConfigSection { [string]$FilePath [EditorConfigProperty[]]$Properties [string[]]$Comment EditorConfigSection([string]$FilePath, [EditorConfigProperty[]]$Properties) { $this.FilePath = $FilePath $this.Properties = $Properties } EditorConfigSection([string]$FilePath, [EditorConfigProperty[]]$Properties, [string[]]$Comment) { $this.FilePath = $FilePath $this.Properties = $Properties $this.Comment = $Comment } EditorConfigSection([hashtable]$Section) { if (!$Section.FilePath) { throw 'Cannot create EditorConfigSection object without FilePath' } if (!$Section.Properties) { throw 'Cannot create EditorConfigSection object without Properties' } if ($Section.Comment) { $this.Comment = $Section.Comment } $this.FilePath = $Section.FilePath if ($Section.Properties -is [hashtable]) { $this.ExpandProperties($Section.Properties) } else { $this.Properties = $Section.Properties } } # It's much more convenient to be able to pass in a hash of all the properties # but we need to expand them all first hidden ExpandProperties([hashtable]$Properties) { $ExpandedProps = @() $Properties.GetEnumerator() | ForEach-Object { $ExpandedProps += [EditorConfigProperty]$_ } $this.Properties = $ExpandedProps } # Override the default ToString method, let's output exactly what we want! [string] ToString() { $Return = '' if ($this.Comment) { $this.Comment | ForEach-Object { if ($_.StartsWith('#')) { $Return += "$_`n" } else { $Return += "# $_`n" } } } if ($this.FilePath -notmatch '^\[.*\]$') { $Return += "[$($this.FilePath)]`n" } else { $Return += "$($this.FilePath)`n" } $this.Properties | ForEach-Object { $Return += "$($_)`n" } return $Return } } |