18
18
19
19
20
20
--- @class xml-generator
21
- local export = {}
21
+ local export = {
22
+ sanitize_style = false
23
+ }
22
24
23
25
--- @class XML.Children
24
- --- @field [ integer] XML.Node | string | fun (): XML.Node
26
+ --- @field [ integer] XML.Node | string
25
27
26
28
--- @class XML.AttributeTable : XML.Children
27
29
--- @field [ string] string | boolean | number
28
30
29
31
--- @class XML.Node
30
- --- @operator call (XML.Children ): XML.Node
32
+ --- @operator call (XML.AttributeTable ): XML.Node
31
33
--- @field tag string
32
34
--- @field children XML.Children
33
35
--- @field attributes XML.AttributeTable
@@ -50,125 +52,100 @@ function export.sanitize_attributes(str)
50
52
end
51
53
52
54
--- @param x any
53
- --- @return type | string
54
- local function typename (x )
55
+ --- @return type | " XML.Node " | string
56
+ function export . typename (x )
55
57
local mt = getmetatable (x )
56
58
if mt and mt .__name then
57
59
return mt .__name
58
60
else
59
61
return type (x )
60
62
end
61
63
end
64
+ local typename = export .typename
62
65
63
66
--- @param node XML.Node
64
67
--- @return string
65
68
function 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
67
73
68
74
for k , v in pairs (node .attributes ) do
69
75
if type (v ) == " boolean" then
70
- if v then html = html .. " " .. k end
76
+ if v then html = html .. " " .. k end
71
77
else
72
- html = html .. " " .. k .. " =\" " .. export .sanitize_attributes (tostring (v )) .. " \" "
78
+ html = html .. " " .. k .. " =\" " .. export .sanitize_attributes (tostring (v )).. " \" "
73
79
end
74
80
end
75
81
76
- html = html .. " >"
82
+ html = html .. " >"
77
83
78
84
for i , v in ipairs (node .children ) do
79
85
if type (v ) ~= " table" then
80
- html = html .. export .sanitize_text (tostring (v ))
86
+ html = html . .sanitize_text (tostring (v ))
81
87
else
82
- html = html .. export .node_to_string (v )
88
+ html = html .. export .node_to_string (v )
83
89
end
84
90
end
85
91
86
- html = html .. " </" .. node .tag .. " >"
92
+ html = html .. " </" .. node .tag .. " >"
87
93
88
94
return html
89
95
end
90
96
91
97
--- @class XML.GeneratorTable
92
- --- @field [ string] fun (attributes : XML.AttributeTable | string | XML.Node ): XML.Node
98
+ --- @field lua _G
99
+ --- @field [ string] XML.Node
93
100
94
101
--- @type XML.GeneratorTable
95
102
export .generator_metatable = setmetatable ({}, {
96
103
--- @param _ XML.GeneratorTable
97
104
--- @param tag_name string
98
105
__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
128
131
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
134
133
end
135
- else
136
- node .children [# node .children + 1 ] = v
137
- end
138
-
139
- node .attributes [i ] = nil
140
- end
141
134
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
152
137
end
138
+ else self .children [# self .children + 1 ] = tname == " XML.Node" and attribs or tostring (attribs ) end
153
139
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 ;
164
142
165
- return self
166
- end
167
- })
168
- end
143
+ __tostring = export .node_to_string
144
+ })
169
145
end
170
146
})
171
147
148
+
172
149
--- Usage:
173
150
--[=[
174
151
```lua
@@ -198,7 +175,7 @@ function export.generate_node(ctx) return ctx(export.generator_metatable) end
198
175
--- @generic T
199
176
--- @param func fun ( ... : T ): XML.Node
200
177
--- @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
202
179
203
180
--- @param ctx fun ( html : XML.GeneratorTable ): table
204
181
--- @return string
@@ -254,16 +231,17 @@ function export.style(css)
254
231
for selector , properties in pairs (css ) do
255
232
if type (selector ) == " table" then selector = table.concat (selector , " , " ) end
256
233
257
- css_str = css_str .. selector .. " {\n "
234
+ css_str = css_str .. selector .. " {\n "
258
235
for property , value in pairs (properties ) do
259
236
if type (value ) == " table" then value = table.concat (value , " , " ) end
260
237
261
- css_str = css_str .. " " .. property .. " : " .. value .. " ;\n "
238
+ css_str = css_str .. " " .. property .. " : " .. value .. " ;\n "
262
239
end
263
- css_str = css_str .. " }\n "
240
+ css_str = css_str .. " }\n "
264
241
end
265
242
266
243
return export .generate_node (function (xml ) return xml .style (css_str ) end )
267
244
end
268
245
246
+
269
247
return export
0 commit comments