diff --git a/Modules/Parser/Package.swift b/Modules/Parser/Package.swift index 4862baaba..7ec9e4468 100644 --- a/Modules/Parser/Package.swift +++ b/Modules/Parser/Package.swift @@ -8,7 +8,7 @@ let package = Package( products: [ .library( name: "Parser", - targets: ["Parser"]), + targets: ["Parser"]) ], dependencies: [ .package(path: "../RSCore") @@ -26,6 +26,6 @@ let package = Package( "Parser" ], resources: [.copy("Resources")] - ), + ) ] ) diff --git a/Modules/Parser/Sources/Parser/FeedParser/Feeds/FeedType.swift b/Modules/Parser/Sources/Parser/FeedParser/Feeds/FeedType.swift index 40a535e2a..6123c3a6c 100644 --- a/Modules/Parser/Sources/Parser/FeedParser/Feeds/FeedType.swift +++ b/Modules/Parser/Sources/Parser/FeedParser/Feeds/FeedType.swift @@ -36,7 +36,7 @@ public enum FeedType: Sendable { return .unknown } let cCharPointer = baseAddress.assumingMemoryBound(to: CChar.self) - + if isProbablyJSON(cCharPointer, count) { if isPartialData { diff --git a/Modules/Parser/Sources/Parser/FeedParser/Feeds/JSON/JSONFeedParser.swift b/Modules/Parser/Sources/Parser/FeedParser/Feeds/JSON/JSONFeedParser.swift index f0f2568f1..2a55c6992 100644 --- a/Modules/Parser/Sources/Parser/FeedParser/Feeds/JSON/JSONFeedParser.swift +++ b/Modules/Parser/Sources/Parser/FeedParser/Feeds/JSON/JSONFeedParser.swift @@ -160,7 +160,7 @@ private extension JSONFeedParser { let dateModified = parseDate(itemDictionary[Key.dateModified] as? String) let authors = parseAuthors(itemDictionary) - var tags: Set? = nil + var tags: Set? if let tagsArray = itemDictionary[Key.tags] as? [String] { tags = Set(tagsArray) } diff --git a/Modules/Parser/Sources/Parser/FeedParser/Feeds/JSON/RSSInJSONParser.swift b/Modules/Parser/Sources/Parser/FeedParser/Feeds/JSON/RSSInJSONParser.swift index 5b685bb3c..0146342ce 100644 --- a/Modules/Parser/Sources/Parser/FeedParser/Feeds/JSON/RSSInJSONParser.swift +++ b/Modules/Parser/Sources/Parser/FeedParser/Feeds/JSON/RSSInJSONParser.swift @@ -53,8 +53,7 @@ public struct RSSInJSONParser { return ParsedFeed(type: .rssInJSON, title: title, homePageURL: homePageURL, feedURL: feedURL, language: feedLanguage, feedDescription: feedDescription, nextURL: nil, iconURL: nil, faviconURL: nil, authors: nil, expired: false, hubs: nil, items: items) - } - catch { throw error } + } catch { throw error } } } @@ -62,7 +61,7 @@ private extension RSSInJSONParser { static func parseItems(_ itemsObject: JSONArray, _ feedURL: String) -> Set { - return Set(itemsObject.compactMap{ (oneItemDictionary) -> ParsedItem? in + return Set(itemsObject.compactMap { (oneItemDictionary) -> ParsedItem? in return parsedItemWithDictionary(oneItemDictionary, feedURL) }) @@ -74,7 +73,7 @@ private extension RSSInJSONParser { let title = itemDictionary["title"] as? String var contentHTML = itemDictionary["description"] as? String - var contentText: String? = nil + var contentText: String? if contentHTML != nil && !(contentHTML!.contains("<")) { contentText = contentHTML contentHTML = nil @@ -83,7 +82,7 @@ private extension RSSInJSONParser { return nil } - var datePublished: Date? = nil + var datePublished: Date? if let datePublishedString = itemDictionary["pubDate"] as? String { datePublished = DateParser.date(string: datePublishedString) } @@ -150,9 +149,8 @@ private extension RSSInJSONParser { return Set([oneTag]) } return nil - } - else if let categoryArray = itemDictionary["category"] as? JSONArray { - return Set(categoryArray.compactMap{ $0["#value"] as? String }) + } else if let categoryArray = itemDictionary["category"] as? JSONArray { + return Set(categoryArray.compactMap { $0["#value"] as? String }) } return nil } diff --git a/Modules/Parser/Sources/Parser/FeedParser/Feeds/ParsedAttachment.swift b/Modules/Parser/Sources/Parser/FeedParser/Feeds/ParsedAttachment.swift index febb32373..e51d5d0b0 100644 --- a/Modules/Parser/Sources/Parser/FeedParser/Feeds/ParsedAttachment.swift +++ b/Modules/Parser/Sources/Parser/FeedParser/Feeds/ParsedAttachment.swift @@ -20,7 +20,7 @@ public final class ParsedAttachment: Hashable, Sendable { if url.isEmpty { return nil } - + self.url = url self.mimeType = mimeType self.title = title diff --git a/Modules/Parser/Sources/Parser/FeedParser/Feeds/ParsedAuthor.swift b/Modules/Parser/Sources/Parser/FeedParser/Feeds/ParsedAuthor.swift index 67672655a..a930d0456 100644 --- a/Modules/Parser/Sources/Parser/FeedParser/Feeds/ParsedAuthor.swift +++ b/Modules/Parser/Sources/Parser/FeedParser/Feeds/ParsedAuthor.swift @@ -14,7 +14,7 @@ public final class ParsedAuthor: Hashable, Codable, Sendable { public let url: String? public let avatarURL: String? public let emailAddress: String? - + public init(name: String?, url: String?, avatarURL: String?, emailAddress: String?) { self.name = name self.url = url @@ -39,17 +39,13 @@ public final class ParsedAuthor: Hashable, Codable, Sendable { public func hash(into hasher: inout Hasher) { if let name { hasher.combine(name) - } - else if let url { + } else if let url { hasher.combine(url) - } - else if let emailAddress { + } else if let emailAddress { hasher.combine(emailAddress) - } - else if let avatarURL{ + } else if let avatarURL { hasher.combine(avatarURL) - } - else { + } else { hasher.combine("") } } diff --git a/Modules/Parser/Sources/Parser/FeedParser/Feeds/ParsedHub.swift b/Modules/Parser/Sources/Parser/FeedParser/Feeds/ParsedHub.swift index b959860b0..abe0e6899 100644 --- a/Modules/Parser/Sources/Parser/FeedParser/Feeds/ParsedHub.swift +++ b/Modules/Parser/Sources/Parser/FeedParser/Feeds/ParsedHub.swift @@ -17,7 +17,7 @@ public final class ParsedHub: Hashable, Sendable { self.type = type self.url = url } - + // MARK: - Hashable public func hash(into hasher: inout Hasher) { diff --git a/Modules/Parser/Sources/Parser/FeedParser/Feeds/ParsedItem.swift b/Modules/Parser/Sources/Parser/FeedParser/Feeds/ParsedItem.swift index 7ec988e8f..c748e8996 100644 --- a/Modules/Parser/Sources/Parser/FeedParser/Feeds/ParsedItem.swift +++ b/Modules/Parser/Sources/Parser/FeedParser/Feeds/ParsedItem.swift @@ -10,8 +10,8 @@ import Foundation public final class ParsedItem: Hashable, Sendable { - public let syncServiceID: String? //Nil when not syncing - public let uniqueID: String //RSS guid, for instance; may be calculated + public let syncServiceID: String? // Nil when not syncing + public let uniqueID: String // RSS guid, for instance; may be calculated public let feedURL: String public let url: String? public let externalURL: String? @@ -27,12 +27,12 @@ public final class ParsedItem: Hashable, Sendable { public let authors: Set? public let tags: Set? public let attachments: Set? - + public init(syncServiceID: String?, uniqueID: String, feedURL: String, url: String?, externalURL: String?, title: String?, language: String?, contentHTML: String?, contentText: String?, summary: String?, imageURL: String?, - bannerImageURL: String?,datePublished: Date?, dateModified: Date?, authors: Set?, + bannerImageURL: String?, datePublished: Date?, dateModified: Date?, authors: Set?, tags: Set?, attachments: Set?) { - + self.syncServiceID = syncServiceID self.uniqueID = uniqueID self.feedURL = feedURL @@ -57,8 +57,7 @@ public final class ParsedItem: Hashable, Sendable { public func hash(into hasher: inout Hasher) { if let syncServiceID = syncServiceID { hasher.combine(syncServiceID) - } - else { + } else { hasher.combine(uniqueID) hasher.combine(feedURL) } @@ -69,4 +68,3 @@ public final class ParsedItem: Hashable, Sendable { lhs.syncServiceID == rhs.syncServiceID && lhs.uniqueID == rhs.uniqueID && lhs.feedURL == rhs.feedURL && lhs.url == rhs.url && lhs.externalURL == rhs.externalURL && lhs.title == rhs.title && lhs.language == rhs.language && lhs.contentHTML == rhs.contentHTML && lhs.contentText == rhs.contentText && lhs.summary == rhs.summary && lhs.imageURL == rhs.imageURL && lhs.bannerImageURL == rhs.bannerImageURL && lhs.datePublished == rhs.datePublished && lhs.dateModified == rhs.dateModified && lhs.authors == rhs.authors && lhs.tags == rhs.tags && lhs.attachments == rhs.attachments } } - diff --git a/Modules/Parser/Sources/Parser/FeedParser/Feeds/XML/AtomParser.swift b/Modules/Parser/Sources/Parser/FeedParser/Feeds/XML/AtomParser.swift index 93e4bef77..1795dee98 100644 --- a/Modules/Parser/Sources/Parser/FeedParser/Feeds/XML/AtomParser.swift +++ b/Modules/Parser/Sources/Parser/FeedParser/Feeds/XML/AtomParser.swift @@ -181,29 +181,17 @@ private extension AtomParser { if SAXEqualTags(localName, XMLName.id) { currentArticle.guid = currentString(saxParser) - } - - else if SAXEqualTags(localName, XMLName.title) { + } else if SAXEqualTags(localName, XMLName.title) { currentArticle.title = currentString(saxParser) - } - - else if SAXEqualTags(localName, XMLName.content) { + } else if SAXEqualTags(localName, XMLName.content) { addContent(saxParser, currentArticle) - } - - else if SAXEqualTags(localName, XMLName.summary) { + } else if SAXEqualTags(localName, XMLName.summary) { addSummary(saxParser, currentArticle) - } - - else if SAXEqualTags(localName, XMLName.link) { + } else if SAXEqualTags(localName, XMLName.link) { addLink(currentArticle) - } - - else if SAXEqualTags(localName, XMLName.published) { + } else if SAXEqualTags(localName, XMLName.published) { currentArticle.datePublished = currentDate(saxParser) - } - - else if SAXEqualTags(localName, XMLName.updated) { + } else if SAXEqualTags(localName, XMLName.updated) { currentArticle.dateModified = currentDate(saxParser) } @@ -212,8 +200,7 @@ private extension AtomParser { if currentArticle.datePublished == nil { currentArticle.datePublished = currentDate(saxParser) } - } - else if SAXEqualTags(localName, XMLName.modified) { + } else if SAXEqualTags(localName, XMLName.modified) { if currentArticle.dateModified == nil { currentArticle.dateModified = currentDate(saxParser) } @@ -258,13 +245,11 @@ private extension AtomParser { if article.link == nil { article.link = resolvedURLString } - } - else if rel == AttributeValue.alternate { + } else if rel == AttributeValue.alternate { if article.permalink == nil { article.permalink = resolvedURLString } - } - else if rel == AttributeValue.enclosure { + } else if rel == AttributeValue.enclosure { if let enclosure = enclosure(resolvedURLString, attributes) { article.addEnclosure(enclosure) } @@ -372,7 +357,7 @@ extension AtomParser: SAXParserDelegate { currentArticle?.language = xmlAttributes["xml:lang"] } - let contentType = xmlAttributes["type"]; + let contentType = xmlAttributes["type"] if contentType == "xhtml" { parsingXHTML = true xhtmlString = "" @@ -416,9 +401,7 @@ extension AtomParser: SAXParserDelegate { if isContentTag { currentArticle?.body = xhtmlString - } - - else if isSummaryTag { + } else if isSummaryTag { if (currentArticle?.body?.count ?? 0) < 1 { currentArticle?.body = xhtmlString } @@ -438,9 +421,7 @@ extension AtomParser: SAXParserDelegate { } else { assertionFailure("xhtmlString must not be nil when parsingXHTML in xmlEndElement.") } - } - - else if parsingAuthor { + } else if parsingAuthor { if SAXEqualTags(localName, XMLName.author) { parsingAuthor = false @@ -448,32 +429,21 @@ extension AtomParser: SAXParserDelegate { currentArticle?.addAuthor(currentAuthor) } currentAuthor = nil - } - else if SAXEqualTags(localName, XMLName.name) { + } else if SAXEqualTags(localName, XMLName.name) { currentAuthor?.name = saxParser.currentStringWithTrimmedWhitespace - } - else if SAXEqualTags(localName, XMLName.email) { + } else if SAXEqualTags(localName, XMLName.email) { currentAuthor?.emailAddress = saxParser.currentStringWithTrimmedWhitespace - } - else if SAXEqualTags(localName, XMLName.uri) { + } else if SAXEqualTags(localName, XMLName.uri) { currentAuthor?.url = saxParser.currentStringWithTrimmedWhitespace } - } - - else if SAXEqualTags(localName, XMLName.entry) { + } else if SAXEqualTags(localName, XMLName.entry) { parsingArticle = false entryDepth = -1 - } - - else if parsingArticle && !parsingSource && depth == entryDepth + 1 { + } else if parsingArticle && !parsingSource && depth == entryDepth + 1 { addArticleElement(saxParser, localName, prefix) - } - - else if SAXEqualTags(localName, XMLName.source) { + } else if SAXEqualTags(localName, XMLName.source) { parsingSource = false - } - - else if !parsingArticle && !parsingSource && SAXEqualTags(localName, XMLName.title) { + } else if !parsingArticle && !parsingSource && SAXEqualTags(localName, XMLName.title) { addFeedTitle(saxParser) } diff --git a/Modules/Parser/Sources/Parser/FeedParser/Feeds/XML/RSSArticle.swift b/Modules/Parser/Sources/Parser/FeedParser/Feeds/XML/RSSArticle.swift index 810dcb0f9..eb908e13b 100644 --- a/Modules/Parser/Sources/Parser/FeedParser/Feeds/XML/RSSArticle.swift +++ b/Modules/Parser/Sources/Parser/FeedParser/Feeds/XML/RSSArticle.swift @@ -6,7 +6,7 @@ // import Foundation -//import FoundationExtras +// import FoundationExtras final class RSSArticle { @@ -81,28 +81,21 @@ private extension RSSArticle { if let permalink, !permalink.isEmpty, let datePublishedTimeStampString { s.append(permalink) s.append(datePublishedTimeStampString) - } - else if let link, !link.isEmpty, let datePublishedTimeStampString { + } else if let link, !link.isEmpty, let datePublishedTimeStampString { s.append(link) s.append(datePublishedTimeStampString) - } - else if let title, !title.isEmpty, let datePublishedTimeStampString { + } else if let title, !title.isEmpty, let datePublishedTimeStampString { s.append(title) s.append(datePublishedTimeStampString) - } - else if let datePublishedTimeStampString { + } else if let datePublishedTimeStampString { s.append(datePublishedTimeStampString) - } - else if let permalink, !permalink.isEmpty { + } else if let permalink, !permalink.isEmpty { s.append(permalink) - } - else if let link, !link.isEmpty { + } else if let link, !link.isEmpty { s.append(link) - } - else if let title, !title.isEmpty { + } else if let title, !title.isEmpty { s.append(title) - } - else if let body, !body.isEmpty { + } else if let body, !body.isEmpty { s.append(body) } diff --git a/Modules/Parser/Sources/Parser/FeedParser/Feeds/XML/RSSAuthor.swift b/Modules/Parser/Sources/Parser/FeedParser/Feeds/XML/RSSAuthor.swift index 297470b85..4b103e362 100644 --- a/Modules/Parser/Sources/Parser/FeedParser/Feeds/XML/RSSAuthor.swift +++ b/Modules/Parser/Sources/Parser/FeedParser/Feeds/XML/RSSAuthor.swift @@ -20,7 +20,7 @@ final class RSSAuthor { self.avatarURL = avatarURL self.emailAddress = emailAddress } - + /// Use when the actual property is unknown. Guess based on contents of the string. (This is common with RSS.) convenience init(singleString: String) { diff --git a/Modules/Parser/Sources/Parser/FeedParser/Feeds/XML/RSSParser.swift b/Modules/Parser/Sources/Parser/FeedParser/Feeds/XML/RSSParser.swift index 57afcd803..b43a46fd8 100644 --- a/Modules/Parser/Sources/Parser/FeedParser/Feeds/XML/RSSParser.swift +++ b/Modules/Parser/Sources/Parser/FeedParser/Feeds/XML/RSSParser.swift @@ -79,11 +79,9 @@ private extension RSSParser { if feed.link == nil { feed.link = saxParser.currentString } - } - else if SAXEqualTags(localName, XMLName.title) { + } else if SAXEqualTags(localName, XMLName.title) { feed.title = saxParser.currentString - } - else if SAXEqualTags(localName, XMLName.language) { + } else if SAXEqualTags(localName, XMLName.language) { feed.language = saxParser.currentString } } @@ -118,26 +116,20 @@ private extension RSSParser { if let currentString = saxParser.currentString { if SAXEqualTags(localName, XMLName.guid) { addGuid(currentString, currentArticle) - } - else if SAXEqualTags(localName, XMLName.author) { + } else if SAXEqualTags(localName, XMLName.author) { addAuthorWithString(currentString, currentArticle) - } - else if SAXEqualTags(localName, XMLName.link) { + } else if SAXEqualTags(localName, XMLName.link) { currentArticle.link = urlString(currentString) - } - else if SAXEqualTags(localName, XMLName.description) { + } else if SAXEqualTags(localName, XMLName.description) { if currentArticle.body == nil { currentArticle.body = currentString } - } - else if !parsingAuthor && SAXEqualTags(localName, XMLName.title) { + } else if !parsingAuthor && SAXEqualTags(localName, XMLName.title) { currentArticle.title = currentString - } - else if SAXEqualTags(localName, XMLName.pubDate) { + } else if SAXEqualTags(localName, XMLName.pubDate) { currentArticle.datePublished = currentDate(saxParser) } - } - else if SAXEqualTags(localName, XMLName.enclosure), let currentAttributes { + } else if SAXEqualTags(localName, XMLName.enclosure), let currentAttributes { addEnclosure(currentAttributes, currentArticle) } } @@ -148,8 +140,7 @@ private extension RSSParser { if let currentString = saxParser.currentString { addAuthorWithString(currentString, currentArticle) } - } - else if SAXEqualTags(localName, XMLName.date) { + } else if SAXEqualTags(localName, XMLName.date) { currentArticle.datePublished = currentDate(saxParser) } } @@ -298,7 +289,7 @@ extension RSSParser: SAXParserDelegate { return } - var xmlAttributes: StringDictionary? = nil + var xmlAttributes: StringDictionary? if (isRDF && SAXEqualTags(localName, XMLName.item)) || SAXEqualTags(localName, XMLName.guid) || SAXEqualTags(localName, XMLName.enclosure) { xmlAttributes = saxParser.attributesDictionary(attributes, attributeCount: attributeCount) } @@ -314,11 +305,9 @@ extension RSSParser: SAXParserDelegate { currentArticle.guid = rdfGuid currentArticle.permalink = rdfGuid } - } - else if prefix == nil && SAXEqualTags(localName, XMLName.image) { + } else if prefix == nil && SAXEqualTags(localName, XMLName.image) { parsingChannelImage = true - } - else if prefix == nil && SAXEqualTags(localName, XMLName.author) { + } else if prefix == nil && SAXEqualTags(localName, XMLName.author) { if parsingArticle { parsingAuthor = true } @@ -337,23 +326,18 @@ extension RSSParser: SAXParserDelegate { if isRDF && SAXEqualTags(localName, XMLName.uppercaseRDF) { endRSSFound = true - } - else if SAXEqualTags(localName, XMLName.rss) { + } else if SAXEqualTags(localName, XMLName.rss) { endRSSFound = true - } - else if SAXEqualTags(localName, XMLName.image) { + } else if SAXEqualTags(localName, XMLName.image) { parsingChannelImage = false - } - else if SAXEqualTags(localName, XMLName.item) { + } else if SAXEqualTags(localName, XMLName.item) { parsingArticle = false - } - else if parsingArticle { + } else if parsingArticle { addArticleElement(saxParser, localName, prefix) if SAXEqualTags(localName, XMLName.author) { parsingAuthor = false } - } - else if !parsingChannelImage { + } else if !parsingChannelImage { addFeedElement(saxParser, localName, prefix) } } @@ -363,4 +347,3 @@ extension RSSParser: SAXParserDelegate { // Required method. } } - diff --git a/Modules/Parser/Sources/Parser/HTMLParser/HTMLEntityDecoder.swift b/Modules/Parser/Sources/Parser/HTMLParser/HTMLEntityDecoder.swift index aa4d0789f..f7d4341c8 100644 --- a/Modules/Parser/Sources/Parser/HTMLParser/HTMLEntityDecoder.swift +++ b/Modules/Parser/Sources/Parser/HTMLParser/HTMLEntityDecoder.swift @@ -70,7 +70,7 @@ private func decodedEntities(_ sourceBuffer: UnsafeBufferPointer, _ didDe resultBuffer.initializeMemory(as: UInt8.self, repeating: 0, count: resultBufferByteCount) let result = resultBuffer.assumingMemoryBound(to: UInt8.self) - + var sourceLocation = 0 var resultLocation = 0 @@ -78,7 +78,7 @@ private func decodedEntities(_ sourceBuffer: UnsafeBufferPointer, _ didDe let ch = sourceBuffer[sourceLocation] - var decodedEntity: String? = nil + var decodedEntity: String? if ch == ampersandCharacter { decodedEntity = decodedEntityValue(sourceBuffer, byteCount, &sourceLocation) @@ -112,7 +112,7 @@ private func addDecodedEntity(_ decodedEntity: String, _ result: UnsafeMutablePo } } -private func decodedEntityValue(_ buffer: UnsafeBufferPointer, _ byteCount: Int, _ sourceLocation: inout Int) -> /*[UInt8]?*/ String? { +private func decodedEntityValue(_ buffer: UnsafeBufferPointer, _ byteCount: Int, _ sourceLocation: inout Int) -> String? { guard let rawEntity = rawEntityValue(buffer, byteCount, &sourceLocation) else { return nil @@ -153,8 +153,7 @@ private func decodedNumericEntity(_ rawEntity: ContiguousArray) -> String if rawEntity[1] == xCharacter || rawEntity[1] == XCharacter { // Hex? decodedNumber = decodedHexEntity(rawEntity) - } - else { + } else { decodedNumber = decodedDecimalEntity(rawEntity) } @@ -247,7 +246,7 @@ private func decodedDecimalEntity(_ rawEntity: ContiguousArray) -> UInt32 if number == 0 { return nil } - + return number } @@ -271,7 +270,7 @@ private func rawEntityValue(_ buffer: UnsafeBufferPointer, _ byteCount: I while true { sourceLocation += 1 - if sourceLocation >= byteCount || entityCharactersIndex >= maxEntityCharacters { // did not parse entity + if sourceLocation >= byteCount || entityCharactersIndex >= maxEntityCharacters { // did not parse entity sourceLocation = savedSourceLocation return nil } diff --git a/Modules/Parser/Sources/Parser/HTMLParser/HTMLMetadata.swift b/Modules/Parser/Sources/Parser/HTMLParser/HTMLMetadata.swift index d51d3988e..5fc8aa28d 100644 --- a/Modules/Parser/Sources/Parser/HTMLParser/HTMLMetadata.swift +++ b/Modules/Parser/Sources/Parser/HTMLParser/HTMLMetadata.swift @@ -28,8 +28,7 @@ public final class HTMLMetadata: Sendable { self.appleTouchIcons = appleTouchIconTags.map { htmlTag in HTMLMetadataAppleTouchIcon(urlString, htmlTag) } - } - else { + } else { self.appleTouchIcons = nil } @@ -37,8 +36,7 @@ public final class HTMLMetadata: Sendable { self.feedLinks = feedLinkTags.map { htmlTag in HTMLMetadataFeedLink(urlString, htmlTag) } - } - else { + } else { self.feedLinks = nil } @@ -89,7 +87,7 @@ public final class HTMLMetadata: Sendable { } let feedLinkTags = alternateLinkTags.filter { tag in - + guard let attributes = tag.attributes, let type = attributes.object(forCaseInsensitiveKey: "type"), typeIsFeedType(type) else { return false } @@ -206,8 +204,7 @@ public final class HTMLMetadataAppleTouchIcon: Sendable { let sizeComponents = sizes.components(separatedBy: CharacterSet(charactersIn: "x")) if sizeComponents.count == 2, let width = Double(sizeComponents[0]), let height = Double(sizeComponents[1]) { self.size = CGSize(width: width, height: height) - } - else { + } else { self.size = nil } } @@ -313,25 +310,19 @@ private extension HTMLOpenGraphProperties { if propertyName == OGValue.ogImage { url = content - } - else if propertyName == OGValue.ogImageURL { + } else if propertyName == OGValue.ogImageURL { url = content - } - else if propertyName == OGValue.ogImageSecureURL { + } else if propertyName == OGValue.ogImageSecureURL { secureURL = content - } - else if propertyName == OGValue.ogImageType { + } else if propertyName == OGValue.ogImageType { mimeType = content - } - else if propertyName == OGValue.ogImageAlt { + } else if propertyName == OGValue.ogImageAlt { altText = content - } - else if propertyName == OGValue.ogImageWidth { + } else if propertyName == OGValue.ogImageWidth { if let value = Double(content) { width = CGFloat(value) } - } - else if propertyName == OGValue.ogImageHeight { + } else if propertyName == OGValue.ogImageHeight { if let value = Double(content) { height = CGFloat(value) } @@ -341,14 +332,14 @@ private extension HTMLOpenGraphProperties { if url == nil && secureURL == nil && mimeType == nil && width == nil && height == nil && altText == nil { return nil } - + return HTMLOpenGraphImage(url: url, secureURL: secureURL, mimeType: mimeType, width: width, height: height, altText: altText) } } public final class HTMLOpenGraphImage: Sendable { - public let url : String? + public let url: String? public let secureURL: String? public let mimeType: String? public let width: CGFloat? @@ -434,4 +425,3 @@ private func absoluteURLStringWithRelativeURLString(_ relativeURLString: String, } return absoluteURL.absoluteURL.standardized.absoluteString } - diff --git a/Modules/Parser/Sources/Parser/HTMLParser/HTMLMetadataParser.swift b/Modules/Parser/Sources/Parser/HTMLParser/HTMLMetadataParser.swift index d78054d54..4179615bb 100644 --- a/Modules/Parser/Sources/Parser/HTMLParser/HTMLMetadataParser.swift +++ b/Modules/Parser/Sources/Parser/HTMLParser/HTMLMetadataParser.swift @@ -34,13 +34,13 @@ private extension HTMLMetadataParser { extension HTMLMetadataParser: SAXHTMLParserDelegate { private struct HTMLName { - + static let link = "link".utf8CString static let meta = "meta".utf8CString } private struct HTMLKey { - + static let href = "href" static let src = "src" static let rel = "rel" @@ -81,8 +81,7 @@ extension HTMLMetadataParser: SAXHTMLParserDelegate { if let d, !d.isEmpty { handleLinkAttributes(d) } - } - else if SAXEqualTags(name, HTMLName.meta) { + } else if SAXEqualTags(name, HTMLName.meta) { let d = saxHTMLParser.attributesDictionary(attributes) if let d, !d.isEmpty { handleMetaAttributes(d) diff --git a/Modules/Parser/Sources/Parser/OPMLParser/OPMLDocument.swift b/Modules/Parser/Sources/Parser/OPMLParser/OPMLDocument.swift index 020ad11d3..07316ca00 100644 --- a/Modules/Parser/Sources/Parser/OPMLParser/OPMLDocument.swift +++ b/Modules/Parser/Sources/Parser/OPMLParser/OPMLDocument.swift @@ -9,8 +9,8 @@ import Foundation public final class OPMLDocument: OPMLItem { - public var title: String? = nil - public var url: String? = nil + public var title: String? + public var url: String? init(url: String?) { self.url = url diff --git a/Modules/Parser/Sources/Parser/OPMLParser/OPMLFeedSpecifier.swift b/Modules/Parser/Sources/Parser/OPMLParser/OPMLFeedSpecifier.swift index a0cd12df6..98b0e3363 100644 --- a/Modules/Parser/Sources/Parser/OPMLParser/OPMLFeedSpecifier.swift +++ b/Modules/Parser/Sources/Parser/OPMLParser/OPMLFeedSpecifier.swift @@ -37,4 +37,3 @@ public struct OPMLFeedSpecifier: Sendable { self.feedURL = feedURL } } - diff --git a/Modules/Parser/Sources/Parser/OPMLParser/OPMLItem.swift b/Modules/Parser/Sources/Parser/OPMLParser/OPMLItem.swift index 57e4232dc..c835c921f 100644 --- a/Modules/Parser/Sources/Parser/OPMLParser/OPMLItem.swift +++ b/Modules/Parser/Sources/Parser/OPMLParser/OPMLItem.swift @@ -20,7 +20,7 @@ public class OPMLItem { (items?.count ?? 0) > 0 } - init(attributes: [String : String]?) { + init(attributes: [String: String]?) { self.titleFromAttributes = attributes?.opml_title ?? attributes?.opml_text self.attributes = attributes @@ -33,7 +33,7 @@ public class OPMLItem { } public func add(_ item: OPMLItem) { - + if items == nil { items = [OPMLItem]() } diff --git a/Modules/Parser/Sources/Parser/OPMLParser/OPMLParser.swift b/Modules/Parser/Sources/Parser/OPMLParser/OPMLParser.swift index 4ec38d5b1..cc1b8e0b8 100644 --- a/Modules/Parser/Sources/Parser/OPMLParser/OPMLParser.swift +++ b/Modules/Parser/Sources/Parser/OPMLParser/OPMLParser.swift @@ -50,7 +50,7 @@ private extension OPMLParser { } func canParseData() -> Bool { - + data.containsASCIIString(") -> Bool { - return tag.withUnsafeBufferPointer { bufferPointer in - + return tag.withUnsafeBufferPointer { _ in + let tagCount = tag.count // includes 0 terminator for i in 0.. Bool } diff --git a/Modules/RSCore/Sources/RSCore/AppKit/NSOutlineView+RSCore.swift b/Modules/RSCore/Sources/RSCore/AppKit/NSOutlineView+RSCore.swift index a16152fba..be87c9e60 100755 --- a/Modules/RSCore/Sources/RSCore/AppKit/NSOutlineView+RSCore.swift +++ b/Modules/RSCore/Sources/RSCore/AppKit/NSOutlineView+RSCore.swift @@ -69,8 +69,7 @@ public extension NSOutlineView { selectRowAndScrollToVisible(row) return } - } - else { + } else { return // if there are no more items, we’re out of rows } } @@ -180,4 +179,3 @@ public extension NSOutlineView { } } #endif - diff --git a/Modules/RSCore/Sources/RSCore/AppKit/NSResponder-Extensions.swift b/Modules/RSCore/Sources/RSCore/AppKit/NSResponder-Extensions.swift index 80e4dcc6f..435a09647 100755 --- a/Modules/RSCore/Sources/RSCore/AppKit/NSResponder-Extensions.swift +++ b/Modules/RSCore/Sources/RSCore/AppKit/NSResponder-Extensions.swift @@ -9,22 +9,21 @@ import AppKit public extension NSResponder { - + func hasAncestor(_ ancestor: NSResponder) -> Bool { - + var nomad: NSResponder = self - while(true) { + while true { if nomad === ancestor { return true } if let _ = nomad.nextResponder { nomad = nomad.nextResponder! - } - else { + } else { break } } - + return false } } diff --git a/Modules/RSCore/Sources/RSCore/AppKit/NSTableView+RSCore.swift b/Modules/RSCore/Sources/RSCore/AppKit/NSTableView+RSCore.swift index bfffba77b..bf8a4ff76 100755 --- a/Modules/RSCore/Sources/RSCore/AppKit/NSTableView+RSCore.swift +++ b/Modules/RSCore/Sources/RSCore/AppKit/NSTableView+RSCore.swift @@ -9,11 +9,11 @@ import AppKit public extension NSTableView { - + var selectionIsEmpty: Bool { return selectedRowIndexes.startIndex == selectedRowIndexes.endIndex } - + func indexesOfAvailableRowsPassingTest(_ test: (Int) -> Bool) -> IndexSet? { // Checks visible and in-flight rows. @@ -43,12 +43,12 @@ public extension NSTableView { let documentVisibleRect = scrollView.documentVisibleRect let r = rect(ofRow: row) - if NSContainsRect(documentVisibleRect, r) { + if documentVisibleRect.contains(r) { return } - let rMidY = NSMidY(r) - var scrollPoint = NSZeroPoint; + let rMidY = r.midY + var scrollPoint = NSPoint.zero scrollPoint.y = floor(rMidY - (documentVisibleRect.size.height / 2.0)) + CGFloat(extraHeight) scrollPoint.y = max(scrollPoint.y, 0) @@ -57,7 +57,7 @@ public extension NSTableView { let clipView = scrollView.contentView - let rClipView = NSMakeRect(scrollPoint.x, scrollPoint.y, NSWidth(clipView.bounds), NSHeight(clipView.bounds)) + let rClipView = NSRect(x: scrollPoint.x, y: scrollPoint.y, width: clipView.bounds.width, height: clipView.bounds.height) clipView.animator().bounds = rClipView } diff --git a/Modules/RSCore/Sources/RSCore/AppKit/NSView+RSCore.swift b/Modules/RSCore/Sources/RSCore/AppKit/NSView+RSCore.swift index 3ad4601bf..b9b515389 100644 --- a/Modules/RSCore/Sources/RSCore/AppKit/NSView+RSCore.swift +++ b/Modules/RSCore/Sources/RSCore/AppKit/NSView+RSCore.swift @@ -9,16 +9,16 @@ import AppKit extension NSView { - + public func asImage() -> NSImage { let rep = bitmapImageRepForCachingDisplay(in: bounds)! cacheDisplay(in: bounds, to: rep) - + let img = NSImage(size: bounds.size) img.addRepresentation(rep) return img } - + } public extension NSView { diff --git a/Modules/RSCore/Sources/RSCore/AppKit/RSAppMovementMonitor.swift b/Modules/RSCore/Sources/RSCore/AppKit/RSAppMovementMonitor.swift index 089acb33f..ac90259b6 100644 --- a/Modules/RSCore/Sources/RSCore/AppKit/RSAppMovementMonitor.swift +++ b/Modules/RSCore/Sources/RSCore/AppKit/RSAppMovementMonitor.swift @@ -13,11 +13,11 @@ public class RSAppMovementMonitor: NSObject { // If provided, the handler will be consulted when the app is moved. // Return true to indicate that the default handler should be invoked. - public var appMovementHandler: ((RSAppMovementMonitor) -> Bool)? = nil + public var appMovementHandler: ((RSAppMovementMonitor) -> Bool)? // DispatchSource offers a monitoring mechanism based on an open file descriptor var fileDescriptor: Int32 = -1 - var dispatchSource: DispatchSourceFileSystemObject? = nil + var dispatchSource: DispatchSourceFileSystemObject? // Save the original location of the app in a file reference URL, which will track its new location. // Note this is NSURL, not URL, because file reference URLs violate value-type assumptions of URL. @@ -77,7 +77,7 @@ public class RSAppMovementMonitor: NSObject { // every time the app becomes active. This catches a good number of edge-case // changes to the app bundle's path, such as when a containing folder or the // volume name changes. - NotificationCenter.default.addObserver(forName: NSApplication.didBecomeActiveNotification, object: nil, queue: nil) { notification in + NotificationCenter.default.addObserver(forName: NSApplication.didBecomeActiveNotification, object: nil, queue: nil) { _ in // Removing observer in invalidate doesn't seem to prevent this getting called? Maybe // because it's on the same invocation of the runloop? if self.isValid() && self.originalAppURL != self.appTrackingURL?.absoluteURL { @@ -130,7 +130,7 @@ public class RSAppMovementMonitor: NSObject { // at the given URL with the "new instance" option to prevent it simply reactivating us. let configuration = NSWorkspace.OpenConfiguration() configuration.createsNewApplicationInstance = true - NSWorkspace.shared.openApplication(at: appURL, configuration: configuration) { _,_ in + NSWorkspace.shared.openApplication(at: appURL, configuration: configuration) { _, _ in NSApp.terminate(self) } } @@ -139,7 +139,7 @@ public class RSAppMovementMonitor: NSObject { let quitAlert = NSAlert() quitAlert.alertStyle = .critical quitAlert.addButton(withTitle: self.alertRelaunchButtonText) - + quitAlert.messageText = self.alertMessageText quitAlert.informativeText = self.alertInformativeText diff --git a/Modules/RSCore/Sources/RSCore/AppKit/RSToolbarItem.swift b/Modules/RSCore/Sources/RSCore/AppKit/RSToolbarItem.swift index 0a05bcd0e..10c1dcdf6 100755 --- a/Modules/RSCore/Sources/RSCore/AppKit/RSToolbarItem.swift +++ b/Modules/RSCore/Sources/RSCore/AppKit/RSToolbarItem.swift @@ -35,7 +35,7 @@ private extension RSToolbarItem { return false } - while(true) { + while true { if let validated = validateWithResponder(responder!) { return validated } diff --git a/Modules/RSCore/Sources/RSCore/AppKit/UserApp.swift b/Modules/RSCore/Sources/RSCore/AppKit/UserApp.swift index 87ea16ddd..d4eb94362 100644 --- a/Modules/RSCore/Sources/RSCore/AppKit/UserApp.swift +++ b/Modules/RSCore/Sources/RSCore/AppKit/UserApp.swift @@ -15,10 +15,10 @@ import AppKit public final class UserApp { public let bundleID: String - public var icon: NSImage? = nil + public var icon: NSImage? public var existsOnDisk = false - public var path: String? = nil - public var runningApplication: NSRunningApplication? = nil + public var path: String? + public var runningApplication: NSRunningApplication? public var isRunning: Bool { @@ -47,8 +47,7 @@ public final class UserApp { if app == runningApplication { break } - } - else { + } else { if !app.isTerminated { runningApplication = app break @@ -61,8 +60,7 @@ public final class UserApp { icon = runningApplication.icon if let bundleURL = runningApplication.bundleURL { path = bundleURL.path - } - else { + } else { path = NSWorkspace.shared.urlForApplication(withBundleIdentifier: bundleID)?.path } if icon == nil, let path = path { @@ -77,8 +75,7 @@ public final class UserApp { icon = NSWorkspace.shared.icon(forFile: path) } existsOnDisk = true - } - else { + } else { existsOnDisk = false icon = nil } @@ -146,4 +143,3 @@ public final class UserApp { } } #endif - diff --git a/Modules/RSCore/Sources/RSCore/Array+RSCore.swift b/Modules/RSCore/Sources/RSCore/Array+RSCore.swift index e583824f3..146c997f1 100644 --- a/Modules/RSCore/Sources/RSCore/Array+RSCore.swift +++ b/Modules/RSCore/Sources/RSCore/Array+RSCore.swift @@ -15,7 +15,7 @@ public extension Array { Array(self[$0 ..< Swift.min($0 + size, count)]) } } - + } public extension Array where Element: Equatable { diff --git a/Modules/RSCore/Sources/RSCore/BatchUpdate.swift b/Modules/RSCore/Sources/RSCore/BatchUpdate.swift index 1396eda22..fc1f289a8 100644 --- a/Modules/RSCore/Sources/RSCore/BatchUpdate.swift +++ b/Modules/RSCore/Sources/RSCore/BatchUpdate.swift @@ -23,7 +23,7 @@ public final class BatchUpdate { /// The shared batch update object. public static let shared = BatchUpdate() - + private var count = 0 /// Is updating in progress? @@ -50,15 +50,15 @@ public final class BatchUpdate { public func end() { precondition(Thread.isMainThread) decrementCount() - } + } } private extension BatchUpdate { - + func incrementCount() { count = count + 1 } - + func decrementCount() { count = count - 1 if count < 1 { @@ -67,7 +67,7 @@ private extension BatchUpdate { postBatchUpdateDidPerform() } } - + func postBatchUpdateDidPerform() { if !Thread.isMainThread { DispatchQueue.main.sync { @@ -77,5 +77,5 @@ private extension BatchUpdate { NotificationCenter.default.post(name: .BatchUpdateDidPerform, object: nil, userInfo: nil) } } - + } diff --git a/Modules/RSCore/Sources/RSCore/BinaryDiskCache.swift b/Modules/RSCore/Sources/RSCore/BinaryDiskCache.swift index 11373c37f..69bb96bb1 100644 --- a/Modules/RSCore/Sources/RSCore/BinaryDiskCache.swift +++ b/Modules/RSCore/Sources/RSCore/BinaryDiskCache.swift @@ -39,23 +39,19 @@ public struct BinaryDiskCache { get { do { return try data(forKey: key) - } - catch {} + } catch {} return nil } - + set { if let data = newValue { do { try setData(data, forKey: key) - } - catch {} - } - else { + } catch {} + } else { do { try deleteData(forKey: key) - } - catch{} + } catch {} } } } diff --git a/Modules/RSCore/Sources/RSCore/Calendar+RSCore.swift b/Modules/RSCore/Sources/RSCore/Calendar+RSCore.swift index 9de5e199d..b083a40ce 100644 --- a/Modules/RSCore/Sources/RSCore/Calendar+RSCore.swift +++ b/Modules/RSCore/Sources/RSCore/Calendar+RSCore.swift @@ -26,5 +26,5 @@ public extension Calendar { static var startOfToday: Date { cached.startOfDay(for: Date()) } - + } diff --git a/Modules/RSCore/Sources/RSCore/Character+RSCore.swift b/Modules/RSCore/Sources/RSCore/Character+RSCore.swift index 233de03ee..49da17164 100644 --- a/Modules/RSCore/Sources/RSCore/Character+RSCore.swift +++ b/Modules/RSCore/Sources/RSCore/Character+RSCore.swift @@ -9,7 +9,7 @@ import Foundation public extension Character { - + var isSimpleEmoji: Bool { guard let firstScalar = unicodeScalars.first else { return false } return firstScalar.properties.isEmoji && firstScalar.value > 0x238C diff --git a/Modules/RSCore/Sources/RSCore/CloudKit/CloudKitError.swift b/Modules/RSCore/Sources/RSCore/CloudKit/CloudKitError.swift index 2d0e1ded7..2e0f4b0b3 100644 --- a/Modules/RSCore/Sources/RSCore/CloudKit/CloudKitError.swift +++ b/Modules/RSCore/Sources/RSCore/CloudKit/CloudKitError.swift @@ -13,16 +13,16 @@ import CloudKit public class CloudKitError: LocalizedError { public let error: Error - + public init(_ error: Error) { self.error = error } - + public var errorDescription: String? { guard let ckError = error as? CKError else { return error.localizedDescription } - + switch ckError.code { case .alreadyShared: return NSLocalizedString("Already Shared: a record or share cannot be saved because doing so would cause the same hierarchy of records to exist in multiple shares.", comment: "Known iCloud Error") @@ -94,5 +94,5 @@ public class CloudKitError: LocalizedError { return NSLocalizedString("Unhandled Error.", comment: "Unknown iCloud Error") } } - + } diff --git a/Modules/RSCore/Sources/RSCore/CloudKit/CloudKitZone.swift b/Modules/RSCore/Sources/RSCore/CloudKit/CloudKitZone.swift index 071f59ff8..312484348 100644 --- a/Modules/RSCore/Sources/RSCore/CloudKit/CloudKitZone.swift +++ b/Modules/RSCore/Sources/RSCore/CloudKit/CloudKitZone.swift @@ -27,7 +27,7 @@ public enum CloudKitZoneError: LocalizedError { } public protocol CloudKitZoneDelegate: AnyObject { - func cloudKitDidModify(changed: [CKRecord], deleted: [CloudKitRecordKey], completion: @escaping (Result) -> Void); + func cloudKitDidModify(changed: [CKRecord], deleted: [CloudKitRecordKey], completion: @escaping (Result) -> Void) } public typealias CloudKitRecordKey = (recordType: CKRecord.RecordType, recordID: CKRecord.ID) @@ -54,7 +54,7 @@ public protocol CloudKitZone: AnyObject { func subscribeToZoneChanges() /// Process a remove notification - func receiveRemoteNotification(userInfo: [AnyHashable : Any], completion: @escaping () -> Void) + func receiveRemoteNotification(userInfo: [AnyHashable: Any], completion: @escaping () -> Void) } @@ -111,21 +111,21 @@ public extension CloudKitZone { return CKRecord.ID(recordName: UUID().uuidString, zoneID: zoneID) } - func retryIfPossible(after: Double, block: @escaping () -> ()) { + func retryIfPossible(after: Double, block: @escaping () -> Void) { let delayTime = DispatchTime.now() + after DispatchQueue.main.asyncAfter(deadline: delayTime, execute: { block() }) } - func receiveRemoteNotification(userInfo: [AnyHashable : Any], completion: @escaping () -> Void) { + func receiveRemoteNotification(userInfo: [AnyHashable: Any], completion: @escaping () -> Void) { let note = CKRecordZoneNotification(fromRemoteNotificationDictionary: userInfo) guard note?.recordZoneID?.zoneName == zoneID.zoneName else { completion() return } - fetchChangesInZone() { result in + fetchChangesInZone { result in if case .failure(let error) = result { os_log(.error, log: self.log, "%@ zone remote notification fetch error: %@", self.zoneID.zoneName, error.localizedDescription) } @@ -140,7 +140,7 @@ public extension CloudKitZone { return } - database.save(CKRecordZone(zoneID: zoneID)) { (recordZone, error) in + database.save(CKRecordZone(zoneID: zoneID)) { (_, error) in if let error = error { DispatchQueue.main.async { completion(.failure(CloudKitError(error))) @@ -211,7 +211,7 @@ public extension CloudKitZone { switch CloudKitZoneResult.resolve(error) { case .zoneNotFound: - self.createZoneRecord() { result in + self.createZoneRecord { result in switch result { case .success: self.query(ckQuery, desiredKeys: desiredKeys, completion: completion) @@ -285,7 +285,7 @@ public extension CloudKitZone { switch CloudKitZoneResult.resolve(error) { case .zoneNotFound: - self.createZoneRecord() { result in + self.createZoneRecord { result in switch result { case .success: self.query(cursor: cursor, desiredKeys: desiredKeys, carriedRecords: records, completion: completion) @@ -315,7 +315,6 @@ public extension CloudKitZone { database?.add(op) } - /// Fetch a CKRecord by using its externalID func fetch(externalID: String?, completion: @escaping (Result) -> Void) { guard let externalID = externalID else { @@ -341,7 +340,7 @@ public extension CloudKitZone { } } case .zoneNotFound: - self.createZoneRecord() { result in + self.createZoneRecord { result in switch result { case .success: self.fetch(externalID: externalID, completion: completion) @@ -405,7 +404,7 @@ public extension CloudKitZone { } case .zoneNotFound: - self.createZoneRecord() { result in + self.createZoneRecord { result in switch result { case .success: self.saveIfNew(records, completion: completion) @@ -473,7 +472,7 @@ public extension CloudKitZone { completion(.success((savedSubscription!))) } case .zoneNotFound: - self.createZoneRecord() { result in + self.createZoneRecord { result in switch result { case .success: self.save(subscription, completion: completion) @@ -666,7 +665,7 @@ public extension CloudKitZone { switch CloudKitZoneResult.resolve(error) { case .zoneNotFound: - self.createZoneRecord() { result in + self.createZoneRecord { result in switch result { case .success: self.modify(recordsToSave: recordsToSave, recordIDsToDelete: recordIDsToDelete, completion: completion) @@ -727,7 +726,7 @@ public extension CloudKitZone { } } - saveChunks() { result in + saveChunks { result in switch result { case .success: deleteChunks() @@ -763,11 +762,11 @@ public extension CloudKitZone { op.fetchAllChanges = true op.qualityOfService = Self.qualityOfService - op.recordZoneChangeTokensUpdatedBlock = { zoneID, token, _ in + op.recordZoneChangeTokensUpdatedBlock = { _, token, _ in savedChangeToken = token } - op.recordWasChangedBlock = { recordID, result in + op.recordWasChangedBlock = { _, result in if let record = try? result.get() { changedRecords.append(record) } @@ -778,7 +777,7 @@ public extension CloudKitZone { deletedRecordKeys.append(recordKey) } - op.recordZoneFetchResultBlock = { recordZoneID, result in + op.recordZoneFetchResultBlock = { _, result in if let (token, _, _) = try? result.get() { savedChangeToken = token } @@ -809,7 +808,7 @@ public extension CloudKitZone { switch CloudKitZoneResult.resolve(error) { case .zoneNotFound: - self.createZoneRecord() { result in + self.createZoneRecord { result in switch result { case .success: self.fetchChangesInZone(completion: completion) diff --git a/Modules/RSCore/Sources/RSCore/CloudKit/CloudKitZoneResult.swift b/Modules/RSCore/Sources/RSCore/CloudKit/CloudKitZoneResult.swift index 30efa7b5a..5997a334a 100644 --- a/Modules/RSCore/Sources/RSCore/CloudKit/CloudKitZoneResult.swift +++ b/Modules/RSCore/Sources/RSCore/CloudKit/CloudKitZoneResult.swift @@ -19,15 +19,15 @@ public enum CloudKitZoneResult { case zoneNotFound case userDeletedZone case failure(error: Error) - + public static func resolve(_ error: Error?) -> CloudKitZoneResult { - + guard error != nil else { return .success } - + guard let ckError = error as? CKError else { return .failure(error: error!) } - + switch ckError.code { case .serviceUnavailable, .requestRateLimited, .zoneBusy: if let retry = ckError.userInfo[CKErrorRetryAfterKey] as? NSNumber { @@ -60,22 +60,22 @@ public enum CloudKitZoneResult { } } - + } private extension CloudKitZoneResult { - + static func anyRequestErrors(_ errors: [AnyHashable: CKError]) -> CloudKitZoneResult? { - if errors.values.contains(where: { $0.code == .changeTokenExpired } ) { + if errors.values.contains(where: { $0.code == .changeTokenExpired }) { return .changeTokenExpired } - if errors.values.contains(where: { $0.code == .zoneNotFound } ) { + if errors.values.contains(where: { $0.code == .zoneNotFound }) { return .zoneNotFound } - if errors.values.contains(where: { $0.code == .userDeletedZone } ) { + if errors.values.contains(where: { $0.code == .userDeletedZone }) { return .userDeletedZone } return nil } - + } diff --git a/Modules/RSCore/Sources/RSCore/CoalescingQueue.swift b/Modules/RSCore/Sources/RSCore/CoalescingQueue.swift index 1010576d9..30003c75c 100644 --- a/Modules/RSCore/Sources/RSCore/CoalescingQueue.swift +++ b/Modules/RSCore/Sources/RSCore/CoalescingQueue.swift @@ -21,7 +21,7 @@ struct QueueCall: Equatable { func perform() { - let _ = target?.perform(selector) + _ = target?.perform(selector) } static func ==(lhs: QueueCall, rhs: QueueCall) -> Bool { @@ -38,7 +38,7 @@ struct QueueCall: Equatable { private let interval: TimeInterval private let maxInterval: TimeInterval private var lastCallTime = Date.distantFuture - private var timer: Timer? = nil + private var timer: Timer? private var calls = [QueueCall]() public init(name: String, interval: TimeInterval = 0.05, maxInterval: TimeInterval = 2.0) { @@ -63,12 +63,12 @@ struct QueueCall: Equatable { call.perform() } } - + @objc func timerDidFire(_ sender: Any?) { lastCallTime = Date() performCallsImmediately() } - + } private extension CoalescingQueue { diff --git a/Modules/RSCore/Sources/RSCore/DisplayNameProvider.swift b/Modules/RSCore/Sources/RSCore/DisplayNameProvider.swift index 05525a815..1edf87d43 100644 --- a/Modules/RSCore/Sources/RSCore/DisplayNameProvider.swift +++ b/Modules/RSCore/Sources/RSCore/DisplayNameProvider.swift @@ -16,7 +16,7 @@ extension Notification.Name { /// A type that provides a name for display to the user. public protocol DisplayNameProvider { - + var nameForDisplay: String { get } } diff --git a/Modules/RSCore/Sources/RSCore/FileManager+RSCore.swift b/Modules/RSCore/Sources/RSCore/FileManager+RSCore.swift index 21759ee56..0b3673c27 100644 --- a/Modules/RSCore/Sources/RSCore/FileManager+RSCore.swift +++ b/Modules/RSCore/Sources/RSCore/FileManager+RSCore.swift @@ -10,7 +10,6 @@ import Foundation public extension FileManager { - /// Returns whether a path refers to a folder. /// /// - Parameter path: The file path to check. @@ -82,7 +81,7 @@ public extension FileManager { guard let filenames = self.filenames(inFolder: folder) else { return nil } - + let url = URL(fileURLWithPath: folder) return filenames.map { url.appendingPathComponent($0).path } } @@ -101,7 +100,7 @@ private extension FileManager { assert(fileExists(atPath: source)) if fileExists(atPath: destination) { - if (overwriting) { + if overwriting { try removeItem(atPath: destination) } } diff --git a/Modules/RSCore/Sources/RSCore/Geometry.swift b/Modules/RSCore/Sources/RSCore/Geometry.swift index b5805adaf..1ed040ef6 100644 --- a/Modules/RSCore/Sources/RSCore/Geometry.swift +++ b/Modules/RSCore/Sources/RSCore/Geometry.swift @@ -16,11 +16,11 @@ public extension CGRect { /// - Returns: A new rectangle, cenetered vertically in `containerRect`, /// with the same size as the source rectangle. func centeredVertically(in containerRect: CGRect) -> CGRect { - var r = self; - r.origin.y = containerRect.midY - (r.height / 2.0); - r = r.integral; - r.size = self.size; - return r; + var r = self + r.origin.y = containerRect.midY - (r.height / 2.0) + r = r.integral + r.size = self.size + return r } /// Centers a rectangle horizontally in another rectangle. @@ -29,11 +29,11 @@ public extension CGRect { /// - Returns: A new rectangle, cenetered horizontally in `containerRect`, /// with the same size as the source rectangle. func centeredHorizontally(in containerRect: CGRect) -> CGRect { - var r = self; - r.origin.x = containerRect.midX - (r.width / 2.0); - r = r.integral; - r.size = self.size; - return r; + var r = self + r.origin.x = containerRect.midX - (r.width / 2.0) + r = r.integral + r.size = self.size + return r } /// Centers a rectangle in another rectangle. diff --git a/Modules/RSCore/Sources/RSCore/MainThreadOperation.swift b/Modules/RSCore/Sources/RSCore/MainThreadOperation.swift index 92a4f97c3..ce89df93d 100644 --- a/Modules/RSCore/Sources/RSCore/MainThreadOperation.swift +++ b/Modules/RSCore/Sources/RSCore/MainThreadOperation.swift @@ -89,8 +89,7 @@ public extension MainThreadOperation { } if Thread.isMainThread { operationDelegate?.operationDidComplete(self) - } - else { + } else { DispatchQueue.main.async { self.informOperationDelegateOfCompletion() } diff --git a/Modules/RSCore/Sources/RSCore/MainThreadOperationQueue.swift b/Modules/RSCore/Sources/RSCore/MainThreadOperationQueue.swift index 95b59bd0c..bfa936a78 100644 --- a/Modules/RSCore/Sources/RSCore/MainThreadOperationQueue.swift +++ b/Modules/RSCore/Sources/RSCore/MainThreadOperationQueue.swift @@ -95,7 +95,7 @@ public final class MainThreadOperationQueue { /// those operations will be canceled also. public func cancelOperations(_ operations: [MainThreadOperation]) { precondition(Thread.isMainThread) - let operationIDsToCancel = operations.map{ ensureOperationID($0) } + let operationIDsToCancel = operations.map { ensureOperationID($0) } assert(allOperationIDsArePendingOrCurrent(operationIDsToCancel)) assert(allOperationIDsAreInStorage(operationIDsToCancel)) @@ -182,8 +182,7 @@ private extension MainThreadOperationQueue { if operation.isCanceled { dependencies.operationIDWasCanceled(operationID) - } - else { + } else { dependencies.operationIDDidComplete(operationID) } @@ -249,7 +248,7 @@ private extension MainThreadOperationQueue { guard !operationIDs.isEmpty else { return } - + let operationIDsToCancel = operationIDsByAddingChildOperationIDs(operationIDs) setCanceledAndRemoveDelegate(for: operationIDsToCancel) callCompletionBlockForOperationIDs(operationIDsToCancel) diff --git a/Modules/RSCore/Sources/RSCore/ManagedResourceFile.swift b/Modules/RSCore/Sources/RSCore/ManagedResourceFile.swift index 02e0b827e..48fc3a63c 100644 --- a/Modules/RSCore/Sources/RSCore/ManagedResourceFile.swift +++ b/Modules/RSCore/Sources/RSCore/ManagedResourceFile.swift @@ -9,13 +9,13 @@ @preconcurrency import Foundation public final class ManagedResourceFile: NSObject, NSFilePresenter { - + private var isDirty = false { didSet { queueSaveToDiskIfNeeded() } } - + private var isLoading = false private let fileURL: URL private let operationQueue: OperationQueue @@ -30,63 +30,63 @@ public final class ManagedResourceFile: NSObject, NSFilePresenter { saveQueue = CoalescingQueue(name: "ManagedResourceFile Save Queue", interval: saveInterval) } } - + public var presentedItemURL: URL? { return fileURL } - + public var presentedItemOperationQueue: OperationQueue { return operationQueue } - + public init(fileURL: URL, load: @escaping () -> Void, save: @escaping () -> Void) { - + self.fileURL = fileURL self.loadCallback = load self.saveCallback = save - + saveQueue = CoalescingQueue(name: "ManagedResourceFile Save Queue", interval: saveInterval) operationQueue = OperationQueue() operationQueue.qualityOfService = .userInteractive operationQueue.maxConcurrentOperationCount = 1 - + super.init() - + NSFileCoordinator.addFilePresenter(self) } - + public func presentedItemDidChange() { guard !isDirty else { return } DispatchQueue.main.async { self.load() } } - + public func savePresentedItemChanges(completionHandler: @escaping (Error?) -> Void) { saveIfNecessary() completionHandler(nil) } - + public func relinquishPresentedItem(toReader reader: @escaping ((() -> Void)?) -> Void) { saveQueue.isPaused = true - reader() { + reader { self.saveQueue.isPaused = false } } - + public func relinquishPresentedItem(toWriter writer: @escaping ((() -> Void)?) -> Void) { saveQueue.isPaused = true - writer() { + writer { self.saveQueue.isPaused = false } } - + public func markAsDirty() { if !isLoading { isDirty = true } } - + public func queueSaveToDiskIfNeeded() { saveQueue.add(self, #selector(saveToDiskIfNeeded)) } @@ -96,27 +96,27 @@ public final class ManagedResourceFile: NSObject, NSFilePresenter { loadCallback() isLoading = false } - + public func saveIfNecessary() { saveQueue.performCallsImmediately() } - + public func resume() { NSFileCoordinator.addFilePresenter(self) } - + public func suspend() { NSFileCoordinator.removeFilePresenter(self) } - + deinit { NSFileCoordinator.removeFilePresenter(self) } - + } private extension ManagedResourceFile { - + @objc func saveToDiskIfNeeded() { if isDirty { isDirty = false diff --git a/Modules/RSCore/Sources/RSCore/PropertyList.swift b/Modules/RSCore/Sources/RSCore/PropertyList.swift index 2246b0e5b..5d94a620b 100644 --- a/Modules/RSCore/Sources/RSCore/PropertyList.swift +++ b/Modules/RSCore/Sources/RSCore/PropertyList.swift @@ -11,7 +11,7 @@ import Foundation // These functions eat errors. public func propertyList(withData data: Data) -> Any? { - + do { return try PropertyListSerialization.propertyList(from: data, options: [], format: nil) } catch { @@ -22,11 +22,10 @@ public func propertyList(withData data: Data) -> Any? { // Create a binary plist. public func data(withPropertyList plist: Any) -> Data? { - + do { return try PropertyListSerialization.data(fromPropertyList: plist, format: .binary, options: 0) - } - catch { + } catch { return nil } } diff --git a/Modules/RSCore/Sources/RSCore/RSImage.swift b/Modules/RSCore/Sources/RSCore/RSImage.swift index 6549f02a1..e579aecba 100644 --- a/Modules/RSCore/Sources/RSCore/RSImage.swift +++ b/Modules/RSCore/Sources/RSCore/RSImage.swift @@ -25,25 +25,25 @@ public extension RSImage { /// - Parameter color: The color with which to fill the mask image. /// - Returns: A new masked image. func maskWithColor(color: CGColor) -> RSImage? { - + #if os(macOS) guard let maskImage = cgImage(forProposedRect: nil, context: nil, hints: nil) else { return nil } #else guard let maskImage = cgImage else { return nil } #endif - + let width = size.width let height = size.height let bounds = CGRect(x: 0, y: 0, width: width, height: height) - + let colorSpace = CGColorSpaceCreateDeviceRGB() let bitmapInfo = CGBitmapInfo(rawValue: CGImageAlphaInfo.premultipliedLast.rawValue) let context = CGContext(data: nil, width: Int(width), height: Int(height), bitsPerComponent: 8, bytesPerRow: 0, space: colorSpace, bitmapInfo: bitmapInfo.rawValue)! - + context.clip(to: bounds, mask: maskImage) context.setFillColor(color) context.fill(bounds) - + if let cgImage = context.makeImage() { #if os(macOS) let coloredImage = RSImage(cgImage: cgImage, size: CGSize(width: cgImage.width, height: cgImage.height)) @@ -54,7 +54,7 @@ public extension RSImage { } else { return nil } - + } #if os(iOS) @@ -112,11 +112,11 @@ public extension RSImage { /// - data: The data object containing the image data. /// - maxPixelSize: The maximum dimension of the image. static func scaleImage(_ data: Data, maxPixelSize: Int) -> CGImage? { - + guard let imageSource = CGImageSourceCreateWithData(data as CFData, nil) else { return nil } - + let numberOfImages = CGImageSourceGetCount(imageSource) // If the image size matches exactly, then return it. @@ -134,14 +134,14 @@ public extension RSImage { if imagePixelWidth.intValue != maxPixelSize { continue } - + guard let imagePixelHeight = imageProperties[kCGImagePropertyPixelHeight] as? NSNumber else { continue } if imagePixelHeight.intValue != maxPixelSize { continue } - + return CGImageSourceCreateImageAtIndex(imageSource, i, nil) } @@ -171,23 +171,22 @@ public extension RSImage { return CGImageSourceCreateImageAtIndex(imageSource, i, nil) } - // If the image data contains a smaller image than the max size, just return it. for i in 0.. maxPixelSize { continue } - + guard let imagePixelHeight = imageProperties[kCGImagePropertyPixelHeight] as? NSNumber else { continue } @@ -197,9 +196,9 @@ public extension RSImage { } } } - + return RSImage.createThumbnail(imageSource, maxPixelSize: maxPixelSize) - + } /// Create a thumbnail from a CGImageSource. @@ -208,10 +207,10 @@ public extension RSImage { /// - imageSource: The `CGImageSource` from which to create the thumbnail. /// - maxPixelSize: The maximum dimension of the resulting image. static func createThumbnail(_ imageSource: CGImageSource, maxPixelSize: Int) -> CGImage? { - let options = [kCGImageSourceCreateThumbnailWithTransform : true, - kCGImageSourceCreateThumbnailFromImageIfAbsent : true, - kCGImageSourceThumbnailMaxPixelSize : NSNumber(value: maxPixelSize)] + let options = [kCGImageSourceCreateThumbnailWithTransform: true, + kCGImageSourceCreateThumbnailFromImageIfAbsent: true, + kCGImageSourceThumbnailMaxPixelSize: NSNumber(value: maxPixelSize)] return CGImageSourceCreateThumbnailAtIndex(imageSource, 0, options as CFDictionary) } - + } diff --git a/Modules/RSCore/Sources/RSCore/Renamable.swift b/Modules/RSCore/Sources/RSCore/Renamable.swift index e65816b20..daf9f5891 100644 --- a/Modules/RSCore/Sources/RSCore/Renamable.swift +++ b/Modules/RSCore/Sources/RSCore/Renamable.swift @@ -18,6 +18,5 @@ public protocol Renamable { /// - completion: A block called when the renaming completes or fails. /// - result: The result of the renaming. func rename(to: String, completion: @escaping (_ result: Result) -> Void) - -} +} diff --git a/Modules/RSCore/Sources/RSCore/SendToBlogEditorApp.swift b/Modules/RSCore/Sources/RSCore/SendToBlogEditorApp.swift index 2e534b070..9346cf607 100644 --- a/Modules/RSCore/Sources/RSCore/SendToBlogEditorApp.swift +++ b/Modules/RSCore/Sources/RSCore/SendToBlogEditorApp.swift @@ -13,7 +13,7 @@ import Foundation public struct SendToBlogEditorApp { - ///The target descriptor of the application. + /// The target descriptor of the application. /// /// The easiest way to get this is probably `UserApp.targetDescriptor` or `NSAppleEventDescriptor(runningApplication:)`. /// @@ -49,7 +49,6 @@ public struct SendToBlogEditorApp { self.sourceFeedURL = sourceFeedURL } - /// Sends the receiver's data to the blog editor application described by `targetDescriptor`. public func send() { @@ -57,7 +56,7 @@ public struct SendToBlogEditorApp { appleEvent.setParam(paramDescriptor, forKeyword: keyDirectObject) - let _ = try? appleEvent.sendEvent(options: [.noReply, .canSwitchLayer, .alwaysInteract], timeout: .AEDefaultTimeout) + _ = try? appleEvent.sendEvent(options: [.noReply, .canSwitchLayer, .alwaysInteract], timeout: .AEDefaultTimeout) } diff --git a/Modules/RSCore/Sources/RSCore/SendToCommand.swift b/Modules/RSCore/Sources/RSCore/SendToCommand.swift index ff83c5f4a..1fec25632 100644 --- a/Modules/RSCore/Sources/RSCore/SendToCommand.swift +++ b/Modules/RSCore/Sources/RSCore/SendToCommand.swift @@ -46,4 +46,3 @@ public protocol SendToCommand { /// - selectedText: The currently selected text. func sendObject(_ object: Any?, selectedText: String?) } - diff --git a/Modules/RSCore/Sources/RSCore/Set+Extensions.swift b/Modules/RSCore/Sources/RSCore/Set+Extensions.swift index 4e127e0bb..2efda344b 100755 --- a/Modules/RSCore/Sources/RSCore/Set+Extensions.swift +++ b/Modules/RSCore/Sources/RSCore/Set+Extensions.swift @@ -18,9 +18,9 @@ public extension Set { return self[index] } - + func anyObject() -> Element? { - + if self.isEmpty { return nil } diff --git a/Modules/RSCore/Sources/RSCore/String+RSCore.swift b/Modules/RSCore/Sources/RSCore/String+RSCore.swift index 237a268d0..867cea516 100644 --- a/Modules/RSCore/Sources/RSCore/String+RSCore.swift +++ b/Modules/RSCore/Sources/RSCore/String+RSCore.swift @@ -25,14 +25,14 @@ public extension String { static func htmlWithLink(_ link: String) -> String { return link.htmlByAddingLink(link) } - + func hmacUsingSHA1(key: String) -> String { var digest = [UInt8](repeating: 0, count: Int(CC_SHA1_DIGEST_LENGTH)) CCHmac(CCHmacAlgorithm(kCCHmacAlgSHA1), key, key.count, self, self.count, &digest) let data = Data(digest) return data.map { String(format: "%02hhx", $0) }.joined() } - + } public extension String { @@ -87,7 +87,7 @@ public extension String { let s = self.trimmingWhitespace - if (s.isEmpty || (!s.contains(".") && !s.mayBeIPv6URL && !s.hostMayBeLocalhost)) { + if s.isEmpty || (!s.contains(".") && !s.mayBeIPv6URL && !s.hostMayBeLocalhost) { return false } @@ -184,7 +184,7 @@ public extension String { return self.replacingCharacters(in: range, with: "") } - return self; + return self } /// Removes an HTML tag and everything between its start and end tags. @@ -264,7 +264,7 @@ public extension String { if let maxCharacters = maxCharacters { charactersAdded += 1 - if (charactersAdded >= maxCharacters) { + if charactersAdded >= maxCharacters { break } } @@ -309,7 +309,6 @@ public extension String { return s.replacingOccurrences(of: "\\n{3,}", with: "\n\n", options: .regularExpression) } - /// Returns a Boolean value indicating whether the string contains another string, case-insensitively. /// /// - Parameter string: The string to search for. diff --git a/Modules/RSCore/Sources/RSCore/UIKit/UIResponder+RSCore.swift b/Modules/RSCore/Sources/RSCore/UIKit/UIResponder+RSCore.swift index a4f334321..232995954 100644 --- a/Modules/RSCore/Sources/RSCore/UIKit/UIResponder+RSCore.swift +++ b/Modules/RSCore/Sources/RSCore/UIKit/UIResponder+RSCore.swift @@ -10,8 +10,8 @@ import UIKit extension UIResponder { - - private weak static var _currentFirstResponder: UIResponder? = nil + + private weak static var _currentFirstResponder: UIResponder? public static var isFirstResponderTextField: Bool { var isTextField = false @@ -27,7 +27,7 @@ extension UIResponder { UIApplication.shared.sendAction(#selector(findFirstResponder(sender:)), to: nil, from: nil, for: nil) return UIResponder._currentFirstResponder } - + public static func resignCurrentFirstResponder() { if let responder = currentFirstResponder { responder.resignFirstResponder() @@ -37,6 +37,6 @@ extension UIResponder { @objc internal func findFirstResponder(sender: AnyObject) { UIResponder._currentFirstResponder = self } - + } #endif diff --git a/Modules/RSCore/Sources/RSCore/UIKit/UIView+RSCore.swift b/Modules/RSCore/Sources/RSCore/UIKit/UIView+RSCore.swift index f3b2892b4..267e047a6 100644 --- a/Modules/RSCore/Sources/RSCore/UIKit/UIView+RSCore.swift +++ b/Modules/RSCore/Sources/RSCore/UIKit/UIView+RSCore.swift @@ -10,32 +10,32 @@ import UIKit extension UIView { - + public func setFrameIfNotEqual(_ rect: CGRect) { if !self.frame.equalTo(rect) { self.frame = rect } } - + public func addChildAndPin(_ view: UIView) { view.translatesAutoresizingMaskIntoConstraints = false addSubview(view) - + NSLayoutConstraint.activate([ safeAreaLayoutGuide.leadingAnchor.constraint(equalTo: view.leadingAnchor), safeAreaLayoutGuide.trailingAnchor.constraint(equalTo: view.trailingAnchor), safeAreaLayoutGuide.topAnchor.constraint(equalTo: view.topAnchor), safeAreaLayoutGuide.bottomAnchor.constraint(equalTo: view.bottomAnchor) ]) - + } - + public func asImage() -> UIImage { let renderer = UIGraphicsImageRenderer(bounds: bounds) return renderer.image { rendererContext in layer.render(in: rendererContext.cgContext) } } - + } #endif diff --git a/Modules/RSCore/Sources/RSCore/UIKit/UIViewController+RSCore.swift b/Modules/RSCore/Sources/RSCore/UIKit/UIViewController+RSCore.swift index 4c024d892..bf8043e09 100644 --- a/Modules/RSCore/Sources/RSCore/UIKit/UIViewController+RSCore.swift +++ b/Modules/RSCore/Sources/RSCore/UIKit/UIViewController+RSCore.swift @@ -10,14 +10,14 @@ import UIKit import SwiftUI extension UIViewController { - + // MARK: Autolayout - + public func addChildAndPinView(_ controller: UIViewController) { view.addChildAndPin(controller.view) addChild(controller) } - + public func replaceChildAndPinView(_ controller: UIViewController) { for subview in view.subviews { subview.removeFromSuperview() @@ -27,9 +27,9 @@ extension UIViewController { } addChildAndPinView(controller) } - + // MARK: Error Handling - + public func presentError(title: String, message: String, dismiss: (() -> Void)? = nil) { let alertController = UIAlertController(title: title, message: message, preferredStyle: .alert) let dismissTitle = NSLocalizedString("OK", comment: "OK") @@ -39,7 +39,7 @@ extension UIViewController { alertController.addAction(dismissAction) self.present(alertController, animated: true, completion: nil) } - + } // MARK: SwiftUI diff --git a/Modules/RSCore/Sources/RSCore/UIKit/UIWindow+RSCore.swift b/Modules/RSCore/Sources/RSCore/UIKit/UIWindow+RSCore.swift index 5c45f8fc1..a5df7ac6b 100644 --- a/Modules/RSCore/Sources/RSCore/UIKit/UIWindow+RSCore.swift +++ b/Modules/RSCore/Sources/RSCore/UIKit/UIWindow+RSCore.swift @@ -9,9 +9,9 @@ import UIKit extension UIWindow { - + public var topViewController: UIViewController? { - + var top = self.rootViewController while true { if let presented = top?.presentedViewController { @@ -33,10 +33,10 @@ extension UIWindow { break } } - + return top - + } - + } #endif diff --git a/Modules/RSCore/Sources/RSCore/UndoableCommand.swift b/Modules/RSCore/Sources/RSCore/UndoableCommand.swift index 5904feaea..3862309bf 100644 --- a/Modules/RSCore/Sources/RSCore/UndoableCommand.swift +++ b/Modules/RSCore/Sources/RSCore/UndoableCommand.swift @@ -23,15 +23,15 @@ extension UndoableCommand { public func registerUndo() { undoManager.setActionName(undoActionName) - undoManager.registerUndo(withTarget: self) { (target) in + undoManager.registerUndo(withTarget: self) { (_) in self.undo() } } public func registerRedo() { - + undoManager.setActionName(redoActionName) - undoManager.registerUndo(withTarget: self) { (target) in + undoManager.registerUndo(withTarget: self) { (_) in self.perform() } } @@ -40,33 +40,33 @@ extension UndoableCommand { // Useful for view controllers. public protocol UndoableCommandRunner: AnyObject { - + var undoableCommands: [UndoableCommand] { get set } var undoManager: UndoManager? { get } - + func runCommand(_ undoableCommand: UndoableCommand) func clearUndoableCommands() } public extension UndoableCommandRunner { - + func runCommand(_ undoableCommand: UndoableCommand) { - + pushUndoableCommand(undoableCommand) undoableCommand.perform() } - + func pushUndoableCommand(_ undoableCommand: UndoableCommand) { - + undoableCommands += [undoableCommand] } - + func clearUndoableCommands() { - + // Useful, for example, when timeline is reloaded and the list of articles changes. // Otherwise things like Redo Mark Read are ambiguous. // (Do they apply to the previous articles or to the current articles?) - + guard let undoManager else { return } diff --git a/Modules/RSCore/Sources/RSCoreResources/AppKit/IndeterminateProgressWindowController.swift b/Modules/RSCore/Sources/RSCoreResources/AppKit/IndeterminateProgressWindowController.swift index 8c1dc27c9..fc483fd0b 100644 --- a/Modules/RSCore/Sources/RSCoreResources/AppKit/IndeterminateProgressWindowController.swift +++ b/Modules/RSCore/Sources/RSCoreResources/AppKit/IndeterminateProgressWindowController.swift @@ -67,5 +67,3 @@ private final class IndeterminateProgressWindowController: NSWindowController { } } #endif - - diff --git a/Modules/RSCore/Sources/RSCoreResources/AppKit/WebViewWindowController.swift b/Modules/RSCore/Sources/RSCoreResources/AppKit/WebViewWindowController.swift index 3bac4f456..6cf8612cd 100644 --- a/Modules/RSCore/Sources/RSCoreResources/AppKit/WebViewWindowController.swift +++ b/Modules/RSCore/Sources/RSCoreResources/AppKit/WebViewWindowController.swift @@ -13,7 +13,7 @@ public final class WebViewWindowController: NSWindowController { @IBOutlet private var webview: WKWebView! private var title: String! - + public convenience init(title: String) { self.init(window: nil) self.title = title @@ -29,7 +29,7 @@ public final class WebViewWindowController: NSWindowController { // We assume there might be images, style sheets, etc. contained by the folder that the file appears in, so we get read access to the parent folder. - let _ = self.window + _ = self.window let fileURL = URL(fileURLWithPath: path) let folderURL = fileURL.deletingLastPathComponent() diff --git a/Modules/RSCore/Tests/RSCoreTests/Data+RSCoreTests.swift b/Modules/RSCore/Tests/RSCoreTests/Data+RSCoreTests.swift index 1c3ec40b4..3f7801599 100644 --- a/Modules/RSCore/Tests/RSCoreTests/Data+RSCoreTests.swift +++ b/Modules/RSCore/Tests/RSCoreTests/Data+RSCoreTests.swift @@ -10,7 +10,7 @@ import XCTest import Foundation @testable import RSCore -//class Data_RSCoreTests: XCTestCase { +// class Data_RSCoreTests: XCTestCase { // var bigHTML: String! // // var pngData: Data! @@ -125,10 +125,10 @@ import Foundation // // } // -//} +// } // Tests to compare the result of Data+RSCore with the old Objective-C versions. -//extension Data_RSCoreTests { +// extension Data_RSCoreTests { // // func testCompare_isProbablyHTML() { // let noLT = "html body".data(using: .utf8)! @@ -186,4 +186,4 @@ import Foundation // // } // -//} +// } diff --git a/Modules/RSCore/Tests/RSCoreTests/MacroProcessorTests.swift b/Modules/RSCore/Tests/RSCoreTests/MacroProcessorTests.swift index 718dd4b25..4da760261 100644 --- a/Modules/RSCore/Tests/RSCoreTests/MacroProcessorTests.swift +++ b/Modules/RSCore/Tests/RSCoreTests/MacroProcessorTests.swift @@ -44,7 +44,7 @@ class MacroProcessorTests: XCTestCase { func testEmptyDelimiters() { do { let template = "foo bar" - let _ = try MacroProcessor.renderedText(withTemplate: template, substitutions: substitutions, macroStart: "") + _ = try MacroProcessor.renderedText(withTemplate: template, substitutions: substitutions, macroStart: "") XCTFail("Error should be thrown") } catch { // Success @@ -52,7 +52,7 @@ class MacroProcessorTests: XCTestCase { do { let template = "foo bar" - let _ = try MacroProcessor.renderedText(withTemplate: template, substitutions: substitutions, macroEnd: "") + _ = try MacroProcessor.renderedText(withTemplate: template, substitutions: substitutions, macroEnd: "") XCTFail("Error should be thrown") } catch { // Success diff --git a/Modules/RSCore/Tests/RSCoreTests/MainThreadOperationTests.swift b/Modules/RSCore/Tests/RSCoreTests/MainThreadOperationTests.swift index 1ab9eae94..0f3cf6f08 100644 --- a/Modules/RSCore/Tests/RSCoreTests/MainThreadOperationTests.swift +++ b/Modules/RSCore/Tests/RSCoreTests/MainThreadOperationTests.swift @@ -212,9 +212,9 @@ class MainThreadOperationTests: XCTestCase { waitForExpectations(timeout: 1.0, handler: nil) XCTAssertTrue(queue.pendingOperationsCount == 0) } - + func testCancelingDisownsOperation() { - + final class SlowFinishingOperation: MainThreadOperation { let didCancelExpectation: XCTestExpectation @@ -231,8 +231,8 @@ class MainThreadOperationTests: XCTestCase { var operationDelegate: MainThreadOperationDelegate? var name: String? var completionBlock: MainThreadOperation.MainThreadOperationCompletionBlock? - - var didStartRunBlock: (() -> ())? + + var didStartRunBlock: (() -> Void)? init(didCancelExpectation: XCTestExpectation) { self.didCancelExpectation = didCancelExpectation @@ -252,7 +252,7 @@ class MainThreadOperationTests: XCTestCase { } } } - + let queue = MainThreadOperationQueue() let didCancelExpectation = expectation(description: "Did Cancel Operation") let completionBlockDidRunExpectation = expectation(description: "Completion Block Did Run") @@ -273,10 +273,10 @@ class MainThreadOperationTests: XCTestCase { } return operation }() - + // The queue should take ownership of the operation (asserted below). queue.add(operation!) - + // Verify something other than this scope has ownership of the operation. weak var addedOperation = operation! operation = nil diff --git a/Modules/RSCore/Tests/RSCoreTests/RSCoreTests.swift b/Modules/RSCore/Tests/RSCoreTests/RSCoreTests.swift index 0a76da1df..255a99c87 100644 --- a/Modules/RSCore/Tests/RSCoreTests/RSCoreTests.swift +++ b/Modules/RSCore/Tests/RSCoreTests/RSCoreTests.swift @@ -10,6 +10,6 @@ final class RSCoreTests: XCTestCase { } static var allTests = [ - ("testExample", testExample), + ("testExample", testExample) ] } diff --git a/Modules/RSCore/Tests/RSCoreTests/String+RSCoreTests.swift b/Modules/RSCore/Tests/RSCoreTests/String+RSCoreTests.swift index ad7d1f881..ae53627a0 100644 --- a/Modules/RSCore/Tests/RSCoreTests/String+RSCoreTests.swift +++ b/Modules/RSCore/Tests/RSCoreTests/String+RSCoreTests.swift @@ -168,16 +168,16 @@ class String_RSCore: XCTestCase { self.measure { for _ in 0..<1000 { - let _ = s1.md5String - let _ = s2.md5String - let _ = s3.md5String - let _ = s4.md5String - let _ = s5.md5String - let _ = s6.md5String - let _ = s7.md5String - let _ = s8.md5String - let _ = s9.md5String - let _ = s10.md5String + _ = s1.md5String + _ = s2.md5String + _ = s3.md5String + _ = s4.md5String + _ = s5.md5String + _ = s6.md5String + _ = s7.md5String + _ = s8.md5String + _ = s9.md5String + _ = s10.md5String } } } diff --git a/Modules/RSCore/Tests/RSCoreTests/XCTestManifests.swift b/Modules/RSCore/Tests/RSCoreTests/XCTestManifests.swift index 4f81fdd24..d0653dea8 100644 --- a/Modules/RSCore/Tests/RSCoreTests/XCTestManifests.swift +++ b/Modules/RSCore/Tests/RSCoreTests/XCTestManifests.swift @@ -3,7 +3,7 @@ import XCTest #if !canImport(ObjectiveC) public func allTests() -> [XCTestCaseEntry] { return [ - testCase(RSCoreTests.allTests), + testCase(RSCoreTests.allTests) ] } #endif diff --git a/Modules/RSTree/Package.swift b/Modules/RSTree/Package.swift index 489b0267c..a82959526 100644 --- a/Modules/RSTree/Package.swift +++ b/Modules/RSTree/Package.swift @@ -9,7 +9,7 @@ let package = Package( .library( name: "RSTree", type: .dynamic, - targets: ["RSTree"]), + targets: ["RSTree"]) ], targets: [ .target( diff --git a/Modules/RSTree/Sources/RSTree/NSOutlineView+RSTree.swift b/Modules/RSTree/Sources/RSTree/NSOutlineView+RSTree.swift index bd26475c9..2aa31af53 100644 --- a/Modules/RSTree/Sources/RSTree/NSOutlineView+RSTree.swift +++ b/Modules/RSTree/Sources/RSTree/NSOutlineView+RSTree.swift @@ -21,7 +21,7 @@ public extension NSOutlineView { if numberOfNodes < 2 { return false } - + let indexOfNodeToSelect = numberOfNodes - 1 for i in 1...indexOfNodeToSelect { // Start at 1 to skip root node. @@ -36,8 +36,7 @@ public extension NSOutlineView { selectRowIndexes(NSIndexSet(index: oneRow) as IndexSet, byExtendingSelection: false) scrollRowToVisible(oneRow) return true - } - else { + } else { expandItem(oneNode) } } diff --git a/Modules/RSTree/Sources/RSTree/Node.swift b/Modules/RSTree/Sources/RSTree/Node.swift index 0c70265fe..886d04cc5 100644 --- a/Modules/RSTree/Sources/RSTree/Node.swift +++ b/Modules/RSTree/Sources/RSTree/Node.swift @@ -11,7 +11,7 @@ import Foundation // Main thread only. public final class Node: Hashable { - + public weak var parent: Node? public let representedObject: AnyObject public var canHaveChildNodes = false @@ -26,11 +26,11 @@ public final class Node: Hashable { } return true } - + public var numberOfChildNodes: Int { return childNodes.count } - + public var indexPath: IndexPath { if let parent = parent { let parentPath = parent.indexPath @@ -39,22 +39,22 @@ public final class Node: Hashable { } preconditionFailure("A Node’s parent must contain it as a child.") } - return IndexPath(index: 0) //root node + return IndexPath(index: 0) // root node } - + public var level: Int { if let parent = parent { return parent.level + 1 } return 0 } - + public var isLeaf: Bool { return numberOfChildNodes < 1 } - + public init(representedObject: AnyObject, parent: Node?) { - + precondition(Thread.isMainThread) self.representedObject = representedObject @@ -63,9 +63,9 @@ public final class Node: Hashable { self.uniqueID = Node.incrementingID Node.incrementingID += 1 } - + public class func genericRootNode() -> Node { - + let node = Node(representedObject: TopLevelRepresentedObject(), parent: nil) node.canHaveChildNodes = true return node @@ -86,7 +86,7 @@ public final class Node: Hashable { } public func childAtIndex(_ index: Int) -> Node? { - + if index >= childNodes.count || index < 0 { return nil } @@ -94,12 +94,12 @@ public final class Node: Hashable { } public func indexOfChild(_ node: Node) -> Int? { - - return childNodes.firstIndex{ (oneChildNode) -> Bool in + + return childNodes.firstIndex { (oneChildNode) -> Bool in oneChildNode === node } } - + public func childNodeRepresentingObject(_ obj: AnyObject) -> Node? { return findNodeRepresentingObject(obj, recursively: false) } @@ -182,12 +182,11 @@ public final class Node: Hashable { } } - public extension Array where Element == Node { func representedObjects() -> [AnyObject] { - return self.map{ $0.representedObject } + return self.map { $0.representedObject } } } diff --git a/Modules/RSTree/Sources/RSTree/NodePath.swift b/Modules/RSTree/Sources/RSTree/NodePath.swift index 1e9fee5d9..d0382c77b 100644 --- a/Modules/RSTree/Sources/RSTree/NodePath.swift +++ b/Modules/RSTree/Sources/RSTree/NodePath.swift @@ -21,8 +21,7 @@ public struct NodePath { if let parent = nomad.parent { tempArray.append(parent) nomad = parent - } - else { + } else { break } } @@ -34,8 +33,7 @@ public struct NodePath { if let node = treeController.nodeInTreeRepresentingObject(representedObject) { self.init(node: node) - } - else { + } else { return nil } } diff --git a/Modules/RSTree/Sources/RSTree/TreeController.swift b/Modules/RSTree/Sources/RSTree/TreeController.swift index cfdaad35c..a534b9b00 100644 --- a/Modules/RSTree/Sources/RSTree/TreeController.swift +++ b/Modules/RSTree/Sources/RSTree/TreeController.swift @@ -9,11 +9,11 @@ import Foundation public protocol TreeControllerDelegate: AnyObject { - + func treeController(treeController: TreeController, childNodesFor: Node) -> [Node]? } -public typealias NodeVisitBlock = (_ : Node) -> Void +public typealias NodeVisitBlock = (_: Node) -> Void public final class TreeController { @@ -21,32 +21,32 @@ public final class TreeController { public let rootNode: Node public init(delegate: TreeControllerDelegate, rootNode: Node) { - + self.delegate = delegate self.rootNode = rootNode rebuild() } public convenience init(delegate: TreeControllerDelegate) { - + self.init(delegate: delegate, rootNode: Node.genericRootNode()) } - + @discardableResult public func rebuild() -> Bool { // Rebuild and re-sort. Return true if any changes in the entire tree. - + return rebuildChildNodes(node: rootNode) } - + public func visitNodes(_ visitBlock: NodeVisitBlock) { - + visitNode(rootNode, visitBlock) } - + public func nodeInArrayRepresentingObject(nodes: [Node], representedObject: AnyObject, recurse: Bool = false) -> Node? { - + for oneNode in nodes { if oneNode.representedObject === representedObject { @@ -85,17 +85,17 @@ public final class TreeController { } private extension TreeController { - + func visitNode(_ node: Node, _ visitBlock: NodeVisitBlock) { - + visitBlock(node) for oneChildNode in node.childNodes { visitNode(oneChildNode, visitBlock) } } - + func nodeArraysAreEqual(_ nodeArray1: [Node]?, _ nodeArray2: [Node]?) -> Bool { - + if nodeArray1 == nil && nodeArray2 == nil { return true } @@ -105,25 +105,25 @@ private extension TreeController { if nodeArray1 == nil && nodeArray2 != nil { return false } - + return nodeArray1! == nodeArray2! } - + func rebuildChildNodes(node: Node) -> Bool { - + if !node.canHaveChildNodes { return false } - + var childNodesDidChange = false - + let childNodes = delegate?.treeController(treeController: self, childNodesFor: node) ?? [Node]() - + childNodesDidChange = !nodeArraysAreEqual(childNodes, node.childNodes) - if (childNodesDidChange) { + if childNodesDidChange { node.childNodes = childNodes } - + for oneChildNode in childNodes { if rebuildChildNodes(node: oneChildNode) { childNodesDidChange = true diff --git a/Modules/RSWeb/Package.swift b/Modules/RSWeb/Package.swift index 55fba142c..9565c0d4e 100644 --- a/Modules/RSWeb/Package.swift +++ b/Modules/RSWeb/Package.swift @@ -9,11 +9,11 @@ let package = Package( .library( name: "RSWeb", type: .dynamic, - targets: ["RSWeb"]), + targets: ["RSWeb"]) ], dependencies: [ .package(path: "../Parser"), - .package(path: "../RSCore"), + .package(path: "../RSCore") ], targets: [ .target( @@ -26,6 +26,6 @@ let package = Package( ), .testTarget( name: "RSWebTests", - dependencies: ["RSWeb"]), + dependencies: ["RSWeb"]) ] ) diff --git a/Modules/RSWeb/Sources/RSWeb/CacheControlInfo.swift b/Modules/RSWeb/Sources/RSWeb/CacheControlInfo.swift index d6de46d38..b17b567dd 100644 --- a/Modules/RSWeb/Sources/RSWeb/CacheControlInfo.swift +++ b/Modules/RSWeb/Sources/RSWeb/CacheControlInfo.swift @@ -21,7 +21,7 @@ public struct CacheControlInfo: Codable, Equatable { public var canResume: Bool { Date() >= resumeDate } - + public init?(urlResponse: HTTPURLResponse) { guard let cacheControlValue = urlResponse.valueForHTTPHeaderField(HTTPResponseHeader.cacheControl) else { return nil @@ -35,7 +35,7 @@ public struct CacheControlInfo: Codable, Equatable { guard let maxAge = Self.parseMaxAge(value) else { return nil } - + let d = Date() self.dateCreated = d self.maxAge = maxAge diff --git a/Modules/RSWeb/Sources/RSWeb/Dictionary+RSWeb.swift b/Modules/RSWeb/Sources/RSWeb/Dictionary+RSWeb.swift index d647fe5e0..c543e1d61 100644 --- a/Modules/RSWeb/Sources/RSWeb/Dictionary+RSWeb.swift +++ b/Modules/RSWeb/Sources/RSWeb/Dictionary+RSWeb.swift @@ -8,7 +8,7 @@ import Foundation -public extension Dictionary where Key == String, Value == String { +public extension Dictionary where Key == String, Value == String { /// Translates a dictionary into a string like `foo=bar¶m2=some%20thing`. var urlQueryString: String? { diff --git a/Modules/RSWeb/Sources/RSWeb/DownloadProgress.swift b/Modules/RSWeb/Sources/RSWeb/DownloadProgress.swift index 1a3444e76..3dae384ad 100755 --- a/Modules/RSWeb/Sources/RSWeb/DownloadProgress.swift +++ b/Modules/RSWeb/Sources/RSWeb/DownloadProgress.swift @@ -11,12 +11,12 @@ import Foundation // Main thread only. public extension Notification.Name { - + static let DownloadProgressDidChange = Notification.Name(rawValue: "DownloadProgressDidChange") } public final class DownloadProgress { - + public var numberOfTasks = 0 { didSet { if numberOfTasks == 0 && numberRemaining != 0 { @@ -27,7 +27,7 @@ public final class DownloadProgress { } } } - + public var numberRemaining = 0 { didSet { if numberRemaining != oldValue { @@ -46,22 +46,22 @@ public final class DownloadProgress { } return n } - + public var isComplete: Bool { assert(Thread.isMainThread) return numberRemaining < 1 } - + public init(numberOfTasks: Int) { assert(Thread.isMainThread) self.numberOfTasks = numberOfTasks } - + public func addToNumberOfTasks(_ n: Int) { assert(Thread.isMainThread) numberOfTasks = numberOfTasks + n } - + public func addToNumberOfTasksAndRemaining(_ n: Int) { assert(Thread.isMainThread) numberOfTasks = numberOfTasks + n @@ -74,14 +74,14 @@ public final class DownloadProgress { numberRemaining = numberRemaining - 1 } } - + public func completeTasks(_ tasks: Int) { assert(Thread.isMainThread) if numberRemaining >= tasks { numberRemaining = numberRemaining - tasks } } - + public func reset() { assert(Thread.isMainThread) numberRemaining = 0 @@ -92,7 +92,7 @@ public final class DownloadProgress { // MARK: - Private private extension DownloadProgress { - + func postDidChangeNotification() { DispatchQueue.main.async { NotificationCenter.default.post(name: .DownloadProgressDidChange, object: self) diff --git a/Modules/RSWeb/Sources/RSWeb/DownloadSession.swift b/Modules/RSWeb/Sources/RSWeb/DownloadSession.swift index b3ff27ac1..91e9ed5c2 100755 --- a/Modules/RSWeb/Sources/RSWeb/DownloadSession.swift +++ b/Modules/RSWeb/Sources/RSWeb/DownloadSession.swift @@ -40,13 +40,12 @@ public protocol DownloadSessionDelegate { /// These URLs are skipped for the rest of the session. private var urlsWith400s = Set() - public init(delegate: DownloadSessionDelegate) { self.delegate = delegate super.init() - + let sessionConfiguration = URLSessionConfiguration.ephemeral sessionConfiguration.requestCachePolicy = .reloadIgnoringLocalCacheData sessionConfiguration.timeoutIntervalForRequest = 15.0 @@ -60,9 +59,9 @@ public protocol DownloadSessionDelegate { sessionConfiguration.httpAdditionalHeaders = userAgentHeaders } - urlSession = URLSession(configuration: sessionConfiguration, delegate: self, delegateQueue: OperationQueue.main) + urlSession = URLSession(configuration: sessionConfiguration, delegate: self, delegateQueue: OperationQueue.main) } - + deinit { urlSession.invalidateAndCancel() } @@ -170,7 +169,7 @@ extension DownloadSession: URLSessionDataDelegate { addDataTaskFromQueueIfNecessary() completionHandler(.allow) } - + public func urlSession(_ session: URLSession, dataTask: URLSessionDataTask, didReceive data: Data) { guard let info = infoForTask(dataTask) else { @@ -279,7 +278,7 @@ private extension DownloadSession { var currentURL = url - while(true) { + while true { if let oneRedirectURL = redirectCache[currentURL] { @@ -289,9 +288,7 @@ private extension DownloadSession { } urls.insert(oneRedirectURL) currentURL = oneRedirectURL - } - - else { + } else { break } } @@ -449,7 +446,7 @@ extension URLSessionTask { // MARK: - DownloadInfo private final class DownloadInfo { - + let url: URL let data = NSMutableData() var urlResponse: URLResponse? @@ -458,9 +455,9 @@ private final class DownloadInfo { self.url = url } - + func addData(_ d: Data) { - + data.append(d) } } diff --git a/Modules/RSWeb/Sources/RSWeb/Downloader.swift b/Modules/RSWeb/Sources/RSWeb/Downloader.swift index c0dc12ca8..d3aed2f8d 100755 --- a/Modules/RSWeb/Sources/RSWeb/Downloader.swift +++ b/Modules/RSWeb/Sources/RSWeb/Downloader.swift @@ -25,7 +25,7 @@ public final class Downloader { sessionConfiguration.httpCookieAcceptPolicy = .never sessionConfiguration.httpMaximumConnectionsPerHost = 1 sessionConfiguration.httpCookieStorage = nil - + if let userAgentHeaders = UserAgent.headers() { sessionConfiguration.httpAdditionalHeaders = userAgentHeaders } @@ -47,7 +47,7 @@ public final class Downloader { urlRequestToUse.addSpecialCaseUserAgentIfNeeded() let task = urlSession.dataTask(with: urlRequestToUse) { (data, response, error) in - DispatchQueue.main.async() { + DispatchQueue.main.async { completion?(data, response, error) } } diff --git a/Modules/RSWeb/Sources/RSWeb/HTMLMetadataCache.swift b/Modules/RSWeb/Sources/RSWeb/HTMLMetadataCache.swift index bfe3bbb78..23e9d3d0d 100644 --- a/Modules/RSWeb/Sources/RSWeb/HTMLMetadataCache.swift +++ b/Modules/RSWeb/Sources/RSWeb/HTMLMetadataCache.swift @@ -17,7 +17,7 @@ public extension Notification.Name { public final class HTMLMetadataCache: Sendable { static let shared = HTMLMetadataCache() - + // Sent along with .htmlMetadataAvailable notification public struct UserInfoKey { public static let htmlMetadata = "htmlMetadata" diff --git a/Modules/RSWeb/Sources/RSWeb/HTMLMetadataDownloader.swift b/Modules/RSWeb/Sources/RSWeb/HTMLMetadataDownloader.swift index d7d034f7f..d5fee8a49 100644 --- a/Modules/RSWeb/Sources/RSWeb/HTMLMetadataDownloader.swift +++ b/Modules/RSWeb/Sources/RSWeb/HTMLMetadataDownloader.swift @@ -19,7 +19,7 @@ public final class HTMLMetadataDownloader: Sendable { private static let logger = Logger(subsystem: Bundle.main.bundleIdentifier!, category: "HTMLMetadataDownloader") private static let debugLoggingEnabled = false - + private let cache = HTMLMetadataCache() private let attemptDatesLock = OSAllocatedUnfairLock(initialState: [String: Date]()) private let urlsReturning4xxsLock = OSAllocatedUnfairLock(initialState: Set()) @@ -88,7 +88,7 @@ private extension HTMLMetadataDownloader { Self.logger.debug("HTMLMetadataDownloader downloading for \(url)") } - Downloader.shared.download(actualURL) { data, response, error in + Downloader.shared.download(actualURL) { data, response, _ in if let data, !data.isEmpty, let response, response.statusIsOK { let urlToUse = response.url ?? actualURL let parserData = ParserData(url: urlToUse.absoluteString, data: data) diff --git a/Modules/RSWeb/Sources/RSWeb/HTTPConditionalGetInfo.swift b/Modules/RSWeb/Sources/RSWeb/HTTPConditionalGetInfo.swift index c62a382d4..c72e0d3f3 100755 --- a/Modules/RSWeb/Sources/RSWeb/HTTPConditionalGetInfo.swift +++ b/Modules/RSWeb/Sources/RSWeb/HTTPConditionalGetInfo.swift @@ -9,10 +9,10 @@ import Foundation public struct HTTPConditionalGetInfo: Codable, Equatable { - + public let lastModified: String? public let etag: String? - + public init?(lastModified: String?, etag: String?) { if lastModified == nil && etag == nil { return nil @@ -20,19 +20,19 @@ public struct HTTPConditionalGetInfo: Codable, Equatable { self.lastModified = lastModified self.etag = etag } - + public init?(urlResponse: HTTPURLResponse) { let lastModified = urlResponse.valueForHTTPHeaderField(HTTPResponseHeader.lastModified) let etag = urlResponse.valueForHTTPHeaderField(HTTPResponseHeader.etag) self.init(lastModified: lastModified, etag: etag) } - public init?(headers: [AnyHashable : Any]) { + public init?(headers: [AnyHashable: Any]) { let lastModified = headers[HTTPResponseHeader.lastModified] as? String let etag = headers[HTTPResponseHeader.etag] as? String self.init(lastModified: lastModified, etag: etag) } - + public func addRequestHeadersToURLRequest(_ urlRequest: inout URLRequest) { // Bug seen in the wild: lastModified with last possible 32-bit date, which is in 2038. Ignore those. // TODO: drop this check in late 2037. diff --git a/Modules/RSWeb/Sources/RSWeb/HTTPDateInfo.swift b/Modules/RSWeb/Sources/RSWeb/HTTPDateInfo.swift index 06d95f811..be5c2c649 100644 --- a/Modules/RSWeb/Sources/RSWeb/HTTPDateInfo.swift +++ b/Modules/RSWeb/Sources/RSWeb/HTTPDateInfo.swift @@ -9,15 +9,15 @@ import Foundation public struct HTTPDateInfo: Codable, Equatable { - + private static let formatter: DateFormatter = { let dateFormatter = DateFormatter() dateFormatter.dateFormat = "EEEE, dd LLL yyyy HH:mm:ss zzz" return dateFormatter }() - + public let date: Date? - + public init?(urlResponse: HTTPURLResponse) { if let headerDate = urlResponse.valueForHTTPHeaderField(HTTPResponseHeader.date) { date = HTTPDateInfo.formatter.date(from: headerDate) @@ -25,5 +25,5 @@ public struct HTTPDateInfo: Codable, Equatable { date = nil } } - + } diff --git a/Modules/RSWeb/Sources/RSWeb/HTTPLinkPagingInfo.swift b/Modules/RSWeb/Sources/RSWeb/HTTPLinkPagingInfo.swift index e63d6c9e5..e18625f06 100644 --- a/Modules/RSWeb/Sources/RSWeb/HTTPLinkPagingInfo.swift +++ b/Modules/RSWeb/Sources/RSWeb/HTTPLinkPagingInfo.swift @@ -9,33 +9,33 @@ import Foundation public struct HTTPLinkPagingInfo { - + public let nextPage: String? public let lastPage: String? - + public init(nextPage: String?, lastPage: String?) { self.nextPage = nextPage self.lastPage = lastPage } public init(urlResponse: HTTPURLResponse) { - + guard let linkHeader = urlResponse.valueForHTTPHeaderField(HTTPResponseHeader.link) else { self.init(nextPage: nil, lastPage: nil) return } let links = linkHeader.components(separatedBy: ",") - + var dict: [String: String] = [:] for link in links { - let components = link.components(separatedBy:"; ") + let components = link.components(separatedBy: "; ") let page = components[0].trimmingCharacters(in: CharacterSet(charactersIn: " <>")) dict[components[1]] = page } - + self.init(nextPage: dict["rel=\"next\""], lastPage: dict["rel=\"last\""]) - + } } diff --git a/Modules/RSWeb/Sources/RSWeb/HTTPRequestHeader.swift b/Modules/RSWeb/Sources/RSWeb/HTTPRequestHeader.swift index 7021a6fcc..5ee282ca3 100755 --- a/Modules/RSWeb/Sources/RSWeb/HTTPRequestHeader.swift +++ b/Modules/RSWeb/Sources/RSWeb/HTTPRequestHeader.swift @@ -13,9 +13,9 @@ public struct HTTPRequestHeader { public static let userAgent = "User-Agent" public static let authorization = "Authorization" public static let contentType = "Content-Type" - + // Conditional GET - + public static let ifModifiedSince = "If-Modified-Since" - public static let ifNoneMatch = "If-None-Match" //Etag + public static let ifNoneMatch = "If-None-Match" // Etag } diff --git a/Modules/RSWeb/Sources/RSWeb/HTTPResponseCode.swift b/Modules/RSWeb/Sources/RSWeb/HTTPResponseCode.swift index e983ced2f..4847bd0a7 100755 --- a/Modules/RSWeb/Sources/RSWeb/HTTPResponseCode.swift +++ b/Modules/RSWeb/Sources/RSWeb/HTTPResponseCode.swift @@ -12,10 +12,10 @@ public struct HTTPResponseCode { // http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html // Not an enum because the main interest is the actual values. - - public static let responseContinue = 100 //"continue" is a language keyword, hence the weird name + + public static let responseContinue = 100 // "continue" is a language keyword, hence the weird name public static let switchingProtocols = 101 - + public static let OK = 200 public static let created = 201 public static let accepted = 202 @@ -23,7 +23,7 @@ public struct HTTPResponseCode { public static let noContent = 204 public static let resetContent = 205 public static let partialContent = 206 - + public static let redirectMultipleChoices = 300 public static let redirectPermanent = 301 public static let redirectTemporary = 302 diff --git a/Modules/RSWeb/Sources/RSWeb/HTTPResponseHeader.swift b/Modules/RSWeb/Sources/RSWeb/HTTPResponseHeader.swift index cfdd588ce..ba86cd3a1 100755 --- a/Modules/RSWeb/Sources/RSWeb/HTTPResponseHeader.swift +++ b/Modules/RSWeb/Sources/RSWeb/HTTPResponseHeader.swift @@ -17,7 +17,7 @@ public struct HTTPResponseHeader { // Conditional GET. See: // http://fishbowl.pastiche.org/2002/10/21/http_conditional_get_for_rss_hackers/ - + public static let lastModified = "Last-Modified" // Changed to the canonical case for lookups against a case sensitive dictionary // https://developer.apple.com/documentation/foundation/httpurlresponse/1417930-allheaderfields diff --git a/Modules/RSWeb/Sources/RSWeb/MacWebBrowser.swift b/Modules/RSWeb/Sources/RSWeb/MacWebBrowser.swift index 948d3c8ea..c4f10e988 100755 --- a/Modules/RSWeb/Sources/RSWeb/MacWebBrowser.swift +++ b/Modules/RSWeb/Sources/RSWeb/MacWebBrowser.swift @@ -21,7 +21,7 @@ public class MacWebBrowser { return false } - if (inBackground) { + if inBackground { let configuration = NSWorkspace.OpenConfiguration() configuration.activates = false @@ -124,23 +124,23 @@ public class MacWebBrowser { /// - url: The URL to open. /// - inBackground: If `true`, attempt to load the URL without bringing the browser to the foreground. @discardableResult public func openURL(_ url: URL, inBackground: Bool = false) -> Bool { - + // TODO: make this function async. - + guard let preparedURL = url.preparedForOpeningInBrowser() else { return false } - + Task { @MainActor in - + let configuration = NSWorkspace.OpenConfiguration() if inBackground { configuration.activates = false } - + NSWorkspace.shared.open([preparedURL], withApplicationAt: self.url, configuration: configuration, completionHandler: nil) } - + return true } } @@ -148,7 +148,7 @@ public class MacWebBrowser { extension MacWebBrowser: CustomDebugStringConvertible { public var debugDescription: String { - if let name = name, let bundleIdentifier = bundleIdentifier{ + if let name = name, let bundleIdentifier = bundleIdentifier { return "MacWebBrowser: \(name) (\(bundleIdentifier))" } else { return "MacWebBrowser" diff --git a/Modules/RSWeb/Sources/RSWeb/MimeType.swift b/Modules/RSWeb/Sources/RSWeb/MimeType.swift index 36225b718..4b384facf 100755 --- a/Modules/RSWeb/Sources/RSWeb/MimeType.swift +++ b/Modules/RSWeb/Sources/RSWeb/MimeType.swift @@ -9,9 +9,9 @@ import Foundation public struct MimeType { - + // This could certainly use expansion. - + public static let png = "image/png" public static let jpeg = "image/jpeg" public static let jpg = "image/jpg" @@ -20,29 +20,29 @@ public struct MimeType { } public extension String { - + func isMimeTypeImage() -> Bool { - + return self.isOfGeneralMimeType("image") } - + func isMimeTypeAudio() -> Bool { - + return self.isOfGeneralMimeType("audio") } - + func isMimeTypeVideo() -> Bool { - + return self.isOfGeneralMimeType("video") } - + func isMimeTypeTimeBasedMedia() -> Bool { - + return self.isMimeTypeAudio() || self.isMimeTypeVideo() } - + private func isOfGeneralMimeType(_ type: String) -> Bool { - + let lower = self.lowercased() if lower.hasPrefix(type) { return true diff --git a/Modules/RSWeb/Sources/RSWeb/Reachability.swift b/Modules/RSWeb/Sources/RSWeb/Reachability.swift index ac09d646a..3bc06b1a1 100644 --- a/Modules/RSWeb/Sources/RSWeb/Reachability.swift +++ b/Modules/RSWeb/Sources/RSWeb/Reachability.swift @@ -48,8 +48,8 @@ public class Reachability { return reachability.connection != .unavailable } - public typealias NetworkReachable = (Reachability) -> () - public typealias NetworkUnreachable = (Reachability) -> () + public typealias NetworkReachable = (Reachability) -> Void + public typealias NetworkUnreachable = (Reachability) -> Void public enum Connection: CustomStringConvertible { @available(*, deprecated, renamed: "unavailable") @@ -72,7 +72,7 @@ public class Reachability { if flags == nil { try? setReachabilityFlags() } - + switch flags?.connection { case .unavailable?, nil: return .unavailable case .none?: return .unavailable diff --git a/Modules/RSWeb/Sources/RSWeb/SpecialCases.swift b/Modules/RSWeb/Sources/RSWeb/SpecialCases.swift index 67c70f6ed..0acbac337 100644 --- a/Modules/RSWeb/Sources/RSWeb/SpecialCases.swift +++ b/Modules/RSWeb/Sources/RSWeb/SpecialCases.swift @@ -22,8 +22,7 @@ extension URL { let result: Bool if let host = host(), host.contains("openrss.org") { result = true - } - else { + } else { result = false } @@ -69,7 +68,7 @@ extension Set where Element == URL { extension URLRequest { mutating func addSpecialCaseUserAgentIfNeeded() { - + if let url, url.isOpenRSSOrgURL { setValue(UserAgent.openRSSOrgUserAgent, forHTTPHeaderField: HTTPRequestHeader.userAgent) } diff --git a/Modules/RSWeb/Sources/RSWeb/String+RSWeb.swift b/Modules/RSWeb/Sources/RSWeb/String+RSWeb.swift index 3bed1da06..198bba279 100644 --- a/Modules/RSWeb/Sources/RSWeb/String+RSWeb.swift +++ b/Modules/RSWeb/Sources/RSWeb/String+RSWeb.swift @@ -35,5 +35,5 @@ public extension String { return escaped } - + } diff --git a/Modules/RSWeb/Sources/RSWeb/URL+RSWeb.swift b/Modules/RSWeb/Sources/RSWeb/URL+RSWeb.swift index 1225a13e6..9f97bfa61 100755 --- a/Modules/RSWeb/Sources/RSWeb/URL+RSWeb.swift +++ b/Modules/RSWeb/Sources/RSWeb/URL+RSWeb.swift @@ -34,8 +34,7 @@ public extension URL { if isHTTPSURL() { return absoluteString.stringByRemovingCaseInsensitivePrefix(URLConstants.prefixHTTPS) - } - else if isHTTPURL() { + } else if isHTTPURL() { return absoluteString.stringByRemovingCaseInsensitivePrefix(URLConstants.prefixHTTP) } @@ -76,7 +75,7 @@ private extension String { let lowerPrefix = prefix.lowercased() let lowerSelf = self.lowercased() - if (lowerSelf == lowerPrefix) { + if lowerSelf == lowerPrefix { return "" } if !lowerSelf.hasPrefix(lowerPrefix) { diff --git a/Modules/RSWeb/Sources/RSWeb/URLComponents+RSWeb.swift b/Modules/RSWeb/Sources/RSWeb/URLComponents+RSWeb.swift index 7ab2ccb9c..78c4cf864 100644 --- a/Modules/RSWeb/Sources/RSWeb/URLComponents+RSWeb.swift +++ b/Modules/RSWeb/Sources/RSWeb/URLComponents+RSWeb.swift @@ -8,7 +8,7 @@ import Foundation public extension URLComponents { - + // `+` is a valid character in query component as per RFC 3986 (https://developer.apple.com/documentation/foundation/nsurlcomponents/1407752-queryitems) // workaround: // - http://www.openradar.me/24076063 @@ -17,18 +17,18 @@ public extension URLComponents { guard !(queryItems?.isEmpty ?? true) else { return nil } - + var allowedCharacters = CharacterSet.urlQueryAllowed allowedCharacters.remove(charactersIn: "!*'();:@&=+$,/?%#[]") - + var queries = [String]() for queryItem in queryItems! { if let value = queryItem.value?.addingPercentEncoding(withAllowedCharacters: allowedCharacters)?.replacingOccurrences(of: "%20", with: "+") { queries.append("\(queryItem.name)=\(value)") } } - + return queries.joined(separator: "&") } - + } diff --git a/Modules/RSWeb/Sources/RSWeb/URLRequest+RSWeb.swift b/Modules/RSWeb/Sources/RSWeb/URLRequest+RSWeb.swift index 348f9d140..654663bf3 100755 --- a/Modules/RSWeb/Sources/RSWeb/URLRequest+RSWeb.swift +++ b/Modules/RSWeb/Sources/RSWeb/URLRequest+RSWeb.swift @@ -11,18 +11,18 @@ import Foundation public extension URLRequest { @discardableResult mutating func addBasicAuthorization(username: String, password: String) -> Bool { - + // Do this *only* with https. And not even then if you can help it. - + let s = "\(username):\(password)" guard let d = s.data(using: .utf8, allowLossyConversion: false) else { return false } - + let base64EncodedString = d.base64EncodedString() let authorization = "Basic \(base64EncodedString)" setValue(authorization, forHTTPHeaderField: HTTPRequestHeader.authorization) - + return true } } diff --git a/Modules/RSWeb/Sources/RSWeb/URLResponse+RSWeb.swift b/Modules/RSWeb/Sources/RSWeb/URLResponse+RSWeb.swift index 9e00b2cbb..a9f219f58 100755 --- a/Modules/RSWeb/Sources/RSWeb/URLResponse+RSWeb.swift +++ b/Modules/RSWeb/Sources/RSWeb/URLResponse+RSWeb.swift @@ -9,15 +9,15 @@ import Foundation public extension URLResponse { - + var statusIsOK: Bool { return forcedStatusCode >= 200 && forcedStatusCode <= 299 } - + var forcedStatusCode: Int { - + // Return actual statusCode or 0 if there isn’t one. - + if let response = self as? HTTPURLResponse { return response.statusCode } @@ -26,20 +26,20 @@ public extension URLResponse { } public extension HTTPURLResponse { - + func valueForHTTPHeaderField(_ headerField: String) -> String? { - + // Case-insensitive. HTTP headers may not be in the case you expect. - + let lowerHeaderField = headerField.lowercased() - + for (key, value) in allHeaderFields { - + if lowerHeaderField == (key as? String)?.lowercased() { return value as? String } } - + return nil } } diff --git a/Modules/RSWeb/Sources/RSWeb/UserAgent.swift b/Modules/RSWeb/Sources/RSWeb/UserAgent.swift index 0a851c51d..dcced5503 100755 --- a/Modules/RSWeb/Sources/RSWeb/UserAgent.swift +++ b/Modules/RSWeb/Sources/RSWeb/UserAgent.swift @@ -9,7 +9,7 @@ import Foundation public struct UserAgent { - + public static func fromInfoPlist() -> String? { return Bundle.main.object(forInfoDictionaryKey: "UserAgent") as? String diff --git a/Modules/RSWeb/Sources/RSWeb/WebServices/Transport.swift b/Modules/RSWeb/Sources/RSWeb/WebServices/Transport.swift index 0705a7c28..1bd38849b 100644 --- a/Modules/RSWeb/Sources/RSWeb/WebServices/Transport.swift +++ b/Modules/RSWeb/Sources/RSWeb/WebServices/Transport.swift @@ -14,7 +14,7 @@ public enum TransportError: LocalizedError { case noURL case suspended case httpError(status: Int) - + public var errorDescription: String? { switch self { case .httpError(let status): @@ -111,27 +111,27 @@ public enum TransportError: LocalizedError { return NSLocalizedString("An unknown network error occurred.", comment: "Unknown error") } } - + } public protocol Transport { - + /// Cancels all pending requests func cancelAll() - + /// Sends URLRequest and returns the HTTP headers and the data payload. func send(request: URLRequest, completion: @escaping (Result<(HTTPURLResponse, Data?), Error>) -> Void) - + /// Sends URLRequest that doesn't require any result information. func send(request: URLRequest, method: String, completion: @escaping (Result) -> Void) - + /// Sends URLRequest with a data payload and returns the HTTP headers and the data payload. func send(request: URLRequest, method: String, payload: Data, completion: @escaping (Result<(HTTPURLResponse, Data?), Error>) -> Void) - + } extension URLSession: Transport { - + public func cancelAll() { getTasksWithCompletionHandler { dataTasks, uploadTasks, downloadTasks in for dataTask in dataTasks { @@ -145,7 +145,7 @@ extension URLSession: Transport { } } } - + public func send(request: URLRequest, completion: @escaping (Result<(HTTPURLResponse, Data?), Error>) -> Void) { let task = self.dataTask(with: request) { (data, response, error) in DispatchQueue.main.async { @@ -169,11 +169,11 @@ extension URLSession: Transport { } public func send(request: URLRequest, method: String, completion: @escaping (Result) -> Void) { - + var sendRequest = request sendRequest.httpMethod = method - - let task = self.dataTask(with: sendRequest) { (data, response, error) in + + let task = self.dataTask(with: sendRequest) { (_, response, error) in DispatchQueue.main.async { if let error = error { return completion(.failure(error)) @@ -193,12 +193,12 @@ extension URLSession: Transport { } task.resume() } - + public func send(request: URLRequest, method: String, payload: Data, completion: @escaping (Result<(HTTPURLResponse, Data?), Error>) -> Void) { - + var sendRequest = request sendRequest.httpMethod = method - + let task = self.uploadTask(with: sendRequest, from: payload) { (data, response, error) in DispatchQueue.main.async { if let error = error { @@ -215,14 +215,14 @@ extension URLSession: Transport { default: completion(.failure(TransportError.httpError(status: response.forcedStatusCode))) } - + } } task.resume() } - + public static func webserviceTransport() -> Transport { - + let sessionConfiguration = URLSessionConfiguration.default sessionConfiguration.requestCachePolicy = .reloadIgnoringLocalCacheData sessionConfiguration.timeoutIntervalForRequest = 60.0 @@ -231,11 +231,11 @@ extension URLSession: Transport { sessionConfiguration.httpMaximumConnectionsPerHost = 2 sessionConfiguration.httpCookieStorage = nil sessionConfiguration.urlCache = nil - + if let userAgentHeaders = UserAgent.headers() { sessionConfiguration.httpAdditionalHeaders = userAgentHeaders } - + return URLSession(configuration: sessionConfiguration) } } diff --git a/Modules/RSWeb/Sources/RSWeb/WebServices/TransportJSON.swift b/Modules/RSWeb/Sources/RSWeb/WebServices/TransportJSON.swift index ff8dee89f..e72a42cb0 100644 --- a/Modules/RSWeb/Sources/RSWeb/WebServices/TransportJSON.swift +++ b/Modules/RSWeb/Sources/RSWeb/WebServices/TransportJSON.swift @@ -9,12 +9,12 @@ import Foundation extension Transport { - + /** Sends an HTTP get and returns JSON object(s) */ public func send(request: URLRequest, resultType: R.Type, dateDecoding: JSONDecoder.DateDecodingStrategy = .iso8601, keyDecoding: JSONDecoder.KeyDecodingStrategy = .useDefaultKeys, completion: @escaping (Result<(HTTPURLResponse, R?), Error>) -> Void) { - + send(request: request) { result in DispatchQueue.main.async { @@ -33,15 +33,13 @@ extension Transport { DispatchQueue.main.async { completion(.success((response, decoded))) } - } - catch { + } catch { DispatchQueue.main.async { completion(.failure(error)) } } } - } - else { + } else { completion(.success((response, nil))) } @@ -51,12 +49,12 @@ extension Transport { } } } - + /** Sends the specified HTTP method with a JSON payload. */ public func send(request: URLRequest, method: String, payload: P, completion: @escaping (Result) -> Void) { - + var postRequest = request postRequest.addValue("application/json; charset=utf-8", forHTTPHeaderField: HTTPRequestHeader.contentType) @@ -79,12 +77,12 @@ extension Transport { } } } - + /** Sends the specified HTTP method with a JSON payload and returns JSON object(s). */ public func send(request: URLRequest, method: String, payload: P, resultType: R.Type, dateDecoding: JSONDecoder.DateDecodingStrategy = .iso8601, keyDecoding: JSONDecoder.KeyDecodingStrategy = .useDefaultKeys, completion: @escaping (Result<(HTTPURLResponse, R?), Error>) -> Void) { - + var postRequest = request postRequest.addValue("application/json; charset=utf-8", forHTTPHeaderField: HTTPRequestHeader.contentType) @@ -95,7 +93,7 @@ extension Transport { completion(.failure(error)) return } - + send(request: postRequest, method: method, payload: data) { result in DispatchQueue.main.async { diff --git a/Modules/RSWeb/Tests/RSWebTests/RSWebTests.swift b/Modules/RSWeb/Tests/RSWebTests/RSWebTests.swift index 4297b1daa..96722281d 100755 --- a/Modules/RSWeb/Tests/RSWebTests/RSWebTests.swift +++ b/Modules/RSWeb/Tests/RSWebTests/RSWebTests.swift @@ -10,22 +10,12 @@ import XCTest @testable import RSWeb class RSWebTests: XCTestCase { - - override func setUp() { - super.setUp() - // Put setup code here. This method is called before the invocation of each test method in the class. - } - - override func tearDown() { - // Put teardown code here. This method is called after the invocation of each test method in the class. - super.tearDown() - } - + func testExample() { // This is an example of a functional test case. // Use XCTAssert and related functions to verify your tests produce the correct results. } - + func testPerformanceExample() { // This is an example of a performance test case. self.measure { @@ -36,7 +26,7 @@ class RSWebTests: XCTestCase { func testAllBrowsers() { let browsers = MacWebBrowser.sortedBrowsers() - XCTAssertNotNil(browsers); + XCTAssertNotNil(browsers) } - + } diff --git a/Modules/Secrets/Sources/Secrets/Credentials.swift b/Modules/Secrets/Sources/Secrets/Credentials.swift index 47a746e4a..873b2e372 100644 --- a/Modules/Secrets/Sources/Secrets/Credentials.swift +++ b/Modules/Secrets/Sources/Secrets/Credentials.swift @@ -28,7 +28,7 @@ public struct Credentials: Equatable, Sendable { public let type: CredentialsType public let username: String public let secret: String - + public init(type: CredentialsType, username: String, secret: String) { self.type = type self.username = username diff --git a/Modules/Secrets/Sources/Secrets/CredentialsManager.swift b/Modules/Secrets/Sources/Secrets/CredentialsManager.swift index 9fa6d14d9..ed0d03002 100644 --- a/Modules/Secrets/Sources/Secrets/CredentialsManager.swift +++ b/Modules/Secrets/Sources/Secrets/CredentialsManager.swift @@ -9,7 +9,7 @@ import Foundation public struct CredentialsManager { - + private static let keychainGroup: String? = { guard let appGroup = Bundle.main.object(forInfoDictionaryKey: "AppGroup") as? String else { return nil @@ -29,7 +29,7 @@ public struct CredentialsManager { if credentials.type != .basic { query[kSecAttrSecurityDomain as String] = credentials.type.rawValue } - + if let securityGroup = keychainGroup { query[kSecAttrAccessGroup as String] = securityGroup } @@ -47,27 +47,27 @@ public struct CredentialsManager { default: throw CredentialsError.unhandledError(status: status) } - + var deleteQuery = query deleteQuery.removeValue(forKey: kSecAttrAccessible as String) SecItemDelete(deleteQuery as CFDictionary) - + let addStatus = SecItemAdd(query as CFDictionary, nil) if addStatus != errSecSuccess { throw CredentialsError.unhandledError(status: status) } } - + public static func retrieveCredentials(type: CredentialsType, server: String, username: String) throws -> Credentials? { - + var query: [String: Any] = [kSecClass as String: kSecClassInternetPassword, kSecAttrAccount as String: username, kSecAttrServer as String: server, kSecMatchLimit as String: kSecMatchLimitOne, kSecReturnAttributes as String: true, kSecReturnData as String: true] - + if type != .basic { query[kSecAttrSecurityDomain as String] = type.rawValue } @@ -75,37 +75,37 @@ public struct CredentialsManager { if let securityGroup = keychainGroup { query[kSecAttrAccessGroup as String] = securityGroup } - + var item: CFTypeRef? let status = SecItemCopyMatching(query as CFDictionary, &item) - + guard status != errSecItemNotFound else { return nil } - + guard status == errSecSuccess else { throw CredentialsError.unhandledError(status: status) } - - guard let existingItem = item as? [String : Any], + + guard let existingItem = item as? [String: Any], let secretData = existingItem[kSecValueData as String] as? Data, let secret = String(data: secretData, encoding: String.Encoding.utf8) else { return nil } - + return Credentials(type: type, username: username, secret: secret) - + } - + public static func removeCredentials(type: CredentialsType, server: String, username: String) throws { - + var query: [String: Any] = [kSecClass as String: kSecClassInternetPassword, kSecAttrAccount as String: username, kSecAttrServer as String: server, kSecMatchLimit as String: kSecMatchLimitOne, kSecReturnAttributes as String: true, kSecReturnData as String: true] - + if type != .basic { query[kSecAttrSecurityDomain as String] = type.rawValue } @@ -113,12 +113,12 @@ public struct CredentialsManager { if let securityGroup = keychainGroup { query[kSecAttrAccessGroup as String] = securityGroup } - + let status = SecItemDelete(query as CFDictionary) guard status == errSecSuccess || status == errSecItemNotFound else { throw CredentialsError.unhandledError(status: status) } - + } - + } diff --git a/Modules/SyncDatabase/Sources/SyncDatabase/Constants.swift b/Modules/SyncDatabase/Sources/SyncDatabase/Constants.swift index 86d01b923..a80e5c0a7 100644 --- a/Modules/SyncDatabase/Sources/SyncDatabase/Constants.swift +++ b/Modules/SyncDatabase/Sources/SyncDatabase/Constants.swift @@ -9,13 +9,13 @@ import Foundation struct DatabaseTableName { - + static let syncStatus = "syncStatus" - + } struct DatabaseKey { - + // Sync Status static let articleID = "articleID" static let key = "key" diff --git a/Modules/SyncDatabase/Sources/SyncDatabase/SyncStatus.swift b/Modules/SyncDatabase/Sources/SyncDatabase/SyncStatus.swift index cb6c71a45..34a7c091d 100644 --- a/Modules/SyncDatabase/Sources/SyncDatabase/SyncStatus.swift +++ b/Modules/SyncDatabase/Sources/SyncDatabase/SyncStatus.swift @@ -11,13 +11,13 @@ import Articles import RSDatabase public struct SyncStatus: Hashable, Equatable { - + public enum Key: String { case read = "read" case starred = "starred" case deleted = "deleted" case new = "new" - + public init(_ articleStatusKey: ArticleStatus.Key) { switch articleStatusKey { case .read: @@ -26,23 +26,23 @@ public struct SyncStatus: Hashable, Equatable { self = Self.starred } } - + } public let articleID: String public let key: SyncStatus.Key public let flag: Bool public let selected: Bool - + public init(articleID: String, key: SyncStatus.Key, flag: Bool, selected: Bool = false) { self.articleID = articleID self.key = key self.flag = flag self.selected = selected } - + public func databaseDictionary() -> DatabaseDictionary { return [DatabaseKey.articleID: articleID, DatabaseKey.key: key.rawValue, DatabaseKey.flag: flag, DatabaseKey.selected: selected] } - + } diff --git a/Modules/SyncDatabase/Sources/SyncDatabase/SyncStatusTable.swift b/Modules/SyncDatabase/Sources/SyncDatabase/SyncStatusTable.swift index 0ab0d80cb..ba00ef6f5 100644 --- a/Modules/SyncDatabase/Sources/SyncDatabase/SyncStatusTable.swift +++ b/Modules/SyncDatabase/Sources/SyncDatabase/SyncStatusTable.swift @@ -49,14 +49,13 @@ struct SyncStatusTable: DatabaseTable { DispatchQueue.main.async { if let error = error { completion(.failure(error)) - } - else { + } else { completion(.success(Array(statuses))) } } } } - + func selectPendingCount(_ completion: @escaping DatabaseIntCompletionBlock) { queue.runInDatabase { databaseResult in var count: Int = 0 @@ -79,8 +78,7 @@ struct SyncStatusTable: DatabaseTable { DispatchQueue.main.async { if let error = error { completion(.failure(error)) - } - else { + } else { completion(.success(count)) } } @@ -90,11 +88,11 @@ struct SyncStatusTable: DatabaseTable { func selectPendingReadStatusArticleIDs(completion: @escaping SyncStatusArticleIDsCompletionBlock) { selectPendingArticleIDsAsync(.read, completion) } - + func selectPendingStarredStatusArticleIDs(completion: @escaping SyncStatusArticleIDsCompletionBlock) { selectPendingArticleIDsAsync(.starred, completion) } - + func resetAllSelectedForProcessing(completion: DatabaseCompletionBlock? = nil) { queue.runInTransaction { databaseResult in @@ -118,7 +116,7 @@ struct SyncStatusTable: DatabaseTable { callCompletion(completion, nil) return } - + queue.runInTransaction { databaseResult in func makeDatabaseCall(_ database: FMDatabase) { @@ -137,13 +135,13 @@ struct SyncStatusTable: DatabaseTable { } } } - + func deleteSelectedForProcessing(_ articleIDs: [String], completion: DatabaseCompletionBlock? = nil) { guard !articleIDs.isEmpty else { callCompletion(completion, nil) return } - + queue.runInTransaction { databaseResult in func makeDatabaseCall(_ database: FMDatabase) { @@ -162,7 +160,7 @@ struct SyncStatusTable: DatabaseTable { } } } - + func insertStatuses(_ statuses: [SyncStatus], completion: @escaping DatabaseCompletionBlock) { queue.runInTransaction { databaseResult in @@ -180,7 +178,7 @@ struct SyncStatusTable: DatabaseTable { } } } - + } private extension SyncStatusTable { @@ -191,13 +189,13 @@ private extension SyncStatusTable { let key = SyncStatus.Key(rawValue: rawKey) else { return nil } - + let flag = row.bool(forColumn: DatabaseKey.flag) let selected = row.bool(forColumn: DatabaseKey.selected) - + return SyncStatus(articleID: articleID, key: key, flag: flag, selected: selected) } - + func selectPendingArticleIDsAsync(_ statusKey: ArticleStatus.Key, _ completion: @escaping SyncStatusArticleIDsCompletionBlock) { queue.runInDatabase { databaseResult in @@ -212,7 +210,7 @@ private extension SyncStatusTable { return } - let articleIDs = resultSet.mapToSet{ $0.string(forColumnIndex: 0) } + let articleIDs = resultSet.mapToSet { $0.string(forColumnIndex: 0) } DispatchQueue.main.async { completion(.success(articleIDs)) } @@ -228,7 +226,7 @@ private extension SyncStatusTable { } } } - + } private func callCompletion(_ completion: DatabaseCompletionBlock?, _ databaseError: DatabaseError?) {