From d396a800f63d8c793bbdb9c078f96412ac895395 Mon Sep 17 00:00:00 2001 From: Shadowfacts Date: Sun, 17 Dec 2023 18:32:00 -0500 Subject: [PATCH] Fix handling of mis-nested tags --- .../HTMLStreamer/AttributedStringConverter.swift | 9 +++++++-- .../AttributedStringConverterTests.swift | 15 +++++++++++++++ 2 files changed, 22 insertions(+), 2 deletions(-) diff --git a/Sources/HTMLStreamer/AttributedStringConverter.swift b/Sources/HTMLStreamer/AttributedStringConverter.swift index eb3c7e1..d2f3170 100644 --- a/Sources/HTMLStreamer/AttributedStringConverter.swift +++ b/Sources/HTMLStreamer/AttributedStringConverter.swift @@ -151,7 +151,7 @@ public struct AttributedStringConverter { private mutating func handleEndTag(_ name: String) { switch name { case "a": - if case .link(.some(_)) = styleStack.last { + if case .link(.some(_)) = lastStyle(.link) { finishRun() } removeLastStyle(.link) @@ -186,7 +186,8 @@ public struct AttributedStringConverter { } } - // needed to correctly handle mis-nested tags + // Finds the last currently-open style of the given type. + // We can't just use the last one because we need to handle mis-nested tags. private mutating func removeLastStyle(_ type: Style.StyleType) { var i = styleStack.index(before: styleStack.endIndex) while i >= styleStack.startIndex { @@ -198,6 +199,10 @@ public struct AttributedStringConverter { } } + private func lastStyle(_ type: Style.StyleType) -> Style? { + styleStack.last { $0.type == type } + } + private lazy var blockquoteParagraphStyle: NSParagraphStyle = { let style = configuration.paragraphStyle.mutableCopy() as! NSMutableParagraphStyle style.headIndent = 32 diff --git a/Tests/HTMLStreamerTests/AttributedStringConverterTests.swift b/Tests/HTMLStreamerTests/AttributedStringConverterTests.swift index fda40fb..14e2d3d 100644 --- a/Tests/HTMLStreamerTests/AttributedStringConverterTests.swift +++ b/Tests/HTMLStreamerTests/AttributedStringConverterTests.swift @@ -119,6 +119,21 @@ final class AttributedStringConverterTests: XCTestCase { XCTAssertEqual(convert("bold both italic"), result) } + func testMisnestedLink() { + let result = NSMutableAttributedString() + result.append(NSAttributedString(string: "hello ", attributes: [ + .link: URL(string: "https://example.com")!, + .font: font, + .paragraphStyle: NSParagraphStyle.default, + ])) + result.append(NSAttributedString(string: "world", attributes: [ + .link: URL(string: "https://example.com")!, + .font: boldFont, + .paragraphStyle: NSParagraphStyle.default, + ])) + XCTAssertEqual(convert("hello world"), result) + } + func testDel() { XCTAssertEqual(convert("blah"), NSAttributedString(string: "blah", attributes: [ .font: font,