function format_date(date) if not date then return date end date = pandoc.utils.normalize_date(pandoc.utils.stringify(date)) local year, month, day = date:match("(%d%d%d%d)-(%d%d)-(%d%d)") if not year then return nil end local time = os.time({year = tonumber(year), month = tonumber(month), day = tonumber(day)}) return { yyyy_mm_dd = os.date("%F", time), yyyy = os.date("%Y", time), mm = os.date("%m", time), dd = os.date("%d", time), rfc3339 = os.date("%FT%T+00:00", time), long = os.date("%B %d, %Y", time), short = os.date("%b %d, %y", time), } end function table_to_list(t, kv, cmp) local l = pandoc.List() if kv then for key, value in pairs(t) do l:insert({key = key, value = value}) end else for _, value in pairs(t) do l:insert(value) end end l:sort(cmp or function(i1, i2) return i1.key < i2.key end) return l end function group_by(l, field, insert) insert = insert or function(group, _, item) if not group then group = l:new({item}) return group end group:insert(item) end local groups = {} for i = 1, #l do local item = l[i] local f = field(item) if f then local out = insert(groups[f], f, item) if out then groups[f] = out end end end return groups end function splitstr(input, sep) sep = sep or "%s" local t = {} for str in input:gmatch("([^" .. sep .. "]+)") do table.insert(t, str) end return t end function relative_to(dir, target) dir = splitstr(dir, "/") target = splitstr(target, "/") local prefix = true local path = "" for i = 1, math.min(#dir, #target) do local t = target[i] if prefix then if dir[i] ~= t then prefix = false path = "../" .. t end else path = "../" .. path .. "/" .. t end end if #dir < #target then for i = #dir + 1, #target do path = path .. (path == "" and "" or "/") .. target[i] end elseif #dir > #target then for _ = #target + 1, #dir do path = "../" .. path end end return path end function make_absolute(rel, base) return rel:find("^/") and rel or base:gsub("^(.*)/.-$", "%1") .. "/" .. rel end function resolve_url(site_url, ref_file, target_file) target_file = target_file:gsub("/index%.html$", "/") local ref_base_dir = ref_file:gsub("^(.*)/.-$", "%1") local abs = target_file local rel = relative_to(ref_base_dir, abs):gsub("/index%.html$", "/") return {abs = abs, rel = rel, full = (site_url .. abs)} end function resolve_layout(layout) if layout then layout = pandoc.utils.stringify(layout) return {id = layout, ["is_" .. layout] = true} end end function resolve_namespace(namespace) namespace = pandoc.utils.stringify(namespace) local root = "index" if namespace ~= "" then root = namespace:gsub("^/([^/]*).*$", "%1") end return {root = {id = root, ["is_" .. root] = true}, full = namespace} end function resolve_category(categories, category) if categories and category then category = pandoc.utils.stringify(category) data = categories[category] data.id = category return data end end function prep_menu(active_id, main_menu) local active_item = nil for i = 1, #main_menu do local item = main_menu[i] local active = pandoc.utils.stringify(item.id) == active_id item.active = active if active then active_item = item end end return { items = main_menu:filter(function(item) return not item.hidden or item.active end), active = active_item, } end function process_pages(global, pages_by_id) if not pages_by_id then pages_by_id = {} end local pages_list = pandoc.List() for _, page in pairs(pages_by_id) do page = process(global, page) pages_list:insert(page) end pages_list:sort(function(p1, p2) if p1.date then if p2.date then return p1.date.yyyy_mm_dd > p2.date.yyyy_mm_dd else return true end elseif p2.date then return false else return p1.title < p2.title end end) local pages_by_category = pages_list:filter(function(p) return p.category ~= nil end) pages_by_category = group_by(pages_by_category, function(p) return p.category.id end, function(data, _, p) if not data then local l = pandoc.List() l:insert(p) return {name = pandoc.utils.stringify(p.category.name), pages = l} else data.pages:insert(p) end end) pages_by_category = table_to_list(pages_by_category, false, function(i1, i2) return i1.name < i2.name end) local pages_data = {all = pages_list, by_id = pages_by_id, by_category = pages_by_category} return pages_data end function process(global, meta) meta.namespace = resolve_namespace(meta.namespace) meta.file_out = pandoc.utils.stringify(meta.file_out):gsub("^out", "") meta.layout = resolve_layout(meta.layout) meta.url = resolve_url(global.site.url, global.file_out, meta.file_out) meta.title = (meta.title and pandoc.utils.stringify(meta.title)) or "" if meta.preview then meta.preview = make_absolute(pandoc.utils.stringify(meta.preview), meta.file_out) meta.preview = resolve_url(global.site.url, global.file_out, meta.preview) end if meta.date then meta.date = format_date(meta.date) end if meta.last_update then meta.last_update = format_date(meta.last_update) else meta.last_update = meta.date end meta.category = resolve_category(global.categories[meta.namespace.root.id], meta.category) if meta.menus and meta.menus.main then meta.menus.main = prep_menu(meta.namespace.root.id, meta.menus.main) end meta.pages = process_pages(global, meta.pages) return meta end function Meta(meta) meta.site.url = pandoc.utils.stringify(meta.site.url):gsub("/$", "") return process(meta, meta) end