Modules/DotForge.Helpers/Private/Resolve-DFCliHelpFlag.ps1
|
#Requires -Version 7.0 function Resolve-DFCliHelpFlag { <# .SYNOPSIS Detects the help flag for an external command and caches the result. .DESCRIPTION Returns a cached flag from $XDG_CACHE_HOME/dotforge/cli-help-flags.json when present (unless -Force). Otherwise tries --help, -help, -?, help, -h (in that order; -h last because it collides with real flags) and accepts the first candidate whose output looks like help and is not an unknown-option error, caching the winner. Returns the best-output candidate uncached when none validate cleanly, or $null when every candidate produced no output. .PARAMETER Name The command name to resolve a help flag for. .PARAMETER Force Ignore (and overwrite) any cached flag and re-detect. .PARAMETER PassThru Return an object containing the resolved Flag and the captured probe result when detection ran. A cached flag has a null Capture value. .OUTPUTS System.String by default. With -PassThru, a PSCustomObject with Flag and Capture properties. #> [CmdletBinding()] param( [Parameter(Mandatory, Position = 0)] [string]$Name, [switch]$Force, [switch]$PassThru ) $cacheDir = Join-Path (Get-DFXdgPath Cache) 'dotforge' $cacheFile = Join-Path $cacheDir 'cli-help-flags.json' $cache = @{} if ($cacheFile -and (Test-Path $cacheFile)) { try { $loaded = Get-Content $cacheFile -Raw | ConvertFrom-Json -AsHashtable if ($loaded) { $cache = $loaded } } catch { $cache = @{} } } if (-not $Force -and $cache.ContainsKey($Name)) { if ($PassThru) { return [pscustomobject]@{ Flag = $cache[$Name]; Capture = $null } } return $cache[$Name] } $candidates = '--help', '-help', '-?', 'help', '-h' $best = $null $bestCapture = $null $bestLines = -1 foreach ($flag in $candidates) { $capture = Invoke-DFCommandCapture -Name $Name -Arguments @($flag) $text = $capture.Text if ([string]::IsNullOrWhiteSpace($text)) { continue } $isError = ($text -match '(?i)(unknown|unrecognized|invalid|unexpected)\b.{0,30}\b(option|flag|argument|switch|command)') -or ($text -match '(?im)^error\b') $lineCount = ($text -split "`r?`n").Where({ $_.Trim() }).Count $looksHelp = ($lineCount -ge 3) -or ($text -match '(?im)^\s*(usage|options|commands|flags|synopsis)\b') if ($looksHelp -and -not $isError) { if ($cacheFile) { $cache[$Name] = $flag Write-DFFileAtomic -Path $cacheFile -Value ($cache | ConvertTo-Json) } if ($PassThru) { return [pscustomobject]@{ Flag = $flag; Capture = $capture } } return $flag } if ($lineCount -gt $bestLines) { $bestLines = $lineCount $best = $flag $bestCapture = $capture } } if ($PassThru) { return [pscustomobject]@{ Flag = $best; Capture = $bestCapture } } return $best } |