Pretty Printed JavaScript Objects

I decided to focus this question on JSON and wl-pprint-annotated objects ( here is the paper behind this library ), because they simplify working with MVCE, but my problem is not really related to pretty-printed JSON objects, and I'm flexible For what a pretty-printed library I use.


Consider the following simplified JavaScript object data type:

data Object = Object [(String, Object)]
            | String String

How can I define a pretty print function that wraps its output on multiple lines in the usual way? What I mean: the printed output should, if possible, correspond to one line. When this is not possible, I expect external objects to start adding new lines before internal ones.

Here is one attempt to use wl-pprint-annotated :

{-# LANGUAGE OverloadedString #-}
import Text.PrettyPrint.Annotated.WL

prettyObject :: Object -> Doc a 
prettyObject (String str) = "\"" <> text str <> "\""
prettyObject (Object fields) = Union ("{" <+> hsep fields' <+> "}")
                                     ("{" <#> indent 2 (vsep fields') <#> "}")

   where
     fields' :: [Doc a]
     fields' = punctuate "," [ text key <> ":" <+> prettyObject val
                             | (key,val) <- fields ]

Now, some test cases.

ghci> o1 = Object [("key1", String "val1")]
ghci> o2 = Object [("key2", String "val2"), ("looooooooooong key3", String "loooooooooooong val3"),("key4", String "val4")]
ghci> o3 = Object [("key5", String "val5"), ("key6", o2), ("key7", String "val7")]
ghci> prettyObject o1
{ key1: "val1" }
ghci> prettyObject o2
{
  key2: "val2",
  looooooooooong key3: "loooooooooooong val3",
  key4: "val4"
}
ghci> prettyObject o3
{ key5: { key1: "val1" }, key6: {
  key2: "val2",
  looooooooooong key3: "loooooooooooong val3",
  key4: "val4"
}, key7: "val7" }

I would like the last conclusion to be

{
  key5: { key1: "val1" },
  key6: {
    key2: "val2",
    looooooooooong key3: "loooooooooooong val3",
    key4: "val4"
  },
  key7: "val7"
}

I am looking for a solution that somehow fits into one of Haskell's existing pretty printed libraries (in fact, I pretty much print much more than just a subset of JSON).

I'm not looking for a solution that determines prettyObject :: Object -> String- the whole point of this approach is that the rendering Docdepends on where it is in the big picture of what is being printed.

+4
source share
1 answer

, , ; ( , !) (WL) .

Union:

prettyObject (Object fields) = Union <one line> <many line>

, , , Union Doc. , {..}; , , :

{ key5: { key1: "val1" }, key6: { ----- line break here
  key2: "val2",

-:

indent' k x = flatAlt (indent k x) (flatten x) 
prettyKVPair (k,v) = indent' 2 $ text k <> ":" <+> pretty v

indent' indent, , . flatAlt , , , (, , ) flatten. prettyObject :

prettyObject :: Object -> Doc a 
prettyObject (Object fields) = sep $ "{" : fields' ++ [ "}" ] where 
  fields' = punctuate "," $ map prettyKVPair fields
...

, Union, sep = group . vsep group = \x -> Union (flatten x) x. , , .

:

>pretty o1
{ key1: "val1" }
>pretty o2
{
  key2: "val2",
  looooooooooong key3: "loooooooooooong val3",
  key4: "val4"
}
>pretty o3
{
  key5: "val5",
  key6: {
    key2: "val2",
    looooooooooong key3: "loooooooooooong val3",
    key4: "val4"
  },
  key7: "val7"
}

, - flatAlt, ! , () , , Doc. Data.Sequence Traversable, "list-like", punctuate, , .

flattenedOf a b = flatAlt a (flatten b) # useful combinator

trailingSep _ [] = [] 
trailingSep s xs = as ++ [ (a <> s) `flattenedOf` a ]
  where as = init xs; a = last xs 

...
prettyObject (Object fields) = <unchanged> where 
  fields' = trailingSep "," $ <unchanged>
+3

Source: https://habr.com/ru/post/1674865/


All Articles