{-# 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 qualified Data.Text              as T
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 :: (String -> Bool) -> FilePath -> IO [Reference]
readBiblioFile :: (String -> Bool) -> String -> IO [Reference]
readBiblioFile idpred :: String -> Bool
idpred f :: String
f
    = case String -> String
getExt String
f of
        ".json"     -> String -> IO ByteString
BL.readFile String
f IO ByteString -> (ByteString -> IO [Reference]) -> IO [Reference]
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= (String -> IO [Reference])
-> ([Reference] -> IO [Reference])
-> Either String [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])
-> (String -> CiteprocException) -> String -> IO [Reference]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> String -> CiteprocException
ErrorReadingBibFile String
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
. (String -> Bool) -> [Reference] -> [Reference]
filterEntries String -> Bool
idpred) (Either String [Reference] -> IO [Reference])
-> (ByteString -> Either String [Reference])
-> ByteString
-> IO [Reference]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ByteString -> Either String [Reference]
forall a. FromJSON a => ByteString -> Either String a
eitherDecode
        ".yaml"     -> String -> IO String
UTF8.readFile String
f IO String -> (String -> IO [Reference]) -> IO [Reference]
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= (String -> IO [Reference])
-> ([Reference] -> IO [Reference])
-> Either String [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])
-> (String -> CiteprocException) -> String -> IO [Reference]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> String -> CiteprocException
ErrorReadingBibFile String
f) [Reference] -> IO [Reference]
forall (m :: * -> *) a. Monad m => a -> m a
return (Either String [Reference] -> IO [Reference])
-> (String -> Either String [Reference])
-> String
-> IO [Reference]
forall b c a. (b -> c) -> (a -> b) -> a -> c
.
                       (String -> Bool) -> String -> Either String [Reference]
readYamlBib String -> Bool
idpred
        ".bib"      -> (String -> Bool) -> Bool -> Bool -> String -> IO [Reference]
readBibtex String -> Bool
idpred Bool
False Bool
True String
f
        ".bibtex"   -> (String -> Bool) -> Bool -> Bool -> String -> IO [Reference]
readBibtex String -> Bool
idpred Bool
True Bool
True String
f
        ".biblatex" -> (String -> Bool) -> Bool -> Bool -> String -> IO [Reference]
readBibtex String -> Bool
idpred Bool
False Bool
True String
f
#ifdef USE_BIBUTILS
        ".mods"     -> (String -> Bool) -> String -> BiblioIn -> IO [Reference]
readBiblioFile' String -> Bool
idpred String
f BiblioIn
mods_in
        ".ris"      -> (String -> Bool) -> String -> BiblioIn -> IO [Reference]
readBiblioFile' String -> Bool
idpred String
f BiblioIn
ris_in
        ".enl"      -> (String -> Bool) -> String -> BiblioIn -> IO [Reference]
readBiblioFile' String -> Bool
idpred String
f BiblioIn
endnote_in
        ".xml"      -> (String -> Bool) -> String -> BiblioIn -> IO [Reference]
readBiblioFile' String -> Bool
idpred String
f BiblioIn
endnotexml_in
        ".wos"      -> (String -> Bool) -> String -> BiblioIn -> IO [Reference]
readBiblioFile' String -> Bool
idpred String
f BiblioIn
isi_in
        ".medline"  -> (String -> Bool) -> String -> BiblioIn -> IO [Reference]
readBiblioFile' String -> Bool
idpred String
f BiblioIn
medline_in
        ".copac"    -> (String -> Bool) -> String -> BiblioIn -> IO [Reference]
readBiblioFile' String -> Bool
idpred String
f BiblioIn
copac_in
        ".nbib"     -> (String -> Bool) -> String -> BiblioIn -> IO [Reference]
readBiblioFile' String -> Bool
idpred String
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
$ String -> String -> CiteprocException
ErrorReadingBibFile String
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 -> String -> String
[BibFormat] -> String -> String
BibFormat -> String
(Int -> BibFormat -> String -> String)
-> (BibFormat -> String)
-> ([BibFormat] -> String -> String)
-> Show BibFormat
forall a.
(Int -> a -> String -> String)
-> (a -> String) -> ([a] -> String -> String) -> Show a
showList :: [BibFormat] -> String -> String
$cshowList :: [BibFormat] -> String -> String
show :: BibFormat -> String
$cshow :: BibFormat -> String
showsPrec :: Int -> BibFormat -> String -> String
$cshowsPrec :: Int -> BibFormat -> String -> String
Show

readBiblioString :: (String -> Bool) -> BibFormat -> String -> IO [Reference]
readBiblioString :: (String -> Bool) -> BibFormat -> String -> IO [Reference]
readBiblioString idpred :: String -> Bool
idpred b :: BibFormat
b s :: String
s
    | BibFormat
Json      <- BibFormat
b = (String -> IO [Reference])
-> ([Reference] -> IO [Reference])
-> Either String [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])
-> (String -> CiteprocException) -> String -> IO [Reference]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> CiteprocException
ErrorReadingBib)
                         [Reference] -> IO [Reference]
forall (m :: * -> *) a. Monad m => a -> m a
return (Either String [Reference] -> IO [Reference])
-> Either String [Reference] -> IO [Reference]
forall a b. (a -> b) -> a -> b
$ ByteString -> Either String [Reference]
forall a. FromJSON a => ByteString -> Either String a
eitherDecode (ByteString -> Either String [Reference])
-> ByteString -> Either String [Reference]
forall a b. (a -> b) -> a -> b
$ String -> ByteString
UTF8.fromStringLazy String
s
    | BibFormat
Yaml      <- BibFormat
b = (String -> IO [Reference])
-> ([Reference] -> IO [Reference])
-> Either String [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])
-> (String -> CiteprocException) -> String -> IO [Reference]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> CiteprocException
ErrorReadingBib)
                         [Reference] -> IO [Reference]
forall (m :: * -> *) a. Monad m => a -> m a
return (Either String [Reference] -> IO [Reference])
-> Either String [Reference] -> IO [Reference]
forall a b. (a -> b) -> a -> b
$ (String -> Bool) -> String -> Either String [Reference]
readYamlBib String -> Bool
idpred String
s
    | BibFormat
Bibtex    <- BibFormat
b = (String -> Bool) -> Bool -> Bool -> String -> IO [Reference]
readBibtexString String -> Bool
idpred Bool
True Bool
True String
s
    | BibFormat
BibLatex  <- BibFormat
b = (String -> Bool) -> Bool -> Bool -> String -> IO [Reference]
readBibtexString String -> Bool
idpred Bool
False Bool
True String
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
$ String -> CiteprocException
ErrorReadingBib (String -> CiteprocException) -> String -> CiteprocException
forall a b. (a -> b) -> a -> b
$
                          "unsupported format " String -> String -> String
forall a. [a] -> [a] -> [a]
++ BibFormat -> String
forall a. Show a => a -> String
show BibFormat
b
#ifdef USE_BIBUTILS
    where
      go :: BiblioIn -> IO [Reference]
go f :: BiblioIn
f = String -> (String -> IO [Reference]) -> IO [Reference]
forall a. String -> (String -> IO a) -> IO a
withTempDir "citeproc" ((String -> IO [Reference]) -> IO [Reference])
-> (String -> IO [Reference]) -> IO [Reference]
forall a b. (a -> b) -> a -> b
$ \tdir :: String
tdir -> do
               let tfile :: String
tfile = String
tdir String -> String -> String
</> "bibutils-tmp.biblio"
               String -> String -> IO ()
UTF8.writeFile String
tfile String
s
               (String -> Bool) -> String -> BiblioIn -> IO [Reference]
readBiblioFile' String -> Bool
idpred String
tfile BiblioIn
f
#endif

#ifdef USE_BIBUTILS
readBiblioFile' :: (String -> Bool) -> FilePath -> BiblioIn -> IO [Reference]
readBiblioFile' :: (String -> Bool) -> String -> BiblioIn -> IO [Reference]
readBiblioFile' idpred :: String -> Bool
idpred fin :: String
fin bin :: BiblioIn
bin
    | BiblioIn
bin BiblioIn -> BiblioIn -> Bool
forall a. Eq a => a -> a -> Bool
== BiblioIn
biblatex_in = (String -> Bool) -> Bool -> Bool -> String -> IO [Reference]
readBibtex String -> Bool
idpred Bool
False Bool
True String
fin
    | Bool
otherwise      = String -> (String -> IO [Reference]) -> IO [Reference]
forall a. String -> (String -> IO a) -> IO a
withTempDir "citeproc"
                       ((String -> IO [Reference]) -> IO [Reference])
-> (String -> IO [Reference]) -> IO [Reference]
forall a b. (a -> b) -> a -> b
$ \tdir :: String
tdir -> do
                            let tfile :: String
tfile = String
tdir String -> String -> String
</> "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 -> String -> 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 -> String -> IO Status
bibl_read  ForeignPtr Param
param ForeignPtr Bibl
bibl String
fin
                              Status
_ <- ForeignPtr Param -> ForeignPtr Bibl -> String -> IO Status
bibl_write ForeignPtr Param
param ForeignPtr Bibl
bibl String
tfile
                              ForeignPtr Bibl -> IO ()
bibl_free ForeignPtr Bibl
bibl
                              ForeignPtr Param -> IO ()
bibl_freeparams ForeignPtr Param
param
                            [Reference]
refs <- (String -> Bool) -> Bool -> Bool -> String -> IO [Reference]
readBibtex String -> Bool
idpred Bool
True Bool
False String
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
$ String -> String -> CiteprocException
ErrorReadingBibFile String
fin (SomeException -> String
forall a. Show a => a -> String
show SomeException
e)

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

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

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

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

selectEntries :: (String -> Bool) -> BS.ByteString -> BS.ByteString
selectEntries :: (String -> Bool) -> ByteString -> ByteString
selectEntries idpred :: String -> Bool
idpred bs :: ByteString
bs =
  case ByteString -> Either (Pos, String) Value
forall v. FromJSON v => ByteString -> Either (Pos, String) 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 (String -> 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 (String -> 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 :: String
e) -> CiteprocException -> ByteString
forall a e. Exception e => e -> a
E.throw (CiteprocException -> ByteString)
-> CiteprocException -> ByteString
forall a b. (a -> b) -> a -> b
$ String -> CiteprocException
ErrorParsingReferences
                           (String -> CiteprocException) -> String -> CiteprocException
forall a b. (a -> b) -> a -> b
$ String
e String -> String -> String
forall a. [a] -> [a] -> [a]
++ " (line " String -> String -> String
forall a. [a] -> [a] -> [a]
++ Int -> String
forall a. Show a => a -> String
show (Pos -> Int
Y.posLine Pos
pos) String -> String -> String
forall a. [a] -> [a] -> [a]
++
                                  " column " String -> String -> String
forall a. [a] -> [a] -> [a]
++ Int -> String
forall a. Show a => a -> String
show (Pos -> Int
Y.posColumn Pos
pos) String -> String -> String
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 (String -> Text
T.pack "id") Object
o of
                                 Just i :: Value
i ->
                                  case (Value -> Parser String) -> Value -> Maybe String
forall a b. (a -> Parser b) -> a -> Maybe b
parseMaybe Value -> Parser String
parseString Value
i of
                                       Just s :: String
s -> String -> Bool
idpred String
s
                                       Nothing -> Bool
False
                                 _ -> Bool
False
                        _ -> Bool
False)

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

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