packages feed

scrod-0.2026.2.21: source/library/Scrod/Xml/Declaration.hs

{-# LANGUAGE TemplateHaskellQuotes #-}

module Scrod.Xml.Declaration where

import qualified Data.ByteString.Builder as Builder
import qualified Data.Text as Text
import qualified Scrod.Extra.Builder as Builder
import qualified Scrod.Extra.Semigroup as Semigroup
import qualified Scrod.Spec as Spec
import qualified Scrod.Xml.Name as Name

-- | XML Declaration (for DOCTYPE and similar), like @\<!name value>@. Similar
-- to 'Instruction' but different delimiters. Cannot contain @>@.
data Declaration = MkDeclaration
  { name :: Name.Name,
    value :: Text.Text
  }
  deriving (Eq, Ord, Show)

encode :: Declaration -> Builder.Builder
encode decl =
  Semigroup.around (Builder.stringUtf8 "<!") (Builder.charUtf8 '>') $
    Name.encode (name decl)
      <> if Text.null (value decl)
        then mempty
        else Builder.charUtf8 ' ' <> Builder.stringUtf8 (Text.unpack $ value decl)

spec :: (Applicative m, Monad n) => Spec.Spec m n -> n ()
spec s = do
  Spec.named s 'encode $ do
    Spec.it s "encodes empty value" $ do
      Spec.assertEq s (Builder.toString . encode $ MkDeclaration (Name.MkName $ Text.pack "foo") (Text.pack "")) "<!foo>"

    Spec.it s "encodes with value" $ do
      Spec.assertEq s (Builder.toString . encode $ MkDeclaration (Name.MkName $ Text.pack "foo") (Text.pack "bar")) "<!foo bar>"

    Spec.it s "encodes doctype" $ do
      Spec.assertEq s (Builder.toString . encode $ MkDeclaration (Name.MkName $ Text.pack "DOCTYPE") (Text.pack "html")) "<!DOCTYPE html>"