2024-09-10 12:28:59 -07:00
function Invoke-Preprocessing {
2024-08-06 23:35:17 +03:00
<#
. SYNOPSIS
A function that does Code Formatting using RegEx , useful when trying to force specific coding standard ( s ) to a project .
. PARAMETER ExcludedFiles
A list of file paths which 're *relative to* ' WorkingDir ' Folder, every item in the list can be pointing to File (doesn' t end with '\' ) or Directory ( ends with '\' ) or None-Existing File / Directory .
2025-05-05 17:18:29 +02:00
By default , it checks if everyitem exists , and throws an exception if one or more are not found ( None-Existing ) .
2024-08-06 23:35:17 +03:00
. PARAMETER WorkingDir
The folder to search inside recursively for files which 're going to be Preprocessed (Code Formatted), unless they' re found in 'ExcludedFiles' List .
Note : The path should be absolute , NOT relative .
. PARAMETER ProgressStatusMessage
The status message used when displaying the progress bar , which 's done through PowerShell ' Write-Progress ' Cmdlet .
This ' s a Required Parameter , as the information displayed to terminal is useful when running this function ,
which might take less than 1 sec to minutes depending on project ' s scale & hardware performance .
. PARAMETER ProgressActivity
The activity message used when displaying the progress bar , which 's done through PowerShell ' Write-Progress ' Cmdlet ,
This 's an Optional Parameter, default value is ' Preprocessing ', used in combination with ' ProgressStatusMessage ' Parameter Value .
. EXAMPLE
Invoke-Preprocessing -WorkingDir " DRIVE:\Path\To\Folder\ " -ExcludedFiles @ ( 'file.txt' , '.\.git\' , '*.png' ) -ProgressStatusMessage " Doing Preprocessing "
2025-10-14 19:51:53 +02:00
Calls 'Invoke-Preprocessing' function using Named Parameters , with 'WorkingDir' ( Mandatory Parameter ) which 's used as the base folder when searching for files recursively (using ' Get-ChildItem '), other two parameters are, in order from right to left, the Optional ' ExcludeFiles ', which can be a path to a file, folder, or pattern-matched (like ' * . png '), and the ' ProgressStatusMessage ', which' s used in Progress Bar .
2024-08-06 23:35:17 +03:00
. EXAMPLE
Invoke-Preprocessing -WorkingDir " DRIVE:\Path\To\Folder\ " -ExcludedFiles @ ( 'file.txt' , '.\.git\' , '*.png' ) -ProgressStatusMessage " Doing Preprocessing " -ProgressActivity " Re-Formatting Code "
Same as Example No . 1 , but uses 'ProgressActivity' which ' s used in Progress Bar .
. EXAMPLE
Invoke-Preprocessing -Skip -WorkingDir " DRIVE:\Path\To\Folder\ " -ExcludedFiles @ ( 'file.txt' , '.\.git\' , '*.png' ) -ProgressStatusMessage " Doing Preprocessing "
#>
2024-09-10 04:05:10 +03:00
param (
2025-05-05 17:18:29 +02:00
[ Parameter ( Mandatory , position = 1 ) ]
2024-08-06 23:35:17 +03:00
[ ValidateScript ( { [ System.IO.Path ] :: IsPathRooted ( $_ ) } ) ]
[ string ] $WorkingDir ,
2025-05-05 17:18:29 +02:00
[ Parameter ( position = 2 ) ]
2024-08-06 23:35:17 +03:00
[ string[] ] $ExcludedFiles ,
2025-05-05 17:18:29 +02:00
[ Parameter ( Mandatory , position = 3 ) ]
2024-08-06 23:35:17 +03:00
[ string ] $ProgressStatusMessage ,
2025-05-05 17:18:29 +02:00
[ Parameter ( position = 4 ) ]
2024-08-06 23:35:17 +03:00
[ string ] $ProgressActivity = " Preprocessing "
2024-09-10 04:05:10 +03:00
)
2024-08-06 23:35:17 +03:00
if ( -NOT ( Test-Path -PathType Container -Path " $WorkingDir " ) ) {
2025-10-14 19:51:53 +02:00
throw " [Invoke-Preprocessing] Invalid Parameter Value for 'WorkingDir', passed value: ' $WorkingDir '. Either the path is a File or Non-Existing/Invlid, please double check your code. "
2024-08-06 23:35:17 +03:00
}
2024-10-01 23:21:49 +03:00
$InternalExcludedFiles = [ System.Collections.Generic.List[string] ] :: new ( $ExcludedFiles . Count )
ForEach ( $excludedFile in $ExcludedFiles ) {
$InternalExcludedFiles . Add ( $excludedFile ) | Out-Null
2024-09-10 04:05:10 +03:00
}
2025-05-05 17:18:29 +02:00
# Validate the ExcludedItems List before continuing on
2024-10-01 23:21:49 +03:00
if ( $ExcludedFiles . Count -gt 0 ) {
ForEach ( $excludedFile in $ExcludedFiles ) {
2024-08-06 23:35:17 +03:00
$filePath = " $( ( $WorkingDir -replace ( '\\$' , '' ) ) + '\' + ( $excludedFile -replace ( '\.\\' , '' ) ) ) "
2025-11-17 12:24:28 -05:00
# Only attempt to create the directory if the excludedFile ends with '\'
if ( $excludedFile -match '\\$' -and -not ( Test-Path " $filePath " ) ) {
New-Item -Path " $filePath " -ItemType Directory -Force | Out-Null
}
2024-10-01 23:21:49 +03:00
$files = Get-ChildItem -Recurse -Path " $filePath " -File -Force
if ( $files . Count -gt 0 ) {
ForEach ( $file in $files ) {
$InternalExcludedFiles . Add ( " $( $file . FullName ) " ) | Out-Null
2024-09-10 04:05:10 +03:00
}
2024-10-01 23:21:49 +03:00
} else { $failedFilesList + = " ' $filePath ', " }
2024-08-06 23:35:17 +03:00
}
$failedFilesList = $failedFilesList -replace ( ',\s*$' , '' )
2025-05-05 17:18:29 +02:00
if ( ( -not $failedFilesList -eq " " ) ) {
Write-Warning " [Invoke-Preprocessing] One or more File Paths and/or File Patterns were not found: $failedFilesList "
2024-09-10 04:05:10 +03:00
}
}
# Get Files List
2024-10-01 23:21:49 +03:00
[ System.Collections.ArrayList ] $files = Get-ChildItem -LiteralPath $WorkingDir -Recurse -Exclude $InternalExcludedFiles -File -Force
2024-09-10 04:05:10 +03:00
# Only keep the 'FullName' Property for every entry in the list
2024-10-01 23:21:49 +03:00
for ( $i = 0 ; $i -lt $files . Count ; $i + + ) {
2024-09-10 04:05:10 +03:00
$file = $files [ $i ]
$files [ $i ] = $file . FullName
}
# If a file(s) are found in Exclude List,
# Remove the file from files list.
2024-10-01 23:21:49 +03:00
ForEach ( $excludedFile in $InternalExcludedFiles ) {
$index = $files . IndexOf ( " $excludedFile " )
if ( $index -ge 0 ) { $files . RemoveAt ( $index ) }
2024-08-06 23:35:17 +03:00
}
2025-05-05 17:18:29 +02:00
# Define a path to store the file hashes
$hashFilePath = Join-Path -Path $WorkingDir -ChildPath " .preprocessor_hashes.json "
2024-08-06 23:35:17 +03:00
2025-05-05 17:18:29 +02:00
# Load existing hashes if the file exists
$existingHashes = @ { }
if ( Test-Path -Path $hashFilePath ) {
# intentionally dosn't use ConvertFrom-Json -AsHashtable as it isn't supported on old powershell versions
$file_content = Get-Content -Path $hashFilePath | ConvertFrom-Json
foreach ( $property in $file_content . PSObject . Properties ) {
$existingHashes [ $property . Name ] = $property . Value
2024-08-06 23:35:17 +03:00
}
}
2025-05-05 17:18:29 +02:00
$newHashes = @ { }
$changedFiles = @ ( )
$hashingAlgorithm = " MD5 "
foreach ( $file in $files ) {
# Calculate the hash of the file
$hash = Get-FileHash -Path $file -Algorithm $hashingAlgorithm | Select-Object -ExpandProperty Hash
$newHashes [ $file ] = $hash
# Check if the hash already exists in the existing hashes
if ( ( $existingHashes . ContainsKey ( $file ) -and $existingHashes [ $file ] -eq $hash ) ) {
# Skip processing this file as it hasn't changed
continue ;
}
else {
# If the hash doesn't exist or has changed, add it to the changed files list
$changedFiles + = $file
}
}
$files = $changedFiles
$numOfFiles = $files . Count
Write-Debug " [Invoke-Preprocessing] Files Changed: $numOfFiles "
if ( $numOfFiles -eq 0 ) {
Write-Debug " [Invoke-Preprocessing] Found 0 Files to Preprocess inside 'WorkingDir' Directory : ' $WorkingDir '. "
return
}
2024-08-06 23:35:17 +03:00
for ( $i = 0 ; $i -lt $numOfFiles ; $i + + ) {
2024-09-10 04:05:10 +03:00
$fullFileName = $files [ $i ]
2024-08-06 23:35:17 +03:00
# TODO:
# make more formatting rules, and document them in WinUtil Official Documentation
2024-09-10 04:05:10 +03:00
( Get-Content " $fullFileName " ) . TrimEnd ( ) `
2024-08-06 23:35:17 +03:00
-replace ( '\t' , ' ' ) `
-replace ( '\)\s*\{' , ') {' ) `
-replace ( '(?<keyword>if|for|foreach)\s*(?<condition>\([.*?]\))\s*\{' , '${keyword} ${condition} {' ) `
-replace ( '\}\s*elseif\s*(?<condition>\([.*?]\))\s*\{' , '} elseif ${condition} {' ) `
-replace ( '\}\s*else\s*\{' , '} else {' ) `
-replace ( 'Try\s*\{' , 'try {' ) `
-replace ( 'Catch\s*\{' , 'catch {' ) `
-replace ( '\}\s*Catch' , '} catch' ) `
-replace ( '\}\s*Catch\s*(?<exceptions>(\[.*?\]\s*(\,)?\s*)+)\s*\{' , '} catch ${exceptions} {' ) `
-replace ( '\}\s*Catch\s*(?<exceptions>\[.*?\])\s*\{' , '} catch ${exceptions} {' ) `
2024-09-10 04:05:10 +03:00
-replace ( '(?<parameter_type>\[[^$0-9]+\])\s*(?<str_after_type>\$.*?)' , '${parameter_type}${str_after_type}' ) `
| Set-Content " $fullFileName "
2025-05-05 17:18:29 +02:00
$newHashes [ $fullFileName ] = Get-FileHash -Path $fullFileName -Algorithm $hashingAlgorithm | Select-Object -ExpandProperty Hash
2024-08-06 23:35:17 +03:00
Write-Progress -Activity $ProgressActivity -Status " $ProgressStatusMessage - Finished $i out of $numOfFiles " -PercentComplete ( ( $i / $numOfFiles ) * 100 )
}
Write-Progress -Activity $ProgressActivity -Status " $ProgressStatusMessage - Finished Task Successfully " -Completed
2025-05-05 17:18:29 +02:00
# Save the new hashes to the file
$newHashes | ConvertTo-Json -Depth 10 | Set-Content -Path $hashFilePath
2024-08-06 23:35:17 +03:00
}