Moduli:parameters/finalizeSet

Nga Enciklopedi Puro Shqiptare
< Moduli:parameters
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...")
(ndrysh) ← Version më i vjetër | shikoni versionin e tanishëm (ndrysh) | Version më i ri → (ndrysh)
Jump to navigation Jump to search

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