Module:Dv/staging

local Utility = require('Module:Utility') local Data = mw.loadData('Module:Dv/MergedJsonData') local Aliases = mw.loadData('Module:Dv/aliases')

local p = {}

p.Error = { CreatureMissing = {-10002}, NoData = {-10003}, }

function p.cleanQueryPath(name) -- Remove non-word characters except / and ? (Unicode enabled) return mw.ustring.gsub(name, '[^%w/?]', '') end

function p.getNodeWithInheritanceSolved(creature) -- Handle an alias (if one exists) for the creature if Aliases[creature] ~= nil then creature = Aliases[creature] end -- Retrieve the creature from the table local node = Data[creature] if node == nil then -- Creature is missing from the data table return nil end

-- Solve inheritance if node inherits from another. local inherits = node.inherits if inherits ~= nil and inherits ~= '' then -- Node inherits information from another. retrieve it with its inheritance solved. local parentNode = p.getNodeWithInheritanceSolved(inherits) if parentNode ~= nil then node = Utility.merge(Utility.deepcopy(parentNode), node) end end -- Apply data overrides if the node is set to require those. local overrideWith = node.overrideWith if overrideWith ~= nil and overrideWith ~= '' then local overridesNode = p.getNodeWithInheritanceSolved(overrideWith) if overridesNode ~= nil then node = Utility.merge(Utility.deepcopy(node), overridesNode) end end return node end

function p.query(route) -- Break the path down by slash local path = {} for part in route:gmatch("[^/]+") do		table.insert(path, part) end -- Separate creature name from the rest of the path and turn it lower-case local creature = table.remove(path, 1):lower -- Retrieve the creature from the table local node = p.getNodeWithInheritanceSolved(creature) if node == nil then -- Creature is missing from the data table return p.Error.CreatureMissing end

-- Traverse data by the path for index, f in ipairs(path) do		if f == '?' then -- Special case to check if a node exists. return true elseif node[f] == 'null' then -- Special case where node is set to a "null" string. Treat it as if it was a real nil. -- Table elements in Lua "don't exist" if their value is null, therefore we need this hack. return p.Error.NoData elseif node[f] ~= nil then node = node[f] elseif path[index-1] == 'colorRegions' and tonumber(f) ~= nil and node[tonumber(f)+1] ~= nil then -- Shift index of a colour region by one. node = node[tonumber(f)+1] elseif path[index-1] ~= 'colorRegions' and tonumber(f) ~= nil and node[tonumber(f)] ~= nil then -- Number-indexed array, treat `f` as a number. node = node[tonumber(f)] else -- Path led to a dead-end. Nothing available. return p.Error.NoData end end

return node end

function p.data(f) local args = f:getParent.args -- Expect one or more non-named arguments in the template, the slash-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 = p.cleanQueryPath(table.concat(Utility.deepcopy(args), '/'))

local result = p.query(path) if result == nil then -- Return an empty string instead of nulls. return '' elseif result == p.Error.CreatureMissing or result == p.Error.NoData then -- Return the default value or an empty string on query failure. return args.default or '' elseif type(result) == 'boolean' then -- Convert boolean result into a 'yes' or 'no'. return result and 'Yes' or 'No' elseif type(result) == 'table' then -- TODO: result is a table, define variables in a compatible way return table.concat(Utility.deepcopy(result), ', ') else -- Return the result. return result end end

return p