aboutsummaryrefslogtreecommitdiffstats
path: root/app/Issue/Parser.hs
diff options
context:
space:
mode:
Diffstat (limited to 'app/Issue/Parser.hs')
-rw-r--r--app/Issue/Parser.hs61
1 files changed, 61 insertions, 0 deletions
diff --git a/app/Issue/Parser.hs b/app/Issue/Parser.hs
new file mode 100644
index 0000000..b7cfa4b
--- /dev/null
+++ b/app/Issue/Parser.hs
@@ -0,0 +1,61 @@
+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