Skip to content

Commit d9204c9

Browse files
committed
use the xml param instead of globals
1 parent a7bc295 commit d9204c9

File tree

1 file changed

+96
-104
lines changed

1 file changed

+96
-104
lines changed

xml-generator.lua

Lines changed: 96 additions & 104 deletions
Original file line numberDiff line numberDiff line change
@@ -20,10 +20,17 @@ end
2020
---@class xml-generator
2121
local export = {}
2222

23+
---@class XML.Children
24+
---@field [integer] XML.Node | string | fun(): XML.Node
25+
26+
---@class XML.AttributeTable : XML.Children
27+
---@field [string] string | boolean | number
28+
2329
---@class XML.Node
30+
---@operator call(XML.Children): XML.Node
2431
---@field tag string
25-
---@field children (XML.Node | string | fun(): XML.Node)[]
26-
---@field attributes { [string] : (string | boolean) }
32+
---@field children XML.Children
33+
---@field attributes XML.AttributeTable
2734

2835
---quotes are allowed in text, not in attributes
2936
---@param str string
@@ -62,7 +69,7 @@ function export.node_to_string(node)
6269
if type(v) == "boolean" then
6370
if v then html = html .. " " .. k end
6471
else
65-
html = html .. " " .. k .. "=\"" .. export.sanitize_attributes(v) .. "\""
72+
html = html .. " " .. k .. "=\"" .. export.sanitize_attributes(tostring(v)) .. "\""
6673
end
6774
end
6875

@@ -81,90 +88,84 @@ function export.node_to_string(node)
8188
return html
8289
end
8390

84-
---@generic T
85-
---@param fn T
86-
---@return T
87-
function export.declare_xml_generator(fn)
88-
local tbl = setmetatable({}, {
89-
---@param self table
90-
---@param tag_name string
91-
__index = function(self, tag_name)
92-
---@param attributes { [string] : string, [integer] : (XML.Node | string | fun(): XML.Node) } | string
93-
---@return table | fun(children: (XML.Node | string | fun(): XML.Node)[]): XML.Node
94-
return function(attributes)
95-
---@type XML.Node
96-
local node = {
97-
tag = tag_name,
98-
children = {},
99-
attributes = {}
100-
}
101-
102-
--if we have a situation such as
103-
--[[
104-
tag "string"
105-
]]
106-
--
107-
--then the content is the `string`
108-
local tname = typename(attributes)
109-
if tname ~= "table" and tname ~= "HTML.Node" then
110-
node.attributes = attributes and { tostring(attributes) } or {}
111-
elseif tname == "XML.Node" then
112-
---local tag = div { p "hi" }
113-
---div(tag)
114-
node.children = { attributes }
115-
attributes = {}
116-
else
117-
node.attributes = attributes --[[@as any]]
118-
end
91+
---@class XML.GeneratorTable
92+
---@field [string] fun(attributes: XML.AttributeTable | string | XML.Node): XML.Node
93+
94+
---@type XML.GeneratorTable
95+
export.generator_metatable = setmetatable({}, {
96+
---@param self XML.GeneratorTable
97+
---@param tag_name string
98+
__index = function(self, tag_name)
99+
---@param attributes { [string] : string, [integer] : (XML.Node | string | fun(): XML.Node) } | string
100+
---@return table | fun(children: (XML.Node | string | fun(): XML.Node)[]): XML.Node
101+
return function(attributes)
102+
---@type XML.Node
103+
local node = {
104+
tag = tag_name,
105+
children = {},
106+
attributes = {}
107+
}
119108

120-
for i, v in ipairs(node.attributes) do
121-
if type(v) == "function" then
122-
export.declare_xml_generator(v)
123-
v = coroutine.wrap(v)
124-
for sub in v do
125-
node.children[#node.children + 1] = sub
126-
end
127-
else
128-
node.children[#node.children + 1] = v
129-
end
109+
--if we have a situation such as
110+
--[[
111+
tag "string"
112+
]]
113+
--
114+
--then the content is the `string`
115+
local tname = typename(attributes)
116+
if tname ~= "table" and tname ~= "HTML.Node" then
117+
node.attributes = attributes and { tostring(attributes) } or {}
118+
elseif tname == "XML.Node" then
119+
---local tag = div { p "hi" }
120+
---div(tag)
121+
node.children = { attributes }
122+
attributes = {}
123+
else
124+
node.attributes = attributes --[[@as any]]
125+
end
130126

131-
node.attributes[i] = nil
127+
for i, v in ipairs(node.attributes) do
128+
if type(v) == "function" then
129+
v = coroutine.wrap(v)
130+
for sub in v do
131+
node.children[#node.children + 1] = sub
132+
end
133+
else
134+
node.children[#node.children + 1] = v
132135
end
133136

134-
return setmetatable(node, {
135-
__type = "XML.Node",
137+
node.attributes[i] = nil
138+
end
136139

137-
__tostring = export.node_to_string,
140+
return setmetatable(node, {
141+
__type = "XML.Node",
138142

139-
---@param self XML.Node
140-
---@param children (XML.Node | string | fun(): XML.Node)[]
141-
__call = function(self, children)
142-
if type(children) ~= "table" then
143-
children = { tostring(children) }
144-
end
143+
__tostring = export.node_to_string,
145144

146-
for _, v in ipairs(children) do
147-
if type(v) == "function" then
148-
export.declare_xml_generator(v)
149-
v = coroutine.wrap(v)
150-
for sub in v do
151-
self.children[#self.children + 1] = sub
152-
end
153-
else
154-
self.children[#self.children + 1] = v
145+
---@param self XML.Node
146+
---@param children XML.Children
147+
__call = function(self, children)
148+
if type(children) ~= "table" then
149+
children = { tostring(children) }
150+
end
151+
152+
for _, v in ipairs(children) do
153+
if type(v) == "function" then
154+
v = coroutine.wrap(v)
155+
for sub in v do
156+
self.children[#self.children + 1] = sub
155157
end
158+
else
159+
self.children[#self.children + 1] = v
156160
end
157-
158-
return self
159161
end
160-
})
161-
end
162-
end
163-
})
164162

165-
setfenv(fn, tbl)
166-
return fn
167-
end
163+
return self
164+
end
165+
})
166+
end
167+
end
168+
})
168169

169170
---Usage:
170171
--[=[
@@ -188,48 +189,45 @@ end)
188189
189190
```
190191
]=]
191-
---@param ctx fun(): table
192-
---@return string
193-
function export.generate_xml(ctx)
194-
return export.node_to_string(export.declare_xml_generator(ctx)())
195-
end
196-
197-
---@param ctx fun(): table
192+
---@param ctx fun(html: XML.GeneratorTable): XML.Node
198193
---@return XML.Node
199-
function export.generate_xml_node(ctx)
200-
return export.declare_xml_generator(ctx)()
201-
end
194+
function export.generate_node(ctx) return ctx(export.generator_metatable) end
195+
196+
---@param ctx fun(html: XML.GeneratorTable): table
197+
---@return string
198+
function export.generate(ctx) return tostring(export.generate_node(ctx)) end
202199

203200
---Turns a lua table into an html table, recursively, with multiple levels of nesting
201+
---@param xml XML.GeneratorTable
204202
---@param tbl table
205203
---@return XML.Node
206-
function export.table(tbl)
204+
function export.html_table(xml, tbl)
207205
---@diagnostic disable: undefined-global
208-
return table {
206+
return xml.table {
209207
function()
210208
local function getval(v)
211209
if type(v) ~= "table" or (getmetatable(v) or {}).__tostring then
212210
return tostring(v)
213211
end
214-
return html_table(v)
212+
return export.html_table(xml, v)
215213
end
216214

217215
for i, v in ipairs(tbl) do
218-
yield(
219-
tr {
220-
td(tostring(i)),
221-
td(getval(v)),
216+
coroutine.yield (
217+
xml.tr {
218+
xml.td(tostring(i)),
219+
xml.td(getval(v)),
222220
}
223221
)
224222

225223
tbl[i] = nil
226224
end
227225

228226
for k, v in pairs(tbl) do
229-
yield(
230-
tr {
231-
td(tostring(k)),
232-
td(getval(v)),
227+
coroutine.yield (
228+
xml.tr {
229+
xml.td(tostring(k)),
230+
xml.td(getval(v)),
233231
}
234232
)
235233
end
@@ -238,8 +236,6 @@ function export.table(tbl)
238236
---@diagnostic enable: undefined-global
239237
end
240238

241-
export.declare_xml_generator(export.table)
242-
243239
---@alias OptionalStringCollection string | string[]
244240
---@param css { [OptionalStringCollection] : { [OptionalStringCollection] : (OptionalStringCollection) } }
245241
---@return XML.Node
@@ -257,11 +253,7 @@ function export.style(css)
257253
css_str = css_str .. "}\n"
258254
end
259255

260-
return export.generate_xml_node(function()
261-
---@diagnostic disable: undefined-global
262-
return style(css_str)
263-
---@diagnostic enable: undefined-global
264-
end)
256+
return export.generate_node(function(xml) return xml.style(css_str) end)
265257
end
266258

267259
return export

0 commit comments

Comments
 (0)