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 +53/−0
- IHP/HSX/HsExpToTH.hs +201/−0
- IHP/HSX/Parser.hs +47/−63
- IHP/HSX/QQ.hs +2/−3
- ihp-hsx.cabal +10/−7
+ 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