@@ -11,17 +11,17 @@ public func render(_ nodes: [Node]) -> String {
1111public func render( _ node: Node ) -> String {
1212 switch node {
1313 case let . comment( string) :
14- return " <!-- \( string . replacingOccurrences ( of : " --> " , with : " --> " ) ) --> "
14+ return " <!-- \( escapeHtmlComment ( string ) ) --> "
1515 case let . doctype( string) :
16- return " <!DOCTYPE \( string . replacingOccurrences ( of : " > " , with : " > " ) ) > "
16+ return " <!DOCTYPE \( escapeDoctype ( string ) ) > "
1717 case let . element( tag, attribs, children) :
1818 let renderedAttribs = render ( attribs)
1919 guard !children. isEmpty else {
2020 return " < " + tag + renderedAttribs + ( voidElements. contains ( tag) ? " > " : " /> " )
2121 }
2222 return " < " + tag + renderedAttribs + " > " + render( children) + " </ " + tag + " > "
2323 case let . text( string) :
24- return escape ( html : string)
24+ return escapeTextNode ( text : string)
2525 case let . raw( string) :
2626 return string
2727 }
@@ -39,20 +39,32 @@ private func render(_ attribs: [(String, String?)]) -> String {
3939 return attribs
4040 . compactMap { key, value in
4141 value. map {
42- " " + key + ( $0. isEmpty ? " " : " = \" \( $0 . replacingOccurrences ( of : " \" " , with : " " " ) ) \" " )
42+ " " + key + ( $0. isEmpty ? " " : " = \" \( escapeAttributeValue ( $0 ) ) \" " )
4343 }
4444 }
4545 . joined ( )
4646}
4747
48- private func escape( html: String ) -> String {
49- return html
48+ public func escapeAttributeValue( _ value: String ) -> String {
49+ return value. replacingOccurrences ( of: " \" " , with: " " " )
50+ }
51+
52+ public func escapeTextNode( text: String ) -> String {
53+ return text
5054 . replacingOccurrences ( of: " & " , with: " & " )
5155 . replacingOccurrences ( of: " < " , with: " < " )
5256}
5357
58+ public func escapeDoctype( _ doctype: String ) -> String {
59+ return doctype. replacingOccurrences ( of: " > " , with: " > " )
60+ }
61+
62+ public func escapeHtmlComment( _ comment: String ) -> String {
63+ return comment. replacingOccurrences ( of: " --> " , with: " --> " )
64+ }
65+
5466/// A set of self-closing "void" elements that should not contain child nodes.
55- private let voidElements : Set < String > = [
67+ public let voidElements : Set < String > = [
5668 " area " ,
5769 " base " ,
5870 " br " ,
0 commit comments