Модул:family tree/nested data
Документацију овог модула можете да направите на страници Модул: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()