<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
	<id>https://chabadpedia.com/index.php?action=history&amp;feed=atom&amp;title=Module%3AValidate_gadgets</id>
	<title>Module:Validate gadgets - Revision history</title>
	<link rel="self" type="application/atom+xml" href="https://chabadpedia.com/index.php?action=history&amp;feed=atom&amp;title=Module%3AValidate_gadgets"/>
	<link rel="alternate" type="text/html" href="https://chabadpedia.com/index.php?title=Module:Validate_gadgets&amp;action=history"/>
	<updated>2026-04-25T02:35:12Z</updated>
	<subtitle>Revision history for this page on the wiki</subtitle>
	<generator>MediaWiki 1.43.1</generator>
	<entry>
		<id>https://chabadpedia.com/index.php?title=Module:Validate_gadgets&amp;diff=12312&amp;oldid=prev</id>
		<title>Shia.k: Created page with &quot;local MessageBox = require(&#039;Module:Message box&#039;) local Gadgets = require(&#039;Module:Gadgets&#039;)  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  -- Lists of valid options for things that aren&#039;t exposed to lua  -- (unlike namespaces that can be accessed from mw.site.namespaces) local VALID_CONTENT_MODELS = {&#039;wikitext&#039;, &#039;javascript&#039;, &#039;css&#039;, &#039;...&quot;</title>
		<link rel="alternate" type="text/html" href="https://chabadpedia.com/index.php?title=Module:Validate_gadgets&amp;diff=12312&amp;oldid=prev"/>
		<updated>2025-07-23T15:51:18Z</updated>

		<summary type="html">&lt;p&gt;Created page with &amp;quot;local MessageBox = require(&amp;#039;Module:Message box&amp;#039;) local Gadgets = require(&amp;#039;Module:Gadgets&amp;#039;)  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  -- Lists of valid options for things that aren&amp;#039;t exposed to lua  -- (unlike namespaces that can be accessed from mw.site.namespaces) local VALID_CONTENT_MODELS = {&amp;#039;wikitext&amp;#039;, &amp;#039;javascript&amp;#039;, &amp;#039;css&amp;#039;, &amp;#039;...&amp;quot;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;New page&lt;/b&gt;&lt;/p&gt;&lt;div&gt;local MessageBox = require(&amp;#039;Module:Message box&amp;#039;)&lt;br /&gt;
local Gadgets = require(&amp;#039;Module:Gadgets&amp;#039;)&lt;br /&gt;
&lt;br /&gt;
local p = {}&lt;br /&gt;
&lt;br /&gt;
local function arr_contains(array, val)&lt;br /&gt;
    for _, value in ipairs(array) do&lt;br /&gt;
        if value == val then&lt;br /&gt;
            return true&lt;br /&gt;
        end&lt;br /&gt;
    end&lt;br /&gt;
    return false&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
-- Lists of valid options for things that aren&amp;#039;t exposed to lua &lt;br /&gt;
-- (unlike namespaces that can be accessed from mw.site.namespaces)&lt;br /&gt;
local VALID_CONTENT_MODELS = {&amp;#039;wikitext&amp;#039;, &amp;#039;javascript&amp;#039;, &amp;#039;css&amp;#039;, &amp;#039;json&amp;#039;, &amp;#039;MassMessageListContent&amp;#039;, &amp;#039;Scribunto&amp;#039;, &amp;#039;sanitized-css&amp;#039;}&lt;br /&gt;
&lt;br /&gt;
p.validate = function (frame)&lt;br /&gt;
	local text = mw.title.new(&amp;#039;MediaWiki:Gadgets-definition&amp;#039;):getContent()&lt;br /&gt;
	local lines = mw.text.split(text, &amp;#039;\n&amp;#039;, false)&lt;br /&gt;
	&lt;br /&gt;
	local repo = {}&lt;br /&gt;
	local allWarnings = {}	&lt;br /&gt;
	&lt;br /&gt;
	-- A bit of parsing is reimplemented here as [[Module:Gadgets]] doesn&amp;#039;t raise warnings&lt;br /&gt;
	-- for invalid lines&lt;br /&gt;
	for _, line in ipairs(lines) do&lt;br /&gt;
		if line:sub(1, 1) == &amp;#039;*&amp;#039; then&lt;br /&gt;
			local name, options, pages = Gadgets.parse_line(line)&lt;br /&gt;
			if not name or #pages == 0 then&lt;br /&gt;
				table.insert(allWarnings, &amp;#039;* Invalid definition: &amp;#039;..line)&lt;br /&gt;
			else&lt;br /&gt;
				repo[name] = { options = options, pages = pages }&lt;br /&gt;
			end&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
	&lt;br /&gt;
	for name, conf in pairs(repo) do&lt;br /&gt;
		local warnings = p.create_warnings(name, conf.options, conf.pages, repo)&lt;br /&gt;
		for _, warning in ipairs(warnings) do&lt;br /&gt;
			table.insert(allWarnings, &amp;#039;*&amp;#039;..name..&amp;#039;: &amp;#039;..warning)&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	if #allWarnings ~= 0 then&lt;br /&gt;
		return MessageBox.main(&amp;#039;ombox&amp;#039;, {&lt;br /&gt;
			text = &amp;#039;&amp;lt;b&amp;gt;Issues in gadget definitions:&amp;lt;/b&amp;gt;\n&amp;#039; .. table.concat(allWarnings, &amp;#039;\n&amp;#039;),&lt;br /&gt;
			type = &amp;#039;delete&amp;#039;,&lt;br /&gt;
			class = &amp;#039;gadgets-validation&amp;#039;&lt;br /&gt;
		})&lt;br /&gt;
	elseif require(&amp;#039;Module:If preview/configuration&amp;#039;).preview then&lt;br /&gt;
		return MessageBox.main(&amp;#039;ombox&amp;#039;, {&lt;br /&gt;
			text = &amp;#039;&amp;lt;b&amp;gt;Issues in gadget definitions:&amp;lt;/b&amp;gt; &amp;lt;i&amp;gt;No issues found!&amp;lt;/i&amp;gt;&amp;#039;,&lt;br /&gt;
			type = &amp;#039;notice&amp;#039;,&lt;br /&gt;
			image = &amp;#039;[[File:Check-green.svg|30px]]&amp;#039;,&lt;br /&gt;
			class = &amp;#039;gadgets-validation&amp;#039;&lt;br /&gt;
		})&lt;br /&gt;
	else &lt;br /&gt;
		return &amp;#039;&amp;#039;&lt;br /&gt;
	end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
p.create_warnings = function(name, options, pages, repo)&lt;br /&gt;
	local warnings = {}&lt;br /&gt;
	&lt;br /&gt;
	-- RL module name (ext.gadget.&amp;lt;name&amp;gt;) should not exceed 255 bytes&lt;br /&gt;
	-- so a limit of 255 - 11 = 244 bytes for gadget name&lt;br /&gt;
	if string.len(name) &amp;gt; 244 then&lt;br /&gt;
		table.insert(warnings, &amp;#039;Gadget name must not exceed 244 bytes&amp;#039;)&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	-- Per ResourceLoader::isValidModuleName&lt;br /&gt;
	if name:gsub(&amp;#039;[|,!]&amp;#039;, &amp;#039;&amp;#039;) ~= name then&lt;br /&gt;
		table.insert(warnings, &amp;#039;Gadget name must not contain pipes (|), commas (,) or exclamation marks (!)&amp;#039;)&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	-- Pattern per MediaWikiGadgetDefinitionsRepo::newFromDefinition&lt;br /&gt;
	if not string.match(name, &amp;quot;^[a-zA-Z][-_:%.%w ]*[a-zA-Z0-9]?$&amp;quot;) then&lt;br /&gt;
		table.insert(warnings, &amp;#039;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&amp;#039;)&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
    if options.type ~= nil and options.type ~= &amp;#039;general&amp;#039; and options.type ~= &amp;#039;styles&amp;#039; then&lt;br /&gt;
    	table.insert(warnings, &amp;#039;Allowed values for type are: general, styles&amp;#039;)&lt;br /&gt;
    end&lt;br /&gt;
    if options.targets ~= nil then&lt;br /&gt;
    	table.insert(warnings, &amp;#039;Setting targets in gadget defintion is deprecated and no longer has any effect&amp;#039;)&lt;br /&gt;
    end&lt;br /&gt;
    if options.namespaces ~= nil then&lt;br /&gt;
    	for _, id in ipairs(mw.text.split(options.namespaces, &amp;#039;,&amp;#039;, false)) do&lt;br /&gt;
    		if not string.match(id, &amp;#039;^-?%d+$&amp;#039;) then&lt;br /&gt;
    			table.insert(warnings, &amp;#039;Invalid namespace id: &amp;#039;..id..&amp;#039; - must be numeric&amp;#039;)&lt;br /&gt;
    		elseif mw.site.namespaces[tonumber(id)] == nil then&lt;br /&gt;
    			table.insert(warnings, &amp;#039;Namespace id &amp;#039;..id..&amp;#039; is invalid&amp;#039;)&lt;br /&gt;
    		end&lt;br /&gt;
    	end&lt;br /&gt;
    end&lt;br /&gt;
    if options.actions ~= nil then&lt;br /&gt;
    	for _, action in ipairs(mw.text.split(options.actions, &amp;#039;,&amp;#039;, false)) do&lt;br /&gt;
    		if not mw.message.new(&amp;#039;action-&amp;#039; .. action):exists() then&lt;br /&gt;
    			table.insert(warnings, &amp;#039;Action &amp;#039;..action..&amp;#039; is unrecognised&amp;#039;)&lt;br /&gt;
    		end&lt;br /&gt;
    	end&lt;br /&gt;
    end&lt;br /&gt;
    if options.contentModels ~= nil then&lt;br /&gt;
    	for _, model in ipairs(mw.text.split(options.contentModels, &amp;#039;,&amp;#039;, false)) do&lt;br /&gt;
    		if not arr_contains(VALID_CONTENT_MODELS, model) then&lt;br /&gt;
    			table.insert(warnings, &amp;#039;Content model &amp;#039;..model..&amp;#039; is unrecognised&amp;#039;)&lt;br /&gt;
    		end&lt;br /&gt;
    	end&lt;br /&gt;
    end&lt;br /&gt;
    if options.skins ~= nil then&lt;br /&gt;
    	for _, skin in ipairs(mw.text.split(options.skins, &amp;#039;,&amp;#039;, false)) do&lt;br /&gt;
    		if not mw.message.new(&amp;#039;skinname-&amp;#039; .. skin):exists() then&lt;br /&gt;
    			table.insert(warnings, &amp;#039;Skin &amp;#039;..skin..&amp;#039; is not available&amp;#039;)&lt;br /&gt;
    		end&lt;br /&gt;
    	end&lt;br /&gt;
    end&lt;br /&gt;
    if options.rights ~= nil then&lt;br /&gt;
    	for _, right in ipairs(mw.text.split(options.rights, &amp;#039;,&amp;#039;, false)) do&lt;br /&gt;
    		if not mw.message.new(&amp;#039;right-&amp;#039; .. right):exists() then&lt;br /&gt;
    			table.insert(warnings, &amp;#039;User right &amp;#039;..right..&amp;#039; does not exist&amp;#039;)&lt;br /&gt;
    		end&lt;br /&gt;
    	end&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    local scripts = {}&lt;br /&gt;
    local styles = {}&lt;br /&gt;
    local jsons = {}&lt;br /&gt;
    for _, page in ipairs(pages) do&lt;br /&gt;
    	page = &amp;#039;MediaWiki:Gadget-&amp;#039; .. page&lt;br /&gt;
    	local title = mw.title.new(page)&lt;br /&gt;
    	if title == nil or not title.exists then&lt;br /&gt;
    		table.insert(warnings, &amp;#039;Page [[&amp;#039;..page..&amp;#039;]] does not exist&amp;#039;)&lt;br /&gt;
    	else &lt;br /&gt;
	    	local ext = title.text:match(&amp;quot;%.([^%.]+)$&amp;quot;)&lt;br /&gt;
	    	if ext == &amp;#039;js&amp;#039; then&lt;br /&gt;
	    		if title.contentModel ~= &amp;#039;javascript&amp;#039; then&lt;br /&gt;
	    			table.insert(warnings, &amp;#039;Page [[&amp;#039;..page..&amp;#039;]] is not of JavaScript content model&amp;#039;)&lt;br /&gt;
	    		else&lt;br /&gt;
	    			table.insert(scripts, page)&lt;br /&gt;
	    		end&lt;br /&gt;
	    	elseif ext == &amp;#039;css&amp;#039; then&lt;br /&gt;
	    		if title.contentModel ~= &amp;#039;css&amp;#039; then&lt;br /&gt;
	    			table.insert(warnings, &amp;#039;Page [[&amp;#039;..page..&amp;#039;]] is not of CSS content model&amp;#039;)&lt;br /&gt;
	    		else&lt;br /&gt;
	    			table.insert(styles, page)&lt;br /&gt;
	    		end&lt;br /&gt;
	    	elseif ext == &amp;#039;json&amp;#039; then&lt;br /&gt;
	    		if title.contentModel ~= &amp;#039;json&amp;#039; then&lt;br /&gt;
	    			table.insert(warnings, &amp;#039;Page [[&amp;#039;..page..&amp;#039;]] is not of JSON content model&amp;#039;)&lt;br /&gt;
	    		else&lt;br /&gt;
	    			table.insert(jsons, page)&lt;br /&gt;
	    		end&lt;br /&gt;
	    	else&lt;br /&gt;
	    		table.insert(warnings, &amp;#039;Page [[&amp;#039;..page..&amp;#039;]] is not JS/CSS/JSON, will be ignored&amp;#039;)&lt;br /&gt;
	    	end&lt;br /&gt;
	    end&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    if not options.hidden then&lt;br /&gt;
	    local description_page = mw.title.new(&amp;#039;MediaWiki:Gadget-&amp;#039;..name)&lt;br /&gt;
	    if description_page == nil or not description_page.exists then&lt;br /&gt;
	    	table.insert(warnings, &amp;#039;Description [[&amp;#039;..description_page.fullText..&amp;#039;]] for use in Special:Preferences does not exist&amp;#039;)&lt;br /&gt;
	    end&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
    if options.package == nil and #jsons &amp;gt; 0 then&lt;br /&gt;
    	table.insert(warnings, &amp;#039;JSON pages cannot be used in non-package gadgets&amp;#039;)&lt;br /&gt;
    end&lt;br /&gt;
    if options.requiresES6 ~= nil and options.default ~= nil then&lt;br /&gt;
    	table.insert(warnings, &amp;#039;Default gadget cannot use requiresES6 flag&amp;#039;)&lt;br /&gt;
    end&lt;br /&gt;
    if options.type == &amp;#039;styles&amp;#039; and #scripts &amp;gt; 0 then&lt;br /&gt;
    	table.insert(warnings, &amp;#039;JS pages will be ignored as gadget sets type=styles&amp;#039;)&lt;br /&gt;
    end&lt;br /&gt;
    if options.type == &amp;#039;styles&amp;#039; and options.peers ~= nil then&lt;br /&gt;
    	table.insert(warnings, &amp;#039;Styles-only gadget cannot have peers&amp;#039;)&lt;br /&gt;
    end&lt;br /&gt;
    if options.type == &amp;#039;styles&amp;#039; and options.dependencies ~= nil then&lt;br /&gt;
    	table.insert(warnings, &amp;#039;Styles-only gadget cannot have dependencies&amp;#039;)&lt;br /&gt;
    end&lt;br /&gt;
    if options.package ~= nil and #scripts == 0 then&lt;br /&gt;
    	table.insert(warnings, &amp;#039;Package gadget must have at least one JS page&amp;#039;)&lt;br /&gt;
    end&lt;br /&gt;
    if options.ResourceLoader == nil and #scripts &amp;gt; 0 then&lt;br /&gt;
    	table.insert(warnings, &amp;#039;ResourceLoader option must be set&amp;#039;)&lt;br /&gt;
    end&lt;br /&gt;
    -- Causes warnings on styles-only gadgets using skins param &lt;br /&gt;
    -- 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&lt;br /&gt;
    -- 	table.insert(warnings, &amp;#039;Conditional load options are not applicable for hidden gadget&amp;#039;)&lt;br /&gt;
    -- end&lt;br /&gt;
&lt;br /&gt;
	if options.peers ~= nil then&lt;br /&gt;
		for _, peer in ipairs(mw.text.split(options.peers, &amp;#039;,&amp;#039;, false)) do &lt;br /&gt;
			if repo[peer] == nil then&lt;br /&gt;
				table.insert(warnings, &amp;#039;Peer gadget &amp;#039;..peer..&amp;#039; is not defined&amp;#039;)&lt;br /&gt;
			elseif Gadgets.get_type(repo[peer]) == &amp;#039;general&amp;#039; then&lt;br /&gt;
				table.insert(warnings, &amp;#039;Peer gadget &amp;#039;..peer..&amp;#039; must be styles-only gadget&amp;#039;)&lt;br /&gt;
			end&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	if options.dependencies ~= nil then&lt;br /&gt;
		for _, dep in ipairs(mw.text.split(options.dependencies, &amp;#039;,&amp;#039;, false)) do&lt;br /&gt;
			if dep:sub(1, 11) == &amp;#039;ext.gadget.&amp;#039; then&lt;br /&gt;
				local dep_gadget = dep:sub(12)&lt;br /&gt;
				if repo[dep_gadget] == nil then&lt;br /&gt;
					table.insert(warnings, &amp;#039;Dependency gadget &amp;#039;..dep_gadget..&amp;#039; is not defined&amp;#039;)&lt;br /&gt;
				end&lt;br /&gt;
			end&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	return warnings&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
return p&lt;/div&gt;</summary>
		<author><name>Shia.k</name></author>
	</entry>
</feed>