Module:Find sources/autodoc: Difference between revisions

From Zoophilia Wiki
Jump to navigationJump to search
meta>Mr. Stradivarius
add a docIntro field to be used instead of the first line of the documentation
meta>Mr. Stradivarius
add code to test the subpages we use so that we don't get script errors when someone enters incorrect data on a random subpage
Line 57: Line 57:
return filtered
return filtered
end
end
local function isValidLink(code)
if type(code) ~= 'string' or code == '' then
return false
end
local linkCfg = maybeLoadData(LINK_ROOT .. code)
if type(linkCfg) ~= 'table' then
return false
end
for _, s in ipairs{'url', 'display'} do
if type(linkCfg[s]) ~= 'string' then
return false
end
end
for _, s in ipairs{'separator'} do
if linkCfg[s] ~= nil and type(linkCfg[s]) ~= 'string' then
return false
end
end
return true
end
local function isValidTemplate(template)
if type(template) ~= 'string' or template == '' then
return false
end
local templateCfg = maybeLoadData(TEMPLATE_ROOT .. template)
if type(templateCfg) ~= 'table' then
return false
end
for _, s in ipairs{'blurb'} do
if type(templateCfg[s]) ~= 'string' then
return false
end
end
for _, s in ipairs{'separator', 'class', 'style'} do
if templateCfg[s] ~= nil and type(templateCfg[s]) ~= 'string' then
return false
end
end
if templateCfg[s] and templateCfg[s] ~= true then
return false
end
if type(templateCfg.links) ~= 'table' then
return false
end
local function isValidLinkTable(t)
if type(t) ~= 'table' then
return false
end
if type(t.code) ~= 'string' then
return false
end
if t.display and type(t.display) ~= 'string' then
return false
end
return true
end
if templateCfg.introLink and not isValidLinkTable(templateCfg.introLink) then
return false
end
for _, t in ipairs(templateCfg.links) do
if not isValidLinkTable(t) then
return false
end
end
return true
end
local function isValidLinkAutdocCfg(t)
if type(t) ~= 'table' then
return false
end
for _, s in ipairs{'description', 'notes'} do
if t[s] and type(t[s]) ~= 'string' then
return false
end
end
return true
end
local function isValidTemplateAutdocCfg(t)
if type(t) ~= 'table' then
return false
end
for _, s in ipairs{'description', 'docIntro'} do
if t[s] and type(t[s]) ~= 'string' then
return false
end
end
if t.shortcuts and type(t.shortcuts) ~= 'table' then
return false
elseif t.shortcuts then
for _, s in ipairs(t.shortcuts) do
if type(s) ~= 'string' then
return false
end
end
end
return true
end


local function makeWikitable(headers, rows)
local function makeWikitable(headers, rows)
Line 90: Line 194:
local function bold(s)
local function bold(s)
return string.format("'''%s'''", s)
return string.format("'''%s'''", s)
end
local function makeWikitextError(msg)
return string.format('<span class="error">%s</span>', msg)
end
end


Line 111: Line 219:
local rows = {}
local rows = {}
for i, code in ipairs(codes) do
for i, code in ipairs(codes) do
local configPage = LINK_ROOT .. code
if isValidLink(code) then
local autodocConfigPage = configPage .. AUTODOC_SUFFIX
local configPage = LINK_ROOT .. code
local linkData = maybeLoadData(autodocConfigPage) or {}
local autodocConfigPage = configPage .. AUTODOC_SUFFIX
local row = {
local linkData = maybeLoadData(autodocConfigPage)
bold(code),
if not isValidLinkAutdocCfg(linkData) then
linkData.description or grey("''No description available''"),
linkData = {}
mFindSources._renderLink(code, {cfg['example-search-term']}),
end
table.concat({
local row = {
makeWikilink(configPage, cfg['link-table-main-config-link-display']),
bold(code),
makeWikilink(autodocConfigPage, cfg['link-table-autodoc-config-link-display'])
linkData.description or grey("''No description available''"),
}, cfg['table-config-separator']),
mFindSources._renderLink(code, {cfg['example-search-term']}),
linkData.notes or ''
table.concat({
}
makeWikilink(configPage, cfg['link-table-main-config-link-display']),
rows[i] = row
makeWikilink(autodocConfigPage, cfg['link-table-autodoc-config-link-display'])
}, cfg['table-config-separator']),
linkData.notes or ''
}
rows[i] = row
else
local msg = string.format(
'Invalid link code detected on page [[%s]].',
LINK_ROOT .. code
)
msg = makeWikitextError(msg)
msg = '| colspan="5" ' .. msg
rows[i] = {msg}
end
end
end
return makeWikitable(headers, rows)
return makeWikitable(headers, rows)
Line 139: Line 260:
local rows = {}
local rows = {}
for i, template in ipairs(templates) do
for i, template in ipairs(templates) do
local configPage = TEMPLATE_ROOT .. template
if isValidTemplate(template) then
local autodocConfigPage = configPage .. AUTODOC_SUFFIX
local configPage = TEMPLATE_ROOT .. template
local templateData = maybeLoadData(autodocConfigPage) or {}
local autodocConfigPage = configPage .. AUTODOC_SUFFIX
local row = {
local templateData = maybeLoadData(autodocConfigPage)
bold(makeWikilink(mw.site.namespaces[10].name .. ':' .. template, template)),
if not isValidTemplateAutdocCfg(templateData) then
templateData.description or grey("''No description available''"),
templateData = {}
mFindSources._main(template, {cfg['example-search-term']}),
end
table.concat({
local row = {
makeWikilink(configPage, cfg['template-table-main-config-link-display']),
bold(makeWikilink(mw.site.namespaces[10].name .. ':' .. template, template)),
makeWikilink(autodocConfigPage, cfg['template-table-autodoc-config-link-display'])
templateData.description or grey("''No description available''"),
}, cfg['table-config-separator'])
mFindSources._main(template, {cfg['example-search-term']}),
}
table.concat({
rows[i] = row
makeWikilink(configPage, cfg['template-table-main-config-link-display']),
makeWikilink(autodocConfigPage, cfg['template-table-autodoc-config-link-display'])
}, cfg['table-config-separator'])
}
rows[i] = row
else
local msg = string.format(
'Invalid template configuration detected on page [[%s]].',
TEMPLATE_ROOT .. template
)
msg = makeWikitextError(msg)
msg = '| colspan="4" ' .. msg
rows[i] = {msg}
end
end
end
return makeWikitable(headers, rows)
return makeWikitable(headers, rows)

Revision as of 14:51, 29 September 2014

Documentation for this module may be created at Module:Find sources/autodoc/doc

-- Define constants
local ROOT_PAGE = 'Module:Find sources'
local TEMPLATE_ROOT = ROOT_PAGE .. '/templates/' -- for template config modules
local LINK_ROOT = ROOT_PAGE .. '/links/' -- for link config modules
local AUTODOC_SUFFIX = '/autodoc'

-- Load necessary modules.
local mFindSources = require('Module:Find sources')
local cfg = mw.loadData('Module:Find sources/autodoc/config')

local p = {}

local function maybeLoadData(page)
	local success, data = pcall(mw.loadData, page)
	return success and data
end

local function escapePattern(s)
	return s:gsub('%p', '%%%0')
end

local function getPrefixPagenames(prefix)
	local specialText = string.format('{{Special:PrefixIndex/%s}}', prefix)
	specialText = mw.getCurrentFrame():preprocess(specialText)
	specialText = mw.text.unstrip(specialText)
	local pagenames = {}
	for s in string.gmatch(specialText, '<a href="[^"]*" title="([^"]*)"[^>]*>[^<]*</a>') do
		pagenames[#pagenames + 1] = mw.text.decode(s)
	end
	return pagenames
end

local function getSubpages(pagenames, prefix)
	local stripped = {}
	for i, page in ipairs(pagenames) do
		local pattern = '^' .. escapePattern(prefix) -- Turn the prefix into a Lua pattern
		stripped[i] = mw.ustring.gsub(page, pattern, '')
	end
	return stripped
end

local function getPrefixSubpages(prefix)
	return getSubpages(getPrefixPagenames(prefix), prefix)
end

local function getFilteredPrefixSubpages(prefix)
	-- Filter out unwanted pages from the subpage list. For now, this means
	-- the autodoc pages.
	local subpages = getPrefixSubpages(prefix)
	local pattern = escapePattern(AUTODOC_SUFFIX) .. '$'
	local filtered = {}
	for _, subpage in ipairs(subpages) do
		if not mw.ustring.find(subpage, pattern) then
			filtered[#filtered + 1] = subpage
		end
	end
	return filtered
end	

local function isValidLink(code)
	if type(code) ~= 'string' or code == '' then
		return false
	end
	local linkCfg = maybeLoadData(LINK_ROOT .. code)
	if type(linkCfg) ~= 'table' then
		return false
	end
	for _, s in ipairs{'url', 'display'} do
		if type(linkCfg[s]) ~= 'string' then
			return false
		end
	end
	for _, s in ipairs{'separator'} do
		if linkCfg[s] ~= nil and type(linkCfg[s]) ~= 'string' then
			return false
		end
	end
	return true
end

local function isValidTemplate(template)
	if type(template) ~= 'string' or template == '' then
		return false
	end
	local templateCfg = maybeLoadData(TEMPLATE_ROOT .. template)
	if type(templateCfg) ~= 'table' then
		return false
	end
	for _, s in ipairs{'blurb'} do
		if type(templateCfg[s]) ~= 'string' then
			return false
		end
	end
	for _, s in ipairs{'separator', 'class', 'style'} do
		if templateCfg[s] ~= nil and type(templateCfg[s]) ~= 'string' then
			return false
		end
	end
	if templateCfg[s] and templateCfg[s] ~= true then
		return false
	end
	if type(templateCfg.links) ~= 'table' then
		return false
	end

	local function isValidLinkTable(t)
		if type(t) ~= 'table' then
			return false
		end
		if type(t.code) ~= 'string' then
			return false
		end
		if t.display and type(t.display) ~= 'string' then
			return false
		end
		return true
	end

	if templateCfg.introLink and not isValidLinkTable(templateCfg.introLink) then
		return false
	end
	for _, t in ipairs(templateCfg.links) do
		if not isValidLinkTable(t) then
			return false
		end
	end

	return true
end

local function isValidLinkAutdocCfg(t)
	if type(t) ~= 'table' then
		return false
	end
	for _, s in ipairs{'description', 'notes'} do
		if t[s] and type(t[s]) ~= 'string' then
			return false
		end
	end
	return true
end

local function isValidTemplateAutdocCfg(t)
	if type(t) ~= 'table' then
		return false
	end
	for _, s in ipairs{'description', 'docIntro'} do
		if t[s] and type(t[s]) ~= 'string' then
			return false
		end
	end
	if t.shortcuts and type(t.shortcuts) ~= 'table' then
		return false
	elseif t.shortcuts then
		for _, s in ipairs(t.shortcuts) do
			if type(s) ~= 'string' then
				return false
			end
		end
	end
	return true
end

local function makeWikitable(headers, rows)
	local ret = {}

	-- Table start
	ret[#ret + 1] = '{| class="wikitable"'

	-- Headers
	ret[#ret + 1] = '|-'
	for i, header in ipairs(headers) do
		ret[#ret + 1] = '! ' .. header
	end

	-- Rows
	for i, row in ipairs(rows) do
		ret[#ret + 1] = '|-'
		for j, cell in ipairs(row) do
			ret[#ret + 1] = '| ' .. cell
		end
	end

	-- Table end
	ret[#ret + 1] = '|}'

	return table.concat(ret, '\n')
end

local function grey(s)
	return string.format('<span style="color: gray;">%s</span>', s)
end

local function bold(s)
	return string.format("'''%s'''", s)
end

local function makeWikitextError(msg)
	return string.format('<span class="error">%s</span>', msg)
end

local function makeWikilink(page, display)
	if display then
		return string.format('[[%s|%s]]', page, display)
	else
		return string.format('[[%s]]', page)
	end
end

function p.linkTable()
	local codes = getFilteredPrefixSubpages(LINK_ROOT)
	local headers = {
		cfg['link-table-code-header'],
		cfg['link-table-description-header'],
		cfg['link-table-example-header'],
		cfg['link-table-config-header'],
		cfg['link-table-notes-header']
	}
	local rows = {}
	for i, code in ipairs(codes) do
		if isValidLink(code) then
			local configPage = LINK_ROOT .. code
			local autodocConfigPage = configPage .. AUTODOC_SUFFIX
			local linkData = maybeLoadData(autodocConfigPage)
			if not isValidLinkAutdocCfg(linkData) then
				linkData = {}
			end
			local row = {
				bold(code),
				linkData.description or grey("''No description available''"),
				mFindSources._renderLink(code, {cfg['example-search-term']}),
				table.concat({
					makeWikilink(configPage, cfg['link-table-main-config-link-display']),
					makeWikilink(autodocConfigPage, cfg['link-table-autodoc-config-link-display'])
				}, cfg['table-config-separator']),
				linkData.notes or ''
			}
			rows[i] = row
		else
			local msg = string.format(
				'Invalid link code detected on page [[%s]].',
				LINK_ROOT .. code
			)
			msg = makeWikitextError(msg)
			msg = '| colspan="5" ' .. msg
			rows[i] = {msg}
		end
	end
	return makeWikitable(headers, rows)
end

function p.templateTable()
	local templates = getFilteredPrefixSubpages(TEMPLATE_ROOT)
	local headers = {
		cfg['template-table-template-header'],
		cfg['template-table-description-header'],
		cfg['template-table-example-header'],
		cfg['template-table-config-header'],
	}
	local rows = {}
	for i, template in ipairs(templates) do
		if isValidTemplate(template) then
			local configPage = TEMPLATE_ROOT .. template
			local autodocConfigPage = configPage .. AUTODOC_SUFFIX
			local templateData = maybeLoadData(autodocConfigPage)
			if not isValidTemplateAutdocCfg(templateData) then
				templateData = {}
			end
			local row = {
				bold(makeWikilink(mw.site.namespaces[10].name .. ':' .. template, template)),
				templateData.description or grey("''No description available''"),
				mFindSources._main(template, {cfg['example-search-term']}),
				table.concat({
					makeWikilink(configPage, cfg['template-table-main-config-link-display']),
					makeWikilink(autodocConfigPage, cfg['template-table-autodoc-config-link-display'])
				}, cfg['table-config-separator'])
			}
			rows[i] = row
		else
			local msg = string.format(
				'Invalid template configuration detected on page [[%s]].',
				TEMPLATE_ROOT .. template
			)
			msg = makeWikitextError(msg)
			msg = '| colspan="4" ' .. msg
			rows[i] = {msg}
		end
	end
	return makeWikitable(headers, rows)
end

local function documentation(template)
	-- This function makes documentation for the template specified in
	-- frame.args[1]. The template name should be without the "Template:"
	-- prefix.

	-- Load necessary modules
	local mDocumentation = require('Module:Documentation')
	local mList = require('Module:List')
	local frame = mw.getCurrentFrame()

	-- Load the config files
	local templateCfg = maybeLoadData(TEMPLATE_ROOT .. template)
	if not templateCfg then
		error(string.format(
			"invalid template name '%s'; no template config found at [[%s]]",
			template,
			TEMPLATE_ROOT .. template
		))
	end
	local autodocCfg = maybeLoadData(TEMPLATE_ROOT .. template .. AUTODOC_SUFFIX) or {}

	-- Get the documentation content
	local content
	do
		-- Shortcuts
		local shortcuts
		if autodocCfg.shortcuts then
			shortcuts = frame:expandTemplate{title = 'Template shortcut', args = autodocCfg.shortcuts}
		end

		-- Link descriptions
		local codes = {}
		if templateCfg.introLink then
			codes[#codes + 1] = templateCfg.introLink.code
		end
		for _, t in ipairs(templateCfg.links) do
			codes[#codes + 1] = t.code
		end
		for i, code in ipairs(codes) do
			local linkAutodocCfg = maybeLoadData(LINK_ROOT .. code .. AUTODOC_SUFFIX) or {}
			codes[i] = linkAutodocCfg.description or code
		end
		local linkDescriptions = mList.bulleted(codes)

		-- Build the content.
		content = frame:expandTemplate{title = 'Find sources documentation', args = {
			template = template,
			shortcuts = shortcuts,
			docIntro = autodocCfg.docIntro,
			isUsedInMainspace = templateCfg.isUsedInMainspace and 'yes' or nil,
			linkDescriptions = linkDescriptions
		}}
	end

	return mDocumentation.main{content = content, ['link box'] = cfg['end-box-blurb']}
end

setmetatable(p, { __index = function(t, template)
	return function()
		return documentation(template)
	end
end})

return p