diff --git a/.swiftlint.yml b/.swiftlint.yml index 99269ae74..a3b1a5127 100644 --- a/.swiftlint.yml +++ b/.swiftlint.yml @@ -8,14 +8,21 @@ line_length: ignores_comments: true ignores_urls: true +large_tuple: + warning: 3 + error: 4 + disabled_rules: - todo - for_where - file_length - force_cast + - force_try excluded: - Modules/Secrets/Sources/Secrets/SecretKey.swift - Modules/Account/Tests/AccountTests/Feedly/ - Widget/Resources/Localized.swift + - Shared/Extensions/NSAttributedString+NetNewsWire.swift + diff --git a/Shared/ArticleExtractor/ArticleExtractor.swift b/Shared/ArticleExtractor/ArticleExtractor.swift index e15bee5cc..a5b2e88e0 100644 --- a/Shared/ArticleExtractor/ArticleExtractor.swift +++ b/Shared/ArticleExtractor/ArticleExtractor.swift @@ -18,7 +18,7 @@ public enum ArticleExtractorState { case cancelled } -protocol ArticleExtractorDelegate { +protocol ArticleExtractorDelegate: AnyObject { func articleExtractionDidFail(with: Error) func articleExtractionDidComplete(extractedArticle: ExtractedArticle) } @@ -29,7 +29,7 @@ class ArticleExtractor { var state: ArticleExtractorState! var article: ExtractedArticle? - var delegate: ArticleExtractorDelegate? + weak var delegate: ArticleExtractorDelegate? var articleLink: String? private var url: URL! diff --git a/Shared/ArticleRendering/ArticleRenderer.swift b/Shared/ArticleRendering/ArticleRenderer.swift index 788ff1cdc..6ef1517aa 100644 --- a/Shared/ArticleRendering/ArticleRenderer.swift +++ b/Shared/ArticleRendering/ArticleRenderer.swift @@ -16,7 +16,12 @@ import Account struct ArticleRenderer { - typealias Rendering = (style: String, html: String, title: String, baseURL: String) + struct Rendering { + let style: String + let html: String + let title: String + let baseURL: String + } struct Page { let url: URL @@ -123,27 +128,27 @@ struct ArticleRenderer { static func articleHTML(article: Article, extractedArticle: ExtractedArticle? = nil, theme: ArticleTheme) -> Rendering { let renderer = ArticleRenderer(article: article, extractedArticle: extractedArticle, theme: theme) - return (renderer.articleCSS, renderer.articleHTML, renderer.title, renderer.baseURL ?? "") + return Rendering(style: renderer.articleCSS, html: renderer.articleHTML, title: renderer.title, baseURL: renderer.baseURL ?? "") } static func multipleSelectionHTML(theme: ArticleTheme) -> Rendering { let renderer = ArticleRenderer(article: nil, extractedArticle: nil, theme: theme) - return (renderer.articleCSS, renderer.multipleSelectionHTML, renderer.title, renderer.baseURL ?? "") + return Rendering(style: renderer.articleCSS, html: renderer.multipleSelectionHTML, title: renderer.title, baseURL: renderer.baseURL ?? "") } static func loadingHTML(theme: ArticleTheme) -> Rendering { let renderer = ArticleRenderer(article: nil, extractedArticle: nil, theme: theme) - return (renderer.articleCSS, renderer.loadingHTML, renderer.title, renderer.baseURL ?? "") + return Rendering(style: renderer.articleCSS, html: renderer.loadingHTML, title: renderer.title, baseURL: renderer.baseURL ?? "") } static func noSelectionHTML(theme: ArticleTheme) -> Rendering { let renderer = ArticleRenderer(article: nil, extractedArticle: nil, theme: theme) - return (renderer.articleCSS, renderer.noSelectionHTML, renderer.title, renderer.baseURL ?? "") + return Rendering(style: renderer.articleCSS, html: renderer.noSelectionHTML, title: renderer.title, baseURL: renderer.baseURL ?? "") } static func noContentHTML(theme: ArticleTheme) -> Rendering { let renderer = ArticleRenderer(article: nil, extractedArticle: nil, theme: theme) - return (renderer.articleCSS, renderer.noContentHTML, renderer.title, renderer.baseURL ?? "") + return Rendering(style: renderer.articleCSS, html: renderer.noContentHTML, title: renderer.title, baseURL: renderer.baseURL ?? "") } } @@ -259,6 +264,7 @@ private extension ArticleRenderer { return d } + // swiftlint:disable:next cyclomatic_complexity func byline() -> String { guard let authors = article?.authors ?? article?.feed?.authors, !authors.isEmpty else { return "" diff --git a/Shared/Commands/DeleteCommand.swift b/Shared/Commands/DeleteCommand.swift index 451e771d9..cf678f0bb 100644 --- a/Shared/Commands/DeleteCommand.swift +++ b/Shared/Commands/DeleteCommand.swift @@ -78,10 +78,7 @@ final class DeleteCommand: UndoableCommand { } for node in nodes { - if let _ = node.representedObject as? Feed { - continue - } - if let _ = node.representedObject as? Folder { + if node.representedObject is Feed || node.representedObject is Folder { continue } return false @@ -171,9 +168,9 @@ private struct SidebarItemSpecifier { func restore() { - if let _ = feed { + if feed != nil { restoreFeed() - } else if let _ = folder { + } else if folder != nil { restoreFolder() } } @@ -268,9 +265,9 @@ private struct DeleteActionName { var numberOfFolders = 0 for node in nodes { - if let _ = node.representedObject as? Feed { + if node.representedObject is Feed { numberOfFeeds += 1 - } else if let _ = node.representedObject as? Folder { + } else if node.representedObject is Folder { numberOfFolders += 1 } else { return nil // Delete only Feeds and Folders. diff --git a/Shared/ExtensionPoints/SendToMarsEditCommand.swift b/Shared/ExtensionPoints/SendToMarsEditCommand.swift index a027d623f..d2d79fc74 100644 --- a/Shared/ExtensionPoints/SendToMarsEditCommand.swift +++ b/Shared/ExtensionPoints/SendToMarsEditCommand.swift @@ -56,7 +56,20 @@ private extension SendToMarsEditCommand { let body = article.contentHTML ?? article.contentText ?? article.summary let authorName = article.authors?.first?.name - let sender = SendToBlogEditorApp(targetDescriptor: targetDescriptor, title: article.title, body: body, summary: article.summary, link: article.externalLink, permalink: article.link, subject: nil, creator: authorName, commentsURL: nil, guid: article.uniqueID, sourceName: article.feed?.nameForDisplay, sourceHomeURL: article.feed?.homePageURL, sourceFeedURL: article.feed?.url) + let sender = SendToBlogEditorApp( + targetDescriptor: targetDescriptor, + title: article.title, + body: body, + summary: article.summary, + link: article.externalLink, + permalink: article.link, + subject: nil, + creator: authorName, commentsURL: nil, + guid: article.uniqueID, + sourceName: article.feed?.nameForDisplay, + sourceHomeURL: article.feed?.homePageURL, + sourceFeedURL: article.feed?.url + ) sender.send() } diff --git a/Shared/ExtensionPoints/SendToMicroBlogCommand.swift b/Shared/ExtensionPoints/SendToMicroBlogCommand.swift index dbecdc77d..0b613b01a 100644 --- a/Shared/ExtensionPoints/SendToMicroBlogCommand.swift +++ b/Shared/ExtensionPoints/SendToMicroBlogCommand.swift @@ -22,7 +22,7 @@ final class SendToMicroBlogCommand: SendToCommand { func canSendObject(_ object: Any?, selectedText: String?) -> Bool { microBlogApp.updateStatus() - guard microBlogApp.existsOnDisk, let article = (object as? ArticlePasteboardWriter)?.article, let _ = article.preferredLink else { + guard microBlogApp.existsOnDisk, let article = (object as? ArticlePasteboardWriter)?.article, article.preferredLink != nil else { return false } diff --git a/Shared/Extensions/ArticleUtilities.swift b/Shared/Extensions/ArticleUtilities.swift index c0548c351..f9ae31797 100644 --- a/Shared/Extensions/ArticleUtilities.swift +++ b/Shared/Extensions/ArticleUtilities.swift @@ -138,6 +138,7 @@ extension Article { } } + // swiftlint:disable:next cyclomatic_complexity func byline() -> String { guard let authors = authors ?? feed?.authors, !authors.isEmpty else { return "" diff --git a/Shared/Favicons/ColorHash.swift b/Shared/Favicons/ColorHash.swift index 920dfa6c3..4cf9633e1 100644 --- a/Shared/Favicons/ColorHash.swift +++ b/Shared/Favicons/ColorHash.swift @@ -41,7 +41,7 @@ public class ColorHash { for char in "\(str)x" { if let scl = String(char).unicodeScalars.first?.value { if hash > maxSafeInteger { - hash = hash / seed2 + hash /= seed2 } hash = hash * seed + CGFloat(scl) } diff --git a/Shared/Timeline/ArticleSorter.swift b/Shared/Timeline/ArticleSorter.swift index 2561ddc4c..575cec8a7 100644 --- a/Shared/Timeline/ArticleSorter.swift +++ b/Shared/Timeline/ArticleSorter.swift @@ -18,9 +18,7 @@ protocol SortableArticle { struct ArticleSorter { - static func sortedByDate(articles: [T], - sortDirection: ComparisonResult, - groupByFeed: Bool) -> [T] { + static func sortedByDate(articles: [T], sortDirection: ComparisonResult, groupByFeed: Bool) -> [T] { if groupByFeed { return sortedByFeedName(articles: articles, sortByDateDirection: sortDirection) } else { @@ -30,8 +28,7 @@ struct ArticleSorter { // MARK: - - private static func sortedByFeedName(articles: [T], - sortByDateDirection: ComparisonResult) -> [T] { + private static func sortedByFeedName(articles: [T], sortByDateDirection: ComparisonResult) -> [T] { // Group articles by "feed-feedID" - feed ID is used to differentiate between // two feeds that have the same name let groupedArticles = Dictionary(grouping: articles) { "\($0.sortableName.lowercased())-\($0.sortableFeedID)" } @@ -44,8 +41,7 @@ struct ArticleSorter { } } - private static func sortedByDate(articles: [T], - sortDirection: ComparisonResult) -> [T] { + private static func sortedByDate(articles: [T], sortDirection: ComparisonResult) -> [T] { return articles.sorted { (article1, article2) -> Bool in if article1.sortableDate == article2.sortableDate { return article1.sortableArticleID < article2.sortableArticleID diff --git a/Shared/Widget/WidgetDataEncoder.swift b/Shared/Widget/WidgetDataEncoder.swift index 83dbf0da9..7260497b7 100644 --- a/Shared/Widget/WidgetDataEncoder.swift +++ b/Shared/Widget/WidgetDataEncoder.swift @@ -64,6 +64,7 @@ public final class WidgetDataEncoder { } } + // swiftlint:disable:next function_body_length private func encodeWidgetData(completion: @escaping (WidgetData?) -> Void) { let dispatchGroup = DispatchGroup() var groupError: Error?