Jump to content

Module:GetShortDescription/sandbox: Difference between revisions

From Wikipedia, the free encyclopedia
Content deleted Content added
testing redirected detection of explicits
test page content while we have it for redirect syntax; to finish later
Line 1: Line 1:


local function isEmpty( value ) return value == nil or value == '' end
local function isEmpty(value) return value == nil or value == '' end


local function notEmpty( value ) return not isEmpty( value ) end
local function notEmpty(value) return not isEmpty(value) end


local function isNone( value ) return value:lower() == 'none' end
local function isNone(value) return value:lower() == 'none' end


local function alarmingMessage( message, preview )
local function alarmingMessage(message, preview)
message = '<span style="color:#d33">[[Module:GetShortDescription]] ' .. message .. '.</span>'
message = '<span style="color:#d33">[[Module:GetShortDescription]] '..message..'.</span>'
if not preview then message = message .. '[[Category:Pages displaying alarming messages about Module:GetShortDescription]]' end
if not preview then
message = message..'[[Category:Pages displaying alarming messages about Module:GetShortDescription]]'
end
return message
return message
end
end


-- Grammatically reasonable concatenation of possible issues into one message per problematic link target.
-- Grammatically reasonable concatenation of possible issues into one message per problematic link target.
local function previewWarning( args_name, quantity_of_things )
local function previewWarning(args_name, quantity_of_things)
local message = ''
local message = ''
if quantity_of_things.params > 3 then message = message .. ' with extraneous parameters' end
if quantity_of_things.params > 3 then
message = message..' with extraneous parameters'
end
if quantity_of_things.descriptions > 1 then message = message .. ', declaring ' .. quantity_of_things.descriptions .. ' short descriptions' end
if quantity_of_things.descriptions > 1 then
message = message..', declaring '..quantity_of_things.descriptions..' short descriptions'
end
if quantity_of_things.templates > 1 or notEmpty( message ) then
if quantity_of_things.templates > 1 or notEmpty(message) then
message = 'has detected that [[:' .. args_name .. '|' .. args_name .. ']] has ' .. quantity_of_things.templates .. ' {{tlx|short description}}' .. message
message = 'has detected that [[:'..args_name..'|'..args_name..']] has '..
quantity_of_things.templates..' {{tlx|short description}}'..message
mw.addWarning( alarmingMessage( message, true ) )
mw.addWarning(alarmingMessage(message, true))
end
end
end
end


local function getWikidataDescription( title, args, fallback )
local function getWikidataDescription(title, args, fallback)
local wikidata_id = mw.wikibase.getEntityIdForTitle( title )
local wikidata_id = mw.wikibase.getEntityIdForTitle(title)
if isEmpty( wikidata_id ) then return nil end
if isEmpty(wikidata_id) then
return nil
end
local wikidata_description, wikidata_description_lang = mw.wikibase.getDescriptionWithLang( wikidata_id )
local wikidata_description, wikidata_description_lang = mw.wikibase.getDescriptionWithLang(wikidata_id)
if isEmpty( wikidata_description ) then return nil end
if isEmpty(wikidata_description) then
return nil
end
local result = { wikidata = wikidata_description }
local result = {wikidata = wikidata_description}
if isEmpty( args.lang_no ) and notEmpty( wikidata_description_lang ) and wikidata_description_lang ~= 'en' then
if isEmpty(args.lang_no) and notEmpty(wikidata_description_lang) and wikidata_description_lang ~= 'en' then
-- According to the docs this is a possibility...
-- According to the docs this is a possibility...
result.wikidata = require( 'Module:Lang' )._lang {
result.wikidata = require('Module:Lang')._lang{
wikidata_description_lang,
wikidata_description_lang,
wikidata_description,
wikidata_description,
Line 45: Line 56:
end
end


local function getShortDescriptionTemplates( title_table )
local function getShortDescriptionTemplates(title_table)
local page_content = title_table:getContent()
local page_content = title_table:getContent()
-- Assume no content means a nonexistent title because it's cheaper than testing if it exists.
-- Assume no content means a nonexistent title because it's cheaper than testing if it exists.
if isEmpty( page_content ) then return { redlink = true } end
if isEmpty(page_content) then
return {redlink = true}
end
local contents_of_all_short_description_templates = {}
local contents_of_all_short_description_templates = {}
-- Because there could be any number of short description templates, and not all where there should be; get all the templates.
-- Because there could be any number of short description templates, and not all where there should be; get all the templates.
for template in page_content:gmatch( '{%b{}}' ) do
for template in page_content:gmatch('{%b{}}') do
local short_description_content = mw.ustring.match( template, '^{{%s*[Ss]hort description%s*|%s*(.-)%s*}}' )
local short_description_content = mw.ustring.match(template, '^{{%s*[Ss]hort description%s*|%s*(.-)%s*}}')
if notEmpty( short_description_content ) then
if notEmpty(short_description_content) then
-- Collect the contents of short description templates.
-- Collect the contents of short description templates.
contents_of_all_short_description_templates[ #contents_of_all_short_description_templates+1 ] = short_description_content
contents_of_all_short_description_templates[#contents_of_all_short_description_templates+1] = short_description_content
end
end
-- An opportunity for efficiency gain exists - to break if another type of template is found e.g. citation templates,
-- An opportunity for efficiency gain exists - to break if another type of template is found e.g. citation templates,
-- but on an appallingly formatted page, a short description template down by the categories would likely be missed.
-- but on an appallingly formatted page, a short description template down by the categories would likely be missed.
end
end
-- Better to lower/upper the case of the possibly very long page_content or this?
local redirect_page = mw.ustring.match(page_content, '^%s*#[Rr][Ee][Dd][Ii][Rr][Ee][Cc][Tt]%s*%[%[')
if redirect_page then
mw.log('redirect page')
-- pass this info along
end
return contents_of_all_short_description_templates
return contents_of_all_short_description_templates
end
end


local function getShortDescription( args_name, args_name_title_table, title, title_table, fallback )
local function getShortDescription(args_name, args_name_title_table, title, title_table, fallback)
local contents_of_all_short_description_templates = {}
local contents_of_all_short_description_templates = {}
local redirected
local redirected
Line 72: Line 93:
-- Check for short description templates on redirect pages.
-- Check for short description templates on redirect pages.
if title ~= args_name then
if title ~= args_name then
contents_of_all_short_description_templates = getShortDescriptionTemplates( args_name_title_table )
contents_of_all_short_description_templates = getShortDescriptionTemplates(args_name_title_table)
if contents_of_all_short_description_templates.redlink then return contents_of_all_short_description_templates end
if contents_of_all_short_description_templates.redlink then
return contents_of_all_short_description_templates
end
redirected = false
redirected = false
end
end
if #contents_of_all_short_description_templates < 1 then
if #contents_of_all_short_description_templates < 1 then
contents_of_all_short_description_templates = getShortDescriptionTemplates( title_table )
contents_of_all_short_description_templates = getShortDescriptionTemplates(title_table)
if notEmpty( redirected ) then redirected = true end
if notEmpty(redirected) then
redirected = true
end
end
end
if contents_of_all_short_description_templates.redlink then return contents_of_all_short_description_templates end
if contents_of_all_short_description_templates.redlink then
return contents_of_all_short_description_templates
end
if #contents_of_all_short_description_templates < 1 then return nil end
if #contents_of_all_short_description_templates < 1 then
return nil
end
local quantity_of_things = {
local quantity_of_things = {
Line 95: Line 124:
-- Look through the short description templates:
-- Look through the short description templates:
for template_content_index, short_description_template_contents in ipairs( contents_of_all_short_description_templates ) do
for template_content_index, short_description_template_contents in ipairs(contents_of_all_short_description_templates) do
-- Split the contents at pipes and trim.
-- Split the contents at pipes and trim.
local short_description_template_params = mw.text.split( short_description_template_contents, '%s*|%s*' )
local short_description_template_params = mw.text.split(short_description_template_contents, '%s*|%s*')
if #short_description_template_params > quantity_of_things.params then
if #short_description_template_params > quantity_of_things.params then
quantity_of_things.params = #short_description_template_params
quantity_of_things.params = #short_description_template_params
end
end
possible_short_descriptions[ template_content_index ] = {}
possible_short_descriptions[template_content_index] = {}
-- Look through the params:
-- Look through the params:
for i, param in ipairs( short_description_template_params ) do
for i, param in ipairs(short_description_template_params) do
if param == 'noreplace' or mw.ustring.match( param, '^2%s*=%s*noreplace$' ) then
if param == 'noreplace' or mw.ustring.match(param, '^2%s*=%s*noreplace$') then
-- Take note of 'noreplace'-ing for establishment of hierarchy later.
-- Take note of 'noreplace'-ing for establishment of hierarchy later.
possible_short_descriptions[ template_content_index ].noreplace = true
possible_short_descriptions[template_content_index].noreplace = true
else
else
local has_equals = param:match( '=' )
local has_equals = param:match('=')
if not has_equals or param:match( '^1' ) then
if not has_equals or param:match('^1') then
-- Grab the short description.
-- Grab the short description.
if has_equals then param = mw.ustring.gsub( param, '^1%s*=%s*', '' ) end
if has_equals then
param = mw.ustring.gsub(param, '^1%s*=%s*', '')
end
-- If the template has both a numbered and an unnumbered short description;
-- If the template has both a numbered and an unnumbered short description;
-- whichever comes last (ltr) will be used by that template, so overwriting works out great.
-- whichever comes last (ltr) will be used by that template, so overwriting works out great.
possible_short_descriptions[ template_content_index ].description = param
possible_short_descriptions[template_content_index].description = param
-- And we want to know the total quantity of descriptions being declared.
-- And we want to know the total quantity of descriptions being declared.
quantity_of_things.descriptions = quantity_of_things.descriptions + 1
quantity_of_things.descriptions = quantity_of_things.descriptions + 1
Line 126: Line 157:
-- Look through the possible short descriptions for definite short descriptions,
-- Look through the possible short descriptions for definite short descriptions,
-- and prepare for working out which of possibly multiple short descriptions is actually being applied for the page:
-- and prepare for working out which of possibly multiple short descriptions is actually being applied for the page:
for i, possible_short_description in ipairs( possible_short_descriptions ) do
for i, possible_short_description in ipairs(possible_short_descriptions) do
if possible_short_description.description then
if possible_short_description.description then
-- If a description is 'noreplace'-ing or 'none'; demote it.
-- If a description is 'noreplace'-ing or 'none'; demote it.
if ( possible_short_description.noreplace or isNone( possible_short_description.description ) ) and #possible_short_descriptions > 1 then
if (possible_short_description.noreplace or isNone(possible_short_description.description)) and
#possible_short_descriptions > 1 then
-- But don't demote it if it's already at the bottom.
-- But don't demote it if it's already at the bottom.
if i > 1 then table.insert( short_descriptions, #short_descriptions, possible_short_description )
if i > 1 then
table.insert(short_descriptions, #short_descriptions, possible_short_description)
else
else short_descriptions[ #short_descriptions+1 ] = possible_short_description end
else short_descriptions[ #short_descriptions+1 ] = possible_short_description end
short_descriptions[#short_descriptions+1] = possible_short_description
end
else
short_descriptions[#short_descriptions+1] = possible_short_description
end
end
end
end
end
-- Let previewWarning() work out if these numbers are bad.
-- Let previewWarning() work out if these numbers are bad.
previewWarning( args_name, quantity_of_things )
previewWarning(args_name, quantity_of_things)
if #short_descriptions >= 1 then
if #short_descriptions >= 1 then
-- Pop!
-- Pop!
local short_description = short_descriptions[ #short_descriptions ].description
local short_description = short_descriptions[#short_descriptions].description
if notEmpty( short_description ) then return { explicit = short_description, fellback = fallback, redirected = redirected } end
if notEmpty(short_description) then
return {explicit = short_description, fellback = fallback, redirected = redirected}
end
end
end
return nil
return nil
end
end


local function isSisterProjectLink( title )
local function isSisterProjectLink(title)
local sister_project_prefixes = {
local sister_project_prefixes = {
'wiktionary', 'wikt',
'wiktionary', 'wikt',
Line 167: Line 205:
'phabricator', 'phab'
'phabricator', 'phab'
}
}
local pre_colon = title:match( '^(%a+):' )
local pre_colon = title:match('^(%a+):')
if pre_colon then
if pre_colon then
for i, sister in ipairs( sister_project_prefixes ) do
for i, sister in ipairs(sister_project_prefixes) do
if pre_colon == sister then return true end
if pre_colon == sister then
return true
end
end
end
end
end
Line 178: Line 218:
-- Literally testing if title_table.isRedirect can be expensive;
-- Literally testing if title_table.isRedirect can be expensive;
-- processing this way resolves (multiple) redirects without the possibly expensive check.
-- processing this way resolves (multiple) redirects without the possibly expensive check.
local function getTitleAndTable( orig_name )
local function getTitleAndTable(orig_name)
local title_table = mw.title.new( orig_name )
local title_table = mw.title.new(orig_name)
title_table = title_table.redirectTarget or title_table
title_table = title_table.redirectTarget or title_table
local title = title_table.prefixedText
local title = title_table.prefixedText
Line 185: Line 225:
return title, title_table
return title, title_table
end
end
return getTitleAndTable( title )
return getTitleAndTable(title)
end
end


local function getDescription( args )
local function getDescription(args)
local args_name = args.name
local args_name = args.name
if isEmpty( args_name ) then return { alarm = 'requires a page name (including namespace)' } end
if isEmpty(args_name) then
return {alarm = 'requires a page name (including namespace)'}
end
-- Keep the orginal name, cleaned up, and its title_table for later.
-- Keep the orginal name, cleaned up, and its title_table for later.
local args_name_title_table = mw.title.new( args_name )
local args_name_title_table = mw.title.new(args_name)
args_name = args_name_title_table.prefixedText
args_name = args_name_title_table.prefixedText
if isSisterProjectLink( args_name ) then return nil end
if isSisterProjectLink(args_name) then
return nil
end
local title, title_table = getTitleAndTable( args_name )
local title, title_table = getTitleAndTable(args_name)
if title ~= args_name then
if title ~= args_name then
if isSisterProjectLink( title ) then return nil end
if isSisterProjectLink(title) then
return nil
end
end
end
Line 209: Line 255:
-- Pass args_name to getShortDescription() so previewWarning()s won't be confusing for redirects.
-- Pass args_name to getShortDescription() so previewWarning()s won't be confusing for redirects.
if notEmpty( only ) then
if notEmpty(only) then
if only == 'explicit' then return getShortDescription( args_name, args_name_title_table, title, title_table ) end
if only == 'explicit' then
return getShortDescription(args_name, args_name_title_table, title, title_table)
end
if only == 'wikidata' then return getWikidataDescription( title, args ) end
if only == 'wikidata' then
return getWikidataDescription(title, args)
end
return { alarm = 'accepts either "explicit" or "wikidata" as the value of |only=' }
return {alarm = 'accepts either "explicit" or "wikidata" as the value of |only='}
end
end
if notEmpty( prefer ) then
if notEmpty(prefer) then
if prefer == 'explicit' then
if prefer == 'explicit' then
local short_description = getShortDescription( args_name, args_name_title_table, title, title_table )
local short_description = getShortDescription(args_name, args_name_title_table, title, title_table)
if notEmpty( short_description ) then
if notEmpty(short_description) then
-- Assume a Wikidata search would be a bad idea for an assumed nonexistent title.
-- Assume a Wikidata search would be a bad idea for an assumed nonexistent title.
if short_description.redlink or ( not isNone( short_description.explicit ) or args.none_is_valid ) then return short_description end
if short_description.redlink or (not isNone(short_description.explicit) or args.none_is_valid) then
return short_description
end
end
end
return getWikidataDescription( title, args, true )
return getWikidataDescription(title, args, true)
end
if prefer == 'wikidata' then
return getWikidataDescription(title, args) or getShortDescription(args_name, args_name_title_table, title, title_table, true)
end
end
return {alarm = 'accepts either "explicit" or "wikidata" as the value of |prefer='}
if prefer == 'wikidata' then return getWikidataDescription( title, args ) or getShortDescription( args_name, args_name_title_table, title, title_table, true ) end
return { alarm = 'accepts either "explicit" or "wikidata" as the value of |prefer=' }
end
end
end
end


local function main( args )
local function main(args)
local result = getDescription( args )
local result = getDescription(args)
if notEmpty( result ) then
if notEmpty(result) then
if result.alarm then result.alarm = alarmingMessage( result.alarm ) end
if result.alarm then
result.alarm = alarmingMessage(result.alarm)
end
if args.stringify then
if args.stringify then
if result.alarm then result = result.alarm else
if result.alarm then
result = result.alarm
else
result = result.explicit or result.wikidata
result = result.explicit or result.wikidata
if args.none_is_nil and isNone( result ) then result = nil end
if args.none_is_nil and isNone(result) then
result = nil
end
end
end
elseif not result.alarm and args.none_is_nil then
elseif not result.alarm and args.none_is_nil then
local description = result.explicit or result.wikidata
local description = result.explicit or result.wikidata
if description and args.none_is_nil and isNone( description ) then result = nil end
if description and args.none_is_nil and isNone(description) then
result = nil
end
end
end
end
end
Line 248: Line 310:
local p = {}
local p = {}


function p.main( frame )
function p.main(frame)
local args = require( 'Module:Arguments' ).getArgs( frame )
local args = require('Module:Arguments').getArgs(frame)
if isEmpty( args ) then return alarmingMessage( 'could not getArgs' ) end -- This really would be alarming.
if isEmpty(args) then
return alarmingMessage('could not getArgs') -- This really would be alarming.
end
return main( args )
return main(args)
end
end



Revision as of 05:39, 21 February 2023

local function isEmpty(value) return value == nil or value == '' end

local function notEmpty(value) return not isEmpty(value) end

local function isNone(value) return value:lower() == 'none' end

local function alarmingMessage(message, preview)
	message = '<span style="color:#d33">[[Module:GetShortDescription]] '..message..'.</span>'
	if not preview then
		message = message..'[[Category:Pages displaying alarming messages about Module:GetShortDescription]]'
	end
	return message
end

-- Grammatically reasonable concatenation of possible issues into one message per problematic link target.
local function previewWarning(args_name, quantity_of_things)
	local message = ''
	if quantity_of_things.params > 3 then
		message = message..' with extraneous parameters'
	end
	if quantity_of_things.descriptions > 1 then
		message = message..', declaring '..quantity_of_things.descriptions..' short descriptions'
	end
	if quantity_of_things.templates > 1 or notEmpty(message) then
		message = 'has detected that [[:'..args_name..'|'..args_name..']] has '..
			quantity_of_things.templates..' {{tlx|short description}}'..message
		mw.addWarning(alarmingMessage(message, true))
	end
end

local function getWikidataDescription(title, args, fallback)
	local wikidata_id = mw.wikibase.getEntityIdForTitle(title)
	if isEmpty(wikidata_id) then
		return nil
	end
	local wikidata_description, wikidata_description_lang = mw.wikibase.getDescriptionWithLang(wikidata_id)
	if isEmpty(wikidata_description) then
		return nil
	end
	local result = {wikidata = wikidata_description}
	if isEmpty(args.lang_no) and notEmpty(wikidata_description_lang) and wikidata_description_lang ~= 'en' then
		-- According to the docs this is a possibility...
		result.wikidata = require('Module:Lang')._lang{
			wikidata_description_lang,
			wikidata_description,
			italic = args.lang_italic,
			nocat = args.lang_nocat,
			size = args.lang_size,
			cat = args.lang_cat,
			rtl = args.lang_rtl
		}
	end
	result.fellback = fallback
	return result
end

local function getShortDescriptionTemplates(title_table)
	local page_content = title_table:getContent()
	
	-- Assume no content means a nonexistent title because it's cheaper than testing if it exists.
	if isEmpty(page_content) then
		return {redlink = true}
	end
	
	local contents_of_all_short_description_templates = {}
	
	-- Because there could be any number of short description templates, and not all where there should be; get all the templates.
	for template in page_content:gmatch('{%b{}}') do
		local short_description_content = mw.ustring.match(template, '^{{%s*[Ss]hort description%s*|%s*(.-)%s*}}')
		if notEmpty(short_description_content) then
			-- Collect the contents of short description templates.
			contents_of_all_short_description_templates[#contents_of_all_short_description_templates+1] = short_description_content
		end
		-- An opportunity for efficiency gain exists - to break if another type of template is found e.g. citation templates,
		-- but on an appallingly formatted page, a short description template down by the categories would likely be missed.
	end
	
	-- Better to lower/upper the case of the possibly very long page_content or this?
	local redirect_page = mw.ustring.match(page_content, '^%s*#[Rr][Ee][Dd][Ii][Rr][Ee][Cc][Tt]%s*%[%[')
	if redirect_page then
		mw.log('redirect page')
		-- pass this info along
	end
	
	return contents_of_all_short_description_templates
end

local function getShortDescription(args_name, args_name_title_table, title, title_table, fallback)
	local contents_of_all_short_description_templates = {}
	local redirected
	
	-- Check for short description templates on redirect pages.
	if title ~= args_name then
		contents_of_all_short_description_templates = getShortDescriptionTemplates(args_name_title_table)
		if contents_of_all_short_description_templates.redlink then
			return contents_of_all_short_description_templates
		end
		redirected = false
	end
	
	if #contents_of_all_short_description_templates < 1 then
		contents_of_all_short_description_templates = getShortDescriptionTemplates(title_table)
		if notEmpty(redirected) then
			redirected = true
		end
	end
	
	if contents_of_all_short_description_templates.redlink then
		return contents_of_all_short_description_templates
	end
	
	if #contents_of_all_short_description_templates < 1 then
		return nil
	end
	
	local quantity_of_things = {
		templates = #contents_of_all_short_description_templates,
		descriptions = 0,
		params = 0
	}
	
	local possible_short_descriptions = {}
	
	-- Look through the short description templates:
	for template_content_index, short_description_template_contents in ipairs(contents_of_all_short_description_templates) do
		-- Split the contents at pipes and trim.
		local short_description_template_params = mw.text.split(short_description_template_contents, '%s*|%s*')
		if #short_description_template_params > quantity_of_things.params then
			quantity_of_things.params = #short_description_template_params
		end
		possible_short_descriptions[template_content_index] = {}
		-- Look through the params:
		for i, param in ipairs(short_description_template_params) do
			if param == 'noreplace' or mw.ustring.match(param, '^2%s*=%s*noreplace$') then
				-- Take note of 'noreplace'-ing for establishment of hierarchy later.
				possible_short_descriptions[template_content_index].noreplace = true
			else
				local has_equals = param:match('=')
				if not has_equals or param:match('^1') then
					-- Grab the short description.
					if has_equals then
						param = mw.ustring.gsub(param, '^1%s*=%s*', '')
					end
					-- If the template has both a numbered and an unnumbered short description;
					-- whichever comes last (ltr) will be used by that template, so overwriting works out great.
					possible_short_descriptions[template_content_index].description = param
					-- And we want to know the total quantity of descriptions being declared.
					quantity_of_things.descriptions = quantity_of_things.descriptions + 1
				end
			end
		end
	end
	
	local short_descriptions = {}
	
	-- Look through the possible short descriptions for definite short descriptions,
	-- and prepare for working out which of possibly multiple short descriptions is actually being applied for the page:
	for i, possible_short_description in ipairs(possible_short_descriptions) do
		if possible_short_description.description then
			-- If a description is 'noreplace'-ing or 'none'; demote it.
			if (possible_short_description.noreplace or isNone(possible_short_description.description)) and
				#possible_short_descriptions > 1 then
				-- But don't demote it if it's already at the bottom.
				if i > 1 then
					table.insert(short_descriptions, #short_descriptions, possible_short_description)
				else
					short_descriptions[#short_descriptions+1] = possible_short_description
				end
			else
				short_descriptions[#short_descriptions+1] = possible_short_description
			end
		end
	end
	
	-- Let previewWarning() work out if these numbers are bad.
	previewWarning(args_name, quantity_of_things)
	
	if #short_descriptions >= 1 then
		-- Pop!
		local short_description = short_descriptions[#short_descriptions].description
		if notEmpty(short_description) then
			return {explicit = short_description, fellback = fallback, redirected = redirected}
		end
	end
	return nil
end

local function isSisterProjectLink(title)
	local sister_project_prefixes = {
		'wiktionary', 'wikt',
		'wikinews', 'n',
		'wikibooks', 'b',
		'wikiquote', 'q',
		'wikisource', 's',
		'wikispecies', 'species',
		'wikiversity', 'v',
		'wikivoyage', 'voy',
		'commons', 'c',
		'wikidata', 'd',
		'mediawikiwiki', 'mw',
		'wikimedia', 'foundation', 'wmf',
		'meta', 'm',
		'incubator',
		'phabricator', 'phab'
	}
	local pre_colon = title:match('^(%a+):')
	if pre_colon then
		for i, sister in ipairs(sister_project_prefixes) do
			if pre_colon == sister then
				return true
			end
		end
	end
	return false
end

-- Literally testing if title_table.isRedirect can be expensive;
-- processing this way resolves (multiple) redirects without the possibly expensive check.
local function getTitleAndTable(orig_name)
	local title_table = mw.title.new(orig_name)
	title_table = title_table.redirectTarget or title_table
	local title = title_table.prefixedText
	if title == orig_name then
		return title, title_table
	end
	return getTitleAndTable(title)
end

local function getDescription(args)
	local args_name = args.name
	if isEmpty(args_name) then
		return {alarm = 'requires a page name (including namespace)'}
	end
	
	-- Keep the orginal name, cleaned up, and its title_table for later.
	local args_name_title_table = mw.title.new(args_name)
	args_name = args_name_title_table.prefixedText
	
	if isSisterProjectLink(args_name) then
		return nil
	end
	
	local title, title_table = getTitleAndTable(args_name)
	
	if title ~= args_name then
		if isSisterProjectLink(title) then
			return nil
		end
	end
	
	local only = args.only
	local prefer = args.prefer or 'explicit'
	
	-- Pass args_name to getShortDescription() so previewWarning()s won't be confusing for redirects.
	
	if notEmpty(only) then
		if only == 'explicit' then
			return getShortDescription(args_name, args_name_title_table, title, title_table)
		end
		if only == 'wikidata' then
			return getWikidataDescription(title, args)
		end
		return {alarm = 'accepts either "explicit" or "wikidata" as the value of |only='}
	end
	
	if notEmpty(prefer) then
		if prefer == 'explicit' then
			local short_description = getShortDescription(args_name, args_name_title_table, title, title_table)
			if notEmpty(short_description) then
				-- Assume a Wikidata search would be a bad idea for an assumed nonexistent title.
				if short_description.redlink or (not isNone(short_description.explicit) or args.none_is_valid) then
					return short_description
				end
			end
			return getWikidataDescription(title, args, true)
		end
		if prefer == 'wikidata' then
			return getWikidataDescription(title, args) or getShortDescription(args_name, args_name_title_table, title, title_table, true)
		end
		return {alarm = 'accepts either "explicit" or "wikidata" as the value of |prefer='}
	end
end

local function main(args)
	local result = getDescription(args)
	if notEmpty(result) then
		if result.alarm then
			result.alarm = alarmingMessage(result.alarm)
		end
		if args.stringify then
			if result.alarm then
				result = result.alarm
			else
				result = result.explicit or result.wikidata
				if args.none_is_nil and isNone(result) then
					result = nil
				end
			end
		elseif not result.alarm and args.none_is_nil then
			local description = result.explicit or result.wikidata
			if description and args.none_is_nil and isNone(description) then
				result = nil
			end
		end
	end
	return result
end

local p = {}

function p.main(frame)
	local args = require('Module:Arguments').getArgs(frame)
	if isEmpty(args) then
		return alarmingMessage('could not getArgs') -- This really would be alarming.
	end
	return main(args)
end

return p