モジュール:Find sources/autodoc

-- Define constants
local ROOT_PAGE = 'Module:Find sources'
local TEMPLATE_LIST = ROOT_PAGE .. '/templates' -- template config module list
local TEMPLATE_ROOT = TEMPLATE_LIST .. '/' -- template config module prefix
local LINK_LIST = ROOT_PAGE .. '/links' -- link config module list
local LINK_ROOT = LINK_LIST .. '/' -- link config module prefix
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 substituteParams(msg, ...)
	return mw.message.newRawMessage(msg, ...):plain()
end
local function sortKeys(t)
	local ret = {}
	for k in pairs(t) do
		ret#ret + 1 = k
	end
	table.sort(ret)
	return ret
end
local function isValidLinkCfg(linkCfg)
	if type(linkCfg) ~= 'table' then
		return false
	end
	for _, s in ipairs{'url', 'display'} do
		if type(linkCfgs) ~= 'string' then
			return false
		end
	end
	for _, s in ipairs{'separator'} do
		if linkCfgs ~= nil and type(linkCfgs) ~= 'string' then
			return false
		end
	end
	return true
end
local function isValidLink(code)
	if type(code) ~= 'string' or code ==  then
		return false
	end
	local linkCfg = maybeLoadData(LINK_ROOT .. code)
	return isValidLinkCfg(linkCfg)
end
local function isValidTemplateCfg(templateCfg)
	if type(templateCfg) ~= 'table' then
		return false
	end
	for _, s in ipairs{'blurb'} do
		if type(templateCfgs) ~= 'string' then
			return false
		end
	end
	for _, s in ipairs{'separator', 'class', 'style'} do
		if templateCfgs ~= nil and type(templateCfgs) ~= 'string' then
			return false
		end
	end
	if templateCfg.isUsedInMainspace and templateCfg.isUsedInMainspace ~= 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 isValidTemplate(template)
	if type(template) ~= 'string' or template ==  then
		return false
	end
	local templateCfg = maybeLoadData(TEMPLATE_ROOT .. template)
	return isValidTemplateCfg(templateCfg)
end
local function isValidLinkAutdocCfg(t)
	if type(t) ~= 'table' then
		return false
	end
	for _, s in ipairs{'description', 'notes'} do
		if ts and type(ts) ~= '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 ts and type(ts) ~= '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 = 
	return table.concat(ret, '\n')
end
local function grey(s)
	return string.format('%s', s)
end
local function bold(s)
	return string.format("%s", s)
end
local function colspan(s, n)
	return string.format('colspan="%d" | %s', n, s)
end
local function makeWikitextError(msg)
	return string.format('%s', msg)
end
local function makeWikilink(page, display)
	if display then
		return string.format('%s', page, display)
	else
		return string.format('%s', page)
	end
end
function p.linkTable()
	local codes = sortKeys(require(LINK_LIST))
	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
			-- Make the example link.
			local success, link = pcall(
				mFindSources._renderLink,
				code,
				{cfg'example-search-term'}
			)
			if not success then
				link = makeWikitextError(link)
			end
			-- Build the row.
			local row = {
				bold(code),
				linkData.description or grey("説明文はありません"),
				link,
				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 
			}
			rowsi = row
		else
			local msg = substituteParams(
				cfg'invalid-link-config-error',
				LINK_ROOT .. code
			)
			msg = makeWikitextError(msg)
			msg = colspan(msg, 5)
			rowsi = {msg}
		end
	end
	return makeWikitable(headers, rows)
end
function p.templateTable()
	local templates = sortKeys(require(TEMPLATE_LIST))
	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
			-- Make the example text
			local success, example = pcall(
				mFindSources._main,
				template,
				{cfg'example-search-term'}
			)
			if not success then
				example = makeWikitextError(example)
			end
			-- Build the row.
			local row = {
				bold(makeWikilink(mw.site.namespaces10.name .. ':' .. template, template)),
				templateData.description or grey("説明文はありません"),
				example,
				table.concat({
					makeWikilink(configPage, cfg'template-table-main-config-link-display'),
					makeWikilink(autodocConfigPage, cfg'template-table-autodoc-config-link-display')
				}, cfg'table-config-separator')
			}
			rowsi = row
		else
			local msg = substituteParams(
				cfg'invalid-template-config-error',
				TEMPLATE_ROOT .. template
			)
			msg = makeWikitextError(msg)
			msg = colspan(msg, 4)
			rowsi = {msg}
		end
	end
	return makeWikitable(headers, rows)
end
local function documentation(template)
	-- This function makes documentation for the template specified in
	-- the template parameter. The template 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 isValidTemplateCfg(templateCfg) then
		error(substituteParams(
			cfg'invalid-template-name-error',
			template,
			TEMPLATE_ROOT .. template
		))
	end
	local autodocCfg = maybeLoadData(TEMPLATE_ROOT .. template .. AUTODOC_SUFFIX)
	if not isValidTemplateAutdocCfg(autodocCfg) then
		autodocCfg = {}
	end
	-- 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)
			if not isValidLinkAutdocCfg(linkAutodocCfg) then
				linkAutodocCfg = {}
			end
			if linkAutodocCfg.notes then
				codesi = (linkAutodocCfg.description or code) .. '：' .. linkAutodocCfg.notes
			else
				codesi = linkAutodocCfg.description or code
			end
		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