diff --git a/GeminiFormat/Document.swift b/GeminiFormat/Document.swift index 5efba8c..34864ee 100644 --- a/GeminiFormat/Document.swift +++ b/GeminiFormat/Document.swift @@ -15,6 +15,12 @@ public struct Document { self.url = url self.lines = lines } + + /// Renders this Document to Gemini formatted text. This is not guaranteed to be the original input text. + public func toGeminiText() -> String { + // todo: should this be \r\n + return lines.map { $0.geminiText() }.joined(separator: "\n") + } } public extension Document { @@ -26,11 +32,49 @@ public extension Document { case heading(String, level: HeadingLevel) case unorderedListItem(String) case quote(String) + + func geminiText() -> String { + switch self { + case let .text(text): + return text + case let .link(url, text: text): + if let text = text { + return "=> \(url.absoluteString) \(text)" + } else { + return "=> \(url.absoluteString)" + } + case let .preformattedToggle(alt: alt): + if let alt = alt { + return "```\(alt)" + } else { + return "```" + } + case let .preformattedText(text): + return text + case let .heading(text, level: level): + return "\(level.geminiText) \(text)" + case let .unorderedListItem(text): + return "* \(text)" + case let .quote(text): + return "> \(text)" + } + } } } public extension Document { enum HeadingLevel: Int { case h1 = 1, h2 = 2, h3 = 3 + + var geminiText: String { + switch self { + case .h1: + return "#" + case .h2: + return "##" + case .h3: + return "###" + } + } } } diff --git a/GeminiFormatTests/DocumentTests.swift b/GeminiFormatTests/DocumentTests.swift new file mode 100644 index 0000000..0096f1e --- /dev/null +++ b/GeminiFormatTests/DocumentTests.swift @@ -0,0 +1,56 @@ +// +// DocumentTests.swift +// GeminiFormatTests +// +// Created by Shadowfacts on 7/12/20. +// + +import XCTest +@testable import GeminiFormat + +class DocumentTests: XCTestCase { + + func testLineText() { + XCTAssertEqual(Document.Line.text("some text").geminiText(), "some text") + XCTAssertEqual(Document.Line.link(URL(string: "gemini://example.com/foo?bar")!, text: "some link").geminiText(), "=> gemini://example.com/foo?bar some link") + XCTAssertEqual(Document.Line.link(URL(string: "gemini://example.com/foo?bar")!, text: nil).geminiText(), "=> gemini://example.com/foo?bar") + XCTAssertEqual(Document.Line.preformattedToggle(alt: "blah").geminiText(), "```blah") + XCTAssertEqual(Document.Line.preformattedToggle(alt: nil).geminiText(), "```") + XCTAssertEqual(Document.Line.preformattedText("test").geminiText(), "test") + XCTAssertEqual(Document.Line.heading("one", level: .h1).geminiText(), "# one") + XCTAssertEqual(Document.Line.heading("two", level: .h2).geminiText(), "## two") + XCTAssertEqual(Document.Line.heading("three", level: .h3).geminiText(), "### three") + XCTAssertEqual(Document.Line.unorderedListItem("list item").geminiText(), "* list item") + XCTAssertEqual(Document.Line.quote("quoted").geminiText(), "> quoted") + } + + func testDocumentText() { + let doc = Document(url: URL(string: "gemini://example.com")!, lines: [ + .text("text"), + .link(URL(string: "gemini://example.com/")!, text: "a link"), + .link(URL(string: "gemini://example.com/foo?bar")!, text: nil), + .preformattedToggle(alt: "blah"), + .preformattedText("test"), + .preformattedToggle(alt: nil), + .heading("one", level: .h1), + .heading("two", level: .h2), + .heading("three", level: .h3), + .unorderedListItem("list item"), + .quote("quoted"), + ]) + XCTAssertEqual(doc.toGeminiText(), """ +text +=> gemini://example.com/ a link +=> gemini://example.com/foo?bar +```blah +test +``` +# one +## two +### three +* list item +> quoted +""") + } + +}