local dir = require "pl.dir" local path = require "pl.path" local term = require "volksdata.term" local nsm = require "volksdata.namespace" local pkar = require "pocket_archive" local logger = pkar.logger -- "nil" table. local NT = {} local no_ll_pnames = { archive_path = true, checksum = true, size = true, submitted = true, sub_id = true, } local M = { -- Parsed typedef configurations. types = {}, -- Field names. Order is kept in encoding laundry lists. The hardcoded -- values come first, all others are harvested from the typedef -- configuration and ordered alphabetically. pnames = {"content_type", "id", "source_path"}, -- Term-to-URI map. URIs are volksdata.Term objects. id_to_uri = {}, -- URI-to-term map. Keys are URI strings, not volksdata.Term objects, -- because key comparison wouldn't work with them. uri_to_id = {}, } M.from_uri = function(type_uri) assert(type_uri) return M.types[M.uri_to_id[nsm.denormalize_uri(type_uri.data)]] end -- Parameters that do not get inherited. local NO_INHERIT = {abstract = true} local MODEL_PATH = path.join(pkar.config_path, "model") local gen_config = dofile(path.join(MODEL_PATH, "generation.lua")) local function add_term(id, uri_str) --if not uri then error(("Term %s has not a URI!"):format(term), 2) end if not uri_str then return end local uri = term.new_iriref_ns(uri_str) if not M.id_to_uri[id] then M.id_to_uri[id] = uri end if not M.uri_to_id[uri_str] then M.uri_to_id[uri_str] = id end end local function parse_model(mod_id) local hierarchy = {} local function traverse(mod_id) logger:debug("traversing: " .. mod_id) local model = dofile(path.join( MODEL_PATH, "typedef", mod_id .. ".lua")) -- Merge separate generator config model.gen = gen_config[mod_id] --model.id = mod_id --print("Model: ") --for k, v in pairs(model) do print (k, v) end -- Prepend to hierarchy. model.id = mod_id -- Store term-to-URI and URI-to-term mappings. add_term(model.id, model.uri) for prop, pdata in pairs(model.properties or {}) do add_term(prop, pdata.uri) end table.insert(hierarchy, 1, model) if model.broader then traverse(model.broader) end end traverse(mod_id) local lineage = {} -- Ordered lineage of types, from ancestor to leaf. local types = {} -- Set of all types. for _, mod in ipairs(hierarchy) do table.insert(lineage, mod.id) types[mod.id] = true end local function merge(src, dest) for k, v in pairs(src) do if NO_INHERIT[k] then goto continue end if type(v) == "table" then dest[k] = dest[k] or {} assert(type(dest[k]) == "table") merge(v, dest[k]) else dest[k] = v end ::continue:: end end local config = {lineage = lineage, types = types} for _, src_config in ipairs(hierarchy) do merge(src_config, config) end return config end local function setup_model() -- Temp store (set) for property names. local all_pnames = {} -- Collect all type names from config file names. for _, fpath in ipairs(dir.getfiles( path.join(MODEL_PATH, "typedef"), "*.lua")) do local mname = path.basename(fpath):gsub(".lua$", "") local typedef = parse_model(mname) -- Store parsed typedef configurations. M.types[mname] = typedef -- Store unique prop names. for pn in pairs(typedef.properties or NT) do if not no_ll_pnames[pn] then all_pnames[pn] = true end end end -- Remove hardcoded prop names, reorder, and append to module's pnames. local pnames_ordered = {} for _, hcpn in ipairs(M.pnames) do all_pnames[hcpn] = nil end for pn in pairs(all_pnames) do table.insert(pnames_ordered, pn) end table.sort(pnames_ordered) for _, pn in ipairs(pnames_ordered) do table.insert(M.pnames, pn) end logger:debug("Property names ordered: " .. table.concat(M.pnames, ", ")) end setup_model() return M