scripts/modules/shared/validation-functions.ps1
# strangeloop Setup - Shared Validation Functions # Version: 1.0.0 # Parameter validation and compatibility checking functions function Test-ParameterValidation { <# .SYNOPSIS Validates parameters and checks for deprecated usage patterns .PARAMETER BoundParameters The $PSBoundParameters from the calling function .PARAMETER AllowedParameters Array of parameter names that are allowed .RETURNS Hashtable with validation results #> param( [Parameter(Mandatory)] [hashtable]$BoundParameters, [string[]]$AllowedParameters = @() ) $result = @{ IsValid = $true Warnings = @() Errors = @() DeprecatedParameters = @() } # Check for deprecated parameters $deprecatedParams = @{ 'mode' = 'The -mode parameter is deprecated. Use targeted phase execution instead.' 'modular' = 'The -modular parameter is deprecated. All setups now use the unified approach.' 'monolith' = 'The -monolith parameter is deprecated. All setups now use the unified approach.' 'approach' = 'The -approach parameter is deprecated. All setups now use the unified approach.' } foreach ($paramName in $BoundParameters.Keys) { if ($deprecatedParams.ContainsKey($paramName.ToLower())) { $result.DeprecatedParameters += $paramName $result.Warnings += $deprecatedParams[$paramName.ToLower()] } } # Check for conflicting parameters $conflictingParams = @( @('phases', 'from-phase'), @('phases', 'to-phase'), @('list-phases', 'phases'), @('list-phases', 'from-phase'), @('list-phases', 'to-phase'), @('help', 'phases'), @('help', 'from-phase'), @('help', 'to-phase') ) foreach ($conflict in $conflictingParams) { if ($BoundParameters.ContainsKey($conflict[0]) -and $BoundParameters.ContainsKey($conflict[1])) { $result.Errors += "Cannot use -$($conflict[0]) and -$($conflict[1]) together" $result.IsValid = $false } } # Validate allowed parameters if specified if ($AllowedParameters.Count -gt 0) { foreach ($paramName in $BoundParameters.Keys) { if ($paramName -notin $AllowedParameters) { $result.Warnings += "Parameter -$paramName is not recognized" } } } return $result } function Test-PathValidation { <# .SYNOPSIS Validates project path format and accessibility .PARAMETER ProjectPath The project path to validate .PARAMETER CreateIfMissing Whether to create the path if it doesn't exist .RETURNS Hashtable with validation results #> param( [Parameter(Mandatory)] [string]$ProjectPath, [switch]$CreateIfMissing ) $result = @{ IsValid = $true Errors = @() Warnings = @() NormalizedPath = $ProjectPath PathType = 'Unknown' } # Normalize path separators $normalizedPath = $ProjectPath.Replace('/', '\') $result.NormalizedPath = $normalizedPath # Determine path type if ($normalizedPath -match '^[A-Za-z]:\\') { $result.PathType = 'Windows' } elseif ($ProjectPath.StartsWith('/') -or $ProjectPath.Contains('/home/')) { $result.PathType = 'WSL' $result.NormalizedPath = $ProjectPath # Keep original format for WSL paths } else { $result.PathType = 'Relative' $result.Warnings += "Relative paths may cause issues. Consider using absolute paths." } # Check for invalid characters $invalidChars = [IO.Path]::GetInvalidPathChars() foreach ($char in $invalidChars) { if ($normalizedPath.Contains($char)) { $result.Errors += "Path contains invalid character: '$char'" $result.IsValid = $false } } # Check path length (Windows limitation) if ($result.PathType -eq 'Windows' -and $normalizedPath.Length -gt 260) { $result.Warnings += "Path length ($($normalizedPath.Length)) exceeds Windows limitation (260 characters)" } # Check if path exists or can be created if ($result.PathType -eq 'Windows') { try { if (-not (Test-Path $normalizedPath)) { if ($CreateIfMissing) { $parentPath = Split-Path $normalizedPath -Parent if (-not (Test-Path $parentPath)) { $result.Errors += "Parent directory does not exist: $parentPath" $result.IsValid = $false } } else { $result.Warnings += "Path does not exist: $normalizedPath" } } } catch { $result.Errors += "Cannot access path: $($_.Exception.Message)" $result.IsValid = $false } } return $result } function Test-LoopNameValidation { <# .SYNOPSIS Validates loop name format and availability .PARAMETER LoopName The loop name to validate .RETURNS Hashtable with validation results #> param( [Parameter(Mandatory)] [string]$LoopName ) $result = @{ IsValid = $true Errors = @() Warnings = @() SuggestedNames = @() } # Import loop functions to access loop registry $loopFunctionsPath = Join-Path $PSScriptRoot "loop-functions.ps1" if (Test-Path $loopFunctionsPath) { . $loopFunctionsPath # Check if loop exists if (-not (Test-LoopExists -LoopName $LoopName)) { $result.IsValid = $false $result.Errors += "Loop '$LoopName' is not in the known loops registry" # Suggest similar names $knownLoops = Get-KnownLoops $suggestions = $knownLoops.Keys | Where-Object { $_ -like "*$LoopName*" -or $LoopName -like "*$_*" } $result.SuggestedNames = $suggestions if ($suggestions.Count -gt 0) { $result.Warnings += "Did you mean one of these: $($suggestions -join ', ')?" } } } else { $result.Warnings += "Cannot validate loop name - loop-functions.ps1 not found" } # Validate name format if ($LoopName -match '[^a-z0-9\-]') { $result.Warnings += "Loop name contains unexpected characters. Expected format: lowercase letters, numbers, and hyphens only" } if ($LoopName.Length -lt 3) { $result.Warnings += "Loop name is very short. Consider using a more descriptive name" } return $result } function Test-PhaseParameterValidation { <# .SYNOPSIS Validates phase-related parameters for consistency .PARAMETER Phases Array of phase names to target .PARAMETER FromPhase Starting phase name .PARAMETER ToPhase Ending phase name .RETURNS Hashtable with validation results #> param( [string[]]$Phases = @(), [string]$FromPhase = '', [string]$ToPhase = '' ) $result = @{ IsValid = $true Errors = @() Warnings = @() } # Import phase functions to access phase information $phaseFunctionsPath = Join-Path $PSScriptRoot "phase-functions.ps1" if (Test-Path $phaseFunctionsPath) { . $phaseFunctionsPath $validPhases = Get-PhaseOrder # Validate individual phase names foreach ($phase in $Phases) { if (-not (Test-PhaseExists -PhaseName $phase)) { $result.IsValid = $false $result.Errors += "Unknown phase: $phase" # Suggest similar phase names $suggestions = $validPhases | Where-Object { $_ -like "*$phase*" -or $phase -like "*$_*" } if ($suggestions.Count -gt 0) { $result.Warnings += "Did you mean: $($suggestions -join ', ')?" } } } # Validate range parameters if (-not [string]::IsNullOrEmpty($FromPhase) -and -not (Test-PhaseExists -PhaseName $FromPhase)) { $result.IsValid = $false $result.Errors += "Unknown from-phase: $FromPhase" } if (-not [string]::IsNullOrEmpty($ToPhase) -and -not (Test-PhaseExists -PhaseName $ToPhase)) { $result.IsValid = $false $result.Errors += "Unknown to-phase: $ToPhase" } # Validate range order if (-not [string]::IsNullOrEmpty($FromPhase) -and -not [string]::IsNullOrEmpty($ToPhase)) { $fromIndex = $validPhases.IndexOf($FromPhase) $toIndex = $validPhases.IndexOf($ToPhase) if ($fromIndex -gt $toIndex) { $result.IsValid = $false $result.Errors += "from-phase ($FromPhase) comes after to-phase ($ToPhase) in execution order" } } } else { $result.Warnings += "Cannot validate phase parameters - phase-functions.ps1 not found" } return $result } function Show-ValidationErrors { <# .SYNOPSIS Displays validation errors and warnings in a user-friendly format .PARAMETER ValidationResult The result from any validation function .PARAMETER ExitOnError Whether to exit the script if errors are found #> param( [Parameter(Mandatory)] [hashtable]$ValidationResult, [switch]$ExitOnError ) # Show warnings if ($ValidationResult.Warnings) { foreach ($warning in $ValidationResult.Warnings) { Write-Warning $warning } } # Show deprecated parameters if ($ValidationResult.ContainsKey('DeprecatedParameters') -and $ValidationResult.DeprecatedParameters -and $ValidationResult.DeprecatedParameters.Count -gt 0) { Write-Warning "Deprecated parameters detected: $($ValidationResult.DeprecatedParameters -join ', ')" } # Show errors if ($ValidationResult.Errors) { foreach ($errorMsg in $ValidationResult.Errors) { Write-Error $errorMsg } } # Show suggestions if available if ($ValidationResult.ContainsKey('SuggestedNames') -and $ValidationResult.SuggestedNames -and $ValidationResult.SuggestedNames.Count -gt 0) { Write-Host "Suggestions: $($ValidationResult.SuggestedNames -join ', ')" -ForegroundColor Yellow } # Exit if requested and errors exist if ($ExitOnError -and -not $ValidationResult.IsValid) { Write-Error "Validation failed. Please correct the errors and try again." exit 1 } } |