--script that retrieves basic data stored in Wikidata, for the datamodel, see https://www.mediawiki.org/wiki/Extension:Wikibase_Client/Lua
local wd =
-- creation of a subobject to store comparison funtions, used for sorting claims-- to be able to build more complex sorts like topological sorts
wd.compare =
local modules = local modulesNames =
local function loadModule(t, key) if modulesNames[key] then local m = require(modulesNames[key]) t[key] = m return m endendsetmetatable(modules,)
local datequalifiers =
--
local defaultlang = mw.getContentLanguage:getCode
function wd.translate(str, rep1, rep2) str = modules.i18n[str] or str if rep1 and (type (rep1)
'string')then str = str:gsub('$2', rep2) end return strend
local function addCat(cat, sortkey) if sortkey then return '' end return ''end
local function formatError(key, category, debug) if debug then return error(modules.i18n[key] or key) end if category then return addCat(category, key) else return addCat('cat-unsorted-issue', key) endend
--
function wd.isSpecial(snak) return (snak.snaktype ~= 'value')end
function wd.getId(snak) if (snak.snaktype
function wd.getNumericId(snak) if (snak.snaktype
function wd.getMainId(claim) return wd.getId(claim.mainsnak)end
function wd.entityId(entity) if type(entity)
'table' then return entity.id endend
function wd.getEntityIdForCurrentPage return mw.wikibase.getEntityIdForCurrentPageend
-- function that returns true if the "qid" parameter is the qid -- of the item that is linked to the calling pagefunction wd.isPageOfQId(qid) local self_id = mw.wikibase.getEntityIdForCurrentPage return self_id ~= nil and qid
function wd.getEntity(val) if type(val)
'-' then return nil end if val
function wd.splitStr(val) -- transforme en table les chaînes venant du Wikitexte qui utilisent des virgules de séparation if type(val)
function wd.isHere(searchset, val) for i, j in pairs(searchset) do if val
local function wikidataLink(entity) local name =':d:' if type(entity)
'table' then if entity["type"]
nil then return formatError('entity-not-found') endend
function wd.siteLink(entity, project, lang) -- returns 3 values: a sitelink (with the relevant prefix) a project name and a language lang = lang or defaultlang if (type(project) ~= 'string') then project = 'wiki' end project = project:lower if project
'string' and (project
defaultlang)) then -- évite de charger l'élément entier return mw.wikibase.sitelink(entity), 'wiki', defaultlang end if project
local entityid = entity.id or entity
local projectdata = projects[project:lower] if not projectdata then -- defaultlink might be in the form "dewiki" rather than "project: 'wiki', lang: 'de' " for k, v in pairs(projects) do if project:match(k .. '$') and mw.language.isKnownLanguageTag(project:sub(1, #project-#k)) then lang = project:sub(1, #project-#k) project = project:sub(#lang + 1, #project) projectdata = projects[project] break end end if not mw.language.isKnownLanguageTag(lang) then return --formatError('invalid-project-code', projet or 'nil') end end if not projectdata then return -- formatError('invalid-project-code', projet or 'nil') end local linkcode = projectdata[1] local prefix = projectdata[2] local multiversion = projectdata[3] if multiversion then linkcode = lang .. linkcode end local link = mw.wikibase.getSitelink(entityid, linkcode) if not link then return nil end if prefix then link = prefix .. ':' .. link end if multiversion then link = ':' .. lang .. ':' .. link end return link, project, langend
-- add new values to a list, avoiding duplicatesfunction wd.addNewValues(olditems, newitems, maxnum, stopval) if not newitems then return olditems end for _, qid in pairs(newitems) do if stopval and (qid
--
local function notSpecial(claim) local type if claim.mainsnak ~= nil then type = claim.mainsnak.snaktype else -- condition respectée quand showonlyqualifier est un paramètre renseigné -- dans ce cas, claim n'est pas une déclaration entière, mais UNE snak qualifiée du main snak type = claim.snaktype end return type
local function hasTargetValue(claim, targets) -- retourne true si la valeur est dans la liste des target, ou si c'est une valeur spéciale filtrée séparément par excludespecial local id = wd.getMainId(claim) local targets = wd.splitStr(targets) return wd.isHere(targets, id) or wd.isSpecial(claim.mainsnak)end
local function excludeValues(claim, values) -- true si la valeur n'est pas dans la liste, ou si c'est une valeur spéciale (filtrée à part par excludespecial) return wd.isSpecial(claim.mainsnak) or not (hasTargetValue(claim, values))end
local function bestRanked(claims) if not claims then return nil end local preferred, normal =, for i, j in pairs(claims) do if j.rank
'normal' then table.insert(normal, j) end end if #preferred > 0 then return preferred else return normal endend
local function withRank(claims, target) if target
'valid' then if claim.rank ~= 'deprecated' then table.insert(newclaims, claim) end elseif claim.rank
function wd.hasQualifier(claim, acceptedqualifs, acceptedvals, excludequalifiervalues) local claimqualifs = claim.qualifiers if (not claimqualifs) then return false end
acceptedqualifs = wd.splitStr(acceptedqualifs) acceptedvals = wd.splitStr(acceptedvals)
local function ok(qualif) -- vérification pour un qualificatif individuel if not claimqualifs[qualif] then return false end if not (acceptedvals) then -- si aucune valeur spécifique n'est demandée, OK return true end for i, wanted in pairs(acceptedvals) do for j, actual in pairs(claimqualifs[qualif]) do if wd.getId(actual)
for i, qualif in pairs(acceptedqualifs) do if ok(qualif) then return true end end return falseend
function wd.hasQualifierNumber(claim, acceptedqualifs, acceptedvals, excludequalifiervalues) local claimqualifs = claim.qualifiers if (not claimqualifs) then return false end
acceptedqualifs = wd.splitStr(acceptedqualifs) acceptedvals = wd.splitStr(acceptedvals)
local function ok(qualif) -- vérification pour un qualificatif individuel if not claimqualifs[qualif] then return false end if not (acceptedvals) then -- si aucune valeur spécifique n'est demandée, OK return true end for i, wanted in pairs(acceptedvals) do for j, actual in pairs(claimqualifs[qualif]) do if mw.wikibase.renderSnak(actual)
for i, qualif in pairs(acceptedqualifs) do if ok(qualif) then return true end end return falseend
local function hasSource(claim, targetsource, sourceproperty) sourceproperty = sourceproperty or 'P248' if targetsource
"any") then -- si n'importe quelle valeur est acceptée tant qu'elle utilise en ref la propriété demandée return true end targetsource = wd.splitStr(targetsource) for _, source in pairs(candidates) do local s = wd.getId(source) for i, target in pairs(targetsource) do if s
local function excludeQualifier(claim, qualifier, qualifiervalues) return not wd.hasQualifier(claim, qualifier, qualifiervalues)end
function wd.hasDate(claim) if not claim then return false --error ? end if wd.getDateFromQualif(claim, 'P585') or wd.getDateFromQualif(claim, 'P580') or wd.getDateFromQualif(claim, 'P582') then return true end return falseend
local function hasLink(claim, site, lang) if (claim.mainsnak.snaktype ~= 'value') then -- ne pas supprimer les valeurs spéciales, il y a une fonction dédiée pour ça return true end local id = wd.getMainId(claim) local link = wd.siteLink(id, site, lang) if link then return true endend
local function isInLanguage(claim, lang) -- ne fonctionne que pour les monolingualtext / étendre aux autres types en utilisant les qualifiers ? if type(lang)
if (lang
'locallang') then lang = mw.getContentLanguage:getCode end -- pour les monolingual text local snak = claim.mainsnak or claim if snak.snaktype
'monolingualtext' then if snak.datavalue.value.language
-- pour les autres types de données : recherche dans les qualificatifs if (lang
'en') then lang = 'Q1860' else lang = invertedlangcodes[lang] end if claim.qualifiers and claim.qualifiers.P407 then if wd.hasQualifier(claim,, ) then return true else return false end end
return true -- si on ne ne sait pas la langue, on condière que c'est bonend
local function firstVals(claims, numval) -- retourn les numval premières valeurs de la table claims local numval = tonumber(numval) or 0 -- raise a error if numval is not a positive integer ? if not claims then return nil end while (#claims > numval) do table.remove(claims) end return claimsend
local function lastVals(claims, numval2) -- retourn les valeurs de la table claims à partir de numval2 local numval2 = tonumber(numval2) or 0 -- raise a error if numval is not a positive integer ? if not claims then return nil end for i=1,numval2 do table.remove(claims, 1) end return claimsend
-- retourne les valeurs de la table claims à partir de removedupesdate,-- sans les dates en doublons avec conversion entre les calendrier julien et grégorien,-- ou uniquement en catégorisant si le paramètre removedupesdate est égale à 'cat'local function removeDupesDate(claims, removedupesdate) if not claims or #claims < 2 then return claims, end local cat = local newClaims = local newIsos =
local function findIndex(searchset, val) -- similaire à wd.isHere mais retourne l'index de la valeur trouvée for i, j in pairs(searchset) do if val
for _, claim in ipairs(claims) do local snack = claim.mainsnak or claim if (snack.snaktype
'time') and snack.datavalue.value.precision >= 11 then -- s'il s'agit d'un time et que la précision est au moins l'année local iso = snack.datavalue.value.time _, _, iso = string.find(iso, "(+%d+-%d+-%d+T)") local deleteIfDuplicate = false if snack.datavalue.value.calendarmodel
"cat" then -- ne faire que catégoriser table.insert(newIsos, iso) table.insert(newClaims, claim) elseif not deleteIfDuplicate then -- supprimer l'autre date si la date courante n'a pas été convertie newClaims[index] = claim end -- sinon supprimer la date courante else -- pas de doublon table.insert(newIsos, iso) table.insert(newClaims, claim) end elseif snack.datavalue.value.calendarmodel
"cat" then -- ne faire que catégoriser table.insert(newIsos, iso) table.insert(newClaims, claim) elseif not deleteIfDuplicate then -- supprimer l'autre date si la date courante n'a pas été convertie newClaims[index] = claim end -- sinon supprimer la date courante else -- pas de doublon table.insert(newIsos, iso) table.insert(newClaims, claim) end else -- autre calendrier table.insert(newIsos, iso) table.insert(newClaims, claim) end else -- précision insuffisante table.insert(newIsos, iso) table.insert(newClaims, claim) end end return newClaims, catend
local function timeFromQualifs(claim, qualifs) local claimqualifs = claim.qualifiers if not claimqualifs then return nil end for i, qualif in pairs(qualifs or timequalifiers) do local vals = claimqualifs[qualif] if vals and (vals[1].snaktype
local function atDate(claim, mydate) if mydate
local myprecision if d[3] then myprecision = 11 -- day elseif d[2] then myprecision = 10 -- month else myprecision = 9 -- year end
-- with point in time local d, storedprecision = timeFromQualifs(claim,) if d then return modules.formatDate.equal(mydate, d, math.min(myprecision, storedprecision)) end -- with start or end date -- TODO: precision local mindate = timeFromQualifs(claim,) local maxdate = timeFromQualifs(claim,) if modules.formatDate.before(mydate, mindate) and modules.formatDate.before(maxdate, mydate) then return true end return falseend
local function check(claim, condition) if type(condition)
local function minPrecision(claim, minprecision) local snack if claim.qualifiers then -- si une date est donnée en qualificatif, c'est elle qu'on utilise de préférence au mainsnak for i, j in ipairs(datequalifiers) do if claim.qualifiers[j] then snack = claim.qualifiers[j][1] break end end end if not snack then snack = claim.mainsnak or claim end if (snack.snaktype
'time') and (snack.datavalue.value.precision < minprecision) then return false end return trueend
function wd.sortClaims(claims, sorttype) if not claims then return nil end if sorttype
'inverted' then return wd.chronoSort(claims, true) elseif sorttype
'ascending' then return wd.quantitySort(claims) elseif sorttype
'function' then table.sort(claims, sorttype) return claims elseif type(sorttype)
'P' then return wd.numericPropertySort(claims, sorttype) end return claimsend
function wd.filterClaims(claims, args) --retire de la tables de claims celles qui sont éliminés par un des filters de la table des filters
local function filter(condition, filterfunction, funargs) if not args[condition] then return end for i = #claims, 1, -1 do if not(filterfunction(claims[i], args[funargs[1]], args[funargs[2]], args[funargs[3]])) then table.remove(claims, i) end end end filter('isinlang', isInLanguage,) filter('excludespecial', notSpecial,) filter('condition', check,) if claims[1] and claims[1].mainsnak then filter('targetvalue', hasTargetValue,) filter('atdate', atDate,) filter('qualifier', wd.hasQualifier,) filter('qualifiernumber', wd.hasQualifierNumber,) filter('excludequalifier', excludeQualifier,) filter('withsource', hasSource,) filter('withdate', wd.hasDate,) filter('excludevalues', excludeValues,) filter('withlink', hasLink,) filter('minprecision', minPrecision,) claims = withRank(claims, args.rank or 'best') end if #claims
end
function wd.loadEntity(entity, cache) if type(entity) ~= 'table' then if cache then if not cache[entity] then cache[entity] = mw.wikibase.getEntity(entity) mw.log("cached") end return cache[entity] else if entity
'-') then entity = nil end return mw.wikibase.getEntity(entity) end else return entity endend
function wd.getClaims(args) -- returns a table of the claims matching some conditions given in args if args.claims then -- if claims have already been set, return them return args.claims end local properties = args.property if type(properties)
--Get entity local entity = args.entity if type(entity)
then entity = nil end elseif type(entity)
'-') then return nil end local claims =
if #properties
if (not claims) or (#claims
--
function wd.getLabel(entity, lang1, lang2) if (not entity) then return nil -- ou option de gestion des erreurs ? end entity = entity.id or (type(entity)
'string') then return nil end lang1 = lang1 or defaultlang local str, lang --str : texte rendu, lang : langue de celui-ci if lang1
lang1) then --pas de catégorie "à traduire" si on a obtenu un texte dans la langue désirée (normalement fr) return str end if lang2 then -- langue secondaire, avec catégorie "à traduire" str2 = mw.wikibase.getLabelByLang(entity, lang2) if str2 then lang = lang2 str = str2 end end if not str then --si ni lang1, ni lang2 ni l'anglais ne sont présents, parcours de la hiérarchie des langues for _, trylang in ipairs(modules.langhierarchy.codes) do str = mw.wikibase.getLabelByLang(entity, trylang) if str then lang = trylang break end end end if str then local translationCat = modules.i18n['to translate'] translationCat = translationCat .. (modules.langhierarchy.cattext[lang] or ) translationCat = addCat(translationCat) return str, translationCat endend
function wd.formatEntity(entity, params)
if (not entity) then return nil --formatError('entity-not-found') end local id = entity if type(id)
params = params or local lang = params.lang or defaultlang local speciallabels = params.speciallabels local displayformat = params.displayformat local labelformat = params.labelformat local labelformat2 = params.labelformat2 local defaultlabel = params.defaultlabel or id local linktype = params.link local defaultlink = params.defaultlink local defaultlinkquery = params.defaultlinkquery
if speciallabels and speciallabels[id] then --speciallabels override the standard label + link combination return speciallabels[id] end if params.displayformat
local link, label, translationCat if type(labelformat)
translationCat = translationCat or "" -- sera toujours ajoutée au résultat mais sera vide si la catégorie de maintenance n'est pas nécessaire if type(labelformat2)
'-') then return nil end link = wd.siteLink(id, 'wikidata') return '' .. id .. '' .. translationCat-- si pas de libellé, on met un lien vers Wikidata pour qu'on comprenne à quoi ça fait référence end
if (linktype
local link = wd.siteLink(entity, linktype, lang)
-- defaultlinkquery will try to link to another page on this Wiki if (not link) and defaultlinkquery then if type(defaultlinkquery)
if link then if mw.ustring.sub(link, 1, 9)
"Catégorie:" then link = ":" .. link --lier vers une catégorie au lieu de catégoriser end return '' .. label .. '' .. translationCat end
-- if not link, you can use defaultlink: a sidelink to another Wikimedia project if (not defaultlink) then defaultlink = end if defaultlink and (defaultlink ~= '-') then local linktype local sidelink, site, langcode if type(defaultlink)
'wiki' then icon, class, title = langcode, "indicateur-langue", wd.translate('see-another-language', mw.language.fetchLanguageName(langcode, defaultlang)) elseif site
function wd.addTrackingCat(prop, cat) -- doit parfois être appelé par d'autres modules if type(prop)
local function unknownValue(snak, label) local str = label
if type(str)
if (not str) then if snak.datatype
if type(str) ~= "string" then return formatError(snak.datatype) end return strend
local function noValue(displayformat) if not displayformat then return wd.translate('novalue') end if type(displayformat)
local function getLangCode(entityid) return modules.langcodes[tonumber(entityid:sub(2))]end
local function showLang(statement, maxLang) -- retourne le code langue entre paranthèse avant la valeur (par exemple pour les biblios et liens externes) local mainsnak = statement.mainsnak if mainsnak.snaktype ~= 'value' then return nil end local langlist = if mainsnak.datavalue.type
elseif (not statement.qualifiers) or (not statement.qualifiers.P407) then return else for i, j in pairs(statement.qualifiers.P407) do if j.snaktype
1 and langlist[1] ~= defaultlang) then -- si c'est en français, pas besoin de le dire langlist.maxLang = maxLang return modules.langmodule.indicationMultilingue(langlist) endend
--
function wd.addStandardQualifs(str, statement) if (not statement) or (not statement.qualifiers) then return str end if not str then return error-- what's that ? end
if statement.qualifiers.P1480 then for i, j in pairs(statement.qualifiers.P1480) do local v = wd.getId(j) if (v
"Q18122778") or (v
"Q5727902") then if (statement.mainsnak.datatype
local function rangeObject(begin, ending, params) --objet comportant un timestamp pour le classement chronologique et deux dateobject (begin et ending) -- local timestamp if begin then timestamp = begin.timestamp else timestamp = ending.timestamp end return end
local function dateObject(orig, params) ---- if not params then params = end local newobj = modules.formatDate.splitDate(orig.time, orig.calendarmodel) newobj.precision = params.precision or orig.precision newobj.type = 'dateobject' return newobjend
local function objectToText(obj, params) if obj.type
'rangeobject' then return modules.formatDate.daterange(obj.begin, obj.ending, params) endend
function wd.getDateFromQualif(statement, qualif) if (not statement) or (not statement.qualifiers) or not (statement.qualifiers[qualif]) then return nil end local v = statement.qualifiers[qualif][1] if v.snaktype ~= 'value' then -- que faire dans ce cas ? return nil end return dateObject(v.datavalue.value)end
function wd.getDate(statement) local period = wd.getDateFromQualif(statement, 'P585') -- retourne un dateobject if period then return period end local begin, ending = wd.getDateFromQualif(statement, 'P580'), wd.getDateFromQualif(statement, 'P582') if begin or ending then return rangeObject(begin, ending) -- retourne un rangeobject fait de deux dateobject end return nilend
function wd.getFormattedDate(statement, params) if not statement then return nil end local str
--cherche la date avec les qualifs P580/P582 local datetable = wd.getDate(statement) if datetable then str = objectToText(datetable, params) end -- puis limite intérieur / supérieur if not str then local start, ending = wd.getDateFromQualif(statement, 'P1319'), wd.getDateFromQualif(statement, 'P1326') str = modules.formatDate.between(start, ending, params) end
-- sinon, le mainsnak, pour les données de type time if (not str) and (statement.mainsnak.datatype
'value') or (mainsnak.snaktype
if str and params and (params.addstandardqualifs ~= '-') then str = wd.addStandardQualifs(str, statement) end return strend
wd.compare.by_quantity = function(c1, c2) local v1 = wd.getDataValue(c1.mainsnak) local v2 = wd.getDataValue(c2.mainsnak) if not (v1 and v2) then return true end return v1 < v2end
--
function wd.chrono_key_sort(arg) local snak_key_get_function = arg.snak_key_get_function local sortKey = arg.sortKey or "dateSortKey" local key_compare_function = arg.key_compare_function or function(c1, c2) return c1 < c2 end return function(claims) for _, claim in ipairs(claims) do if not claim[sortKey] then local key = snak_key_get_function(claim) if key then claim[sortKey] = wd.compare.get_claim_date(key) else claim[sortKey] = 0 end end end table.sort(claims, function(c1, c2) return key_compare_function(c1[sortKey], c2[sortKey]) end ) return claims endend
function wd.quantitySort(claims, inverted) local function sort(c1, c2) local v1 = wd.getDataValue(c1.mainsnak) local v2 = wd.getDataValue(c2.mainsnak) if not (v1 and v2) then return true end if inverted then return v2 < v1 end return v1 < v2 end table.sort(claims, sort) return claimsend
function wd.compare.get_claim_date(claim) local snack = claim.mainsnak or claim local iso if (snack.snaktype
'time') then iso = snack.datavalue.value.time else iso = timeFromQualifs(claim, datequalifiers) or '0' end -- transformation en nombre (indication de la base car gsub retourne deux valeurs) return tonumber(iso:gsub('(%d)%D', '%1'), 10)end
function wd.compare.chronoCompare(c1, c2) return wd.compare.get_claim_date(c1) < wd.compare.get_claim_date(c2)end
-- fonction pour renverser l’ordre d’une autre fonctionfunction wd.compare.rev(comp_criteria) return function(c1, c2) -- attention les tris en lua attendent des fonctions de comparaison strictement inférieur, on doit -- vérifier la non égalité quand on inverse l’ordre d’un critère, d’ou "and comp_criteria(c2,c1)" return not(comp_criteria(c1,c2)) and comp_criteria(c2,c1) endend
-- Fonction qui trie des Claims de type time selon l'ordre chronologique-- Une clé de tri nomée « dateSortKey » est ajouté à chaque claim.-- Si des clés de tri de ce nom existent déjà, elles sont utilisées sans modification.
function wd.chronoSort(claims, inverted) for _, claim in ipairs(claims) do if not claim.dateSortKey then claim.dateSortKey = wd.compare.get_claim_date(claim) end end table.sort(claims, function (c1, c2) if inverted then return c2.dateSortKey < c1.dateSortKey end return c1.dateSortKey < c2.dateSortKey end ) return claimsend
local function get_numeric_claim_value(claim, propertySort) local val local claimqualifs = claim.qualifiers if claimqualifs then local vals = claimqualifs[propertySort] if vals and vals[1].snaktype
function wd.compare.numeric(propertySort) return function(c1, c2) return get_numeric_claim_value(c1, propertySort) < get_numeric_claim_value(c2, propertySort) endend
-- Fonction qui trie des Claims de type value selon l'ordre de la propriété fournit-- Une clé de tri nomée « dateSortKey » est ajouté à chaque claim.-- Si des clés de tri de ce nom existent déjà, elles sont utilisées sans modification.
function wd.numericPropertySort(claims, propertySort) for _, claim in ipairs(claims) do if not claim.dateSortKey then local val = get_numeric_claim_value(claim, propertySort) claim.dateSortKey = tonumber(val or 0) end end table.sort(claims, function (c1, c2) return c1.dateSortKey < c2.dateSortKey end ) return claimsend
--
--
local refs = local hashes = for i, ref in pairs(refdata) do local s local function hasValue(prop) -- checks that the prop is here with valid value if ref.snaks[prop] and ref.snaks[prop][1].snaktype
if ref.snaks.P248 then -- cas lorsque P248 (affirmé dans) est utilisé for j, source in pairs(ref.snaks.P248) do if source.snaktype
if hasValue('P8091') then arkKey = wd.formatSnak(ref.snaks.P8091[1],) url = 'https://n2t.net/' .. arkKey if hasValue('P1476') then title = wd.formatSnak(ref.snaks.P1476[1]) else title = arkKey end elseif hasValue('P854') then url = wd.formatSnak(ref.snaks.P854[1],) if hasValue('P1476') then title = wd.formatSnak(ref.snaks.P1476[1]) else title = mw.ustring.gsub(url, '^[Hh][Tt][Tt][Pp]([Ss]?):(/?)([^/])', 'http%1://%3') end end
--todo : handle multiple values for author, etc. if hasValue('P1810') then -- sous le nom description = 'sous le nom ' .. wd.formatSnak(ref.snaks.P1810[1]) end if hasValue('P813') then -- date de consultation accessdate = wd.formatSnak(ref.snaks.P813[1]) end if hasValue('P50') then -- author (item type) author = wd.formatSnak(ref.snaks.P50[1]) elseif hasValue('P2093') then -- author (string type) author = wd.formatSnak(ref.snaks.P2093[1]) end if hasValue('P123') then -- éditeur publisher = wd.formatSnak(ref.snaks.P123[1]) end if hasValue('P1683') then -- citation quotation = wd.formatSnak(ref.snaks.P1683[1]) end if hasValue('P577') then -- date de publication publishdate = wd.formatSnak(ref.snaks.P577[1]) end if hasValue('P407') then -- langue de l'œuvre local id = wd.getId(ref.snaks.P407[1]) publishlang = getLangCode(id) end s = modules.cite.lienWeb table.insert(hashes, ref.hash) table.insert(refs, s)
elseif ref.snaks.P854 and ref.snaks.P854[1].snaktype
#refs then return refs, hashes end return refs endend
function wd.sourceStr(sources, hashes) if not sources or (#sources
#sources for i, j in ipairs(sources) do local refArgs = if useHashes and hashes[i] ~= '-' then refArgs.args = end sources[i] = mw.getCurrentFrame:extensionTag(refArgs) end return table.concat(sources, ',')end
function wd.getDataValue(snak, params) if not params then params = end local speciallabels = params.speciallabels -- parfois on a besoin de faire une liste d'éléments pour lequel le libellé doit être changé, pas très pratique d'utiliser une fonction pour ça
if snak.snaktype ~= 'value' then return nil end
local datatype = snak.datatype local value = snak.datavalue.value local displayformat = params.displayformat if type(displayformat)
if datatype
if datatype
'raw' then return value else return modules.weblink.makelink(value, params.text) end end
if datatype
if datatype
if (datatype
'external-id') or (datatype
'function' then urlpattern = urlpattern(value) end -- encodage de l'identifiant qui se retrouve dans le path de l'URL, à l'exception des slashes parfois rencontrés, qui sont des séparateurs à ne pas encoder local encodedValue = mw.uri.encode(value, 'PATH'):gsub('%%2F', '/') -- les parenthèses autour du encodedValue:gsub sont nécessaires, sinon sa 2e valeur de retour est aussi passée en argument au mw.ustring.gsub parent local url = mw.ustring.gsub(urlpattern, '$1', (encodedValue:gsub('%%', '%%%%'))) value = '[' .. url .. ' ' .. (params.text or value) .. ']' end return value end if datatype
'raw' then return value.time else local dateobject = dateObject(value,) return objectToText(dateobject, params) end end
if datatype
'latitude' then return value.latitude elseif displayformat
if datatype
if unit then unit = unit:match('Q%d+') end if not unit then unit = 'dimensionless' end local raw if displayformat
'monolingualtext' then if value.language
end
function wd.stringTable(args) -- like getClaims, but get a list of string rather than a list of snaks, for easier manipulation local claims = args.claims local cat =
if not claims then claims = wd.getClaims(args) end if not claims or claims
function wd.getQualifiers(statement, qualifs, params) if not statement.qualifiers then return nil end local vals = if type(qualifs)
0 then return nil end return valsend
function wd.getFormattedQualifiers(statement, qualifs, params) if not params then params = end local qualiftable = wd.getQualifiers(statement, qualifs) if not qualiftable then return nil end qualiftable = wd.filterClaims(qualiftable, params) or for i, j in pairs(qualiftable) do qualiftable[i] = wd.formatSnak(j, params) end return modules.linguistic.conj(qualiftable, params.conjtype)end
function wd.showQualifiers(str, statement, args) local qualifs = args.showqualifiers if not qualifs then return str -- or error ? end if type(qualifs)
'function' then formattedqualifs = args.qualifformat(statement, qualifs, qualifargs) else formattedqualifs = wd.getFormattedQualifiers(statement, qualifs, qualifargs) end if formattedqualifs and formattedqualifs ~= "" then str = str .. " (" .. formattedqualifs .. ")" end return strend
function wd.formatSnak(snak, params) if not params then params = end -- pour faciliter l'appel depuis d'autres modules if snak.snaktype
'novalue' then return noValue(params.novaluelabel) elseif snak.snaktype
function wd.formatStatement(statement, args) -- FONCTION A REORGANISER (pas très lisible) if not args then args = end if not statement.type or statement.type ~= 'statement' then return formatError('unknown-claim-type') end local prop = statement.mainsnak.property
local str
-- special displayformat f if args.statementformat and (type(args.statementformat)
'time') and (statement.mainsnak.dateformat ~= '-') then if args.displayformat
'value' then str = statement.mainsnak.datavalue.value.time else str = wd.getFormattedDate(statement, args) end elseif args.showonlyqualifier and (args.showonlyqualifier ~= ) then str = wd.getFormattedQualifiers(statement, args.showonlyqualifier, args) if not str then return nil end if args.addstandardqualifs ~= '-' then str = wd.addStandardQualifs(str, statement) end else str = wd.formatSnak(statement.mainsnak, args) if (args.addstandardqualifs ~= '-') and (args.displayformat ~= 'raw') then str = wd.addStandardQualifs(str, statement) end end
-- ajouts divers if args.showlang
if args.showdate then -- when "showdate and chronosort are both set, date retrieval is performed twice local period = wd.getFormattedDate(statement, args, "-") -- 3 arguments indicate the we should not use additional qualifiers, alrady added by wd.formatStatement if period then str = str .. " (" .. period .. ")" end end
if args.showsource and args.showsource ~= '-' then local sources, hashes = wd.getReferences(statement) if sources then local source = wd.sourceStr(sources, hashes) if source then str = str .. source end end end
return strend
function wd.addLinkBack(str, id, property) if not id or id
'table' then property = property[1] end id = wd.entityId(id)
local class = if property then class = 'wd_' .. string.lower(property) end local icon = '' local title = wd.translate('see-wikidata-value') local url = mw.uri.fullUrl('d:' .. id, 'uselang=fr') url.fragment = property -- ajoute une #ancre si paramètre "property" défini url = tostring(url) local v = mw.html.create('span') :addClass(class) :wikitext(str) :tag('span') :addClass('noprint wikidata-linkback') :wikitext(icon:format(title, url)) :allDone return tostring(v)end
function wd.addRefAnchor(str, id)--Insère une ancre pour une référence générée à partir d'un élément wd. L'id Wikidata sert d'identifiant à l'ancre, à utiliser dans les modèles type "harvsp"-- return tostring(mw.html.create('span') :attr('id', id) :attr('class', "ouvrage") :wikitext(str) )end
--
local function formatStatementsGrouped(args, type) -- regroupe les affirmations ayant la même valeur en mainsnak, mais des qualificatifs différents -- (seulement pour les propriétés de type élément)
local claims = wd.getClaims(args) if not claims then return nil end local groupedClaims =
-- regroupe les affirmations par valeur de mainsnak local function addClaim(claim) local id = wd.getMainId(claim) for i, j in pairs(groupedClaims) do if (j.id
local stringTable =
-- instructions ad hoc pour les paramètres concernant la mise en forme d'une déclaration individuelle local funs =
for i, group in pairs(groupedClaims) do -- bricolage pour utiliser les arguments de formatStatements local str = wd.formatEntity(group.id, args) if not str then str = '???' -- pour éviter erreur Lua si formatEntity a retourné nil end for i, fun in pairs(funs) do if args[fun.param] then str = fun.fun(str, group.claims, args) end end table.insert(stringTable, str) end args.valuetable = stringTable return wd.formatStatements(args)end
function wd.formatStatements(args)--Format statement and concat them cleanly
if args.value
-- If a value is already set: use it, except if it's the special value (use wikidata) if args.value and args.value ~= then local valueexpl = wd.translate("activate-query") if args.value ~= valueexpl then return args.value end -- There is no value set, and args.expl disables wikidata on empty values elseif args.expl then return nil end
if args.grouped and args.grouped ~= then args.grouped = false return formatStatementsGrouped(args) end local valuetable = args.valuetable -- dans le cas où les valeurs sont déjà formtées local props -- les prorpriétés réellement utilisées (dans certainse cas, ce ne sont pas toutes celles de ags.property local cat = if not valuetable then -- cas le plus courant valuetable, props, cat = wd.stringTable(args) end
local str = modules.linguistic.conj(valuetable, args.conjtype) if not str then return args.default end if not props then props = wd.splitStr(args.property)[1] end if args.ucfirst ~= '-' then str = modules.linguistic.ucfirst(str) end
if args.addcat and (args.addcat ~= '-') then str = str .. wd.addTrackingCat(props) .. cat end if args.linkback and (args.linkback ~= '-') then str = wd.addLinkBack(str, args.entity, props) end if args.returnnumberofvalues then return str, #valuetable end return strend
function wd.formatAndCat(args) if not args then return nil end args.linkback = args.linkback or true args.addcat = true if args.value then -- do not ignore linkback and addcat, as formatStatements do if args.value
function wd.getTheDate(args) local claims = wd.getClaims(args) if not claims then return nil end local formattedvalues = for i, j in pairs(claims) do local v = wd.getFormattedDate(j, args) if v then table.insert(formattedvalues, v) end end local val = modules.linguistic.conj(formattedvalues) if not val then return nil end if args.addcat
function wd.keyDate (event, item, params) params = params or params.entity = item if type(event)
'Q' then -- on demande un élément utilisé dans P:P793 (événement clé) params.property = 'P793' params.targetvalue = event params.addcat = params.addcat or true return wd.getTheDate(params) elseif string.sub(event, 1, 1)
function wd.mainDate(entity) -- essaye P580/P582 local args = args.property = 'P580' local startpoint = wd.formatStatements(args) args.property = 'P582' local endpoint = wd.formatStatements(args)
local str if (startpoint or endpoint) then str = modules.formatDate.daterange(startpoint, endpoint, params) str = wd.addLinkBack(str, entity, 'P582') return str end
-- défaut : P585 args.property = args.linkback = true return wd.formatStatements(args)end
--
function wd.getIds(item, query) query.excludespecial = true query.displayformat = 'raw' query.entity = item query.addstandardqualifs = '-' return wd.stringTable(query)end
-- recursively adds a list of qid to an existing list, based on the results of a queryfunction wd.addVals(list, query, maxdepth, maxnodes, stopval) maxdepth = tonumber(maxdepth) or 10 maxnodes = tonumber(maxnodes) or 100 if (maxdepth < 0) then return list end if stopval and wd.isHere(list, stopval) then return list end local origsize = #list for i = 1, origsize do -- tried a "checkpos" param instead of starting to 1 each time, but no impact on performance local candidates = wd.getIds(list[i], query) list = wd.addNewValues(list, candidates, maxnodes, stopval) if list[#list]
origsize) then return list end return wd.addVals(list, query, maxdepth - 1, maxnodes, stopval, origsize + 1)end
-- returns a list of items transitively matching a query (orig item is not included in the list)
function wd.transitiveVals(item, query, maxdepth, maxnodes, stopval) maxdepth = tonumber(maxdepth) or 5 if type(query)
-- récupération des valeurs local vals = wd.getIds(item, query) if not vals then return nil end local v = wd.addVals(vals, query, maxdepth - 1, maxnodes, stopval) if not v then return nil end
-- réarrangement des valeurs if query.valorder
return vend
-- returns true if an item is the value of a query, transitivelyfunction wd.inTransitiveVals(searchedval, sourceval, query, maxdepth, maxnodes) local vals = wd.transitiveVals(sourceval, query, maxdepth, maxnodes, searchedval) if (not vals) then return false end for _, val in ipairs(vals) do if (val
-- returns true if an item is a superclass of another, based on P279function wd.isSubclass(class, item, maxdepth) local query = if class
-- returns true if one of the best ranked P31 values of an item is the target or a subclass of the target-- rank = 'valid' would seem to make sense, but it would need to check for date qualifiers as some P31 values have begin or end datefunction wd.isInstance(targetclass, item, maxdepth) maxdepth = maxdepth or 10 local directclasses = wd.transitiveVals(item,, 1) if not directclasses then return false end for i, class in pairs(directclasses) do if wd.isSubclass(targetclass, class, maxdepth - 1) then return true end end return falseend
-- return the first value in a transitive query that belongs to a particular class. For instance find a value of P131 that is a province of Canadafunction wd.findVal(sourceitem, targetclass, query, recursion, instancedepth) if type(query)
--
function wd.getDescription(entity, lang) lang = lang or defaultlang
local description if lang
function wd.Dump(entity) entity = wd.getEntity(entity) if not entity then return formatError("entity-param-not-provided") end return "
"..mw.dumpObject(entity)..""end
function wd.frameFun(frame) local args = frame.args local funname = args[1] table.remove(args, 1) return wd[funname](args)end
return wd