|ref=harv - get names and date from template parameters
|ref= - assemble an anchor id from positional parameters
|ref= - assemble an anchor id from positional parameters
|ref= - skip; do nothing because an anchor id intentionally suppressed; TODO: keep with a type code of '0'?
|ref=<text> - save param value because may match an anchor id override value in template |ref= parameter or |id= parameter  
local function anchor_id_make_cs12 (template)
local ref; -- content of |ref=
local template_name; -- name of the template
local anchor_id; -- the assembled anchor id from this template
local date;
local params = {}; -- table of template parameters  
template_name = template_name_get (template); -- get first char uppercase trimmed template name; ignore subpages ~/new, ~/sandbox
if not template_name or template_skip[template_name] then
return nil; -- could not extract template name from (possibly corrupted) template (extraneous opening { in the template will cause this)
end  
if redirects_patent[template_name] then
date = date_get (template, alias_patterns_patent_date); -- get date; done here because might be in
else
date = date_get (template, alias_patterns_date);
end  
ref = template:match ('|%s*ref%s*=%s*(%b{})'); -- first look for |ref= or |ref= because we will strip templates from the cs1|2 template
if not ref then
if template:match ('|%s*ref%s*=([^|}]+)') then -- |ref= not found; if there is a |ref= param with an assigned value
ref = template:match ('|%s*ref%s*=([^|}]+)'); -- get the value; whitespace is a 'value'
if ref then -- nil when |ref=|... or when |ref=}} (no spaces between assignment operator and pipe or closing brace)
ref = mw.text.trim (ref); -- something, could be just whitespace, so trim leading / trailing whitespace
if '' == ref then -- trimming a string of whitespace makes an empty string
ref = nil; -- make empty ref same as missing ref
end
end
end
end  
template_params_get (template, params); -- build a table of template parameters and their values  
if not ref then -- |ref= not set, might be cite LSA which doesn't support |ref=
if 'cite lsa' == template_name then
return 'CITEREF' .. (params.last or *) .. (params.year or *); -- cite LSA always creates an anchor id using only |last= and |year= (no aliases)
end
end  
if 'harv' == ref or not ref then -- |ref=harv specified or |ref= missing or empty
if redirects_patent[template_name] then -- if this is a cite patent template
anchor_id = names_get (params, aliases_inventor); -- inventor names only
else -- cs1|2 template
anchor_id = names_get (params, aliases_contributor) or -- get contributor, author, or editor names
names_get (params, aliases_author) or
vnames_get (params, 'vauthors') or -- |vauthors=
names_get (params, aliases_editor) or
vnames_get (params, 'veditors'); -- |veditors=
end  
if anchor_id then -- if names were gotten
anchor_id = 'CITEREF' .. anchor_id .. date;
end  
elseif ref:match ('%b{}') then -- ref holds a template
anchor_id = sfnref_get (ref); -- returns content of or ; nil else  
elseif '' == ref and not redirects_patent[template_name] then -- |ref=; not supported by cite patent
return nil; -- anchor id expicitly suppressed  
else
anchor_id = ref; -- |ref=<text> may match an anchor id override value in template |ref= parameter
end  
return anchor_id; -- anchor_id text; nil else
end  
----------------------------< L I S T _ A D D >--------------------------------------------------------------  
adds an <item> to <list> table; for anchor IDs, the boolean <encode> argument must be set true; no return value  
local function list_add (item, list, encode)
if item then -- if there was an item
if encode then -- for anchor IDs ...
item = mw.uri.anchorEncode (item); -- encode to remove wikimarkup, convert spaces to underscores etc
end  
if not list[item] then -- if not already saved
list[item] = 1; -- save it
else -- here when this item already saved
list[item] = list[item] + 1; -- to indicate that there are multiple items
end
end
end  
----------------------------< A N C H O R _ I D _ M A K E _ A N C H O R >------------------------------------  
make anchor IDs from ; there may be more than one because is not limited to the number of
anchors it may hold.  
local function anchor_id_make_anchor (template, anchor_id_list)
template = template:gsub ('^$', '', 1); -- remove outer and template name  
template = wikilink_strip (template); -- strip any wikilink markup (there shouldn't be any but just in case)  
local params = {};
local anchor_id;  
for param in template:gmatch ('%b{}') do -- loop through the template; remove and save templates (presumed to be sfnref or harvid)
table.insert (params, param); -- save it
template = template:gsub ('%b{}', '', 1); -- remove it from source template
end  
for _, t in ipairs (params) do -- spin through the templates in params
anchor_id = sfnref_get (t); -- attempt to decode and
if anchor_id then -- nil when not or
list_add (anchor_id, anchor_id_list, true); -- add anchor ID to the list
end
end  
template = template:gsub ('|%s*|', '|'); -- when pipe follows pipe with or without white space, remove extraneous pipe
template = template:gsub ('^|', *):gsub('|$', *); -- remove extraneous leading and trailing pipes  
params = mw.text.split (template, '%s*|%s*'); -- split at the pipe and remove extraneous space characters  
for _, t in ipairs (params) do -- spin through the anchor IDs
anchor_id = mw.text.trim (t); -- trim white space
if '' ~= anchor_id then -- should always have something
list_add (anchor_id, anchor_id_list, true); -- add anchor ID to the list
end
end
end  
----------------------------< T E M P L A T E _ L I S T _ A D D >--------------------------------------------  
makes a list of templates use in the article.  
local function template_list_add (template)
local template = template:match ('  
--2, cs1|2-like, vcite xxx, harvc, anchor, wikicite templates  
Because cs1|2 wrapper templates can, and often do, hide the author and date parameters inside the wrapper,
these parameters are not available in the article's wikisource so , , and templates that
link correctly to those wrapper templates will incorrectly show error messages. Use |ignore-err=yes in the ,
, and templates to supress the error message.  
creates a list of templates used in the article for use with the whitelist  
creates a list of article-local whitelisted anchor IDs from  
local function anchor_id_list_make
article_content_get ; -- attempt to get this article's content  
if '' == Article_content then -- when there is no article content
return ''; -- no point in continuing
end  
local template; -- place to hold the template that we found
local template_name;
local anchor_id; -- place to hold an anchor id as it is extracted / decoded  
local find_pattern = '%f[{] for example) so declare ourselves done
end  
template_name = template_name_get (template); -- get first char uppercase trimmed template name; ignore subpages ~/new, ~/sandbox
template_list_add (template); -- add this template's name to the list  
if data.known_templates_cs12 [template_name] then
anchor_id = anchor_id_make_cs12 (template); -- extract an anchor id from this template
list_add (anchor_id, anchor_id_list, true)  
elseif data.known_templates_vcite [template_name] then
local ref = template:match ('|%s*ref%s*=%s*(%b{})'); -- first look for |ref= or |ref= because we will strip templates from the vcite template
if ref then -- |ref=
anchor_id = sfnref_get (ref); -- returns content of or ; nil else
list_add (anchor_id, anchor_id_list, true);
else
local params = {};  
template_params_get (template, params); -- build a table of template parameters and their values  
anchor_id = params['ref']; -- when both set, vcite uses value from |ref=
if not anchor_id and params['harvid'] then
anchor_id = 'CITEREF' .. params['harvid']; -- in vcite, |harvid= auto-adds 'CITEREF' prefix to the value in |harvid=
end
list_add (anchor_id, anchor_id_list, true);
end  
elseif data.known_templates_harvc [template_name] then