Skip to content

Commit 78b9cfe

Browse files
added initial closure functionality; minor performance improvements
1 parent 307596a commit 78b9cfe

File tree

7 files changed

+215
-165
lines changed

7 files changed

+215
-165
lines changed

Sources/HTMLKit/HTMLKit.swift

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,12 +22,22 @@ public macro escapeHTML(
2222
// MARK: HTML
2323
/// - Returns: The inferred concrete type that conforms to `CustomStringConvertible & Sendable`.
2424
@freestanding(expression)
25+
//@available(*, deprecated, message: "innerHTML is now initialized using brackets instead of parentheses")
2526
public macro html<T: CustomStringConvertible & Sendable>(
2627
encoding: HTMLEncoding = .string,
2728
lookupFiles: [StaticString] = [],
2829
_ innerHTML: CustomStringConvertible & Sendable...
2930
) -> T = #externalMacro(module: "HTMLKitMacros", type: "HTMLElementMacro")
3031

32+
// MARK: HTML
33+
/// - Returns: The inferred concrete type that conforms to `CustomStringConvertible & Sendable`.
34+
@freestanding(expression)
35+
public macro html<T: CustomStringConvertible & Sendable>(
36+
encoding: HTMLEncoding = .string,
37+
lookupFiles: [StaticString] = [],
38+
_ innerHTML: () -> CustomStringConvertible & Sendable...
39+
) -> T = #externalMacro(module: "HTMLKitMacros", type: "HTMLElementMacro")
40+
3141
/// - Returns: An existential conforming to `CustomStringConvertible & Sendable`.
3242
@freestanding(expression)
3343
public macro anyHTML(

Sources/HTMLKitParse/ParseData.swift

Lines changed: 23 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -151,6 +151,18 @@ extension HTMLKitUtilities {
151151
}
152152
}
153153
}
154+
if let statements = context.expansion.trailingClosure?.statements {
155+
for statement in statements {
156+
switch statement.item {
157+
case .expr(let expr):
158+
if let inner_html = parseInnerHTML(context: context, expr: expr) {
159+
innerHTML.append(inner_html)
160+
}
161+
default:
162+
break
163+
}
164+
}
165+
}
154166
return ElementData(context.encoding, global_attributes, attributes, innerHTML, trailingSlash)
155167
}
156168

@@ -215,7 +227,13 @@ extension HTMLKitUtilities {
215227
context: HTMLExpansionContext,
216228
child: LabeledExprSyntax
217229
) -> (CustomStringConvertible & Sendable)? {
218-
if let expansion = child.expression.macroExpansion {
230+
return parseInnerHTML(context: context, expr: child.expression)
231+
}
232+
public static func parseInnerHTML(
233+
context: HTMLExpansionContext,
234+
expr: ExprSyntax
235+
) -> (CustomStringConvertible & Sendable)? {
236+
if let expansion = expr.macroExpansion {
219237
var c = context
220238
c.arguments = expansion.arguments
221239
switch expansion.macroName.text {
@@ -229,12 +247,12 @@ extension HTMLKitUtilities {
229247
default:
230248
return "" // TODO: fix?
231249
}
232-
} else if let element = parse_element(context: context, expr: child.expression) {
250+
} else if let element = parse_element(context: context, expr: expr) {
233251
return element
234-
} else if let string = parseLiteralValue(context: context, expression: child.expression)?.value(key: "", escape: context.escape, escapeAttributes: context.escapeAttributes) {
252+
} else if let string = parseLiteralValue(context: context, expression: expr)?.value(key: "", escape: context.escape, escapeAttributes: context.escapeAttributes) {
235253
return string
236254
} else {
237-
unallowedExpression(context: context, node: child)
255+
unallowedExpression(context: context, node: expr)
238256
return nil
239257
}
240258
}
@@ -252,7 +270,7 @@ extension HTMLKitUtilities {
252270
}
253271

254272
// MARK: Unallowed Expression
255-
static func unallowedExpression(context: HTMLExpansionContext, node: LabeledExprSyntax) {
273+
static func unallowedExpression(context: HTMLExpansionContext, node: ExprSyntax) {
256274
context.context.diagnose(Diagnostic(node: node, message: DiagnosticMsg(id: "unallowedExpression", message: "String Interpolation is required when encoding runtime values."), fixIts: [
257275
FixIt(message: DiagnosticMsg(id: "useStringInterpolation", message: "Use String Interpolation."), changes: [
258276
FixIt.Change.replace(

Sources/HTMLKitParse/ParseLiteral.swift

Lines changed: 23 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -16,14 +16,15 @@ extension HTMLKitUtilities {
1616
context: HTMLExpansionContext,
1717
expression: ExprSyntax
1818
) -> LiteralReturnType? {
19-
if let boolean = expression.booleanLiteral?.literal.text {
20-
return .boolean(boolean == "true")
21-
}
22-
if let string = expression.integerLiteral?.literal.text {
23-
return .int(Int(string)!)
24-
}
25-
if let string = expression.floatLiteral?.literal.text {
26-
return .float(Float(string)!)
19+
switch expression.kind {
20+
case .booleanLiteralExpr:
21+
return .boolean(expression.booleanLiteral?.literal.text == "true")
22+
case .integerLiteralExpr:
23+
return .int(Int(expression.integerLiteral!.literal.text)!)
24+
case .floatLiteralExpr:
25+
return .float(Float(expression.floatLiteral!.literal.text)!)
26+
default:
27+
break
2728
}
2829
guard var returnType = extractLiteral(context: context, expression: expression) else {
2930
return nil
@@ -138,18 +139,20 @@ extension HTMLKitUtilities {
138139
context: HTMLExpansionContext,
139140
expression: ExprSyntax
140141
) -> LiteralReturnType? {
141-
if let _ = expression.as(NilLiteralExprSyntax.self) {
142-
return nil
143-
}
144-
if let stringLiteral = expression.stringLiteral {
142+
switch expression.kind {
143+
case .nilLiteralExpr: return nil
144+
case .memberAccessExpr, .forceUnwrapExpr:
145+
return .interpolation("\(expression)")
146+
case .stringLiteralExpr:
147+
let stringLiteral = expression.stringLiteral!
145148
let string = stringLiteral.string(encoding: context.encoding)
146149
if stringLiteral.segments.count(where: { $0.is(ExpressionSegmentSyntax.self) }) == 0 {
147150
return .string(string)
148151
} else {
149152
return .interpolation(string)
150153
}
151-
}
152-
if let function = expression.functionCall {
154+
case .functionCallExpr:
155+
let function = expression.functionCall!
153156
if let decl = function.calledExpression.declRef?.baseName.text {
154157
switch decl {
155158
case "StaticString":
@@ -160,11 +163,7 @@ extension HTMLKitUtilities {
160163
}
161164
}
162165
return .interpolation("\(function)")
163-
}
164-
if expression.memberAccess != nil || expression.is(ForceUnwrapExprSyntax.self) {
165-
return .interpolation("\(expression)")
166-
}
167-
if let array = expression.array {
166+
case .arrayExpr:
168167
let separator:String
169168
switch context.key {
170169
case "accept", "coords", "exportparts", "imagesizes", "imagesrcset", "sizes", "srcset":
@@ -175,7 +174,7 @@ extension HTMLKitUtilities {
175174
separator = " "
176175
}
177176
var results:[Sendable] = []
178-
for element in array.elements {
177+
for element in expression.array!.elements {
179178
if let attribute = HTMLAttribute.Extra.parse(context: context, expr: element.expression) {
180179
results.append(attribute)
181180
} else if let literal = parseLiteralValue(context: context, expression: element.expression) {
@@ -194,12 +193,12 @@ extension HTMLKitUtilities {
194193
}
195194
}
196195
return .array(results)
197-
}
198-
if let decl = expression.declRef {
196+
case .declReferenceExpr:
199197
warnInterpolation(context: context, node: expression)
200-
return .interpolation(decl.baseName.text)
198+
return .interpolation(expression.declRef!.baseName.text)
199+
default:
200+
return nil
201201
}
202-
return nil
203202
}
204203
}
205204

0 commit comments

Comments
 (0)