Skip to content

Commit 8cea34d

Browse files
throw compiler error if output contains interpolation when converting to bytes
1 parent ac9d9fb commit 8cea34d

File tree

2 files changed

+45
-25
lines changed

2 files changed

+45
-25
lines changed

Sources/HTMLKitMacros/HTMLElement.swift

Lines changed: 40 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -21,30 +21,47 @@ import struct NIOCore.ByteBuffer
2121
enum HTMLElement : ExpressionMacro {
2222
static func expansion(of node: some FreestandingMacroExpansionSyntax, in context: some MacroExpansionContext) throws -> ExprSyntax {
2323
let string:String = parse_macro(context: context, expression: node.as(MacroExpansionExprSyntax.self)!)
24-
// TODO: check for interpolation
25-
func bytes<T: FixedWidthInteger>(_ bytes: [T]) -> String {
26-
return "[" + bytes.map({ "\($0)" }).joined(separator: ",") + "]"
27-
}
28-
switch HTMLElementType(rawValue: node.macroName.text) {
29-
case .htmlUTF8Bytes:
30-
return "\(raw: bytes([UInt8](string.utf8)))"
31-
case .htmlUTF16Bytes:
32-
return "\(raw: bytes([UInt16](string.utf16)))"
33-
case .htmlUTF8CString:
34-
return "\(raw: string.utf8CString)"
35-
36-
#if canImport(Foundation)
37-
case .htmlData:
38-
return "Data(\(raw: bytes([UInt8](string.utf8))))"
39-
#endif
40-
41-
#if canImport(NIOCore)
42-
case .htmlByteBuffer:
43-
return "ByteBuffer(bytes: \(raw: bytes([UInt8](string.utf8))))"
44-
#endif
45-
46-
default: return "\"\(raw: string)\""
24+
let has_interpolation:Bool = !string.ranges(of: try! Regex("\\((.*)\\)")).isEmpty
25+
var set:Set<HTMLElementType?> = [.htmlUTF8Bytes, .htmlUTF16Bytes, .htmlUTF8CString]
26+
27+
#if canImport(Foundation)
28+
set.insert(.htmlData)
29+
#endif
30+
31+
#if canImport(NIOCore)
32+
set.insert(.htmlByteBuffer)
33+
#endif
34+
35+
if set.contains(HTMLElementType(rawValue: node.macroName.text)) {
36+
guard !has_interpolation else {
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+
return ""
39+
}
40+
func bytes<T: FixedWidthInteger>(_ bytes: [T]) -> String {
41+
return "[" + bytes.map({ "\($0)" }).joined(separator: ",") + "]"
42+
}
43+
switch HTMLElementType(rawValue: node.macroName.text) {
44+
case .htmlUTF8Bytes:
45+
return "\(raw: bytes([UInt8](string.utf8)))"
46+
case .htmlUTF16Bytes:
47+
return "\(raw: bytes([UInt16](string.utf16)))"
48+
case .htmlUTF8CString:
49+
return "\(raw: string.utf8CString)"
50+
51+
#if canImport(Foundation)
52+
case .htmlData:
53+
return "Data(\(raw: bytes([UInt8](string.utf8))))"
54+
#endif
55+
56+
#if canImport(NIOCore)
57+
case .htmlByteBuffer:
58+
return "ByteBuffer(bytes: \(raw: bytes([UInt8](string.utf8))))"
59+
#endif
60+
61+
default: break
62+
}
4763
}
64+
return "\"\(raw: string)\""
4865
}
4966
}
5067

Tests/HTMLKitTests/HTMLKitTests.swift

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,9 @@ extension HTMLKitTests {
5959
#if canImport(NIOCore)
6060
let _:ByteBuffer = #htmlByteBuffer("")
6161
#endif
62+
63+
//let bro:String = ""
64+
//let _:[UInt8] = #htmlUTF8Bytes("\(bro)")
6265
}
6366
func representation1() -> StaticString {
6467
#html()
@@ -244,10 +247,10 @@ extension HTMLKitTests {
244247

245248
@Test func no_value_type() {
246249
let expected_string:String = "<!DOCTYPE html><html><body><h1>HTMLKitTests</h1></body></html>"
247-
let test1:String = #html(#body(#h1("HTMLKitTests")))
250+
let test1 = #html(#body(#h1("HTMLKitTests")))
248251
#expect(type(of: test1) == String.self)
249252
#expect(test1 == expected_string)
250-
let test2:StaticString = #html(#body(#h1(StaticString("HTMLKitTests"))))
253+
let test2 = #html(#body(#h1(StaticString("HTMLKitTests"))))
251254
#expect(type(of: test2) == StaticString.self)
252255
#expect(test2 == expected_string)
253256
}

0 commit comments

Comments
 (0)