Module:Validate gadgets explained

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 falseend

-- 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 =

p.validate = function (frame) 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 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] = 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',) elseif require('Module:If preview/configuration').preview then return MessageBox.main('ombox',) else return endend

p.create_warnings = function(name, options, pages, repo) local warnings = -- RL module name (ext.gadget.) 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

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 mw.message.new('action-' .. action):exists 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

local scripts = local styles = local jsons = 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 table.insert(scripts, page) end elseif ext

'css' then if title.contentModel ~= 'css' then table.insert(warnings, 'Page '..page..' is not of CSS content model') else table.insert(styles, page) end elseif ext

'json' then if title.contentModel ~= 'json' then table.insert(warnings, 'Page '..page..' is not of JSON content model') else table.insert(jsons, page) end else table.insert(warnings, 'Page '..page..' is not JS/CSS/JSON, 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 #jsons > 0 then table.insert(warnings, 'JSON 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 #scripts > 0 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 #scripts

0 then table.insert(warnings, 'Package gadget must have at least one JS page') end if options.ResourceLoader

nil and #scripts > 0 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 warningsend

return p