packages feed

dhall-docs (empty) → 0.0.1

raw patch · 40 files changed

+2868/−0 lines, 40 filesdep +HaXmldep +basedep +bytestringsetup-changed

Dependencies added: HaXml, base, bytestring, containers, dhall, dhall-docs, directory, doctest, file-embed, filepath, lucid, megaparsec, mmark, mtl, optparse-applicative, path, path-io, pretty, prettyprinter, tar, tasty, tasty-silver, text

Files

+ CHANGELOG.md view
@@ -0,0 +1,3 @@+0.0.1++* Project skeleton with command line options
+ LICENSE view
@@ -0,0 +1,27 @@+Copyright (c) 2020 Gabriel Gonzalez+All rights reserved.++Redistribution and use in source and binary forms, with or without+modification, are permitted provided that the following conditions are met:++1. Redistributions of source code must retain the above copyright notice, this+list of conditions and the following disclaimer.++2. 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.++3. Neither the name of the author nor the names of its 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 HOLDER 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.
+ Setup.hs view
@@ -0,0 +1,2 @@+import Distribution.Simple+main = defaultMain
+ dhall-docs.cabal view
@@ -0,0 +1,133 @@+Name: dhall-docs+Version: 0.0.1+Cabal-Version: >=1.10+Build-Type: Simple+Tested-With: GHC == 8.6.1+License: BSD3+License-File: LICENSE+Copyright: 2020 Germán Robayo+Author: Germán Robayo+Maintainer: Gabriel439@gmail.com+Bug-Reports: https://github.com/dhall-lang/dhall-haskell/issues+Synopsis: Generate HTML docs from a dhall package+Description:+    Use this package if you want to create HTML documentation from your dhall+    packages:+    .+    * See the "Dhall.Docs" module if you want to use this package as a library+    .+    * Use the @dhall-docs@ program from this package if you want an executable+    .+    The "Dhall.Docs" module also contains instructions for how to use this package+Category: Compiler+Extra-Source-Files:+    CHANGELOG.md+    tasty/data/package/*.dhall+    tasty/data/package/a/*.dhall+    tasty/data/package/a/b/*.dhall+    tasty/data/package/a/b/c/*.dhall+    tasty/data/package/deep/nested/folder/*.dhall+    tasty/data/golden/*.dhall.html+    tasty/data/golden/a/*.dhall.html+    tasty/data/golden/a/b/*.dhall.html+    tasty/data/golden/a/b/c/*.dhall.html+    tasty/data/golden/deep/nested/folder/*.dhall.html+    tasty/data/golden/*.html+    tasty/data/golden/a/*.html+    tasty/data/golden/a/b/*.html+    tasty/data/golden/a/b/c/*.html+    tasty/data/golden/deep/nested/folder/*.html+Data-Files:+    *.css+    *.js+    *.svg+Data-Dir:+    src/Dhall/data++Source-Repository head+    Type: git+    Location: https://github.com/dhall-lang/dhall-haskell/tree/master/dhall-json+++Flag ghci-data-files+  description: To enable use of data-files while running `stack ghci`+  default: False++Library+    Hs-Source-Dirs: src+    Build-Depends:+        base                 >= 4.9.1.0  && < 5   ,+        bytestring                          < 0.11,+        containers                                ,+        directory            >= 1.3.0.0  && < 1.4 ,+        dhall                >= 1.32.0            ,+        file-embed           >= 0.0.10.0          ,+        filepath             >= 1.4      && < 1.5 ,+        lucid                >= 2.9.12   && < 2.10,+        mmark                >= 0.0.7.0  && < 0.8 ,+        megaparsec           >= 7        && < 8.1 ,+        path                 >= 0.7.0    && < 0.8 ,+        path-io              >= 1.6.0    && < 1.7 ,+        prettyprinter        >= 1.5.1    && < 1.7 ,+        tar                  >= 0.5.1.0  && < 0.6 ,+        text                 >= 0.11.1.0 && < 1.3 ,+        mtl                  >= 2.2.1    && < 2.3 ,+        optparse-applicative >= 0.14.0.0 && < 0.16+    Exposed-Modules:+        Dhall.Docs+        Dhall.Docs.Core+    Other-Modules:+        Dhall.Docs.Embedded+        Dhall.Docs.Html+        Dhall.Docs.Markdown+        Dhall.Docs.Store+        Paths_dhall_docs+    GHC-Options: -Wall+    Default-Language: Haskell2010+    if flag(ghci-data-files)+        Other-Modules: Paths_dhall_docs+    else+        Cpp-Options: "-DEMBED"++Executable dhall-docs+    Hs-Source-Dirs: dhall-docs+    Main-Is: Main.hs+    Build-Depends:+        base      ,+        dhall     ,+        dhall-docs+    Other-Modules:+        Paths_dhall_docs+    GHC-Options: -Wall+    Default-Language: Haskell2010++Test-Suite doctest+    Type: exitcode-stdio-1.0+    Hs-Source-Dirs: doctest+    Main-Is: Main.hs+    GHC-Options: -Wall+    Build-Depends:+        base                           ,+        directory,+        filepath                 < 1.5 ,+        doctest    >= 0.7.0   && < 0.18+    Other-Extensions: OverloadedStrings RecordWildCards+    Default-Language: Haskell2010++Test-Suite tasty+    Type: exitcode-stdio-1.0+    Hs-Source-Dirs: tasty+    Main-Is: Main.hs+    Build-Depends:+        base                   ,+        containers             ,+        dhall-docs             ,+        HaXml        >= 1.25.5 ,+        path                   ,+        path-io                ,+        pretty       >= 1.1.1.1,+        tasty        <  1.4    ,+        tasty-silver <= 3.1.15 ,+        text+    GHC-Options: -Wall+    Default-Language: Haskell2010
+ dhall-docs/Main.hs view
@@ -0,0 +1,6 @@+module Main where++import qualified Dhall.Docs++main :: IO ()+main = Dhall.Docs.main
+ doctest/Main.hs view
@@ -0,0 +1,18 @@+module Main where++import System.FilePath ((</>))++import qualified GHC.IO.Encoding+import qualified System.Directory+import qualified System.IO+import qualified Test.DocTest++main :: IO ()+main = do+    GHC.IO.Encoding.setLocaleEncoding System.IO.utf8+    pwd    <- System.Directory.getCurrentDirectory+    prefix <- System.Directory.makeAbsolute pwd+    Test.DocTest.doctest+        [ "--fast"+        , prefix </> "src"+        ]
+ src/Dhall/Docs.hs view
@@ -0,0 +1,132 @@+{-| This module contains the top level and options parsing of the @dhall-docs@+    executable+-}+{-# LANGUAGE LambdaCase        #-}+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE RecordWildCards   #-}++module Dhall.Docs+    ( -- * Options+      Options(..)+    , parserInfoOptions+    , parseOptions++      -- * Execution+    , main+    , defaultMain+    ) where++import Control.Applicative ((<|>))+import Data.Monoid         ((<>))+import Data.Text           (Text)+import Data.Version        (showVersion)+import Dhall.Docs.Core+import Options.Applicative (Parser, ParserInfo)+import Path                (Abs, Dir, Path)++import qualified Control.Monad+import qualified Data.Text+import qualified Data.Text.IO        as Text.IO+import qualified GHC.IO.Encoding+import qualified Options.Applicative+import qualified Path+import qualified Path.IO+import qualified Paths_dhall_docs    as Meta+import qualified System.Directory+import qualified System.Exit+import qualified System.IO++-- | Command line options+data Options+    = Options+        { packageDir :: FilePath         -- ^ Directory where your package resides+        , docLink :: FilePath            -- ^ Link to the generated documentation+        , resolvePackageName :: Path Abs Dir -> Text+        }+    | Version++-- | `Parser` for the `Options` type+parseOptions :: Parser Options+parseOptions =+    (   Options+    <$> Options.Applicative.strOption+        ( Options.Applicative.long "input"+       <> Options.Applicative.metavar "INPUT"+       <> Options.Applicative.help "Directory of your dhall package" )+    <*> Options.Applicative.strOption+        ( Options.Applicative.long "output-link"+       <> Options.Applicative.metavar "OUTPUT-LINK"+       <> Options.Applicative.help+            ( "Path to the link targeting the directory with the generated "+           <> "documentation. The path needs to not exist or to be a symlink, "+           <> "otherwise the tool won't generate any docs at all"+            )+       <> Options.Applicative.value "./docs" )+    <*> parsePackageNameResolver+    ) <|> parseVersion+  where+    parseVersion =+        Options.Applicative.flag'+            Version+            (   Options.Applicative.long "version"+            <>  Options.Applicative.help "Display version"+            )++    parsePackageNameResolver :: Parser (Path Abs Dir -> Text)+    parsePackageNameResolver = fmap f (Options.Applicative.optional p)+      where+        -- Directories on the `path` modules always ends in "/", so we have+        -- to remove last one with `init`+        f  Nothing = Data.Text.pack . init . Path.fromRelDir . Path.dirname+        f (Just packageName) = const $ Data.Text.pack packageName++        p = Options.Applicative.strOption+                (   Options.Applicative.long "package-name"+                <>  Options.Applicative.metavar "PACKAGE-NAME"+                <>  Options.Applicative.help+                            (  "Override for the package name seen on HTML "+                            <> "navbars. By default, it will extract it from "+                            <> "the input"+                            )+                )++-- | `ParserInfo` for the `Options` type+parserInfoOptions :: ParserInfo Options+parserInfoOptions =+    let progDesc = "Generate HTML documentation from a dhall package or file" in+    Options.Applicative.info+        (Options.Applicative.helper <*> parseOptions)+        (   Options.Applicative.fullDesc+        <>  Options.Applicative.progDesc progDesc+        )+++-- | Default execution of @dhall-docs@ command+defaultMain :: Options -> IO ()+defaultMain = \case+    Options{..} -> do+        GHC.IO.Encoding.setLocaleEncoding System.IO.utf8+        resolvedPackageDir <- Path.IO.resolveDir' packageDir++        outDirExists <- System.Directory.doesPathExist docLink+        Control.Monad.when outDirExists $ do+            isLink <- System.Directory.pathIsSymbolicLink docLink+            if isLink then System.Directory.removeFile docLink+            else die $ "The specified --output-link (" <> Data.Text.pack docLink+                    <> ") already exists and it's not a symlink."++        resolvedDocLink <- Path.IO.resolveDir' docLink+        let packageName = resolvePackageName resolvedPackageDir+        generateDocs resolvedPackageDir resolvedDocLink packageName+    Version ->+        putStrLn (showVersion Meta.version)++die :: Text -> IO a+die e = do+    Text.IO.hPutStrLn System.IO.stderr e++    System.Exit.exitFailure++-- | Entry point for the @dhall-docs@ executable+main :: IO ()+main = Options.Applicative.execParser parserInfoOptions >>= defaultMain
+ src/Dhall/Docs/Core.hs view
@@ -0,0 +1,435 @@+{-| Contains all the functions that generate documentation++    We should always try to do as little work as possible in an `IO` context.+    To do so, just wrap your function in `IO` if you need to do I/O operations,+    and make pure functions receive that IO result as an input+-}+{-# LANGUAGE CPP                   #-}+{-# LANGUAGE FlexibleInstances     #-}+{-# LANGUAGE MultiParamTypeClasses #-}+{-# LANGUAGE NamedFieldPuns        #-}+{-# LANGUAGE OverloadedStrings     #-}+{-# LANGUAGE RecordWildCards       #-}+{-# LANGUAGE TemplateHaskell       #-}+{-# LANGUAGE TupleSections         #-}+-- {-# OPTIONS_GHC -Wno-unused-imports #-}++module Dhall.Docs.Core (generateDocs, generateDocsPure, GeneratedDocs(..)) where++import Control.Monad.Writer.Class (MonadWriter)+import Data.Function              (on)+import Data.Map.Strict            (Map)+import Data.Monoid                ((<>))+import Data.Text                  (Text)+import Data.Void                  (Void)+import Dhall.Core+    ( Binding (..)+    , Expr (..)+    , Import+    , MultiLet (..)+    , Var (..)+    , denote+    )+import Dhall.Docs.Embedded+import Dhall.Docs.Html+import Dhall.Docs.Markdown+import Dhall.Docs.Store+import Dhall.Parser+    ( Header (..)+    , ParseError (..)+    , exprAndHeaderFromText+    )+import Dhall.Src                  (Src)+import Path                       (Abs, Dir, File, Path, Rel, (</>))+import Text.Megaparsec            (ParseErrorBundle (..))++import qualified Control.Applicative        as Applicative+import qualified Control.Monad+import qualified Control.Monad.Writer.Class as Writer+import qualified Data.ByteString+import qualified Data.Either+import qualified Data.List+import qualified Data.List.NonEmpty         as NonEmpty+import qualified Data.Map.Strict            as Map+import qualified Data.Maybe+import qualified Data.Maybe                 as Maybe+import qualified Data.Text+import qualified Data.Text.IO               as Text.IO+import qualified Data.Text.Lazy             as Text.Lazy+import qualified Dhall.Core+import qualified Lucid+import qualified Path+import qualified Path.IO+import qualified System.FilePath            as FilePath+import qualified Text.Megaparsec++-- $setup+-- >>> :set -XQuasiQuotes+-- >>> import Path (reldir)++-- | The result of the doc-generator pure component+data GeneratedDocs a = GeneratedDocs [DocsGenWarning] a++instance Functor GeneratedDocs where+    fmap f (GeneratedDocs w a) = GeneratedDocs w (f a)++instance Applicative GeneratedDocs where+    pure = GeneratedDocs []++    GeneratedDocs w f <*> GeneratedDocs w' a = GeneratedDocs (w <> w') (f a)++instance Monad GeneratedDocs where+    GeneratedDocs w a >>= f =+        let GeneratedDocs w' b = f a+            in GeneratedDocs (w <> w') b++instance MonadWriter [DocsGenWarning] GeneratedDocs where+    tell w = GeneratedDocs w ()++    listen (GeneratedDocs w a) = GeneratedDocs w (a, w)+    pass (GeneratedDocs w (a, f)) = GeneratedDocs (f w) a++data DocsGenWarning+    = InvalidDhall (Text.Megaparsec.ParseErrorBundle Text Void)+    | InvalidMarkdown MarkdownParseError++instance Show DocsGenWarning where+    show (InvalidDhall err) =+        "\n\ESC[1;33mWarning\ESC[0m: Invalid Input\n\n" <>+        Text.Megaparsec.errorBundlePretty err <>+        "... documentation won't be generated for this file"++    show (InvalidMarkdown MarkdownParseError{..}) =+        "\n\ESC[1;33mWarning\ESC[0m: Header comment is not markdown\n\n" <>+        Text.Megaparsec.errorBundlePretty unwrap <>+        "The original non-markdown text will be pasted in the documentation"++-- | Represents a Dhall file that can be rendered as documentation.+--   If you'd like to improve or add features to a .dhall documentation page,+--   add that extra information here.+data DhallFile = DhallFile+    { path :: Path Rel File             -- ^ Path of the file+    , expr :: Expr Src Import           -- ^ File contents+    , header :: Header                  -- ^ Parsed `Header` of the file+    , mType :: Maybe (Expr Void Import) -- ^ Type of the parsed expression,+                                        --   extracted from the source code+    , examples :: [Expr Void Import]    -- ^ Examples extracted from assertions+                                        --   in the file+    }++{-| Takes a list of files paths with their contents and returns the list of+    valid `DhallFile`s.++    Returned files contains all the information to be used on `Html ()`+    generation.++    The result is sorted by `path`+-}+getAllDhallFiles :: [(Path Rel File, Text)] -> GeneratedDocs [DhallFile]+getAllDhallFiles = emitErrors . map toDhallFile . filter hasDhallExtension+  where+    hasDhallExtension :: (Path Rel File, Text) -> Bool+    hasDhallExtension (absFile, _) = case Path.splitExtension absFile of+        Nothing -> False+        Just (_, ext) -> ext == ".dhall"++    toDhallFile :: (Path Rel File, Text) -> Either DocsGenWarning DhallFile+    toDhallFile (relFile, contents) =+        case exprAndHeaderFromText (Path.fromRelFile relFile) contents of+            Right (header, expr) ->+                let denoted = denote expr :: Expr Void Import in+                Right DhallFile+                    { path = relFile+                    , expr, header+                    , mType = extractTypeIfInSource denoted+                    , examples = examplesFromAssertions denoted+                    }+            Left ParseError{..} ->+                Left $ InvalidDhall unwrap++    emitErrors :: [Either DocsGenWarning DhallFile] -> GeneratedDocs [DhallFile]+    emitErrors errorsOrDhallFiles = do+        let (errors, dhallFiles) = Data.Either.partitionEithers errorsOrDhallFiles+        Writer.tell errors+        let sortedDhallFiles = Data.List.sortBy (compare `on` path) dhallFiles+        return sortedDhallFiles++    bindings :: Expr Void Import -> [Binding Void Import]+    bindings expr = case expr of+        Let b@Binding{} e ->+            let MultiLet bs _ = Dhall.Core.multiLet b e+            in NonEmpty.toList bs+        _ -> []+++    extractTypeIfInSource :: Expr Void Import -> Maybe (Expr Void Import)+    extractTypeIfInSource expr = do+        V name index <- maybeNameInLet expr+        (Binding _ _ _ (Just (_, exprType)) _ _) <-+            getLetBindingWithIndex index $ getLetBindingsWithName name+        return exprType+      where+        -- | For an expression of the form @let x0 = y0 let x1 = y1 ... in e@+        --   where @e@ is a variable, maybeNameInLet returns the variable name.+        maybeNameInLet :: Expr Void Import -> Maybe Var+        maybeNameInLet (Var v@(V _ _)) = Just v+        maybeNameInLet (Let _ e) = maybeNameInLet e+        maybeNameInLet _ = Nothing+++        {-| For an expression of the form @let x0 = y0 x1 = y1 ... in e@+            and a variable name @v@, this returns every @xi@ that is equal to+            v in the reverse order of the source code.++            For example, take a file like this:++        >   let x = 1+        >   let y = 2+        >   let z = 3+        >   in x + y + z++            ... this will return the bindings in this order: [z, y, x]++            Only the "global" level of the file is analyzed+        -}+        getLetBindingsWithName :: Text -> [Binding Void Import]+        getLetBindingsWithName name = filter bindName $ reverse $ bindings expr+          where+            bindName (Binding _ x _ _ _ _) = x == name+++        getLetBindingWithIndex :: Int -> [Binding Void Import] -> Maybe (Binding Void Import)+        getLetBindingWithIndex i bs =+            case drop i bs of+                [] -> Nothing+                binding : _ -> Just binding++    examplesFromAssertions :: Expr Void Import -> [Expr Void Import]+    examplesFromAssertions expr = Maybe.mapMaybe fromAssertion values+      where+        values :: [Expr Void Import]+        values = map value $ bindings expr++        fromAssertion :: Expr Void Import -> Maybe (Expr Void Import)+        fromAssertion (Assert e) =  Just e+        fromAssertion _ = Nothing++{-| Given a relative path, returns as much @..\/@ misdirections as needed+    to go to @.@++>>> resolveRelativePath [reldir|.|]+""+>>> resolveRelativePath [reldir|a|]+"../"+>>> resolveRelativePath [reldir|a/b/c|]+"../../../"+-}+resolveRelativePath :: Path Rel Dir -> FilePath+resolveRelativePath currentDir =+    case FilePath.dropTrailingPathSeparator $ Path.fromRelDir currentDir of+        "." -> ""+        _ -> "../" <> resolveRelativePath (Path.parent currentDir)++{-| Generates `Text` from the html representation of a `DhallFile`+-}+makeHtml+    :: Text                 -- ^ Package name+    -> DhallFile            -- ^ Parsed header+    -> GeneratedDocs Text+makeHtml packageName DhallFile {..} = do+    let relativeResourcesPath = resolveRelativePath $ Path.parent path+    let strippedHeader = stripCommentSyntax header+    headerAsHtml <-+        case markdownToHtml path strippedHeader of+            Left err -> do+                Writer.tell [InvalidMarkdown err]+                return $ Lucid.toHtml strippedHeader+            Right html -> return html++    let htmlAsText = Text.Lazy.toStrict $ Lucid.renderText $ dhallFileToHtml+            path+            expr+            examples+            headerAsHtml+            DocParams { relativeResourcesPath, packageName }++    return htmlAsText+  where+    stripCommentSyntax :: Header -> Text+    stripCommentSyntax (Header h)+        | Just s <- Data.Text.stripPrefix "--" strippedHeader+            = Data.Text.strip s+        | Just commentPrefixStripped <- Data.Text.stripPrefix "{-" strippedHeader+        , Just commentSuffixStripped <- Data.Text.stripSuffix "-}" commentPrefixStripped+            = Data.Text.strip commentSuffixStripped+        | otherwise = strippedHeader+      where+        strippedHeader = Data.Text.strip h++{-| Create an @index.html@ file on each available folder in the input.++    Each @index.html@ lists the files and directories of its directory. Listed+    directories will be compacted as much as it cans to improve readability.++    For example, take the following directory-tree structure++    > .+    > ├── a+    > │   └── b+    > │       └── c+    > │           └── b.dhall+    > └── a.dhall++    To improve navigation, the index at @./index.html@ should list+    @a/b/c@ and no @index.html@ should be generated inside of `a/` or+    `a/b/`, but yes on `a/b/c/` in the last one there is the @b.dhall@ file+-}+createIndexes :: Text -> [DhallFile] -> [(Path Rel File, Text)]+createIndexes packageName files = map toIndex dirToDirsAndFilesMapAssocs+  where+    -- Files grouped by their directory+    dirToFilesMap :: Map (Path Rel Dir) [DhallFile]+    dirToFilesMap = Map.unionsWith (<>) $ map toMap files+      where+        toMap :: DhallFile -> Map (Path Rel Dir) [DhallFile]+        toMap dhallFile =+            Map.singleton (Path.parent $ path dhallFile) [dhallFile]++    {-  This is used to compute the list of exported packages on each folder.+        We try to compress the folders as much as we can. See `createIndexes`+        documentation to get more information.+    -}+    dirToDirsMap :: Map (Path Rel Dir) [Path Rel Dir]+    dirToDirsMap = Map.map removeHereDir $ foldl go initialMap dirs+      where+        -- > removeHeredir [$(mkRelDir "a"), $(mkRelDir ".")]+        --   [$(mkRelDir "a")]+        removeHereDir :: [Path Rel Dir] -> [Path Rel Dir]+        removeHereDir = filter f+          where+            f :: Path Rel Dir -> Bool+            f reldir = Path.parent reldir /= reldir++        dirs :: [Path Rel Dir]+        dirs = Map.keys dirToFilesMap++        initialMap :: Map (Path Rel Dir) [Path Rel Dir]+        initialMap = Map.fromList $ map (,[]) dirs++        go :: Map (Path Rel Dir) [Path Rel Dir] -> Path Rel Dir -> Map (Path Rel Dir) [Path Rel Dir]+        go dirMap d = Map.adjust ([d] <>) (key $ Path.parent d) dirMap+          where+            key :: Path Rel Dir -> Path Rel Dir+            key dir = if dir `Map.member` dirMap then dir else key $ Path.parent dir++    dirToDirsAndFilesMapAssocs :: [(Path Rel Dir, ([DhallFile], [Path Rel Dir]))]+    dirToDirsAndFilesMapAssocs = Map.assocs $ Map.mapWithKey f dirToFilesMap+      where+        f :: Path Rel Dir -> [DhallFile] -> ([DhallFile], [Path Rel Dir])+        f dir dhallFiles = case dirToDirsMap Map.!? dir of+            Nothing -> fileAnIssue "dirToDirsAndFilesMapAssocs"+            Just dirs -> (dhallFiles, dirs)++    toIndex :: (Path Rel Dir, ([DhallFile], [Path Rel Dir])) -> (Path Rel File, Text)+    toIndex (indexDir, (dhallFiles, dirs)) =+        (indexDir </> $(Path.mkRelFile "index.html"), Text.Lazy.toStrict $ Lucid.renderText html)+      where+        html = indexToHtml+            indexDir+            (map (\DhallFile{..} -> (stripPrefix $ addHtmlExt path, mType)) dhallFiles)+            (map stripPrefix dirs)+            DocParams { relativeResourcesPath = resolveRelativePath indexDir, packageName }++        stripPrefix :: Path Rel a -> Path Rel a+        stripPrefix relpath =+            if Path.toFilePath relpath == Path.toFilePath indexDir then relpath+            else Data.Maybe.fromMaybe (fileAnIssue "Bug+with+stripPrefix")+                $ Path.stripProperPrefix indexDir relpath++-- | Takes a file and adds an @.html@ file extension to it+addHtmlExt :: Path Rel File -> Path Rel File+addHtmlExt relFile =+    Data.Maybe.fromMaybe (fileAnIssue "addHtmlExt") $ Path.addExtension ".html" relFile++-- | If you're wondering the GitHub query params for issue creation:+-- https://docs.github.com/en/github/managing-your-work-on-github/about-automation-for-issues-and-pull-requests-with-query-parameters+fileAnIssue :: Text -> a+fileAnIssue titleName =+    error $ "\ESC[1;31mError\ESC[0mDocumentation generator bug\n\n" <>++            "Explanation: This error message means that there is a bug in the " <>+            "Dhall Documentation generator. You didn't did anything wrong, but " <>+            "if you would like to see this problem fixed then you should report " <>+            "the bug at:\n\n" <>++            "https://github.com/dhall-lang/dhall-haskell/issues/new?labels=dhall-docs,bug\n\n" <>++            "explaining your issue and add \"" <> Data.Text.unpack titleName <> "\" as error code " <>+            "so we can find the proper location in the source code where the error happened\n\n" <>++            "Please, also include your package in the issue. It can be in:\n\n" <>+            "* A compressed archive (zip, tar, etc)\n" <>+            "* A git repository, preferably with a commit reference"++{-| Generate all of the docs for a package. This function does all the `IO ()`+    related tasks to call `generateDocsPure`+-}+generateDocs+    :: Path Abs Dir -- ^ Input directory+    -> Path Abs Dir -- ^ Link to be created to the generated documentation+    -> Text         -- ^ Package name, used in some HTML titles+    -> IO ()+generateDocs inputDir outLink packageName = do+    (_, absFiles) <- Path.IO.listDirRecur inputDir+    contents <- mapM (Text.IO.readFile . Path.fromAbsFile) absFiles+    strippedFiles <- mapM (Path.stripProperPrefix inputDir) absFiles+    let GeneratedDocs warnings docs = generateDocsPure packageName $ zip strippedFiles contents+    mapM_ print warnings+    if null docs then+        putStrLn $+            "No documentation was generated because no file with .dhall " <>+            "extension was found"+    else Path.IO.withSystemTempDir "dhall-docs" $ \tempDir -> do+        copyDataDir tempDir+        mapM_ (writeGenFile tempDir) docs++        outputHash <- makeHashForDirectory tempDir+        outDir <- Applicative.liftA2 (</>)+                    getDocsHomeDirectory+                    (Path.parseRelDir+                        $ show outputHash <> "-" <> Data.Text.unpack packageName)++        Path.IO.copyDirRecur tempDir outDir+        Path.IO.createDirLink outDir outLink+  where+    writeGenFile :: Path Abs Dir -> (Path Rel File, Text) -> IO ()+    writeGenFile outDir (relFile, contents) = do+        Path.IO.ensureDir (outDir </> Path.parent relFile)+        Text.IO.writeFile (Path.fromAbsFile $ outDir </> relFile) contents++    copyDataDir :: Path Abs Dir -> IO ()+    copyDataDir outDir = do+        dataDir <- getDataDir+        Control.Monad.forM_ dataDir $ \(filename, contents) -> do+            let finalPath = Path.fromAbsFile $ outDir </> filename+            Data.ByteString.writeFile finalPath contents++{-| Generates all the documentation of dhall package in a pure way i.e.+    without an `IO` context. This let you generate documentation from a list of+    dhall-files without saving them to the filesystem.++    If you want the `IO` version of this function, check `generateDocs`+-}+generateDocsPure+    :: Text                    -- ^ Package name+    -> [(Path Rel File, Text)] -- ^ (Input file, contents)+    -> GeneratedDocs [(Path Rel File, Text)]+generateDocsPure packageName inputFiles = go+  where+    go :: GeneratedDocs [(Path Rel File, Text)]+    go = do+        dhallFiles <- getAllDhallFiles inputFiles+        htmls <- mapM (makeHtml packageName) dhallFiles+        let indexes = createIndexes packageName dhallFiles+        return (zip (map (addHtmlExt . path) dhallFiles) htmls <> indexes)+
+ src/Dhall/Docs/Embedded.hs view
@@ -0,0 +1,45 @@+{-| Compile-time generated files, used to put all data-files in the executable+    to make it easy to distribute.+-}++{-# LANGUAGE CPP             #-}+{-# LANGUAGE TemplateHaskell #-}+{-# LANGUAGE TupleSections   #-}++module Dhall.Docs.Embedded (getDataDir) where++import Data.ByteString (ByteString)+import Path            (File, Path, Rel)++import qualified Path++#if defined(EMBED)++import Data.FileEmbed (embedDir)++#else++import Paths_dhall_docs hiding (getDataDir)++import qualified Control.Monad+import qualified Data.ByteString as ByteString+import qualified Path.IO++#endif++getDataDir :: IO [(Path Rel File, ByteString)]+#if defined(EMBED)+getDataDir = return $(embedDir "src/Dhall/data") >>= mapM f+  where+    f :: (FilePath, ByteString) -> IO (Path Rel File, ByteString)+    f (filePath, contents) = (,contents) <$> Path.parseRelFile filePath+#else+getDataDir = do+    dir <- Path.parent+        <$> (getDataFileName "src/Dhall/data/index.css" >>= Path.parseAbsFile)+    files <- snd <$> Path.IO.listDir dir+    Control.Monad.forM files $ \file -> do+        contents <- ByteString.readFile $ Path.fromAbsFile file+        return (Path.filename file, contents)++#endif
+ src/Dhall/Docs/Html.hs view
@@ -0,0 +1,298 @@+{-| Functions used to generate HTML from a dhall package.+    You can see this module as logic-less HTML building blocks for the whole+    generator tool.++    There are functions that uses `FilePath` instead of `Path a b`. That is because+    the `Path` module doesn't allows to use ".." on its paths and that is needed+    here to properly link css and images.+-}++{-# LANGUAGE ExtendedDefaultRules #-}+{-# LANGUAGE OverloadedStrings    #-}+{-# LANGUAGE RecordWildCards      #-}++module Dhall.Docs.Html+    ( dhallFileToHtml+    , indexToHtml+    , DocParams(..)+    ) where++import Data.Monoid  ((<>))+import Data.Text    (Text)+import Data.Void    (Void)+import Dhall.Core   (Expr, Import)+import Dhall.Pretty (Ann (..))+import Dhall.Src    (Src)+import Lucid+import Path         (Dir, File, Path, Rel)++import qualified Control.Monad+import qualified Data.Foldable+import qualified Data.Text+import qualified Data.Text.Prettyprint.Doc                           as Pretty+import qualified Data.Text.Prettyprint.Doc.Render.Util.SimpleDocTree as Pretty+import qualified Dhall.Pretty+import qualified Path+import qualified System.FilePath                                     as FilePath++-- $setup+-- >>> :set -XQuasiQuotes+-- >>> import Path (reldir, relfile)++-- | Internal utility to differentiate if a Dhall expr is a type annotation+--   or the whole file+data ExprType = TypeAnnotation | FileContentsExpr+++exprToHtml :: ExprType -> Expr a Import -> Html ()+exprToHtml exprType expr = pre_ $ renderTree prettyTree+  where+    layout = case exprType of+        FileContentsExpr -> Dhall.Pretty.layout+        TypeAnnotation -> typeLayout++    prettyTree = Pretty.treeForm+        $ layout+        $ Dhall.Pretty.prettyExpr expr++    textSpaces :: Int -> Text+    textSpaces n = Data.Text.replicate n (Data.Text.singleton ' ')++    renderTree :: Pretty.SimpleDocTree Ann -> Html ()+    renderTree sds = case sds of+        Pretty.STEmpty -> return ()+        Pretty.STChar c -> toHtml $ Data.Text.singleton c+        Pretty.STText _ t -> toHtml t+        Pretty.STLine i -> br_ [] >> toHtml (textSpaces i)+        Pretty.STAnn ann content -> encloseInTagFor ann (renderTree content)+        Pretty.STConcat contents -> foldMap renderTree contents++    encloseInTagFor :: Ann -> Html () -> Html ()+    encloseInTagFor ann = span_ [class_ classForAnn]+      where+        classForAnn = "dhall-" <> case ann of+            Keyword -> "keyword"+            Syntax -> "syntax"+            Label -> "label"+            Literal -> "literal"+            Builtin -> "builtin"+            Operator -> "operator"++    typeLayout :: Pretty.Doc ann -> Pretty.SimpleDocStream ann+    typeLayout = Pretty.removeTrailingWhitespace . Pretty.layoutSmart opts+      where+        -- this is done so the type of a dhall file fits in a single line+        -- its a safe value, since types in source codes are not that large+        opts :: Pretty.LayoutOptions+        opts = Pretty.defaultLayoutOptions+                { Pretty.layoutPageWidth =+                    Pretty.Unbounded+                }+++-- | Params for commonly supplied values on the generated documentation+data DocParams = DocParams+    { relativeResourcesPath :: FilePath -- ^ Relative resource path to the+                                        --   front-end files+    , packageName :: Text               -- ^ Name of the package+    }++-- | Generates an @`Html` ()@ with all the information about a dhall file+dhallFileToHtml+    :: Path Rel File            -- ^ Source file name, used to extract the title+    -> Expr Src Import          -- ^ Contents of the file+    -> [Expr Void Import]       -- ^ Examples extracted from the assertions of the file+    -> Html ()                  -- ^ Header document as HTML+    -> DocParams                -- ^ Parameters for the documentation+    -> Html ()+dhallFileToHtml filePath expr examples header params@DocParams{..} =+    doctypehtml_ $ do+        headContents htmlTitle params+        body_ $ do+            navBar params+            mainContainer $ do+                setPageTitle params NotIndex breadcrumb+                copyToClipboardButton htmlTitle+                br_ []+                div_ [class_ "doc-contents"] header+                Control.Monad.unless (null examples) $ do+                    h3_ "Examples"+                    div_ [class_ "source-code code-examples"] $+                        mapM_ (exprToHtml FileContentsExpr) examples+                h3_ "Source"+                div_ [class_ "source-code"] $ exprToHtml FileContentsExpr expr+  where+    breadcrumb = relPathToBreadcrumb filePath+    htmlTitle = breadCrumbsToText breadcrumb++-- | Generates an index @`Html` ()@ that list all the dhall files in that folder+indexToHtml+    :: Path Rel Dir                                -- ^ Index directory+    -> [(Path Rel File, Maybe (Expr Void Import))] -- ^ Generated files in that directory+    -> [Path Rel Dir]                              -- ^ Generated directories in that directory+    -> DocParams                                   -- ^ Parameters for the documentation+    -> Html ()+indexToHtml indexDir files dirs params@DocParams{..} = doctypehtml_ $ do+    headContents htmlTitle params+    body_ $ do+        navBar params+        mainContainer $ do+            setPageTitle params Index breadcrumbs+            copyToClipboardButton htmlTitle+            br_ []+            Control.Monad.unless (null files) $ do+                h3_ "Exported files: "+                ul_ $ mconcat $ map listFile files++            Control.Monad.unless (null dirs) $ do+                h3_ "Exported packages: "+                ul_ $ mconcat $ map listDir dirs++  where+    listFile :: (Path Rel File, Maybe (Expr Void Import)) -> Html ()+    listFile (file, maybeType) =+        let fileRef = Data.Text.pack $ Path.fromRelFile file+            itemText = Data.Text.pack $ tryToTakeExt file+        in li_ $ do+            a_ [href_ fileRef] $ toHtml itemText+            Data.Foldable.forM_ maybeType $ \typeExpr -> do+                span_ [class_ "of-type-token"] ":"+                span_ [class_ "dhall-type source-code"] $ exprToHtml TypeAnnotation typeExpr+++    listDir :: Path Rel Dir -> Html ()+    listDir dir =+        let dirPath = Data.Text.pack $ Path.fromRelDir dir in+        li_ $ a_ [href_ (dirPath <> "index.html")] $ toHtml dirPath++    tryToTakeExt :: Path Rel File -> FilePath++    tryToTakeExt file = Path.fromRelFile $ case Path.splitExtension file of+        Nothing -> file+        Just (f, _) -> f++    breadcrumbs = relPathToBreadcrumb indexDir+    htmlTitle = breadCrumbsToText breadcrumbs++copyToClipboardButton :: Text -> Html ()+copyToClipboardButton filePath =+    a_ [class_ "copy-to-clipboard", data_ "path" filePath]+        $ i_ $ small_ "Copy path to clipboard"+++setPageTitle :: DocParams -> HtmlFileType -> Breadcrumb -> Html ()+setPageTitle DocParams{..} htmlFileType breadcrumb =+    h2_ [class_ "doc-title"] $ do+        span_ [class_ "crumb-divider"] "/"+        a_ [href_ $ Data.Text.pack $ relativeResourcesPath <> "index.html"]+            $ toHtml packageName+        breadCrumbsToHtml htmlFileType breadcrumb+++-- | ADT for handling bread crumbs. This is essentially a backwards list+--   See `relPathToBreadcrumb` for more information.+data Breadcrumb+    = Crumb Breadcrumb String+    | EmptyCrumb+    deriving Show++data HtmlFileType = NotIndex | Index++{-| Convert a relative path to a `Breadcrumb`.++>>> relPathToBreadcrumb [reldir|a/b/c|]+Crumb (Crumb (Crumb EmptyCrumb "a") "b") "c"+>>> relPathToBreadcrumb [reldir|.|]+Crumb EmptyCrumb ""+>>> relPathToBreadcrumb [relfile|c/foo.baz|]+Crumb (Crumb EmptyCrumb "c") "foo.baz"+-}+relPathToBreadcrumb :: Path Rel a -> Breadcrumb+relPathToBreadcrumb relPath = foldl Crumb EmptyCrumb splittedRelPath+  where+    filePath = Path.toFilePath relPath++    splittedRelPath :: [String]+    splittedRelPath = case FilePath.dropTrailingPathSeparator filePath of+        "." -> [""]+        _ -> FilePath.splitDirectories filePath++-- | Render breadcrumbs as `Html ()`+breadCrumbsToHtml :: HtmlFileType -> Breadcrumb -> Html ()+breadCrumbsToHtml htmlFileType = go startLevel+  where+    startLevel = case htmlFileType of+        NotIndex -> -1+        Index -> 0++    -- copyBreadcrumbButton :: Html ()+    -- copyBreadcrumbButton =+    --     button_+    --         [ class_ "btn copy-breadcrumb"+    --         , data_ "breadcrumb" $ breadCrumbsToText breadcrumb+    --         ] ""++    go :: Int -> Breadcrumb -> Html ()+    go _ EmptyCrumb = return ()+    go level (Crumb bc name) = do+        go (level + 1) bc+        span_ [class_ "crumb-divider"] $ toHtml ("/" :: Text)+        elem_ [class_ "title-crumb", href_ hrefTarget] $ toHtml name+      where+        hrefTarget = Data.Text.replicate level "../" <> "index.html"+        elem_ = if level == startLevel then span_ else a_+++-- | Render breadcrumbs as plain text+breadCrumbsToText :: Breadcrumb -> Text+breadCrumbsToText EmptyCrumb = ""+breadCrumbsToText (Crumb bc c) = breadCrumbsToText bc <> "/" <> Data.Text.pack c+++-- | nav-bar component of the HTML documentation+navBar+    :: DocParams -- ^ Parameters for doc generation+    -> Html ()+navBar DocParams{..} = div_ [class_ "nav-bar"] $ do++    -- Left side of the nav-bar+    img_ [ class_ "dhall-icon"+         , src_ $ Data.Text.pack $ relativeResourcesPath <> "dhall-icon.svg"+         ]+    p_ [class_ "package-title"] $ toHtml packageName++    div_ [class_ "nav-bar-content-divider"] ""++    -- Right side of the nav-bar+    -- with makeOption [id_ "go-to-source-code"] "Source code"+    with makeOption [id_ "switch-light-dark-mode"] "Switch Light/Dark Mode"+  where+    makeOption = with a_ [class_ "nav-option"]+++headContents :: Text -> DocParams -> Html ()+headContents title DocParams{..} =+    head_ $ do+        title_ $ toHtml title+        stylesheet $ relativeResourcesPath <> "index.css"+        stylesheet "https://fonts.googleapis.com/css2?family=Fira+Code:wght@400;500;600;700&family=Lato&display=swap"+        script relativeResourcesPath+        meta_ [charset_ "UTF-8"]++-- | main-container component builder of the HTML documentation+mainContainer :: Html() -> Html ()+mainContainer = div_ [class_ "main-container"]++stylesheet :: FilePath -> Html ()+stylesheet path =+    link_+        [ rel_ "stylesheet"+        , type_ "text/css"+        , href_ $ Data.Text.pack path]++script :: FilePath -> Html ()+script relativeResourcesPath =+    script_+        [ type_ "text/javascript"+        , src_ $ Data.Text.pack $ relativeResourcesPath <> "index.js"]+        ("" :: Text)
+ src/Dhall/Docs/Markdown.hs view
@@ -0,0 +1,32 @@+{-| Contains all utilities related to markdown processing+-}+module Dhall.Docs.Markdown+    ( MarkdownParseError(..)+    , markdownToHtml+    ) where++import Data.Text       (Text)+import Lucid+import Path            (File, Path, Rel)+import Text.Megaparsec (ParseErrorBundle (..))+import Text.MMark      (MMarkErr)++import qualified Path+import qualified Text.MMark as MMark++-- | Wrapper around `MMarkErr` errors+newtype MarkdownParseError = MarkdownParseError+    { unwrap :: ParseErrorBundle Text MMarkErr+    }++{-| Takes a text that could contain markdown and returns the generated HTML.+    If an error occurs while parsing, it also returns the error information.+-}+markdownToHtml+    :: Path Rel File -- ^ Used by `Mmark.parse` for error messages+    -> Text          -- ^ Text to parse+    -> Either MarkdownParseError (Html ())+markdownToHtml relFile contents =+    case MMark.parse (Path.fromRelFile relFile) contents of+        Left err -> Left MarkdownParseError { unwrap = err }+        Right mmark -> Right $ MMark.render mmark
+ src/Dhall/Docs/Store.hs view
@@ -0,0 +1,48 @@+{-| Utilities to interact with the dhall-docs home directory+-}+{-# OPTIONS_GHC -Wno-unused-imports #-}+{-# LANGUAGE QuasiQuotes #-}+++module Dhall.Docs.Store (getDocsHomeDirectory, makeHashForDirectory) where++import Dhall.Crypto (SHA256Digest (..), sha256Hash)+import Path         (Abs, Dir, Path, Rel)+import Path.IO      (XdgDirectory (..))++import qualified Codec.Archive.Tar       as Tar+import qualified Codec.Archive.Tar.Entry as Tar.Entry+import qualified Data.ByteString.Lazy+import qualified Data.List+import qualified Path+import qualified Path.IO++{-| Fetches the dhall-docs home directory. If @XDG_DATA_HOME@ env var is+    defined, then @${XDG_DATA_HOME}/dhall-docs@ will be returned. Otherwise,+    "${HOME}/.local/share/dhall-docs"+-}+getDocsHomeDirectory :: IO (Path Abs Dir)+getDocsHomeDirectory = do+    dir <- Path.IO.getXdgDir Path.IO.XdgData $ Just $ [Path.reldir|dhall-docs|]+    Path.IO.ensureDir dir+    return dir++{-| Compute the hash for a directory. It takes into account the hierarchy+    structure of it and the contents of its files, but not the name of the+    actual files.++    This is done by computing the hash of each file and sorting them by its+    absolute file name, and computing the hash of the concatenation of all+    hashes.+-}+makeHashForDirectory :: Path Abs Dir -> IO SHA256Digest+makeHashForDirectory dir = do+    -- Builds a map so key order is preserved between several calls+    files <- Data.List.sort . map Path.fromRelFile . snd+            <$> Path.IO.listDirRecurRel dir++    let setTimeToZero entry = entry{Tar.Entry.entryTime = 0}+    inMemoryTarBytes <- Data.ByteString.Lazy.toStrict . Tar.write . map setTimeToZero+                <$> Tar.pack (Path.fromAbsDir dir) files++    return $ sha256Hash inMemoryTarBytes
+ src/Dhall/data/dhall-icon.svg view
@@ -0,0 +1,1 @@+<?xml version="1.0" encoding="UTF-8" standalone="no"?><!-- Generator: Gravit.io --><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" style="isolation:isolate" viewBox="701 377 180 180" width="180pt" height="180pt"><defs><clipPath id="_clipPath_bHCrHBHhrzISq2YnO5draXOg8wrP22Y8"><rect x="701" y="377" width="180" height="180"/></clipPath></defs><g clip-path="url(#_clipPath_bHCrHBHhrzISq2YnO5draXOg8wrP22Y8)"><path d=" M 791 377 C 840.672 377 881 417.328 881 467 C 881 516.672 840.672 557 791 557 C 741.328 557 701 516.672 701 467 C 701 417.328 741.328 377 791 377 Z  M 773.725 507.794 C 778.868 506.416 784.161 509.472 785.539 514.615 C 786.917 519.757 783.861 525.051 778.718 526.429 C 773.576 527.807 768.282 524.751 766.904 519.608 C 765.526 514.466 768.582 509.172 773.725 507.794 Z  M 825.655 406.546 C 827.502 407.041 828.6 408.943 828.105 410.79 C 827.61 412.637 825.709 413.734 823.862 413.239 L 820.634 412.375 C 820.047 417.121 816.961 443.216 818.245 458.044 C 804.548 469.874 780.875 505.457 780.875 505.457 L 793.315 459.031 C 795.744 458.876 798.412 457.332 799.076 454.852 C 799.909 451.743 798.061 448.542 794.952 447.709 C 791.843 446.876 788.642 448.724 787.809 451.833 C 787.145 454.313 788.683 456.984 790.709 458.332 L 778.269 504.759 C 778.269 504.759 774.975 463.985 769.612 445.012 C 778.328 433.72 788.578 408.768 790.391 404.271 L 787.15 403.403 C 785.303 402.908 784.206 401.006 784.701 399.159 C 785.196 397.312 787.097 396.215 788.944 396.71 L 825.655 406.546 L 825.655 406.546 Z " fill-rule="evenodd" fill="rgb(235,235,235)"/></g></svg>
+ src/Dhall/data/index.css view
@@ -0,0 +1,244 @@+/*+    primary-color: #C4C4C4+    secondary-color: #EBEBEB+    accent-color1: #FFA632+    accent-color2: #008489+    accent-color3: #914669+*/++/******** Common rules ********/++body {+    padding: 0;+    margin: 0;+    background-color: #EBEBEB;+    transition: 0.5s;+}++body * {+    font-family: 'Lato', sans-serif;+}++a {+    transition: 0.5s;+    color: #008489;+}++a:visited {+    color: #914669;+}++a:active {+    color: #FFA632;+}++/******** Markdown specific code ********/++code {+    font-family: 'Fira Code', monospace;+}++blockquote {+    border-left: 9px solid #aaa;+    background-color: #bdbdbd;+    padding: 0.2rem;+    color: #616161;+}++/******** Nav bar **********/++.nav-bar {+    display: flex;+    align-items: center;+    padding: 0.3rem;+    background-color: #484848;+    color: #EBEBEB;+    transition: 0.5s;+}++.nav-bar .dhall-icon {+    max-width: 2.5rem;+    margin: 0.5rem;+}++.nav-bar .package-title {+    font-size: 1.3rem;+    margin: 0;+    margin-left: 1rem;+}++.nav-bar a.nav-option {+    font-size: 1rem;+    height: 100%;+    margin: 0 0.5rem;+    cursor: pointer;+    transition: 0.5s;+    text-decoration: none;+}++.nav-bar a.nav-option:hover {+    text-decoration: underline;+    text-decoration-color: #EBEBEB;+}++.nav-bar a.nav-option:active, .nav-bar a.nav-option, .nav-bar a.nav-option:visited {+    color: #EBEBEB;+}++.nav-bar .nav-bar-content-divider {+    flex: 1;+}++/******** Main content **********/++.main-container {+    padding: 2rem;+    padding-top: 0;+    transition: 0.5s;+}++h2.doc-title span, h2.doc-title a {+    font-family: 'Fira Code', monospace;+}++span.crumb-divider:first-child {+    margin-left: 0;+}++span.crumb-divider {+    margin: 0 0.5rem;+}++a.title-crumb {+    text-decoration: none;+}++a.title-crumb:hover {+    text-decoration: underline;+}++a.copy-to-clipboard {+    margin-top: 0;+    color: #888 !important;+    user-select: none;+    cursor: pointer;+    text-decoration: none;+}++a.copy-to-clipboard:hover {+    text-decoration: underline;+}++h2.doc-title {+    margin-bottom: 0;+}++/******** Source code **********/+++.code-examples > pre {+    padding-top: 0 !important;+    padding-bottom: 0 !important;+}++.source-code {+    padding: 0rem;+}++.source-code pre {+    padding: 1rem;+    font-family: 'Fira Code', monospace;+    color: #333333;+}++.source-code span {+    font-family: 'Fira Code', monospace;+    color: #333333;+}++.source-code span.dhall-keyword {+    color: #0000FF;+    font-weight: bold;+}++.source-code span.dhall-syntax {+    color: #AF00DB;+}++.source-code span.dhall-literal {+    color: #098658;+    font-weight: bold;+}++.source-code span.dhall-builtin {+    color: #267F99;+    font-weight: bold;+}++.dhall-type {+    font-family: 'Fira Code', monospace;+}++.dhall-type pre {+    display: inline;+    padding: 0;+}++span.of-type-token {+    margin-left: 0.5rem;+    margin-right: 0.5rem;+}++/******** Dark mode styling ********/++.dark-mode .main-container {+    color: #EBEBEB;+}++body.dark-mode {+    background-color: #484848;+}++.dark-mode .nav-bar {+    background-color: #5d5d5d;+}++.dark-mode a {+    color: #FFA632;+}++.dark-mode a:visited {+    color: #008489;+}++.dark-mode a:active {+    color: #914669;+}++.dark-mode .source-code pre {+    color: #D4D4D4;+}++.dark-mode .source-code span {+    color: #D4D4D4;+}++.dark-mode .source-code span.dhall-keyword {+    color: #569CD6;+}++.dark-mode .source-code span.dhall-syntax {+    color: #C586C0;+}++.dark-mode .source-code span.dhall-literal {+    color: #B5CEA8;+}++.dark-mode .source-code span.dhall-builtin {+    color: #4EC9B0;+}++.dark-mode a.copy-to-clipboard {+    color: #bdbdbd !important;+}
+ src/Dhall/data/index.js view
@@ -0,0 +1,36 @@+const DARK_MODE_OPT = 'dark-mode'+const DARK_MODE_ACTIVE = 'dark-mode-active'+const DARK_MODE_INACTIVE = 'dark-mode-inactive'++function onReady() {+  if (localStorage.getItem(DARK_MODE_OPT) == DARK_MODE_ACTIVE) {+    document.body.classList.add('dark-mode')+  } else {+    document.body.classList.remove('dark-mode')+  }+  document.getElementById('switch-light-dark-mode')+    .addEventListener('click', () => {+      document.body.classList.toggle('dark-mode')+      if (document.body.classList.contains('dark-mode')) {+        localStorage.setItem(DARK_MODE_OPT, DARK_MODE_ACTIVE)+      } else {+        localStorage.setItem(DARK_MODE_OPT, DARK_MODE_INACTIVE)+      }+    })++  document.querySelectorAll('a.copy-to-clipboard').forEach(node =>+    node.addEventListener('click', () => {+      const temp = document.createElement('input')+      document.body.append(temp)+      temp.value = node.dataset.path+      temp.select()+      document.execCommand("copy");+      temp.remove()+    }))+}++if (document.readyState != 'loading'){+  onReady();+} else {+  document.addEventListener('DOMContentLoaded', onReady);+}
+ tasty/Main.hs view
@@ -0,0 +1,65 @@+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE TemplateHaskell   #-}+{-# OPTIONS_GHC -Wno-unused-imports #-}++module Main (main) where++import Data.Map.Strict (Map)+import Data.Text       (Text)+import Dhall.Docs.Core+import Path            (Dir, File, Path, Rel, (</>))+import Test.Tasty      (TestTree)++import qualified Control.Monad+import qualified Data.Map.Strict               as Map+import qualified Data.Text+import qualified Data.Text.IO                  as Text.IO+import qualified GHC.IO.Encoding+import qualified Path+import qualified Path.IO+import qualified Test.Tasty+import qualified Test.Tasty.Silver             as Silver+import qualified Test.Tasty.Silver.Interactive as Silver+import qualified Text.PrettyPrint              as Pretty+import qualified Text.XML.HaXml.Html.Parse     as HaXml+import qualified Text.XML.HaXml.Pretty         as HaXml++main :: IO ()+main = do+    GHC.IO.Encoding.setLocaleEncoding GHC.IO.Encoding.utf8++    input <- getPackageContents+    let GeneratedDocs _ docs = generateDocsPure "test-package" input+    let docsMap = Map.fromList docs+    Silver.defaultMain $ testTree docsMap++getDirContents :: Path Rel Dir -> IO [(Path Rel File, Text)]+getDirContents dataDir = do+    files <- snd <$> Path.IO.listDirRecurRel dataDir+    Control.Monad.forM files $ \file -> do+        contents <- Text.IO.readFile $ Path.fromRelFile $ dataDir </> file+        return (file, contents)++goldenDir :: Path Rel Dir+goldenDir = $(Path.mkRelDir "./tasty/data/golden")++getPackageContents :: IO [(Path Rel File, Text)]+getPackageContents = getDirContents $(Path.mkRelDir "./tasty/data/package")++testTree :: Map (Path Rel File) Text -> TestTree+testTree docsMap =+    Test.Tasty.testGroup "dhall-docs"+        $ map makeTest $ Map.assocs docsMap+  where+    makeTest :: (Path Rel File, Text) -> TestTree+    makeTest (testFile, text) =+        Silver.goldenVsAction testName goldenFilePath action converter+      where+        goldenFilePath = Path.fromRelFile $ goldenDir </> testFile+        testName = Path.fromRelFile testFile+        action = return prettyHtmlDoc+        converter = Data.Text.pack++        prettyHtmlDoc = Pretty.render+            $ HaXml.document+            $ HaXml.htmlParse testName (Data.Text.unpack text)
+ tasty/data/golden/IndexesExample.dhall.html view
@@ -0,0 +1,77 @@+<!DOCTYPE HTML>+<html+  ><head+    ><title+    >/IndexesExample.dhall</title+    ><link href="index.css" type="text/css" rel="stylesheet"+    /><link href="https://fonts.googleapis.com/css2?family=Fira+Code:wght@400;500;600;700&amp;family=Lato&amp;display=swap"+            type="text/css" rel="stylesheet"+    /><script src="index.js" type="text/javascript"+    /><meta charset="UTF-8"/></head+  ><body+    ><div class="nav-bar"+      ><img src="dhall-icon.svg" class="dhall-icon"+      /><p class="package-title"+      >test-package</p+      ><div class="nav-bar-content-divider"+      /><a id="switch-light-dark-mode" class="nav-option"+      >Switch Light/Dark Mode</a></div+    ><div class="main-container"+      ><h2 class="doc-title"+        ><span class="crumb-divider"+        >/</span+        ><a href="index.html"+        >test-package</a+        ><span class="crumb-divider"+        >/</span+        ><span href="index.html" class="title-crumb"+        >IndexesExample.dhall</span></h2+      ><a data-path="/IndexesExample.dhall" class="copy-to-clipboard"+        ><i+          ><small+          >Copy path to clipboard</small></i></a+      ><br+      /><div class="doc-contents"+        ><p+        >Checking indexes</p>+</div+      ><h3+      >Source</h3+      ><div class="source-code"+        ><pre+          ><span class="dhall-keyword"+          >let</span+          > <span class="dhall-label"+          >x</span+          ><br+          />    <span class="dhall-syntax"+          >:</span+          > <span class="dhall-builtin"+          >Bool</span+          ><br+          />    <span class="dhall-syntax"+          >=</span+          > <span class="dhall-builtin"+          >True</span+          ><br+          /><br+          /><span class="dhall-keyword"+          >let</span+          > <span class="dhall-label"+          >x</span+          ><br+          />    <span class="dhall-syntax"+          >:</span+          > <span class="dhall-builtin"+          >Natural</span+          ><br+          />    <span class="dhall-syntax"+          >=</span+          > <span class="dhall-literal"+          >1</span+          ><br+          /><br+          /><span class="dhall-keyword"+          >in</span+          >  <span class="dhall-label"+          >x@1</span></pre></div></div></body></html>
+ tasty/data/golden/InvalidMarkdown.dhall.html view
@@ -0,0 +1,82 @@+<!DOCTYPE HTML>+<html+  ><head+    ><title+    >/InvalidMarkdown.dhall</title+    ><link href="index.css" type="text/css" rel="stylesheet"+    /><link href="https://fonts.googleapis.com/css2?family=Fira+Code:wght@400;500;600;700&amp;family=Lato&amp;display=swap"+            type="text/css" rel="stylesheet"+    /><script src="index.js" type="text/javascript"+    /><meta charset="UTF-8"/></head+  ><body+    ><div class="nav-bar"+      ><img src="dhall-icon.svg" class="dhall-icon"+      /><p class="package-title"+      >test-package</p+      ><div class="nav-bar-content-divider"+      /><a id="switch-light-dark-mode" class="nav-option"+      >Switch Light/Dark Mode</a></div+    ><div class="main-container"+      ><h2 class="doc-title"+        ><span class="crumb-divider"+        >/</span+        ><a href="index.html"+        >test-package</a+        ><span class="crumb-divider"+        >/</span+        ><span href="index.html" class="title-crumb"+        >InvalidMarkdown.dhall</span></h2+      ><a data-path="/InvalidMarkdown.dhall" class="copy-to-clipboard"+        ><i+          ><small+          >Copy path to clipboard</small></i></a+      ><br+      /><div class="doc-contents"+      >Represents an status in our messaging system `+-- look, another line</div+      ><h3+      >Source</h3+      ><div class="source-code"+        ><pre+          ><span class="dhall-keyword"+          >let</span+          > <span class="dhall-label"+          >Pair</span+          > <span class="dhall-syntax"+          >=</span+          > ./Pair.dhall<br+          /><br+          /><span class="dhall-keyword"+          >let</span+          > <span class="dhall-label"+          >DeliveryStatus</span+          > <span class="dhall-syntax"+          >=</span+          > <span class="dhall-syntax"+          >&lt;</span+          > <span class="dhall-label"+          >Sent</span+          > <span class="dhall-syntax"+          >:</span+          > <span class="dhall-label"+          >Pair</span+          > <span class="dhall-builtin"+          >Natural</span+          > <span class="dhall-builtin"+          >Text</span+          > <span class="dhall-syntax"+          >|</span+          > <span class="dhall-label"+          >InProgress</span+          > <span class="dhall-syntax"+          >|</span+          > <span class="dhall-label"+          >InQueue</span+          > <span class="dhall-syntax"+          >&gt;</span+          ><br+          /><br+          /><span class="dhall-keyword"+          >in</span+          >  <span class="dhall-label"+          >DeliveryStatus</span></pre></div></div></body></html>
+ tasty/data/golden/MarkdownExample.dhall.html view
@@ -0,0 +1,141 @@+<!DOCTYPE HTML>+<html+  ><head+    ><title+    >/MarkdownExample.dhall</title+    ><link href="index.css" type="text/css" rel="stylesheet"+    /><link href="https://fonts.googleapis.com/css2?family=Fira+Code:wght@400;500;600;700&amp;family=Lato&amp;display=swap"+            type="text/css" rel="stylesheet"+    /><script src="index.js" type="text/javascript"+    /><meta charset="UTF-8"/></head+  ><body+    ><div class="nav-bar"+      ><img src="dhall-icon.svg" class="dhall-icon"+      /><p class="package-title"+      >test-package</p+      ><div class="nav-bar-content-divider"+      /><a id="switch-light-dark-mode" class="nav-option"+      >Switch Light/Dark Mode</a></div+    ><div class="main-container"+      ><h2 class="doc-title"+        ><span class="crumb-divider"+        >/</span+        ><a href="index.html"+        >test-package</a+        ><span class="crumb-divider"+        >/</span+        ><span href="index.html" class="title-crumb"+        >MarkdownExample.dhall</span></h2+      ><a data-path="/MarkdownExample.dhall" class="copy-to-clipboard"+        ><i+          ><small+          >Copy path to clipboard</small></i></a+      ><br+      /><div class="doc-contents"+        ><h1 id="heading-1"+        >Heading 1</h1+        >+<h2 id="heading-2"+        >Heading 2</h2+        >+<h3 id="heading-3"+        >Heading 3</h3+        >+<h4 id="heading-4"+        >Heading 4</h4+        >+<h5 id="heading-5"+        >Heading 5</h5+        >+<h6 id="heading-6"+        >Heading 6</h6+        >+<p+          >Message data type for our <em+          >messaging-system</em> config.</p+        >+<pre+          ><code+          >It is similar to the `kafka` message dto.+</code></pre+        >+<p+        >testing again another random text.</p+        >+<p+          ><strong+          >NOTE</strong>: This is really important to know</p+        >+<p+        >This allows you to:</p+        >+<ul+          >+<li+          >+Send messages+</li+          >+<li+            >+Receive messages, knowing that:+<ul+              >+<li+              >+nothing works (?)+</li+              >+<li+              >+weird huh+</li>+</ul>+</li>+</ul+        >+<p+        >As somebody said,</p+        >+<blockquote+          >+<p+          >The best way to code is to not code</p>+</blockquote+        >+<p+        >Here I show you some haskell code</p+        >+<pre+          ><code class="language-haskell"+          >main = putStrLn &quot;dhall rulez&quot;+</code></pre>+</div+      ><h3+      >Source</h3+      ><div class="source-code"+        ><pre+          ><span class="dhall-syntax"+          >{</span+          > <span class="dhall-label"+          >remitent</span+          > <span class="dhall-syntax"+          >:</span+          > <span class="dhall-builtin"+          >Text</span+          ><span class="dhall-syntax"+          >,</span+          > <span class="dhall-label"+          >deliveryStatus</span+          > <span class="dhall-syntax"+          >:</span+          > ./DeliveryStatus.dhall<span class="dhall-syntax"+          >,</span+          > <span class="dhall-label"+          >body</span+          > <span class="dhall-syntax"+          >:</span+          > <span class="dhall-builtin"+          >Text</span+          > <span class="dhall-syntax"+          >}</span></pre></div></div></body></html>
+ tasty/data/golden/Pair.dhall.html view
@@ -0,0 +1,134 @@+<!DOCTYPE HTML>+<html+  ><head+    ><title+    >/Pair.dhall</title+    ><link href="index.css" type="text/css" rel="stylesheet"+    /><link href="https://fonts.googleapis.com/css2?family=Fira+Code:wght@400;500;600;700&amp;family=Lato&amp;display=swap"+            type="text/css" rel="stylesheet"+    /><script src="index.js" type="text/javascript"+    /><meta charset="UTF-8"/></head+  ><body+    ><div class="nav-bar"+      ><img src="dhall-icon.svg" class="dhall-icon"+      /><p class="package-title"+      >test-package</p+      ><div class="nav-bar-content-divider"+      /><a id="switch-light-dark-mode" class="nav-option"+      >Switch Light/Dark Mode</a></div+    ><div class="main-container"+      ><h2 class="doc-title"+        ><span class="crumb-divider"+        >/</span+        ><a href="index.html"+        >test-package</a+        ><span class="crumb-divider"+        >/</span+        ><span href="index.html" class="title-crumb"+        >Pair.dhall</span></h2+      ><a data-path="/Pair.dhall" class="copy-to-clipboard"+        ><i+          ><small+          >Copy path to clipboard</small></i></a+      ><br+      /><div class="doc-contents"+        ><p+          >Just a <em+          >Pair</em> right here</p>+</div+      ><h3+      >Source</h3+      ><div class="source-code"+        ><pre+          ><span class="dhall-keyword"+          >let</span+          > <span class="dhall-label"+          >Pair</span+          ><br+          />    <span class="dhall-syntax"+          >:</span+          > <span class="dhall-syntax"+          >∀</span+          ><span class="dhall-syntax"+          >(</span+          ><span class="dhall-label"+          >A</span+          > <span class="dhall-syntax"+          >:</span+          > <span class="dhall-builtin"+          >Type</span+          ><span class="dhall-syntax"+          >)</span+          > <span class="dhall-syntax"+          >→</span+          > <span class="dhall-syntax"+          >∀</span+          ><span class="dhall-syntax"+          >(</span+          ><span class="dhall-label"+          >B</span+          > <span class="dhall-syntax"+          >:</span+          > <span class="dhall-builtin"+          >Type</span+          ><span class="dhall-syntax"+          >)</span+          > <span class="dhall-syntax"+          >→</span+          > <span class="dhall-builtin"+          >Type</span+          ><br+          />    <span class="dhall-syntax"+          >=</span+          > <span class="dhall-syntax"+          >λ</span+          ><span class="dhall-syntax"+          >(</span+          ><span class="dhall-label"+          >A</span+          > <span class="dhall-syntax"+          >:</span+          > <span class="dhall-builtin"+          >Type</span+          ><span class="dhall-syntax"+          >)</span+          > <span class="dhall-syntax"+          >→</span+          > <span class="dhall-syntax"+          >λ</span+          ><span class="dhall-syntax"+          >(</span+          ><span class="dhall-label"+          >B</span+          > <span class="dhall-syntax"+          >:</span+          > <span class="dhall-builtin"+          >Type</span+          ><span class="dhall-syntax"+          >)</span+          > <span class="dhall-syntax"+          >→</span+          > <span class="dhall-syntax"+          >{</span+          > <span class="dhall-label"+          >first</span+          > <span class="dhall-syntax"+          >:</span+          > <span class="dhall-label"+          >A</span+          ><span class="dhall-syntax"+          >,</span+          > <span class="dhall-label"+          >second</span+          > <span class="dhall-syntax"+          >:</span+          > <span class="dhall-label"+          >B</span+          > <span class="dhall-syntax"+          >}</span+          ><br+          /><br+          /><span class="dhall-keyword"+          >in</span+          >  <span class="dhall-label"+          >Pair</span></pre></div></div></body></html>
+ tasty/data/golden/a/b.dhall.html view
@@ -0,0 +1,57 @@+<!DOCTYPE HTML>+<html+  ><head+    ><title+    >/a/b.dhall</title+    ><link href="../index.css" type="text/css" rel="stylesheet"+    /><link href="https://fonts.googleapis.com/css2?family=Fira+Code:wght@400;500;600;700&amp;family=Lato&amp;display=swap"+            type="text/css" rel="stylesheet"+    /><script src="../index.js" type="text/javascript"+    /><meta charset="UTF-8"/></head+  ><body+    ><div class="nav-bar"+      ><img src="../dhall-icon.svg" class="dhall-icon"+      /><p class="package-title"+      >test-package</p+      ><div class="nav-bar-content-divider"+      /><a id="switch-light-dark-mode" class="nav-option"+      >Switch Light/Dark Mode</a></div+    ><div class="main-container"+      ><h2 class="doc-title"+        ><span class="crumb-divider"+        >/</span+        ><a href="../index.html"+        >test-package</a+        ><span class="crumb-divider"+        >/</span+        ><a href="index.html" class="title-crumb"+        >a</a+        ><span class="crumb-divider"+        >/</span+        ><span href="index.html" class="title-crumb"+        >b.dhall</span></h2+      ><a data-path="/a/b.dhall" class="copy-to-clipboard"+        ><i+          ><small+          >Copy path to clipboard</small></i></a+      ><br+      /><div class="doc-contents"+        ><p+        >Hi there boys</p>+</div+      ><h3+      >Source</h3+      ><div class="source-code"+        ><pre+          ><span class="dhall-keyword"+          >let</span+          > <span class="dhall-label"+          >b</span+          > <span class="dhall-syntax"+          >=</span+          > <span class="dhall-literal"+          >1</span+          > <span class="dhall-keyword"+          >in</span+          > <span class="dhall-label"+          >b</span></pre></div></div></body></html>
+ tasty/data/golden/a/b/c.dhall.html view
@@ -0,0 +1,61 @@+<!DOCTYPE HTML>+<html+  ><head+    ><title+    >/a/b/c.dhall</title+    ><link href="../../index.css" type="text/css" rel="stylesheet"+    /><link href="https://fonts.googleapis.com/css2?family=Fira+Code:wght@400;500;600;700&amp;family=Lato&amp;display=swap"+            type="text/css" rel="stylesheet"+    /><script src="../../index.js" type="text/javascript"+    /><meta charset="UTF-8"/></head+  ><body+    ><div class="nav-bar"+      ><img src="../../dhall-icon.svg" class="dhall-icon"+      /><p class="package-title"+      >test-package</p+      ><div class="nav-bar-content-divider"+      /><a id="switch-light-dark-mode" class="nav-option"+      >Switch Light/Dark Mode</a></div+    ><div class="main-container"+      ><h2 class="doc-title"+        ><span class="crumb-divider"+        >/</span+        ><a href="../../index.html"+        >test-package</a+        ><span class="crumb-divider"+        >/</span+        ><a href="../index.html" class="title-crumb"+        >a</a+        ><span class="crumb-divider"+        >/</span+        ><a href="index.html" class="title-crumb"+        >b</a+        ><span class="crumb-divider"+        >/</span+        ><span href="index.html" class="title-crumb"+        >c.dhall</span></h2+      ><a data-path="/a/b/c.dhall" class="copy-to-clipboard"+        ><i+          ><small+          >Copy path to clipboard</small></i></a+      ><br+      /><div class="doc-contents"+        ><p+        >Hi there boys</p>+</div+      ><h3+      >Source</h3+      ><div class="source-code"+        ><pre+          ><span class="dhall-keyword"+          >let</span+          > <span class="dhall-label"+          >c</span+          > <span class="dhall-syntax"+          >=</span+          > <span class="dhall-literal"+          >1</span+          > <span class="dhall-keyword"+          >in</span+          > <span class="dhall-label"+          >c</span></pre></div></div></body></html>
+ tasty/data/golden/a/b/c/a.dhall.html view
@@ -0,0 +1,65 @@+<!DOCTYPE HTML>+<html+  ><head+    ><title+    >/a/b/c/a.dhall</title+    ><link href="../../../index.css" type="text/css" rel="stylesheet"+    /><link href="https://fonts.googleapis.com/css2?family=Fira+Code:wght@400;500;600;700&amp;family=Lato&amp;display=swap"+            type="text/css" rel="stylesheet"+    /><script src="../../../index.js" type="text/javascript"+    /><meta charset="UTF-8"/></head+  ><body+    ><div class="nav-bar"+      ><img src="../../../dhall-icon.svg" class="dhall-icon"+      /><p class="package-title"+      >test-package</p+      ><div class="nav-bar-content-divider"+      /><a id="switch-light-dark-mode" class="nav-option"+      >Switch Light/Dark Mode</a></div+    ><div class="main-container"+      ><h2 class="doc-title"+        ><span class="crumb-divider"+        >/</span+        ><a href="../../../index.html"+        >test-package</a+        ><span class="crumb-divider"+        >/</span+        ><a href="../../index.html" class="title-crumb"+        >a</a+        ><span class="crumb-divider"+        >/</span+        ><a href="../index.html" class="title-crumb"+        >b</a+        ><span class="crumb-divider"+        >/</span+        ><a href="index.html" class="title-crumb"+        >c</a+        ><span class="crumb-divider"+        >/</span+        ><span href="index.html" class="title-crumb"+        >a.dhall</span></h2+      ><a data-path="/a/b/c/a.dhall" class="copy-to-clipboard"+        ><i+          ><small+          >Copy path to clipboard</small></i></a+      ><br+      /><div class="doc-contents"+        ><p+        >Hi there boys</p>+</div+      ><h3+      >Source</h3+      ><div class="source-code"+        ><pre+          ><span class="dhall-keyword"+          >let</span+          > <span class="dhall-label"+          >a</span+          > <span class="dhall-syntax"+          >=</span+          > <span class="dhall-literal"+          >1</span+          > <span class="dhall-keyword"+          >in</span+          > <span class="dhall-label"+          >a</span></pre></div></div></body></html>
+ tasty/data/golden/a/b/c/index.html view
@@ -0,0 +1,47 @@+<!DOCTYPE HTML>+<html+  ><head+    ><title+    >/a/b/c</title+    ><link href="../../../index.css" type="text/css" rel="stylesheet"+    /><link href="https://fonts.googleapis.com/css2?family=Fira+Code:wght@400;500;600;700&amp;family=Lato&amp;display=swap"+            type="text/css" rel="stylesheet"+    /><script src="../../../index.js" type="text/javascript"+    /><meta charset="UTF-8"/></head+  ><body+    ><div class="nav-bar"+      ><img src="../../../dhall-icon.svg" class="dhall-icon"+      /><p class="package-title"+      >test-package</p+      ><div class="nav-bar-content-divider"+      /><a id="switch-light-dark-mode" class="nav-option"+      >Switch Light/Dark Mode</a></div+    ><div class="main-container"+      ><h2 class="doc-title"+        ><span class="crumb-divider"+        >/</span+        ><a href="../../../index.html"+        >test-package</a+        ><span class="crumb-divider"+        >/</span+        ><a href="../../index.html" class="title-crumb"+        >a</a+        ><span class="crumb-divider"+        >/</span+        ><a href="../index.html" class="title-crumb"+        >b</a+        ><span class="crumb-divider"+        >/</span+        ><span href="index.html" class="title-crumb"+        >c</span></h2+      ><a data-path="/a/b/c" class="copy-to-clipboard"+        ><i+          ><small+          >Copy path to clipboard</small></i></a+      ><br+      /><h3+      >Exported files: </h3+      ><ul+        ><li+          ><a href="a.dhall.html"+          >a.dhall</a></li></ul></div></body></html>
+ tasty/data/golden/a/b/index.html view
@@ -0,0 +1,49 @@+<!DOCTYPE HTML>+<html+  ><head+    ><title+    >/a/b</title+    ><link href="../../index.css" type="text/css" rel="stylesheet"+    /><link href="https://fonts.googleapis.com/css2?family=Fira+Code:wght@400;500;600;700&amp;family=Lato&amp;display=swap"+            type="text/css" rel="stylesheet"+    /><script src="../../index.js" type="text/javascript"+    /><meta charset="UTF-8"/></head+  ><body+    ><div class="nav-bar"+      ><img src="../../dhall-icon.svg" class="dhall-icon"+      /><p class="package-title"+      >test-package</p+      ><div class="nav-bar-content-divider"+      /><a id="switch-light-dark-mode" class="nav-option"+      >Switch Light/Dark Mode</a></div+    ><div class="main-container"+      ><h2 class="doc-title"+        ><span class="crumb-divider"+        >/</span+        ><a href="../../index.html"+        >test-package</a+        ><span class="crumb-divider"+        >/</span+        ><a href="../index.html" class="title-crumb"+        >a</a+        ><span class="crumb-divider"+        >/</span+        ><span href="index.html" class="title-crumb"+        >b</span></h2+      ><a data-path="/a/b" class="copy-to-clipboard"+        ><i+          ><small+          >Copy path to clipboard</small></i></a+      ><br+      /><h3+      >Exported files: </h3+      ><ul+        ><li+          ><a href="c.dhall.html"+          >c.dhall</a></li></ul+      ><h3+      >Exported packages: </h3+      ><ul+        ><li+          ><a href="c/index.html"+          >c/</a></li></ul></div></body></html>
+ tasty/data/golden/a/index.html view
@@ -0,0 +1,45 @@+<!DOCTYPE HTML>+<html+  ><head+    ><title+    >/a</title+    ><link href="../index.css" type="text/css" rel="stylesheet"+    /><link href="https://fonts.googleapis.com/css2?family=Fira+Code:wght@400;500;600;700&amp;family=Lato&amp;display=swap"+            type="text/css" rel="stylesheet"+    /><script src="../index.js" type="text/javascript"+    /><meta charset="UTF-8"/></head+  ><body+    ><div class="nav-bar"+      ><img src="../dhall-icon.svg" class="dhall-icon"+      /><p class="package-title"+      >test-package</p+      ><div class="nav-bar-content-divider"+      /><a id="switch-light-dark-mode" class="nav-option"+      >Switch Light/Dark Mode</a></div+    ><div class="main-container"+      ><h2 class="doc-title"+        ><span class="crumb-divider"+        >/</span+        ><a href="../index.html"+        >test-package</a+        ><span class="crumb-divider"+        >/</span+        ><span href="index.html" class="title-crumb"+        >a</span></h2+      ><a data-path="/a" class="copy-to-clipboard"+        ><i+          ><small+          >Copy path to clipboard</small></i></a+      ><br+      /><h3+      >Exported files: </h3+      ><ul+        ><li+          ><a href="b.dhall.html"+          >b.dhall</a></li></ul+      ><h3+      >Exported packages: </h3+      ><ul+        ><li+          ><a href="b/index.html"+          >b/</a></li></ul></div></body></html>
+ tasty/data/golden/deep/nested/folder/index.html view
@@ -0,0 +1,65 @@+<!DOCTYPE HTML>+<html+  ><head+    ><title+    >/deep/nested/folder</title+    ><link href="../../../index.css" type="text/css" rel="stylesheet"+    /><link href="https://fonts.googleapis.com/css2?family=Fira+Code:wght@400;500;600;700&amp;family=Lato&amp;display=swap"+            type="text/css" rel="stylesheet"+    /><script src="../../../index.js" type="text/javascript"+    /><meta charset="UTF-8"/></head+  ><body+    ><div class="nav-bar"+      ><img src="../../../dhall-icon.svg" class="dhall-icon"+      /><p class="package-title"+      >test-package</p+      ><div class="nav-bar-content-divider"+      /><a id="switch-light-dark-mode" class="nav-option"+      >Switch Light/Dark Mode</a></div+    ><div class="main-container"+      ><h2 class="doc-title"+        ><span class="crumb-divider"+        >/</span+        ><a href="../../../index.html"+        >test-package</a+        ><span class="crumb-divider"+        >/</span+        ><a href="../../index.html" class="title-crumb"+        >deep</a+        ><span class="crumb-divider"+        >/</span+        ><a href="../index.html" class="title-crumb"+        >nested</a+        ><span class="crumb-divider"+        >/</span+        ><span href="index.html" class="title-crumb"+        >folder</span></h2+      ><a data-path="/deep/nested/folder" class="copy-to-clipboard"+        ><i+          ><small+          >Copy path to clipboard</small></i></a+      ><br+      /><h3+      >Exported files: </h3+      ><ul+        ><li+          ><a href="my-even.dhall.html"+          >my-even.dhall</a+          ><span class="of-type-token"+          >:</span+          ><span class="dhall-type source-code"+            ><pre+              ><span class="dhall-builtin"+              >Natural</span+              > <span class="dhall-syntax"+              >→</span+              > <span class="dhall-syntax"+              >&lt;</span+              > <span class="dhall-label"+              >even</span+              > <span class="dhall-syntax"+              >|</span+              > <span class="dhall-label"+              >odd</span+              > <span class="dhall-syntax"+              >&gt;</span></pre></span></li></ul></div></body></html>
+ tasty/data/golden/deep/nested/folder/my-even.dhall.html view
@@ -0,0 +1,246 @@+<!DOCTYPE HTML>+<html+  ><head+    ><title+    >/deep/nested/folder/my-even.dhall</title+    ><link href="../../../index.css" type="text/css" rel="stylesheet"+    /><link href="https://fonts.googleapis.com/css2?family=Fira+Code:wght@400;500;600;700&amp;family=Lato&amp;display=swap"+            type="text/css" rel="stylesheet"+    /><script src="../../../index.js" type="text/javascript"+    /><meta charset="UTF-8"/></head+  ><body+    ><div class="nav-bar"+      ><img src="../../../dhall-icon.svg" class="dhall-icon"+      /><p class="package-title"+      >test-package</p+      ><div class="nav-bar-content-divider"+      /><a id="switch-light-dark-mode" class="nav-option"+      >Switch Light/Dark Mode</a></div+    ><div class="main-container"+      ><h2 class="doc-title"+        ><span class="crumb-divider"+        >/</span+        ><a href="../../../index.html"+        >test-package</a+        ><span class="crumb-divider"+        >/</span+        ><a href="../../index.html" class="title-crumb"+        >deep</a+        ><span class="crumb-divider"+        >/</span+        ><a href="../index.html" class="title-crumb"+        >nested</a+        ><span class="crumb-divider"+        >/</span+        ><a href="index.html" class="title-crumb"+        >folder</a+        ><span class="crumb-divider"+        >/</span+        ><span href="index.html" class="title-crumb"+        >my-even.dhall</span></h2+      ><a data-path="/deep/nested/folder/my-even.dhall"+          class="copy-to-clipboard"+        ><i+          ><small+          >Copy path to clipboard</small></i></a+      ><br+      /><div class="doc-contents"+        ><p+        >Check if a natural is even or not returning an union data-type</p>+</div+      ><h3+      >Examples</h3+      ><div class="source-code code-examples"+        ><pre+          ><span class="dhall-label"+          >my-even</span+          > <span class="dhall-literal"+          >1</span+          > <span class="dhall-operator"+          >≡</span+          > <span class="dhall-syntax"+          >&lt;</span+          > <span class="dhall-label"+          >even</span+          > <span class="dhall-syntax"+          >|</span+          > <span class="dhall-label"+          >odd</span+          > <span class="dhall-syntax"+          >&gt;</span+          ><span class="dhall-syntax"+          >.</span+          ><span class="dhall-label"+          >odd</span></pre+        ><pre+          ><span class="dhall-label"+          >my-even</span+          > <span class="dhall-literal"+          >2</span+          > <span class="dhall-operator"+          >≡</span+          > <span class="dhall-syntax"+          >&lt;</span+          > <span class="dhall-label"+          >even</span+          > <span class="dhall-syntax"+          >|</span+          > <span class="dhall-label"+          >odd</span+          > <span class="dhall-syntax"+          >&gt;</span+          ><span class="dhall-syntax"+          >.</span+          ><span class="dhall-label"+          >even</span></pre></div+      ><h3+      >Source</h3+      ><div class="source-code"+        ><pre+          ><span class="dhall-keyword"+          >let</span+          > <span class="dhall-label"+          >my-even</span+          ><br+          />    <span class="dhall-syntax"+          >:</span+          > <span class="dhall-builtin"+          >Natural</span+          > <span class="dhall-syntax"+          >→</span+          > <span class="dhall-syntax"+          >&lt;</span+          > <span class="dhall-label"+          >even</span+          > <span class="dhall-syntax"+          >|</span+          > <span class="dhall-label"+          >odd</span+          > <span class="dhall-syntax"+          >&gt;</span+          ><br+          />    <span class="dhall-syntax"+          >=</span+          > <span class="dhall-syntax"+          >λ</span+          ><span class="dhall-syntax"+          >(</span+          ><span class="dhall-label"+          >n</span+          > <span class="dhall-syntax"+          >:</span+          > <span class="dhall-builtin"+          >Natural</span+          ><span class="dhall-syntax"+          >)</span+          > <span class="dhall-syntax"+          >→</span+          ><br+          />        <span class="dhall-keyword"+          >if</span+          > <span class="dhall-builtin"+          >Natural/even</span+          > <span class="dhall-label"+          >n</span+          > <span class="dhall-keyword"+          >then</span+          > <span class="dhall-syntax"+          >&lt;</span+          > <span class="dhall-label"+          >even</span+          > <span class="dhall-syntax"+          >|</span+          > <span class="dhall-label"+          >odd</span+          > <span class="dhall-syntax"+          >&gt;</span+          ><span class="dhall-syntax"+          >.</span+          ><span class="dhall-label"+          >even</span+          > <span class="dhall-keyword"+          >else</span+          > <span class="dhall-syntax"+          >&lt;</span+          > <span class="dhall-label"+          >even</span+          > <span class="dhall-syntax"+          >|</span+          > <span class="dhall-label"+          >odd</span+          > <span class="dhall-syntax"+          >&gt;</span+          ><span class="dhall-syntax"+          >.</span+          ><span class="dhall-label"+          >odd</span+          ><br+          /><br+          /><span class="dhall-keyword"+          >let</span+          > <span class="dhall-label"+          >example0</span+          > <span class="dhall-syntax"+          >=</span+          > <span class="dhall-keyword"+          >assert</span+          > <span class="dhall-syntax"+          >:</span+          > <span class="dhall-label"+          >my-even</span+          > <span class="dhall-literal"+          >1</span+          > <span class="dhall-operator"+          >≡</span+          > <span class="dhall-syntax"+          >&lt;</span+          > <span class="dhall-label"+          >even</span+          > <span class="dhall-syntax"+          >|</span+          > <span class="dhall-label"+          >odd</span+          > <span class="dhall-syntax"+          >&gt;</span+          ><span class="dhall-syntax"+          >.</span+          ><span class="dhall-label"+          >odd</span+          ><br+          /><br+          /><span class="dhall-keyword"+          >let</span+          > <span class="dhall-label"+          >example0</span+          > <span class="dhall-syntax"+          >=</span+          > <span class="dhall-keyword"+          >assert</span+          > <span class="dhall-syntax"+          >:</span+          > <span class="dhall-label"+          >my-even</span+          > <span class="dhall-literal"+          >2</span+          > <span class="dhall-operator"+          >≡</span+          > <span class="dhall-syntax"+          >&lt;</span+          > <span class="dhall-label"+          >even</span+          > <span class="dhall-syntax"+          >|</span+          > <span class="dhall-label"+          >odd</span+          > <span class="dhall-syntax"+          >&gt;</span+          ><span class="dhall-syntax"+          >.</span+          ><span class="dhall-label"+          >even</span+          ><br+          /><br+          /><span class="dhall-keyword"+          >in</span+          >  <span class="dhall-label"+          >my-even</span></pre></div></div></body></html>
+ tasty/data/golden/index.html view
@@ -0,0 +1,99 @@+<!DOCTYPE HTML>+<html+  ><head+    ><title+    >/</title+    ><link href="index.css" type="text/css" rel="stylesheet"+    /><link href="https://fonts.googleapis.com/css2?family=Fira+Code:wght@400;500;600;700&amp;family=Lato&amp;display=swap"+            type="text/css" rel="stylesheet"+    /><script src="index.js" type="text/javascript"+    /><meta charset="UTF-8"/></head+  ><body+    ><div class="nav-bar"+      ><img src="dhall-icon.svg" class="dhall-icon"+      /><p class="package-title"+      >test-package</p+      ><div class="nav-bar-content-divider"+      /><a id="switch-light-dark-mode" class="nav-option"+      >Switch Light/Dark Mode</a></div+    ><div class="main-container"+      ><h2 class="doc-title"+        ><span class="crumb-divider"+        >/</span+        ><a href="index.html"+        >test-package</a+        ><span class="crumb-divider"+        >/</span+        ><span href="index.html" class="title-crumb"/></h2+      ><a data-path="/" class="copy-to-clipboard"+        ><i+          ><small+          >Copy path to clipboard</small></i></a+      ><br+      /><h3+      >Exported files: </h3+      ><ul+        ><li+          ><a href="IndexesExample.dhall.html"+          >IndexesExample.dhall</a+          ><span class="of-type-token"+          >:</span+          ><span class="dhall-type source-code"+            ><pre+              ><span class="dhall-builtin"+              >Bool</span></pre></span></li+        ><li+          ><a href="InvalidMarkdown.dhall.html"+          >InvalidMarkdown.dhall</a></li+        ><li+          ><a href="MarkdownExample.dhall.html"+          >MarkdownExample.dhall</a></li+        ><li+          ><a href="Pair.dhall.html"+          >Pair.dhall</a+          ><span class="of-type-token"+          >:</span+          ><span class="dhall-type source-code"+            ><pre+              ><span class="dhall-syntax"+              >∀</span+              ><span class="dhall-syntax"+              >(</span+              ><span class="dhall-label"+              >A</span+              > <span class="dhall-syntax"+              >:</span+              > <span class="dhall-builtin"+              >Type</span+              ><span class="dhall-syntax"+              >)</span+              > <span class="dhall-syntax"+              >→</span+              > <span class="dhall-syntax"+              >∀</span+              ><span class="dhall-syntax"+              >(</span+              ><span class="dhall-label"+              >B</span+              > <span class="dhall-syntax"+              >:</span+              > <span class="dhall-builtin"+              >Type</span+              ><span class="dhall-syntax"+              >)</span+              > <span class="dhall-syntax"+              >→</span+              > <span class="dhall-builtin"+              >Type</span></pre></span></li+        ><li+          ><a href="package.dhall.html"+          >package.dhall</a></li></ul+      ><h3+      >Exported packages: </h3+      ><ul+        ><li+          ><a href="deep/nested/folder/index.html"+          >deep/nested/folder/</a></li+        ><li+          ><a href="a/index.html"+          >a/</a></li></ul></div></body></html>
+ tasty/data/golden/package.dhall.html view
@@ -0,0 +1,64 @@+<!DOCTYPE HTML>+<html+  ><head+    ><title+    >/package.dhall</title+    ><link href="index.css" type="text/css" rel="stylesheet"+    /><link href="https://fonts.googleapis.com/css2?family=Fira+Code:wght@400;500;600;700&amp;family=Lato&amp;display=swap"+            type="text/css" rel="stylesheet"+    /><script src="index.js" type="text/javascript"+    /><meta charset="UTF-8"/></head+  ><body+    ><div class="nav-bar"+      ><img src="dhall-icon.svg" class="dhall-icon"+      /><p class="package-title"+      >test-package</p+      ><div class="nav-bar-content-divider"+      /><a id="switch-light-dark-mode" class="nav-option"+      >Switch Light/Dark Mode</a></div+    ><div class="main-container"+      ><h2 class="doc-title"+        ><span class="crumb-divider"+        >/</span+        ><a href="index.html"+        >test-package</a+        ><span class="crumb-divider"+        >/</span+        ><span href="index.html" class="title-crumb"+        >package.dhall</span></h2+      ><a data-path="/package.dhall" class="copy-to-clipboard"+        ><i+          ><small+          >Copy path to clipboard</small></i></a+      ><br+      /><div class="doc-contents"+        ><p+        >This is your package entrypoint documentation</p>+</div+      ><h3+      >Source</h3+      ><div class="source-code"+        ><pre+          ><span class="dhall-syntax"+          >{</span+          > <span class="dhall-label"+          >Message</span+          > <span class="dhall-syntax"+          >=</span+          > ./Message.dhall<br+          /><span class="dhall-syntax"+          >,</span+          > <span class="dhall-label"+          >DeliveryStatus</span+          > <span class="dhall-syntax"+          >=</span+          > ./DeliveryStatus.dhall<br+          /><span class="dhall-syntax"+          >,</span+          > <span class="dhall-label"+          >Pair</span+          > <span class="dhall-syntax"+          >=</span+          > ./Pair.dhall<br+          /><span class="dhall-syntax"+          >}</span></pre></div></div></body></html>
+ tasty/data/package/IndexesExample.dhall view
@@ -0,0 +1,6 @@+{- Checking indexes -}++let x : Bool = True+let x : Natural = 1++in x@1
+ tasty/data/package/InvalidMarkdown.dhall view
@@ -0,0 +1,15 @@+-- Represents an status in our messaging system `+-- look, another line++let Pair = ./Pair.dhall++let DeliveryStatus =+    < Sent: Pair Natural Text {-| Message has been _sent_. It carries a ./Pair.dhall reference+                                    containing on the `first` field number of retries+                                    and on the `second` field the delivered text+                                -}+    | InProgress                -- | Message is on the way!+    | InQueue                   -- | Delivery for this message **hasn't** started+    >++in DeliveryStatus
+ tasty/data/package/MarkdownExample.dhall view
@@ -0,0 +1,41 @@+{-+# Heading 1++## Heading 2++### Heading 3++#### Heading 4++##### Heading 5++###### Heading 6++Message data type for our _messaging-system_ config.++    It is similar to the `kafka` message dto.+testing again another random text.++**NOTE**: This is really important to know++This allows you to:++* Send messages+* Receive messages, knowing that:+    - nothing works (?)+    - weird huh++As somebody said,++> The best way to code is to not code++Here I show you some haskell code++```haskell+main = putStrLn "dhall rulez"+```+-}+{ remitent: Text                         --| Remitent name+, deliveryStatus: ./DeliveryStatus.dhall --| Status+, body: Text                             --| Message body+}
+ tasty/data/package/Pair.dhall view
@@ -0,0 +1,11 @@++{-  Just a *Pair* right here+-}++let Pair+  : forall(A: Type) -- | Type of first position+  -> forall(B: Type) -- | Type of second position+  -> Type+  = λ(A: Type) -> λ(B: Type) -> {first: A, second: B}++in Pair
+ tasty/data/package/ShouldBeIgnored.dhall view
@@ -0,0 +1,4 @@+{-+Should be ignored since it's syntactically invalid+-}+{
+ tasty/data/package/a/b.dhall view
@@ -0,0 +1,5 @@+{-+Hi there boys+-}++let b = 1 in b
+ tasty/data/package/a/b/c.dhall view
@@ -0,0 +1,5 @@+{-+Hi there boys+-}++let c = 1 in c
+ tasty/data/package/a/b/c/a.dhall view
@@ -0,0 +1,5 @@+{-+Hi there boys+-}++let a = 1 in a
+ tasty/data/package/deep/nested/folder/my-even.dhall view
@@ -0,0 +1,12 @@+{-+Check if a natural is even or not returning an union data-type+-}+let my-even+    : Natural → < even | odd >+    = λ(n : Natural) →+        if Natural/even n then < even | odd>.even else < even | odd >.odd++let example0 = assert : my-even 1 === <even | odd>.odd+let example0 = assert : my-even 2 === <even | odd>.even++in my-even
+ tasty/data/package/package.dhall view
@@ -0,0 +1,7 @@+{-+This is your package entrypoint documentation+-}+{ Message = ./Message.dhall+, DeliveryStatus = ./DeliveryStatus.dhall+, Pair = ./Pair.dhall+}