diff options
author | Karl Berry <karl@freefriends.org> | 2024-09-15 19:57:10 +0000 |
---|---|---|
committer | Karl Berry <karl@freefriends.org> | 2024-09-15 19:57:10 +0000 |
commit | 53b0a5c02bb3face43d87688c11529571b8a5f7d (patch) | |
tree | fab9407e8a82cf21642859ebe9e93b0417edb881 /Master/texmf-dist | |
parent | 64d95f88768a1dde4edfda5e2b69a57251783f5b (diff) |
citation-style-language (15sep24)
git-svn-id: svn://tug.org/texlive/trunk@72292 c570f23f-e606-0410-a88d-b1316a301751
Diffstat (limited to 'Master/texmf-dist')
17 files changed, 581 insertions, 438 deletions
diff --git a/Master/texmf-dist/doc/latex/citation-style-language/CHANGELOG.md b/Master/texmf-dist/doc/latex/citation-style-language/CHANGELOG.md index 4a08dd63029..7a21395f0fa 100644 --- a/Master/texmf-dist/doc/latex/citation-style-language/CHANGELOG.md +++ b/Master/texmf-dist/doc/latex/citation-style-language/CHANGELOG.md @@ -7,6 +7,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +## [0.6.4] - 2024-09-15 + +### Fixed + +- Refactor `processCitationCluster()` to fix unexpected nil ([#77](https://github.com/zepinglee/citeproc-lua/issues/77)). + ## [0.6.3] - 2024-08-28 ### Added @@ -241,7 +247,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Initial CTAN release. -[Unreleased]: https://github.com/zepinglee/citeproc-lua/compare/v0.6.3...HEAD +[Unreleased]: https://github.com/zepinglee/citeproc-lua/compare/v0.6.4...HEAD +[0.6.4]: https://github.com/zepinglee/citeproc-lua/compare/v0.6.3...v0.6.4 [0.6.3]: https://github.com/zepinglee/citeproc-lua/compare/v0.6.2...v0.6.3 [0.6.2]: https://github.com/zepinglee/citeproc-lua/compare/v0.6.1...v0.6.2 [0.6.1]: https://github.com/zepinglee/citeproc-lua/compare/v0.6.0...v0.6.1 diff --git a/Master/texmf-dist/doc/latex/citation-style-language/citation-style-language-doc.pdf b/Master/texmf-dist/doc/latex/citation-style-language/citation-style-language-doc.pdf Binary files differindex 1ca15f70276..5ec6858cc0c 100644 --- a/Master/texmf-dist/doc/latex/citation-style-language/citation-style-language-doc.pdf +++ b/Master/texmf-dist/doc/latex/citation-style-language/citation-style-language-doc.pdf diff --git a/Master/texmf-dist/doc/latex/citation-style-language/citation-style-language-doc.tex b/Master/texmf-dist/doc/latex/citation-style-language/citation-style-language-doc.tex index 385fef912f5..72b5a5cbaf5 100644 --- a/Master/texmf-dist/doc/latex/citation-style-language/citation-style-language-doc.tex +++ b/Master/texmf-dist/doc/latex/citation-style-language/citation-style-language-doc.tex @@ -51,7 +51,7 @@ }% } -\date{2024-08-28 v0.6.3} +\date{2024-09-15 v0.6.4} \maketitle diff --git a/Master/texmf-dist/doc/man/man1/citeproc-lua.1 b/Master/texmf-dist/doc/man/man1/citeproc-lua.1 index a23c8b7228a..a411466460a 100644 --- a/Master/texmf-dist/doc/man/man1/citeproc-lua.1 +++ b/Master/texmf-dist/doc/man/man1/citeproc-lua.1 @@ -1,4 +1,4 @@ -.TH citeproc-lua 1 "0.6.3" +.TH citeproc-lua 1 "0.6.4" .SH NAME citeproc-lua \- make CSL citations and bibliography for LaTeX .SH SYNOPSIS diff --git a/Master/texmf-dist/doc/man/man1/citeproc-lua.man1.pdf b/Master/texmf-dist/doc/man/man1/citeproc-lua.man1.pdf Binary files differindex 6bbb9759bc3..df8856ea910 100644 --- a/Master/texmf-dist/doc/man/man1/citeproc-lua.man1.pdf +++ b/Master/texmf-dist/doc/man/man1/citeproc-lua.man1.pdf diff --git a/Master/texmf-dist/scripts/citation-style-language/citeproc-bibtex-data.lua b/Master/texmf-dist/scripts/citation-style-language/citeproc-bibtex-data.lua index d1fdc99e02d..fc1d04d4f44 100644 --- a/Master/texmf-dist/scripts/citation-style-language/citeproc-bibtex-data.lua +++ b/Master/texmf-dist/scripts/citation-style-language/citeproc-bibtex-data.lua @@ -1272,6 +1272,11 @@ return { source = "apa.dbx", type = "literal", }, + citations = { + csl = nil, + source = "publist.dbx", + type = "literal", + }, citedate = { csl = nil, source = "seuthesis.bst", @@ -4205,11 +4210,6 @@ return { csl = nil, source = "adrbirthday.bst", }, - citations = { - csl = nil, - source = "publist.dbx", - type = "literal", - }, }, macros = { acmcs = { diff --git a/Master/texmf-dist/scripts/citation-style-language/citeproc-engine.lua b/Master/texmf-dist/scripts/citation-style-language/citeproc-engine.lua index 0f5e35c385d..01966fe2193 100644 --- a/Master/texmf-dist/scripts/citation-style-language/citeproc-engine.lua +++ b/Master/texmf-dist/scripts/citation-style-language/citeproc-engine.lua @@ -59,6 +59,17 @@ local Position = util.Position ---@field citationItems CitationItem[] ---@field properties CitationProperties ---@field citation_index integer +---@field sorted_items CitationItem[] + +---@class CitationItem +---@field id CiteId +---@field prefix string? +---@field suffix string? +---@field locator string? +---@field label string? +---@field position_level Position? +---@field near_note boolean? +---@field num_citations integer? ---@class CitationProperties ---@field noteIndex NoteIndex, @@ -114,7 +125,6 @@ local Registry = {} ---@field registry Registry ---@field cite_first_note_numbers table<ItemId, NoteIndex> ---@field cite_last_note_numbers table<ItemId, NoteIndex> ----@field note_citations_map table<NoteIndex, CitationId[]> ---@field tainted_item_ids table<ItemId, boolean> ---@field disam_irs IrNode[] ---@field cite_irs_by_output table<string, IrNode[]> @@ -177,7 +187,6 @@ function CiteProc.new(sys, style, lang, force_lang) cite_first_note_numbers = {}, cite_last_note_numbers = {}, - note_citations_map = {}, tainted_item_ids = {}, @@ -212,16 +221,6 @@ function CiteProc:get_independent_parent() return self.style.info.independent_parent end -function CiteProc:check_valid_citation_element() - if not self.style.citation then - if self.style.info and self.style.info.independent_parent then - util.error(string.format("This is a dependent style linked to '%s'.", self.style.info.independent_parent)) - else - util.error('No <citation> in style.') - end - end -end - ---@param ids CiteId[] function CiteProc:updateItems(ids) -- util.debug(string.format('updateItems(%s)', table.concat(ids, ", "))) @@ -257,7 +256,6 @@ function CiteProc:updateItems(ids) self.registry.previous_citation = nil self.cite_first_note_numbers = {} self.cite_last_note_numbers = {} - self.note_citations_map = {} for _, item in ipairs(self.registry.registry) do item.year_suffix_number = nil @@ -306,106 +304,214 @@ function CiteProc:updateUncitedItems(uncited_ids) self.registry.previous_citation = nil self.cite_first_note_numbers = {} self.cite_last_note_numbers = {} - self.note_citations_map = {} end ----@alias PreCitation [CitationId, NoteIndex, ChapterIndex] ----@alias PostCitation [CitationId, NoteIndex, ChapterIndex] +---@alias PreCitation [CitationId, NoteIndex, ChapterIndex?] +---@alias PostCitation [CitationId, NoteIndex, ChapterIndex?] ---@param citation CitationData ----@param citationsPre PreCitation[] ----@param citationsPost PostCitation[] ----@return (table | (integer | string | CitationId)[])[] -function CiteProc:processCitationCluster(citation, citationsPre, citationsPost) +---@param citations_pre PreCitation[] +---@param citations_post PostCitation[] +---@return [table, [integer, string, CitationId][]] +function CiteProc:processCitationCluster(citation, citations_pre, citations_post) -- util.debug(string.format('processCitationCluster(%s)', citation.citationID)) - self:check_valid_citation_element() - citation = self:normalize_citation_input(citation) - self:_check_input(citation, citationsPre, citationsPost) - - -- Registor citation - self.registry.citations_by_id[citation.citationID] = citation + self:_check_valid_citation_element() + citation = self:_normalize_citation_input(citation) + self:_check_input(citation, citations_pre, citations_post) - local citation_note_pairs = {} - util.extend(citation_note_pairs, citationsPre) - table.insert(citation_note_pairs, {citation.citationID, citation.properties.noteIndex}) - util.extend(citation_note_pairs, citationsPost) - -- util.debug(citation_note_pairs) - - local citations_by_id = {} - local citation_list = {} - for _, pair in ipairs(citation_note_pairs) do - local citation_id, note_number = table.unpack(pair) - local citation_ = self.registry.citations_by_id[citation_id] - if not citation_ then - util.error("Citation not in registry.") - end - citations_by_id[citation_.citationID] = citation_ - table.insert(citation_list, citation_) + local citation_list, item_ids = self:_build_reconstituted_citation_list(citation, citations_pre, citations_post) + self:updateItems(item_ids) + if #citation.sorted_items > 1 and self.style.citation.sort then + citation.sorted_items = self.style.citation:sorted_citation_items(citation.citationItems, self) end - self.registry.citations_by_id = citations_by_id - self.registry.citation_list = citation_list - -- update self.registry.citations_by_item_id - local item_ids = {} - self.registry.citations_by_item_id = {} - for _, citation_ in ipairs(citation_list) do - for _, cite_item in ipairs(citation_.citationItems) do - if not self.registry.citations_by_item_id[cite_item.id] then - self.registry.citations_by_item_id[cite_item.id] = {} - table.insert(item_ids, cite_item.id) - end - table.insert(self.registry.citations_by_item_id[cite_item.id], citation_) - end - end - self:updateItems(item_ids) + local tainted_citation_ids = self:_set_positions(citation_list) + + tainted_citation_ids[citation.citationID] = true local params = { bibchange = false, citation_errors = {}, } - local output = {} + -- TODO: evaluate params.bibchange - local tainted_citation_ids = self:get_tainted_citation_ids(citation_note_pairs) - tainted_citation_ids[citation.citationID] = true + local result = self:_rerun_changed_cites(tainted_citation_ids) - -- Citeproc-js marks all related citations as tainted but I don't think it's - -- necessary. - if self.style.class == "note" and self.style.has_disambiguate then - for _, cite_item in ipairs(citation.citationItems) do - for _, citation_ in ipairs(self.registry.citations_by_item_id[cite_item.id]) do - tainted_citation_ids[citation_.citationID] = true - end - end + return {params, result} +end + +-- A variant of processCitationCluster() for easy use with LaTeX. +-- It should be run after refreshing the registry (updateItems()) with all items +---@param citation CitationData +---@return string +function CiteProc:process_citation(citation) + -- util.debug(string.format('process_citation(%s)', citation.citationID)) + self:_check_valid_citation_element() + citation = self:_normalize_citation_input(citation) + + local citations_pre = {} + for _, citation_ in ipairs(self.registry.citation_list) do + table.insert(citations_pre, {citation_.citationID, citation_.properties.noteIndex}) end + self:_check_input(citation, citations_pre, {}) - -- util.debug(tainted_citation_ids) + local citation_list, item_ids = self:_build_reconstituted_citation_list(citation, citations_pre, {}) + -- self:updateItems(item_ids) + for i, cite_item in ipairs(citation.citationItems) do + self:get_item(cite_item.id) + end + if #citation.sorted_items > 1 and self.style.citation.sort then + citation.sorted_items = self.style.citation:sorted_citation_items(citation.citationItems, self) + end - -- params.bibchange = #tainted_citation_ids > 0 - for citation_id, _ in pairs(tainted_citation_ids) do - local citation_ = self.registry.citations_by_id[citation_id] + self:_set_positions(citation_list) + local tainted_citation_ids = {[citation.citationID] = true} + local result = self:_rerun_changed_cites(tainted_citation_ids) + return result[1][2] +end - local citation_index = citation_.citation_index +function CiteProc:makeCitationCluster(citation_items) + local special_form = nil + local items = {} - local mode = citation_.properties.mode - if mode == "suppress-author" and self.style.class == "note" then - mode = nil + for i, cite_item in ipairs(citation_items) do + cite_item = self:_normalize_cite_item(cite_item) + local item_data = self:get_item(cite_item.id) + + -- Create a wrapper of the orignal item from registry so that + -- it may hold different `locator` or `position` values for cites. + local cite_item = setmetatable(cite_item, {__index = item_data}) + + if not special_form then + for _, form in ipairs({"author-only", "suppress-author", "coposite"}) do + if cite_item[form] then + special_form = form + end + end end - local citation_element = self.style.citation - if mode == "author-only" and self.style.intext then - citation_element = self.style.intext - elseif mode == "full-cite" then - citation_element = self.style.full_citation + + -- Set "first-reference-note-number" variable when called from + -- processCitationCluster() > updateItems() + local citations = self.registry.citations_by_item_id[cite_item.id] + if citations and #citations > 0 then + cite_item["first-reference-note-number"] = citations[1].properties.noteIndex end - local citation_str = citation_element:build_citation_str(citation_, self) - table.insert(output, {citation_index, citation_str, citation_id}) + cite_item.position_level = Position.First + if self.cite_first_note_numbers[cite_item.id] then + cite_item.position_level = Position.Subsequent + else + self.cite_first_note_numbers[cite_item.id] = 0 + end + + local preceding_cite + if i == 1 then + local previous_citation = self.registry.previous_citation + if previous_citation then + if #previous_citation.citationItems == 1 and previous_citation.citationItems[1].id == cite_item.id then + preceding_cite = previous_citation.citationItems[1] + end + end + elseif citation_items[i - 1].id == cite_item.id then + preceding_cite = citation_items[i - 1] + end + + if preceding_cite then + cite_item.position_level = self:_get_ibid_position(cite_item, preceding_cite) + end + + table.insert(items, cite_item) + end + + if self.registry.requires_sorting then + self:sort_bibliography() + end + + self:_check_valid_citation_element() + local citation_element = self.style.citation + if special_form == "author-only" and self.style.intext then + citation_element = self.style.intext end - return {params, output} + local res = citation_element:build_cluster(items, self) + + -- local context = { + -- build = {}, + -- engine=self, + -- } + -- local res = self.style:render_citation(items, context) + + self.registry.previous_citation = { + citationID = "pseudo-citation", + citationItems = items, + properties = { + noteIndex = 0, + } + } + return res end -function CiteProc:normalize_citation_input(citation) +---@param bibsection any +---@return [{[string]: string | number | boolean}, string[]] +function CiteProc:makeBibliography(bibsection) + -- The bibsection works as a filter described in + -- <https://citeproc-js.readthedocs.io/en/latest/running.html#selective-output-with-makebibliography>. + if not self.style.bibliography then + return {{}, {}} + end + + local res = {} + + self.registry.widest_label = "" + self.registry.maxoffset = 0 + + local ids = self:_get_sorted_refs() + if bibsection then + ids = self:_filter_with_bibsection(ids, bibsection) + end + for _, id in ipairs(ids) do + local str = self.style.bibliography:build_bibliography_str(id, self) + table.insert(res, str) + end + + local bib_start = self.output_format.markups["bibstart"] + local bib_end = self.output_format.markups["bibend"] + if type(bib_start) == "function" then + bib_start = bib_start(self) + end + if type(bib_end) == "function" then + bib_end = bib_end(self) + end + + local params = { + hangingindent = self.style.bibliography.hanging_indent, + ["second-field-align"] = self.style.bibliography.second_field_align or false, + linespacing = self.style.bibliography.line_spacing, + entryspacing = self.style.bibliography.entry_spacing, + maxoffset = self.registry.maxoffset, + widest_label = self.registry.widest_label, + bibstart = bib_start, + bibend = bib_end, + entry_ids = util.clone(self.registry.reflist), + } + + return {params, res} +end + +function CiteProc:_check_valid_citation_element() + if not self.style.citation then + if self.style.info and self.style.info.independent_parent then + util.error(string.format("This is a dependent style linked to '%s'.", self.style.info.independent_parent)) + else + util.error('No <citation> in style.') + end + end +end + +---@param citation CitationData +---@return CitationData +function CiteProc:_normalize_citation_input(citation) citation = util.deep_copy(citation) if not citation.citationID then @@ -416,7 +522,7 @@ function CiteProc:normalize_citation_input(citation) citation.citationItems = {} end for i, cite_item in ipairs(citation.citationItems) do - citation.citationItems[i] = self:normalize_cite_item(cite_item) + citation.citationItems[i] = self:_normalize_cite_item(cite_item) end -- Fix missing noteIndex: sort_CitationNumberPrimaryAscendingViaMacroCitation.txt @@ -430,12 +536,14 @@ function CiteProc:normalize_citation_input(citation) citation.properties.chapterIndex = 0 end + citation.sorted_items = util.clone(citation.citationItems) + return citation end ---@param cite_item CitationItem ---@return CitationItem -function CiteProc:normalize_cite_item(cite_item) +function CiteProc:_normalize_cite_item(cite_item) -- Shallow copy cite_item = util.clone(cite_item) cite_item.id = tostring(cite_item.id) @@ -471,214 +579,237 @@ function CiteProc:normalize_cite_item(cite_item) end ---@param citation CitationData ----@param citationsPre PreCitation[] ----@param citationsPost PostCitation[] -function CiteProc:_check_input(citation, citationsPre, citationsPost) - ---@type {[CitationId]: boolean} +---@param citations_pre PreCitation[] +---@param citations_post PostCitation[] +function CiteProc:_check_input(citation, citations_pre, citations_post) + local citation_info_list = {} + do + for i, pre_citation in ipairs(citations_pre) do + local citation_id = pre_citation[1] + local note_index = pre_citation[2] + local chapter_number = pre_citation[3] or self.registry.citations_by_id[citation_id].properties.chapterIndex or 0 + local name = string.format("citationsPre[%d]", i) + table.insert(citation_info_list, {citation_id, note_index, chapter_number, name}) + end + table.insert(citation_info_list, {citation.citationID, citation.properties.noteIndex, citation.properties.chapterIndex or 0, "citation"}) + for i, post_citation in ipairs(citations_post) do + local citation_id = post_citation[1] + local note_index = post_citation[2] + local chapter_number = post_citation[3] or self.registry.citations_by_id[citation_id].properties.chapterIndex or 0 + local name = string.format("citationsPost[%d]", i) + table.insert(citation_info_list, {citation_id, note_index, chapter_number, name}) + end + end + + ---@type table<CitationId, boolean> local citation_dict = {} local last_note_number = 0 local last_chapter_number = 0 - for i, pre_citation in ipairs(citationsPre) do - local citation_id = pre_citation[1] - local note_number = pre_citation[2] - local chapter_number = pre_citation[3] + for _, citation_info in ipairs(citation_info_list) do + local citation_id, note_index, chapter_number, name = table.unpack(citation_info) if citation_dict[citation_id] then - error(string.format("Previously referenced citationID '%s' encountered in citationsPre", citation_id)) + error(string.format("Previously referenced citationID '%s' encountered at %s", name)) end + citation_dict[citation_id] = true if chapter_number and chapter_number > 0 then if chapter_number < last_chapter_number then - util.warning(string.format("Chapter index sequence is not sane at citationsPre[%d]", i)) + util.warning(string.format("Chapter index sequence is not sane at %s", name)) end if chapter_number ~= last_chapter_number then last_note_number = 0 end last_chapter_number = chapter_number end - if note_number and note_number > 0 then - if note_number < last_note_number then - util.warning(string.format("Note index sequence is not sane at citationsPre[%d]", i)) + if note_index > 0 then + if note_index < last_note_number then + util.warning(string.format("Note index sequence is not sane at %s", name)) end - last_note_number = note_number + last_note_number = note_index end - citation_dict[citation_id] = true - end - - do - local citation_id = citation.citationID - local note_number = citation.properties.noteIndex - local chapter_number = citation.properties.chapterIndex - if (citation_dict[citation_id]) then - error("Citation with previously referenced citationID " .. citation_id) - end - if note_number and note_number > 0 then - if note_number < last_note_number then - util.warning("Note index sequence is not sane for citation " .. citation_id) - end - last_note_number = note_number - end - if chapter_number and chapter_number > 0 then - if chapter_number < last_chapter_number then - util.warning("Chapter index sequence is not sane for citation " .. citation_id) - end - last_chapter_number = chapter_number - end - citation_dict[citation_id] = true - end - - for i, post_citation in ipairs(citationsPost) do - local citation_id = post_citation[1] - local note_number = post_citation[2] - local chapter_number = post_citation[3] - if citation_dict[citation_id] then - error(string.format("Previously referenced citationID '%s' encountered in citationsPost", citation_id)) - end - if note_number and note_number > 0 then - if note_number < last_note_number then - util.warning(string.format("Note index sequence is not sane at citationsPost[%d]", i)) - end - last_note_number = note_number - end - if chapter_number and chapter_number > 0 then - if chapter_number < last_chapter_number then - util.warning(string.format("Chapter index sequence is not sane at citationsPost[%d]", i)) - end - last_chapter_number = chapter_number - end - citation_dict[citation_id] = true end end --- A variant of processCitationCluster() for easy use with LaTeX. --- It should be run after refreshing the registry (updateItems()) with all items -function CiteProc:process_citation(citation) - -- util.debug(citation) - -- util.debug(citationsPre) - -- Fix missing noteIndex: sort_CitationNumberPrimaryAscendingViaMacroCitation.txt - - citation = self:normalize_citation_input(citation) - - -- Registor citation +---@param citation CitationData +---@param citations_pre PreCitation[] +---@param citations_post PostCitation[] +---@return CitationData[] +---@return CiteId[] +function CiteProc:_build_reconstituted_citation_list(citation, citations_pre, citations_post) self.registry.citations_by_id[citation.citationID] = citation - table.insert(self.registry.citation_list, citation) - + ---@type [CitationId, NoteIndex][] local citation_note_pairs = {} - for _, citation_ in ipairs(self.registry.citation_list) do - table.insert(citation_note_pairs, {citation_.citationID, citation_.properties.noteIndex}) - end + util.extend(citation_note_pairs, citations_pre) + table.insert(citation_note_pairs, {citation.citationID, citation.properties.noteIndex}) + util.extend(citation_note_pairs, citations_post) - -- update self.registry.citations_by_item_id - for _, cite_item in ipairs(citation.citationItems) do - if not self.registry.citations_by_item_id[cite_item.id] then - self.registry.citations_by_item_id[cite_item.id] = {} + ---@type CiteId[] + local item_ids = {} + ---@type table<ItemId, boolean> + local item_id_dict = {} + ---@type CitationData[] + local citation_list = {} + ---@type table<CitationId, CitationData> + local citations_by_id = {} + -- TODO: Remove citations_by_item_id + ---@type table<ItemId, CitationData[]> + local citations_by_item_id = {} + + for citation_index, pair in ipairs(citation_note_pairs) do + local citation_id, note_index = table.unpack(pair) + local citation_ = self.registry.citations_by_id[citation_id] + if not citation_ then + util.error("Citation not in registry.") end - table.insert(self.registry.citations_by_item_id[cite_item.id], citation) - end + citation_.citation_index = citation_index + citation_.properties.noteIndex = note_index - -- self:updateItems(item_ids) - for i, cite_item in ipairs(citation.citationItems) do - self:get_item(cite_item.id) + table.insert(citation_list, citation_) + citations_by_id[citation_.citationID] = citation_ + for _, cite_item in ipairs(citation_.citationItems) do + if not item_id_dict[cite_item.id] then + item_id_dict[cite_item.id] = true + table.insert(item_ids, cite_item.id) + citations_by_item_id[cite_item.id] = {} + end + table.insert(citations_by_item_id[cite_item.id], citation_) + end end + self.registry.citation_list = citation_list + self.registry.citations_by_id = citations_by_id + self.registry.citations_by_item_id = citations_by_item_id + return citation_list, item_ids +end - local tainted_citation_ids = self:get_tainted_citation_ids(citation_note_pairs) +---@param citation_list CitationData[] +---@return table<CitationId, boolean> +function CiteProc:_set_positions(citation_list) + ---@type table<CitationId, boolean> + local tainted_citation_ids = {} - local mode = citation.properties.mode - if mode == "suppress-author" and self.style.class == "note" then - mode = nil + ---@type {[integer]: CitationData[]} + local chapter_citations = {} + for _, citation in ipairs(citation_list) do + local chapter_number = citation.properties.chapterIndex + if not chapter_citations[chapter_number] then + chapter_citations[chapter_number] = {} + end + table.insert(chapter_citations[chapter_number], citation) end - local citation_element = self.style.citation - if mode == "author-only" and self.style.intext then - citation_element = self.style.intext - elseif mode == "full-cite" then - citation_element = self.style.full_citation + + for _, citations in pairs(chapter_citations) do + self:_update_chapter_positions(citations, tainted_citation_ids) end - local citation_str = citation_element:build_citation_str(citation, self) + -- Update tainted citation ids because of citation-number's change + -- The self.tainted_item_ids were added in the sort_bibliography() procedure. + for item_id, _ in pairs(self.tainted_item_ids) do + if self.registry.citations_by_item_id[item_id] then + for _, citation in ipairs(self.registry.citations_by_item_id[item_id]) do + tainted_citation_ids[citation.citationID] = true + end + end + end - return citation_str + return tainted_citation_ids end - -function CiteProc:get_tainted_citation_ids(citation_note_pairs) - local tainted_citation_ids = {} - - self.cite_first_note_numbers = {} - self.cite_last_note_numbers = {} - self.note_citations_map = {} - -- { - -- 1 = {"citation-1", "citation-2"}, - -- 2 = {"citation-2"}, - -- } - - -- Citations with noteIndex == 0 are in-text citations and they may also - -- have position properties. +---@param citation_list CitationData[] +---@param tainted_citation_ids table<CitationId, boolean> +---@return table<string, boolean> +function CiteProc:_update_chapter_positions(citation_list, tainted_citation_ids) + ---@type CitationData[] local in_text_citations = {} - - local last_chapter_number = 0 - - local previous_citation - for citation_index, pair in ipairs(citation_note_pairs) do - local citation_id, note_number = table.unpack(pair) - -- util.debug(citation_id) - local citation = self.registry.citations_by_id[citation_id] - citation.properties.noteIndex = note_number - citation.citation_index = citation_index - - local chapter_number = citation.properties.chapterIndex - if chapter_number and chapter_number ~= last_chapter_number then - self.cite_first_note_numbers = {} - self.cite_last_note_numbers = {} - self.note_citations_map = {} - previous_citation = nil + ---@type CitationData[] + local note_citations = {} + for _, citation in ipairs(citation_list) do + if citation.properties.noteIndex == 0 then + table.insert(in_text_citations, citation) + else + table.insert(note_citations, citation) end + end + for _, citations in ipairs({in_text_citations, note_citations}) do + ---@type table<CiteId, NoteIndex> + local first_ref = {} + ---@type table<CiteId, NoteIndex> + local last_ref = {} + ---@type table<NoteIndex, CitationId[]> + local num_citations_in_note = {} - local tainted = false - - local prev_citation = previous_citation - if note_number == 0 then - -- Find the previous in-text citation. - prev_citation = in_text_citations[#in_text_citations] - end - local previous_cite - for _, cite_item in ipairs(citation.citationItems) do - tainted = self:set_cite_item_position(cite_item, note_number, previous_cite, prev_citation, citation) - - -- https://citeproc-js.readthedocs.io/en/latest/csl-json/markup.html#citations - -- Citations within the main text of the document have a noteIndex of zero. - if (self.style.class == "note" and note_number > 0) or citation.properties.mode ~= "author-only" then - self.cite_last_note_numbers[cite_item.id] = note_number - previous_cite = cite_item + for _, citation in ipairs(citations) do + local note_index = citation.properties.noteIndex + if not num_citations_in_note[note_index] then + num_citations_in_note[note_index] = {} end + table.insert(num_citations_in_note[note_index], citation.citationID) end - if tainted then - tainted_citation_ids[citation.citationID] = true - end + local previous_citation + for _, citation in ipairs(citations) do + local mode = citation.properties.mode + local note_index = citation.properties.noteIndex + local previous_cite + for _, cite_item in ipairs(citation.sorted_items) do + local position_properties = { + position_level = cite_item.position_level, + ["first-reference-note-number"] = cite_item["first-reference-note-number"], + near_note = cite_item.near_note, + } + + self:_set_cite_item_position(cite_item, note_index, previous_cite, previous_citation, citation, first_ref, last_ref, num_citations_in_note) + + if self:_check_tainted_position_change(cite_item, position_properties) then + tainted_citation_ids[citation.citationID] = true + end - if not self.note_citations_map[note_number] then - self.note_citations_map[note_number] = {} - end - table.insert(self.note_citations_map[note_number], citation.citationID) - if citation.properties.mode ~= "author-only" then - if note_number == 0 then - table.insert(in_text_citations, citation) - else + -- https://citeproc-js.readthedocs.io/en/latest/csl-json/markup.html#citations + -- Citations within the main text of the document have a noteIndex of zero. + if mode ~= "author-only" and mode ~= "full-cite" then + if not first_ref[cite_item.id] and note_index > 0 then + -- note_index == 0 implied an in-text citation + first_ref[cite_item.id] = note_index + end + last_ref[cite_item.id] = note_index + previous_cite = cite_item + end + end + + if mode ~= "author-only" and mode ~= "full-cite" then previous_citation = citation end end - last_chapter_number = chapter_number - end - - -- Update tainted citation ids because of citation-number's change - -- The self.tainted_item_ids were added in the sort_bibliography() procedure. - for item_id, _ in pairs(self.tainted_item_ids) do - if self.registry.citations_by_item_id[item_id] then - for _, citation in ipairs(self.registry.citations_by_item_id[item_id]) do - tainted_citation_ids[citation.citationID] = true + if self.style.class == "note" and self.style.has_disambiguate then + ---@type table<CiteId, CitationData[]> + local citations_by_item_id = {} + for _, citation in ipairs(citations) do + if citation.properties.mode ~= "author-only" and citation.properties.mode ~= "full-cite" then + for _, cite_item in ipairs(citation.sorted_items) do + if not citations_by_item_id[cite_item.id] then + citations_by_item_id[cite_item.id] = {} + end + table.insert(citations_by_item_id[cite_item.id], citation) + end + end + end + for _, citation in ipairs(citations) do + if citation.properties.mode ~= "author-only" and citation.properties.mode ~= "full-cite" then + for _, cite_item in ipairs(citation.sorted_items) do + assert(citations_by_item_id[cite_item.id]) + local num_citations = #citations_by_item_id[cite_item.id] + if not cite_item.num_citations or (num_citations < 2) ~= (cite_item.num_citations < 2) then + -- self.tainted_item_ids[cite_item.id] = true + for _, citation_ in ipairs(citations_by_item_id[cite_item.id]) do + tainted_citation_ids[citation_.citationID] = true + end + end + cite_item.num_citations = num_citations + end + end end end end @@ -686,58 +817,41 @@ function CiteProc:get_tainted_citation_ids(citation_note_pairs) return tainted_citation_ids end -function CiteProc:set_cite_item_position(cite_item, note_number, previous_cite, previous_citation, citation) - local position = Position.First - +function CiteProc:_set_cite_item_position(cite_item, note_index, previous_cite, previous_citation, citation, first_ref, last_ref, num_citations_in_note) -- https://citeproc-js.readthedocs.io/en/latest/csl-json/markup.html#citations -- Citations within the main text of the document have a noteIndex of zero. - if citation.properties.mode == "author-only" then + if citation.properties.mode == "author-only" or citation.properties.mode == "full-cite" then -- discretionary_IbidInAuthorDateStyleWithoutIntext.txt - cite_item.position_level = position - return false + cite_item.position_level = Position.First + cite_item.near_note = false + return end - local first_reference_note_number = self.cite_first_note_numbers[cite_item.id] + local first_reference_note_number = first_ref[cite_item.id] if first_reference_note_number then - position = Position.Subsequent - elseif note_number > 0 then - -- note_number == 0 implied an in-text citation - self.cite_first_note_numbers[cite_item.id] = note_number + cite_item.position_level = Position.Subsequent + cite_item["first-reference-note-number"] = first_reference_note_number + else + cite_item.position_level = Position.First end - local preceding_cite_item = self:get_preceding_cite_item(cite_item, previous_cite, previous_citation, note_number) + local preceding_cite_item = self:_find_preceding_ibid_item(cite_item, previous_cite, previous_citation, note_index, num_citations_in_note) if preceding_cite_item then - position = self:_get_cite_position(cite_item, preceding_cite_item) + cite_item.position_level = self:_get_ibid_position(cite_item, preceding_cite_item) end - local near_note = false - local last_note_number = self.cite_last_note_numbers[cite_item.id] + cite_item.near_note = false + local last_note_number = last_ref[cite_item.id] if last_note_number then - local note_distance = note_number - last_note_number - if note_distance <= self.style.citation.near_note_distance then - near_note = true - end + local note_distance = note_index - last_note_number + cite_item.near_note = (note_distance <= self.style.citation.near_note_distance) end - local tainted = false - if cite_item.position_level ~= position then - tainted = true - cite_item.position_level = position - end - if cite_item["first-reference-note-number"] ~= first_reference_note_number then - tainted = true - cite_item["first-reference-note-number"] = first_reference_note_number - end - if cite_item.near_note ~= near_note then - tainted = true - cite_item.near_note = near_note - end - return tainted end -- Find the preceding cite referencing the same item -function CiteProc:get_preceding_cite_item(cite_item, previous_cite, previous_citation, note_number) +function CiteProc:_find_preceding_ibid_item(cite_item, previous_cite, previous_citation, note_index, num_citations_in_note) if previous_cite then -- a. the current cite immediately follows on another cite, within the same -- citation, that references the same item @@ -752,11 +866,11 @@ function CiteProc:get_preceding_cite_item(cite_item, previous_cite, previous_cit -- b. the current cite is the first cite in the citation, and the previous -- citation consists of a single cite referencing the same item local previous_note_number = previous_citation.properties.noteIndex - local num_previous_note_citations = #self.note_citations_map[previous_note_number] - if (previous_note_number == note_number - 1 and num_previous_note_citations == 1) - or previous_note_number == note_number then - if #previous_citation.citationItems == 1 then - previous_cite = previous_citation.citationItems[1] + local num_previous_note_citations = #num_citations_in_note[previous_note_number] + if (previous_note_number == note_index - 1 and num_previous_note_citations == 1) + or previous_note_number == note_index then + if #previous_citation.sorted_items == 1 then + previous_cite = previous_citation.sorted_items[1] if previous_cite.id == cite_item.id then return previous_cite end @@ -766,7 +880,7 @@ function CiteProc:get_preceding_cite_item(cite_item, previous_cite, previous_cit return nil end -function CiteProc:_get_cite_position(item, preceding_cite) +function CiteProc:_get_ibid_position(item, preceding_cite) if preceding_cite.locator then if item.locator then if item.locator == preceding_cite.locator and item.label == preceding_cite.label then @@ -786,142 +900,51 @@ function CiteProc:_get_cite_position(item, preceding_cite) end end -function CiteProc:makeCitationCluster(citation_items) - local special_form = nil - local items = {} - - for i, cite_item in ipairs(citation_items) do - cite_item = self:normalize_cite_item(cite_item) - local item_data = self:get_item(cite_item.id) - - -- Create a wrapper of the orignal item from registry so that - -- it may hold different `locator` or `position` values for cites. - local cite_item = setmetatable(cite_item, {__index = item_data}) - - if not special_form then - for _, form in ipairs({"author-only", "suppress-author", "coposite"}) do - if cite_item[form] then - special_form = form - end - end - end - - -- Set "first-reference-note-number" variable when called from - -- processCitationCluster() > updateItems() - local citations = self.registry.citations_by_item_id[cite_item.id] - if citations and #citations > 0 then - item_data["first-reference-note-number"] = citations[1].properties.noteIndex +function CiteProc:_check_tainted_position_change(cite_item, position_properties) + for key, value in pairs(position_properties) do + if cite_item[key] ~= value then + return true end + end + return false +end - cite_item.position_level = Position.First - if self.cite_first_note_numbers[cite_item.id] then - cite_item.position_level = Position.Subsequent - else - self.cite_first_note_numbers[cite_item.id] = 0 +---@param tainted_citation_ids table<CitationId, boolean> +---@return [integer, string, CitationId][] +function CiteProc:_rerun_changed_cites(tainted_citation_ids) + local result = {} + for citation_id, _ in pairs(tainted_citation_ids) do + local citation = self.registry.citations_by_id[citation_id] + local citation_index = citation.citation_index + local mode = citation.properties.mode + if mode == "suppress-author" and self.style.class == "note" then + mode = nil end - - local preceding_cite - if i == 1 then - local previous_citation = self.registry.previous_citation - if previous_citation then - if #previous_citation.citationItems == 1 and previous_citation.citationItems[1].id == cite_item.id then - preceding_cite = previous_citation.citationItems[1] - end + local citation_element = self.style.citation + if mode == "author-only" and self.style.intext then + citation_element = self.style.intext + elseif mode == "full-cite" then + if self.style.class == "note" then + citation_element = self.style.citation + else + citation_element = self.style.full_citation end - elseif citation_items[i - 1].id == cite_item.id then - preceding_cite = citation_items[i - 1] end - if preceding_cite then - cite_item.position_level = self:_get_cite_position(cite_item, preceding_cite) - end - - table.insert(items, cite_item) - end - - if self.registry.requires_sorting then - self:sort_bibliography() - end - - self:check_valid_citation_element() - local citation_element = self.style.citation - if special_form == "author-only" and self.style.intext then - citation_element = self.style.intext - end - - local res = citation_element:build_cluster(items, self) - - -- local context = { - -- build = {}, - -- engine=self, - -- } - -- local res = self.style:render_citation(items, context) - - self.registry.previous_citation = { - citationID = "pseudo-citation", - citationItems = items, - properties = { - noteIndex = 0, - } - } - return res -end - ----@param bibsection any ----@return [{[string]: string | number | boolean}, string[]] -function CiteProc:makeBibliography(bibsection) - -- The bibsection works as a filter described in - -- <https://citeproc-js.readthedocs.io/en/latest/running.html#selective-output-with-makebibliography>. - if not self.style.bibliography then - return {{}, {}} - end - - local res = {} - - self.registry.widest_label = "" - self.registry.maxoffset = 0 - - local ids = self:get_sorted_refs() - if bibsection then - ids = self:filter_with_bibsection(ids, bibsection) + local citation_str = citation_element:build_citation_str(citation, self) + table.insert(result, {citation_index, citation_str, citation_id}) end - for _, id in ipairs(ids) do - local str = self.style.bibliography:build_bibliography_str(id, self) - table.insert(res, str) - end - - local bib_start = self.output_format.markups["bibstart"] - local bib_end = self.output_format.markups["bibend"] - if type(bib_start) == "function" then - bib_start = bib_start(self) - end - if type(bib_end) == "function" then - bib_end = bib_end(self) - end - - local params = { - hangingindent = self.style.bibliography.hanging_indent, - ["second-field-align"] = self.style.bibliography.second_field_align or false, - linespacing = self.style.bibliography.line_spacing, - entryspacing = self.style.bibliography.entry_spacing, - maxoffset = self.registry.maxoffset, - widest_label = self.registry.widest_label, - bibstart = bib_start, - bibend = bib_end, - entry_ids = util.clone(self.registry.reflist), - } - - return {params, res} + return result end -function CiteProc:get_sorted_refs() +function CiteProc:_get_sorted_refs() if self.registry.requires_sorting then self:sort_bibliography() end return self.registry.reflist end -function CiteProc:filter_with_bibsection(ids, bibsection) +function CiteProc:_filter_with_bibsection(ids, bibsection) if bibsection.quash then return self:filter_quash(ids, bibsection) elseif bibsection.select then diff --git a/Master/texmf-dist/scripts/citation-style-language/citeproc-manager.lua b/Master/texmf-dist/scripts/citation-style-language/citeproc-manager.lua index 4f824feab24..e361d6f6a8a 100644 --- a/Master/texmf-dist/scripts/citation-style-language/citeproc-manager.lua +++ b/Master/texmf-dist/scripts/citation-style-language/citeproc-manager.lua @@ -7,6 +7,7 @@ local citeproc_manager = {} require("lualibs") +local json_encode = utilities.json.tojson local json_decode = utilities.json.tolua local citeproc = require("citeproc") @@ -14,7 +15,7 @@ local bibtex_data = require("citeproc-bibtex-data") local bibtex_parser = require("citeproc-bibtex-parser") local latex_parser = require("citeproc-latex-parser") local util = citeproc.util -local unicode = require("citeproc-unicode") +local unicode = require("citeproc-unicode") ---@param file_name string @@ -221,6 +222,7 @@ end ---@alias LanguageCode string ---@class RefSection +---@field index integer ---@field initialized boolean ---@field style_id string? ---@field bib_resources FilePath[] @@ -233,12 +235,14 @@ end ---@field citations CitationData[] ---@field citations_pre table[] ---@field bibliography_configs string[] +---@field style string local RefSection = {} ---@return RefSection function RefSection:new() ---@type RefSection local ref_section = { + index = 0, initialized = false, style_id = nil, bib_resources = {}, @@ -251,6 +255,7 @@ function RefSection:new() citations = {}, citations_pre = {}, bibliography_configs = {}, + style = "", } setmetatable(ref_section, self) self.__index = self @@ -276,6 +281,9 @@ function RefSection:make_citeproc_engine() self.lang = nil end + self.style = style + -- self.items + self.engine = citeproc.new(citeproc_sys, style, self.lang, force_lang) self:_check_dependent_style(citeproc_sys) @@ -334,6 +342,86 @@ function RefSection:_update_uncited_items() self.uncited_ids = uncited_ids end +function RefSection:record_fixture() + if not self.fixture then + self.fixture = { + mode = "citation", + description = tex.jobname, + result = "", + bibliography_result = "", + citations = "", + ["citation-items"] = "", + csl = self.style, + input = "", + version = "1.0", + citation_results = {}, + } + end + local fixture = self.fixture + + local cited_id_dict = {} + for _, citation in ipairs(self.citations) do + for _, cite_item in ipairs(citation.citationItems) do + cited_id_dict[cite_item.id] = true + end + end + local input_items = {} + for _, item in ipairs(self.items) do + if cited_id_dict[item.id] then + table.insert(input_items, item) + end + end + fixture.input = json_encode(input_items) + + local citation_items = {} + for _, citation in ipairs(self.citations) do + table.insert(citation_items, util.clone(citation.citationItems)) + end + fixture["citation-items"] = json_encode(citation_items) + + local citations = {} + local citations_pre = {} + for _, citation in ipairs(self.citations) do + table.insert(citations, {citation, util.clone(citations_pre), {}}) + table.insert(citations_pre, {citation.citationID, citation.properties.noteIndex}) + end + fixture.citations = string.gsub(json_encode(citations), "{%s*}", "[]") + + local result = {} + for i, citation_result in ipairs(fixture.citation_results) do + if i == #fixture.citation_results then + table.insert(result, string.format(">>[%d] %s", i - 1, citation_result)) + else + table.insert(result, string.format("..[%d] %s", i - 1, citation_result)) + end + end + fixture.result = table.concat(result, "\n") + + local fixture_output = {} + local function make_block(section, str) + return string.format(">>===== %s =====>>\n%s\n<<===== %s =====<<\n", string.upper(section), str, string.upper(section)) + end + for _, section in ipairs({"mode", "description", "result", "bibliography_result", "citations", "citation-items", "csl", "input", "version"}) do + if not (section == "bibliography_result" and fixture[section] == "") then + table.insert(fixture_output, make_block(section, fixture[section])) + end + end + local fixture_str = table.concat(fixture_output, "\n\n") + + local file_name = string.format("%s.txt", tex.jobname) + if self.index > 0 then + file_name = string.format("%s-%d.txt", tex.jobname, self.index) + end + + local fixture_file = io.open(file_name, "w") + if fixture_file then + fixture_file:write(fixture_str) + fixture_file:close() + else + error(string.format("Failed to write fixture file '%s'", file_name)) + end +end + ---@class CslCitationManager ---@field global_ref_section RefSection @@ -342,6 +430,7 @@ end ---@field ref_sections table<integer, RefSection> ---@field ref_section RefSection ---@field hyperref_loaded boolean +---@field regression_test boolean local CslCitationManager = {} ---@return CslCitationManager @@ -361,6 +450,7 @@ function CslCitationManager:new() ref_section = ref_section, hyperref_loaded = false, + regression_test = false, } setmetatable(o, self) @@ -388,6 +478,10 @@ function CslCitationManager:init(style_id, bib_resources_str, lang) if self.hyperref_loaded then global_ref_section.engine:enable_linking() end + if self.regression_test then + self.global_ref_section:record_fixture() + end + self.ref_section_index = 0 end @@ -414,6 +508,7 @@ function CslCitationManager:begin_ref_section(style_id, bib_resources_str, lang) self.ref_section = self.ref_sections[self.ref_section_index] if not self.ref_section then self.ref_section = RefSection:new() + self.ref_section.index = self.ref_section_index self.ref_sections[self.ref_section_index] = self.ref_section end @@ -434,6 +529,10 @@ function CslCitationManager:begin_ref_section(style_id, bib_resources_str, lang) self.ref_section.engine:enable_linking() end + if self.regression_test then + self.ref_section:record_fixture() + end + end @@ -456,6 +555,7 @@ function CslCitationManager:register_citation_info(ref_section_index_str, citati if not ref_section then ref_section = RefSection:new() self.ref_sections[ref_section_index] = ref_section + ref_section.index = ref_section_index end local citation = self:_make_citation(citation_info) @@ -493,6 +593,8 @@ function CslCitationManager:cite(citation_info) local citation = self:_make_citation(citation_info) -- util.debug(citation) + table.insert(self.ref_section.citations, citation) + local citation_str -- if preview_mode then -- -- TODO: preview mode in first pass of \blockquote of csquotes @@ -512,6 +614,11 @@ function CslCitationManager:cite(citation_info) -- and <https://tex.stackexchange.com/questions/519954/backslashes-in-macros-defined-in-lua-code>. tex.sprint(string.format("\\expandafter\\def\\csname l__csl_citation_tl\\endcsname{%s}", citation_str)) + if self.regression_test then + table.insert(self.ref_section.fixture.citation_results, citation_str) + self.ref_section:record_fixture() + end + table.insert(self.ref_section.citations_pre, {citation.citationID, citation.properties.noteIndex}) end @@ -627,6 +734,11 @@ function CslCitationManager:bibliography(filter_str) end local bib_lines = self:make_bibliography(filter_str) tex.print(util.split(table.concat(bib_lines, "\n"), "\n")) + + if self.regression_test then + self.ref_section.fixture.bibliography_result = table.concat(bib_lines, "\n") + self.ref_section:record_fixture() + end end ---@param filter_str string @@ -799,6 +911,7 @@ function CslCitationManager:read_aux_file(aux_content) if not ref_section then ref_section = RefSection:new() self.ref_sections[ref_section_index] = ref_section + ref_section.index = ref_section_index self.ref_section = ref_section end if command == "\\csl@aux@style" then diff --git a/Master/texmf-dist/scripts/citation-style-language/citeproc-node-citation.lua b/Master/texmf-dist/scripts/citation-style-language/citeproc-node-citation.lua index 839c22e1b51..183d9f68070 100644 --- a/Master/texmf-dist/scripts/citation-style-language/citeproc-node-citation.lua +++ b/Master/texmf-dist/scripts/citation-style-language/citeproc-node-citation.lua @@ -178,13 +178,6 @@ end ---@alias CiteId string | number ----@class CitationItem ----@field id CiteId ----@field prefix string? ----@field suffix string? ----@field locator string? ----@field label string? - ---comment ---@param citation_items CitationItem[] ---@param engine CiteProc @@ -195,6 +188,8 @@ function Citation:build_cluster(citation_items, engine, properties) local output_format = engine.output_format ---@type CiteIr[] local irs = {} + -- The citation_items are already sorted when evaluate the positions + -- To be removed citation_items = self:sorted_citation_items(citation_items, engine) for _, cite_item in ipairs(citation_items) do local ir = self:build_fully_disambiguated_ir(cite_item, output_format, engine, properties) @@ -437,7 +432,7 @@ end ---@param cite_item CitationItem ---@param output_format OutputFormat ---@param engine CiteProc ----@param properties table +---@param properties CitationProperties ---@return CiteIr function Citation:build_fully_disambiguated_ir(cite_item, output_format, engine, properties) -- util.debug(cite_item.id) @@ -451,12 +446,14 @@ function Citation:build_fully_disambiguated_ir(cite_item, output_format, engine, -- Disambiguation should be based on the subsequent form -- disambiguate_BasedOnEtAlSubsequent.txt cite_item.position_level = Position.Subsequent + cite_item["first-reference-note-number"] = properties.noteIndex local disam_ir = self:build_ambiguous_ir(cite_item, output_format, engine) disam_ir = self:apply_disambiguate_add_givenname(disam_ir, engine) disam_ir = self:apply_disambiguate_add_names(disam_ir, engine) disam_ir = self:apply_disambiguate_conditionals(disam_ir, engine) disam_ir = self:apply_disambiguate_add_year_suffix(disam_ir, engine) cite_item.position_level = Position.First + cite_item["first-reference-note-number"] = nil end return cite_ir @@ -1034,7 +1031,6 @@ function Citation:apply_disambiguate_conditionals(cite_ir, engine) -- Update ir output local inlines = ir_:flatten(disam_format) local disam_str = disam_format:output(inlines, nil) - -- util.debug("update: " .. ir_.cite_item.id .. ": " .. disam_str) ir_.disam_str = disam_str if not engine.cite_irs_by_output[disam_str] then engine.cite_irs_by_output[disam_str] = {} diff --git a/Master/texmf-dist/scripts/citation-style-language/citeproc-util.lua b/Master/texmf-dist/scripts/citation-style-language/citeproc-util.lua index 12d2b14ee95..46a4c0aaa77 100644 --- a/Master/texmf-dist/scripts/citation-style-language/citeproc-util.lua +++ b/Master/texmf-dist/scripts/citation-style-language/citeproc-util.lua @@ -1063,7 +1063,7 @@ util.roman_numerals = { -- Choose ----@enum Postion +---@enum Position local Position = { First = 0, Subsequent = 1, diff --git a/Master/texmf-dist/scripts/citation-style-language/citeproc.lua b/Master/texmf-dist/scripts/citation-style-language/citeproc.lua index 31b624b4d93..c71b90577ed 100755 --- a/Master/texmf-dist/scripts/citation-style-language/citeproc.lua +++ b/Master/texmf-dist/scripts/citation-style-language/citeproc.lua @@ -16,7 +16,7 @@ else util = require("citeproc.util") end -citeproc.__VERSION__ = "0.6.3" +citeproc.__VERSION__ = "0.6.4" citeproc.new = engine.CiteProc.new citeproc.util = util diff --git a/Master/texmf-dist/tex/latex/citation-style-language/citation-style-language-init.sty b/Master/texmf-dist/tex/latex/citation-style-language/citation-style-language-init.sty index de5b5bed4ce..9032b60fee8 100644 --- a/Master/texmf-dist/tex/latex/citation-style-language/citation-style-language-init.sty +++ b/Master/texmf-dist/tex/latex/citation-style-language/citation-style-language-init.sty @@ -83,6 +83,10 @@ \cs_new:Npn \__csl_initialize_lua_module: { + \bool_if:NT \l__csl_regression_test_bool + { + \lua_now:n { csl_citation_manager.regression_test = true } + } \tl_set:Nx \l_tmpa_tl { \clist_use:Nn \l__csl_bib_resources_clist { , } } \lua_now:e { diff --git a/Master/texmf-dist/tex/latex/citation-style-language/citation-style-language.sty b/Master/texmf-dist/tex/latex/citation-style-language/citation-style-language.sty index f6039b4008c..33ce246978a 100644 --- a/Master/texmf-dist/tex/latex/citation-style-language/citation-style-language.sty +++ b/Master/texmf-dist/tex/latex/citation-style-language/citation-style-language.sty @@ -9,7 +9,7 @@ \RequirePackage{expl3} \RequirePackage{xparse} -\ProvidesExplPackage {citation-style-language} {2024-08-28} {0.6.3} +\ProvidesExplPackage {citation-style-language} {2024-09-15} {0.6.4} {Citation Style Language for LaTeX} \RequirePackage { l3keys2e } diff --git a/Master/texmf-dist/tex/latex/citation-style-language/locales/csl-locales-de-AT.xml b/Master/texmf-dist/tex/latex/citation-style-language/locales/csl-locales-de-AT.xml index 833ff58f768..2d27ec8635d 100644 --- a/Master/texmf-dist/tex/latex/citation-style-language/locales/csl-locales-de-AT.xml +++ b/Master/texmf-dist/tex/latex/citation-style-language/locales/csl-locales-de-AT.xml @@ -20,7 +20,7 @@ <name>Frank Bennett</name> </translator> <rights license="http://creativecommons.org/licenses/by-sa/3.0/">This work is licensed under a Creative Commons Attribution-ShareAlike 3.0 License</rights> - <updated>2024-03-09T15:20:54-05:00</updated> + <updated>2024-08-27T14:30:55-04:00</updated> </info> <style-options punctuation-in-quote="false"/> <date form="text"> @@ -46,7 +46,7 @@ <term name="no-publisher" form="short">n.p.</term> <term name="on">on</term> <term name="op-cit">op. cit.</term> <!-- like ibid., the abbreviated form is the regular form --> - <term name="original-work-published">original work published</term> + <term name="original-work-published">Ursprünglich erschienen</term> <term name="personal-communication">persönliche Kommunikation</term> <term name="podcast">podcast</term> <term name="podcast-episode">podcast episode</term> diff --git a/Master/texmf-dist/tex/latex/citation-style-language/locales/csl-locales-de-CH.xml b/Master/texmf-dist/tex/latex/citation-style-language/locales/csl-locales-de-CH.xml index 47a13f2740f..9edebba8375 100644 --- a/Master/texmf-dist/tex/latex/citation-style-language/locales/csl-locales-de-CH.xml +++ b/Master/texmf-dist/tex/latex/citation-style-language/locales/csl-locales-de-CH.xml @@ -14,7 +14,7 @@ <name>Sebastian Karcher</name> </translator> <rights license="http://creativecommons.org/licenses/by-sa/3.0/">This work is licensed under a Creative Commons Attribution-ShareAlike 3.0 License</rights> - <updated>2024-03-09T15:20:54-05:00</updated> + <updated>2024-08-27T14:30:55-04:00</updated> </info> <style-options punctuation-in-quote="false"/> <date form="text"> @@ -40,7 +40,7 @@ <term name="no-publisher" form="short">n.p.</term> <term name="on">on</term> <term name="op-cit">op. cit.</term> <!-- like ibid., the abbreviated form is the regular form --> - <term name="original-work-published">original work published</term> + <term name="original-work-published">Ursprünglich erschienen</term> <term name="personal-communication">persönliche Kommunikation</term> <term name="podcast">podcast</term> <term name="podcast-episode">podcast episode</term> diff --git a/Master/texmf-dist/tex/latex/citation-style-language/locales/csl-locales-de-DE.xml b/Master/texmf-dist/tex/latex/citation-style-language/locales/csl-locales-de-DE.xml index f7e25ad0f31..903378388a3 100644 --- a/Master/texmf-dist/tex/latex/citation-style-language/locales/csl-locales-de-DE.xml +++ b/Master/texmf-dist/tex/latex/citation-style-language/locales/csl-locales-de-DE.xml @@ -17,7 +17,7 @@ <name>jakov</name> </translator> <rights license="http://creativecommons.org/licenses/by-sa/3.0/">This work is licensed under a Creative Commons Attribution-ShareAlike 3.0 License</rights> - <updated>2024-03-09T15:20:54-05:00</updated> + <updated>2024-08-27T14:30:55-04:00</updated> </info> <style-options punctuation-in-quote="false"/> <date form="text"> @@ -43,7 +43,7 @@ <term name="no-publisher" form="short">n.p.</term> <term name="on">on</term> <term name="op-cit">op. cit.</term> <!-- like ibid., the abbreviated form is the regular form --> - <term name="original-work-published">original work published</term> + <term name="original-work-published">Ursprünglich erschienen</term> <term name="personal-communication">persönliche Kommunikation</term> <term name="podcast">podcast</term> <term name="podcast-episode">podcast episode</term> diff --git a/Master/texmf-dist/tex/latex/citation-style-language/styles/apa.csl b/Master/texmf-dist/tex/latex/citation-style-language/styles/apa.csl index a78e7f315fd..97fc1afd6cf 100644 --- a/Master/texmf-dist/tex/latex/citation-style-language/styles/apa.csl +++ b/Master/texmf-dist/tex/latex/citation-style-language/styles/apa.csl @@ -14,7 +14,7 @@ <category citation-format="author-date"/> <category field="psychology"/> <category field="generic-base"/> - <updated>2024-08-24T12:16:51-04:00</updated> + <updated>2024-08-27T14:44:31-04: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"> @@ -832,7 +832,7 @@ <group delimiter=" "> <text variable="genre" text-case="capitalize-first"/> <group delimiter=" "> - <text term="author" form="verb"/> + <text term="container-author" form="verb"/> <names variable="interviewer"> <name and="symbol" initialize-with=". " delimiter=", "/> </names> |