Private/Generator/Test-OpenApiGenFunction.ps1
|
function Test-OpenApiGenFunction { <# .SYNOPSIS Checks that generated source parses and that the function it defines binds. .DESCRIPTION Parses the text with the PowerShell parser (no parse errors, exactly one top-level function with the expected name), then defines the function in a throwaway child scope and reads its parameter metadata and syntax, which builds every attribute (a duplicate alias, a bad ValidateRange or an invalid parameter set fails here). Nothing is run and nothing leaks out of the child scope. Returns { IsValid, Errors, ParameterNames, ParameterSets, Syntax }. #> [CmdletBinding()] [OutputType([pscustomobject])] param( [Parameter(Mandatory = $true)] [string]$Text, [Parameter(Mandatory = $true)] [string]$FunctionName ) $errors = New-Object -TypeName System.Collections.ArrayList $parameterNames = @() $parameterSets = @() $syntax = $null $tokens = $null $parseErrors = $null $ast = [System.Management.Automation.Language.Parser]::ParseInput($Text, [ref]$tokens, [ref]$parseErrors) foreach ($parseError in @($parseErrors)) { [void]$errors.Add("Parse error at line $($parseError.Extent.StartLineNumber): $($parseError.Message)") } if ($errors.Count -eq 0) { $functions = @($ast.EndBlock.Statements | Where-Object -FilterScript { $_ -is [System.Management.Automation.Language.FunctionDefinitionAst] }) $otherStatements = @($ast.EndBlock.Statements | Where-Object -FilterScript { -not ($_ -is [System.Management.Automation.Language.FunctionDefinitionAst]) }) if ($functions.Count -ne 1 -or $functions[0].Name -ne $FunctionName -or $otherStatements.Count -gt 0) { [void]$errors.Add("The text must define exactly one function named '$FunctionName' and nothing else.") } } if ($errors.Count -eq 0) { $bindResult = & { # Child scope: the function disappears when the script block ends try { . ([scriptblock]::Create($Text)) # Module-qualified: the generated function may be named like one of these cmdlets $command = Microsoft.PowerShell.Management\Get-Item -LiteralPath "function:$FunctionName" -ErrorAction Stop $names = @($command.Parameters.Keys) $sets = @(foreach ($set in $command.ParameterSets) { $set.Name }) $usage = (Microsoft.PowerShell.Core\Get-Command -Name $FunctionName -CommandType Function -Syntax -ErrorAction Stop | Microsoft.PowerShell.Utility\Out-String).Trim() [pscustomobject]@{ Error = $null; Names = $names; Sets = $sets; Syntax = $usage } } catch { [pscustomobject]@{ Error = $_.Exception.Message; Names = @(); Sets = @(); Syntax = $null } } } if ($null -ne $bindResult.Error) { [void]$errors.Add("Bind check failed: $($bindResult.Error)") } else { $parameterNames = $bindResult.Names $parameterSets = $bindResult.Sets $syntax = $bindResult.Syntax } } return [pscustomobject]@{ IsValid = ($errors.Count -eq 0) Errors = $errors.ToArray() ParameterNames = $parameterNames ParameterSets = $parameterSets Syntax = $syntax } } |