{- This Source Code Form is subject to the terms of the Mozilla Public License,
   v. 2.0. If a copy of the MPL was not distributed with this file, You can
   obtain one at https://mozilla.org/MPL/2.0/. -}

-- | Template Haskell helpers.
module Language.GraphQL.TH
    ( gql
    ) where

import Language.Haskell.TH.Quote (QuasiQuoter(..))
import Language.Haskell.TH (Exp(..), Lit(..))

stripIndentation :: String -> String
stripIndentation :: String -> String
stripIndentation String
code = forall a. [a] -> [a]
reverse
    forall a b. (a -> b) -> a -> b
$ String -> String
dropNewlines
    forall a b. (a -> b) -> a -> b
$ forall a. [a] -> [a]
reverse
    forall a b. (a -> b) -> a -> b
$ [String] -> String
unlines
    forall a b. (a -> b) -> a -> b
$ forall {t}. (Eq t, Num t) => t -> String -> String
indent Int
spaces forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> String -> [String]
lines String
withoutLeadingNewlines
  where
    indent :: t -> String -> String
indent t
0 String
xs = String
xs
    indent t
count (Char
' ' : String
xs) = t -> String -> String
indent (t
count forall a. Num a => a -> a -> a
- t
1) String
xs
    indent t
_ String
xs = String
xs
    withoutLeadingNewlines :: String
withoutLeadingNewlines = String -> String
dropNewlines String
code
    dropNewlines :: String -> String
dropNewlines = forall a. (a -> Bool) -> [a] -> [a]
dropWhile (forall a. Eq a => a -> a -> Bool
== Char
'\n')
    spaces :: Int
spaces = forall (t :: * -> *) a. Foldable t => t a -> Int
length forall a b. (a -> b) -> a -> b
$ forall a. (a -> Bool) -> [a] -> [a]
takeWhile (forall a. Eq a => a -> a -> Bool
== Char
' ') String
withoutLeadingNewlines

-- | Removes leading and trailing newlines. Indentation of the first line is
-- removed from each line of the string.
gql :: QuasiQuoter
gql :: QuasiQuoter
gql = QuasiQuoter
    { quoteExp :: String -> Q Exp
quoteExp = forall (f :: * -> *) a. Applicative f => a -> f a
pure forall b c a. (b -> c) -> (a -> b) -> a -> c
. Lit -> Exp
LitE forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> Lit
StringL forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> String
stripIndentation
    , quotePat :: String -> Q Pat
quotePat = forall a b. a -> b -> a
const
        forall a b. (a -> b) -> a -> b
$ forall (m :: * -> *) a. MonadFail m => String -> m a
fail String
"Illegal gql QuasiQuote (allowed as expression only, used as a pattern)"
    , quoteType :: String -> Q Type
quoteType = forall a b. a -> b -> a
const
        forall a b. (a -> b) -> a -> b
$ forall (m :: * -> *) a. MonadFail m => String -> m a
fail String
"Illegal gql QuasiQuote (allowed as expression only, used as a type)"
    , quoteDec :: String -> Q [Dec]
quoteDec = forall a b. a -> b -> a
const
        forall a b. (a -> b) -> a -> b
$ forall (m :: * -> *) a. MonadFail m => String -> m a
fail String
"Illegal gql QuasiQuote (allowed as expression only, used as a declaration)"
    }