@@ -20,8 +20,7 @@ import struct NIOCore.ByteBuffer
20
20
21
21
enum HTMLElement : ExpressionMacro {
22
22
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!)
25
24
var set : Set < HTMLElementType ? > = [ . htmlUTF8Bytes, . htmlUTF16Bytes, . htmlUTF8CString]
26
25
27
26
#if canImport(Foundation)
@@ -33,6 +32,7 @@ enum HTMLElement : ExpressionMacro {
33
32
#endif
34
33
35
34
if set. contains ( HTMLElementType ( rawValue: node. macroName. text) ) {
35
+ let has_interpolation : Bool = !string. ranges ( of: try ! Regex ( " \\ ((.*) \\ ) " ) ) . isEmpty
36
36
guard !has_interpolation else {
37
37
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. " ) ) )
38
38
return " "
@@ -66,6 +66,7 @@ enum HTMLElement : ExpressionMacro {
66
66
}
67
67
68
68
private extension HTMLElement {
69
+ // MARK: Parse Macro
69
70
static func parse_macro( context: some MacroExpansionContext , expression: MacroExpansionExprSyntax ) -> String {
70
71
guard let elementType: HTMLElementType = HTMLElementType ( rawValue: expression. macroName. text) else { return " \( expression) " }
71
72
let childs : SyntaxChildren = expression. arguments. children ( viewMode: . all)
@@ -94,6 +95,7 @@ private extension HTMLElement {
94
95
}
95
96
return string
96
97
}
98
+ // MARK: Parse Arguments
97
99
static func parse_arguments( context: some MacroExpansionContext , elementType: HTMLElementType , children: Slice < SyntaxChildren > ) -> ElementData {
98
100
var attributes : [ String ] = [ ] , innerHTML : [ String ] = [ ]
99
101
for element in children {
@@ -118,14 +120,15 @@ private extension HTMLElement {
118
120
}
119
121
return ElementData ( attributes: attributes, innerHTML: innerHTML)
120
122
}
123
+ // MARK: Parse Global Attributes
121
124
static func parse_global_attributes( context: some MacroExpansionContext , elementType: HTMLElementType , array: ArrayExprSyntax ) -> [ String ] {
122
125
var keys : Set < String > = [ ] , attributes : [ String ] = [ ]
123
126
for element in array. elements {
124
127
let function : FunctionCallExprSyntax = element. expression. as ( FunctionCallExprSyntax . self) !, key_argument : LabeledExprSyntax = function. arguments. first!, key_element : ExprSyntax = key_argument. expression
125
128
var key : String = function. calledExpression. memberAccess!. declName. baseName. text, value : String ? = nil
126
129
switch key {
127
130
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 ) !
129
132
if returnType == . string {
130
133
literalValue. escapeHTML ( escapeAttributes: true )
131
134
}
@@ -138,7 +141,7 @@ private extension HTMLElement {
138
141
break
139
142
case " event " :
140
143
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 ) {
142
145
if result. 1 == . string {
143
146
result. 0 . escapeHTML ( escapeAttributes: true )
144
147
}
@@ -167,14 +170,15 @@ private extension HTMLElement {
167
170
}
168
171
return attributes
169
172
}
173
+ // MARK: Parse innerHTML
170
174
static func parse_inner_html( context: some MacroExpansionContext , elementType: HTMLElementType , child: LabeledExprSyntax ) -> String ? {
171
175
if let macro: MacroExpansionExprSyntax = child. expression. macroExpansion {
172
176
var string : String = parse_macro ( context: context, expression: macro)
173
177
if elementType == . escapeHTML {
174
178
string. escapeHTML ( escapeAttributes: false )
175
179
}
176
180
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 {
178
182
string. escapeHTML ( escapeAttributes: false )
179
183
return string
180
184
} else {
@@ -184,7 +188,7 @@ private extension HTMLElement {
184
188
}
185
189
static func unallowed_expression( context: some MacroExpansionContext , node: LabeledExprSyntax ) {
186
190
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: [
188
192
FixIt . Change. replace (
189
193
oldNode: Syntax ( node) ,
190
194
newNode: Syntax ( StringLiteralExprSyntax ( content: " \\ ( \( node) ) " ) )
@@ -212,9 +216,10 @@ private extension HTMLElement {
212
216
}
213
217
}
214
218
219
+ // MARK: Parse Attribute
215
220
static func parse_attribute( context: some MacroExpansionContext , elementType: HTMLElementType , key: String , argument: LabeledExprSyntax ) -> String ? {
216
221
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 ) {
218
223
switch result. 1 {
219
224
case . boolean: return result. 0 . elementsEqual ( " true " ) ? " " : nil
220
225
case . string:
@@ -233,27 +238,15 @@ private extension HTMLElement {
233
238
}
234
239
return nil
235
240
}
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 ) ? {
244
243
if let boolean: String = expression. booleanLiteral? . literal. text {
245
244
return ( boolean, . boolean)
246
245
}
247
246
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 {
249
248
return ( string, . string)
250
249
}
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
- }
257
250
if let function: FunctionCallExprSyntax = expression. as ( FunctionCallExprSyntax . self) {
258
251
switch key {
259
252
case " height " , " width " :
@@ -276,29 +269,32 @@ private extension HTMLElement {
276
269
return ( HTMLElementAttribute . Extra. htmlValue ( enumName: enumName ( elementType: elementType, key: key) , for: decl) , . string)
277
270
}
278
271
}
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
298
281
}
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)
302
298
}
303
299
return nil
304
300
}
@@ -320,6 +316,7 @@ private extension HTMLElement {
320
316
}
321
317
return ( string, returnType)
322
318
}
319
+ // MARK: Flatten Interpolation
323
320
static func flatten_interpolation( context: some MacroExpansionContext , remaining_interpolation: inout Int , expr: ExpressionSegmentSyntax ) -> String {
324
321
let expression : ExprSyntax = expr. expressions. first!. expression
325
322
var string : String = " \( expr) "
@@ -525,7 +522,7 @@ enum HTMLElementType : String, CaseIterable {
525
522
}
526
523
527
524
// MARK: Misc
528
- extension ExprSyntax {
525
+ extension SyntaxProtocol {
529
526
var booleanLiteral : BooleanLiteralExprSyntax ? { self . as ( BooleanLiteralExprSyntax . self) }
530
527
var stringLiteral : StringLiteralExprSyntax ? { self . as ( StringLiteralExprSyntax . self) }
531
528
var integerLiteral : IntegerLiteralExprSyntax ? { self . as ( IntegerLiteralExprSyntax . self) }
0 commit comments