diff --git a/Script doc auto/Gadgets.lua b/Script doc auto/Gadgets.lua
new file mode 100644
index 0000000..e34bdbd
--- /dev/null
+++ b/Script doc auto/Gadgets.lua
@@ -0,0 +1,86 @@
+local p = {}
+
+p.parse = function()
+ local text = mw.title.new('MediaWiki:Gadgets-definition'):getContent()
+ local lines = mw.text.split(text, '\n', false)
+
+ local repo = {}
+ for _, line in ipairs(lines) do
+ if line:sub(1, 1) == '*' then
+ local name, options, pages = p.parse_line(line)
+ if name and #pages ~= 0 then
+ repo[name] = { options = options, pages = pages }
+ end
+ end
+ end
+ return repo
+end
+
+p.parse_line = function(def)
+ local pattern = "^%*%s*(.+)%s*(%b[])%s*(.-)$"
+ local name, opts, pageList = string.match(def, pattern)
+
+ if name then
+ name = mw.text.trim(name)
+ end
+
+ -- Process options string into a Lua table
+ local options = {}
+ if opts then
+ -- Extracting the options without square brackets and trimming spaces
+ opts = opts:sub(2, -2):gsub("%s+", "")
+
+ 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
+ end
+
+ -- Process page list into an array
+ local pages = {}
+ if pageList then
+ for page in pageList:gmatch("[^|]+") do
+ table.insert(pages, mw.text.trim(page))
+ end
+ end
+ return name, options, pages
+end
+
+p.get_type = function(def)
+ if def.options.type == 'general' or def.options.type == 'styles' then
+ return def.options.type
+ end
+ if def.options.dependencies ~= nil then
+ return 'general'
+ end
+ for _, page in ipairs(def.pages) do
+ if not string.match(page, '%.css$') then
+ return 'general'
+ end
+ end
+ return 'styles'
+end
+
+p.get_usage = function(name)
+ name = name:gsub("_", " ")
+
+ local success, tabData = pcall(mw.ext.data.get, 'GadgetUsage.tab')
+ if not success or not tabData or not tabData.data then
+ return -1
+ end
+
+ for _, row in ipairs(tabData.data) do
+ if row[1] == name then
+ return tonumber(row[2]) or -1
+ end
+ end
+
+ return -1
+end
+
+return p
\ No newline at end of file
diff --git a/Script doc auto/main.lua b/Script doc auto/main.lua
new file mode 100644
index 0000000..a2c9260
--- /dev/null
+++ b/Script doc auto/main.lua
@@ -0,0 +1,148 @@
+local MessageBox = require('Module:Message box')
+local Gadgets = require('Module:Gadgets')
+local Arguments = require('Module:Arguments')
+local TableTools = require('Module:TableTools')
+
+local p = {}
+
+p.main = function(frame)
+ local args = Arguments.getArgs(frame)
+ return p.core(args.page or mw.title.getCurrentTitle().fullText)
+end
+
+p.core = function(page)
+ local text = ''
+
+ local content = mw.title.new(page).content
+ if content then
+ local result = content:match("/%* ({{mfd.-}})")
+ if result then
+ text = text .. mw.getCurrentFrame():preprocess(result)
+ end
+ end
+
+ local len = page:len()
+ if len < 4 then
+ -- Too short page name, do nothing more
+ return text
+ end
+
+ return p.makeMessage(page)
+end
+
+local skins = TableTools.listToSet({
+ 'common', 'vector-2022', 'vector', 'timeless', 'minerva', 'monobook', 'modern', 'cologneblue', 'citizen'
+})
+
+p.gadget_text = function(name, repo)
+ local lang = mw.getContentLanguage()
+ local options = repo[name].options
+ local dependents = {}
+ if options.hidden ~= nil then
+ -- Find dependents
+ for n, c in pairs(repo) do
+ local deps = c.options.dependencies and
+ TableTools.listToSet(mw.text.split(c.options.dependencies, ',', false)) or {}
+ local peers = c.options.peers and
+ TableTools.listToSet(mw.text.split(c.options.peers, ',', false)) or {}
+ if deps['ext.gadget.'..name] ~= nil or peers[name] ~= nil then
+ table.insert(dependents, '[[Special:Gadgets#gadget-'..n..'|'..n..']]')
+ end
+ end
+ end
+ local usage = Gadgets.get_usage(name)
+ if usage == -1 then
+ usage = "an unknown number of"
+ else
+ usage = lang:formatNum(usage)
+ end
+ return 'This page is loaded as a part of the ' ..
+ '[[Special:Gadgets#gadget-'..name..'|'..name..']] gadget' ..
+ (options.hidden ~= nil and ', a hidden gadget'..
+ (#dependents > 0 and ' used by '..mw.text.listToText(dependents)..'.' or '.') or
+ (options.default ~= nil and ', which is enabled by default.' or
+ (', used by '..usage..' users. ')))
+end
+
+p.makeMessage = function(page)
+ local pageparts = mw.text.split(page, '.', true)
+ local pagetype = '.' .. pageparts[#pageparts]
+
+ local pagetypes = TableTools.listToSet({
+ '.js', '.css', '.json', '.vue'
+ })
+
+ if #pageparts<2 or pagetypes[pagetype] == nil then
+ return ''
+ end
+
+ local function listSisters(title, intro)
+ local output = {intro}
+ for sistertype in pairs(pagetypes) do
+ if sistertype ~= pagetype then
+ local sisterpage = mw.title.new(title .. sistertype)
+ if sisterpage.exists then
+ table.insert(output,
+ 'an accompanying '..sistertype..' page at [['..sisterpage.fullText..']]'
+ )
+ end
+ end
+ end
+ --listToText with Oxford commas
+ return mw.text.listToText(output, ', ', (#output > 2) and ', and ' or ' and ') .. '.'
+ end
+
+ local text = ''
+ local basepage = mw.title.new(page:sub(0, -1 * (#pagetype + 1)))
+
+ if basepage.namespace == 2 then
+ if skins[basepage.subpageText] ~= nil and (pagetype == '.js' or pagetype == '.css') then
+ -- We are on a user skin file
+ local sistertype = (pagetype == '.js') and '.css' or '.js'
+ local sisterpage = mw.title.new(basepage.fullText .. sistertype)
+ text = 'The accompanying '..sistertype..' page for this skin '..
+ (sisterpage.exists and 'is' or 'can be added')..' at [['..sisterpage.fullText..']].'
+ else
+ -- We are on some script page, not a user skin file
+ if basepage.exists then
+ text = listSisters(basepage.fullText, 'This user script seems to have a documentation page at [['..basepage.fullText..']]')
+ else
+ text = listSisters(basepage.fullText)
+ text = 'Documentation for this user script can be added at [['..basepage.fullText..']]' ..
+ ((#text > 1) and '. This user script seems to have ' or '') ..
+ text
+ end
+ end
+ elseif basepage.namespace == 8 then
+ if basepage.text:find('^Gadget-') ~= nil then
+ local gadgetRepo = Gadgets.parse()
+ local shortName = basepage.text:gsub('^Gadget%-', '') .. pagetype
+ for name, config in pairs(gadgetRepo) do
+ if TableTools.inArray(config.pages, shortName) then
+ text = text .. p.gadget_text(name, gadgetRepo)
+ end
+ end
+ if text ~= '' then
+ local sisterText = listSisters(basepage.fullText)
+ text = text ..
+ ((#sisterText > 1) and (' There seems to be ' .. sisterText) or '') ..
+ '
'
+ end
+ end
+ end
+
+ if text ~= '' then
+ return mw.getCurrentFrame():extensionTag{
+ name = 'templatestyles', args = { src = 'Module:Script doc auto/styles.css' }
+ } .. MessageBox.main('fmbox', {
+ class = 'script-doc-auto-box',
+ id = 'mw-script-doc',
+ type = 'system',
+ image = '[[File:Ledger_open_button.webp|43x40px|link=]]',
+ text = text
+ })
+ end
+ return ''
+end
+
+return p
\ No newline at end of file
diff --git a/Script doc auto/styles.css b/Script doc auto/styles.css
new file mode 100644
index 0000000..e814811
--- /dev/null
+++ b/Script doc auto/styles.css
@@ -0,0 +1,18 @@
+/* {{pp-template|small=yes}} */
+/* colors same as [[Module:Documentation/styles.css]] */
+.script-doc-auto-box.script-doc-auto-box {
+ background: #061016;
+}
+
+@media screen {
+ html.skin-theme-clientpref-night .script-doc-auto-box.script-doc-auto-box {
+ background-color: #061016;
+ }
+}
+
+
+@media screen and ( prefers-color-scheme: dark) {
+ html.skin-theme-clientpref-os .script-doc-auto-box.script-doc-auto-box {
+ background-color: #061016;
+ }
+}
\ No newline at end of file