Private/ConvertTo-AACJsonMarkup.ps1
|
function ConvertTo-AACJsonMarkup { <# .SYNOPSIS Colours JSON text as Spectre.Console markup: property names, strings, numbers, true/false and null each in their own colour, the punctuation grey. .DESCRIPTION names deepskyblue1 "location": strings darkseagreen2 "westeurope" numbers mediumpurple2 42 booleans gold1 true null grey50 italic null { } [ ] , grey50 The text is tokenised, not parsed, so it keeps its own layout; everything is escaped, so a '[' inside a value stays text. #> [CmdletBinding()] [OutputType([string])] param( [Parameter(Mandatory)] [AllowEmptyString()] [string] $Json ) $escape = { param($Text) [Spectre.Console.Markup]::Escape([string]$Text) } $pattern = '(?<string>"(?:\\.|[^"\\])*")(?<colon>\s*:)?|(?<number>-?\d+(?:\.\d+)?(?:[eE][+-]?\d+)?)|(?<bool>\btrue\b|\bfalse\b)|(?<null>\bnull\b)|(?<punct>[{}\[\],])' $out = [System.Text.StringBuilder]::new() $at = 0 foreach ($m in [regex]::Matches($Json, $pattern)) { if ($m.Index -gt $at) { $null = $out.Append((& $escape $Json.Substring($at, $m.Index - $at))) } if ($m.Groups['string'].Success) { $color = if ($m.Groups['colon'].Success) { 'deepskyblue1' } else { 'darkseagreen2' } $null = $out.Append("[$color]$(& $escape $m.Groups['string'].Value)[/]") if ($m.Groups['colon'].Success) { $null = $out.Append("[grey50]$(& $escape $m.Groups['colon'].Value)[/]") } } elseif ($m.Groups['number'].Success) { $null = $out.Append("[mediumpurple2]$($m.Value)[/]") } elseif ($m.Groups['bool'].Success) { $null = $out.Append("[gold1]$($m.Value)[/]") } elseif ($m.Groups['null'].Success) { $null = $out.Append('[grey50 italic]null[/]') } else { $null = $out.Append("[grey50]$(& $escape $m.Value)[/]") } $at = $m.Index + $m.Length } if ($at -lt $Json.Length) { $null = $out.Append((& $escape $Json.Substring($at))) } $out.ToString() } |