Module:Validate gadgets
Appearance
![]() | This Lua module is used in system messages. Changes to it can cause immediate changes to the Wikipedia user interface. To avoid major disruption, any changes should be tested in the module's /sandbox or /testcases subpages, or in your own module sandbox. The tested changes can be added to this page in a single edit. Please discuss changes on the talk page before implementing them. |
![]() | This module depends on the following other modules: |
{{#invoke:Validate gadgets|validate}}
This module checks the gadget definitions in MediaWiki:Gadgets-definition for errors and other issues.
No output is produced if there are no warnings. But during previews, a message with a green check will be shown.
local messageBox = require('Module:Message box')
local p = {}
local function arr_contains(array, val)
for _, value in ipairs(array) do
if value == val then
return true
end
end
return false
end
-- Valid options for things that aren't exposed to lua
-- (unlike namespaces that can be accessed from mw.site.namespaces)
local VALID_SKINS = {'vector', 'vector-2022', 'minerva', 'timeless', 'monobook', 'modern', 'cologneblue'}
local VALID_CONTENT_MODELS = {'wikitext', 'javascript', 'css', 'json', 'MassMessage', 'Scribunto', 'sanitized-css'}
local VALID_RIGHTS = {'minoredit', 'viewmywatchlist', 'rollback'} -- not exhaustive
local VALID_ACTIONS = {'view', 'edit', 'history', 'info'} -- not exhaustive
p.validate = function (frame)
local text = mw.title.new('MediaWiki:Gadgets-definition'):getContent()
local lines = mw.text.split(text, '\n', false)
local msg = '<b>Issues in gadget definitions:</b>\n'
for _, line in ipairs(lines) do
if line:sub(1, 1) == '*' then
local name, warnings = p.parse_line(line)
for _, warning in ipairs(warnings) do
msg = msg.. '*'..name..': '..warning .. '\n'
end
end
end
return messageBox.main('ombox', {
text = msg,
type = 'delete'
})
end
p.parse_line = function(def)
local pattern = "^%*%s*(%S+)%s*(%b[])%s*(.-)$"
local name, opts, fileList = string.match(def, pattern)
if name and opts then
-- Extracting the options without square brackets and trimming spaces
opts = opts:sub(2, -2):gsub("%s+", "")
end
local warnings = {}
if string.len(name) > 255 then
table.insert(warnings, 'Gadget name exceeds 255 bytes')
end
-- Process options string into a Lua table
local options = {}
for pair in opts:gmatch("%s*([^|]+)%s*|?") do
local key, value = pair:match("%s*([^=]+)%s*=%s*([^=|]+)%s*")
if key and value then
options[key:match("%s*(.-)%s*$")] = value:match("^%s*(.-)%s*$")
else
key = pair:match("%s*(.-)%s*$")
options[key] = true
end
end
-- Process file list into an array
local files = {}
for file in fileList:gmatch("[^|]+") do
files[#files + 1] = file:gsub("%s+", "") -- Remove spaces
end
if options.ResourceLoader == nil then
table.insert(warnings, 'ResourceLoader option must be set')
end
if options.type ~= nil and options.type ~= 'general' and options.type ~= 'styles' then
table.insert(warnings, 'Allowed values for type are: general, styles')
end
if options.targets ~= nil then
for _, target in ipairs(mw.text.split(options.targets, ',', false)) do
if target ~= 'desktop' and target ~= 'mobile' then
table.insert(warnings, 'Target '..target..' is invalid. Allowed values: desktop, mobile')
end
end
end
if options.namespaces ~= nil then
for _, id in ipairs(mw.text.split(options.namespaces, ',', false)) do
id = tonumber(id)
if mw.site.namespaces[id] == nil then
table.insert(warnings, 'Namespace '..id..' is invalid')
end
end
end
if options.actions ~= nil then
for _, action in ipairs(mw.text.split(options.actions, ',', false)) do
if not arr_contains(VALID_ACTIONS, action) then
table.insert(warnings, 'Action '..action..' is unrecognised')
end
end
end
if options.contentModels ~= nil then
for _, model in ipairs(mw.text.split(options.contentModels, ',', false)) do
if not arr_contains(VALID_CONTENT_MODELS, model) then
table.insert(warnings, 'Content model '..model..' is unrecognised')
end
end
end
if options.skins ~= nil then
for _, skin in ipairs(mw.text.split(options.skins, ',', false)) do
if not arr_contains(VALID_SKINS, skin) then
table.insert(warnings, 'Skin '..skin..' is not available')
end
end
end
if options.rights ~= nil then
for _, right in ipairs(mw.text.split(options.rights, ',', false)) do
if not arr_contains(VALID_RIGHTS, right) then
table.insert(warnings, 'User right '..right..' does not exist')
end
end
end
for _, page in ipairs(files) do
page = 'MediaWiki:Gadget-' .. page
local title = mw.title.new(page)
if title == nil or not title.exists then
table.insert(warnings, 'Page '..page..' does not exist')
end
local ext = title.text:match("%.([^%.]+)$")
if ext == 'js' and title.contentModel ~= 'javascript' then
table.insert(warnings, 'Page '..page..' is not of JavaScript content model')
end
if ext == 'css' and title.contentModel ~= 'css' then
table.insert(warnings, 'Page '..page..' is not of CSS content model')
end
if ext == 'json' and title.contentModel ~= 'json' then
table.insert(warnings, 'Page '..page..' is not of JSON content model')
end
end
return name, warnings
end
return p