packages feed

graphql-spice-1.0.6.0: src/Language/GraphQL/TH.hs

{- 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/. -}

module Language.GraphQL.TH
    ( gql
    ) where

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

stripIndentation :: String -> String
stripIndentation code = reverse
    $ dropWhile isLineBreak
    $ reverse
    $ unlines
    $ indent spaces <$> lines' withoutLeadingNewlines
  where
    indent 0 xs = xs
    indent count (' ' : xs) = indent (count - 1) xs
    indent _ xs = xs
    withoutLeadingNewlines = dropWhile isLineBreak code
    spaces = length $ takeWhile (== ' ') withoutLeadingNewlines
    lines' "" = []
    lines' string =
        let (line, rest) = break isLineBreak string
            reminder =
                case rest of
                    [] -> []
                    '\r' : '\n' : strippedString -> lines' strippedString
                    _ : strippedString -> lines' strippedString
         in line : reminder
    isLineBreak = flip any ['\n', '\r'] . (==)

-- | Removes leading and trailing newlines. Indentation of the first line is
-- removed from each line of the string.
gql :: QuasiQuoter
gql = QuasiQuoter
    { quoteExp = pure . LitE . StringL . stripIndentation
    , quotePat = const
        $ fail "Illegal gql QuasiQuote (allowed as expression only, used as a pattern)"
    , quoteType = const
        $ fail "Illegal gql QuasiQuote (allowed as expression only, used as a type)"
    , quoteDec = const
        $ fail "Illegal gql QuasiQuote (allowed as expression only, used as a declaration)"
    }