Module:Template parameter value: Difference between revisions

Safer nicotine wiki Tobacco Harm Reduction
Jump to navigation Jump to search
m (1 revision imported)
imported>MSGJ
(reverting that last update per our discussion, if anyone needs this functionality then let's discuss again)
 
Line 1: Line 1:
local p = {}
local p = {}
local escape = require("Module:String")._escapePattern
local _getParameters = require("Module:Transcluder").getParameters
function trimspaces(s)
local escapeString = require("Module:String")._escapePattern
return string.gsub(s, "^%s*(.-)%s*$", "%1")
local yesno = require("Module:Yesno")
end


local function getTitle(title)
local function getTitle(title)
Line 11: Line 10:
end
end


--string.gmatch will check the largest block it can without re-scanning whats inside, but we need whats inside
local function matchAllTemplates(str)
local matches = {}
for template in string.gmatch(str, "{%b{}}") do
table.insert(matches, template)
local innerContent = string.sub(template, 3, -3)
for _,subtemplate in next,matchAllTemplates(innerContent) do
table.insert(matches, subtemplate)
end
end
return matches
end
local function escapeComments(content)
for comment in string.gmatch(content, "%b<>") do
if string.sub(comment,1,4) == "<!--" and string.sub(comment,-3,-1) == "-->" then
local safeComment = string.gsub("<!--" .. mw.text.nowiki(string.sub(comment,4,-3)) .. "-->", "%%", "%%%%")
content = string.gsub(content, escapeString(comment), safeComment, 1)
end
end
return content
end
--Transcluder's getParameters, but force all keys to be a string (helps with template inputs)
local function getParameters(template)
local parameters, text, paramOrder = _getParameters(template)
local newParams = {}
for key,value in next,parameters do
newParams[tostring(key)] = value
end
local newParamOrder = {}
for index,key in next,paramOrder do
newParamOrder[index] = tostring(key)
end
return newParams, text, newParamOrder
end
-- Returns a table containing parameters and a table with the order in which each of their values were found.
-- Since this considers all subtemplates, a single parameter is expected to have multiple values.
-- E.g. {{ABC|X={{DEF|X=Value|Y=Other value}}{{ABC|X=Yes}}|Y=P}}
-- Would return {X={"{{DEF|X=Value|Y=Other value}}", "Value", "Yes"}, Y={"Other value", "P"}}
local function getAllParameters(template)
local parameterTree = setmetatable({}, {
__index = function(self,key)
rawset(self,key,{})
return rawget(self,key)
end
})
local params, _, paramOrder = getParameters(template)
for _,key in ipairs(paramOrder) do
local value = params[key]
table.insert(parameterTree[key], value) --Insert the initial value into the tree
for subtemplate in string.gmatch(value, "{%b{}}") do --And now check for subvalues
local subparams = getAllParameters(subtemplate)
for subkey,subset in next,subparams do
for _,subvalue in ipairs(subset) do
table.insert(parameterTree[subkey], subvalue) --And add any we find to our tree
end
end
end
end
return parameterTree
end
--Primary module entry point. Returns a success boolean and either the result or why it failed.
function p.getValue(page, templates, parameter, options)
if not (templates and parameter) then --Required parameters
return false, "Missing required parameters 'templates' and 'parameter'"
end
parameter = tostring(parameter) --Force consistency
options = options or {}
local templateIndex = tonumber(options.templateIndex) or 1
local parameterIndex = tonumber(options.parameterIndex) or 1
local ignoreSubtemplates = options.ignoreSubtemplates or false
if type(templates) == "string" then
templates = mw.text.split(templates, ", ?")
end
local title = getTitle(page)
if title == nil then
return false, "Requested title doesn't exist"
end
local content = escapeComments(title:getContent() or "")
local foundTemplates = 0
local foundParameters = 0
for _,template in next,matchAllTemplates(content) do
for _,wantedTemplate in pairs(templates) do
if string.match(template, "^{{%s*"..wantedTemplate.."%s*[|}]") then
foundTemplates = foundTemplates + 1
if foundTemplates == templateIndex then --Found our wanted template
local value
if ignoreSubtemplates then
value = getParameters(template)[parameter] or ""
else
value = getAllParameters(template)[parameter][parameterIndex] or ""
end
value = string.gsub(value, "</?%a*include%a*>", "")
value = mw.text.trim(value)
return true, value
end
end
end
end
return false, "No valid template found"
end
--Template entry point. Returns an empty string upon failure
function p.main(frame)
function p.main(frame)
local args = require('Module:Arguments').getArgs(frame, {
local args = require('Module:Arguments').getArgs(frame, {
wrappers = 'Template:Template parameter value'
wrappers = 'Template:Template parameter value'
})
})
local template = escape(args[2])
local options = {
local parameter = escape(args[4])
templateIndex = args[3],
local numberedParameter = (tonumber(parameter) ~= nil)
parameterIndex = args[5],
ignoreSubtemplates = yesno(args.ignore_subtemplates or args.ist) or false
local templateCount = 0
}
local parameterCount = 0
local success,result = p.getValue(args[1], args[2], args[4], options)
local pipemarker = '~_~TPVPIPEMARKER~_~'
if not success then
local templateMatch = tonumber(args[3] or 1)
return ""
local parameterMatch = tonumber(args[5] or 1)*(numberedParameter and parameter or 1)
else
return frame:preprocess(result)
local targettitle = getTitle(args[1])
if targettitle == nil then return "" end
    local content = string.gsub(targettitle:getContent() or "", "[\r\n]", "")
-- Escape some pipes
content = string.gsub(content, '(%[%[[^%[{}]*)|([^%[%]{}]*%]%])', '%1' .. pipemarker ..'%2')
while templateCount ~= templateMatch do
if content == nil then return "" end
content = string.match(content, '{{' .. template .. "(.+)")
templateCount = templateCount + 1
end
end
while parameterCount ~= parameterMatch do
if content == nil then return "" end
content = string.match(content, '|%s*' .. (numberedParameter and "" or parameter .. '%s*=%s*') .. '([^|].*)')
parameterCount = parameterCount + 1
end
if content == nil then return "" end
content = string.gsub(content, "</?%a*include%a*>", "")
content = string.match(content, '^([^|}]*{{[^}]+}}[^|}]*)|') or string.match(content, '([^|}]+)')
content = string.gsub(content, pipemarker, '|')
content = frame:preprocess{text = content}
content = trimspaces(content)
return content
end
end
--Potentially useful module entry points
p.matchAllTemplates = matchAllTemplates
p.getParameters = getParameters
p.getAllParameters = getAllParameters


return p
return p

Latest revision as of 22:39, 26 March 2023

Documentation for this module may be created at Module:Template parameter value/doc

local p = {}
local _getParameters = require("Module:Transcluder").getParameters
local escapeString = require("Module:String")._escapePattern
local yesno = require("Module:Yesno")

local function getTitle(title)
	local success, titleObj = pcall(mw.title.new, title)
	if success then return titleObj
	else return nil end
end

--string.gmatch will check the largest block it can without re-scanning whats inside, but we need whats inside
local function matchAllTemplates(str)
	local matches = {}
	for template in string.gmatch(str, "{%b{}}") do
		table.insert(matches, template)
		local innerContent = string.sub(template, 3, -3)
		for _,subtemplate in next,matchAllTemplates(innerContent) do
			table.insert(matches, subtemplate)
		end
	end
	return matches
end

local function escapeComments(content)
	for comment in string.gmatch(content, "%b<>") do
		if string.sub(comment,1,4) == "<!--" and string.sub(comment,-3,-1) == "-->" then
			local safeComment = string.gsub("<!--" .. mw.text.nowiki(string.sub(comment,4,-3)) .. "-->", "%%", "%%%%")
			content = string.gsub(content, escapeString(comment), safeComment, 1)
		end
	end
	return content
end

--Transcluder's getParameters, but force all keys to be a string (helps with template inputs)
local function getParameters(template)
	local parameters, text, paramOrder = _getParameters(template)
	local newParams = {}
	for key,value in next,parameters do
		newParams[tostring(key)] = value
	end
	local newParamOrder = {}
	for index,key in next,paramOrder do
		newParamOrder[index] = tostring(key)
	end
	return newParams, text, newParamOrder
end

-- Returns a table containing parameters and a table with the order in which each of their values were found.
-- Since this considers all subtemplates, a single parameter is expected to have multiple values.
-- E.g. {{ABC|X={{DEF|X=Value|Y=Other value}}{{ABC|X=Yes}}|Y=P}}
-- Would return {X={"{{DEF|X=Value|Y=Other value}}", "Value", "Yes"}, Y={"Other value", "P"}}
local function getAllParameters(template)
	local parameterTree = setmetatable({}, {
		__index = function(self,key)
			rawset(self,key,{})
			return rawget(self,key)
		end
	})
	local params, _, paramOrder = getParameters(template)
	for _,key in ipairs(paramOrder) do
		local value = params[key]
		table.insert(parameterTree[key], value) --Insert the initial value into the tree
		for subtemplate in string.gmatch(value, "{%b{}}") do --And now check for subvalues
			local subparams = getAllParameters(subtemplate)
			for subkey,subset in next,subparams do
				for _,subvalue in ipairs(subset) do
					table.insert(parameterTree[subkey], subvalue) --And add any we find to our tree
				end
			end
		end
	end
	return parameterTree
end

--Primary module entry point. Returns a success boolean and either the result or why it failed.
function p.getValue(page, templates, parameter, options)
	if not (templates and parameter) then --Required parameters
		return false, "Missing required parameters 'templates' and 'parameter'"
	end
	parameter = tostring(parameter) --Force consistency
	options = options or {}
	local templateIndex = tonumber(options.templateIndex) or 1
	local parameterIndex = tonumber(options.parameterIndex) or 1
	local ignoreSubtemplates = options.ignoreSubtemplates or false
	if type(templates) == "string" then
		templates = mw.text.split(templates, ", ?")
	end
	
	local title = getTitle(page)
	if title == nil then
		return false, "Requested title doesn't exist"
	end
	local content = escapeComments(title:getContent() or "")
	
	local foundTemplates = 0
	local foundParameters = 0
	for _,template in next,matchAllTemplates(content) do
		for _,wantedTemplate in pairs(templates) do
			if string.match(template, "^{{%s*"..wantedTemplate.."%s*[|}]") then
				foundTemplates = foundTemplates + 1
				if foundTemplates == templateIndex then --Found our wanted template
					local value
					if ignoreSubtemplates then
						value = getParameters(template)[parameter] or ""
					else
						value = getAllParameters(template)[parameter][parameterIndex] or ""
					end

					value = string.gsub(value, "</?%a*include%a*>", "")
					value = mw.text.trim(value)
					return true, value
				end
			end
		end
	end

	return false, "No valid template found"
end

--Template entry point. Returns an empty string upon failure
function p.main(frame)
	local args = require('Module:Arguments').getArgs(frame, {
		wrappers = 'Template:Template parameter value'
	})
	local options = {
		templateIndex = args[3],
		parameterIndex = args[5],
		ignoreSubtemplates = yesno(args.ignore_subtemplates or args.ist) or false
	}
	local success,result = p.getValue(args[1], args[2], args[4], options)
	if not success then
		return ""
	else
		return frame:preprocess(result)
	end
end

--Potentially useful module entry points
p.matchAllTemplates = matchAllTemplates
p.getParameters = getParameters
p.getAllParameters = getAllParameters

return p