Skip to content

Commit 05eb897

Browse files
Refactor Invoke-DbatoolsFormatter for improved formatting
Simplifies the formatter by removing custom alignment-preserving settings and redundant code. Now uses a placeholder approach to preserve aligned assignments, streamlines file type checks, and only writes files if actual formatting changes are detected. Improves maintainability and reliability of the formatting process.
1 parent 4b4c3b5 commit 05eb897

File tree

1 file changed

+36
-114
lines changed

1 file changed

+36
-114
lines changed

public/Invoke-DbatoolsFormatter.ps1

Lines changed: 36 additions & 114 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,6 @@ function Invoke-DbatoolsFormatter {
55
66
.DESCRIPTION
77
Uses PSSA's Invoke-Formatter to format the target files and saves it without the BOM.
8-
Preserves manually aligned hashtables and assignment operators.
9-
Only writes files if formatting changes are detected.
108
119
.PARAMETER Path
1210
The path to the ps1 file that needs to be formatted
@@ -59,48 +57,6 @@ function Invoke-DbatoolsFormatter {
5957
$CBHRex = [regex]'(?smi)\s+\<\#[^#]*\#\>'
6058
$CBHStartRex = [regex]'(?<spaces>[ ]+)\<\#'
6159
$CBHEndRex = [regex]'(?<spaces>[ ]*)\#\>'
62-
63-
# Create custom formatter settings that preserve alignment
64-
$customSettings = @{
65-
IncludeRules = @(
66-
'PSPlaceOpenBrace',
67-
'PSPlaceCloseBrace',
68-
'PSUseConsistentIndentation',
69-
'PSUseConsistentWhitespace'
70-
)
71-
Rules = @{
72-
PSPlaceOpenBrace = @{
73-
Enable = $true
74-
OnSameLine = $true
75-
NewLineAfter = $true
76-
IgnoreOneLineBlock = $true
77-
}
78-
PSPlaceCloseBrace = @{
79-
Enable = $true
80-
NewLineAfter = $false
81-
IgnoreOneLineBlock = $true
82-
NoEmptyLineBefore = $false
83-
}
84-
PSUseConsistentIndentation = @{
85-
Enable = $true
86-
Kind = 'space'
87-
PipelineIndentation = 'IncreaseIndentationForFirstPipeline'
88-
IndentationSize = 4
89-
}
90-
PSUseConsistentWhitespace = @{
91-
Enable = $true
92-
CheckInnerBrace = $true
93-
CheckOpenBrace = $true
94-
CheckOpenParen = $true
95-
CheckOperator = $false # This is key - don't mess with operator spacing
96-
CheckPipe = $true
97-
CheckPipeForRedundantWhitespace = $false
98-
CheckSeparator = $true
99-
CheckParameter = $false
100-
}
101-
}
102-
}
103-
10460
$OSEOL = "`n"
10561
if ($psVersionTable.Platform -ne 'Unix') {
10662
$OSEOL = "`r`n"
@@ -115,29 +71,13 @@ function Invoke-DbatoolsFormatter {
11571
Stop-Function -Message "Cannot find or resolve $p" -Continue
11672
}
11773

118-
# Skip directories and non-PowerShell files
74+
# Skip directories
11975
if (Test-Path -Path $realPath -PathType Container) {
12076
Write-Message -Level Verbose "Skipping directory: $realPath"
12177
continue
12278
}
12379

124-
if ($realPath -notmatch '\.ps1$|\.psm1$|\.psd1$') {
125-
Write-Message -Level Verbose "Skipping non-PowerShell file: $realPath"
126-
continue
127-
}
128-
129-
try {
130-
$originalContent = Get-Content -Path $realPath -Raw -Encoding UTF8
131-
} catch {
132-
Stop-Function -Message "Unable to read file $realPath : $($_.Exception.Message)" -Continue
133-
}
134-
135-
# If Get-Content failed, originalContent might be null or empty
136-
if (-not $originalContent) {
137-
Write-Message -Level Verbose "Skipping empty or unreadable file: $realPath"
138-
continue
139-
}
140-
80+
$originalContent = Get-Content -Path $realPath -Raw -Encoding UTF8
14181
$content = $originalContent
14282

14383
if ($OSEOL -eq "`r`n") {
@@ -150,93 +90,75 @@ function Invoke-DbatoolsFormatter {
15090
}
15191
}
15292

153-
# Strip ending empty lines from both original and working content
93+
#strip ending empty lines
15494
$content = $content -replace "(?s)$OSEOL\s*$"
155-
$originalStripped = $originalContent -replace "(?s)$OSEOL\s*$"
15695

157-
try {
158-
# Format the content
159-
$content = Invoke-Formatter -ScriptDefinition $content -Settings $customSettings -ErrorAction Stop
160-
# Also format the original to compare
161-
$originalFormatted = Invoke-Formatter -ScriptDefinition $originalStripped -Settings $customSettings -ErrorAction Stop
162-
} catch {
163-
Write-Message -Level Warning "Unable to format $realPath : $($_.Exception.Message)"
164-
continue
96+
# Preserve aligned assignments before formatting
97+
# Look for patterns with multiple spaces before OR after the = sign
98+
$alignedPatterns = [regex]::Matches($content, '(?m)^\s*(\$\w+|\w+)\s{2,}=\s*.+$|^\s*(\$\w+|\w+)\s*=\s{2,}.+$')
99+
$placeholders = @{}
100+
101+
foreach ($match in $alignedPatterns) {
102+
$placeholder = "___ALIGNMENT_PLACEHOLDER_$($placeholders.Count)___"
103+
$placeholders[$placeholder] = $match.Value
104+
$content = $content.Replace($match.Value, $placeholder)
165105
}
166106

167-
# Ensure both contents are strings before processing
168-
if (-not $content -or $content -isnot [string]) {
169-
Write-Message -Level Warning "Formatter returned unexpected content type for $realPath"
170-
continue
107+
try {
108+
$formattedContent = Invoke-Formatter -ScriptDefinition $content -Settings CodeFormattingOTBS -ErrorAction Stop
109+
if ($formattedContent) {
110+
$content = $formattedContent
111+
}
112+
} catch {
113+
# Just silently continue - the formatting might still work partially
171114
}
172115

173-
if (-not $originalFormatted -or $originalFormatted -isnot [string]) {
174-
Write-Message -Level Warning "Formatter returned unexpected content type for original in $realPath"
175-
continue
116+
# Restore the aligned patterns
117+
foreach ($key in $placeholders.Keys) {
118+
$content = $content.Replace($key, $placeholders[$key])
176119
}
177120

178-
# Apply CBH fix to formatted content
121+
#match the ending indentation of CBH with the starting one, see #4373
179122
$CBH = $CBHRex.Match($content).Value
180123
if ($CBH) {
124+
#get starting spaces
181125
$startSpaces = $CBHStartRex.Match($CBH).Groups['spaces']
182126
if ($startSpaces) {
127+
#get end
183128
$newCBH = $CBHEndRex.Replace($CBH, "$startSpaces#>")
184129
if ($newCBH) {
130+
#replace the CBH
185131
$content = $content.Replace($CBH, $newCBH)
186132
}
187133
}
188134
}
189-
190-
# Apply CBH fix to original formatted content
191-
$originalCBH = $CBHRex.Match($originalFormatted).Value
192-
if ($originalCBH) {
193-
$startSpaces = $CBHStartRex.Match($originalCBH).Groups['spaces']
194-
if ($startSpaces) {
195-
$newOriginalCBH = $CBHEndRex.Replace($originalCBH, "$startSpaces#>")
196-
if ($newOriginalCBH) {
197-
$originalFormatted = $originalFormatted.Replace($originalCBH, $newOriginalCBH)
198-
}
199-
}
200-
}
201-
202135
$Utf8NoBomEncoding = New-Object System.Text.UTF8Encoding $False
203136
$correctCase = @(
204137
'DbaInstanceParameter'
205138
'PSCredential'
206139
'PSCustomObject'
207140
'PSItem'
208141
)
209-
210-
# Process the formatted content
211142
$realContent = @()
212143
foreach ($line in $content.Split("`n")) {
213144
foreach ($item in $correctCase) {
214145
$line = $line -replace $item, $item
215146
}
147+
#trim whitespace lines
216148
$realContent += $line.Replace("`t", " ").TrimEnd()
217149
}
218-
$finalContent = $realContent -Join "$OSEOL"
219150

220-
# Process the original formatted content the same way
221-
$originalProcessed = @()
222-
foreach ($line in $originalFormatted.Split("`n")) {
223-
foreach ($item in $correctCase) {
224-
$line = $line -replace $item, $item
225-
}
226-
$originalProcessed += $line.Replace("`t", " ").TrimEnd()
227-
}
228-
$originalFinalContent = $originalProcessed -Join "$OSEOL"
151+
$newContent = $realContent -Join "$OSEOL"
229152

230-
# Only write the file if there are actual changes
231-
if ($finalContent -ne $originalFinalContent) {
232-
try {
233-
Write-Message -Level Verbose "Formatting changes detected in $realPath"
234-
[System.IO.File]::WriteAllText($realPath, $finalContent, $Utf8NoBomEncoding)
235-
} catch {
236-
Stop-Function -Message "Unable to write file $realPath : $($_.Exception.Message)" -Continue
237-
}
153+
# Compare without empty lines to detect real changes
154+
$originalNonEmpty = ($originalContent -split "[\r\n]+" | Where-Object { $_.Trim() }) -join ""
155+
$newNonEmpty = ($newContent -split "[\r\n]+" | Where-Object { $_.Trim() }) -join ""
156+
157+
if ($originalNonEmpty -ne $newNonEmpty) {
158+
[System.IO.File]::WriteAllText($realPath, $newContent, $Utf8NoBomEncoding)
159+
Write-Message -Level Verbose "Updated: $realPath"
238160
} else {
239-
Write-Message -Level Verbose "No formatting changes needed for $realPath"
161+
Write-Message -Level Verbose "No changes needed: $realPath"
240162
}
241163
}
242164
}

0 commit comments

Comments
 (0)