Transpilers/Keywords/Assert.psx.ps1
<# .SYNOPSIS Assert keyword .DESCRIPTION Assert is a common keyword in many programming languages. In PipeScript, Asset will take a condition and an optional action. If the condition returns null, false, or empty, the assertion will be thrown. The condition may be contained in either parenthesis or a [ScriptBlock]. If there is no action, the assertion will throw an exception containing the condition. If the action is a string, the assertion will throw that error as a string. If the action is a ScriptBlock, it will be run if the assertion is false. Assertions will not be transpiled or included if -Verbose or -Debug has not been set. Additionally, while running, Assertions will be ignored if -Verbose or -Debug has not been set. .EXAMPLE # With no second argument, assert will throw an error with the condition of the assertion. Invoke-PipeScript { assert (1 -ne 1) } -Debug .EXAMPLE # With a second argument of a string, assert will throw an error Invoke-PipeScript { assert ($false) "It's not true!" } -Debug .EXAMPLE # Conditions can also be written as a ScriptBlock Invoke-PipeScript { assert {$false} "Process id '$pid' Asserted" } -Verbose .EXAMPLE # If the assertion action was a ScriptBlock, no exception is automatically thrown Invoke-PipeScript { assert ($false) { Write-Information "I Assert There Is a Problem"} } -Verbose .EXAMPLE # assert can be used with the object pipeline. $_ will be the current object. Invoke-PipeScript { 1..4 | assert {$_ % 2} "$_ is not odd!" } -Debug .EXAMPLE # You can provide a ```[ScriptBlock]``` as the second argument to see each failure Invoke-PipeScript { 1..4 | assert {$_ % 2} { Write-Error "$_ is not odd!" } } -Debug #> [ValidateScript({ # This transpiler should run if the command is literally 'assert' $commandAst = $_ return ($commandAst -and $CommandAst.CommandElements[0].Value -eq 'assert') })] param( # The CommandAst [Parameter(Mandatory,ValueFromPipeline,ParameterSetName='CommandAst')] [Management.Automation.Language.CommandAst] $CommandAst ) process { $CommandName, $CommandArgs = $commandAst.CommandElements $firstArg, $secondArg = $CommandArgs # If the first arg can be a condition in simple or complex form if (-not $firstArg -or $firstArg.GetType().Name -notin 'ParenExpressionAst', 'ScriptBlockExpressionAst', 'VariableExpressionAst', 'MemberExpressionAst', 'StringConstantExpressionAst', 'ExpandableStringExpressionAst') { # If it was the wrong type, let them know. Write-Error "Assert must be followed by one of the following expressions: * Variable * Member * String * Parenthesis * ScriptBlock " return } # If there was a second argument, it must be a string or ScriptBlock. if ($secondArg -and $secondArg.GetType().Name -notin 'ScriptBlockExpressionAst', 'StringConstantExpressionAst', 'ExpandableStringExpressionAst') { Write-Error "Assert must be followed by a ScriptBlock or string" return } # We need to create a [ScriptBlock] for the condition so we can transpile it. $firstArgTypeName = $firstArg.GetType().Name # The condition will always check for -DebugPreference or -VerbosePreference. $checkDebugPreference = '($debugPreference,$verbosePreference -ne ''silentlyContinue'')' $condition = [ScriptBlock]::Create("($checkDebugPreference -and -not $( # If the condition is already in parenthesis, if ($firstArgTypeName -eq 'ParenExpressionAst') { "$FirstArg" # leave it alone. } # If the condition is a ScriptBlockExpression, elseif ($firstArgTypeName -eq 'ScriptBlockExpressionAst') { # put it in parenthesis. "($($FirstArg.GetScriptBlock()))" } # Otherwise else { "($FirstArg)" # embed the condition in parenthesis. } ))") # Transpile the condition. $condition = $condition | .>Pipescript # Now we create the entire assertion script $newScript = # If there was no second argument if (-not $secondArg) { # Rethrow the condition "if $condition { throw '{$($firstArg -replace "'", "''")}' } " } elseif ($secondArg.GetType().Name -eq 'ScriptBlockExpressionAst') { # If the second argument was a script, transpile and embed it. "if $condition {$($secondArg.GetScriptBlock().Transpile())}" } else { # Otherwise, throw the second argument. "if $condition { throw $secondArg } " } $inPipeline = $false if ($CommandAst.Parent -is [Management.Automation.Language.PipelineAst] -and $CommandAst.Parent.PipelineElements.Count -gt 1) { $inPipeline = $true } if ($DebugPreference, $VerbosePreference -ne 'silentlyContinue') { if ($inPipeline) { [scriptblock]::Create("& { process { $newScript } }") } else { [scriptblock]::Create($newScript) } } else { if ($inPipeline) { {& { process { $_ }}} } else { {} } } } |