Skip to content

Commit 26c72f7

Browse files
minor changes & performance improvements + possible fix for missing modules
1 parent 3bb3232 commit 26c72f7

File tree

11 files changed

+113
-99
lines changed

11 files changed

+113
-99
lines changed

Package.swift

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -103,9 +103,13 @@ let package = Package(
103103
.target(
104104
name: "HTMLKit",
105105
dependencies: [
106+
"CSS",
106107
"HTMLAttributes",
108+
"HTMLElements",
109+
"HTMLKitParse",
107110
"HTMLKitUtilities",
108-
"HTMLKitMacros"
111+
"HTMLKitMacros",
112+
"HTMX"
109113
]
110114
),
111115

Sources/HTMLKitParse/ParseData.swift

Lines changed: 45 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -69,36 +69,26 @@ extension HTMLKitUtilities {
6969
return "\(raw: encodingResult(context: context, node: context.expansion, string: string, for: encoding))"
7070
}
7171
private static func encodingResult(context: HTMLExpansionContext, node: MacroExpansionExprSyntax, string: String, for encoding: HTMLEncoding) -> String {
72-
func hasNoInterpolation() -> Bool {
73-
let hasInterpolation:Bool = !string.ranges(of: try! Regex("\\((.*)\\)")).isEmpty
74-
guard !hasInterpolation else {
75-
if !context.ignoresCompilerWarnings {
76-
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.")))
77-
}
78-
return false
79-
}
80-
return true
81-
}
8272
func bytes<T: FixedWidthInteger>(_ bytes: [T]) -> String {
8373
return "[" + bytes.map({ "\($0)" }).joined(separator: ",") + "]"
8474
}
8575
switch encoding {
8676
case .utf8Bytes:
87-
guard hasNoInterpolation() else { return "" }
77+
guard hasNoInterpolation(context, node, string) else { return "" }
8878
return bytes([UInt8](string.utf8))
8979
case .utf16Bytes:
90-
guard hasNoInterpolation() else { return "" }
80+
guard hasNoInterpolation(context, node, string) else { return "" }
9181
return bytes([UInt16](string.utf16))
9282
case .utf8CString:
93-
guard hasNoInterpolation() else { return "" }
83+
guard hasNoInterpolation(context, node, string) else { return "" }
9484
return "\(string.utf8CString)"
9585

9686
case .foundationData:
97-
guard hasNoInterpolation() else { return "" }
87+
guard hasNoInterpolation(context, node, string) else { return "" }
9888
return "Data(\(bytes([UInt8](string.utf8))))"
9989

10090
case .byteBuffer:
101-
guard hasNoInterpolation() else { return "" }
91+
guard hasNoInterpolation(context, node, string) else { return "" }
10292
return "ByteBuffer(bytes: \(bytes([UInt8](string.utf8))))"
10393

10494
case .string:
@@ -107,14 +97,23 @@ extension HTMLKitUtilities {
10797
return encoded.replacingOccurrences(of: "$0", with: string)
10898
}
10999
}
100+
private static func hasNoInterpolation(_ context: HTMLExpansionContext, _ node: MacroExpansionExprSyntax, _ string: String) -> Bool {
101+
guard string.firstRange(of: try! Regex("\\((.*)\\)")) == nil else {
102+
if !context.ignoresCompilerWarnings {
103+
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 intended result.")))
104+
}
105+
return false
106+
}
107+
return true
108+
}
110109

111110
// MARK: Parse Arguments
112111
public static func parseArguments(
113112
context: HTMLExpansionContext,
114113
otherAttributes: [String:String] = [:]
115114
) -> ElementData {
116115
var context = context
117-
var global_attributes:[HTMLAttribute] = []
116+
var globalAttributes:[HTMLAttribute] = []
118117
var attributes:[String:Sendable] = [:]
119118
var innerHTML:[CustomStringConvertible & Sendable] = []
120119
var trailingSlash:Bool = false
@@ -129,7 +128,7 @@ extension HTMLKitUtilities {
129128
case "lookupFiles":
130129
context.lookupFiles = Set(child.expression.array!.elements.compactMap({ $0.expression.stringLiteral?.string(encoding: context.encoding) }))
131130
case "attributes":
132-
(global_attributes, trailingSlash) = parseGlobalAttributes(context: context, array: child.expression.array!.elements)
131+
(globalAttributes, trailingSlash) = parseGlobalAttributes(context: context, array: child.expression.array!.elements)
133132
default:
134133
context.key = otherAttributes[key] ?? key
135134
if let test = HTMLAttribute.Extra.parse(context: context, expr: child.expression) {
@@ -141,8 +140,7 @@ extension HTMLKitUtilities {
141140
case .int(let i): attributes[key] = i
142141
case .float(let f): attributes[key] = f
143142
case .array:
144-
let escaped:LiteralReturnType = literal.escapeArray()
145-
switch escaped {
143+
switch literal.escapeArray() {
146144
case .array(let a): attributes[key] = a
147145
default: break
148146
}
@@ -169,27 +167,30 @@ extension HTMLKitUtilities {
169167
}
170168
}
171169
}
172-
return ElementData(context.encoding, global_attributes, attributes, innerHTML, trailingSlash)
170+
return ElementData(context.encoding, globalAttributes, attributes, innerHTML, trailingSlash)
173171
}
174172

175173
// MARK: Parse Encoding
176174
public static func parseEncoding(expression: ExprSyntax) -> HTMLEncoding? {
177-
if let key = expression.memberAccess?.declName.baseName.text {
178-
return HTMLEncoding(rawValue: key)
179-
} else if let function = expression.functionCall {
175+
switch expression.kind {
176+
case .memberAccessExpr:
177+
return HTMLEncoding(rawValue: expression.memberAccess!.declName.baseName.text)
178+
case .functionCallExpr:
179+
let function = expression.functionCall!
180180
switch function.calledExpression.as(MemberAccessExprSyntax.self)?.declName.baseName.text {
181181
case "custom":
182-
guard let logic = function.arguments.first?.expression.stringLiteral?.string(encoding: .string) else { break }
182+
guard let logic = function.arguments.first?.expression.stringLiteral?.string(encoding: .string) else { return nil }
183183
if function.arguments.count == 1 {
184184
return .custom(logic)
185185
} else {
186186
return .custom(logic, stringDelimiter: function.arguments.last!.expression.stringLiteral!.string(encoding: .string))
187187
}
188188
default:
189-
break
189+
return nil
190190
}
191+
default:
192+
return nil
191193
}
192-
return nil
193194
}
194195

195196
// MARK: Parse Global Attributes
@@ -328,13 +329,13 @@ extension HTMLKitUtilities {
328329

329330
// MARK: Misc
330331
extension ExprSyntax {
331-
package func string(context: HTMLExpansionContext) -> String? {
332+
package func string(_ context: HTMLExpansionContext) -> String? {
332333
return HTMLKitUtilities.parseLiteralValue(context: context, expression: self)?.value(key: context.key)
333334
}
334-
package func boolean(context: HTMLExpansionContext) -> Bool? {
335+
package func boolean(_ context: HTMLExpansionContext) -> Bool? {
335336
booleanLiteral?.literal.text == "true"
336337
}
337-
package func enumeration<T : HTMLParsable>(context: HTMLExpansionContext) -> T? {
338+
package func enumeration<T : HTMLParsable>(_ context: HTMLExpansionContext) -> T? {
338339
if let function = functionCall, let member = function.calledExpression.memberAccess {
339340
var c = context
340341
c.key = member.declName.baseName.text
@@ -348,28 +349,28 @@ extension ExprSyntax {
348349
}
349350
return nil
350351
}
351-
package func int(context: HTMLExpansionContext) -> Int? {
352+
package func int(_ context: HTMLExpansionContext) -> Int? {
352353
guard let s = HTMLKitUtilities.parseLiteralValue(context: context, expression: self)?.value(key: context.key) else { return nil }
353354
return Int(s)
354355
}
355-
package func arrayString(context: HTMLExpansionContext) -> [String]? {
356-
array?.elements.compactMap({ $0.expression.string(context: context) })
356+
package func arrayString(_ context: HTMLExpansionContext) -> [String]? {
357+
array?.elements.compactMap({ $0.expression.string(context) })
357358
}
358-
package func arrayEnumeration<T: HTMLParsable>(context: HTMLExpansionContext) -> [T]? {
359-
array?.elements.compactMap({ $0.expression.enumeration(context: context) })
359+
package func arrayEnumeration<T: HTMLParsable>(_ context: HTMLExpansionContext) -> [T]? {
360+
array?.elements.compactMap({ $0.expression.enumeration(context) })
360361
}
361-
package func dictionaryStringString(context: HTMLExpansionContext) -> [String:String] {
362+
package func dictionaryStringString(_ context: HTMLExpansionContext) -> [String:String] {
362363
var d:[String:String] = [:]
363364
if let elements = dictionary?.content.as(DictionaryElementListSyntax.self) {
364365
for element in elements {
365-
if let key = element.key.string(context: context), let value = element.value.string(context: context) {
366+
if let key = element.key.string(context), let value = element.value.string(context) {
366367
d[key] = value
367368
}
368369
}
369370
}
370371
return d
371372
}
372-
package func float(context: HTMLExpansionContext) -> Float? {
373+
package func float(_ context: HTMLExpansionContext) -> Float? {
373374
guard let s = HTMLKitUtilities.parseLiteralValue(context: context, expression: self)?.value(key: context.key) else { return nil }
374375
return Float(s)
375376
}
@@ -391,11 +392,11 @@ package struct DiagnosticMsg : DiagnosticMessage, FixItMessage {
391392

392393
// MARK: HTMLExpansionContext
393394
extension HTMLExpansionContext {
394-
func string() -> String? { expression?.string(context: self) }
395-
func boolean() -> Bool? { expression?.boolean(context: self) }
396-
func enumeration<T : HTMLParsable>() -> T? { expression?.enumeration(context: self) }
397-
func int() -> Int? { expression?.int(context: self) }
398-
func float() -> Float? { expression?.float(context: self) }
399-
func arrayString() -> [String]? { expression?.arrayString(context: self) }
400-
func arrayEnumeration<T: HTMLParsable>() -> [T]? { expression?.arrayEnumeration(context: self) }
395+
func string() -> String? { expression?.string(self) }
396+
func boolean() -> Bool? { expression?.boolean(self) }
397+
func enumeration<T : HTMLParsable>() -> T? { expression?.enumeration(self) }
398+
func int() -> Int? { expression?.int(self) }
399+
func float() -> Float? { expression?.float(self) }
400+
func arrayString() -> [String]? { expression?.arrayString(self) }
401+
func arrayEnumeration<T: HTMLParsable>() -> [T]? { expression?.arrayEnumeration(self) }
401402
}

Sources/HTMLKitParse/ParseLiteral.swift

Lines changed: 25 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -16,19 +16,7 @@ extension HTMLKitUtilities {
1616
context: HTMLExpansionContext,
1717
expression: ExprSyntax
1818
) -> LiteralReturnType? {
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
28-
}
29-
guard var returnType = extractLiteral(context: context, expression: expression) else {
30-
return nil
31-
}
19+
guard let returnType = extractLiteral(context: context, expression: expression) else { return nil }
3220
guard returnType.isInterpolation else { return returnType }
3321
var remainingInterpolation:Int = 1
3422
var string:String
@@ -40,8 +28,8 @@ extension HTMLKitUtilities {
4028
segments.append(segment)
4129
if let expression = segment.as(ExpressionSegmentSyntax.self) {
4230
interpolation.append(expression)
31+
remainingInterpolation += 1
4332
}
44-
remainingInterpolation += segment.is(StringSegmentSyntax.self) ? 0 : 1
4533
}
4634
var minimum:Int = 0
4735
for expr in interpolation {
@@ -77,29 +65,17 @@ extension HTMLKitUtilities {
7765
}
7866
// TODO: promote interpolation via lookupFiles here (remove `warnInterpolation` above and from `promoteInterpolation`)
7967
if remainingInterpolation > 0 {
80-
returnType = .interpolation(string)
68+
return .interpolation(string)
8169
} else {
82-
returnType = .string(string)
70+
return .string(string)
8371
}
84-
return returnType
8572
}
8673
// MARK: Promote Interpolation
8774
static func promoteInterpolation(
8875
context: HTMLExpansionContext,
8976
remainingInterpolation: inout Int,
9077
expr: ExpressionSegmentSyntax
9178
) -> [any (SyntaxProtocol & SyntaxHashable)] {
92-
func create(_ string: String) -> StringLiteralExprSyntax {
93-
var s = StringLiteralExprSyntax(content: string)
94-
s.openingQuote = TokenSyntax(stringLiteral: "")
95-
s.closingQuote = TokenSyntax(stringLiteral: "")
96-
return s
97-
}
98-
func interpolate(_ syntax: ExprSyntaxProtocol) -> ExpressionSegmentSyntax {
99-
var list = LabeledExprListSyntax()
100-
list.append(LabeledExprSyntax(expression: syntax))
101-
return ExpressionSegmentSyntax(expressions: list)
102-
}
10379
var values:[any (SyntaxProtocol & SyntaxHashable)] = []
10480
for element in expr.expressions {
10581
let expression = element.expression
@@ -131,13 +107,32 @@ extension HTMLKitUtilities {
131107
}
132108
return values
133109
}
110+
static func create(_ string: String) -> StringLiteralExprSyntax {
111+
var s = StringLiteralExprSyntax(content: string)
112+
s.openingQuote = TokenSyntax(stringLiteral: "")
113+
s.closingQuote = TokenSyntax(stringLiteral: "")
114+
return s
115+
}
116+
static func interpolate(_ syntax: ExprSyntaxProtocol) -> ExpressionSegmentSyntax {
117+
var list = LabeledExprListSyntax()
118+
list.append(LabeledExprSyntax(expression: syntax))
119+
return ExpressionSegmentSyntax(expressions: list)
120+
}
121+
134122
// MARK: Extract Literal
135123
static func extractLiteral(
136124
context: HTMLExpansionContext,
137125
expression: ExprSyntax
138126
) -> LiteralReturnType? {
139127
switch expression.kind {
140-
case .nilLiteralExpr: return nil
128+
case .nilLiteralExpr:
129+
return nil
130+
case .booleanLiteralExpr:
131+
return .boolean(expression.booleanLiteral!.literal.text == "true")
132+
case .integerLiteralExpr:
133+
return .int(Int(expression.integerLiteral!.literal.text)!)
134+
case .floatLiteralExpr:
135+
return .float(Float(expression.floatLiteral!.literal.text)!)
141136
case .memberAccessExpr, .forceUnwrapExpr:
142137
return .interpolation("\(expression)")
143138
case .stringLiteralExpr:
@@ -260,6 +255,7 @@ public enum LiteralReturnType {
260255

261256
// MARK: Misc
262257
extension MemberAccessExprSyntax {
258+
@inlinable
263259
var singleLineDescription : String {
264260
var string = "\(self)"
265261
string.removeAll { $0.isWhitespace }

Sources/HTMLKitParse/extensions/HTMLElementValueType.swift

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,7 @@ import SwiftSyntax
1212

1313
extension HTMLElementValueType {
1414
package static func get<T: HTMLElement>(_ context: HTMLExpansionContext, _ bruh: T.Type) -> T {
15-
let data = HTMLKitUtilities.parseArguments(context: context, otherAttributes: T.otherAttributes)
16-
return T(context.encoding, data)
15+
return T(context.encoding, HTMLKitUtilities.parseArguments(context: context, otherAttributes: T.otherAttributes))
1716
}
1817
package static func parseElement(
1918
context: HTMLExpansionContext,

Sources/HTMLKitParse/extensions/HTMX.swift

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ extension HTMXAttribute : HTMLParsable {
2323
case "disinherit": self = .disinherit(string())
2424
case "encoding": self = .encoding(string())
2525
case "ext": self = .ext(string())
26-
case "headers": self = .headers(js: boolean() ?? false, context.arguments.last!.expression.dictionaryStringString(context: context))
26+
case "headers": self = .headers(js: boolean() ?? false, context.arguments.last!.expression.dictionaryStringString(context))
2727
case "history": self = .history(enumeration())
2828
case "historyElt": self = .historyElt(boolean())
2929
case "include": self = .include(string())
@@ -37,19 +37,19 @@ extension HTMXAttribute : HTMLParsable {
3737
case "replaceURL": self = .replaceURL(enumeration())
3838
case "request":
3939
guard let js = boolean() else { return nil }
40-
let timeout = context.arguments.get(1)?.expression.string(context: context)
41-
let credentials = context.arguments.get(2)?.expression.string(context: context)
42-
let noHeaders = context.arguments.get(3)?.expression.string(context: context)
40+
let timeout = context.arguments.getPositive(1)?.expression.string(context)
41+
let credentials = context.arguments.getPositive(2)?.expression.string(context)
42+
let noHeaders = context.arguments.getPositive(3)?.expression.string(context)
4343
self = .request(js: js, timeout: timeout, credentials: credentials, noHeaders: noHeaders)
4444
case "sync":
4545
guard let s = string() else { return nil }
46-
self = .sync(s, strategy: context.arguments.last!.expression.enumeration(context: context))
46+
self = .sync(s, strategy: context.arguments.last!.expression.enumeration(context))
4747
case "validate": self = .validate(enumeration())
4848

4949
case "get": self = .get(string())
5050
case "post": self = .post(string())
5151
case "on", "onevent":
52-
guard let s = context.arguments.last?.expression.string(context: context) else { return nil }
52+
guard let s = context.arguments.last?.expression.string(context) else { return nil }
5353
if context.key == "on" {
5454
self = .on(enumeration(), s)
5555
} else {

Sources/HTMLKitParse/extensions/html/HTMLAttributes.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ extension HTMLAttribute : HTMLParsable {
2323
case "class": self = .class(arrayString())
2424
case "contenteditable": self = .contenteditable(enumeration())
2525
case "data", "custom":
26-
guard let id = string(), let value = context.arguments.last?.expression.string(context: context) else {
26+
guard let id = string(), let value = context.arguments.last?.expression.string(context) else {
2727
return nil
2828
}
2929
if context.key == "data" {
@@ -64,7 +64,7 @@ extension HTMLAttribute : HTMLParsable {
6464
case "trailingSlash": self = .trailingSlash
6565
case "htmx": self = .htmx(enumeration())
6666
case "event":
67-
guard let event:HTMLEvent = enumeration(), let value = context.arguments.last?.expression.string(context: context) else {
67+
guard let event:HTMLEvent = enumeration(), let value = context.arguments.last?.expression.string(context) else {
6868
return nil
6969
}
7070
self = .event(event, value)

Sources/HTMLKitUtilities/HTMLElementType.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
// Created by Evan Anderson on 11/21/24.
66
//
77

8-
public enum HTMLElementType : String, CaseIterable, Sendable {
8+
public enum HTMLElementType : String, Sendable {
99
case html
1010

1111
case a

Sources/HTMLKitUtilities/HTMLEncoding.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@ public enum HTMLEncoding : Sendable {
6464
///
6565
case custom(_ logic: String, stringDelimiter: String = "\\\"")
6666

67+
@inlinable
6768
public init?(rawValue: String) {
6869
switch rawValue {
6970
case "string": self = .string

0 commit comments

Comments
 (0)