Jump to content

Module:GetShortDescription

Permanently protected module
From Wikipedia, the free encyclopedia
This is an old revision of this page, as edited by Fred Gandt (talk | contribs) at 10:46, 29 January 2023 (test handling all the things). The present address (URL) is a permanent link to this revision, which may differ significantly from the current revision.

local p = {}

local mLang = require( 'Module:Lang' )

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

local function errorMessage( message )
	return '<strong class="error">ERROR with invocation of [[Module:GetShortDescription]]: ' .. message .. '.</strong>'
end

local function previewWarning( name, message )
	mw.addWarning( '<span style="color:#d33">[[Module:GetShortDescription]] has detected that the {{tlc|short description}} on ' ..
		pipedLink( name ) .. ' ' .. message .. '.</span>' )
end

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

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

local function getWikidataDescription( name, lang )
	local wikidata_id = mw.wikibase.getEntityIdForTitle( name )
	
	-- Return nil immediately if we don't know the wikidata_id
	if isEmpty( wikidata_id ) then return nil end
	
	local wikidata_description, wikidata_description_lang = mw.wikibase.getDescriptionWithLang( wikidata_id )
	
	-- Return nil immediately if we don't get a description
	if isEmpty( wikidata_description ) then return nil end
	
	-- Return wikidata_description immediately if no more processing is required.
	if notEmpty( lang.no ) or wikidata_description_lang == 'en' then return wikidata_description end
	
	if isEmpty( wikidata_description_lang ) then return nil end
	return  mLang._lang {
		wikidata_description_lang,
		wikidata_description,
		italic = lang.italic,
		nocat = lang.nocat,
		size = lang.size,
		cat = lang.cat,
		rtl = lang.rtl
	}
end

local function getExplicitDescription( name )
	local page_content = mw.title.new( name ):getContent()
	if isEmpty( page_content ) then return errorMessage( 'could not getContent of ' .. pipedLink( name ) ) end
	
	-- The following mess is required as an alternative to preprocessing,
	-- which apart from being expensive:
		-- causes empty strings to be returned if the invocation is substituted
		-- cannot differentiate which of multiple short descriptions is the one being applied
	-- More than one short description template?
	-- Yup.
	
	local contents_of_all_short_description_templates = {}
	
	-- For all templates:
	for template in mw.ustring.gmatch( page_content, '%{%b{}}' ) do
		
		-- Test for short description content
		local short_description_content = mw.ustring.match( template, '^{{%s*[Ss]hort description%s*|%s*(.-)%s*}}' )
		
		-- and if found
		if notEmpty( short_description_content ) then
			
			-- add it to contents_of_all_short_description_templates.
			contents_of_all_short_description_templates[ #contents_of_all_short_description_templates+1 ] = short_description_content
			
		-- In order to break as soon as possible after searching for short descriptions;
		-- test for templates almost certain to follow, like citation templates, and if found, break.
		-- elseif mw.ustring.match( template, '^{{%s*[Cc]it[ea]' ) then break
		end
	end
	
	-- Return nil immediately if no contents_of_all_short_description_templates are found
	local number_of_short_description_templates = #contents_of_all_short_description_templates
	if number_of_short_description_templates < 1 then return nil end
	
	-- Short descriptions defined by template {{short description}} may properly contain:
		-- a numbered or unnumbered 1st param for the description
		-- a numbered or unnumbered 2nd param for noreplace
		-- the pagetype named param
	-- but may also contain:
		-- an empty description or no piped params at all
		-- two descriptions; one numbered and one not
		-- unknown params
	-- we might therefore need to understand the content of:
		-- {{short description|2=noreplace|pagetype=Redirect|Short desc}} or
		-- {{short description|2=noreplace|1=Short desc|pagetype=Redirect}} or
		-- {{short description|pagetype=Redirect|Short desc|noreplace}} or
		-- {{short description|unknown=param|Short desc}} or
		-- {{short description|Short desc|1=Another short desc}} and so on
	-- all with a variety white space.
	
	if number_of_short_description_templates > 1 then
		previewWarning( name, 'has ' .. number_of_short_description_templates .. ' short description templates' )
	end
	
	local possible_short_descriptions = {}
	for tci, short_description_template_contents in ipairs( contents_of_all_short_description_templates ) do
		possible_short_descriptions[ tci ] = {}
		local short_description_template_params = mw.text.split( short_description_template_contents, '%s*|%s*' )
		if #short_description_template_params > 3 then
			previewWarning( name, 'is [[Template:Short description/doc|misconfigured]]' )
		end
		for i, param in ipairs( short_description_template_params ) do
			if not param:match( '=' ) or param:match( '^1' ) then
				if param == 'noreplace' then
					possible_short_descriptions[ tci ][ 'noreplace' ] = true
				else
					possible_short_descriptions[ tci ][ 'description' ] = param
				end
			end
		end
	end
	
	-- remove possible_short_descriptions with no descriptions
	-- and demote noreplace descriptions
	
	local probable_short_descriptions = {}
	
	for i, possible_short_description in ipairs( possible_short_descriptions ) do
		if possible_short_description[ 'description' ] then
			if possible_short_description[ 'noreplace' ] then
				table.insert( probable_short_descriptions, #probable_short_descriptions, possible_short_description )
			end
			probable_short_descriptions[ #probable_short_descriptions+1 ] = possible_short_description
		end
	end
	
	if #probable_short_descriptions < 1 then
		previewWarning( name, 'declares no short description' )
		return nil
	elseif #probable_short_descriptions > 1 then
		previewWarning( name, 'declares ' .. #possible_short_descriptions .. ' short descriptions' ) -- TODO: this when we know more
	end
	
	mw.logObject( probable_short_descriptions )
	
	local probable_short_description = probable_short_descriptions[ #probable_short_descriptions ][ 'description' ]
	
	mw.log( probable_short_description )
	
	-- The possible_short_description might be in the form 'short description' or '1=short description',
	-- but it could also simply start with a '1'.
	if probable_short_description:match( '=' ) then
		probable_short_description = mw.ustring.gsub( probable_short_description, '^1%s*=%s*', '' )
	end
	
	-- Now we know what this template's short description is; check if it's in use and return nil if not.
	if probable_short_description:match( '^[Nn]one$' ) then return nil end
	
	mw.log( probable_short_description )
	return probable_short_description
end

local function getShortDescription( args )
	local name = args.name
	if isEmpty( name ) then return errorMessage( 'a page name (including namespace) MUST be provided' ) end
	local result
	local only = args.only
	local prefer = args.prefer
	if isEmpty( prefer ) then prefer = 'explicit' end
	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
	}
	if only == 'explicit' then result = getExplicitDescription( name ) -- TODO: if the end result is noreplace; the real short desc might be implicit or wikidata
	elseif only == 'wikidata' then result = getWikidataDescription( name, lang )
	elseif prefer == 'explicit' then result = getExplicitDescription( name ) or getWikidataDescription( name, lang )
	elseif prefer == 'wikidata' then result = getWikidataDescription( name, lang ) or getExplicitDescription( name )
	end
	return result or args.fallback
end

function p.main( frame ) return getShortDescription( frame.args ) or '' end

return p