Skip to content

Commit 5a60786

Browse files
replaced unchecked(HTMLEncoding) HTMLEncoding case with an uncheckedHTML macro
1 parent 2571e6c commit 5a60786

File tree

8 files changed

+37
-60
lines changed

8 files changed

+37
-60
lines changed

Sources/HTMLKit/HTMLKit.swift

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,16 +23,25 @@ extension StringProtocol {
2323
public static func == (left: StaticString, right: Self) -> Bool { left.description == right }
2424
}
2525

26+
// MARK: Escape HTML
2627
@freestanding(expression)
2728
public macro escapeHTML(
2829
encoding: HTMLEncoding = .string,
2930
_ innerHTML: CustomStringConvertible & Sendable...
3031
) -> String = #externalMacro(module: "HTMLKitMacros", type: "EscapeHTML")
3132

32-
// MARK: HTML Representation
33+
// MARK: HTML
3334
@freestanding(expression)
3435
public macro html<T: CustomStringConvertible>(
3536
encoding: HTMLEncoding = .string,
3637
lookupFiles: [StaticString] = [],
3738
_ innerHTML: CustomStringConvertible & Sendable...
39+
) -> T = #externalMacro(module: "HTMLKitMacros", type: "HTMLElementMacro")
40+
41+
/// Same as `#html` but ignoring compiler warnings.
42+
@freestanding(expression)
43+
public macro uncheckedHTML<T: CustomStringConvertible>(
44+
encoding: HTMLEncoding = .string,
45+
lookupFiles: [StaticString] = [],
46+
_ innerHTML: CustomStringConvertible & Sendable...
3847
) -> T = #externalMacro(module: "HTMLKitMacros", type: "HTMLElementMacro")

Sources/HTMLKitMacros/EscapeHTML.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ import SwiftSyntaxMacros
1212

1313
enum EscapeHTML : ExpressionMacro {
1414
static func expansion(of node: some FreestandingMacroExpansionSyntax, in context: some MacroExpansionContext) throws -> ExprSyntax {
15-
let c:HTMLExpansionContext = HTMLExpansionContext(context: context, encoding: .string, key: "", arguments: node.arguments)
15+
let c:HTMLExpansionContext = HTMLExpansionContext(context: context, expansion: node.as(ExprSyntax.self)!.macroExpansion!, ignoresCompilerWarnings: false, encoding: .string, key: "", arguments: node.arguments)
1616
return "\"\(raw: HTMLKitUtilities.escapeHTML(context: c))\""
1717
}
1818
}

Sources/HTMLKitMacros/HTMLElement.swift

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import SwiftSyntaxMacros
1313

1414
enum HTMLElementMacro : ExpressionMacro {
1515
static func expansion(of node: some FreestandingMacroExpansionSyntax, in context: some MacroExpansionContext) throws -> ExprSyntax {
16-
return try HTMLKitUtilities.expandHTMLMacro(context: context, macroNode: node.as(ExprSyntax.self)!.macroExpansion!)
16+
let ignoresCompilerWarnings:Bool = node.macroName.text == "uncheckedHTML"
17+
return try HTMLKitUtilities.expandHTMLMacro(context: HTMLExpansionContext(context: context, expansion: node.as(ExprSyntax.self)!.macroExpansion!, ignoresCompilerWarnings: ignoresCompilerWarnings, encoding: .string, key: "", arguments: node.arguments))
1718
}
1819
}

Sources/HTMLKitParse/ParseData.swift

Lines changed: 8 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -38,16 +38,16 @@ extension HTMLKitUtilities {
3838
}
3939

4040
// MARK: Expand #html
41-
public static func expandHTMLMacro(context: some MacroExpansionContext, macroNode: MacroExpansionExprSyntax) throws -> ExprSyntax {
42-
let (string, encoding):(String, HTMLEncoding) = expand_macro(context: HTMLExpansionContext(context: context, encoding: .string, key: "", arguments: macroNode.arguments))
43-
return "\(raw: encodingResult(context: context, node: macroNode, string: string, for: encoding))"
41+
public static func expandHTMLMacro(context: HTMLExpansionContext) throws -> ExprSyntax {
42+
let (string, encoding):(String, HTMLEncoding) = expand_macro(context: context)
43+
return "\(raw: encodingResult(context: context, node: context.expansion, string: string, for: encoding))"
4444
}
45-
private static func encodingResult(context: some MacroExpansionContext, node: MacroExpansionExprSyntax, string: String, for encoding: HTMLEncoding) -> String {
45+
private static func encodingResult(context: HTMLExpansionContext, node: MacroExpansionExprSyntax, string: String, for encoding: HTMLEncoding) -> String {
4646
func hasNoInterpolation() -> Bool {
4747
let has_interpolation:Bool = !string.ranges(of: try! Regex("\\((.*)\\)")).isEmpty
4848
guard !has_interpolation else {
49-
if !encoding.isUnchecked {
50-
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.")))
49+
if !context.ignoresCompilerWarnings {
50+
context.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.")))
5151
}
5252
return false
5353
}
@@ -57,9 +57,6 @@ extension HTMLKitUtilities {
5757
return "[" + bytes.map({ "\($0)" }).joined(separator: ",") + "]"
5858
}
5959
switch encoding {
60-
case .unchecked(let e):
61-
return encodingResult(context: context, node: node, string: string, for: e)
62-
6360
case .utf8Bytes:
6461
guard hasNoInterpolation() else { return "" }
6562
return bytes([UInt8](string.utf8))
@@ -144,9 +141,6 @@ extension HTMLKitUtilities {
144141
return HTMLEncoding(rawValue: key)
145142
} else if let function:FunctionCallExprSyntax = expression.functionCall {
146143
switch function.calledExpression.as(MemberAccessExprSyntax.self)?.declName.baseName.text {
147-
case "unchecked":
148-
guard let encoding:HTMLEncoding = parseEncoding(expression: function.arguments.first!.expression) else { break }
149-
return .unchecked(encoding)
150144
case "custom":
151145
guard let logic:String = function.arguments.first?.expression.stringLiteral?.string else { break }
152146
if function.arguments.count == 1 {
@@ -248,12 +242,13 @@ extension HTMLKitUtilities {
248242
context: HTMLExpansionContext,
249243
node: some SyntaxProtocol
250244
) {
251-
/*if let fix:String = InterpolationLookup.find(context: context, node, files: lookupFiles) {
245+
/*if let fix:String = InterpolationLookup.find(context: context, node) {
252246
let expression:String = "\(node)"
253247
let ranges:[Range<String.Index>] = string.ranges(of: expression)
254248
string.replace(expression, with: fix)
255249
remaining_interpolation -= ranges.count
256250
} else {*/
251+
guard !context.ignoresCompilerWarnings else { return }
257252
context.context.diagnose(Diagnostic(node: node, message: DiagnosticMsg(id: "unsafeInterpolation", message: "Interpolation may introduce raw HTML.", severity: .warning)))
258253
//}
259254
}

Sources/HTMLKitParse/ParseLiteral.swift

Lines changed: 6 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -57,12 +57,10 @@ extension HTMLKitUtilities {
5757
}
5858
string = segments.map({ "\($0)" }).joined()
5959
} else {
60-
if !context.isUnchecked {
61-
if let function:FunctionCallExprSyntax = expression.functionCall {
62-
warn_interpolation(context: context, node: function.calledExpression)
63-
} else {
64-
warn_interpolation(context: context, node: expression)
65-
}
60+
if let function:FunctionCallExprSyntax = expression.functionCall {
61+
warn_interpolation(context: context, node: function.calledExpression)
62+
} else {
63+
warn_interpolation(context: context, node: expression)
6664
}
6765
if let member:MemberAccessExprSyntax = expression.memberAccess {
6866
string = "\\(" + member.singleLineDescription + ")"
@@ -131,9 +129,7 @@ extension HTMLKitUtilities {
131129
// TODO: lookup and try to promote | need to wait for swift-syntax to update to access SwiftLexicalLookup
132130
//}
133131
values.append(interpolate(expression))
134-
if !context.isUnchecked {
135-
warn_interpolation(context: context, node: expression)
136-
}
132+
warn_interpolation(context: context, node: expression)
137133
}
138134
}
139135
return values
@@ -201,9 +197,7 @@ extension HTMLKitUtilities {
201197
return .array(results)
202198
}
203199
if let decl:DeclReferenceExprSyntax = expression.declRef {
204-
if !context.isUnchecked {
205-
warn_interpolation(context: context, node: expression)
206-
}
200+
warn_interpolation(context: context, node: expression)
207201
return .interpolation(decl.baseName.text)
208202
}
209203
return nil

Sources/HTMLKitUtilities/HTMLEncoding.swift

Lines changed: 2 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -34,13 +34,6 @@ public enum HTMLEncoding : Sendable {
3434
/// - Returns: `String`/`StaticString`
3535
case string
3636

37-
/// Ignores compilation warnings when encoding.
38-
///
39-
/// - Parameters:
40-
/// - encoding: HTMLEncoding you want to encode the result to.
41-
/// - Returns: The encoding's returned value.
42-
indirect case unchecked(HTMLEncoding)
43-
4437
/// - Returns: `[UInt8]`
4538
case utf8Bytes
4639

@@ -74,12 +67,6 @@ public enum HTMLEncoding : Sendable {
7467
public init?(rawValue: String) {
7568
switch rawValue {
7669
case "string": self = .string
77-
case "unchecked(.string)": self = .unchecked(.string)
78-
case "unchecked(.utf8Bytes)": self = .unchecked(.utf8Bytes)
79-
case "unchecked(.utf8CString)": self = .unchecked(.utf8CString)
80-
case "unchecked(.utf16Bytes)": self = .unchecked(.utf16Bytes)
81-
case "unchecked(.foundationData)": self = .unchecked(.foundationData)
82-
case "unchecked(.byteBuffer)": self = .unchecked(.byteBuffer)
8370
case "utf8Bytes": self = .utf8Bytes
8471
case "utf8CString": self = .utf8CString
8572
case "utf16Bytes": self = .utf16Bytes
@@ -92,23 +79,12 @@ public enum HTMLEncoding : Sendable {
9279
@inlinable
9380
public func stringDelimiter(forMacro: Bool) -> String {
9481
switch self {
95-
case .string, .unchecked(.string):
82+
case .string:
9683
return forMacro ? "\\\"" : "\""
97-
case .unchecked(.utf8Bytes), .unchecked(.utf16Bytes), .unchecked(.utf8CString), .unchecked(.foundationData), .unchecked(.byteBuffer),
98-
.utf8Bytes, .utf16Bytes, .utf8CString, .foundationData, .byteBuffer:
84+
case .utf8Bytes, .utf16Bytes, .utf8CString, .foundationData, .byteBuffer:
9985
return "\""
10086
case .custom(_, let delimiter):
10187
return delimiter
102-
case .unchecked:
103-
return ""
104-
}
105-
}
106-
107-
@inlinable
108-
public var isUnchecked : Bool {
109-
switch self {
110-
case .unchecked: return true
111-
default: return false
11288
}
11389
}
11490
}

Sources/HTMLKitUtilities/HTMLExpansionContext.swift

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import SwiftSyntaxMacros
1111
/// Data required to process an HTML expansion.
1212
public struct HTMLExpansionContext {
1313
public let context:MacroExpansionContext
14+
public let expansion:MacroExpansionExprSyntax
1415

1516
/// `HTMLEncoding` of this expansion.
1617
public var encoding:HTMLEncoding
@@ -22,14 +23,20 @@ public struct HTMLExpansionContext {
2223
/// Complete file paths used for looking up interpolation (when trying to promote to an equivalent `StaticString`).
2324
public var lookupFiles:Set<String>
2425

26+
public let ignoresCompilerWarnings:Bool
27+
2528
public init(
2629
context: MacroExpansionContext,
30+
expansion: MacroExpansionExprSyntax,
31+
ignoresCompilerWarnings: Bool,
2732
encoding: HTMLEncoding,
2833
key: String,
2934
arguments: LabeledExprListSyntax,
3035
lookupFiles: Set<String> = []
3136
) {
3237
self.context = context
38+
self.expansion = expansion
39+
self.ignoresCompilerWarnings = ignoresCompilerWarnings
3340
self.encoding = encoding
3441
self.key = key
3542
self.arguments = arguments
@@ -40,9 +47,4 @@ public struct HTMLExpansionContext {
4047
public var expression : ExprSyntax? {
4148
arguments.first?.expression
4249
}
43-
44-
/// Whether the encoding is unchecked.
45-
public var isUnchecked : Bool {
46-
encoding.isUnchecked
47-
}
4850
}

Tests/HTMLKitTests/InterpolationTests.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -333,7 +333,7 @@ extension InterpolationTests {
333333
}
334334

335335
@Test func uncheckedInterpolation() {
336-
let _:String = #html(encoding: .unchecked(.string), div(InterpolationTests.patrick))
336+
let _:String = #uncheckedHTML(encoding: .string, div(InterpolationTests.patrick))
337337
}
338338
}
339339

0 commit comments

Comments
 (0)