diff --git a/Sources/SyndiKit/Common/Entryable.swift b/Sources/SyndiKit/Common/Entryable.swift index 164dd02..b381ae7 100644 --- a/Sources/SyndiKit/Common/Entryable.swift +++ b/Sources/SyndiKit/Common/Entryable.swift @@ -5,7 +5,7 @@ public protocol Entryable { /// Unique Identifier of the Item. var id: EntryID { get } /// The URL of the item. - var url: URL { get } + var url: URL? { get } /// The title of the item. var title: String { get } /// HTML content of the item. diff --git a/Sources/SyndiKit/Formats/Feeds/Atom/AtomEntry.swift b/Sources/SyndiKit/Formats/Feeds/Atom/AtomEntry.swift index 0dc2288..dc982bc 100644 --- a/Sources/SyndiKit/Formats/Feeds/Atom/AtomEntry.swift +++ b/Sources/SyndiKit/Formats/Feeds/Atom/AtomEntry.swift @@ -1,8 +1,6 @@ import Foundation public struct AtomEntry: Codable { - public static let defaultURL = URL(string: "/")! - /// A permanent, universally unique identifier for an entry. public let id: EntryID @@ -61,8 +59,8 @@ extension AtomEntry: Entryable { atomCategories } - public var url: URL { - links.first?.href ?? Self.defaultURL + public var url: URL? { + links.first?.href } public var contentHtml: String? { diff --git a/Sources/SyndiKit/Formats/Feeds/JSONFeed/JSONItem.swift b/Sources/SyndiKit/Formats/Feeds/JSONFeed/JSONItem.swift index dee2e4f..e324310 100644 --- a/Sources/SyndiKit/Formats/Feeds/JSONFeed/JSONItem.swift +++ b/Sources/SyndiKit/Formats/Feeds/JSONFeed/JSONItem.swift @@ -2,7 +2,7 @@ import Foundation public struct JSONItem: Codable { public let guid: EntryID - public let url: URL + public let url: URL? public let title: String public let contentHtml: String? public let summary: String? diff --git a/Sources/SyndiKit/Formats/Feeds/RSS/RSSItem.swift b/Sources/SyndiKit/Formats/Feeds/RSS/RSSItem.swift index 647bebb..bb31542 100644 --- a/Sources/SyndiKit/Formats/Feeds/RSS/RSSItem.swift +++ b/Sources/SyndiKit/Formats/Feeds/RSS/RSSItem.swift @@ -3,7 +3,7 @@ import XMLCoder public struct RSSItem: Codable { public let title: String - public let link: URL + public let link: URL? public let description: CData? public let guid: EntryID public let pubDate: Date? @@ -135,7 +135,7 @@ public struct RSSItem: Codable { public init(from decoder: Decoder) throws { let container = try decoder.container(keyedBy: CodingKeys.self) title = try container.decode(String.self, forKey: .title) - link = try container.decode(URL.self, forKey: .link) + link = try container.decodeIfPresent(URL.self, forKey: .link) description = try container.decodeIfPresent(CData.self, forKey: .description) guid = try container.decode(EntryID.self, forKey: .guid) pubDate = try container.decodeDateIfPresentAndValid(forKey: .pubDate) @@ -297,7 +297,7 @@ extension RSSItem: Entryable { categoryTerms } - public var url: URL { + public var url: URL? { link } diff --git a/Sources/SyndiKit/Formats/Media/Wordpress/WordPressPost.swift b/Sources/SyndiKit/Formats/Media/Wordpress/WordPressPost.swift index 10daded..e7effb5 100644 --- a/Sources/SyndiKit/Formats/Media/Wordpress/WordPressPost.swift +++ b/Sources/SyndiKit/Formats/Media/Wordpress/WordPressPost.swift @@ -149,9 +149,11 @@ public extension WordPressPost { guard let modifiedDate = item.wpModifiedDate else { throw WordPressError.missingField(.modifiedDate) } + guard let link = item.link else { + throw WordPressError.missingField(.link) + } let title = item.title - let link = item.link let categoryTerms = item.categoryTerms let meta = item.wpPostMeta let pubDate = item.pubDate diff --git a/Tests/SyndiKitTests/RSSCodedTests.swift b/Tests/SyndiKitTests/RSSCodedTests.swift index 56f9dcc..384a3e5 100644 --- a/Tests/SyndiKitTests/RSSCodedTests.swift +++ b/Tests/SyndiKitTests/RSSCodedTests.swift @@ -406,6 +406,27 @@ public final class SyndiKitTests: XCTestCase { try assertInvalidGeoData(from: invalidCoords) } + func testPodcastMissingLink() throws { + guard let feed = try? Content.xmlFeeds["wait-wait-dont-tell-me"]?.get() else { + XCTFail("Missing Podcast \(name)") + return + } + + guard let rss = feed as? RSSFeed else { + XCTFail("Wrong Type \(name)") + return + } + + guard rss.channel.items.count > 193 else { + XCTFail("Missing Item \(name)") + return + } + + let item = rss.channel.items[193] + + XCTAssertNil(item.link) + } + private func assertInvalidGeoData(from xmlStr: String) throws { guard let data = xmlStr.data(using: .utf8) else { XCTFail("Expected data out of \(xmlStr)")