Module:License Wikidata

require('strict')

local p = {} --p stands for package

local getArgs = require('Module:Arguments').getArgs local tableToolsModule = require("Module:TableTools") local dateModule = require("Module:Era")

local property_ids = { ['deathyear'] = 'P570', ['pubyear'] = 'P577', ['edition'] = 'P629' }

local function clean_table(t) return tableToolsModule.removeDuplicates(tableToolsModule.compressSparseArray(t)) end

--[=[	Death/publication year ]=]

local function getYearFromSingleStatement(statement) local snak = statement.mainsnak -- We're not using mw.wikibase.formatValue because we only want years. if snak.snaktype ~= 'value' then return nil end -- Precision is less than a year. if snak.datavalue.value.precision < 9 then return nil end -- Year is approximate. -- P1480 = sourcing circumstances, Q5727902 = circa. if statement.qualifiers ~= nil and statement.qualifiers.P1480 ~= nil then for _, qualifier in pairs(statement.qualifiers.P1480) do			if qualifier.datavalue ~= nil and qualifier.datavalue.value.id == 'Q5727902' then return nil end end end -- Extract year from the time value. local _, _, extractedYear = string.find(snak.datavalue.value.time, '([%+%-]%d%d%d+)%-') local year = tonumber(extractedYear) -- Handle BCE years. -1 BCE = 0. if year < 0 then year = year + 1 end return year end

local function getItemFromWikidataID(wikidata_id) if wikidata_id ~= nil and wikidata_id ~= '' then return mw.wikibase.getEntity(wikidata_id) or nil else return mw.wikibase.getEntity or nil end end

local function getYearsFromWikidata(args) local item = getItemFromWikidataID(args.wikidata_id) if not item then return nil end local year_prop = args.year_prop -- Compile a list of year statements. local statements = item:getBestStatements(year_prop) if #statements == 0 then return nil end -- Compile a list of years, one from each statement. local years = {} for _, statement in pairs(statements) do		table.insert(years, getYearFromSingleStatement(statement)) end years = clean_table(years) if #years == 0 then return nil end -- Return a sorted list of years. table.sort(years) return years end

local function sortForBestYear(args) local years = args.years if not years then return nil end if args.reverse_sort then table.sort(years, function(a, b) return a > b end) else table.sort(years) end for _, year in pairs(years) do		if tonumber(year) then return tonumber(year) end end return nil end

local function getBestYearFromWikidata(args) local wikidata_years = getYearsFromWikidata({		['wikidata_id'] = args.wikidata_id,		['year_prop'] = args.year_prop	}) return sortForBestYear({['years'] = wikidata_years, ['reverse_sort'] = args.reverse_sort}) end

local function getAuthorDeathYearFromWikidata(wikidata_id) return getBestYearFromWikidata({		['wikidata_id'] = wikidata_id,		['year_prop'] = property_ids['deathyear'],		['reverse_sort'] = true	}) end

local function getPublicationYearFromWikidata(wikidata_id) return getBestYearFromWikidata({		['wikidata_id'] = wikidata_id,		['year_prop'] = property_ids['pubyear'],		['reverse_sort'] = false	}) end

--[=[	Creator death years ]=]

local function getCreatorsFromSingleProp(item, creator_prop) -- Compile a list of creator statements. local statements = item:getBestStatements(creator_prop) if #statements == 0 then return nil end -- Compile a list of creators, one from each statement. local creators = {} for _, statement in pairs(statements) do		local snak = statement.mainsnak if snak.snaktype == 'value' and snak.datavalue['type'] == 'wikibase-entityid' and snak.datavalue.value['entity-type'] == 'item' then table.insert(creators, snak.datavalue.value.id) end end creators = clean_table(creators) if #creators == 0 then return nil end return creators end

local function getCreators(item, creator_props) local all_creators = {} -- is there a better way to merge tables? for _, creator_prop in pairs(creator_props) do		local creators = getCreatorsFromSingleProp(item, creator_prop) if creators then for _, creator in pairs(creators) do				table.insert(all_creators, creator) end end end all_creators = clean_table(all_creators) if #all_creators == 0 then return nil end return all_creators end

local function getCreatorDeathYearsFromWikidata(args) local item = getItemFromWikidataID(args.wikidata_id) if not item then return nil end --[=[		What I really want is a list of all subproperties of P170 and P767 (unless there are some that shouldn't be included). ]=]	local creator_props = args.creator_props or { ['creator'] = 'P170', ['author'] = 'P50', ['librettist'] = 'P87', ['composer'] = 'P86', ['orchestrator'] = 'P10806', ['adapted by'] = 'P5202', ['screenwriter'] = 'P58', ['lyrics by'] = 'P676', ['performer'] = 'P175', ['illustrator'] = 'P110', ['letterer'] = 'P9191', ['inker'] = 'P10836', ['penciller'] = 'P10837', ['colorist'] = 'P6338', ['contributor'] = 'P767', ['translator'] = 'P655' }	if not creator_props then return nil end local creators = getCreators(item, creator_props) if not creators then return nil end local deathyears = {} for _, creator in pairs(creators) do		local deathyear = getAuthorDeathYearFromWikidata(creator) if deathyear then table.insert(deathyears, deathyear) else return nil -- if creator doesn't have deathyear end end deathyears = clean_table(deathyears) if #deathyears == 0 then return nil end table.sort(deathyears) return deathyears end

local function getBestCreatorDeathYearFromWikidata(args) local wikidata_years = getCreatorDeathYearsFromWikidata({		['wikidata_id'] = args.wikidata_id,		['creator_props'] = args.creator_props	}) return sortForBestYear({['years'] = wikidata_years, ['reverse_sort'] = true}) end

local function getBestYear(args) local manual_years = args.manual_years local wikidata_function = args.wikidata_function local wikidata_function_args = args.wikidata_function_args if manual_years then for _, year in pairs(manual_years) do			if tonumber(year) then return tonumber(year) end end end if wikidata_function then return wikidata_function(wikidata_function_args) end return nil end

local function getAuthorDeathYear(args) return getBestYear({		['manual_years'] = args.deathyears, 		['wikidata_function'] = getAuthorDeathYearFromWikidata,		['wikidata_function_args'] = args.wikidata_id	}) end

local function getWorkCreatorDeathYear(args) return getBestYear({		['manual_years'] = args.deathyears, 		['wikidata_function'] = getBestCreatorDeathYearFromWikidata,		['wikidata_function_args'] = {['wikidata_id'] = args.wikidata_id, ['creator_props'] = args.creator_props}	}) end

local function getPublicationYear(args) --[=[	return getBestYear({		['manual_years'] = args.pubyears, 		['wikidata_function'] = getPublicationYearFromWikidata,		['wikidata_function_args'] = args.wikidata_id	}) ]=]	return getBestYear({['manual_years'] = args.pubyears}) end

local function getWorkCreatorOrAuthorDeathYear(args) local deathyear local namespace = args.namespace or mw.title.getCurrentTitle.nsText if namespace == 'Author' or namespace == 'Author talk' then deathyear = getAuthorDeathYear(args) else deathyear = getWorkCreatorDeathYear(args) end return deathyear end

local function getWorkOrAuthorPublicationYear(args) local pubyear = nil local namespace = args.namespace or mw.title.getCurrentTitle.nsText if namespace ~= 'Author' and namespace ~= 'Author talk' then pubyear = getPublicationYear(args) end return pubyear end

local function getWorksFromEdition(wikidata_id) local item = getItemFromWikidataID(wikidata_id) if not item then return nil end local statements = item:getBestStatements(property_ids['edition']) if #statements == 0 then return nil end local work_ids = {} for i = 1, #statements do		local statement = statements[i] if statement.mainsnak and statement.mainsnak.datatype == 'wikibase-item' and statement.mainsnak.datavalue and statement.mainsnak.datavalue.value and statement.mainsnak.datavalue.value.id then table.insert(work_ids, statement.mainsnak.datavalue.value.id) end end if #work_ids == 0 then return nil end return work_ids end

local function getWorkOrEditionYear(yearFunction, args) args = args or {} local wikidata_id = args.wikidata_id local work_ids = getWorksFromEdition(wikidata_id) or {} for i = 1, #work_ids do		args.wikidata_id = work_ids[i] local work_year = yearFunction(args) if work_year then return work_year end end args.wikidata_id = wikidata_id return yearFunction(args) end

--[=[	Public functions ]=]

function p.getAuthorDeathYear(args) return getWorkOrEditionYear(getAuthorDeathYear, args) end

function p.getPublicationYear(args) return getWorkOrEditionYear(getPublicationYear, args) end

function p.getWorkCreatorDeathYear(args) return getWorkOrEditionYear(getWorkCreatorDeathYear, args) end

function p.getWorkCreatorOrAuthorDeathYear(args) return getWorkOrEditionYear(getWorkCreatorOrAuthorDeathYear, args) end

function p.getWorkOrAuthorPublicationYear(args) return getWorkOrEditionYear(getWorkOrAuthorPublicationYear, args) end

return p