packages feed

ihp-hsx 0.18.0 → 0.20.0

raw patch · 5 files changed

+313/−73 lines, 5 filesdep +ghcdep −haskell-src-metadep ~basedep ~bytestringdep ~megaparsecPVP ok

version bump matches the API change (PVP)

Dependencies added: ghc

Dependencies removed: haskell-src-meta

Dependency ranges changed: base, bytestring, megaparsec, template-haskell, text

API changes (from Hackage documentation)

+ IHP.HSX.HaskellParser: parseHaskellExpression :: SourcePos -> [Extension] -> String -> Either (Int, Int, String) Exp
+ IHP.HSX.HsExpToTH: toExp :: HsExpr GhcPs -> Exp
- IHP.HSX.Parser: parseHsx :: SourcePos -> Text -> Either (ParseErrorBundle Text Void) Node
+ IHP.HSX.Parser: parseHsx :: SourcePos -> [Extension] -> Text -> Either (ParseErrorBundle Text Void) Node

Files

+ IHP/HSX/HaskellParser.hs view
@@ -0,0 +1,53 @@+module IHP.HSX.HaskellParser (parseHaskellExpression) where++import Prelude+import GHC.Parser.Lexer (ParseResult (..), PState (..))+import qualified GHC.Parser.Errors.Ppr as ParserErrorPpr+import GHC.Types.SrcLoc+import qualified GHC.Parser as Parser+import qualified GHC.Parser.Lexer as Lexer+import GHC.Data.FastString+import GHC.Data.StringBuffer+import GHC.Parser.PostProcess+import Text.Megaparsec.Pos+import qualified "template-haskell" Language.Haskell.TH as TH++import qualified GHC.Data.EnumSet as EnumSet+import GHC+import IHP.HSX.HsExpToTH (toExp)++parseHaskellExpression :: SourcePos -> [TH.Extension] -> String -> Either (Int, Int, String) TH.Exp+parseHaskellExpression sourcePos extensions input =+        case expr of+            POk parserState result -> Right (toExp (unLoc result))+            PFailed parserState ->+                let+                    error = concatMap (show . ParserErrorPpr.pprError) (parserState.errors)+                    realLoc = (psRealLoc parserState.loc)+                    line = srcLocLine realLoc+                    col = srcLocCol realLoc+                in+                    Left (line, col, error)+    where+        expr :: ParseResult (LocatedA (HsExpr GhcPs))+        expr = case Lexer.unP Parser.parseExpression parseState of+                POk parserState result -> Lexer.unP (runPV (unECP result)) parserState+                PFailed parserState -> PFailed parserState++        location :: RealSrcLoc+        location = mkRealSrcLoc filename line col+        +        filename :: FastString+        filename = mkFastString sourcePos.sourceName++        line :: Int+        line = unPos sourcePos.sourceLine++        col :: Int+        col = unPos sourcePos.sourceColumn++        buffer = stringToStringBuffer input+        parseState = Lexer.initParserState parserOpts buffer location++        parserOpts :: Lexer.ParserOpts+        parserOpts = Lexer.mkParserOpts EnumSet.empty (EnumSet.fromList extensions) False False False False
+ IHP/HSX/HsExpToTH.hs view
@@ -0,0 +1,201 @@+{-# LANGUAGE ViewPatterns #-}+{-|+Module: IHP.HSX.HsExpToTH+Copyright: (c) digitally induced GmbH, 2022+Description: Converts Haskell AST to Template Haskell AST++Based on https://github.com/guibou/PyF/blob/b3aaee12d34380e55aa3909690041eccb8fcf001/src/PyF/Internal/Meta.hs+-}+module IHP.HSX.HsExpToTH (toExp) where++import Prelude++import GHC.Hs.Expr as Expr+import GHC.Hs.Extension as Ext+import GHC.Hs.Pat as Pat+import GHC.Hs.Lit+import qualified Data.ByteString as B+import qualified Language.Haskell.TH.Syntax as TH+import GHC.Types.SrcLoc+import GHC.Types.Name+import GHC.Types.Name.Reader+import GHC.Data.FastString+import GHC.Utils.Outputable (Outputable, ppr, showSDocUnsafe)+import GHC.Types.Basic (Boxity(..))+import GHC.Types.SourceText (il_value, rationalFromFractionalLit)+import qualified GHC.Unit.Module as Module+import GHC.Stack+import qualified Data.List.NonEmpty as NonEmpty+import Language.Haskell.Syntax.Type++fl_value = rationalFromFractionalLit++toLit :: HsLit GhcPs -> TH.Lit+toLit (HsChar _ c) = TH.CharL c+toLit (HsCharPrim _ c) = TH.CharPrimL c+toLit (HsString _ s) = TH.StringL (unpackFS s)+toLit (HsStringPrim _ s) = TH.StringPrimL (B.unpack s)+toLit (HsInt _ i) = TH.IntegerL (il_value i)+toLit (HsIntPrim _ i) = TH.IntPrimL i+toLit (HsWordPrim _ i) = TH.WordPrimL i+toLit (HsInt64Prim _ i) = TH.IntegerL i+toLit (HsWord64Prim _ i) = TH.WordPrimL i+toLit (HsInteger _ i _) = TH.IntegerL i+toLit (HsRat _ f _) = TH.FloatPrimL (fl_value f)+toLit (HsFloatPrim _ f) = TH.FloatPrimL (fl_value f)+toLit (HsDoublePrim _ f) = TH.DoublePrimL (fl_value f)++toLit' :: OverLitVal -> TH.Lit+toLit' (HsIntegral i) = TH.IntegerL (il_value i)+toLit' (HsFractional f) = TH.RationalL (fl_value f)+toLit' (HsIsString _ fs) = TH.StringL (unpackFS fs)++toType :: HsType GhcPs -> TH.Type+toType (HsWildCardTy _) = TH.WildCardT+toType (HsTyVar _ _ n) =+  let n' = unLoc n+   in if isRdrTyVar n'+        then TH.VarT (toName n')+        else TH.ConT (toName n')+toType t = todo "toType" t++toName :: RdrName -> TH.Name+toName n = case n of+  (Unqual o) -> TH.mkName (occNameString o)+  (Qual m o) -> TH.mkName (Module.moduleNameString m <> "." <> occNameString o)+  (Orig _ _) -> error "orig"+  (Exact _) -> error "exact"++toFieldExp :: a+toFieldExp = undefined++toPat :: Pat.Pat GhcPs -> TH.Pat+toPat (Pat.VarPat _ (unLoc -> name)) = TH.VarP (toName name)+toPat (TuplePat _ p _) = TH.TupP (map (toPat . unLoc) p)+toPat p = todo "toPat" p++toExp :: Expr.HsExpr GhcPs -> TH.Exp+toExp (Expr.HsVar _ n) =+  let n' = unLoc n+   in if isRdrDataCon n'+        then TH.ConE (toName n')+        else TH.VarE (toName n')++toExp (Expr.HsUnboundVar _ n)              = TH.UnboundVarE (TH.mkName . occNameString $ n)++toExp Expr.HsIPVar {}+  = noTH "toExp" "HsIPVar"++toExp (Expr.HsLit _ l)+  = TH.LitE (toLit l)++toExp (Expr.HsOverLit _ OverLit {ol_val})+  = TH.LitE (toLit' ol_val)++toExp (Expr.HsApp _ e1 e2)+  = TH.AppE (toExp . unLoc $ e1) (toExp . unLoc $ e2)++toExp (Expr.HsAppType _ e HsWC {hswc_body}) = TH.AppTypeE (toExp . unLoc $ e) (toType . unLoc $ hswc_body)+toExp (Expr.ExprWithTySig _ e HsWC{hswc_body=unLoc -> HsSig{sig_body}}) = TH.SigE (toExp . unLoc $ e) (toType . unLoc $ sig_body)++toExp (Expr.OpApp _ e1 o e2)+  = TH.UInfixE (toExp . unLoc $ e1) (toExp . unLoc $ o) (toExp . unLoc $ e2)++toExp (Expr.NegApp _ e _)+  = TH.AppE (TH.VarE 'negate) (toExp . unLoc $ e)++-- NOTE: for lambda, there is only one match+toExp (Expr.HsLam _ (Expr.MG _ (unLoc -> (map unLoc -> [Expr.Match _ _ (map unLoc -> ps) (Expr.GRHSs _ [unLoc -> Expr.GRHS _ _ (unLoc -> e)] _)])) _))+  = TH.LamE (fmap toPat ps) (toExp e)++-- toExp (Expr.Let _ bs e)                       = TH.LetE (toDecs bs) (toExp e)+--+toExp (Expr.HsIf _ a b c)                   = TH.CondE (toExp (unLoc a)) (toExp (unLoc b)) (toExp (unLoc c))++-- toExp (Expr.MultiIf _ ifs)                    = TH.MultiIfE (map toGuard ifs)+-- toExp (Expr.Case _ e alts)                    = TH.CaseE (toExp e) (map toMatch alts)+-- toExp (Expr.Do _ ss)                          = TH.DoE (map toStmt ss)+-- toExp e@Expr.MDo{}                            = noTH "toExp" e+--+toExp (Expr.ExplicitTuple _ args boxity) = ctor tupArgs+  where+    toTupArg (Expr.Present _ e) = Just $ unLoc e+    toTupArg (Expr.Missing _) = Nothing+    toTupArg _ = error "impossible case"++    ctor = case boxity of+      Boxed -> TH.TupE+      Unboxed -> TH.UnboxedTupE++    tupArgs = fmap ((fmap toExp) . toTupArg) args++-- toExp (Expr.List _ xs)                        = TH.ListE (fmap toExp xs)+toExp (Expr.HsPar _ e)+  = TH.ParensE (toExp . unLoc $ e)++toExp (Expr.SectionL _ (unLoc -> a) (unLoc -> b))+  = TH.InfixE (Just . toExp $ a) (toExp b) Nothing++toExp (Expr.SectionR _ (unLoc -> a) (unLoc -> b))+  = TH.InfixE Nothing (toExp a) (Just . toExp $ b)++toExp (Expr.RecordCon _ name HsRecFields {rec_flds})+  = TH.RecConE (toName . unLoc $ name) (fmap toFieldExp rec_flds)++toExp (Expr.RecordUpd _ (unLoc -> e) xs)                 = TH.RecUpdE (toExp e) $ case xs of+    Left fields ->+        let+            f (unLoc -> x) = (name, value)+                where+                    value = toExp $ unLoc $ hsRecFieldArg x+                    name =+                        case unLoc (hsRecFieldLbl x) of+                            Unambiguous _ (unLoc -> name) -> toName name+                            Ambiguous _ (unLoc -> name) -> toName name+        in+            map f fields+    Right xs -> error "todo"+-- toExp (Expr.ListComp _ e ss)                  = TH.CompE $ map convert ss ++ [TH.NoBindS (toExp e)]+--  where+--   convert (Expr.QualStmt _ st)                = toStmt st+--   convert s                                   = noTH "toExp ListComp" s+-- toExp (Expr.ExpTypeSig _ e t)                 = TH.SigE (toExp e) (toType t)+--+toExp (Expr.ExplicitList _ (map unLoc -> args)) = TH.ListE (map toExp args)++toExp (Expr.ArithSeq _ _ e)+  = TH.ArithSeqE $ case e of+    (From a) -> TH.FromR (toExp $ unLoc a)+    (FromThen a b) -> TH.FromThenR (toExp $ unLoc a) (toExp $ unLoc b)+    (FromTo a b) -> TH.FromToR (toExp $ unLoc a) (toExp $ unLoc b)+    (FromThenTo a b c) -> TH.FromThenToR (toExp $ unLoc a) (toExp $ unLoc b) (toExp $ unLoc c)+++toExp (Expr.HsProjection _ locatedFields) =+  let+    extractFieldLabel (HsFieldLabel _ locatedStr) = locatedStr+    extractFieldLabel _ = error "Don't know how to handle XHsFieldLabel constructor..."+  in+    TH.ProjectionE (NonEmpty.map (unpackFS . unLoc . extractFieldLabel . unLoc) locatedFields)++toExp (Expr.HsGetField _ expr locatedField) =+  let+    extractFieldLabel (HsFieldLabel _ locatedStr) = locatedStr+    extractFieldLabel _ = error "Don't know how to handle XHsFieldLabel constructor..."+  in+    TH.GetFieldE (toExp (unLoc expr)) (unpackFS . unLoc . extractFieldLabel . unLoc $ locatedField)+++toExp (Expr.HsOverLabel _ fastString) = TH.LabelE (unpackFS fastString)++toExp e = todo "toExp" e+++todo :: Outputable e => String -> e -> a+todo fun thing = error . concat $ [moduleName, ".", fun, ": not implemented: ", (showSDocUnsafe $ ppr thing)]++noTH :: (HasCallStack, Show e) => String -> e -> a+noTH fun thing = error . concat $ [moduleName, ".", fun, ": no TemplateHaskell for: ", show thing]++moduleName :: String+moduleName = "IHP.HSX.HsExpToTH"
IHP/HSX/Parser.hs view
@@ -25,16 +25,14 @@ import Data.Void import qualified Data.Char as Char import qualified Data.Text as Text-import Control.Monad.Fail import Data.String.Conversions import qualified Data.List as List import Control.Monad (unless)-import Prelude (show)-import qualified Language.Haskell.Meta as Haskell-import qualified Language.Haskell.TH.Syntax as Haskell+import qualified "template-haskell" Language.Haskell.TH.Syntax as Haskell import qualified "template-haskell" Language.Haskell.TH as TH import qualified Data.Set as Set import qualified Data.Containers.ListUtils as List+import qualified IHP.HSX.HaskellParser as HaskellParser  data AttributeValue = TextValue !Text | ExpressionValue !Haskell.Exp deriving (Eq, Show) @@ -58,11 +56,15 @@ -- > let position = Megaparsec.SourcePos filePath (Megaparsec.mkPos line) (Megaparsec.mkPos col) -- > let hsxText = "<strong>Hello</strong>" -- >--- > let (Right node) = parseHsx position hsxText-parseHsx :: SourcePos -> Text -> Either (ParseErrorBundle Text Void) Node-parseHsx position code = runParser (setPosition position *> parser) "" code+-- > let (Right node) = parseHsx position [] hsxText+parseHsx :: SourcePos -> [TH.Extension] -> Text -> Either (ParseErrorBundle Text Void) Node+parseHsx position extensions code =+    let+        ?extensions = extensions+    in+        runParser (setPosition position *> parser) "" code -type Parser = Parsec Void Text+type Parser a = (?extensions :: [TH.Extension]) => Parsec Void Text a  setPosition pstateSourcePos = updateParserState (\state -> state {         statePosState = (statePosState state) { pstateSourcePos }@@ -76,12 +78,15 @@     eof     pure node +hsxElement :: Parser Node hsxElement = try hsxComment <|> try hsxSelfClosingElement <|> hsxNormalElement +manyHsxElement :: Parser Node manyHsxElement = do     children <- many hsxChild     pure (Children (stripTextNodeWhitespaces children)) +hsxSelfClosingElement :: Parser Node hsxSelfClosingElement = do     _ <- char '<'     name <- hsxElementName@@ -93,6 +98,7 @@     space     pure (Node name attributes [] isLeaf) +hsxNormalElement :: Parser Node hsxNormalElement = do     (name, attributes) <- hsxOpeningElement     let parsePreEscapedTextChildren transformText = do@@ -117,6 +123,7 @@             otherwise -> parseNormalHSXChildren     pure (Node name attributes children False) +hsxOpeningElement :: Parser (Text, [Attribute]) hsxOpeningElement = do     char '<'     name <- hsxElementName@@ -148,13 +155,24 @@  hsxSplicedAttributes :: Parser Attribute hsxSplicedAttributes = do-    name <- between (string "{...") (string "}") (takeWhile1P Nothing (\c -> c /= '}'))+    (pos, name) <- between (string "{...") (string "}") do+            pos <- getSourcePos+            code <- takeWhile1P Nothing (\c -> c /= '}')+            pure (pos, code)     space-    haskellExpression <- case Haskell.parseExp (cs name) of-            Right expression -> pure (patchExpr expression)-            Left error -> fail (show error)+    haskellExpression <- parseHaskellExpression pos (cs name)     pure (SpreadAttributes haskellExpression) +parseHaskellExpression :: SourcePos -> Text -> Parser Haskell.Exp+parseHaskellExpression sourcePos input = do+    case HaskellParser.parseHaskellExpression sourcePos ?extensions (cs input) of+        Right expression -> pure expression+        Left (line, col, error) -> do+            pos <- getSourcePos+            setPosition pos { sourceLine = mkPos line, sourceColumn = mkPos col }+            fail (show error)++hsxNodeAttribute :: Parser Attribute hsxNodeAttribute = do     key <- hsxAttributeName     space@@ -195,7 +213,7 @@             || "hx-" `Text.isPrefixOf` name             || name `Set.member` attributes -        rawAttribute = takeWhile1P Nothing (\c -> Char.isAlphaNum c || c == '-')+        rawAttribute = takeWhile1P Nothing (\c -> Char.isAlphaNum c || c == '-' || c == '_')   hsxQuotedValue :: Parser AttributeValue@@ -205,10 +223,11 @@  hsxSplicedValue :: Parser AttributeValue hsxSplicedValue = do-    value <- between (char '{') (char '}') (takeWhile1P Nothing (\c -> c /= '}'))-    haskellExpression <- case Haskell.parseExp (cs value) of-            Right expression -> pure (patchExpr expression)-            Left error -> fail (show error)+    (pos, value) <- between (char '{') (char '}') do+        pos <- getSourcePos+        code <- takeWhile1P Nothing (\c -> c /= '}')+        pure (pos, code)+    haskellExpression <- parseHaskellExpression pos (cs value)     pure (ExpressionValue haskellExpression)  hsxClosingElement name = (hsxClosingElement' name) <?> friendlyErrorMessage@@ -220,6 +239,7 @@             char ('>')             pure () +hsxChild :: Parser Node hsxChild = hsxElement <|> hsxSplicedNode <|> try (space >> hsxElement) <|> hsxText  -- | Parses a hsx text node@@ -236,19 +256,20 @@  hsxSplicedNode :: Parser Node hsxSplicedNode = do-        expression <- doParse-        haskellExpression <- case Haskell.parseExp (cs expression) of-                Right expression -> pure (patchExpr expression)-                Left error -> fail (show error)+        (pos, expression) <- doParse+        haskellExpression <- parseHaskellExpression pos (cs expression)         pure (SplicedNode haskellExpression)     where         doParse = do-            tree <- node+            (pos, tree) <- node             let value = (treeToString "" tree)-            pure $ Text.init $ Text.tail value+            pure (pos, Text.init $ Text.tail value) -        parseTree = node <|> leaf-        node = TokenNode <$> between (char '{') (char '}') (many parseTree)+        parseTree = (snd <$> node) <|> leaf+        node = between (char '{') (char '}') do+                pos <- getSourcePos+                tree <- many parseTree+                pure (pos, TokenNode tree)         leaf = TokenLeaf <$> takeWhile1P Nothing (\c -> c /= '{' && c /= '}')         treeToString :: Text -> TokenTree -> Text         treeToString acc (TokenLeaf value)  = acc <> value@@ -365,7 +386,7 @@         , "visibility", "word-spacing", "writing-mode", "is"         , "cellspacing", "cellpadding", "bgcolor", "classes"         , "loading"-        , "frameborder", "allow", "allowfullscreen", "nonce", "referrerpolicy"+        , "frameborder", "allow", "allowfullscreen", "nonce", "referrerpolicy", "slot"         ]  parents :: Set Text@@ -593,40 +614,3 @@         filterDuplicateSpaces' (char:rest) False | Char.isSpace char = ' ':(filterDuplicateSpaces' rest True)         filterDuplicateSpaces' (char:rest) isRemovingSpaces = char:(filterDuplicateSpaces' rest False)         filterDuplicateSpaces' [] isRemovingSpaces = []---patchExpr :: TH.Exp -> TH.Exp-patchExpr (TH.UInfixE (TH.VarE varName) (TH.VarE hash) (TH.VarE labelValue)) | hash == TH.mkName "#" = TH.AppE (TH.VarE varName) fromLabel-    where-            fromLabel = TH.AppTypeE (TH.VarE (TH.mkName "fromLabel")) (TH.LitT (TH.StrTyLit (show labelValue)))---- UInfixE (UInfixE a (VarE |>) (VarE get)) (VarE #) (VarE firstName)-patchExpr input@(TH.UInfixE (TH.UInfixE a (TH.VarE arrow) (TH.VarE get)) (TH.VarE hash) (TH.VarE labelValue)) | (hash == TH.mkName "#") && (arrow == TH.mkName "|>") && (get == TH.mkName "get") =-        (TH.UInfixE (patchExpr a) (TH.VarE arrow) (TH.AppE (TH.VarE get) fromLabel))-    where-            fromLabel = TH.AppTypeE (TH.VarE (TH.mkName "fromLabel")) (TH.LitT (TH.StrTyLit (show labelValue)))--- UInfixE (UInfixE a (VarE $) (VarE get)) (VarE #) (AppE (VarE id) (VarE checklist))-patchExpr (TH.UInfixE (TH.UInfixE a b get) (TH.VarE hash) (TH.AppE (TH.VarE labelValue) (TH.VarE d))) | (hash == TH.mkName "#") =-        TH.UInfixE (patchExpr a) (patchExpr b) (TH.AppE (TH.AppE get fromLabel) (TH.VarE d))-    where-            fromLabel = TH.AppTypeE (TH.VarE (TH.mkName "fromLabel")) (TH.LitT (TH.StrTyLit (show labelValue)))-patchExpr (TH.UInfixE (TH.VarE varName) (TH.VarE hash) (TH.AppE (TH.VarE labelValue) arg)) | hash == TH.mkName "#" = TH.AppE (TH.AppE (TH.VarE varName) fromLabel) arg-    where-            fromLabel = TH.AppTypeE (TH.VarE (TH.mkName "fromLabel")) (TH.LitT (TH.StrTyLit (show labelValue)))-patchExpr (TH.UInfixE (TH.VarE a) (TH.VarE hash) (TH.AppE (TH.VarE labelValue) (TH.VarE b))) | hash == TH.mkName "#" =-        TH.AppE (TH.AppE (TH.VarE a) fromLabel) (TH.VarE b)-    where-            fromLabel = TH.AppTypeE (TH.VarE (TH.mkName "fromLabel")) (TH.LitT (TH.StrTyLit (show labelValue)))--patchExpr (TH.UInfixE a b c) = TH.UInfixE (patchExpr a) (patchExpr b) (patchExpr c)-patchExpr (TH.ParensE e) = TH.ParensE (patchExpr e)-patchExpr (TH.RecUpdE a b) = TH.RecUpdE (patchExpr a) b-patchExpr (TH.AppE a b) = TH.AppE (patchExpr a) (patchExpr b)-patchExpr (TH.LamE a b) = TH.LamE a (patchExpr b)-patchExpr (TH.LetE a b) = TH.LetE a' (patchExpr b)-    where-        a' = List.map patchDec a-        patchDec (TH.ValD a (TH.NormalB b) c) = (TH.ValD a (TH.NormalB (patchExpr b)) c)-        patchDec a = a-patchExpr (TH.CondE a b c) = TH.CondE (patchExpr a) (patchExpr b) (patchExpr c)-patchExpr (TH.SigE a b) = TH.SigE (patchExpr a) b-patchExpr e = e
IHP/HSX/QQ.hs view
@@ -8,7 +8,6 @@ module IHP.HSX.QQ (hsx) where  import           Prelude-import qualified Data.Text as Text import Data.Text (Text) import           IHP.HSX.Parser import qualified "template-haskell" Language.Haskell.TH           as TH@@ -20,7 +19,6 @@ import Text.Blaze.Internal (attribute, MarkupM (Parent, Leaf), StaticString (..)) import Data.String.Conversions import IHP.HSX.ToHtml-import Control.Monad.Fail import qualified Text.Megaparsec as Megaparsec import qualified Text.Blaze.Html.Renderer.String as BlazeString import qualified Data.Text as Text@@ -38,7 +36,8 @@ quoteHsxExpression :: String -> TH.ExpQ quoteHsxExpression code = do         hsxPosition <- findHSXPosition-        expression <- case parseHsx hsxPosition (cs code) of+        extensions <- TH.extsEnabled+        expression <- case parseHsx hsxPosition extensions (cs code) of                 Left error   -> fail (Megaparsec.errorBundlePretty error)                 Right result -> pure result         compileToHaskell expression
ihp-hsx.cabal view
@@ -1,6 +1,6 @@ cabal-version:       2.2 name:                ihp-hsx-version:             0.18.0+version:             0.20.0 synopsis:            JSX-like but for Haskell description:         JSX-like templating syntax for Haskell license:             MIT@@ -19,15 +19,15 @@ library     default-language: Haskell2010     build-depends:-          base               >= 4.1 && <= 4.16+          base               >= 4.16.3 && < 4.17         , blaze-html         >= 0.9.1 && < 0.10-        , bytestring         >= 0.10.12 && < 0.11-        , text               >= 1.2.4 && < 1.3+        , bytestring         >= 0.11.3 && < 0.12+        , template-haskell   >= 2.18.0 && < 2.19+        , text               >= 1.2.5 && < 1.3         , containers         >= 0.6.5 && < 0.7-        , template-haskell   >= 2.16.0 && < 2.17         , blaze-markup       >= 0.8.2 && < 0.9-        , haskell-src-meta   >= 0.8.7 && < 0.9-        , megaparsec         >= 9.0.1 && < 9.1+        , ghc                >= 9.2.4 && < 9.3+        , megaparsec         >= 9.2.1 && < 9.3         , string-conversions >= 0.4.0 && < 0.5     default-extensions:         OverloadedStrings@@ -62,6 +62,7 @@         , LambdaCase         , StandaloneDeriving         , TemplateHaskell+        , OverloadedRecordDot     ghc-options:         -fstatic-argument-transformation         -funbox-strict-fields@@ -80,3 +81,5 @@         , IHP.HSX.QQ         , IHP.HSX.ToHtml         , IHP.HSX.ConvertibleStrings+        , IHP.HSX.HaskellParser+        , IHP.HSX.HsExpToTH