Transpilers/Core/PipeScript.Inline.psx.ps1
<# .Synopsis Inline Transpiler .Description The PipeScript Core Inline Transpiler. This makes Source Generators with inline PipeScript work. Regardless of underlying source language, a source generator works in a fairly straightforward way. Inline PipeScript will be embedded within the file (usually in comments). If a Regular Expression can match each section, then the content in each section can be replaced. #> param( # A string containing the text contents of the file [Parameter(Mandatory,ParameterSetName='SourceTextReplace')] [Parameter(Mandatory,ParameterSetName='SourceStartAndEnd')] [string] $SourceText, [Parameter(Mandatory,ParameterSetName='SourceTextReplace')] [Alias('Replace')] [ValidateScript({ if ($_.GetGroupNames() -notcontains 'PS' -and $_.GetGroupNames() -notcontains 'PipeScript' ) { throw "Group Name PS or PipeScript required" } return $true })] [regex] $ReplacePattern, # The Start Pattern. # This indicates the beginning of what should be considered PipeScript. # An expression will match everything until -EndPattern [Parameter(Mandatory,ParameterSetName='SourceStartAndEnd')] [Alias('StartRegex')] [Regex] $StartPattern, # The End Pattern # This indicates the end of what should be considered PipeScript. [Parameter(Mandatory,ParameterSetName='SourceStartAndEnd')] [Alias('EndRegex')] [Regex] $EndPattern, # A custom replacement evaluator. # If not provided, will run any embedded scripts encountered. # The output of these scripts will be the replacement text. [Parameter(ParameterSetName='SourceTextReplace')] [Parameter(ParameterSetName='SourceStartAndEnd')] [Alias('Replacer')] [ScriptBlock] $ReplacementEvaluator, # If set, will not transpile script blocks. [Parameter(ParameterSetName='SourceStartAndEnd')] [Parameter(ParameterSetName='SourceTextReplace')] [switch] $NoTranspile, # The path to the source file. [Parameter(ParameterSetName='SourceTextReplace')] [Parameter(ParameterSetName='SourceStartAndEnd')] [string] $SourceFile, # A Script Block that will be injected before each inline is run. [Parameter(ParameterSetName='SourceTextReplace')] [Parameter(ParameterSetName='SourceStartAndEnd')] [ScriptBlock] $Begin, # A Script Block that will be piped to after each output. [Parameter(ParameterSetName='SourceTextReplace')] [Parameter(ParameterSetName='SourceStartAndEnd')] [Alias('Process')] [ScriptBlock] $ForeachObject, # A Script Block that will be injected after each inline script is run. [Parameter(ParameterSetName='SourceTextReplace')] [Parameter(ParameterSetName='SourceStartAndEnd')] [ScriptBlock] $End ) begin { $TempModule = New-Module -ScriptBlock { } } process { $psParameterSet = $psCmdlet.ParameterSetName if ($psParameterSet -eq 'SourceStartAndEnd') { $ReplacePattern = [Regex]::New(" # Match the PipeScript Start $StartPattern # Match until the PipeScript end. This will be PipeScript (?<PipeScript> (?:.|\s){0,}?(?=\z|$endPattern) ) # Then Match the PipeScript End $EndPattern ", 'IgnoreCase, IgnorePatternWhitespace', '00:00:10') $psParameterSet = 'SourceTextReplace' } if ($psParameterSet -eq 'SourceTextReplace') { $fileText = $SourceText if (-not $PSBoundParameters["ReplacementEvaluator"]) { $ReplacementEvaluator = { param($match) $pipeScriptText = if ($Match.Groups["PipeScript"].Value) { $Match.Groups["PipeScript"].Value } elseif ($match.Groups["PS"].Value) { $Match.Groups["PS"].Value } if (-not $pipeScriptText) { return } $InlineScriptBlock = [scriptblock]::Create($pipeScriptText) if (-not $InlineScriptBlock) { return } if (-not $NoTranspile) { $TranspiledOutput = $InlineScriptBlock | .>Pipescript if ($TranspiledOutput -is [ScriptBlock]) { $InlineScriptBlock = $TranspiledOutput } } $inlineAstString = $InlineScriptBlock.Ast.Extent.ToString() if ($InlineScriptBlock.ParamBlock) { $inlineAstString = $inlineAstString.Replace($InlineScriptBlock.ParamBlock.Extent.ToString(), '') } $inlineAstString = $inlineAstString $AddForeach = $( if ($ForeachObject) { '|' + [Environment]::NewLine @(foreach ($foreachStatement in $ForeachObject) { if ($foreachStatement.Ast.ProcessBlock -or $foreachStatement.Ast.BeginBlock) { ". {$ForeachStatement}" } elseif ($foreachStatement.Ast.EndBlock.Statements -and $foreachStatement.Ast.EndBlock.Statements[0].PipelineElements[0].CommandElements -and $foreachStatement.Ast.EndBlock.Statements[0].PipelineElements[0].CommandElements.Value -in 'Foreach-Object', '%') { "$ForeachStatement" } else { "Foreach-Object {$ForeachStatement}" } }) -join (' |' + [Environment]::NewLine) } ) $statements = @( if ($begin) { "$begin" } if ($AddForeach) { "@($inlineAstString)" + $AddForeach.Trim() } else { $inlineAstString } if ($end) { "$end" } ) $codeToRun = [ScriptBlock]::Create($statements -join [Environment]::Newline) "$(. $TempModule $codeToRun)" } } return $ReplacePattern.Replace($fileText, $ReplacementEvaluator) } } |