jgm / citeproc

CSL citation processing library in Haskell
BSD 2-Clause "Simplified" License
154 stars 16 forks source link

Regression with no-name citations #8

Closed jgm closed 4 years ago

jgm commented 4 years ago

Currently this fails. We get Newspaper 2012e, 2012f instead of a,b.

>>===== MODE =====>>
citation
<<===== MODE =====<<

>>===== RESULT =====>>
(<i>Magazine</i> 2012a; <i>Magazine</i> 2012b; <i>Magazine</i> 2012c; <i>Magazine</i> 2012d; <i>Newspaper</i> 2012a; <i>Newspaper</i> 2012b)
<<===== RESULT =====<<

>>===== CSL =====>>

<?xml version="1.0" encoding="utf-8"?>
<style xmlns="http://purl.org/net/xbiblio/csl" class="in-text" version="1.0" demote-non-dropping-particle="display-and-sort" page-range-format="chicago">
  <info>
    <title>Chicago Manual of Style 17th edition (author-date)</title>
    <id>http://www.zotero.org/styles/chicago-author-date</id>
    <link href="http://www.zotero.org/styles/chicago-author-date" rel="self"/>
    <link href="http://www.chicagomanualofstyle.org/tools_citationguide.html" rel="documentation"/>
    <author>
      <name>Julian Onions</name>
      <email>julian.onions@gmail.com</email>
    </author>
    <contributor>
      <name>Sebastian Karcher</name>
    </contributor>
    <contributor>
      <name>Richard Karnesky</name>
      <email>karnesky+zotero@gmail.com</email>
      <uri>http://arc.nucapt.northwestern.edu/Richard_Karnesky</uri>
    </contributor>
    <contributor>
      <name>Andrew Dunning</name>
      <email>andrew.dunning@utoronto.ca</email>
      <uri>https://orcid.org/0000-0003-0464-5036</uri>
    </contributor>
    <contributor>
      <name>Matthew Roth</name>
      <email>matthew.g.roth@yale.edu</email>
      <uri> https://orcid.org/0000-0001-7902-6331</uri>
    </contributor>
    <category citation-format="author-date"/>
    <category field="generic-base"/>
    <summary>The author-date variant of the Chicago style</summary>
    <updated>2018-01-24T12:00:00+00:00</updated>
    <rights license="http://creativecommons.org/licenses/by-sa/3.0/">This work is licensed under a Creative Commons Attribution-ShareAlike 3.0 License</rights>
  </info>
  <locale xml:lang="en">
    <terms>
      <term name="editor" form="verb-short">ed.</term>
      <term name="container-author" form="verb">by</term>
      <term name="translator" form="verb-short">trans.</term>
      <term name="editortranslator" form="verb">edited and translated by</term>
      <term name="translator" form="short">trans.</term>
    </terms>
  </locale>
  <macro name="secondary-contributors">
    <choose>
      <if type="chapter entry-dictionary entry-encyclopedia paper-conference" match="none">
        <group delimiter=". ">
          <names variable="editor translator" delimiter=". ">
            <label form="verb" text-case="capitalize-first" suffix=" "/>
            <name and="text" delimiter=", "/>
          </names>
          <names variable="director" delimiter=". ">
            <label form="verb" text-case="capitalize-first" suffix=" "/>
            <name and="text" delimiter=", "/>
          </names>
        </group>
      </if>
    </choose>
  </macro>
  <macro name="container-contributors">
    <choose>
      <if type="chapter entry-dictionary entry-encyclopedia paper-conference" match="any">
        <group prefix=", " delimiter=", ">
          <names variable="container-author" delimiter=", ">
            <label form="verb" suffix=" "/>
            <name and="text" delimiter=", "/>
          </names>
          <names variable="editor translator" delimiter=", ">
            <label form="verb" suffix=" "/>
            <name and="text" delimiter=", "/>
          </names>
        </group>
      </if>
    </choose>
  </macro>
  <macro name="editor">
    <names variable="editor">
      <name name-as-sort-order="first" and="text" sort-separator=", " delimiter=", " delimiter-precedes-last="always"/>
      <label form="short" prefix=", "/>
    </names>
  </macro>
  <macro name="translator">
    <names variable="translator">
      <name name-as-sort-order="first" and="text" sort-separator=", " delimiter=", " delimiter-precedes-last="always"/>
      <label form="short" prefix=", "/>
    </names>
  </macro>
  <macro name="recipient">
    <choose>
      <if type="personal_communication">
        <choose>
          <if variable="genre">
            <text variable="genre" text-case="capitalize-first"/>
          </if>
          <else>
            <text term="letter" text-case="capitalize-first"/>
          </else>
        </choose>
      </if>
    </choose>
    <names variable="recipient" delimiter=", ">
      <label form="verb" prefix=" " text-case="lowercase" suffix=" "/>
      <name and="text" delimiter=", "/>
    </names>
  </macro>
  <macro name="substitute-title">
    <choose>
      <if type="article-magazine article-newspaper review review-book" match="any">
        <text macro="container-title"/>
      </if>
    </choose>
  </macro>
  <macro name="contributors">
    <group delimiter=". ">
      <names variable="author">
        <name and="text" name-as-sort-order="first" sort-separator=", " delimiter=", " delimiter-precedes-last="always"/>
        <label form="short" prefix=", "/>
        <substitute>
          <names variable="editor"/>
          <names variable="translator"/>
          <names variable="director"/>
          <text macro="substitute-title"/>
          <text macro="title"/>
        </substitute>
      </names>
      <text macro="recipient"/>
    </group>
  </macro>
  <macro name="contributors-short">
    <names variable="author">
      <name form="short" and="text" delimiter=", " initialize-with=". "/>
      <substitute>
        <names variable="editor"/>
        <names variable="translator"/>
        <names variable="director"/>
        <text macro="substitute-title"/>
        <text macro="title"/>
      </substitute>
    </names>
  </macro>
  <macro name="interviewer">
    <names variable="interviewer" delimiter=", ">
      <label form="verb" prefix=" " text-case="capitalize-first" suffix=" "/>
      <name and="text" delimiter=", "/>
    </names>
  </macro>
  <macro name="archive">
    <group delimiter=". ">
      <text variable="archive_location" text-case="capitalize-first"/>
      <text variable="archive"/>
      <text variable="archive-place"/>
    </group>
  </macro>
  <macro name="access">
    <group delimiter=". ">
      <choose>
        <if type="graphic report" match="any">
          <text macro="archive"/>
        </if>
        <else-if type="article-journal bill book chapter legal_case legislation motion_picture paper-conference" match="none">
          <text macro="archive"/>
        </else-if>
      </choose>
      <choose>
        <if type="webpage post-weblog" match="any">
          <date variable="issued" form="text"/>
        </if>
      </choose>
      <choose>
        <if variable="issued" match="none">
          <group delimiter=" ">
            <text term="accessed" text-case="capitalize-first"/>
            <date variable="accessed" form="text"/>
          </group>
        </if>
      </choose>
      <choose>
        <if type="legal_case" match="none">
          <choose>
            <if variable="DOI">
              <text variable="DOI" prefix="https://doi.org/"/>
            </if>
            <else>
              <text variable="URL"/>
            </else>
          </choose>
        </if>
      </choose>
    </group>
  </macro>
  <macro name="title">
    <choose>
      <if variable="title" match="none">
        <choose>
          <if type="personal_communication" match="none">
            <text variable="genre" text-case="capitalize-first"/>
          </if>
        </choose>
      </if>
      <else-if type="bill book graphic legislation motion_picture song" match="any">
        <text variable="title" text-case="title" font-style="italic"/>
        <group prefix=" (" suffix=")" delimiter=" ">
          <text term="version"/>
          <text variable="version"/>
        </group>
      </else-if>
      <else-if variable="reviewed-author">
        <choose>
          <if variable="reviewed-title">
            <group delimiter=". ">
              <text variable="title" text-case="title" quotes="true"/>
              <group delimiter=", ">
                <text variable="reviewed-title" text-case="title" font-style="italic" prefix="Review of "/>
                <names variable="reviewed-author">
                  <label form="verb-short" text-case="lowercase" suffix=" "/>
                  <name and="text" delimiter=", "/>
                </names>
              </group>
            </group>
          </if>
          <else>
            <group delimiter=", ">
              <text variable="title" text-case="title" font-style="italic" prefix="Review of "/>
              <names variable="reviewed-author">
                <label form="verb-short" text-case="lowercase" suffix=" "/>
                <name and="text" delimiter=", "/>
              </names>
            </group>
          </else>
        </choose>
      </else-if>
      <else-if type="legal_case interview patent" match="any">
        <text variable="title"/>
      </else-if>
      <else>
        <text variable="title" text-case="title" quotes="true"/>
      </else>
    </choose>
  </macro>
  <macro name="edition">
    <choose>
      <if type="bill book graphic legal_case legislation motion_picture report song" match="any">
        <choose>
          <if is-numeric="edition">
            <group delimiter=" " prefix=". ">
              <number variable="edition" form="ordinal"/>
              <text term="edition" form="short" strip-periods="true"/>
            </group>
          </if>
          <else>
            <text variable="edition" text-case="capitalize-first" prefix=". "/>
          </else>
        </choose>
      </if>
      <else-if type="chapter entry-dictionary entry-encyclopedia paper-conference" match="any">
        <choose>
          <if is-numeric="edition">
            <group delimiter=" " prefix=", ">
              <number variable="edition" form="ordinal"/>
              <text term="edition" form="short"/>
            </group>
          </if>
          <else>
            <text variable="edition" prefix=", "/>
          </else>
        </choose>
      </else-if>
    </choose>
  </macro>
  <macro name="locators">
    <choose>
      <if type="article-journal">
        <choose>
          <if variable="volume">
            <text variable="volume" prefix=" "/>
            <group prefix=" (" suffix=")">
              <choose>
                <if variable="issue">
                  <text variable="issue"/>
                </if>
                <else>
                  <date variable="issued">
                    <date-part name="month"/>
                  </date>
                </else>
              </choose>
            </group>
          </if>
          <else-if variable="issue">
            <group delimiter=" " prefix=", ">
              <text term="issue" form="short"/>
              <text variable="issue"/>
              <date variable="issued" prefix="(" suffix=")">
                <date-part name="month"/>
              </date>
            </group>
          </else-if>
          <else>
            <date variable="issued" prefix=", ">
              <date-part name="month"/>
            </date>
          </else>
        </choose>
      </if>
      <else-if type="legal_case">
        <text variable="volume" prefix=", "/>
        <text variable="container-title" prefix=" "/>
        <text variable="page" prefix=" "/>
      </else-if>
      <else-if type="bill book graphic legal_case legislation motion_picture report song" match="any">
        <group prefix=". " delimiter=". ">
          <group>
            <text term="volume" form="short" text-case="capitalize-first" suffix=" "/>
            <number variable="volume" form="numeric"/>
          </group>
          <group>
            <number variable="number-of-volumes" form="numeric"/>
            <text term="volume" form="short" prefix=" " plural="true"/>
          </group>
        </group>
      </else-if>
      <else-if type="chapter entry-dictionary entry-encyclopedia paper-conference" match="any">
        <choose>
          <if variable="page" match="none">
            <group prefix=". ">
              <text term="volume" form="short" text-case="capitalize-first" suffix=" "/>
              <number variable="volume" form="numeric"/>
            </group>
          </if>
        </choose>
      </else-if>
    </choose>
  </macro>
  <macro name="locators-chapter">
    <choose>
      <if type="chapter entry-dictionary entry-encyclopedia paper-conference" match="any">
        <choose>
          <if variable="page">
            <group prefix=", ">
              <text variable="volume" suffix=":"/>
              <text variable="page"/>
            </group>
          </if>
        </choose>
      </if>
    </choose>
  </macro>
  <macro name="locators-article">
    <choose>
      <if type="article-newspaper">
        <group prefix=", " delimiter=", ">
          <group delimiter=" ">
            <text variable="edition"/>
            <text term="edition"/>
          </group>
          <group>
            <text term="section" form="short" suffix=" "/>
            <text variable="section"/>
          </group>
        </group>
      </if>
      <else-if type="article-journal">
        <choose>
          <if variable="volume issue" match="any">
            <text variable="page" prefix=": "/>
          </if>
          <else>
            <text variable="page" prefix=", "/>
          </else>
        </choose>
      </else-if>
    </choose>
  </macro>
  <macro name="point-locators">
    <choose>
      <if variable="locator">
        <choose>
          <if locator="page" match="none">
            <choose>
              <if type="bill book graphic legal_case legislation motion_picture report song" match="any">
                <choose>
                  <if variable="volume">
                    <group>
                      <text term="volume" form="short" suffix=" "/>
                      <number variable="volume" form="numeric"/>
                      <label variable="locator" form="short" prefix=", " suffix=" "/>
                    </group>
                  </if>
                  <else>
                    <label variable="locator" form="short" suffix=" "/>
                  </else>
                </choose>
              </if>
              <else>
                <label variable="locator" form="short" suffix=" "/>
              </else>
            </choose>
          </if>
          <else-if type="bill book graphic legal_case legislation motion_picture report song" match="any">
            <number variable="volume" form="numeric" suffix=":"/>
          </else-if>
        </choose>
        <text variable="locator"/>
      </if>
    </choose>
  </macro>
  <macro name="container-prefix">
    <text term="in" text-case="capitalize-first"/>
  </macro>
  <macro name="container-title">
    <choose>
      <if type="chapter entry-dictionary entry-encyclopedia paper-conference" match="any">
        <text macro="container-prefix" suffix=" "/>
      </if>
    </choose>
    <choose>
      <if type="webpage">
        <text variable="container-title" text-case="title"/>
      </if>
      <else-if type="legal_case" match="none">
        <group delimiter=" ">
          <text variable="container-title" text-case="title" font-style="italic"/>
          <choose>
            <if type="post-weblog">
              <text value="(blog)"/>
            </if>
          </choose>
        </group>
      </else-if>
    </choose>
  </macro>
  <macro name="publisher">
    <group delimiter=": ">
      <text variable="publisher-place"/>
      <text variable="publisher"/>
    </group>
  </macro>
  <macro name="date">
    <choose>
      <if variable="issued">
        <group delimiter=" ">
          <date variable="original-date" form="text" date-parts="year" prefix="(" suffix=")"/>
          <date variable="issued">
            <date-part name="year"/>
          </date>
        </group>
      </if>
      <else-if variable="status">
        <text variable="status" text-case="capitalize-first"/>
      </else-if>
      <else>
        <text term="no date" form="short"/>
      </else>
    </choose>
  </macro>
  <macro name="date-in-text">
    <choose>
      <if variable="issued">
        <group delimiter=" ">
          <date variable="original-date" form="text" date-parts="year" prefix="[" suffix="]"/>
          <date variable="issued">
            <date-part name="year"/>
          </date>
        </group>
      </if>
      <else-if variable="status">
        <text variable="status"/>
      </else-if>
      <else>
        <text term="no date" form="short"/>
      </else>
    </choose>
  </macro>
  <macro name="day-month">
    <date variable="issued">
      <date-part name="month"/>
      <date-part name="day" prefix=" "/>
    </date>
  </macro>
  <macro name="collection-title">
    <choose>
      <if match="none" type="article-journal">
        <choose>
          <if match="none" is-numeric="collection-number">
            <group delimiter=", ">
              <text variable="collection-title" text-case="title"/>
              <text variable="collection-number"/>
            </group>
          </if>
          <else>
            <group delimiter=" ">
              <text variable="collection-title" text-case="title"/>
              <text variable="collection-number"/>
            </group>
          </else>
        </choose>
      </if>
    </choose>
  </macro>
  <macro name="collection-title-journal">
    <choose>
      <if type="article-journal">
        <group delimiter=" ">
          <text variable="collection-title"/>
          <text variable="collection-number"/>
        </group>
      </if>
    </choose>
  </macro>
  <macro name="event">
    <group>
      <text term="presented at" suffix=" "/>
      <text variable="event"/>
    </group>
  </macro>
  <macro name="description">
    <choose>
      <if type="interview">
        <group delimiter=". ">
          <text macro="interviewer"/>
          <text variable="medium" text-case="capitalize-first"/>
        </group>
      </if>
      <else-if type="patent">
        <group delimiter=" " prefix=". ">
          <text variable="authority"/>
          <text variable="number"/>
        </group>
      </else-if>
      <else>
        <text variable="medium" text-case="capitalize-first" prefix=". "/>
      </else>
    </choose>
    <choose>
      <if variable="title" match="none"/>
      <else-if type="thesis personal_communication speech" match="any"/>
      <else>
        <group delimiter=" " prefix=". ">
          <text variable="genre" text-case="capitalize-first"/>
          <choose>
            <if type="report">
              <text variable="number"/>
            </if>
          </choose>
        </group>
      </else>
    </choose>
  </macro>
  <macro name="issue">
    <choose>
      <if type="legal_case">
        <text variable="authority" prefix=". "/>
      </if>
      <else-if type="speech">
        <group prefix=". " delimiter=", ">
          <group delimiter=" ">
            <text variable="genre" text-case="capitalize-first"/>
            <text macro="event"/>
          </group>
          <text variable="event-place"/>
          <text macro="day-month"/>
        </group>
      </else-if>
      <else-if type="article-newspaper article-magazine personal_communication" match="any">
        <date variable="issued" form="text" prefix=", "/>
      </else-if>
      <else-if type="patent">
        <group delimiter=", " prefix=", ">
          <group delimiter=" ">
            <!--Needs Localization-->
            <text value="filed"/>
            <date variable="submitted" form="text"/>
          </group>
          <group delimiter=" ">
            <choose>
              <if variable="issued submitted" match="all">
                <text term="and"/>
              </if>
            </choose>
            <!--Needs Localization-->
            <text value="issued"/>
            <date variable="issued" form="text"/>
          </group>
        </group>
      </else-if>
      <else-if type="article-journal" match="any"/>
      <else>
        <group prefix=". " delimiter=", ">
          <choose>
            <if type="thesis">
              <text variable="genre" text-case="capitalize-first"/>
            </if>
          </choose>
          <text macro="publisher"/>
        </group>
      </else>
    </choose>
  </macro>
  <citation et-al-min="4" et-al-use-first="1" disambiguate-add-year-suffix="true" disambiguate-add-names="true" disambiguate-add-givenname="true" givenname-disambiguation-rule="primary-name" collapse="year" after-collapse-delimiter="; ">
    <layout prefix="(" suffix=")" delimiter="; ">
      <group delimiter=", ">
        <choose>
          <if variable="issued accessed" match="any">
            <group delimiter=" ">
              <text macro="contributors-short"/>
              <text macro="date-in-text"/>
            </group>
          </if>
          <!---comma before forthcoming and n.d.-->
          <else>
            <group delimiter=", ">
              <text macro="contributors-short"/>
              <text macro="date-in-text"/>
            </group>
          </else>
        </choose>
        <text macro="point-locators"/>
      </group>
    </layout>
  </citation>
  <bibliography hanging-indent="true" et-al-min="11" et-al-use-first="7" subsequent-author-substitute="&#8212;&#8212;&#8212;" entry-spacing="0">
    <sort>
      <key macro="contributors"/>
      <key variable="issued"/>
      <key variable="title"/>
    </sort>
    <layout suffix=".">
      <group delimiter=". ">
        <text macro="contributors"/>
        <text macro="date"/>
        <text macro="title"/>
      </group>
      <text macro="description"/>
      <text macro="secondary-contributors" prefix=". "/>
      <text macro="container-title" prefix=". "/>
      <text macro="container-contributors"/>
      <text macro="edition"/>
      <text macro="locators-chapter"/>
      <text macro="collection-title-journal" prefix=", " suffix=", "/>
      <text macro="locators"/>
      <text macro="collection-title" prefix=". "/>
      <text macro="issue"/>
      <text macro="locators-article"/>
      <text macro="access" prefix=". "/>
    </layout>
  </bibliography>
</style>
<<===== CSL =====<<

>>===== INPUT =====>>
[
  {
    "container-title": "Magazine",
    "id": "item1",
    "issued": {
      "date-parts": [
        [
          2012
        ]
      ]
    },
    "title": "Title A",
    "type": "article-magazine"
  },
  {
    "container-title": "Magazine",
    "id": "item2",
    "issued": {
      "date-parts": [
        [
          2012
        ]
      ]
    },
    "title": "Title B",
    "type": "article-magazine"
  },
  {
    "container-title": "Magazine",
    "id": "item3",
    "issued": {
      "date-parts": [
        [
          2012
        ]
      ]
    },
    "title": "Title C",
    "type": "article-magazine"
  },
  {
    "container-title": "Magazine",
    "id": "item4",
    "issued": {
      "date-parts": [
        [
          2012
        ]
      ]
    },
    "title": "Title D",
    "type": "article-magazine"
  },
  {
    "container-title": "Newspaper",
    "id": "item5",
    "issued": {
      "date-parts": [
        [
          2012
        ]
      ]
    },
    "title": "Title E",
    "type": "article-magazine"
  },
  {
    "container-title": "Newspaper",
    "id": "item6",
    "issued": {
      "date-parts": [
        [
          2012
        ]
      ]
    },
    "title": "Title F",
    "type": "article-magazine"
  }
]

<<===== INPUT =====<<

>>===== VERSION =====>>
1.0
<<===== VERSION =====<<
jgm commented 4 years ago

There's one issue remaining: citeproc.js gives the result

(<i>Magazine</i> 2012a; <i>Magazine</i> 2012b; <i>Magazine</i> 2012c; <i>Magazine</i> 2012d; <i>Newspaper</i> 2012a; <i>Newspaper</i> 2012b)

while this library collapses and gives

(<i>Magazine</i> 2012a; 2012b; 2012c; 2012d; <i>Newspaper</i> 2012a; 2012b)

Which is correct according to the spec? (@denismaier do you know?)

denismaier commented 4 years ago

I think your library is correct since the title is rendered as through cs:substitute. @fbennett, what do you think? Is there a special reason for this test behaviour?

fbennett commented 4 years ago

Will wait for other responses, but it looks to me like collapsing there is the right thing to do, aesthetically. An edge-case question would be whether the match for collapse purposes should be based on exact match of rendered field and value, string value, or string value and decorations (italics etc). Would think the first of those three, but that would be good to confirm.