{-# LANGUAGE OverloadedStrings #-}
{- |
   Module      : Text.Pandoc.Readers.RIS
   Copyright   : Copyright (C) 2022-2023 John MacFarlane
   License     : GNU GPL, version 2 or above

   Maintainer  : John MacFarlane <jgm@berkeley.edu>
   Stability   : alpha
   Portability : portable

Parses RIS bibliographies into a Pandoc document
with empty body and `references` and `nocite` fields
in the metadata.  A wildcard `nocite` is used so that
if the document is rendered in another format, the
entire bibliography will be printed.
-}
module Text.Pandoc.Readers.RIS
  ( readRIS
  )
where

import Text.Pandoc.Options
import Text.Pandoc.Definition
import Text.Pandoc.Parsing
import Data.Char (isAsciiUpper, isDigit, isSpace, ord, chr)
import Data.List (foldl')
import Citeproc (Reference(..), ItemId(..), Val(..), Date(..), DateParts(..),
                 toVariable)
import Text.Pandoc.Builder as B
import Text.Pandoc.Class (PandocMonad)
import Text.Pandoc.Citeproc.MetaValue (referenceToMetaValue)
import Text.Pandoc.Citeproc.Name (toName, NameOpts(..))
import Control.Monad.Except (throwError)
import qualified Data.Text as T
import Data.Text (Text)
import Data.Maybe (fromMaybe)
import qualified Data.Map as M
import Safe (readMay)

-- | Read RIS from an input string and return a Pandoc document.
-- The document will have only metadata, with an empty body.
-- The metadata will contain a `references` field with the
-- bibliography entries, and a `nocite` field with the wildcard `[@*]`.
readRIS :: (PandocMonad m, ToSources a)
        => ReaderOptions -> a -> m Pandoc
readRIS :: forall (m :: * -> *) a.
(PandocMonad m, ToSources a) =>
ReaderOptions -> a -> m Pandoc
readRIS ReaderOptions
_opts a
inp = do
  Either PandocError [Reference Text]
parsed <- forall (m :: * -> *) t st a.
(Monad m, ToSources t) =>
ParsecT Sources st m a -> st -> t -> m (Either PandocError a)
readWithM forall (m :: * -> *). PandocMonad m => RISParser m [Reference Text]
risReferences () a
inp
  case Either PandocError [Reference Text]
parsed of
    Right [Reference Text]
refs -> do
      [Reference Inlines]
refs' <- forall (t :: * -> *) (m :: * -> *) a b.
(Traversable t, Monad m) =>
(a -> m b) -> t a -> m (t b)
mapM (forall (t :: * -> *) (f :: * -> *) a b.
(Traversable t, Applicative f) =>
(a -> f b) -> t a -> f (t b)
traverse (forall (m :: * -> *) a. Monad m => a -> m a
return forall b c a. (b -> c) -> (a -> b) -> a -> c
. Text -> Inlines
text)) [Reference Text]
refs
      forall (m :: * -> *) a. Monad m => a -> m a
return forall a b. (a -> b) -> a -> b
$
        forall a b. (HasMeta a, ToMetaValue b) => Text -> b -> a -> a
setMeta Text
"nocite" ([Citation] -> Inlines -> Inlines
cite [Citation {citationId :: Text
citationId = Text
"*"
                                         , citationPrefix :: [Inline]
citationPrefix = []
                                         , citationSuffix :: [Inline]
citationSuffix = []
                                         , citationMode :: CitationMode
citationMode = CitationMode
NormalCitation
                                         , citationNoteNum :: Int
citationNoteNum = Int
0
                                         , citationHash :: Int
citationHash = Int
0}] (Text -> Inlines
str Text
"[@*]")) forall a b. (a -> b) -> a -> b
$
        forall a b. (HasMeta a, ToMetaValue b) => Text -> b -> a -> a
setMeta Text
"references" (forall a b. (a -> b) -> [a] -> [b]
map Reference Inlines -> MetaValue
referenceToMetaValue [Reference Inlines]
refs') forall a b. (a -> b) -> a -> b
$
        Blocks -> Pandoc
B.doc forall a. Monoid a => a
mempty
    Left PandocError
e       -> forall e (m :: * -> *) a. MonadError e m => e -> m a
throwError PandocError
e

type RISParser m = ParsecT Sources () m

risLine :: PandocMonad m => RISParser m (Text, Text)
risLine :: forall (m :: * -> *). PandocMonad m => RISParser m (Text, Text)
risLine = do
  Text
key <- String -> Text
T.pack forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> forall s (m :: * -> *) t u a.
Stream s m t =>
Int -> ParsecT s u m a -> ParsecT s u m [a]
count Int
2 (forall (m :: * -> *) s u.
(Monad m, Stream s m Char, UpdateSourcePos s Char) =>
(Char -> Bool) -> ParsecT s u m Char
satisfy (\Char
c -> Char -> Bool
isAsciiUpper Char
c Bool -> Bool -> Bool
|| Char -> Bool
isDigit Char
c))
  String
_ <- forall s (m :: * -> *) t u a.
Stream s m t =>
ParsecT s u m a -> ParsecT s u m [a]
many1 forall s (m :: * -> *) st.
(Stream s m Char, UpdateSourcePos s Char) =>
ParsecT s st m Char
spaceChar
  forall (m :: * -> *) s u.
(Monad m, Stream s m Char, UpdateSourcePos s Char) =>
Char -> ParsecT s u m Char
char Char
'-'
  Text
val <- (forall s (m :: * -> *) t u a.
Stream s m t =>
ParsecT s u m a -> ParsecT s u m [a]
many1 forall s (m :: * -> *) st.
(Stream s m Char, UpdateSourcePos s Char) =>
ParsecT s st m Char
spaceChar forall (f :: * -> *) a b. Applicative f => f a -> f b -> f b
*> forall (m :: * -> *) st. Monad m => ParsecT Sources st m Text
anyLine) forall s u (m :: * -> *) a.
ParsecT s u m a -> ParsecT s u m a -> ParsecT s u m a
<|> forall a. Monoid a => a
mempty forall (f :: * -> *) a b. Functor f => a -> f b -> f a
<$ forall (m :: * -> *) s u.
(Monad m, Stream s m Char, UpdateSourcePos s Char) =>
ParsecT s u m Char
newline
  forall (m :: * -> *) a. Monad m => a -> m a
return (Text
key, Text -> Text
T.strip Text
val)

risSeparator :: PandocMonad m => RISParser m ()
risSeparator :: forall (m :: * -> *). PandocMonad m => RISParser m ()
risSeparator = do
  forall s u (m :: * -> *) a. ParsecT s u m a -> ParsecT s u m a
try forall a b. (a -> b) -> a -> b
$ forall (m :: * -> *) s u.
(Monad m, Stream s m Char, UpdateSourcePos s Char) =>
String -> ParsecT s u m String
string String
"ER"
  String
_ <- forall s (m :: * -> *) t u a.
Stream s m t =>
ParsecT s u m a -> ParsecT s u m [a]
many1 forall s (m :: * -> *) st.
(Stream s m Char, UpdateSourcePos s Char) =>
ParsecT s st m Char
spaceChar
  forall (m :: * -> *) s u.
(Monad m, Stream s m Char, UpdateSourcePos s Char) =>
Char -> ParsecT s u m Char
char Char
'-'
  Text
_ <- forall (m :: * -> *) st. Monad m => ParsecT Sources st m Text
anyLine
  forall s (m :: * -> *) t u a.
Stream s m t =>
ParsecT s u m a -> ParsecT s u m ()
optional forall s (m :: * -> *) st.
(Stream s m Char, UpdateSourcePos s Char) =>
ParsecT s st m Text
blanklines

risRecord :: PandocMonad m => RISParser m [(Text, Text)]
risRecord :: forall (m :: * -> *). PandocMonad m => RISParser m [(Text, Text)]
risRecord = forall s (m :: * -> *) t u a end.
Stream s m t =>
ParsecT s u m a -> ParsecT s u m end -> ParsecT s u m [a]
manyTill forall (m :: * -> *). PandocMonad m => RISParser m (Text, Text)
risLine forall (m :: * -> *). PandocMonad m => RISParser m ()
risSeparator

risRecordToReference :: [(Text, Text)] -> Reference Text
risRecordToReference :: [(Text, Text)] -> Reference Text
risRecordToReference [(Text, Text)]
keys = forall {a}. Reference a -> Reference a
addId forall a b. (a -> b) -> a -> b
$ forall (t :: * -> *) a b.
Foldable t =>
(a -> b -> b) -> b -> t a -> b
foldr forall {a}.
(Eq a, IsString a) =>
(a, Text) -> Reference Text -> Reference Text
go forall {a}. Reference a
defref [(Text, Text)]
keys
 where
   go :: (a, Text) -> Reference Text -> Reference Text
go (a
key, Text
val) =
     case a
key of
       a
"TY" -> \Reference Text
ref -> Reference Text
ref{ referenceType :: Text
referenceType =
          forall a. a -> Maybe a -> a
fromMaybe Text
"misc" (forall k a. Ord k => k -> Map k a -> Maybe a
M.lookup Text
val Map Text Text
risTypes) }
       a
"ID" -> \Reference Text
ref -> Reference Text
ref{ referenceId :: ItemId
referenceId = Text -> ItemId
ItemId Text
val }
       a
"VL" -> forall {a}. Text -> a -> Reference a -> Reference a
addVar Text
"volume" Text
val
       a
"KW" -> \Reference Text
ref ->
         Reference Text
ref{ referenceVariables :: Map Variable (Val Text)
referenceVariables =
               forall k a.
Ord k =>
(Maybe a -> Maybe a) -> k -> Map k a -> Map k a
M.alter (\Maybe (Val Text)
x -> case Maybe (Val Text)
x of
                           Maybe (Val Text)
Nothing -> forall a. a -> Maybe a
Just forall a b. (a -> b) -> a -> b
$ forall a. Text -> Val a
TextVal Text
val
                           Just (TextVal Text
kws)
                                   -> forall a. a -> Maybe a
Just (forall a. Text -> Val a
TextVal (Text
kws forall a. Semigroup a => a -> a -> a
<> Text
", " forall a. Semigroup a => a -> a -> a
<> Text
val))
                           Maybe (Val Text)
_ -> Maybe (Val Text)
x)
               Variable
"keyword"
               (forall a. Reference a -> Map Variable (Val a)
referenceVariables Reference Text
ref) }
       a
"PB" -> forall {a}. Text -> a -> Reference a -> Reference a
addVar Text
"publisher" Text
val
       a
"PP" -> forall {a}. Text -> a -> Reference a -> Reference a
addVar Text
"publisher-place" Text
val
       a
"DO" -> forall {a}. Text -> a -> Reference a -> Reference a
addVar Text
"DOI" Text
val
       a
"SP" -> \Reference Text
ref ->
         case forall k a. Ord k => k -> Map k a -> Maybe a
M.lookup Variable
"page" (forall a. Reference a -> Map Variable (Val a)
referenceVariables Reference Text
ref) of
           Maybe (Val Text)
Nothing -> forall {a}. Text -> a -> Reference a -> Reference a
addVar Text
"page" Text
val Reference Text
ref
           Just (FancyVal Text
eg) -> forall {a}. Text -> a -> Reference a -> Reference a
addVar Text
"page" (Text
val forall a. Semigroup a => a -> a -> a
<> Text
eg) Reference Text
ref
           Maybe (Val Text)
_ -> Reference Text
ref
       a
"EP" -> \Reference Text
ref ->
         case forall k a. Ord k => k -> Map k a -> Maybe a
M.lookup Variable
"page" (forall a. Reference a -> Map Variable (Val a)
referenceVariables Reference Text
ref) of
           Maybe (Val Text)
Nothing -> forall {a}. Text -> a -> Reference a -> Reference a
addVar Text
"page" (Text
"-" forall a. Semigroup a => a -> a -> a
<> Text
val) Reference Text
ref
           Just (FancyVal Text
eg) -> forall {a}. Text -> a -> Reference a -> Reference a
addVar Text
"page" (Text
val forall a. Semigroup a => a -> a -> a
<> Text
"-" forall a. Semigroup a => a -> a -> a
<> Text
eg) Reference Text
ref
           Maybe (Val Text)
_ -> Reference Text
ref
       a
"AU" -> forall {a}. Variable -> Text -> Reference a -> Reference a
addName Variable
"author" Text
val
       a
"A1" -> forall {a}. Variable -> Text -> Reference a -> Reference a
addName Variable
"author" Text
val
       a
"ED" -> forall {a}. Variable -> Text -> Reference a -> Reference a
addName Variable
"editor" Text
val
       a
"A2" -> forall {a}. Variable -> Text -> Reference a -> Reference a
addName Variable
"editor" Text
val
       a
"TI" -> forall {a}. Text -> a -> Reference a -> Reference a
addVar Text
"title" Text
val
       a
"T1" -> forall {a}. Text -> a -> Reference a -> Reference a
addVar Text
"title" Text
val
       a
"CT" -> forall {a}. Text -> a -> Reference a -> Reference a
addVar Text
"title" Text
val
       a
"BT" -> \Reference Text
ref ->
         if forall a. Reference a -> Text
referenceType Reference Text
ref forall a. Eq a => a -> a -> Bool
== Text
"book"
            then forall {a}. Text -> a -> Reference a -> Reference a
addVar Text
"title" Text
val Reference Text
ref
            else forall {a}. Text -> a -> Reference a -> Reference a
addVar Text
"container-title" Text
val Reference Text
ref
       a
"JO" -> forall {a}. Text -> a -> Reference a -> Reference a
addVar Text
"container-title" Text
val
       a
"JF" -> forall {a}. Text -> a -> Reference a -> Reference a
addVar Text
"container-title" Text
val
       a
"T2" -> forall {a}. Text -> a -> Reference a -> Reference a
addVar Text
"container-title" Text
val
       a
"ET" -> forall {a}. Text -> a -> Reference a -> Reference a
addVar Text
"edition" Text
val
       a
"NV" -> forall {a}. Text -> a -> Reference a -> Reference a
addVar Text
"number-of-volumes" Text
val
       a
"AB" -> forall {a}. Text -> a -> Reference a -> Reference a
addVar Text
"abstract" Text
val
       a
"PY" -> forall {a}. Variable -> Text -> Reference a -> Reference a
addYear Variable
"issued" Text
val
       a
"Y1" -> forall {a}. Variable -> Text -> Reference a -> Reference a
addYear Variable
"issued" Text
val
       a
"IS" -> forall {a}. Text -> a -> Reference a -> Reference a
addVar Text
"issue" Text
val
       a
"SN" -> forall {a}. Text -> a -> Reference a -> Reference a
addVar Text
"ISSN" Text
val
       a
"LA" -> forall {a}. Text -> a -> Reference a -> Reference a
addVar Text
"language" Text
val
       a
"UR" -> forall {a}. Text -> a -> Reference a -> Reference a
addVar Text
"url" Text
val
       a
"LK" -> forall {a}. Text -> a -> Reference a -> Reference a
addVar Text
"url" Text
val
       a
_ -> forall a. a -> a
id -- TODO
   addVar :: Text -> a -> Reference a -> Reference a
addVar Text
k a
v Reference a
r = Reference a
r{ referenceVariables :: Map Variable (Val a)
referenceVariables =
                       forall k a. Ord k => k -> a -> Map k a -> Map k a
M.insert (Text -> Variable
toVariable Text
k) (forall a. a -> Val a
FancyVal a
v)
                       (forall a. Reference a -> Map Variable (Val a)
referenceVariables Reference a
r) }
   addName :: Variable -> Text -> Reference a -> Reference a
addName Variable
k Text
v Reference a
r =
     let new :: [Name]
new = forall (m :: * -> *). Monad m => NameOpts -> [Inline] -> m Name
toName NameOpts{ nameOptsPrefixIsNonDroppingParticle :: Bool
nameOptsPrefixIsNonDroppingParticle = Bool
False
                              , nameOptsUseJuniorComma :: Bool
nameOptsUseJuniorComma = Bool
False }
                forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a. Many a -> [a]
B.toList forall b c a. (b -> c) -> (a -> b) -> a -> c
.  Text -> Inlines
B.text forall a b. (a -> b) -> a -> b
$ Text
v
         f :: Maybe (Val a) -> Maybe (Val a)
f Maybe (Val a)
Nothing   = forall a. a -> Maybe a
Just (forall a. [Name] -> Val a
NamesVal [Name]
new)
         f (Just (NamesVal [Name]
ns)) = forall a. a -> Maybe a
Just (forall a. [Name] -> Val a
NamesVal ([Name]
new forall a. [a] -> [a] -> [a]
++ [Name]
ns))
         f (Just Val a
x) = forall a. a -> Maybe a
Just Val a
x
      in Reference a
r{ referenceVariables :: Map Variable (Val a)
referenceVariables =
              forall k a.
Ord k =>
(Maybe a -> Maybe a) -> k -> Map k a -> Map k a
M.alter forall {a}. Maybe (Val a) -> Maybe (Val a)
f Variable
k (forall a. Reference a -> Map Variable (Val a)
referenceVariables Reference a
r) }
   addYear :: Variable -> Text -> Reference a -> Reference a
addYear Variable
k Text
v Reference a
r =
     let d :: Val a
d = forall a. Date -> Val a
DateVal forall a b. (a -> b) -> a -> b
$
              case forall a. Read a => String -> Maybe a
readMay (Text -> String
T.unpack Text
v) of
                Maybe Int
Nothing ->
                  Date { dateParts :: [DateParts]
dateParts = []
                       , dateCirca :: Bool
dateCirca = Bool
False
                       , dateSeason :: Maybe Int
dateSeason = forall a. Maybe a
Nothing
                       , dateLiteral :: Maybe Text
dateLiteral = forall a. a -> Maybe a
Just Text
v }
                Just Int
y ->
                  Date { dateParts :: [DateParts]
dateParts = [[Int] -> DateParts
DateParts [Int
y]]
                       , dateCirca :: Bool
dateCirca = Bool
False
                       , dateSeason :: Maybe Int
dateSeason = forall a. Maybe a
Nothing
                       , dateLiteral :: Maybe Text
dateLiteral = forall a. Maybe a
Nothing }
      in Reference a
r{ referenceVariables :: Map Variable (Val a)
referenceVariables = forall k a. Ord k => k -> a -> Map k a -> Map k a
M.insert Variable
k forall {a}. Val a
d (forall a. Reference a -> Map Variable (Val a)
referenceVariables Reference a
r) }

   defref :: Reference a
defref = Reference{
       referenceId :: ItemId
referenceId = forall a. Monoid a => a
mempty
     , referenceType :: Text
referenceType = forall a. Monoid a => a
mempty
     , referenceDisambiguation :: Maybe DisambiguationData
referenceDisambiguation = forall a. Maybe a
Nothing
     , referenceVariables :: Map Variable (Val a)
referenceVariables = forall a. Monoid a => a
mempty }
   addId :: Reference a -> Reference a
addId Reference a
rec =
     if forall a. Reference a -> ItemId
referenceId Reference a
rec forall a. Eq a => a -> a -> Bool
== forall a. Monoid a => a
mempty
        then Reference a
rec{ referenceId :: ItemId
referenceId = Text -> ItemId
ItemId (Text
authors forall a. Semigroup a => a -> a -> a
<> Text
pubdate) }
        else Reference a
rec
   authors :: Text
authors = Text -> [Text] -> Text
T.intercalate Text
"_" forall a b. (a -> b) -> a -> b
$
               [(Char -> Bool) -> Text -> Text
T.takeWhile (\Char
c -> Char
c forall a. Eq a => a -> a -> Bool
/= Char
',' Bool -> Bool -> Bool
&& Bool -> Bool
not (Char -> Bool
isSpace Char
c)) Text
n
                 | (Text
k, Text
n) <- [(Text, Text)]
keys, Text
k forall a. Eq a => a -> a -> Bool
== Text
"AU" Bool -> Bool -> Bool
|| Text
k forall a. Eq a => a -> a -> Bool
== Text
"A1"]
   pubdate :: Text
pubdate = forall a. Monoid a => [a] -> a
mconcat [Text
"_" forall a. Semigroup a => a -> a -> a
<> Text
d | (Text
k, Text
d) <- [(Text, Text)]
keys, Text
k forall a. Eq a => a -> a -> Bool
== Text
"PY" Bool -> Bool -> Bool
|| Text
k forall a. Eq a => a -> a -> Bool
== Text
"Y1"]

risReferences :: PandocMonad m => RISParser m [Reference Text]
risReferences :: forall (m :: * -> *). PandocMonad m => RISParser m [Reference Text]
risReferences = do
  [[(Text, Text)]]
recs <- forall s u (m :: * -> *) a. ParsecT s u m a -> ParsecT s u m [a]
many forall (m :: * -> *). PandocMonad m => RISParser m [(Text, Text)]
risRecord
  forall (m :: * -> *) s u.
(Monad m, Stream s m Char, UpdateSourcePos s Char) =>
ParsecT s u m ()
spaces
  forall s (m :: * -> *) t u.
(Stream s m t, Show t) =>
ParsecT s u m ()
eof
  forall (m :: * -> *) a. Monad m => a -> m a
return forall a b. (a -> b) -> a -> b
$ [Reference Text] -> [Reference Text]
fixDuplicateIds forall a b. (a -> b) -> a -> b
$ forall a b. (a -> b) -> [a] -> [b]
map [(Text, Text)] -> Reference Text
risRecordToReference [[(Text, Text)]]
recs

fixDuplicateIds :: [Reference Text] -> [Reference Text]
fixDuplicateIds :: [Reference Text] -> [Reference Text]
fixDuplicateIds = forall a. [a] -> [a]
reverse forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a b. (a, b) -> b
snd forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall (t :: * -> *) b a.
Foldable t =>
(b -> a -> b) -> b -> t a -> b
foldl' forall {a}.
(Map ItemId Int, [Reference a])
-> Reference a -> (Map ItemId Int, [Reference a])
go (forall a. Monoid a => a
mempty, [])
 where
   go :: (Map ItemId Int, [Reference a])
-> Reference a -> (Map ItemId Int, [Reference a])
go (Map ItemId Int
ids_seen, [Reference a]
refs) Reference a
ref =
     case forall k a. Ord k => k -> Map k a -> Maybe a
M.lookup (forall a. Reference a -> ItemId
referenceId Reference a
ref) Map ItemId Int
ids_seen of
       Maybe Int
Nothing -> (forall k a. Ord k => k -> a -> Map k a -> Map k a
M.insert (forall a. Reference a -> ItemId
referenceId Reference a
ref) (Char -> Int
ord Char
'a') Map ItemId Int
ids_seen, Reference a
refforall a. a -> [a] -> [a]
:[Reference a]
refs)
       Just Int
n  -> (forall k a. Ord k => k -> a -> Map k a -> Map k a
M.insert (forall a. Reference a -> ItemId
referenceId Reference a
ref) (Int
nforall a. Num a => a -> a -> a
+Int
1) Map ItemId Int
ids_seen,
                     Reference a
ref{ referenceId :: ItemId
referenceId =
                          Text -> ItemId
ItemId forall b c a. (b -> c) -> (a -> b) -> a -> c
. (forall a. Semigroup a => a -> a -> a
<> Char -> Text
T.singleton (Int -> Char
chr Int
n)) forall b c a. (b -> c) -> (a -> b) -> a -> c
. ItemId -> Text
unItemId forall a b. (a -> b) -> a -> b
$
                           forall a. Reference a -> ItemId
referenceId Reference a
ref }
                    forall a. a -> [a] -> [a]
: [Reference a]
refs)

risTypes :: M.Map Text Text
risTypes :: Map Text Text
risTypes = forall k a. Ord k => [(k, a)] -> Map k a
M.fromList
    [ (Text
"ABST", Text
"article")
    , (Text
"ADVS", Text
"motion-picture")
    , (Text
"AGGR", Text
"dataset")
    , (Text
"ANCIENT", Text
"book")
    , (Text
"ART", Text
"graphic")
    , (Text
"BILL", Text
"bill")
    , (Text
"BLOG", Text
"post-weblog")
    , (Text
"BOOK", Text
"book")
    , (Text
"CASE", Text
"legal_case")
    , (Text
"CHAP", Text
"chapter")
    , (Text
"CHART", Text
"graphic")
    , (Text
"CLSWK", Text
"book")
    , (Text
"COMP", Text
"program")
    , (Text
"CONF", Text
"paper-conference")
    , (Text
"CPAPER", Text
"paper-conference")
    , (Text
"CTLG", Text
"catalog")
    , (Text
"DATA", Text
"dataset")
    , (Text
"DBASE", Text
"dataset")
    , (Text
"DICT", Text
"book")
    , (Text
"EBOOK", Text
"book")
    , (Text
"ECHAP", Text
"chapter")
    , (Text
"EDBOOK", Text
"book")
    , (Text
"EJOUR", Text
"article")
    , (Text
"WEB", Text
"webpage")
    , (Text
"ENCYC", Text
"entry-encyclopedia")
    , (Text
"EQUA", Text
"figure")
    , (Text
"FIGURE", Text
"figure")
    , (Text
"GEN", Text
"entry")
    , (Text
"GOVDOC", Text
"report")
    , (Text
"GRANT", Text
"report")
    , (Text
"HEAR", Text
"report")
    , (Text
"ICOMM", Text
"personal_communication")
    , (Text
"INPR", Text
"article-journal")
    , (Text
"JFULL", Text
"article-journal")
    , (Text
"JOUR", Text
"article-journal")
    , (Text
"LEGAL", Text
"legal_case")
    , (Text
"MANSCPT", Text
"manuscript")
    , (Text
"MAP", Text
"map")
    , (Text
"MGZN", Text
"article-magazine")
    , (Text
"MPCT", Text
"motion-picture")
    , (Text
"MULTI", Text
"webpage")
    , (Text
"MUSIC", Text
"musical_score")
    , (Text
"NEWS", Text
"article-newspaper")
    , (Text
"PAMP", Text
"pamphlet")
    , (Text
"PAT", Text
"patent")
    , (Text
"PCOMM", Text
"personal_communication")
    , (Text
"RPRT", Text
"report")
    , (Text
"SER", Text
"article")
    , (Text
"SLIDE", Text
"graphic")
    , (Text
"SOUND", Text
"musical_score")
    , (Text
"STAND", Text
"report")
    , (Text
"STAT", Text
"legislation")
    , (Text
"THES", Text
"thesis")
    , (Text
"UNBILL", Text
"bill")
    , (Text
"UNPB", Text
"unpublished")
    , (Text
"VIDEO", Text
"graphic") ]