Module:Issue list

local p = {}

p.i18n = { process_args_module = "Module:ProcessArgs", description_arg_prefix = nil, -- specify a string if you want to have separate parameters for descriptions of searched terms. -- Useful as terms are necessarily English, and users may want to have localized descriptions term_wrap = '"%s"', -- a string wrapped into quotes, for text output; quotes may be language-specific pair_separator = ", ", final_or_separator = ", or ", two_item_or_separator = " or ", -- the separators are used to concatenate tables to make strings like "A or B", "A, B, or C" message = 'Issues relating to %s are maintained on the bug tracker. Report issues there.' }

--[[ Concatenates a table using a set of separators. Behavior depends on which of the separators are provided.

Parameters: • some_table (sequence table): the table to concatenate; required • pair_sep (string; required), final_sep (string), two_sep (string): separators used in concatenation

If only `pair_sep` is provided, behaves like `table.concat(some_table, pair_sep)`.

If `final_sep` is also provided, it is used to separate the last pair of table entries.

If `two_sep` is also provided, it is used to separate the entries instead of `final_sep` if there are two of them.

Returns a string with the concatenated table.

Example:

``` local table1 = {"a", "b", "c"} local table2 = {"a", "b"}

print( concat_table_3sep(table1, ", ") ) -- prints "a, b, c" print( concat_table_3sep(table1, ", ", " and ") ) -- prints "a, b and c" print( concat_table_3sep(table1, ", ", ", and ", " and ") ) -- prints "a, b, and c"

print( concat_table_3sep(table2, ", ") ) -- prints "a, b" print( concat_table_3sep(table2, ", ", " and ") ) -- prints "a and b" print( concat_table_3sep(table2, ", ", ", and ", " and ") ) -- prints "a and b" ``` ]] function p.concat_table_3sep(some_table, pair_sep, final_sep, two_sep) local length = #some_table if length < 3 then local sep = two_sep or final_sep or pair_sep return table.concat(some_table, sep) end

local result_table = {} for index = 1, length - 2 do		table.insert(result_table, some_table[index]) table.insert(result_table, pair_sep) end table.insert(result_table, some_table[length - 1]) table.insert(result_table, final_sep or pair_sep) table.insert(result_table, some_table[length]) return table.concat(result_table) end

--[[ Similar to ipairs, but iterates over string keys with a constant prefix and a variable integer suffix.

Parameters: • some_table (table): the table to iterate over • prefix (string): the key prefix to use when iterating • allow_numberless (boolean, optional): if truthy, allows reading the key without an integer suffix as if it had the suffix 1. WARNING: behavior is unspecified if: 1) allow_numberless is truthy;     2) a key without an integer suffix is mapped to a value; 3) a key with integer suffix 1 is also mapped to a value.    In such cases, there is no guarantee on which of the two values is used.

Example: ``` local t = { a1 = 1, a2 = 4, a3 = 9 }

for index, value in prefixed_ipairs(t, "a") do	print(index, value) end ```

This prints ``` 1	1 2	4 3	9 ```

With `allow_numberless = true`, the above example would also work identically for the following table: ``` local t = { a = 1, a2 = 4, a3 = 9 } ```

However, with the following table, the example may print either 1 or 2 in the first line, depending on how prefixed_ipairs is currently implemented: ``` local t = { a = 1, a1 = 2, -- Don't do this! a2 = 4, a3 = 9 } ``` ]] function p.prefixed_ipairs(some_table, prefix, allow_numberless) local i = 0 return function i = i + 1 local value = some_table[prefix .. tostring(i)] if i == 1 and allow_numberless and some_table[prefix] ~= nil then value = some_table[prefix] end if value ~= nil then return i, value end end end

-- Helper functions -- Returns the human-readable description of search terms. local function get_subject_string(inclusions) local lang = mw.language.getContentLanguage local wrapped_inclusions = {} for index, inclusion in ipairs(inclusions) do		table.insert(wrapped_inclusions, p.i18n.term_wrap:format(lang:ucfirst(inclusion))) end return p.concat_table_3sep(		wrapped_inclusions,		p.i18n.pair_separator,		p.i18n.final_or_separator,		p.i18n.two_item_or_separator	) end

-- Returns the part of the query string that lists what items to query. local function get_query_string_inclusions(inclusions) local query_inclusions = {} for index, inclusion in ipairs(inclusions) do table.insert(query_inclusions, 'summary ~ "' .. inclusion .. '"') end return "(" .. table.concat(query_inclusions, ' or ') .. ")" end

-- Returns the part of the query string that removes certain items from the output. local function get_query_string_exclusions(exclusions) if #exclusions == 0 then return "" end local negated_exclusions = {} for index, exclusion in ipairs(exclusions) do table.insert(negated_exclusions, "-" .. exclusion) end local exclusions_string = table.concat(negated_exclusions, " ") return (' and summary ~ "%s"'):format(exclusions_string) end

-- Returns the query string for Mojira. local function get_query_string(inclusions_string, exclusions_string) local query_string = 'project in (MC, MCPE, MCCE) and (resolution is empty or resolution in (1, 2, 6))' .. exclusions_string .. " and " .. inclusions_string .. " order by resolution desc" return mw.uri.encode(query_string, "PATH") end

-- Main functions and entry points - p.issue_list = function(descriptions, inclusions, exclusions) local subject_string = get_subject_string(descriptions or inclusions) local inclusions_string = get_query_string_inclusions(inclusions) local exclusions_string = get_query_string_exclusions(exclusions) local query_string = get_query_string(inclusions_string, exclusions_string) local message = p.i18n.message:format(subject_string, query_string) return message end

-- Entry point for Template:Issue list. p.issue_list_entry = function(frame) local args = require(p.i18n.process_args_module).norm local inclusions = {} local exclusions = {} for _, arg in ipairs(args) do		if arg:find("^-") then table.insert(exclusions, (arg:gsub("-", ""))) else table.insert(inclusions, arg) end end if #inclusions == 0 then inclusions[1] = mw.title.getCurrentTitle.text end local descriptions if p.i18n.description_arg_prefix then descriptions = {} for _, arg in p.prefixed_ipairs(args, p.i18n.description_arg_prefix, true) do			table.insert(descriptions, arg) end end if #descriptions == 0 then table.insert(descriptions, mw.title.getCurrentTitle.text) end return p.issue_list(descriptions, inclusions, exclusions) end

return p