diff options
Diffstat (limited to 'src/Text/Pandoc/Citeproc/MetaValue.hs')
-rw-r--r-- | src/Text/Pandoc/Citeproc/MetaValue.hs | 252 |
1 files changed, 252 insertions, 0 deletions
diff --git a/src/Text/Pandoc/Citeproc/MetaValue.hs b/src/Text/Pandoc/Citeproc/MetaValue.hs new file mode 100644 index 000000000..53b14f904 --- /dev/null +++ b/src/Text/Pandoc/Citeproc/MetaValue.hs @@ -0,0 +1,252 @@ +{-# LANGUAGE OverloadedStrings #-} +module Text.Pandoc.Citeproc.MetaValue + ( referenceToMetaValue + , metaValueToReference + , metaValueToText + , metaValueToPath + ) +where + +import Citeproc.Types +import Text.Pandoc.Definition +import Text.Pandoc.Builder as B +import Text.Pandoc.Walk (query) +import Text.Pandoc.Shared (stringify) +import Data.Maybe +import Safe +import qualified Data.Set as Set +import qualified Data.Map as M +import qualified Data.Text as T +import Data.Text (Text) +import Text.Printf (printf) +import Control.Applicative ((<|>)) + +metaValueToText :: MetaValue -> Maybe Text +metaValueToText (MetaString t) = Just t +metaValueToText (MetaInlines ils) = Just $ stringify ils +metaValueToText (MetaBlocks bls) = Just $ stringify bls +metaValueToText (MetaList xs) = T.unwords <$> mapM metaValueToText xs +metaValueToText _ = Nothing + +metaValueToPath :: MetaValue -> Maybe FilePath +metaValueToPath = fmap T.unpack . metaValueToText + +metaValueToBool :: MetaValue -> Maybe Bool +metaValueToBool (MetaBool b) = Just b +metaValueToBool (MetaString "true") = Just True +metaValueToBool (MetaString "false") = Just False +metaValueToBool (MetaInlines ils) = + metaValueToBool (MetaString (stringify ils)) +metaValueToBool _ = Nothing + +referenceToMetaValue :: Reference Inlines -> MetaValue +referenceToMetaValue ref = + let ItemId id' = referenceId ref + type' = referenceType ref + in MetaMap $ M.insert "id" (MetaString id') + $ M.insert "type" (MetaString type') + $ M.map valToMetaValue + $ M.mapKeys fromVariable + $ referenceVariables ref + + +valToMetaValue :: Val Inlines -> MetaValue +valToMetaValue (TextVal t) = MetaString t +valToMetaValue (FancyVal ils) = MetaInlines (B.toList ils) +valToMetaValue (NumVal n) = MetaString (T.pack $ show n) +valToMetaValue (NamesVal ns) = MetaList $ map nameToMetaValue ns +valToMetaValue (DateVal d) = dateToMetaValue d + +nameToMetaValue :: Name -> MetaValue +nameToMetaValue name = + MetaMap $ + (maybe id (M.insert "family" . MetaString) (nameFamily name)) . + (maybe id (M.insert "given" . MetaString) (nameGiven name)) . + (maybe id (M.insert "dropping-particle" . MetaString) + (nameDroppingParticle name)) . + (maybe id (M.insert "non-dropping-particle" . MetaString) + (nameNonDroppingParticle name)) . + (maybe id (M.insert "suffix" . MetaString) (nameSuffix name)) . + (maybe id (M.insert "literal" . MetaString) (nameLiteral name)) . + (if nameCommaSuffix name + then M.insert "comma-suffix" (MetaBool True) + else id) . + (if nameStaticOrdering name + then M.insert "static-ordering" (MetaBool True) + else id) + $ mempty + +dateToMetaValue :: Date -> MetaValue +dateToMetaValue date = + MetaString $ + (case dateLiteral date of + Just l -> l + Nothing -> T.intercalate "/" $ map datePartsToEDTF $ dateParts date) + <> (if dateCirca date then "~" else "") + where + datePartsToEDTF (DateParts dps) = + T.pack $ + (case dps of + (y:_) | y > 9999 || y < -10000 -> ('y':) + _ -> id) $ + case dps of + (y:m:d:_) + | y < -1 -> printf "%05d-%02d-%02d" (y+1) m d + | otherwise -> printf "%04d-%02d-%02d" y m d + (y:m:[]) + | y < -1 -> printf "%05d-%02d" (y+1) m + | otherwise -> printf "%04d-%02d" y m + (y:[]) + | y < -1 -> printf "%05d" (y+1) + | otherwise -> printf "%04d" y + _ -> mempty + +metaValueToReference :: MetaValue -> Maybe (Reference Inlines) +metaValueToReference (MetaMap m) = do + let m' = M.mapKeys normalizeKey m + id' <- M.lookup "id" m' >>= metaValueToText + type' <- (M.lookup "type" m' >>= metaValueToText) <|> pure "" + let m'' = M.delete "id" $ M.delete "type" m' + let vars = M.mapKeys toVariable $ M.mapWithKey metaValueToVal m'' + return $ Reference { referenceId = ItemId id' + , referenceType = type' + , referenceDisambiguation = Nothing + , referenceVariables = vars } +metaValueToReference _ = Nothing + +metaValueToVal :: Text -> MetaValue -> Val Inlines +metaValueToVal k v + | k `Set.member` dateVariables + = DateVal $ metaValueToDate v + | k `Set.member` nameVariables + = NamesVal $ metaValueToNames v + | k == "other-ids" + = TextVal $ fromMaybe mempty $ metaValueToText v + -- will create space-separated list + | otherwise = + case v of + MetaString t -> TextVal t + MetaInlines ils -> FancyVal (B.fromList ils) + MetaBlocks bs -> FancyVal (B.fromList $ query id bs) + MetaBool b -> TextVal (if b then "true" else "false") + MetaList _ -> TextVal mempty + MetaMap _ -> TextVal mempty + +metaValueToDate :: MetaValue -> Date +metaValueToDate (MetaMap m) = + Date + { dateParts = dateparts + , dateCirca = circa + , dateSeason = season + , dateLiteral = literal } + where + dateparts = case M.lookup "date-parts" m of + Just (MetaList xs) -> + mapMaybe metaValueToDateParts xs + Just _ -> [] + Nothing -> + maybe [] (:[]) $ metaValueToDateParts (MetaMap m) + circa = fromMaybe False $ + M.lookup "circa" m >>= metaValueToBool + season = M.lookup "season" m >>= metaValueToInt + literal = M.lookup "literal" m >>= metaValueToText +metaValueToDate (MetaList xs) = + Date{ dateParts = mapMaybe metaValueToDateParts xs + , dateCirca = False + , dateSeason = Nothing + , dateLiteral = Nothing } +metaValueToDate x = + fromMaybe emptyDate $ metaValueToText x >>= rawDateEDTF + + +metaValueToInt :: MetaValue -> Maybe Int +metaValueToInt x = metaValueToText x >>= readMay . T.unpack + +metaValueToDateParts :: MetaValue -> Maybe DateParts +metaValueToDateParts (MetaList xs) = + Just $ DateParts $ map (fromMaybe 0 . metaValueToInt) xs +metaValueToDateParts (MetaMap m) = + case (M.lookup "year" m >>= metaValueToInt, + ((M.lookup "month" m >>= metaValueToInt) + <|> + ((+ 20) <$> (M.lookup "season" m >>= metaValueToInt))), + M.lookup "day" m >>= metaValueToInt) of + (Just y, Just mo, Just d) -> Just $ DateParts [y, mo, d] + (Just y, Just mo, Nothing) -> Just $ DateParts [y, mo] + (Just y, Nothing, _) -> Just $ DateParts [y] + _ -> Nothing +metaValueToDateParts _ = Nothing + +emptyDate :: Date +emptyDate = Date { dateParts = [] + , dateCirca = False + , dateSeason = Nothing + , dateLiteral = Nothing } + +metaValueToNames :: MetaValue -> [Name] +metaValueToNames (MetaList xs) = mapMaybe metaValueToName xs +metaValueToNames x = maybeToList $ metaValueToName x + +metaValueToName :: MetaValue -> Maybe Name +metaValueToName (MetaMap m) = extractParticles <$> + Just Name + { nameFamily = family + , nameGiven = given + , nameDroppingParticle = dropping + , nameNonDroppingParticle = nondropping + , nameSuffix = suffix + , nameCommaSuffix = commasuffix + , nameStaticOrdering = staticordering + , nameLiteral = literal + } + where + family = M.lookup "family" m >>= metaValueToText + given = M.lookup "given" m >>= metaValueToText + dropping = M.lookup "dropping-particle" m + >>= metaValueToText + nondropping = M.lookup "non-dropping-particle" m + >>= metaValueToText + suffix = M.lookup "suffix" m >>= metaValueToText + commasuffix = fromMaybe False $ + M.lookup "comma-suffix" m >>= metaValueToBool + staticordering = fromMaybe False $ + M.lookup "static-ordering" m >>= metaValueToBool + literal = M.lookup "literal" m >>= metaValueToText +metaValueToName x = extractParticles <$> + case metaValueToText x of + Nothing -> Nothing + Just lit -> Just Name + { nameFamily = Nothing + , nameGiven = Nothing + , nameDroppingParticle = Nothing + , nameNonDroppingParticle = Nothing + , nameSuffix = Nothing + , nameCommaSuffix = False + , nameStaticOrdering = False + , nameLiteral = Just lit } + +dateVariables :: Set.Set Text +dateVariables = Set.fromList + [ "accessed", "container", "event-date", "issued", + "original-date", "submitted" ] + +nameVariables :: Set.Set Text +nameVariables = Set.fromList + [ "author", "collection-editor", "composer", + "container-author", "director", "editor", + "editorial-director", "illustrator", + "interviewer", "original-author", + "recipient", "reviewed-author", + "translator" ] + +normalizeKey :: Text -> Text +normalizeKey k = + case T.toLower k of + "doi" -> "DOI" + "isbn" -> "ISBN" + "issn" -> "ISSN" + "pmcid" -> "PMCID" + "pmid" -> "PMID" + "url" -> "URL" + x -> x + |