5
5
// Created by Evan Anderson on 3/31/25.
6
6
//
7
7
8
- import SwiftSyntax
9
-
10
8
extension HTMLKitUtilities {
11
- static let defaultPreservedWhitespaceTags : Set < String > = Set ( [
12
- " a " , " abbr " ,
13
- " b " , " bdi " , " bdo " , " button " ,
14
- " cite " , " code " ,
15
- " data " , " dd " , " dfn " , " dt " ,
16
- " em " ,
17
- " h1 " , " h2 " , " h3 " , " h4 " , " h5 " , " h6 " ,
18
- " i " ,
19
- " kbd " ,
20
- " label " , " li " ,
21
- " mark " ,
22
- " p " ,
23
- " q " ,
24
- " rp " ,
25
- " rt " ,
26
- " ruby " ,
27
- " s " , " samp " , " small " , " span " , " strong " , " sub " , " sup " ,
28
- " td " , " time " , " title " , " tr " ,
29
- " u " ,
30
- " var " ,
31
- " wbr "
32
- ] . map { " < " + $0 + " > " } )
9
+ static let defaultPreservedWhitespaceTags : Set < Substring > = Set ( Array < HTMLElementType > ( arrayLiteral :
10
+ . a , . abbr,
11
+ . b , . bdi, . bdo, . button,
12
+ . cite, . code,
13
+ . data, . dd , . dfn, . dt ,
14
+ . em ,
15
+ . h1 , . h2 , . h3 , . h4 , . h5 , . h6 ,
16
+ . i ,
17
+ . kbd,
18
+ . label, . li ,
19
+ . mark,
20
+ . p ,
21
+ . q ,
22
+ . rp ,
23
+ . rt ,
24
+ . ruby,
25
+ . s , . samp, . small, . span, . strong, . sub, . sup,
26
+ . td , . time, . title, . tr ,
27
+ . u ,
28
+ . variable ,
29
+ . wbr
30
+ ) . map { " < " + $0. tagName + " > " } )
33
31
34
32
/// Removes whitespace between elements.
35
33
public static func minify(
36
34
html: String ,
37
- preservingWhitespaceForTags: Set < String > = [ ]
35
+ preservingWhitespaceForTags: Set < Substring > = [ ]
38
36
) -> String {
39
- var preservedWhitespaceTags : Set < String > = Self . defaultPreservedWhitespaceTags
40
- preservedWhitespaceTags. formUnion ( preservingWhitespaceForTags)
41
37
var result : String = " "
42
38
result. reserveCapacity ( html. count)
43
39
let tagRegex = " [^/>]+ "
44
- let openElementRegex = " (< \( tagRegex) >) "
45
- let openElementRanges = html. ranges ( of: try ! Regex ( openElementRegex) )
46
-
47
- let closeElementRegex = " (</ \( tagRegex) >) "
48
- let closeElementRanges = html. ranges ( of: try ! Regex ( closeElementRegex) )
40
+ let openElementRanges = html. ranges ( of: try ! Regex ( " (< \( tagRegex) >) " ) )
41
+ let closeElementRanges = html. ranges ( of: try ! Regex ( " (</ \( tagRegex) >) " ) )
49
42
50
43
var openingRangeIndex = 0
51
44
var ignoredClosingTags : Set < Range < String . Index > > = [ ]
52
45
for openingRange in openElementRanges {
53
46
let tag = html [ openingRange]
54
47
result += tag
55
- let closure : ( Character ) -> Bool = preservedWhitespaceTags. contains ( String ( tag) ) ? { _ in true } : {
56
- !( $0. isWhitespace || $0. isNewline)
57
- }
48
+ let closure = Self . defaultPreservedWhitespaceTags. contains ( tag) || preservingWhitespaceForTags. contains ( tag) ? appendAll : appendIfPreserved
58
49
let closestClosingRange = closeElementRanges. first ( where: { $0. lowerBound > openingRange. upperBound } )
59
- if let nextOpeningRange = openElementRanges. get ( openingRangeIndex + 1 ) {
50
+ if let nextOpeningRange = openElementRanges. getPositive ( openingRangeIndex + 1 ) {
60
51
var i = openingRange. upperBound
61
52
var lowerBound = nextOpeningRange. lowerBound
62
53
if let closestClosingRange {
@@ -68,13 +59,7 @@ extension HTMLKitUtilities {
68
59
}
69
60
}
70
61
// anything after the opening tag, upto the end of the next closing tag
71
- while i < lowerBound {
72
- let char = html [ i]
73
- if closure ( char) {
74
- result. append ( char)
75
- }
76
- html. formIndex ( after: & i)
77
- }
62
+ closure ( html, & i, lowerBound, & result)
78
63
// anything after the closing tag and before the next opening tag
79
64
while i < nextOpeningRange. lowerBound {
80
65
let char = html [ i]
@@ -85,12 +70,8 @@ extension HTMLKitUtilities {
85
70
}
86
71
} else if let closestClosingRange {
87
72
// anything after the opening tag and before the next closing tag
88
- let slice = html [ openingRange. upperBound..< closestClosingRange. lowerBound]
89
- for char in slice {
90
- if closure ( char) {
91
- result. append ( char)
92
- }
93
- }
73
+ var i = openingRange. upperBound
74
+ closure ( html, & i, closestClosingRange. lowerBound, & result)
94
75
}
95
76
openingRangeIndex += 1
96
77
}
@@ -101,4 +82,31 @@ extension HTMLKitUtilities {
101
82
}
102
83
return result
103
84
}
85
+ }
86
+
87
+ // MARK: append
88
+ extension HTMLKitUtilities {
89
+ fileprivate static func appendAll(
90
+ html: String ,
91
+ i: inout String . Index ,
92
+ bound: String . Index ,
93
+ result: inout String
94
+ ) {
95
+ result += html [ i..< bound]
96
+ i = bound
97
+ }
98
+ fileprivate static func appendIfPreserved(
99
+ html: String ,
100
+ i: inout String . Index ,
101
+ bound: String . Index ,
102
+ result: inout String
103
+ ) {
104
+ while i < bound {
105
+ let char = html [ i]
106
+ if !( char. isWhitespace || char. isNewline) {
107
+ result. append ( char)
108
+ }
109
+ html. formIndex ( after: & i)
110
+ }
111
+ }
104
112
}
0 commit comments