Module:Television infoboxes disambiguation check

Module:Television infoboxes disambiguation check handles the validation of disambiguation of pages using a television-related infobox. Currently Module:Infobox television disambiguation check and Module:Infobox television season disambiguation check are setup to work with it.

local validateDisambiguation = require('Module:Television infoboxes disambiguation check')
local trackingCategory, debugString = validateDisambiguation.main(title, validDisambiguationTypeList, validDisambiguationPatternList, exceptionList, otherInfoboxList)

Parameter list

change
Parameter Explanation Status
title The page's title. required
validDisambiguationTypeList An array of valid disambiguation types. required
validDisambiguationPatternList An array of DisambiguationPattern. required
exceptionList An array of page names that should not be validated; If there are none, pass an empty array. required
otherInfoboxList An array of key/value pairs of the type the disambiguation to check for (key) and the tracking category to add it to (value). required

local libraryUtil = require('libraryUtil')

--=============================================================--
-- DisambiguationPattern class.
local function DisambiguationPattern(o)
	local DisambiguationPattern = o or {pattern = "", type = ""}
	local checkSelf = libraryUtil.makeCheckSelfFunction( 'Television infoboxes disambiguation check', 'DisambiguationPattern', DisambiguationPattern, 'Television infoboxes disambiguation check object' )

	return DisambiguationPattern
end

--=============================================================--

-- Constants.
local DAB_VALID = {
	[true] = "valid",
	[false] = "invalid"
}

local CATEGORY_INCORRECT = "[[Category:Television articles with incorrect naming style]]"

local validationTypeList = {
	["VALIDATION_TYPE_YEAR_COUNTRY"] = 1,
	["VALIDATION_TYPE_YEAR"] = 2,
	["VALIDATION_TYPE_COUNTRY"] = 3,
	["VALIDATION_TYPE_YEAR_SEASON_NUMBER"] = 4,
	["VALIDATION_TYPE_COUNTRY_SEASON_NUMBER"] = 5,
	["VALIDATION_TYPE_SEASON_NUMBER"] = 6,
	["VALIDATION_TYPE_COUNTRY_SEASON"] = 7,
	["VALIDATION_TYPE_YEAR_COUNTRY_SEASON_NUMBER"] = 8
}

local debugMessageList = {
	["DEBUG_EMPTY_TITLE"] = "Debug: Error: Empty title.",
	["DEBUG_NO_DAB"] = "Debug: No disambiguation.",
	["DEBUG_TITLE_ON_EXCEPTION"] = "Debug: Title on exception list.",
	["DEBUG_VALID_FORMAT"] = "Debug: Using a valid format.",
	["DEBUG_NOT_VALID_FORMAT"] = "Debug: Not a valid format.",
	["DEBUG_YEAR_COUNTRY"] = "Debug: Using a valid format with an extended Year and Country - {}.",
	["DEBUG_YEAR"] = "Debug: Using a valid format with an extended Year - {}.",
	["DEBUG_COUNTRY"] = "Debug: Using a valid format with an extended Country - {}.",
	["DEBUG_INCORRECT_STYLE"] = "Debug: Using a valid format but using an incorrect extended style.",
	["DEBUG_INCORRECT_INFOBOX"] = "Debug: Using incorrect infobox - {}.",
	["DEBUG_YEAR_SEASON_NUMBER"] = "Debug: Using a valid format with an extended Year and Season number - {}.",	
	["DEBUG_COUNTRY_SEASON_NUMBER"] = "Debug: Using a valid format with an extended Country and Season number - {}.",	
	["DEBUG_SEASON_NUMBER"] = "Debug: Using a valid format with a Season number - {}.",
	["DEBUG_COUNTRY_SEASON"] = "Debug: Using a valid format with a Country and the word Season - {}.",
	["DEBUG_YEAR_COUNTRY_SEASON_NUMBER"] = "Debug: Using a valid format with an extended Year, Country and Season number - {}."
}

-- Local function which checks if both booleans are true or not.
local function validateTwoParameters(isValid1, isValid2)
	if (isValid1 and isValid2) then
		return true
	else
		return false
	end
end

-- Validate that the season number entered is a valid number -
-- that it does not start with a leading zero (0).
local function validateSeasonNumber(seasonNumber)
	if (tonumber(string.sub(seasonNumber, 1, 1)) == 0) then
		return false
	else
		return true
	end
end

-- Validate that the year entered is a valid year.
local function validateYear(year)
	if (string.len(year) == 4) then
		return true
	else
		return false
	end
end

-- Validate that the text entered is a supported country adjective.
local function validateCountryAdjective(adjective)
	local data = mw.loadData('Module:Country adjective')

	-- Search for a country corresponding to the given text.
	if (data.getCountryFromAdj[adjective]) then
		return true
	else
		return false
	end
end

-- Checks pages using by validating the disambiguation patterns.
local function validatePatterns(disambiguation, disambiguationPatternList)
	local year = ""
	local adjective = ""
	local seasonNumber = ""
	local isYearValid
	local isAdjectiveValid
	local isSeasonNumberValid

	for i, v in ipairs(disambiguationPatternList) do
		local currentDisambiguationPattern = disambiguationPatternList[i]
		if (disambiguation:match(currentDisambiguationPattern.pattern)) then
			
			-- Year and Country styles: "1999 American TV series"
			if (currentDisambiguationPattern.type == validationTypeList["VALIDATION_TYPE_YEAR_COUNTRY"]) then
				year, adjective = disambiguation:match(currentDisambiguationPattern.pattern)
				isYearValid = validateYear(year)
				isAdjectiveValid = validateCountryAdjective(adjective)

				local isValid = validateTwoParameters(isYearValid, isAdjectiveValid)
				return isValid, debugMessageList["DEBUG_YEAR_COUNTRY"]:gsub("{}", DAB_VALID[isValid])

			-- Year styles: "1999 TV series"
			elseif (currentDisambiguationPattern.type == validationTypeList["VALIDATION_TYPE_YEAR"]) then
				year = disambiguation
				isYearValid = validateYear(year)
				return isYearValid, debugMessageList["DEBUG_YEAR"]:gsub("{}", DAB_VALID[isYearValid])

			-- Country styles: "American TV series"
			elseif (currentDisambiguationPattern.type == validationTypeList["VALIDATION_TYPE_COUNTRY"]) then
				adjective = disambiguation
				isAdjectiveValid = validateCountryAdjective(adjective)
				return isAdjectiveValid, debugMessageList["DEBUG_COUNTRY"]:gsub("{}", DAB_VALID[isAdjectiveValid])

			-- Year and Season number styles: "1999 TV series, season 1"
			elseif (currentDisambiguationPattern.type == validationTypeList["VALIDATION_TYPE_YEAR_SEASON_NUMBER"]) then
				year, seasonNumber = disambiguation:match(currentDisambiguationPattern.pattern)
				isYearValid = validateYear(year)
				isSeasonNumberValid = validateSeasonNumber(seasonNumber)

				local isValid = validateTwoParameters(isYearValid, isSeasonNumberValid)
				return isValid, debugMessageList["DEBUG_YEAR_SEASON_NUMBER"]:gsub("{}", DAB_VALID[isValid])

			-- Country and Season number styles: "American season 1" and "American TV series, season 1"
			elseif (currentDisambiguationPattern.type == validationTypeList["VALIDATION_TYPE_COUNTRY_SEASON_NUMBER"]) then
				adjective, seasonNumber = disambiguation:match(currentDisambiguationPattern.pattern)
				isAdjectiveValid = validateCountryAdjective(mw.text.trim(adjective))
				isSeasonNumberValid = validateSeasonNumber(seasonNumber)
				
				local isValid = validateTwoParameters(isAdjectiveValid, isSeasonNumberValid)
				return isValid, debugMessageList["DEBUG_COUNTRY_SEASON_NUMBER"]:gsub("{}", DAB_VALID[isValid])

			-- Country and the word season: "American season"
			elseif (currentDisambiguationPattern.type == validationTypeList["VALIDATION_TYPE_COUNTRY_SEASON"]) then
				adjective = disambiguation:match(currentDisambiguationPattern.pattern)
				isAdjectiveValid = validateCountryAdjective(mw.text.trim(adjective))
				return isAdjectiveValid, debugMessageList["DEBUG_COUNTRY_SEASON"]:gsub("{}", DAB_VALID[isAdjectiveValid])

			--Season number styles: "season 1"
			elseif (currentDisambiguationPattern.type == validationTypeList["VALIDATION_TYPE_SEASON_NUMBER"]) then
				seasonNumber = disambiguation:match(currentDisambiguationPattern.pattern)
				isSeasonNumberValid = validateSeasonNumber(seasonNumber)
				return isSeasonNumberValid, debugMessageList["DEBUG_SEASON_NUMBER"]:gsub("{}", DAB_VALID[isSeasonNumberValid])

			-- Year, Country and Season number styles: "Gladiators (2008 British TV series, series 2)"
			elseif (currentDisambiguationPattern.type == validationTypeList["VALIDATION_TYPE_YEAR_COUNTRY_SEASON_NUMBER"]) then
				year, adjective, seasonNumber = disambiguation:match(currentDisambiguationPattern.pattern)
				isYearValid = validateYear(year)
				isAdjectiveValid = validateCountryAdjective(mw.text.trim(adjective))
				isSeasonNumberValid = validateSeasonNumber(seasonNumber)
				
				local isValid = validateTwoParameters(isYearValid, isAdjectiveValid)
				isValid = validateTwoParameters(isValid, isSeasonNumberValid)
				return isValid, debugMessageList["DEBUG_YEAR_COUNTRY_SEASON_NUMBER"]:gsub("{}", DAB_VALID[isValid])
				
			-- Not a valid supported style.
			else
				-- Do nothing.
			end
		else
			-- Do nothing.
		end
	end
	return false, debugMessageList["DEBUG_INCORRECT_STYLE"]
end

-- Validate that the disambiguation type is one of the supported types.
local function validateDisambiguationType(disambiguation, validDisambiguationTypeList)
	local extendedDisambiguation
	local count = 0
	
	for i, v in ipairs(validDisambiguationTypeList) do
		extendedDisambiguation, count = disambiguation:gsub(v, '')
		extendedDisambiguation = mw.text.trim(extendedDisambiguation)
		if (count ~= 0) then
			-- Disambiguation was a valid type; Exit loop.
			break
		end
	end
	
	count = count ~= 0 
	return count, extendedDisambiguation

end

-- Validate that the complete disambiguation is using a supported style.
local function validateDisambiguation(invoker, disambiguation, validDisambiguationTypeList, validDisambiguationPatternList)
	-- Check if the list is empty.
	if (table.getn(validDisambiguationTypeList) ~= 0) then
		local isDisambiguationValid, extendedDisambiguation = validateDisambiguationType(disambiguation, validDisambiguationTypeList)
	
		-- Exit module if the disambiguation type is not a supported style.
		if (not isDisambiguationValid) then
			return false, debugMessageList["DEBUG_NOT_VALID_FORMAT"]
		end
 
 		-- Check if there is no extended disambiguation.
		if (extendedDisambiguation == '') then
			return true, debugMessageList["DEBUG_VALID_FORMAT"]
		end
		
		-- A bit of hack so I won't need to refactor a ton of code.
		if (invoker ~= "infobox television season") then
			disambiguation = extendedDisambiguation
		end
	end
	
	return validatePatterns(disambiguation, validDisambiguationPatternList)
end

-- Check if the page is using disambiguation style that belongs to a different infobox.
local function isPageUsingIncorrectInfobox(disambiguation, otherInfoboxList)
	for k, v in pairs(otherInfoboxList) do
		if (string.match(disambiguation, k)) then
			return true, v, debugMessageList["DEBUG_INCORRECT_INFOBOX"]:gsub("{}", k)
		end
	end
	return false
end

-- Validate that the title has brackets that are part of the title and not part of disambiguation.
local function isOnExceptionList(title, exceptionList)
	for _, v in ipairs(exceptionList) do
		if (v == title) then
			return true
		elseif (string.match(title, v)) then
			return true
		end
	end
	return false
end

-- Get the disambiguation text and make sure that if the title has more than 1 pair of brackets, it returns the last one.
local function getDisambiguation(title)
	local match = require("Module:String")._match
	return match(title, "%s%((.-)%)", 1, -1, false, "")
--	return (string.match (title, '%s*%b()$') or ''):gsub('[%(%)]', '')
end

-- Validate that arg is not nill and not empty.
local function isEmpty(arg)
	if (not arg or arg == "") then
		return true
	else
		return false
	end
end

-- Returns two objects:
--- The first is either an empty string or a tracking category which will appear when using the live version.
--- The second is a debug string which will appear when using /testcases.
local function main(title, invoker, validDisambiguationTypeList, validDisambiguationPatternList, exceptionList, otherInfoboxList, invalidTitleStyleList)
	-- Exit module if the parameter has no value.
	if (isEmpty(title)) then
		return "", debugMessageList["DEBUG_EMPTY_TITLE"]
	end

	-- Exit module if the title has brackets that are part of the title (not disambiguation).
	if (isOnExceptionList(title, exceptionList)) then
		return "", debugMessageList["DEBUG_TITLE_ON_EXCEPTION"]
	end
	
	if (invoker == "infobox television season") then
		if (#invalidTitleStyleList ~= 0) then
			for i = 1, #invalidTitleStyleList do
				if (string.find(title, invalidTitleStyleList[i])) then
					return CATEGORY_INCORRECT, debugMessageList["DEBUG_NOT_VALID_FORMAT"]
				end
			end
		end
	end
		
				
	-- Get the disambiguation.
	local disambiguation = getDisambiguation(title)

	-- Exit module if the title has no disambiguation.
	if (isEmpty(disambiguation)) then
		return "", debugMessageList["DEBUG_NO_DAB"]
	end

	-- Exit module if the disambiguation belongs to a different infobox.
	local isValid, category, debugString = isPageUsingIncorrectInfobox(disambiguation, otherInfoboxList)
	if (isValid) then
		return category, debugString
	end
	
	-- Check if the disambiguation is valid.
	isValid, debugString = validateDisambiguation(invoker, disambiguation, validDisambiguationTypeList, validDisambiguationPatternList)
	
	-- Check if the disambiguation is not valid and add category.
	if (not isValid) then
		category = CATEGORY_INCORRECT
	end

	return category, debugString
end

return {
	main = main,
	DisambiguationPattern = DisambiguationPattern
	}