1818
1919
2020--- @class xml-generator
21- local export = {}
21+ local export = {
22+ sanitize_style = false
23+ }
2224
2325--- @class XML.Children
24- --- @field [ integer] XML.Node | string | fun (): XML.Node
26+ --- @field [ integer] XML.Node | string
2527
2628--- @class XML.AttributeTable : XML.Children
2729--- @field [ string] string | boolean | number
2830
2931--- @class XML.Node
30- --- @operator call (XML.Children ): XML.Node
32+ --- @operator call (XML.AttributeTable ): XML.Node
3133--- @field tag string
3234--- @field children XML.Children
3335--- @field attributes XML.AttributeTable
@@ -50,125 +52,100 @@ function export.sanitize_attributes(str)
5052end
5153
5254--- @param x any
53- --- @return type | string
54- local function typename (x )
55+ --- @return type | " XML.Node " | string
56+ function export . typename (x )
5557 local mt = getmetatable (x )
5658 if mt and mt .__name then
5759 return mt .__name
5860 else
5961 return type (x )
6062 end
6163end
64+ local typename = export .typename
6265
6366--- @param node XML.Node
6467--- @return string
6568function export .node_to_string (node )
66- local html = " <" .. node .tag
69+ local sanitize = (not export .sanitize_style ) and node .tag ~= " style"
70+ local sanitize_text = sanitize and export .sanitize_text or function (...) return ... end
71+
72+ local html = " <" .. node .tag
6773
6874 for k , v in pairs (node .attributes ) do
6975 if type (v ) == " boolean" then
70- if v then html = html .. " " .. k end
76+ if v then html = html .. " " .. k end
7177 else
72- html = html .. " " .. k .. " =\" " .. export .sanitize_attributes (tostring (v )) .. " \" "
78+ html = html .. " " .. k .. " =\" " .. export .sanitize_attributes (tostring (v )).. " \" "
7379 end
7480 end
7581
76- html = html .. " >"
82+ html = html .. " >"
7783
7884 for i , v in ipairs (node .children ) do
7985 if type (v ) ~= " table" then
80- html = html .. export .sanitize_text (tostring (v ))
86+ html = html . .sanitize_text (tostring (v ))
8187 else
82- html = html .. export .node_to_string (v )
88+ html = html .. export .node_to_string (v )
8389 end
8490 end
8591
86- html = html .. " </" .. node .tag .. " >"
92+ html = html .. " </" .. node .tag .. " >"
8793
8894 return html
8995end
9096
9197--- @class XML.GeneratorTable
92- --- @field [ string] fun (attributes : XML.AttributeTable | string | XML.Node ): XML.Node
98+ --- @field lua _G
99+ --- @field [ string] XML.Node
93100
94101--- @type XML.GeneratorTable
95102export .generator_metatable = setmetatable ({}, {
96103 --- @param _ XML.GeneratorTable
97104 --- @param tag_name string
98105 __index = function (_ , 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- }
108-
109- -- if we have a situation such as
110- --- ```lua
111- --- tag "string"
112- --- ```
113- --
114- -- then the content is the `string`
115- local tname = typename (attributes )
116- if tname ~= " table" and tname ~= " XML.Node" then
117- node .attributes = attributes and { tostring (attributes ) } or {}
118- elseif tname == " XML.Node" then
119-
120- --- ```lua
121- --- local tag = div { p "hi" }
122- --- div(tag)
123- --- ```
124- node .children = { attributes }
125- else
126- node .attributes = attributes --[[ @as any]]
127- end
106+ -- When used
107+ if tag_name == " lua" then return _G end
108+
109+ --- @type XML.Node
110+ local node = {
111+ tag = tag_name ,
112+ children = {},
113+ attributes = {}
114+ }
115+ return setmetatable (node , {
116+ --- @param self XML.Node
117+ --- @param attribs XML.AttributeTable | string | XML.Node
118+ --- @return XML.Node
119+ __call = function (self , attribs )
120+ local tname = typename (attribs )
121+ if tname == " table" then
122+ for i , v in ipairs (attribs --[[ @as (string | XML.Node | fun(): XML.Node)[] ]] ) do
123+ local tname = typename (v )
124+ if tname == " function" then
125+ --- @type fun (): XML.Node | string
126+ v = coroutine.wrap (v )
127+ for elem in v do self .children [# self .children + 1 ] = elem end
128+ else
129+ self .children [# self .children + 1 ] = v
130+ end
128131
129- for i , v in ipairs (node .attributes ) do
130- if type (v ) == " function" then
131- v = coroutine.wrap (v )
132- for sub in v do
133- node .children [# node .children + 1 ] = sub
132+ attribs [i ] = nil
134133 end
135- else
136- node .children [# node .children + 1 ] = v
137- end
138-
139- node .attributes [i ] = nil
140- end
141134
142- return setmetatable (node , {
143- __name = " XML.Node" ,
144-
145- __tostring = export .node_to_string ,
146-
147- --- @param self XML.Node
148- --- @param children XML.Children
149- __call = function (self , children )
150- if type (children ) ~= " table" then
151- children = { tostring (children ) }
135+ for key , value in pairs (attribs --[[ @as { [string] : string | boolean | number }]] ) do
136+ self .attributes [key ] = value
152137 end
138+ else self .children [# self .children + 1 ] = tname == " XML.Node" and attribs or tostring (attribs ) end
153139
154- for _ , v in ipairs (children ) do
155- if type (v ) == " function" then
156- v = coroutine.wrap (v )
157- for sub in v do
158- self .children [# self .children + 1 ] = sub
159- end
160- else
161- self .children [# self .children + 1 ] = v
162- end
163- end
140+ return self
141+ end ;
164142
165- return self
166- end
167- })
168- end
143+ __tostring = export .node_to_string
144+ })
169145 end
170146})
171147
148+
172149--- Usage:
173150--[=[
174151```lua
@@ -198,7 +175,7 @@ function export.generate_node(ctx) return ctx(export.generator_metatable) end
198175--- @generic T
199176--- @param func fun ( ... : T ): XML.Node
200177--- @return fun ( ... : T ): XML.Node
201- function export .declare_generator (func ) return setfenv (func , table ) end
178+ function export .declare_generator (func ) return setfenv (func , export . generator_metatable ) end
202179
203180--- @param ctx fun ( html : XML.GeneratorTable ): table
204181--- @return string
@@ -254,16 +231,17 @@ function export.style(css)
254231 for selector , properties in pairs (css ) do
255232 if type (selector ) == " table" then selector = table.concat (selector , " , " ) end
256233
257- css_str = css_str .. selector .. " {\n "
234+ css_str = css_str .. selector .. " {\n "
258235 for property , value in pairs (properties ) do
259236 if type (value ) == " table" then value = table.concat (value , " , " ) end
260237
261- css_str = css_str .. " " .. property .. " : " .. value .. " ;\n "
238+ css_str = css_str .. " " .. property .. " : " .. value .. " ;\n "
262239 end
263- css_str = css_str .. " }\n "
240+ css_str = css_str .. " }\n "
264241 end
265242
266243 return export .generate_node (function (xml ) return xml .style (css_str ) end )
267244end
268245
246+
269247return export
0 commit comments