<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
	<id>https://linguifex.com/w/index.php?action=history&amp;feed=atom&amp;title=Module%3Aparameters%2FfinalizeSet</id>
	<title>Module:parameters/finalizeSet - Revision history</title>
	<link rel="self" type="application/atom+xml" href="https://linguifex.com/w/index.php?action=history&amp;feed=atom&amp;title=Module%3Aparameters%2FfinalizeSet"/>
	<link rel="alternate" type="text/html" href="https://linguifex.com/w/index.php?title=Module:parameters/finalizeSet&amp;action=history"/>
	<updated>2026-04-04T10:31:12Z</updated>
	<subtitle>Revision history for this page on the wiki</subtitle>
	<generator>MediaWiki 1.43.6</generator>
	<entry>
		<id>https://linguifex.com/w/index.php?title=Module:parameters/finalizeSet&amp;diff=462417&amp;oldid=prev</id>
		<title>Sware: Created page with &quot;local parameters_track_module = &quot;Module:parameters/track&quot;  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 = &#039;expected set members to be of type &quot;string&quot; or &quot;number&quot;, but saw %s&#039;  --[==[ -- Takes `t`, a list or key map which defines a set, and returns a key map for the set (...&quot;</title>
		<link rel="alternate" type="text/html" href="https://linguifex.com/w/index.php?title=Module:parameters/finalizeSet&amp;diff=462417&amp;oldid=prev"/>
		<updated>2025-07-10T11:29:56Z</updated>

		<summary type="html">&lt;p&gt;Created page with &amp;quot;local parameters_track_module = &amp;quot;Module:parameters/track&amp;quot;  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 = &amp;#039;expected set members to be of type &amp;quot;string&amp;quot; or &amp;quot;number&amp;quot;, but saw %s&amp;#039;  --[==[ -- Takes `t`, a list or key map which defines a set, and returns a key map for the set (...&amp;quot;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;New page&lt;/b&gt;&lt;/p&gt;&lt;div&gt;local parameters_track_module = &amp;quot;Module:parameters/track&amp;quot;&lt;br /&gt;
&lt;br /&gt;
local dump = mw.dumpObject&lt;br /&gt;
local error = error&lt;br /&gt;
local format = string.format&lt;br /&gt;
local pairs = pairs&lt;br /&gt;
local tostring = tostring&lt;br /&gt;
local type = type&lt;br /&gt;
&lt;br /&gt;
local function track(...)&lt;br /&gt;
	track = require(parameters_track_module)&lt;br /&gt;
	return track(...)&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local type_err = &amp;#039;expected set members to be of type &amp;quot;string&amp;quot; or &amp;quot;number&amp;quot;, but saw %s&amp;#039;&lt;br /&gt;
&lt;br /&gt;
--[==[&lt;br /&gt;
-- 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).&lt;br /&gt;
&lt;br /&gt;
In addition to distinguishing lists from key maps, this function performs various validation checks:&lt;br /&gt;
* Sets may only contain strings and number.&lt;br /&gt;
* List inputs must be contiguous arrays, with no keys in use (even if they are non-numbers).&lt;br /&gt;
* Key maps are treated as having two different kinds of key:&lt;br /&gt;
** If a key&amp;#039;s value is boolean {true}, it is a standard key.&lt;br /&gt;
** If a key&amp;#039;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 {&amp;quot;foo&amp;quot;} is set to {&amp;quot;bar&amp;quot;}, then {&amp;quot;foo&amp;quot;} is an alias of the key {&amp;quot;bar&amp;quot;}, which must be a non-alias key that is also in the key map.]==]&lt;br /&gt;
return function(t, name)&lt;br /&gt;
	-- 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.&lt;br /&gt;
	-- Lists and key maps are mutually exclusive, as they can be distinguished by the presence of boolean `true` as a value:&lt;br /&gt;
		-- (1) If `t` is a list, then `true` is an invalid value, because sets may only contain strings and numbers.&lt;br /&gt;
		-- (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`.&lt;br /&gt;
	-- (Formally, an empty table could be either, but it&amp;#039;s more efficient to treat it as a key map.)&lt;br /&gt;
	local i, new_map, list_err, map_err, duplicate_in_list = 0&lt;br /&gt;
	-- The two parses are separated into blocks, which can be skipped on any&lt;br /&gt;
	-- further iterations if that parse fails.&lt;br /&gt;
	for k, v in pairs(t) do&lt;br /&gt;
		local k_type, v_type = type(k)&lt;br /&gt;
		-- The while-blocks make it possible to use `break` as a substitute for&lt;br /&gt;
		-- `goto`, and both unconditionally terminate after one iteration.&lt;br /&gt;
		while not list_err do&lt;br /&gt;
			-- Catch holes using the same method as [[Module:table/isArray]],&lt;br /&gt;
			-- but also check for non-number keys.&lt;br /&gt;
			i = i + 1&lt;br /&gt;
			if k_type ~= &amp;quot;number&amp;quot; or t[i] == nil then&lt;br /&gt;
				list_err = &amp;quot;input list is not contiguous&amp;quot;&lt;br /&gt;
				break&lt;br /&gt;
			end&lt;br /&gt;
			-- If `t` is a list then `v` is a set member, so it must be a string&lt;br /&gt;
			-- or number.&lt;br /&gt;
			v_type = type(v)&lt;br /&gt;
			if not (v_type == &amp;quot;string&amp;quot; or v_type == &amp;quot;number&amp;quot;) then&lt;br /&gt;
				list_err = format(&lt;br /&gt;
					type_err,&lt;br /&gt;
					v_type == &amp;quot;boolean&amp;quot; and tostring(v) or v_type&lt;br /&gt;
				)&lt;br /&gt;
			-- Populate `new_map` with valid keys.&lt;br /&gt;
			elseif not new_map then&lt;br /&gt;
				new_map = {[v] = true}&lt;br /&gt;
			-- If new_map[v] is already set, then `t` has duplicates. This&lt;br /&gt;
			-- should be tracked, but only if `t` does turn out to be a list, so&lt;br /&gt;
			-- flag it with `duplicate_in_list` for now.&lt;br /&gt;
			elseif new_map[v] then&lt;br /&gt;
				duplicate_in_list = true&lt;br /&gt;
			else&lt;br /&gt;
				new_map[v] = true&lt;br /&gt;
			end&lt;br /&gt;
			break&lt;br /&gt;
		end&lt;br /&gt;
		while not map_err do&lt;br /&gt;
			-- If `t` is a list then `k` is a set member, so it must be a string&lt;br /&gt;
			-- or number.&lt;br /&gt;
			if not (k_type == &amp;quot;string&amp;quot; or k_type == &amp;quot;number&amp;quot;) then&lt;br /&gt;
				map_err = format(&lt;br /&gt;
					type_err,&lt;br /&gt;
					k_type == &amp;quot;boolean&amp;quot; and tostring(k) or k_type&lt;br /&gt;
				)&lt;br /&gt;
				break&lt;br /&gt;
			-- If `v` is true, `k` is a non-alias key.&lt;br /&gt;
			elseif v == true then&lt;br /&gt;
				break&lt;br /&gt;
			-- Filter out invalid self-aliases.&lt;br /&gt;
			elseif k == v then&lt;br /&gt;
				map_err = format(&lt;br /&gt;
					&amp;quot;set member %s cannot be an alias of itself&amp;quot;,&lt;br /&gt;
					dump(k)&lt;br /&gt;
				)&lt;br /&gt;
				break&lt;br /&gt;
			elseif not v_type then&lt;br /&gt;
				v_type = type(v)&lt;br /&gt;
			end&lt;br /&gt;
			-- Only possible to be an alias of another key, which must be a&lt;br /&gt;
			-- string or number.&lt;br /&gt;
			if not (v_type == &amp;quot;string&amp;quot; or v_type == &amp;quot;number&amp;quot;) then&lt;br /&gt;
				map_err = format(&lt;br /&gt;
					&amp;#039;expected set key %s have the value true or a value of type &amp;quot;string&amp;quot; or &amp;quot;number&amp;quot;, but saw %s&amp;#039;,&lt;br /&gt;
					dump(k), v_type == &amp;quot;boolean&amp;quot; and tostring(v) or v_type&lt;br /&gt;
				)&lt;br /&gt;
				break&lt;br /&gt;
			end&lt;br /&gt;
			-- Must be an alias of a non-alias, so the value for the key `v`&lt;br /&gt;
			-- must be `true`.&lt;br /&gt;
			local main = t[v]&lt;br /&gt;
			if main ~= true then&lt;br /&gt;
				map_err = format(&lt;br /&gt;
					&amp;quot;set member %s is specified as an alias of %s, %s&amp;quot;,&lt;br /&gt;
					dump(k), dump(v), main == nil and &amp;quot;which is not in the set&amp;quot; or &amp;quot;which is also an alias&amp;quot;&lt;br /&gt;
				)&lt;br /&gt;
			end&lt;br /&gt;
			break&lt;br /&gt;
		end&lt;br /&gt;
		-- If both parses have failed, throw an error with the two messages.&lt;br /&gt;
		if list_err and map_err then&lt;br /&gt;
			error(format(&lt;br /&gt;
				&amp;quot;Internal error: the `set` spec%s cannot be parsed as either a list or a key map:\nlist parse: %s\nmap parse: %s&amp;quot;,&lt;br /&gt;
				name and format(&amp;quot; for parameter %s&amp;quot;, dump(name)) or &amp;quot;&amp;quot;, map_err, list_err&lt;br /&gt;
			))&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
	-- If `t` can be parsed as a key map, just return it.&lt;br /&gt;
	if not map_err then&lt;br /&gt;
		return t&lt;br /&gt;
	-- Otherwise, `t` is a list, so track duplicate entries if it has been&lt;br /&gt;
	-- flagged.&lt;br /&gt;
	elseif duplicate_in_list then&lt;br /&gt;
		track(&amp;quot;duplicate entry in set list&amp;quot;)&lt;br /&gt;
	end&lt;br /&gt;
	-- Return the new key map.&lt;br /&gt;
	return new_map&lt;br /&gt;
end&lt;/div&gt;</summary>
		<author><name>Sware</name></author>
	</entry>
</feed>