@@ -20,8 +20,7 @@ import struct NIOCore.ByteBuffer
2020
2121enum HTMLElement : ExpressionMacro {
2222 static func expansion( of node: some FreestandingMacroExpansionSyntax , in context: some MacroExpansionContext ) throws -> ExprSyntax {
23- let string : String = parse_macro ( context: context, expression: node. as ( MacroExpansionExprSyntax . self) !)
24- let has_interpolation : Bool = !string. ranges ( of: try ! Regex ( " \\ ((.*) \\ ) " ) ) . isEmpty
23+ let string : String = parse_macro ( context: context, expression: node. macroExpansion!)
2524 var set : Set < HTMLElementType ? > = [ . htmlUTF8Bytes, . htmlUTF16Bytes, . htmlUTF8CString]
2625
2726 #if canImport(Foundation)
@@ -33,6 +32,7 @@ enum HTMLElement : ExpressionMacro {
3332 #endif
3433
3534 if set. contains ( HTMLElementType ( rawValue: node. macroName. text) ) {
35+ let has_interpolation : Bool = !string. ranges ( of: try ! Regex ( " \\ ((.*) \\ ) " ) ) . isEmpty
3636 guard !has_interpolation else {
3737 context. diagnose ( Diagnostic ( node: node, message: DiagnosticMsg ( id: " interpolationNotAllowedForDataType " , message: " String Interpolation is not allowed for this data type. Runtime values get converted to raw text, which is not the expected result. " ) ) )
3838 return " "
@@ -66,6 +66,7 @@ enum HTMLElement : ExpressionMacro {
6666}
6767
6868private extension HTMLElement {
69+ // MARK: Parse Macro
6970 static func parse_macro( context: some MacroExpansionContext , expression: MacroExpansionExprSyntax ) -> String {
7071 guard let elementType: HTMLElementType = HTMLElementType ( rawValue: expression. macroName. text) else { return " \( expression) " }
7172 let childs : SyntaxChildren = expression. arguments. children ( viewMode: . all)
@@ -94,6 +95,7 @@ private extension HTMLElement {
9495 }
9596 return string
9697 }
98+ // MARK: Parse Arguments
9799 static func parse_arguments( context: some MacroExpansionContext , elementType: HTMLElementType , children: Slice < SyntaxChildren > ) -> ElementData {
98100 var attributes : [ String ] = [ ] , innerHTML : [ String ] = [ ]
99101 for element in children {
@@ -118,14 +120,15 @@ private extension HTMLElement {
118120 }
119121 return ElementData ( attributes: attributes, innerHTML: innerHTML)
120122 }
123+ // MARK: Parse Global Attributes
121124 static func parse_global_attributes( context: some MacroExpansionContext , elementType: HTMLElementType , array: ArrayExprSyntax ) -> [ String ] {
122125 var keys : Set < String > = [ ] , attributes : [ String ] = [ ]
123126 for element in array. elements {
124127 let function : FunctionCallExprSyntax = element. expression. as ( FunctionCallExprSyntax . self) !, key_argument : LabeledExprSyntax = function. arguments. first!, key_element : ExprSyntax = key_argument. expression
125128 var key : String = function. calledExpression. memberAccess!. declName. baseName. text, value : String ? = nil
126129 switch key {
127130 case " custom " , " data " :
128- var ( literalValue, returnType) : ( String , LiteralReturnType ) = parse_literal_value ( context: context, elementType: elementType, key: key, argument : function. arguments. last!) !
131+ var ( literalValue, returnType) : ( String , LiteralReturnType ) = parse_literal_value ( context: context, elementType: elementType, key: key, expression : function. arguments. last!. expression ) !
129132 if returnType == . string {
130133 literalValue. escapeHTML ( escapeAttributes: true )
131134 }
@@ -138,7 +141,7 @@ private extension HTMLElement {
138141 break
139142 case " event " :
140143 key = " on " + key_element. memberAccess!. declName. baseName. text
141- if var result: ( String , LiteralReturnType ) = parse_literal_value ( context: context, elementType: elementType, key: key, argument : function. arguments. last!) {
144+ if var result: ( String , LiteralReturnType ) = parse_literal_value ( context: context, elementType: elementType, key: key, expression : function. arguments. last!. expression ) {
142145 if result. 1 == . string {
143146 result. 0 . escapeHTML ( escapeAttributes: true )
144147 }
@@ -167,14 +170,15 @@ private extension HTMLElement {
167170 }
168171 return attributes
169172 }
173+ // MARK: Parse innerHTML
170174 static func parse_inner_html( context: some MacroExpansionContext , elementType: HTMLElementType , child: LabeledExprSyntax ) -> String ? {
171175 if let macro: MacroExpansionExprSyntax = child. expression. macroExpansion {
172176 var string : String = parse_macro ( context: context, expression: macro)
173177 if elementType == . escapeHTML {
174178 string. escapeHTML ( escapeAttributes: false )
175179 }
176180 return string
177- } else if var string: String = parse_literal_value ( context: context, elementType: elementType, key: " " , argument : child) ? . value {
181+ } else if var string: String = parse_literal_value ( context: context, elementType: elementType, key: " " , expression : child. expression ) ? . value {
178182 string. escapeHTML ( escapeAttributes: false )
179183 return string
180184 } else {
@@ -184,7 +188,7 @@ private extension HTMLElement {
184188 }
185189 static func unallowed_expression( context: some MacroExpansionContext , node: LabeledExprSyntax ) {
186190 context. diagnose ( Diagnostic ( node: node, message: DiagnosticMsg ( id: " unallowedExpression " , message: " String Interpolation is required when encoding runtime values. " ) , fixIts: [
187- FixIt ( message: DiagnosticMsg ( id: " useStringInterpolation " , message: " Use String Interpolation. " , severity : . error ) , changes: [
191+ FixIt ( message: DiagnosticMsg ( id: " useStringInterpolation " , message: " Use String Interpolation. " ) , changes: [
188192 FixIt . Change. replace (
189193 oldNode: Syntax ( node) ,
190194 newNode: Syntax ( StringLiteralExprSyntax ( content: " \\ ( \( node) ) " ) )
@@ -212,9 +216,10 @@ private extension HTMLElement {
212216 }
213217 }
214218
219+ // MARK: Parse Attribute
215220 static func parse_attribute( context: some MacroExpansionContext , elementType: HTMLElementType , key: String , argument: LabeledExprSyntax ) -> String ? {
216221 let expression : ExprSyntax = argument. expression
217- if var result: ( String , LiteralReturnType ) = parse_literal_value ( context: context, elementType: elementType, key: key, argument : argument ) {
222+ if var result: ( String , LiteralReturnType ) = parse_literal_value ( context: context, elementType: elementType, key: key, expression : expression ) {
218223 switch result. 1 {
219224 case . boolean: return result. 0 . elementsEqual ( " true " ) ? " " : nil
220225 case . string:
@@ -233,27 +238,15 @@ private extension HTMLElement {
233238 }
234239 return nil
235240 }
236- static func get_separator( key: String ) -> String {
237- switch key {
238- case " accept " , " coords " , " exportparts " , " imagesizes " , " imagesrcset " , " sizes " , " srcset " : return " , "
239- default : return " "
240- }
241- }
242- static func parse_literal_value( context: some MacroExpansionContext , elementType: HTMLElementType , key: String , argument: LabeledExprSyntax ) -> ( value: String , returnType: LiteralReturnType ) ? {
243- let expression : ExprSyntax = argument. expression
241+ // MARK: Parse Literal Value
242+ static func parse_literal_value( context: some MacroExpansionContext , elementType: HTMLElementType , key: String , expression: ExprSyntax ) -> ( value: String , returnType: LiteralReturnType ) ? {
244243 if let boolean: String = expression. booleanLiteral? . literal. text {
245244 return ( boolean, . boolean)
246245 }
247246 func return_string_or_interpolation( ) -> ( String , LiteralReturnType ) ? {
248- if let string: String = expression. stringLiteral? . string {
247+ if let string: String = expression. stringLiteral? . string ?? expression . integerLiteral ? . literal . text ?? expression . floatLiteral ? . literal . text {
249248 return ( string, . string)
250249 }
251- if let integer: String = expression. integerLiteral? . literal. text {
252- return ( integer, . string)
253- }
254- if let float: String = expression. floatLiteral? . literal. text {
255- return ( float, . string)
256- }
257250 if let function: FunctionCallExprSyntax = expression. as ( FunctionCallExprSyntax . self) {
258251 switch key {
259252 case " height " , " width " :
@@ -276,29 +269,32 @@ private extension HTMLElement {
276269 return ( HTMLElementAttribute . Extra. htmlValue ( enumName: enumName ( elementType: elementType, key: key) , for: decl) , . string)
277270 }
278271 }
279- let separator : String = get_separator ( key: key)
280- let string_return_logic : ( ExprSyntax , String ) -> String = {
281- if $1. contains ( separator) {
282- context. diagnose ( Diagnostic ( node: $0, message: DiagnosticMsg ( id: " characterNotAllowedInDeclaration " , message: " Character \" " + separator + " \" is not allowed when declaring values for \" " + key + " \" . " ) ) )
283- }
284- return $1
285- }
286- if let value: String = expression. array? . elements. compactMap ( {
287- if let string: String = $0. expression. stringLiteral? . string {
288- return string_return_logic ( $0. expression, string)
289- }
290- if let string: String = $0. expression. integerLiteral? . literal. text {
291- return string
292- }
293- if let string: String = $0. expression. floatLiteral? . literal. text {
294- return string
295- }
296- if let string: String = $0. expression. memberAccess? . declName. baseName. text {
297- return HTMLElementAttribute . Extra. htmlValue ( enumName: enumName ( elementType: elementType, key: key) , for: string)
272+ if let array: ArrayExprSyntax = expression. array {
273+ let separator : String
274+ switch key {
275+ case " accept " , " coords " , " exportparts " , " imagesizes " , " imagesrcset " , " sizes " , " srcset " :
276+ separator = " , "
277+ break
278+ default :
279+ separator = " "
280+ break
298281 }
299- return nil
300- } ) . joined ( separator: separator) {
301- return ( value, . string)
282+ return ( array. elements. compactMap ( {
283+ if let string: String = $0. expression. stringLiteral? . string {
284+ if string. contains ( separator) {
285+ context. diagnose ( Diagnostic ( node: $0. expression, message: DiagnosticMsg ( id: " characterNotAllowedInDeclaration " , message: " Character \" " + separator + " \" is not allowed when declaring values for \" " + key + " \" . " ) ) )
286+ return nil
287+ }
288+ return string
289+ }
290+ if let string: String = $0. expression. integerLiteral? . literal. text ?? $0. expression. floatLiteral? . literal. text {
291+ return string
292+ }
293+ if let string: String = $0. expression. memberAccess? . declName. baseName. text {
294+ return HTMLElementAttribute . Extra. htmlValue ( enumName: enumName ( elementType: elementType, key: key) , for: string)
295+ }
296+ return nil
297+ } ) . joined ( separator: separator) , . string)
302298 }
303299 return nil
304300 }
@@ -320,6 +316,7 @@ private extension HTMLElement {
320316 }
321317 return ( string, returnType)
322318 }
319+ // MARK: Flatten Interpolation
323320 static func flatten_interpolation( context: some MacroExpansionContext , remaining_interpolation: inout Int , expr: ExpressionSegmentSyntax ) -> String {
324321 let expression : ExprSyntax = expr. expressions. first!. expression
325322 var string : String = " \( expr) "
@@ -525,7 +522,7 @@ enum HTMLElementType : String, CaseIterable {
525522}
526523
527524// MARK: Misc
528- extension ExprSyntax {
525+ extension SyntaxProtocol {
529526 var booleanLiteral : BooleanLiteralExprSyntax ? { self . as ( BooleanLiteralExprSyntax . self) }
530527 var stringLiteral : StringLiteralExprSyntax ? { self . as ( StringLiteralExprSyntax . self) }
531528 var integerLiteral : IntegerLiteralExprSyntax ? { self . as ( IntegerLiteralExprSyntax . self) }
0 commit comments