packages feed

noli (empty) → 0.1.0.0

raw patch · 7 files changed

+237/−0 lines, 7 filesdep +basedep +cmarkdep +directorysetup-changed

Dependencies added: base, cmark, directory, lucid, regex-compat, text

Files

+ LICENSE view
@@ -0,0 +1,30 @@+Copyright Author name here (c) 2020++All rights reserved.++Redistribution and use in source and binary forms, with or without+modification, are permitted provided that the following conditions are met:++    * Redistributions of source code must retain the above copyright+      notice, this list of conditions and the following disclaimer.++    * Redistributions in binary form must reproduce the above+      copyright notice, this list of conditions and the following+      disclaimer in the documentation and/or other materials provided+      with the distribution.++    * Neither the name of Author name here nor the names of other+      contributors may be used to endorse or promote products derived+      from this software without specific prior written permission.++THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ README.md view
@@ -0,0 +1,1 @@+# noli
+ Setup.hs view
@@ -0,0 +1,2 @@+import Distribution.Simple+main = defaultMain
+ noli.cabal view
@@ -0,0 +1,27 @@+name:                noli+version:             0.1.0.0+synopsis:            A static site generator+description:            A static site generator+homepage:            https://github.com/githubuser/noli#readme+license:             BSD3+license-file:        LICENSE+author:              Author name here+maintainer:          example@example.com+copyright:           2020 Author name here+category:            Web+build-type:          Simple+cabal-version:       >=1.10+extra-source-files:  README.md++library+  hs-source-dirs:      src+  exposed-modules:     Noli,+                       Noli.Types+  other-modules:       PostUtils+  default-language:    Haskell2010+  build-depends:       base >= 4.7 && < 5,+                       text,+                       lucid,+                       cmark,+                       directory,+                       regex-compat
+ src/Noli.hs view
@@ -0,0 +1,76 @@+module Noli+  ( buildProject,+    buildSite,+    compilePosts,+  )+where++import Control.Monad+  ( unless,+    when,+  )+import Data.Text (unpack)+import qualified Data.Text.IO as DT+import Data.Text.Internal (Text)+import Data.Text.Lazy (toStrict)+import Lucid.Base+  ( Html,+    renderText,+  )+import Noli.Types+import PostUtils+  ( compilePost,+    copyFolder,+    extname,+  )+import System.Directory+  ( createDirectory,+    doesDirectoryExist,+    listDirectory,+    removeDirectoryRecursive,+    setCurrentDirectory,+  )++-- | Compile the posts starting from the templates and the folder where the markdown files are.+compilePosts :: PostTemplate -> FilePath -> IO [Post]+compilePosts postCompiler fp = do+  filePaths <- listDirectory fp+  let markdownFilePaths =+        Prelude.map (fp ++) $+          Prelude.filter (\fn -> extname fn == "md") filePaths+  mapM (compilePost postCompiler) markdownFilePaths++-- | Build the dynamic `Project` which works as a basis for the final static site.+--   It takes three arguments and returns a compiled `Project`+buildProject :: Settings -> [Page] -> PostTemplate -> IO Project+buildProject settings pages postCompiler = do+  ps <- compilePosts postCompiler $ posts_location settings+  return Project {posts = ps, pages = pages}++-- | Build the final static site+-- Takes two arguments and creates the files needed for the static site, saving them in the previously-set `dist_location`.+buildSite :: Settings -> Project -> IO ()+buildSite settings' project = do+  distExists <- doesDirectoryExist $ dist_location settings'+  when distExists $ removeDirectoryRecursive $ dist_location settings'+  createDirectory $ dist_location settings'+  copyFolder+    (static_location settings')+    (dist_location settings' ++ "static/")+  setCurrentDirectory $ dist_location settings'+  Prelude.mapM_+    ( \p ->+        DT.writeFile+          (unpack (pagename p) ++ ".html")+          (toStrict $ renderText $ template p)+    )+    (pages project)+  createDirectory "./posts"+  setCurrentDirectory "./posts"+  Prelude.mapM_+    ( \p ->+        DT.writeFile+          (unpack (filename p) ++ ".html")+          (toStrict $ renderText $ compiled_html p)+    )+    (posts project)
+ src/Noli/Types.hs view
@@ -0,0 +1,41 @@+module Noli.Types (Settings (..), Post (..), Project (..), Page (..), PostTemplate) where++import Data.Text+import Lucid.Base++-- | The "dynamic" representation of the static site+data Project = Project+  { posts :: [Post],+    pages :: [Page]+  }++data Settings = Settings+  { -- | The name of the site+    name :: Text,+    -- | The author's full name+    author :: Text,+    -- | The path to the folder that contains the markdown files+    posts_location :: FilePath,+    -- | The path to where the compiled static site will be saved+    dist_location :: FilePath,+    -- | The path to the static folder+    static_location :: FilePath+  }++data Post = Post+  { title :: Text,+    location :: FilePath,+    filename :: Text,+    raw :: Text,+    raw_html :: Text,+    compiled_html :: Html ()+  }+  deriving (Show)++data Page = Page {pagename :: Text, template :: Html ()}++type PostTitle = Text++type PostBody = Text++type PostTemplate = PostTitle -> PostBody -> Html ()
+ src/PostUtils.hs view
@@ -0,0 +1,60 @@+module PostUtils (compilePost, extname, copyFolder) where++import CMark (commonmarkToHtml)+import Control.Monad (unless)+import Data.Maybe (fromJust)+import Data.Text (pack)+import Data.Text.Internal (Text)+import Lucid.Base (Html)+import Noli.Types+import System.Directory (copyFile, createDirectory, doesDirectoryExist, doesFileExist, listDirectory)+import Text.Regex (Regex, matchRegex, mkRegex)++postNameRegex :: Regex+postNameRegex = mkRegex "/?([A-Za-z_]+)\\.md$"++extname :: FilePath -> FilePath+extname = Prelude.reverse . Prelude.takeWhile ('.' /=) . Prelude.reverse++compilePost :: PostTemplate -> FilePath -> IO Post+compilePost postCompiler fp = do+  fileContents <- pack <$> readFile fp+  let compiledFileContents = commonmarkToHtml [] fileContents+      fn = fromJust $ getPostFileName fp+      t = getPostName fn+      compiledHtml = postCompiler (pack t) compiledFileContents+  return+    Post+      { title = pack t,+        location = fp,+        filename = pack fn,+        raw = fileContents,+        raw_html = compiledFileContents,+        compiled_html = compiledHtml+      }++getPostFileName :: FilePath -> Maybe String+getPostFileName fp = case match of+  Nothing -> Nothing+  Just (x : xs) -> Just x+  where+    match = matchRegex postNameRegex fp++getPostName :: String -> String+getPostName fn =+  let repl '_' = ' '+      repl x = x+   in Prelude.map repl fn++copyFolder :: FilePath -> FilePath -> IO ()+copyFolder source destination = do+  destinationExists <- doesDirectoryExist destination+  unless destinationExists $ createDirectory destination+  sourceFiles <- listDirectory source+  Prelude.mapM_ copyFile' sourceFiles+  where+    copyFile' source_file = do+      is_file <- doesFileExist $ source ++ source_file+      if is_file+        then copyFile (source ++ source_file) (destination ++ source_file)+        else copyFolder (source ++ source_file ++ "/") (destination ++ source_file ++ "/")