Moduli:parameters/finalizeSet
< Moduli:parameters
Jump to navigation
Jump to search
Versioni i datës 10 gusht 2025 08:58 nga Kujdestari7 (diskuto | kontribute) (Krijoi faqen me "local parameters_track_module = "Module:parameters/track" local dump = mw.dumpObject local error = error local format = string.format local pairs = pairs local tostring = tostring local type = type local function track(...) track = require(parameters_track_module) return track(...) end local type_err = 'expected set members to be of type "string" or "number", but saw %s' --[==[ -- Takes `t`, a list or key map which defines a set, and returns a key map for the set (wh...")
Udhëzuesi për këtë modul mund të krijohet te Moduli:parameters/finalizeSet/doc.
local parameters_track_module = "Module:parameters/track"
local dump = mw.dumpObject
local error = error
local format = string.format
local pairs = pairs
local tostring = tostring
local type = type
local function track(...)
track = require(parameters_track_module)
return track(...)
end
local type_err = 'expected set members to be of type "string" or "number", but saw %s'
--[==[
-- Takes `t`, a list or key map which defines a set, and returns a key map for the set (which might be the original input value).
In addition to distinguishing lists from key maps, this function performs various validation checks:
* Sets may only contain strings and number.
* List inputs must be contiguous arrays, with no keys in use (even if they are non-numbers).
* Key maps are treated as having two different kinds of key:
** If a key's value is boolean {true}, it is a standard key.
** If a key's value is anything else, it is an alias of the specified key (which must not be an alias itself). For instance, if the key {"foo"} is set to {"bar"}, then {"foo"} is an alias of the key {"bar"}, which must be a non-alias key that is also in the key map.]==]
return function(t, name)
-- Iterates over `t` using pairs(), doing separate key map and list parses simultaneously. If the key map parse succeeds, `t` will simply be returned, but if the list parse succeeds, a key map of the values in the list will be returned instead.
-- Lists and key maps are mutually exclusive, as they can be distinguished by the presence of boolean `true` as a value:
-- (1) If `t` is a list, then `true` is an invalid value, because sets may only contain strings and numbers.
-- (2) If `t` is a key map, then it must contain at least one `true` as a value, because any keys which do not have `true` as their value are (by definition) aliases, and aliases must be pointed to a non-alias key (i.e. a key which has the value `true`), which is only possible if one or more keys are set to `true`.
-- (Formally, an empty table could be either, but it's more efficient to treat it as a key map.)
local i, new_map, list_err, map_err, duplicate_in_list = 0
-- The two parses are separated into blocks, which can be skipped on any
-- further iterations if that parse fails.
for k, v in pairs(t) do
local k_type, v_type = type(k)
-- The while-blocks make it possible to use `break` as a substitute for
-- `goto`, and both unconditionally terminate after one iteration.
while not list_err do
-- Catch holes using the same method as [[Module:table/isArray]],
-- but also check for non-number keys.
i = i + 1
if k_type ~= "number" or t[i] == nil then
list_err = "input list is not contiguous"
break
end
-- If `t` is a list then `v` is a set member, so it must be a string
-- or number.
v_type = type(v)
if not (v_type == "string" or v_type == "number") then
list_err = format(
type_err,
v_type == "boolean" and tostring(v) or v_type
)
-- Populate `new_map` with valid keys.
elseif not new_map then
new_map = {[v] = true}
-- If new_map[v] is already set, then `t` has duplicates. This
-- should be tracked, but only if `t` does turn out to be a list, so
-- flag it with `duplicate_in_list` for now.
elseif new_map[v] then
duplicate_in_list = true
else
new_map[v] = true
end
break
end
while not map_err do
-- If `t` is a list then `k` is a set member, so it must be a string
-- or number.
if not (k_type == "string" or k_type == "number") then
map_err = format(
type_err,
k_type == "boolean" and tostring(k) or k_type
)
break
-- If `v` is true, `k` is a non-alias key.
elseif v == true then
break
-- Filter out invalid self-aliases.
elseif k == v then
map_err = format(
"set member %s cannot be an alias of itself",
dump(k)
)
break
elseif not v_type then
v_type = type(v)
end
-- Only possible to be an alias of another key, which must be a
-- string or number.
if not (v_type == "string" or v_type == "number") then
map_err = format(
'expected set key %s have the value true or a value of type "string" or "number", but saw %s',
dump(k), v_type == "boolean" and tostring(v) or v_type
)
break
end
-- Must be an alias of a non-alias, so the value for the key `v`
-- must be `true`.
local main = t[v]
if main ~= true then
map_err = format(
"set member %s is specified as an alias of %s, %s",
dump(k), dump(v), main == nil and "which is not in the set" or "which is also an alias"
)
end
break
end
-- If both parses have failed, throw an error with the two messages.
if list_err and map_err then
error(format(
"Internal error: the `set` spec%s cannot be parsed as either a list or a key map:\nlist parse: %s\nmap parse: %s",
name and format(" for parameter %s", dump(name)) or "", map_err, list_err
))
end
end
-- If `t` can be parsed as a key map, just return it.
if not map_err then
return t
-- Otherwise, `t` is a list, so track duplicate entries if it has been
-- flagged.
elseif duplicate_in_list then
track("duplicate entry in set list")
end
-- Return the new key map.
return new_map
end