Private/Filters.ps1
|
# The fixed list of filters. None of them can loop. # name = number of arguments, kind of value it works on $script:PsdFilters = [ordered]@{ lower = 0, 'text'; upper = 0, 'text'; trim = 0, 'text'; replace = 2, 'text'; split = 1, 'text' join = 1, 'list'; first = 0, 'list'; last = 0, 'list'; sort = 0, 'list'; unique = 0, 'list'; count = 0, 'list' keys = 0, 'map'; values = 0, 'map' } function Compare-PsdScalar { param($A, $B) if ((Test-PsdNumber $A) -and (Test-PsdNumber $B)) { return ([double]$A).CompareTo([double]$B) } [string]::Compare((Format-PsdScalarText $A), (Format-PsdScalarText $B), [System.StringComparison]::OrdinalIgnoreCase) } function Invoke-PsdFilter { param($Filter, $Value, $FArgs, $Ev) $ctx = $Ev.Doc.Ctx $name = $Filter.Name.ToLowerInvariant() $err = { param($code, $msg, [string[]] $hint = @()) Add-PsdNodeError $ctx $code $msg $Ev.Node $Filter.Start ($Filter.End - $Filter.Start) -Hint $hint $null } if (-not $script:PsdFilters.Contains($name)) { $all = @($script:PsdFilters.PSBase.Keys) -join ', ' $dym = Get-PsdDidYouMean $Filter.Name $script:PsdFilters.PSBase.Keys return (& $err 'PSD311' "'$($Filter.Name)' isn't a filter." @($dym, "Filters: $all.")) } $want, $kind = $script:PsdFilters[$name] if ($FArgs.Count -ne $want) { $n = if ($want -eq 1) { '1 argument' } else { "$want arguments" } return (& $err 'PSD312' "'$name' takes $n, but got $($FArgs.Count).") } if ($null -eq $Value) { return $null } $okKind = switch ($kind) { 'text' { $Value -is [string] } 'list' { Test-PsdList $Value } 'map' { $Value -is [System.Collections.IDictionary] } } if (-not $okKind) { $what = @{ text = 'text'; list = 'a list'; map = 'a map' }[$kind] return (& $err 'PSD312' "'$name' works on $what, but this is $(Get-PsdKindText $Value).") } $textArgs = New-PsdList foreach ($a in $FArgs) { if (Test-PsdContainer $a) { return (& $err 'PSD312' "the arguments of '$name' have to be text or numbers.") } $textArgs.Add((Format-PsdScalarText $a)) } if ($name -in 'join', 'sort') { foreach ($x in $Value) { if (Test-PsdContainer $x) { return (& $err 'PSD312' "'$name' needs a list of text or numbers, but an item is $(Get-PsdKindText $x).") } } } switch ($name) { 'lower' { return $Value.ToLowerInvariant() } 'upper' { return $Value.ToUpperInvariant() } 'trim' { return $Value.Trim() } 'replace' { if ($textArgs[0].Length -eq 0) { return (& $err 'PSD312' "'replace' can't replace empty text.") } return $Value.Replace($textArgs[0], $textArgs[1]) } 'split' { $out = New-PsdList if ($textArgs[0].Length -eq 0) { foreach ($c in $Value.ToCharArray()) { $out.Add([string]$c) } } else { foreach ($p in $Value.Split([string[]]@($textArgs[0]), [System.StringSplitOptions]::None)) { $out.Add($p) } } return , $out } 'join' { $parts = foreach ($x in $Value) { Format-PsdScalarText $x } return ($parts -join $textArgs[0]) } 'first' { if ($Value.Count -eq 0) { return $null }; return , $Value[0] } 'last' { if ($Value.Count -eq 0) { return $null }; return , $Value[$Value.Count - 1] } 'count' { if ($Value -is [System.Collections.IDictionary]) { return $Value.PSBase.Count }; return $Value.Count } 'sort' { $out = Get-PsdItems $Value # Insertion sort keeps equal items in order. for ($i = 1; $i -lt $out.Count; $i++) { $x = $out[$i] $j = $i - 1 while ($j -ge 0 -and (Compare-PsdScalar $out[$j] $x) -gt 0) { $out[$j + 1] = $out[$j]; $j-- } $out[$j + 1] = $x } return , $out } 'unique' { $out = New-PsdList foreach ($x in $Value) { if (-not (Test-PsdListHas $out $x)) { $out.Add($x) } } return , $out } 'keys' { $out = New-PsdList; foreach ($k in $Value.PSBase.Keys) { $out.Add($k) }; return , $out } 'values' { $out = New-PsdList; foreach ($k in $Value.PSBase.Keys) { $out.Add($Value[$k]) }; return , $out } } $null } |