<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="yi">
	<id>https://yi.hamichlol.org.il/w/index.php?action=history&amp;feed=atom&amp;title=%D7%99%D7%97%D7%99%D7%93%D7%94%3AParamValidator</id>
	<title>יחידה:ParamValidator - ווערסיע היסטאריע</title>
	<link rel="self" type="application/atom+xml" href="https://yi.hamichlol.org.il/w/index.php?action=history&amp;feed=atom&amp;title=%D7%99%D7%97%D7%99%D7%93%D7%94%3AParamValidator"/>
	<link rel="alternate" type="text/html" href="https://yi.hamichlol.org.il/w/index.php?title=%D7%99%D7%97%D7%99%D7%93%D7%94:ParamValidator&amp;action=history"/>
	<updated>2026-04-04T04:48:46Z</updated>
	<subtitle>ווערסיע היסטאריע פאר דעם בלאט אויפן וויקי</subtitle>
	<generator>MediaWiki 1.39.4</generator>
	<entry>
		<id>https://yi.hamichlol.org.il/w/index.php?title=%D7%99%D7%97%D7%99%D7%93%D7%94:ParamValidator&amp;diff=205428&amp;oldid=prev</id>
		<title>צמא לדעת: אידיש</title>
		<link rel="alternate" type="text/html" href="https://yi.hamichlol.org.il/w/index.php?title=%D7%99%D7%97%D7%99%D7%93%D7%94:ParamValidator&amp;diff=205428&amp;oldid=prev"/>
		<updated>2023-02-26T14:04:45Z</updated>

		<summary type="html">&lt;p&gt;אידיש&lt;/p&gt;
&lt;table style=&quot;background-color: #fff; color: #202122;&quot; data-mw=&quot;interface&quot;&gt;
				&lt;col class=&quot;diff-marker&quot; /&gt;
				&lt;col class=&quot;diff-content&quot; /&gt;
				&lt;col class=&quot;diff-marker&quot; /&gt;
				&lt;col class=&quot;diff-content&quot; /&gt;
				&lt;tr class=&quot;diff-title&quot; lang=&quot;yi&quot;&gt;
				&lt;td colspan=&quot;2&quot; style=&quot;background-color: #fff; color: #202122; text-align: center;&quot;&gt;→ עלטערע  ווערסיע&lt;/td&gt;
				&lt;td colspan=&quot;2&quot; style=&quot;background-color: #fff; color: #202122; text-align: center;&quot;&gt;רעוויזיע פון 14:04, 26 פעברואר 2023&lt;/td&gt;
				&lt;/tr&gt;&lt;tr&gt;&lt;td colspan=&quot;2&quot; class=&quot;diff-lineno&quot; id=&quot;mw-diff-left-l290&quot;&gt;שורה 290:&lt;/td&gt;
&lt;td colspan=&quot;2&quot; class=&quot;diff-lineno&quot;&gt;שורה 290:&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;	&lt;/div&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;	&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;	-- for purple pages:&lt;/div&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;	-- for purple pages:&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;diff-marker&quot; data-marker=&quot;−&quot;&gt;&lt;/td&gt;&lt;td style=&quot;color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #ffe49c; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;	if frame:getParent().args['skip parameters validation'] then return '[[ &lt;del style=&quot;font-weight: bold; text-decoration: none;&quot;&gt;קטגוריה&lt;/del&gt;:&lt;del style=&quot;font-weight: bold; text-decoration: none;&quot;&gt;דפים עם שגיאות פרמטריות שקיבלו חנינה&lt;/del&gt;]]' end&lt;/div&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot; data-marker=&quot;+&quot;&gt;&lt;/td&gt;&lt;td style=&quot;color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #a3d3ff; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;	if frame:getParent().args['skip parameters validation'] then return '[[ &lt;ins style=&quot;font-weight: bold; text-decoration: none;&quot;&gt;קאטעגאריע&lt;/ins&gt;:&lt;ins style=&quot;font-weight: bold; text-decoration: none;&quot;&gt;בלעטער מיט פאראמעטער פעלערן וואס זענען געווארן פארקוקט&lt;/ins&gt;]]' end&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;	local options, report, template_name = util.extract_options( frame ), '', frame:getParent():getTitle()&lt;/div&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;	local options, report, template_name = util.extract_options( frame ), '', frame:getParent():getTitle()&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;br/&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;br/&gt;&lt;/td&gt;&lt;/tr&gt;

&lt;!-- diff cache key hamichlol_main_yi-mw_:diff::1.12:old-82290:rev-205428 --&gt;
&lt;/table&gt;</summary>
		<author><name>צמא לדעת</name></author>
	</entry>
	<entry>
		<id>https://yi.hamichlol.org.il/w/index.php?title=%D7%99%D7%97%D7%99%D7%93%D7%94:ParamValidator&amp;diff=82290&amp;oldid=prev</id>
		<title>שרגא: 1 רעוויזיע אימפארטירט: אימפארטירט פון די יידישע וויקיפעדיע, זע ביישטייערער ליסטע</title>
		<link rel="alternate" type="text/html" href="https://yi.hamichlol.org.il/w/index.php?title=%D7%99%D7%97%D7%99%D7%93%D7%94:ParamValidator&amp;diff=82290&amp;oldid=prev"/>
		<updated>2022-11-24T13:54:38Z</updated>

		<summary type="html">&lt;p&gt;1 רעוויזיע אימפארטירט: אימפארטירט פון די יידישע וויקיפעדיע, זע ביישטייערער ליסטע&lt;/p&gt;
&lt;table style=&quot;background-color: #fff; color: #202122;&quot; data-mw=&quot;interface&quot;&gt;
				&lt;col class=&quot;diff-marker&quot; /&gt;
				&lt;col class=&quot;diff-content&quot; /&gt;
				&lt;col class=&quot;diff-marker&quot; /&gt;
				&lt;col class=&quot;diff-content&quot; /&gt;
				&lt;tr class=&quot;diff-title&quot; lang=&quot;yi&quot;&gt;
				&lt;td colspan=&quot;2&quot; style=&quot;background-color: #fff; color: #202122; text-align: center;&quot;&gt;→ עלטערע  ווערסיע&lt;/td&gt;
				&lt;td colspan=&quot;2&quot; style=&quot;background-color: #fff; color: #202122; text-align: center;&quot;&gt;רעוויזיע פון 13:54, 24 נאוועמבער 2022&lt;/td&gt;
				&lt;/tr&gt;
&lt;!-- diff cache key hamichlol_main_yi-mw_:diff::1.12:old-61023:rev-82290 --&gt;
&lt;/table&gt;</summary>
		<author><name>שרגא</name></author>
	</entry>
	<entry>
		<id>https://yi.hamichlol.org.il/w/index.php?title=%D7%99%D7%97%D7%99%D7%93%D7%94:ParamValidator&amp;diff=61023&amp;oldid=prev</id>
		<title>שרגא: 1 רעוויזיע אימפארטירט פֿון :wikipedia:he:יחידה:ParamValidator: ייבוא מוויקיפדיה העברית, ראה רשימת התורמים</title>
		<link rel="alternate" type="text/html" href="https://yi.hamichlol.org.il/w/index.php?title=%D7%99%D7%97%D7%99%D7%93%D7%94:ParamValidator&amp;diff=61023&amp;oldid=prev"/>
		<updated>2022-11-22T20:44:24Z</updated>

		<summary type="html">&lt;p&gt;1 רעוויזיע אימפארטירט פֿון &lt;a href=&quot;https://en.wikipedia.org/wiki/he:%D7%99%D7%97%D7%99%D7%93%D7%94:ParamValidator&quot; class=&quot;extiw&quot; title=&quot;wikipedia:he:יחידה:ParamValidator&quot;&gt;wikipedia:he:יחידה:ParamValidator&lt;/a&gt;: ייבוא מוויקיפדיה העברית, ראה רשימת התורמים&lt;/p&gt;
&lt;a href=&quot;https://yi.hamichlol.org.il/w/index.php?title=%D7%99%D7%97%D7%99%D7%93%D7%94:ParamValidator&amp;amp;diff=61023&amp;amp;oldid=82289&quot;&gt;זעט די חילוקים&lt;/a&gt;</summary>
		<author><name>שרגא</name></author>
	</entry>
	<entry>
		<id>https://yi.hamichlol.org.il/w/index.php?title=%D7%99%D7%97%D7%99%D7%93%D7%94:ParamValidator&amp;diff=82289&amp;oldid=prev</id>
		<title>yi&gt;Hasley: rv</title>
		<link rel="alternate" type="text/html" href="https://yi.hamichlol.org.il/w/index.php?title=%D7%99%D7%97%D7%99%D7%93%D7%94:ParamValidator&amp;diff=82289&amp;oldid=prev"/>
		<updated>2022-04-13T12:21:45Z</updated>

		<summary type="html">&lt;p&gt;rv&lt;/p&gt;
&lt;a href=&quot;https://yi.hamichlol.org.il/w/index.php?title=%D7%99%D7%97%D7%99%D7%93%D7%94:ParamValidator&amp;amp;diff=82289&amp;amp;oldid=61022&quot;&gt;זעט די חילוקים&lt;/a&gt;</summary>
		<author><name>yi&gt;Hasley</name></author>
	</entry>
	<entry>
		<id>https://yi.hamichlol.org.il/w/index.php?title=%D7%99%D7%97%D7%99%D7%93%D7%94:ParamValidator&amp;diff=61022&amp;oldid=prev</id>
		<title>wikipedia:he&gt;PurpleBuffalo: שינה את הגדרות ההגנה של הדף &quot;יחידה:ParamValidator&quot;: טיפול מונע (וק:במ) ([עריכה=רק עורכי תבניות או ממשק מורשים] (בלתי מוגבלת בזמן) [העברה=רק עורכי תבניות או ממשק מורשים] (בלתי מוגבלת בזמן))</title>
		<link rel="alternate" type="text/html" href="https://yi.hamichlol.org.il/w/index.php?title=%D7%99%D7%97%D7%99%D7%93%D7%94:ParamValidator&amp;diff=61022&amp;oldid=prev"/>
		<updated>2021-12-23T11:55:20Z</updated>

		<summary type="html">&lt;p&gt;שינה את הגדרות ההגנה של הדף &amp;quot;&lt;a href=&quot;/%D7%99%D7%97%D7%99%D7%93%D7%94:ParamValidator&quot; title=&quot;יחידה:ParamValidator&quot;&gt;יחידה:ParamValidator&lt;/a&gt;&amp;quot;: טיפול מונע (וק:במ) ([עריכה=רק עורכי תבניות או ממשק מורשים] (בלתי מוגבלת בזמן) [העברה=רק עורכי תבניות או ממשק מורשים] (בלתי מוגבלת בזמן))&lt;/p&gt;
&lt;p&gt;&lt;b&gt;נייער בלאַט&lt;/b&gt;&lt;/p&gt;&lt;div&gt;--[=[&lt;br /&gt;
&lt;br /&gt;
This module is based on idea and original code of [[User:IKhitron]].&lt;br /&gt;
&lt;br /&gt;
the source of this module is in //he.wikipedia.org/wiki/Module:ParamValidator&lt;br /&gt;
&lt;br /&gt;
main purpose: use &amp;quot;templatedata&amp;quot; to verify the parameters passed to a template&lt;br /&gt;
&lt;br /&gt;
Terminology: &amp;quot;numeric parameter&amp;quot; means order-based parameter. e.g. if the template is transcluded like so {{x  | k |  | a = m | b = }}&lt;br /&gt;
&amp;quot;a&amp;quot; and &amp;quot;b&amp;quot; are &amp;quot;named&amp;quot; parameters, and there are 2 &amp;quot;numeric&amp;quot;, or order based parameters, 1 and 2. &lt;br /&gt;
we say that the value of a is &amp;quot;m&amp;quot;, the value of 1 is &amp;quot;k&amp;quot;, and &amp;quot;b&amp;quot; and 2 are &amp;quot;empty&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
This module exports two functions: calculateViolations( frame, subpages ), and validateParams( frame ). &lt;br /&gt;
&lt;br /&gt;
calculateViolations( frame, subpages ) finds templatedata, in template page or in one of its subpages in the list, if provided.&lt;br /&gt;
it returns a table with the violations. if there are none, the table is empty. otherwise it has the structure&lt;br /&gt;
{&lt;br /&gt;
	violation1 = { param1 = value1, param2 = value2 },&lt;br /&gt;
	violation2 = { ... },&lt;br /&gt;
	...&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
violation1, violation2 etc. are one of the names of specific violations, as described below. &lt;br /&gt;
param1, param2 etc. are either the names of parameter passed to the template, or defined in templatedata.&lt;br /&gt;
value1, value2 etc. are the values passed to the template, or an empty string if no such parameter was passed.&lt;br /&gt;
&lt;br /&gt;
the different violations are as follow:&lt;br /&gt;
	* &amp;quot;no-templatedata&amp;quot;: 			no valid tempaltedata was found in tempalte page, or documentation subpage&lt;br /&gt;
	* &amp;quot;undeclared&amp;quot;: 				named parameters with non-empty value, does not exist in templatedata&lt;br /&gt;
	* &amp;quot;empty-undeclared&amp;quot;: 			named parameters with empty value, does not exist in templatedata&lt;br /&gt;
	* &amp;quot;undeclared-numeric&amp;quot;: 		numeric parameters with non-empty value, does not exist in templatedata&lt;br /&gt;
	* &amp;quot;empty-undeclared-numeric&amp;quot;: 	numeric parameters with empty value, does not exist in templatedata&lt;br /&gt;
	* &amp;quot;deprecated&amp;quot;:  				parameters with non-empty value, marked as &amp;quot;deprecated&amp;quot; in tempaltedata&lt;br /&gt;
	* &amp;quot;empty-deprecated&amp;quot;:  			parameters with empty value, marked as &amp;quot;deprecated&amp;quot; in tempaltedata&lt;br /&gt;
	* &amp;quot;empty-required&amp;quot;: 			missing or empty parameter marked as &amp;quot;required&amp;quot; in tempaltedata&lt;br /&gt;
	* &amp;quot;incompatible&amp;quot;:				a non-empty parameter passed to the template, incompatible with the parameter type defined in templatedata &lt;br /&gt;
	* &amp;quot;duplicate&amp;quot;:					a value is passed for the same parameter (or any of its aliases) more than once&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The second function, validateParams( frame ), can be called from the tempalte' using #invoke.&lt;br /&gt;
it expects a parameter named &amp;quot;options&amp;quot;, which contains the definition of the output. typically, it's used by placing something like so:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;includeonly&amp;gt;{{#invoke:ParamValidator | validateParams | options = {{PV default options}} }}&amp;lt;/includeonly&amp;gt;&lt;br /&gt;
&lt;br /&gt;
at the top of the template (be mindful not to add extra spaces and newlines to the template).&lt;br /&gt;
to bypass some mediawiki limitation, it is also possible to pass the options as &amp;quot;module&amp;quot;, like so (use one of the two, but not both):&lt;br /&gt;
&amp;lt;includeonly&amp;gt;{{#invoke:ParamValidator | validateParams | module_options = Module:PV default options}} }}&amp;lt;/includeonly&amp;gt;&lt;br /&gt;
&lt;br /&gt;
the first form expects a template named &amp;quot;Template:PV default options&amp;quot; which contains the options, and the 2nd form expects a module, &lt;br /&gt;
suitable for mw.loadData(), which returns a map of namespace =&amp;gt; options (i.e. { [0] = &amp;lt;options&amp;gt;, [2] =&amp;gt; &amp;lt;options&amp;gt; } .... )&lt;br /&gt;
&lt;br /&gt;
the options parameter should be a JSON-encoded string, defining the output, and some special behaviors. &lt;br /&gt;
the example above assumes that a wiki page named [[Template:PV default options]] exists, and contains valid JSON string. &lt;br /&gt;
for each of the violations defined above, &amp;quot;options&amp;quot; may define an output string, so basically, &amp;quot;options&amp;quot; looks like so:&lt;br /&gt;
{&lt;br /&gt;
	violation1: outputstring1,&lt;br /&gt;
	violation2: outputstring2,&lt;br /&gt;
	.... ,&lt;br /&gt;
	behavior1: some value,&lt;br /&gt;
	....&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
not all violations have to be defined. a violation not defined in &amp;quot;options&amp;quot; will be ignored.&lt;br /&gt;
&lt;br /&gt;
when invoked, it extract &amp;quot;subpages&amp;quot; from the options parameter, and calls:&lt;br /&gt;
 calculateViolations( frame, subpages )&lt;br /&gt;
if the returned table is empty, no violation were found, and an empty string is returned and nothing else happens.&lt;br /&gt;
&lt;br /&gt;
otherwise, for each of the violations, i.e., the keys of the returned table, when &amp;quot;options&amp;quot; contains this key,&lt;br /&gt;
the corresonding value is appended to the output.&lt;br /&gt;
&lt;br /&gt;
some further processing is done:&lt;br /&gt;
1) several tokens are replaced with calculated values. these are described below.&lt;br /&gt;
2) some &amp;quot;meta&amp;quot; violations are calculated: when any none-ignored violation occured, &lt;br /&gt;
	the &amp;quot;any&amp;quot; meta-violation is added to the output in the same way, &lt;br /&gt;
	i.e. the string keyed by &amp;quot;any&amp;quot; in the options is appended to output with appropriate substitutions.&lt;br /&gt;
	similarly, &amp;quot;multiple&amp;quot; meta-violation is created when more than one type of non-ignored violations occured.&lt;br /&gt;
3) if the output is not empty, a prefix and suffix strings are prepended and appended to it. &lt;br /&gt;
&lt;br /&gt;
these are the tokens and the replacement. &lt;br /&gt;
	* &amp;quot;templatename&amp;quot;:	full template name, including namespace.&lt;br /&gt;
	* &amp;quot;tname_naked&amp;quot;:	template name without namespace.&lt;br /&gt;
	* &amp;quot;paramname&amp;quot;:  	comma-separated list of parameters&lt;br /&gt;
	* &amp;quot;paramandvalue&amp;quot;: is replaced by comma-separated list of &amp;quot;name: value&amp;quot; pairs of parameters and values&lt;br /&gt;
the first two are applied to the whole output, including the suffux and prefix,&lt;br /&gt;
and the rest are applied to the individual violations, each with its own list of offending parameters and values.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
the rest of the if the value of some keys is null, this error condition will be ignored, and not counted when calculating &amp;quot;any&amp;quot; and &amp;quot;multiple&amp;quot; conditions.&lt;br /&gt;
&lt;br /&gt;
some other optional fields can be passed via options:&lt;br /&gt;
	* &amp;quot;doc-subpage&amp;quot;: can be either a string, or a list (in square bracktes) of strings, indicating subpages of the template &lt;br /&gt;
			that may contain templatedata. &lt;br /&gt;
	* &amp;quot;ignore&amp;quot;: list of patterns. any parameter whose name matches any pattern, will not considered in violation of any of the rules.&lt;br /&gt;
	* &amp;quot;skip-empty-numeric&amp;quot;: if a quoted number, the module will ignore non-declared empty numeric parameters up to this number&lt;br /&gt;
	* &amp;quot;wrapper-prefix&amp;quot;: openning wrapper element of outpot (defaults to &amp;quot;&amp;lt;div class = 'paramvalidator-wrapper'&amp;gt;&amp;quot;) &lt;br /&gt;
	* &amp;quot;wrapper-suffix&amp;quot;: closing wrapper element of output (defaults to &amp;quot;&amp;lt;/div&amp;gt;&amp;quot;) &lt;br /&gt;
&lt;br /&gt;
additional option parameters, named options1, options2, etc. can be passed. any entry defined in these options will &lt;br /&gt;
override the previous value. a typical use may be like so:&lt;br /&gt;
&lt;br /&gt;
	&lt;br /&gt;
typically, this JSON structure will be placed in a separate template, and retrieved for the module-use as shown above.&lt;br /&gt;
&amp;lt;includeonly&amp;gt;{{#invoke:ParamValidator | validateParams | options = {{PV default options}} | options1 = {&amp;quot;key&amp;quot;:&amp;quot;value&amp;quot;} }}&amp;lt;/includeonly&amp;gt;&lt;br /&gt;
&amp;quot;key&amp;quot; can override any of the options fields described above.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
]=]&lt;br /&gt;
&lt;br /&gt;
local util = {&lt;br /&gt;
	empty = function( s ) &lt;br /&gt;
		return s == nil  or type( s ) == 'string' and mw.text.trim( s ) == ''   &lt;br /&gt;
	end&lt;br /&gt;
	, &lt;br /&gt;
	extract_options = function( frame, optionsPrefix )&lt;br /&gt;
		optionsPrefix = optionsPrefix or 'options' &lt;br /&gt;
		&lt;br /&gt;
&lt;br /&gt;
		local options, n, more = {}&lt;br /&gt;
		if frame.args['module_options'] then&lt;br /&gt;
			local module_options = mw.loadData( frame.args['module_options'] ) &lt;br /&gt;
			if type( module_options ) ~= 'table' then return {} end&lt;br /&gt;
			local title = mw.title.getCurrentTitle()&lt;br /&gt;
			local local_ptions = module_options[ title.namespace ] or module_options[ title.nsText ] or {} &lt;br /&gt;
			for k, v in pairs( local_ptions ) do options[k] = v end&lt;br /&gt;
		end&lt;br /&gt;
		&lt;br /&gt;
		repeat&lt;br /&gt;
			ok, more = pcall( mw.text.jsonDecode, frame.args[optionsPrefix .. ( n or '' )] )&lt;br /&gt;
			if ok and type( more ) == 'table' then&lt;br /&gt;
				for k, v in pairs( more ) do options[k] = v end&lt;br /&gt;
			end&lt;br /&gt;
			n = ( n or 0 ) + 1&lt;br /&gt;
		until not ok&lt;br /&gt;
&lt;br /&gt;
		return options&lt;br /&gt;
	end&lt;br /&gt;
	, &lt;br /&gt;
	build_namelist = function ( template_name, sp )&lt;br /&gt;
		local res = { template_name }&lt;br /&gt;
		if sp then&lt;br /&gt;
			if type( sp ) == 'string' then sp = { sp } end&lt;br /&gt;
			for _, p in ipairs( sp ) do table.insert( res, template_name .. '/' .. p ) end&lt;br /&gt;
		end&lt;br /&gt;
		return res&lt;br /&gt;
	end&lt;br /&gt;
	,&lt;br /&gt;
	table_empty = function( t ) -- normally, test if next(t) is nil, but for some perverse reason, non-empty tables returned by loadData return nil...&lt;br /&gt;
		if type( t ) ~= 'table' then return true end&lt;br /&gt;
		for a, b in pairs( t ) do return false end&lt;br /&gt;
		return true&lt;br /&gt;
	end&lt;br /&gt;
	,&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
local function _readTemplateData( templateName ) &lt;br /&gt;
	local title = mw.title.makeTitle( 0, templateName )  &lt;br /&gt;
	local templateContent = title and title.exists and title:getContent() -- template's raw content&lt;br /&gt;
	local capture =  templateContent and mw.ustring.match( templateContent, '&amp;lt;templatedata%s*&amp;gt;(.*)&amp;lt;/templatedata%s*&amp;gt;' ) -- templatedata as text&lt;br /&gt;
--	capture = capture and mw.ustring.gsub( capture, '&amp;quot;(%d+)&amp;quot;', tonumber ) -- convert &amp;quot;1&amp;quot;: {} to 1: {}. frame.args uses numerical indexes for order-based params.&lt;br /&gt;
	local trailingComma = capture and mw.ustring.find( capture, ',%s*[%]%}]' ) -- look for ,] or ,} : jsonDecode allows it, but it's verbotten in json&lt;br /&gt;
	if capture and not trailingComma then return pcall( mw.text.jsonDecode, capture ) end&lt;br /&gt;
	return false&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function readTemplateData( templateName )&lt;br /&gt;
	if type( templateName ) == 'string' then &lt;br /&gt;
		templateName = { templateName, templateName .. '/' .. docSubPage }&lt;br /&gt;
	end&lt;br /&gt;
	if type( templateName ) == &amp;quot;table&amp;quot; then&lt;br /&gt;
		for _, name in ipairs( templateName ) do&lt;br /&gt;
			local td, result = _readTemplateData( name ) &lt;br /&gt;
			if td then return result end&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
	return nil&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
-- this is the function to be called by other modules. it expects the frame, and then an optional list of subpages, e.g. { &amp;quot;Documentation&amp;quot; }.&lt;br /&gt;
-- if second parameter is nil, only tempalte page will be searched for templatedata.&lt;br /&gt;
local function calculateViolations( frame, subpages )&lt;br /&gt;
-- used for parameter type validy test. keyed by TD 'type' string. values are function(val) returning bool.&lt;br /&gt;
	local type_validators = { &lt;br /&gt;
		['number'] = function( s ) return mw.language.getContentLanguage():parseFormattedNumber( s ) end&lt;br /&gt;
	}&lt;br /&gt;
	&lt;br /&gt;
	local function compatible( typ, val )&lt;br /&gt;
		local func = type_validators[typ]&lt;br /&gt;
		return type( func ) ~= 'function' or util.empty( val ) or func( val )&lt;br /&gt;
	end&lt;br /&gt;
	&lt;br /&gt;
	local function list_empty_or_contains(ar, searched) &lt;br /&gt;
		if not ar or #ar == 0 then return true end &lt;br /&gt;
		for _, val in ipairs(ar) do if val == searched then return true end end&lt;br /&gt;
		return false&lt;br /&gt;
	end&lt;br /&gt;
	&lt;br /&gt;
	local t_frame = frame:getParent()&lt;br /&gt;
	local t_args, template_name = t_frame.args, t_frame:getTitle()&lt;br /&gt;
	local td_source = util.build_namelist( template_name, subpages )&lt;br /&gt;
	local templatedata = readTemplateData( td_source )&lt;br /&gt;
	local td_params = templatedata and templatedata.params&lt;br /&gt;
	local all_aliases, all_series = {}, {}&lt;br /&gt;
	&lt;br /&gt;
	&lt;br /&gt;
	if not td_params then return { ['no-templatedata'] = { [''] = '' } } end&lt;br /&gt;
	-- from this point on, we know templatedata is valid.&lt;br /&gt;
&lt;br /&gt;
	local res = {} -- before returning to caller, we'll prune empty tables&lt;br /&gt;
&lt;br /&gt;
	-- allow for aliases&lt;br /&gt;
	for _, p in pairs( td_params ) do for _, alias in ipairs( p.aliases or {} ) do &lt;br /&gt;
		all_aliases[alias] = p&lt;br /&gt;
		if tonumber(alias) then all_aliases[tonumber(alias)] = p end&lt;br /&gt;
	end end&lt;br /&gt;
&lt;br /&gt;
	-- handle undeclared and deprecated&lt;br /&gt;
	local already_seen = {}&lt;br /&gt;
	local series = frame.args['series']&lt;br /&gt;
	for p_name, value in pairs( t_args ) do&lt;br /&gt;
		local tp_param, noval, numeric, table_name = td_params[p_name] or all_aliases[p_name], util.empty( value ), tonumber( p_name )&lt;br /&gt;
		local hasval = not noval&lt;br /&gt;
&lt;br /&gt;
		if not tp_param and series then -- 2nd chance. check to see if series&lt;br /&gt;
			for s_name, p in pairs(td_params) do &lt;br /&gt;
				if mw.ustring.match( p_name, '^' .. s_name .. '%d+' .. '$') then &lt;br /&gt;
					-- mw.log('found p_name '.. p_name .. '  s_name:' .. s_name, ' p is:', p) debugging series support&lt;br /&gt;
					tp_param = p &lt;br /&gt;
				end -- don't bother breaking. td always correct.&lt;br /&gt;
			end 				&lt;br /&gt;
		end&lt;br /&gt;
		&lt;br /&gt;
		if not tp_param then -- not in TD: this is called undeclared&lt;br /&gt;
			-- calculate the relevant table for this undeclared parameter, based on parameter and value types&lt;br /&gt;
			table_name = &lt;br /&gt;
				noval and numeric and 'empty-undeclared-numeric' or&lt;br /&gt;
				noval and not numeric and 'empty-undeclared' or&lt;br /&gt;
				hasval and numeric and 'undeclared-numeric' or&lt;br /&gt;
				'undeclared' -- tzvototi nishar.&lt;br /&gt;
		else -- in td: test for deprecation and mistype. if deprecated, no further tests&lt;br /&gt;
			table_name = tp_param.deprecated and hasval and 'deprecated' &lt;br /&gt;
				or tp_param.deprecated and noval and 'empty-deprecated' &lt;br /&gt;
				or not compatible( tp_param.type, value ) and 'incompatible' &lt;br /&gt;
				or not series and already_seen[tp_param] and hasval and 'duplicate'&lt;br /&gt;
				or hasval and not list_empty_or_contains(tp_param.suggestedvalues , value) and 'unsuggested-value'&lt;br /&gt;
&lt;br /&gt;
				&lt;br /&gt;
			already_seen[tp_param] = hasval&lt;br /&gt;
		end&lt;br /&gt;
		-- report it.&lt;br /&gt;
		if table_name then &lt;br /&gt;
			res[table_name] = res[table_name] or {}&lt;br /&gt;
			res[table_name][p_name] = value &lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
	&lt;br /&gt;
	-- test for empty/missing paraeters declared &amp;quot;required&amp;quot; &lt;br /&gt;
	for p_name, param in pairs( td_params ) do &lt;br /&gt;
		if param.required and util.empty( t_args[p_name] ) then&lt;br /&gt;
			local is_alias&lt;br /&gt;
			for _, alias in ipairs( param.aliases or {} ) do is_alias = is_alias or not util.empty( t_args[alias] ) end&lt;br /&gt;
			if not is_alias then&lt;br /&gt;
				res['empty-required'] = res['empty-required'] or {} &lt;br /&gt;
				res['empty-required'][p_name] = '' &lt;br /&gt;
			end&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
	&lt;br /&gt;
	return res&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
-- wraps report in hidden frame&lt;br /&gt;
local function wrapReport(report, template_name, options)&lt;br /&gt;
	if util.empty( report ) then return '' end&lt;br /&gt;
	local naked = mw.title.new( template_name )['text'] &lt;br /&gt;
	&lt;br /&gt;
	mw.log(report)&lt;br /&gt;
	report = ( options['wrapper-prefix'] or &amp;quot;&amp;lt;div class = 'paramvalidator-wrapper'&amp;gt;&amp;lt;span class='paramvalidator-error'&amp;gt;&amp;quot; )&lt;br /&gt;
			.. report&lt;br /&gt;
			.. ( options['wrapper-suffix'] or &amp;quot;&amp;lt;/span&amp;gt;&amp;lt;/div&amp;gt;&amp;quot; )&lt;br /&gt;
	&lt;br /&gt;
	report = mw.ustring.gsub( report, 'tname_naked', naked )&lt;br /&gt;
	report = mw.ustring.gsub( report, 'templatename', template_name )&lt;br /&gt;
	return report&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
-- this is the &amp;quot;user&amp;quot; version, called with {{#invoke:}} returns a string, as defined by the options parameter&lt;br /&gt;
local function validateParams( frame )&lt;br /&gt;
	&lt;br /&gt;
	-- for purple pages:&lt;br /&gt;
	if frame:getParent().args['skip parameters validation'] then return '[[ קטגוריה:דפים עם שגיאות פרמטריות שקיבלו חנינה]]' end&lt;br /&gt;
	local options, report, template_name = util.extract_options( frame ), '', frame:getParent():getTitle()&lt;br /&gt;
&lt;br /&gt;
	local ignore = function( p_name )&lt;br /&gt;
		for _, pattern in ipairs( options['ignore'] or {} ) do&lt;br /&gt;
			if mw.ustring.match( p_name, '^' .. pattern .. '$' ) then return true end&lt;br /&gt;
		end&lt;br /&gt;
		return false&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	local replace_macros = function( s, param_names )&lt;br /&gt;
		local function concat_and_escape( t ) &lt;br /&gt;
			local s = table.concat( t, ', ' )&lt;br /&gt;
			return ( mw.ustring.gsub( s, '%%', '%%%%' ) )&lt;br /&gt;
		end&lt;br /&gt;
		&lt;br /&gt;
		if s and ( type( param_names ) == 'table' ) then&lt;br /&gt;
			local k_ar, kv_ar = {}, {}&lt;br /&gt;
			for k, v in pairs( param_names ) do&lt;br /&gt;
				table.insert( k_ar, k )&lt;br /&gt;
				table.insert( kv_ar, k .. ': ' .. v)&lt;br /&gt;
			end&lt;br /&gt;
			s = mw.ustring.gsub( s, 'paramname', concat_and_escape( k_ar ) ) &lt;br /&gt;
			s = mw.ustring.gsub( s, 'paramandvalue', concat_and_escape( kv_ar ) )&lt;br /&gt;
		end&lt;br /&gt;
		return s&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	local report_params = function( key, param_names )&lt;br /&gt;
		local res = replace_macros( options[key], param_names )&lt;br /&gt;
		report = report ..  ( res or '' )&lt;br /&gt;
		return res&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	-- no option no work.&lt;br /&gt;
	if util.table_empty( options ) then return '' end&lt;br /&gt;
&lt;br /&gt;
	-- get the errors.&lt;br /&gt;
	local violations = calculateViolations( frame, options['doc-subpage'] )&lt;br /&gt;
	-- special request of bora: use skip_empty_numeric&lt;br /&gt;
	if violations['empty-undeclared-numeric'] then &lt;br /&gt;
		for i = 1, tonumber( options['skip-empty-numeric'] ) or 0 do &lt;br /&gt;
			violations['empty-undeclared-numeric'][i] = nil &lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
	&lt;br /&gt;
	-- handle ignore list, and prune empty violations - in that order!&lt;br /&gt;
	local offenders = 0&lt;br /&gt;
	for name, tab in pairs( violations ) do &lt;br /&gt;
		-- remove ignored parameters from all violations&lt;br /&gt;
		for pname in pairs( tab ) do if ignore( pname ) then tab[pname] = nil end end&lt;br /&gt;
		-- prune empty violations&lt;br /&gt;
		if util.table_empty( tab ) then violations[name] = nil end&lt;br /&gt;
	-- WORK IS DONE. report the errors.&lt;br /&gt;
	-- if report then count it.&lt;br /&gt;
		if violations[name] and report_params( name, tab ) then offenders = offenders + 1 end &lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	if offenders &amp;gt; 1 then report_params( 'multiple' ) end&lt;br /&gt;
	if offenders ~= 0 then report_params( 'any' ) end -- could have tested for empty( report ), but since we count them anyway...&lt;br /&gt;
	return wrapReport(report, template_name, options)&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
return {&lt;br /&gt;
	['validateparams'] = validateParams,&lt;br /&gt;
	['calculateViolations'] = calculateViolations,&lt;br /&gt;
	['wrapReport'] = wrapReport&lt;br /&gt;
}&lt;/div&gt;</summary>
		<author><name>wikipedia:he&gt;PurpleBuffalo</name></author>
	</entry>
</feed>