@@ -13,238 +13,72 @@ import SwiftDiagnostics
1313
1414struct HTMLElement : ExpressionMacro {
1515 static func expansion( of node: some FreestandingMacroExpansionSyntax , in context: some MacroExpansionContext ) throws -> ExprSyntax {
16- let arguments : LabeledExprListSyntax = node. arguments
16+ return " \( raw: parse_element ( node: node, context: context) ) "
17+ }
18+ }
19+
20+ extension HTMLElement {
21+ static func parse_element( node: some FreestandingMacroExpansionSyntax , context: some MacroExpansionContext ) -> String {
1722 let macroName : String = node. macroName. text
18- var type : HTMLElementType = HTMLElementType ( rawValue: macroName) ?? HTMLElementType . a
19- var attributes : [ String ] = [ ] , extra_attributes : [ String ] = [ ]
20- var items : [ Item ] = [ ]
23+ let type : HTMLElementType = HTMLElementType ( rawValue: macroName) ?? HTMLElementType . a
24+ let data : ElementData = parse_arguments ( arguments: node. arguments)
25+ var string : String = ( type == . html ? " <!DOCTYPE html> " : " " ) + " < " + type. rawValue + data. attributes + " > " + data. innerHTML
26+ if !type. isVoid {
27+ string += " </ " + type. rawValue + " > "
28+ }
29+ return " \" " + string + " \" "
30+ }
31+ static func parse_arguments( arguments: LabeledExprListSyntax ) -> ElementData {
32+ var attributes : [ String ] = [ ]
33+ var innerHTML : [ String ] = [ ]
2134 for element in arguments. children ( viewMode: . all) {
2235 if let child: LabeledExprSyntax = element. as ( LabeledExprSyntax . self) {
2336 if let key: String = child. label? . text {
2437 switch key {
25- case " elementType " :
26- type = HTMLElementType ( rawValue: child. expression. as ( MemberAccessExprSyntax . self) !. declName. baseName. text) ?? HTMLElementType . div
27- break
2838 case " attributes " :
2939 attributes = parse_attributes ( child: child)
3040 break
31- case " accept " ,
32- " alt " ,
33- " as " ,
34- " attributionsrc " ,
35- " autocomplete " ,
36- " autoplay " ,
37- " blocking " ,
38- " browsingtopics " ,
39- " capture " ,
40- " charset " ,
41- " checked " ,
42- " cite " ,
43- " cols " ,
44- " coords " ,
45- " content " ,
46- " controls " ,
47- " controlslist " ,
48- " credentialless " ,
49- " crossorigin " ,
50- " csp " ,
51- " datetime " ,
52- " decoding " ,
53- " default " ,
54- " defer " ,
55- " dirname " ,
56- " disabled " ,
57- " disablepictureinpicture " ,
58- " disableremoteplayback " ,
59- " download " ,
60- " elementtiming " ,
61- " fetchpriority " ,
62- " for " ,
63- " form " ,
64- " formaction " ,
65- " formenctype " ,
66- " formmethod " ,
67- " formnovalidate " ,
68- " formtarget " ,
69- " height " ,
70- " high " ,
71- " href " ,
72- " hreflang " ,
73- " httpEquiv " ,
74- " imagesizes " ,
75- " integrity " ,
76- " ismap " ,
77- " kind " ,
78- " label " ,
79- " list " ,
80- " loading " ,
81- " loop " ,
82- " low " ,
83- " max " ,
84- " maxlength " ,
85- " media " ,
86- " min " ,
87- " minlength " ,
88- " multiple " ,
89- " muted " ,
90- " name " ,
91- " nomodule " ,
92- " onafterprint " ,
93- " onbeforeprint " ,
94- " onbeforeunload " ,
95- " onblur " ,
96- " onerror " ,
97- " onfocus " ,
98- " onhashchange " ,
99- " onlanguagechange " ,
100- " onload " ,
101- " onmessage " ,
102- " onoffline " ,
103- " ononline " ,
104- " onpopstate " ,
105- " onresize " ,
106- " onstorange " ,
107- " onunload " ,
108- " open " ,
109- " optimum " ,
110- " pattern " ,
111- " ping " ,
112- " placeholder " ,
113- " playsinline " ,
114- " popovertarget " ,
115- " popovertargetaction " ,
116- " poster " ,
117- " preload " ,
118- " readonly " ,
119- " referrerpolicy " ,
120- " rel " ,
121- " reversed " ,
122- " required " ,
123- " rows " ,
124- " sandbox " ,
125- " scope " ,
126- " selected " ,
127- " shadowrootclonable " ,
128- " shadowrootdelegatesfocus " ,
129- " shadowrootmode " ,
130- " shadowrootserializable " ,
131- " shape " ,
132- " size " ,
133- " sizes " ,
134- " src " ,
135- " srcdoc " ,
136- " srclang " ,
137- " srcset " ,
138- " start " ,
139- " step " ,
140- " target " ,
141- " template " ,
142- " type " ,
143- " usemap " ,
144- " value " ,
145- " width " ,
146- " wrap " ,
147- " xmlns " :
148- let string : String = parse_extra_attribute ( child: child)
149- if !string. isEmpty {
150- extra_attributes. append ( string)
151- }
152- break
15341 case " innerHTML " :
154- let array : ArrayElementListSyntax = child. expression. as ( ArrayExprSyntax . self) !. elements
155- parse_body ( node: node, context: context, macroName: macroName, array: array, items: & items)
42+ innerHTML = parse_inner_html ( child: child)
15643 break
157- default :
44+ default : // extra attribute
45+ if let string: String = parse_extra_attribute ( child: child) {
46+ attributes. append ( string)
47+ }
15848 break
15949 }
160- } else if let array: ArrayElementListSyntax = child. expression. as ( ArrayExprSyntax . self) ? . elements {
161- parse_body ( node: node, context: context, macroName: macroName, array: array, items: & items)
16250 }
16351 }
16452 }
165- let attributes_string : String = attributes. isEmpty ? " " : " " + attributes. joined ( separator: " " )
166- let extra_attributes_string : String = extra_attributes. isEmpty ? " " : " " + extra_attributes. joined ( separator: " " )
167- var string : String = ( type == . html ? " \" <!DOCTYPE html> " : " \" " ) + " < " + type. rawValue + attributes_string + extra_attributes_string + " > "
168- if !items. isEmpty {
169- string += " \" "
170- }
171- for item in items {
172- string += " + " + item. string
173- }
174- if !type. isVoid {
175- string += ( items. isEmpty ? " " : " + \" " ) + " </ " + type. rawValue + " > \" "
176- }
177- return " \( raw: string) "
53+ return ElementData ( attributes: attributes, innerHTML: innerHTML)
17854 }
179- private static func parse_body( node: some FreestandingMacroExpansionSyntax , context: some MacroExpansionContext , macroName: String , array: ArrayElementListSyntax , items: inout [ Item ] ) {
180- for element in array {
181- if let test: MacroExpansionExprSyntax = element. expression. as ( MacroExpansionExprSyntax . self) {
182- let key : String
183- let recursive : Bool = macroName == test. macroName. text
184- if recursive { // swift macro limitation
185- key = " #HTMLElement(elementType: . " + test. macroName. text + " , "
186- } else {
187- if test. macroName. text == " HTMLElement " {
188- items. append ( Item ( isMacro: true , value: " \( test) " ) )
189- break
190- } else {
191- key = " # " + test. macroName. text + " ( "
192- }
193- }
194- var values : [ String ] = [ ]
195- for child in test. arguments. children ( viewMode: . all) {
196- let label : LabeledExprSyntax = child. as ( LabeledExprSyntax . self) !, key : String = label. label!. text + " : " , expression : ExprSyntax = label. expression
197- var string : String = " "
198- if let array: ArrayElementListSyntax = expression. as ( ArrayExprSyntax . self) ? . elements {
199- var body_items : [ Item ] = [ ]
200- parse_body ( node: node, context: context, macroName: macroName, array: array, items: & body_items)
201- string = key + " [ " + body_items. map ( { $0. string } ) . joined ( separator: " , " ) + " ] "
202- } else {
203- string = key + " \( expression) "
204- }
205- if !string. isEmpty {
206- values. append ( string)
207- }
208- }
209- if recursive && values. isEmpty {
210- values. append ( " innerHTML: [] " )
211- }
212- items. append ( Item ( isMacro: true , value: key + values. joined ( separator: " , " ) + " ) " ) )
213- } else if let text: String = element. expression. as ( StringLiteralExprSyntax . self) ? . string {
214- items. append ( Item ( isMacro: false , value: text) )
215- } else {
216- var string : String = " \( element) "
217- while string [ string. startIndex] . isWhitespace {
218- string. removeFirst ( )
219- }
220- while string [ string. index ( before: string. endIndex) ] . isWhitespace || string [ string. index ( before: string. endIndex) ] == " , " {
221- string. removeLast ( )
222- }
223- var jugs : [ Character ] = [ ] , offset : Int = 1
224- while string [ string. index ( string. startIndex, offsetBy: offset) ] != " ( " {
225- jugs. append ( string [ string. index ( string. startIndex, offsetBy: offset) ] )
226- offset += 1
227- }
228- if string [ string. index ( string. startIndex, offsetBy: offset + 1 ) ] == " . " {
229- let ez : String = String ( jugs)
230- string. insert ( contentsOf: " HTMLElementAttribute. " + ez[ ez. startIndex] . uppercased ( ) + ez[ ez. index ( after: ez. startIndex) ... ] , at: string. index ( string. startIndex, offsetBy: offset+ 1 ) )
231- }
232- if !string. starts ( with: " HTMLElementAttribute " ) {
233- string. insert ( contentsOf: " HTMLElementAttribute " , at: string. startIndex)
55+ static func parse_element_macro( expression: MacroExpansionExprSyntax ) -> String {
56+ guard let elementType: HTMLElementType = HTMLElementType ( rawValue: expression. macroName. text) else { return " \( expression) " }
57+ let data : ElementData = parse_arguments ( arguments: expression. arguments)
58+ return " < " + elementType. rawValue + data. attributes + " > " + data. innerHTML + ( elementType. isVoid ? " " : " </ " + elementType. rawValue + " > " )
59+ }
60+ static func parse_inner_html( child: LabeledExprSyntax ) -> [ String ] {
61+ var innerHTML : [ String ] = [ ]
62+ if let array: ArrayElementListSyntax = child. expression. as ( ArrayExprSyntax . self) ? . elements {
63+ for yoink in array {
64+ if let macro: MacroExpansionExprSyntax = yoink. expression. as ( MacroExpansionExprSyntax . self) {
65+ innerHTML. append ( parse_element_macro ( expression: macro) )
66+ } else if let string: String = yoink. expression. as ( StringLiteralExprSyntax . self) ? . string {
67+ innerHTML. append ( string)
23468 }
235- items. append ( Item ( isMacro: true , value: string) )
23669 }
23770 }
71+ return innerHTML
23872 }
23973}
24074
241- extension HTMLElement {
242- struct Item {
243- let string : String
75+ struct ElementData {
76+ let attributes : String
77+ let innerHTML : String
24478
245- init ( isMacro : Bool , value : String ) {
246- string = isMacro ? value : " \" " + value + " \" "
247- }
79+ init ( attributes : [ String ] , innerHTML : [ String ] ) {
80+ self . attributes = attributes . isEmpty ? " " : " " + attributes . joined ( separator : " " )
81+ self . innerHTML = innerHTML . joined ( )
24882 }
24983}
25084
@@ -332,14 +166,14 @@ private extension HTMLElement {
332166 return function. arguments. first!. expression. as ( ArrayExprSyntax . self) !. elements. map ( { $0. expression. as ( StringLiteralExprSyntax . self) !. string } )
333167 }
334168
335- static func parse_extra_attribute( child: LabeledExprSyntax ) -> String {
169+ static func parse_extra_attribute( child: LabeledExprSyntax ) -> String ? {
336170 let key : String = child. label!. text
337171 func yup( _ value: String ) -> String {
338172 return key + " = \\ \" " + value + " \\ \" "
339173 }
340174 let expression : ExprSyntax = child. expression
341175 if let boolean: String = expression. as ( BooleanLiteralExprSyntax . self) ? . literal. text {
342- return boolean. elementsEqual ( " true " ) ? key : " "
176+ return boolean. elementsEqual ( " true " ) ? key : nil
343177 }
344178 if let string: String = expression. as ( StringLiteralExprSyntax . self) ? . string {
345179 return yup ( string)
@@ -348,15 +182,15 @@ private extension HTMLElement {
348182 return yup ( " \\ (HTMLElementAttribute. " + key[ key. startIndex] . uppercased ( ) + key[ key. index ( after: key. startIndex) ... ] + " . " + member + " ) " )
349183 }
350184 if let _: NilLiteralExprSyntax = expression. as ( NilLiteralExprSyntax . self) {
351- return " "
185+ return nil
352186 }
353187 if let integer: String = expression. as ( IntegerLiteralExprSyntax . self) ? . literal. text {
354188 return yup ( integer)
355189 }
356190 if let float: String = expression. as ( FloatLiteralExprSyntax . self) ? . literal. text {
357191 return yup ( float)
358192 }
359- return " "
193+ return nil
360194 }
361195}
362196
0 commit comments