vestigia

Detect where execution depends on secrets.
git clone git://git.ppad.tech/vestigia.git
Log | Files | Refs | README | LICENSE

Json.hs (1794B)


      1 {-# OPTIONS_HADDOCK prune #-}
      2 {-# LANGUAGE OverloadedStrings #-}
      3 
      4 -- |
      5 -- Module: Vestigia.Json
      6 -- Copyright: (c) 2026 Jared Tobin
      7 -- License: MIT
      8 -- Maintainer: Jared Tobin <jared@ppad.tech>
      9 --
     10 -- A JSON value and its encoding: enough to write a report, with
     11 -- object keys in the order given.
     12 
     13 module Vestigia.Json (
     14     Value(..)
     15   , encode
     16   ) where
     17 
     18 import Data.Char (ord)
     19 import qualified Data.Text as T
     20 import Numeric (showHex)
     21 
     22 -- | A JSON value. An object keeps its keys in the order given.
     23 data Value =
     24     Null
     25   | Bool !Bool
     26   | Number !Integer
     27   | String !T.Text
     28   | Array ![Value]
     29   | Object ![(T.Text, Value)]
     30   deriving (Eq, Show)
     31 
     32 -- | The value's encoding, indented two spaces per level.
     33 --
     34 -- >>> encode (Object [("a", Array [Number 1, Null])])
     35 -- "{\n  \"a\": [\n    1,\n    null\n  ]\n}\n"
     36 encode :: Value -> T.Text
     37 encode v = go 0 v <> "\n"
     38   where
     39     go :: Int -> Value -> T.Text
     40     go d x = case x of
     41       Null -> "null"
     42       Bool b -> if b then "true" else "false"
     43       Number n -> T.pack (show n)
     44       String s -> str s
     45       Array [] -> "[]"
     46       Array xs -> "[\n" <> T.intercalate ",\n"
     47         [ pad (d + 1) <> go (d + 1) y | y <- xs ]
     48         <> "\n" <> pad d <> "]"
     49       Object [] -> "{}"
     50       Object kvs -> "{\n" <> T.intercalate ",\n"
     51         [ pad (d + 1) <> str k <> ": " <> go (d + 1) y
     52         | (k, y) <- kvs ]
     53         <> "\n" <> pad d <> "}"
     54 
     55     pad d = T.replicate (2 * d) " "
     56 
     57 str :: T.Text -> T.Text
     58 str s = "\"" <> T.concatMap esc s <> "\""
     59   where
     60     esc c = case c of
     61       '"' -> "\\\""
     62       '\\' -> "\\\\"
     63       '\n' -> "\\n"
     64       '\r' -> "\\r"
     65       '\t' -> "\\t"
     66       _ | ord c < 0x20 ->
     67             let h = showHex (ord c) ""
     68             in T.pack ("\\u" <> replicate (4 - length h) '0' <> h)
     69         | otherwise -> T.singleton c