-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathh.lua
115 lines (107 loc) · 3.02 KB
/
h.lua
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
local void_tags = {
"area", "base", "basefont", "br", "col",
"frame", "hr", "img", "input", "link",
"meta", "param", "embed", "command", "keygen",
"source", "track", "wbr"
}
local function is_void_tag(tag)
for _, void_tag in ipairs(void_tags) do
if void_tag == tag then
return true
end
end
return false
end
local function kebab_case(tag)
if not tag:match("^[a-z]") and tag:match("%u%u") and tag:match("[^%w]") then
return tag
end
local kebab = tag:gsub("(%u)", "-%1"):lower()
return kebab:gsub("^%-", "")
end
local function create_element(tag, atts, children)
return {
tag = tag,
atts = atts or {},
children = children or {}
}
end
local function is_atts(tbl, tag)
if tag:lower() == "doctype" then
return true
end
for k, v in pairs(tbl) do
if type(k) ~= "string" or type(v) == "table" then
return false
end
end
return true
end
setmetatable(_G, {
__index = function(_, tag)
return function(...)
local atts
local children = { ... }
if type(children[1]) == "table" and is_atts(children[1], tag) and #children ~= 1 then
atts = children[1]
children = { select(2, ...) }
end
if atts == nil and is_atts(children[1], tag) then
atts = children[1]
children = { select(2, children) }
end
atts = atts or children[1]
return create_element(tag, atts, children)
end
end
})
local function sanitize_value(str)
return (str:gsub("[<>&]", {
["<"] = "<",
[">"] = ">",
["&"] = "&"
}))
end
local function h(element)
if type(element) ~= "table" then return sanitize_value(element) or "" end
local tkeys = {}
-- asume as nodeList
if type(element.atts) ~= "table" then
local node_list = {}
for _, k in ipairs(element) do
table.insert(node_list, h(k) or "")
end
return table.concat(node_list)
end
for k in pairs(element.atts) do table.insert(tkeys, k) end
if #tkeys then table.sort(tkeys) end
local atts = ""
local children = ""
for _, k in ipairs(tkeys) do
local v = element.atts[k]
if type(v) ~= "table" then
if k ~= "children" then
atts = atts .. " " .. k .. "=\"" .. sanitize_value(v) .. "\""
else
children = v
end
end
end
for _, child in ipairs(element.children) do
if type(child) == "table" then
children = children .. h(child)
elseif element.tag == "script" then
children = children .. child
else
children = children .. sanitize_value(child)
end
end
if element.tag:lower() == "doctype" then
return "<!" .. kebab_case(element.tag:lower()) .. " " .. table.concat(element.atts, " ") .. ">" .. children
elseif is_void_tag(element.tag) then
return "<" .. kebab_case(element.tag) .. atts .. ">"
else
return "<" .. kebab_case(element.tag) .. atts .. ">" .. children .. "</" .. kebab_case(element.tag) .. ">"
end
end
return h