Module:SscCitedWorks

From Bodhicitta
Revision as of 17:46, 25 August 2026 by Jeremi (talk | contribs) (List of works quoted in the Śikṣāsamuccaya, counting quotations not segments)
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)

Documentation for this module may be created at Module:SscCitedWorks/doc

local p = {}

-- The list of works quoted in the Śikṣāsamuccaya, generated from the aligned
-- translation memory.
--
-- The join is the RKTS catalogue number. A quote segment records its source as
-- "Ratnameghasūtra (RKTSK 231)", and the text page holds the same id in
-- DrlPageName, so no title matching is involved.
--
-- COUNTS ARE QUOTATIONS, NOT SEGMENTS. One quotation is often split across
-- consecutive segments, so counting segments overstates badly: the
-- Pitāputrasamāgamanasūtra has 62 quote segments but is quoted 14 times, and one
-- of its runs is 36 segments long. Across the SSC, 633 segments are 345
-- quotations. SMW cannot express "consecutive", so the grouping happens here.
--
-- A chapter change breaks a run: two adjacent quotes from one work in different
-- chapters are two quotations. No run in the current data crosses a chapter
-- boundary, but the rule is correct and costs nothing.

local SSC_PREFIX = '~Translation Memory:016-Tsadra-SSC-Root/*'
local SSC_PAGE = 'Texts/Śikṣāsamuccaya'
local SEGMENT_LIMIT = 5000

local function firstValue(v)
	if type(v) == 'table' then return v[1] end
	return v
end

-- Quotation counts keyed by RKTS id.
local function quotationsById()
	local query = mw.smw.ask{
		'[[' .. SSC_PREFIX .. ']][[QuoteSource::+]]',
		'?QuoteSource#=QuoteSource',
		'?SegmentOrder#=SegmentOrder',
		'?TranslationChapter#=TranslationChapter',
		limit = SEGMENT_LIMIT
	}
	if not query then return {} end

	local segments = {}
	for _, row in ipairs(query) do
		local order = tonumber(firstValue(row.SegmentOrder))
		local source = firstValue(row.QuoteSource)
		if order and type(source) == 'string' then
			table.insert(segments, {
				order   = order,
				source  = source,
				chapter = tostring(firstValue(row.TranslationChapter) or ''),
			})
		end
	end
	table.sort(segments, function(a, b) return a.order < b.order end)

	local counts, previous = {}, nil
	for _, seg in ipairs(segments) do
		local continues = previous
			and seg.source == previous.source
			and seg.chapter == previous.chapter
			and seg.order == previous.order + 1
		if not continues then
			local canon, number = seg.source:match('(RKTS[KT])%s*([%d%-]+)')
			if canon then
				local id = canon:upper() .. ' ' .. number
				counts[id] = (counts[id] or 0) + 1
			end
		end
		previous = seg
	end
	return counts
end

function p.main(frame)
	local counts = quotationsById()

	local ids = {}
	for id in pairs(counts) do table.insert(ids, id) end
	if #ids == 0 then return '' end
	table.sort(ids)

	-- One query for every quoted id, rather than one per work.
	local pages = mw.smw.ask{
		'[[DrlPageName::' .. table.concat(ids, '||') .. ']]',
		'?#-=Page',
		'?DrlPageName#=DrlPageName',
		'?Display title of=Title',
		'?FullTitleTib=FullTitleTib',
		'?Fulltitletrans=FullTitleTrans',
		'?Classification=Classification',
		limit = 500
	}
	if not pages then return '' end

	local works = {}
	for _, row in ipairs(pages) do
		local page = firstValue(row.Page)
		local id = firstValue(row.DrlPageName)
		if page and page ~= SSC_PAGE and id and counts[id] then
			local label = firstValue(row.Title)
			if not label or label == '' then label = page:gsub('^Texts/', '') end
			table.insert(works, {
				page  = page,
				label = label,
				tib   = firstValue(row.FullTitleTib),
				trans = firstValue(row.FullTitleTrans),
				class = firstValue(row.Classification),
				count = counts[id],
			})
		end
	end
	if #works == 0 then return '' end

	-- Alphabetical by title, matching the hand-written page it replaces. Sorting
	-- by count would bury the sūtras quoted once among the busiest works.
	table.sort(works, function(a, b) return a.label < b.label end)

	local out = {}
	for _, w in ipairs(works) do
		local author = {}
		if w.tib and w.tib ~= '' then table.insert(author, 'Tib. ' .. w.tib) end
		if w.trans and w.trans ~= '' then table.insert(author, 'Eng. ' .. w.trans) end

		table.insert(out, '<div class="row filterable">')
		table.insert(out, '<div class="col-md-3 col-lg-2 pr-md-5 pt-md-1 pb-1 text-center ' ..
			'text-md-right border-right timeline-border font-serif position-relative">' ..
			'<span class="ssc-cited-count">' .. w.count .. '</span>' ..
			'<span class="ssc-cited-label">' ..
			(w.count == 1 and 'quotation' or 'quotations') .. '</span></div>')
		table.insert(out, frame:expandTemplate{
			title = 'TimelineTileHorizontalTranslations',
			args = {
				wrapperclasses = 'col-md-9 px-2 px-md-5 py-0 font-serif',
				texts = '[[' .. w.page .. '|' .. w.label .. ']]',
				author = table.concat(author, ' &nbsp;·&nbsp; '),
				description = w.class or '',
			}
		})
		table.insert(out, '</div>')
	end

	return frame:preprocess(table.concat(out, '\n'))
end

return p