Jump to content

Module:GetShortDescription/sandbox

From Wikipedia, the free encyclopedia
This is an old revision of this page, as edited by Fred Gandt (talk | contribs) at 02:43, 9 February 2023 (correction for redirect title conversion; will properly test later; so tired). The present address (URL) is a permanent link to this revision, which may differ significantly from the current revision.
local getArgs = require( 'Module:Arguments' ).getArgs
local mLang = require( 'Module:Lang' )

local function pipedLink( name ) return '[[:' .. name ..  '|' .. name .. ']]' end

local function isNone( desc ) return type( desc ) == 'string' and desc:match( '^[Nn]one$' ) end

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

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

local objectify_alarm
local report_redlinks

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]]'
		if objectify_alarm then return { alarm = message } end
	end
	return message
end

-- Grammatically reasonable concatenation of possible issues into one message per problematic link target.
local function previewWarning( 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 ' .. pipedLink( name ) .. ' ' .. 'has ' .. quantity_of_things.templates .. ' {{tlx|short description}}' .. message
		mw.addWarning( alarmingMessage( message, true ) )
	end
end

local function getWikidataDescription( name, lang, not_explicit )
	local wikidata_id = mw.wikibase.getEntityIdForTitle( name )
	if isEmpty( wikidata_id ) then return nil end
	local wikidata_description, wikidata_description_lang = mw.wikibase.getDescriptionWithLang( wikidata_id )
	if isEmpty( wikidata_description ) or isNone( wikidata_description ) then return nil end
	if isEmpty( lang.no ) and notEmpty( wikidata_description_lang ) and wikidata_description_lang ~= 'en' then
		wikidata_description = mLang._lang {
			wikidata_description_lang,
			wikidata_description,
			italic = lang.italic,
			nocat = lang.nocat,
			size = lang.size,
			cat = lang.cat,
			rtl = lang.rtl
		}
	end
	if notEmpty( not_explicit ) then wikidata_description = { wikidata = wikidata_description } end
	return wikidata_description
end

local function getExplicitDescription( name, new_title )
	local page_content = new_title:getContent()
	if isEmpty( page_content ) then
		-- Try to avoid asking if the page exists; it can be expensive.
		if report_redlinks and not new_title.exists then return { redlink = true } end
		return nil
	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
	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 = {}
	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 ] = {}
		for i, param in ipairs( short_description_template_params ) do
			-- Because regular expressions haven't been invented yet...
			-- ignore everything that isn't a declaration of 'noreplace'
			-- or a short description that isn't 'none'.
			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
					if has_equals then param = mw.ustring.gsub( param, '^1%s*=%s*', '' ) end
						-- If we made it this far; grab the short description.
						-- If the template has both a numbered and an unnumbered short description;
						-- whichever comes last (ltr) will be used for the page, so overwriting works out great.
						possible_short_descriptions[ template_content_index ].description = param
						-- But 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 = {}
	for i, possible_short_description in ipairs( possible_short_descriptions ) do
		if possible_short_description.description then
			-- If a description is 'noreplace'-ing; demote it.
			if possible_short_description.noreplace 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( name, quantity_of_things )
	if #short_descriptions >= 1 then return short_descriptions[ #short_descriptions ].description end
	return nil
end

local function isSisterProjectLink( name )
	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 = name: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

local function getShortDescription( args )
	objectify_alarm = args.objectify_alarm
	report_redlinks = args.report_redlinks
	local args_name = args.name
	if isEmpty( args_name ) then return alarmingMessage( 'requires a page name (including namespace)' ) end
	
	local new_title = mw.title.new( args_name )
	new_title = new_title.redirectTarget or new_title
	local name = new_title.prefixedText
	
	local fallback = args.fallback
	if isSisterProjectLink( name ) then return fallback end
	local prefer = args.prefer or 'explicit'
	local only = args.only
	local lang = {
		italic = args.lang_italic,
		nocat = args.lang_nocat,
		size = args.lang_size,
		cat = args.lang_cat,
		rtl = args.lang_rtl,
		no = args.lang_no
	}
	local result
	
	if only == 'explicit' then result = getExplicitDescription( args_name, new_title )
	elseif only == 'wikidata' then result = getWikidataDescription( name, lang )
	elseif prefer == 'explicit' then
		result = getExplicitDescription( args_name, new_title )
		if isEmpty( result ) then result = getWikidataDescription( name, lang, true )
		elseif isNone( result ) then
			local wikidata_description = getWikidataDescription( name, lang, true )
			if notEmpty( wikidata_description ) then
				wikidata_description.none = true
				result = wikidata_description
			end
		end
	elseif prefer == 'wikidata' then result = getWikidataDescription( name, lang ) or getExplicitDescription( args_name, new_title ) end
	
	if isNone( result ) then result = nil end
	
	return result or fallback
end

local p = {}

function p.main( frame )
	local args = getArgs( frame )
	if isEmpty( args ) then return alarmingMessage( 'could not getArgs' ) end
	return getShortDescription( args ) or ''
end

return p