resources/agentic-copilot/scripts/build/Test-TextFileFormatting.ps1
|
[CmdletBinding()] param( [string]$ProjectRoot = (Split-Path -Parent (Split-Path -Parent $PSScriptRoot)) ) function Test-TextFileFormatting { [CmdletBinding()] param( [Parameter(Mandatory)][string]$ProjectRoot ) $violationList = @(Get-TextFileFormattingViolationList -ProjectRoot $ProjectRoot) return [pscustomobject]@{ ProjectRoot = $ProjectRoot IsValid = $violationList.Count -eq 0 Violations = $violationList } } function Get-TextFileFormattingViolationList { [CmdletBinding()] param( [Parameter(Mandatory)][string]$ProjectRoot ) foreach ($file in @(Get-TextFileFormattingTargetFileList -ProjectRoot $ProjectRoot)) { if (-not (Test-TextFileFormattingContentHasSingleTrailingNewline -Path $file.FullName)) { Get-TextFileFormattingRelativePath -ProjectRoot $ProjectRoot -Path $file.FullName } } } function Get-TextFileFormattingTargetFileList { [CmdletBinding()] param( [Parameter(Mandatory)][string]$ProjectRoot ) $rootFileList = @(Get-ChildItem -LiteralPath $ProjectRoot -Force -File | Where-Object {Test-TextFileFormattingCandidate -FileInfo $_}) $scopedFileList = foreach ($relativePath in @('.github', 'docs', 'scripts', 'src', 'tests')) { $directoryPath = Join-Path $ProjectRoot $relativePath if (-not (Test-Path -LiteralPath $directoryPath -PathType Container)) { continue } Get-ChildItem -LiteralPath $directoryPath -Recurse -Force -File | Where-Object {Test-TextFileFormattingCandidate -FileInfo $_} } return @($rootFileList + $scopedFileList | Sort-Object FullName -Unique) } function Test-TextFileFormattingCandidate { [CmdletBinding()] param( [Parameter(Mandatory)][System.IO.FileInfo]$FileInfo ) $allowedExtensionList = @( '.md', '.ps1', '.psd1', '.psm1', '.json', '.txt', '.yml', '.yaml', '.html' ) $allowedNameList = @( '.gitignore', '.gitattributes', '.editorconfig' ) return $allowedExtensionList -contains $FileInfo.Extension -or $allowedNameList -contains $FileInfo.Name } function Test-TextFileFormattingContentHasSingleTrailingNewline { [CmdletBinding()] param( [Parameter(Mandatory)][string]$Path ) $content = Get-Content -LiteralPath $Path -Raw if ($null -eq $content -or $content.Length -eq 0) { return $true } if ($content -notmatch "(\r\n|\n)$") { return $false } return $content -notmatch "(\r\n|\n){2,}$" } function Get-TextFileFormattingRelativePath { [CmdletBinding()] param( [Parameter(Mandatory)][string]$ProjectRoot, [Parameter(Mandatory)][string]$Path ) $trimCharacterList = [char[]]@( [System.IO.Path]::DirectorySeparatorChar, [System.IO.Path]::AltDirectorySeparatorChar ) $resolvedProjectRoot = [System.IO.Path]::GetFullPath($ProjectRoot).TrimEnd($trimCharacterList) $resolvedPath = [System.IO.Path]::GetFullPath($Path) if (-not $resolvedPath.StartsWith($resolvedProjectRoot, [System.StringComparison]::OrdinalIgnoreCase)) { return $Path } $relativePath = $resolvedPath.Substring($resolvedProjectRoot.Length).TrimStart($trimCharacterList) return $relativePath.Replace('\', '/') } if ($MyInvocation.InvocationName -ne '.') { $result = Test-TextFileFormatting -ProjectRoot $ProjectRoot if (-not $result.IsValid) { $message = @( 'Text file ending violations were found. Each tracked text file must end immediately after exactly one newline terminator, with no blank spacer lines at the bottom.' @($result.Violations | ForEach-Object {"- $_"}) ) -join [Environment]::NewLine throw $message } Write-Host 'All tracked text files end immediately after exactly one newline terminator with no extra blank lines at the bottom.' } |