-- SPDX-License-Identifier: AGPL-3.0-only local function html_escape(s) expect(1, s, "string") s = string.gsub(s, "&", "&") s = string.gsub(s, "<", "<") s = string.gsub(s, ">", ">") s = string.gsub(s, "'", "'") s = string.gsub(s, "\"", """) return s end local function html(el, tbl) expect(1, el, "string") expect(2, tbl, "table") innerHtml = "" attributes = "" for k, v in pairs(tbl) do if type(k) == "string" then expect.field(tbl, k, "string") attributes = attributes .. " " .. k .. "='" .. html_escape(v) .. "'" end end for k, v in ipairs(tbl) do expect.field(tbl, k, "string", "table") if type(v) == "table" then v = html_escape(v[1]) end innerHtml = innerHtml .. v end return string.format("<%s%s>%s", el, attributes, innerHtml, el) end local function root(tbl) return "\n" .. html("html", tbl) end return setmetatable( { root = root }, { __call = html, __index = function (idx) return function(tbl) html(idx, tbl) end end })