citeproc 0.12 → 0.13
raw patch · 8 files changed
+206/−78 lines, 8 filesPVP ok
version bump matches the API change (PVP)
API changes (from Hackage documentation)
+ Citeproc.Types: [citationResetPosition] :: Citation a -> Bool
- Citeproc.Types: Citation :: Maybe Text -> Maybe Int -> Maybe a -> Maybe a -> [CitationItem a] -> Citation a
+ Citeproc.Types: Citation :: Maybe Text -> Bool -> Maybe Int -> Maybe a -> Maybe a -> [CitationItem a] -> Citation a
Files
- CHANGELOG.md +9/−0
- citeproc.cabal +1/−5
- man/citeproc.1 +58/−52
- man/citeproc.1.md +9/−2
- src/Citeproc/Eval.hs +10/−6
- src/Citeproc/Types.hs +16/−7
- test/Spec.hs +7/−6
- test/extra/issue_160.txt +96/−0
CHANGELOG.md view
@@ -1,5 +1,14 @@ # citeproc changelog +## 0.13++ * Add `citationResetPosition` field to `Citation`. [API change]+ When this field is set, it causes the processor to forget all+ information about past citations. This affects processing of+ `position`. The intended usage is to set this for the first+ citation of every chapter, so that "subsequent" behavior is+ reset at chapter boundaries. See #160 for discussion.+ ## 0.12 * Fix suppression of substituted variables for number,
citeproc.cabal view
@@ -1,6 +1,6 @@ cabal-version: 2.2 name: citeproc-version: 0.12+version: 0.13 synopsis: Generates citations and bibliography from CSL styles. description: citeproc parses CSL style files and uses them to generate a list of formatted citations and bibliography@@ -25,10 +25,6 @@ test/csl/*.txt test/extra/*.txt test/overrides/*.txt-tested-with: GHC == 8.0.2, GHC == 8.2.2,- GHC == 8.4.4, GHC == 8.6.5,- GHC == 8.8.4, GHC == 8.10.7,- GHC == 9.0.2, GHC == 9.2.2 source-repository head type: git
man/citeproc.1 view
@@ -1,6 +1,6 @@-.\" Automatically generated by Pandoc 3.6+.\" Automatically generated by Pandoc 3.8.3 .\"-.TH "citeproc" "1" "" "citeproc 0.8.1.1"+.TH "citeproc" "1" "" "citeproc 0.12" .SH NAME citeproc \- process citations using a CSL stylesheet. .SH SYNOPSIS@@ -23,7 +23,7 @@ Specify a CSL abbreviations file. .TP \f[CR]l\f[R] \f[I]LANG\f[R], \f[CR]\-\-lang=\f[R]\f[I]LANG\f[R]-Specify a locale to override the style\[cq]s default.+Specify a locale to override the style\(cqs default. A BCP 47 language tag is expected: for example, \f[CR]en\f[R], \f[CR]de\f[R], \f[CR]en\-US\f[R], \f[CR]fr\-CA\f[R], \f[CR]ug\-Cyrl\f[R].@@ -31,16 +31,16 @@ specify options for collation. Here are some examples: .RS-.IP \[bu] 2-\f[CR]zh\-u\-co\-pinyin\f[R] \[en] Chinese with the Pinyin collation.-.IP \[bu] 2-\f[CR]es\-u\-co\-trad\f[R] \[en] Spanish with the traditional collation+.IP \(bu 2+\f[CR]zh\-u\-co\-pinyin\f[R] \(en Chinese with the Pinyin collation.+.IP \(bu 2+\f[CR]es\-u\-co\-trad\f[R] \(en Spanish with the traditional collation (with \f[CR]Ch\f[R] sorting after \f[CR]C\f[R]).-.IP \[bu] 2-\f[CR]fr\-u\-kb\f[R] \[en] French with \[lq]backwards\[rq] accent-sorting (with \f[CR]coté\f[R] sorting after \f[CR]côte\f[R]).-.IP \[bu] 2-\f[CR]en\-US\-u\-kf\-upper\f[R] \[en] English with uppercase letters+.IP \(bu 2+\f[CR]fr\-u\-kb\f[R] \(en French with \(lqbackwards\(rq accent sorting+(with \f[CR]coté\f[R] sorting after \f[CR]côte\f[R]).+.IP \(bu 2+\f[CR]en\-US\-u\-kf\-upper\f[R] \(en English with uppercase letters sorting before lower (default is lower before upper). .RE .TP@@ -71,11 +71,11 @@ The input JSON should have the structure: .IP .EX-{ \[dq]citations\[dq]: [ \f[B]...list\f[R] \f[B]of\f[R] \f[B]citations...\f[R] ],- \[dq]references\[dq]: [ \f[B]...list\f[R] \f[B]of\f[R] \f[B]references...\f[R] ],- \[dq]style\[dq]: \[dq]<style>...</style>\[dq],- \[dq]abbreviations\[dq]: { \f[B]...abbreviations...\f[R] },- \[dq]lang\[dq]: \[dq]fr\-FR\[dq] }+{ \(dqcitations\(dq: [ \f[B]...list\f[R] \f[B]of\f[R] \f[B]citations...\f[R] ],+ \(dqreferences\(dq: [ \f[B]...list\f[R] \f[B]of\f[R] \f[B]references...\f[R] ],+ \(dqstyle\(dq: \(dq<style>...</style>\(dq,+ \(dqabbreviations\(dq: { \f[B]...abbreviations...\f[R] },+ \(dqlang\(dq: \(dqfr\-FR\(dq } .EE .PP None of these fields is mandatory.@@ -92,16 +92,22 @@ A citation is structured like this: .IP .EX-{ \[dq]citationID\[dq]: \[dq]foo\[dq],- \[dq]citationItems\[dq]: [ \f[B]...list\f[R] \f[B]of\f[R] \f[B]citationItems...\f[R] ],- \[dq]citationNoteNumber\[dq]: 3 }+{ \(dqcitationID\(dq: \(dqfoo\(dq,+ \(dqcitationResetPosition\(dq: \f[B]false\f[R],+ \(dqcitationItems\(dq: [ \f[B]...list\f[R] \f[B]of\f[R] \f[B]citationItems...\f[R] ],+ \(dqcitationNoteNumber\(dq: 3 } .EE .PP Only \f[CR]citationItems\f[R] is necessary.+.PP+\f[CR]citationResetPosition\f[R] controls whether position information+is to be reset before the citation is processed (which affects whether+full citations or abbreviated forms are used, in some styles).+.PP Alternatively, instead of .IP .EX-{ \[dq]citationItems\[dq]: [ \f[B]...\f[R] ] }+{ \(dqcitationItems\(dq: [ \f[B]...\f[R] ] } .EE .PP one can just specify an array of items directly:@@ -113,12 +119,12 @@ A citation item is structured like this: .IP .EX-{ \[dq]id\[dq]: \[dq]foo\[dq],- \[dq]type\[dq]: \[dq]suppress\-author\[dq],- \[dq]label\[dq]: \[dq]page\[dq],- \[dq]locator\[dq]: \[dq]45\[dq],- \[dq]prefix\[dq]: \[dq]see \[dq],- \[dq]suffix\[dq]: \[dq] and others\[dq] }+{ \(dqid\(dq: \(dqfoo\(dq,+ \(dqtype\(dq: \(dqsuppress\-author\(dq,+ \(dqlabel\(dq: \(dqpage\(dq,+ \(dqlocator\(dq: \(dq45\(dq,+ \(dqprefix\(dq: \(dqsee \(dq,+ \(dqsuffix\(dq: \(dq and others\(dq } .EE .PP Only \f[CR]id\f[R] is mandatory.@@ -130,40 +136,40 @@ .IP .EX {- \[dq]author\[dq]: [+ \(dqauthor\(dq: [ {- \[dq]family\[dq]: \[dq]Aristotle\[dq]+ \(dqfamily\(dq: \(dqAristotle\(dq } ],- \[dq]id\[dq]: \[dq]aristotle:prior\[dq],- \[dq]issued\[dq]: {- \[dq]date\-parts\[dq]: [+ \(dqid\(dq: \(dqaristotle:prior\(dq,+ \(dqissued\(dq: {+ \(dqdate\-parts\(dq: [ [ 1989 ] ] },- \[dq]publisher\[dq]: \[dq]Hackett\[dq],- \[dq]publisher\-place\[dq]: \[dq]Indianapolis\[dq],- \[dq]title\[dq]: \[dq]Prior analytics\[dq],- \[dq]translator\[dq]: [+ \(dqpublisher\(dq: \(dqHackett\(dq,+ \(dqpublisher\-place\(dq: \(dqIndianapolis\(dq,+ \(dqtitle\(dq: \(dqPrior analytics\(dq,+ \(dqtranslator\(dq: [ {- \[dq]family\[dq]: \[dq]Smith\[dq],- \[dq]given\[dq]: \[dq]Robin\[dq]+ \(dqfamily\(dq: \(dqSmith\(dq,+ \(dqgiven\(dq: \(dqRobin\(dq } ],- \[dq]type\[dq]: \[dq]book\[dq]+ \(dqtype\(dq: \(dqbook\(dq } .EE .PP An abbreviations object has this form: .IP .EX-{ \[dq]default\[dq]: {- \[dq]container\-title\[dq]: {- \[dq]Lloyd\[aq]s Law Reports\[dq]: \[dq]Lloyd\[aq]s Rep\[dq],- \[dq]Estates Gazette\[dq]: \[dq]EG\[dq],- \[dq]Scots Law Times\[dq]: \[dq]SLT\[dq]+{ \(dqdefault\(dq: {+ \(dqcontainer\-title\(dq: {+ \(dqLloyd\(aqs Law Reports\(dq: \(dqLloyd\(aqs Rep\(dq,+ \(dqEstates Gazette\(dq: \(dqEG\(dq,+ \(dqScots Law Times\(dq: \(dqSLT\(dq } } }@@ -176,9 +182,9 @@ The output JSON will have the structure: .IP .EX-{ \[dq]citations\[dq]: [ \f[B]...list\f[R] \f[B]of\f[R] \f[B]strings...\f[R] ],- \[dq]bibliography\[dq]: [ \f[B]...list\f[R] \f[B]of\f[R] \f[B]arrays:\f[R] \f[B]item\f[R] \f[B]id\f[R] \f[B]and\f[R] \f[B]a\f[R] \f[B]string...\f[R] ],- \[dq]warnings\[dq]: [ \f[B]...list\f[R] \f[B]of\f[R] \f[B]warnings...\f[R] ]+{ \(dqcitations\(dq: [ \f[B]...list\f[R] \f[B]of\f[R] \f[B]strings...\f[R] ],+ \(dqbibliography\(dq: [ \f[B]...list\f[R] \f[B]of\f[R] \f[B]arrays:\f[R] \f[B]item\f[R] \f[B]id\f[R] \f[B]and\f[R] \f[B]a\f[R] \f[B]string...\f[R] ],+ \(dqwarnings\(dq: [ \f[B]...list\f[R] \f[B]of\f[R] \f[B]warnings...\f[R] ] } .EE .PP@@ -188,14 +194,14 @@ .IP .EX [- \[dq]\[em]\[em]\[em]. 1983b. \[lq]The Concept of Truth in Formalized Languages.\[rq] In \[dq],+ \(dq\(em\(em\(em. 1983b. \(lqThe Concept of Truth in Formalized Languages.\(rq In \(dq, {- \[dq]format\[dq]: \[dq]italics\[dq],- \[dq]contents\[dq]: [- \[dq]Logic, Semantics, Metamathematics\[dq]+ \(dqformat\(dq: \(dqitalics\(dq,+ \(dqcontents\(dq: [+ \(dqLogic, Semantics, Metamathematics\(dq ] },- \[dq], edited by John Corcoran, 152\[en]278. Indianapolis: Hackett.\[dq]+ \(dq, edited by John Corcoran, 152\(en278. Indianapolis: Hackett.\(dq ] .EE .PP
man/citeproc.1.md view
@@ -93,12 +93,19 @@ ``` json { "citationID": "foo",+ "citationResetPosition": false, "citationItems": [ ...list of citationItems... ], "citationNoteNumber": 3 } ``` -Only `citationItems` is necessary. Alternatively,-instead of+Only `citationItems` is necessary.++`citationResetPosition` controls whether position information+is to be reset before the citation is processed (which affects+whether full citations or abbreviated forms are used, in some+styles).++Alternatively, instead of ``` json { "citationItems": [ ... ] }
src/Citeproc/Eval.hs view
@@ -201,7 +201,7 @@ -> reverse sortedIds _ -> sortedIds let bibCitations = map (\ident ->- Citation (Just $ unItemId ident) Nothing Nothing Nothing+ Citation (Just $ unItemId ident) False Nothing Nothing Nothing [CitationItem ident Nothing Nothing NormalCite Nothing Nothing Nothing]) sortedIds return (bibCitations, bibSortKeyMap)@@ -436,18 +436,18 @@ , citationItemLocator = Nothing , citationItemPrefix = Nothing , citationItemSuffix = Nothing }- let cleanCitation (Citation a b c d (i1:i2:is))+ let cleanCitation (Citation a b c d e (i1:i2:is)) | citationItemType i1 == AuthorOnly , citationItemType i2 == SuppressAuthor- = Citation a b c d+ = Citation a b c d e (map removeAffix (i2{ citationItemType = NormalCite }:is))- cleanCitation (Citation a b c d is)- = Citation a b c d (map removeAffix is)+ cleanCitation (Citation a b c d e is)+ = Citation a b c d e (map removeAffix is) -- note that citations must go first, and order must be preserved: -- we use a "basic item" that strips off prefixes, suffixes, locators let citations' = map cleanCitation citations ++- [Citation Nothing Nothing Nothing Nothing (map basicItem ghostItems)]+ [Citation Nothing False Nothing Nothing Nothing (map basicItem ghostItems)] allCites <- renderCitations citations' mblang <- asks (localeLanguage . contextLocale)@@ -1146,6 +1146,10 @@ fromMaybe mempty (citationItemSuffix x) <> suff }]) (citationSuffix citation)++ when (citationResetPosition citation) $+ modify $ \st -> st{ stateLastCitedMap = mempty+ , stateNoteMap = mempty } items <- mapM evalItem' (zip positionsInCitation (addCitationAffixes (citationItems citation)))
src/Citeproc/Types.hs view
@@ -315,11 +315,17 @@ -- | A citation (which may include several items, e.g. -- in @(Smith 2000; Jones 2010, p. 30)@). data Citation a =- Citation { citationId :: Maybe Text- , citationNoteNumber :: Maybe Int- , citationPrefix :: Maybe a- , citationSuffix :: Maybe a- , citationItems :: [CitationItem a] }+ Citation { citationId :: Maybe Text+ , citationResetPosition :: Bool -- ^ Reset the position information+ -- that determines whether citation items are "subsequent,"+ -- prior to processing this citation.+ -- Note that this affects all subsequent citations, not just this+ -- one.+ , citationNoteNumber :: Maybe Int+ , citationPrefix :: Maybe a+ , citationSuffix :: Maybe a+ , citationItems :: [CitationItem a]+ } deriving (Show, Eq, Ord) instance (FromJSON a, Eq a) => FromJSON (Citation a) where@@ -329,28 +335,31 @@ case ary V.!? 0 of Just v' -> (withObject "Citation" $ \o -> Citation <$> o .:? "citationID"+ <*> o .:? "citationResetPosition" .!= False <*> ((o .: "properties" >>= (.: "noteIndex")) <|> pure Nothing) <*> o .:? "citationPrefix" <*> o .:? "citationSuffix" <*> o .: "citationItems") v'- <|> Citation Nothing Nothing Nothing Nothing <$> parseJSON v'+ <|> Citation Nothing False Nothing Nothing Nothing <$> parseJSON v' Nothing -> fail "Empty array") v <|> withObject "Citation" (\o -> Citation <$> o .:? "citationID"+ <*> o .:? "citationResetPosition" .!= False <*> o .:? "citationNoteNumber" <*> o .:? "citationPrefix" <*> o .:? "citationSuffix" <*> o .: "citationItems") v <|>- (Citation Nothing Nothing Nothing Nothing <$> parseJSON v)+ (Citation Nothing False Nothing Nothing Nothing <$> parseJSON v) instance ToJSON a => ToJSON (Citation a) where toJSON c = object $ [ ("citationID", toJSON $ citationId c) | isJust (citationId c) ] +++ [ ("citationResetPosition", toJSON $ citationResetPosition c) ] ++ [ ("citationPrefix", toJSON $ citationPrefix c) | isJust (citationPrefix c) ] ++ [ ("citationSuffix", toJSON $ citationSuffix c) | isJust (citationSuffix c) ] ++ [ ("citationItems" , toJSON $ citationItems c) ] ++
test/Spec.hs view
@@ -152,6 +152,7 @@ referencesToCitation :: [Reference a] -> Citation a referencesToCitation rs = Citation { citationId = Nothing+ , citationResetPosition = False , citationNoteNumber = Nothing , citationPrefix = Nothing , citationSuffix = Nothing@@ -314,19 +315,19 @@ putStrLn "" let categories = sort $ Set.toList $ foldr (Set.insert . category) mempty testCases- putStrLn $ printf "%-30s %6s %6s %6s %6s"+ putStrLn $ printf "%-29s %6s %6s %6s %6s" ("CATEGORY" :: String)- ("PASS" :: String)- ("FAIL" :: String)- ("ERROR" :: String)- ("SKIP" :: String)+ (" PASS" :: String)+ (" FAIL" :: String)+ (" ERROR" :: String)+ (" SKIP" :: String) let resultsFor cat = do let p = length . filter ((== cat) . fst) . passed $ counts let f = length . filter ((== cat) . fst) . failed $ counts let e = length . filter ((== cat) . fst) . errored $ counts let s = length . filter ((== cat) . fst) . skipped $ counts let percent = (fromIntegral p / fromIntegral (p + f + e) :: Double)- putStrLn $ printf "%-30s %6d %6d %6d %6d |%-20s|"+ putStrLn $ printf "%-29s %6d %6d %6d %6d |%-20s|" (T.unpack cat) p f e s (replicate (floor (percent * 20.0)) '+') mapM_ resultsFor categories
+ test/extra/issue_160.txt view
@@ -0,0 +1,96 @@+>>===== MODE =====>>+citation+<<===== MODE =====<<+++>>===== RESULT =====>>+..[0] (Doe)+..[1] (Doe)+<<===== RESULT =====<<+++>>===== CITATIONS =====>>+[+ {+ "citationID": "CITATION-1",+ "citationItems": [+ {+ "id": "ITEM-1"+ }+ ],+ "properties": {+ "noteIndex": 1+ }+ }+, {+ "citationID": "CITATION-2",+ "citationResetPosition": true,+ "citationItems": [+ {+ "id": "ITEM-1"+ }+ ],+ "properties": {+ "noteIndex": 3+ }+ }+]+<<===== CITATIONS =====<<++++>>===== CSL =====>>+<style + xmlns="http://purl.org/net/xbiblio/csl"+ class="note"+ version="1.0">+ <info>+ <id />+ <title />+ <updated>2009-08-10T04:49:00+09:00</updated>+ </info>+ <citation>+ <layout delimiter="; " prefix="(" suffix=")">+ <choose>+ <if position="first">+ <names variable="author">+ <name form="short"/>+ </names>+ <group prefix=" ">+ <label variable="locator" form="short" suffix=" "/>+ <text variable="locator"/>+ </group>+ </if>+ <else-if position="subsequent">+ <text value="I am subsequent"/>+ </else-if>+ <else>+ <text value="I am ibid or ibid-with-locator"/>+ </else>+ </choose>+ </layout>+ </citation>+</style>+<<===== CSL =====<<+++>>===== INPUT =====>>+[+ {+ "author": [+ {+ "family": "Doe", + "given": "John"+ }+ ], + "id": "ITEM-1", + "type": "book"+ }+]+<<===== INPUT =====<<+++>>===== VERSION =====>>+1.0+<<===== VERSION =====<<+