Module:User:kc kennylau/ancestor chain

local p = {}

local lang = mw.loadData("Module:languages/data/all") local fam = mw.loadData("Module:families/data") local etyl = mw.loadData("Module:etymology languages/data")

local function get_data(code) return lang[code] or etyl[code] or error("language code " .. code .. " not recognized") end

local function get_sort_value(val) data = get_data(val) return data[1] or data.canonicalName end

local function format(code) if lang[code] then return " " elseif etyl[code] then return " " end end

local function dump(data, prefix) if type(data) == "string" then return format(data) else local result = {} local branch = "├───" local next_level = prefix .. "│　　　　"		local length = #data for i, val in ipairs(data) do			if i == length then branch = "└───" next_level = prefix .. "　　　 　"			end if not val[1] then table.insert(result, prefix .. branch .. dump(val.name) .. " ") else table.insert(result, "\n{| class=mw-collapsible style=border-collapse:collapse\n|") table.insert(result, prefix .. branch .. dump(val.name)) table.insert(result, "\n|-\n|") table.insert(result, dump(val, next_level)) table.insert(result, "\n|}\n") end end return table.concat(result) end end

local function deep_sort(current) local result = {} local is_table = {} for key, val in pairs(current) do		if type(key) == "number" then table.insert(result, val) else is_table[key] = true table.insert(result, key) end end table.sort(result, function(a, b)		return get_sort_value(a) < get_sort_value(b)	end) local i = 2 while i < #result do		while get_data(result[i - 1]) == get_data(result[i]) do			table.remove(result, i)		end i = i + 1 end for i = 1, #result do		if is_table[result[i]] then local name = result[i] result[i] = deep_sort(current[result[i]]) result[i].name = name else result[i] = { name = result[i] } end end return result end

local function find_code(t, code) for _, val in ipairs(t) do		if val.name == code then -- "name" is really code return { val } else local result = find_code(val, code) if result then return result end end end end

local function find_ancestors(origin, key, val) if val.ancestors then return val.ancestors elseif etyl[key] and val.parent and val.parent:match("%-pro$") then return { val.parent } elseif val[3] or val.family then while true do			key = val[3] or val.family val = fam[key] if not key or key == "qfa-not" or key == "qfa-und" then return nil elseif val.protoLanguage and origin ~= val.protoLanguage then return { val.protoLanguage } elseif origin ~= key .. "-pro" and lang[key .. "-pro"] then return { key .. "-pro" } end end end end

local function make_nested(data, children) local make_nil = {} for key, val in pairs(data) do		if type(key) == "number" then if children[val] then data[val] = make_nested(children[val], children) table.insert(make_nil, key) children[val] = nil end else data[key] = make_nested(val, children) end end for _, key in ipairs(make_nil) do		data[key] = nil end return data end

local function get_children local children = {} for _, data in ipairs { lang, etyl } do		for key, val in pairs(data) do			local ancestors = find_ancestors(key, key, val) if ancestors then for _, ancestor in ipairs(ancestors) do					if ancestor ~= key then if children[ancestor] then table.insert(children[ancestor], key) else children[ancestor] = { key } end end end end end end return children end

function p.show(frame) local children = get_children local nested = make_nested(children, children) nested = deep_sort(nested) local descendants_of = frame.args[1] if descendants_of then if not lang[descendants_of] then error("The language code " .. descendants_of .. " is not a valid non-etymology language.") end nested = find_code(nested, descendants_of) end local result = {} for i = 1, #nested do table.insert(result, "\n\n\n{| class=mw-collapsible style=border-collapse:collapse\n|" .. format(nested[i].name) .. "\n|-\n|") table.insert(result, dump(nested[i], "　　")) table.insert(result, "\n|}") end return table.concat(result) end

return p