Module:Find sources/autodoc

From Zoophilia Wiki
Revision as of 15:14, 28 September 2014 by meta>Mr. Stradivarius (use a metatable to get the template name from the function we are passed, in line with the main module)
Jump to navigationJump to search

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

-- Config
local cfg = {}
cfg['example-search-term'] = 'Example'
cfg['link-table-code-header'] = 'Code'
cfg['link-table-description-header'] = 'Description'
cfg['link-table-example-header'] = 'Example'
cfg['link-table-config-header'] = 'Configuration'
cfg['link-table-main-config-link-display'] = 'main'
cfg['link-table-autodoc-config-link-display'] = 'documentation'
cfg['link-table-notes-header'] = 'Notes'
cfg['end-box-blurb'] = 'This documentation is generated by ' ..
	'[[Template:Find sources documentation]] with data provided by ' ..
	'[[Module:Find sources/autodoc]]. See ' ..
	'[[Module:Find sources#Documentation]] for an overview.'

-- 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 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 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 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
		local configPage = LINK_ROOT .. code
		local autodocConfigPage = configPage .. AUTODOC_SUFFIX
		local linkData = maybeLoadData(autodocConfigPage) or {}
		local row = {
			"'''" .. code .. "'''",
			linkData.description or grey("''No description available''"),
			mFindSources._renderLink(code, {cfg['example-search-term']}),
			string.format(
				'%s, %s',
				makeWikilink(configPage, cfg['link-table-main-config-link-display']),
				makeWikilink(autodocConfigPage, cfg['link-table-autodoc-config-link-display'])
			),
			linkData.notes or ''
		}
		rows[i] = row
	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')

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