local path = require 'pandoc.path' 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 make_absolute(rel, base) return path.is_absolute(rel) and rel or path.join({ path.directory(base), rel }) end function resolve_url(site_url, ref_file, target_file) target_file = target_file:gsub("/index%.html$", "/") local ref_base_dir = path.directory(ref_file) local abs = target_file local rel = path.make_relative(abs, ref_base_dir, true) 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 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 return nil end local pages_all = pandoc.List() local pages_asc_title = pandoc.List() local pages_desc_date = pandoc.List() for _, page in pairs(pages_by_id) do local p = process(global, page) pages_all:insert(p) pages_asc_title:insert(p) if p.date then pages_desc_date:insert(p) end end pages_all:sort(function(p1, p2) if p1.position then if p2.position then return tonumber(p1.position) < tonumber(p2.position) else return true end elseif p2.position then return false elseif 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) pages_desc_date:sort(function(p1, p2) if p1.position then if p2.position then return tonumber(p1.position) < tonumber(p2.position) else return true end else return p1.date.yyyy_mm_dd > p2.date.yyyy_mm_dd end end) pages_asc_title:sort(function(p1, p2) if p1.position then if p2.position then return tonumber(p1.position) < tonumber(p2.position) else return true end elseif p2.position then return false else return p1.title < p2.title end end) local pages_data = { all = pages_all, desc_date = pages_desc_date, asc_title = pages_asc_title, by_id = pages_by_id, } return pages_data end local titlecase_exceptions = pandoc.List({ "a", "an", "and", "as", "at", "but", "by", "en", "for", "if", "in", "nor", "of", "on", "or", "per", "the", "to", "v%.?", "vs%.?", "via", }) function titlecase(str) return str:gsub("(%S)(%S*)(%s*)", function(a, b, space) local word = a .. b local is_exception = word:match("%u") or titlecase_exceptions:find_if( function(exception) return word:match("^" .. exception .. "$") end) if is_exception then return word .. space end return string.upper(a) .. b .. space end) 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 titlecase(pandoc.utils.stringify(meta.title))) or "" if meta.position then meta.position = pandoc.utils.stringify(meta.position) end if meta.create_feed then if meta.file_out:match(".html$") then meta.feed = { url = resolve_url(global.site.url, global.file_out, meta.file_out:gsub(".html$", ".xml")), } else meta.page = { url = resolve_url(global.site.url, global.file_out, meta.file_out:gsub(".xml$", ".html")), } end end 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.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) if meta.date then meta.date = format_date(meta.date) elseif meta.pages and #meta.pages.desc_date ~= 0 then meta.date = meta.pages.desc_date[1].date end if meta.last_update then meta.last_update = format_date(meta.last_update) elseif meta.pages and #meta.pages.desc_date ~= 0 then meta.last_update = meta.pages.desc_date[1].last_update elseif meta.date then meta.last_update = meta.date end return meta end function Meta(meta) meta.site.url = pandoc.utils.stringify(meta.site.url):gsub("/$", "") return process(meta, meta) end