local M = {} M.__index = M function M.site_builder(header, footer) local config = {} local site_config = {} local fes_mod = package.loaded.fes if fes_mod and fes_mod.config then config = fes_mod.config if config.site then site_config = config.site end end local self = { version = site_config.version or "", title = site_config.title or "Document", header = header or [[ {{TITLE}}
]], footer = footer or [[
]], parts = {} } return setmetatable(self, M) end function M:custom(str) table.insert(self.parts, str) return self end function M:g(str) self:custom(str) return self end function M:h1(str) str = str or "" self:custom("

" .. str .. "

") return self end function M:h2(str) str = str or "" self:custom("

" .. str .. "

") return self end function M:h3(str) str = str or "" self:custom("

" .. str .. "

") return self end function M:h4(str) str = str or "" self:custom("

" .. str .. "

") return self end function M:h5(str) str = str or "" self:custom("
" .. str .. "
") return self end function M:h6(str) str = str or "" self:custom("
" .. str .. "
") return self end function M:p(str) str = str or "" table.insert(self.parts, "

" .. str .. "

") return self end function M:note(content) content = content or "" self:custom('
' .. content .. '
') return self end function M:muted(content) content = content or "" self:custom('
' .. content .. '
') return self end function M:a(link, str) link = link or "example.com" str = str or link table.insert(self.parts, "" .. str .. "") return self end function M:external(link, str) link = link or "example.com" str = str or link table.insert(self.parts, "" .. str .. "") return self end function M:version() return self.version end function M:ul(items) items = items or {} local html = "" self:custom(html) return self end function M:ol(items) items = items or {} local html = "
    " for _, item in ipairs(items) do html = html .. "
  1. " .. tostring(item) .. "
  2. " end html = html .. "
" self:custom(html) return self end function M:li(str) str = str or "" self:custom("
  • " .. str .. "
  • ") return self end function M:code(str) str = str or "" self:custom("" .. str .. "") return self end function M:pre(str) str = str or "" self:custom("
    " .. str .. "
    ") return self end function M:blockquote(str) str = str or "" self:custom("
    " .. str .. "
    ") return self end function M:hr() self:custom("
    ") return self end function M:divider() self:custom('
    ') return self end function M:img(src, alt) src = src or "" alt = alt or "" self:custom('' .. alt .. '') return self end function M:table(headers, rows) headers = headers or {} rows = rows or {} local html = "" for _, header in ipairs(headers) do html = html .. "" end html = html .. "" for _, row in ipairs(rows) do html = html .. "" for _, cell in ipairs(row) do html = html .. "" end html = html .. "" end html = html .. "
    " .. tostring(header) .. "
    " .. tostring(cell) .. "
    " self:custom(html) return self end function M:div(content, class) content = content or "" class = class or "" local class_attr = class ~= "" and (' class="' .. class .. '"') or "" self:custom("" .. content .. "") return self end function M:span(content, class) content = content or "" class = class or "" local class_attr = class ~= "" and (' class="' .. class .. '"') or "" self:custom("" .. content .. "") return self end function M:strong(str) str = str or "" self:custom("" .. str .. "") return self end function M:em(str) str = str or "" self:custom("" .. str .. "") return self end function M:br() self:custom("
    ") return self end function M:section(content) content = content or "" self:custom('
    ' .. content .. '
    ') return self end function M:links(link_list) link_list = link_list or {} local html = '' self:custom(html) return self end function M:lead(str) str = str or "" self:custom('

    ' .. str .. '

    ') return self end function M:small(str) str = str or "" self:custom('
    ' .. str .. '
    ') return self end function M:highlight(str) str = str or "" self:custom('' .. str .. '') return self end function M:build() local header = self.header:gsub("{{TITLE}}", self.title or "Document") return header .. table.concat(self.parts) .. self.footer end M.__tostring = function(self) return self:build() end return M