This module was created by User:CodeHydro (Alexander Zhikun He).
User:Jackmcbarn and User:Mr._Stradivarius provided a great deal of assistance in writting p.main

p.main draw heavily from the following version of Template:Asbox of the English Wikipedia, authored primarily by User:Rich_Farmbrough
https://en.wikipedia.org/w/index.php?title=Template:Asbox&oldid=619510287

p.templatepage is derived from the following revision of Template:Asbox/templatepage, authored primarily by User:MSGJ
https://en.wikipedia.org/w/index.php?title=Template:Asbox/templatepage&oldid=632914791

Both templates had significant contributions from numerous others listed in the revision history tab of their respective pages.
--]]
local WRAPPER_TEMPLATE, args = 'Template:Asbox'
local templatestyles = 'Asbox/styles.css'
local p, Buffer, stubCats = {
	--Prevents dupli-cats... get it? Maybe not?
	cats = setmetatable({}, {__newindex = function
		if not rawget then
			rawset
			table.insert
		end
	end}),
	--initializes variables required by both p.main and p.templatepage
	init = function
		args, page = args or require('Module:Arguments').getArgs(frame, {
			wrappers = WRAPPER_TEMPLATE
		--Ensures demo parameter will never affect category output for articles
		self.demo = self.demo or page.namespace ~= 0 and args.demo
		return args, page
	end

--
Formats category links. Stores them until called with cat.done=true
Takes multiple or single categories in the form of 'cat'
or a table of strings and/or tables containing parts. (See below)

local attention, catTag, catKey = Buffer'Stub message templates needing attention', 'Category:%s', '%s|%s%s'
local function category(cat)
	for _, v in ipairs((tostring(cat) == cat or cat.t) and {cat} or cat) do
		--[[
		If v is a table:
			[1] = full category name; defaults to local attention if blank
			k = Category sort key. Prefix before v.t
			t = page.text or args.tempsort#; appended after k (or in its place if omitted). Required if v is not a string
		Basically the same as v = (v[1] or attention) .. ' | ' .. (v.k or '') .. v.t
		]]
		if v and v ~= true then--reject v = nil, false, or true
			p.cats[catTag:format(tostring(v) == v and
				v
				or (v[1] and Buffer(v[1]) or attention):_in(v.k):_(v.t):_str
			)] = true
		end
	end
	return cat.done and table.concat or ''
end

--
Makes an ombox warning;
Takes table {ifNot = Boolean, text, {cat. sort key, cat. sort name}}
Will return an empty string instead when ifNot evaluates to true 

local function ombox(v)
	if v.ifNot then return end
	p.ombox = p.ombox or require('Module:Message box').ombox
	category{v[2]}
	return p.ombox{
		type = 'content',
		text = v[1]
end

--category= is omitted (See p.template)

local function catStub
	stubCats = {missing = {}, v = {}}
	-- zwj and zwnj have semantical use in other other wikis, don't remove them
	local zwj = '\226\128\141' -- U+200D, E2 80 8D
	local zwnj = '\226\128\140' -- U+200C, E2 80 8C
	local disallowedUnicodeChars = '[^%w%p%s' .. zwj .. zwnj .. ']' -- for i18n we make this a separate string
	local code
	for k, _ in pairs(args) do
		--Find category parameters and store the number (main cat = '')
		table.insert(stubCats, string.match(k, '^category(%d*)$'))
	end
	table.sort(stubCats)
	for k, v in ipairs(stubCats) do
		--Get category names and, if called by p.templatepage, the optional sort key
		local tsort, cat = args['tempsort' .. v], mw.ustring.gsub--remove all hidden unicode chars 
		--Do not place template in main category if |tempsort = 'no'. However, DO place articles of that template in the main category.
		table.insert(stubCats.v,
			 page and 
			or cat
		)
		--Check category existance only if on the template page (i.e. stub documentation)
		if page then
			if not mw.title.new('Category:' .. cat).exists then
				code = code or mw.html.create'code':wikitext'|category'
				table.insert(stubCats.missing, tostring(mw.clone(code):wikitext(v)))
			end
			--[[
			Checks non-demo stub template for documentation and flags if doc is present.
			All stub cats names are checked and flagged if it does not match 'Category: [] stub'.
			The main stub cat is exempt from the name check if the stub template has its own doc
			.
			]]
			table.insert
		end
	end
	--Add category names after loop is completed
	category(stubCats.v)
	return #stubCats.missing > 0 and ombox{
		--Changed, original msg:
		--One or more of the stub categories defined in this template do not seem to exist!
		--Please double-check the parameters , and .
		'The following parameter'
			.. (#stubCats.missing == 1 and ' defines a stub category that does' or 's define stub categories that do')
			.. ' not exist: ' .. mw.text.listToText(stubCats.missing),
end

--Shows population of categories found by catStub. Outputs demo values if none
local function population
	local wikitext, base = {}, '* :Category:%s (population: %s)\n'
	if not args.category and stubCats[1] ~= false then
		table.insert
	end
	for _, v in ipairs(stubCats) do
		table.insert(wikitext, base:format(
			v and args['category' .. v] or '}',
			v and mw.site.stats.pagesInCategory or 0
		))
	end
	return table.concat(wikitext)
end

--Includes standard stub documention and flags stub templates with bad parameter values.
function p.templatepage
	args, page = p:init
	local tStubDoc = mw.title.new'Template:Stub documentation'
	local pageDoc = page:subPageTitle('doc')
	--Reorganization note: Original Asbox alternates between outputting categories and checking on params |category#=.
	--Rather than checking multiple times and switching tasks, all stub category param operations have been rolled into catStub
	return Buffer(
		ombox{--Show ombox warnings for missing args.
			ifNot = args.category,
			'The  parameter is not set. Please add an appropriate stub category.',
			ifNot = args.subject or args.article or args.qualifier,
			'This stub template contains no description! At least one of the parameters  must be defined.',
			done = p.demo ~= 'doc',--Outputs categories if not doc demo
			'Stub message templates',
			args.icon and
				'Stub message templates using icon parameter'
				or args.image and (
					mw.title.new('Media:' .. mw.text.split[1]).exists--do nothing if exists. category will reject true
					or {k = 'B', t = page.text}
				)
				or 'Stub message templates without images',
			args.imagealt and {k = 'I', t = page.text},
			require('Module:Documentation').main{
				content = Buffer(page.text ~= 'Stub' and--This comparison performed in before it invokes Module:Asbox stubtree
						require('Module:Asbox stubtree').subtree{args = {pagename = page.text}}
					)
					)
						frame:expandTemplate{title = pageDoc.text}
					)
				['link box'] = Buffer'This documentation is automatically generated by Module:Asbox.'
								tStubDoc:fullUrl,
								tStubDoc:fullUrl
							))
						)
						"This template is fully protected and any categories should be added to the template's ["
						.. pageDoc:fullUrl
						.. '| /doc] subpage, which is not protected.'
					)' '
		)
end

function p.main
	args, page = p:init
	local output = mw.html.create'div'
					mw.html.create'td'
							args.image or '',
							args.pix or '40x30',
							args.imagealt or 'Stub icon'
						))
				)
							Buffer'This':_(args.subject):_(args.article or 'article'):_(args.qualifier)' ',--space
							' is a stub. You can help Wikipedia by [',
							page:fullUrl,
							' expanding it].'
						)
						mw.html.create
					)
			require'Module:Navbar'._navbar{
				args.name,
				mini = 'yes',
			)
	--
	Stub categories for templates include a sort key; this ensures that all stub tags appear at the beginning of their respective categories.
	Articles using the template do not need a sort key since they have unique names.
	When p.demo equals 'doc', the demo stub categories will appear as those for a stub template.
	Otherwise, any non-nil p.demo will emulate article space categories (plus any error cats unless set to 'art')
	
	if page.namespace == 0 then -- Main namespace
		category'All stub articles'
		catStub
	elseif p.demo then
		if p.demo ~= 'doc' then catStub end
		--Unless p.demo is set to 'art', it will also include error categories normally only shown on
		--the template but not in the article. The elseif after namespace == 0 means demo cats will never show in article space.
		p.demodoc = p.demo ~= 'art' and p.templatepage
		output = mw.html.create
				'Demo categories: ',
				(category{done = true}:gsub('(%[%[)(Category:)([^|%]]-)(%|)', '%1%2%3|%2%3%4'):gsub('(%[%[)(Category:)', '%1:%2'))
			):done
	else
		--Checks for valid name; emulates original template's check using }}}
		local normalizedName = mw.title.new(args.name or '')
		if normalizedName and normalizedName.fullText == page.fullText then
			output = mw.html.create:node(output):wikitext(p.templatepage)
		elseif not page.isSubpage and page.namespace == 10 then-- Template namespace and not a subpage
			category
		end
	end
	return frame:extensionTag{ name = 'templatestyles', args = { src = templatestyles} } .. tostring(output:wikitext(not p.demo and category{done = true} or nil))
end