Module:Citation/CS1/Whitelist and Module:Format link: Difference between pages

From Frontierpedia, the Microsoft Agent encyclopedia
(Difference between pages)
m (1 revision imported)
 
m (1 revision imported)
 
Line 1: Line 1:
--[[--------------------------< S U P P O R T E D  P A R A M E T E R S >--------------------------------------
--------------------------------------------------------------------------------
-- 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 {{format link}} 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]]


Because a steady-state signal conveys no useful information, whitelist.basic_arguments[] list items can have three values:
local p = {}
true - these parameters are valid and supported parameters
false - these parameters are deprecated but still supported
tracked - these parameters are valid and supported parameters tracked in an eponymous properties category
nil - these parameters are no longer supported. remove entirely
]]


local basic_arguments = {
--------------------------------------------------------------------------------
['accessdate'] = true,
-- Helper functions
['access-date'] = true,
--------------------------------------------------------------------------------
['agency'] = true,
['archivedate'] = true,
['archive-date'] = true,
['archive-format'] = true,
['archiveurl'] = true,
['archive-url'] = true,
['article'] = true,
['article-format'] = true,
['article-url'] = true,
['article-url-access'] = true,
['arxiv'] = true, -- cite arxiv; here because allowed in cite ... as identifier
['asin'] = true,
['ASIN'] = true,
['asin-tld'] = true,
['at'] = true,
['author'] = true,
['author-first'] = true,
['author-given'] = true,
['author-last'] = true,
['author-surname'] = true,
['authorlink'] = true,
['author-link'] = true,
['author-mask'] = true,
['authors'] = true,
['bibcode'] = true,
['bibcode-access'] = true,
['biorxiv'] = true, -- cite biorxiv; here because allowed in cite ... as identifier
['chapter'] = true,
['chapter-format'] = true,
['chapter-url'] = true,
['chapter-url-access'] = true,
['citeseerx'] = true, -- cite citeseerx; here because allowed in cite ... as identifier
['collaboration'] = true,
['contribution'] = true,
['contribution-format'] = true,
['contribution-url'] = true,
['contribution-url-access'] = true,
['contributor'] = true,
['contributor-first'] = true,
['contributor-given'] = true,
['contributor-last'] = true,
['contributor-surname'] = true,
['contributor-link'] = true,
['contributor-mask'] = true,
['date'] = true,
['department'] = true,
['df'] = true,
['dictionary'] = true,
['display-authors'] = true,
['display-contributors'] = true,
['display-editors'] = true,
['display-interviewers'] = true,
['display-subjects'] = true,
['display-translators'] = true,
['doi'] = true,
['DOI'] = true,
['doi-access'] = true,
['doi-broken-date'] = true,
['edition'] = true,
['editor'] = true,
['editor-first'] = true,
['editor-given'] = true,
['editor-last'] = true,
['editor-surname'] = true,
['editor-link'] = true,
['editor-mask'] = true,
['eissn'] = true,
['EISSN'] = true,
['encyclopaedia'] = true,
['encyclopedia'] = true,
['entry'] = true,
['entry-format'] = true,
['entry-url'] = true,
['entry-url-access'] = true,
['eprint'] = true, -- cite arxiv; here because allowed in cite ... as identifier
['first'] = true,
['format'] = true,
['given'] = true,
['hdl'] = true,
['HDL'] = true,
['hdl-access'] = true,
['host'] = true, -- unique to certain templates?
['id'] = true,
['ID'] = true,
['institution'] = true, -- constrain to cite thesis?
['interviewer'] = true,
['interviewer-first'] = true,
['interviewer-given'] = true,
['interviewer-last'] = true,
['interviewer-surname'] = true,
['interviewer-link'] = true,
['interviewer-mask'] = true,
['isbn'] = true,
['ISBN'] = true,
['ismn'] = true,
['ISMN'] = true,
['issn'] = true,
['ISSN'] = true,
['issue'] = true,
['jfm'] = true,
['JFM'] = true,
['journal'] = true,
['jstor'] = true,
['JSTOR'] = true,
['jstor-access'] = true,
['lang'] = true,
['language'] = true,
['last'] = true,
['lay-date'] = false,
['lay-format'] = false,
['lay-source'] = false,
['lay-url'] = false,
['lccn'] = true,
['LCCN'] = true,
['location'] = true,
['magazine'] = true,
['medium'] = true,
['minutes'] = true, -- constrain to cite AV media and podcast?
['mode'] = true,
['mr'] = true,
['MR'] = true,
['name-list-style'] = true,
['newspaper'] = true,
['no-pp'] = true,
['no-tracking'] = true,
['number'] = true,
['oclc'] = true,
['OCLC'] = true,
['ol'] = true,
['OL'] = true,
['ol-access'] = true,
['orig-date'] = true,
['origyear'] = true,
['orig-year'] = true,
['osti'] = true,
['OSTI'] = true,
['osti-access'] = true,
['others'] = true,
['p'] = true,
['page'] = true,
['pages'] = true,
['people'] = true,
['periodical'] = true,
['place'] = true,
['pmc'] = true,
['PMC'] = true,
['pmc-embargo-date'] = true,
['pmid'] = true,
['PMID'] = true,
['postscript'] = true,
['pp'] = true,
['publication-date'] = true,
['publication-place'] = true,
['publisher'] = true,
['quotation'] = true,
['quote'] = true,
['quote-page'] = true,
['quote-pages'] = true,
['ref'] = true,
['rfc'] = true,
['RFC'] = true,
['sbn'] = true,
['SBN'] = true,
['scale'] = true,
['script-article'] = true,
['script-chapter'] = true,
['script-contribution'] = true,
['script-entry'] = true,
['script-journal'] = true,
['script-magazine'] = true,
['script-newspaper'] = true,
['script-periodical'] = true,
['script-quote'] = true,
['script-section'] = true,
['script-title'] = true,
['script-website'] = true,
['script-work'] = true,
['section'] = true,
['section-format'] = true,
['section-url'] = true,
['section-url-access'] = true,
['series'] = true,
['ssrn'] = true, -- cite ssrn; these three here because allowed in cite ... as identifier
['SSRN'] = true,
['ssrn-access'] = true,
['subject'] = true,
['subject-link'] = true,
['subject-mask'] = true,
['surname'] = true,
['s2cid'] = true,
['S2CID'] = true,
['s2cid-access'] = true,
['template-doc-demo'] = true,
['time'] = true, -- constrain to cite av media and podcast?
['time-caption'] = true, -- constrain to cite av media and podcast?
['title'] = true,
['title-link'] = true,
['translator'] = true,
['translator-first'] = true,
['translator-given'] = true,
['translator-last'] = true,
['translator-surname'] = true,
['translator-link'] = true,
['translator-mask'] = true,
['trans-article'] = true,
['trans-chapter'] = true,
['trans-contribution'] = true,
['trans-entry'] = true,
['trans-journal'] = true,
['trans-magazine'] = true,
['trans-newspaper'] = true,
['trans-periodical'] = true,
['trans-quote'] = true,
['trans-section'] = true,
['trans-title'] = true,
['trans-website'] = true,
['trans-work'] = true,
['type'] = true,
['url'] = true,
['URL'] = true,
['url-access'] = true,
['url-status'] = true,
['vauthors'] = true,
['veditors'] = true,
['version'] = true,
['via'] = true,
['volume'] = true,
['website'] = true,
['work'] = true,
['year'] = true,
['zbl'] = true,
['ZBL'] = true,
}


local numbered_arguments = {
local function getArgs(frame)
['author#'] = true,
-- Fetches the arguments from the parent frame. Whitespace is trimmed and
['author-first#'] = true,
-- blanks are removed.
['author#-first'] = true,
mArguments = require('Module:Arguments')
['author-given#'] = true,
return mArguments.getArgs(frame, {parentOnly = true})
['author#-given'] = true,
end
['author-last#'] = true,
['author#-last'] = true,
['author-surname#'] = true,
['author#-surname'] = true,
['author-link#'] = true,
['author#-link'] = true,
['authorlink#'] = true,
['author#link'] = true,
['author-mask#'] = true,
['author#-mask'] = true,
['contributor#'] = true,
['contributor-first#'] = true,
['contributor#-first'] = true,
['contributor-given#'] = true,
['contributor#-given'] = true,
['contributor-last#'] = true,
['contributor#-last'] = true,
['contributor-surname#'] = true,
['contributor#-surname'] = true,
['contributor-link#'] = true,
['contributor#-link'] = true,
['contributor-mask#'] = true,
['contributor#-mask'] = true,
['editor#'] = true,
['editor-first#'] = true,
['editor#-first'] = true,
['editor-given#'] = true,
['editor#-given'] = true,
['editor-last#'] = true,
['editor#-last'] = true,
['editor-surname#'] = true,
['editor#-surname'] = true,
['editor-link#'] = true,
['editor#-link'] = true,
['editor-mask#'] = true,
['editor#-mask'] = true,
['first#'] = true,
['given#'] = true,
['host#'] = true,
['interviewer#'] = true,
['interviewer-first#'] = true,
['interviewer#-first'] = true,
['interviewer-given#'] = true,
['interviewer#-given'] = true,
['interviewer-last#'] = true,
['interviewer#-last'] = true,
['interviewer-surname#'] = true,
['interviewer#-surname'] = true,
['interviewer-link#'] = true,
['interviewer#-link'] = true,
['interviewer-mask#'] = true,
['interviewer#-mask'] = true,
['last#'] = true,
['subject#'] = true,
['subject-link#'] = true,
['subject#-link'] = true,
['subject-mask#'] = true,
['subject#-mask'] = true,
['surname#'] = true,
['translator#'] = true,
['translator-first#'] = true,
['translator#-first'] = true,
['translator-given#'] = true,
['translator#-given'] = true,
['translator-last#'] = true,
['translator#-last'] = true,
['translator-surname#'] = true,
['translator#-surname'] = true,
['translator-link#'] = true,
['translator#-link'] = true,
['translator-mask#'] = true,
['translator#-mask'] = true,
}


local function removeInitialColon(s)
-- Removes the initial colon from a string, if present.
return s:match('^:?(.*)')
end


--[[--------------------------< P R E P R I N T  S U P P O R T E D  P A R A M E T E R S >--------------------
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


Cite arXiv, cite biorxiv, cite citeseerx, and cite ssrn are preprint templates that use the limited set of parameters
local function parseLink(link)
defined in the limited_basic_arguments and limited_numbered_arguments tables.  Those lists are supplemented with a
-- Parse a link and return a table with the link's components.
template-specific list of parameters that are required by the particular template and may be exclusive to one of the
-- These components are:
preprint templates.  Some of these parameters may also be available to the general cs1|2 templates.
-- - 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)


Same conventions for true/false/tracked/nil as above.
-- 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


local preprint_arguments = {
-- Find the section, if it exists.
arxiv = {
local section
['arxiv'] = true, -- cite arxiv and arxiv identifiers
if postHash and postHash ~= '' then
['class'] = true,
section = postHash
['eprint'] = true, -- cite arxiv and arxiv identifiers
end
},
biorxiv = {
return {
['biorxiv'] = true,
link = link,
},
page = page,
citeseerx = {
section = section,
['citeseerx'] = true,
display = display,
},
ssrn = {
['ssrn'] = true,
['SSRN'] = true,
['ssrn-access'] = true,
},
}
}
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


--[[--------------------------< L I M I T E D  S U P P O R T E D  P A R A M E T E R S >----------------------
local function missingArgError(target)
mError = require('Module:Error')
return mError.error{message =
'Error: no link or target specified! ([[' .. target .. '#Errors|help]])'
}
end


cite arxiv, cite biorxiv, cite citeseerx, and cite ssrn templates are preprint templates so are allowed only a
--------------------------------------------------------------------------------
limited subset of parameters allowed to all other cs1|2 templates.  The limited subset is defined here.
-- Main functions
--------------------------------------------------------------------------------


Same conventions for true/false/tracked/nil as above.
function p.formatLink(frame)
-- The formatLink export function, for use in templates.
]]
yesno = require('Module:Yesno')
local args = getArgs(frame)
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


local limited_basic_arguments = {
return p._formatLink{
['at'] = true,
link = link,
['author'] = true,
display = args[2] or args.display,
['author-first'] = true,
target = target,
['author-given'] = true,
italicizePage = yesno(args.italicizepage),
['author-last'] = true,
italicizeSection = yesno(args.italicizesection),
['author-surname'] = true,
categorizeMissing = args.categorizemissing
['author-link'] = true,
['authorlink'] = true,
['author-mask'] = true,
['authors'] = true,
['collaboration'] = true,
['date'] = true,
['df'] = true,
['display-authors'] = true,
['first'] = true,
['given'] = true,
['language'] = true,
['last'] = true,
['mode'] = true,
['name-list-style'] = true,
['no-tracking'] = true,
['p'] = true,
['page'] = true,
['pages'] = true,
['postscript'] = true,
['pp'] = true,
['quotation'] = true,
['quote'] = true,
['ref'] = true,
['surname'] = true,
['template-doc-demo'] = true,
['title'] = true,
['trans-title'] = true,
['vauthors'] = true,
['year'] = true,
}
}
end


local limited_numbered_arguments = {
function p._formatLink(options)
['author#'] = true,
-- The formatLink export function, for use in modules.
['author-first#'] = true,
checkType('_formatLink', 1, options, 'table')
['author#-first'] = true,
local function check(key, expectedType) --for brevity
['author-given#'] = true,
checkTypeForNamedArg(
['author#-given'] = true,
'_formatLink', key, options[key], expectedType or 'string', true
['author-last#'] = true,
)
['author#-last'] = true,
end
['author-surname#'] = true,
check('link')
['author#-surname'] = true,
check('display')
['author-link#'] = true,
check('target')
['author#-link'] = true,
check('italicizePage', 'boolean')
['authorlink#'] = true,
check('italicizeSection', 'boolean')
['author#link'] = true,
check('categorizeMissing')
['author-mask#'] = true,
['author#-mask'] = true,
['first#'] = true,
['given#'] = true,
['last#'] = true,
['surname#'] = true,
}


-- 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


--[[--------------------------< U N I Q U E _ A R G U M E N T S >----------------------------------------------
local parsed = parseLink(options.link)
local display = options.display or parsed.display
local catMissing = options.categorizeMissing
local category = ''


Some templates have unique parameters.  Those templates and their unique parameters are listed here. Keys in this
-- Find the display text
table are the template's CitationClass parameter value
if not display then display = formatDisplay(parsed, options) end


Same conventions for true/false/tracked/nil as above.
-- 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('[[Category:%s]]', 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]]%s', parsed.link, display, category)
end
end


local unique_arguments = {
--------------------------------------------------------------------------------
['audio-visual'] = {
-- Derived convenience functions
['transcript'] = true,
--------------------------------------------------------------------------------
['transcript-format'] = true,
['transcript-url'] = true,
},
conference = {
['book-title'] = true,
['conference'] = true,
['conference-format'] = true,
['conference-url'] = true,
['event'] = true,
},
episode = {
['airdate'] = true,
['air-date'] = true,
['credits'] = true,
['episode-link'] = true, -- alias of |title-link=
['network'] = true,
['season'] = true,
['series-link'] = true,
['series-no'] = true,
['series-number'] = true,
['station'] = true,
['transcript'] = true,
['transcript-format'] = true,
['transcripturl'] = false,
['transcript-url'] = true,
},
mailinglist = {
['mailing-list'] = true,
},
map = {
['cartography'] = true,
['inset'] = true,
['map'] = true,
['map-format'] = true,
['map-url'] = true,
['map-url-access'] = true,
['script-map'] = true,
['sections'] = true,
['sheet'] = true,
['sheets'] = true,
['trans-map'] = true,
},
newsgroup = {
['message-id'] = true,
['newsgroup'] = true,
},
report = {
['docket'] = true,
},
serial = {
['airdate'] = true,
['air-date'] = true,
['credits'] = true,
['episode'] = true, -- cite serial only TODO: make available to cite episode?
['episode-link'] = true, -- alias of |title-link=
['network'] = true,
['series-link'] = true,
['station'] = true,
},
speech = {
['conference'] = true,
['conference-format'] = true,
['conference-url'] = true,
['event'] = true,
},
thesis = {
['degree'] = true,
['docket'] = true,
},
}
 
 
--[[--------------------------< T E M P L A T E _ L I S T _ G E T >--------------------------------------------
 
gets a list of the templates from table t
 
]]


local function template_list_get (t)
function p.formatPages(options, pages)
local out = {}; -- a table for output
-- Formats an array of pages using formatLink and the given options table,
for k, _ in pairs (t) do -- spin through the table and collect the keys
-- and returns it as an array. Nil values are not allowed.
table.insert (out, k) -- add each key to the output table
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
end
return out; -- and done
return ret
end
end


 
return p
--[[--------------------------< E X P O R T E D  T A B L E S >------------------------------------------------
]]
 
return {
basic_arguments = basic_arguments,
numbered_arguments = numbered_arguments,
limited_basic_arguments = limited_basic_arguments,
limited_numbered_arguments = limited_numbered_arguments,
 
preprint_arguments = preprint_arguments,
preprint_template_list = template_list_get (preprint_arguments), -- make a template list from preprint_arguments{} table
unique_arguments = unique_arguments,
unique_param_template_list = template_list_get (unique_arguments), -- make a template list from unique_arguments{} table
};

Latest revision as of 00:28, 18 October 2022

Documentation for this module may be created at Module:Format link/doc

--------------------------------------------------------------------------------
-- 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 {{format link}} 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(frame)
	-- Fetches the arguments from the parent frame. Whitespace is trimmed and
	-- blanks are removed.
	mArguments = require('Module:Arguments')
	return mArguments.getArgs(frame, {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: no link or target specified! ([[' .. target .. '#Errors|help]])'
	}
end

--------------------------------------------------------------------------------
-- Main functions
--------------------------------------------------------------------------------

function p.formatLink(frame)
	-- The formatLink export function, for use in templates.
	yesno = require('Module:Yesno')
	local args = getArgs(frame)
	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('[[Category:%s]]', 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]]%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