More actions
Documentation for this module may be created at Module:TrickValidator/doc
local p = {}
-- Full suggested structure kept for reference and "almost same" tolerance
local requiredSections = {
"Description",
"Use Cases & Purpose",
"Conditions and limits",
"How to Perform",
"Origin & History",
"Variations & Related Tricks",
"Examples in Practice"
}
-- Core sections that MUST exist (case-insensitive; '&' titles accept left/right/full)
local coreRequired = {
"Description",
"Conditions and limits",
"How to Perform",
}
-- Too-few-sections threshold (example given: "only 3" triggers). Set to 4.
local MIN_SECTIONS = 4
-- Utils
local function norm(s)
if not s then return "" end
s = mw.text.trim(s)
s = mw.ustring.gsub(s, "&", "&")
s = mw.ustring.lower(s)
-- unify "and" with "&" for matching
s = mw.ustring.gsub(s, "%s+and%s+", " & ")
-- normalize spaces around ampersand
s = mw.ustring.gsub(s, "%s*&%s*", " & ")
-- collapse spaces/underscores
s = mw.ustring.gsub(s, "[%s_]+", " ")
return mw.text.trim(s)
end
local function ampVariants(title)
-- returns full + left/right variants if '&' present after normalization
local out = {}
local t = norm(title)
out[t] = true
local ampPos = mw.ustring.find(t, "&", 1, true)
if ampPos then
local left = mw.text.trim(mw.ustring.sub(t, 1, ampPos - 1))
local right = mw.text.trim(mw.ustring.sub(t, ampPos + 1))
if left ~= "" then out[left] = true end
if right ~= "" then out[right] = true end
end
return out
end
local function getPageWikitext()
local t = mw.title.getCurrentTitle()
return t and t:getContent() or nil
end
local function l2Headings(wikitext)
local out = {}
if not wikitext then return out end
wikitext = "\n" .. wikitext .. "\n"
for h in mw.ustring.gmatch(wikitext, "\n==%s*([^=\n][^\n]-)%s*==%s*\n") do
table.insert(out, mw.text.trim(h))
end
return out
end
local function buildPresentSet(headings)
-- set of normalized headings; for any '&' title, also record left/right parts
local present = {}
for _, h in ipairs(headings) do
local n = norm(h)
present[n] = true
for v, _ in pairs(ampVariants(n)) do
present[v] = true
end
end
return present
end
local function hasSection(present, name)
-- accepts full or left/right if '&' (also treats "and" as '&')
for v, _ in pairs(ampVariants(name)) do
if present[v] then return true end
end
return false
end
local function countMatches(present, list)
local c = 0
for _, name in ipairs(list) do
if hasSection(present, name) then c = c + 1 end
end
return c
end
function p.validate(frame)
local pageContent = getPageWikitext()
if not pageContent then
return "" -- cannot validate without content
end
local found = l2Headings(pageContent)
local present = buildPresentSet(found)
-- Rule 1: Check for missing CORE sections first, as this is the most critical error.
local missing = {}
for _, req in ipairs(coreRequired) do
if not hasSection(present, req) then
table.insert(missing, req)
end
end
if #missing > 0 then
local msg = "This article is missing required section(s): '''" .. table.concat(missing, "''', '''") .. "'''."
return '<div class="mw-message-box mw-message-box-error">' .. msg .. '</div>[[Category:Trick articles with formatting errors]]'
end
-- Rule 2: Now check if there are too few sections overall.
-- This check is now secondary to the core section requirement.
if #found < MIN_SECTIONS then
local msg = "This article has too few sections. Add more sections to match the typical structure."
return '<div class="mw-message-box mw-message-box-error">' .. msg .. '</div>[[Category:Trick articles with formatting errors]]'
end
-- The "almost the same" tolerance logic is now redundant if the goal is only
-- to enforce core sections and a minimum count. If it had a different purpose,
-- it would need to be re-evaluated. Based on the comments, its purpose seems
-- to have been superseded, so it can be safely removed or left as a final "pass" condition.
-- For example, keeping it here does no harm, as the critical checks have already passed.
local expected = #requiredSections
local matched = countMatches(present, requiredSections)
if matched >= expected - 1 then
return "" -- considered "almost the same", which is fine.
end
-- All checks passed.
return ""
end
return p