module Issue.Parser ( ParseResult (..), parse, ) where import CMark qualified as D import Control.Exception (throw) import Control.Monad (liftM2) import Data.Text qualified as T import Data.Void (Void) import Exception qualified as E import Text.Megaparsec qualified as P data ParseResult = ParseResult { heading :: D.Node, paragraphs :: [D.Node], tags :: [D.Node], comments :: [[D.Node]] } deriving (Show) parse :: [T.Text] -> D.Node -> Maybe ParseResult parse markers (D.Node _ D.DOCUMENT ns) = either (throw . E.InvalidIssue) id $ P.parse (parser markers) "" ns parse _ _ = error "parse: input is no markdown document" parser :: [T.Text] -> P.Parsec Void [D.Node] (Maybe ParseResult) parser markers = P.optional (P.satisfy (isMarkerNode markers)) >>= \case Just heading -> Just <$> ( ParseResult heading <$> P.takeWhileP Nothing (not . liftM2 (||) isCommentNode isTagNode) <*> P.takeWhileP Nothing isTagNode <*> P.many ( (:) <$> P.satisfy isCommentNode <*> P.takeWhileP Nothing (not . isCommentNode) ) <* P.eof ) Nothing -> pure Nothing isCommentNode :: D.Node -> Bool isCommentNode (D.Node _ D.PARAGRAPH (D.Node _ (D.TEXT s) _ : _)) = "COMMENT" `T.isPrefixOf` s isCommentNode _ = False isTagNode :: D.Node -> Bool isTagNode (D.Node _ D.PARAGRAPH (D.Node _ (D.TEXT s) _ : _)) = "@" `T.isPrefixOf` s isTagNode _ = False isMarkerNode :: [T.Text] -> D.Node -> Bool isMarkerNode markers (D.Node _ D.PARAGRAPH (D.Node _ (D.TEXT s) _ : _)) = any (`T.isPrefixOf` s) markers isMarkerNode _ _ = False