private/Get-TerraformCommandGrammar.ps1
function Get-TerraformCommandGrammar { [CmdletBinding()] param( [Parameter(Mandatory)] [string[]] $Command ) $Grammar = @{ Commands = @(); Options = @() } $Executable = $Command[0] $Arguments = $Command[1..$Command.Length] $Output = &$Executable $Arguments -help Write-Verbose "Exporting grammar for '$($Command -join ' ')'..." $Mode = $null $CurrentOption = $null foreach($Line in $Output) { if($Line.StartsWith("Main commands:") -or $Line.StartsWith("All other commands:") -or $Line.StartsWith("Subcommands:")) { Write-Debug "[$($Command -join ' ')] Found beginning of commands ($Line)" $Mode = 'Commands' continue } elseif($Line.StartsWith("Global options") -or $Line -match "^[a-zA-Z ]*Options:$") { Write-Debug "[$($Command -join ' ')] Found beginning of options ($Line)" $Mode = 'Options' continue } if($null -eq $Mode) { continue } $LineParts = $Line -split '\s{2,}' | Where-Object { -not [string]::IsNullOrEmpty($_) } | ForEach-Object { $_.Trim() } Write-Debug "[$($Command -join ' ')][$Mode] Processing line: '$($LineParts -join ' ')'" switch($Mode) { # Only found command one-liner in TF output 'Commands' { # Empty line separator if([string]::IsNullOrEmpty($Line)) { continue } $Name, $Description = $LineParts # Subcommands $Subgrammar = Get-TerraformCommandGrammar -Command ($Command + @($Name)) $Grammar.Commands += @{ Name = $Name Description = $Description Commands = $Subgrammar.Commands Options = $Subgrammar.Options } } # Options can have description on multiple line # And have empty line between definition 'Options' { # New option (-<name> <description>) if($Line -match "^\s*-") { if($null -ne $CurrentOption) { Write-Debug "[$($Command -join ' ')][$Mode] End of option '$($CurrentOption.Name)'" $Grammar.Options += $CurrentOption $CurrentOption = $null } $Parameter, $Description = $LineParts $ParameterWithoutEqualParts = $Parameter -split ' ' # Special case (terraform plan -var) if($ParameterWithoutEqualParts.Length -gt 1) { $ParameterName, $ParameterValue = $ParameterWithoutEqualParts } else { $ParameterName, $ParameterValue = $Parameter.Split('=') } Write-Debug "[$($Command -join ' ')][$Mode] Start of option '$ParameterName' ($Line)" $CurrentOption = @{ Name = $ParameterName.TrimStart('-') Description = $Description } if($null -eq $ParameterValue) { $CurrentOption.Flag = $true } if($ParameterValue -match 'file|path|DIR') { $CurrentOption.PathValue = $true } if($ParameterValue -in @('true', 'false')) { $CurrentOption.AllowedValues = @('true', 'false') } } # Description line or empty line elseif($null -ne $CurrentOption) { $CurrentOption.Description += "`n$($Line.Trim())" } } } } if($null -ne $CurrentOption) { $Grammar.Options += $CurrentOption } return $Grammar } |