MustachePlaceholders/private/Expand-PlaceholderPipelineRec.ps1
|
function Expand-PlaceholderPipelineRec { [cmdletbinding()] param ( $value, [string] $pipeline ) $pipeline = $pipeline.Trim() if (-not $pipeline.StartsWith("|")) { # should not get here, just in case throw "Invalid pipeline element '$pipeline' for the value '$value'" } $pipeline = $pipeline.Substring(1).Trim() # here we have something like 'toLower() | toUpper()' $currentExpressionString = $pipeline $restOfPipeline = "" if ($pipeline.IndexOf('|') -gt 0) { $currentExpressionString = $pipeline.Substring(0, $pipeline.IndexOf('|')).Trim() # eg: toLower() $restOfPipeline = $pipeline.Substring($pipeline.IndexOf('|')).Trim() # eg: | toUpper()' } # start to identify function: $functionNameGroup = "functionname" $functionArgsGroup = "functionargs" # we don\t really need variables, so check for variables are minimal. Improve if this functionalitiy is needed $FUNCTION_REGEXP_ST = "^(?<$functionNameGroup>[a-zA-Z0-9_]+)?(\((?<$functionArgsGroup>.*)\))?" # https://regex101.com/r/5CIzOv/1 # Valid examples: # fn1('dfdf', 'dfdf', adsf, ) # fn2 # fn3(234) # fn4() $fnRegex = [regex]$FUNCTION_REGEXP_ST $functionName = "" $functionArgs = @() $fnMatchList = $fnRegex.Matches($currentExpressionString) if ($fnMatchList.Count -eq 1) { # there should only be 1 match. Otherwise more than one function like expression passed, which is error $fnGroup = $fnMatchList.Groups | Where-Object { $_.Name -eq $functionNameGroup } $fnARgsGroup = $fnMatchList.Groups | Where-Object { $_.Name -eq $functionArgsGroup } if (@($fnGroup).Count -eq 1) { $functionName = $fnGroup.Value.Trim() } if (($fnARgsGroup).Count -eq 1) { # Parse arguments safely without Invoke-Expression $rawVars = $fnARgsGroup.Value.Trim().Split(',') foreach ($raw in $rawVars) { $tok = $raw.Trim() if ([string]::IsNullOrWhiteSpace($tok)) { continue } # full arrays support todo if needed. # Empty array/object tokens -> coerce to empty string to avoid '[]' later being executed anywhere if ($tok -match '^\[\s*\]$') { $functionArgs += @(); continue } if ($tok -match '^\{\s*\}$') { $functionArgs += @{}; continue } # Quoted strings if ($tok.StartsWith("'") -and $tok.EndsWith("'")) { $functionArgs += $tok.Trim("'"); continue } if ($tok.StartsWith('"') -and $tok.EndsWith('"')) { $functionArgs += $tok.Trim('"'); continue } # Booleans if ($tok -ieq 'true') { $functionArgs += $true; continue } if ($tok -ieq 'false') { $functionArgs += $false; continue } # Numbers if ($tok -match '^[+-]?[0-9]+$') { $functionArgs += [int]$tok; continue } if ($tok -match '^[+-]?[0-9]*\.[0-9]+$') { $functionArgs += [double]$tok; continue } # Fallback: pass as raw string token $functionArgs += $tok } } } if ($functionName -eq "") { throw "Invalid function expression ' $currentExpressionString'. Should match: '$FUNCTION_REGEXP_ST' and have only one function with correct but optional variables. . Could not resolve '$inputValue'" } $resolvedCurrentValue = Invoke-PlaceholderFunction -inputValue $value -functionName $functionName -extraArgs $functionArgs if ($restOfPipeline -ne "") { # dive to next iteration return Expand-PlaceholderPipelineRec -value $resolvedCurrentValue -pipeline $restOfPipeline } else { return $resolvedCurrentValue } # $PIPELINE_PATTERN = "\{\{\s*([a-zA-Z0-9_]+\??(\??\.[a-zA-Z0-9_]+)*)\s*(?<$pipeLineGroupName>\|.*)?\}\}" # https://regex101.com/r/IBFgBT/1 } |