Module:Dv/sandbox-json

-- Usage: use the Template:Dv

-- override values in table dst with values of table src, or adds them local function merge(dst, src) for k, v in pairs(src) do   if type(dst[k]) == 'table' and type(v) == 'table' then dst[k] = merge(dst[k], v)   else dst[k] = v   end end return dst end

local function deepcopy(orig) if type(orig) == 'table' then local copy = {} for k, v in pairs(orig) do     copy[deepcopy(k)] = deepcopy(v) end return copy end return orig end

local function createVardefines(t, f, prefix) for k, v in pairs(t) do   if type(v) == 'table' then f:callParserFunction('#vardefine:' .. (prefix == '' and prefix or prefix .. '/') .. k, 'table') createVardefines(v, f, (prefix == '' and prefix or prefix .. '/') .. k)   else f:callParserFunction('#vardefine:' .. (prefix == '' and prefix or prefix .. '/') .. k, v)   end end end

-- retrieves data for a creature from the Lua and Obelisk tables -- ignores "overridewith" and "inherits" local function queryDatabasesForCreature(obeliskData, luaData, creature) local nodeLua = luaData and luaData[creature] local nodeObelisk = obeliskData and obeliskData[creature] local node = nil -- find the creature if nodeLua == nil and nodeObelisk == nil then -- creature not found in both databases return nil, nil, nil elseif nodeObelisk == nil or nodeLua == nil then -- creature found only in one database node = deepcopy(nodeObelisk or nodeLua) else -- creature found in both databases. -- copy json node and merge Dv/data into it   node = merge(deepcopy(nodeObelisk), nodeLua) end return nodeLua, nodeObelisk, node end

-- merges data from a parent creature into creatureNode -- expects parentName and creatureNode to not be nils local function solveInheritance(obeliskData, luaData, creatureNode, parentName) local nodeLua, nodeObelisk, parentNode = queryDatabasesForCreature(obeliskData, luaData, parentName) if parentNode == nil then return creatureNode end

return merge(deepcopy(parentNode), creatureNode) end

-- retrieves a creature from Dv/data and/or Dv/json local function getCreatureFromDatabase(obeliskData, luaData, creatureName) local nodeLua, nodeObelisk, node = queryDatabasesForCreature(obeliskData, luaData, creatureName) if node == nil then return '' -- 'creature data not found: ' .. creature end -- solve inheritance for Obelisk data. -- suggested by coldino to lower migration needs; the JSON generator may export -- creatures using another one as the "base", emiting only information specific -- to that variant. -- the groups can be configured in the generator's config/overrides.yaml file if nodeObelisk ~= nil and type(nodeObelisk.inherits) == 'string' then node = solveInheritance(obeliskData, luaData, node, nodeObelisk.inherits) end

-- solve inheritance for Lua data. this also pulls data from Obelisk -- only ran if the field differs across both data sets if nodeLua ~= nil and type(nodeLua.inherits) == 'string' and (nodeObelisk == nil or nodeObelisk.inherits ~= nodeLua.inherits) then node = solveInheritance(obeliskData, luaData, node, nodeLua.inherits) end

-- apply overrides within the Lua table if nodeLua ~= nil and type(nodeLua.overridewith) == 'string' then local overridesNode = luaData[nodeLua.overridewith] if overridesNode ~= nil then node = merge(node, overridesNode) end end

return node end

local p = {} function p.data(f) local args = f:getParent.args -- expects one or more non-named arguments in the template, the /-separated path to the data if args[1] == nil then return 'arguments expected, see documentation of Template:Dv' end -- concat all non-named arguments (args is not a real table, deepcopy creates one) local path = table.concat(deepcopy(args), '/')

-- remove non-word characters except / then lowercase path = path:gsub('[^%w/]', '')

local folders = {} -- list of path parts for part in path:gmatch("[^/]+") do   table.insert(folders, part) end

-- separate creature name from the rest of the path local creature = table.remove(folders, 1):lower

-- replace creature name alias with actual name local aliases = mw.loadData('Module:dv/aliases') if aliases[creature] ~= nil then creature = aliases[creature] end

-- retrieve the databases local obeliskData = mw.loadData('Module:dv/json').species local luaData = mw.loadData('Module:dv/sandbox-data')

local node = getCreatureFromDatabase(obeliskData, luaData, creature)

-- search data for path for _, f in ipairs(folders) do   -- access by plain key (f) local nodeF = node[f]

if nodeF == nil and tonumber(f) ~= nil then -- try to get node while treating folder as a number nodeF = node[tonumber(f) + 1] end

if nodeF ~= nil then node = nodeF else return '' -- no data available for given path end end

if type(node) == 'table' then if args.defineVars ~= nil then createVardefines(node, f, args.defineVars) return 'variables defined' end

if args.commaList ~= nil then return table.concat(deepcopy(node), ', ') end

return 'path not specific enough: ' .. path -- given path leads to a folder instead of a value end

return node end

return p