packages feed

network-uri-template-0.1.0.0: src/Network/URI/Template/VarValue.hs

-- |
--
-- Module      : Network.URI.Template.VarValue
-- Copyright   : (c) 2025 Patrick Brisbin
-- License     : AGPL-3
-- Maintainer  : pbrisbin@gmail.com
-- Stability   : experimental
-- Portability : POSIX
module Network.URI.Template.VarValue
  ( VarValue (..)
  , varValueP
  , varValuePretty
  ) where

import Prelude

import Data.String (IsString (..))
import Data.Text (Text, pack)
import Network.URI.Template.Internal.Parse
import Network.URI.Template.Internal.Pretty

data VarValue
  = VarNull
  | VarValue Text
  | VarList [Text]
  | VarMap [(Text, Text)]
  deriving stock (Show)

instance IsString VarValue where
  fromString = VarValue . pack

varValueP :: Parser VarValue
varValueP =
  choice
    [ varMapP <?> "map variable value"
    , varListP <?> "list variable value"
    , varStringP <?> "string variable value"
    , varNumberP <?> "numeric variable value"
    , varNullP <?> "null variable value"
    ]

varMapP :: Parser VarValue
varMapP = VarMap <$> csvP '[' ']' kvP

kvP :: Parser (Text, Text)
kvP =
  (,)
    <$> (char '(' *> hspace *> quoted <* commaP)
    <*> (quoted <* hspace <* char ')')

varListP :: Parser VarValue
varListP = VarList <$> csvP '(' ')' quoted

varStringP :: Parser VarValue
varStringP = VarValue <$> quoted

varNumberP :: Parser VarValue
varNumberP = VarValue . pack <$> some digitChar

varNullP :: Parser VarValue
varNullP = VarNull <$ string "null"

csvP :: Char -> Char -> Parser a -> Parser [a]
csvP l r p = char l *> hspace *> sepBy p commaP <* hspace <* char r

commaP :: Parser Char
commaP = try (hspace *> char ',' <* hspace) <?> "comma"

varValuePretty :: VarValue -> Doc Ann
varValuePretty = \case
  VarNull -> annotate AnnVarName "null"
  VarValue t -> stPretty t
  VarList ts -> csvPretty "(" ")" $ map stPretty ts
  VarMap kvs -> csvPretty "[" "]" $ map (uncurry kvPretty) kvs

csvPretty :: Text -> Text -> [Doc Ann] -> Doc Ann
csvPretty l r ds =
  hcat
    [ annotate AnnPunctuation $ pretty l
    , hsep $ punctuate (annotate AnnPunctuation comma) ds
    , annotate AnnPunctuation $ pretty r
    ]

stPretty :: Text -> Doc Ann
stPretty t =
  hcat
    [ annotate AnnPunctuation "\""
    , annotate AnnString $ pretty t
    , annotate AnnPunctuation "\""
    ]

kvPretty :: Text -> Text -> Doc Ann
kvPretty k v =
  hcat
    [ annotate AnnPunctuation "("
    , annotate AnnVarName (pretty k)
    , annotate AnnPunctuation ","
    , stPretty v
    , annotate AnnPunctuation ")"
    ]