Moduł:Sprawdź

Z VatoWiki
Przejdź do nawigacji Przejdź do wyszukiwania

Dokumentacja dla tego modułu może zostać utworzona pod nazwą Moduł:Sprawdź/opis

local function checkUri(uri)
	local urilen = #uri
	for _,v in ipairs(mw.loadData("Moduł:Cytuj/dane").supportedUriSchemas) do
		if (#v < urilen) and (string.lower(string.sub(uri,1, #v)) == v) then
			return not string.match(uri, '%s')
		end
	end
end

function checkImageName(name)
	if not name or (#name==0) or string.match(name, "[#<>%[%]|{}]") then
		return false
	end
	
	local title = mw.title.makeTitle("Plik", name)
	if not title then
		return false
	end
	
	local res = {
		prefix = {
			plik = true,
			image = true,
			grafika = true,
			file = true,
		},
		extension = {
			jpg = true,
			jpeg = true,
			jpe = true,
			png = true,
			svg = true,
			tif = true,
			tiff = true,
			gif = true,
			xcf = true,
			pdf = true,
			djvu = true,
			webp = true,
		},
	}
	
	local prefix = string.match(name, "^:? *([^:]+) *:")
	if prefix and res.prefix[string.lower(prefix)] then
		return false
	end
	
	local extension = string.match(name, "%S.*%.([^%.]+)$")
	return extension and res.extension[string.lower(extension)]
end

local function findPlainHttp(text)
	if text then
		text = mw.ustring.gsub(text, "%[[hH][tT][tT][pP][sS]?://%S+", "_")
		return string.match(text, "[hH][tT][tT][pP][sS]?://%S")
	end
end

local function findFile(text)
	-- schowaj wyjątek: obrazek generowany przez Szablon:Link-interwiki
	text = mw.ustring.gsub(text, "%[%[Plik:Wikidata%-logo%-en%.svg|10x9px|link=:d:Q%d+|Informacje powiązane z artykułem „.-” w Wikidanych%]%]", "")
	-- normalize
	text = mw.ustring.gsub(text, "%s*[Pp]lik%s*:%s*", "Plik:")
	text = mw.ustring.gsub(text, "%s*[Ff]ile%s*:%s*", "Plik:")
	text = mw.ustring.gsub(text, "%s*[Gg]rafika%s*:%s*", "Plik:")
	text = mw.ustring.gsub(text, "%s*[Ii]mage%s*:%s*", "Plik:")
	return mw.ustring.match(text, "%[%[Plik:([^%[%]|]+)[|%]]")
end

-- Lista of template params for wikicode. Like this:
-- | grafika = | data śmierci = | www = 
local function listToTplParams(strArray)
	return "| " .. table.concat(strArray, " = | ") .. " =";
end

local function showTemplate(templateName, args)
	local result = {}
	local flags = {}
	table.insert(result, mw.text.nowiki("{{"))
	if mw.isSubsting() then
		table.insert(result, "subst:")
	end
	
	local title = mw.title.new(templateName)
	if title.namespace ~= 10 then
		table.insert(result, title.nsText)
		table.insert(result, ":")
	end
	
	table.insert(result, title.text)

	if args then
		local i = 1
		while args[i] do
			table.insert(result, "|")
			table.insert(result, mw.text.nowiki(args[i]))
			i = i + 1
		end
		
		for k, v in pairs(args) do
			local index = tonumber(k)
			if (type(k) == "string") or (index and ((index < 1) or (index > i))) then
				table.insert(result, "|")
				table.insert(result, tostring(k))
				table.insert(result, "=")
				table.insert(result, mw.text.nowiki(v))
			end
		end
	end

	table.insert(result, mw.text.nowiki("}}"))
	return table.concat(result)
end

local function infoboxCatTitle(infobox, class)
	local catTitle = mw.title.makeTitle(14, "Infoboksy – "..class.." – "..infobox)
	if not catTitle.exists then
		mw.logObject(catTitle, "Dedykowana kategoria błędów w infoboksie nie istnieje")
		catTitle = mw.title.makeTitle(14, "Infoboksy – "..class)
	end
	
	mw.logObject(catTitle, "infoboxCatTitle")
	return catTitle
end

local function daysInMonth(year, month)
	if month == 1 then return 31 end
	if month == 2 then return ((year % 4) == 0) and 29 or 28 end
	if month == 3 then return 31 end
	if month == 4 then return 30 end
	if month == 5 then return 31 end
	if month == 6 then return 30 end
	if month == 7 then return 31 end
	if month == 8 then return 31 end
	if month == 9 then return 30 end
	if month == 10 then return 31 end
	if month == 11 then return 30 end
	if month == 12 then return 31 end
	return 0
end

local function isDate20YYMMDD(date)
	local y, m, d = mw.ustring.match(date, "^(20[0-9][0-9])%-([01][0-9])%-([0123][0-9])$")
	local year = tonumber(y)
	local month = tonumber(m)
	local day = tonumber(d)
	local result = year and month and day
		and (year >= 2001)
		and (month >= 1) and (month <= 12)
		and (day >= 1) and (day <= daysInMonth(year, month))
	if not result then
		mw.logObject({date=date,year=year,month=month,day=day}, "isDate20YYMMDD")
	end
	return result
end

return {
	["Porównaj"] = function(frame)
		local config = frame:getParent().args[""] or ""
		local options = mw.text.split(config, "|")
		local templateName = mw.text.trim(options[1])
		if #templateName == 0 then
			local title = mw.title.getCurrentTitle()
			if title.namespace == 10 then
				templateName = mw.ustring.match(title.text, "^(.-)/opis")
					or mw.ustring.match(title.text, "^(.-)/test")
					or mw.ustring.match(title.text, "^(.-)/brudnopis")
					or title.text
			end
			if #templateName == 0 then
				mw.log("brak nazwy szablonu")
				return
			end
		end
	
		local templateTitle = mw.title.new(templateName, 10)
		if templateTitle.id == 0 then
			mw.log("szablon '"..templateName.."' nie istnieje")
			return
		end
		
		local sandboxName = templateName.."/brudnopis"
		local sandboxTitle = mw.title.new(sandboxName, 10)
		if sandboxTitle.id == 0 then
			mw.log("brudnopis '"..sandboxName.."' nie istnieje")
			return
		end
		
		local i = 2
		local showparams = true
		local showinfo = true
		local vertical = false
		while i <= #options do
			local option = mw.text.trim(options[i])
			if option == "bez wikikodu" then
				showparams = false
			elseif option == "bez opisu" then
				showinfo = false
			elseif option == "pionowo" then
				vertical = true
			end
			
			i = i + 1
		end
	
		local templateParams = {}
		local params = {}
		for k, v in pairs(frame:getParent().args) do
			if k ~= "" then
				templateParams[k] = v
				table.insert(params, k)
			end
		end
	
		local result = {}
		table.insert(result, '<table style="width: 100%;">')
		
		if showparams and (#params > 0) then
			local compare = function(a, b)
				-- return a < b
				if (type(a) == "number") and (type(b) == "number") then
					return a < b
				end
				
				if (type(a) == "string") and (type(b) == "string") then
					return a < b
				end
				
				if (type(a) == "number") and (type(b) == "string") then
					return true
				end
				
				return false
			end
			
			table.sort(params, compare)
			table.insert(result, "<caption><code>&#x7B;&#x7B;")
			table.insert(result, templateName)
			for i, k in ipairs(params) do
				table.insert(result, " &#x7C; ")
				local p = mw.text.nowiki(tostring(k))
				local v = mw.text.nowiki(templateParams[k])
				table.insert(result, p)
				table.insert(result, " = ")
				table.insert(result, v)
			end
			table.insert(result, "&#x7D;&#x7D;</code></caption>")
		end
		
		local templateResult = frame:expandTemplate{ title=templateName, args=templateParams}
		local sandboxResult = frame:expandTemplate{ title=sandboxName, args=templateParams}
		
		if templateResult and string.match(templateResult, "^{|") then
			templateResult = "\n"..templateResult
		end
		if sandboxResult and string.match(sandboxResult, "^{|") then
			sandboxResult = "\n"..sandboxResult
		end
		
		if vertical and showinfo then
			table.insert(result, '<tr><th style="width: 15em">[[Szablon:')
			table.insert(result, templateName)
			table.insert(result, '|Szablon]]</th><td>')
			table.insert(result, templateResult)
			table.insert(result, '</td></tr><tr><th>[[Szablon:')
			table.insert(result, sandboxName)
			table.insert(result, '|Brudnopis szablonu]]</th><td>')
			table.insert(result, sandboxResult)
			table.insert(result, '</td></tr>')
		elseif vertical then
			table.insert(result, '<tr><td>')
			table.insert(result, templateResult)
			table.insert(result, '</td></tr><tr><td>')
			table.insert(result, sandboxResult)
			table.insert(result, '</td></tr>')
		else
			if showinfo then
				table.insert(result, '<tr><th style="width: 50%;">[[Szablon:')
				table.insert(result, templateName)
				table.insert(result, '|Szablon]]</th><th style="width: 50%;">[[Szablon:')
				table.insert(result, sandboxName)
				table.insert(result, '|Brudnopis szablonu]]</th></tr>')
			end
			
			table.insert(result, '<tr style="vertical-align: top;"><td>')
			table.insert(result, templateResult)
			table.insert(result, '</td><td>')
			table.insert(result, sandboxResult)
			table.insert(result, '</td></tr>')
		end
		
		table.insert(result, "</table>")
		return table.concat(result)
	end,

	["Parametry"] = function(frame)
		if mw.title.getCurrentTitle().contentModel ~= "wikitext" then
			mw.logObject(mw.title.getCurrentTitle().contentModel, "mw.title.getCurrentTitle().contentModel")
			return -- to nie ma sensu w takim wypadku
		end

		local unknown = {}
		local invalid = {}
		local deprecated = {}
		local nakedurl = {}
		local files = {}
		local templateName = frame:getParent():getTitle()
		local infobox = mw.ustring.match(templateName, "^Szablon:(.- infobox)$")
		local config = frame.args[""]
		local class, space, category = string.match(config or "", "^%s*(%S+)(%s+)(.-)%s*$")
		local nl = space and string.match(space, "\n") or ""
		class = class or config

		local function argName(arg)
			return type(arg) ~= "string" and tostring(arg) or ('"'..arg..'"')
		end
		
		local required = {}
		for k, v in pairs(frame.args) do
			if mw.ustring.match(v, "!$") then
				required[k] = true
				if infobox then
					-- odróżniaj pola sugerowane w infoboksach, które mogą być puste
					if v == "!" or mw.ustring.match(v, "%?!$") then
						required[k] = false
					else
						local pattern = string.match(v,"^(^.-$)!?$")
						if pattern and mw.ustring.match("", pattern) then
							required[k] = false
						end
					end
				end
			end
		end
		
		local emptyArg = false
		for k, v in pairs(frame:getParent().args) do
			required[k] = nil
			local kind = frame.args[k]
			if kind == "" or kind == "!" then
				kind = "text?"
			end
				
			if k == "" then
				emptyArg = v
			elseif not kind then
				table.insert(unknown, argName(k))
			elseif (kind == "num") or (kind == "num!") then
				local n = tonumber(v)
				if not n then table.insert(invalid, argName(k)) end
			elseif (kind == "num?") or (kind == "num?!") then
				local n = (#v == 0) or tonumber(v)
				if not n then table.insert(invalid, argName(k)) end
			elseif (kind == "grafika") or (kind == "grafika!") then
				if findPlainHttp(v) then
					table.insert(nakedurl, argName(k))
				else
					local g = checkImageName(v)
					if not g then table.insert(invalid, argName(k)) end
				end
			elseif (kind == "grafika?") or (kind == "grafika?!") then
				if findPlainHttp(v) then
					table.insert(nakedurl, argName(k))
				else
					local g = (#v == 0) or checkImageName(v)
					if not g then table.insert(invalid, argName(k)) end
				end
			elseif (kind == "uri") or (kind == "uri!") then
				local u = checkUri(v)
				if not u then table.insert(invalid, argName(k)) end
			elseif (kind == "uri?") or (kind == "uri?!") then
				local u = (#v == 0) or checkUri(v)
				if not u then table.insert(invalid, argName(k)) end
			elseif (kind == "txt") or (kind == "txt!") then
				if #v == 0 then
					table.insert(invalid, argName(k))
				elseif checkUri(v) then
					table.insert(nakedurl, argName(k))
				elseif findPlainHttp(v) then
					table.insert(nakedurl, argName(k))
				end
			elseif (kind == "text") or (kind == "text!") or (kind == "text?") then
				if ((kind ~= "text?") and (#v == 0)) then
					table.insert(invalid, argName(k))
				elseif findFile(v) then
					table.insert(files, argName(k))
				elseif checkUri(v) then
					table.insert(nakedurl, argName(k))
				elseif findPlainHttp(v) then
					table.insert(nakedurl, argName(k))
				end
			elseif kind == "old" then
				table.insert(deprecated, argName(k))
			elseif kind == "uri*" then -- specjalny przpadek dla pola 'url' w [[Szablon:Cytuj]]
				local u = checkUri(v) or checkUri(mw.text.unstripNoWiki(v))
				if not u then table.insert(invalid, argName(k)) end
			else
				local pattern = string.match(kind,"^(^.-$)!?$")
				if pattern and not mw.ustring.match(v, pattern) then
					table.insert(invalid, argName(k))
				elseif (#v > 0) and checkUri(v) then
					table.insert(nakedurl, argName(k))
				elseif findPlainHttp(v) then
					table.insert(nakedurl, argName(k))
				end
			end
		end
		
		local missing = {}
		local suggested = {}
		mw.logObject(required, "required")
		for k, v in pairs(required) do
			table.insert(v and missing or suggested, k)
		end
		
		if (#missing == 0) and (#suggested == 0) and (#unknown == 0) and (#invalid == 0) and (#deprecated == 0) and (#nakedurl == 0) and (#files == 0) then
			return nil
		end

		local errorClasses = 0
		
		-- generate messages for each category of problems
		local messages = {}
		if #invalid > 0 then
			errorClasses = errorClasses + 2
			table.insert(messages, "Nieprawidłowe/puste pola: " .. mw.text.listToText(invalid) .. ".")
		end

		if (#missing > 0) or (#suggested > 0) then
			errorClasses = errorClasses + 1
			if (#missing > 0) then table.insert(messages, "Brakujące pola: " .. mw.text.listToText(missing) .. ".") end
			if (#suggested > 0) then table.insert(messages, "Sugerowane pola (wstaw w kodzie): <code>" .. listToTplParams(suggested) .. "</code>") end
		end

		if #unknown > 0 then
			errorClasses = errorClasses + 4
			table.insert(messages, "Nieznane pola: " .. mw.text.listToText(unknown) .. ".")
		end

		if #deprecated > 0 then
			errorClasses = errorClasses + 8
			table.insert(messages, "Przestarzałe pola: " .. mw.text.listToText(deprecated) .. ".")
		end
		
		if #nakedurl > 0 then
			errorClasses = errorClasses + 16
			table.insert(messages, "Gołe linki: " .. mw.text.listToText(nakedurl) .. ".")
		end
		
		if #files > 0 then
			errorClasses = errorClasses + 32
			table.insert(messages, "Nieoczekiwana grafika: " .. mw.text.listToText(files) .. ".")
		end

		-- nop?
		if templateName then
			showTemplate(templateName, frame:getParent().args)
		end

		-- render messages
		local message = mw.html.create()
		if emptyArg then
			message:wikitext("|=", emptyArg, "| ")
		end
		if infobox then
			message:wikitext("\n* ", table.concat(messages, "\n* "))
		else
			message:wikitext(table.concat(messages, " "))
		end
		message = tostring(message)

		-- result container
		local result = mw.html.create(infobox and "table" or "span")
		result:addClass("problemy")
			:addClass(class or nil)
			:attr("aria-hidden", "true")

		local restext = result
		if infobox then
			result:addClass("infobox")
			restext = result:tag("tr"):tag("td")
		else
			result:attr("data-nosnippet", "")
		end
		
 		if templateName then
			restext:wikitext(showTemplate(templateName).." ")
			-- pomiń ten komunikat jeśli zabraknie tylko pól sugerowanych w infoboksie
			if not infobox or (errorClasses ~= 1) or (#missing > 0) then
	 			local warning = mw.html.create()
	 			warning:tag("code"):wikitext(showTemplate(templateName, frame:getParent().args))
	 			warning:wikitext(" ")
	 			warning:tag("span"):addClass("problemy"):wikitext(message)
	 			mw.addWarning(tostring(warning))
 			end
 		end
 		
 		restext:wikitext(message)
 
		if category then
			result:wikitext(category)
		end
		if infobox then
			if (errorClasses == 1) and (#missing <= 0) then
				result:addClass("tylko-braki") -- tylko SUGEROWANE braki
			end
			if (#missing > 0) or (#suggested > 0) then
				result:wikitext("[[Kategoria:", infoboxCatTitle(infobox, "brakujące parametry").text, "]]")
			end
			if mw.title.getCurrentTitle().namespace == 0 then
				if #invalid > 0 then
					result:wikitext("[[Kategoria:", infoboxCatTitle(infobox, "nieprawidłowe parametry").text, "]]")
				end
				if #unknown > 0 then
					result:wikitext("[[Kategoria:", infoboxCatTitle(infobox, "nieznane parametry").text, "]]")
				end
				if #deprecated > 0 then
					result:wikitext("[[Kategoria:", infoboxCatTitle(infobox, "przestarzałe parametry").text, "]]")
				end
				if #nakedurl > 0 then
					result:wikitext("[[Kategoria:", infoboxCatTitle(infobox, "gołe linki").text, "]]")
				end
				if #files > 0 then
					result:wikitext("[[Kategoria:", infoboxCatTitle(infobox, "grafika w nieodpowiednim miejscu").text, "]]")
				end
			end
		end

		return nl..tostring(result)
	end,

	["odn"] = function(frame)
		local pf = frame:getParent()
		local i = 1
		local problems = false
		local yeardetected = false
		while true do
			local arg = pf.args[i]
			if not arg then
				problems = i == 1 and "brak argumentów" or false
				break
			end
	 
			if (i > 5) or yeardetected then
				problems = "za dużo argumentów pozycyjnych"
				break
			end
	 
			if #arg == 0 then
				problems = "pusty argument"
				break
			end
	 
			if arg ~= mw.text.trim(arg) then
				problems = "nieoczekiwane odstępy na początku lub końcu argumentu"
				break
			end
	 
			if string.match(arg, "^%d+%l?$") then
				yeardetected = true
				if i == 1 then
					problems = "rok musi być ostatnim parametrem po nazwiskach autorów"
					break
				end
			elseif string.match(arg, "^s[%-%.:]%s*%d+") then
				problems = "prawdopodobnie nieprawidłowo podany numer strony"
				break
			elseif string.match(arg, "%s%s") then
				problems = "podwójne odstępy"
				break
			elseif mw.ustring.match(arg, "^%a+%d") then
				if not mw.ustring.match(arg, "^[%u%d]+$") then
					problems = "prawdopodobnie sklejone argumenty (brak pionowej kreski)"
					break
				end
			elseif mw.ustring.match(arg, "^OdeB ") then
				-- [[Ordre de Bataille]]
			elseif mw.ustring.match(arg, "^%u%l+%u") then
				local justification = {
					["De"] = true,
					["Del"] = true,
					["Di"] = true,
					["Le"] = true,
					["Mac"] = true,
					["Mc"] = true,
					["Te"] = true, -- TeSelle
					["Sar"] = true, -- SarDesai
					["Van"] = true, -- VanBuren
					["La"] = true, -- LaSalle
				}
				if not justification[mw.ustring.match(arg, "^%u%l+")] then
					problems = "prawdopodobnie sklejone argumenty (brak pionowej kreski)"
					break
				end
			end
	 
			i = i + 1
		end
	 
		if not problems then
			local odn = pf.args.odn
			if odn and ((#odn ~= 1) or (odn < "a") or (odn > "z")) then
				problems = "nieoczekiwany parametr odn"
			end
		end
	 
	 	if not problems then
	 		local s = pf.args.s
	 		if s and string.match(s, "&[a-z]+;") then
	 			problems = "użyto encji HTML w numerze strony"
	 		end
	 	end
	 
		if not problems then
			if pf.args.strona or pf.args.ss or pf.args.strony or pf.args.p or pf.args.page or pf.args.pp or pf.args.pages then
				problems = "przestarzały parametr z numerem strony"
			end
		end
	
	 	if not problems then
	 		return nil
	 	end
	 	
	 	local result = mw.html.create("span")
	 		:addClass("problemy")
	 		:addClass("problemy-w-odn")
	 	if mw.title.getCurrentTitle().namespace == 0 then
	 		result:wikitext("[[Kategoria:Szablon odn do sprawdzenia]]")
	 	end
	 	result:wikitext("ODN: ", problems)
	 	return tostring(result)
	end,
	
	["Wikidane"] = function(frame)
		local property = frame.args.cecha
		local field = frame.args.pole
		local value = frame.args[1]
		if not property or not field then
			return
		end
		
		if not value then
			value = frame:getParent().args[field]
			if not value or (#value == 0) then
				return
			end
		end
		
		local entity = mw.wikibase.getEntity()
		if not entity or not entity.claims or not entity.claims[property] then
			return
		end
		
		for i, v in ipairs(entity.claims[property]) do
			if v.mainsnak.snaktype == "value" then
				if value == v.mainsnak.datavalue.value then
					return
				end
			end
		end
	
		local template = frame:getParent():getTitle()
		local infobox = mw.ustring.match(template, "^Szablon:(.- infobox)$")
		return mw.ustring.format("[[Kategoria:%s – niezgodność w Wikidanych – %s – %s]]", infobox and "Infoboksy" or "Szablony", infobox or template, field)
	end,

	["bez parametrów"] = function(frame)
		for k, v in pairs(frame:getParent().args) do
			return nil
		end
		
		return "tak"
	end,

	["pole z hostem"] = function (frame)
		local host = frame.args.host
		if host and (#host > 0) then
			for k, v in pairs(frame:getParent().args) do
				local link = string.match(v, "[hH][tT][tT][pP][sS]?://[%S]+")
				if link then
					local uri = mw.uri.new(link)
					local valid, _ = mw.uri.validate(uri)
					if valid and uri.host and (#uri.host > 0) then
						if host == uri.host then
							mw.logObject({k, link}, "cały")
							return k
						end
						
						if #host < #uri.host then
							local s1 = '.'..host
							local s2 = string.sub(uri.host, -#s1)
							if s1 == s2 then
								mw.logObject({k, link}, "fragment")
								return k
							end
						end
					end
				end
			end
		end
	end,
	
	["pola z autorami"] = function (frame)
		local result = {}
		local nazwisko = frame.args["nazwisko"]
		local imie = frame.args["imię"]
		local autor = frame.args["autor"]
		local link = frame.args["link"]
		local maxIndex = tonumber(frame.args["max"])
		local prefix = frame.args["przed"] or ""
		local suffix = frame.args["po"] or ""
		for i = 1, maxIndex do
			local s = i == 1 and "" or tostring(i)
			local nin = string.gsub(nazwisko, '#', s)
			local iin = string.gsub(imie, '#', s)
			local ain = string.gsub(autor, '#', s)
			local lin = string.gsub(link, '#', s)
			local niv = frame:getParent().args[nin]
			local iiv = frame:getParent().args[iin]
			local aiv = frame:getParent().args[ain]
			local liv = frame:getParent().args[lin]
			local nis = niv and (#niv > 0)
			local iis = iiv and (#iiv > 0)
			local ais = aiv and (#aiv > 0)
			local lis = liv and (#liv > 0)
			local bad = (nis and ais) -- nazwisko -> zbędny autor
				or (nis and not iis) -- nazwisko bez imienia
				or (lis and not nis and not ais) -- tylko link
				or (iis and not nis) -- imię bez nazwiska
			if bad then
				table.insert(result, i)
			end
		end
	
		if #result > 0 then
			return prefix..mw.text.listToText(result)..suffix
		end
	end,
	
	["uri"] = function(frame)
		mw.logObject(frame:getParent():getTitle(), "parent:title")
		_ = mw.title.new("Moduł:Sprawdź/deprecated/uri").id
		local link = frame.args["link"]
		local space = frame.args["spacja"]
		local check = checkUri(link)
		if check then
			return link
		end
		
		return (space and (check ~= nil)) and link or ""
	end,

	--[[Sprawdzanie url do szablonów
	
		Wykorzystanie:
		{{#invoke:Sprawdź|url|{{{www|}}}|[{{{www}}} Strona internetowa]}}
		{{#invoke:Sprawdź|url|{{{www}}}|[{{{www}}} Strona internetowa]}}
	
		@param #1 Url do sprawdzenia.
			Ciąg typu "{{{abc}}}" pominie sprawdzenie, żeby pokazać wartość na stronie szablonu.
		@param #2 Tekst do wyświetlenia gdy OK.
		@return pusty string gdy błędny, "ok" lub zawartość #2 gdy OK.
	]] 
	["url"] = function(frame)
		local link = frame.args[1]
		local okText = frame.args[2] or "ok"
		local isValid = string.find(link, '{{{') == 1 or checkUri(link)
		if isValid then
			return okText
		end
		return ""
	end,
	
	["lista nazw niepustych argumentów"] = function(frame)
		local argNames = {}
		for k, v in pairs(frame:getParent().args) do
			if #mw.text.trim(v) > 0 then
				table.insert(argNames, tostring(k))
			end
		end
		
		return table.concat(argNames, ", ")
	end,
	
	["zapis daty dostępu"] = function(frame)
		local accessDate = frame:getParent().args["data dostępu"]
		if accessDate and (#accessDate > 0) then
			if not isDate20YYMMDD(accessDate) then
				local builder = mw.html.create('span')
					:addClass('problemy')
					:wikitext('zły zapis daty dostępu')
				if mw.title.getCurrentTitle().namespace == 0 then
					builder:wikitext('[[Kategoria:Szablon cytowania – zły zapis daty dostępu]]')
				end
				return builder
			end
		end
	end,
}