mirror of
https://github.com/hasura/graphql-engine.git
synced 2024-12-19 21:41:44 +03:00
a7195155ab
dupe of @chrisdone's work https://github.com/hasura/graphql-engine-mono/pull/2852 with a branch rename prev pr: https://github.com/hasura/graphql-engine-mono/pull/2901 next PR: https://github.com/hasura/graphql-engine-mono/pull/2921 PR-URL: https://github.com/hasura/graphql-engine-mono/pull/2911 Co-authored-by: Chris Done <11019+chrisdone@users.noreply.github.com> GitOrigin-RevId: 81130e100c220a235d9869c89e90d63515e35f74
122 lines
3.4 KiB
Haskell
122 lines
3.4 KiB
Haskell
{-# LANGUAGE LambdaCase #-}
|
|
{-# LANGUAGE NamedFieldPuns #-}
|
|
{-# LANGUAGE ScopedTypeVariables #-}
|
|
{-# OPTIONS_GHC -fno-warn-orphans #-}
|
|
|
|
-- | Templating yaml files.
|
|
module Harness.Yaml
|
|
( yaml,
|
|
shouldReturnYaml,
|
|
)
|
|
where
|
|
|
|
import Control.Exception
|
|
import Control.Monad.Reader
|
|
import Control.Monad.Trans.Resource
|
|
import Data.Aeson
|
|
import Data.Aeson qualified as Aeson
|
|
import Data.ByteString.Char8 qualified as BS8
|
|
import Data.Conduit
|
|
import Data.Conduit.List qualified as CL
|
|
import Data.Text.Encoding.Error qualified as T
|
|
import Data.Yaml qualified
|
|
import Data.Yaml.Internal qualified
|
|
import Instances.TH.Lift ()
|
|
import Language.Haskell.TH
|
|
import Language.Haskell.TH.Lift as TH
|
|
import Language.Haskell.TH.Quote
|
|
import System.IO.Unsafe
|
|
import Test.Hspec (shouldBe)
|
|
import Text.Libyaml qualified as Libyaml
|
|
import Prelude
|
|
|
|
-- | Exceptions that will be thrown mercilessly.
|
|
data YamlTemplateException
|
|
= AnchorsAreDisabled
|
|
| YamlEncodingProblem T.UnicodeException
|
|
deriving stock (Show)
|
|
|
|
instance Exception YamlTemplateException
|
|
|
|
deriving instance Lift Libyaml.Event
|
|
|
|
deriving instance Lift Libyaml.Style
|
|
|
|
deriving instance Lift Libyaml.Tag
|
|
|
|
deriving instance Lift Libyaml.SequenceStyle
|
|
|
|
deriving instance Lift Libyaml.MappingStyle
|
|
|
|
-- | For the test suite: diff structural, but display in a readable
|
|
-- way.
|
|
newtype Visual = Visual {unVisual :: Value}
|
|
deriving (Eq)
|
|
|
|
instance Show Visual where
|
|
show = BS8.unpack . Data.Yaml.encode . unVisual
|
|
|
|
-- | The action @actualIO@ should produce the @expected@ YAML,
|
|
-- represented (by the yaml package) as an aeson 'Value'.
|
|
--
|
|
-- We use 'Visual' internally to easily display the 'Value' as YAML
|
|
-- when the test suite uses its 'Show' instance.
|
|
shouldReturnYaml :: IO Value -> Value -> IO ()
|
|
shouldReturnYaml actualIO expected = do
|
|
actual <- actualIO
|
|
shouldBe (Visual actual) (Visual expected)
|
|
|
|
yaml :: QuasiQuoter
|
|
yaml =
|
|
QuasiQuoter
|
|
{ quoteExp = templateYaml,
|
|
quotePat = \_ -> fail "invalid",
|
|
quoteType = \_ -> fail "invalid",
|
|
quoteDec = \_ -> fail "invalid"
|
|
}
|
|
|
|
-- | Template a YAML file contents. Throws a bunch of exception types:
|
|
-- 'YamlTemplateException' or 'YamlException' or 'ParseException'.
|
|
--
|
|
-- Produces 'Value'.
|
|
templateYaml :: String -> Q Exp
|
|
templateYaml inputString = do
|
|
events <-
|
|
runIO
|
|
( runConduitRes
|
|
(Libyaml.decode inputBytes .| CL.mapM processor .| CL.consume)
|
|
)
|
|
[|
|
|
unsafePerformIO
|
|
( do
|
|
bs <-
|
|
runConduitRes
|
|
(CL.sourceList (concat $(listE events)) .| Libyaml.encode)
|
|
case Data.Yaml.decodeEither' bs of
|
|
Left e -> throw e
|
|
Right (v :: Aeson.Value) -> pure v
|
|
)
|
|
|]
|
|
where
|
|
inputBytes = BS8.pack inputString
|
|
|
|
-- | Process the events as they come in, potentially expanding any
|
|
-- aliases to objects.
|
|
processor :: Libyaml.Event -> ResourceT IO (Q Exp)
|
|
processor =
|
|
\case
|
|
Libyaml.EventAlias anchorName ->
|
|
pure
|
|
[|
|
|
Data.Yaml.Internal.objToEvents
|
|
Data.Yaml.Internal.defaultStringStyle
|
|
(Data.Aeson.toJSON $(varE (mkName anchorName)))
|
|
[]
|
|
|]
|
|
-- We disable anchors because aliases are used only to refer to
|
|
-- Haskell variables, not YAML anchors.
|
|
(Libyaml.EventScalar _ _ _ (Just {})) -> throwM AnchorsAreDisabled
|
|
(Libyaml.EventSequenceStart _ _ (Just {})) -> throwM AnchorsAreDisabled
|
|
(Libyaml.EventMappingStart _ _ (Just {})) -> throwM AnchorsAreDisabled
|
|
event -> pure (TH.lift [event])
|