Zelda Wiki

Want to contribute to this wiki?
Sign up for an account, and get started!

Come join the Zelda Wiki community Discord server!

READ MORE

Zelda Wiki
Advertisement
The printable version is no longer supported and may have rendering errors. Please update your browser bookmarks and please use the default browser print function instead.
local p = {}

local i18n = require("Module:I18n")
local s = i18n.getString
local utilsError = require("Module:UtilsError")
local utilsTable = require("Module:UtilsTable")

local function code(s)
	return string.format("<code>%s</code>", s)
end

local function err(str, name, path, options, vars)
	vars = utilsTable.merge(vars or {}, {
		path = code(name .. utilsTable.printPath(path))
	})
	local msg = i18n.getString(str, vars)
	
	local options = options or {}
	local quiet = options.quiet
	local stackTrace = options.stackTrace
	local isUsageError = options.isUsageError
	
	if isUsageError then
		local invokeFrameTitle = mw.getCurrentFrame():getParent():getTitle()
		if mw.title.new(invokeFrameTitle).nsText == "Template" then
			msg = string.format("Misuse of [[%s]]: %s", invokeFrameTitle, msg)
		end
	end
	
	if not quiet then
		utilsError.warn(msg, {
			traceBack = stackTrace,
			omitFrames = 2
		})
	end
	return msg
end

function p.required(value, name, path, isKey, options)
	if value == nil then
		return err("msg.required", name, path, options)
	end
end

function p.nonEmpty(value, name, path, isKey, options)
	local isEmpty = 
		value == nil 
		or type(value) == "string" and value == ""
		or type(value) == "table" and utilsTable.isEqual({}, value)
	if isEmpty then
		return err("msg.empty", name, path, options, {
			actualValue = code(utilsTable.print(value))
		})
	end
end

function p.deprecated(value, name, path, isKey, options)
	if value ~= nil then
		return err("msg.deprecated", name, path, options, {
			value = code(value)
		})
	end
end

function p.type(expectedType)
	return function(value, name, path, isKey, options)
		local actualType = type(value)
		if value ~= nil and actualType ~= expectedType then
			local msg = isKey and "msg.typeKey" or "msg.type"
			return err(msg, name, path, options, {
				expectedType = code(expectedType),
				actualType = code(actualType),
				key = isKey and code(tostring(value)) or nil,
			})
		end
	end
end

local function enumDetails(enum)
	if enum.reference then
		return s("msg.enumReference", {
			referencePage = enum.reference
		})
	else
		return s("msg.enumAccepted", {
			values = code(utilsTable.print(enum, true))
		})
	end
end
			
function p.enum(acceptedValues)
	return function (value, name, path, isKey, options)
		if type(acceptedValues) == "function" then
			acceptedValues = acceptedValues()
		end
		-- Sometimes the argument is a list of values. It's easier to pretend that's always the case.
		local values = value
		local multivalue = type(value) == "table"
		if not multivalue then
			values = { value }
		end
		for k, value in ipairs(values) do
			if not utilsTable.keyOf(acceptedValues, value) then
				local path = utilsTable.concat(path or {}, multivalue and k or nil)
				local msg = isKey and "msg.enumKey" or "msg.enum"
				return err(msg, name, path, options, {
					actualValue = code(value),
					enumDetails = enumDetails(acceptedValues),
					key = code(tostring(value)),
				})
			end
		end
	end
end
function p._enum(acceptedValues)
	return function (value, name, path, isKey, options)
		if type(acceptedValues) == "function" then
			acceptedValues = acceptedValues()
		end
		-- Sometimes the argument is a list of values. It's easier to pretend that's always the case.
		local values = value
		local multivalue = type(value) == "table"
		if not multivalue then
			values = { value }
		end
		local errors = {}
		for k, value in ipairs(values) do
			if not utilsTable.keyOf(acceptedValues, value) then
				local path = utilsTable.concat(path or {}, multivalue and k or nil)
				local msg = isKey and "msg.enumKey" or "msg.enum"
				table.insert(errors, err(msg, name, path, options, {
					actualValue = code(value),
					enumDetails = enumDetails(acceptedValues),
					key = code(tostring(value)),
				}))
			end
		end
		return errors
	end
end

i18n.loadStrings({
	en = {
		msg = {
			empty = "${path} must be non-empty but is ${actualValue}.",
			required = "${path} is required but is <code>nil</code>.",
			type = "${path} is type ${actualType} but type ${expectedType} was expected.",
			typeKey = "${path} key ${key} is type ${actualType} but type ${expectedType} was expected.",
			deprecated = "${path} is deprecated but has value ${value}.",
			
			enum = "${path} has unexpected value ${actualValue}. ${enumDetails}",
			enumKey = "${key} is not an acceptable key for ${path}. ${enumDetails}",
			enumAccepted = "The accepted values are: ${values}",
			enumReference = "For a list of accepted values, refer to ${referencePage}.",
		},
	},
})

return p
Advertisement