Mòdulu:paràmitri

La ducumintazzioni di stu mòdulu si pò criari nta Mòdulu:paràmitri/doc

local m_table = require("Mòdulu:tabbella")

local p = {}

p.NUMBER = "number"
p.INT = "int"
p.FLOAT = "float"
p.BOOLEAN = "boolean"

p.UNKNOWN_PARAM = "unknown parameter"
p.MISSING_PARAM = "missing required parameter"
p.EMPTY_PARAM = "empty required parameter"
p.INVALID_VALUE = "invalid value"
p.VALUE_NOT_IN_ENUM = "value not in enum"
p.INVALID_TYPE = "invalid type"
p.ALIAS_TO_UNKNOWN = "alias to undefined parameter"
p.ALIAS_TO_ALIAS = "alias to alias parameter"
p.ALIAS_TO_ITSELF = "alias to itself"
p.ENUM_WITH_CHECKER = "enum with checker"
p.ENUM_INVALID_VALUE = "invalid enum values"

local UNCATCHABLE_ERRORS = {
  p.INVALID_TYPE,
  p.ALIAS_TO_UNKNOWN,
  p.ALIAS_TO_ALIAS,
  p.ALIAS_TO_ITSELF,
  p.ENUM_WITH_CHECKER,
  p.ENUM_INVALID_VALUE,
}

local ERROR_MESSAGES = {
  [p.UNKNOWN_PARAM] = 'Paràmitru "%s" scanusciutu',
  [p.MISSING_PARAM] = 'Paràmitru addimannatu "%s" assenti',
  [p.EMPTY_PARAM] = 'Paràmitru addimannatu "%s" vacanti',
  [p.INVALID_VALUE] = 'Valuri nun vàliddu pû paràmitru "%s" ("%s") di tipu %s',
  [p.VALUE_NOT_IN_ENUM] = 'Valuri nun vàliddu pû paràmitru "%s" ("%s")',
  [p.INVALID_TYPE] = 'Tipu scanusciutu pû paràmitru "%s" ("%s")',
  [p.ALIAS_TO_UNKNOWN] = 'Paràmitru "%s", alias abbersu nu paràmitru nun difinutu "%s"',
  [p.ALIAS_TO_ALIAS] = 'Paràmitru "%s", alias abbersu nu àutru alias ("%s")',
  [p.ALIAS_TO_ITSELF] = 'Paràmitru "%s", alias abbersu iḍḍu stissu',
  [p.ENUM_WITH_CHECKER] = 'Lu paràmitru "%s" è n’enumerazzioni c’una pricunnizzioni',
  [p.ENUM_INVALID_VALUE] = 'Valuri enumiratu nun vàliddu pû paràmitru "%s" ("%s") di tipu %s',
}

local function buildErrorMessage(errorType, ...)
  return {
    errorType = errorType,
    errorData = { ... }
  }
end

local function toBoolean(argValue, argName, scnTypeName, errorType)
  if m_table.contains({ "1", "sì", "viru", "sini", "si" }, argValue) then
    return true
  elseif m_table.contains({ "0", "no", "noni", "farsu","fàusu","fàvusu","falsu","favusu","fausu" }, argValue) then
    return false
  else
    error(buildErrorMessage(errorType, argName, argValue, scnTypeName))
  end
end

local function toNumber(argValue, argName, toInt, scnTypeName, errorType)
  local val = tonumber(argValue)

  if val ~= nil then
    if not toInt or toInt and val == math.floor(val) then
      return val
    end
  end

  error(buildErrorMessage(errorType, argName, argValue, scnTypeName))
end

local function getValue(expectedType, rawValue, argName, errorType)
  local value, scnTypeName

  -- Vérification des types des arguments.
  if expectedType == nil then
    scnTypeName = "catina"
    if type(rawValue) ~= "string" then
      error(buildErrorMessage(errorType, argName, rawValue, scnTypeName))
    end
    value = rawValue
  elseif expectedType == p.NUMBER then
    scnTypeName = "nùmmiru"
    value = toNumber(rawValue, argName, false, scnTypeName, errorType)
  elseif expectedType == p.INT then
    scnTypeName = "nteru"
    value = toNumber(rawValue, argName, true, scnTypeName, errorType)
  elseif expectedType == p.FLOAT then
    scnTypeName = "float"
    value = toNumber(rawValue, argName, false, scnTypeName, errorType)
  elseif expectedType == p.BOOLEAN then
    scnTypeName = "booleanu"
    value = toBoolean(rawValue, argName, scnTypeName, errorType)
  end

  return value, scnTypeName
end

local function checkParametersDefinitions(definedParameters)
  local validTypes = { p.BOOLEAN, p.NUMBER, p.INT, p.FLOAT }

  for paramName, paramValue in pairs(definedParameters) do
    if paramValue.type and not m_table.contains(validTypes, paramValue.type) then
      error(buildErrorMessage(p.INVALID_TYPE, paramName, paramValue.type))
    end
    if paramValue.enum then
      if paramValue.checker then
        error(buildErrorMessage(p.ENUM_WITH_CHECKER, paramName))
      else
        for _, enumValue in ipairs(paramValue.enum) do
          getValue(paramValue.type, enumValue, paramName, p.ENUM_INVALID_VALUE)
        end
      end
    end

    if paramValue.alias_of then
      local alias = paramValue.alias_of

      if not definedParameters[alias] then
        error(buildErrorMessage(p.ALIAS_TO_UNKNOWN, paramName, paramValue.alias_of))
      elseif alias == paramName then
        error(buildErrorMessage(p.ALIAS_TO_ITSELF, paramName))
      elseif definedParameters[alias].alias_of then
        error(buildErrorMessage(p.ALIAS_TO_ALIAS, paramName, paramValue.alias_of))
      end
    end
  end
end

local function extractArgumentKey(param, processedArgs, argName, definedParameters)
  local key
  local outParam

  if param.alias_of then
    if not processedArgs[param.alias_of] then
      key = param.alias_of
      outParam = definedParameters[param.alias_of]
    end
  else
    key = argName
    outParam = param
  end

  return key, outParam
end

local function extractArgumentValue(param, key, argName, argValue, processedArgs)
  if argValue then
    argValue = mw.text.trim(argValue)
  end

  if argValue == "" then
    if param.required and param.allow_empty or not param.required then
      argValue = nil
      processedArgs[key] = nil
    else
      error(buildErrorMessage(p.EMPTY_PARAM, argName))
    end
  end

  if argValue then
    local value, scnTypeName = getValue(param.type, argValue, argName, p.INVALID_VALUE)
    if type(param.enum) == "table" and not m_table.contains(param.enum, value) then
      error(buildErrorMessage(p.VALUE_NOT_IN_ENUM, argName, value))
    elseif type(param.checker) == "function" and not param.checker(value) then
      error(buildErrorMessage(p.INVALID_VALUE, argName, value, scnTypeName))
    end
    processedArgs[key] = value
  end
end

local function parseArguments(args, definedParameters)
  local processedArgs = {}

  for argName, argValue in pairs(args) do
    local param = definedParameters[argName]

    if param then
      local key, actualParam = extractArgumentKey(param, processedArgs, argName, definedParameters)
      if key then
        extractArgumentValue(actualParam, key, argName, argValue, processedArgs)
      end
    else
      error(buildErrorMessage(p.UNKNOWN_PARAM, argName))
    end
  end

  return processedArgs
end

local function checkRequiredParameters(processedArgs, definedParameters)
  for paramName, paramValue in pairs(definedParameters) do
    if processedArgs[paramName] == nil and paramValue.alias_of == nil then
      if paramValue.required and not paramValue.allow_empty then
        error(buildErrorMessage(p.MISSING_PARAM, paramName))
      elseif paramValue.default ~= nil then
        processedArgs[paramName] = paramValue.default
      end
    end
  end
end

function p.process(args, definedParameters, silentErrors)
  local success, result = pcall(function()
    checkParametersDefinitions(definedParameters)
    local processedArgs = parseArguments(args, definedParameters)
    checkRequiredParameters(processedArgs, definedParameters)
    return processedArgs
  end)

  if not success then
    local errorType = result.errorType
    local errorData = result.errorData
    local errorMessage = mw.ustring.format(ERROR_MESSAGES[errorType], unpack(errorData))

    if silentErrors and not m_table.contains(UNCATCHABLE_ERRORS, errorType) then
      local argName = errorData[1]
      local argValue = type(argName) == "number" and tonumber(argName) or argName

      return { argValue, errorType, errorMessage }, false

    elseif m_table.contains(UNCATCHABLE_ERRORS, errorType) then
      errorMessage = "Erruri nternu: " .. errorMessage
    end
    error(errorMessage, 0)
  end

  return result, true
end

function p.checkParametersFromTemplate(frame)
	local templateName = mw.ustring.sub(frame:getParent():getTitle(), 8)
	local expectedArgs = {}
	for _, arg in ipairs(frame.args) do expectedArgs[arg] = true end
	local templateArgs = frame:getParent().args
	local cats = ''
	for templateArg, _ in pairs(templateArgs) do
		if not expectedArgs[tostring(templateArg)] then
			cats = cats .. '[[Catigurìa:Chiamata dû template ' .. templateName .. ' cû paràmitru scanusciutu  "' .. templateArg .. '"]]'
			if not mw.title.new('Catigurìa:Chiamata dû template ' .. templateName .. ' cû paràmitru scanusciutu "' .. templateArg .. '"').exists then
				cats = cats .. '[[Catigurìa:Chiamata dû template ' .. templateName .. ' c’un paràmitru scanusciutu|' .. templateArg .. ']]'
			end
		end
	end
	return cats
end

return p