packages feed

lasercutter-0.1.0.0: bench/HTML.hs

{-# LANGUAGE StrictData      #-}
{-# OPTIONS_GHC -Wno-orphans #-}

module HTML where

import Control.Monad (join)
import Data.Bool (bool)
import Data.Foldable (traverse_)
import Data.Set (Set)
import Data.Text (Text)
import Lasercutter
import Text.HTML.TagSoup (Tag(TagText, TagOpen))
import Text.HTML.TagSoup.Tree


type HTML = TagTree Text

data Selector
  = Both Selector Selector
  | Alt Selector Selector
  | Negate Selector
  | HasTag Text
  | WithAttr Text (Maybe Text -> Bool)

matchSelector :: Selector -> TagTree Text -> Bool
matchSelector (Both se1 se2) tt                             = matchSelector se1 tt && matchSelector se2 tt
matchSelector (Alt se1 se2)  tt                             = matchSelector se1 tt || matchSelector se2 tt
matchSelector (Negate se)    tt                             = not $ matchSelector se tt
matchSelector (HasTag txt)  (TagBranch txt' _ _)            = txt == txt'
matchSelector (HasTag txt)  (TagLeaf (TagOpen txt' _))      = txt == txt'
matchSelector (HasTag _)    (TagLeaf _)                     = False
matchSelector (WithAttr txt f) (TagBranch _ x0 _)           = f $ lookup txt x0
matchSelector (WithAttr txt f)  (TagLeaf (TagOpen _ attrs)) = f $ lookup txt attrs
matchSelector (WithAttr _ _)   (TagLeaf _)                  = False

instance IsTree (TagTree t) where
  getChildren (TagBranch _ _ tts) = tts
  getChildren (TagLeaf _) = []

at :: Text -> Parser bc (TagTree Text) a -> Parser bc (TagTree Text) a
at t p
  = expect
  $ bool
      <$> pure Nothing
      <*> fmap Just p
      <*> proj (matchSelector $ HasTag t)

textOf :: TagTree a -> Maybe a
textOf = \case
  TagLeaf (TagText txt) -> Just txt
  _ -> Nothing

text :: Parser bc (TagTree a) (Maybe a)
text = proj textOf

getText :: Parser bc (TagTree Text) Text
getText = expect text

example :: TagTree Text
example =
  TagBranch "html" [("lang", "en")]
    [ TagBranch "head" []
      [ TagBranch "title" [] [ TagLeaf $ TagText "Hello World!" ]
      , TagBranch "style" [("type", "text/css")]
          [ TagLeaf $ TagText "css"
          ]
      ]
    , TagBranch "body" []
      [ TagBranch "h1" [] [ TagLeaf $ TagText "Hi" ]
      , TagBranch "p" [("id", "lorem")] [ TagLeaf $ TagText "lorem ipsum" ]
      , TagBranch "p" []
          [ TagLeaf $ TagText "more p"
          , TagBranch "b" []
              [ TagLeaf $ TagText "bold"
              ]
          , TagLeaf $ TagText "done"
          ]
      , TagBranch "script" []
          [ TagLeaf $ TagText "dont want no scripts"
          ]
      ]
    ]

chroot :: Selector -> Parser bc HTML a -> Parser bc HTML a
chroot s = one . chroots s


chroots :: Selector -> Parser bc HTML a -> Parser bc HTML [a]
chroots = target . matchSelector


texts :: Parser bc HTML [Text]
texts = targetMap textOf


texts' :: Selector -> Parser bc HTML [Text]
texts' sel =
  fmap (catMaybes . join) $ target (matchSelector sel) $ onChildren text

isText :: HTML -> Bool
isText (TagLeaf (TagText _)) = True
isText _ = False


textNoScript :: Parser (Set Text) HTML [Text]
textNoScript =
  asum
    [ at "h1" texts
    , at "p" texts
    , at "b" texts
    ]


getTag :: HTML -> [Text]
getTag (TagBranch txt _ _) = pure txt
getTag (TagLeaf (TagOpen txt _)) = pure txt
getTag _ = mempty


main :: IO ()
main = traverse_ (traverse_ print) $ runParser getTag example
  $ fmap catMaybes
  $ target isText
  $ bool
      <$> text
      <*> pure Nothing
      <*> fmap ((`elem` ["script", "style"]) . head) breadcrumbs