Module:Documentation/Template

local p = {} local h = {}

local i18n = require("Module:I18n") local s = i18n.getString local utilsLayout = require("Module:UtilsLayout") local utilsMarkup = require("Module:UtilsMarkup") local utilsTable = require("Module:UtilsTable")

local FORMATS = { inline = { templateData = "", argSeparator = "|", afterLastArg = "", },	block = { templateData = "", argSeparator = "\n |", afterLastArg = "\n", } }

function p.Template(frame) local title = mw.title.getCurrentTitle local templateName = title.text local moduleName = frame.args.module or title.baseText return p.printTemplateDoc(templateName, moduleName) end

function p.Examples(frame) local args = frame:getParent.args local examples = h.examplesFromFrame(args) return p.printExamples(examples) end

function p.printTemplateDoc(templateName, moduleName) moduleName = moduleName or templateName local templateSpec = require("Module:" .. moduleName).Templates[templateName] local result = "\n" if templateSpec.purpose then result = result .. utilsMarkup.heading(2, s("heading.purpose")) result = result .. mw.getCurrentFrame:preprocess(templateSpec.purpose) .. "\n" end result = result .. utilsMarkup.heading(2, s("heading.usage")) if templateSpec.usesData then local dataSource = utilsMarkup.link(templateSpec.usesData) result = result .. utilsMarkup.italic(s("usesData", {dataSource = dataSource})) .. "\n" end if templateSpec.storesData then local dataSource = utilsMarkup.link(templateSpec.storesData) result = result .. utilsMarkup.italic(s("storesData", {dataSource = dataSource})) .. "\n" end result = result .. p.printUsage(templateName, templateSpec) if templateSpec.examples then local examples = h.examplesFromSpec(templateName, templateSpec) result = result .. utilsMarkup.heading(3, s("heading.examples")) result = result .. p.printExamples(examples) end result = result .. h.templateData(templateSpec) return result end

function p.printUsage(templateName, templateSpec) local params = {} local paramOrder = templateSpec.paramOrder local format = templateSpec.format local hasPositionalParams = false for k, v in pairs(templateSpec.params) do		if type(k) == "number" then hasPositionalParams = true end local i = paramOrder and utilsTable.keyOf(paramOrder, k) or (#params + 1) params[i] = utilsTable.merge({}, v, { 			param = k 		}) end local format = FORMATS[templateSpec.format] local result = "" if hasPositionalParams then result = result .. utilsLayout.tabs({			{				label = s("tabs.syntax"),				content = h.syntax(templateName, params, format)			},			{				label = s("tabs.boilerplate"),				content = h.boilerplate(templateName, params, format, templateSpec.boilerplate)			},		}) else result = h.boilerplate(templateName, params, format, templateSpec.boilerplate) end result = result .. h.params(params) return result end

function p.printExamples(examples) for i, example in ipairs(examples) do		local input = mw.text.trim(example.input) if string.find(input, "\n") or examples.vertical then input = utilsMarkup.pre(input, {				wrapLines = false			}) else input = utilsMarkup.code(mw.text.nowiki(input)) end if example.output then local output, categories = utilsMarkup.stripCategories(example.output) local output = utilsMarkup.killBacklinks(output) local categoryList = utilsMarkup.bulletList(categories) examples[i] = { input = input, output = output, categoryList = categoryList }		else examples[i] = { input = input }		end end if not examples.vertical then return utilsLayout.table({			hideEmptyColumns = true,			headers = { s("header.input"), s("header.output"), s("header.categoriesAdded"), header = true },			rows = utilsTable.map(examples, function(example) return {example.input, example.output, example.categoryList} end)		}) end local result = "" for _, example in ipairs(examples) do		local headerStyles = { ["width"] = "5rem" -- for alignment. See Template:Letter/Documentation for an example of why this is needed }		result = result .. utilsLayout.table({			hideEmptyRows = true,			rows = {				{					{ header = true, content= s("header.input"), styles = headerStyles}, 					example.input,				},				{					{ header = true, content = s("header.output"), styles = headerStyles}, 					example.output				},				{					{ header = true, content = s("header.categoriesAdded"), styles = headerStyles },					example.categoryList				},			}		}) .. "\n" end return result end

function h.syntax(templateName, params, format) local args = {} for i, param in ipairs(params) do		args[i] = { param = param.param, value = param.placeholder or string.format("<%s>", param.name or param.param) }	end local result = h.printTemplateInstance(templateName, args, format) return utilsMarkup.pre(result) end

function h.boilerplate(templateName, params, format, options) local options = options or {} local args = {} for i, param in ipairs(params) do		args[i] = { param = param.param, value = "", }	end local result = h.printTemplateInstance(templateName, args, format) if options.commentBefore then result = "" .. result end return utilsMarkup.pre(result) end

function h.examplesFromFrame(examples) local result = { vertical = examples.vertical }	for i, example in ipairs(examples) do		local input = mw.text.unstripNoWiki(example) local output = mw.getCurrentFrame:preprocess(mw.text.decode(input)) result[i] = { input = input, output = output }	end return result end

function h.examplesFromSpec(templateName, templateSpec) local paramOrder = templateSpec.paramOrder local examples = templateSpec.examples local result = { vertical = examples.vertical }	for i, example in ipairs(examples) do		local args = {} for k, v in pairs(example) do			local idx = paramOrder and utilsTable.keyOf(paramOrder, k) or (#args + 1) args[idx] = { param = k,				value = v			} end result[i] = {} result[i].input = h.printTemplateInstance(templateName, args, FORMATS[templateSpec.format]) if not templateSpec.storesData then result[i].output = mw.getCurrentFrame:expandTemplate({				title = templateName, 				args = example			}) end end return result end

function h.printTemplateInstance(name, args, format) local result = "" return result end

function h.params(params) return utilsLayout.table({		hideEmptyColumns = true,		headers = {s("header.parameter"), s("header.status"), s("header.description"), s("header.enum")},		rows = utilsTable.map(params, h.paramRow),	}) end function h.paramRow(param) local paramCell = utilsMarkup.code(param.param) if param.name and param.name ~= param.param then paramCell = end local statusCell = param.required and s("status.required") or s("status.optional") local descriptionCell = param.desc local enumCell = param.enum and h.printEnum(param) or "" return {paramCell, statusCell, descriptionCell, enumCell} end function h.printEnum(param) local enum = param.enum local dependsOn = param.enumDependsOn local enumReference = type(enum) == "table" and enum.reference or nil if dependsOn then return s("enum.depends", { arg = utilsMarkup.code(dependsOn) }) elseif enumReference then return s("enum.ref", { dataSource = enumReference }) else local values = utilsTable.map(enum, utilsMarkup.code) return utilsMarkup.bulletList(values) end end

function h.templateData(templateSpec) local data = { description = templateSpec.purpose, params = {}, paramOrder = templateSpec.paramOrder, }	for k, v in pairs(templateSpec.params) do		data.params[k] = { label = v.name or k,			required = v.required, description = v.desc, aliases = type(k) == "number" and {v.name} or nil, type = v.type, }	end local templateData = mw.getCurrentFrame:extensionTag("templatedata", mw.text.jsonEncode(data)) local html = mw.html.create("div") :addClass("mw-collapsible mw-collapsed") :attr("data-expandtext", s("templateData.show")) :attr("data-collapsetext", s("templateData.hide")) :css("float", "left") :wikitext(templateData) return tostring(html) end

i18n.loadStrings({	en = {		usesData = "This template relies on the centralized data stored at ${dataSource}.",		storesData = "This template is used to store centralized data at ${dataSource}.",		enum = {			ref = "See ${dataSource}",			depends = "Depends on ${arg}",		},		header = {			description = "Description",			parameter = "Parameter",			status = "Status",			enum = "Accepted values",			categoriesAdded = "Categories added",			input = "Input",			output = "Output",		},		heading = {			examples = "Examples",			purpose = "Purpose",			usage = "Usage",		},		status = {			optional = "optional",			required = "required",		},		tabs = {			boilerplate = "Boilerplate",			syntax = "Syntax",		},		templateData = {			show = "show TemplateData ▼",			hide = "hide TemplateData ▲",		},	} })

return p