Skip to content

Commit 6622b1a

Browse files
now just need to fix some logic for unit tests to pass
1 parent bccc860 commit 6622b1a

File tree

7 files changed

+150
-34
lines changed

7 files changed

+150
-34
lines changed

Sources/HTMLKit/HTMLKit.swift

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,8 +31,6 @@ public macro escapeHTML<T: ExpressibleByStringLiteral>(_ innerHTML: T...) -> T =
3131
@freestanding(expression)
3232
public macro html<T: ExpressibleByStringLiteral>(
3333
lookupFiles: [StaticString] = [],
34-
attributes: [HTMLElementAttribute] = [],
35-
xmlns: T? = nil,
3634
_ innerHTML: HTMLElement...
3735
) -> T = #externalMacro(module: "HTMLKitMacros", type: "HTMLElementMacro")
3836

Sources/HTMLKitMacros/HTMLElement.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -160,7 +160,7 @@ private extension HTMLElementMacro {
160160
string = String(string[string.index(after: string.startIndex)...])
161161
if let htmx:HTMLElementAttribute.HTMX = HTMLElementAttribute.HTMX(rawValue: string) {
162162
key = "hx-" + htmx.key
163-
let htmlValue:String = htmx.htmlValue
163+
let htmlValue:String = htmx.htmlValue!
164164
var delimiter:String = "\\\"", isBoolean:Bool = false
165165
func check_boolean(_ boolean: Bool) {
166166
isBoolean = true

Sources/HTMLKitUtilities/HTMLKitUtilities.swift

Lines changed: 134 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -265,6 +265,60 @@ package indirect enum HTMLElementValueType {
265265
cleanup(&range)
266266
return String(slice)
267267
}
268+
static func cGlobalAttributes(key: String, _ range: inout Substring) -> [HTMLElementAttribute] {
269+
guard consumable(key: key, range: &range), range.first == "[" else { return [] }
270+
range.removeFirst()
271+
cleanup(&range)
272+
var attributes:[HTMLElementAttribute] = []
273+
var string:String = "", depth:Int = 1, attribute_depth:Int = 0
274+
func parse_attribute() {
275+
if string.first == "." {
276+
string.removeFirst()
277+
}
278+
//print("HTMLKitUtilities;cGlobalAttributes;parse_attribute;string=\(string)")
279+
if let attribute:HTMLElementAttribute = HTMLElementAttribute(rawValue: string) {
280+
attributes.append(attribute)
281+
}
282+
cleanup(&range)
283+
}
284+
loop: while let char:Character = range.first {
285+
switch char {
286+
case "[":
287+
depth += 1
288+
break
289+
case "]":
290+
depth -= 1
291+
if depth == 0 {
292+
range.removeFirst()
293+
parse_attribute()
294+
break loop
295+
}
296+
break
297+
case "(":
298+
attribute_depth += 1
299+
break
300+
case ")":
301+
attribute_depth -= 1
302+
break
303+
default:
304+
if attribute_depth != 0 {
305+
break
306+
} else if depth == 1 {
307+
switch char {
308+
case ",":
309+
parse_attribute()
310+
string = ""
311+
continue
312+
default:
313+
break
314+
}
315+
}
316+
break
317+
}
318+
string.append(range.removeFirst())
319+
}
320+
return attributes
321+
}
268322
static func cString(key: String, _ range: inout Substring) -> String? {
269323
guard consumable(key: key, range: &range) else { return nil }
270324
guard !range.isEmpty else { return "" }
@@ -457,6 +511,7 @@ package indirect enum HTMLElementValueType {
457511
case "header": return header(rawValue: rawValue)
458512
case "hgroup": return hgroup(rawValue: rawValue)
459513
case "hr": return hr(rawValue: rawValue)
514+
case "html": return html(rawValue: rawValue)
460515
case "i": return i(rawValue: rawValue)
461516
case "iframe": return iframe(rawValue: rawValue)
462517
case "img": return img(rawValue: rawValue)
@@ -556,7 +611,7 @@ public enum HTMLElementAttribute {
556611
case itemtype(String? = nil)
557612
case lang(String? = nil)
558613
case nonce(String? = nil)
559-
case part([(String)] = [])
614+
case part([String] = [])
560615
case popover(Extra.popover? = nil)
561616
case slot(String? = nil)
562617
case spellcheck(Extra.spellcheck? = nil)
@@ -579,6 +634,58 @@ public enum HTMLElementAttribute {
579634
@available(*, deprecated, message: "General consensus considers this \"bad practice\" and you shouldn't mix your HTML and JavaScript. This will never be removed and remains deprecated to encourage use of other techniques. Learn more at https://developer.mozilla.org/en-US/docs/Learn/JavaScript/Building_blocks/Events#inline_event_handlers_—_dont_use_these.")
580635
case event(Extra.event, _ value: String? = nil)
581636

637+
public init?(rawValue: String) {
638+
guard rawValue.last == ")" else { return nil }
639+
let key:Substring = rawValue.split(separator: "(")[0]
640+
func string() -> String { HTMLElementAttribute.string(key: key, rawValue: rawValue) }
641+
func boolean() -> Bool { HTMLElementAttribute.boolean(key: key, rawValue: rawValue) }
642+
func enumeration<T : HTMLInitializable>() -> T { HTMLElementAttribute.enumeration(key: key, rawValue: rawValue) }
643+
func int() -> Int { HTMLElementAttribute.int(key: key, rawValue: rawValue) }
644+
func array_string() -> [String] { HTMLElementAttribute.array_string(key: key, rawValue: rawValue) }
645+
func float() -> Float { HTMLElementAttribute.float(key: key, rawValue: rawValue) }
646+
switch key {
647+
case "accesskey": self = .accesskey(string())
648+
case "ariaattribute": self = .ariaattribute(enumeration())
649+
case "role": self = .role(enumeration())
650+
case "autocapitalize": self = .autocapitalize(enumeration())
651+
case "autofocus": self = .autofocus(boolean())
652+
case "class": self = .class(array_string())
653+
case "contenteditable": self = .contenteditable(enumeration())
654+
case "data": self = .data("", "") // TODO: fix
655+
case "dir": self = .dir(enumeration())
656+
case "draggable": self = .draggable(enumeration())
657+
case "enterkeyhint": self = .enterkeyhint(enumeration())
658+
case "exportparts": self = .exportparts(array_string())
659+
case "hidden": self = .hidden(enumeration())
660+
case "id": self = .id(string())
661+
case "inert": self = .inert(boolean())
662+
case "inputmode": self = .inputmode(enumeration())
663+
case "is": self = .is(string())
664+
case "itemid": self = .itemid(string())
665+
case "itemprop": self = .itemprop(string())
666+
case "itemref": self = .itemref(string())
667+
case "itemscope": self = .itemscope(boolean())
668+
case "itemtype": self = .itemtype(string())
669+
case "lang": self = .lang(string())
670+
case "nonce": self = .nonce(string())
671+
case "part": self = .part(array_string())
672+
case "popover": self = .popover(enumeration())
673+
case "slot": self = .slot(string())
674+
case "spellcheck": self = .spellcheck(enumeration())
675+
case "style": self = .style(string())
676+
case "tabindex": self = .tabindex(int())
677+
case "title": self = .title(string())
678+
case "translate": self = .translate(enumeration())
679+
case "virtualkeyboardpolicy": self = .virtualkeyboardpolicy(enumeration())
680+
case "writingsuggestions": self = .writingsuggestions(enumeration())
681+
case "trailingSlash": self = .trailingSlash
682+
case "htmx": self = .htmx(enumeration())
683+
case "custom": self = .custom("", "") // TODO: fix
684+
case "event": self = .event(.click, "") // TODO: fix
685+
default: return nil
686+
}
687+
}
688+
582689
public var key : String {
583690
switch self {
584691
case .accesskey(_): return "accesskey"
@@ -618,7 +725,15 @@ public enum HTMLElementAttribute {
618725

619726
case .trailingSlash: return ""
620727

621-
case .htmx(let htmx): return "htmx-" + htmx.key
728+
case .htmx(let htmx):
729+
switch htmx {
730+
case .ws(let value):
731+
return "ws-" + value.key
732+
case .sse(let value):
733+
return "sse-" + value.key
734+
default:
735+
return "hx-" + htmx.key
736+
}
622737
case .custom(let id, _): return id
623738
case .event(let event, _): return "on" + event.rawValue
624739
}
@@ -686,7 +801,7 @@ extension HTMLElementAttribute {
686801
let start:String.Index = rawValue.startIndex, end:String.Index = rawValue.index(before: rawValue.endIndex)
687802
return rawValue[rawValue.index(start, offsetBy: key.count + 1)..<end] == "true"
688803
}
689-
static func enumeration<T : RawRepresentable>(key: Substring, rawValue: String) -> T where T.RawValue == String {
804+
static func enumeration<T : HTMLInitializable>(key: Substring, rawValue: String) -> T {
690805
let start:String.Index = rawValue.startIndex, end:String.Index = rawValue.index(before: rawValue.endIndex)
691806
return T(rawValue: String(rawValue[rawValue.index(start, offsetBy: key.count + 2)..<end]))!
692807
}
@@ -800,7 +915,7 @@ public extension HTMLElementAttribute.Extra {
800915
let key:Substring = rawValue.split(separator: "(")[0]
801916
func string() -> String { HTMLElementAttribute.string(key: key, rawValue: rawValue) }
802917
func boolean() -> Bool { HTMLElementAttribute.boolean(key: key, rawValue: rawValue) }
803-
func enumeration<T : RawRepresentable>() -> T where T.RawValue == String { HTMLElementAttribute.enumeration(key: key, rawValue: rawValue) }
918+
func enumeration<T : HTMLInitializable>() -> T { HTMLElementAttribute.enumeration(key: key, rawValue: rawValue) }
804919
func int() -> Int { HTMLElementAttribute.int(key: key, rawValue: rawValue) }
805920
func array_string() -> [String] { HTMLElementAttribute.array_string(key: key, rawValue: rawValue) }
806921
func float() -> Float { HTMLElementAttribute.float(key: key, rawValue: rawValue) }
@@ -978,49 +1093,49 @@ public extension HTMLElementAttribute.Extra {
9781093
}
9791094
}
9801095

981-
public enum Autocomplete : String {
1096+
public enum Autocomplete : String, HTMLInitializable {
9821097
case none, inline, list, both
9831098
}
984-
public enum Checked : String {
1099+
public enum Checked : String, HTMLInitializable {
9851100
case `false`, `true`, mixed, undefined
9861101
}
987-
public enum Current : String {
1102+
public enum Current : String, HTMLInitializable {
9881103
case page, step, location, date, time, `true`, `false`
9891104
}
990-
public enum DropEffect : String {
1105+
public enum DropEffect : String, HTMLInitializable {
9911106
case copy, execute, link, move, none, popup
9921107
}
993-
public enum Expanded : String {
1108+
public enum Expanded : String, HTMLInitializable {
9941109
case `false`, `true`, undefined
9951110
}
996-
public enum Grabbed : String {
1111+
public enum Grabbed : String, HTMLInitializable {
9971112
case `true`, `false`, undefined
9981113
}
999-
public enum HasPopup : String {
1114+
public enum HasPopup : String, HTMLInitializable {
10001115
case `false`, `true`, menu, listbox, tree, grid, dialog
10011116
}
1002-
public enum Hidden : String {
1117+
public enum Hidden : String, HTMLInitializable {
10031118
case `false`, `true`, undefined
10041119
}
1005-
public enum Invalid : String {
1120+
public enum Invalid : String, HTMLInitializable {
10061121
case grammar, `false`, spelling, `true`
10071122
}
1008-
public enum Live : String {
1123+
public enum Live : String, HTMLInitializable {
10091124
case assertive, off, polite
10101125
}
1011-
public enum Orientation : String {
1126+
public enum Orientation : String, HTMLInitializable {
10121127
case horizontal, undefined, vertical
10131128
}
1014-
public enum Pressed : String {
1129+
public enum Pressed : String, HTMLInitializable {
10151130
case `false`, mixed, `true`, undefined
10161131
}
1017-
public enum Relevant : String {
1132+
public enum Relevant : String, HTMLInitializable {
10181133
case additions, all, removals, text
10191134
}
1020-
public enum Selected : String {
1135+
public enum Selected : String, HTMLInitializable {
10211136
case `true`, `false`, undefined
10221137
}
1023-
public enum Sort : String {
1138+
public enum Sort : String, HTMLInitializable {
10241139
case ascending, descending, none, other
10251140
}
10261141
}

Sources/HTMLKitUtilities/HTMX.swift

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
//
77

88
public extension HTMLElementAttribute {
9-
enum HTMX {
9+
enum HTMX : HTMLInitializable {
1010
case boost(TrueOrFalse)
1111
case confirm(String)
1212
case delete(String)
@@ -53,7 +53,7 @@ public extension HTMLElementAttribute {
5353
func literal() -> String { HTMLElementAttribute.literal(key: key, rawValue: rawValue) }
5454
func string() -> String { HTMLElementAttribute.string(key: key, rawValue: rawValue) }
5555
func boolean() -> Bool { HTMLElementAttribute.boolean(key: key, rawValue: rawValue) }
56-
func enumeration<T : RawRepresentable>() -> T where T.RawValue == String { HTMLElementAttribute.enumeration(key: key, rawValue: rawValue) }
56+
func enumeration<T : HTMLInitializable>() -> T { HTMLElementAttribute.enumeration(key: key, rawValue: rawValue) }
5757
func int() -> Int { HTMLElementAttribute.int(key: key, rawValue: rawValue) }
5858
func array_string() -> [String] { HTMLElementAttribute.array_string(key: key, rawValue: rawValue) }
5959
func float() -> Float { HTMLElementAttribute.float(key: key, rawValue: rawValue) }
@@ -227,7 +227,7 @@ public extension HTMLElementAttribute {
227227
}
228228
}
229229

230-
public var htmlValue : String {
230+
public var htmlValue : String? {
231231
switch self {
232232
case .boost(let value): return value.rawValue
233233
case .confirm(let value): return value
@@ -291,7 +291,7 @@ public extension HTMLElementAttribute {
291291

292292
public extension HTMLElementAttribute.HTMX {
293293
// MARK: Boost
294-
enum TrueOrFalse : String {
294+
enum TrueOrFalse : String, HTMLInitializable {
295295
case `true`, `false`
296296
}
297297

@@ -433,7 +433,7 @@ public extension HTMLElementAttribute.HTMX {
433433
}
434434

435435
// MARK: Swap
436-
enum Swap : String {
436+
enum Swap : String, HTMLInitializable {
437437
case innerHTML, outerHTML
438438
case textContent
439439
case beforebegin, afterbegin

Sources/HTMLKitUtilities/LiteralElements.swift

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -144,7 +144,11 @@ public struct custom : HTMLElement {
144144
public var attributes:[HTMLElementAttribute]
145145
public var innerHTML:[CustomStringConvertible]
146146

147-
public init?(rawValue: String) {
147+
public init?(rawValue: String) { // TODO: fix
148+
guard let key:Substring = rawValue.split(separator: "(").first, String(key) == "custom" else {
149+
return nil
150+
}
151+
var range:Substring = rawValue[rawValue.index(rawValue.startIndex, offsetBy: key.count + 1) ..< rawValue.index(rawValue.endIndex, offsetBy: -1)]
148152
tag = ""
149153
isVoid = false
150154
attributes = []

Sources/HTMLKitUtilityMacros/HTMLElements.swift

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -44,10 +44,9 @@ enum HTMLElements : DeclarationMacro {
4444
var attributes:[(String, String, String)] = []
4545
if let test = item.value.as(ArrayExprSyntax.self)?.elements {
4646
initializers += "public init?(rawValue: String) {\n"
47-
initializers += "guard let key:Substring = rawValue.split(separator: \"(\").first else { return nil }\n"
48-
initializers += "guard String(key) == tag else { return nil }\n"
47+
initializers += "guard let key:Substring = rawValue.split(separator: \"(\").first, String(key) == tag else { return nil }\n"
4948
initializers += "var range:Substring = rawValue[rawValue.index(rawValue.startIndex, offsetBy: key.count+1)..<rawValue.index(rawValue.endIndex, offsetBy: -1)]\n"
50-
initializers += "self = .init("
49+
initializers += "self = .init(\nattributes: HTMLElementValueType.cGlobalAttributes(key: \"attributes\", &range),"
5150
attributes.reserveCapacity(test.count)
5251
for element in test {
5352
var key:String = "", key_literal:String = ""

Tests/HTMLKitTests/ElementTests.swift

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -49,10 +49,10 @@ struct ElementTests {
4949
extension ElementTests {
5050
// MARK: html
5151
@Test func _html() {
52-
var string:StaticString = #html()
52+
var string:StaticString = #html(html())
5353
#expect(string == "<!DOCTYPE html><html></html>")
5454

55-
string = #html(xmlns: "test")
55+
string = #html(html(xmlns: "test"))
5656
#expect(string == "<!DOCTYPE html><html xmlns=\"test\"></html>")
5757
}
5858

@@ -421,7 +421,7 @@ extension ElementTests {
421421
}
422422

423423
@Test func no_value_type() {
424-
let expected_string:String = "<!DOCTYPE html><html><body><h1>HTMLKitTests</h1></body></html>"
424+
let expected_string:String = "<body><h1>HTMLKitTests</h1></body>"
425425
let test1:String = #html(body(h1("HTMLKitTests")))
426426
#expect(type(of: test1) == String.self)
427427
#expect(test1 == expected_string)

0 commit comments

Comments
 (0)