Zelda Wiki

OoT Navi.png

Hey! Listen!

This wiki contains spoilers! Read at your own risk!

READ MORE

Zelda Wiki
Advertisement
Zelda Wiki
10,256
pages

local p = {}
local h = {}

local i18n = require("Module:I18n")
local s = i18n.getString
local lex = require("Module:Documentation/Lexer")
local utilsFunction = require("Module:UtilsFunction")
local utilsLayout = require("Module:UtilsLayout")
local utilsMarkup = require("Module:UtilsMarkup")
local utilsPage = require("Module:UtilsPage")
local utilsSchema = require("Module:UtilsSchema")
local utilsString = require("Module:UtilsString")
local utilsTable = require("Module:UtilsTable")

local MAX_ARGS_LENGTH = 50

function getModulePage(frame)
	local docPage = mw.title.new(frame:getParent():getTitle())
	local modulePage = docPage.basePageTitle
	local subpageText = modulePage.subpageText
	if subpageText == "Data" then
		modulePage = modulePage.basePageTitle
	end
	return modulePage.fullText, subpageText
end

function p.Schema(frame)
	local modulePage = frame.args.module or getModulePage(frame)
	local module = require(modulePage)
	local schemaName = frame.args[1]
	return p.schema(module.Schemas[schemaName], schemaName)
end

function p.Module(frame)
	local modulePage, subpage = getModulePage(frame)
	local categories = utilsMarkup.categories(h.getCategories(frame.args.type))
	if subpage == "Data" then
		return p.dataDoc(modulePage) .. categories
	end
	return p.moduleDoc(modulePage) .. categories
end

function p.dataDoc(modulePage)
	local result = "''For information on editing module data in general, see [[Guidelines:Modules/Data]].''\n"
	local module = require(modulePage)
	local tabs = {}
	if type(module.Data) == "function" then
		table.insert(tabs, {
			label = "Data",
			content = module.Data(mw.getCurrentFrame())
		})
	end
	if module.Schemas and module.Schemas.Data then
		table.insert(tabs, {
			label = "Schema",
			content = p.schema(module.Schemas.Data, "Data")
		})
	end
	result = result .. utilsLayout.tabs(tabs, {
		{
			tabs = {
				collapse = true
			}
		}
	})
	return result
end

function p.schema(schema, schemaName)
	local definitions = utilsSchema.getTypeDefinitions(schema, schemaName or "", function(keyDef)
		local key = keyDef.key
		local symbolicType = keyDef.symbolicType
		local rawType = keyDef.rawType
		local typeLabel = keyDef.typeLabel
		local desc = keyDef.desc
		local subkeys = keyDef.subkeys
		local parentType = keyDef.parentType
		local isSubschema = keyDef.isSubschema
		
		if schemaName == "..." and not parentType then
			symbolicType = "vararg" .. symbolicType
		end
		
		symbolicType = mw.text.nowiki(symbolicType)
		
		if subkeys and subkeys.allOf then
			subkeys = utilsTable.concat(subkeys, utilsTable.flatten(subkeys.allOf))
			subkeys.allOf = nil
		end
		
		if isSubschema then
			if not desc and not subkeys then
				return nil
			end
			local definition = utilsTable.flatten(subkeys or {})
			if desc then
				table.insert(definition, 1, {nil, desc})
			end
			return {{
				label = typeLabel or symbolicType,
				tooltip = utilsMarkup.code(symbolicType),
				content = utilsMarkup.definitionList(definition)
			}}
		end
		if subkeys and subkeys.oneOf and #subkeys.oneOf > 0 then
			local tabData = utilsTable._uniqueBy("content")(utilsTable.flatten(subkeys.oneOf))
			if #tabData == 1 then
				subkeys = utilsTable.concat(subkeys, tabData[1].content)
			else
				subkeys = utilsTable.concat({utilsLayout.tabs(tabData)}, subkeys)
			end
			subkeys.oneOf = nil
		end

		if key and key ~= "" then
			key = tostring(mw.html.create("span")
				:css("color", "#f8f8f2")
				:wikitext(utilsMarkup.code(key))
			)
			key = utilsMarkup.link("Module:Documentation/Documentation#Schemas", key)
			local type = typeLabel or symbolicType
			key = utilsMarkup.tooltip(key, utilsMarkup.code(type))
		end
		
		definition = {key}
		if desc then
			table.insert(definition, desc)
		end
		if subkeys then
			definition = utilsTable.concat(definition, subkeys)
		end
		if parentType == utilsSchema.TYPES.record then
			definition = {definition}
		end
		
		return definition
	end)
	if not schemaName then
		definitions = utilsTable.flatten(utilsTable.tail(definitions))
		definitions = {{nil, definitions}}
	else
		definitions = {definitions}
	end
	local definitionsList = utilsMarkup.definitionList(definitions)
	return definitionsList
end

function p.moduleDoc(modulePage, section)
	local headingLevel = section and 3 or 2
	local module, doc = h.resolveDoc(modulePage, section)
	local output = ""
	if not section then
		if type(module) == "table" and module.Templates then
			local templates = utilsTable.keys(module.Templates)
			table.sort(templates)
			for i in ipairs(templates) do
				templates[i] = utilsMarkup.link("Template:"..templates[i])
			end
			local templateList = utilsMarkup.bulletList(templates)
			output = "This is the main module for the following templates:" .. templateList .. "\n"
		end
		if (#doc.functions > 0 or doc.sections) and type(module) == "table" and module.Templates then
			output = output .. "In addition, this module exports the following functions. __TOC__\n"
		elseif (#doc.functions > 0 or doc.sections) then
			output = "This module exports the following functions. __TOC__\n"
		end
	end
	for _, functionDoc in ipairs(doc.functions or {}) do
		output = output .. utilsMarkup.heading(headingLevel, functionDoc.name) .. "\n"
		if functionDoc.wip then
			output = output .. mw.getCurrentFrame():expandTemplate({
				title = "WIP",
				args = {
					align = "left",
				}	
			}) .. '<div style="clear:left"/>'
		end
		
		if functionDoc.fp then
			output = output .. utilsLayout.tabs({
				{
					label = functionDoc.name,
					content = h.printFunctionDoc(functionDoc)
				},
				{
					label = functionDoc.fp.name,
					content = h.printFunctionDoc(functionDoc.fp)
				}
			})
		else
			output = output .. h.printFunctionDoc(functionDoc)
		end
	end
	if doc.sections then
		for _, section in ipairs(doc.sections) do
			local sectionModule = type(section.section) == "string" and section.section or modulePage
			if section.heading then
				output = output .. utilsMarkup.heading(headingLevel, section.heading)
				output = output .. p.moduleDoc(sectionModule, section.section) .. "\n"
			else
				output = output .. p.moduleDoc(sectionModule, section.section)
			end
		end
	end
	return output
end

function h.resolveDoc(modulePage, section)
	local module = require(modulePage)
	local doc = {}
	if type(section) == "table" then
		doc = section
	elseif type(module) == "table" then
		doc = module.Documentation or {}
	end
	local err = utilsSchema.validate(p.Schemas.Documentation, "Documentation", doc, "p.Documentation")
	if err then
		mw.logObject(err)
	end
	if doc.sections then
		doc.functions = {}
		doc.snippets = h.snippets(modulePage)
		return module, doc
	end
	local functionNamesInSource = h.functionNamesInSource(modulePage)
	local functionNamesInDoc = {}
	for k, v in pairs(doc) do
		table.insert(functionNamesInDoc, k)
		if doc._params then
			table.insert(functionNamesInDoc, "_" .. k)
		end
	end
	local functionNames = utilsTable.intersection(functionNamesInSource, functionNamesInDoc)
	local undefinedFunctions = utilsTable.difference(functionNamesInDoc, functionNames)
	if #undefinedFunctions > 0 then
		local msg = string.format("Documentation references functions that do not exist: <code>%s</code>", utilsTable.print(undefinedFunctions, true))
		mw.addWarning(msg)
	end
	local functions = {}
	doc.snippets = h.snippets(modulePage)
	for _, functionName in ipairs(functionNames) do
		table.insert(functions, h.resolveFunctionDoc(module, doc, functionName))
		doc[functionName] = nil
	end
	doc.functions = functions
	return module, doc
end
function h.functionNamesInSource(modulePage)
	local source = mw.title.new(modulePage):getContent()
	local lexLines = lex(source)
	local functionNames = {}
	for _, tokens in ipairs(lexLines) do
		tokens = utilsTable.filter(tokens, function(token) 
			return token.type ~= "whitespace" 
		end)
		tokens = utilsTable.map(tokens, "data")
		if utilsTable.isEqual(
			utilsTable.slice(tokens, 1, 3),
			{"function", "p", "."}
		) then
			table.insert(functionNames, tokens[4])
		end
	end
	return functionNames
end

function h.resolveFunctionDoc(module, moduleDoc, functionName)
	local functionDoc = moduleDoc[functionName]
	functionDoc.name = functionName
	functionDoc.fn = module[functionDoc.name]
	functionDoc.cases = functionDoc.cases or {}
	functionDoc.snippets = h.getFunctionSnippets(moduleDoc.snippets, functionDoc.name)
	if type(functionDoc.returns) ~= "table" then
		functionDoc.returns = {functionDoc.returns}
		for i, case in ipairs(functionDoc.cases) do
			case.expect = {case.expect}
		end
	end
	local paramSchemas = module.Schemas and module.Schemas[functionDoc.name] or {}
	local resolvedParams = utilsTable.map(functionDoc.params, function(param)
		return { name = param, schema = paramSchemas[param] }
	end)
	if functionDoc._params then
		functionDoc.fp = mw.clone(functionDoc)
		functionDoc.fp.name = "_" .. functionDoc.name
		functionDoc.fp.fn = module[functionDoc.fp.name]
		for _, case in ipairs(functionDoc.fp.cases) do
			case.args = case.args and utilsTable.map(functionDoc._params, function(paramGroup)
				return utilsTable.map(paramGroup, function(param)
					return case.args[utilsTable.keyOf(functionDoc.params, param)]
				end)
			end)
		end
		functionDoc.fp.params = utilsTable.map(functionDoc._params, function(paramGroup)
			return utilsTable.map(paramGroup, function(param)
				return resolvedParams[utilsTable.keyOf(functionDoc.params, param)]
			end)
		end)
		functionDoc.fp.snippets = h.getFunctionSnippets(moduleDoc.snippets, functionDoc.fp.name)
	end
	functionDoc.params = {resolvedParams}
	for _, case in ipairs(functionDoc.cases) do
		case.args = {case.args}
	end
	return functionDoc
end
function h.getFunctionSnippets(moduleSnippets, functionName)
	local functionSnippets = {}
	for k, v in pairs(moduleSnippets or {}) do
		local s, e = k:find(functionName)
		if e then
			local snippetKey = string.sub(k, e + 1)
			functionSnippets[snippetKey] = v
		end
	end
	return functionSnippets
end

function h.printFunctionDoc(functionDoc)
	local result = ""
	result = result .. h.printFunctionSyntax(functionDoc)
	result = result .. h.printFunctionDescription(functionDoc)
	result = result .. h.printParamsDescription(functionDoc)
	result = result .. h.printReturnsDescription(functionDoc.returns)
	result = result .. h.printFunctionCases(functionDoc)
	return result
end

function h.printFunctionSyntax(functionDoc)
	local result = functionDoc.name
	for _, params in ipairs(functionDoc.params) do
		result = result .. "(" .. h.printParamsSyntax(params) .. ")"
	end
	return utilsMarkup.code(result) .. "\n"
end
function h.printParamsSyntax(params)
	local paramsSyntax = {}
	for _, param in ipairs(params or {}) do
		local paramSyntax = param.name
		if param.schema and not param.schema.required then
			paramSyntax = "[" .. paramSyntax .. "]"
		end
		table.insert(paramsSyntax, paramSyntax)
	end
	return table.concat(paramsSyntax, ", ") 
end

function h.printFunctionDescription(functionDoc)
	local result = ""
	if functionDoc.desc then
		result = "\n" .. mw.getCurrentFrame():preprocess(functionDoc.desc) .. "\n"
	end
	return result
end

function h.printParamsDescription(functionDoc)
	if not functionDoc.params or #functionDoc.params == 0 then
		return ""
	end
	local allParams = utilsTable.flatten(functionDoc.params)
	local paramDefinitions = {}
	for _, param in ipairs(allParams) do
		if param.schema then
			table.insert(paramDefinitions, p.schema(param.schema, param.name))
		end
	end
	if #paramDefinitions == 0 then
		return ""
	end
	local paramList = utilsMarkup.list(paramDefinitions)
	local heading = ";" .. s("headers.parameters") .. "\n"
	return heading .. paramList
end

function h.printReturnsDescription(returns)
	if not returns or #returns == 0 then
		return ""
	end
	local returnsList = utilsMarkup.bulletList(returns)
	local heading = "\n;" .. s("headers.returns") .. "\n"
	local result = heading .. mw.getCurrentFrame():preprocess(returnsList)
	return result
end

function h.printFunctionCases(doc)
	if not doc.cases or #doc.cases == 0 then
		return ""
	end
	local result = "\n;" .. s("headers.examples") .. "\n"
	
	local inputColumn = s("headers.input")
	local outputColumn = s("headers.output")
	local resultColumn = s("headers.result")
	local statusColumn = utilsMarkup.tooltip(s("headers.status"), s("explainStatusColumn"))
	
	local headerCells = utilsTable.compact({
		inputColumn, 
		not doc.cases.resultOnly and outputColumn or nil, 
		not doc.cases.outputOnly and resultColumn or nil, 
		statusColumn,
	})
	local tableData = {
		hideEmptyColumns = true,
		rows = {
			{
				header = true,
				cells = headerCells,
			}
		},
	}
	for _, case in ipairs(doc.cases) do
		local caseRows = h.case(doc, case, doc.cases)
		tableData.rows = utilsTable.concat(tableData.rows, caseRows)
	end
	result = result .. utilsLayout.table(tableData) .. "\n"
	return result
end

h.snippets = utilsFunction.memoize(function(modulePage)
	local snippetPagename = modulePage .. "/Documentation/Snippets"
	if not utilsPage.exists(snippetPagename) then
		return nil
	end
	local snippets = {}
	local snippetPage = mw.title.new(snippetPagename)
	local module = require(snippetPagename)
	local text = snippetPage:getContent()
	local lexLines = lex(text)
	local names = {}
	local starts = {}
	local ends = {}
	for i, line in ipairs(lexLines) do
		if line[1] and line[1].type == "keyword" and line[1].data == "function" then
			local isOpenParens = function(token)
				return utilsString.startsWith(token.data, "(")
			end
			local fnName = line[utilsTable.findIndex(line, isOpenParens) - 1].data
			table.insert(starts, i + 1)
			table.insert(names, fnName)
		end
		if #line == 1 and line[1].type == "keyword" and line[1].data == "end" then
			table.insert(ends, i - 1)
		end
	end
	local lines = utilsString.split(text, "\n")
	for i, fnName in ipairs(names) do
		local fnLines = utilsTable.slice(lines, starts[i], ends[i])
		fnLines = utilsTable.map(fnLines, function(line)
			line = string.gsub(line, "^\t", "")
			line = string.gsub(line, "\t", "  ")
			return line
		end)
		local fnCode = table.concat(fnLines, "\n")
		snippets[fnName] = {
			fn = module[fnName],
			code = fnCode,
		}
	end
	return snippets
end)

function h.case(doc, case, options)
	local rows = {}
	local input, outputs
	local snippet = case.snippet and doc.snippets[tostring(case.snippet)]
	if snippet then
		input = utilsMarkup.lua(snippet.code, { wrapLines = false })
		outputs = {snippet.fn()}
	elseif case.args then
		input = h.printInput(doc, case.args)
		outputs = h.evaluateFunction(doc.fn, case.args)
	else
		return {}
	end
	local expected = case.expect or {}
	
	for i = 1, #doc.returns do
		local outputData, resultData, statusData = h.evaluateOutput(outputs[i], expected[i])
		table.insert(rows, utilsTable.compact({
			not options.resultOnly and outputData or nil,
			not options.outputOnly and resultData or nil,
			statusData
		}))
	end
	
	table.insert(rows[1], 1, {
		content = input,
		rowspan = #doc.returns,
	})
	if case.desc then
		table.insert(rows, 1, {
			{
				header = true,
				colspan = -1,
				styles = {
					["text-align"] = "left"
				},
				content = case.desc,
			}
		})
	end
	return rows
end

function h.printInput(doc, argsList)
	local result = doc.name
	local allArgs = utilsTable.flatten(argsList)
	local lineWrap = #allArgs == 1 and type(allArgs[1]) == "string"
	for i, args in ipairs(argsList) do
		result = result .. "(" .. h.printInputArgs(args, doc.params[i], lineWrap) .. ")"
	end
	return utilsMarkup.lua(result, {
		wrapLines = lineWrap
	})
end
function h.printInputArgs(args, params)
	args = args or {}
	local argsText = {}
	for i = 1, math.max(#params, #args) do
		local argText = args[i] == nil and "nil" or utilsTable.print(args[i])
		if not (#args == 1 and type(args[i]) == "table") then
			argText = string.gsub(argText, "\n", "\n  ") --ensures proper indentation of multiline table args
		end
		table.insert(argsText, argText)
	end
	
	-- Trim nil arguments off the end so long as they're optional (but keep the first one).
	local argsText = utilsTable.dropRightWhile(argsText, function(argText, i)
		return i > 1 and argText == "nil" and params[i] and params[i].schema and not params[i].schema.required
	end)
	
	local result = table.concat(argsText, ", ")
	local lines = mw.text.split(result, "\n")
	-- print multiline if there's multiple args with at least one table or a line longer than the max length
	if #args > 1 and (#lines > 1 or #lines[1] > MAX_ARGS_LENGTH) then
		result = "\n  " .. table.concat(argsText, ",\n  ") .. "\n"
	end
	
	return result
end

function h.evaluateFunction(fn, args)
	for i = 1, #args - 1 do
		fn = fn(unpack(args[i]))
	end
	return {fn(unpack(args[#args]))}
end

function h.evaluateOutput(output, expected)
	local formattedOutput = h.formatValue(output)
	local outputData = formattedOutput
	local resultData = ""
	if type(output) == "string" then
		resultData = utilsMarkup.killBacklinks(output)
		resultData = utilsMarkup.stripCategories(output)
	end
	if type(expected) == "string" then
		expected = string.gsub(expected, "\t", "")
	end
	local passed = utilsTable.isEqual(expected, output)
	local statusData = (expected ~= nil or output == nil) and h.printStatus(passed) or nil
	if statusData and not passed then
		local expectedOutput = h.formatValue(expected)
		outputData = utilsLayout.table({
			hideEmptyColumns = true,
			styles = { width = "100%" },
			rows = {
				{ 
					{ 
						header = true, 
						content = "Expected", 
						styles = { width = "1em"}, -- "shrink-wraps" this column
					}, 
					{ content = expectedOutput },
				},
				{
					{ header = true, content = "Actual" }, 
					{ content = formattedOutput },
				},
			}
		})
	end
	return outputData, resultData, statusData
end

function h.formatValue(val)
	if type(val) == "string" then
		val = string.gsub(val, "&#", "&#38;#") -- show entity codes
		val = utilsTable.print(val)
		val = string.gsub(val, "\n", "\\n\n") -- Show newlines	
		return utilsMarkup.pre(val) 
	end
	return utilsMarkup.lua(val)
end

function h.printStatus(success)
	local img = success and "[[File:Green check.svg|16px|center|link=]]" or "[[File:TFH Red Link desperate.png|48px|center|link=]]"
	local msg = success and s("explainStatusGood") or s("explainStatusBad")
	img = utilsMarkup.tooltip(img, msg)
	local cat = ""
	if not success and mw.title.getCurrentTitle().subpageText ~= "Documentation" then
		cat = utilsMarkup.category(s("failingTestsCategory"))
	end
	return img .. cat
end

function h.getCategories(type)
	local title = mw.title.getCurrentTitle()
	local isDoc = title.subpageText == "Documentation"
	local moduleTitle = (isDoc or isData) and mw.title.new(title.baseText) or title
	local isData = moduleTitle.subpageText == "Data"
	local isUtil = utilsString.startsWith(moduleTitle.text, "Utils")
	local isSubmodule = moduleTitle.subpageText ~= moduleTitle.text
	if type == "submodule" then
		isSubmodule = true
	end

	if isDoc and isData then
		return {s("cat.dataDoc")}
	end
	if isDoc and isSubmodule then
		return {s("cat.submoduleDoc")}
	end
	if isDoc then
		return  {s("cat.moduleDoc")}
	end
	
	if isData then
		return {s("cat.data")}
	end
	if isSubmodule then
		return {s("cat.submodules")}
	end
	if isUtil then
		return {s("cat.modules"), s("cat.utilityModules")}
	end

	return {s("cat.modules")}
end

i18n.loadStrings({
	en = {
		failingTestsCategory = "Category:Modules with failing tests",
		explainStatusColumn = "Indicates whether a feature is working as expected",
		explainStatusGood = "This feature is working as expected",
		explainStatusBad = "This feature is not working as expected",
		headers = {
			parameters = "Parameters",
			returns = "Returns",
			examples = "Examples",
			input = "Input",
			output = "Output",
			result = "Result",
			categories = "Categories",
			categoriesAdded = "Categories added",
			status = "Status",
		},
		cat = {
			modules = "Category:Modules",
			submodules = "Category:Submodules",
			utilityModules = "Category:Utility Modules",
			moduleDoc = "Category:Module Documentation",
			submoduleDoc = "Category:Submodule Documentation",
			data = "Category:Module Data",
			dataDoc = "Category:Module Data Documentation",
		}
	}
})

p.Schemas = {
	Documentation = {
		oneOf = {
			{ _ref = "#/definitions/functions" },
			{ _ref = "#/definitions/sections" },
		},
		definitions = {
			functions = {
				desc = "Map of function names to function documentation. Functions are printed in the order in which they appear in the source code.",
				type = "map",
				keys = { type = "string" },
				values = {
					type = "record",
					properties = {
						{
							name = "desc",
							type = "string",
							desc = "Description of the function. Use only when clarification is needed—usually the param/returns/cases doc speaks for itself.",
						},
						{
							name = "params",
							required = true,
							type = "array",
							items = { type = "string" },
							desc = "An array of parameter names. Integrates with [[Module:Schema#Functions|Module:Schema]].",
						},
						{
							name = "_params",
							type = "array",
							items = {
								type = "array", 
								items = { type = "string" },
							},
							desc = "To be specified for functions with an alternative [[Guidelines:Modules#Higher Order Function|higher-order function]]."
						},
						{
							name = "returns",
							desc = "A string describing the return value of the function, or an array of such strings if the function returns multiple values",
							oneOf = { 
								{ type = "string" },
								{ type = "array", items = { type = "string" } },
							},
						},
						{
							name = "cases",
							desc = "A collection of use cases that double as test cases, plus a couple flags.",
							allOf = {
								{
									type = "record",
									properties = {
										{
											name = "resultOnly",
											type = "boolean",
											desc = "When <code>true</code>, displays only rendered wikitext as opposed to raw function output. Useful for functions returning strings of complex wikitext.",
										},
										{
											name = "outputOnly",
											type = "boolean",
											desc = "When <code>true</code>, displays only the raw output of the function (opposite of <code>resultOnly</code>). Enabled by default for functions returning data of type other than <code>string</code>."
										},
									},
								},
								{
									type = "array",
									items = {
										oneOf = {
											["snippet"] = {
												type = "record",
												properties = {
													{
														name = "desc",
														type = "string",
														desc = "A description of the use case.",
													},
													{
														name = "snippet",
														required = true,
														oneOf = {
															{ type = "number" },
															{ type = "string" }
														},
														desc = "See [[Module:UtilsTable]] for examples of usage.",
													},
													{
														name = "expect",
														type = "any",
														desc = "The expected return value, which is deep-compared against the actual value to determine pass/fail status. Or, an array of such items if there are multiple return values.",
													},
												}
											},
											["args"] = {
												type = "record",
												properties = {
													{
														name = "desc",
														type = "string",
														desc = "A description of the use case.",
													},
													{
														name = "args",
														type = "array",
														items = { type = "any" },
														desc = "An array of arguments to pass to the function.",
													},
													{
														name = "expect",
														type = "any",
														desc = "The expected return value, which is deep-compared against the actual value to determine pass/fail status. Or, an array of such items if there are multiple return values.",
													},
												},
											},
										}
									},
								}
							},
						},
						{
							name = "wip",
							type = "boolean",
							desc = "Tags the function doc with [[Template:WIP]]."
						}
					},
				},
			},
			sections = {
				type = "record",
				properties = {
					{
						name = "sections",
						type = "array",
						required = true,
						items = {
							type = "record",
							properties = {
								{
									name = "heading",
									type = "string",
								},
								{
									name = "section",
									required = true,
									oneOf = {
										{ type = "string" },
										{
											_ref = "#/definitions/functions",
											required = true,
											_hideSubkeys = true,
										},
									},
								}
							}
						},
					},
				},
			},
		}
	},
}

return p
Advertisement