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