@@ -10,23 +10,13 @@ import SwiftSyntax
10
10
import SwiftSyntaxMacros
11
11
12
12
enum HTMLElements : DeclarationMacro {
13
+ // MARK: expansion
13
14
static func expansion( of node: some FreestandingMacroExpansionSyntax , in context: some MacroExpansionContext ) throws -> [ DeclSyntax ] {
14
15
let dictionary : DictionaryElementListSyntax = node. arguments. children ( viewMode: . all) . first!. as ( LabeledExprSyntax . self) !. expression. as ( DictionaryExprSyntax . self) !. content. as ( DictionaryElementListSyntax . self) !
15
16
16
17
var items : [ DeclSyntax ] = [ ]
17
18
items. reserveCapacity ( dictionary. count)
18
19
19
- func separator( key: String ) -> String {
20
- switch key {
21
- case " accept " , " coords " , " exportparts " , " imagesizes " , " imagesrcset " , " sizes " , " srcset " :
22
- return " , "
23
- case " allow " :
24
- return " ; "
25
- default :
26
- return " "
27
- }
28
- }
29
-
30
20
let void_elements : Set < String > = [
31
21
" area " , " base " , " br " , " col " , " embed " , " hr " , " img " , " input " , " link " , " meta " , " source " , " track " , " wbr "
32
22
]
@@ -92,22 +82,21 @@ enum HTMLElements : DeclarationMacro {
92
82
}
93
83
string += attribute_declarations
94
84
95
- initializers += " \n public init( \n "
96
- initializers += " attributes: [HTMLAttribute] = [], \n "
97
- for (key, value_type, default_value) in attributes {
98
- initializers += key + " : " + value_type + default_value + " , \n "
99
- }
100
- initializers += " _ innerHTML: CustomStringConvertible & Sendable... \n ) { \n "
101
- initializers += " self.attributes = attributes \n "
102
- for (key, _, _) in attributes {
103
- var keyLiteral = key
104
- if keyLiteral. first == " ` " {
105
- keyLiteral. removeFirst ( )
106
- keyLiteral. removeLast ( )
107
- }
108
- initializers += " self. \( keyLiteral) = \( key) \n "
109
- }
110
- initializers += " self.innerHTML = innerHTML \n } \n "
85
+ initializers += " \n " + defaultInitializer(
86
+ attributes: attributes,
87
+ innerHTMLValueType: " [CustomStringConvertible & Sendable] = [] " ,
88
+ assignInnerHTML: " innerHTML "
89
+ )
90
+ initializers += " \n " + defaultInitializer(
91
+ attributes: attributes,
92
+ innerHTMLValueType: " CustomStringConvertible & Sendable... " ,
93
+ assignInnerHTML: " innerHTML "
94
+ )
95
+ initializers += " \n " + defaultInitializer(
96
+ attributes: attributes,
97
+ innerHTMLValueType: " () -> CustomStringConvertible & Sendable... " ,
98
+ assignInnerHTML: " innerHTML.map { $0() } "
99
+ )
111
100
112
101
initializers += " public init(_ encoding: HTMLEncoding, _ data: HTMLKitUtilities.ElementData) { \n "
113
102
initializers += " self.encoding = encoding \n "
@@ -116,14 +105,14 @@ enum HTMLElements : DeclarationMacro {
116
105
initializers += " self.trailingSlash = data.trailingSlash \n "
117
106
}
118
107
initializers += " self.attributes = data.globalAttributes \n "
119
- for (key, value_type , _) in attributes {
108
+ for (key, valueType , _) in attributes {
120
109
var keyLiteral = key
121
110
if keyLiteral. first == " ` " {
122
111
keyLiteral. removeFirst ( )
123
112
keyLiteral. removeLast ( )
124
113
}
125
- var value = " as? \( value_type ) "
126
- switch value_type {
114
+ var value = " as? \( valueType ) "
115
+ switch valueType {
127
116
case " Bool " :
128
117
value += " ?? false "
129
118
default :
@@ -142,24 +131,22 @@ enum HTMLElements : DeclarationMacro {
142
131
attributes_func += " let sd = encoding.stringDelimiter(forMacro: fromMacro) \n "
143
132
itemsArray += " var items:[String] = [] \n "
144
133
}
145
- for (key, value_type , _) in attributes {
134
+ for (key, valueType , _) in attributes {
146
135
var keyLiteral = key
147
136
if keyLiteral. first == " ` " {
148
137
keyLiteral. removeFirst ( )
149
138
keyLiteral. removeLast ( )
150
139
}
151
- let variable_name = keyLiteral
152
- if keyLiteral == " httpEquiv " {
153
- keyLiteral = " http-equiv "
154
- } else if keyLiteral == " acceptCharset " {
155
- keyLiteral = " accept-charset "
140
+ let variableName = keyLiteral
141
+ switch keyLiteral {
142
+ case " httpEquiv " : keyLiteral = " http-equiv "
143
+ case " acceptCharset " : keyLiteral = " accept-charset "
144
+ default : break
156
145
}
157
- if value_type == " Bool " {
158
- itemsArray += " if \( key) { items.append( \" \( keyLiteral) \" ) } \n "
159
- } else if value_type. first == " [ " {
160
- itemsArray += " if let _ \( variable_name) :String = "
146
+ if valueType. first == " [ " {
147
+ itemsArray += " if let _ \( variableName) :String = "
161
148
let separator = separator ( key: key)
162
- switch value_type {
149
+ switch valueType {
163
150
case " [String] " :
164
151
itemsArray += " \( key) ? "
165
152
case " [Int] " , " [Float] " :
@@ -168,18 +155,23 @@ enum HTMLElements : DeclarationMacro {
168
155
itemsArray += " \( key) ?.compactMap({ return $0.htmlValue(encoding: encoding, forMacro: fromMacro) }) "
169
156
}
170
157
itemsArray += " .joined(separator: \" \( separator) \" ) { \n "
171
- itemsArray += #"let k:String = _ \#( variable_name ) .isEmpty ? "" : "=" + sd + _ \#( variable_name ) + sd"#
158
+ itemsArray += #"let k:String = _ \#( variableName ) .isEmpty ? "" : "=" + sd + _ \#( variableName ) + sd"#
172
159
itemsArray += " \n items.append( \" \( keyLiteral) \" + k) "
173
160
itemsArray += " \n } \n "
174
- } else if value_type == " String " || value_type == " Int " || value_type == " Float " || value_type == " Double " {
175
- let value = value_type == " String " ? key : " String(describing: \( key) ) "
176
- itemsArray += #"if let \#( key) { items.append(" \#( keyLiteral) =" + sd + \#( value) + sd) }"#
177
- itemsArray += " \n "
178
161
} else {
179
- itemsArray += " if let \( key) , let v = \( key) .htmlValue(encoding: encoding, forMacro: fromMacro) { \n "
180
- itemsArray += #"let s = \#( key) .htmlValueIsVoidable && v.isEmpty ? "" : "=" + sd + v + sd"#
181
- itemsArray += " \n items.append( \" \( keyLiteral) \" + s) "
182
- itemsArray += " \n } \n "
162
+ switch valueType {
163
+ case " Bool " :
164
+ itemsArray += " if \( key) { items.append( \" \( keyLiteral) \" ) } \n "
165
+ case " String " , " Int " , " Float " , " Double " :
166
+ let value = valueType == " String " ? key : " String(describing: \( key) ) "
167
+ itemsArray += #"if let \#( key) { items.append(" \#( keyLiteral) =" + sd + \#( value) + sd) }"#
168
+ itemsArray += " \n "
169
+ default :
170
+ itemsArray += " if let \( key) , let v = \( key) .htmlValue(encoding: encoding, forMacro: fromMacro) { \n "
171
+ itemsArray += #"let s = \#( key) .htmlValueIsVoidable && v.isEmpty ? "" : "=" + sd + v + sd"#
172
+ itemsArray += " \n items.append( \" \( keyLiteral) \" + s) "
173
+ itemsArray += " \n } \n "
174
+ }
183
175
}
184
176
}
185
177
render += attributes_func + itemsArray
@@ -199,6 +191,41 @@ enum HTMLElements : DeclarationMacro {
199
191
}
200
192
return items
201
193
}
194
+ // MARK: separator
195
+ static func separator( key: String ) -> String {
196
+ switch key {
197
+ case " accept " , " coords " , " exportparts " , " imagesizes " , " imagesrcset " , " sizes " , " srcset " :
198
+ return " , "
199
+ case " allow " :
200
+ return " ; "
201
+ default :
202
+ return " "
203
+ }
204
+ }
205
+ // MARK: default initializer
206
+ static func defaultInitializer(
207
+ attributes: [ ( String , String , String ) ] ,
208
+ innerHTMLValueType: String ,
209
+ assignInnerHTML: String
210
+ ) -> String {
211
+ var initializers = " public init( \n "
212
+ initializers += " attributes: [HTMLAttribute] = [], \n "
213
+ for (key, valueType, defaultValue) in attributes {
214
+ initializers += key + " : " + valueType + defaultValue + " , \n "
215
+ }
216
+ initializers += " _ innerHTML: \( innerHTMLValueType) \n ) { \n "
217
+ initializers += " self.attributes = attributes \n "
218
+ for (key, _, _) in attributes {
219
+ var keyLiteral = key
220
+ if keyLiteral. first == " ` " {
221
+ keyLiteral. removeFirst ( )
222
+ keyLiteral. removeLast ( )
223
+ }
224
+ initializers += " self. \( keyLiteral) = \( key) \n "
225
+ }
226
+ initializers += " self.innerHTML = \( assignInnerHTML) \n } \n "
227
+ return initializers
228
+ }
202
229
// MARK: parse value type
203
230
static func parse_value_type( isArray: inout Bool , key: String , _ expr: ExprSyntax ) -> ( value_type: String , default_value: String , value_type_literal: HTMLElementValueType ) {
204
231
let value_type_key : String
0 commit comments