|
16 | 16 |
|
17 | 17 | dynamicParam { |
18 | 18 | # If we didn't have a Converter library, create one. |
19 | | - if (-not $PipeScriptConverters) { $script:PipeScriptConverters = @{} } |
| 19 | + if (-not $script:PipeScriptConverters) { $script:PipeScriptConverters = @{} } |
20 | 20 |
|
21 | 21 | $myInv = $MyInvocation |
22 | 22 | # Then, determine what the name of the pattern in the library would be. |
23 | 23 | $NameRegex = '[=\.\<\>@\$\!\*]+(?<Name>[\p{L}\p{N}\-\.\+]+)[=\.\<\>@\$\!\*]{0,}' |
24 | 24 |
|
| 25 | + $myInvocationName = '' |
| 26 | + |
25 | 27 | $mySafeName = |
26 | 28 | if ('.', '&' -contains $myInv.InvocationName -and |
27 | | - ( |
28 | | - $myInv.Line.Substring($MyInvocation.OffsetInLine) -match |
29 | | - "^\s{0,}$NameRegex" |
30 | | - ) -or ( |
31 | | - $myInv.Line.Substring($MyInvocation.OffsetInLine) -match |
32 | | - "^\s{0,}\$\{$NameRegex}" |
| 29 | + $( |
| 30 | + $myInvocationName = $myInv.Line.Substring($MyInvocation.OffsetInLine) |
| 31 | + $myInvocationName -match "^\s{0,}$NameRegex" |
| 32 | + ) -or |
| 33 | + $( |
| 34 | + $myInvocationName = $myInv.Line.Substring($MyInvocation.OffsetInLine) -match |
| 35 | + $myInvocationName -match "^\s{0,}\$\{$NameRegex}" |
33 | 36 | ) |
34 | 37 | ) |
35 | 38 | { |
|
38 | 41 | elseif ($MyInv.InvocationName) |
39 | 42 | { |
40 | 43 | $myInv.InvocationName -replace $NameRegex, '${Name}' |
| 44 | + $myInvocationName = $myInv.InvocationName |
41 | 45 | } |
42 | 46 | else { |
43 | 47 | $callstackPeek = @(Get-PSCallStack)[-1] |
|
50 | 54 | } |
51 | 55 |
|
52 | 56 | if ($callerName) { |
| 57 | + $myInvocationName = $CallerName |
53 | 58 | $callerName -replace $NameRegex, '${Name}' |
54 | 59 | } |
55 | 60 | } |
|
58 | 63 | $mySafeName = 'PipeScript' |
59 | 64 | } |
60 | 65 |
|
61 | | - # Find the Converter in the library. |
62 | | - $converter = Get-Transpiler | Where-Object DisplayName -eq $mySafeName |
63 | | - if ($converter) { |
| 66 | + # Find the Converter in the library |
| 67 | + if (-not $script:PipeScriptConverters[$mySafeName]) { |
| 68 | + $converter = Get-Transpiler | Where-Object DisplayName -eq $mySafeName |
| 69 | + $script:PipeScriptConverters[$mySafeName] = $converter |
| 70 | + } |
| 71 | + |
| 72 | + $converter = $script:PipeScriptConverters[$mySafeName] |
| 73 | + |
| 74 | + |
| 75 | + if ($converter.Metadata.'PipeScript.Keyword') { |
| 76 | + $keywordDynamicParameters = [Management.Automation.RuntimeDefinedParameterDictionary]::new() |
| 77 | + $keywordDynamicParameters.Add('ArgumentList', [Management.Automation.RuntimeDefinedParameter]::new( |
| 78 | + 'ArgumentList', |
| 79 | + ([PSObject[]]), |
| 80 | + @( |
| 81 | + $paramAttr = [Management.Automation.ParameterAttribute]::new() |
| 82 | + $paramAttr.ValueFromRemainingArguments = $true |
| 83 | + $paramAttr |
| 84 | + ) |
| 85 | + )) |
| 86 | + $keywordDynamicParameters.Add('InputObject', [Management.Automation.RuntimeDefinedParameter]::new( |
| 87 | + 'InputObject', |
| 88 | + ([PSObject]), |
| 89 | + @( |
| 90 | + $paramAttr = [Management.Automation.ParameterAttribute]::new() |
| 91 | + $paramAttr.ValueFromPipeline = $true |
| 92 | + $paramAttr |
| 93 | + ) |
| 94 | + )) |
| 95 | + $keywordDynamicParameters |
| 96 | + } elseif ($converter) { |
64 | 97 | $converter.GetDynamicParameters() |
65 | 98 | } |
66 | 99 |
|
67 | 100 | } |
68 | 101 |
|
69 | 102 | begin { |
70 | 103 | $steppablePipelines = |
71 | | - @(if (-not $mySafeName -and $psBoundParameters['Name']) { |
72 | | - $names = $psBoundParameters['Name'] |
73 | | - $null = $psBoundParameters.Remove('Name') |
| 104 | + @(if ($mySafeName -or $psBoundParameters['Name']) { |
| 105 | + $names = @($mySafeName) + $psBoundParameters['Name'] |
| 106 | + if ($names) { |
| 107 | + $null = $psBoundParameters.Remove('Name') |
| 108 | + } |
74 | 109 | foreach ($cmd in $script:PipeScriptConverters[$names]) { |
| 110 | + if ($cmd.Metadata.'PipeScript.Keyword') { |
| 111 | + continue |
| 112 | + } |
75 | 113 | $steppablePipeline = {& $cmd @PSBoundParameters }.GetSteppablePipeline($MyInvocation.CommandOrigin) |
76 | 114 | $null = $steppablePipeline.Begin($PSCmdlet) |
77 | 115 | $steppablePipeline |
78 | 116 | } |
79 | 117 | $psBoundParameters['Name'] = $names |
80 | 118 | }) |
| 119 | + |
| 120 | + $keywordScript = |
| 121 | + if (-not $steppablePipelines) { |
| 122 | + $myInv = $myinvocation |
| 123 | + $callstackPeek = @(Get-PSCallStack)[1] |
| 124 | + $CommandAst = if ($callstackPeek.InvocationInfo.MyCommand.ScriptBlock) { |
| 125 | + @($callstackPeek.InvocationInfo.MyCommand.ScriptBlock.Ast.FindAll({ |
| 126 | + param($ast) |
| 127 | + $ast.Extent.StartLineNumber -eq $myInv.ScriptLineNumber -and |
| 128 | + $ast.Extent.StartColumnNumber -eq $myInv.OffsetInLine -and |
| 129 | + $ast -is [Management.Automation.Language.CommandAst] |
| 130 | + },$true)) |
| 131 | + } |
| 132 | + $commandAst | & $converter |
| 133 | + } |
| 134 | + |
| 135 | + $accumulatedInput = [Collections.Queue]::new() |
81 | 136 | } |
82 | 137 |
|
83 | 138 | process { |
84 | | - if (-not $mySafeName -and -not $steppablePipelines) { |
| 139 | + $myParams = @{} + $psBoundParameters |
| 140 | + if (-not $mySafeName) { |
85 | 141 | Write-Error "Must call Use-Pipescript with one of it's aliases." |
86 | 142 | return |
87 | 143 | } |
|
91 | 147 | $sp.Process($in) |
92 | 148 | } |
93 | 149 | return |
| 150 | + } elseif (-not $steppablePipelines) { |
| 151 | + |
| 152 | + if ($myParams["InputObject"]) { |
| 153 | + $accumulatedInput.Enqueue($myParams["InputObject"]) |
| 154 | + } else { |
| 155 | + & $keywordScript |
| 156 | + } |
94 | 157 | } |
95 | | - $paramCopy = [Ordered]@{} + $psBoundParameters |
96 | | - & $Converter @paramCopy |
| 158 | + |
97 | 159 | } |
98 | 160 |
|
99 | 161 | end { |
| 162 | + if ($accumulatedInput.Count -and $keywordScript) { |
| 163 | + # When a script is returned for a given keyword, it will likely be wrapped in a process block |
| 164 | + # because that is what allows the transpiled code to run the most effeciently. |
| 165 | + # Since we're running this ad-hoc, we need to change the statement slightly, |
| 166 | + # so we're left with a script block that has a process block. |
| 167 | + if ($keywordScript -match '^[\.\&]\s{0,}\{') { |
| 168 | + $keywordScript = [ScriptBlock]::Create(($keywordScript -replace '^[\.\&]\s{0,}\{' -replace '\}$')) |
| 169 | + } |
| 170 | + $accumulatedInput.ToArray() | & $keywordScript |
| 171 | + } |
100 | 172 | foreach ($sp in $steppablePipelines) { |
101 | 173 | $sp.End() |
102 | 174 | } |
|
0 commit comments