Moduł:Brudnopis/Paweł Ziemian/Duplikaty

Z Wikipedii, wolnej encyklopedii

Dokumentacja dla tego modułu może zostać utworzona pod nazwą Moduł:Brudnopis/Paweł Ziemian/Duplikaty/opis

local FindPositionsInReverseOrder = function(text, plainPattern)
	local result = {}
	if #plainPattern > 0 then
		local init = 1
		while init do
			init = string.find(text, plainPattern, init, true)
			if init then
				table.insert(result, 1, init)
				init = init + #plainPattern
			end
		end
	end
	
	return result
end

local RemoveInPlace = function(text, start, len)
	local before = start > 1 and string.sub(text, 1, start-1) or ""
	local stop = start + len
	local after = stop <= #text and string.sub(text, stop) or ""
	return before..string.rep("_", len)..after
end

local function FindTemplatesWithDuplicatedArguments(contents)
	-- zgumkowanie obszarów nie podlegających szablonowej analize
	local text = contents
	-- komentarze HTML
	text = string.gsub(text, "<!%-%-.-%-%->", function(s) return string.rep('_', #s) end)
	-- sekcje <nowiki>
	text = string.gsub(text, "<nowiki>.-</nowiki>", function(s) return string.rep('_', #s) end)
	-- wzory matematyczne
	text = string.gsub(text, "<math>.-</math>", function(s) return string.rep('_', #s) end)
	-- wikilinki iteracyjnie od końca
	for _, startPos in ipairs(FindPositionsInReverseOrder(text, "[[")) do
		local endPos = string.find(text, "]]", startPos, true)
		if endPos then
			local eol = string.find(text, "\n", startPos, true)
			if eol and (eol < endPos) then
				endPos = nil
			end
		end
		
		local len = endPos and (endPos - startPos + 2) or 2
		text = RemoveInPlace(text, startPos, len)
	end

	-- wyszukiwanie pozycji szablonów
	local templatePositions = {}
	-- iteracyjnie od ostatniego
	for _, startPos in ipairs(FindPositionsInReverseOrder(text, "{{")) do
		local endPos = string.find(text, "}}", startPos, true)
		local len = endPos and (endPos - startPos + 2) or 2
		if (len > 2) then
			local template = string.sub(text, startPos, startPos+len-1)
			local separators = {}
			local init = 2
			while init  do
				init = string.find(template, "|", init, true)
				if init then
					table.insert(separators, startPos+init-1)
					init = init + 1
				end
			end
			
			-- tylko szablony z wieloma parametrami są interesujące
			if #separators >= 2 then
				local index = 0
				local m = {}
				local d = {}
				local hasDuplicates = false
				local params = {}
				for i, v in ipairs(separators) do
					local p = {
						start = separators[i],
						len = (separators[i+1] or endPos) - separators[i] - 1,
					}
					local param = string.sub(contents, p.start+1, p.start+p.len)
					local eqPos = string.find(param, "=", 1, true)
					if eqPos then
						p.name = mw.text.trim(string.sub(param, 1, eqPos-1))
						p.namelen = eqPos-1
					else
						index = index + 1
						p.name = tostring(index)
					end
					table.insert(params, p)
					if not m[p.name] then
						m[p.name] = p
					elseif not d[p.name] then
						hasDuplicates = true
						d[p.name] = { m[p.name], p }
					else
						table.insert(d[p.name], p)
					end
				end
				
				if hasDuplicates then
					local suspectedTemplate = { start=startPos, len=len, duplicates = d, params = params }
					table.insert(templatePositions, 1, suspectedTemplate)
				end
			end
		end

		text = RemoveInPlace(text, startPos, len)
	end
	
	return #templatePositions > 0 and templatePositions or false
end

local function FormatReportWithDuplicatedArgumentsInTemplates(duplicates, contents)
	local builder = mw.html.create("ul")
	for k, v in pairs(duplicates) do
		local item = builder:tag("li")
		item:tag("pre"):wikitext(mw.text.nowiki(string.sub(contents, v.start, v.start+v.len-1)))
		local dups = item:tag("ol")
		for _, p in pairs(v.params) do
			if v.duplicates[p.name] then
				local item = dups:tag("li")
				item:tag("tt"):wikitext(mw.text.nowiki(string.sub(contents, p.start, p.start+p.len)))
				if not p.namelen then
					item:tag("sup"):wikitext("(", mw.text.nowiki(p.name), ")")
				end
			end
		end
	end
	
	return tostring(builder)
end

local function Process(contents)
	if not contents or (#contents <= 0) then
		return
	end

	local duplicates = FindTemplatesWithDuplicatedArguments(contents)
	if duplicates then
		return FormatReportWithDuplicatedArgumentsInTemplates(duplicates, contents)
	end
end

return {
	
["w tekście"] = function (frame)
	return Process(require('Module:Arguments').getArgs(frame)[1])
end,

["na stronie"] = function (frame)
	return Process(mw.title.getCurrentTitle():getContent())
end,
	
}