Module:template link

local export = {}

local m_str_utils = require("Module:string utilities") local m_table = require("Module:table") local string = string local table = table

local concat = table.concat local encode_uri = mw.uri.encode local format = string.format local format_link -- defined as export.format_link below local is_substing = mw.isSubsting local lower = string.lower local make_title = mw.title.makeTitle -- unconditionally adds the specified namespace prefix local new_title = mw.title.new -- specified namespace prefix is only added if the input doesn't contain one local pairs = pairs local parse_template_name = require("Module:template parser").parseTemplateName local php_trim = m_str_utils.php_trim local process_params = require("Module:parameters").process local shallowcopy = m_table.shallowcopy local sorted_pairs = m_table.sortedPairs local split = m_str_utils.split local insert = table.insert local type = type

local data = mw.loadData("Module:template link/data") local magic_words = data.magic_words local link_parameter_0 = data.link_parameter_0 local link_parameter_1 = data.link_parameter_1 local parser_extension_tags = mw.loadData("Module:data/parser extension tags")

do -- Generate a link. If the target title doesn't have a fragment, use "#top" -- (which is an implicit anchor at the top of every page), as this ensures -- self-links still display as links, since bold display is distracting and -- unintuitive for template links. local function link_page(title, display) local fragment = title.fragment fragment = fragment == "" and "top" or fragment return format(			"%s",			encode_uri(title.prefixedText, "WIKI"),			encode_uri(fragment, "WIKI"),			display		) end -- pf_arg0 or arg1 may need to be linked if a given parser function treats -- them as a pagename. If a key exists in `namespace`, the value is the -- namespace for the page: if not 0, then the namespace prefix will always -- be added to the input (e.g. can only target the Module:	-- namespace, so inputting "Template:foo" gives "Module:Template:foo", and	-- "Module:foo" gives "Module:Module:foo"). However, this isn't possible -- with mainspace (namespace 0), so prefixes are respected. make_title -- handles all of this automatically. local function finalize_arg(pagename, namespace) if not namespace then return pagename end local title = make_title(namespace, pagename) if not title then return pagename end return link_page(title, pagename) end local function render_title(name, args) -- parse_template_name returns a table of transclusion modifiers plus -- the normalized template/magic word name, which will be used as link -- targets. The second return value pf_arg0 is argument 0, which is -- returned if the target is a parser function (e.g. "foo" in		-- ""). Note: the second parameter checks if there -- are any arguments, since parser variables cannot take arguments -- (e.g. 2024 is a parser variable, but 2024		-- transcludes "Template:CURRENTYEAR"). In such cases, the returned -- table explicitly includes the "Template:" prefix in the template -- name. The third parameter instructs it to retain any fragment in the -- template name in the returned table, if present. local chunks, pf_arg0 = parse_template_name(			name,			args and pairs(args)(args) ~= nil,			true		) if chunks == nil then return name end local chunks_len = #chunks -- Additionally, generate the corresponding table `rawchunks`, which -- is a list of colon-separated chunks in the raw input. This is used -- to retrieve the display forms for each chunk. local rawchunks = split(name, ":") for i = 1, chunks_len - 1 do			chunks[i] = format(				"%s",				encode_uri(magic_words[chunks[i]], "WIKI"),				rawchunks[i]			) end local chunk = chunks[chunks_len] local link = magic_words[chunk] -- If the name is not listed in magic_words, it must be a template, -- so return a link to it with link_page, concatenating the remaining -- chunks in `rawchunks` to form the display text. -- Use new_title with the default namespace 10 (Template:) to generate -- a target title, which is the same setting used for retrieving -- templates (including those in other namespaces, as prefixes override		-- the default). if not link then chunks[chunks_len] = link_page(				new_title(chunk, 10),				concat(rawchunks, "&#58;", chunks_len) -- :			) return concat(chunks, "&#58;") -- : end local arg1 = args and args[1] or nil -- Otherwise, it's a magic word. Some magic words have different links, -- depending on whether argument 1 is specified (e.g. "baz" in		-- ). if type(link) == "table" then link = arg1 and link[1] or link[0] end chunks[chunks_len] = format(			"%s",			encode_uri(link, "WIKI"),			rawchunks[chunks_len]		) -- If we don't have pf_arg0, it must be a parser variable, so return. if not pf_arg0 then return concat(chunks, "&#58;") -- : -- #TAG: has special handling, because documentation links for parser -- extension tags come from Module:data/parser extension tags. elseif chunk == "#TAG:" then local tag = parser_extension_tags[lower(php_trim(pf_arg0))] if tag then pf_arg0 = format(					"%s",					encode_uri(tag, "WIKI"),					pf_arg0				) end -- Otherwise, finalize pf_arg0 and add it to `chunks`. else pf_arg0 = finalize_arg(pf_arg0, link_parameter_0[chunk]) end chunks[chunks_len + 1] = pf_arg0 -- Finalize arg1 (if applicable) then return. if arg1 then args[1] = finalize_arg(arg1, link_parameter_1[chunk]) end return concat(chunks, "&#58;") -- : end

function export.format_link(title, args, nested) local output = {render_title(title, args)} -- Iterate over numbered arguments, adding them as implicit parameters -- (i.e. with no key) for as long as they correspond with a counter -- from 1. Then, add any remaining parameters with explicit keys -- (including any non-sequential numbered parameters). if args then local iter = sorted_pairs(args) local i, k, v = 1, iter while k == i do				insert(output, v)				k, v = iter i = i + 1 end if k ~= nil then repeat insert(output, k .. "&#61;" .. v) -- = k, v = iter until k == nil end end -- Add opening/closing braces and delimiting pipes. output = "&#123;&#123;" .. concat(output, "&#124;") .. "&#125;&#125;" -- 		-- Return, enclosing in "	end	format_link = export.format_link end

function export.show(frame) if is_substing then return require("Module:unsubst").unsubst_template("format_link") end local iargs = process_params(frame.args, {		["annotate"] = {},		["nested"] = {type = "boolean"}	}) -- iargs.annotate allows a template to specify the title, so the input -- arguments will match the output. Otherwise, we treat parameter 1 as the -- template name and offset any implicit arguments. local title = iargs.annotate if title then return format_link(title, shallowcopy(frame:getParent.args), iargs.nested) end -- Process parameters with the return_unknown flag set. `title` contains -- the title at key 1; everything else goes in `args`. local args title, args = process_params(frame:getParent.args, {		[1] = {required = true, allow_empty = true, allow_whitespace = true}	}, true) title = title[1] -- Shift all implicit arguments down by 1. Non-sequential numbered -- parameters don't get shifted; however, this offset means that if the -- input contains (e.g.) en, representing , -- the parameter at 3= is instead treated as sequential by this module, -- because it's indistinguishable from en, which represents -- . On the other hand, en is handled correctly, -- because there's still a gap before 4=. -- Unfortunately, there's no way to know the original input, so	-- there's no clear way to fix this; the only difference is that explicit -- parameters have whitespace trimmed from their values while implicit ones -- don't, but we can't assume that every input with no whitespace was given -- with explicit numbering. -- This also causes bigger problems for any parser functions which treat -- their inputs as arrays, or in some other nonstandard way (e.g.	-- treats "bar=baz" as parameter 1). Without -- knowing the original input, these can't be reconstructed accurately. -- The way around this is to use tags in the input, since this -- module won't unstrip them by design. local i = 2 repeat local arg = args[i] args[i - 1] = arg i = i + 1 until arg == nil return format_link(title, args, iargs.nested) end

return export