-
Notifications
You must be signed in to change notification settings - Fork 9
/
Copy pathHtml2Hamlet.hs
87 lines (75 loc) · 3.11 KB
/
Html2Hamlet.hs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE ViewPatterns #-}
module Main (main) where
import Control.Arrow
import Control.Monad
import Control.Monad.Trans
import qualified Data.ByteString.Lazy.Char8 as L
import Data.Char
import qualified Data.Map as Map
import Data.Maybe
import Data.Monoid
import qualified Data.Text as T
import qualified Data.Text.Lazy as TL
import Data.Version (showVersion)
import Network.HTTP.Conduit
import Options.Declarative
import System.IO
import qualified Text.HTML.DOM as HTML
import Text.PrettyPrint.Leijen.Text hiding ((<>))
import Text.Regex.TDFA
import Text.XML
import Text.XML.Cursor (child, fromDocument, node)
import Paths_html2hamlet (version)
main :: IO ()
main = run "html2hamlet" (Just $ showVersion version) cmd
cmd :: Arg "FILES/URLS..." [String]
-> Cmd "HTML to Hamlet converter" ()
cmd (get -> []) = liftIO $
writeHamlet L.getContents putDoc
cmd (get -> files) = do
logger <- getLogger
liftIO $ forM_ files $ \file -> do
if file =~ ("^https?://" :: String)
then do
writeHamlet (simpleHttp file) $ \doc -> do
let saveName = changeSuffix $ httpFileName file
logger 1 $ "Convert " ++ show file ++ " to " ++ show saveName
withFile saveName WriteMode (`hPutDoc` doc)
else do
writeHamlet (L.readFile file) $ \doc -> do
let saveName = changeSuffix file
logger 1 $ "Convert " ++ show file ++ " to " ++ show saveName
withFile saveName WriteMode (`hPutDoc` doc)
writeHamlet :: IO L.ByteString -> (Doc -> IO ()) -> IO ()
writeHamlet reader writer =
writer . convert =<< reader
httpFileName :: String -> String
httpFileName url = fromMaybe "index.html" $ do
[_, _, f, _, _, _] <- listToMaybe $ url =~ ("https?://(.*/)*([^#?]*)((#[^?]*)|(\\?[^#]*))*" :: String)
guard $ not $ null f
return f
changeSuffix :: String -> String
changeSuffix file = (++ ".hamlet") $ fromMaybe file $ do
[_, baseName] <- listToMaybe $ file =~ ("(.*)\\.html?$" :: String)
return baseName
convert :: L.ByteString -> Doc
convert = cvt . fromDocument . HTML.parseLBS where
cvt doc = "$doctype 5" <$$> go doc
go cur = fromNode (node cur) <$$> indent 4 (vsep (map go $ child cur))
fromNode :: Node -> Doc
fromNode (NodeElement (Element tag attrs _)) =
"<" <> hsep (text' (nameLocalName tag): battr attrs) <> ">"
fromNode (NodeContent t )
| T.all isSpace t = mempty
| otherwise = string $ TL.fromStrict $ T.dropWhile isSpace t
fromNode (NodeComment t ) = vsep $ map (("$# " <>) . text') $ T.lines t
fromNode (NodeInstruction _) = mempty
battr :: Map.Map Name T.Text -> [Doc]
battr = concatMap (f . first nameLocalName) . Map.toList where
f ("class", val) = map (("." <>) . text') $ T.words val
f ("id", val) = ["#" <> text' val]
f (key, val) = [text' key <> "=\"" <> text' val <> "\""]
text' :: T.Text -> Doc
text' = text . TL.fromStrict