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

--[[
* Mòdulu pro implementare sas funtzionalidades de sos templates:
* {{Wikidata}}, {{WikidataQ}}, {{WikidataIdx}}, {{WikidataN}}, {{WikidataLabel}},
* {{WikidataLink}}, {{WikidataId}}, {{WikidataTipo}} e {{WikidataIstanza}}.
* Permitit de atzedere a Wikidata in manera prus avantzada de {{#property}}.

* Per la maggior parte riscritto e ampliato a partire dalla versione iniziale a:
* http://test2.wikipedia.org/w/index.php?title=Module:Wikidata&oldid=52322
]]

-- =============================================================================
-- No imprees mai mw.wikibase.getEntity, pro esèmpiu un'impreu ebbia de
-- mw.wikibase.getEntity('Q183') faghet ismanniare de 7 MB s'impreu de memòria
-- pro Lua est lenta meda si ripetuta (ùnicu impreu in getDatatype,
-- petzi pro propiedades, ca non bi sunt alternativas).
-- =============================================================================

require('Module:No globals')

local getArgs = require('Module:Arguments').getArgs
local mConvert = require('Module:Cunversione')
local mLanguages = require('Module:Limbàgios')

-- Categoria pro sas pàginas cun errores
local errorCategory = '[[Categoria:Boghes cun errores de su mòdulu Wikidata]]'

-- Messàgios
local i18n = {
	errors = {
		['entityid-param-not-provided'] = "Paràmetru ''entityid'' non frunidu",
		['property-param-not-provided'] = "Paràmetru ''property'' non frunidu",
		['qualifier-param-not-provided'] = "Paràmetru ''qualifier'' non frunidu",
		['value-param-not-provided'] = "Paràmetru ''valore'' de chircare non frunidu",
		['entity-not-found'] = 'Entidade no agatada',
		['unknown-claim-type'] = 'Casta assertzione disconnota',
		['unknown-snak-type'] = 'Casta di snak disconnotu',
		['unknown-datavalue-type'] = 'Casta de datu disconnotu',
		['unknown-entity-type'] = 'Casta de entidade disconnota'
	},
	somevalue = "''valore disconnotu''",
	novalue = "''perunu valore''",
	datatypes = {
		['commonsMedia'] = 'documentu multimediale in Commons',
		['external-id'] = 'identificativu esternu',
		['geo-shape'] = 'forma geogràfica',
		['globe-coordinate'] = 'coordinatas geogràficas',
		['math'] = 'espressione matemàtica',
		['monolingualtext'] = 'testu monolimba',
		['quantity'] = 'cantidade',
		['string'] = 'istringa',
		['tabular-data'] = 'tabular data',
		['time'] = 'data e ora',
		['url'] = 'URL',
		['wikibase-item'] = 'elementu',
		['wikibase-property'] = 'propiedade'
	}
}

local p = {}

-------------------------------------------------------------------------------
--                             Formatters
-------------------------------------------------------------------------------

local function errhandler(msg)
	local cat = mw.title.getCurrentTitle().namespace == 0 and errorCategory or ''
	return string.format('<span class="error">%s</span>%s', msg, cat)
end

local function formatList(values, ordered)
	local fmt = ordered and '<ol><li>%s</li></ol>' or '<ul><li>%s</li></ul>'
	return #values > 0 and string.format(fmt, mw.text.listToText(values, '</li><li>', '</li><li>')) or ''
end

local function formatExtLink(url)
	local protocols = { ftp = true, http = true, https = true }

	local success, uri = pcall(function() return mw.uri.new(url) end)
	if success and uri.protocol and protocols[uri.protocol] then
		local dest = tostring(uri)
		return string.format('<div style="word-break: break-all;">[%s %s]</div>', dest, dest:gsub(uri.protocol .. '://', ''))	
	else
		return url
	end
end

local function formatEntityId(entityId)
	local label = mw.wikibase.getLabel(entityId)
	local siteLink = mw.wikibase.getSitelink(entityId)
	local ret
	if siteLink and label then
		ret = mw.getContentLanguage():ucfirst(label) == siteLink and
			  string.format('[[%s]]', label) or
			  string.format('[[%s|%s]]', siteLink, label)
	elseif siteLink then
		ret = string.format('[[%s]]', siteLink)
	elseif label then
		ret = label
	else
		ret = ''
	end
	return ret
end

local function formatMonolingualtext(value, args)
	local ret = ''
	if not args.includelang or args.includelang:match('%f[a-z]' .. value.language .. '%f[^a-z]') then
		if not args.excludelang or not args.excludelang:match('%f[a-z]' .. value.language .. '%f[^a-z]') then
			ret = value.text
			if args.showlang then
				ret = mLanguages.limbas({ value.language }) .. '&nbsp;' .. ret
			end
		end
	end
	return ret
end

local function formatTimeWithPrecision(time, precision)
	local months = {
		'ghennàrgiu', 'freàrgiu', 'martzu', 'abrile', 'maju', 'làmpadas',
		'trìulas', 'austu', 'cabudanni', 'santugaine', 'santandria', 'nadale'
	}
	local ret, year, month, day
 
	year, month, day = time:match('(%d+)%-(%d%d)%-(%d%d).+')
	year, month, day = tonumber(year), tonumber(month), tonumber(day)
	if precision == 9 then
		ret = year
	elseif precision == 10 then
		ret = months[month] .. ' ' .. year
	elseif precision == 11 then
		ret = day .. ' ' .. months[month] .. ' ' .. year
		ret = ret:gsub('^1%s', '1º ')
	end
	if precision >= 9 and precision <= 11 then
		ret = ret .. (time:sub(1, 1) == '-' and ' a.C.' or '')
	end

	return ret
end

local function formatTime(value, args)
	local ret
 
	if args.time == 'precision' then
		ret = value.precision
	elseif args.time == 'calendarmodel' then
		ret = value.calendarmodel
	elseif args.time == 'year' and value.precision >= 9 then
		ret = formatTimeWithPrecision(value.time, 9)
	elseif args.time == 'month' and value.precision >= 10 then
		ret = formatTimeWithPrecision(value.time, 10)
	elseif args.time == 'day' and value.precision >= 11 then
		ret = formatTimeWithPrecision(value.time, 11)
	elseif not args.time then
		ret = formatTimeWithPrecision(value.time, value.precision)
	end

	return ret or ''
end

local function formatGlobecoordinate(value, args)
	local ret
	if args.coord == 'latitude' then
		ret = value.latitude
	elseif args.coord == 'longitude' then
		ret = value.longitude
	elseif args.coord == 'globe' then
		ret = value.globe
	else
		ret = string.format('%s, %s', value.latitude, value.longitude)
	end
	return ret
end

local function formatFromPattern(str, args)
	local pattern = args.pattern
	pattern = mw.ustring.gsub(pattern, '\\{', '{')
	pattern = mw.ustring.gsub(pattern, '\\}', '}')
	return mw.getCurrentFrame():preprocess(mw.message.newRawMessage(pattern, str):plain())
end

local function formatUserValue(value, args)
	if args.extlink then
		value = formatExtLink(value)
	end
	return args.pattern and formatFromPattern(value, args) or value
end

local function getEntityIdFromValue(value)
	local prefix = ''
	if value['entity-type'] == 'item' then
		prefix = 'Q'
	elseif value['entity-type'] == 'property' then
		prefix = 'P'
	else
		error(i18n.errors['unknown-entity-type'])
	end
	return prefix .. value['numeric-id']
end

local function formatUnitSymbol(entityId, args)
	local ret
	for _, lang in ipairs({ 'mul', 'it', 'en' }) do
		ret = p._getProperty({ 'P5061', includelang = lang, from = entityId })
		if ret and ret ~= '' then
			break
		else
			ret = nil
		end
	end
	local space = ret == '°' and '' or ' '
	if ret and args.showunitlink then
		local link = mw.wikibase.getSitelink(entityId)
		if link then
			ret = string.format('[[%s|%s]]', link, ret)
		end
	end
	return ret and (space .. ret) or ''
end

-- http://lua-users.org/wiki/SimpleRound
local function round(num, idp)
	local mult = 10 ^ (idp or 0)
	return math.floor(num * mult + 0.5) / mult
end


local function formatQuantity(value, args)
	local ret = tonumber(value.amount)

	if (args.unit or args.showunit) and value.unit ~= '1' then
		local unitId = mw.ustring.match(value.unit, 'Q%d+')
		if args.unit then
			local opts = {
				showunit = args.showunit,
				showunitlink = args.showunitlink,
				formatnum = args.formatnum,
				rounding = args.rounding
			}
			ret = mConvert._main(ret, unitId, args.unit, opts)
		else
			-- si benit pedidu petzi su sìmbulu de s'unidade
			-- chene sa cunversione l'otenet dae P5061
			ret = args.rounding and round(ret, args.rounding) or ret
			if args.formatnum then
				ret = mw.language.getContentLanguage():formatNum(ret)
			end
			ret = ret .. formatUnitSymbol(unitId, args)
		end
	elseif args.formatnum then
		ret = args.rounding and round(ret, args.rounding) or ret
		ret = mw.language.getContentLanguage():formatNum(ret)
	elseif args.formatduration and value.unit ~= '1' then
		local unitId = mw.ustring.match(value.unit, 'Q%d+')
		ret = mConvert._main(ret, unitId, 'second')
		ret = ret and mw.language.getContentLanguage()
				:formatDuration(tonumber(ret), { 'days', 'hours', 'minutes', 'seconds' })
	end

	return ret
end

local function formatDatavalue(datavalue, snakdatatype, args)
	local ret

	if datavalue.type == 'wikibase-entityid' then
		local entityId = getEntityIdFromValue(datavalue.value)
		if args.showprop then
			ret = p._getProperty({ args.showprop, n = 1, from = entityId }) or ''
		else
			ret = args.formatting == 'raw' and entityId or formatEntityId(entityId)
		end
	elseif datavalue.type == 'string' then
		ret = datavalue.value
		if args.extlink and snakdatatype == 'url' then
			ret = formatExtLink(ret)
		elseif args.urlencode then
			ret = mw.uri.encode(ret)
		end
	elseif datavalue.type == 'monolingualtext' then
		ret = formatMonolingualtext(datavalue.value, args)
	elseif datavalue.type == 'time' then
		if args.formatting == 'raw' then
			ret = datavalue.value.time
		else
			ret = formatTime(datavalue.value, args)
		end
	elseif datavalue.type == 'globecoordinate' then
		ret = formatGlobecoordinate(datavalue.value, args)
	elseif datavalue.type == 'quantity' then
		ret = formatQuantity(datavalue.value, args)
	else
		error(i18n.errors['unknown-datavalue-type'])
	end

	return ret
end

local function formatSnak(snak, args)
	if snak.snaktype == 'somevalue' then
		return i18n['somevalue']
	elseif snak.snaktype == 'novalue' then
		return i18n['novalue']
	elseif snak.snaktype == 'value' then
		return formatDatavalue(snak.datavalue, snak.datatype, args)
	else
		error(i18n.errors['unknown-snak-type'])
	end
end

-- Est a su plurale ca fintzas sos qualifier podent tènnere prus de unu balore
-- (s'otenet insertende duas bortas su matessi qualifier)
local function formatQualifiers(claim, qualifierId, args, rawTable, retTable)
	local formattedQualifiers = retTable or {}

	if claim.qualifiers and claim.qualifiers[qualifierId] then
		local qualifiers = claim.qualifiers[qualifierId]
		-- cun args.nq ischertat petzi s'n-èsimu qualifier
		if args.nq then
			local n = tonumber(args.nq)
			qualifiers = (n and n <= #qualifiers) and { qualifiers[n] } or {}
		end
		for _, qualifier in ipairs(qualifiers) do
			local formattedQualifier = formatSnak(qualifier, args)
			if formattedQualifier ~= '' then
				if args.pattern then
					formattedQualifier = formatFromPattern(formattedQualifier, args)
					if formattedQualifier ~= '' then
						table.insert(formattedQualifiers, formattedQualifier)
					end
				else
					table.insert(formattedQualifiers, formattedQualifier)
				end
			end
		end
	end

	if rawTable then
		return formattedQualifiers
	end

	return #formattedQualifiers > 0 and
		   mw.text.listToText(formattedQualifiers, args.separator, args.conjunction) or nil
end

local function appendQualifiers(statement, text, args)
	local formattedQualifiers = {}
	local qualifierIds = mw.text.split(args.showqualifiers, ',')
	for _, qualifierId in ipairs(qualifierIds) do
		if statement.qualifiers[qualifierId] then
			local formattedQualifier = formatQualifiers(statement, qualifierId, args)
			table.insert(formattedQualifiers, formattedQualifier)
		end
	end
	if #formattedQualifiers > 0 then
		text = string.format('%s (%s)', text, mw.text.listToText(formattedQualifiers, ', ', ', '))
	end
	return text
end

local function formatStatement(statement, args)
	if not statement.type or statement.type ~= 'statement' then
		error(i18n.errors['unknown-claim-type'])
	end
 
	local ret = formatSnak(statement.mainsnak, args)
	-- eventuale showqualifiers
	if args.showqualifiers and statement.qualifiers then
		ret = appendQualifiers(statement, ret, args)
	end

	return ret
end

local function formatStatements(claims, args, rawTable)
	local formattedStatements = {}

	for _, claim in ipairs(claims) do
		local formattedStatement = formatStatement(claim, args)
		if formattedStatement ~= '' then
			-- eventuale pattern
			if args.pattern then
				formattedStatement = formatFromPattern(formattedStatement, args)
				if formattedStatement ~= '' then
					table.insert(formattedStatements, formattedStatement)
				end
			else
				table.insert(formattedStatements, formattedStatement)
			end
		end
	end
	if rawTable then
		return formattedStatements
	end

	return ((args.list or args.orderedlist) and #formattedStatements > 1) and
		   formatList(formattedStatements, args.orderedlist ~= nil) or 
		   mw.text.listToText(formattedStatements, args.separator, args.conjunction)
end

-------------------------------------------------------------------------------
--                      Leghidura e ischerta statement
-------------------------------------------------------------------------------

-- Daet true si su statement cuntenet su qualifier rechertu cun unu datu balore
local function hasQualifierValue(statement, qualifierId, qualifierValue)
	local ret = false
	for _, qualifier in ipairs(statement.qualifiers[qualifierId]) do
		local isItem = qualifier.snaktype == 'value' and
					   qualifier.datavalue.type == 'wikibase-entityid'
		-- pro sas propiedades de casta item su cunfrontu est esecutadu in s'id
		if formatSnak(qualifier, isItem and { formatting = 'raw' } or {}) == qualifierValue then
			ret = true
			break
		end
	end
	return ret
end

-- Daet sos claim cun su rank rechertu
local function filterRankValue(claims, rank)
	local ret = {}
	for _, claim in ipairs(claims) do
		if claim.rank == rank then
			table.insert(ret, claim)
		end
	end
	return ret
end

-- Frunit una sequence Lua continente sos statement pro sa property recherta,
-- fintzas bòida si sa propiedade no esistet, o non b'ant balores chi satisfaghent sos critèrios
-- ("rank", "qualifier", "qualifiertype", "noqualifier", ...).
-- Frunit nil petzi si la pàgina no est ligada a un'elementu Wikidata e no est indicadu su from.
local function getClaims(propertyId, args)
	local entityId, claims, filteredClaims
	
	entityId = args.from or mw.wikibase.getEntityIdForCurrentPage()
	if not entityId then
		return nil
	end
	
	-- su default rank est 'best'
	args.rank = args.rank or 'best'
	if args.rank == 'best' then
		claims = mw.wikibase.getBestStatements(entityId, propertyId)
	else
		-- statements filtrados pro rank
		claims = mw.wikibase.getAllStatements(entityId, propertyId)
		claims = filterRankValue(claims, args.rank)
	end

	-- statements filtrados pro snaktype
	if args.snaktype then
		filteredClaims = {}
		for _, claim in ipairs(claims) do
			if claim.mainsnak.snaktype == args.snaktype then
				table.insert(filteredClaims, claim)
			end
		end
		claims = filteredClaims
	end

	-- statements filtrados pro qualifier
	if args.qualifier then
		filteredClaims = {}
		for _, claim in ipairs(claims) do
			if claim.qualifiers and claim.qualifiers[args.qualifier] then
				if args.qualifiervalue then
					if hasQualifierValue(claim, args.qualifier, args.qualifiervalue) then
						table.insert(filteredClaims, claim)
					end
				else
					table.insert(filteredClaims, claim)
				end
			end
		end
		claims = filteredClaims
	end

	-- statements filtrados pro èssere chene unu qualifier
	if args.noqualifier then
		filteredClaims = {}
		for _, claim in ipairs(claims) do
			if not (claim.qualifiers and claim.qualifiers[args.noqualifier]) then
				table.insert(filteredClaims, claim)
			end
		end
		claims = filteredClaims
	end

	-- statements filtrados pro non tènnere unu tzertu balore a unu seguru qualifier optzionale
	if args.qualifieroptnovalue and args.qualifiervalue then
		filteredClaims = {}
		for _, claim in ipairs(claims) do
			if claim.qualifiers and claim.qualifiers[args.qualifieroptnovalue] then
				if not hasQualifierValue(claim, args.qualifieroptnovalue, args.qualifiervalue) then
					table.insert(filteredClaims, claim)
				end
			else
				table.insert(filteredClaims, claim)
			end
		end
		claims = filteredClaims
	end

	-- cun args.qualifiertype=latest frunit solu su prus reghente
	if args.qualifier and args.qualifiertype == 'latest' then
		local latest, latestTime
		for _, claim in ipairs(claims) do
			if claim.qualifiers and claim.qualifiers[args.qualifier] then
				for _, qualifier in ipairs(claim.qualifiers[args.qualifier]) do
					if qualifier.datavalue.type == 'time' then
						if not latestTime or qualifier.datavalue.value.time > latestTime then
							latest = claim
							latestTime = qualifier.datavalue.value.time
						end
					end
				end
			end
		end
		claims = latest and { latest } or {}
	end

	-- cun args.n frunit petzi s'n-èsimu elementu
	if args.n then
		local n = tonumber(args.n)
		claims = (n and n <= #claims) and { claims[n] } or {}
	end

	return claims
end

-------------------------------------------------------------------------------
--                  Funtzionalidades esportadas pro àteros mòdulos
-------------------------------------------------------------------------------

function p._getClaims(propertyId, args)
	return getClaims(propertyId, args or {})
end

function p._formatStatement(statement, args)
	return formatStatement(statement, args or {})
end

function p._formatQualifiers(claim, qualifierId, args, rawTable, retTable)
	return formatQualifiers(claim, qualifierId, args or {}, rawTable, retTable)
end

-- Frunit su balore de una propiedade de Wikidata opuru nil si s'entity o
-- sa propiedade no esistent, o si pro paràmetros de issèberu sos statement sunt zero.
function p._getProperty(args, rawTable)
	local propertyId, value, claims, ret

	-- paràmetros positzionales
	propertyId = args[1] and string.upper(args[1])
	if not propertyId then
		error(i18n.errors['property-param-not-provided'], 2)
	end
	value = args[2]
	-- fix uppercase
	args.qualifier = args.qualifier and string.upper(args.qualifier)

	if value then
		ret = formatUserValue(value, args)
	elseif args.wd ~= 'no' then
		claims = getClaims(propertyId, args)
		ret = (claims and #claims > 0) and formatStatements(claims, args, rawTable) or nil
	end

	return ret
end

-- Frunit su balore de unu qualifier de una propiedade de Wikidata,
-- o nil si s'entity o sa propiedade no esistent, o si pro paràmetros de issèberu non b'ant resurtados.
function p._getQualifier(args)
	local propertyId, qualifierId, value, claims, ret

	-- paràmetros positzionales
	propertyId = args[1] and string.upper(args[1])
	if not propertyId then
		error(i18n.errors['property-param-not-provided'], 2)
	end
	qualifierId = args[2] and string.upper(args[2])
	if not qualifierId then
		error(i18n.errors['qualifier-param-not-provided'], 2)
	end
	value = args[3]

	if value then
		ret = formatUserValue(value, args)
	elseif args.wd ~= 'no' then
		claims = getClaims(propertyId, args)
		if claims and #claims > 0 then
			local formattedQualifiers = {}
			for _, claim in ipairs(claims) do
				formattedQualifiers = formatQualifiers(claim, qualifierId, args, true, formattedQualifiers)
			end
			ret = #formattedQualifiers > 0 and
				  mw.text.listToText(formattedQualifiers, args.separator, args.conjunction) or nil
		end
	end

	return ret
end

-- Frunit s'ìnditze de su statement cun su balore rechertu, o nil si no agatadu.
function p._indexOf(args)
	local ret, propertyId, value, claims

	-- paràmetros positzionales
	propertyId = args[1] and string.upper(args[1])
	if not propertyId then
		error(i18n.errors['property-param-not-provided'], 2)
	end
	value = args[2]
	if not value then
		error(i18n.errors['value-param-not-provided'], 2)
	end

	claims = getClaims(propertyId, args)
	if claims and #claims > 0 then
		args.formatting = 'raw'
		for i, claim in ipairs(claims) do
			if formatStatement(claim, args) == value then
				ret = i
				break
			end
		end
	end

	return ret
end

-- Frunit il numero di statement di una proprietà di Wikidata.
function p._N(args) 
	local propertyId, claims

	-- paràmetros positzionales
	propertyId = args[1] and string.upper(args[1])
	if not propertyId then
		error(i18n.errors['property-param-not-provided'], 2)
	end
	-- get claims
	claims = getClaims(propertyId, args)

	return claims and #claims or 0
end

-- Frunit true si la propiedade ispetzificada tenet comente valore
-- a su nessi unu intre sos entityId colados comente a argumentu.
function p._propertyHasEntity(propertyId, args)
	local statements = p._getProperty({ propertyId, from = args.from, formatting = 'raw' }, true)
	if statements then
		for _, statement in ipairs(statements) do
			for _, entityId in ipairs(args) do
				if statement == entityId then
					return true
				end
			end
		end
	end

	return false
end

-- Frunit true si la propiedade P31 (instance of) tenet comente a balore nessi unu tra sos entityId ispetzificados
function p._instanceOf(args)
	return p._propertyHasEntity('P31', args)
end

-- Frunit true si sa propiedade P279 (subclass of) tenet comente valore a su nessi unu tra sos entityId ispetzificados
function p._subclassOf(args)
	return p._propertyHasEntity('P279', args)
end

-- Frunit l'etichetta di un item o di una proprietà Wikidata.
function p._getLabel(args)
	local entityId = args[1] and string.upper(args[1])
	local ret
	if args[2] then
		ret = mw.wikibase.getLabelByLang(entityId, args[2])
	else
		ret = mw.wikibase.getLabel(entityId)
	end
	return ret
end

-- Frunit su tìtulu de sa pàgina ligada a unu datu item Wikidata.
function p._getLink(args) 
	-- paràmetros positzionales
	local entityId = args[1] and string.upper(args[1])
	if not entityId then
		error(i18n.errors['entityid-param-not-provided'], 2)
	end
	
	return entityId:sub(1, 1) == 'Q' and formatEntityId(entityId) or nil
end

-- Frunit su datatype de una propiedade Wikidata.
function p._getDatatype(args) 
	local propertyId, entity

	-- paràmetros positzionales
	propertyId = args[1] and string.upper(args[1])
	if not propertyId then
		error(i18n.errors['property-param-not-provided'], 2)
	end

	entity = mw.wikibase.getEntity(propertyId)
	if not entity then
		error(i18n.errors['entity-not-found'], 2)
	end

	if not i18n.datatypes[entity.datatype] then
		error(i18n.errors['unknown-datavalue-type'], 2)
	end

	return i18n.datatypes[entity.datatype]
end

-- Frunit s'ID de s'item Wikidata ligadu a sa pàgina currente o a una pàgina ispetzificada
-- (ammenta·ti: sighit sos redirect firmende·si a su primu redirect ligadu a un'elementu)
function p._getId(args)
	local ret
	if args[1] then
		local title = mw.title.new(args[1])
		while title do
			local id = mw.wikibase.getEntityIdForTitle(title.prefixedText)
			if id then
				ret = id
				break
			else
				title = title.redirectTarget
			end
		end
	else
		ret = mw.wikibase.getEntityIdForCurrentPage()
	end
	return ret
end

-------------------------------------------------------------------------------
--                 Funtziones esportadas pro sos templates
-------------------------------------------------------------------------------

-- Funtzione pro su template {{Wikidata}}
function p.getProperty(frame)
	return select(2, xpcall(function()
		return p._getProperty(getArgs(frame, { parentOnly = true }))
	end, errhandler))
end

-- Funtzione pro su template {{WikidataQ}}
function p.getQualifier(frame)
	return select(2, xpcall(function()
		return p._getQualifier(getArgs(frame, { parentOnly = true }))
	end, errhandler))
end

-- Funtzione pro su template {{WikidataIdx}}
function p.indexOf(frame)
	return select(2, xpcall(function()
		return p._indexOf(getArgs(frame, { parentOnly = true }))
	end, errhandler))
end

-- Funtzione pro su template {{WikidataN}}
function p.N(frame)
	return select(2, xpcall(function()
		return p._N(getArgs(frame, { parentOnly = true }))
	end, errhandler))
end

-- Funtzione pro su template {{WikidataLabel}}
function p.getLabel(frame)
	return select(2, xpcall(function()
		return p._getLabel(getArgs(frame, { parentOnly = true }))
	end, errhandler))
end

-- Funtzione pro su template {{WikidataLink}}
function p.getLink(frame)
	return select(2, xpcall(function()
		return p._getLink(getArgs(frame, { parentOnly = true }))
	end, errhandler))
end

-- Funtzione pro su template {{WikidataIstanza}}
function p.instanceOf(frame)
	return select(2, xpcall(function()
		return p._instanceOf(getArgs(frame, { parentOnly = true })) and 1 or ''
	end, errhandler))
end

-- Funtzione pro su template {{WikidataTipo}}
function p.getDatatype(frame)
	return select(2, xpcall(function()
		return p._getDatatype(getArgs(frame, { parentOnly = true }))
	end, errhandler))
end

-- Funtzione pro su template {{WikidataId}}
function p.getId(frame)
	return select(2, xpcall(function()
		return p._getId(getArgs(frame, { parentOnly = true }))
	end, errhandler))
end

return p