Oromis56 (discussion | contributions) Aucun résumé des modifications |
Oromis56 (discussion | contributions) Aucun résumé des modifications |
||
Ligne 20 : | Ligne 20 : | ||
local equalsSecond = splitted[2] and mw.text.trim(splitted[2]) == mw.ustring.lower(mw.text.trim(element2)) |
local equalsSecond = splitted[2] and mw.text.trim(splitted[2]) == mw.ustring.lower(mw.text.trim(element2)) |
||
local equalsThird = splitted[3] and mw.text.trim(splitted[3]) == mw.ustring.lower(mw.text.trim(element2)) |
local equalsThird = splitted[3] and mw.text.trim(splitted[3]) == mw.ustring.lower(mw.text.trim(element2)) |
||
− | mw.addWarning(element2) |
+ | --mw.addWarning(element2) |
return equalsFirt or equalsSecond or equalsThird |
return equalsFirt or equalsSecond or equalsThird |
||
end |
end |
Version du 14 septembre 2020 à 12:35
[créer | historique | purger]Documentation
Ce module n'a pas de documentation. Si vous savez comment l'utiliser, merci de la créer.local input = {}
local program = {}
local filter = {}
local parser = {}
local builder = {}
local dataModule = 'Module:BlockstateList'
-- Comparateur pour les blocs. Compare le bloc 'element1' à 'element2' si celui-ci ne possède pas de '|', ou au deux parties séparées par '|' si celui-ci en possède un
local comparatorBlock = function(element1, element2)
element2 = mw.ustring.lower(element2)
local splitted = mw.text.split(mw.ustring.lower(element1), '|', true)
return mw.text.trim(splitted[1]) == element2 or (splitted[2] and mw.text.trim(splitted[2]) == element2) or (splitted[3] and mw.text.trim(splitted[3]))
end
local comparatorBlock = function(element2, element1)
element2 = mw.ustring.lower(element2)
local splitted = mw.text.split(mw.ustring.lower(element1), '|', true)
local equalsFirst = mw.text.trim(splitted[1]) == mw.text.trim(mw.ustring.lower(element2))
local equalsSecond = splitted[2] and mw.text.trim(splitted[2]) == mw.ustring.lower(mw.text.trim(element2))
local equalsThird = splitted[3] and mw.text.trim(splitted[3]) == mw.ustring.lower(mw.text.trim(element2))
--mw.addWarning(element2)
return equalsFirt or equalsSecond or equalsThird
end
-- Comparateur pour les blockstates. Vérifie la simple égalité en ignorant la casse et en ayant trim les entrées
local comparatorBlockstate = function (element1, element2)
return mw.text.trim(mw.ustring.lower(element1)) == mw.text.trim(mw.ustring.lower(element2))
end
function input.main(frame)
-- Si le module est appelé par un template, on récupère les paramètres passés au template
if mw.getCurrentFrame():getParent() then
frame = mw.getCurrentFrame():getParent()
end
success, msg = program.run(frame.args)
if not success then
mw.addWarning('[Erreur] ' .. msg)
else
--mw.addWarning('<nowiki>' .. msg .. '</nowiki>')
return frame:preprocess(msg)
end
end
--[[
Lance le filtrage puis la construction du tableau sur les données
@param args un dictionnaire d'arguments passé au programme
@return1 vrai si l'exécution du programme s'est faite sans erreur, faux sinon
@return2 le tableau au format wikicode
]]
function program.run(args)
-- Récupération des données
local data = require(dataModule)
local success, result = program.parseArguments(args)
if success then
success, data = filter.data(data, result.blockstates, result.blocks)
if success then
return true, program.buildTable(data, result.anchor, result.order, result.width)
else
return false, data
end
else
return false, result
end
end
--[[
@param data les données des blockstates
@param anchor vrai si une ancre doit être affichée sur le nom du blockstate, faux sinon
@param order l'ordre d'affichage des colonnes
@return le tableau complet sous le format wikicode
]]
function program.buildTable(data, anchor, order, width)
return builder.header(order, width) .. builder.lines(data, anchor, order) .. '\n|}\n{{-}}'
end
--[[
@param args un dictionnaire d'arguments passé au programme
@return1 vrai si chaque élément a réussi à être parsé, faux sinon
@return2 si return1 vrai, retourne un dictionnaire avec les différentes valeurs parsées, sinon, retourne le message d'erreur
]]
function program.parseArguments(args)
local error = false
local msgError = ''
-- Parsing du paramètre 'block'
local blocks = parser.multiParam(args.block)
-- Parsing du paramètre 'blockstate'
local blockstates = parser.multiParam(args.blockstate)
-- Parsing du paramètre 'anchor'
local anchor = false
error, msgError = parser.boolean(args.anchor or 'false')
if not error then
anchor = msgError
end
-- Parsing du paramètre width
local width = nil
if not error and args.width then
error, msgError = parser.int(args.width)
if not error then
width = msgError
end
end
-- Parsing du paramètre 'order'
if not error and args.order then
error, msgError = parser.order(args.order)
end
if error then
return false, msgError
else
return true, { blocks = blocks, blockstates = blockstates, anchor = anchor, order = args.order or '1234', width = width }
end
end
----- FONCTIONS DE CONSTRUCTION DE LA TABLE -----
--[[
@param order l'ordre d'affichage des colonnes
@return le header sous le format wikicode en prenant compte de 'order'
]]
function builder.header(order, width)
local widthText = ''
-- Gestion du paramètre width
if width then
widthText = ' style="width:' .. width .. '%"'
end
local header = '{|align="left" class="wikitable sortable"' .. widthText .. '\n'
for c in order:gmatch("[1234]") do
header = header .. builder.getColumnDeclaration(tonumber(c))
end
return header
end
--[[
@param data les données des blockstates
@param anchor vrai si une ancre doit être affichée sur le nom du blockstate, faux sinon
@param order l'ordre d'affichage des colonnes
@return les lignes du blockstate au format wikicode
]]
function builder.lines(data, anchor, order)
local lines = ''
local keyTable = {}
-- Trie en fonction des clés
for state, _ in pairs(data) do
table.insert(keyTable, state)
end
table.sort(keyTable)
for _, state in ipairs(keyTable) do
lines = lines .. '|-\n' .. builder.line(state, data[state], anchor, order)
end
return lines
end
--[[
@param state le nom du blockstate
@param value la valeur du blockstate dans les données
@param anchor vrai si une ancre doit être affichée sur le nom du blockstate, faux sinon
@param order l'ordre d'affichage des colonnes
@return la ligne du blockstate au format wikicode
]]
function builder.line(state, value, anchor, order)
local line = ''
for column in order:gmatch("[1234]") do
if column == '1' then
line = line .. '| rowspan="' .. #(value.entries) .. '" | ' .. builder.nameLine(state, anchor)
elseif column == '2' then
line = line .. '| rowspan="' .. #(value.entries) .. '" | ' .. value.description
elseif column == '3' then
line = line .. '| ' .. builder.valueLine(value.entries[1].values)
elseif column == '4' then
line = line .. '| ' .. builder.blockLine(value.entries[1].blocks)
end
line = line .. '\n'
end
if order:find('[34]') then
table.remove(value.entries, 1)
end
if #(value.entries) > 0 then
line = line .. builder.entryLine(value.entries, mw.ustring.gsub(order, '[^34]', ''))
end
return line
end
--[[
@param column un index de colonne parmi {1, 2, 3, 4}
@return l'en-tête de colonne du numéro de colonne spécifié en paramètre
]]
function builder.getColumnDeclaration(column)
return ({
'! colspan="1" style="text-align: center;" | Nom de l\'états\n',
'! colspan="1" style="text-align: center;" | Description\n',
'! colspan="1" style="text-align: center;" | Valeur de l\'état\n',
'! colspan="1" style="text-align: center;" | Blocs\n'
})[column]
end
--[[
@param string le nom du blockstate
@param anchor vrai si les noms des blockstates doivent être une ancre, faux sinon
@return la case 'nom' formatée
]]
function builder.nameLine(name, anchor)
local line = ''
-- Prise en compte de l'ancre
if anchor then
line = line .. '{{anchor|' .. name .. '}} '
end
line = line .. '{{code|' .. name .. '}}'
return line
end
--[[
@param data une liste d'entrées à afficher dans les cellules 'valeur' et 'bloc'
@param order l'ordre d'affichage des colonnes
@return la partie de 'bloc' et 'valeur' de la ligne si celle-ci possède plusieurs entrées, au format wikicode
]]
function builder.entryLine(data, order)
local lines = ''
-- Parcours de toutes les entrées
for _, entry in ipairs(data) do
lines = lines .. '\n|-\n'
for column in order:gmatch("[34]") do
if column == '3' then
lines = lines .. '| ' .. builder.valueLine(entry.values)
elseif column == '4' then
lines = lines .. '| ' .. builder.blockLine(entry.blocks)
end
lines = lines .. '\n'
end
end
return lines
end
--[[
@param data une liste de valeurs à afficher dans la cellule
@return la cellule du tableau sous le format wikicode
]]
function builder.valueLine(data)
local cell = ''
for i, value in ipairs(data) do
-- Gestion des valeurs de la forme 'MIN - MAX'
if(type(value) == 'table') then
cell = cell .. '{{code|' .. value.min .. '}} - {{code|' .. value.max .. '}}'
else
cell = cell .. '{{code|' .. value .. '}}'
-- Séparation des différentes valeurs par un retour à la ligne (sans en mettre après le dernier élément)
if i < #data then
cell = cell .. ' <br/> '
end
end
end
return cell
end
--[[
@param data une liste de blocs à afficher dans la cellule
@return la cellule du tableau sous le format wikicode
]]
function builder.blockLine(data)
local cell = ''
for i, block in ipairs(data) do
-- Gestion des blocs si pas cachées
if block:find('|', 0, true) then
cell = cell .. '{{LienBloc|id=' .. block .. '}}'
else
cell = cell .. '{{LienBloc|' .. block:gsub("^%l", string.upper) .. '}}'
end
-- Séparation des différentes valeurs par un retour à la ligne (sans en mettre après le dernier élément)
if i < #data then
cell = cell .. ' <br/> '
end
end
return cell
end
----- FONCTIONS DE FILTRE -----
--[[
@param data un tableau de donnée
@param blockstates une séquence de blockstates à récupérer dans 'data'
@param blocks une séquence de blocs à récupérer dans 'data' filtré
@return 'data', filtré en fonction des deux contraintes 'blockstates' et blocks'
le retour contiendra donc tous les blockstates de 'blockstates' demandés si ils répondent à la contrainte 'blocks'
]]
function filter.data(data, blockstates, blocks)
local stateConstraint = #blockstates ~= 0
-- Parcours de tous les blockstates
for k, v in pairs(data) do
-- Suppression du blockstate courant si celui-ci n'est pas spécifié dans la containte 'blockstates' (non nulle)
if stateConstraint and not table.contains(blockstates, k, comparatorBlockstate) then
data[k] = nil
-- Suppression du blockstate courant si aucun bloc lui appartenant ne répond à la containte 'blocks' (non nulle)
elseif #blocks ~= 0 and not filter.blocks(v, blocks) then
data[k] = nil
end
if stateConstraint and table.contains(blockstates, k, comparatorBlockstate) then
table.remove(blockstates, table.indexOf(blockstates, k, comparatorBlockstate))
end
end
-- Vérification de la validation des contraintes pour les retours
if stateConstraint and #blockstates ~= 0 then
return false, table.concat(blockstates, ", ") .. ' n\'existe(nt) pas. Vous pouvez compléter la liste en cliquant [[' .. dataModule .. '|ici]].'
elseif #blocks ~= 0 and table.getMapSize(data) == 0 then
return false, 'Aucun état de bloc ne possède l\'un des blocs demandés. Vous pouvez compléter la liste en cliquant [[' .. dataModule .. '|ici]].'
else
return true, data
end
end
--[[
Filtre state pour ne garder que les entrées qui correspondent à la contrainte si cell-ci existe
@param state les attributs d'un blockstate
@param blocks les contraintes de blocs
@return vrai si le blockstate possède au moins un bloc de la contrainte dans le cas où celle-ci existe, faux sinon
]]
function filter.blocks(state, blocks)
local keep = #blocks == 0
local toRemove = {}
-- Parcours de toutes les entrées de state
for k, v in ipairs(state.entries) do
local foundBlock = false
-- Parcours de tous les blocs de l'entrée courante à la recherche d'un qui pourrait répondre à la contrainte
for _, block in ipairs(v.blocks) do
foundBlock = foundBlock or table.contains(blocks, block, comparatorBlock)
keep = keep or foundBlock
end
-- Suppression de l'entrée si elle ne correspond pas à la contrainte
if not foundBlock and #blocks ~= 0 then
table.insert(toRemove, k)
end
end
local shift = 0
for _, v in ipairs(toRemove) do
table.remove(state.entries, v - shift)
shift = shift + 1
end
return keep
end
----- FONCTIONS DE PARSING -----
--[[
@param v
@return1 faux si 'v' a bien réussi à être converti en boolean, c'est-à-dire si 'v' est un élément de l'ensemble {'true', 'false', 'vrai', 'faux'}
@return2 la valeur parsée si return1 vrai, un message d'erreur sinon
]]
function parser.boolean(v)
if (type(v) == 'string') and (v == 'true' or v == 'false' or v == 'vrai' or v == 'faux') then
return false, v == 'true' or v == 'vrai'
else
return true, "'" .. tostring(v) .. "' n'est pas un booléen valide."
end
end
--[[
@param v
@return1 faux si 'v' a bien réussi à être converti en entier compris entre 0 et 100 inclu
@return2 la valeur parsée si return1 vrai, un message d'erreur sinon
]]
function parser.int(v)
local matches = tonumber((type(v) == 'string') and string.match(v, '^%d+$'))
if matches and 0 <= matches and matches <= 100 then
return false, matches
else
return true, "'" .. tostring(v) .. "' n'est pas un pourcentage valide (0-100)."
end
end
--[[
@param param une valeur d'un paramètre sous forme de string pouvant énumérer plusieurs valeurs ou non
@return1 une séquence possédant chaque valeur de 'param'
]]
function parser.multiParam(param)
return ((param == '' or param == nil) and '') or mw.text.split(mw.text.trim(param or ''), ' *, *')
end
--[[
@param order un string
@return1 vrai si le string est un sous-ensemble de {1, 2, 3, 4}, faux sinon
@return2 le message d'erreur si return1 est faux, chaîne vide sinon
]]
function parser.order(order)
local record = {true, true, true, true}
if order and #order <= 4 and #order > 0 then
for c in order:gmatch("[^%c]") do
if c:match("[1234]") then
if record[tonumber(c)] then
record[tonumber(c)] = false
else
-- Renvoie d'une erreur dans le cas où l'une des colonnes est demandée à être cachée plusieurs fois
return true, "'" .. c .. "' dans '" .. order .. "' ne peut pas être présent plusieurs fois."
end
else
-- Renvoie d'une erreur dans le cas où l'un des caractères n'est pas un numéro de colonne valide
return true, "'" .. c .. "' dans '" .. order .. "' n'est pas un numéro de colonne valide."
end
end
elseif order and (#order > 4 or #order == 0) then
-- Renvoie d'une erreur dans le cas où il y a plus ou moins de caractères que demandé
return true, "'" .. order .. "' doit posséder de 1 à 4 caractères uniques parmi [1234]."
end
return false, ''
end
--------------------------------
--[[
@param array une séquence d'élément
@param element un élément dont la présence doit être vérifiée dans 'array'
@param comparator une fonction comparatrice
@return vrai si un élément de 'array' est égal à 'element' selon 'comparator', faux sinon
]]
function table.contains(array, element, comparator)
for _, v in ipairs(array) do
if comparator(v, element) then
return true
end
end
return false
end
--[[
@param array une séquence d'élément
@param element un élément dont la présence doit être vérifiée dans 'array'
@param comparator une fonction comparatrice
@return vrai si 'element' est dans 'array' selon l'égalité définie par 'comparator'
]]
function table.indexOf(array, element, comparator)
for k, v in ipairs(array) do
if comparator(v, element) then
return k
end
end
end
function table.getMapSize(map)
local counter = 0
for _, _ in pairs(map) do
counter = counter + 1
end
return counter
end
return input