Skip to content
This repository was archived by the owner on Jul 19, 2025. It is now read-only.

Commit 8458e90

Browse files
committed
Add support for JSON literals
To support usages like `mkjson o=$(mkjson x=10)`
1 parent ec3e3a6 commit 8458e90

3 files changed

Lines changed: 50 additions & 13 deletions

File tree

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# mkjson
22

3-
[![Build status](https://dev.azure.com/mfussenegger/mkjson/_apis/build/status/mkjson-CI?branchName=master)](https://dev.azure.com/mfussenegger/mkjson/_build/latest?definitionId=2)
3+
[![Build status](https://dev.azure.com/mfussenegger/mkjson/_apis/build/status/mkjson%20CI?branchName=master)](https://dev.azure.com/mfussenegger/mkjson/_build/latest?definitionId=7)
44

55
`mkjson` is a CLI to generate JSON records.
66

src/Expr.hs

Lines changed: 48 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -2,22 +2,26 @@
22

33
module Expr where
44

5-
import Data.Scientific (Scientific)
6-
import Data.String (IsString (..))
7-
import Data.Text (Text)
8-
import qualified Data.Text as T
9-
import Text.Parsec (many, many1, optionMaybe, parse, sepBy,
10-
(<|>), between)
11-
import Text.Parsec.Char (char, digit, letter, noneOf, spaces)
12-
import Text.Parsec.Error (ParseError)
13-
import Text.Parsec.Text (Parser)
5+
import Data.Aeson (Value (..), decode', encode)
6+
import Data.Scientific (Scientific)
7+
import Data.String (IsString (..))
8+
import Data.Text (Text)
9+
import qualified Data.Text as T
10+
import qualified Data.Text.Lazy as TL
11+
import qualified Data.Text.Lazy.Encoding as TL
12+
import Text.Parsec (between, many, many1, optionMaybe,
13+
parse, sepBy, (<|>))
14+
import Text.Parsec.Char (char, digit, letter, noneOf, spaces)
15+
import Text.Parsec.Error (ParseError)
16+
import Text.Parsec.Text (Parser)
1417

1518
-- $setup
1619
-- >>> :set -XOverloadedStrings
1720

1821
data Expr = IntLiteral !Integer
1922
| DoubleLiteral !Scientific
2023
| StringLiteral !Text
24+
| JsonLiteral !Value
2125
| FunctionCall !Function
2226
deriving (Show, Eq)
2327

@@ -40,7 +44,33 @@ expr = literal <|> functionCall
4044

4145

4246
literal :: Parser Expr
43-
literal = number <|> stringLiteral
47+
literal = number <|> stringLiteral <|> jsonLiteral
48+
49+
50+
showExpr :: Expr -> Text
51+
showExpr (StringLiteral s) = "\"" <> s <> "\""
52+
showExpr (IntLiteral n) = T.pack . show $ n
53+
showExpr (DoubleLiteral n) = T.pack . show $ n
54+
showExpr (JsonLiteral s) = TL.toStrict . TL.decodeUtf8 $ encode s
55+
showExpr (FunctionCall _) = error "Can only convert literals to text representation"
56+
57+
58+
jsonLiteral :: Parser Expr
59+
jsonLiteral = do
60+
assignments <- between (char '{') (char '}') (assignment `sepBy` comma)
61+
let
62+
objStr = "{" <> T.intercalate ", " assignments <> "}"
63+
case decode' (TL.encodeUtf8 . TL.fromStrict $ objStr) of
64+
Nothing -> error $ "Invalid JSON string: " <> T.unpack objStr
65+
Just v -> pure $ JsonLiteral v
66+
where
67+
assignment = do
68+
key <- stringLiteral
69+
_ <- colon
70+
value <- literal
71+
pure $ showExpr key <> ": " <> showExpr value
72+
colon = char ':' >> spaces
73+
comma = char ',' >> spaces
4474

4575

4676
number :: Parser Expr
@@ -59,8 +89,8 @@ number = do
5989
stringLiteral :: Parser Expr
6090
stringLiteral = StringLiteral . T.pack <$> string
6191
where
62-
singleQuote = char '\''
63-
string = between singleQuote singleQuote (many (noneOf "\'"))
92+
quote = char '\'' <|> char '"'
93+
string = between quote quote (many (noneOf "\'\""))
6494

6595

6696
functionCall :: Parser Expr
@@ -106,5 +136,11 @@ ident = do
106136
--
107137
-- >>> parseExpr "''"
108138
-- Right (StringLiteral "")
139+
--
140+
-- >>> parseExpr "{}"
141+
-- Right (JsonLiteral (Object (fromList [])))
142+
--
143+
-- >>> parseExpr "{\"x\": 10, \"y\": {}}"
144+
-- Right (JsonLiteral (Object (fromList [("x",Number 10.0),("y",Object (fromList []))])))
109145
parseExpr :: Text -> Either ParseError Expr
110146
parseExpr = parse expr "(unknown)"

src/Fake.hs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -354,6 +354,7 @@ eval :: Expr -> Fake Value
354354
eval (IntLiteral x) = pure $ Number $ fromInteger x
355355
eval (StringLiteral x) = pure $ String x
356356
eval (DoubleLiteral x) = pure $ Number x
357+
eval (JsonLiteral s) = pure $ s
357358
eval (FunctionCall (Function "uuid4" [])) = String . UUID.toText <$> State.state random
358359
eval (FunctionCall (Function "uuid1" [])) = String . UUID.toText <$> liftIO uuid1
359360
eval (FunctionCall (Function "ulid" [])) = getUlid

0 commit comments

Comments
 (0)