Module:Sandbox/trappist the monk/wrapper doc

require ('strict');


--[[--------------------------< A R T I C L E _ C O N T E N T _ G E T >----------------------------------------

get template content

]]

local function template_content_get (template)
	if not template:match ('^[Tt]emplate:') then								-- when template name does not include template namespace
		template = 'Template:' .. template;										-- add it
	end
	local content =  mw.title.new (template):getContent();						-- get the content of the template
	if not content then															-- nil when template does not exist
		return nil, '<span style="color:#bf3c2c">cannot find [[' .. template .. ']]</span>';	-- return nil with error message
	end

	content = content:gsub ('<!%-%-[^>]*%-%->', '');							-- remove html comments that might be placed near our parameters of interest
	return content;
end


--[[--------------------------< A L I A S _ M A P >------------------------------------------------------------

special case

read the contents of |_alias-map= and add unordered list and parameter formatting

|alias-map= holds a comma-separated list of colon-separated parameter pairs where the left parameter name is the 
wrapper template's parameter name (from) and the right parameter name is the working template's parameter name (to).

render as:
* from → to

]]

local function alias_map (alias_map_t)
	for k, v in ipairs (alias_map_t) do
		alias_map_t[k] = v:gsub ('([^:]+)%s*:%s*(.+)', '%*{{para|%1}} → {{para|%2}}');	-- make an unordered list item
	end

	return alias_map_t;
end


--[[--------------------------< S P E C I A L _ S O R T >------------------------------------------------------

special sort function for the alias map list (sort only by the from portion of 'from:to') and for the default
settings list (sort by parameter name only)

]]

local function special_sort (seq_t, pattern)
	local function comp (a, b)													-- local function to do the sort comparison
		pattern = pattern or '^[^:]+';											-- default to pattern for alias map sorting; pattern for default settings is '|[^|]+'
		a = a:match (pattern);													-- compare the 'from' portions only
		b = b:match (pattern);
		a = mw.text.trim (a);													-- make sure no extraneous white space
		b = mw.text.trim (b);
		return a < b;															-- and do the comparison
	end
	
	return table.sort (seq_t, comp);											-- do the sort and done
end


--[[--------------------------< S I M P L E >------------------------------------------------------------------

read the contents of <simple_t> (|_reuse= or |_exclude= parameter lists) and add unordered list and parameter
formatting

|_reuse= and |_exclude= each hold a simple list of comma-separated parameter names

]]

local function simple (simple_t)
	for k, v in ipairs (simple_t) do
		simple_t[k] = v:gsub ('(.+)', '%*{{para|%1}}');							-- make an unordered list item
	end
	
	return simple_t;
end


--[[--------------------------< D E F A U L T _ S E T T I N G S >----------------------------------------------

extracts {{#invoke:Template wrapper...}} from the template wikitext, converts from 'wrap' to 'list' and then
preprocesses to get a rendering of only the default parameters.  Converts that rendering to an unsorted list
sorted by parameter name.

]]

local function default_settings (template_content, frame, settings_t)
	local start, _ = template_content:find ('{{#invoke:Template wrapper');

	local listed = template_content:match ('%b{}', start);						-- extract the #invoke
	listed = listed:gsub ('| *wrap *|', '|list|');								-- switch to list mode
	listed = mw.text.unstripNoWiki (frame:preprocess (listed));					-- get the 'listed' template and unstrip the nowikis
	listed = listed:gsub ('&#125;&#125;</code>', '<wbr>');						-- replace with html wbr tag for use as a delimiter
	listed = listed:gsub ('<code[^>]*>', '');									-- delete opening code tag

	local wrapper_t = {}														-- individual parameters will go here
	for v in listed:gmatch ('<wbr>([^<]+)') do									-- extract wach parameter and its value
		v = mw.text.decode (v);													-- convert html entities
		v = v:gsub ('^|', '*{{para|'):gsub ('=', '|', 1) .. '}}';				-- format into an unordered list item
		table.insert (wrapper_t, v);											-- and save it
	end
	
	special_sort (wrapper_t, '|[^|]+');											-- sort by parameter name
	table.insert (wrapper_t, 1, settings_t.intro);								-- add the introductory sentence
	table.insert (wrapper_t, 1, settings_t.hdr_lvl .. settings_t.hdr .. settings_t.hdr_lvl);	-- and the section heading
	return table.concat (wrapper_t, '\n');										-- and make a big damn string and done
end


--[[--------------------------< G E T _ P A R A M _ V A L _ A S _ S E Q >--------------------------------------

extract the comma-separated list of parameter names from a parameter and split on the commas into a sequence of
parameters.  return the sequence when parameter is found in <template_content>; nil else

]]

local function get_param_val_as_seq (template_content, parameter)
	local param_value = template_content:match ('| *' .. parameter .. ' *= *([^|]*)');	-- extract parameter value
	if not param_value then														-- match failed
		return nil;
	end
	param_value = mw.text.trim (param_value);									-- no leading or trailing whitespace
	return mw.text.split (param_value, '%s*,%s');								-- return a sequence of comma-separated values
end


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

{{#invoke:Sandbox/trappist the monk/wrapper doc|main|template=Infobox Australian place}}

]]

local function main (frame)
	local args_t = require ('Module:Arguments').getArgs (frame);				-- get arguments from the invoke
	local template_content, msg = template_content_get (args_t.template);		-- get the template contents

	if not template_content then
		return msg;																-- when <template_content> nil, msg has an error message
	end
	
	local hdr_lvl = string.rep ('=', tonumber (args_t.hdr_lvl) or 3);			-- default to '==='

	local params_t = {
		{
		pattern = '_alias%-map',												-- for use in string.match()
		func = alias_map,														-- function to reformat comma-separated list into an unordered list
		sort_func = special_sort,
		hdr = 'Alias map',														-- section header name
		intro = 'Introductory sentence ... [[Module:Template_wrapper#alias-map|documentation]]',
		}, 
		{
		pattern = '_reuse',
		func = simple,
		sort_func = table.sort,
		hdr = 'Reused parameters',
		intro = 'Introductory sentence ... [[Module:Template_wrapper#reuse|documentation]]',
		},
		{
		pattern = '_exclude',
		func = simple,
		sort_func = table.sort,
		hdr = 'Excluded parameters',
		intro = 'Introductory sentence ... [[Module:Template_wrapper#exclude|documentation]]',
		},
		defaults_t = {
			hdr = 'Default settings',
			hdr_lvl = hdr_lvl,
			intro = 'Introductory sentence ... ',
		}
	};

	local out_t = {};															-- final output goes here

	for _, v_t in ipairs (params_t) do											-- for each of the known parameters
		local param_seq_t = get_param_val_as_seq (template_content, v_t.pattern);	-- a sequence of parameter values nil else
		if param_seq_t then														-- if we got a sequence
			v_t.sort_func (param_seq_t);
			param_seq_t = v_t.func (param_seq_t);								-- reformat into an unordered list
			if 20 < #param_seq_t then											-- when the unordered list has more than 20 items
				table.insert (param_seq_t, 1, '{{div col}}');					-- add basic column formatting
				table.insert (param_seq_t, '{{div col end}}');
			end
			table.insert (param_seq_t, 1, v_t.intro);							-- insert introductory sentence
			table.insert (param_seq_t, 1, hdr_lvl .. v_t.hdr .. hdr_lvl);		-- insert a header
			table.insert (out_t, table.concat (param_seq_t, '\n'));				-- and make a big damn string
		end
	end

	table.insert (out_t, default_settings (template_content, frame, params_t.defaults_t));

	table.insert (out_t, 1, '<syntaxhighlight lang="wikitext">');				-- add styling for final rendering
	table.insert (out_t, '</syntaxhighlight>');
	return frame:preprocess (table.concat (out_t, '\n\n'));						-- and make a big damn string and done
end


--[[--------------------------< E X P O R T S >----------------------------------------------------------------
]]

return {
	main = main,
	}