@@ -0,0 +1,50 @@
1+module Docs.Search.ModuleParser where
2+
3+import Prelude
4+
5+import Control.Alt ((<|>))
6+import Data.Either (hush)
7+import Data.Foldable (intercalate)
8+import Data.Maybe (Maybe)
9+import Data.Newtype (wrap)
10+import Docs.Search.Types (ModuleName)
11+import StringParser (Parser, char, choice, fix, many, manyTill, noneOf, regex, runParser, sepBy, sepBy1, string, try, whiteSpace)
12+
13+parseModuleName :: String -> Maybe ModuleName
14+parseModuleName = map wrap <<< hush <<< runParser do
15+ void $ many whiteSpaceOrComment
16+ moduleHeader
17+
18+whiteSpaceOrComment :: Parser Unit
19+whiteSpaceOrComment =
20+ choice
21+ [ try $ multiLineComment
22+ , try $ singleLineComment
23+ , try $ void whiteSpace
24+ ]
25+
26+multiLineComment :: Parser Unit
27+multiLineComment = do
28+ void $ string "{-"
29+ void $ manyTill (void $ noneOf []) (string "-}")
30+
31+singleLineComment :: Parser Unit
32+singleLineComment = do
33+ void $ string "--"
34+ void $ manyTill (void $ noneOf ['\n']) (char '\n')
35+
36+
37+moduleHeader :: Parser String
38+moduleHeader = do
39+ void $ string "module"
40+ void $ many whiteSpaceOrComment
41+ moduleName
42+
43+moduleName :: Parser String
44+moduleName = sepBy1 moduleNameWord (string ".") <#> intercalate "."
45+
46+moduleNameWord :: Parser String
47+moduleNameWord = do
48+ first <- regex "[A-Z]"
49+ rest <- regex "[a-z0-9]*"
50+ pure $ first <> rest