<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
	<id>https://linguifex.com/w/index.php?action=history&amp;feed=atom&amp;title=Module%3Acheckparams</id>
	<title>Module:checkparams - Revision history</title>
	<link rel="self" type="application/atom+xml" href="https://linguifex.com/w/index.php?action=history&amp;feed=atom&amp;title=Module%3Acheckparams"/>
	<link rel="alternate" type="text/html" href="https://linguifex.com/w/index.php?title=Module:checkparams&amp;action=history"/>
	<updated>2026-04-22T03:26:10Z</updated>
	<subtitle>Revision history for this page on the wiki</subtitle>
	<generator>MediaWiki 1.43.6</generator>
	<entry>
		<id>https://linguifex.com/w/index.php?title=Module:checkparams&amp;diff=495423&amp;oldid=prev</id>
		<title>Sware: 1 revision imported</title>
		<link rel="alternate" type="text/html" href="https://linguifex.com/w/index.php?title=Module:checkparams&amp;diff=495423&amp;oldid=prev"/>
		<updated>2026-04-21T12:01:17Z</updated>

		<summary type="html">&lt;p&gt;1 revision imported&lt;/p&gt;
&lt;table style=&quot;background-color: #fff; color: #202122;&quot; data-mw=&quot;interface&quot;&gt;
				&lt;tr class=&quot;diff-title&quot; lang=&quot;en&quot;&gt;
				&lt;td colspan=&quot;1&quot; style=&quot;background-color: #fff; color: #202122; text-align: center;&quot;&gt;← Older revision&lt;/td&gt;
				&lt;td colspan=&quot;1&quot; style=&quot;background-color: #fff; color: #202122; text-align: center;&quot;&gt;Revision as of 12:01, 21 April 2026&lt;/td&gt;
				&lt;/tr&gt;&lt;tr&gt;&lt;td colspan=&quot;2&quot; class=&quot;diff-notice&quot; lang=&quot;en&quot;&gt;&lt;div class=&quot;mw-diff-empty&quot;&gt;(No difference)&lt;/div&gt;
&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;</summary>
		<author><name>Sware</name></author>
	</entry>
	<entry>
		<id>https://linguifex.com/w/index.php?title=Module:checkparams&amp;diff=495422&amp;oldid=prev</id>
		<title>wikt&gt;Theknightwho: Compare function moved to Module:compare.</title>
		<link rel="alternate" type="text/html" href="https://linguifex.com/w/index.php?title=Module:checkparams&amp;diff=495422&amp;oldid=prev"/>
		<updated>2025-05-07T02:07:27Z</updated>

		<summary type="html">&lt;p&gt;Compare function moved to &lt;a href=&quot;/wiki/Module:compare&quot; title=&quot;Module:compare&quot;&gt;Module:compare&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;b&gt;New page&lt;/b&gt;&lt;/p&gt;&lt;div&gt;local export = {}&lt;br /&gt;
&lt;br /&gt;
local compare_module = &amp;quot;Module:compare&amp;quot;&lt;br /&gt;
local debug_module = &amp;quot;Module:debug&amp;quot;&lt;br /&gt;
local maintenance_category_module = &amp;quot;Module:maintenance category&amp;quot;&lt;br /&gt;
local parameters_module = &amp;quot;Module:parameters&amp;quot;&lt;br /&gt;
local template_parser_module = &amp;quot;Module:template parser&amp;quot;&lt;br /&gt;
local utilities_module = &amp;quot;Module:utilities&amp;quot;&lt;br /&gt;
&lt;br /&gt;
local concat = table.concat&lt;br /&gt;
local get_current_title = mw.title.getCurrentTitle&lt;br /&gt;
local html_create = mw.html.create&lt;br /&gt;
local match = string.match&lt;br /&gt;
local new_title = mw.title.new&lt;br /&gt;
local next = next&lt;br /&gt;
local pairs = pairs&lt;br /&gt;
local require = require&lt;br /&gt;
local select = select&lt;br /&gt;
local sort = table.sort&lt;br /&gt;
local tostring = tostring&lt;br /&gt;
local type = type&lt;br /&gt;
&lt;br /&gt;
local function find_parameters(...)&lt;br /&gt;
	find_parameters = require(template_parser_module).find_parameters&lt;br /&gt;
	return find_parameters(...)&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function format_categories(...)&lt;br /&gt;
	format_categories = require(utilities_module).format_categories&lt;br /&gt;
	return format_categories(...)&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function formatted_error(...)&lt;br /&gt;
	formatted_error = require(debug_module).formatted_error&lt;br /&gt;
	return formatted_error(...)&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function process_params(...)&lt;br /&gt;
	process_params = require(parameters_module).process&lt;br /&gt;
	return process_params(...)&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function uses_hidden_category(...)&lt;br /&gt;
	uses_hidden_category = require(maintenance_category_module).uses_hidden_category&lt;br /&gt;
	return uses_hidden_category(...)&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local compare&lt;br /&gt;
local function get_compare()&lt;br /&gt;
	compare, get_compare = require(compare_module), nil&lt;br /&gt;
	return compare&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
-- Returns a table of all arguments in `template_args` which are not supported&lt;br /&gt;
-- by `template_title` or listed in `additional`.&lt;br /&gt;
local function get_invalid_args(template_title, template_args, additional)&lt;br /&gt;
	local content = template_title:getContent()&lt;br /&gt;
	if not content then&lt;br /&gt;
		-- This should only be possible if the input frame has been tampered with.&lt;br /&gt;
		error(&amp;quot;Could not retrieve the page content of \&amp;quot;&amp;quot; .. template_title.prefixedText .. &amp;quot;\&amp;quot;.&amp;quot;)&lt;br /&gt;
	end&lt;br /&gt;
	local allowed_params, seen = {}, {}&lt;br /&gt;
	-- Detect all params used by the parent template. param:get_name() takes the&lt;br /&gt;
	-- parent frame arg table as an argument so that preprocessing will take&lt;br /&gt;
	-- them into account, since it will matter if the name contains another&lt;br /&gt;
	-- parameter (e.g. the outer param in &amp;quot;{{{foo{{{bar}}}baz}}}&amp;quot; will change&lt;br /&gt;
	-- depending on the value for bar=). `seen` memoizes results based on the&lt;br /&gt;
	-- raw parameter text (which is stored as a string in the parameter object),&lt;br /&gt;
	-- which avoids unnecessary param:get_name() calls, which are non-trivial.&lt;br /&gt;
	for param in find_parameters(content) do&lt;br /&gt;
		local raw = param.raw&lt;br /&gt;
		if not seen[raw] then&lt;br /&gt;
			allowed_params[param:get_name(template_args)] = true&lt;br /&gt;
			seen[raw] = true&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	-- Add any additional allowed arguments.&lt;br /&gt;
	if additional then&lt;br /&gt;
		local i = 0&lt;br /&gt;
		while true do&lt;br /&gt;
			i = i + 1&lt;br /&gt;
			local param = additional[i]&lt;br /&gt;
			if param == nil then&lt;br /&gt;
				break&lt;br /&gt;
			end&lt;br /&gt;
			allowed_params[param] = true&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	local invalid_args = select(2, process_params(&lt;br /&gt;
		template_args,&lt;br /&gt;
		allowed_params,&lt;br /&gt;
		&amp;quot;return unknown&amp;quot;&lt;br /&gt;
	))&lt;br /&gt;
&lt;br /&gt;
	if not next(invalid_args) then&lt;br /&gt;
		return invalid_args&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	-- Some templates use params 1 and 3 without using 2, which means that 2&lt;br /&gt;
	-- will be in the list of invalid args when used as an empty placeholder&lt;br /&gt;
	-- (e.g. {{foo|foo||bar}}). Detect and remove any empty positional&lt;br /&gt;
	-- placeholder args.&lt;br /&gt;
	local max_pos = 0&lt;br /&gt;
	for param in pairs(allowed_params) do&lt;br /&gt;
		if type(param) == &amp;quot;number&amp;quot; and param &amp;gt; max_pos then&lt;br /&gt;
			max_pos = param&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	for param, arg in pairs(invalid_args) do&lt;br /&gt;
		if (&lt;br /&gt;
			type(param) == &amp;quot;number&amp;quot; and&lt;br /&gt;
			param &amp;gt;= 1 and&lt;br /&gt;
			param &amp;lt; max_pos and&lt;br /&gt;
			-- Ignore if arg is empty, or only contains chars trimmed by&lt;br /&gt;
			-- MediaWiki when handling named parameters.&lt;br /&gt;
			match(arg, &amp;quot;^[%z\t-\v\r ]*$&amp;quot;)&lt;br /&gt;
		) then&lt;br /&gt;
			invalid_args[param] = nil&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	return invalid_args&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
-- Convert `args` into an array of sorted PARAM=ARG strings, using the parameter&lt;br /&gt;
-- name as the sortkey, with numbered params sorted before strings.&lt;br /&gt;
local function args_to_sorted_tuples(args)&lt;br /&gt;
	local msg, i = {}, 0&lt;br /&gt;
	for k, v in pairs(args) do&lt;br /&gt;
		i = i + 1&lt;br /&gt;
		msg[i] = {k, v}&lt;br /&gt;
	end&lt;br /&gt;
	sort(msg, compare or get_compare())&lt;br /&gt;
	for j = 1, i do&lt;br /&gt;
		msg[j] = concat(msg[j], &amp;quot;=&amp;quot;)&lt;br /&gt;
	end&lt;br /&gt;
	return msg&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function apply_pre_tag(frame, invalid_args)&lt;br /&gt;
	return frame:extensionTag(&amp;quot;pre&amp;quot;, concat(invalid_args, &amp;quot;\n&amp;quot;))&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function make_message(template_name, invalid_args, no_link)&lt;br /&gt;
	local open, close&lt;br /&gt;
	if no_link then&lt;br /&gt;
		open, close = &amp;quot;&amp;quot;, &amp;quot;&amp;quot;&lt;br /&gt;
	else&lt;br /&gt;
		open, close = &amp;quot;[[&amp;quot;, &amp;quot;]]&amp;quot;&lt;br /&gt;
	end&lt;br /&gt;
	return &amp;quot;The template &amp;quot; .. open .. template_name .. close .. &amp;quot; does not use the parameter(s): &amp;quot; .. invalid_args .. &amp;quot; Please see &amp;quot; .. open .. &amp;quot;Module:checkparams&amp;quot; .. close .. &amp;quot; for help with this warning.&amp;quot;&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
-- Called by non-Lua templates using &amp;quot;{{#invoke:checkparams|warn}}&amp;quot;. `frame`&lt;br /&gt;
-- is checked for the following params:&lt;br /&gt;
-- `1=` (optional) a comma separated list of additional allowed parameters&lt;br /&gt;
-- `nowarn=` (optional) do not include preview warning in warning_text&lt;br /&gt;
-- `noattn=` (optional) do not include attention seeking span in in warning_text&lt;br /&gt;
function export.warn(frame)&lt;br /&gt;
	local parent = frame:getParent()&lt;br /&gt;
	local template_name = parent:getTitle()&lt;br /&gt;
	local template_title = new_title(template_name)&lt;br /&gt;
&lt;br /&gt;
	local boolean = {type = &amp;quot;boolean&amp;quot;}&lt;br /&gt;
	local iargs = process_params(frame.args, {&lt;br /&gt;
		[1] = {type = &amp;quot;parameter&amp;quot;, sublist = true},&lt;br /&gt;
		[&amp;quot;nowarn&amp;quot;] = boolean,&lt;br /&gt;
		[&amp;quot;noattn&amp;quot;] = boolean,&lt;br /&gt;
	})&lt;br /&gt;
&lt;br /&gt;
	local invalid_args = get_invalid_args(template_title, parent.args, iargs[1])&lt;br /&gt;
&lt;br /&gt;
	-- If there are no invalid template args, return.&lt;br /&gt;
	if not next(invalid_args) then&lt;br /&gt;
		return &amp;quot;&amp;quot;&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	-- Otherwise, generate &amp;quot;Invalid params&amp;quot; warning to be inserted onto the&lt;br /&gt;
	-- wiki page.&lt;br /&gt;
	local warn, attn, cat&lt;br /&gt;
	invalid_args = args_to_sorted_tuples(invalid_args)&lt;br /&gt;
&lt;br /&gt;
	-- Show warning in previewer.&lt;br /&gt;
	if not iargs.nowarn then&lt;br /&gt;
		warn = tostring(html_create(&amp;quot;sup&amp;quot;)&lt;br /&gt;
			:addClass(&amp;quot;error&amp;quot;)&lt;br /&gt;
			:addClass(&amp;quot;previewonly&amp;quot;)&lt;br /&gt;
			:tag(&amp;quot;small&amp;quot;)&lt;br /&gt;
				:wikitext(make_message(template_name, apply_pre_tag(frame, invalid_args)))&lt;br /&gt;
			:allDone())&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	-- Add attentionseeking message. &amp;lt;pre&amp;gt; tags don&amp;#039;t work in HTML attributes,&lt;br /&gt;
	-- so use semicolons as delimiters.&lt;br /&gt;
	if not iargs.noattn then&lt;br /&gt;
		attn = tostring(html_create(&amp;quot;span&amp;quot;)&lt;br /&gt;
			:addClass(&amp;quot;attentionseeking&amp;quot;)&lt;br /&gt;
			:attr(&amp;quot;title&amp;quot;, make_message(template_name, concat(invalid_args, &amp;quot;; &amp;quot;) .. &amp;quot;.&amp;quot;, &amp;quot;no_link&amp;quot;))&lt;br /&gt;
			:allDone())&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	-- Categorize if neither the current page nor the template would go in a hidden maintenance category.&lt;br /&gt;
	if not (uses_hidden_category(get_current_title()) or uses_hidden_category(template_title)) then&lt;br /&gt;
		cat = format_categories(&amp;quot;Pages using invalid parameters when calling &amp;quot; .. template_name, nil, &amp;quot;-&amp;quot;, nil, &amp;quot;force_output&amp;quot;)&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	return (warn or &amp;quot;&amp;quot;) .. (attn or &amp;quot;&amp;quot;) .. (cat or &amp;quot;&amp;quot;)&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
-- Called by non-Lua templates using &amp;quot;{{#invoke:checkparams|error}}&amp;quot;. `frame`&lt;br /&gt;
-- is checked for the following params:&lt;br /&gt;
-- `1=` (optional) a comma separated list of additional allowed parameters&lt;br /&gt;
function export.error(frame)&lt;br /&gt;
	local parent = frame:getParent()&lt;br /&gt;
	local template_name = parent:getTitle()&lt;br /&gt;
&lt;br /&gt;
	local additional = process_params(frame.args, {&lt;br /&gt;
		[1] = {type = &amp;quot;parameter&amp;quot;, sublist = true},&lt;br /&gt;
	})[1]&lt;br /&gt;
&lt;br /&gt;
	local invalid_args = get_invalid_args(new_title(template_name), parent.args, additional)&lt;br /&gt;
&lt;br /&gt;
	-- Use formatted_error, so that we can use &amp;lt;pre&amp;gt; tags in error messages:&lt;br /&gt;
	-- any whitespace which isn&amp;#039;t trimmed is treated as literal, so errors&lt;br /&gt;
	-- caused by double-spaces or erroneous newlines in inputs need to be&lt;br /&gt;
	-- displayed accurately.&lt;br /&gt;
	if next(invalid_args) then&lt;br /&gt;
		return formatted_error(make_message(&lt;br /&gt;
			template_name,&lt;br /&gt;
			apply_pre_tag(frame, args_to_sorted_tuples(invalid_args))&lt;br /&gt;
		))&lt;br /&gt;
	end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
return export&lt;/div&gt;</summary>
		<author><name>wikt&gt;Theknightwho</name></author>
	</entry>
</feed>