Документацију овог модула можете да направите на страници Модул:family tree/nested data/док

--[=[

Authors: [[User:kc_kennylau]], [[User:JohnC5]], [[User:Erutuon]], [[User:Suzukaze-c]]

--]=]

local regular_languages = require("Module:languages/alldata")
local families = require("Module:families/data")

-- Version of [[Module:etymology languages/data]] that chooses the language-
-- codiest code of several codes that have the same data. For instance,
-- it chooses "de-AT" over "Austrian German".
local etymology_languages = require("Module:family tree/etymology languages")

local supplementary_language_and_family_data
local use_supplementary_language_and_family_data
	= mw.title.getCurrentTitle().nsText ~= "Category"
if use_supplementary_language_and_family_data then
	supplementary_language_and_family_data = require("Module:family tree/data")
end

local fun = require("Module:fun")
local all = fun.all

local function get_data(code)
	return regular_languages[code] or etymology_languages[code] or families[code]
		or mw.log("language code " .. tostring(code) .. " not recognized")
end

local get_sort_value = fun.memoize(function (code)
	local data = get_data(code)
	return data and (data[1] or data.canonicalName):gsub("Proto%-", "") or ""
end)

-- used in deep_sort
local function compare(a, b)
	return get_sort_value(a) < get_sort_value(b)
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, compare)
	
	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

-- Reliably get family for etymology language.
local function get_family(code)
	while code do
		local data = get_data(code)
		if not data then
			return nil
		end
		local family = data[3] or data.family
		if family then -- This is a regular language or family code.
			return family
		end
		-- This is an etymology language code. Go up in the chain of parenthood.
		code = data.parent
	end
end

local function in_same_family_as(family_code)
	return function(lang_code)
		return get_family(lang_code) == family_code
	end
end

local protolanguage_of = {}

local function get_proto(fam_code, data)
	local proto = data.protoLanguage
	if proto then
		protolanguage_of[fam_code] = proto
		return proto
	end
	proto = fam_code .. "-pro"
	if regular_languages[proto] or etymology_languages[proto] then
		protolanguage_of[fam_code] = proto
		return proto
	end
end

local function find_ancestors(origin, code, val)
	-- First look for the special family tree–only ancestor.
	if use_supplementary_language_and_family_data
	and supplementary_language_and_family_data[origin]
	and supplementary_language_and_family_data[origin].parent then
		return { supplementary_language_and_family_data[origin].parent }
	
	-- Handle etymology languages.
	elseif etymology_languages[code] then
		local parent = val.parent
		if parent then
			return { parent }
		end
	
	-- Handle regular languages
	-- Return ancestors value if the ancestors belong to the same language
	-- family.
	elseif val.ancestors and all(in_same_family_as(val[3] or val.family), val.ancestors) then
		return val.ancestors
	
	-- Handle regular languages and language families.
	-- Return a proto-language if possible, else a language family.
	elseif val[3] or val.family then
		-- Go up through the language families that the language or family
		-- belongs to.
		while true do
			code = val[3] or val.family
			val = families[code]
			-- no family, "not a family", undetermined family
			if not (code and val and code ~= "qfa-not" and code ~= "qfa-und") then
				if code and not val then
					-- Error in data table!
					mw.log("no such family code: " .. code)
				end
				return nil
			end
			local proto = get_proto(code, val)
			if proto and proto ~= origin then
				return { proto }
			else
				return { code }
			end
		end
	end
end

local make_auto_subtabler = require("Module:auto-subtable")

local function make_parent_to_children_map()
	local children = make_auto_subtabler{}
	
	for _, data_module in ipairs { regular_languages, etymology_languages, families } do
		for code, data in pairs(data_module) do
			local ancestors = find_ancestors(code, code, data)
			if ancestors then
				for _, ancestor in ipairs(ancestors) do
					if ancestor ~= code then
						table.insert(children[ancestor], code)
					end
				end
			end
		end
	end
	
	-- No more auto subtabling needed.
	return children:un_auto_subtable()
end

local function reverse_comp(a, b)
	return a > b
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)
			end
		else
			data[key] = make_nested(val, children)
		end
	end
	if make_nil[2] then -- Make sure larger keys are removed first.
		table.sort(make_nil, reverse_comp)
	end
	for _, key in ipairs(make_nil) do
		table.remove(data, key)
	end
	return data
end

local function main()
	local children = make_parent_to_children_map()
	
	local nested = make_nested(children, children)
	
	nested = deep_sort(nested)
	
	return { nested = nested, protolanguage_of = protolanguage_of }
end

return main()