git.iko.soy/typeable/compaREST
on master help sign in
Added styling to HTML output (#84)

* Added html template * added awsm.css submodule * Embed styling * Removed extra dependency * checkout submodules on CI * Fixed wording * Rmoved file

commit38341ca51fe5c1f91c4e6de687b63442c9faa63d authoriko <ilyakooo0@gmail.com> dateTue 22 Jun 2021, 17:15 (5 years ago) parent2440f23
8 files changed+149−77
.github/workflows/haskell.yml+2 .gitmodules+3 app/FormatHeuristic.hs+76−53 app/Main.hs+1−5 awsm-css+1 openapi-diff.cabal+5−1 src/OpenAPI/Checker/Report.hs+22−18 src/OpenAPI/Checker/Report/Html/Template.hs+39
.github/workflows/haskell.yml+2
@@ -12,6 +12,8 @@ jobs:
1212
1313 steps:
1414 - uses: actions/checkout@v2
15+ with:
16+ submodules: recursive
1517 - name: Cache
1618 uses: actions/cache@v1
1719 with:
.gitmodulesnew file+3
@@ -0,0 +1,3 @@
1+[submodule "awsm-css"]
2+ path = awsm-css
3+ url = https://github.com/igoradamenko/awsm.css.git
app/FormatHeuristic.hs+76−53
@@ -6,64 +6,87 @@ module FormatHeuristic
66 )
77where
88
9+import Data.ByteString.Lazy (ByteString)
910import Data.Char (toLower)
11+import Data.Functor
12+import qualified Data.Map as M
13+import Data.Text (Text)
14+import qualified Data.Text.Lazy as TL
15+import qualified Data.Text.Lazy.Encoding as TL
16+import qualified OpenAPI.Checker.Report.Html.Template as Html
1017import System.FilePath (takeExtension)
18+import Text.DocTemplates.Internal
1119import Text.Pandoc
1220
13−formatFromFilePath :: PandocMonad m => FilePath -> Maybe (Writer m)
21+formatFromFilePath :: forall m. PandocMonad m => FilePath -> Maybe (Pandoc -> m ByteString)
1422formatFromFilePath x =
1523 case takeExtension (map toLower x) of
16− ".adoc" -> f "asciidoc"
17− ".asciidoc" -> f "asciidoc"
18− ".context" -> f "context"
19− ".ctx" -> f "context"
20− ".db" -> f "docbook"
21− ".doc" -> f "doc" -- so we get an "unknown reader" error
22− ".docx" -> f "docx"
23− ".dokuwiki" -> f "dokuwiki"
24− ".epub" -> f "epub"
25− ".fb2" -> f "fb2"
26− ".htm" -> f "html"
27− ".html" -> f "html"
28− ".icml" -> f "icml"
29− ".json" -> f "json"
30− ".latex" -> f "latex"
31− ".lhs" -> f "markdown+lhs"
32− ".ltx" -> f "latex"
33− ".markdown" -> f "markdown"
34− ".mkdn" -> f "markdown"
35− ".mkd" -> f "markdown"
36− ".mdwn" -> f "markdown"
37− ".mdown" -> f "markdown"
38− ".Rmd" -> f "markdown"
39− ".md" -> f "markdown"
40− ".ms" -> f "ms"
41− ".muse" -> f "muse"
42− ".native" -> f "native"
43− ".odt" -> f "odt"
44− ".opml" -> f "opml"
45− ".org" -> f "org"
46− ".pdf" -> f "pdf" -- so we get an "unknown reader" error
47− ".pptx" -> f "pptx"
48− ".roff" -> f "ms"
49− ".rst" -> f "rst"
50− ".rtf" -> f "rtf"
51− ".s5" -> f "s5"
52− ".t2t" -> f "t2t"
53− ".tei" -> f "tei"
54− ".tei.xml" -> f "tei"
55− ".tex" -> f "latex"
56− ".texi" -> f "texinfo"
57− ".texinfo" -> f "texinfo"
58− ".text" -> f "markdown"
59− ".textile" -> f "textile"
60− ".txt" -> f "markdown"
61− ".wiki" -> f "mediawiki"
62− ".xhtml" -> f "html"
63− ".ipynb" -> f "ipynb"
64− ".csv" -> f "csv"
65− ".bib" -> f "biblatex"
66− ['.', y] | y `elem` ['1' .. '9'] -> f "man"
24+ ".adoc" -> f "asciidoc" def
25+ ".asciidoc" -> f "asciidoc" def
26+ ".context" -> f "context" def
27+ ".ctx" -> f "context" def
28+ ".db" -> f "docbook" def
29+ ".doc" -> f "doc" def -- so we get an "unknown reader" error
30+ ".docx" -> f "docx" def
31+ ".dokuwiki" -> f "dokuwiki" def
32+ ".epub" -> f "epub" def
33+ ".fb2" -> f "fb2" def
34+ ".htm" -> html
35+ ".html" -> html
36+ ".icml" -> f "icml" def
37+ ".json" -> f "json" def
38+ ".latex" -> f "latex" def
39+ ".lhs" -> f "markdown+lhs" def
40+ ".ltx" -> f "latex" def
41+ ".markdown" -> markdown
42+ ".mkdn" -> markdown
43+ ".mkd" -> markdown
44+ ".mdwn" -> markdown
45+ ".mdown" -> markdown
46+ ".Rmd" -> markdown
47+ ".md" -> markdown
48+ ".ms" -> f "ms" def
49+ ".muse" -> f "muse" def
50+ ".native" -> f "native" def
51+ ".odt" -> f "odt" def
52+ ".opml" -> f "opml" def
53+ ".org" -> f "org" def
54+ -- so we get an "unknown reader" error
55+ ".pdf" -> f "pdf" def
56+ ".pptx" -> f "pptx" def
57+ ".roff" -> f "ms" def
58+ ".rst" -> f "rst" def
59+ ".rtf" -> f "rtf" def
60+ ".s5" -> f "s5" def
61+ ".t2t" -> f "t2t" def
62+ ".tei" -> f "tei" def
63+ ".tei.xml" -> f "tei" def
64+ ".tex" -> f "latex" def
65+ ".texi" -> f "texinfo" def
66+ ".texinfo" -> f "texinfo" def
67+ ".text" -> markdown
68+ ".textile" -> f "textile" def
69+ ".txt" -> markdown
70+ ".wiki" -> f "mediawiki" def
71+ ".xhtml" -> f "html" def
72+ ".ipynb" -> f "ipynb" def
73+ ".csv" -> f "csv" def
74+ ".bib" -> f "biblatex" def
75+ ['.', y] | y `elem` ['1' .. '9'] -> f "man" def
6776 _ -> Nothing
6877 where
69− f k = lookup k writers
78+ markdown, html :: Maybe (Pandoc -> m ByteString)
79+ markdown = f "markdown" markdownOpt
80+ html =
81+ f
82+ "html"
83+ def
84+ { writerTemplate = Just Html.template
85+ , -- Not actually used. Needed to silence warning.
86+ writerVariables = Context $ M.fromList [("pagetitle", toVal ("OpenApi Diff" :: Text))]
87+ }
88+ markdownOpt = def {writerExtensions = githubMarkdownExtensions}
89+ f k opt =
90+ lookup k writers <&> \case
91+ TextWriter g -> fmap (TL.encodeUtf8 . TL.fromStrict) . g opt
92+ ByteStringWriter g -> g opt
app/Main.hs+1−5
@@ -38,11 +38,7 @@ main = do
3838 StdoutMode -> lift . T.putStrLn <=< runPandocIO . writeMarkdown options
3939 FileMode f -> case formatFromFilePath f of
4040 Nothing -> \_ -> throwError UnknownOutputFormat
41− Just (TextWriter writer) -> lift . T.writeFile f <=< runPandocIO . writer options
42− Just (ByteStringWriter writer) -> lift . BSL.writeFile f <=< runPandocIO . writer options
43− -- output :: Either (PathsPrefixTree Behave AnIssue 'APILevel) () -> ExceptT Errors IO ()
44− -- output inp = do
45− -- undefined
41+ Just writer -> lift . BSL.writeFile f <=< runPandocIO . writer
4642 (report, status) = runReport (a, b)
4743 either handler pure <=< runExceptT $ write report
4844 case status of
awsm-cssnew file+1

Submodule changed.

openapi-diff.cabal+5−1
@@ -105,6 +105,8 @@ library
105105 , mtl
106106 , aeson
107107 , generic-data
108+ , doctemplates
109+ , file-embed
108110 hs-source-dirs: src
109111 exposed-modules: Data.HList
110112 , OpenAPI.Checker.Behavior
@@ -136,6 +138,7 @@ library
136138 , Data.OpenUnion.Extra
137139 , OpenAPI.Checker.Report.Jet
138140 , OpenAPI.Checker.Run
141+ , OpenAPI.Checker.Report.Html.Template
139142
140143executable openapi-diff
141144 import: common-options
@@ -151,6 +154,8 @@ executable openapi-diff
151154 , optparse-applicative
152155 , mtl
153156 , aeson
157+ , containers
158+ , doctemplates
154159 ghc-options: -threaded
155160 -rtsopts
156161 -with-rtsopts=-N
@@ -177,7 +182,6 @@ test-suite openapi-diff-test
177182 , pandoc
178183 , data-default
179184 , lens
180− , openapi3
181185 ghc-options: -threaded
182186 -rtsopts
183187 -with-rtsopts=-N
src/OpenAPI/Checker/Report.hs+22−18
@@ -148,28 +148,32 @@ smartHeader i = do
148148showErrs :: forall a. Typeable a => ProcessedChanges a -> ReportMonad ()
149149showErrs x@(P.PathsPrefixNode currentIssues _) = do
150150 let -- Extract this pattern if more cases like this arise
151− ( removedPaths :: [Issue 'APILevel]
151+ ( removedPaths :: Maybe (Orientation, [Issue 'APILevel])
152152 , otherIssues :: Set (FunctorTuple (Const Orientation) AnIssue a)
153153 ) = case eqT @a @'APILevel of
154− Just Refl ->
155− let (p, o) =
156− S.partition
157− (\(FunctorTuple _ (AnIssue u)) -> case u of
158− NoPathsMatched {} -> True
159− AllPathsFailed {} -> True)
160− currentIssues
161− p' = S.toList p <&> (\(FunctorTuple _ (AnIssue i)) -> i)
162− in (p', o)
163− Nothing -> (mempty, currentIssues)
154+ Just Refl
155+ | (S.toList -> p@(FunctorTuple (Const ori) _ : _), o) <-
156+ S.partition
157+ (\(FunctorTuple _ (AnIssue u)) -> case u of
158+ NoPathsMatched {} -> True
159+ AllPathsFailed {} -> True)
160+ currentIssues ->
161+ let p' = p <&> (\(FunctorTuple _ (AnIssue i)) -> i)
162+ in (Just (ori, p'), o)
163+ _ -> (Nothing, currentIssues)
164164 jts <- asks sourceJets
165165 for_ otherIssues $ \(FunctorTuple (Const ori) (AnIssue i)) -> tell . describeIssue ori $ i
166− unless ([] == removedPaths) $ do
167− smartHeader "Removed paths"
168− tell $
169− bulletList $
170− removedPaths <&> \case
171− (NoPathsMatched p) -> para . code $ T.pack p
172− (AllPathsFailed p) -> para . code $ T.pack p
166+ case removedPaths of
167+ Just (ori, paths) -> do
168+ smartHeader $ case ori of
169+ Forward -> "Removed paths"
170+ Backward -> "Added paths"
171+ tell $
172+ bulletList $
173+ paths <&> \case
174+ (NoPathsMatched p) -> para . code $ T.pack p
175+ (AllPathsFailed p) -> para . code $ T.pack p
176+ Nothing -> pure ()
173177 unfoldM x (observeJetShowErrs <$> jts) $ \(P.PathsPrefixNode _ subIssues) -> do
174178 for_ subIssues $ \(WrapTypeable (AStep m)) ->
175179 for_ (M.toList m) $ \(bhv, subErrors) -> do
src/OpenAPI/Checker/Report/Html/Template.hsnew file+39
@@ -0,0 +1,39 @@
1+{-# LANGUAGE TemplateHaskell #-}
2+
3+module OpenAPI.Checker.Report.Html.Template
4+ ( template
5+ )
6+where
7+
8+import Control.Monad.Identity
9+import Data.ByteString (ByteString)
10+import Data.FileEmbed
11+import Data.Text (Text)
12+import qualified Data.Text.Encoding as T
13+import Text.DocTemplates
14+
15+template :: Template Text
16+template =
17+ either error id . runIdentity . compileTemplate "" $
18+ "<!doctype html>\
19+ \<html lang=\"en\">\
20+ \<head>\
21+ \<style>"
22+ <> T.decodeUtf8 awsmCss
23+ <> "</style>\
24+ \<meta charset=\"utf-8\">\
25+ \<title></title>\
26+ \<meta name=\"description\" content=\"\">\
27+ \<meta name=\"generator\" content=\"OpenApi Diff\" />\
28+ \<meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0, user-scalable=yes\" />\
29+ \</head>\
30+ \<body>\
31+ \<header><h1>⛄ OpenApi Diff</h1></header>\
32+ \<main>\
33+ \$body$\
34+ \</main>\
35+ \</body>\
36+ \</html>"
37+
38+awsmCss :: ByteString
39+awsmCss = $(makeRelativeToProject "awsm-css/dist/awsm.min.css" >>= embedFile)