Module:paramètres

Définition, traduction, prononciation, anagramme et synonyme sur le dictionnaire libre Wiktionnaire.
Sauter à la navigation Sauter à la recherche
Ce module a pour objectif d’aider à traiter les paramètres de modèles dans les modules LUA.

process(args, defined_parameters)

Paramètres

args de type table
Les arguments du modèle, généralement obtenus en utilisant frame.args ou frame:getParent().args.
defined_parameters de type table
La liste des paramètres acceptés par le module.
Chaque paramètre est une entrée de la table defined_parameters dont la clé est le nom du paramètre et la valeur est une table qui peut contenir les entrées suivantes :
  • required (booléen, défaut : false) : indique que le paramètre est obligatoire.
  • alias_of (chaine/entier) : le nom du paramètre dont ce paramètre est un alias.
  • default (chaine/nombre/booléen) : la valeur par défaut, utilisée si l’argument n’est pas présent dans la table args.
  • type (chaine) : le type du paramètre ; number pour nombre, boolean pour booléen, omit pour chaine. Les valeurs autorisées pour le type booléen sont 1, oui et vrai pour true et 0, non et faux pour false.
  • allow_empty (booléen, défaut : false) : indique si un paramètre obligatoire peut être laissé vide.
  • checker : précondition, fonction permettant de tester la valeur de l’argument ; elle doit posséder un seul paramètre et retourner un booléen. Ne peut pas être présent sur un alias.
  • enum : liste des valeurs autorisées pour le paramètre.
Cas particuliers
Si alias_of est présent, la valeur required n’est pas prise en compte.
Si required est true ou alias_of n’est pas nil, la valeur default ne sera pas prise en compte.
Si required n’est pas présent ou est false, la valeur allow_empty ne sera pas prise en compte.
Si alias_of pointe vers un paramètre qui est lui-même un alias, n’existe pas ou vers lui-même, une erreur est lancée.
Les erreurs suivantes ne sont pas masquées par le mode silencieux :
  • Type invalide
  • Alias vers lui-même
  • Alias vers un autre alias
  • Alias vers un paramètre non défini
  • Attributs checker et enum renseignés en même temps
Le message d’erreur est alors préfixé de "Erreur interne :"

Valeur retournée

La fonction retourne les arguments avec leurs valeurs converties dans le type spécifié pour chaque paramètre.

Exemples

Définition d’un paramètre obligatoire
{ [1] = { required = true } }                  -- paramètre positionnel
{ ["nom du paramètre"] = { required = true } } -- paramètre nommé
Définition d’un alias
{
  [1] = {},
  ["a"] = { alias_of = 1 }
}
Définition d’une valeur par défaut
{ [1] = { default = "valeur par défaut" } }
Spécification d’un type
{ [1] = { type = "number" } }  -- nombre
{ [1] = { type = "boolean" } } -- booléen
{ [1] = { } }                  -- chaine
Spécification d’une précondition
{ [1] = { checker = function(s) return s == "a" or s == "b" end } }
Spécification d’une énumération
{ [1] = { enum = { "v1", "v2" } } }
Exemple pour le module prononciation
{
  [1] = { required = true, allow_empty = true },
  [2] = { required = true },
  ["pron"] = { alias_of = 1 },
  ["lang"] = { alias_of = 2 }
}

info Documentation du Module:paramètres : v · d · m · h.


local m_table = require("Module:table")

local export = {}

-- Types
export.NUMBER = "number"
export.INT = "int"
export.FLOAT = "float"
export.BOOLEAN = "boolean"

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

--- Liste des erreurs non masquées par le mode silencieux.
local UNCATCHABLE_ERRORS = {
  export.INVALID_TYPE,
  export.ALIAS_TO_UNKNOWN,
  export.ALIAS_TO_ALIAS,
  export.ALIAS_TO_ITSELF,
  export.ENUM_WITH_CHECKER,
  export.ENUM_INVALID_VALUE,
}

--- Liste des templates de messages d’erreur.
local ERROR_MESSAGES = {
  [export.UNKNOWN_PARAM] = "Paramètre « %s » inconnu",
  [export.MISSING_PARAM] = "Paramètre requis « %s » absent",
  [export.EMPTY_PARAM] = "Paramètre requis « %s » vide",
  [export.INVALID_VALUE] = 'Valeur invalide pour le paramètre « %s » ("%s") de type %s',
  [export.VALUE_NOT_IN_ENUM] = 'Valeur invalide pour le paramètre « %s » ("%s")',
  [export.INVALID_TYPE] = 'Type inconnu pour le paramètre « %s » ("%s")',
  [export.ALIAS_TO_UNKNOWN] = 'Paramètre « %s », alias vers un paramètre non défini « %s »',
  [export.ALIAS_TO_ALIAS] = 'Paramètre « %s », alias vers un autre alias (« %s »)',
  [export.ALIAS_TO_ITSELF] = 'Paramètre « %s », alias vers lui-même',
  [export.ENUM_WITH_CHECKER] = "Le paramètre « %s » est une énumération avec une précondition",
  [export.ENUM_INVALID_VALUE] = 'Valeur énumérée invalide pour le paramètre « %s » ("%s") de type %s',
}

--- Construit l’objet d’erreur.
--- @param errorType string Le type de l’erreur.
--- @vararg any Les données pour formater le message d’erreur.
--- @return table Un objet contenant le type d’erreur à l’indice "error_type" et les autres données à l’indice "error_data".
local function buildErrorMessage(errorType, ...)
  return {
    ["errorType"] = errorType,
    ["errorData"] = { ... }
  }
end

--- Convertit une chaine en booléen.
--- true = "1", "oui" ou "vrai"
--- false = "0", "non" ou "faux"
--- @param argValue string La valeur à convertir.
--- @param argName string Le nom de l’argument correspondant à la valeur.
--- @param frTypeName string Le type attendu en français.
--- @return boolean La valeur booléenne du premier argument.
local function toBoolean(argValue, argName, frTypeName, errorType)
  if m_table.contains({ "1", "oui", "vrai" }, argValue) then
    return true
  elseif m_table.contains({ "0", "non", "faux" }, argValue) then
    return false
  else
    error(buildErrorMessage(errorType, argName, argValue, frTypeName))
  end
end

--- Convertit une chaine en nombre.
--- @param argValue string La valeur à convertir.
--- @param argName string Le nom de l’argument correspondant à la valeur.
--- @param toInt boolean Indique si le nombre doit être un entier.
--- @param frTypeName string Le type attendu en français.
--- @return number La valeur numérique du premier argument.
local function toNumber(argValue, argName, toInt, frTypeName, 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, frTypeName))
end

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

  -- Vérification des types des arguments.
  if expectedType == nil then
    frTypeName = "chaine"
    if type(rawValue) ~= "string" then
      error(buildErrorMessage(errorType, argName, rawValue, frTypeName))
    end
    value = rawValue
  elseif expectedType == export.NUMBER then
    frTypeName = "nombre"
    value = toNumber(rawValue, argName, false, frTypeName, errorType)
  elseif expectedType == export.INT then
    frTypeName = "entier"
    value = toNumber(rawValue, argName, true, frTypeName, errorType)
  elseif expectedType == export.FLOAT then
    frTypeName = "flottant"
    value = toNumber(rawValue, argName, false, frTypeName, errorType)
  elseif expectedType == export.BOOLEAN then
    frTypeName = "booléen"
    value = toBoolean(rawValue, argName, frTypeName, errorType)
  end

  return value, frTypeName
end

--- Vérifie la validité des définitions des paramètres.
--- @param definedParameters table La définition des paramètres.
local function checkParametersDefinitions(definedParameters)
  local validTypes = { export.BOOLEAN, export.NUMBER, export.INT, export.FLOAT }

  for paramName, paramValue in pairs(definedParameters) do
    if paramValue.type and not m_table.contains(validTypes, paramValue.type) then
      error(buildErrorMessage(export.INVALID_TYPE, paramName, paramValue.type))
    end
    if paramValue.enum then
      if paramValue.checker then
        error(buildErrorMessage(export.ENUM_WITH_CHECKER, paramName))
      else
        for _, enumValue in ipairs(paramValue.enum) do
          -- Vérification du type de la valeur.
          getValue(paramValue.type, enumValue, paramName, export.ENUM_INVALID_VALUE)
        end
      end
    end

    if paramValue.alias_of then
      local alias = paramValue.alias_of

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

--- Extrait la clé de l’argument donné après avoir résolu l’alias éventuel.
--- @param param table La définition du paramètre.
--- @param processedArgs table Les paramètres en cours de traitement.
--- @param argName string Le nom du paramètre.
--- @return string|nil Le nom du paramètre à utiliser ou nil si le paramètre
---                    est un alias dont l’argument de base a déjà une valeur.
local function extractArgumentKey(param, processedArgs, argName)
  local key

  if param.alias_of then
    -- L’alias n’écrase pas la valeur du paramètre de base.
    if processedArgs[param.alias_of] == nil then
      key = param.alias_of
    end
  else
    key = argName
  end

  return key
end

--- Extrait la valeur de l’argument donné.
--- @param param table La définition du paramètre.
--- @param key string Le nom de l’argument après résolution de l’alias.
--- @param argName string Le nom de l’argument de base.
--- @param processedArgs table Les arguments en cours de traitement.
local function extractArgumentValue(param, key, argName, argValue, processedArgs)
  if argValue then
    argValue = mw.text.trim(argValue)
  end

  if argValue == "" then
    -- Un paramètre requis vide doit avoir la propriété allow_empty à true
    -- pour ne pas lancer d’erreur.
    if param.required and param.allow_empty or not param.required then
      argValue = nil
      processedArgs[key] = nil
    else
      error(buildErrorMessage(export.EMPTY_PARAM, argName))
    end
  end

  if argValue then
    -- Récupération de la valeur après transtypage éventuel.
    local value, frTypeName = getValue(param.type, argValue, key, export.INVALID_VALUE)
    -- Vérification des contraintes d’énumération ou de la précondition.
    if type(param.enum) == "table" and not m_table.contains(param.enum, value) then
      error(buildErrorMessage(export.VALUE_NOT_IN_ENUM, argName, value))
    elseif type(param.checker) == "function" and not param.checker(value) then
      error(buildErrorMessage(export.INVALID_VALUE, argName, value, frTypeName))
    end
    processedArgs[key] = value
  end
end

--- Traite les arguments.
--- @param args table Les arguments à traiter.
--- @param definedParameters table La définition des paramètres.
--- @return table Les arguments traités.
local function parseArguments(args, definedParameters)
  local processedArgs = {}

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

    if param then
      local key = extractArgumentKey(param, processedArgs, argName)
      if key then
        extractArgumentValue(param, key, argName, argValue, processedArgs)
      end
    else
      -- Les paramètres non définis lancent une erreur.
      error(buildErrorMessage(export.UNKNOWN_PARAM, argName))
    end
  end

  return processedArgs
end

--- Vérifie que les paramètre requis sont effectivement renseignés.
--- @param processedArgs table Les arguments retournés par la fonction parse_args.
--- @param definedParameters table La définition des paramètres.
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(export.MISSING_PARAM, paramName))
      elseif paramValue.default ~= nil then
        processedArgs[paramName] = paramValue.default
      end
    end
  end
end

--- Fonction permettant de traiter les arguments du module appelant.
--- Pour plus de détails, voir la documentation du module.
--- @param args table Les arguments du module appelant.
--- @param definedParameters table Les paramètres définis.
--- @param silentErrors boolean Si true, les paramètres problématiques sont retournés au lieu de lancer une erreur ; ne devrait être utilisé que dans le cas où un comportement précis est nécessaire.
--- @return table|string|number,boolean Une table contenant les paramètres traités ou le nom du paramètre ayant déclanché une erreur et un booléen indiquant le statut.
function export.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

      -- Ajout d’une mention pour les erreurs internes.
    elseif m_table.contains(UNCATCHABLE_ERRORS, errorType) then
      errorMessage = "Erreur interne : " .. errorMessage
    end
    -- Suppression de la trace de l’erreur, on garde juste le message.
    error(errorMessage, 0)
  end

  return result, true
end

return export