@@ -10,23 +10,13 @@ import SwiftSyntax
1010import SwiftSyntaxMacros
1111
1212enum HTMLElements : DeclarationMacro {
13+ // MARK: expansion
1314 static func expansion( of node: some FreestandingMacroExpansionSyntax , in context: some MacroExpansionContext ) throws -> [ DeclSyntax ] {
1415 let dictionary : DictionaryElementListSyntax = node. arguments. children ( viewMode: . all) . first!. as ( LabeledExprSyntax . self) !. expression. as ( DictionaryExprSyntax . self) !. content. as ( DictionaryElementListSyntax . self) !
1516
1617 var items : [ DeclSyntax ] = [ ]
1718 items. reserveCapacity ( dictionary. count)
1819
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-
3020 let void_elements : Set < String > = [
3121 " area " , " base " , " br " , " col " , " embed " , " hr " , " img " , " input " , " link " , " meta " , " source " , " track " , " wbr "
3222 ]
@@ -92,22 +82,21 @@ enum HTMLElements : DeclarationMacro {
9282 }
9383 string += attribute_declarations
9484
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+ )
111100
112101 initializers += " public init(_ encoding: HTMLEncoding, _ data: HTMLKitUtilities.ElementData) { \n "
113102 initializers += " self.encoding = encoding \n "
@@ -116,14 +105,14 @@ enum HTMLElements : DeclarationMacro {
116105 initializers += " self.trailingSlash = data.trailingSlash \n "
117106 }
118107 initializers += " self.attributes = data.globalAttributes \n "
119- for (key, value_type , _) in attributes {
108+ for (key, valueType , _) in attributes {
120109 var keyLiteral = key
121110 if keyLiteral. first == " ` " {
122111 keyLiteral. removeFirst ( )
123112 keyLiteral. removeLast ( )
124113 }
125- var value = " as? \( value_type ) "
126- switch value_type {
114+ var value = " as? \( valueType ) "
115+ switch valueType {
127116 case " Bool " :
128117 value += " ?? false "
129118 default :
@@ -142,24 +131,22 @@ enum HTMLElements : DeclarationMacro {
142131 attributes_func += " let sd = encoding.stringDelimiter(forMacro: fromMacro) \n "
143132 itemsArray += " var items:[String] = [] \n "
144133 }
145- for (key, value_type , _) in attributes {
134+ for (key, valueType , _) in attributes {
146135 var keyLiteral = key
147136 if keyLiteral. first == " ` " {
148137 keyLiteral. removeFirst ( )
149138 keyLiteral. removeLast ( )
150139 }
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
156145 }
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 = "
161148 let separator = separator ( key: key)
162- switch value_type {
149+ switch valueType {
163150 case " [String] " :
164151 itemsArray += " \( key) ? "
165152 case " [Int] " , " [Float] " :
@@ -168,18 +155,23 @@ enum HTMLElements : DeclarationMacro {
168155 itemsArray += " \( key) ?.compactMap({ return $0.htmlValue(encoding: encoding, forMacro: fromMacro) }) "
169156 }
170157 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"#
172159 itemsArray += " \n items.append( \" \( keyLiteral) \" + k) "
173160 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 "
178161 } 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+ }
183175 }
184176 }
185177 render += attributes_func + itemsArray
@@ -199,6 +191,41 @@ enum HTMLElements : DeclarationMacro {
199191 }
200192 return items
201193 }
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+ }
202229 // MARK: parse value type
203230 static func parse_value_type( isArray: inout Bool , key: String , _ expr: ExprSyntax ) -> ( value_type: String , default_value: String , value_type_literal: HTMLElementValueType ) {
204231 let value_type_key : String
0 commit comments