Модуль:GetField: различия между версиями
Материал из Space Station 14 Вики
Pok (обсуждение | вклад) м Замена текста — «GeneratorTplId» на «getAllTpl» |
Pok (обсуждение | вклад) Нет описания правки |
||
| (не показано 8 промежуточных версий этого же участника) | |||
| Строка 1: | Строка 1: | ||
local p = {} | local p = {} | ||
local lang = mw.language.getContentLanguage() | |||
local JsonPaths = require('Module:JsonPaths') | local JsonPaths = require('Module:JsonPaths') | ||
local project = JsonPaths.project() | |||
local getArgs = require('Module:Arguments').getArgs | local getArgs = require('Module:Arguments').getArgs | ||
| Строка 352: | Строка 354: | ||
local moduleName = get_module_name(pagePath) | local moduleName = get_module_name(pagePath) | ||
data = data or load_cached_data(moduleName) | |||
if not data then | if not data then | ||
return "" | return "" | ||
| Строка 362: | Строка 362: | ||
local extra = flatten_entry(entry) | local extra = flatten_entry(entry) | ||
local tplStr = "{{" .. | local templatePath = tplPath | ||
if project ~= nil and project ~= "" then | |||
templatePath = project .. ":" .. lang:ucfirst(tplPath) | |||
templatePath = "{{#ifexist:Шаблон:" .. templatePath .. "|" .. templatePath .. "|" .. tplPath .. "}}" | |||
end | |||
local tplStr = "{{Шаблон:" .. templatePath .. "|id=" .. tostring(id) | |||
if extra ~= "" then | if extra ~= "" then | ||
tplStr = tplStr .. "|" .. extra | tplStr = tplStr .. "|" .. extra | ||
| Строка 838: | Строка 844: | ||
local jsonStr = mw.text.unstripNoWiki(args[1] or args.json or "") | local jsonStr = mw.text.unstripNoWiki(args[1] or args.json or "") | ||
local tplPath = mw.text.unstripNoWiki(args[2] or args.template or "") | local tplPath = mw.text.unstripNoWiki(args[2] or args.template or "") | ||
if jsonStr == "" or tplPath == "" then | if jsonStr == "" or tplPath == "" then | ||
return "" | return "" | ||
| Строка 848: | Строка 855: | ||
local okDp, dp = pcall(require, "Module:GetField") | local okDp, dp = pcall(require, "Module:GetField") | ||
local calls = {} | |||
local | local projectPath = nil | ||
if project ~= nil and project ~= "" then | |||
projectPath = project .. ":" .. lang:ucfirst(tplPath) | |||
end | |||
local function makeTemplatePrefix() | |||
if projectPath then | |||
return "{{Шаблон:{{#ifexist:Шаблон:" .. projectPath .. "|" .. projectPath .. "|" .. tplPath .. "}}" | |||
end | |||
return "{{" .. tplPath | |||
end | |||
local function makeCall(id, obj) | local function makeCall(id, obj) | ||
| Строка 856: | Строка 875: | ||
end | end | ||
local parts = { | local parts = { makeTemplatePrefix(), "id=" .. id } | ||
if type(obj) == "table" then | if type(obj) == "table" then | ||
Текущая версия от 13:34, 25 марта 2026
Для документации этого модуля может быть создана страница Модуль:GetField/doc
local p = {}
local lang = mw.language.getContentLanguage()
local JsonPaths = require('Module:JsonPaths')
local project = JsonPaths.project()
local getArgs = require('Module:Arguments').getArgs
local function get_module_name(pagePath)
return JsonPaths.get(pagePath)
end
local function load_cached_data(moduleName)
local ok, loaded = pcall(mw.loadData, moduleName)
if not ok or not loaded then
return nil
end
return loaded
end
local function parse_indexed_part(part)
local key, idx = string.match(part, "^(.-)%[(%d+)%]$")
if key then
return key, tonumber(idx)
end
local num = tonumber(part)
if num then
return nil, num
end
return part, nil
end
local function get_by_path(tbl, path)
if not tbl or path == "" then
return nil
end
local cur = tbl
for part in string.gmatch(path, "([^%.]+)") do
local key, idx = parse_indexed_part(part)
if key and key ~= "" then
if type(cur) ~= "table" then
return nil
end
local nextCur = cur[key]
if nextCur == nil then
nextCur = cur["!type:" .. key]
end
cur = nextCur
end
if idx then
if type(cur) ~= "table" then
return nil
end
cur = cur[idx]
end
if cur == nil then
return nil
end
end
return cur
end
local function format_value(v)
local okJson, json = pcall(mw.text.jsonEncode, v)
if okJson and json == "null" then
return "null"
end
if v == nil then
return ""
end
local t = type(v)
if t == "string" or t == "number" or t == "boolean" then
return tostring(v)
elseif t == "table" then
local ok, json2 = pcall(mw.text.jsonEncode, v)
if ok and json2 then
return json2
end
return ""
else
return tostring(v)
end
end
local function to_nowiki(v)
return "<nowiki>" .. v .. "</nowiki>"
end
local function is_array(tbl)
local max = 0
local count = 0
for k in pairs(tbl) do
if type(k) ~= "number" then
return false
end
if k > max then
max = k
end
count = count + 1
end
return count > 0 and max == count
end
local function deep_copy(src)
local dst = {}
for k, v in pairs(src) do
if type(v) == "table" then
dst[k] = deep_copy(v)
else
dst[k] = v
end
end
return dst
end
local function deep_merge(dst, src)
for k, v in pairs(src) do
if type(v) == "table" and type(dst[k]) == "table" then
deep_merge(dst[k], v)
elseif type(v) == "table" then
dst[k] = deep_copy(v)
else
dst[k] = v
end
end
end
local function resolve_entry(data, id)
if type(data) ~= "table" then
return nil
end
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 deep_copy(specific)
end
end
end
local base = data["default"]
if type(base) == "table" then
return deep_copy(base)
end
return nil
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
return ids
end
local function contains_target(v, target)
if type(v) == "table" then
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
return tostring(v) == target
end
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 find_matching_ids(idsTable, keyPath, searchValue)
local target = tostring(searchValue)
local matches = {}
for idKey, entry in pairs(idsTable) do
if type(entry) == "table" then
local v = get_by_path(entry, keyPath)
if v ~= nil and contains_target(v, target) then
matches[#matches + 1] = idKey
end
end
end
return matches
end
local function preprocess_or_return(frame, text)
if type(frame) == "table" and type(frame.preprocess) == "function" then
return frame:preprocess(text)
end
return text
end
local function get_field_loose(entry, fieldId)
local value = entry[fieldId]
if value ~= nil then
return value
end
if fieldId == "" then
return nil
end
local first = string.sub(fieldId, 1, 1)
local tail = string.sub(fieldId, 2)
value = entry[string.lower(first) .. tail]
if value ~= nil then
return value
end
return entry[string.upper(first) .. tail]
end
local function apply_pattern(s, pattern, repl)
if not pattern or pattern == "" or not s then
return s
end
local text = tostring(s)
local replacement
if repl and repl ~= "" then
replacement = tostring(repl)
replacement = replacement:gsub("\\(%d)", "%%%1")
else
replacement = "%1"
end
local patt = pattern
if not patt:find("%^") and not patt:find("%$") then
patt = "^" .. patt .. "$"
end
return (text:gsub(patt, replacement))
end
local function flatten_parts(entry)
if type(entry) ~= "table" then
return {}
end
local parts = {}
local function append_table_json(key, value)
local ok, json = pcall(mw.text.jsonEncode, value)
if ok and json then
parts[#parts + 1] = key .. "=" .. to_nowiki(json)
end
end
local function walk(tbl, prefix)
local keys = {}
for k in pairs(tbl) do
keys[#keys + 1] = k
end
table.sort(keys, function(a, b)
return tostring(a) < tostring(b)
end)
for _, k in ipairs(keys) do
local v = tbl[k]
local kStr = tostring(k)
local key = (prefix == "" and kStr or prefix .. "." .. kStr)
if type(v) == "table" then
if next(v) ~= nil then
append_table_json(key, v)
if is_array(v) then
local first = v[1]
if type(first) == "table" then
walk(first, key)
end
else
walk(v, key)
end
end
else
parts[#parts + 1] = key .. "=" .. tostring(v)
end
end
end
walk(entry, "")
return parts
end
local function flatten_entry(entry)
local parts = flatten_parts(entry)
if #parts == 0 then
return ""
end
return table.concat(parts, "|")
end
local function build_tpl(id, pagePath, tplPath, data)
if id == "" or pagePath == "" or tplPath == "" then
return ""
end
local moduleName = get_module_name(pagePath)
data = data or load_cached_data(moduleName)
if not data then
return ""
end
local entry = resolve_entry(data, id)
local extra = flatten_entry(entry)
local templatePath = tplPath
if project ~= nil and project ~= "" then
templatePath = project .. ":" .. lang:ucfirst(tplPath)
templatePath = "{{#ifexist:Шаблон:" .. templatePath .. "|" .. templatePath .. "|" .. tplPath .. "}}"
end
local tplStr = "{{Шаблон:" .. templatePath .. "|id=" .. tostring(id)
if extra ~= "" then
tplStr = tplStr .. "|" .. extra
end
tplStr = tplStr .. "}}"
return tplStr
end
function p.findInGenerator(frame)
local args = frame.args or {}
local searchId = args[1] or ""
local kind = (args[2] or ""):lower()
local fieldId = args[3] or ""
if searchId == "" or fieldId == "" then
return ""
end
if kind ~= "prototype" and kind ~= "component" then
return ""
end
local storeName = (kind == "prototype") and "prototype_store.json" or "component_store.json"
local moduleName = get_module_name(storeName)
local data = load_cached_data(moduleName)
if not data then
return ""
end
local entry = data[searchId]
if type(entry) ~= "table" then
return ""
end
local value = get_field_loose(entry, fieldId)
if value == nil then
return ""
end
local out = {}
local t = type(value)
if t == "table" then
for _, v in ipairs(value) do
out[#out + 1] = v
end
else
out[1] = value
end
return mw.text.jsonEncode(out)
end
function p.flattenField(frame)
local args = frame.args or {}
local id = args[1] or ""
local pagePath = args[2] or ""
if id == "" or pagePath == "" then
return ""
end
local moduleName = get_module_name(pagePath)
local data = load_cached_data(moduleName)
if not data then
return ""
end
local entry = resolve_entry(data, id) or {}
return flatten_entry(entry)
end
function p.get(frame)
local args = getArgs(frame, { removeBlanks = false })
local id = args[1] or ""
local pagePath = args[2] or ""
local keyPath = args[3] or ""
if pagePath == "" then
return ""
end
local moduleName = get_module_name(pagePath)
local data = load_cached_data(moduleName)
if not data then
return ""
end
local entry = resolve_entry(data, id)
if entry == nil then
return ""
end
if keyPath == "" then
return format_value(entry)
end
local value = get_by_path(entry, keyPath)
return format_value(value)
end
function p.searchId(frame)
local args = getArgs(frame, { removeBlanks = false })
local searchValue = args[1] or ""
local pagePath = args[2] or ""
local keyPath = args[3] or ""
local searchType = (args.searchType or ""):lower()
if searchValue == "" or pagePath == "" or keyPath == "" then
return ""
end
if searchType == "" then
searchType = "value"
end
local moduleName = get_module_name(pagePath)
local data = load_cached_data(moduleName)
if not data then
return "[]"
end
local ids = collect_id_keys(data)
if #ids == 0 then
return ""
end
local matches
if searchType == "key" then
local target = tostring(searchValue)
matches = {}
for _, idKey in ipairs(ids) do
local entry = resolve_entry(data, idKey)
if type(entry) == "table" then
local v = get_by_path(entry, keyPath)
if type(v) == "table" and v[target] ~= nil then
matches[#matches + 1] = idKey
end
end
end
else
local target = tostring(searchValue)
matches = {}
for _, idKey in ipairs(ids) do
local entry = resolve_entry(data, idKey)
if type(entry) == "table" then
local v = get_by_path(entry, keyPath)
if v ~= nil and contains_target(v, target) then
matches[#matches + 1] = idKey
end
end
end
end
if #matches == 0 then
return ""
end
local ok, json = pcall(mw.text.jsonEncode, matches)
if ok and json then
return json
end
return ""
end
function p.searchIdTpl(frame)
local args = getArgs(frame, { removeBlanks = false })
local searchValue = args[1] or ""
local pagePath = args[2] or ""
local keyPath = args[3] or ""
local tplPath = mw.text.unstripNoWiki(args[4] or "")
local searchType = (args.searchType or ""):lower()
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 "")
end
if pagePath == "" or keyPath == "" or tplPath == "" then
return ""
end
if searchType ~= "path" and searchValue == "" then
return ""
end
local moduleName = get_module_name(pagePath)
local data = load_cached_data(moduleName)
if not data then
return ""
end
local ids = collect_id_keys(data)
if #ids == 0 then
return ""
end
local matches
if searchType == "path" then
matches = {}
for _, idKey in ipairs(ids) do
local entry = resolve_entry(data, idKey)
if type(entry) == "table" then
local v = get_by_path(entry, keyPath)
if is_nonempty_value(v) then
matches[#matches + 1] = idKey
end
end
end
elseif searchType == "key" then
local target = tostring(searchValue)
matches = {}
for _, idKey in ipairs(ids) do
local entry = resolve_entry(data, idKey)
if type(entry) == "table" then
local v = get_by_path(entry, keyPath)
if type(v) == "table" and v[target] ~= nil then
matches[#matches + 1] = idKey
end
end
end
else
local target = tostring(searchValue)
matches = {}
for _, idKey in ipairs(ids) do
local entry = resolve_entry(data, idKey)
if type(entry) == "table" then
local v = get_by_path(entry, keyPath)
if v ~= nil and contains_target(v, target) then
matches[#matches + 1] = idKey
end
end
end
end
if #matches == 0 then
return ""
end
local out = {}
for _, idKey in ipairs(matches) do
local tpl = build_tpl(idKey, pagePath, tplPath, data)
if tpl ~= "" then
out[#out + 1] = tpl
end
end
if #out == 0 then
return ""
end
local result = table.concat(out, " ")
return preprocess_or_return(frame, result)
end
function p.getTpl(frame)
local args = getArgs(frame, { removeBlanks = false })
local id = args[1] or ""
local pagePath = args[2] or ""
local tplPath = mw.text.unstripNoWiki(args[3] or "")
if id == "" or pagePath == "" or tplPath == "" then
return ""
end
local moduleName = get_module_name(pagePath)
local data = frame.data
if not data then
data = load_cached_data(moduleName)
end
if not data then
return ""
end
local tplStr = build_tpl(id, pagePath, tplPath, data)
return preprocess_or_return(frame, tplStr)
end
function p.searchStoreTpl(frame)
local args = getArgs(frame, { removeBlanks = false })
local searchId = args[1] or ""
local kind = (args[2] or ""):lower()
local generatorId = args[3] or ""
local tplPath = mw.text.unstripNoWiki(args[4] or "")
if searchId == "" or generatorId == "" or tplPath == "" then
return ""
end
if kind ~= "prototype" and kind ~= "component" then
return ""
end
local dir = (kind == "prototype") and "prototype/" or "component/"
local pagePath = dir .. generatorId .. ".json"
local idsJson = p.findInGenerator({ args = { searchId, kind, generatorId } })
local ok, ids = pcall(mw.text.jsonDecode, idsJson or "")
if not ok or type(ids) ~= "table" or #ids == 0 then
return ""
end
local moduleName = get_module_name(pagePath)
local data = load_cached_data(moduleName)
if not data then
return ""
end
local out = {}
for _, id in ipairs(ids) do
local tpl = build_tpl(id, pagePath, tplPath, data)
if tpl ~= "" then
out[#out + 1] = tpl
end
end
local result = table.concat(out, " ")
return preprocess_or_return(frame, result)
end
function p.flattenParams(entry)
return flatten_parts(entry)
end
function p.searchStore(frame)
local args = getArgs(frame, { removeBlanks = false })
local searchId = args[1] or ""
local kind = (args[2] or ""):lower()
local generatorId = args[3] or ""
if searchId == "" or generatorId == "" then
return ""
end
if kind ~= "prototype" and kind ~= "component" then
return ""
end
local idsJson = p.findInGenerator({ args = { searchId, kind, generatorId } })
local ok, ids = pcall(mw.text.jsonDecode, idsJson or "")
if not ok or type(ids) ~= "table" or #ids == 0 then
return ""
end
local okOut, outJson = pcall(mw.text.jsonEncode, ids)
if okOut and outJson then
return outJson
end
return ""
end
function p.hasComp(frame)
local args = getArgs(frame, { removeBlanks = false })
local entityId = args[1] or ""
local compName = args[2] or ""
if entityId == "" or compName == "" then
return "false"
end
local moduleName = get_module_name("component.json")
local data = load_cached_data(moduleName)
if not data then
return "false"
end
if type(data) ~= "table" then
return "false"
end
local entry = data[entityId]
if type(entry) ~= "table" then
return "false"
end
local target = tostring(compName)
for _, v in ipairs(entry) do
if tostring(v) == target then
return "true"
end
end
return "false"
end
function p.getAll(frame)
local args = getArgs(frame, { removeBlanks = false })
local pagePath = args[1] or ""
local replace = mw.text.unstripNoWiki(args.replace or "")
local pattern = mw.text.unstripNoWiki(args.pattern or "(.*)")
if pagePath == "" then
return ""
end
local moduleName = get_module_name(pagePath)
local data = load_cached_data(moduleName)
if not data then
return ""
end
local idsTable = data.id
if type(idsTable) ~= "table" then
return ""
end
local ids = {}
for k in pairs(idsTable) do
ids[#ids + 1] = k
end
table.sort(ids)
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
return preprocess_or_return(frame, table.concat(out, "\n"))
end
local ok, json = pcall(mw.text.jsonEncode, ids)
if ok and json then
return json
end
return ""
end
function p.getAllTpl(frame)
local args = getArgs(frame, { removeBlanks = false })
local pagePath = args[1] or ""
local tplPath = args[2] or ""
if pagePath == "" or tplPath == "" then
return ""
end
local moduleName = get_module_name(pagePath)
local data = load_cached_data(moduleName)
if not data then
return ""
end
local idsTable = data.id
if type(idsTable) ~= "table" then
return ""
end
local out = {}
for idKey in pairs(idsTable) do
local tpl = build_tpl(idKey, pagePath, tplPath, data)
if tpl ~= "" then
out[#out + 1] = tpl
end
end
table.sort(out)
local result = table.concat(out, " ")
return preprocess_or_return(frame, result)
end
function p.json(frame)
local args = getArgs(frame, { removeBlanks = false })
local jsonStr = mw.text.unstripNoWiki(args[1] or args.json or "")
local tplPath = mw.text.unstripNoWiki(args[2] or args.template or "")
if jsonStr == "" or tplPath == "" then
return ""
end
local ok, data = pcall(mw.text.jsonDecode, jsonStr)
if not ok or type(data) ~= "table" then
return ""
end
local okDp, dp = pcall(require, "Module:GetField")
local calls = {}
local projectPath = nil
if project ~= nil and project ~= "" then
projectPath = project .. ":" .. lang:ucfirst(tplPath)
end
local function makeTemplatePrefix()
if projectPath then
return "{{Шаблон:{{#ifexist:Шаблон:" .. projectPath .. "|" .. projectPath .. "|" .. tplPath .. "}}"
end
return "{{" .. tplPath
end
local function makeCall(id, obj)
if type(id) ~= "string" then
return
end
local parts = { makeTemplatePrefix(), "id=" .. id }
if type(obj) == "table" then
if okDp and dp and type(dp.flattenParams) == "function" then
local extra = dp.flattenParams(obj)
for i = 1, #extra do
parts[#parts + 1] = extra[i]
end
else
for k, v in pairs(obj) do
if v ~= nil then
parts[#parts + 1] = tostring(k) .. "=" .. tostring(v)
end
end
end
elseif obj ~= nil then
parts[#parts + 1] = "value=" .. tostring(obj)
end
parts[#parts + 1] = "}}"
calls[#calls + 1] = table.concat(parts, "|")
end
if is_array(data) then
for _, item in ipairs(data) do
if type(item) == "table" then
for k, v in pairs(item) do
makeCall(k, v)
end
end
end
else
for k, v in pairs(data) do
makeCall(k, v)
end
end
if #calls == 0 then
return ""
end
local rendered = table.concat(calls, " ")
return frame:preprocess(rendered)
end
function p.jsonList(frame)
local args = getArgs(frame, { removeBlanks = false })
local jsonStr = mw.text.unstripNoWiki(args[1] or args.json or "")
if jsonStr == "" then
return ""
end
local ok, data = pcall(mw.text.jsonDecode, jsonStr)
if not ok or type(data) ~= "table" then
return ""
end
local outputType = (args.type or "list"):lower()
local bullet = mw.text.unstripNoWiki(args.prefix or "* ")
local sep = mw.text.unstripNoWiki(args.sep or ": ")
if outputType == "none" then
bullet = ""
sep = ""
end
local keyPattern = mw.text.unstripNoWiki(args.key_pattern or "(.*)")
local keyReplace = mw.text.unstripNoWiki(args.key_replace or "\\1")
local valuePattern = mw.text.unstripNoWiki(args.value_pattern or "(.*)")
local valueReplace = mw.text.unstripNoWiki(args.value_replace or "\\1")
local pairPattern = mw.text.unstripNoWiki(args.pattern or "(.*)")
local pairReplace = mw.text.unstripNoWiki(args.replace or "\\1")
local out = {}
if is_array(data) then
for _, v in ipairs(data) do
local text = ""
if type(v) == "table" then
if is_array(v) then
text = table.concat(v, ", ")
else
local okJson, jsonVal = pcall(mw.text.jsonEncode, v)
if okJson and jsonVal then
text = jsonVal
end
end
else
text = tostring(v)
end
if text ~= "" then
local patt = valuePattern ~= "" and valuePattern or keyPattern
local repl = valueReplace ~= "" and valueReplace or keyReplace
text = apply_pattern(text, patt, repl)
local line
if outputType == "enum" then
line = text
else
line = bullet .. text
end
if pairPattern ~= "" then
line = apply_pattern(line, pairPattern, pairReplace)
end
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)
for _, k in ipairs(keys) do
local v = data[k]
local vStr
if type(v) == "table" then
local okJson, jsonVal = pcall(mw.text.jsonEncode, v)
if okJson and jsonVal then
vStr = jsonVal
else
vStr = ""
end
else
vStr = tostring(v)
end
local baseKey = apply_pattern(tostring(k), keyPattern, "\\1")
local MARK_KEY = "\31KEY\31"
local vRepl = (valueReplace or "\\1"):gsub("\\2", MARK_KEY)
local vStr0 = apply_pattern(vStr, valuePattern, vRepl)
vStr0 = tostring(vStr0):gsub(MARK_KEY, baseKey)
local MARK_VAL = "\31VAL\31"
local kRepl = (keyReplace or "\\1"):gsub("\\2", MARK_VAL)
local keyStr0 = apply_pattern(tostring(k), keyPattern, kRepl)
local keyStr = tostring(keyStr0):gsub(MARK_VAL, vStr0)
vStr = vStr0
if vStr ~= "" then
local line
if outputType == "enum" then
line = vStr .. " " .. keyStr
else
line = bullet .. keyStr .. sep .. vStr
end
if pairPattern ~= "" then
line = apply_pattern(line, pairPattern, pairReplace)
end
table.insert(out, line)
end
end
end
if outputType == "enum" then
return frame:preprocess(table.concat(out, ", "))
elseif outputType == "list" then
return frame:preprocess(table.concat(out, "\n"))
else
return frame:preprocess(table.concat(out, ""))
end
end
return p