Module:User:JeffDoozan/allowparams

local m_str_utils = require("Module:string utilities")

local concat = table.concat local error = error local find_arguments = require("Module:template parser").findArguments local format_categories = require("Module:utilities").format_categories local gsplit = m_str_utils.gsplit local gsub = string.gsub local html_create = mw.html.create local insert = table.insert local match = string.match local new_title = mw.title.new local next = next local pairs = pairs local process_params = require("Module:parameters").process local scribunto_param_key = m_str_utils.scribunto_param_key local select = select local sort = table.sort local tostring = tostring local type = type

local export = {}

local function get_template_title(frame) return frame:getParent:getTitle end

local function get_template_content(frame) return new_title(get_template_title(frame)):getContent end

local function get_allowed_args(frame) -- returns a table of allowed args local args = {} -- first, detect all args used by the parent template -- find_arguments takes the parent argument table as the second parameter so that argument names can be preprocessed, since these can vary based on the input if an argument name contains another argument (e.g. ) for arg in find_arguments(get_template_content(frame), frame:getParent.args) do		args[arg] = {} end -- if frame.args[1] contains a comma separated list of param names, add those as well local additional = frame.args[1] if additional then for arg in gsplit(additional, ",", true) do -- scribunto_param_key normalizes the arg into the form returned by find_arguments (i.e. trimmed and converted to a number if appropriate) arg = scribunto_param_key(arg) if not args[arg] then args[arg] = {} end end end return args end

local function compare_params(a, b)	a, b = a[1], b[1] local type_a = type(a) if type_a == type(b) then return a < b	end return type_a == "number" end

local function sort_params(invalid_args) -- sort a table of parameters in the form {k, v}, sorting numbers before strings local msg = {} for k, v in pairs(invalid_args) do		insert(msg, {k, v}) end sort(msg, compare_params) for i = 1, #msg do		msg[i] = concat(msg[i], "=") end return msg end

local function apply_pre_tag(frame, invalid_args) return frame:extensionTag("pre", concat(invalid_args, "\n")) end

local function make_message(template_name, invalid_args, no_link) local open = no_link and "" or ""	local close = no_link and "" or "" return "The template " .. open .. template_name .. close .. " does not use the parameter(s): " .. invalid_args .. " Please see " .. open .. "Module:checkparams" .. close .. " for help with this warning." end

local function make_warning_text(frame, template_name, invalid_args, nowarn, noattn, nocat) -- generate "Invalid params" warning to be inserted into wiki page -- template_name (required) name of the template with invalid params -- invalid_args (required) table of invalid args -- nocat= (optional) do not included category in warning_text -- noattn= (optional) do not include attention seeking span in in warning_text -- nowarn= (optional) do not include preview warning in warning_text local warn, attn, cat -- show warning in previewer if not nowarn then warn = tostring(html_create("sup")			:addClass("error")			:addClass("previewonly")			:tag("small")				:wikitext(make_message(template_name, apply_pre_tag(frame, invalid_args)))			:allDone) end -- add attentionseeking message -- tags don't work in HTML attributes, so use semicolons as delimiters if not noattn then attn = tostring(html_create("span")			:addClass("attentionseeking")			:attr("title", make_message(template_name, concat(invalid_args, "; ") .. ".", "no_link"))			:allDone) end if not nocat then cat = format_categories(			{"Pages using bad params when calling " .. template_name},			nil,			"-",			nil,			"force_output"		) end return (warn or "") .. (attn or "") .. (cat or "") end

local function remove_placeholder_args(allowed_params, invalid_args) -- some templates use params 1 and 3 without using 2, -- which means that 2 will be in the list of invalid args -- when used as an empty placeholder like in 	-- this function will detect and remove any empty positionaly placeholder args -- from a list of invalid_args local max_pos = 0 for param in pairs(allowed_params) do		if type(param) == "number" and param > max_pos then max_pos = param end end for param in pairs(invalid_args) do		if (			type(param) == "number" and			param >= 1 and			param < max_pos and			not match(invalid_args[param], "[^%z\t-\v\r ]") -- charset used by MediaWiki to trim parameters		) then invalid_args[param] = nil end end end

function export.process(frame, allowed_params, nowarn, noattn, nocat) -- This is desgined to be called by other Lua modules instead of calling Module:parameters.process -- frame - the frame containing the arguments to be checked -- allowed_params - a table of valid arguments -- nocat - if specified, will not included category in warning_text -- noattn - if specified, will not include attention seeking span in in warning_text -- nowarn - if specified, will not include preview warning in warning_text -- returns valid_args, invalid_args, warning_text local valid_args, invalid_args = process_params(		frame.args,		allowed_params,		"return unknown"	) if next(invalid_args) then remove_placeholder_args(allowed_params, invalid_args) end if next(invalid_args) then local template_name = frame:getTitle return valid_args, invalid_args, make_warning_text(frame, template_name, sort_params(invalid_args), nowarn, noattn, nocat) end return valid_args, invalid_args, "" end

function export.warn(frame) -- This is designed to be called by non-Lua templates using "" -- the passed frame is checked for the following params: -- 1= (optional) a comma separated list of allowed parameters - if not specified, allows all parameters used as variables inside the template -- nowarn= (optional) do not include preview warning in warning_text -- noattn= (optional) do not include attention seeking span in in warning_text -- nocat= (optional) do not included category in warning_text local args = frame.args return select(3, export.process( frame:getParent, get_allowed_args(frame), args.nowarn or false, args.noattn or false, args.nocat or false )) end

do local placeholder = "_message_" function export.placeholder_error -- A dummy function that throws an error with a placeholder message. error(placeholder, 0) end

function export.error(frame) -- This is designed to be called by non-Lua templates using "" -- the passed frame is checked for the following params: -- 1= (optional) a comma separated list of allowed parameters - if not specified, allows all parameters used as variables inside the template local allowed_args = get_allowed_args(frame) mw.log("Allowed args:", mw.dumpObject(allowed_args)) local invalid_args = select(2, process_params( frame:getParent.args, allowed_args, "return unknown" ))		if next(invalid_args) then remove_placeholder_args(allowed_args, invalid_args) end -- Throw an error via callParserFunction, which generates a real error with traceback, automatic categorization in CAT:E etc., but the error message is returned as a string. Then, replace the placeholder error message with an error containing tags. -- This is necessary because tags don't work in conventional error messages, so whitespace-related issues can't be shown accurately. Any whitespace which isn't trimmed is treated as literal, so errors caused by double-spaces or erroneous newlines in inputs need to be displayed accurately. if next(invalid_args) then return (gsub( frame:callParserFunction("#invoke", "checkparams", "placeholder_error"), placeholder, make_message(get_template_title(frame), apply_pre_tag(frame, sort_params(invalid_args))) ))		end end end

return export