{-# LANGUAGE NoImplicitPrelude #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE CPP                      #-}
{-# LANGUAGE ScopedTypeVariables      #-}
{-# LANGUAGE PatternGuards            #-}
-----------------------------------------------------------------------------
-- |
-- Module      :  Text.CSL.Input.Bibutils
-- Copyright   :  (C) 2008 Andrea Rossato
-- License     :  BSD3
--
-- Maintainer  :  andrea.rossato@unitn.it
-- Stability   :  unstable
-- Portability :  unportable
--
-----------------------------------------------------------------------------

module Text.CSL.Input.Bibutils
    ( readBiblioFile
    , readBiblioString
    , BibFormat (..)
    , convertRefs
    ) where

import Prelude
import qualified Control.Exception      as E
import           Data.Aeson
import           Data.Aeson.Types       (parseMaybe)
import qualified Data.ByteString.Lazy   as BL
import qualified Data.ByteString        as BS
import qualified Data.HashMap.Strict    as HM
import           Data.Text              (Text)
import qualified Data.Text              as T
import qualified Data.Text.Lazy         as TL
import qualified Data.YAML.Aeson        as YA
import qualified Data.YAML              as Y
import qualified Data.Vector            as V
import           Data.Char
import qualified Data.Map               as M
import           System.FilePath        (takeExtension)
import           Text.CSL.Compat.Pandoc (readMarkdown)
import           Text.CSL.Exception
import           Text.CSL.Input.Bibtex
import           Text.CSL.Reference     hiding (Value)
import           Text.CSL.Util          (parseString)
import           Text.Pandoc            hiding (readMarkdown)
import qualified Text.Pandoc.UTF8       as UTF8

#ifdef USE_BIBUTILS
import           Control.Exception      (bracket, catch)
import           Control.Monad.Trans    (liftIO)
import           System.Directory
import           System.FilePath        ((<.>), (</>))
import           System.IO.Error        (isAlreadyExistsError)
import           Text.Bibutils
#endif

-- | Read a file with a bibliographic database. The database format
-- is recognized by the file extension.  The first argument is
-- a predicate to filter citation identifiers.
--
-- Supported formats are: @json@, @mods@, @bibtex@, @biblatex@, @ris@,
-- @endnote@, @endnotexml@, @isi@, @medline@, @copac@, and @nbib@.
readBiblioFile :: (Text -> Bool) -> FilePath -> IO [Reference]
readBiblioFile :: (Text -> Bool) -> FilePath -> IO [Reference]
readBiblioFile idpred :: Text -> Bool
idpred f :: FilePath
f
    = case FilePath -> FilePath
getExt FilePath
f of
        ".json"     -> FilePath -> IO ByteString
BL.readFile FilePath
f IO ByteString -> (ByteString -> IO [Reference]) -> IO [Reference]
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= (FilePath -> IO [Reference])
-> ([Reference] -> IO [Reference])
-> Either FilePath [Reference]
-> IO [Reference]
forall a c b. (a -> c) -> (b -> c) -> Either a b -> c
either
                       (CiteprocException -> IO [Reference]
forall e a. Exception e => e -> IO a
E.throwIO (CiteprocException -> IO [Reference])
-> (FilePath -> CiteprocException) -> FilePath -> IO [Reference]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. FilePath -> FilePath -> CiteprocException
ErrorReadingBibFile FilePath
f)
                       ([Reference] -> IO [Reference]
forall (m :: * -> *) a. Monad m => a -> m a
return ([Reference] -> IO [Reference])
-> ([Reference] -> [Reference]) -> [Reference] -> IO [Reference]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Text -> Bool) -> [Reference] -> [Reference]
filterEntries Text -> Bool
idpred) (Either FilePath [Reference] -> IO [Reference])
-> (ByteString -> Either FilePath [Reference])
-> ByteString
-> IO [Reference]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ByteString -> Either FilePath [Reference]
forall a. FromJSON a => ByteString -> Either FilePath a
eitherDecode
        ".yaml"     -> FilePath -> IO FilePath
UTF8.readFile FilePath
f IO FilePath -> (FilePath -> IO [Reference]) -> IO [Reference]
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= (FilePath -> IO [Reference])
-> ([Reference] -> IO [Reference])
-> Either FilePath [Reference]
-> IO [Reference]
forall a c b. (a -> c) -> (b -> c) -> Either a b -> c
either
                       (CiteprocException -> IO [Reference]
forall e a. Exception e => e -> IO a
E.throwIO (CiteprocException -> IO [Reference])
-> (FilePath -> CiteprocException) -> FilePath -> IO [Reference]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. FilePath -> FilePath -> CiteprocException
ErrorReadingBibFile FilePath
f) [Reference] -> IO [Reference]
forall (m :: * -> *) a. Monad m => a -> m a
return (Either FilePath [Reference] -> IO [Reference])
-> (FilePath -> Either FilePath [Reference])
-> FilePath
-> IO [Reference]
forall b c a. (b -> c) -> (a -> b) -> a -> c
.
                       (Text -> Bool) -> Text -> Either FilePath [Reference]
readYamlBib Text -> Bool
idpred (Text -> Either FilePath [Reference])
-> (FilePath -> Text) -> FilePath -> Either FilePath [Reference]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. FilePath -> Text
T.pack
        ".bib"      -> (Text -> Bool) -> Bool -> Bool -> FilePath -> IO [Reference]
readBibtex Text -> Bool
idpred Bool
False Bool
True FilePath
f
        ".bibtex"   -> (Text -> Bool) -> Bool -> Bool -> FilePath -> IO [Reference]
readBibtex Text -> Bool
idpred Bool
True Bool
True FilePath
f
        ".biblatex" -> (Text -> Bool) -> Bool -> Bool -> FilePath -> IO [Reference]
readBibtex Text -> Bool
idpred Bool
False Bool
True FilePath
f
#ifdef USE_BIBUTILS
        ".mods"     -> (Text -> Bool) -> FilePath -> BiblioIn -> IO [Reference]
readBiblioFile' Text -> Bool
idpred FilePath
f BiblioIn
mods_in
        ".ris"      -> (Text -> Bool) -> FilePath -> BiblioIn -> IO [Reference]
readBiblioFile' Text -> Bool
idpred FilePath
f BiblioIn
ris_in
        ".enl"      -> (Text -> Bool) -> FilePath -> BiblioIn -> IO [Reference]
readBiblioFile' Text -> Bool
idpred FilePath
f BiblioIn
endnote_in
        ".xml"      -> (Text -> Bool) -> FilePath -> BiblioIn -> IO [Reference]
readBiblioFile' Text -> Bool
idpred FilePath
f BiblioIn
endnotexml_in
        ".wos"      -> (Text -> Bool) -> FilePath -> BiblioIn -> IO [Reference]
readBiblioFile' Text -> Bool
idpred FilePath
f BiblioIn
isi_in
        ".medline"  -> (Text -> Bool) -> FilePath -> BiblioIn -> IO [Reference]
readBiblioFile' Text -> Bool
idpred FilePath
f BiblioIn
medline_in
        ".copac"    -> (Text -> Bool) -> FilePath -> BiblioIn -> IO [Reference]
readBiblioFile' Text -> Bool
idpred FilePath
f BiblioIn
copac_in
        ".nbib"     -> (Text -> Bool) -> FilePath -> BiblioIn -> IO [Reference]
readBiblioFile' Text -> Bool
idpred FilePath
f BiblioIn
nbib_in
        _           -> CiteprocException -> IO [Reference]
forall e a. Exception e => e -> IO a
E.throwIO (CiteprocException -> IO [Reference])
-> CiteprocException -> IO [Reference]
forall a b. (a -> b) -> a -> b
$ FilePath -> FilePath -> CiteprocException
ErrorReadingBibFile FilePath
f "the format of the bibliographic database could not be recognized from the file extension"
#else
        _           -> E.throwIO $ ErrorReadingBibFile f "bibliography format not supported"
#endif

data BibFormat
    = Json
    | Yaml
    | Bibtex
    | BibLatex
#ifdef USE_BIBUTILS
    | Ris
    | Endnote
    | EndnotXml
    | Isi
    | Medline
    | Copac
    | Mods
    | Nbib
#endif
    deriving Int -> BibFormat -> FilePath -> FilePath
[BibFormat] -> FilePath -> FilePath
BibFormat -> FilePath
(Int -> BibFormat -> FilePath -> FilePath)
-> (BibFormat -> FilePath)
-> ([BibFormat] -> FilePath -> FilePath)
-> Show BibFormat
forall a.
(Int -> a -> FilePath -> FilePath)
-> (a -> FilePath) -> ([a] -> FilePath -> FilePath) -> Show a
showList :: [BibFormat] -> FilePath -> FilePath
$cshowList :: [BibFormat] -> FilePath -> FilePath
show :: BibFormat -> FilePath
$cshow :: BibFormat -> FilePath
showsPrec :: Int -> BibFormat -> FilePath -> FilePath
$cshowsPrec :: Int -> BibFormat -> FilePath -> FilePath
Show

readBiblioString :: (Text -> Bool) -> BibFormat -> Text -> IO [Reference]
readBiblioString :: (Text -> Bool) -> BibFormat -> Text -> IO [Reference]
readBiblioString idpred :: Text -> Bool
idpred b :: BibFormat
b s :: Text
s
    | BibFormat
Json      <- BibFormat
b = (FilePath -> IO [Reference])
-> ([Reference] -> IO [Reference])
-> Either FilePath [Reference]
-> IO [Reference]
forall a c b. (a -> c) -> (b -> c) -> Either a b -> c
either (CiteprocException -> IO [Reference]
forall e a. Exception e => e -> IO a
E.throwIO (CiteprocException -> IO [Reference])
-> (FilePath -> CiteprocException) -> FilePath -> IO [Reference]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. FilePath -> CiteprocException
ErrorReadingBib)
                         [Reference] -> IO [Reference]
forall (m :: * -> *) a. Monad m => a -> m a
return (Either FilePath [Reference] -> IO [Reference])
-> Either FilePath [Reference] -> IO [Reference]
forall a b. (a -> b) -> a -> b
$ ByteString -> Either FilePath [Reference]
forall a. FromJSON a => ByteString -> Either FilePath a
eitherDecode
                                (ByteString -> Either FilePath [Reference])
-> ByteString -> Either FilePath [Reference]
forall a b. (a -> b) -> a -> b
$ Text -> ByteString
UTF8.fromTextLazy
                                (Text -> ByteString) -> Text -> ByteString
forall a b. (a -> b) -> a -> b
$ Text -> Text
TL.fromStrict Text
s
    | BibFormat
Yaml      <- BibFormat
b = (FilePath -> IO [Reference])
-> ([Reference] -> IO [Reference])
-> Either FilePath [Reference]
-> IO [Reference]
forall a c b. (a -> c) -> (b -> c) -> Either a b -> c
either (CiteprocException -> IO [Reference]
forall e a. Exception e => e -> IO a
E.throwIO (CiteprocException -> IO [Reference])
-> (FilePath -> CiteprocException) -> FilePath -> IO [Reference]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. FilePath -> CiteprocException
ErrorReadingBib)
                         [Reference] -> IO [Reference]
forall (m :: * -> *) a. Monad m => a -> m a
return (Either FilePath [Reference] -> IO [Reference])
-> Either FilePath [Reference] -> IO [Reference]
forall a b. (a -> b) -> a -> b
$ (Text -> Bool) -> Text -> Either FilePath [Reference]
readYamlBib Text -> Bool
idpred Text
s
    | BibFormat
Bibtex    <- BibFormat
b = (Text -> Bool) -> Bool -> Bool -> Text -> IO [Reference]
readBibtexString Text -> Bool
idpred Bool
True Bool
True Text
s
    | BibFormat
BibLatex  <- BibFormat
b = (Text -> Bool) -> Bool -> Bool -> Text -> IO [Reference]
readBibtexString Text -> Bool
idpred Bool
False Bool
True Text
s
#ifdef USE_BIBUTILS
    | BibFormat
Ris       <- BibFormat
b = BiblioIn -> IO [Reference]
go BiblioIn
ris_in
    | BibFormat
Endnote   <- BibFormat
b = BiblioIn -> IO [Reference]
go BiblioIn
endnote_in
    | BibFormat
EndnotXml <- BibFormat
b = BiblioIn -> IO [Reference]
go BiblioIn
endnotexml_in
    | BibFormat
Isi       <- BibFormat
b = BiblioIn -> IO [Reference]
go BiblioIn
isi_in
    | BibFormat
Medline   <- BibFormat
b = BiblioIn -> IO [Reference]
go BiblioIn
medline_in
    | BibFormat
Copac     <- BibFormat
b = BiblioIn -> IO [Reference]
go BiblioIn
copac_in
    | BibFormat
Mods      <- BibFormat
b = BiblioIn -> IO [Reference]
go BiblioIn
mods_in
    | BibFormat
Nbib      <- BibFormat
b = BiblioIn -> IO [Reference]
go BiblioIn
nbib_in
#endif
    | Bool
otherwise      = CiteprocException -> IO [Reference]
forall e a. Exception e => e -> IO a
E.throwIO (CiteprocException -> IO [Reference])
-> CiteprocException -> IO [Reference]
forall a b. (a -> b) -> a -> b
$ FilePath -> CiteprocException
ErrorReadingBib (FilePath -> CiteprocException) -> FilePath -> CiteprocException
forall a b. (a -> b) -> a -> b
$
                          "unsupported format " FilePath -> FilePath -> FilePath
forall a. [a] -> [a] -> [a]
++ BibFormat -> FilePath
forall a. Show a => a -> FilePath
show BibFormat
b
#ifdef USE_BIBUTILS
    where
      go :: BiblioIn -> IO [Reference]
go f :: BiblioIn
f = FilePath -> (FilePath -> IO [Reference]) -> IO [Reference]
forall a. FilePath -> (FilePath -> IO a) -> IO a
withTempDir "citeproc" ((FilePath -> IO [Reference]) -> IO [Reference])
-> (FilePath -> IO [Reference]) -> IO [Reference]
forall a b. (a -> b) -> a -> b
$ \tdir :: FilePath
tdir -> do
               let tfile :: FilePath
tfile = FilePath
tdir FilePath -> FilePath -> FilePath
</> "bibutils-tmp.biblio"
               FilePath -> FilePath -> IO ()
UTF8.writeFile FilePath
tfile (Text -> FilePath
T.unpack Text
s)
               (Text -> Bool) -> FilePath -> BiblioIn -> IO [Reference]
readBiblioFile' Text -> Bool
idpred FilePath
tfile BiblioIn
f
#endif

#ifdef USE_BIBUTILS
readBiblioFile' :: (Text -> Bool) -> FilePath -> BiblioIn -> IO [Reference]
readBiblioFile' :: (Text -> Bool) -> FilePath -> BiblioIn -> IO [Reference]
readBiblioFile' idpred :: Text -> Bool
idpred fin :: FilePath
fin bin :: BiblioIn
bin
    | BiblioIn
bin BiblioIn -> BiblioIn -> Bool
forall a. Eq a => a -> a -> Bool
== BiblioIn
biblatex_in = (Text -> Bool) -> Bool -> Bool -> FilePath -> IO [Reference]
readBibtex Text -> Bool
idpred Bool
False Bool
True FilePath
fin
    | Bool
otherwise      = FilePath -> (FilePath -> IO [Reference]) -> IO [Reference]
forall a. FilePath -> (FilePath -> IO a) -> IO a
withTempDir "citeproc"
                       ((FilePath -> IO [Reference]) -> IO [Reference])
-> (FilePath -> IO [Reference]) -> IO [Reference]
forall a b. (a -> b) -> a -> b
$ \tdir :: FilePath
tdir -> do
                            let tfile :: FilePath
tfile = FilePath
tdir FilePath -> FilePath -> FilePath
</> "bibutils-tmp"
                            (SomeException -> IO ()) -> IO () -> IO ()
forall e a. Exception e => (e -> IO a) -> IO a -> IO a
E.handle SomeException -> IO ()
handleBibfileError (IO () -> IO ()) -> IO () -> IO ()
forall a b. (a -> b) -> a -> b
$ do
                              ForeignPtr Param
param <- BiblioIn -> BiblioOut -> FilePath -> IO (ForeignPtr Param)
bibl_initparams BiblioIn
bin BiblioOut
bibtex_out "hs-bibutils"
                              ForeignPtr Bibl
bibl  <- IO (ForeignPtr Bibl)
bibl_init
                              ForeignPtr Param -> IO ()
unsetBOM        ForeignPtr Param
param
                              ForeignPtr Param -> Charset -> IO ()
setCharsetIn    ForeignPtr Param
param Charset
bibl_charset_unicode
                              ForeignPtr Param -> Charset -> IO ()
setCharsetOut   ForeignPtr Param
param Charset
bibl_charset_unicode
                              Status
_ <- ForeignPtr Param -> ForeignPtr Bibl -> FilePath -> IO Status
bibl_read  ForeignPtr Param
param ForeignPtr Bibl
bibl FilePath
fin
                              Status
_ <- ForeignPtr Param -> ForeignPtr Bibl -> FilePath -> IO Status
bibl_write ForeignPtr Param
param ForeignPtr Bibl
bibl FilePath
tfile
                              ForeignPtr Bibl -> IO ()
bibl_free ForeignPtr Bibl
bibl
                              ForeignPtr Param -> IO ()
bibl_freeparams ForeignPtr Param
param
                            [Reference]
refs <- (Text -> Bool) -> Bool -> Bool -> FilePath -> IO [Reference]
readBibtex Text -> Bool
idpred Bool
True Bool
False FilePath
tfile
                            [Reference] -> IO [Reference]
forall (m :: * -> *) a. Monad m => a -> m a
return ([Reference] -> IO [Reference]) -> [Reference] -> IO [Reference]
forall a b. (a -> b) -> a -> b
$! [Reference]
refs
  where handleBibfileError :: E.SomeException -> IO ()
        handleBibfileError :: SomeException -> IO ()
handleBibfileError e :: SomeException
e = CiteprocException -> IO ()
forall e a. Exception e => e -> IO a
E.throwIO (CiteprocException -> IO ()) -> CiteprocException -> IO ()
forall a b. (a -> b) -> a -> b
$ FilePath -> FilePath -> CiteprocException
ErrorReadingBibFile FilePath
fin (SomeException -> FilePath
forall a. Show a => a -> FilePath
show SomeException
e)

-- | Perform a function in a temporary directory and clean up.
withTempDir :: FilePath -> (FilePath -> IO a) -> IO a
withTempDir :: FilePath -> (FilePath -> IO a) -> IO a
withTempDir baseName :: FilePath
baseName = IO FilePath -> (FilePath -> IO ()) -> (FilePath -> IO a) -> IO a
forall a b c. IO a -> (a -> IO b) -> (a -> IO c) -> IO c
bracket (Integer -> FilePath -> IO FilePath
createTempDir 0 FilePath
baseName)
  (FilePath -> IO ()
removeDirectoryRecursive)

-- | Create a temporary directory with a unique name.
createTempDir :: Integer -> FilePath -> IO FilePath
createTempDir :: Integer -> FilePath -> IO FilePath
createTempDir num :: Integer
num baseName :: FilePath
baseName = do
  FilePath
sysTempDir <- IO FilePath
getTemporaryDirectory
  let dirName :: FilePath
dirName = FilePath
sysTempDir FilePath -> FilePath -> FilePath
</> FilePath
baseName FilePath -> FilePath -> FilePath
<.> Integer -> FilePath
forall a. Show a => a -> FilePath
show Integer
num
  IO FilePath -> IO FilePath
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (IO FilePath -> IO FilePath) -> IO FilePath -> IO FilePath
forall a b. (a -> b) -> a -> b
$ IO FilePath -> (IOError -> IO FilePath) -> IO FilePath
forall e a. Exception e => IO a -> (e -> IO a) -> IO a
Control.Exception.catch (FilePath -> IO ()
createDirectory FilePath
dirName IO () -> IO FilePath -> IO FilePath
forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> FilePath -> IO FilePath
forall (m :: * -> *) a. Monad m => a -> m a
return FilePath
dirName) ((IOError -> IO FilePath) -> IO FilePath)
-> (IOError -> IO FilePath) -> IO FilePath
forall a b. (a -> b) -> a -> b
$
      \e :: IOError
e -> if IOError -> Bool
isAlreadyExistsError IOError
e
            then Integer -> FilePath -> IO FilePath
createTempDir (Integer
num Integer -> Integer -> Integer
forall a. Num a => a -> a -> a
+ 1) FilePath
baseName
            else IOError -> IO FilePath
forall a. IOError -> IO a
ioError IOError
e
#endif

getExt :: String -> String
getExt :: FilePath -> FilePath
getExt = FilePath -> FilePath
takeExtension (FilePath -> FilePath)
-> (FilePath -> FilePath) -> FilePath -> FilePath
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Char -> Char) -> FilePath -> FilePath
forall a b. (a -> b) -> [a] -> [b]
map Char -> Char
toLower

readYamlBib :: (Text -> Bool) -> Text -> Either String [Reference]
readYamlBib :: (Text -> Bool) -> Text -> Either FilePath [Reference]
readYamlBib idpred :: Text -> Bool
idpred s :: Text
s =
  case Text -> Pandoc
readMarkdown Text
s' of
         (Pandoc meta :: Meta
meta _) -> Maybe MetaValue -> Either FilePath [Reference]
convertRefs (Text -> Meta -> Maybe MetaValue
lookupMeta "references" Meta
meta)
  where s' :: Text
s' = Text -> Text
addTop (Text -> Text) -> (Text -> Text) -> Text -> Text
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Text -> Text
addBottom
                    (Text -> Text) -> (Text -> Text) -> Text -> Text
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ByteString -> Text
UTF8.toText
                    (ByteString -> Text) -> (Text -> ByteString) -> Text -> Text
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Text -> Bool) -> ByteString -> ByteString
selectEntries Text -> Bool
idpred
                    (ByteString -> ByteString)
-> (Text -> ByteString) -> Text -> ByteString
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Text -> ByteString
UTF8.fromText
                    (Text -> Text) -> Text -> Text
forall a b. (a -> b) -> a -> b
$ Text
s
        addTop :: Text -> Text
addTop = ("---\n" Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<>)
        addBottom :: Text -> Text
addBottom = (Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> "...\n")

selectEntries :: (Text -> Bool) -> BS.ByteString -> BS.ByteString
selectEntries :: (Text -> Bool) -> ByteString -> ByteString
selectEntries idpred :: Text -> Bool
idpred bs :: ByteString
bs =
  case ByteString -> Either (Pos, FilePath) Value
forall v. FromJSON v => ByteString -> Either (Pos, FilePath) v
YA.decode1Strict ByteString
bs of
       Right (Array vs :: Array
vs) -> [Value] -> ByteString
forall v. ToJSON v => v -> ByteString
YA.encode1Strict ([Value] -> [Value]
filterObjects ([Value] -> [Value]) -> [Value] -> [Value]
forall a b. (a -> b) -> a -> b
$ Array -> [Value]
forall a. Vector a -> [a]
V.toList Array
vs)
       Right (Object o :: Object
o) ->
              case Text -> Object -> Maybe Value
forall k v. (Eq k, Hashable k) => k -> HashMap k v -> Maybe v
HM.lookup (FilePath -> Text
T.pack "references") Object
o of
                   Just (Array vs :: Array
vs) ->
                     HashMap Text [Value] -> ByteString
forall v. ToJSON v => v -> ByteString
YA.encode1Strict (Text -> [Value] -> HashMap Text [Value] -> HashMap Text [Value]
forall k v.
(Eq k, Hashable k) =>
k -> v -> HashMap k v -> HashMap k v
HM.insert (FilePath -> Text
T.pack "references")
                                    ([Value] -> [Value]
filterObjects ([Value] -> [Value]) -> [Value] -> [Value]
forall a b. (a -> b) -> a -> b
$ Array -> [Value]
forall a. Vector a -> [a]
V.toList Array
vs) HashMap Text [Value]
forall a. Monoid a => a
mempty)
                   _ -> ByteString
BS.empty
       Right _ -> ByteString
BS.empty
       Left (pos :: Pos
pos,e :: FilePath
e) -> CiteprocException -> ByteString
forall a e. Exception e => e -> a
E.throw (CiteprocException -> ByteString)
-> CiteprocException -> ByteString
forall a b. (a -> b) -> a -> b
$ FilePath -> CiteprocException
ErrorParsingReferences
                           (FilePath -> CiteprocException) -> FilePath -> CiteprocException
forall a b. (a -> b) -> a -> b
$ FilePath
e FilePath -> FilePath -> FilePath
forall a. [a] -> [a] -> [a]
++ " (line " FilePath -> FilePath -> FilePath
forall a. [a] -> [a] -> [a]
++ Int -> FilePath
forall a. Show a => a -> FilePath
show (Pos -> Int
Y.posLine Pos
pos) FilePath -> FilePath -> FilePath
forall a. [a] -> [a] -> [a]
++
                                  " column " FilePath -> FilePath -> FilePath
forall a. [a] -> [a] -> [a]
++ Int -> FilePath
forall a. Show a => a -> FilePath
show (Pos -> Int
Y.posColumn Pos
pos) FilePath -> FilePath -> FilePath
forall a. [a] -> [a] -> [a]
++
                                  ")"
    where filterObjects :: [Value] -> [Value]
filterObjects = (Value -> Bool) -> [Value] -> [Value]
forall a. (a -> Bool) -> [a] -> [a]
filter
               (\x :: Value
x -> case Value
x of
                        Object o :: Object
o ->
                            case Text -> Object -> Maybe Value
forall k v. (Eq k, Hashable k) => k -> HashMap k v -> Maybe v
HM.lookup (FilePath -> Text
T.pack "id") Object
o of
                                 Just i :: Value
i ->
                                  case (Value -> Parser Text) -> Value -> Maybe Text
forall a b. (a -> Parser b) -> a -> Maybe b
parseMaybe Value -> Parser Text
parseString Value
i of
                                       Just s :: Text
s -> Text -> Bool
idpred Text
s
                                       Nothing -> Bool
False
                                 _ -> Bool
False
                        _ -> Bool
False)

filterEntries :: (Text -> Bool) -> [Reference] -> [Reference]
filterEntries :: (Text -> Bool) -> [Reference] -> [Reference]
filterEntries idpred :: Text -> Bool
idpred = (Reference -> Bool) -> [Reference] -> [Reference]
forall a. (a -> Bool) -> [a] -> [a]
filter (\r :: Reference
r -> Text -> Bool
idpred (Literal -> Text
unLiteral (Reference -> Literal
refId Reference
r)))

convertRefs :: Maybe MetaValue -> Either String [Reference]
convertRefs :: Maybe MetaValue -> Either FilePath [Reference]
convertRefs Nothing = [Reference] -> Either FilePath [Reference]
forall a b. b -> Either a b
Right []
convertRefs (Just v :: MetaValue
v) =
  case Value -> Result [Reference]
forall a. FromJSON a => Value -> Result a
fromJSON (MetaValue -> Value
metaValueToJSON MetaValue
v) of
       Data.Aeson.Error s :: FilePath
s   ->
         -- check for empty string and treat it as empty list:
         -- ---
         -- references:
         -- ...
         case Value -> Result FilePath
forall a. FromJSON a => Value -> Result a
fromJSON (MetaValue -> Value
metaValueToJSON MetaValue
v) of
               Success (FilePath
"" :: String) -> [Reference] -> Either FilePath [Reference]
forall a b. b -> Either a b
Right []
               _          -> FilePath -> Either FilePath [Reference]
forall a b. a -> Either a b
Left FilePath
s
       Success x :: [Reference]
x            -> [Reference] -> Either FilePath [Reference]
forall a b. b -> Either a b
Right [Reference]
x

metaValueToJSON :: MetaValue -> Value
metaValueToJSON :: MetaValue -> Value
metaValueToJSON (MetaMap m :: Map Text MetaValue
m)       = Map Text Value -> Value
forall a. ToJSON a => a -> Value
toJSON (Map Text Value -> Value) -> Map Text Value -> Value
forall a b. (a -> b) -> a -> b
$ (MetaValue -> Value) -> Map Text MetaValue -> Map Text Value
forall a b k. (a -> b) -> Map k a -> Map k b
M.map MetaValue -> Value
metaValueToJSON Map Text MetaValue
m
metaValueToJSON (MetaList xs :: [MetaValue]
xs)     = [Value] -> Value
forall a. ToJSON a => a -> Value
toJSON ([Value] -> Value) -> [Value] -> Value
forall a b. (a -> b) -> a -> b
$ (MetaValue -> Value) -> [MetaValue] -> [Value]
forall a b. (a -> b) -> [a] -> [b]
map MetaValue -> Value
metaValueToJSON [MetaValue]
xs
metaValueToJSON (MetaString t :: Text
t)    = Text -> Value
forall a. ToJSON a => a -> Value
toJSON Text
t
metaValueToJSON (MetaBool b :: Bool
b)      = Bool -> Value
forall a. ToJSON a => a -> Value
toJSON Bool
b
metaValueToJSON (MetaInlines ils :: [Inline]
ils) = [Inline] -> Value
forall a. ToJSON a => a -> Value
toJSON [Inline]
ils
metaValueToJSON (MetaBlocks bs :: [Block]
bs)   = [Block] -> Value
forall a. ToJSON a => a -> Value
toJSON [Block]
bs