<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
	<id>https://petitplanet.wiki/Module:BucketPut?action=history&amp;feed=atom</id>
	<title>Module:BucketPut - Revision history</title>
	<link rel="self" type="application/atom+xml" href="https://petitplanet.wiki/Module:BucketPut?action=history&amp;feed=atom"/>
	<link rel="alternate" type="text/html" href="https://petitplanet.wiki/Module:BucketPut?action=history"/>
	<updated>2026-10-27T14:27:02Z</updated>
	<subtitle>Revision history for this page on the wiki</subtitle>
	<generator>MediaWiki 1.46.2</generator>
	<entry>
		<id>https://petitplanet.wiki/index.php?title=Module:BucketPut&amp;diff=10511&amp;oldid=prev</id>
		<title>Stevium: Created Module:BucketPut</title>
		<link rel="alternate" type="text/html" href="https://petitplanet.wiki/index.php?title=Module:BucketPut&amp;diff=10511&amp;oldid=prev"/>
		<updated>2026-04-26T14:03:07Z</updated>

		<summary type="html">&lt;p&gt;Created Module:BucketPut&lt;/p&gt;
&lt;p&gt;&lt;b&gt;New page&lt;/b&gt;&lt;/p&gt;&lt;div&gt;-- Imported from: https://bucket.miraheze.org/wiki/Module:BucketPut&lt;br /&gt;
&lt;br /&gt;
local p = {}&lt;br /&gt;
local getArgs = require(&amp;#039;Module:Arguments&amp;#039;).getArgs&lt;br /&gt;
local yesno = require(&amp;#039;Module:Yesno&amp;#039;)&lt;br /&gt;
local lang = mw.language.getContentLanguage()&lt;br /&gt;
&lt;br /&gt;
local O_TYPE = &amp;quot;type&amp;quot;&lt;br /&gt;
local O_DELIM = &amp;quot;delimiter&amp;quot;&lt;br /&gt;
local O_REQUIRED = &amp;quot;required&amp;quot;&lt;br /&gt;
local OPTIONS = { O_TYPE, O_DELIM, O_REQUIRED }&lt;br /&gt;
&lt;br /&gt;
local O_ALIASES = {&lt;br /&gt;
	delim = &amp;#039;delimiter&amp;#039;,&lt;br /&gt;
	notnull = &amp;#039;required&amp;#039;,&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
local C_TARGS = &amp;quot;templateargs&amp;quot;&lt;br /&gt;
local C_SUB = &amp;quot;sub&amp;quot;&lt;br /&gt;
local C_NOSAVE = &amp;quot;nosave&amp;quot;&lt;br /&gt;
local C_LOG = &amp;quot;log&amp;quot;&lt;br /&gt;
local CONF_VALS = { C_TARGS, C_SUB, C_NOSAVE, C_LOG }&lt;br /&gt;
&lt;br /&gt;
---Is `value` one of the `targets`?&lt;br /&gt;
---@param value string Type you want to check is in list.&lt;br /&gt;
---@param targets string[] List of targets that `value` could be.&lt;br /&gt;
---@return boolean&lt;br /&gt;
local function oneof(value, targets)&lt;br /&gt;
	for _, target in ipairs(targets) do&lt;br /&gt;
		if value == target then&lt;br /&gt;
			return true&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
	return false&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
---Parse a single value based on type name&lt;br /&gt;
---@param t string Type name&lt;br /&gt;
---@param v string Value to parse&lt;br /&gt;
---@return boolean success Did parsing succeed?&lt;br /&gt;
---@return any value Parsed value if success, string if fail.&lt;br /&gt;
function p.parse_typed_value(t, v)&lt;br /&gt;
	-- probably should return an object instead&lt;br /&gt;
	if oneof(t, { &amp;quot;text&amp;quot; }) then&lt;br /&gt;
		-- possible TODO with page&lt;br /&gt;
		return true, v&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	if oneof(t, { &amp;quot;int&amp;quot;, &amp;quot;integer&amp;quot; }) then&lt;br /&gt;
		local val = tonumber(v)&lt;br /&gt;
		if val ~= nil and val % 1 == 0 then&lt;br /&gt;
			return true, val&lt;br /&gt;
		else&lt;br /&gt;
			return false, &amp;quot;integer&amp;quot;&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	if oneof(t, { &amp;quot;float&amp;quot;, &amp;quot;double&amp;quot;, &amp;quot;num&amp;quot;, &amp;quot;number&amp;quot; }) then&lt;br /&gt;
		local val = tonumber(v)&lt;br /&gt;
		if val ~= nil then&lt;br /&gt;
			return true, val&lt;br /&gt;
		else&lt;br /&gt;
			return false, &amp;quot;number&amp;quot;&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	if oneof(t, { &amp;quot;bool&amp;quot;, &amp;quot;boolean&amp;quot;, &amp;quot;yesno&amp;quot; }) then&lt;br /&gt;
		local val = yesno(v)&lt;br /&gt;
		if val ~= nil then&lt;br /&gt;
			return true, val&lt;br /&gt;
		else&lt;br /&gt;
			return false, &amp;quot;boolean&amp;quot;&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	if oneof(t, { &amp;quot;date&amp;quot;, &amp;quot;time&amp;quot;, &amp;quot;datetime&amp;quot;, &amp;quot;timestamp&amp;quot; }) then&lt;br /&gt;
		local s, r = pcall(lang.formatDate, lang, &amp;quot;c&amp;quot;, v)&lt;br /&gt;
		if s then&lt;br /&gt;
			return s, r&lt;br /&gt;
		else&lt;br /&gt;
			return false, &amp;quot;timestamp&amp;quot;&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	if oneof(t, { &amp;quot;unixtime&amp;quot; }) then&lt;br /&gt;
		local s, r = pcall(lang.formatDate, lang, &amp;quot;U&amp;quot;, v)&lt;br /&gt;
		if s then&lt;br /&gt;
			r = tonumber(r)&lt;br /&gt;
				or error(&amp;quot;Could not convert &amp;quot; .. r .. &amp;quot; to a number&amp;quot;)&lt;br /&gt;
			return s, r&lt;br /&gt;
		else&lt;br /&gt;
			return false, &amp;quot;Unix timestamp&amp;quot;&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	error(&amp;quot;Unsupported type: &amp;quot; .. mw.dumpObject(t))&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
---Recursively and safely add items of `keylist` to `args`.&lt;br /&gt;
---&lt;br /&gt;
---`add_to_args({}, { &amp;quot;a&amp;quot;, &amp;quot;b&amp;quot;, &amp;quot;c&amp;quot; }, &amp;quot;d&amp;quot;)`&lt;br /&gt;
---will yield&lt;br /&gt;
---`{ a = { b = { c = &amp;quot;d&amp;quot; } } }`&lt;br /&gt;
---@param args table&lt;br /&gt;
---@param keylist (string | number)[]&lt;br /&gt;
---@param value any&lt;br /&gt;
local function add_to_args(args, keylist, value)&lt;br /&gt;
	local nextvalue = args&lt;br /&gt;
	for i, valuename in ipairs(keylist) do&lt;br /&gt;
		if i == #keylist then&lt;br /&gt;
			nextvalue[valuename] = value&lt;br /&gt;
		else&lt;br /&gt;
			nextvalue[valuename] = nextvalue[valuename] or {}&lt;br /&gt;
			nextvalue = nextvalue[valuename]&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
---Parse specific key-value combination and modify output table.&lt;br /&gt;
---@param out_args table&lt;br /&gt;
---@param out_config table&lt;br /&gt;
---@param key string&lt;br /&gt;
---@param value string&lt;br /&gt;
---@return nil&lt;br /&gt;
function p.parse_args(out_args, out_config, key, value)&lt;br /&gt;
	if type(key) ~= &amp;quot;string&amp;quot; then&lt;br /&gt;
		return&lt;br /&gt;
	end&lt;br /&gt;
	value = mw.text.trim(value)&lt;br /&gt;
	if value == &amp;#039;&amp;#039; then&lt;br /&gt;
		return&lt;br /&gt;
	end&lt;br /&gt;
	-- basic conditions for parser working&lt;br /&gt;
&lt;br /&gt;
	local optkey, optname = key:match(&amp;quot;^([%w_]+)%-(.+)$&amp;quot;)&lt;br /&gt;
	-- [%w_] matches all valid bucket field names at time of writing&lt;br /&gt;
	-- (non-exhaustively, i.e. all valid names are matched by [%w_], but [%w_]&lt;br /&gt;
	-- also matches some invalid names)&lt;br /&gt;
	if optkey and optname then&lt;br /&gt;
		if O_ALIASES[optname] then&lt;br /&gt;
			optname = O_ALIASES[optname]&lt;br /&gt;
		end&lt;br /&gt;
		if not oneof(optname, OPTIONS) then&lt;br /&gt;
			local fmt = &amp;quot;Invalid option %s for parameter %s&amp;quot;&lt;br /&gt;
			error(fmt:format(optname, optkey))&lt;br /&gt;
		end&lt;br /&gt;
		return add_to_args(out_args, { optkey, optname }, value)&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	local ckey = key:match(&amp;quot;^%+(.+)$&amp;quot;)&lt;br /&gt;
	if ckey then&lt;br /&gt;
		if not oneof(ckey, CONF_VALS) then&lt;br /&gt;
			error(ckey .. &amp;quot; not a recognised config option&amp;quot;)&lt;br /&gt;
		end&lt;br /&gt;
		out_config[ckey] = value&lt;br /&gt;
		-- modify out_config rather than out_args&lt;br /&gt;
		return&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	return add_to_args(out_args, { key, 1 }, value)&lt;br /&gt;
	-- none of the above apply so treat as raw arg&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
---Turn parsed argument object to single value to send to `mw.bucket.put`.&lt;br /&gt;
---@param argname string&lt;br /&gt;
---@param data table&lt;br /&gt;
---@return any&lt;br /&gt;
function p.get_bucket_arg(argname, data)&lt;br /&gt;
	local item = data[1]&lt;br /&gt;
	if not item then&lt;br /&gt;
		if not yesno(data[O_REQUIRED]) then&lt;br /&gt;
			return&lt;br /&gt;
		end&lt;br /&gt;
		error((&amp;quot;Required argument %s was not given&amp;quot;):format(argname))&lt;br /&gt;
	end&lt;br /&gt;
	item = mw.text.trim(item)&lt;br /&gt;
	local type = data[O_TYPE] or &amp;quot;text&amp;quot;&lt;br /&gt;
&lt;br /&gt;
	if not data[O_DELIM] then&lt;br /&gt;
		local success, value_or_typename = p.parse_typed_value(type, item)&lt;br /&gt;
		if success then&lt;br /&gt;
			return value_or_typename&lt;br /&gt;
			-- value&lt;br /&gt;
		else&lt;br /&gt;
			local fmt = &amp;quot;Invalid %s given for parameter %s: %s&amp;quot;&lt;br /&gt;
			error(fmt:format(value_or_typename, mw.dumpObject(argname), mw.dumpObject(item)))&lt;br /&gt;
			-- typename&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	local delim = data[O_DELIM]&lt;br /&gt;
	delim = delim:gsub(&amp;#039;%f[\\]\\n&amp;#039;, &amp;#039;\n&amp;#039;)&lt;br /&gt;
	delim = delim:gsub(&amp;#039;\\\\n&amp;#039;, &amp;#039;\\n&amp;#039;)&lt;br /&gt;
	--[[&lt;br /&gt;
		removes a backslash from start, so:&lt;br /&gt;
		\n -&amp;gt; newline&lt;br /&gt;
		\\n -&amp;gt; \n&lt;br /&gt;
		\\\n -&amp;gt; \\n&lt;br /&gt;
		etc.&lt;br /&gt;
	]]&lt;br /&gt;
&lt;br /&gt;
	local items = {}&lt;br /&gt;
	for entry in mw.text.gsplit(item, delim) do&lt;br /&gt;
		entry = mw.text.trim(entry)&lt;br /&gt;
		if entry ~= &amp;quot;&amp;quot; then&lt;br /&gt;
			local success, value_or_typename = p.parse_typed_value(type, entry)&lt;br /&gt;
			if success then&lt;br /&gt;
				table.insert(items, value_or_typename)&lt;br /&gt;
				-- value&lt;br /&gt;
			else&lt;br /&gt;
				local fmt = &amp;quot;Invalid %s given for parameter %s: %s&amp;quot;&lt;br /&gt;
				error(fmt:format(value_or_typename, mw.dumpObject(argname), mw.dumpObject(entry)))&lt;br /&gt;
				-- typename&lt;br /&gt;
			end&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	return items&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
---Turn list of parsed arguments into `mw.bucket.put` arg table.&lt;br /&gt;
---@param out_args table&lt;br /&gt;
---@return table&lt;br /&gt;
function p.get_bucket_args(out_args)&lt;br /&gt;
	local bucket_args = {}&lt;br /&gt;
	for arg, data in pairs(out_args) do&lt;br /&gt;
		bucket_args[arg] = p.get_bucket_arg(arg, data)&lt;br /&gt;
	end&lt;br /&gt;
	return bucket_args&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
---Main invokable function.&lt;br /&gt;
---@param frame any&lt;br /&gt;
function p.put(frame)&lt;br /&gt;
	local args = getArgs(frame, { frameOnly = true })&lt;br /&gt;
	local parent_args = getArgs(frame, { parentOnly = true })&lt;br /&gt;
	local bucket_name = mw.text.trim(args[1] or &amp;#039;&amp;#039;)&lt;br /&gt;
&lt;br /&gt;
	-- Replicate the behavior of $wgCargoStoreUseTemplateArgsFallback for specified arguments&lt;br /&gt;
	local implicit_store_args = mw.text.trim(args[&amp;#039;+&amp;#039; .. C_TARGS] or &amp;#039;&amp;#039;)&lt;br /&gt;
	for arg in implicit_store_args:gmatch(&amp;quot;[^,]+&amp;quot;) do&lt;br /&gt;
		arg = mw.text.trim(arg)&lt;br /&gt;
		args[arg] = parent_args[arg]&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	-- Convert all arguments to consistent format&lt;br /&gt;
	local out_args = {}&lt;br /&gt;
	local out_config = {}&lt;br /&gt;
	for k, v in pairs(args) do&lt;br /&gt;
		p.parse_args(out_args, out_config, k, v)&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	local bucket_args = p.get_bucket_args(out_args)&lt;br /&gt;
&lt;br /&gt;
	if yesno(out_config[C_LOG]) then&lt;br /&gt;
		mw.log(&amp;quot;Passed args: &amp;quot; .. mw.dumpObject(args))&lt;br /&gt;
		mw.log(&amp;quot;out_args: &amp;quot; .. mw.dumpObject(out_args))&lt;br /&gt;
		mw.log(&amp;quot;out_config: &amp;quot; .. mw.dumpObject(out_config))&lt;br /&gt;
		mw.log(&amp;quot;bucket_args: &amp;quot; .. mw.dumpObject(bucket_args))&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	-- put changes to bucket&lt;br /&gt;
	if not yesno(out_config[C_NOSAVE]) then&lt;br /&gt;
		local bucket = mw.bucket(bucket_name)&lt;br /&gt;
		if out_config[C_SUB] then&lt;br /&gt;
			bucket.sub(out_config[C_SUB])&lt;br /&gt;
		end&lt;br /&gt;
		bucket.put(bucket_args)&lt;br /&gt;
	end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
return p&lt;/div&gt;</summary>
		<author><name>Stevium</name></author>
	</entry>
</feed>