Модуль:GetField: различия между версиями
Pok (обсуждение | вклад) Нет описания правки |
Pok (обсуждение | вклад) мНет описания правки |
||
| (не показано 20 промежуточных версий этого же участника) | |||
| Строка 4: | Строка 4: | ||
local getArgs = require('Module:Arguments').getArgs | local getArgs = require('Module:Arguments').getArgs | ||
function p.loadCachedData(pagePath) | |||
local | local titleName = JsonPaths.get(pagePath) | ||
if not | if not titleName or titleName == "" then | ||
return nil | return nil | ||
end | end | ||
return | |||
local ok, data = pcall(mw.loadData, titleName) | |||
if not ok or type(data) ~= "table" then | |||
return nil | |||
end | |||
return data | |||
end | end | ||
| Строка 90: | Строка 96: | ||
local function format_value(v) | local function format_value(v) | ||
if v == nil then | if v == nil then | ||
return " | return "" | ||
end | end | ||
| Строка 146: | Строка 152: | ||
end | end | ||
function p.ucfirst(s) | |||
if type( | if not s or s == "" then return s end | ||
return string.upper(s:sub(1, 1)) .. (s:sub(2) or "") | |||
end | |||
function p.normalizeComponentName(name) | |||
if type(name) ~= "string" or name == "" then | |||
return nil | |||
end | |||
name = mw.text.trim(name) | |||
if name:sub(1, 5) == "type:" then | |||
name = name:sub(6) | |||
elseif name:sub(1, 6) == "!type:" then | |||
name = name:sub(7) | |||
end | |||
if name == "" then | |||
return nil | return nil | ||
end | end | ||
return name | |||
end | |||
local function split_data_page_path(pagePath) | |||
local kind, name = string.match(pagePath or "", "^(component)/([^/]+)%.json$") | |||
if not kind then | |||
return nil, nil | |||
end | |||
return kind, p.ucfirst(name) | |||
end | |||
if | local function get_component_from_entity(entity, componentName) | ||
if type(entity) ~= "table" or type(entity.components) ~= "table" then | |||
return nil | |||
end | |||
return entity.components["type:" .. componentName] | |||
or entity.components[componentName] | |||
or entity.components["!type:" .. componentName] | |||
end | |||
local function load_specific_entry(pagePath, id, allowDefault) | |||
local kind, name = split_data_page_path(pagePath) | |||
if not kind or not id or id == "" then | |||
return nil | |||
end | |||
if kind ~= "component" then | |||
return nil | |||
end | |||
local base | |||
local defaultData = p.loadCachedData(kind .. "/" .. name .. "/defaultFields.json") | |||
if type(defaultData) == "table" then | |||
base = deep_copy(defaultData) | |||
end | |||
local entityPage = "prototype/Entity/" .. id .. ".json" | |||
local entity = p.loadCachedData(entityPage) | |||
local specific = get_component_from_entity(entity, name) | |||
if type(specific) ~= "table" then | |||
if allowDefault == false then | |||
return nil | |||
end | end | ||
return base | |||
end | end | ||
if base then | |||
deep_merge(base, specific) | |||
return base | return base | ||
end | end | ||
return | return specific | ||
end | end | ||
local function | local function resolve_entry_from_data(data, id, allowDefault) | ||
if type(data) ~= "table" then | if type(data) ~= "table" then | ||
return | return nil | ||
end | end | ||
local | if id and id ~= "" then | ||
local direct = data[id] | |||
if direct ~= nil then | |||
return direct | |||
end | |||
local idsTable = data.id | |||
if type(idsTable) == "table" then | |||
local specific = idsTable[id] | |||
if type(specific) == "table" then | |||
local base = data["default"] | |||
if type(base) == "table" then | |||
local merged = deep_copy(base) | |||
deep_merge(merged, specific) | |||
return merged | |||
end | |||
return specific | |||
end | |||
end | end | ||
end | end | ||
if allowDefault == false then | |||
return nil | |||
end | |||
local base = data["default"] | |||
if type(base) == "table" then | |||
return base | |||
end | end | ||
return | return nil | ||
end | end | ||
local function | local function load_entry(id, pagePath, data, allowDefault) | ||
local specificPageEntry = load_specific_entry(pagePath, id, allowDefault) | |||
return | if specificPageEntry ~= nil then | ||
return specificPageEntry | |||
end | end | ||
for | data = data or p.loadCachedData(pagePath) | ||
if allowDefault == nil then | |||
allowDefault = true | |||
end | |||
return resolve_entry_from_data(data, id, allowDefault) | |||
end | |||
local function collect_id_keys(data) | |||
if type(data) ~= "table" then | |||
return {} | |||
end | |||
local idsTable = data.id | |||
local ids = {} | |||
if type(idsTable) == "table" then | |||
for k in pairs(idsTable) do | |||
ids[#ids + 1] = k | |||
end | |||
return ids | |||
end | |||
for k in pairs(data) do | |||
if k ~= "default" and k ~= "id" then | |||
ids[#ids + 1] = k | |||
end | end | ||
end | end | ||
return | return ids | ||
end | end | ||
local function | local function contains_target(v, target) | ||
if v == | if type(v) == "string" then | ||
return | return v == target | ||
end | end | ||
if type(v) == "table" then | if type(v) == "table" then | ||
return | if is_array(v) then | ||
for _, item in ipairs(v) do | |||
if tostring(item) == target then | |||
return true | |||
end | |||
end | |||
return false | |||
end | |||
for _, item in pairs(v) do | |||
if tostring(item) == target then | |||
return true | |||
end | |||
end | |||
return false | |||
end | end | ||
return | |||
return tostring(v) == target | |||
end | end | ||
local function preprocess_or_return(frame, text) | local function is_nonempty_value(v) | ||
if v == nil then | |||
return false | |||
end | |||
if type(v) == "table" then | |||
return next(v) ~= nil | |||
end | |||
return true | |||
end | |||
local function preprocess_or_return(frame, text) | |||
if type(frame) == "table" and type(frame.preprocess) == "function" then | if type(frame) == "table" and type(frame.preprocess) == "function" then | ||
return frame:preprocess(text) | return frame:preprocess(text) | ||
| Строка 413: | Строка 510: | ||
end | end | ||
local function build_tpl(id, pagePath, tplPath, data, tplArgs, preEntry) | local function build_tpl(id, pagePath, tplPath, data, tplArgs, preEntry, strictExact) | ||
if id == "" or pagePath == "" or tplPath == "" then | if id == "" or pagePath == "" or tplPath == "" then | ||
return "" | return "" | ||
end | end | ||
local | local entry | ||
if strictExact then | |||
if | entry = load_entry(id, pagePath, data, false) | ||
else | |||
entry = preEntry or load_entry(id, pagePath, data) | |||
end | |||
if entry == nil then | |||
return "" | return "" | ||
end | end | ||
local extra = flatten_entry(entry) | local extra = flatten_entry(entry) | ||
local extraTplArgs = tplArgs or "" | local extraTplArgs = tplArgs or "" | ||
| Строка 447: | Строка 548: | ||
local searchId = args[1] or "" | local searchId = args[1] or "" | ||
local kind = (args[2] or ""):lower() | local kind = (args[2] or ""):lower() | ||
local fieldId = args[3] or "" | local fieldId = p.ucfirst(args[3] or "") | ||
if searchId == "" or fieldId == "" then | if searchId == "" or fieldId == "" then | ||
| Строка 457: | Строка 558: | ||
local storeName = (kind == "prototype") and "prototype_store.json" or "component_store.json" | local storeName = (kind == "prototype") and "prototype_store.json" or "component_store.json" | ||
local | local data = p.loadCachedData(storeName) | ||
if not data then | if not data then | ||
return "" | return "" | ||
| Строка 494: | Строка 594: | ||
end | end | ||
local entry = load_entry(id, pagePath) or {} | |||
local entry = | |||
return flatten_entry(entry) | return flatten_entry(entry) | ||
end | end | ||
| Строка 518: | Строка 612: | ||
end | end | ||
local entry = load_entry(id, pagePath) or {} | |||
local entry = | |||
local parts = flatten_selected_parts(entry, keys) | local parts = flatten_selected_parts(entry, keys) | ||
if #parts == 0 then | if #parts == 0 then | ||
| Строка 543: | Строка 631: | ||
end | end | ||
local entry = load_entry(id, pagePath) | |||
local entry = | |||
if entry == nil then | if entry == nil then | ||
return "" | return "" | ||
| Строка 646: | Строка 728: | ||
return false | return false | ||
end | |||
local function split_csv_list(text) | |||
text = mw.text.unstripNoWiki(text or "") | |||
local out = {} | |||
for part in string.gmatch(text, "([^,]+)") do | |||
part = mw.text.trim(part) | |||
if part ~= "" then | |||
out[#out + 1] = part | |||
end | |||
end | |||
return out | |||
end | end | ||
| Строка 662: | Строка 758: | ||
end | end | ||
local | local data = p.loadCachedData(pagePath) | ||
if not data then | if not data then | ||
return "[]" | return "[]" | ||
| Строка 682: | Строка 777: | ||
for _, idKey in ipairs(ids) do | for _, idKey in ipairs(ids) do | ||
local entry = | local entry = resolve_entry_from_data(data, idKey) | ||
if type(entry) == "table" and entry_matches_path(entry, parsedPath, target, searchType) then | if type(entry) == "table" and entry_matches_path(entry, parsedPath, target, searchType) then | ||
matches[#matches + 1] = idKey | matches[#matches + 1] = idKey | ||
| Строка 700: | Строка 795: | ||
end | end | ||
function | local function collect_ids_from_entry(entry) | ||
local | local out = {} | ||
local | local seen = {} | ||
if | local function add(v) | ||
if v == nil then | |||
return | |||
end | |||
local s = tostring(v) | |||
if s ~= "" and not seen[s] then | |||
seen[s] = true | |||
out[#out + 1] = s | |||
end | |||
end | end | ||
if | if type(entry) == "table" then | ||
if is_array(entry) then | |||
for _, v in ipairs(entry) do | |||
add(v) | |||
end | |||
else | |||
for _, v in pairs(entry) do | |||
if type(v) == "table" and is_array(v) then | |||
for _, item in ipairs(v) do | |||
add(item) | |||
end | |||
elseif type(v) ~= "table" then | |||
add(v) | |||
end | |||
end | |||
end | |||
else | |||
add(entry) | |||
end | end | ||
return out | |||
end | |||
function p.search(frame) | |||
local args = getArgs(frame, { removeBlanks = false }) | |||
local mode = (args[1] or ""):lower() | |||
local rawList = args[2] or "" | |||
if | if mode ~= "component" and mode ~= "tag" then | ||
return "" | return "" | ||
end | end | ||
if | |||
local targets = split_csv_list(rawList) | |||
if #targets == 0 then | |||
return "" | return "" | ||
end | end | ||
local | local pagePath = (mode == "component") and "component.json" or "tag.json" | ||
local data = | local data = p.loadCachedData(pagePath) | ||
if not data then | if not data then | ||
return "" | return "" | ||
end | end | ||
local | local matches = {} | ||
local seen = {} | |||
local function add_id(id) | |||
local s = tostring(id) | |||
if s ~= "" and not seen[s] then | |||
seen[s] = true | |||
matches[#matches + 1] = s | |||
end | |||
end | end | ||
for _, key in ipairs(targets) do | |||
local entry = resolve_entry_from_data(data, key) | |||
if entry ~= nil then | |||
local ids = collect_ids_from_entry(entry) | |||
for _, id in ipairs(ids) do | |||
add_id(id) | |||
end | end | ||
end | end | ||
end | end | ||
table.sort(matches, function(a, b) | |||
return | return tostring(a) < tostring(b) | ||
end | end) | ||
local | local ok, json = pcall(mw.text.jsonEncode, matches) | ||
if ok and json then | |||
return json | |||
end | end | ||
return "" | |||
end | end | ||
function p. | function p.searchIdTpl(frame) | ||
local args = getArgs(frame, { removeBlanks = false }) | local args = getArgs(frame, { removeBlanks = false }) | ||
local | local searchValue = args[1] or "" | ||
local pagePath = args[2] or "" | local pagePath = args[2] or "" | ||
local tplPath = mw.text.unstripNoWiki(args[ | local keyPath = args[3] or "" | ||
local tplArgs = | local tplPath = mw.text.unstripNoWiki(args[4] or "") | ||
local tplArgs = args.tplArgs or args.templateArgs or "" | |||
local searchType = (args.searchType or ""):lower() | |||
if | if searchType == "" then | ||
searchType = "value" | |||
end | |||
if searchType == "path" then | |||
searchValue = "" | |||
pagePath = args[1] or "" | |||
keyPath = args[2] or "" | |||
tplPath = mw.text.unstripNoWiki(args[3] or "") | |||
tplArgs = args[4] or args.tplArgs or args.templateArgs or "" | |||
end | |||
tplPath, tplArgs = split_template_spec(tplPath, tplArgs) | |||
if pagePath == "" or keyPath == "" or tplPath == "" then | |||
return "" | |||
end | |||
if searchType ~= "path" and searchValue == "" then | |||
return "" | return "" | ||
end | end | ||
local | local data = p.loadCachedData(pagePath) | ||
if not data then | if not data then | ||
return "" | |||
end | end | ||
if not | |||
local parsedPath = parse_path(keyPath) | |||
if not parsedPath then | |||
return "" | return "" | ||
end | end | ||
local | local ids = collect_id_keys(data) | ||
if #ids == 0 then | |||
if | |||
return "" | return "" | ||
end | end | ||
local | local matches = {} | ||
local | local entryCache = {} | ||
local | if searchType == "path" then | ||
local | for _, idKey in ipairs(ids) do | ||
local entry = resolve_entry_from_data(data, idKey) | |||
entryCache[idKey] = entry | |||
if type(entry) == "table" and entry_has_any_nonempty_path(entry, parsedPath) then | |||
matches[#matches + 1] = idKey | |||
end | |||
end | |||
else | |||
local target = tostring(searchValue) | |||
for _, idKey in ipairs(ids) do | |||
local entry = resolve_entry_from_data(data, idKey) | |||
entryCache[idKey] = entry | |||
if type(entry) == "table" and entry_matches_path(entry, parsedPath, target, searchType) then | |||
matches[#matches + 1] = idKey | |||
end | |||
end | |||
end | end | ||
if #matches == 0 then | |||
return "" | return "" | ||
end | end | ||
local out = {} | local out = {} | ||
for _, | for _, idKey in ipairs(matches) do | ||
local tpl = build_tpl( | local tpl = build_tpl(idKey, pagePath, tplPath, data, tplArgs, entryCache[idKey], true) | ||
if tpl ~= "" then | if tpl ~= "" then | ||
out[#out + 1] = tpl | out[#out + 1] = tpl | ||
end | end | ||
end | |||
if #out == 0 then | |||
return "" | |||
end | end | ||
| Строка 856: | Строка 973: | ||
end | end | ||
function p. | function p.getTpl(frame) | ||
return | local args = getArgs(frame, { removeBlanks = false }) | ||
end | local id = args[1] or "" | ||
local pagePath = args[2] or "" | |||
function p. | local tplPath = mw.text.unstripNoWiki(args[3] or "") | ||
local tplArgs = args[4] or args.tplArgs or args.templateArgs or "" | |||
tplPath, tplArgs = split_template_spec(tplPath, tplArgs) | |||
if id == "" or pagePath == "" or tplPath == "" then | |||
return "" | |||
end | |||
local data = frame.data | |||
local tplStr = build_tpl(id, pagePath, tplPath, data, tplArgs, nil, true) | |||
return preprocess_or_return(frame, tplStr) | |||
end | |||
function p.searchStoreTpl(frame) | |||
local args = getArgs(frame, { removeBlanks = false }) | local args = getArgs(frame, { removeBlanks = false }) | ||
local searchId = args[1] or "" | local searchId = args[1] or "" | ||
local kind = (args[2] or ""):lower() | local kind = (args[2] or ""):lower() | ||
local generatorId = args[3] or "" | local generatorId = p.ucfirst(args[3] or "") | ||
local tplPath = mw.text.unstripNoWiki(args[4] or "") | |||
local tplArgs = args[5] or args.tplArgs or args.templateArgs or "" | |||
tplPath, tplArgs = split_template_spec(tplPath, tplArgs) | |||
if searchId == "" or generatorId == "" then | if searchId == "" or generatorId == "" or tplPath == "" then | ||
return "" | return "" | ||
end | end | ||
| Строка 872: | Строка 1005: | ||
return "" | return "" | ||
end | end | ||
local dir = (kind == "prototype") and "prototype/" or "component/" | |||
local pagePath = dir .. generatorId .. ".json" | |||
local idsJson = p.findInGenerator({ args = { searchId, kind, generatorId } }) | local idsJson = p.findInGenerator({ args = { searchId, kind, generatorId } }) | ||
| Строка 879: | Строка 1015: | ||
end | end | ||
local | local data = p.loadCachedData(pagePath) | ||
if not data then | |||
return "" | |||
end | |||
local out = {} | |||
for _, id in ipairs(ids) do | |||
local entry = resolve_entry_from_data(data, id) | |||
if entry ~= nil then | |||
local tpl = build_tpl(id, pagePath, tplPath, data, tplArgs, entry, true) | |||
if tpl ~= "" then | |||
out[#out + 1] = tpl | |||
end | |||
end | |||
end | end | ||
local result = table.concat(out, " ") | |||
return preprocess_or_return(frame, result) | |||
end | |||
function p.flattenParams(entry) | |||
return flatten_parts(entry) | |||
end | end | ||
function p. | function p.searchStore(frame) | ||
local args = getArgs(frame, { removeBlanks = false }) | local args = getArgs(frame, { removeBlanks = false }) | ||
local | local searchId = args[1] or "" | ||
local | local kind = (args[2] or ""):lower() | ||
local generatorId = p.ucfirst(args[3] or "") | |||
if | if searchId == "" or generatorId == "" then | ||
return " | return "" | ||
end | |||
if kind ~= "prototype" and kind ~= "component" then | |||
return "" | |||
end | end | ||
local | local idsJson = p.findInGenerator({ args = { searchId, kind, generatorId } }) | ||
local | local ok, ids = pcall(mw.text.jsonDecode, idsJson or "") | ||
if not | if not ok or type(ids) ~= "table" or #ids == 0 then | ||
return " | return "" | ||
end | end | ||
local okOut, outJson = pcall(mw.text.jsonEncode, ids) | |||
return | if okOut and outJson then | ||
return outJson | |||
end | end | ||
return "" | |||
if | end | ||
return | |||
function p.loadEntityData(entityId) | |||
if entityId == "" then | |||
return nil | |||
end | end | ||
local pagePath = "prototype/Entity/" .. entityId .. ".json" | |||
return p.loadCachedData(pagePath) | |||
end | |||
function p.entityHasComponent(entity, compName) | |||
if type(entity) ~= "table" or type(entity.components) ~= "table" then | |||
return false | |||
end | end | ||
return " | return entity.components[compName] ~= nil | ||
or entity.components["type:" .. compName] ~= nil | |||
or entity.components["!type:" .. compName] ~= nil | |||
end | end | ||
function p. | function p.collectEntityComponents(entity) | ||
if type(entity) ~= "table" or type(entity.components) ~= "table" then | |||
return {} | |||
return | |||
end | end | ||
local | local out = {} | ||
local | local seen = {} | ||
local comps = entity.components | |||
local | if #comps > 0 then | ||
for _, v in ipairs(comps) do | |||
local name = p.normalizeComponentName(v) | |||
if name and not seen[name] then | |||
seen[name] = true | |||
out[#out + 1] = name | |||
end | |||
end | |||
else | |||
for k in pairs(comps) do | |||
local name = p.normalizeComponentName(k) | |||
if name and not seen[name] then | |||
seen[name] = true | |||
out[#out + 1] = name | |||
end | |||
end | |||
end | end | ||
table.sort(out) | |||
return out | |||
end | |||
function p.hasComp(frame) | |||
local args = getArgs(frame, { removeBlanks = false }) | |||
local entityId = args[1] or "" | |||
local compName = args[2] or "" | |||
if | if entityId == "" or compName == "" then | ||
return "false" | |||
return | |||
end | end | ||
local | local entity = p.loadEntityData(entityId) | ||
if | if not entity then | ||
return | return "false" | ||
end | end | ||
return "" | return p.entityHasComponent(entity, compName) and "true" or "false" | ||
end | end | ||
function p. | function p.getComp(frame) | ||
local args = getArgs(frame, { removeBlanks = false }) | |||
local entityId = args[1] or "" | |||
if entityId == "" then | |||
return "" | |||
end | |||
local entity = p.loadEntityData(entityId) | |||
if not entity then | |||
return "" | |||
end | |||
local out = p.collectEntityComponents(entity) | |||
local ok, json = pcall(mw.text.jsonEncode, out) | |||
if ok and json then | |||
return json | |||
end | |||
return "" | |||
end | |||
function p.getAll(frame) | |||
local args = getArgs(frame, { removeBlanks = false }) | local args = getArgs(frame, { removeBlanks = false }) | ||
local pagePath = args[1] or "" | local pagePath = args[1] or "" | ||
local | local replace = mw.text.unstripNoWiki(args.replace or "") | ||
local | local pattern = mw.text.unstripNoWiki(args.pattern or "(.*)") | ||
if pagePath | if pagePath == "" then | ||
return "" | return "" | ||
end | end | ||
local | local data = p.loadCachedData(pagePath) | ||
if not data then | if not data then | ||
return "" | return "" | ||
end | end | ||
local idsTable = data.id | local idsTable = data.id or data | ||
if type(idsTable) ~= "table" then | if type(idsTable) ~= "table" then | ||
return "" | return "" | ||
end | end | ||
local | local ids = {} | ||
for k in pairs(idsTable) do | |||
ids[#ids + 1] = k | |||
end | |||
table.sort(ids) | |||
for | if replace ~= "" then | ||
local out = {} | |||
for _, id in ipairs(ids) do | |||
local text = apply_pattern(id, pattern, replace) | |||
if text ~= "" then | |||
out[#out + 1] = text | |||
end | |||
end | |||
if #out == 0 then | |||
return "" | |||
end | end | ||
return preprocess_or_return(frame, table.concat(out, "\n")) | |||
end | end | ||
local ok, json = pcall(mw.text.jsonEncode, ids) | |||
if ok and json then | |||
return json | |||
end | |||
return "" | |||
end | end | ||
function p.getAllTpl(frame) | |||
local | local args = getArgs(frame, { removeBlanks = false }) | ||
if | local pagePath = args[1] or "" | ||
return " | local tplPath = args[2] or "" | ||
local tplArgs = args[3] or args.tplArgs or args.templateArgs or "" | |||
tplPath, tplArgs = split_template_spec(tplPath, tplArgs) | |||
if pagePath == "" or tplPath == "" then | |||
return "" | |||
end | end | ||
local data = p.loadCachedData(pagePath) | |||
local | if not data then | ||
return "" | |||
end | end | ||
local idsTable = data.id or data | |||
return | if type(idsTable) ~= "table" then | ||
end | return "" | ||
end | |||
local out = {} | |||
for idKey in pairs(idsTable) do | |||
local entry = resolve_entry_from_data(data, idKey) | |||
if entry ~= nil then | |||
if | local tpl = build_tpl(idKey, pagePath, tplPath, data, tplArgs, entry, true) | ||
if tpl ~= "" then | |||
out[#out + 1] = tpl | |||
end | |||
end | end | ||
end | end | ||
table.sort(out) | |||
table. | local result = table.concat(out, " ") | ||
return preprocess_or_return(frame, result) | |||
end | |||
local function encode_nowiki_json(value) | |||
local ok, json = pcall(mw.text.jsonEncode, value) | |||
if ok and json then | |||
return "<nowiki>" .. json .. "</nowiki>" | |||
end | |||
return nil | |||
end | |||
if | local function collect_sorted_keys(tbl, stringOnly) | ||
local keys = {} | |||
for k in pairs(tbl) do | |||
if not stringOnly or type(k) == "string" then | |||
keys[#keys + 1] = k | |||
end | end | ||
end | |||
table.sort(keys, function(a, b) | |||
return tostring(a) < tostring(b) | return tostring(a) < tostring(b) | ||
end) | end) | ||
return keys | return keys | ||
end | end | ||
local function | local function choose_id_key(obj) | ||
local keys = {} | |||
end | for k in pairs(obj) do | ||
if type(k) == "string" then | |||
keys[#keys + 1] = k | |||
end | |||
end | |||
if #keys == 0 then | |||
if | return nil | ||
return | |||
end | end | ||
table.sort(keys, function(a, b) | |||
local av = obj[a] | |||
return | local bv = obj[b] | ||
local aPrimitive = type(av) ~= "table" | |||
local bPrimitive = type(bv) ~= "table" | |||
if aPrimitive ~= bPrimitive then | |||
return not aPrimitive | |||
end | end | ||
return true | return tostring(a) < tostring(b) | ||
end) | |||
return keys[1] | |||
end | |||
local function is_wrapper_block_key(key) | |||
return type(key) == "string" and not key:match("^[%a_][%w_]*$") | |||
end | |||
local function is_array_of_primitives(tbl) | |||
if type(tbl) ~= "table" or not is_array(tbl) then | |||
return false | |||
end | |||
for _, v in ipairs(tbl) do | |||
if type(v) == "table" then | |||
return false | |||
end | |||
end | |||
return true | |||
end | end | ||
| Строка 1299: | Строка 1535: | ||
local pairPattern = mw.text.unstripNoWiki(args.pattern or "(.*)") | local pairPattern = mw.text.unstripNoWiki(args.pattern or "(.*)") | ||
local pairReplace = mw.text.unstripNoWiki(args.replace or "\\1") | local pairReplace = mw.text.unstripNoWiki(args.replace or "\\1") | ||
local maxItems = tonumber(args.max or args.limit or args.max_count or args.maxCount or "") | |||
if maxItems ~= nil then | |||
maxItems = math.floor(maxItems) | |||
if maxItems < 0 then | |||
maxItems = nil | |||
end | |||
end | |||
local out = {} | local out = {} | ||
if is_array(data) then | if is_array(data) then | ||
local processed = 0 | |||
for _, v in ipairs(data) do | for _, v in ipairs(data) do | ||
processed = processed + 1 | |||
if maxItems ~= nil and processed > maxItems then | |||
break | |||
end | |||
local text = "" | local text = "" | ||
| Строка 1324: | Строка 1575: | ||
text = apply_pattern(text, patt, repl) | text = apply_pattern(text, patt, repl) | ||
local line | local line | ||
if outputType == "enum" then | if outputType == "enum" then | ||
line = text | line = text | ||
else | else | ||
line = bullet .. text | line = bullet .. text | ||
end | end | ||
if pairPattern ~= "" then | if pairPattern ~= "" then | ||
line = apply_pattern(line, pairPattern, pairReplace) | line = apply_pattern(line, pairPattern, pairReplace) | ||
end | end | ||
table.insert(out, line) | table.insert(out, line) | ||
end | |||
end | |||
else | |||
local keys = {} | |||
for k in pairs(data) do | |||
keys[#keys + 1] = k | |||
end | |||
table.sort(keys, function(a, b) | |||
return tostring(a) < tostring(b) | |||
end) | |||
local processed = 0 | |||
for _, k in ipairs(keys) do | |||
processed = processed + 1 | |||
if maxItems ~= nil and processed > maxItems then | |||
break | |||
end | end | ||
local v = data[k] | local v = data[k] | ||
local vStr | local vStr | ||
| Строка 1409: | Строка 1667: | ||
end | end | ||
local entry = load_entry(id, dataPage) or {} | |||
local entry = | |||
local parts = flatten_selected_parts(entry, paramNames) | local parts = flatten_selected_parts(entry, paramNames) | ||
if #parts == 0 then | if #parts == 0 then | ||