diff --git a/.swiftlint.yml b/.swiftlint.yml new file mode 100644 index 00000000..434cfd7b --- /dev/null +++ b/.swiftlint.yml @@ -0,0 +1,85 @@ +# Project configuration +excluded: + - Pods + - Scripts + - vendor + +# Rules +whitelist_rules: + # Colons should be next to the identifier when specifying a type. + - colon + + # There should be no space before and one after any comma. + - comma + + # if,for,while,do statements shouldn't wrap their conditionals in parentheses. + - control_statement + + # Arguments can be omitted when matching enums with associated types if they + # are not used. + - empty_enum_arguments + + # Prefer `() -> ` over `Void -> `. + - empty_parameters + + # MARK comment should be in valid format. + - mark + + # Opening braces should be preceded by a single space and on the same line as + # the declaration. + - opening_brace + + # Files should have a single trailing newline. + - trailing_newline + + # Lines should not have trailing semicolons. + - trailing_semicolon + + # Lines should not have trailing whitespace. + - trailing_whitespace + + - custom_rules + +# Rules configuration + +control_statement: + severity: error + +custom_rules: + + natural_content_alignment: + name: "Natural Content Alignment" + regex: '\.contentHorizontalAlignment(\s*)=(\s*)(\.left|\.right)' + message: "Forcing content alignment left or right can affect the Right-to-Left layout. Use naturalContentHorizontalAlignment instead." + severity: warning + + natural_text_alignment: + name: "Natural Text Alignment" + regex: '\.textAlignment(\s*)=(\s*).left' + message: "Forcing text alignment to left can affect the Right-to-Left layout. Consider setting it to `natural`" + severity: warning + + inverse_text_alignment: + name: "Inverse Text Alignment" + regex: '\.textAlignment(\s*)=(\s*).right' + message: "When forcing text alignment to the right, be sure to handle the Right-to-Left layout case properly, and then silence this warning with this line `// swiftlint:disable:next inverse_text_alignment`" + severity: warning + + localization_comment: + name: "Localization Comment" + regex: 'NSLocalizedString([^,]+,\s+comment:\s*"")' + message: "Localized strings should include a description giving context for how the string is used." + severity: warning + + string_interpolation_in_localized_string: + name: "String Interpolation in Localized String" + regex: 'NSLocalizedString\("[^"]*\\\(\S*\)' + message: "Localized strings must not use interpolated variables. Instead, use `String(format:`" + severity: error + + swiftui_localization: + name: "SwiftUI Localization" + regex: 'LocalizedStringKey' + message: "Using `LocalizedStringKey` is incompatible with our tooling and doesn't allow you to provide a hint/context comment for translators either. Please use `NSLocalizedString` instead, even with SwiftUI code." + severity: error + excluded: '.*Widgets/.*' diff --git a/Podfile b/Podfile index e894c28d..d4e7cf79 100644 --- a/Podfile +++ b/Podfile @@ -33,3 +33,7 @@ target 'WordPressKitTests' do pod 'OHHTTPStubs/Swift', '~> 9.0' pod 'OCMock', '~> 3.4' end + +abstract_target 'CLI' do + pod 'SwiftLint' +end diff --git a/Podfile.lock b/Podfile.lock index 98200650..d1f06a6d 100644 --- a/Podfile.lock +++ b/Podfile.lock @@ -23,6 +23,7 @@ PODS: - OHHTTPStubs/OHPathHelpers (9.1.0) - OHHTTPStubs/Swift (9.1.0): - OHHTTPStubs/Default + - SwiftLint (0.47.1) - UIDeviceIdentifier (2.0.0) - WordPressShared (1.16.1): - CocoaLumberjack (~> 3.4) @@ -36,6 +37,7 @@ DEPENDENCIES: - OCMock (~> 3.4) - OHHTTPStubs (~> 9.0) - OHHTTPStubs/Swift (~> 9.0) + - SwiftLint - UIDeviceIdentifier (~> 2.0) - WordPressShared (~> 1.15-beta) - wpxmlrpc (~> 0.9.0) @@ -48,6 +50,7 @@ SPEC REPOS: - NSObject-SafeExpectations - OCMock - OHHTTPStubs + - SwiftLint - UIDeviceIdentifier - WordPressShared - wpxmlrpc @@ -59,10 +62,11 @@ SPEC CHECKSUMS: NSObject-SafeExpectations: ab8fe623d36b25aa1f150affa324e40a2f3c0374 OCMock: 29f6e52085b4e7d9b075cbf03ed7c3112f82f934 OHHTTPStubs: 90eac6d8f2c18317baeca36698523dc67c513831 + SwiftLint: f80f1be7fa96d30e0aa68e58d45d4ea1ccaac519 UIDeviceIdentifier: af4e11e25a2ea670078e2bd677bb0e8144f9f063 WordPressShared: 5477f179c7fe03b5d574f91adda66f67d131827e wpxmlrpc: bf55a43a7e710bd2a4fb8c02dfe83b1246f14f13 -PODFILE CHECKSUM: 16cc178a9361ce125accbf66bdbfd2a3604e1009 +PODFILE CHECKSUM: 05f7474abf9ca7c6575332cfc7313ba59b04e9ec -COCOAPODS: 1.11.2 +COCOAPODS: 1.10.2 diff --git a/WordPressKit.xcodeproj/project.pbxproj b/WordPressKit.xcodeproj/project.pbxproj index 7aa22b91..b9c2a32d 100644 --- a/WordPressKit.xcodeproj/project.pbxproj +++ b/WordPressKit.xcodeproj/project.pbxproj @@ -3,7 +3,7 @@ archiveVersion = 1; classes = { }; - objectVersion = 46; + objectVersion = 54; objects = { /* Begin PBXBuildFile section */ @@ -2547,6 +2547,7 @@ 9368C7761EC5EF1B0092CE8E /* Sources */, 9368C7771EC5EF1B0092CE8E /* Frameworks */, 9368C7791EC5EF1B0092CE8E /* Resources */, + 3FB7632C284DC9CD0091C04F /* Run SwiftLint */, ); buildRules = ( ); @@ -2566,6 +2567,7 @@ 9368C7811EC5EF1B0092CE8E /* Frameworks */, 9368C7821EC5EF1B0092CE8E /* Resources */, B07A9DD36A28DB40846D1682 /* [CP] Embed Pods Frameworks */, + 3FB7632D284DCC9A0091C04F /* Run SwiftLint */, ); buildRules = ( ); @@ -2931,6 +2933,43 @@ shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; showEnvVarsInLog = 0; }; + 3FB7632C284DC9CD0091C04F /* Run SwiftLint */ = { + isa = PBXShellScriptBuildPhase; + alwaysOutOfDate = 1; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + ); + inputPaths = ( + ); + name = "Run SwiftLint"; + outputFileListPaths = ( + ); + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "$SRCROOT/Pods/SwiftLint/swiftlint lint --path $SRCROOT/WordPressKit\n"; + }; + 3FB7632D284DCC9A0091C04F /* Run SwiftLint */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + ); + inputPaths = ( + ); + name = "Run SwiftLint"; + outputFileListPaths = ( + ); + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "$SRCROOT/Pods/SwiftLint/swiftlint lint --path $SRCROOT/WordPressKitTests\n"; + }; 50C31E8D1B97D5FA0D543935 /* [CP] Check Pods Manifest.lock */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; @@ -3422,7 +3461,8 @@ IPHONEOS_DEPLOYMENT_TARGET = 13.0; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = iphoneos; - SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; + SWIFT_COMPILATION_MODE = wholemodule; + SWIFT_OPTIMIZATION_LEVEL = "-O"; SWIFT_VERSION = 4.2; TARGETED_DEVICE_FAMILY = "1,2"; VALIDATE_PRODUCT = YES; @@ -3449,7 +3489,11 @@ DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = WordPressKit/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@loader_path/Frameworks", + ); MARKETING_VERSION = 4.15.0; PRODUCT_BUNDLE_IDENTIFIER = com.automattic.WordPressKit; PRODUCT_NAME = "$(TARGET_NAME)"; @@ -3477,7 +3521,11 @@ DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = WordPressKit/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@loader_path/Frameworks", + ); MARKETING_VERSION = 4.15.0; PRODUCT_BUNDLE_IDENTIFIER = com.automattic.WordPressKit; PRODUCT_NAME = "$(TARGET_NAME)"; @@ -3498,7 +3546,11 @@ "$(SDKROOT)/usr/include/libxml2", ); INFOPLIST_FILE = WordPressKitTests/Info.plist; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@loader_path/Frameworks", + ); PRODUCT_BUNDLE_IDENTIFIER = com.automattic.WordPressKitTests; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_OBJC_BRIDGING_HEADER = "WordPressKitTests/WordPressKitTests-Bridging-Header.h"; @@ -3519,7 +3571,11 @@ "$(SDKROOT)/usr/include/libxml2", ); INFOPLIST_FILE = WordPressKitTests/Info.plist; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@loader_path/Frameworks", + ); PRODUCT_BUNDLE_IDENTIFIER = com.automattic.WordPressKitTests; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_OBJC_BRIDGING_HEADER = "WordPressKitTests/WordPressKitTests-Bridging-Header.h"; @@ -3576,7 +3632,8 @@ IPHONEOS_DEPLOYMENT_TARGET = 13.0; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = iphoneos; - SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; + SWIFT_COMPILATION_MODE = wholemodule; + SWIFT_OPTIMIZATION_LEVEL = "-O"; SWIFT_VERSION = 4.2; TARGETED_DEVICE_FAMILY = "1,2"; VALIDATE_PRODUCT = YES; @@ -3603,7 +3660,11 @@ DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = WordPressKit/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@loader_path/Frameworks", + ); MARKETING_VERSION = 4.15.0; PRODUCT_BUNDLE_IDENTIFIER = com.automattic.WordPressKit; PRODUCT_NAME = "$(TARGET_NAME)"; @@ -3624,7 +3685,11 @@ "$(SDKROOT)/usr/include/libxml2", ); INFOPLIST_FILE = WordPressKitTests/Info.plist; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@loader_path/Frameworks", + ); PRODUCT_BUNDLE_IDENTIFIER = com.automattic.WordPressKitTests; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_OBJC_BRIDGING_HEADER = "WordPressKitTests/WordPressKitTests-Bridging-Header.h"; @@ -3681,7 +3746,8 @@ IPHONEOS_DEPLOYMENT_TARGET = 13.0; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = iphoneos; - SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; + SWIFT_COMPILATION_MODE = wholemodule; + SWIFT_OPTIMIZATION_LEVEL = "-O"; SWIFT_VERSION = 4.2; TARGETED_DEVICE_FAMILY = "1,2"; VALIDATE_PRODUCT = YES; @@ -3708,7 +3774,11 @@ DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = WordPressKit/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@loader_path/Frameworks", + ); MARKETING_VERSION = 4.15.0; PRODUCT_BUNDLE_IDENTIFIER = com.automattic.WordPressKit; PRODUCT_NAME = "$(TARGET_NAME)"; @@ -3729,7 +3799,11 @@ "$(SDKROOT)/usr/include/libxml2", ); INFOPLIST_FILE = WordPressKitTests/Info.plist; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@loader_path/Frameworks", + ); PRODUCT_BUNDLE_IDENTIFIER = com.automattic.WordPressKitTests; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_OBJC_BRIDGING_HEADER = "WordPressKitTests/WordPressKitTests-Bridging-Header.h"; diff --git a/WordPressKit/HTTPAuthenticationAlertController.swift b/WordPressKit/HTTPAuthenticationAlertController.swift index 718b9206..222e34e7 100644 --- a/WordPressKit/HTTPAuthenticationAlertController.swift +++ b/WordPressKit/HTTPAuthenticationAlertController.swift @@ -36,7 +36,13 @@ open class HTTPAuthenticationAlertController { private static func controllerForServerTrustChallenge(_ challenge: URLAuthenticationChallenge) -> UIAlertController { let title = NSLocalizedString("Certificate error", comment: "Popup title for wrong SSL certificate.") - let message = String(format: NSLocalizedString("The certificate for this server is invalid. You might be connecting to a server that is pretending to be “%@” which could put your confidential information at risk.\n\nWould you like to trust the certificate anyway?", comment: ""), challenge.protectionSpace.host) + let message = String( + format: NSLocalizedString( + "The certificate for this server is invalid. You might be connecting to a server that is pretending to be “%@” which could put your confidential information at risk.\n\nWould you like to trust the certificate anyway?", + comment: "Message in the wrong SSL certificate popup" + ), + challenge.protectionSpace.host + ) let controller = UIAlertController(title: title, message: message, preferredStyle: .alert) let cancelAction = UIAlertAction(title: NSLocalizedString("Cancel", comment: "Cancel button label"), diff --git a/WordPressKit/WordPressOrgXMLRPCValidator.swift b/WordPressKit/WordPressOrgXMLRPCValidator.swift index 5e4ea3fa..a149afe3 100644 --- a/WordPressKit/WordPressOrgXMLRPCValidator.swift +++ b/WordPressKit/WordPressOrgXMLRPCValidator.swift @@ -23,7 +23,7 @@ import CocoaLumberjack case .notWordPressError: return NSLocalizedString("That doesn't look like a WordPress site.", comment: "Message to show to user when he tries to add a self-hosted site that isn't a WordPress site.") case .mobilePluginRedirectedError: - return NSLocalizedString("You seem to have installed a mobile plugin from DudaMobile which is preventing the app to connect to your blog", comment: "") + return NSLocalizedString("You seem to have installed a mobile plugin from DudaMobile which is preventing the app to connect to your blog", comment: "Message to show to a user when they try to add a self-hosted side with a pluging from DudaMobile.") case .invalid: return NSLocalizedString("Couldn't connect to the WordPress site. There is no valid WordPress site at this address. Check the site address (URL) you entered.", comment: "Error message shown a URL points to a valid site but not a WordPress site.") case .blocked: