From 005be9fbf58197ba2a726bb92f31884aba1e68a2 Mon Sep 17 00:00:00 2001 From: Lars Mueller Date: Tue, 4 Jan 2022 13:42:46 +0100 Subject: [PATCH] Add web.html.[un]escape --- build/html_entities.lua | 19 +++++++++++++++++++ init.lua | 2 ++ test.lua | 8 ++++++++ web.lua | 28 ++++++++++++++++++++++++++++ 4 files changed, 57 insertions(+) create mode 100644 build/html_entities.lua create mode 100644 web.lua diff --git a/build/html_entities.lua b/build/html_entities.lua new file mode 100644 index 0000000..57ebf04 --- /dev/null +++ b/build/html_entities.lua @@ -0,0 +1,19 @@ +-- Generate lookup table for HTML entities out of https://html.spec.whatwg.org/entities.json +-- Requires https://github.com/brunoos/luasec to fetch the JSON +local https = require 'ssl.https' +local res, code = https.request"https://html.spec.whatwg.org/entities.json" +assert(code == 200) +local entity_map = {} +for entity, chars in pairs(assert(modlib.json:read_string(res))) do + entity_map[entity:sub(2, #entity - 1)] = table.concat(modlib.table.map(chars.codepoints, modlib.text.utf8)) +end +local entries = {} +for entity, chars in pairs(entity_map) do + table.insert(entries, ("[%q] = %q"):format(entity, chars)) +end +local serialized = [[-- HTML entity lookup table generated by build/html_entities.lua. Do not edit. +return {]] .. table.concat(entries, ", ") .. "}" +local loaded = assert(loadstring(serialized)) +setfenv(loaded, {}) +assert(modlib.table.equals(entity_map, loaded())) +modlib.file.write(modlib.mod.get_resource("modlib", "web", "html", "entities.lua"), serialized) \ No newline at end of file diff --git a/init.lua b/init.lua index b915cd4..0d43015 100644 --- a/init.lua +++ b/init.lua @@ -153,6 +153,8 @@ if minetest then modlib.conf.build_setting_tree() end +-- Run build scripts +-- dofile(modlib.mod.get_resource("modlib", "build", "html_entities.lua")) --[[ --modlib.mod.include"test.lua" diff --git a/test.lua b/test.lua index 2c17c06..d1560f9 100644 --- a/test.lua +++ b/test.lua @@ -324,6 +324,14 @@ do end) end +do + local text = " & '\"" + local escaped = web.html.escape(text) + assert(web.html.unescape(escaped) == text) + assert(web.html.unescape("*") == _G.string.char(42)) + assert(web.html.unescape("B") == _G.string.char(0x42)) +end + if not _G.minetest then return end assert(minetest.luon:read_string(minetest.luon:write_string(ItemStack""))) diff --git a/web.lua b/web.lua new file mode 100644 index 0000000..dafcbd2 --- /dev/null +++ b/web.lua @@ -0,0 +1,28 @@ +-- TODO incorporate https://github.com/minetest/minetest/pull/11578 +return { + html = setmetatable({ + escape = function(text) + return text:gsub(".", { + ["<"] = "<", + [">"] = ">", + ["&"] = "&", + ["'"] = "'", + ['"'] = """, + }) + end + }, {__index = function(self, key) + if key == "unescape" then + local func = assert(loadfile(modlib.mod.get_resource("modlib", "web", "html", "entities.lua"))) + setfenv(func, {}) + local named_entities = assert(func()) + local function unescape(text) + return text + :gsub("&([A-Za-z]+);", named_entities) -- named + :gsub("&#(%d+);", function(digits) return modlib.text.utf8(tonumber(digits)) end) -- decimal + :gsub("&#x(%x+);", function(digits) return modlib.text.utf8(tonumber(digits, 16)) end) -- hex + end + self.unescape = unescape + return unescape + end + end}) +} \ No newline at end of file