# Module:Format link

---
-- Format link
---
-- Makes a wikilink from the given link and display values. Links are escaped
-- with colons if necessary, and links to sections are detected and displayed
-- with " § " as a separator rather than the standard MediaWiki "#". Used in
-- the template.
---
local libraryUtil = require('libraryUtil')
local checkType = libraryUtil.checkType
local checkTypeForNamedArg = libraryUtil.checkTypeForNamedArg
local mArguments -- lazily initialise Module:Arguments
local mError -- lazily initialise Module:Error
local yesno -- lazily initialise Module:Yesno  
local p = {}  
---
-- Helper functions
---  
local function getArgs
-- Fetches the arguments from the parent . Whitespace is trimmed and
-- blanks are removed.
mArguments = require('Module:Arguments')
return mArguments.getArgs(, {parentOnly = true})
end  
local function removeInitialColon(s)
-- Removes the initial colon from a string, if present.
return s:match('^:?(.*)')
end  
local function maybeItalicize(s, shouldItalicize)
-- Italicize s if s is a string and the shouldItalicize parameter is true.
if s and shouldItalicize then
return '<i>' .. s .. '</i>'
else
return s
end
end  
local function parseLink(link)
-- Parse a link and return a table with the link's components.
-- These components are:
-- - link: the link, stripped of any initial colon (always present)
-- - page: the page name (always present)
-- - section: the page name (may be nil)
-- - display: the display text, if manually entered after a pipe (may be nil)
link = removeInitialColon(link)  
-- Find whether a faux display value has been added with the magic
-- word.
local prePipe, display = link:match('^(.-)|(.*)$')
link = prePipe or link  
-- Find the page, if it exists.
-- For links like #Bar, the page will be nil.
local preHash, postHash = link:match('^(.-)#(.*)$')
local page
if not preHash then
-- We have a link like Foo.
page = link
elseif preHash ~= '' then
-- We have a link like Foo#Bar.
page = preHash
end  
-- Find the section, if it exists.
local section
if postHash and postHash ~= '' then
section = postHash
end  
return {
link = link,
page = page,
section = section,
display = display,
}
end  
local function formatDisplay(parsed, options)
-- Formats a display string based on a parsed link table (matching the
-- output of parseLink) and an options table (matching the input options for
-- _formatLink).
local page = maybeItalicize(parsed.page, options.italicizePage)
local section = maybeItalicize(parsed.section, options.italicizeSection)
if (not section) then
return page
elseif (not page) then
return mw.ustring.format('§&nbsp;%s', section)
else
return mw.ustring.format('%s §&nbsp;%s', page, section)
end
end  
local function missingArgError(target)
mError = require('Module:Error')
return mError.error{message =
'Error:nolinkortargetspecified!(help)'
}
end  
---
-- Main functions
---  
function p.formatLink
-- The formatLink export function, for use in templates.
yesno = require('Module:Yesno')
local args = getArgs
local link = args[1] or args.link
local target = args[3] or args.target
if not (link or target) then
return missingArgError('Template:Format link')
end  
return p._formatLink{
link = link,
display = args[2] or args.display,
target = target,
italicizePage = yesno(args.italicizepage),
italicizeSection = yesno(args.italicizesection),
categorizeMissing = args.categorizemissing
}
end  
function p._formatLink(options)
-- The formatLink export function, for use in modules.
checkType('_formatLink', 1, options, 'table')
local function check(key, expectedType) --for brevity
checkTypeForNamedArg(
'_formatLink', key, options[key], expectedType or 'string', true
end
check('link')
check('display')
check('target')
check('italicizePage', 'boolean')
check('italicizeSection', 'boolean')
check('categorizeMissing')  
-- Normalize link and target and check that at least one is present
if options.link == '' then options.link = nil end
if options.target == '' then options.target = nil end
if not (options.link or options.target) then
return missingArgError('Module:Format link')
end  
local parsed = parseLink(options.link)
local display = options.display or parsed.display
local catMissing = options.categorizeMissing
local category = ''  
-- Find the display text
if not display then display = formatDisplay(parsed, options) end  
-- Handle the target option if present
if options.target then
local parsedTarget = parseLink(options.target)
parsed.link = parsedTarget.link
parsed.page = parsedTarget.page
end  
-- Test if page exists if a diagnostic category is specified
if catMissing and (mw.ustring.len(catMissing) > 0) then
local title = nil
if parsed.page then title = mw.title.new(parsed.page) end
if title and (not title.isExternal) then
local success, exists = pcall(function return title.exists end)
if success and not exists then
category = mw.ustring.format('', catMissing)
end
end
end  
-- Format the result as a link
if parsed.link == display then
return mw.ustring.format(':%s%s', parsed.link, category)
else
return mw.ustring.format('%s%s', parsed.link, display, category)
end
end  
---
-- Derived convenience functions
---  
function p.formatPages(options, pages)
-- Formats an array of pages using formatLink and the given options table,
-- and returns it as an array. Nil values are not allowed.
local ret = {}
for i, page in ipairs(pages) do
ret[i] = p._formatLink{
link = page,
categorizeMissing = options.categorizeMissing,
italicizePage = options.italicizePage,
italicizeSection = options.italicizeSection
}
end
return ret
end  
return p