Permanently protected module
From Wikipedia, the free encyclopedia


--- @module

local p = {}



local maintenance_categories = {

	incorrectly_formatted = "[[Category:Pages using infobox television episode with incorrectly formatted values|%s]]",

	unlinked_values = "[[Category:Pages using infobox television episode with unlinked values|%s]]",

	image_values_without_an_image = "[[Category:Pages using infobox television episode with image-related values without an image]]",

	unnecessary_title_parameter = "[[Category:Pages using infobox television episode with unnecessary title parameter]]",

	non_matching_title = "[[Category:Pages using infobox television episode with non-matching title]]",

	flag_icon = "[[Category:Pages using infobox television with flag icon]]",

	dates_incorrectly_formatted = "[[Category:Pages using infobox television episode with nonstandard dates]]",

	manual_display_title = "[[Category:Pages using infobox television episode with unnecessary manual displaytitle]]",

	list_markup = "[[Category:Pages using infobox television episode with unnecessary list markup]]",

}



--- Returns the text after removing line breaks (<br> tags) and additional spaces as a result.

---

--- @param text string

--- @return string

local function get_name_with_br_fixes(text)

	local title, _ = string.gsub(text, "<br%s?/?>", "")

	title, _ = string.gsub(title, "  ", " ")

	return title

end



--- Returns the page name after replacing quotation marks for single quotes and fixing it to use the

--- "Space+single" and "Single+space" templates if a leading or trailing apostrophe or quotation mark is used.

---

--- Note: per [[MOS:QWQ]] an episode title with quotation marks should be replaced with single quotes.

---

--- @param frame table

--- @param article_title string

--- @return string

local function get_page_name_with_apostrophe_quotation_fixes(frame, article_title)

	local page_name, _ = string.gsub(article_title, '"', "'")



	local left_side_template = frame:expandTemplate{title = "Space+single"}

	local right_side_template = frame:expandTemplate{title = "Single+space"}

	page_name, _ = string.gsub(string.gsub(page_name, "^'", left_side_template), "'$", right_side_template)



	return page_name

end



--- Returns the series link.

---

--- @param series string

--- @return string

local function get_series_link(series)

	local delink = require("Module:Delink")._delink

	return delink({series, wikilinks = "target"})

end



--- Returns two strings:

---- The series name after de-linking it and escaping "-".

---- The series name after de-linking it.

---

--- @param series string

--- @return string, string

local function get_series_name(series)

	local delink = require("Module:Delink")._delink

	local series_name = delink({series})



	-- Escape the character "-" as it is needed for string.find() to work.

	local _

	local series_name_escaped, _ = string.gsub(series_name, "-", "%%-")

	return series_name_escaped, series_name

end



--- Returns a table consisting of the episode's title parts.

---

--- The return table's properties:

--- - title - The episode's title.

--- - disambiguation - the disambiguation text without parentheses.

---

--- Note: could potentially be moved to an outside module for other template and module uses.

---

--- @param text string

--- @return table<string, string | nil>

local function get_title_parts(text)

	local title, disambiguation = string.match(text, "^(.+) (%b())$")



	local titleString = title -- TODO: needed until https://github.com/Benjamin-Dobell/IntelliJ-Luanalysis/issues/63 is resolved.

	if not title or type(title) ~= "string" then

		titleString = text

	end



	---@type table<string, string | nil>

	local title_parts = {title = --[[---@not number | nil]] titleString, disambiguation = nil}



	if not disambiguation or type(disambiguation) ~= "string" then

		return title_parts

	end



	-- Remove outside parentheses from names which use parentheses as part of the name such as "episode (Randall and Hopkirk (Deceased))".

	disambiguation = string.sub(--[[---@not number | nil]] disambiguation, 2, -2)

	title_parts.disambiguation = --[[---@not number]] disambiguation

	return title_parts

end



--- Returns the title used in the {{Lowercase title}} template and an optional maintenance category.

---

--- @param page_text string

--- @param args table

--- @param title_parts table

--- @return string | nil

local function get_lowercase_template_status(page_text, args, title_parts)

	local lowercase_template =  string.match(page_text, "{{[Ll]owercase title.-}}")

	if lowercase_template then

		local lowercase_title, _ = string.gsub(title_parts.title,"^%u", string.lower)

		if args.title then

			if args.title == lowercase_title then

				return maintenance_categories.unnecessary_title_parameter

			else

				return maintenance_categories.non_matching_title

			end

			return ""

		end

		return lowercase_title

	end



	return nil

end



--- Returns the title used in the {{Correct title}} template and an optional maintenance category.

---

--- @param page_text string

--- @param args table

--- @param return_category boolean

--- @return string | nil

local function get_correct_title_value(page_text, args, return_category)

	local correct_title_template_pattern = "{{[Cc]orrect title|title=(.*)|reason=.-}}"



	local correct_title = string.match(page_text, correct_title_template_pattern)



	if not correct_title then

		correct_title_template_pattern = "{{[Cc]orrect title|(.*)|reason=.-}}"

		correct_title = string.match(page_text, correct_title_template_pattern)

	end



	if not correct_title and type(correct_title) ~= "string" then

		return nil

	end



	local correct_title_title_parts = get_title_parts(correct_title)



	if not correct_title_title_parts.disambiguation then

		-- If the correct title value has no disambiguation, check if the title used in the infobox is the same as the title used for the correct title value.

		if return_category and args.title then

			if args.title == correct_title_title_parts.title then

				return maintenance_categories.unnecessary_title_parameter

			else

				return maintenance_categories.non_matching_title

			end

		end

		return correct_title_title_parts.title

	end



	local series_name_escaped, _ = get_series_name(args.series)



	if series_name_escaped ~= "" and (correct_title_title_parts.disambiguation == series_name_escaped or string.find(correct_title_title_parts.disambiguation, series_name_escaped)) then

		if return_category and args.title then

			if args.title == correct_title_title_parts.title then

				return maintenance_categories.unnecessary_title_parameter

			else

				return maintenance_categories.non_matching_title

			end

		end

		return correct_title_title_parts.title

	end



	-- Can't determine if the text in parentheses is disambiguation or part of the title since |series= isn't used.

	if return_category then

		return ""

	end



	return correct_title

end



--- Returns the display title text used in either the {{DISPLAYTITLE}} or {{Italic title}} templates.

---

--- @param page_text string

--- @param article_title string

--- @return string | nil

local function get_display_title_text(page_text, article_title)

	local title_modification = string.match(page_text, "{{DISPLAYTITLE:(.-)}}")

	if title_modification and type(title_modification) == "string" then

		return --[[---@not number | nil]] title_modification

	end



	title_modification = string.match(page_text, "{{Italic title|string=(.-)}}")

	if title_modification and type(title_modification) == "string" then

		local italic_title_text, _ = string.gsub(article_title, --[[---@not number | nil]] title_modification, "''" .. title_modification .. "''")

		return italic_title_text

	end



	return nil

end



--- Returns a maintenance category if the italic_title value is not "no".

---

--- Infobox parameters checked:

--- - |italic_title=

---

--- @param args table

--- @return string

local function is_italic_title_valid_value(args)

	if args.italic_title and args.italic_title ~= "no" then

		return string.format(maintenance_categories.incorrectly_formatted, "italic_title")

	end

	return ""

end



--- Returns a maintenance category if the date is not formatted correctly with a {{Start date}} template.

--- Allow "Unaired" as a valid value for unaired television episodes.

---

--- Infobox parameters checked:

--- - |airdate=

--- - |released=

--- - |airdate_overall=

---

--- @param start_date string

--- @return string

local function are_dates_formatted_correctly(start_date)

	if start_date and (string.find(start_date, "film%-date") or not string.find(start_date, "itvstart") and start_date ~= "Unaired") then

		return maintenance_categories.dates_incorrectly_formatted

	end

	return ""

end



--- Returns a maintenance category if list markup is used. The infobox can handle list markup correctly.

---

--- Note: the code here is temporarily checking only the parameters which have been converted

--- to use the plainlist class directly. Once current uses will be converted, the function will check all parameters

--- for incorrect usage.

---

--- Infobox parameters checked:

---	- Parameters listed below.

---

--- Currently checks for the following list markup:

--- - <br> tags - per [[MOS:NOBR]].

--- - <li> tags.

--- - "plainlist" class.

--- - "hlist" class.

---

--- @param args table

--- @return string

local function uses_list_markup(args)

	local invalid_tags = {

		"br" = "<[bB][rR]%s?/?>",

		"li" = "<li>",

		"plainlist" = "plainlist",

		"hlist" = "hlist",

	}



	---@type table<string, boolean>

	local parameters = {

		director = true,

		writer = true,

		story = true,

		teleplay = true,

		narrator = true,

		presenter = true,

		producer = true,

		music = true,

		photographer = true,

		editor = true,

		production = true,

		airdate = true,

		guests = true,

		commentary = true,

	}



	for parameter_name, _ in pairs(parameters) do

		for _, list_pattern in pairs(invalid_tags) do

			local parameter_value = argsparameter_name

			if parameter_value and string.find(parameter_value, list_pattern) then

				return maintenance_categories.list_markup

			end

		end

	end

	return ""

end



--- Returns a maintenance category if a flag icon is used.

---

--- All of the infobox values are checked.

---

--- @param args table

--- @return string

local function has_flag_icon(args)

	for _, value in pairs(args) do

		if string.find(value, "flagicon") then

			return maintenance_categories.flag_icon

		end

	end

	return ""

end



--- Returns a maintenance category if the values are linked.

---

--- Infobox parameters checked:

--- - |episode=

--- - |season=

--- - |series_no=

--- - |episode_list=

---

--- The function currently checks if the following values are present:

--- - ]] - links.

---

--- @param args table

--- @return string

local function are_values_linked(args)

	local parameters = {

		episode = args.episode,

		season = args.season,

		series_no = args.series_no,

		episode_list = args.episode_list,

	}



	for key, value in pairs(parameters) do

		if string.find(value, "]]", 1, true) then

			return string.format(maintenance_categories.incorrectly_formatted, key)

		end

	end

	return ""

end



--- Returns a maintenance category if the values are formatted.

---

--- Most of the infobox values are checked. Not included are:

--- - |title= - is handled in is_infobox_title_equal_to_article_title()

--- - |series= - is handled in are_values_links_only()

--- - |next= - is handled in are_values_links_only()

--- - |prev= is handled in are_values_links_only()

--- - |rtitle=

--- - |rprev=

--- - |rnext=

--- - |image_alt=

--- - |alt=

--- - |caption=

--- - |based_on=

--- - |music=

--- - |guests=

--- - |module=

---

--- The function currently checks if the following values are present:

--- - '' - italics or bold.

---

--- Note:

--- If the series is American Horror Story then the season_article value is allowed to be formatted.

--- If in the future more series need this exception then the hardcoded value in the function should be taken out into a list.

---

--- @param args table

--- @return string

local function are_values_formatted(args)

	---@type table<string, boolean>

	local ignore_parameters = {

		title = true,

		series = true,

		prev = true,

		next = true,

		rtitle = true,

		rprev = true,

		rnext = true,

		image_alt = true,

		alt = true,

		caption = true,

		based_on = true,

		music = true,

		guests = true,

		module = true,

	}



	for key, value in pairs(args) do

		if not ignore_parameterskey and string.find(value, "''", 1, true) then

			if key == "season_article" and args.series == "[[American Horror Story]]" then --TODO: This is hardcoded for now.

				-- Do nothing.

			else

				return string.format(maintenance_categories.incorrectly_formatted, key)

			end

		end

	end

	return ""

end



--- Returns a maintenance category if the values use additional overall numbering.

---

--- Infobox parameters checked:

--- - |episode=

--- - |season=

--- - |series_no=

---

--- The function currently checks if the following values are present:

--- - overall - unsupported series overall numbering.

---

--- @param args table

--- @return string

local function are_values_using_overall(args)

	local parameters = {

		episode = args.episode,

		season = args.season,

		series_no = args.series_no,

	}



	for key, value in pairs(parameters) do

		if string.find(value, "overall") then

			return string.format(maintenance_categories.incorrectly_formatted, key)

		end

	end



	return ""

end



--- Returns a maintenance category if the values are unlinked and if additional characters are found in the text.

---

--- Infobox parameters checked:

--- - |series=

--- - |prev=

--- - |next=

---

--- The function currently checks if a value is unlinked or if there is any additional character

--- before or after the linked text.

---

--- @param args table

--- @return string

local function are_values_links_only(args)

	local parameters = {

		series = args.series,

		prev = args.prev,

		next = args.next,

	}



	for key, value in pairs(parameters) do

		-- Check whether the values are linked.

		if not string.find(value, "%[%[.*%]%]") then

			return string.format(maintenance_categories.unlinked_values, key)

		end



		-- Check whether the values have anything before or after link brackets.

		if string.gsub(value, "(%[%[.*%]%])", "") ~= "" then

			return string.format(maintenance_categories.incorrectly_formatted, key)

		end

	end



	return ""

end



--- Returns a maintenance category if the |image= value includes the "File:" or "Image:" prefix.

---

--- Infobox parameters checked:

--- - |image=

---

--- @param image string

--- @return string

local function is_image_using_incorrect_syntax(image)

	if not image then

		return ""

	end



	if string.find(image, "[Ff]ile:") or string.find(image, "[Ii]mage:") then

		return string.format(maintenance_categories.incorrectly_formatted, "image")

	end



	return ""

end



--- Returns a maintenance category if the |image_size= value includes "px".

---

--- Infobox parameters checked:

--- - |image_size=

---

--- @param image_size string

--- @return string

local function is_image_size_using_px(image_size)

	if image_size and string.find(image_size, "px") then

		return string.format(maintenance_categories.incorrectly_formatted, "image_size")

	end

	return ""

end



--- Returns a maintenance category if there is no image file while image auxiliary values are present.

---

--- Infobox parameters checked:

--- - |image=

--- - |image_size=

--- - |image_upright=

--- - |image_alt=

--- - |alt=

--- - |caption=

---

--- @param args table

--- @return string

local function are_image_auxiliary_values_used_for_no_image(args)

	if args.image then

		return ""

	end



	if args.image_size or args.image_upright or args.image_alt or args.alt or args.caption then

		return maintenance_categories.image_values_without_an_image

	end



	return ""

end



--- Returns a maintenance category if the infobox title is equal to the article title.

---

--- Infobox parameters checked:

--- - |title=

--- - |series=

--- - |italic_title

---

--- The function currently checks if the infobox title is equal to the article title while ignoring styling such as:

--- - Nowrap spans.

--- - Line breaks.

--- - Leading and trailing apostrophe spaces.

---

--- A return value can be one of three options:

--- - The value of maintenance_categories.non_matching_title - when the args.title does not match the article title.

--- - The value of maintenance_categories.unnecessary_title_parameter - when the args.title matches the article title.

--- - An empty string - when args.title isn't used or the args.title uses an allowed modification

--- (such as a nowrap template) while the rest of the args.title matchs the article title.

---

--- Testing parameters:

--- - |page_test= - a real Wikipedia page to read the content of the page.

--- - |page_title_test= - the title of the page being checked.

---

--- @param frame table

--- @param args table

--- @return string

local function is_infobox_title_equal_to_article_title(frame, args)

	if not args.title then

		return ""

	end



	local page_text

	if args.page_test then

		page_text = mw.title.new(args.page_test):getContent()

	else

		page_text = mw.title.getCurrentTitle():getContent()

	end



	-- Check if the article is using a {{Correct title}} template.

	local correct_title = get_correct_title_value(page_text, args, true)

	if correct_title then

		return correct_title

	end



	local article_title = args.page_title_test

	if not args.page_title_test then

		article_title = mw.title.getCurrentTitle().text

	end



	local title_parts = get_title_parts(article_title)



	-- Check if the article is using a {{Lowercase title}} template.

	local lowercase_title = get_lowercase_template_status(page_text, args, title_parts)

	if lowercase_title then

		return lowercase_title

	end



	if title_parts.disambiguation then

		local series_name_escaped, _ = get_series_name(args.series)

		series_name_escaped = get_name_with_br_fixes(series_name_escaped)

		if series_name_escaped ~= "" and (title_parts.disambiguation == series_name_escaped or string.find(title_parts.disambiguation, series_name_escaped)) then

			-- Remove disambiguation.

			article_title = title_parts.title

		end

	end



	if args.italic_title then

		-- Check if the article is using a {{DISPLAYTITLE}} or {{Italic title}} template.

		local title_modification = get_display_title_text(page_text, article_title)

		if title_modification then

			if title_modification == args.title then

				return maintenance_categories.unnecessary_title_parameter

			else

				return maintenance_categories.non_matching_title

			end

		end

	end



	local page_name = get_page_name_with_apostrophe_quotation_fixes(frame, article_title)



	-- Remove nowrap span.

	if string.find(args.title, "nowrap") then

		local title = frame:expandTemplate{title = "Strip tags", args = {args.title}}

		if title == page_name then

			return ""

		end

		return maintenance_categories.non_matching_title

	end



	-- Remove line breaks and additional spaces as a result.

	if string.find(args.title, "<br%s?/?>") then

		local title = get_name_with_br_fixes(args.title)

		if title == page_name then

			return ""

		end

		return maintenance_categories.non_matching_title

	end



	if args.title == page_name then

		return maintenance_categories.unnecessary_title_parameter

	end



	-- Article and infobox titles do not match.

	return maintenance_categories.non_matching_title

end



--- Returns the relevant maintenance categories based on the {{Infobox television episode}} values validated.

---

--- @param frame table

--- @return string

function p.validate_values(frame)

	local getArgs = require("Module:Arguments").getArgs

	local args = getArgs(frame)



	---@type string[]

	local categories = {}

	table.insert(categories, is_infobox_title_equal_to_article_title(frame, args))

	table.insert(categories, are_image_auxiliary_values_used_for_no_image(args))

	table.insert(categories, is_image_using_incorrect_syntax(args.image))

	table.insert(categories, is_image_size_using_px(args.image_size))

	table.insert(categories, are_values_links_only(args))

	table.insert(categories, are_values_using_overall(args))

	table.insert(categories, are_values_formatted(args))

	table.insert(categories, are_values_linked(args))

	table.insert(categories, has_flag_icon(args))

	table.insert(categories, uses_list_markup(args))

	table.insert(categories, are_dates_formatted_correctly(args.airdate or args.released))

	table.insert(categories, is_italic_title_valid_value(args))



	return table.concat(categories)

end



--- Returns an {{Italic dab2}} instance if title qualifies. Also returns a maintenance category if conditions are met.

---

--- The article's title is italicized if the series name is included in the article's title disambiguation.

--- No italicization happens if one of the following conditions is met:

---

--- - |italic_title= is set to "no".

--- - The article's title does not use disambiguation.

--- - No |series= value is set.

--- - The article's disambiguation is not equal or does not include the series name.

---

--- The page is added to a maintenance category if the title is italicized and there is already an

--- {{Italic dab}}, {{Italic title}} or {{DISPLAYTITLE}} template.

---

--- Infobox parameters checked:

--- - |series=

--- - |italic_title=

---

--- Testing parameters:

--- - |page_test= - a real Wikipedia page to read the content of the page.

--- - |page_title_test= - the title of the page being checked.

---

--- @param frame table

--- @return string, string

function p.italic_title(frame)

	local getArgs = require("Module:Arguments").getArgs

	local args = getArgs(frame)



	local page_text

	if args.page_test then

		page_text = mw.title.new(args.page_test):getContent()

	else

		page_text = mw.title.getCurrentTitle():getContent()

	end



	local maintenance_category = ""

	-- In case the page does not need to be italicized or can't be automatically done, a "no" value will disable both

	-- the italicization and the error handling.

	if args.italic_title == "no" then

		return "", maintenance_category

	end



	local article_title = args.page_title_test

	if not args.page_title_test then

		article_title = mw.title.getCurrentTitle().text

	end



	-- Check if the page already has an {{Italic dab}}, {{Italic title}} or {{DISPLAYTITLE}} template.

	local has_italic_dab, _ = string.find(page_text, "{{[Ii]talic dab")

	local has_italic_title, _ = string.find(page_text, "{{[Ii]talic title")

	local has_display_title, _ = string.find(page_text, "{{DISPLAYTITLE")



	if has_italic_dab or has_italic_title or has_display_title then

		maintenance_category = maintenance_categories.manual_display_title

	end



	local title_parts = get_title_parts(article_title)



	-- The title is not italicized if the title does not use disambiguation or if the series parameter isn't used.

	if not title_parts.disambiguation or not args.series then

		return "", maintenance_category

	end



	local series_name_escaped, series_name = get_series_name(args.series)

	series_name_escaped = get_name_with_br_fixes(series_name_escaped)

	series_name = get_name_with_br_fixes(series_name)



	-- Check if the disambiguation equals the series name or if the series name can be found in the disambiguation.

	local italic_dab

	if title_parts.disambiguation == series_name then

		italic_dab = frame:expandTemplate{title = "Italic dab2"}

	elseif string.find(title_parts.disambiguation, series_name_escaped) then

		italic_dab = frame:expandTemplate{title = "Italic dab2", args = {string = series_name}}

	else

		return "", maintenance_category

	end



	if args.page_title_test and italic_dab then

		italic_dab = "italic_dab"

	end

	return italic_dab, maintenance_category



end



--- Returns a formatted title string.

---

--- @param rtitle string

--- @return string

local function create_title_with_rtitle_value(rtitle)

	local title_pattern = '"(.*)" and "(.*)"'

	if string.find(rtitle, title_pattern) then

		local episode1, episode2 = string.match(rtitle, title_pattern)

		local title_format = "\"'''%s'''\" and \"'''%s'''\""

		return string.format(title_format, episode1, episode2)

	end



	local title_pattern_br = '"(.*)" and%s?<br%s?/?>%s?"(.*)"'

	if string.find(rtitle, title_pattern_br) then

		local episode1, episode2 = string.match(rtitle, title_pattern_br)

		local title_format = "\"'''%s'''\" and<br/> \"'''%s'''\""

		return string.format(title_format, episode1, episode2)

	end



	return string.format("'''%s'''", rtitle)

end



--- Returns the text used for the |above= field of the infobox.

---

--- Infobox parameters checked:

--- - |rtitle=

--- - |title=

--- - |series=

---

--- Testing parameters:

--- - |page_test= - a real Wikipedia page to read the content of the page.

--- - |page_title_test= - the title of the page being checked.

---

--- @param frame table

--- @return string

local function _above_title(frame, args)

	if args.rtitle then

		return create_title_with_rtitle_value(args.rtitle)

	end



	local page

	if args.page_test then

		page = mw.title.new(args.page_test)

	else

		page = mw.title.getCurrentTitle()

	end



	local page_text = page:getContent()



	local article_title = args.page_title_test

	if not args.page_title_test then

		article_title = page.text

	end



	local title_format = "\"'''%s'''\""



	local correct_title = get_correct_title_value(page_text, args, false)

	if correct_title then

		return string.format(title_format, correct_title)

	end



	local title_parts = get_title_parts(article_title)



	local lowercase_title = get_lowercase_template_status(page_text, args, title_parts)

	if lowercase_title then

		return string.format(title_format, lowercase_title)

	end



	local series_name_escaped, _ = get_series_name(args.series)



	-- args.no_bold is used from IMDb episode so it requires this correction here also.

	if (args.italic_title and not args.rtitle) or args.no_bold then

		local title_modification = get_display_title_text(page_text, article_title)



		if title_modification then

			if title_parts.disambiguation == series_name_escaped then

				local correct_title_title_parts = get_title_parts(title_modification)

				title_modification = correct_title_title_parts.title

			end

			return string.format(title_format, title_modification)

		end

	end



	if args.title then

		return string.format(title_format, args.title)

	end



	if not title_parts.disambiguation or (series_name_escaped ~= "" and (title_parts.disambiguation == series_name_escaped or string.find(title_parts.disambiguation, series_name_escaped))) or args.no_bold then

		return string.format(title_format, get_page_name_with_apostrophe_quotation_fixes(frame, title_parts.title))

	end



	return string.format(title_format, get_page_name_with_apostrophe_quotation_fixes(frame, article_title))

end



--- Returns the episode title from the article title, with textual fixes if needed.

---

--- Used by {{Infobox television episode}} and {{IMDb episode}} to automatically style the title without needing manual input.

---

--- @param frame table

--- @return string

function p.above_title(frame)

	local getArgs = require("Module:Arguments").getArgs

	local args = getArgs(frame)

	local title = _above_title(frame, args)

	

	-- The title used by {{IMDb episode}} should not be in bold.

	if args.no_bold then

		title = string.gsub(title, "'''", "")

	end

	return title

end



--- Returns a list of episodes link if not formatted, otherwise returns the text used for args.episode_list.

---

--- Infobox parameters checked:

--- - |episode_list=

--- - |series=

---

--- @param frame table

--- @return string

function p.episode_list(frame)

	local getArgs = require("Module:Arguments").getArgs

	---@type table<string, string>

	local args = getArgs(frame)



	if args.episode_list then

		for _, v in pairs({"]]", "''"}) do

			if string.find(args.episode_list, v) then

				return args.episode_list

			end

		end



		if string.find(args.episode_list, "[Ss]toryline") then

			return "[[" .. args.episode_list .. "|Storylines]]"

		end



		return "[[" .. args.episode_list .. "|List of episodes]]"

	end



	if args.series then

		local series_name = get_series_link(args.series)

		local list_of_episodes = "List of " .. series_name .. " episodes"



		if mw.title.new(list_of_episodes):getContent() then

			return "[[" .. list_of_episodes .. "|List of episodes]]"

		end

	end

end



--- Returns the relevant maintenance categories based on the {{Infobox television crossover episode}} values validated.

---

--- @param frame table

--- @return string

function p.validate_values_crossover(frame)

	local getArgs = require("Module:Arguments").getArgs

	local args = getArgs(frame)



	---@type string[]

	local categories = {}

	table.insert(categories, are_image_auxiliary_values_used_for_no_image(args))

	table.insert(categories, is_image_using_incorrect_syntax(args.image))

	table.insert(categories, is_image_size_using_px(args.image_size))

	table.insert(categories, has_flag_icon(args))

	table.insert(categories, are_dates_formatted_correctly(args.airdate_overall))



	for i = 1, 5 do

		if not args"series" .. i then

			break

		end



		local nested_args = {

			series = args"series" .. i],

			episode = args"episode_no" .. i],

			season = args"season" .. i],

			airdate = args"airdate" .. i],

			prev = args"prev" .. i],

			next = args"next" .. i],

			episode_list = args"episode_list" .. i],

		}



		table.insert(categories, are_values_links_only(nested_args))

		table.insert(categories, are_values_using_overall(nested_args))

		table.insert(categories, are_values_formatted(nested_args))

		table.insert(categories, are_values_linked(nested_args))

		table.insert(categories, are_dates_formatted_correctly(nested_args.airdate))

	end



	return table.concat(categories, "")

end



return p