Editing
Module:Validate gadgets
Jump to navigation
Jump to search
Warning:
You are not logged in. Your IP address will be publicly visible if you make any edits. If you
log in
or
create an account
, your edits will be attributed to your username, along with other benefits.
Anti-spam check. Do
not
fill this in!
local MessageBox = require('Module:Message box') local Gadgets = require('Module:Gadgets') 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 local BOOLEAN_OPTIONS = { 'ResourceLoader', 'default', 'package', 'hidden', 'supportsUrlLoad', 'requiresES6' } local STRING_OPTIONS = { 'type', 'dependencies', 'peers', 'namespaces', 'actions', 'contentModels', 'categories', 'targets', 'skins', 'rights' } -- Lists of valid options for things that aren't exposed to lua -- (unlike namespaces that can be accessed from mw.site.namespaces) local VALID_CONTENT_MODELS = {'wikitext', 'javascript', 'css', 'json', 'vue', 'MassMessageListContent', 'Scribunto', 'sanitized-css', 'SecurePoll'} local VALID_ACTIONS = {'view', 'edit', 'history', 'info', 'move', 'delete', 'undelete', 'protect', 'block' } -- not exhaustive p.validate = function () local text = mw.title.new('MediaWiki:Gadgets-definition'):getContent() local lines = mw.text.split(text, '\n', false) local repo = {} local allWarnings = {} -- A bit of parsing is reimplemented here as [[Module:Gadgets]] doesn't raise warnings -- for invalid lines for _, line in ipairs(lines) do if line:sub(1, 1) == '*' then local name, options, pages = Gadgets.parse_line(line) if not name or #pages == 0 then table.insert(allWarnings, '* Invalid definition: '..line) else repo[name] = { options = options, pages = pages } end end end for name, conf in pairs(repo) do local warnings = p.create_warnings(name, conf.options, conf.pages, repo) for _, warning in ipairs(warnings) do table.insert(allWarnings, '*'..name..': '..warning) end end if #allWarnings ~= 0 then return MessageBox.main('ombox', { text = '<b>Issues in gadget definitions:</b>\n' .. table.concat(allWarnings, '\n'), type = 'delete', class = 'gadgets-validation' }) elseif require('Module:If preview/configuration').preview then return MessageBox.main('ombox', { text = '<b>Issues in gadget definitions:</b> <i>No issues found!</i>', type = 'notice', image = '[[File:Check-green.svg|30px]]', class = 'gadgets-validation' }) else return '' end end p.create_warnings = function(name, options, pages, repo) local warnings = {} -- RL module name (ext.gadget.<name>) should not exceed 255 bytes -- so a limit of 255 - 11 = 244 bytes for gadget name if string.len(name) > 244 then table.insert(warnings, 'Gadget name must not exceed 244 bytes') end -- Per ResourceLoader::isValidModuleName if name:gsub('[|,!]', '') ~= name then table.insert(warnings, 'Gadget name must not contain pipes (|), commas (,) or exclamation marks (!)') end -- Pattern per MediaWikiGadgetDefinitionsRepo::newFromDefinition if not string.match(name, "^[a-zA-Z][-_:%.%w ]*[a-zA-Z0-9]?$") then table.insert(warnings, 'Gadget name is used as part of the name of a form field, and must follow the rules defined in https://www.w3.org/TR/html4/types.html#type-cdata') end -- Look for invalid options for key, value in pairs(options) do if arr_contains(BOOLEAN_OPTIONS, key) then if value ~= true then table.insert(warnings, 'Option '..key..' is a boolean: should have no value') end elseif arr_contains(STRING_OPTIONS, key) then if value == true then table.insert(warnings, 'Option '..key..' must have a value') end else table.insert(warnings, 'Option '..key..' is unrecognised') end 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 table.insert(warnings, 'Setting targets in gadget defintion is deprecated and no longer has any effect') end if options.namespaces ~= nil then for _, id in ipairs(mw.text.split(options.namespaces, ',', false)) do if not string.match(id, '^-?%d+$') then table.insert(warnings, 'Invalid namespace id: '..id..' - must be numeric') elseif mw.site.namespaces[tonumber(id)] == nil then table.insert(warnings, 'Namespace id '..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 mw.message.new('skinname-' .. skin):exists() 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 mw.message.new('right-' .. right):exists() then table.insert(warnings, 'User right '..right..' does not exist') end end end -- TODO: check that pages in options.categories exist, but Gadgets.parse_line removes -- whitespaces in options, mangling the category names local hasScripts = false local hasJsons = false local hasVues = false for _, page in ipairs(pages) 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') else local ext = title.text:match("%.([^%.]+)$") if ext == 'js' then if title.contentModel ~= 'javascript' then table.insert(warnings, 'Page [['..page..']] is not of JavaScript content model') else hasScripts = true end elseif ext == 'css' then if title.contentModel ~= 'css' then table.insert(warnings, 'Page [['..page..']] is not of CSS content model') end elseif ext == 'json' then if title.contentModel ~= 'json' then table.insert(warnings, 'Page [['..page..']] is not of JSON content model') else hasJsons = true end elseif ext == 'vue' then if title.contentModel ~= 'vue' then table.insert(warnings, 'Page [['..page..']] is not of Vue content model') else hasVues = true end else table.insert(warnings, 'Page [['..page..']] is not JS/CSS/JSON/Vue, will be ignored') end end end if not options.hidden then local description_page = mw.title.new('MediaWiki:Gadget-'..name) if description_page == nil or not description_page.exists then table.insert(warnings, 'Description [['..description_page.fullText..']] for use in Special:Preferences does not exist') end end if options.package == nil and hasJsons then table.insert(warnings, 'JSON pages cannot be used in non-package gadgets') end if options.package == nil and hasVues then table.insert(warnings, 'Vue pages cannot be used in non-package gadgets') end if options.requiresES6 ~= nil and options.default ~= nil then table.insert(warnings, 'Default gadget cannot use requiresES6 flag') end if options.type == 'styles' and hasScripts then table.insert(warnings, 'JS pages will be ignored as gadget sets type=styles') end if options.type == 'styles' and options.peers ~= nil then table.insert(warnings, 'Styles-only gadget cannot have peers') end if options.type == 'styles' and options.dependencies ~= nil then table.insert(warnings, 'Styles-only gadget cannot have dependencies') end if options.package ~= nil and not hasScripts then table.insert(warnings, 'Package gadget must have at least one JS page') end if options.ResourceLoader == nil and hasScripts then table.insert(warnings, 'ResourceLoader option must be set') end -- Causes warnings on styles-only gadgets using skins param -- if options.hidden ~= nil and (options.namespaces ~= nil or options.actions ~= nil or options.rights ~= nil or options.contentModels ~= nil or options.skins ~= nil) then -- table.insert(warnings, 'Conditional load options are not applicable for hidden gadget') -- end if options.peers ~= nil then for _, peer in ipairs(mw.text.split(options.peers, ',', false)) do if repo[peer] == nil then table.insert(warnings, 'Peer gadget '..peer..' is not defined') elseif Gadgets.get_type(repo[peer]) == 'general' then table.insert(warnings, 'Peer gadget '..peer..' must be styles-only gadget') end end end if options.dependencies ~= nil then for _, dep in ipairs(mw.text.split(options.dependencies, ',', false)) do if dep:sub(1, 11) == 'ext.gadget.' then local dep_gadget = dep:sub(12) if repo[dep_gadget] == nil then table.insert(warnings, 'Dependency gadget '..dep_gadget..' is not defined') end end end end return warnings end return p
Summary:
Please note that all contributions to Eurovision Wiki may be edited, altered, or removed by other contributors. If you do not want your writing to be edited mercilessly, then do not submit it here.
You are also promising us that you wrote this yourself, or copied it from a public domain or similar free resource (see
Eurovision Wiki:Copyrights
for details).
Do not submit copyrighted work without permission!
Cancel
Editing help
(opens in new window)
Pages included on this page:
Template:Lua
(
edit
)
Template:Sandbox other
(
edit
)
Template:Used in system
(
edit
)
Module:Arguments
(
edit
)
Module:Effective protection level
(
edit
)
Module:High-use
(
edit
)
Module:List
(
edit
)
Module:Lua banner
(
edit
)
Module:Message box
(
edit
)
Module:Message box/configuration
(
edit
)
Module:Message box/ombox.css
(
edit
)
Module:String
(
edit
)
Module:TableTools
(
edit
)
Module:Transclusion count
(
edit
)
Module:Transclusion count/data/V
(
edit
)
Module:Validate gadgets/doc
(
edit
)
Module:Yesno
(
edit
)
Navigation menu
Personal tools
Not logged in
Talk
Contributions
Create account
Log in
Namespaces
Module
Discussion
English
Views
Read
Edit source
View history
More
Search
Navigation
Main page
Recent changes
Random page
Help about MediaWiki
Special pages
Tools
What links here
Related changes
Page information