Transpilers/Explicit.psx.ps1
<# .Synopsis Makes Output from a PowerShell function Explicit. .Description Makes a PowerShell function explicitly output. All statements will be assigned to $null, unless they explicitly use Write-Output or echo. If Write-Output or echo is used, the command will be replaced for more effecient output. .EXAMPLE Invoke-PipeScript { [explicit()] param() "This Will Not Output" Write-Output "This Will Output" } .EXAMPLE { [explicit]{ 1,2,3,4 echo "Output" } } | .>PipeScript #> [OutputType([ScriptBlock])] param( # The ScriptBlock that will be transpiled. [Parameter(Mandatory,ValueFromPipeline)] [ScriptBlock] $ScriptBlock ) process { # Search the ScriptBlock for $pipelines = $ScriptBlock.Ast.FindAll({ param($ast) # all pipelines if ($ast -isnot [System.Management.Automation.Language.PipelineAst]) { return $false } # (as long as they are not the child or grandchild of Command, Assignment, or Return statements) $ignoreTypes = 'CommandAst', 'AssignmentStatementAst', 'ReturnStatementAst' $pipelineParent = $ast.Parent $pipelineGrandParent = $ast.Parent.Parent if ($pipelineParent -and $pipelineParent.GetType().Name -in $ignoreTypes) { return $false } if ($pipelineGrandParent -and $pipelineGrandParent.GetType().Name -in $ignoreTypes) { return $false } return $true }, $false) $astReplacements = [Ordered]@{} foreach ($pipeline in $pipelines) { $nullify = $pipeline.PipelineElements[-1] -isnot [Management.Automation.Language.CommandAst] if (-not $nullify) { $cmdName = $pipeline.PipelineElements[-1].CommandElements[0].Value $isOutputCmdName = '^(?>Out|Write|Show|Format)' $resolvedAlias = $ExecutionContext.SessionState.InvokeCommand.GetCommand($cmdName, 'Alias') $nullify = $cmdName -notmatch $isOutputCmdName -and $resolvedAlias.Definition -notmatch $isOutputCmdName $isWriteOutput = $cmdName -in 'Write-Output', 'echo', 'write' if ($isWriteOutput) { if ($pipeline.PipelineElements.Count -gt 1) { $strPipeline = "$pipeline" $restOfPipeline = $strPipeline.Substring(0, $strPipeline.Length - $pipeline.PipelineElements[-1].ToString().Length) $astReplacements[$pipeline] = [ScriptBlock]::Create($restOfPipeline.TrimEnd().TrimEnd('|')) } else { $ce = $pipeline.PipelineElements[0].CommandElements $astReplacements[$pipeline] = [ScriptBlock]::Create($ce[1..($ce.Count - 1)] -join ' ') } continue } } if ($nullify) { $astReplacements[$pipeline] = [ScriptBlock]::Create("`$null = $pipeline") } } Update-PipeScript -ScriptBlock $ScriptBlock -AstReplacement $astReplacements } |