Module:Delink
-- This module de-links most wikitext.
 
 require(&quot;strict&quot;)
 
 local p = {}
 
 local getArgs
 
 local function delinkReversePipeTrick(s)
 	if s:match(&quot;^%[%[|.*[|\n]&quot;) then -- Check for newlines or multiple pipes.
 		return s
 	end
 	return s:match(&quot;%[%[|(.*)%]%]&quot;)
 
 end
 
 local function delinkPipeTrick(s)
 	-- We need to deal with colons, brackets, and commas, per [[Help:Pipe trick]].
 	-- First, remove the text before the first colon, if any.
 	if s:match(&quot;:&quot;) then
 		s = s:match(&quot;%[%[.-:(.*)|%]%]&quot;)
 	-- If there are no colons, grab all of the text apart from the square brackets and the pipe.
 	else
 		s = s:match(&quot;%[%[(.*)|%]%]&quot;)
 	end
 	
 	-- Next up, brackets and commas.
 	if s:match(&quot;%(.-%)$&quot;) then -- Brackets trump commas.
 		s = s:match(&quot;(.-) ?%(.-%)$&quot;)
 	elseif s:match(&quot;,&quot;) then -- If there are no brackets, display only the text before the first comma.
 		s = s:match(&quot;(.-),.*$&quot;)
 	end
 	return s
 end
 
 -- Return wikilink target |wikilinks=target
 local function getDelinkedTarget(s)
 	local result = s
 	-- Deal with the reverse pipe trick.
 	if result:match(&quot;%[%[|&quot;) then
 		return delinkReversePipeTrick(result)
 	end
 	
 	result = mw.uri.decode(result, &quot;PATH&quot;) -- decode percent-encoded entities. Leave underscores and plus signs.
 	result = mw.text.decode(result, true) -- decode HTML entities.
 	
 	-- Check for bad titles. To do this we need to find the
 	-- title area of the link, i.e. the part before any pipes.
 	local target_area
 	if result:match(&quot;|&quot;) then -- Find if we're dealing with a piped link.
 		target_area = result:match(&quot;^%[%[(.-)|.*%]%]&quot;)
 	else
 		target_area = result:match(&quot;^%[%[(.-)%]%]&quot;)
 	end
 
 	-- Check for bad characters.
 	if mw.ustring.match(target_area, &quot;[%[%]&lt;&gt;{}%%%c\n]&quot;) and mw.ustring.match(target_area, &quot;[%[%]&lt;&gt;{}%%%c\n]&quot;) ~= &quot;?&quot; then
 		return s
 	end
 	
 	return target_area
 end
 
 local function getDelinkedLabel(s)
 	local result = s
 	-- Deal with the reverse pipe trick.
 	if result:match(&quot;%[%[|&quot;) then
 		return delinkReversePipeTrick(result)
 	end
 
 	result = mw.uri.decode(result, &quot;PATH&quot;) -- decode percent-encoded entities. Leave underscores and plus signs.
 	result = mw.text.decode(result, true) -- decode HTML entities.
 
 	-- Check for bad titles. To do this we need to find the
 	-- title area of the link, i.e. the part before any pipes.
 	local target_area
 	if result:match(&quot;|&quot;) then -- Find if we're dealing with a piped link.
 		target_area = result:match(&quot;^%[%[(.-)|.*%]%]&quot;)
 	else
 		target_area = result:match(&quot;^%[%[(.-)%]%]&quot;)
 	end
 
 	-- Check for bad characters.
 	if mw.ustring.match(target_area, &quot;[%[%]&lt;&gt;{}%%%c\n]&quot;) and mw.ustring.match(target_area, &quot;[%[%]&lt;&gt;{}%%%c\n]&quot;) ~= &quot;?&quot; then
 		return s
 	end
 
 	-- Check for categories, interwikis, and files.
 	local colon_prefix = result:match(&quot;%[%[(.-):.*%]%]&quot;) or &quot;&quot; -- Get the text before the first colon.
 	local ns = mw.site.namespaces[colon_prefix] -- see if this is a known namespace
 	if mw.language.isKnownLanguageTag(colon_prefix) or (ns and (ns.canonicalName == &quot;File&quot; or ns.canonicalName == &quot;Category&quot;)) then
 		return &quot;&quot;
 	end
 
 	-- Remove the colon if the link is using the [[Help:Colon trick]].
 	if result:match(&quot;%[%[:&quot;) then
 		result = &quot;[[&quot; .. result:match(&quot;%[%[:(.*%]%])&quot;)
 	end
 
 	-- Deal with links using the [[Help:Pipe trick]].
 	if mw.ustring.match(result, &quot;^%[%[[^|]*|%]%]&quot;) then
 		return delinkPipeTrick(result)
 	end
 	
 	-- Find the display area of the wikilink
 	if result:match(&quot;|&quot;) then -- Find if we're dealing with a piped link.
 		result = result:match(&quot;^%[%[.-|(.+)%]%]&quot;)
 		-- Remove new lines from the display of multiline piped links,
 		-- where the pipe is before the first new line.
 		result = result:gsub(&quot;\n&quot;, &quot;&quot;)
 	else
 		result = result:match(&quot;^%[%[(.-)%]%]&quot;)
 	end
 
 	return result
 end
 
 local function delinkURL(s)
 	-- Assume we have already delinked internal wikilinks, and that
 	-- we have been passed some text between two square brackets [foo].
 	
 	-- If the text contains a line break it is not formatted as a URL, regardless of other content.
 	if s:match(&quot;\n&quot;) then
 		return s
 	end
 	
 	-- Check if the text has a valid URL prefix and at least one valid URL character.
 	local valid_url_prefixes = {&quot;//&quot;, &quot;http://&quot;, &quot;https://&quot;, &quot;ftp://&quot;, &quot;gopher://&quot;, &quot;mailto:&quot;, &quot;news:&quot;, &quot;irc://&quot;} 
 	local url_prefix
 	for _ ,v in ipairs(valid_url_prefixes) do
 		if mw.ustring.match(s, '^%[' .. v ..'[^&quot;%s].*%]' ) then
 			url_prefix = v
 			break
 		end
 	end
 	
 	-- Get display text
 	if not url_prefix then
 		return s
 	end
 	s = s:match(&quot;^%[&quot; .. url_prefix .. &quot;(.*)%]&quot;) -- Grab all of the text after the URL prefix and before the final square bracket.
 	s = s:match('^.-([&quot;&lt;&gt; ].*)') or &quot;&quot; -- Grab all of the text after the first URL separator character (&quot;&lt;&gt; ).
 	s = mw.ustring.match(s, &quot;^%s*(%S.*)$&quot;) or &quot;&quot; -- If the separating character was a space, trim it off.
 	
 	local s_decoded = mw.text.decode(s, true)
 	if mw.ustring.match(s_decoded, &quot;%c&quot;) then
 		return s
 	end
 
 	return s_decoded
 
 end
 
 local function delinkLinkClass(text, pattern, delinkFunction)
 	if type(text) ~= &quot;string&quot; then
 		error(&quot;Attempt to de-link non-string input.&quot;, 2)
 	end
 	if type(pattern) ~= &quot;string&quot; or mw.ustring.sub(pattern, 1, 1) ~= &quot;^&quot; then
 		error('Invalid pattern detected. Patterns must begin with &quot;^&quot;.', 2)
 	end
 	-- Iterate over the text string, and replace any matched text. using the 
 	-- delink function. We need to iterate character by character rather 
 	-- than just use gsub, otherwise nested links aren't detected properly.
 	local result = &quot;&quot;
 	while text ~= &quot;&quot; do
 		-- Replace text using one iteration of gsub.
 		text = mw.ustring.gsub(text, pattern, delinkFunction, 1)
 		-- Append the left-most character to the result string.
 		result = result .. mw.ustring.sub(text, 1, 1)
 		text = mw.ustring.sub(text, 2, -1)
 	end
 	return result
 end
 
 function p._delink(args)
 	local text = args[1] or &quot;&quot;
 	if args.refs == &quot;yes&quot; then
 		-- Remove any [[Help:Strip markers]] representing ref tags. In most situations 
 		-- this is not a good idea - only use it if you know what you are doing!
 		text = mw.ustring.gsub(text, &quot;UNIQ%w*%-ref%-%d*%-QINU&quot;, &quot;&quot;)
 	end
 	if args.comments ~= &quot;no&quot; then
 		text = text:gsub(&quot;&lt;!%-%-.-%-%-&gt;&quot;, &quot;&quot;) -- Remove html comments.
 	end
 
 	if args.wikilinks ~= &quot;no&quot; and args.wikilinks ~= &quot;target&quot; then
 		-- De-link wikilinks and return the label portion of the wikilink.
 		text = delinkLinkClass(text, &quot;^%[%[.-%]%]&quot;, getDelinkedLabel)
 	elseif args.wikilinks == &quot;target&quot; then
 		-- De-link wikilinks and return the target portions of the wikilink.
 		text = delinkLinkClass(text, &quot;^%[%[.-%]%]&quot;, getDelinkedTarget)
 	end
 	if args.urls ~= &quot;no&quot; then
 		text = delinkLinkClass(text, &quot;^%[.-%]&quot;, delinkURL) -- De-link URLs.
 	end
 	if args.whitespace ~= &quot;no&quot; then
 		-- Replace single new lines with a single space, but leave double new lines
 		-- and new lines only containing spaces or tabs before a second new line.
 		text = mw.ustring.gsub(text, &quot;([^\n \t][ \t]*)\n([ \t]*[^\n \t])&quot;, &quot;%1 %2&quot;)
 		text = text:gsub(&quot;[ \t]+&quot;, &quot; &quot;) -- Remove extra tabs and spaces.
 	end
 	return text
 end
 
 function p.delink(frame)
 	if not getArgs then
 		getArgs = require('Module:Arguments').getArgs
 	end
 	return p._delink(getArgs(frame, {wrappers = 'Template:Delink'}))
 end