    --- * -*- outline-regexp:"--- \\*"; -*-
    --- ** doc
    {-|

    CSV utilities.

    -}

    --- ** language
    {-# LANGUAGE OverloadedStrings    #-}

    --- ** exports
    module Hledger.Read.CsvUtils (
      CSV, CsvRecord, CsvValue,
      printCSV,
      -- * Tests
      tests_CsvUtils,
    )
    where

    --- ** imports
    import Prelude hiding (Applicative(..))
    import Data.List (intersperse)
    import Data.Text (Text)
    import qualified Data.Text as T
    import qualified Data.Text.Lazy as TL
    import qualified Data.Text.Lazy.Builder as TB

    import Hledger.Utils

    --- ** doctest setup
    -- $setup
    -- >>> :set -XOverloadedStrings

    type CSV       = [CsvRecord]
    type CsvRecord = [CsvValue]
    type CsvValue  = Text

    printCSV :: [CsvRecord] -> TL.Text
    printCSV :: [CsvRecord] -> Text
    printCSV = Builder -> Text
    TB.toLazyText (Builder -> Text)
    -> ([CsvRecord] -> Builder) -> [CsvRecord] -> Text
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . [Builder] -> Builder
    unlinesB ([Builder] -> Builder)
    -> ([CsvRecord] -> [Builder]) -> [CsvRecord] -> Builder
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . (CsvRecord -> Builder) -> [CsvRecord] -> [Builder]
    forall a b. (a -> b) -> [a] -> [b]
    map CsvRecord -> Builder
    printRecord
        where printRecord :: CsvRecord -> Builder
    printRecord = (Text -> Builder) -> CsvRecord -> Builder
    forall m a. Monoid m => (a -> m) -> [a] -> m
    forall (t :: * -> *) m a.
    (Foldable t, Monoid m) =>
    (a -> m) -> t a -> m
    foldMap Text -> Builder
    TB.fromText (CsvRecord -> Builder)
    -> (CsvRecord -> CsvRecord) -> CsvRecord -> Builder
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . Text -> CsvRecord -> CsvRecord
    forall a. a -> [a] -> [a]
    intersperse Text
    "," (CsvRecord -> CsvRecord)
    -> (CsvRecord -> CsvRecord) -> CsvRecord -> CsvRecord
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . (Text -> Text) -> CsvRecord -> CsvRecord
    forall a b. (a -> b) -> [a] -> [b]
    map Text -> Text
    printField
              printField :: Text -> Text
    printField = Text -> Text -> Text -> Text
    wrap Text
    "\"" Text
    "\"" (Text -> Text) -> (Text -> Text) -> Text -> Text
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . HasCallStack => Text -> Text -> Text -> Text
    Text -> Text -> Text -> Text
    T.replace Text
    "\"" Text
    "\"\""

    --- ** tests

    tests_CsvUtils :: TestTree
    tests_CsvUtils :: TestTree
    tests_CsvUtils = TestName -> [TestTree] -> TestTree
    testGroup TestName
    "CsvUtils" [
      ]