From 0e7a3bf49edd361b99eb35f8a65a24f435dddffa Mon Sep 17 00:00:00 2001 From: RandomHashTags Date: Tue, 26 Nov 2024 00:26:51 -0600 Subject: [PATCH] literal expansion logic for the html macro is now publicly available through `HTMLKitUtilities.expandHTMLMacro` --- Sources/HTMLKitMacros/HTMLElement.swift | 47 +----------------------- Sources/HTMLKitUtilities/ParseData.swift | 47 ++++++++++++++++++++++++ 2 files changed, 48 insertions(+), 46 deletions(-) diff --git a/Sources/HTMLKitMacros/HTMLElement.swift b/Sources/HTMLKitMacros/HTMLElement.swift index 42d019a..dc0a032 100644 --- a/Sources/HTMLKitMacros/HTMLElement.swift +++ b/Sources/HTMLKitMacros/HTMLElement.swift @@ -12,51 +12,6 @@ import SwiftSyntaxMacros enum HTMLElementMacro : ExpressionMacro { static func expansion(of node: some FreestandingMacroExpansionSyntax, in context: some MacroExpansionContext) throws -> ExprSyntax { - let (string, encoding):(String, HTMLEncoding) = expand_macro(context: context, macro: node.macroExpansion!) - func has_no_interpolation() -> Bool { - let has_interpolation:Bool = !string.ranges(of: try! Regex("\\((.*)\\)")).isEmpty - guard !has_interpolation else { - 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."))) - return false - } - return true - } - func bytes(_ bytes: [T]) -> String { - return "[" + bytes.map({ "\($0)" }).joined(separator: ",") + "]" - } - switch encoding { - case .utf8Bytes: - guard has_no_interpolation() else { return "" } - return "\(raw: bytes([UInt8](string.utf8)))" - case .utf16Bytes: - guard has_no_interpolation() else { return "" } - return "\(raw: bytes([UInt16](string.utf16)))" - case .utf8CString: - return "\(raw: string.utf8CString)" - - case .foundationData: - guard has_no_interpolation() else { return "" } - return "Data(\(raw: bytes([UInt8](string.utf8))))" - - case .byteBuffer: - guard has_no_interpolation() else { return "" } - return "ByteBuffer(bytes: \(raw: bytes([UInt8](string.utf8))))" - - case .string: - return "\"\(raw: string)\"" - case .custom(let encoded): - return "\(raw: encoded.replacingOccurrences(of: "$0", with: string))" - } - } -} - -private extension HTMLElementMacro { - // MARK: Expand Macro - static func expand_macro(context: some MacroExpansionContext, macro: MacroExpansionExprSyntax) -> (String, HTMLEncoding) { - guard macro.macroName.text == "html" else { - return ("\(macro)", .string) - } - let data:HTMLKitUtilities.ElementData = HTMLKitUtilities.parseArguments(context: context, children: macro.arguments.children(viewMode: .all)) - return (data.innerHTML.map({ String(describing: $0) }).joined(), data.encoding) + return try HTMLKitUtilities.expandHTMLMacro(context: context, macroNode: node.macroExpansion!) } } \ No newline at end of file diff --git a/Sources/HTMLKitUtilities/ParseData.swift b/Sources/HTMLKitUtilities/ParseData.swift index da1b729..a53f8c5 100644 --- a/Sources/HTMLKitUtilities/ParseData.swift +++ b/Sources/HTMLKitUtilities/ParseData.swift @@ -24,6 +24,44 @@ public extension HTMLKitUtilities { return String(describing: c) }).joined() } + // MARK: Expand #html + static func expandHTMLMacro(context: some MacroExpansionContext, macroNode: MacroExpansionExprSyntax) throws -> ExprSyntax { + let (string, encoding):(String, HTMLEncoding) = expand_macro(context: context, macro: macroNode) + func has_no_interpolation() -> Bool { + let has_interpolation:Bool = !string.ranges(of: try! Regex("\\((.*)\\)")).isEmpty + guard !has_interpolation else { + context.diagnose(Diagnostic(node: macroNode, 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."))) + return false + } + return true + } + func bytes(_ bytes: [T]) -> String { + return "[" + bytes.map({ "\($0)" }).joined(separator: ",") + "]" + } + switch encoding { + case .utf8Bytes: + guard has_no_interpolation() else { return "" } + return "\(raw: bytes([UInt8](string.utf8)))" + case .utf16Bytes: + guard has_no_interpolation() else { return "" } + return "\(raw: bytes([UInt16](string.utf16)))" + case .utf8CString: + return "\(raw: string.utf8CString)" + + case .foundationData: + guard has_no_interpolation() else { return "" } + return "Data(\(raw: bytes([UInt8](string.utf8))))" + + case .byteBuffer: + guard has_no_interpolation() else { return "" } + return "ByteBuffer(bytes: \(raw: bytes([UInt8](string.utf8))))" + + case .string: + return "\"\(raw: string)\"" + case .custom(let encoded): + return "\(raw: encoded.replacingOccurrences(of: "$0", with: string))" + } + } // MARK: Parse Arguments static func parseArguments( context: some MacroExpansionContext, @@ -342,6 +380,15 @@ extension HTMLKitUtilities { context.diagnose(Diagnostic(node: node, message: DiagnosticMsg(id: "unsafeInterpolation", message: "Interpolation may introduce raw HTML.", severity: .warning))) } } + + // MARK: Expand Macro + static func expand_macro(context: some MacroExpansionContext, macro: MacroExpansionExprSyntax) -> (String, HTMLEncoding) { + guard macro.macroName.text == "html" else { + return ("\(macro)", .string) + } + let data:HTMLKitUtilities.ElementData = HTMLKitUtilities.parseArguments(context: context, children: macro.arguments.children(viewMode: .all)) + return (data.innerHTML.map({ String(describing: $0) }).joined(), data.encoding) + } } // MARK: Misc