Module:Template wrapper/doc: Difference between revisions

From WikiMD's Wellness Encyclopedia
m 1 revision imported
 
No edit summary
 
Line 1: Line 1:
<!-- Please place categories where indicated at the bottom of this page and interwikis at Wikidata (see [[Wikipedia:Wikidata]]) -->
require('strict');


{{high-use}}
local error_msg = '<span style=\"font-size:100%\" class=\"error\"><code style=\"color:inherit; border:inherit; padding:inherit;\">&#124;_template=</code> missing or empty</span>';


This module is to be used in [[Wikipedia:Wrapper templates|wrapper templates]] to allow those templates to provide default parameter values and allow editors to pass additional parameters to the underlying working template.


When writing a wrapper template, give this module all of the normally required default parameters necessary to use the wrapper template in its base form. Editors then use the wrapper template as-is or may supply additional wrapper and canonical parameters. Any of the canonical parameters supported by the working template may be added to the wrapper template or supplied by editors in article space. When an editor supplies a parameter that has a default value in the wrapper template, the editor-supplied value overrides the default. When it is necessary to remove a default parameter, editors may set the parameter value to the special keyword <code>unset</code> which will cause this wrapper module to erase the wrapper template's default value for that parameter. This module discards empty named parameters.
--[[--------------------------< I S _ I N _ T A B L E >--------------------------------------------------------


Positional parameters are not normally passed on to the working template.  Setting {{para|_include-positional|yes}} will pass all positional parameters to the working template.  Positional parameters cannot be excluded; positional parameters may be <code>unset</code>.
scan through tbl looking for value; return true if found, false else


Parameters that are used only by the wrapper should be either positional ({{param|{{var|n}}}}) or listed in {{para|_exclude}} (a comma-separated list of named parameters). This module will not pass <code>_excluded</code> parameters to the working template.
]]


== Usage ==
local function is_in_table (tbl, value)
    for k, v in pairs (tbl) do
        if v == value then return true end
    end
    return false;
end


<code><nowiki>{{#invoke:</nowiki>{{BASEPAGENAME}}|wrap|_template={{var|working template}}|_exclude={{var|named parameter}}, {{var|named parameter}}, ...|_reuse={{var|named parameter}}, {{var|named parameter}}, ...|_alias-map={{var|alias parameter}}:{{var|canonical parameter}}|_include-positional=yes|&lt;{{var|default parameter}}>|&lt;{{var|default parameter}}>|...}}</code>


;Control parameters
--[[--------------------------< A D D _ P A R A M E T E R >----------------------------------------------------
:{{para|_template}} – (required) the name, without namespace, of the working template (the template that is wrapped); see §[[#template|_template]] below
:{{para|_exclude}} – comma-separated list of parameter names used by the wrapper template that are not to be passed to the working template; see §[[#exclude|_exclude]] below
:{{para|_reuse}} – comma-separated list of canonical names that have meaning to both the wrapper template and to the working template; see §[[#reuse|_reuse]] below
:{{para|_alias-map}} – comma-separated list of wrapper-template parameter names that are to be treated as aliases of specified working template canonical parameters; see §[[#alias-map|_alias-map]] below
:{{para|_include-positional}} – pass all positional parameters to the working template; see §[[#include-positional|_include-positional]] below


;Definitions
adds parameter name and its value to args table according to the state of boolean list argument; kv pair for
:canonical parameter – a parameter supported and used by the working template
template execution; k=v string for template listing.
:wrapper parameter – a parameter used by the wrapper template; may provide data for canonical parameters or control other aspects of the wrapper template
:alias parameter – a wrapper parameter that is contextually meaningful to the wrapper template but must be renamed to a canonical parameter for use by the working template
:reused parameter – a parameter that is shared by both wrapper and working templates and has been modified by wrapper template
:default parameter – a canonical parameter given a default value in the wrapper template


{| class="nowrap"
]]
|+parameter processing
!style="border:1px solid black"|wrapper<br />template !! !!style="border:1px solid black" colspan="11"|Module:Template wrapper !! !! style="border:1px solid black"|working<br />template
|-
| style="border: 1px solid black;"|{{para|plain=yes|{{var|canonical parameters}}}}||&nbsp;→&nbsp;||style="text-align: center;"|–––––––→||&nbsp;→&nbsp;||style="text-align: center;"|–––––––→||&nbsp;→&nbsp;||style="text-align: center;"|–––––––→||&nbsp;→&nbsp;||style="text-align: center;"|–––––––→||&nbsp;→&nbsp;||style="text-align: center;"|–––––––→||&nbsp;→&nbsp;||style="border: 2px solid black;" rowspan="5"|filter<br />exclued<br />parameters|| ||style="border: 2px solid black;" rowspan="10"|working<br />template
|-
| style="border: 1px solid black;"|{{para|plain=yes|{{var|wrapper parameters}}}}||&nbsp;→&nbsp;||style="text-align: center;"|–––––––→||&nbsp;→&nbsp;||style="text-align: center;"|–––––––→||&nbsp;→&nbsp;||style="text-align: center;"|–––––––→||&nbsp;→&nbsp;||style="text-align: center;"|–––––––→||&nbsp;→&nbsp;||style="text-align: center;"|–––––––→||&nbsp;→&nbsp;
|-
|&nbsp;|| || style="border: 1px solid black;"|{{para|plain=yes|[[#_exclude|_exclude]]}}||&nbsp;→&nbsp;||style="text-align: center;"|–––––––→||&nbsp;→&nbsp;||style="text-align: center;"|–––––––→||&nbsp;→&nbsp;||style="text-align: center;"|–––––––→||&nbsp;→&nbsp;||style="text-align: center;"|–––––––→||&nbsp;→&nbsp;||&nbsp;→&nbsp;
|-
|&nbsp;|| || style="border: 1px solid black;"|{{para|plain=yes|[[#_include-positional|_include-positional]]}}||&nbsp;→&nbsp;||style="text-align: center;"|–––––––→||&nbsp;→&nbsp;||style="text-align: center;"|–––––––→||&nbsp;→&nbsp;||style="text-align: center;"|–––––––→||&nbsp;→&nbsp;||style="text-align: center;"|–––––––→||&nbsp;→&nbsp;
|-
|&nbsp;|| || style="border: 1px solid black;"|{{para|plain=yes|[[#_alias-map|_alias-map]]}}||&nbsp;→&nbsp;||style="border: 2px solid black;" rowspan="3"|convert alias<br />parameters to<br />canonical<br />parameters||&nbsp;→&nbsp;||style="border: 1px solid black;" rowspan="2"|{{para|plain=yes|{{var|canonical parameters}}}}||&nbsp;→&nbsp;||style="text-align: center;"|–––––––→||&nbsp;→&nbsp;||style="text-align: center;"|–––––––→||&nbsp;→&nbsp;|| ||&nbsp;→&nbsp;
|-
|&nbsp;|| || || ||&nbsp;→&nbsp;||&nbsp;→&nbsp;||style="border: 2px solid black;" rowspan="4"|modify<br />reused<br />canonical<br />parameters
|-
| style="border: 1px solid black;"|{{para|plain=yes|{{var|alias parameters}}}}||&nbsp;→&nbsp;||style="text-align: center;"|–––––––→||&nbsp;→&nbsp;|| || || ||&nbsp;→&nbsp;||style="border: 1px solid black;"|{{para|plain=yes|{{var|reused parameters}}}}||&nbsp;→&nbsp;||style="text-align: center;"|–––→||&nbsp;→&nbsp;
|-
|&nbsp;|| || style="border: 1px solid black;"|{{para|plain=yes|[[#_reuse|_reuse]]}}||&nbsp;→&nbsp;||style="text-align: center;"|–––––––→||&nbsp;→&nbsp;||style="text-align: center;"|–––––––→||&nbsp;→&nbsp;
|-
| style="border: 1px solid black;"|{{para|plain=yes|{{var|canonical parameters}}}}||&nbsp;→&nbsp;||style="text-align: center;"|–––––––→||&nbsp;→&nbsp;||style="text-align: center;"|–––––––→||&nbsp;→&nbsp;||style="text-align: center;"|–––––––→||&nbsp;→&nbsp;
|-
|&nbsp;|| || style="border: 1px solid black;"|{{para|plain=yes|{{var|default parameters}}}}||&nbsp;→&nbsp;||style="text-align: center;"|–––––––→||&nbsp;→&nbsp;||style="text-align: center;"|–––––––→||&nbsp;→&nbsp;||style="text-align: center;"|–––––––→||&nbsp;→&nbsp;||style="text-align: center;"|–––––––→||&nbsp;→&nbsp;||style="text-align: center;"|–––→||&nbsp;→&nbsp;
|}


==Parameter details==
local function add_parameter (k, v, args, list)
===_template===
if list then
The only required parameter, {{para|_template}} supplies the name, without namespace, of the working template (the template that is wrapped).  If this parameter is omitted, Module:Template wrapper will emit the error message:
table.insert( args, table.concat ({k, '=', v})); -- write parameter names and values to args table as string
:<span style="font-size:100%" class="error"><code style="color:inherit; border:inherit; padding:inherit;">&#124;_template=</code> missing or empty</span>
else
args[k] = v; -- copy parameters to args table
end
end


===_alias-map===
{{para|_alias-map}} takes a comma-separated list of wrapper-template parameters that are to be treated as aliases of specified working template canonical parameters.  Each mapping element of the list has the form:
:<code>&lt;{{var|from}}>:&lt;{{var|to}}></code> – where: <code>&lt;{{var|from}}></code> is a wrapper parameter name and <code>&lt;{{var|to}}></code> is a canonical parameter name
In this example, it may be preferable for a wrapper template to use {{para|assessor}} which may be unknown to the working template but the working template may have an equivalent {{para|author}} so in the <code><nowiki>{{#invoke:}}</nowiki></code> we would write:
:{{para|_alias-map|assessor:author}}
Positional parameters may also be mapped to canonical parameters:
:{{para|_alias-map|1:author, 2:title, 3:language}}
Enumerated wrapper parameters may be mapped to enumerated canonical parameters using the <code>#</code> enumerator specifier:
:{{para|_alias-map|assessor#:author#}}
Given the above example, {{para|assessor2}} will map to {{para|author2}}; also, {{para|assessor}} and {{para|assessor1}} will map to {{para|author1}}


Multiple wrapper parameters can map to a single canonical parameter:
--[[--------------------------< A L I A S _ M A P _ G E T >----------------------------------------------------
:{{para|_alias-map|1:author, assessor:author}}
Wrapper parameters listed in {{para|alias-map}} are not passed to the working template.  Mapping positional parameters when {{para|_include-positional|yes}} may give undesirable results.  {{para|_alias-map|1:author}} and {{para|_include-positional|yes}} will cause all other positional parameters to be passed to the working template as is: wrapper template <code><nowiki>{{{2}}}</nowiki></code> becomes working template <code><nowiki>{{{2}}}</nowiki></code>, etc; working template will not get <code><nowiki>{{{1}}}</nowiki></code> though it will get {{para|author}}.


===_reuse===
returns a table of local template (parent frame) parameter names and the target template names that match where
{{para|_reuse}} takes a comma-separated list of canonical parameters that have meaning to both the wrapper template and to the working template
in [key]=<value> pairs where:
[key] is local template parameter name (an alias)
<value> is target template parameter name (the canonical parameter name used in the working template)


In the simplest cases, a canonical parameter passed into the wrapper template overrides a default parameter provided in the wrapper template.  Sometimes a wrapper parameter is the same as a canonical parameter and the wrapper template needs to modify the parameter value before it is passed to the working template.  In this example, {{para|title}} is both a wrapper parameter and a canonical parameter that the wrapper template needs to modify before passing to the working template.  To do this we first write:
The parameter |_alias-map= has the form:
:{{para|_reuse|title}}
|_alias-map=<list>
then, in the wrapper template's <code><nowiki>{{#invoke:Template wrapper|wrap|_template=...|...}}</nowiki></code> we write:
where <list> is a comma-separated list of alias / canonical parameter name pairs in the form
:{{para|title|Modified <nowiki>{{{title}}}</nowiki>}}
<from> : <to>
where:
<from> is the local template's parameter name (alias)
<to> is the target template's parameter name (canonical)
for enumerated parameters place an octothorp (#) where the enumerator digits are placed in the parameter names:
<from#> : <to#>


_reused parameters cannot be overridden.
]]


===_exclude===
local function alias_map_get (_alias_map)
{{para|_exclude}} takes a comma-separated list of parameters used by the wrapper template that are not to be passed to the working template. This list applies to all wrapper and canonical parameters (including those canonical parameters that are renamed alias parameters) received from the wrapper template.
local T = mw.text.split (_alias_map, '%s*,%s*'); -- convert the comma-separated list into a table of alias pairs
local mapped_aliases = {}; -- mapped aliases will go here
local l_name, t_name; -- parameter names
for _, alias_pair in ipairs (T) do -- loop through the table of alias pairs
l_name, t_name = alias_pair:match ('(.-)%s*:%s*(.+)'); -- from each pair, get local and target parameter names
if l_name and t_name then -- if both are set
if tonumber (l_name) then
l_name = tonumber (l_name); -- convert number-as-text to a number
end
mapped_aliases[l_name] = t_name; -- add them to the map table
end
end


As an example, a wrapper template might use {{para|id}} to supply a portion of the value assigned to default parameter {{para|url}} so we would write:
return mapped_aliases;
:{{para|_exclude|id}}
end
then, in the wrapper template's <code><nowiki>{{#invoke:Template wrapper|wrap|_template=...|...}}</nowiki></code> we write:
:{{para|url|<nowiki>https://example.com/{{{id}}}</nowiki>}}
The modified {{para|url}} value is passed on to working template but {{para|id}} and its value is not.


_reused and default parameters cannot be excluded.


===_include-positional===
--[[--------------------------< F R A M E _ A R G S _ G E T >--------------------------------------------------
{{para|_include-positional}} is a boolean parameter that takes only one value: <code>yes</code>; the default (empty, missing) is <code>no</code> (positional parameters normally excluded).  When set to <code>yes</code>, Module:Template wrapper will pass all positional parameters to the working template.


See also §[[#_alias-map|_alias-map]].
Fetch the wrapper template's 'default' and control parameters; adds default parameters to args


===Overriding default parameters===
returns content of |_template= parameter (name of the working template); nil else
Editors may override default parameters by simply setting the default parameter to the desired value in the wrapper template.  This module ignores empty parameters (those parameters that are named but which do not have an assigned value).  When it is desirable to override a default parameter to no value, use the special keyword <code>unset</code>.  Default parameters with this value are passed to the working template as empty (no assigned value) parameters.


_reused parameters cannot be <code>unset</code> or overridden.
]]


==Debugging/documentation mode==
local function frame_args_get (frame_args, args, list)
This module has two entry points.  A wrapper template might use a module <code><nowiki>{{#invoke:}}</nowiki></code> written like this:
local template;
:<code><nowiki>{{#invoke:</nowiki>{{BASEPAGENAME}}|<nowiki>{{#if:{{{_debug|}}}|list|wrap}}</nowiki>|_template=<{{var|working template}}>|_exclude=_debug, ...|...}}</code>
where the {{para|_debug}} wrapper parameter, set to any value, will cause the module to render the call to the working template without actually calling the working template.


As an example, {{tlx|cite wikisource}} is a wrapper template that uses {{tlx|citation}} as its working template.  {{tld|cite wikisource}} accepts positional parameters but {{tld|citation}} does not so the wrapper template must convert the positional parameters to named parameters which it does using the {{para|_alias-map}} parameter:
for k, v in pairs (frame_args) do -- here we get the wrapper template's 'default' parameters
:<syntaxhighlight lang="wikitext">{{#invoke:template wrapper|{{#if:{{{_debug|}}}|list|wrap}}|_template=citation
if 'string' == type (k) and (v and ('' ~= v)) then -- do not pass along positional or empty parameters
  |_exclude=..., _debug <!-- unnecessary detail omitted -->
if '_template' == k then
  |_alias-map=1:title, 2:author, 3:language</syntaxhighlight>
template = v; -- save the name of template that we are wrapping
This example uses positional parameters and sets {{para|_debug|yes}} to show that the {{tld|citation}} template is correctly formed:
elseif '_exclude' ~= k and '_reuse' ~= k and '_include-positional' ~= k  and '_alias-map' ~= k then -- these already handled so ignore here;
:<code><nowiki>{{cite wikisource|Sentido y sensibilidad|Jane Austen|es|_debug=yes}}</nowiki></code>
add_parameter (k, v, args, list); -- add all other parameters to args in the style dictated by list
::{{cite wikisource|Sentido y sensibilidad|Jane Austen|es|_debug=yes}}
end
and, with {{para|_debug}} unset:
end
:<code><nowiki>{{cite wikisource|Sentido y sensibilidad|Jane Austen|es|_debug=}}</nowiki></code>
end
::{{cite wikisource|Sentido y sensibilidad|Jane Austen|es|_debug=}}
The {{para|_debug}} name is chosen here for convenience but may be anything so long as it matches the <code><nowiki>{{#if:}}</nowiki></code> in the <code><nowiki>{{#invoke:}}</nowiki></code>.


You may also call the <code>link</code> function to get something like the left-hand side of [[Template:yy]]. This is essentially the <code>list</code> function with the template name turned into a link.
return template; -- return contents of |_template= parameter
{{yytop|headers=no}}
end
{{yy|User in New Zealand|4}}
{{yybottom}}


<includeonly>{{sandbox other||
<!-- Categories below this line, please; interwikis at Wikidata -->


}}</includeonly>
--[=[--------------------------< P F R A M E _ A R G S _ G E T >------------------------------------------------
 
Fetches the wrapper template's 'live' parameters; adds live parameters that aren't members of the exclude table to
args table; positional parameters may not be excluded
 
no return value
 
]=]
 
local function pframe_args_get (pframe_args, args, exclude, _include_positional, list)
for k, v in pairs (pframe_args) do
if 'string' == type (k) and not is_in_table (exclude, k) then -- do not pass along excluded parameters
if v and ('' ~= v) then -- pass along only those parameters that have assigned values
if 'unset' == v:lower() then -- special keyword to unset 'default' parameters set in the wrapper template
v = ''; -- unset the value in the args table
end
add_parameter (k, v, args, list) -- add all other parameters to args in the style dictated by list; alias map only supported for local-template parameters
end
end
end
 
if _include_positional then
for i, v in ipairs (pframe_args) do -- pass along positional parameters
if 'unset' == v:lower() then -- special keyword to unset 'default' parameters set in the wrapper template
v = ''; -- unset the value in the args table
end
add_parameter (i, v, args, list);
end
end
end
 
 
--[[--------------------------< _ M A I N >--------------------------------------------------------------------
 
Collect the various default and live parameters into args styled according to boolean list.
 
returns name of the working or listed template or nil for an error message
 
]]
 
local function _main (frame, args, list)
local template;
local exclude = {}; -- table of parameter names for parameters that are not passed to the working template
local reuse_list = {}; -- table of pframe parameter names whose values are modified before they are passed to the working template as the same name
local alias_map = {}; -- table that maps parameter aliases to working template canonical parameter names
local _include_positional;
if frame.args._exclude and ('' ~= frame.args._exclude) then -- if there is |_exclude= and it's not empty
exclude = mw.text.split (frame.args._exclude, "%s*,%s*"); -- make a table from its contents
end
-- TODO: |_reuse= needs a better name (|_reuse=)
if frame.args._reuse and ('' ~= frame.args._reuse) then -- if there is |_reuse= and it's not empty
reuse_list = mw.text.split (frame.args._reuse, "%s*,%s*"); -- make a table from its contents
end
 
if frame.args['_alias-map'] and ('' ~= frame.args['_alias-map']) then -- if there is |_alias-map= and it's not empty
alias_map = alias_map_get (frame.args['_alias-map']); -- make a table from its contents
end
 
template = frame_args_get (frame.args, args, list); -- get parameters provided in the {{#invoke:template wrapper|...|...}}
if nil == template or '' == template then -- this is the one parameter that is required by this module
return nil; -- not present, tell calling function to emit an error message
end
_include_positional = 'yes' == frame.args['_include-positional']; -- when true pass all positional parameters along with non-excluded named parameters to ...
-- ... the working template; positional parameters are not excludable
local _pframe_args = frame:getParent().args; -- here we get the wrapper template's 'live' parameters from pframe.args
local pframe_args = {}; -- a local table that we can modify
 
for k, v in pairs (_pframe_args) do -- make a copy that we can modify
pframe_args[k] = v;
end
-- here we look for pframe parameters that are aliases of canonical parameter names; when found
-- we replace the alias with the canonical.  We do this here because the reuse_list works on
-- canonical parameter names so first we convert alias parameter names to canonical names and then
-- we remove those canonical names from the pframe table that are reused (provided to the working
-- template through the frame args table)
 
for k, v in pairs (alias_map) do -- k is alias name, v is canonical name
if pframe_args[k] then -- if pframe_args has parameter with alias name
pframe_args[v] = _pframe_args[k]; -- create new canonical name with alias' value
pframe_args[k] = nil; -- unset the alias
end
end
 
for k, v in pairs (pframe_args) do -- do enumerated parameter alias -> canonical translation
if 'string' == type (k) then -- only named parameters can be enumerated
if alias_map[k..'#'] then -- non-enumerated alias matches enumerated parameter pattern? enumerator at end only
pframe_args[alias_map[k..'#']:gsub('#', '')] = v; -- remove '#' and copy parameter to pframe_args table
pframe_args[k] = nil; -- unset the alias
elseif k:match ('%d+') then -- if this parameter name contains digits
local temp = k:gsub ('%d+', '#'); -- make a copy; digits replaced with single '#'
local enum = k:match ('%d+'); -- get the enumerator
if alias_map[temp] then -- if this parameter is a recognized enumerated alias
pframe_args[alias_map[temp]:gsub('#', enum)] = v; -- use canonical name and replace '#' with enumerator and add to pframe_args
pframe_args[k] = nil; -- unset the alias
end
end
end
end
 
-- pframe parameters that are _reused are 'reused' have the form something like this:
-- |chapter=[[wikisource:{{{chapter}}}|{{{chapter}}}]]
-- where a parameter in the wrapping template is modified and then passed to the working template
-- using the same parameter name (in this example |chapter=)
 
-- remove parameters that will be reused
for k, v in ipairs (reuse_list) do -- k is numerical index, v is canonical parameter name to ignore
if pframe_args[v] then -- if pframe_args has parameter that should be ignored
pframe_args[v] = nil; -- unset the ignored parameter
end
end
 
pframe_args_get (pframe_args, args, exclude, _include_positional, list); -- add parameters and values to args that are not listed in the exclude table
 
return template; -- args now has all default and live parameters, return working template name
end
 
 
--[[--------------------------< W R A P >----------------------------------------------------------------------
 
Template entry point.  Call this function to 'execute' the working template
 
]]
 
local function wrap (frame)
local args = {}; -- table of default and live parameters and their values to be passed to the wrapped template
local template; -- the name of the working template
 
template = _main (frame, args, false); -- get default and live parameters and the name of the working template
if not template then -- template name is required
return error_msg; -- emit error message and abandon if template name not present
end
 
return frame:expandTemplate {title=template, args=args}; -- render the working template
end
 
 
--[[--------------------------< L I S T >----------------------------------------------------------------------
 
Template entry point.  Call this function to 'display' the source for the working template.  This function added
as a result of a TfD here: Wikipedia:Templates_for_discussion/Log/2018_April_28#Module:PassArguments
 
This function replaces a similarly named function which was used in {{cite compare}} and {{cite compare2}}
 
Values in the args table are numerically indexed strings in the form 'name=value'
 
]]
 
local function list(frame, do_link)
local args = {}; -- table of default and live parameters and their values to be passed to the listed template
local template; -- the name of the listed template
 
template = _main (frame, args, true); -- get default and live parameters and the name of the listed template
if not template then -- template name is required
return error_msg; -- emit error message and abandon if template name not present
end
if do_link then
template = ('[[%s|%s]]'):format(frame:expandTemplate{ title='Transclude', args = {template} }, template)
end
table.sort(args)
for i = 1, #args do
local stripped = args[i]:match('^' .. i .. '=([^=]*)$')
if stripped then args[i] = stripped else break end
end
return frame:preprocess(table.concat({
'<code style="color:inherit; background:inherit; border:none;">&#123;&#123;',
template,
('<wbr><nowiki>|%s</nowiki>'):rep(#args):format(unpack(args)), '&#125;&#125;</code>'})); -- render the template
end
 
local function link (frame)
return list(frame, true)
end
 
--[[--------------------------< E X P O R T E D  F U N C T I O N S >------------------------------------------
]]
 
return {
link = link,
list = list,
wrap = wrap,
};

Latest revision as of 05:00, 7 January 2025

require('strict');

local error_msg = '|_template= missing or empty';


--[[--------------------------< I S _ I N _ T A B L E >--------------------------------------------------------

scan through tbl looking for value; return true if found, false else

]]

local function is_in_table (tbl, value)

   for k, v in pairs (tbl) do
       if v == value then return true end
   end
   return false;

end


--[[--------------------------< A D D _ P A R A M E T E R >----------------------------------------------------

adds parameter name and its value to args table according to the state of boolean list argument; kv pair for template execution; k=v string for template listing.

]]

local function add_parameter (k, v, args, list) if list then table.insert( args, table.concat ({k, '=', v})); -- write parameter names and values to args table as string else args[k] = v; -- copy parameters to args table end end


--[[--------------------------< A L I A S _ M A P _ G E T >----------------------------------------------------

returns a table of local template (parent frame) parameter names and the target template names that match where in [key]=<value> pairs where: [key] is local template parameter name (an alias) <value> is target template parameter name (the canonical parameter name used in the working template)

The parameter |_alias-map= has the form: |_alias-map=<list> where <list> is a comma-separated list of alias / canonical parameter name pairs in the form <from> : <to> where: <from> is the local template's parameter name (alias) <to> is the target template's parameter name (canonical) for enumerated parameters place an octothorp (#) where the enumerator digits are placed in the parameter names: <from#> : <to#>

]]

local function alias_map_get (_alias_map) local T = mw.text.split (_alias_map, '%s*,%s*'); -- convert the comma-separated list into a table of alias pairs local mapped_aliases = {}; -- mapped aliases will go here local l_name, t_name; -- parameter names

for _, alias_pair in ipairs (T) do -- loop through the table of alias pairs l_name, t_name = alias_pair:match ('(.-)%s*:%s*(.+)'); -- from each pair, get local and target parameter names if l_name and t_name then -- if both are set if tonumber (l_name) then l_name = tonumber (l_name); -- convert number-as-text to a number end mapped_aliases[l_name] = t_name; -- add them to the map table end end

return mapped_aliases; end


--[[--------------------------< F R A M E _ A R G S _ G E T >--------------------------------------------------

Fetch the wrapper template's 'default' and control parameters; adds default parameters to args

returns content of |_template= parameter (name of the working template); nil else

]]

local function frame_args_get (frame_args, args, list) local template;

for k, v in pairs (frame_args) do -- here we get the wrapper template's 'default' parameters if 'string' == type (k) and (v and ( ~= v)) then -- do not pass along positional or empty parameters if '_template' == k then template = v; -- save the name of template that we are wrapping elseif '_exclude' ~= k and '_reuse' ~= k and '_include-positional' ~= k and '_alias-map' ~= k then -- these already handled so ignore here; add_parameter (k, v, args, list); -- add all other parameters to args in the style dictated by list end end end

return template; -- return contents of |_template= parameter end


--[=[--------------------------< P F R A M E _ A R G S _ G E T >------------------------------------------------

Fetches the wrapper template's 'live' parameters; adds live parameters that aren't members of the exclude table to args table; positional parameters may not be excluded

no return value

]=]

local function pframe_args_get (pframe_args, args, exclude, _include_positional, list) for k, v in pairs (pframe_args) do if 'string' == type (k) and not is_in_table (exclude, k) then -- do not pass along excluded parameters if v and ( ~= v) then -- pass along only those parameters that have assigned values if 'unset' == v:lower() then -- special keyword to unset 'default' parameters set in the wrapper template v = ; -- unset the value in the args table end add_parameter (k, v, args, list) -- add all other parameters to args in the style dictated by list; alias map only supported for local-template parameters end end end

if _include_positional then for i, v in ipairs (pframe_args) do -- pass along positional parameters if 'unset' == v:lower() then -- special keyword to unset 'default' parameters set in the wrapper template v = ; -- unset the value in the args table end add_parameter (i, v, args, list); end end end


--[[--------------------------< _ M A I N >--------------------------------------------------------------------

Collect the various default and live parameters into args styled according to boolean list.

returns name of the working or listed template or nil for an error message

]]

local function _main (frame, args, list) local template; local exclude = {}; -- table of parameter names for parameters that are not passed to the working template local reuse_list = {}; -- table of pframe parameter names whose values are modified before they are passed to the working template as the same name local alias_map = {}; -- table that maps parameter aliases to working template canonical parameter names local _include_positional;

if frame.args._exclude and ( ~= frame.args._exclude) then -- if there is |_exclude= and it's not empty exclude = mw.text.split (frame.args._exclude, "%s*,%s*"); -- make a table from its contents end -- TODO: |_reuse= needs a better name (|_reuse=) if frame.args._reuse and ( ~= frame.args._reuse) then -- if there is |_reuse= and it's not empty reuse_list = mw.text.split (frame.args._reuse, "%s*,%s*"); -- make a table from its contents end

if frame.args['_alias-map'] and ( ~= frame.args['_alias-map']) then -- if there is |_alias-map= and it's not empty alias_map = alias_map_get (frame.args['_alias-map']); -- make a table from its contents end

template = frame_args_get (frame.args, args, list); -- get parameters provided in the Script error: The function "..." does not exist. if nil == template or == template then -- this is the one parameter that is required by this module return nil; -- not present, tell calling function to emit an error message end

_include_positional = 'yes' == frame.args['_include-positional']; -- when true pass all positional parameters along with non-excluded named parameters to ... -- ... the working template; positional parameters are not excludable

local _pframe_args = frame:getParent().args; -- here we get the wrapper template's 'live' parameters from pframe.args local pframe_args = {}; -- a local table that we can modify

for k, v in pairs (_pframe_args) do -- make a copy that we can modify pframe_args[k] = v; end

-- here we look for pframe parameters that are aliases of canonical parameter names; when found -- we replace the alias with the canonical. We do this here because the reuse_list works on -- canonical parameter names so first we convert alias parameter names to canonical names and then -- we remove those canonical names from the pframe table that are reused (provided to the working -- template through the frame args table)

for k, v in pairs (alias_map) do -- k is alias name, v is canonical name if pframe_args[k] then -- if pframe_args has parameter with alias name pframe_args[v] = _pframe_args[k]; -- create new canonical name with alias' value pframe_args[k] = nil; -- unset the alias end end

for k, v in pairs (pframe_args) do -- do enumerated parameter alias -> canonical translation if 'string' == type (k) then -- only named parameters can be enumerated if alias_map[k..'#'] then -- non-enumerated alias matches enumerated parameter pattern? enumerator at end only pframe_args[alias_map[k..'#']:gsub('#', )] = v; -- remove '#' and copy parameter to pframe_args table pframe_args[k] = nil; -- unset the alias elseif k:match ('%d+') then -- if this parameter name contains digits local temp = k:gsub ('%d+', '#'); -- make a copy; digits replaced with single '#' local enum = k:match ('%d+'); -- get the enumerator

if alias_map[temp] then -- if this parameter is a recognized enumerated alias pframe_args[alias_map[temp]:gsub('#', enum)] = v; -- use canonical name and replace '#' with enumerator and add to pframe_args pframe_args[k] = nil; -- unset the alias end end end end

-- pframe parameters that are _reused are 'reused' have the form something like this: -- |chapter=[[wikisource:{{{chapter}}}|{{{chapter}}}]] -- where a parameter in the wrapping template is modified and then passed to the working template -- using the same parameter name (in this example |chapter=)

-- remove parameters that will be reused for k, v in ipairs (reuse_list) do -- k is numerical index, v is canonical parameter name to ignore if pframe_args[v] then -- if pframe_args has parameter that should be ignored pframe_args[v] = nil; -- unset the ignored parameter end end

pframe_args_get (pframe_args, args, exclude, _include_positional, list); -- add parameters and values to args that are not listed in the exclude table

return template; -- args now has all default and live parameters, return working template name end


--[[--------------------------< W R A P >----------------------------------------------------------------------

Template entry point. Call this function to 'execute' the working template

]]

local function wrap (frame) local args = {}; -- table of default and live parameters and their values to be passed to the wrapped template local template; -- the name of the working template

template = _main (frame, args, false); -- get default and live parameters and the name of the working template if not template then -- template name is required return error_msg; -- emit error message and abandon if template name not present end

return frame:expandTemplate {title=template, args=args}; -- render the working template end


--[[--------------------------< L I S T >----------------------------------------------------------------------

Template entry point. Call this function to 'display' the source for the working template. This function added as a result of a TfD here: Wikipedia:Templates_for_discussion/Log/2018_April_28#Module:PassArguments

This function replaces a similarly named function which was used in Template:Cite compare and Template:Cite compare2

Values in the args table are numerically indexed strings in the form 'name=value'

]]

local function list(frame, do_link) local args = {}; -- table of default and live parameters and their values to be passed to the listed template local template; -- the name of the listed template

template = _main (frame, args, true); -- get default and live parameters and the name of the listed template if not template then -- template name is required return error_msg; -- emit error message and abandon if template name not present end if do_link then template = ('%s'):format(frame:expandTemplate{ title='Transclude', args = {template} }, template) end table.sort(args) for i = 1, #args do local stripped = args[i]:match('^' .. i .. '=([^=]*)$') if stripped then args[i] = stripped else break end end return frame:preprocess(table.concat({ '{{', template, ('|%s'):rep(#args):format(unpack(args)), '}}'})); -- render the template end

local function link (frame) return list(frame, true) end

--[[--------------------------< E X P O R T E D F U N C T I O N S >------------------------------------------ ]]

return { link = link, list = list, wrap = wrap, };