Content deleted Content added
No edit summary
No edit summary
စာတွဲ: နောက်ပြန်ပြင်ခဲ့ပြီး
စာကြောင်း ၁ -
local m_str_utils = require("Module:string utilities")
 
local require_when_needed = require("Module:utilities/require when needed")
 
local dump = mw.dumpObject
local floor = math.floor
local gsplit = mw.text.gsplit
local gsub = string.gsub
local huge = math.huge
local insert = table.insert
local list_to_set = require("Module:table").listToSet
local list_to_text = mw.text.listToText
local match = string.match
local max = math.max
local pairs = pairs
local pattern_escape = m_str_utils.pattern_escape
local remove_holes = require_when_needed("Module:parameters/remove holes")
local scribunto_param_key = m_str_utils.scribunto_param_key
local sort = table.sort
local trim = mw.text.trim
local type = type
local yesno = require_when_needed("Module:yesno")
 
local export = {}
 
local function track(page, calling_module, calling_function, param_name)
local track = require("Module:debug/track")("parameters/" .. page)
end
local tracking_page = "parameters/" .. page
 
-- Cascades down in specificity, as each level is a prerequisite for the next.
local function save_pattern(name, list_name, patterns)
track(tracking_page)
name = type(name) == "string" and gsub(name, "\1", "") or name
if calling_module then
if match(list_name, "\1") then
track(tracking_page .. "/" .. calling_module)
patterns["^" .. gsub(pattern_escape(list_name), "\1", "([1-9]%%d*)") .. "$"] = name
if calling_function then
else
track(tracking_page .. "/" .. calling_module .. "/" .. calling_function)
patterns["^" .. pattern_escape(list_name) .. "([1-9]%d*)$"] = name
if param_name then
end
track(tracking_page .. "/" .. calling_module .. "/" .. calling_function .. "/" .. param_name)
end
 
local function concat_list(list, conjunction, dump_vals)
if dump_vals then
for i = 1, #list do
list[i] = dump(list[i])
end
end
return list_to_text(list, nil, conjunction)
return true
end
 
local function check_set(val, name, param)
function export.process(args, params, return_unknown, calling_module, calling_function)
if not param.set[val] then
local args_new = {}
local list = {}
for k in pairs(param.set) do
if not calling_module then
insert(list, dump(k))
track("no calling module")
end
sort(list)
if not calling_function then
-- If the parameter is not required then put "or empty" at the end of the list, to avoid implying the parameter is actually required.
track("no calling function", calling_module)
if not param.required then
insert(list, "empty")
end
error("Parameter " .. dump(name) .. " must be " .. (#param.set > 1 and "either " or "") .. concat_list(list, " or ") .. "; the value " .. dump(val) .. " is not valid.")
end
end
 
local get_val = setmetatable({
["boolean"] = function(val)
-- Set makes no sense with booleans, so don't bother checking for it.
return yesno(val, true)
end,
["family"] = function(val, name, param)
if param.set then
check_set(val, name, param)
end
return require("Module:families")[param.method == "name" and "getByCanonicalName" or "getByCode"](val) or
error("Parameter " .. dump(name) .. " should be a valid family " .. (param.method == "name" and "name" or "code") .. "; the value " .. dump(val) .. " is not valid. See [[WT:LOF]].")
end,
["language"] = function(val, name, param)
if param.set then
check_set(val, name, param)
end
local lang = require("Module:languages")[param.method == "name" and "getByCanonicalName" or "getByCode"](val, nil, param.etym_lang, param.family)
if lang then
return lang
end
local list = {"language"}
local links = {"[[WT:LOL]]"}
if param.etym_lang then
insert(list, "etymology language")
insert(links, "[[WT:LOL/E]]")
end
if param.family then
insert(list, "family")
insert(links, "[[WT:LOF]]")
end
error("Parameter " .. dump(name) .. " should be a valid " .. concat_list(list, " or ") .. " " .. (param.method == "name" and "name" or "code") .. "; the value " .. dump(val) .. " is not valid. See " .. concat_list(links, " and ") .. ".")
end,
["number"] = function(val, name, param)
if type(val) == "number" then
return val
end
-- Avoid converting inputs like "nan" or "inf".
val = tonumber(val:match("^[+%-]?%d+%.?%d*")) or
error("Parameter " .. dump(name) .. " should be a valid number; the value " .. dump(val) .. " is not valid.")
if param.set then
check_set(val, name, param)
end
return val
end,
["script"] = function(val, name, param)
if param.set then
check_set(val, name, param)
end
return require("Module:scripts")[param.method == "name" and "getByCanonicalName" or "getByCode"](val) or
error("Parameter " .. dump(name) .. " should be a valid script " .. (param.method == "name" and "name" or "code") .. "; the value " .. dump(val) .. " is not valid. See [[WT:LOS]].")
end,
["string"] = function(val, name, param)
if param.set then
check_set(val, name, param)
end
return val
end,
["wikimedia language"] = function(val, name, param)
if param.set then
check_set(val, name, param)
end
return require("Module:wikimedia languages").getByCode(val) or
error("Parameter " .. dump(name) .. " should be a valid wikimedia language code; the value " .. dump(val) .. " is not valid.")
end,
}, {
__call = function(self, val, name, param)
local func, sublist = self[param.type or "string"], param.sublist
if not func then
error(dump(param.type) .. " is not a recognized parameter type.")
elseif sublist then
local ret_val = {}
for v in gsplit(val, sublist == true and "%s*,%s*" or sublist) do
insert(ret_val, func(v, name, param))
end
return ret_val
else
return func(val, name, param)
end
end
})
 
function export.process(args, params, return_unknown)
-- Process parameters for specific properties
local args_new = {}
local required = {}
local seen = {}
local patterns = {}
local names_with_equal_sign = {}
local list_from_index = nil
for name, param in pairs(params) do
-- Populate required table, and make sure aliases aren't set to required.
if param.required then
if param.alias_of then
error("`params` table error: parameter " .. dump(name) .. " is an alias of " .. dump(param.alias_of) .. ", but is also set as a required parameter. Only " .. dump(name) .. " should be set as required.")
track("required alias", calling_module, calling_function, name)
end
required[name] = true
end
-- Convert param.set from a list into a set.
if name == 1 and param.no_lang_code then
-- `seen` prevents double-conversion if multiple parameter keys share the same param table.
if not params["notlangcode"] then
local set = param.set
error("The parameter \"notlangcode\" must be enabled for this template.", 2)
if set and not seen[param] then
elseif not args["notlangcode"] and require("Module:languages").getByCode(args[name]) then
param.set = list_to_set(set)
error("The parameter \"" .. name .. "\" should not be a language code.", 2)
seen[param] = true
end
local alias = param.alias_of
if alias then
-- Check that the alias_of is set to a valid parameter.
if not params[alias] then
error("`params` table error: parameter " .. dump(name) .. " is an alias of an invalid parameter.")
end
-- Check that all the parameters in params are in the form Scribunto normalizes input argument keys into (e.g. 1 not "1", "foo" not " foo "). Otherwise, this function won't be able to normalize the input arguments in the expected way.
local normalized = scribunto_param_key(alias)
if alias ~= normalized then
error("`params` table error: parameter " .. dump(alias) .. " (a " .. type(alias) .. ") given in the alias_of field of parameter " .. dump(name) .. " is not a normalized Scribunto parameter. Should be " .. dump(normalized) .. " (a " .. type(normalized) .. ").")
-- Aliases can't be lists unless the canonical parameter is also a list.
elseif param.list and not params[alias].list then
error("`params` table error: the list parameter " .. dump(name) .. " is set as an alias of " .. dump(alias) .. ", which is not a list parameter.")
-- Aliases can't be aliases of other aliases.
elseif params[alias].alias_of then
error("`params` table error: alias_of cannot be set to another alias: parameter " .. dump(name) .. " is set as an alias of " .. dump(alias) .. ", which is in turn an alias of " .. dump(params[alias].alias_of) .. ". Set alias_of for " .. dump(name) .. " to " .. dump(params[alias].alias_of) .. ".")
end
end
local normalized = scribunto_param_key(name)
if name ~= normalized then
error("`params` table error: parameter " .. dump(name) .. " (a " .. type(name) .. ") is not a normalized Scribunto parameter. Should be " .. dump(normalized) .. " (a " .. type(normalized) .. ").")
end
if param.list then
if not param.alias_of then
-- A helper function to escape magic characters in a string
local key = name
-- Magic characters: ^$()%.[]*+-?
local if plaintype(name) == require("Module:string/pattern_escape") then
key = gsub(name, "\1", "")
 
end
local key = name
-- _list is used as a temporary flag.
if type(name) == "string" then
args_new[key] = string.gsub(name,{maxindex "=" 0, "")_list = true}
end
if param.default ~= nil then
args_new[key] = {param.default, maxindex = 1}
else
args_new[key] = {maxindex = 0}
end
Line ၇၀ ⟶ ၂၁၃:
-- where the first item is a numbered parameter and the
-- subsequent ones are named, such as 1, pl2, pl3.
ifsave_pattern(name, string.find(param.list, "="patterns) then
elseif type(name) == "number" then
patterns["^" .. string.gsub(plain(param.list), "=", "(%%d+)") .. "$"] = name
if list_from_index then
else
error("`params` table error: only one numeric parameter can be a list, unless the list property is a string.")
patterns["^" .. plain(param.list) .. "(%d+)$"] = name
end
elseif type(name) == "number" then
-- If the name is a number, then all indexed parameters from
-- this number onwards go in the list.
list_from_index = name
else
if string.findsave_pattern(name, "=")name, thenpatterns)
patterns["^" .. string.gsub(plain(name), "=", "(%%d+)") .. "$"] = string.gsub(name, "=", "")
else
patterns["^" .. plain(name) .. "(%d+)$"] = name
end
end
if string.findmatch(name, "=\1") then
insert(names_with_equal_sign, name)
-- DO NOT SIDE-EFFECT A TABLE WHILE ITERATING OVER IT.
-- Some elements may be skipped or processed twice if you do.
-- Instead, track the changes we want to make to `params`, and
-- do them after the iteration over `params` is done.
table.insert(names_with_equal_sign, name)
end
elseif param.default ~= nil then
args_new[name] = param.default
end
end
 
--Process required changes to `params`.
for i = 1, #names_with_equal_sign do
if #names_with_equal_sign > 0 then
local name = names_with_equal_sign[i]
local m_params_data = calling_module and mw.loadData("Module:parameters/data")[calling_module]
params[gsub(name, "\1", "")] = params[name]
-- If there is a ready-made version in the data module, use that.
params[name] = nil
if m_params_data and m_params_data[calling_function .. "_no_equals"] then
params = m_params_data[calling_function .. "_no_equals"]
-- Otherwise, shallow copy the params table and substitute the keys.
else
params = require("Module:table").shallowcopy(params)
for _, name in ipairs(names_with_equal_sign) do
track("name with equals", calling_module, calling_function, name)
params[string.gsub(name, "=", "")] = params[name]
params[name] = nil
end
end
end
 
-- Process the arguments
local args_unknown = {}
Line ၁၂၁ ⟶ ၂၄၃:
for name, val in pairs(args) do
local orig_name, raw_type, index, normalized = nilname, type(name)
if type(name)raw_type == "number" then
if list_from_index ~= nil and name >= list_from_index then
index = name - list_from_index + 1
Line ၁၃၁ ⟶ ၂၅၃:
-- Does this argument name match a pattern?
for pattern, pname in pairs(patterns) do
index = mw.ustring.match(name, pattern)
-- It matches, so store the parameter name and the
-- numeric index extracted from the argument name.
Line ၁၄၅ ⟶ ၂၆၆:
local param = params[name]
if param and param.require_index then
-- If a parameter without the trailing index was found, and
-- Disallow require_index isfor setnumeric onparameter the paramnames, set the param toas nilthis todoesn't treatmake itsense.
if raw_type == "number" then
-- as if it isn't recognized.
error("`params` table error: cannot set require_index for numeric parameter " .. dump(name) .. ".")
if not index and param and param.require_index then
-- If a parameter without the trailing index was found, and
param = nil
-- require_index is set on the param, set the param to nil to treat it
-- as if it isn't recognized.
elseif not index then
param = nil
end
end
-- If no index was found, use 1 as the default index.
-- This makes list parameters like g, g2, g3 put g at index 1.
-- If `separate_no_index` is set, then use 0 as the default instead.
index = index or (param and param.separate_no_index and 0) or 1
-- If the argument is not in the list of parameters, trigger an error.
Line ၁၆၃ ⟶ ၂၈၄:
args_unknown[name] = val
else
error("TheParameter parameter \"" .. dump(name) .. "\" is not used by this template.", 2)
end
else
-- Check that separate_no_index is not being used with a numeric parameter.
if param.separate_no_index then
if raw_type == "number" then
error("`params` table error: cannot set separate_no_index for numeric parameter " .. dump(name) .. ".")
elseif type(param.alias_of) == "number" then
error("`params` table error: cannot set separate_no_index for parameter " .. dump(name) .. ", as it is an alias of numeric parameter " .. dump(param.alias_of) .. ".")
end
end
-- If no index was found, use 1 as the default index.
-- This makes list parameters like g, g2, g3 put g at index 1.
-- If `separate_no_index` is set, then use 0 as the default instead.
if param.list then
index = index or param.separate_no_index and 0 or 1
end
-- Normalize to the canonical parameter name. If it's a list, but the alias is not, then determine the index.
local raw_name = param.alias_of
if param.alias_of then
raw_type = type(raw_name)
if raw_type == "number" then
if params[raw_name].list then
index = index or param.separate_no_index and 0 or 1
normalized = raw_name + index - 1
else
normalized = raw_name
end
name = raw_name
else
name = gsub(raw_name, "\1", "")
if params[name].list then
index = index or param.separate_no_index and 0 or 1
end
if not index or index == 0 then
normalized = name
elseif name == raw_name then
normalized = name .. index
else
normalized = gsub(raw_name, "\1", index)
end
end
else
normalized = orig_name
end
-- Remove leading and trailing whitespace unless allow_whitespace is true.
if not param.allow_whitespace then
val = mw.text.trim(val)
end
Line ၁၇၅ ⟶ ၃၄၁:
val = nil
-- Track empty parameters, unless (1) allow_empty is set or (2) they're numbered parameters where a higher numbered parameter is also in use (e.g. track {{l|en|term|}}, but not {{l|en||term}}).
if type(name)raw_type == "number" and not max_index then
-- Find the highest numbered parameter that's in use/an empty string, as we don't want parameters like 500= to mean we can't track any empty parameters with a lower index than 500.
local max_contiguous_indexn = 0
while args[max_contiguous_indexn + 1] do
max_contiguous_indexn = max_contiguous_indexn + 1
end
max_index = 0
if max_contiguous_index > 0 then
for name,n val= inn, 1, pairs(args)-1 do
if args[n] ~= "" then
if type(name) == "number" and name > 0 and name <= max_contiguous_index and ((not max_index) or name > max_index) and val ~= "" then
max_index = namen
endbreak
end
end
max_index = max_index or 0
end
if type(name)raw_type ~= "number" or name > max_index then
-- Disable this for now as it causes slowdowns on large pages like [[a]].
track("empty parameter", calling_module, calling_function, name)
-- track("empty parameter")
end
end
-- Convert to proper type if necessary.
if param.type == "boolean" then
val = not (not val or val == "" or val == "0" or val == "no" or val == "n" or val == "false")
elseif param.type == "number" then
val = tonumber(val)
elseif param.type then
track("unrecognized type", calling_module, calling_function, name)
track("unrecognized type/" .. tostring(param.type), calling_module, calling_function, name)
end
-- Can't use "if val" alone, because val may be a boolean false.
if val ~= nil then
-- Convert to proper type if necessary.
val = get_val(val, orig_name, params[raw_name] or param)
-- Mark it as no longer required, as it is present.
required[param.alias_of or name] = nil
-- Store the argument value.
if param.listindex then
-- If the parameter is an alias of anotherduplicated, storethrow itan as the original,error.
if args_new[name][index] ~= nil then
-- but avoid overwriting it; the original takes precedence.
error("Parameter " .. dump(normalized) .. " has been entered more than once. This is probably because a list parameter has been entered without an index and with index 1 at the same time, or because a parameter alias has been used.")
if not param.alias_of then
end
args_new[name][index] = val
-- Store the highest index we find.
args_new[name].maxindex = math.max(index, args_new[name].maxindex)
if args_new[name][0] ~= nil then
args_new[name].default = args_new[name][0]
if args_new[name][0].maxindex == 0 nilthen
args_new[name].maxindex = 1
end
elseif args args_new[param.alias_ofname][0] == nil then
if params[param.alias_of] and params[param.alias_of].list then
end
args_new[param.alias_of][index] = val
if params[name].list then
-- Don't store index 0, as it's a proxy for the default.
if index > 0 then
args_new[name][index] = val
-- Store the highest index we find.
args_new[param.alias_ofname].maxindex = math.max(index, args_new[param.alias_ofname].maxindex)
else
args_new[param.alias_of] = val
end
else
args_new[name] = val
end
else
-- If the parameter is an alias of anotherduplicated, storethrow itan as the original,error.
if args_new[name] ~= nil then
-- but avoid overwriting it; the original takes precedence.
error("Parameter " .. dump(normalized) .. " has been entered more than once. This is probably because a parameter alias has been used.")
end
if not param.alias_of then
args_new[name] = val
else
elseif args[param.alias_of] == nil then
if params[param.alias_of] and params[param.alias_of].list then
args_new[param.alias_of][1] = val
-- Store the highest index we find.
args_new[param.alias_of].maxindex = math.max(1, args_new[param.alias_of].maxindex)
else
args_new[param.alias_of] = val
Line ၂၄၉ ⟶ ၄၁၇:
end
end
end
end
end
-- Remove holes in any list parameters if needed.
for name, val in pairs(args_new) do
if type(val) == "table" and val._list then
if params[name].disallow_holes then
local highest = 0
for num, _ in pairs(val) do
if type(num) == "number" and num > 0 and num < huge and floor(num) == num then
highest = max(highest, num)
end
end
for i = 1, highest do
if val[i] == nil then
error(("For %s=, saw hole at index %s; disallowed because `disallow_holes` specified"):format(name, i))
end
end
-- Some code depends on only numeric params being present when no holes are allowed (e.g. by checking for the
-- presence of arguments using next()), so remove `maxindex`.
val.maxindex = nil
elseif not params[name].allow_holes then
args_new[name] = remove_holes(val)
end
end
end
-- Handle defaults.
for name, param in pairs(params) do
if param.default ~= nil then
local arg_new = args_new[name]
if type(arg_new) == "table" and arg_new._list then
if arg_new[1] == nil then
arg_new[1] = get_val(param.default, name, param)
end
if arg_new.maxindex == 0 then
arg_new.maxindex = 1
end
arg_new._list = nil
elseif arg_new == nil then
args_new[name] = get_val(param.default, name, param)
end
end
Line ၂၅၇ ⟶ ၄၆၇:
if mw.title.getCurrentTitle().namespace ~= 10 then
local list = {}
for name, param in pairs(required) do
table.insert(list, dump(name))
end
iflocal n = #list > 0 then
if n > 0 then
error('The parameters "' .. mw.text.listToText(list, '", "', '" and "') .. '" are required.', 2)
error("Parameter" .. (
n == 1 and (" " .. list[1] .. " is") or
("s " .. concat_list(list, " and ", true) .. " are")
) .. " required.", 2)
end
end
-- Remove holesthe intemporary any_list list parameters if neededflag.
for name_, valarg_new in pairs(args_new) do
if type(valarg_new) == "table" and not params[name].allow_holes then
arg_new._list = nil
args_new[name] = require("Module:parameters/remove_holes")(val)
end
end