7
7
8
8
import SwiftSyntax
9
9
import SwiftSyntaxMacros
10
+ import SwiftDiagnostics
10
11
import HTMLKitUtilities
11
12
12
13
struct HTMLElement : ExpressionMacro {
@@ -28,9 +29,14 @@ private extension HTMLElement {
28
29
if let child: LabeledExprSyntax = element. as ( LabeledExprSyntax . self) {
29
30
if var key: String = child. label? . text { // attributes
30
31
if key == " data " {
31
- let tuple : TupleExprSyntax = child. expression. as ( TupleExprSyntax . self) !
32
+ //context.diagnose(Diagnostic(node: node, message: ErrorDiagnostic(id: "bro", message: child.expression.debugDescription)))
33
+ let tuple : TupleExprSyntax = child. expression. as ( TupleExprSyntax . self) !, valueExpression : ExprSyntax = tuple. elements. last!. expression
34
+ var ( value, returnType) : ( String , LiteralReturnType ) = parse_literal_value ( elementType: elementType, key: " data " , expression: valueExpression) !
35
+ if returnType == . interpolation {
36
+ value = " \\ ( " + value + " ) "
37
+ }
32
38
key += " - \( tuple. elements. first!. expression. as ( StringLiteralExprSyntax . self) !. string) "
33
- attributes. append ( key + " = \\ \" \( tuple . elements . last! . expression . as ( StringLiteralExprSyntax . self ) ! . string ) \\ \" " )
39
+ attributes. append ( key + " = \\ \" " + value + " \\ \" " )
34
40
} else {
35
41
if key == " acceptCharset " {
36
42
key = " accept-charset "
@@ -67,54 +73,47 @@ private extension HTMLElement {
67
73
}
68
74
}
69
75
70
- static func parse_attribute( elementType: HTMLElementType , key: String , expression: ExprSyntax ) -> String ? {
71
- if let boolean: String = expression. as ( BooleanLiteralExprSyntax . self) ? . literal. text {
72
- return boolean. elementsEqual ( " true " ) ? key : nil
76
+ static func enumName( elementType: HTMLElementType , key: String ) -> String {
77
+ switch elementType. rawValue + key {
78
+ case " buttontype " : return " buttontype "
79
+ case " inputtype " : return " inputmode "
80
+ case " oltype " : return " numberingtype "
81
+ case " scripttype " : return " scripttype "
82
+ default : return key
73
83
}
84
+ }
85
+
86
+ static func parse_attribute( elementType: HTMLElementType , key: String , expression: ExprSyntax ) -> String ? {
74
87
func yup( _ value: String ) -> String { key + " = \\ \" " + value + " \\ \" " }
75
- if let string: String = expression. as ( StringLiteralExprSyntax . self) ? . string {
76
- return yup ( string)
77
- }
78
- if let integer: String = expression. as ( IntegerLiteralExprSyntax . self) ? . literal. text {
79
- return yup ( integer)
80
- }
81
- if let float: String = expression. as ( FloatLiteralExprSyntax . self) ? . literal. text {
82
- return yup ( float)
83
- }
84
- func enumName( ) -> String {
85
- switch elementType. rawValue + key { // better performance than switching key, than switching elementType
86
- case " buttontype " : return " buttontype "
87
- case " inputtype " : return " inputmode "
88
- case " oltype " : return " numberingtype "
89
- case " scripttype " : return " scripttype "
90
- default : return key
88
+ if let ( string, returnType) : ( String , LiteralReturnType ) = parse_literal_value ( elementType: elementType, key: key, expression: expression) {
89
+ switch returnType {
90
+ case . boolean: return string. elementsEqual ( " true " ) ? key : nil
91
+ case . string: return yup ( string)
92
+ case . interpolation: return yup ( " \\ ( " + string + " ) " )
91
93
}
92
94
}
93
95
if let value: String = expression. as ( ArrayExprSyntax . self) ? . elements. compactMap ( {
94
- if let string: String = $0. expression. as ( StringLiteralExprSyntax . self ) ? . string {
96
+ if let string: String = $0. expression. stringLiteral ? . string {
95
97
return string
96
98
}
97
- if let string: String = $0. expression. as ( IntegerLiteralExprSyntax . self ) ? . literal. text {
99
+ if let string: String = $0. expression. integerLiteral ? . literal. text {
98
100
return string
99
101
}
100
102
if let string: String = $0. expression. as ( MemberAccessExprSyntax . self) ? . declName. baseName. text {
101
- return HTMLElementAttribute . htmlValue ( enumName: enumName ( ) , for: string)
103
+ return HTMLElementAttribute . htmlValue ( enumName: enumName ( elementType : elementType , key : key ) , for: string)
102
104
}
103
105
return nil
104
106
} ) . joined ( separator: get_separator ( key: key) ) {
105
107
return yup ( value)
106
108
}
107
109
func member( _ value: String ) -> String {
108
110
var string : String = String ( value [ value. index ( after: value. startIndex) ... ] )
109
- string = HTMLElementAttribute . htmlValue ( enumName: enumName ( ) , for: string)
111
+ string = HTMLElementAttribute . htmlValue ( enumName: enumName ( elementType : elementType , key : key ) , for: string)
110
112
return yup ( string)
111
113
}
112
114
if let function: FunctionCallExprSyntax = expression. as ( FunctionCallExprSyntax . self) {
113
115
return member ( " \( function) " )
114
116
}
115
- if let value: String = expression. as ( MemberAccessExprSyntax . self) ? . declName. baseName. text {
116
- return member ( " . " + value)
117
- }
118
117
return nil
119
118
}
120
119
static func get_separator( key: String ) -> String {
@@ -123,6 +122,53 @@ private extension HTMLElement {
123
122
default : return " "
124
123
}
125
124
}
125
+ static func parse_literal_value( elementType: HTMLElementType , key: String , expression: ExprSyntax ) -> ( value: String , returnType: LiteralReturnType ) ? {
126
+ if let boolean: String = expression. booleanLiteral? . literal. text {
127
+ return ( boolean, . boolean)
128
+ }
129
+ if let string: String = expression. stringLiteral? . string {
130
+ return ( string, . string)
131
+ }
132
+ if let integer: String = expression. integerLiteral? . literal. text {
133
+ return ( integer, . string)
134
+ }
135
+ if let float: String = expression. floatLiteral? . literal. text {
136
+ return ( float, . string)
137
+ }
138
+ if let function: FunctionCallExprSyntax = expression. as ( FunctionCallExprSyntax . self) {
139
+ switch key {
140
+ case " height " , " width " :
141
+ var value : String = " \( function) "
142
+ value = String ( value [ value. index ( after: value. startIndex) ... ] )
143
+ value = HTMLElementAttribute . htmlValue ( enumName: enumName ( elementType: elementType, key: key) , for: value)
144
+ return ( value, . string)
145
+ default :
146
+ return ( " \( function) " , . interpolation)
147
+ }
148
+ }
149
+ if let member: MemberAccessExprSyntax = expression. as ( MemberAccessExprSyntax . self) {
150
+ let decl : String = member. declName. baseName. text
151
+ if let base: ExprSyntax = member. base {
152
+ if let integer: String = base. integerLiteral? . literal. text {
153
+ switch decl {
154
+ case " description " :
155
+ return ( integer, . string)
156
+ default :
157
+ return ( integer, . interpolation)
158
+ }
159
+ } else {
160
+ return ( " \( member) " , . interpolation)
161
+ }
162
+ } else {
163
+ return ( HTMLElementAttribute . htmlValue ( enumName: enumName ( elementType: elementType, key: key) , for: decl) , . string)
164
+ }
165
+ }
166
+ return nil
167
+ }
168
+ }
169
+
170
+ enum LiteralReturnType {
171
+ case boolean, string, interpolation
126
172
}
127
173
128
174
// MARK: HTMLElementType
@@ -270,6 +316,12 @@ enum HTMLElementType : String {
270
316
}
271
317
}
272
318
319
+ extension ExprSyntax {
320
+ var booleanLiteral : BooleanLiteralExprSyntax ? { self . as ( BooleanLiteralExprSyntax . self) }
321
+ var stringLiteral : StringLiteralExprSyntax ? { self . as ( StringLiteralExprSyntax . self) }
322
+ var integerLiteral : IntegerLiteralExprSyntax ? { self . as ( IntegerLiteralExprSyntax . self) }
323
+ var floatLiteral : FloatLiteralExprSyntax ? { self . as ( FloatLiteralExprSyntax . self) }
324
+ }
273
325
extension StringLiteralExprSyntax {
274
326
var string : String { " \( segments) " }
275
327
}
0 commit comments