require("strict")
local libraryUtil = require("libraryUtil")
-----------------------------------------------------------------------
-- DisambiguationPattern "class"
-----------------------------------------------------------------------
local function DisambiguationPattern(o)
local obj = o or { pattern = "", type = 0 }
libraryUtil.makeCheckSelfFunction(
"Television infoboxes disambiguation check",
"DisambiguationPattern",
obj,
"Television infoboxes disambiguation check object"
)
return obj
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_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_YEAR_COUNTRY_SEASON_NUMBER = "Debug: Using a valid format with an extended Year, Country and Season number - {}."
}
-----------------------------------------------------------------------
-- Validation helpers
-----------------------------------------------------------------------
local function validateTwoParameters(a, b)
return not not (a and b)
end
local function validateSeasonNumber(seasonNumber)
if not seasonNumber then
return false
end
return tonumber(seasonNumber:sub(1, 1)) ~= 0
end
local function validateYear(year)
return year and #year == 4
end
local function validateCountryAdjective(adj)
if not adj or adj == "" then
return false
end
local data = mw.loadData("Module:Country adjective")
return not not data.getCountryFromAdj[adj]
end
-----------------------------------------------------------------------
-- Pattern validation engine
-----------------------------------------------------------------------
local function validatePatterns(disambiguation, patternList)
local year, adjective, seasonNumber
local isYearValid, isAdjectiveValid, isSeasonNumberValid
for i = 1, #patternList do
local p = patternList[i]
if disambiguation:match(p.pattern) then
-- YEAR + COUNTRY
if p.type == validationTypeList.VALIDATION_TYPE_YEAR_COUNTRY then
year, adjective = disambiguation:match(p.pattern)
isYearValid = validateYear(year)
isAdjectiveValid = validateCountryAdjective(adjective)
local ok = validateTwoParameters(isYearValid, isAdjectiveValid)
return ok, debugMessageList.DEBUG_YEAR_COUNTRY:gsub("{}", DAB_VALID[ok])
-- YEAR
elseif p.type == validationTypeList.VALIDATION_TYPE_YEAR then
year = disambiguation
isYearValid = validateYear(year)
return isYearValid, debugMessageList.DEBUG_YEAR:gsub("{}", DAB_VALID[isYearValid])
-- COUNTRY
elseif p.type == validationTypeList.VALIDATION_TYPE_COUNTRY then
adjective = disambiguation
isAdjectiveValid = validateCountryAdjective(adjective)
return isAdjectiveValid, debugMessageList.DEBUG_COUNTRY:gsub("{}", DAB_VALID[isAdjectiveValid])
-- YEAR + SEASON
elseif p.type == validationTypeList.VALIDATION_TYPE_YEAR_SEASON_NUMBER then
year, seasonNumber = disambiguation:match(p.pattern)
isYearValid = validateYear(year)
isSeasonNumberValid = validateSeasonNumber(seasonNumber)
local ok = validateTwoParameters(isYearValid, isSeasonNumberValid)
return ok, debugMessageList.DEBUG_YEAR_SEASON_NUMBER:gsub("{}", DAB_VALID[ok])
-- COUNTRY + SEASON
elseif p.type == validationTypeList.VALIDATION_TYPE_COUNTRY_SEASON_NUMBER then
adjective, seasonNumber = disambiguation:match(p.pattern)
isAdjectiveValid = validateCountryAdjective(mw.text.trim(adjective))
isSeasonNumberValid = validateSeasonNumber(seasonNumber)
local ok = validateTwoParameters(isAdjectiveValid, isSeasonNumberValid)
return ok, debugMessageList.DEBUG_COUNTRY_SEASON_NUMBER:gsub("{}", DAB_VALID[ok])
-- SEASON ONLY
elseif p.type == validationTypeList.VALIDATION_TYPE_SEASON_NUMBER then
seasonNumber = disambiguation:match(p.pattern)
isSeasonNumberValid = validateSeasonNumber(seasonNumber)
return isSeasonNumberValid, debugMessageList.DEBUG_SEASON_NUMBER:gsub("{}", DAB_VALID[isSeasonNumberValid])
-- YEAR + COUNTRY + SEASON
elseif p.type == validationTypeList.VALIDATION_TYPE_YEAR_COUNTRY_SEASON_NUMBER then
year, adjective, seasonNumber = disambiguation:match(p.pattern)
isYearValid = validateYear(year)
isAdjectiveValid = validateCountryAdjective(mw.text.trim(adjective))
isSeasonNumberValid = validateSeasonNumber(seasonNumber)
local ok = validateTwoParameters(isYearValid, isAdjectiveValid)
ok = validateTwoParameters(ok, isSeasonNumberValid)
return ok, debugMessageList.DEBUG_YEAR_COUNTRY_SEASON_NUMBER:gsub("{}", DAB_VALID[ok])
end
end
end
return false, debugMessageList.DEBUG_INCORRECT_STYLE
end
-----------------------------------------------------------------------
-- Disambiguation type validation
-----------------------------------------------------------------------
local function validateDisambiguationType(disambiguation, typeList)
local extended = disambiguation
local count = 0
for i = 1, #typeList do
local t = typeList[i]
extended, count = extended:gsub(t, "")
extended = mw.text.trim(extended)
if count ~= 0 then
break
end
end
return count ~= 0, extended
end
local function validateDisambiguation(invoker, disambiguation, typeList, patternList)
if #typeList ~= 0 then
local ok, extended = validateDisambiguationType(disambiguation, typeList)
if not ok then
return false, debugMessageList.DEBUG_NOT_VALID_FORMAT
end
if extended == "" then
return true, debugMessageList.DEBUG_VALID_FORMAT
end
if invoker ~= "infobox television season" then
disambiguation = extended
end
end
return validatePatterns(disambiguation, patternList)
end
-----------------------------------------------------------------------
-- Incorrect infobox detection
-----------------------------------------------------------------------
local function isPageUsingIncorrectInfobox(invoker, disambiguation, otherList)
-- Only skip incorrect-infobox detection for SEASON pages.
-- Season pages often have disambiguations like:
-- "season 1", "series 2", "season 1 TV series"
-- These should NOT trigger incorrect-infobox errors.
if invoker == "infobox television season" then
if disambiguation:match("^[Ss]eason%s+%d+")
or disambiguation:match("^[Ss]eries%s+%d+") then
return false
end
end
-- Normal incorrect-infobox detection
for k, v in pairs(otherList) do
if disambiguation:match(k) then
return true, v, debugMessageList.DEBUG_INCORRECT_INFOBOX:gsub("{}", k)
end
end
return false
end
-----------------------------------------------------------------------
-- Exception list
-----------------------------------------------------------------------
local function isOnExceptionList(title, list)
for _, v in ipairs(list) do
if v == title or title:match(v) then
return true
end
end
return false
end
-----------------------------------------------------------------------
-- Disambiguation extraction (supports new naming)
-----------------------------------------------------------------------
-- Get the disambiguation text and support both:
-- - Parenthetical only: "Big Brother (American TV series)"
-- - Parenthetical + season: "Big Brother (American TV series) season 5"
-- - Season only: "Lost season 1"
local function getDisambiguation(title)
local match = require("Module:String")._match
-- Last parenthetical chunk, if any.
local paren = match(title, "%s%((.-)%)", 1, -1, false, "")
-- Trailing "season X" or "series X", if any (X can be wrong; validation will decide).
local base, seasonPart = title:match("^(.-)%s+(season%s+.+)$")
if not base then
base, seasonPart = title:match("^(.-)%s+(series%s+.+)$")
end
if paren ~= "" and seasonPart then
-- Example: "Big Brother (American TV series) season 5"
-- Returns: "American TV series season 5"
return paren .. " " .. seasonPart
elseif paren ~= "" then
-- Example: "Big Brother (American TV series)"
-- Returns: "American TV series"
return paren
elseif seasonPart then
-- Example: "Lost season 1"
-- Returns: "season 1"
return seasonPart
else
return ""
end
end
-----------------------------------------------------------------------
-- Utility
-----------------------------------------------------------------------
local function isEmpty(x)
return not x or x == ""
end
-----------------------------------------------------------------------
-- Main entry point
-----------------------------------------------------------------------
local function main(title, invoker, typeList, patternList, exceptionList, otherInfoboxList, invalidTitleStyleList)
if isEmpty(title) then
return "", debugMessageList.DEBUG_EMPTY_TITLE
end
if isOnExceptionList(title, exceptionList) then
return "", debugMessageList.DEBUG_TITLE_ON_EXCEPTION
end
if invoker == "infobox television season" then
for i = 1, #invalidTitleStyleList do
if title:find(invalidTitleStyleList[i]) then
return CATEGORY_INCORRECT, debugMessageList.DEBUG_NOT_VALID_FORMAT
end
end
end
local disambiguation = getDisambiguation(title)
if isEmpty(disambiguation) then
return "", debugMessageList.DEBUG_NO_DAB
end
local wrong, category, dbg = isPageUsingIncorrectInfobox(invoker, disambiguation, otherInfoboxList)
if wrong then
return category, dbg
end
local ok, dbg2 = validateDisambiguation(invoker, disambiguation, typeList, patternList)
if not ok then
return CATEGORY_INCORRECT, dbg2
end
return "", dbg2
end
-----------------------------------------------------------------------
-- Export
-----------------------------------------------------------------------
return {
main = main,
DisambiguationPattern = DisambiguationPattern,
VALIDATION_TYPE_YEAR_COUNTRY = validationTypeList.VALIDATION_TYPE_YEAR_COUNTRY,
VALIDATION_TYPE_YEAR = validationTypeList.VALIDATION_TYPE_YEAR,
VALIDATION_TYPE_COUNTRY = validationTypeList.VALIDATION_TYPE_COUNTRY,
VALIDATION_TYPE_YEAR_SEASON_NUMBER = validationTypeList.VALIDATION_TYPE_YEAR_SEASON_NUMBER,
VALIDATION_TYPE_COUNTRY_SEASON_NUMBER = validationTypeList.VALIDATION_TYPE_COUNTRY_SEASON_NUMBER,
VALIDATION_TYPE_SEASON_NUMBER = validationTypeList.VALIDATION_TYPE_SEASON_NUMBER,
VALIDATION_TYPE_YEAR_COUNTRY_SEASON_NUMBER = validationTypeList.VALIDATION_TYPE_YEAR_COUNTRY_SEASON_NUMBER
}