/
HTML.swift
85 lines (65 loc) · 2.31 KB
/
HTML.swift
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
/**
* Ink
* Copyright (c) John Sundell 2019
* MIT license, see LICENSE file for details
*/
internal struct HTML: Fragment {
var modifierTarget: Modifier.Target { .html }
private var string: Substring
static func read(using reader: inout Reader) throws -> HTML {
let startIndex = reader.currentIndex
let rootElement = try reader.readHTMLElement()
guard !rootElement.isSelfClosing else {
let html = reader.characters(in: startIndex..<reader.currentIndex)
return HTML(string: html)
}
var rootElementCount = 1
while !reader.didReachEnd {
guard reader.currentCharacter == "<" else {
reader.advanceIndex()
continue
}
guard var element = try? reader.readHTMLElement() else {
continue
}
guard rootElement.name != element.name else {
rootElementCount += 1
continue
}
guard element.name.first == "/" else {
continue
}
element.name = element.name.dropFirst()
if rootElement.name == element.name {
rootElementCount -= 1
guard rootElementCount > 0 else { break }
}
}
let html = reader.characters(in: startIndex..<reader.currentIndex)
return HTML(string: html)
}
func html(usingURLs urls: NamedURLCollection,
modifiers: ModifierCollection) -> String {
return String(string)
}
}
private extension Reader {
typealias HTMLElement = (name: Substring, isSelfClosing: Bool)
mutating func readHTMLElement() throws -> HTMLElement {
try read("<")
let startIndex = currentIndex
while !didReachEnd {
guard !currentCharacter.isWhitespace, currentCharacter != ">" else {
let name = characters(in: startIndex..<currentIndex)
try require(!name.isEmpty)
let suffix = try read(until: ">", allowLineBreaks: true)
guard name.last != "/" else {
return (name.dropLast(), true)
}
return (name, suffix.last == "/" || name == "!--")
}
advanceIndex()
}
throw Error()
}
}