diff --git a/.swiftformat b/.swiftformat index 158bf1817..f687af1d7 100644 --- a/.swiftformat +++ b/.swiftformat @@ -1,33 +1,8 @@ ---allman false ---binarygrouping none ---closingparen balanced ---commas inline ---conflictmarkers reject ---decimalgrouping none ---elseposition same-line ---empty void ---exponentcase lowercase ---exponentgrouping disabled ---fractiongrouping disabled ---fragment false ---header ignore ---hexgrouping none ---hexliteralcase uppercase ---ifdef outdent ---importgrouping alphabetized ---indent 4 ---indentcase false ---linebreaks lf ---octalgrouping none ---operatorfunc spaced ---patternlet inline +--swiftversion 5.3 +--xcodeindentation enabled +--disable unusedArguments, redundantReturn, redundantSelf, trailingCommas, trailingClosures, wrapArguments, wrapMultilineStatementBraces +--enable blockComments, isEmpty +--emptybraces spaced +--ifdef no-indent +--importgrouping testable-first --ranges no-space ---self insert ---selfrequired ---semicolons inline ---stripunusedargs closure-only ---trailingclosures ---trimwhitespace always ---wraparguments before-first ---wrapcollections before-first ---xcodeindentation disabled diff --git a/PhoneNumberKit/Bundle+Resources.swift b/PhoneNumberKit/Bundle+Resources.swift index 9eeb008c8..7c8e638b0 100644 --- a/PhoneNumberKit/Bundle+Resources.swift +++ b/PhoneNumberKit/Bundle+Resources.swift @@ -1,6 +1,6 @@ import Foundation -private class CurrentBundleFinder {} +private class CurrentBundleFinder { } // The custom bundle locator code is needed to work around a bug in Xcode // where SwiftUI previews in an SPM module will crash if they try to use @@ -12,15 +12,15 @@ extension Bundle { #if DEBUG && SWIFT_PACKAGE let bundleName = "PhoneNumberKit_PhoneNumberKit" let candidates = [ - /* Bundle should be present here when the package is linked into an App. */ + // Bundle should be present here when the package is linked into an App. Bundle.main.resourceURL, - /* Bundle should be present here when the package is linked into a framework. */ + // Bundle should be present here when the package is linked into a framework. Bundle(for: CurrentBundleFinder.self).resourceURL, - /* For command-line tools. */ + // For command-line tools. Bundle.main.bundleURL, - /* Bundle should be present here when running previews from a different package (this is the path to "…/Debug-iphonesimulator/"). */ + // Bundle should be present here when running previews from a different package (this is the path to "…/Debug-iphonesimulator/"). Bundle(for: CurrentBundleFinder.self).resourceURL?.deletingLastPathComponent().deletingLastPathComponent(), - /* Bundle should be present here when running previews from a framework which imports framework whick imports PhoneNumberKit package (this is the path to "…/Debug-iphonesimulator/"). */ + // Bundle should be present here when running previews from a framework which imports framework whick imports PhoneNumberKit package (this is the path to "…/Debug-iphonesimulator/"). Bundle(for: CurrentBundleFinder.self).resourceURL?.deletingLastPathComponent() ] for candidate in candidates { @@ -30,7 +30,7 @@ extension Bundle { } } #endif - + #if SWIFT_PACKAGE return Bundle.module #else diff --git a/PhoneNumberKit/Constants.swift b/PhoneNumberKit/Constants.swift index 263cbbd58..39b6c989b 100644 --- a/PhoneNumberKit/Constants.swift +++ b/PhoneNumberKit/Constants.swift @@ -19,18 +19,16 @@ enum PhoneNumberCountryCodeSource { // MARK: Public Enums -/** - Enumeration for parsing error types - - - GeneralError: A general error occured. - - InvalidCountryCode: A country code could not be found or the one found was invalid - - InvalidNumber: The string provided is not a number - - TooLong: The string provided is too long to be a valid number - - TooShort: The string provided is too short to be a valid number - - Deprecated: The method used was deprecated - - metadataNotFound: PhoneNumberKit was unable to read the included metadata - - ambiguousNumber: The string could not be resolved to a single valid number - */ +/// Enumeration for parsing error types +/// +/// - GeneralError: A general error occured. +/// - InvalidCountryCode: A country code could not be found or the one found was invalid +/// - InvalidNumber: The string provided is not a number +/// - TooLong: The string provided is too long to be a valid number +/// - TooShort: The string provided is too short to be a valid number +/// - Deprecated: The method used was deprecated +/// - metadataNotFound: PhoneNumberKit was unable to read the included metadata +/// - ambiguousNumber: The string could not be resolved to a single valid number public enum PhoneNumberError: Error, Equatable { case generalError case invalidCountryCode @@ -63,21 +61,19 @@ public enum PhoneNumberFormat { case national // 06 89 12 34 56 } -/** - Phone number type enumeration - - fixedLine: Fixed line numbers - - mobile: Mobile numbers - - fixedOrMobile: Either fixed or mobile numbers if we can't tell conclusively. - - pager: Pager numbers - - personalNumber: Personal number numbers - - premiumRate: Premium rate numbers - - sharedCost: Shared cost numbers - - tollFree: Toll free numbers - - voicemail: Voice mail numbers - - vOIP: Voip numbers - - uan: UAN numbers - - unknown: Unknown number type - */ +/// Phone number type enumeration +/// - fixedLine: Fixed line numbers +/// - mobile: Mobile numbers +/// - fixedOrMobile: Either fixed or mobile numbers if we can't tell conclusively. +/// - pager: Pager numbers +/// - personalNumber: Personal number numbers +/// - premiumRate: Premium rate numbers +/// - sharedCost: Shared cost numbers +/// - tollFree: Toll free numbers +/// - voicemail: Voice mail numbers +/// - vOIP: Voip numbers +/// - uan: UAN numbers +/// - unknown: Unknown number type public enum PhoneNumberType: String, Codable { case fixedLine case mobile @@ -95,13 +91,13 @@ public enum PhoneNumberType: String, Codable { } public enum PossibleLengthType: String, Codable { - case national - case localOnly + case national + case localOnly } // MARK: Constants -struct PhoneNumberConstants { +enum PhoneNumberConstants { static let defaultCountry = "US" static let defaultExtnPrefix = " ext. " static let longPhoneNumber = "999999999999999" @@ -118,14 +114,14 @@ struct PhoneNumberConstants { static let separatorBeforeNationalNumber = " " } -struct PhoneNumberPatterns { +enum PhoneNumberPatterns { // MARK: Patterns static let firstGroupPattern = "(\\$\\d)" static let fgPattern = "\\$FG" static let npPattern = "\\$NP" - static let allNormalizationMappings = ["0":"0", "1":"1", "2":"2", "3":"3", "4":"4", "5":"5", "6":"6", "7":"7", "8":"8", "9":"9", "٠":"0", "١":"1", "٢":"2", "٣":"3", "٤":"4", "٥":"5", "٦":"6", "٧":"7", "٨":"8", "٩":"9", "۰":"0", "۱":"1", "۲":"2", "۳":"3", "۴":"4", "۵":"5", "۶":"6", "۷":"7", "۸":"8", "۹":"9", "*":"*", "#":"#", ",":",", ";":";"] + static let allNormalizationMappings = ["0": "0", "1": "1", "2": "2", "3": "3", "4": "4", "5": "5", "6": "6", "7": "7", "8": "8", "9": "9", "٠": "0", "١": "1", "٢": "2", "٣": "3", "٤": "4", "٥": "5", "٦": "6", "٧": "7", "٨": "8", "٩": "9", "۰": "0", "۱": "1", "۲": "2", "۳": "3", "۴": "4", "۵": "5", "۶": "6", "۷": "7", "۸": "8", "۹": "9", "*": "*", "#": "#", ",": ",", ";": ";"] static let capturingDigitPattern = "([0-90-9٠-٩۰-۹])" static let extnPattern = "(?:;ext=([0-90-9٠-٩۰-۹]{1,7})|[ \\t,]*(?:e?xt(?:ensi(?:ó?|ó))?n?|e?xtn?|[,xxX##~~;]|int|anexo|int)[:\\..]?[ \\t,-]*([0-90-9٠-٩۰-۹]{1,7})#?|[- ]+([0-90-9٠-٩۰-۹]{1,5})#)$" @@ -153,6 +149,6 @@ struct PhoneNumberPatterns { static let validStartPattern = "[++0-90-9٠-٩۰-۹]" static let validPhoneNumberPattern = "^[0-90-9٠-٩۰-۹]{2}$|^[++]*(?:[-x\u{2010}-\u{2015}\u{2212}\u{30FC}\u{FF0D}-\u{FF0F} \u{00A0}\u{00AD}\u{200B}\u{2060}\u{3000}()\u{FF08}\u{FF09}\u{FF3B}\u{FF3D}.\\[\\]/~\u{2053}\u{223C}\u{FF5E}*]*[0-9\u{FF10}-\u{FF19}\u{0660}-\u{0669}\u{06F0}-\u{06F9}]){3,}[-x\u{2010}-\u{2015}\u{2212}\u{30FC}\u{FF0D}-\u{FF0F} \u{00A0}\u{00AD}\u{200B}\u{2060}\u{3000}()\u{FF08}\u{FF09}\u{FF3B}\u{FF3D}.\\[\\]/~\u{2053}\u{223C}\u{FF5E}*A-Za-z0-9\u{FF10}-\u{FF19}\u{0660}-\u{0669}\u{06F0}-\u{06F9}]*(?:(?:;ext=([0-90-9٠-٩۰-۹]{1,7})|[ \\t,]*(?:e?xt(?:ensi(?:ó?|ó))?n?|e?xtn?|[,xxX##~~;]|int|anexo|int)[:\\..]?[ \\t,-]*([0-90-9٠-٩۰-۹]{1,7})#?|[- ]+([0-90-9٠-٩۰-۹]{1,5})#)?$)?[,;]*$" - + static let countryCodePatten = "^[a-zA-Z]{2}$" } diff --git a/PhoneNumberKit/Formatter.swift b/PhoneNumberKit/Formatter.swift index c172fd9b8..cc33ffa9b 100644 --- a/PhoneNumberKit/Formatter.swift +++ b/PhoneNumberKit/Formatter.swift @@ -106,10 +106,8 @@ final class Formatter { } public extension PhoneNumber { - /** - Adjust national number for display by adding leading zero if needed. Used for basic formatting functions. - - Returns: A string representing the adjusted national number. - */ + /// Adjust national number for display by adding leading zero if needed. Used for basic formatting functions. + /// - Returns: A string representing the adjusted national number. func adjustedNationalNumber() -> String { if self.leadingZero == true { return "0" + String(nationalNumber) diff --git a/PhoneNumberKit/MetadataManager.swift b/PhoneNumberKit/MetadataManager.swift index a34e1d815..0e8bbb8c4 100644 --- a/PhoneNumberKit/MetadataManager.swift +++ b/PhoneNumberKit/MetadataManager.swift @@ -1,5 +1,5 @@ // -// Metadata.swift +// MetadataManager.swift // PhoneNumberKit // // Created by Roy Marmelstein on 03/10/2015. @@ -10,7 +10,7 @@ import Foundation final class MetadataManager { private(set) var territories = [MetadataTerritory]() - + private var territoriesByCode = [UInt64: [MetadataTerritory]]() private var mainTerritoryByCode = [UInt64: MetadataTerritory]() private var territoriesByCountry = [String: MetadataTerritory]() @@ -70,7 +70,7 @@ final class MetadataManager { /// - parameter code: international country code (e.g 44 for the UK). /// /// - returns: optional array of MetadataTerritory objects. - internal func filterTerritories(byCode code: UInt64) -> [MetadataTerritory]? { + func filterTerritories(byCode code: UInt64) -> [MetadataTerritory]? { return self.territoriesByCode[code] } @@ -79,7 +79,7 @@ final class MetadataManager { /// - parameter country: ISO 3166 compliant region code (e.g "GB" for the UK). /// /// - returns: A MetadataTerritory object. - internal func filterTerritories(byCountry country: String) -> MetadataTerritory? { + func filterTerritories(byCountry country: String) -> MetadataTerritory? { return self.territoriesByCountry[country.uppercased()] } @@ -88,7 +88,7 @@ final class MetadataManager { /// - parameter code: An international country code (e.g 1 for the US). /// /// - returns: A MetadataTerritory object. - internal func mainTerritory(forCode code: UInt64) -> MetadataTerritory? { + func mainTerritory(forCode code: UInt64) -> MetadataTerritory? { return self.mainTerritoryByCode[code] } } diff --git a/PhoneNumberKit/MetadataTypes.swift b/PhoneNumberKit/MetadataTypes.swift index c7bf8edfe..acf715829 100644 --- a/PhoneNumberKit/MetadataTypes.swift +++ b/PhoneNumberKit/MetadataTypes.swift @@ -8,30 +8,28 @@ import Foundation -/** - MetadataTerritory object - - Parameter codeID: ISO 3166 compliant region code - - Parameter countryCode: International country code - - Parameter internationalPrefix: International prefix. Optional. - - Parameter mainCountryForCode: Whether the current metadata is the main country for its country code. - - Parameter nationalPrefix: National prefix - - Parameter nationalPrefixFormattingRule: National prefix formatting rule - - Parameter nationalPrefixForParsing: National prefix for parsing - - Parameter nationalPrefixTransformRule: National prefix transform rule - - Parameter emergency: MetadataPhoneNumberDesc for emergency numbers - - Parameter fixedLine: MetadataPhoneNumberDesc for fixed line numbers - - Parameter generalDesc: MetadataPhoneNumberDesc for general numbers - - Parameter mobile: MetadataPhoneNumberDesc for mobile numbers - - Parameter pager: MetadataPhoneNumberDesc for pager numbers - - Parameter personalNumber: MetadataPhoneNumberDesc for personal number numbers - - Parameter premiumRate: MetadataPhoneNumberDesc for premium rate numbers - - Parameter sharedCost: MetadataPhoneNumberDesc for shared cost numbers - - Parameter tollFree: MetadataPhoneNumberDesc for toll free numbers - - Parameter voicemail: MetadataPhoneNumberDesc for voice mail numbers - - Parameter voip: MetadataPhoneNumberDesc for voip numbers - - Parameter uan: MetadataPhoneNumberDesc for uan numbers - - Parameter leadingDigits: Optional leading digits for the territory - */ +/// MetadataTerritory object +/// - Parameter codeID: ISO 3166 compliant region code +/// - Parameter countryCode: International country code +/// - Parameter internationalPrefix: International prefix. Optional. +/// - Parameter mainCountryForCode: Whether the current metadata is the main country for its country code. +/// - Parameter nationalPrefix: National prefix +/// - Parameter nationalPrefixFormattingRule: National prefix formatting rule +/// - Parameter nationalPrefixForParsing: National prefix for parsing +/// - Parameter nationalPrefixTransformRule: National prefix transform rule +/// - Parameter emergency: MetadataPhoneNumberDesc for emergency numbers +/// - Parameter fixedLine: MetadataPhoneNumberDesc for fixed line numbers +/// - Parameter generalDesc: MetadataPhoneNumberDesc for general numbers +/// - Parameter mobile: MetadataPhoneNumberDesc for mobile numbers +/// - Parameter pager: MetadataPhoneNumberDesc for pager numbers +/// - Parameter personalNumber: MetadataPhoneNumberDesc for personal number numbers +/// - Parameter premiumRate: MetadataPhoneNumberDesc for premium rate numbers +/// - Parameter sharedCost: MetadataPhoneNumberDesc for shared cost numbers +/// - Parameter tollFree: MetadataPhoneNumberDesc for toll free numbers +/// - Parameter voicemail: MetadataPhoneNumberDesc for voice mail numbers +/// - Parameter voip: MetadataPhoneNumberDesc for voip numbers +/// - Parameter uan: MetadataPhoneNumberDesc for uan numbers +/// - Parameter leadingDigits: Optional leading digits for the territory public struct MetadataTerritory: Decodable { public let codeID: String public let countryCode: UInt64 @@ -58,13 +56,11 @@ public struct MetadataTerritory: Decodable { public let leadingDigits: String? } -/** - MetadataPhoneNumberDesc object - - Parameter exampleNumber: An example phone number for the given type. Optional. - - Parameter nationalNumberPattern: National number regex pattern. Optional. - - Parameter possibleNumberPattern: Possible number regex pattern. Optional. - - Parameter possibleLengths: Possible phone number lengths. Optional. - */ +/// MetadataPhoneNumberDesc object +/// - Parameter exampleNumber: An example phone number for the given type. Optional. +/// - Parameter nationalNumberPattern: National number regex pattern. Optional. +/// - Parameter possibleNumberPattern: Possible number regex pattern. Optional. +/// - Parameter possibleLengths: Possible phone number lengths. Optional. public struct MetadataPhoneNumberDesc: Decodable { public let exampleNumber: String? public let nationalNumberPattern: String? @@ -77,17 +73,15 @@ public struct MetadataPossibleLengths: Decodable { let localOnly: String? } -/** - MetadataPhoneNumberFormat object - - Parameter pattern: Regex pattern. Optional. - - Parameter format: Formatting template. Optional. - - Parameter intlFormat: International formatting template. Optional. - - - Parameter leadingDigitsPatterns: Leading digits regex pattern. Optional. - - Parameter nationalPrefixFormattingRule: National prefix formatting rule. Optional. - - Parameter nationalPrefixOptionalWhenFormatting: National prefix optional bool. Optional. - - Parameter domesticCarrierCodeFormattingRule: Domestic carrier code formatting rule. Optional. - */ +/// MetadataPhoneNumberFormat object +/// - Parameter pattern: Regex pattern. Optional. +/// - Parameter format: Formatting template. Optional. +/// - Parameter intlFormat: International formatting template. Optional. +/// +/// - Parameter leadingDigitsPatterns: Leading digits regex pattern. Optional. +/// - Parameter nationalPrefixFormattingRule: National prefix formatting rule. Optional. +/// - Parameter nationalPrefixOptionalWhenFormatting: National prefix optional bool. Optional. +/// - Parameter domesticCarrierCodeFormattingRule: Domestic carrier code formatting rule. Optional. public struct MetadataPhoneNumberFormat: Decodable { public let pattern: String? public let format: String? @@ -99,6 +93,6 @@ public struct MetadataPhoneNumberFormat: Decodable { } /// Internal object for metadata parsing -internal struct PhoneNumberMetadata: Decodable { +struct PhoneNumberMetadata: Decodable { var territories: [MetadataTerritory] } diff --git a/PhoneNumberKit/ParseManager.swift b/PhoneNumberKit/ParseManager.swift index b7d38f688..afe7b9dc5 100644 --- a/PhoneNumberKit/ParseManager.swift +++ b/PhoneNumberKit/ParseManager.swift @@ -8,9 +8,7 @@ import Foundation -/** - Manager for parsing flow. - */ +/// Manager for parsing flow. final class ParseManager { weak var metadataManager: MetadataManager? let parser: PhoneNumberParser @@ -22,12 +20,10 @@ final class ParseManager { self.regexManager = regexManager } - /** - Parse a string into a phone number object with a custom region. Can throw. - - Parameter numberString: String to be parsed to phone number struct. - - Parameter region: ISO 3166 compliant region code. - - parameter ignoreType: Avoids number type checking for faster performance. - */ + /// Parse a string into a phone number object with a custom region. Can throw. + /// - Parameter numberString: String to be parsed to phone number struct. + /// - Parameter region: ISO 3166 compliant region code. + /// - parameter ignoreType: Avoids number type checking for faster performance. func parse(_ numberString: String, withRegion region: String, ignoreType: Bool) throws -> PhoneNumber { guard let metadataManager = metadataManager, let regexManager = regexManager else { throw PhoneNumberError.generalError } // Make sure region is in uppercase so that it matches metadata (1) @@ -65,13 +61,13 @@ final class ParseManager { return result } } - + if let result = try validPhoneNumber(from: nationalNumber, using: regionMetadata, countryCode: regionMetadata.countryCode, ignoreType: ignoreType, numberString: numberString, numberExtension: numberExtension) { return result } throw PhoneNumberError.invalidNumber } - + // If country code is not default, grab correct metadata (6) if countryCode != regionMetadata.countryCode, let countryMetadata = metadataManager.mainTerritory(forCode: countryCode) { regionMetadata = countryMetadata @@ -90,7 +86,7 @@ final class ParseManager { } } } - + switch possibleResults.count { case 0: throw PhoneNumberError.invalidNumber case 1: return possibleResults.first! @@ -100,16 +96,14 @@ final class ParseManager { // Parse task - /** - Fastest way to parse an array of phone numbers. Uses custom region code. - - Parameter numberStrings: An array of raw number strings. - - Parameter region: ISO 3166 compliant region code. - - parameter ignoreType: Avoids number type checking for faster performance. - - Returns: An array of valid PhoneNumber objects. - */ + /// Fastest way to parse an array of phone numbers. Uses custom region code. + /// - Parameter numberStrings: An array of raw number strings. + /// - Parameter region: ISO 3166 compliant region code. + /// - parameter ignoreType: Avoids number type checking for faster performance. + /// - Returns: An array of valid PhoneNumber objects. func parseMultiple(_ numberStrings: [String], withRegion region: String, ignoreType: Bool, shouldReturnFailedEmptyNumbers: Bool = false) -> [PhoneNumber] { var hasError = false - + var multiParseArray = [PhoneNumber](unsafeUninitializedCapacity: numberStrings.count) { buffer, initializedCount in DispatchQueue.concurrentPerform(iterations: numberStrings.count) { index in let numberString = numberStrings[index] @@ -124,7 +118,7 @@ final class ParseManager { initializedCount = numberStrings.count } - if hasError && !shouldReturnFailedEmptyNumbers { + if hasError, !shouldReturnFailedEmptyNumbers { multiParseArray = multiParseArray.filter { $0.type != .notParsed } } @@ -162,8 +156,7 @@ final class ParseManager { return nil } - //MARK: Internal method - + // MARK: Internal method /// Creates a valid phone number given a specifc region metadata, used internally by the parse function private func validPhoneNumber(from nationalNumber: String, using regionMetadata: MetadataTerritory, countryCode: UInt64, ignoreType: Bool, numberString: String, numberExtension: String?) throws -> PhoneNumber? { @@ -177,7 +170,7 @@ final class ParseManager { // Test number against general number description for correct metadata (2) if let generalNumberDesc = regionMetadata.generalDesc, - regexManager.hasValue(generalNumberDesc.nationalNumberPattern) == false || parser.isNumberMatchingDesc(nationalNumber, numberDesc: generalNumberDesc) == false { + regexManager.hasValue(generalNumberDesc.nationalNumberPattern) == false || parser.isNumberMatchingDesc(nationalNumber, numberDesc: generalNumberDesc) == false { return nil } // Finalize remaining parameters and create phone number object (3) @@ -189,7 +182,7 @@ final class ParseManager { // Check if the number if of a known type (4) var type: PhoneNumberType = .unknown if ignoreType == false { - if let regionCode = getRegionCode(of: finalNationalNumber, countryCode: countryCode, leadingZero: leadingZero), let foundMetadata = metadataManager.filterTerritories(byCountry: regionCode){ + if let regionCode = getRegionCode(of: finalNationalNumber, countryCode: countryCode, leadingZero: leadingZero), let foundMetadata = metadataManager.filterTerritories(byCountry: regionCode) { regionMetadata = foundMetadata } type = self.parser.checkNumberType(String(nationalNumber), metadata: regionMetadata, leadingZero: leadingZero) @@ -200,5 +193,4 @@ final class ParseManager { return PhoneNumber(numberString: numberString, countryCode: countryCode, leadingZero: leadingZero, nationalNumber: finalNationalNumber, numberExtension: numberExtension, type: type, regionID: regionMetadata.codeID) } - } diff --git a/PhoneNumberKit/PartialFormatter.swift b/PhoneNumberKit/PartialFormatter.swift index 0d98fa27b..53fedd473 100644 --- a/PhoneNumberKit/PartialFormatter.swift +++ b/PhoneNumberKit/PartialFormatter.swift @@ -59,7 +59,7 @@ public final class PartialFormatter { public var maxDigits: Int? func updateMetadataForDefaultRegion() { - guard let metadataManager = metadataManager else { return } + guard let metadataManager else { return } if let regionMetadata = metadataManager.filterTerritories(byCountry: defaultRegion) { self.defaultMetadata = metadataManager.mainTerritory(forCode: regionMetadata.countryCode) } else { @@ -86,24 +86,24 @@ public final class PartialFormatter { return currentMetadata?.codeID ?? "US" } else { return self.currentMetadata?.countryCode == 1 || self.currentMetadata?.countryCode == 7 - ? self.defaultRegion - : self.currentMetadata?.codeID ?? self.defaultRegion + ? self.defaultRegion + : self.currentMetadata?.codeID ?? self.defaultRegion } } } public func nationalNumber(from rawNumber: String) -> String { - guard let parser = parser else { return rawNumber } + guard let parser else { return rawNumber } let iddFreeNumber = self.extractIDD(rawNumber) var nationalNumber = parser.normalizePhoneNumber(iddFreeNumber) - if self.prefixBeforeNationalNumber.count > 0 { + if !self.prefixBeforeNationalNumber.isEmpty { nationalNumber = self.extractCountryCallingCode(nationalNumber) } nationalNumber = self.extractNationalPrefix(nationalNumber) - if let maxDigits = maxDigits { + if let maxDigits { let extra = nationalNumber.count - maxDigits if extra > 0 { @@ -116,13 +116,11 @@ public final class PartialFormatter { // MARK: Lifecycle - /** - Formats a partial string (for use in TextField) - - - parameter rawNumber: Unformatted phone number string - - - returns: Formatted phone number string. - */ + /// Formats a partial string (for use in TextField) + /// + /// - parameter rawNumber: Unformatted phone number string + /// + /// - returns: Formatted phone number string. public func formatPartial(_ rawNumber: String) -> String { // Always reset variables with each new raw number self.resetVariables() @@ -131,7 +129,7 @@ public final class PartialFormatter { return rawNumber } let split = splitNumberAndPausesOrWaits(rawNumber) - + var nationalNumber = self.nationalNumber(from: split.number) if let formats = availableFormats(nationalNumber) { if let formattedNumber = applyFormat(nationalNumber, formats: formats) { @@ -147,13 +145,14 @@ public final class PartialFormatter { } var finalNumber = String() - if self.withPrefix, self.prefixBeforeNationalNumber.count > 0 { + if self.withPrefix, !self.prefixBeforeNationalNumber.isEmpty { finalNumber.append(self.prefixBeforeNationalNumber) } - if self.withPrefix, self.shouldAddSpaceAfterNationalPrefix, self.prefixBeforeNationalNumber.count > 0, self.prefixBeforeNationalNumber.last != PhoneNumberConstants.separatorBeforeNationalNumber.first { + if self.withPrefix, self.shouldAddSpaceAfterNationalPrefix, !self.prefixBeforeNationalNumber.isEmpty, + self.prefixBeforeNationalNumber.last != PhoneNumberConstants.separatorBeforeNationalNumber.first { finalNumber.append(PhoneNumberConstants.separatorBeforeNationalNumber) } - if nationalNumber.count > 0 { + if !nationalNumber.isEmpty { finalNumber.append(nationalNumber) } if finalNumber.last == PhoneNumberConstants.separatorBeforeNationalNumber.first { @@ -165,7 +164,7 @@ public final class PartialFormatter { // MARK: Formatting Functions - internal func resetVariables() { + func resetVariables() { self.currentMetadata = self.defaultMetadata self.prefixBeforeNationalNumber = String() self.shouldAddSpaceAfterNationalPrefix = false @@ -173,14 +172,15 @@ public final class PartialFormatter { // MARK: Formatting Tests - internal func isValidRawNumber(_ rawNumber: String) -> Bool { + func isValidRawNumber(_ rawNumber: String) -> Bool { do { // In addition to validPhoneNumberPattern, // accept any sequence of digits and whitespace, prefixed or not by a plus sign let validPartialPattern = "[++]?(\\s*\\d)+\\s*$|\(PhoneNumberPatterns.validPhoneNumberPattern)" let validNumberMatches = try regexManager?.regexMatches(validPartialPattern, string: rawNumber) - let validStart = self.regexManager?.stringPositionByRegex(PhoneNumberPatterns.validStartPattern, string: rawNumber) - if validNumberMatches?.count == 0 || validStart != 0 { + let validStart = self.regexManager?.stringPositionByRegex(PhoneNumberPatterns.validStartPattern, + string: rawNumber) + if validNumberMatches?.isEmpty == true || validStart != 0 { return false } } catch { @@ -189,24 +189,23 @@ public final class PartialFormatter { return true } - internal func isNanpaNumberWithNationalPrefix(_ rawNumber: String) -> Bool { + func isNanpaNumberWithNationalPrefix(_ rawNumber: String) -> Bool { guard self.currentMetadata?.countryCode == 1, rawNumber.count > 1 else { return false } - let firstCharacter: String = String(describing: rawNumber.first) - let secondCharacter: String = String(describing: rawNumber[rawNumber.index(rawNumber.startIndex, offsetBy: 1)]) - return (firstCharacter == "1" && secondCharacter != "0" && secondCharacter != "1") + let firstCharacter = String(describing: rawNumber.first) + let secondCharacter = String(describing: rawNumber[rawNumber.index(rawNumber.startIndex, offsetBy: 1)]) + return firstCharacter == "1" && secondCharacter != "0" && secondCharacter != "1" } func isFormatEligible(_ format: MetadataPhoneNumberFormat) -> Bool { guard let phoneFormat = format.format else { return false } - do { - let validRegex = try regexManager?.regexWithPattern(PhoneNumberPatterns.eligibleAsYouTypePattern) - if validRegex?.firstMatch(in: phoneFormat, options: [], range: NSRange(location: 0, length: phoneFormat.count)) != nil { - return true - } - } catch {} + let validRegex = try? regexManager?.regexWithPattern(PhoneNumberPatterns.eligibleAsYouTypePattern) + if validRegex? + .firstMatch(in: phoneFormat, options: [], range: NSRange(location: 0, length: phoneFormat.count)) != nil { + return true + } return false } @@ -233,13 +232,14 @@ public final class PartialFormatter { func extractNationalPrefix(_ rawNumber: String) -> String { var processedNumber = rawNumber - var startOfNationalNumber: Int = 0 + var startOfNationalNumber = 0 if self.isNanpaNumberWithNationalPrefix(rawNumber) { self.prefixBeforeNationalNumber.append("1 ") } else { do { if let nationalPrefix = currentMetadata?.nationalPrefixForParsing { - let nationalPrefixPattern = String(format: PhoneNumberPatterns.nationalPrefixParsingPattern, arguments: [nationalPrefix]) + let nationalPrefixPattern = String(format: PhoneNumberPatterns.nationalPrefixParsingPattern, + arguments: [nationalPrefix]) let matches = try regexManager?.matchedStringByRegex(nationalPrefixPattern, string: rawNumber) if let m = matches?.first { startOfNationalNumber = m.count @@ -264,7 +264,9 @@ public final class PartialFormatter { if self.prefixBeforeNationalNumber.isEmpty == false, self.prefixBeforeNationalNumber.first != "+" { self.prefixBeforeNationalNumber.append(PhoneNumberConstants.separatorBeforeNationalNumber) } - if let potentialCountryCode = parser?.extractPotentialCountryCode(rawNumber, nationalNumber: &numberWithoutCountryCallingCode), potentialCountryCode != 0 { + if let potentialCountryCode = parser?.extractPotentialCountryCode(rawNumber, + nationalNumber: &numberWithoutCountryCallingCode), + potentialCountryCode != 0 { processedNumber = numberWithoutCountryCallingCode self.currentMetadata = self.metadataManager?.mainTerritory(forCode: potentialCountryCode) let potentialCountryCodeString = String(potentialCountryCode) @@ -277,30 +279,29 @@ public final class PartialFormatter { } return processedNumber } - + func splitNumberAndPausesOrWaits(_ rawNumber: String) -> (number: String, pausesOrWaits: String) { if rawNumber.isEmpty { return (rawNumber, "") } - + let splitByComma = rawNumber.split(separator: ",", maxSplits: 1, omittingEmptySubsequences: false) let splitBySemiColon = rawNumber.split(separator: ";", maxSplits: 1, omittingEmptySubsequences: false) - + if splitByComma[0].count != splitBySemiColon[0].count { let foundCommasFirst = splitByComma[0].count < splitBySemiColon[0].count - + if foundCommasFirst { return (String(splitByComma[0]), "," + splitByComma[1]) - } - else { + } else { return (String(splitBySemiColon[0]), ";" + splitBySemiColon[1]) } } return (rawNumber, "") } - + func availableFormats(_ rawNumber: String) -> [MetadataPhoneNumberFormat]? { - guard let regexManager = regexManager else { return nil } + guard let regexManager else { return nil } var tempPossibleFormats = [MetadataPhoneNumberFormat]() var possibleFormats = [MetadataPhoneNumberFormat]() if let metadata = currentMetadata { @@ -319,7 +320,7 @@ public final class PartialFormatter { } } } - if possibleFormats.count == 0 { + if possibleFormats.isEmpty { possibleFormats.append(contentsOf: tempPossibleFormats) } return possibleFormats @@ -328,71 +329,89 @@ public final class PartialFormatter { } func applyFormat(_ rawNumber: String, formats: [MetadataPhoneNumberFormat]) -> String? { - guard let regexManager = regexManager else { return nil } + guard let regexManager else { return nil } for format in formats { - if let pattern = format.pattern, let formatTemplate = format.format { - let patternRegExp = String(format: PhoneNumberPatterns.formatPattern, arguments: [pattern]) - do { - let matches = try regexManager.regexMatches(patternRegExp, string: rawNumber) - if matches.count > 0 { - if let nationalPrefixFormattingRule = format.nationalPrefixFormattingRule { - let separatorRegex = try regexManager.regexWithPattern(PhoneNumberPatterns.prefixSeparatorPattern) - let nationalPrefixMatches = separatorRegex.matches(in: nationalPrefixFormattingRule, options: [], range: NSRange(location: 0, length: nationalPrefixFormattingRule.count)) - if nationalPrefixMatches.count > 0 { - self.shouldAddSpaceAfterNationalPrefix = true - } - } - let formattedNumber = regexManager.replaceStringByRegex(pattern, string: rawNumber, template: formatTemplate) - return formattedNumber - } - } catch {} + guard let pattern = format.pattern, let formatTemplate = format.format else { continue } + let patternRegExp = String(format: PhoneNumberPatterns.formatPattern, arguments: [pattern]) + guard let matches = try? regexManager.regexMatches(patternRegExp, string: rawNumber), + !matches.isEmpty else { continue } + if let nationalPrefixFormattingRule = format.nationalPrefixFormattingRule { + let separatorRegex = try? regexManager.regexWithPattern(PhoneNumberPatterns.prefixSeparatorPattern) + let nationalPrefixMatches = separatorRegex?.matches( + in: nationalPrefixFormattingRule, + options: [], + range: NSRange( + location: 0, + length: nationalPrefixFormattingRule.count + ) + ) + if let nationalPrefixMatches, !nationalPrefixMatches.isEmpty { + self.shouldAddSpaceAfterNationalPrefix = true + } } + let formattedNumber = regexManager.replaceStringByRegex( + pattern, + string: rawNumber, + template: formatTemplate + ) + return formattedNumber } return nil } func createFormattingTemplate(_ format: MetadataPhoneNumberFormat, rawNumber: String) -> String? { - guard var numberPattern = format.pattern, let numberFormat = format.format, let regexManager = regexManager else { + guard var numberPattern = format.pattern, + let numberFormat = format.format, + let regexManager, + numberPattern.range(of: "|") == nil, + let characterClassRegex = try? regexManager.regexWithPattern(PhoneNumberPatterns.characterClassPattern), + let standaloneDigitRegex = try? regexManager.regexWithPattern(PhoneNumberPatterns.standaloneDigitPattern) + else { return nil } - guard numberPattern.range(of: "|") == nil else { - return nil - } - do { - let characterClassRegex = try regexManager.regexWithPattern(PhoneNumberPatterns.characterClassPattern) - numberPattern = characterClassRegex.stringByReplacingMatches(in: numberPattern, withTemplate: "\\\\d") - - let standaloneDigitRegex = try regexManager.regexWithPattern(PhoneNumberPatterns.standaloneDigitPattern) - numberPattern = standaloneDigitRegex.stringByReplacingMatches(in: numberPattern, withTemplate: "\\\\d") - - if let tempTemplate = getFormattingTemplate(numberPattern, numberFormat: numberFormat, rawNumber: rawNumber) { - if let nationalPrefixFormattingRule = format.nationalPrefixFormattingRule { - let separatorRegex = try regexManager.regexWithPattern(PhoneNumberPatterns.prefixSeparatorPattern) - let nationalPrefixMatch = separatorRegex.firstMatch(in: nationalPrefixFormattingRule, options: [], range: NSRange(location: 0, length: nationalPrefixFormattingRule.count)) - if nationalPrefixMatch != nil { - self.shouldAddSpaceAfterNationalPrefix = true - } - } - return tempTemplate + + numberPattern = characterClassRegex.stringByReplacingMatches(in: numberPattern, withTemplate: "\\\\d") + numberPattern = standaloneDigitRegex.stringByReplacingMatches(in: numberPattern, withTemplate: "\\\\d") + + if let tempTemplate = getFormattingTemplate(numberPattern, numberFormat: numberFormat, rawNumber: rawNumber) { + if let nationalPrefixFormattingRule = format.nationalPrefixFormattingRule, + let separatorRegex = try? regexManager.regexWithPattern(PhoneNumberPatterns.prefixSeparatorPattern), + separatorRegex.firstMatch( + in: nationalPrefixFormattingRule, + options: [], + range: NSRange(location: 0, length: nationalPrefixFormattingRule.count) + ) != nil { + shouldAddSpaceAfterNationalPrefix = true } - } catch {} + return tempTemplate + } return nil } func getFormattingTemplate(_ numberPattern: String, numberFormat: String, rawNumber: String) -> String? { - guard let regexManager = regexManager else { return nil } - do { - let matches = try regexManager.matchedStringByRegex(numberPattern, string: PhoneNumberConstants.longPhoneNumber) - if let match = matches.first { - if match.count < rawNumber.count { - return nil - } - var template = regexManager.replaceStringByRegex(numberPattern, string: match, template: numberFormat) - template = regexManager.replaceStringByRegex("9", string: template, template: PhoneNumberConstants.digitPlaceholder) - return template - } - } catch {} - return nil + guard + let regexManager, + let matches = try? regexManager.matchedStringByRegex( + numberPattern, + string: PhoneNumberConstants.longPhoneNumber + ), + let match = matches.first else { + return nil + } + if match.count < rawNumber.count { + return nil + } + var template = regexManager.replaceStringByRegex( + numberPattern, + string: match, + template: numberFormat + ) + template = regexManager.replaceStringByRegex( + "9", + string: template, + template: PhoneNumberConstants.digitPlaceholder + ) + return template } func applyFormattingTemplate(_ template: String, rawNumber: String) -> String { @@ -413,7 +432,7 @@ public final class PartialFormatter { } if rebuiltIndex < rawNumber.count { let nationalCharacterIndex = rawNumber.index(rawNumber.startIndex, offsetBy: rebuiltIndex) - let remainingNationalNumber: String = String(rawNumber[nationalCharacterIndex...]) + let remainingNationalNumber = String(rawNumber[nationalCharacterIndex...]) rebuiltString.append(remainingNationalNumber) } rebuiltString = rebuiltString.trimmingCharacters(in: CharacterSet.whitespacesAndNewlines) diff --git a/PhoneNumberKit/PhoneNumber+Codable.swift b/PhoneNumberKit/PhoneNumber+Codable.swift index 4f284b361..2c61aa1de 100644 --- a/PhoneNumberKit/PhoneNumber+Codable.swift +++ b/PhoneNumberKit/PhoneNumber+Codable.swift @@ -38,9 +38,9 @@ public enum PhoneNumberEncodingUtils { public static var defaultPhoneNumberKit: () -> PhoneNumberKit = { .init() } } -extension JSONDecoder { +public extension JSONDecoder { /// The strategy used to decode a `PhoneNumber` value. - public var phoneNumberDecodingStrategy: PhoneNumberDecodingStrategy { + var phoneNumberDecodingStrategy: PhoneNumberDecodingStrategy { get { return userInfo[.phoneNumberDecodingStrategy] as? PhoneNumberDecodingStrategy ?? .default } @@ -50,7 +50,7 @@ extension JSONDecoder { } /// The `PhoneNumberKit` instance used for parsing when decoding, if needed. - public var phoneNumberKit: () -> PhoneNumberKit { + var phoneNumberKit: () -> PhoneNumberKit { get { return userInfo[.phoneNumberKit] as? () -> PhoneNumberKit ?? PhoneNumberDecodingUtils.defaultPhoneNumberKit } @@ -60,9 +60,9 @@ extension JSONDecoder { } } -extension JSONEncoder { +public extension JSONEncoder { /// The strategy used to encode a `PhoneNumber` value. - public var phoneNumberEncodingStrategy: PhoneNumberEncodingStrategy { + var phoneNumberEncodingStrategy: PhoneNumberEncodingStrategy { get { return userInfo[.phoneNumberEncodingStrategy] as? PhoneNumberEncodingStrategy ?? .default } @@ -72,7 +72,7 @@ extension JSONEncoder { } /// The `PhoneNumberKit` instance used for formatting when encoding, if needed. - public var phoneNumberKit: () -> PhoneNumberKit { + var phoneNumberKit: () -> PhoneNumberKit { get { return userInfo[.phoneNumberKit] as? () -> PhoneNumberKit ?? PhoneNumberEncodingUtils.defaultPhoneNumberKit } diff --git a/PhoneNumberKit/PhoneNumber.swift b/PhoneNumberKit/PhoneNumber.swift index d25962f96..997424add 100644 --- a/PhoneNumberKit/PhoneNumber.swift +++ b/PhoneNumberKit/PhoneNumber.swift @@ -8,16 +8,14 @@ import Foundation -/** - Parsed phone number object - - - numberString: String used to generate phone number struct - - countryCode: Country dialing code as an unsigned. Int. - - leadingZero: Some countries (e.g. Italy) require leading zeros. Bool. - - nationalNumber: National number as an unsigned. Int. - - numberExtension: Extension if available. String. Optional - - type: Computed phone number type on access. Returns from an enumeration - PNPhoneNumberType. - */ +/// Parsed phone number object +/// +/// - numberString: String used to generate phone number struct +/// - countryCode: Country dialing code as an unsigned. Int. +/// - leadingZero: Some countries (e.g. Italy) require leading zeros. Bool. +/// - nationalNumber: National number as an unsigned. Int. +/// - numberExtension: Extension if available. String. Optional +/// - type: Computed phone number type on access. Returns from an enumeration - PNPhoneNumberType. public struct PhoneNumber { public let numberString: String public let countryCode: UInt64 @@ -50,46 +48,39 @@ extension PhoneNumber: Hashable { } } -extension PhoneNumber { - public static func notPhoneNumber() -> PhoneNumber { +public extension PhoneNumber { + static func notPhoneNumber() -> PhoneNumber { return PhoneNumber(numberString: "", countryCode: 0, leadingZero: false, nationalNumber: 0, numberExtension: nil, type: .notParsed, regionID: nil) } - public func notParsed() -> Bool { + func notParsed() -> Bool { return self.type == .notParsed } - - /** - Get a callable URL from the number. - - Returns: A callable URL. - */ - public var url: URL? { + + /// Get a callable URL from the number. + /// - Returns: A callable URL. + var url: URL? { return URL(string: "tel://" + numberString) } } /// In past versions of PhoneNumberKit you were able to initialize a PhoneNumber object to parse a String. Please use a PhoneNumberKit object's methods. public extension PhoneNumber { - /** - DEPRECATED. - Parse a string into a phone number object using default region. Can throw. - - Parameter rawNumber: String to be parsed to phone number struct. - */ + /// DEPRECATED. + /// Parse a string into a phone number object using default region. Can throw. + /// - Parameter rawNumber: String to be parsed to phone number struct. @available(*, unavailable, message: "use PhoneNumberKit instead to produce PhoneNumbers") init(rawNumber: String) throws { assertionFailure(PhoneNumberError.deprecated.localizedDescription) throw PhoneNumberError.deprecated } - /** - DEPRECATED. - Parse a string into a phone number object using custom region. Can throw. - - Parameter rawNumber: String to be parsed to phone number struct. - - Parameter region: ISO 3166 compliant region code. - */ + /// DEPRECATED. + /// Parse a string into a phone number object using custom region. Can throw. + /// - Parameter rawNumber: String to be parsed to phone number struct. + /// - Parameter region: ISO 3166 compliant region code. @available(*, unavailable, message: "use PhoneNumberKit instead to produce PhoneNumbers") init(rawNumber: String, region: String) throws { throw PhoneNumberError.deprecated } } - diff --git a/PhoneNumberKit/PhoneNumberFormatter.swift b/PhoneNumberKit/PhoneNumberFormatter.swift index 47fa218f1..da83de103 100644 --- a/PhoneNumberKit/PhoneNumberFormatter.swift +++ b/PhoneNumberKit/PhoneNumberFormatter.swift @@ -58,7 +58,7 @@ open class PhoneNumberFormatter: Foundation.Formatter { // MARK: NSFormatter implementation extension PhoneNumberFormatter { - open override func string(for obj: Any?) -> String? { + override open func string(for obj: Any?) -> String? { if let pn = obj as? PhoneNumber { return self.phoneNumberKit.format(pn, toType: self.withPrefix ? .international : .national) } @@ -68,12 +68,12 @@ extension PhoneNumberFormatter { return nil } - open override func getObjectValue(_ obj: AutoreleasingUnsafeMutablePointer?, for string: String, errorDescription error: AutoreleasingUnsafeMutablePointer?) -> Bool { + override open func getObjectValue(_ obj: AutoreleasingUnsafeMutablePointer?, for string: String, errorDescription error: AutoreleasingUnsafeMutablePointer?) -> Bool { if self.generatesPhoneNumber { do { obj?.pointee = try self.phoneNumberKit.parse(string) as AnyObject? return true - } catch (let e) { + } catch let e { error?.pointee = e.localizedDescription as NSString return false } @@ -85,9 +85,7 @@ extension PhoneNumberFormatter { // MARK: Phone number formatting - /** - * To keep the cursor position, we find the character immediately after the cursor and count the number of times it repeats in the remaining string as this will remain constant in every kind of editing. - */ + /// To keep the cursor position, we find the character immediately after the cursor and count the number of times it repeats in the remaining string as this will remain constant in every kind of editing. private struct CursorPosition { let numberAfterCursor: unichar let repetitionCountFromEnd: Int @@ -146,7 +144,7 @@ extension PhoneNumberFormatter { return .replace } - open override func isPartialStringValid( + override open func isPartialStringValid( _ partialStringPtr: AutoreleasingUnsafeMutablePointer, proposedSelectedRange proposedSelRangePtr: NSRangePointer?, originalString origString: String, diff --git a/PhoneNumberKit/PhoneNumberKit.swift b/PhoneNumberKit/PhoneNumberKit.swift index d191ec64e..4a267a2b8 100644 --- a/PhoneNumberKit/PhoneNumberKit.swift +++ b/PhoneNumberKit/PhoneNumberKit.swift @@ -11,7 +11,7 @@ import Foundation import Contacts #endif -public typealias MetadataCallback = (() throws -> Data?) +public typealias MetadataCallback = () throws -> Data? public final class PhoneNumberKit { // Manager objects @@ -49,9 +49,9 @@ public final class PhoneNumberKit { public func parse(_ numberStrings: [String], withRegion region: String = PhoneNumberKit.defaultRegionCode(), ignoreType: Bool = false, shouldReturnFailedEmptyNumbers: Bool = false) -> [PhoneNumber] { return self.parseManager.parseMultiple(numberStrings, withRegion: region, ignoreType: ignoreType, shouldReturnFailedEmptyNumbers: shouldReturnFailedEmptyNumbers) } - + // MARK: Checking - + /// Checks if a number string is a valid PhoneNumber object /// /// - Parameters: @@ -97,7 +97,7 @@ public final class PhoneNumberKit { /// /// - returns: An array of ISO 3166 compliant region codes. public func allCountries() -> [String] { - let results = self.metadataManager.territories.map { $0.codeID } + let results = self.metadataManager.territories.map(\.codeID) return results } @@ -107,7 +107,7 @@ public final class PhoneNumberKit { /// /// - returns: optional array of ISO 3166 compliant region codes. public func countries(withCode countryCode: UInt64) -> [String]? { - let results = self.metadataManager.filterTerritories(byCode: countryCode)?.map { $0.codeID } + let results = self.metadataManager.filterTerritories(byCode: countryCode)?.map(\.codeID) return results } @@ -227,26 +227,26 @@ public final class PhoneNumberKit { let possibleLengths = possiblePhoneNumberLengths(forTerritory: territory, phoneNumberType: phoneNumberType) switch lengthType { - case .national: return possibleLengths?.national.flatMap { self.parsePossibleLengths($0) } ?? [] - case .localOnly: return possibleLengths?.localOnly.flatMap { self.parsePossibleLengths($0) } ?? [] + case .national: return possibleLengths?.national.flatMap { self.parsePossibleLengths($0) } ?? [] + case .localOnly: return possibleLengths?.localOnly.flatMap { self.parsePossibleLengths($0) } ?? [] } } private func possiblePhoneNumberLengths(forTerritory territory: MetadataTerritory, phoneNumberType: PhoneNumberType) -> MetadataPossibleLengths? { switch phoneNumberType { - case .fixedLine: return territory.fixedLine?.possibleLengths - case .mobile: return territory.mobile?.possibleLengths - case .pager: return territory.pager?.possibleLengths - case .personalNumber: return territory.personalNumber?.possibleLengths - case .premiumRate: return territory.premiumRate?.possibleLengths - case .sharedCost: return territory.sharedCost?.possibleLengths - case .tollFree: return territory.tollFree?.possibleLengths - case .voicemail: return territory.voicemail?.possibleLengths - case .voip: return territory.voip?.possibleLengths - case .uan: return territory.uan?.possibleLengths - case .fixedOrMobile: return nil // caller needs to combine results for .fixedLine and .mobile - case .unknown: return nil - case .notParsed: return nil + case .fixedLine: return territory.fixedLine?.possibleLengths + case .mobile: return territory.mobile?.possibleLengths + case .pager: return territory.pager?.possibleLengths + case .personalNumber: return territory.personalNumber?.possibleLengths + case .premiumRate: return territory.premiumRate?.possibleLengths + case .sharedCost: return territory.sharedCost?.possibleLengths + case .tollFree: return territory.tollFree?.possibleLengths + case .voicemail: return territory.voicemail?.possibleLengths + case .voip: return territory.voip?.possibleLengths + case .uan: return territory.uan?.possibleLengths + case .fixedOrMobile: return nil // caller needs to combine results for .fixedLine and .mobile + case .unknown: return nil + case .notParsed: return nil } } @@ -270,9 +270,9 @@ public final class PhoneNumberKit { let rangeLimits = trimmedComponent.components(separatedBy: "-").compactMap { Int($0) } guard rangeLimits.count == 2, - let rangeStart = rangeLimits.first, - let rangeEnd = rangeLimits.last - else { return [] } + let rangeStart = rangeLimits.first, + let rangeEnd = rangeLimits.last + else { return [] } return Array(rangeStart...rangeEnd) } @@ -332,7 +332,7 @@ public final class PhoneNumberKit { let handle = FileHandle(forReadingAtPath: jsonPath) else { throw PhoneNumberError.metadataNotFound } - + defer { if #available(iOS 13.0, macOS 10.15, macCatalyst 13.1, tvOS 13.0, watchOS 6.0, *) { try? handle.close() @@ -340,23 +340,22 @@ public final class PhoneNumberKit { handle.closeFile() } } - + let data = handle.readDataToEndOfFile() return data } } #if canImport(UIKit) -extension PhoneNumberKit { - +public extension PhoneNumberKit { /// Configuration for the CountryCodePicker presented from PhoneNumberTextField if `withDefaultPickerUI` is `true` - public enum CountryCodePicker { + enum CountryCodePicker { /// Common Country Codes are shown below the Current section in the CountryCodePicker by default public static var commonCountryCodes: [String] = [] /// When the Picker is shown from the textfield it is presented modally public static var forceModalPresentation: Bool = false - + /// Set the search bar of the Picker to always visible public static var alwaysShowsSearchBar: Bool = false } diff --git a/PhoneNumberKit/PhoneNumberParser.swift b/PhoneNumberKit/PhoneNumberParser.swift index 9ed92de97..85acc49f0 100644 --- a/PhoneNumberKit/PhoneNumberParser.swift +++ b/PhoneNumberKit/PhoneNumberParser.swift @@ -8,9 +8,7 @@ import Foundation -/** - Parser. Contains parsing functions. - */ +/// Parser. Contains parsing functions. final class PhoneNumberParser { let metadata: MetadataManager let regex: RegexManager @@ -22,11 +20,9 @@ final class PhoneNumberParser { // MARK: Normalizations - /** - Normalize a phone number (e.g +33 612-345-678 to 33612345678). - - Parameter number: Phone number string. - - Returns: Normalized phone number string. - */ + /// Normalize a phone number (e.g +33 612-345-678 to 33612345678). + /// - Parameter number: Phone number string. + /// - Returns: Normalized phone number string. func normalizePhoneNumber(_ number: String) -> String { let normalizationMappings = PhoneNumberPatterns.allNormalizationMappings return self.regex.stringByReplacingOccurrences(number, map: normalizationMappings) @@ -34,13 +30,11 @@ final class PhoneNumberParser { // MARK: Extractions - /** - Extract country code (e.g +33 612-345-678 to 33). - - Parameter number: Number string. - - Parameter nationalNumber: National number string - inout. - - Parameter metadata: Metadata territory object. - - Returns: Country code is UInt64. - */ + /// Extract country code (e.g +33 612-345-678 to 33). + /// - Parameter number: Number string. + /// - Parameter nationalNumber: National number string - inout. + /// - Parameter metadata: Metadata territory object. + /// - Returns: Country code is UInt64. func extractCountryCode(_ number: String, nationalNumber: inout String, metadata: MetadataTerritory) throws -> UInt64 { var fullNumber = number guard let possibleCountryIddPrefix = metadata.internationalPrefix else { @@ -76,12 +70,10 @@ final class PhoneNumberParser { return 0 } - /** - Extract potential country code (e.g +33 612-345-678 to 33). - - Parameter fullNumber: Full number string. - - Parameter nationalNumber: National number string. - - Returns: Country code is UInt64. Optional. - */ + /// Extract potential country code (e.g +33 612-345-678 to 33). + /// - Parameter fullNumber: Full number string. + /// - Parameter nationalNumber: National number string. + /// - Returns: Country code is UInt64. Optional. func extractPotentialCountryCode(_ fullNumber: String, nationalNumber: inout String) -> UInt64? { let nsFullNumber = fullNumber as NSString if nsFullNumber.length == 0 || nsFullNumber.substring(to: 1) == "0" { @@ -162,22 +154,18 @@ final class PhoneNumberParser { return .unknown } - /** - Checks if number matches description. - - Parameter nationalNumber: National number string. - - Parameter numberDesc: MetadataPhoneNumberDesc of a given phone number type. - - Returns: True or false. - */ + /// Checks if number matches description. + /// - Parameter nationalNumber: National number string. + /// - Parameter numberDesc: MetadataPhoneNumberDesc of a given phone number type. + /// - Returns: True or false. func isNumberMatchingDesc(_ nationalNumber: String, numberDesc: MetadataPhoneNumberDesc?) -> Bool { return self.regex.matchesEntirely(numberDesc?.nationalNumberPattern, string: nationalNumber) } - /** - Checks and strips if prefix is international dialing pattern. - - Parameter number: Number string. - - Parameter iddPattern: iddPattern for a given country. - - Returns: True or false and modifies the number accordingly. - */ + /// Checks and strips if prefix is international dialing pattern. + /// - Parameter number: Number string. + /// - Parameter iddPattern: iddPattern for a given country. + /// - Returns: True or false and modifies the number accordingly. func parsePrefixAsIdd(_ number: inout String, iddPattern: String) -> Bool { if self.regex.stringPositionByRegex(iddPattern, string: number) == 0 { do { @@ -209,11 +197,9 @@ final class PhoneNumberParser { // MARK: Strip helpers - /** - Strip an extension (e.g +33 612-345-678 ext.89 to 89). - - Parameter number: Number string. - - Returns: Modified number without extension and optional extension as string. - */ + /// Strip an extension (e.g +33 612-345-678 ext.89 to 89). + /// - Parameter number: Number string. + /// - Returns: Modified number without extension and optional extension as string. func stripExtension(_ number: inout String) -> String? { do { let matches = try regex.regexMatches(PhoneNumberPatterns.extnPattern, string: number) @@ -230,12 +216,10 @@ final class PhoneNumberParser { } } - /** - Strip international prefix. - - Parameter number: Number string. - - Parameter possibleIddPrefix: Possible idd prefix for a given country. - - Returns: Modified normalized number without international prefix and a PNCountryCodeSource enumeration. - */ + /// Strip international prefix. + /// - Parameter number: Number string. + /// - Parameter possibleIddPrefix: Possible idd prefix for a given country. + /// - Returns: Modified normalized number without international prefix and a PNCountryCodeSource enumeration. func stripInternationalPrefixAndNormalize(_ number: inout String, possibleIddPrefix: String?) -> PhoneNumberCountryCodeSource { if self.regex.matchesAtStart(PhoneNumberPatterns.leadingPlusCharsPattern, string: number as String) { number = self.regex.replaceStringByRegex(PhoneNumberPatterns.leadingPlusCharsPattern, string: number as String) @@ -253,12 +237,10 @@ final class PhoneNumberParser { } } - /** - Strip national prefix. - - Parameter number: Number string. - - Parameter metadata: Final country's metadata. - - Returns: Modified number without national prefix. - */ + /// Strip national prefix. + /// - Parameter number: Number string. + /// - Parameter metadata: Final country's metadata. + /// - Returns: Modified number without national prefix. func stripNationalPrefix(_ number: inout String, metadata: MetadataTerritory) { guard let possibleNationalPrefix = metadata.nationalPrefixForParsing else { return @@ -275,7 +257,7 @@ final class PhoneNumberParser { let nationalNumberRule = metadata.generalDesc?.nationalNumberPattern let firstMatchString = number.substring(with: firstMatch.range) let numOfGroups = firstMatch.numberOfRanges - 1 - var transformedNumber: String = String() + var transformedNumber = String() let firstRange = firstMatch.range(at: numOfGroups) let firstMatchStringWithGroup = (firstRange.location != NSNotFound && firstRange.location < number.count) ? number.substring(with: firstRange) : String() let firstMatchStringWithGroupHasValue = self.regex.hasValue(firstMatchStringWithGroup) diff --git a/PhoneNumberKit/RegexManager.swift b/PhoneNumberKit/RegexManager.swift index a00736863..24be4630e 100644 --- a/PhoneNumberKit/RegexManager.swift +++ b/PhoneNumberKit/RegexManager.swift @@ -31,7 +31,7 @@ final class RegexManager { regularExpressionPool[pattern] } - if let cached = cached { + if let cached { return cached } @@ -71,22 +71,19 @@ final class RegexManager { // MARK: Match helpers func matchesAtStart(_ pattern: String, string: String) -> Bool { - do { - let matches = try regexMatches(pattern, string: string) - for match in matches { - if match.range.location == 0 { - return true - } - } - } catch {} - return false + guard + let matches = try? regexMatches(pattern, string: string), + matches.first(where: { $0.range.location == 0 }) != nil else { + return false + } + return true } func stringPositionByRegex(_ pattern: String, string: String) -> Int { do { let matches = try regexMatches(pattern, string: string) if let match = matches.first { - return (match.range.location) + return match.range.location } return -1 } catch { @@ -95,19 +92,19 @@ final class RegexManager { } func matchesExist(_ pattern: String?, string: String) -> Bool { - guard let pattern = pattern else { + guard let pattern else { return false } do { let matches = try regexMatches(pattern, string: string) - return matches.count > 0 + return !matches.isEmpty } catch { return false } } func matchesEntirely(_ pattern: String?, string: String) -> Bool { - guard var pattern = pattern else { + guard var pattern else { return false } pattern = "^(\(pattern))$" @@ -115,16 +112,10 @@ final class RegexManager { } func matchedStringByRegex(_ pattern: String, string: String) throws -> [String] { - do { - let matches = try regexMatches(pattern, string: string) - var matchedStrings = [String]() - for match in matches { - let processedString = string.substring(with: match.range) - matchedStrings.append(processedString) - } - return matchedStrings - } catch {} - return [] + guard let matches = try? regexMatches(pattern, string: string) else { + return [] + } + return matches.map { string.substring(with: $0.range) } } // MARK: String and replace @@ -137,7 +128,12 @@ final class RegexManager { if matches.count == 1 { let range = regex.rangeOfFirstMatch(in: string) if range != nil { - replacementResult = regex.stringByReplacingMatches(in: string, options: [], range: range, withTemplate: template) + replacementResult = regex.stringByReplacingMatches( + in: string, + options: [], + range: range, + withTemplate: template + ) } return replacementResult } else if matches.count > 1 { @@ -154,7 +150,12 @@ final class RegexManager { let regex = try regexWithPattern(pattern) let range = regex.rangeOfFirstMatch(in: string) if range != nil { - return regex.stringByReplacingMatches(in: string, options: [], range: range, withTemplate: templateString) + return regex.stringByReplacingMatches( + in: string, + options: [], + range: range, + withTemplate: templateString + ) } return string } catch { @@ -164,7 +165,7 @@ final class RegexManager { func stringByReplacingOccurrences(_ string: String, map: [String: String], keepUnmapped: Bool = false) -> String { var targetString = String() - for i in 0 ..< string.count { + for i in 0.. Bool { if let valueString = value { - if valueString.trimmingCharacters(in: spaceCharacterSet).count == 0 { + if valueString.trimmingCharacters(in: spaceCharacterSet).isEmpty { return false } return true diff --git a/PhoneNumberKit/UI/CountryCodePickerOptions.swift b/PhoneNumberKit/UI/CountryCodePickerOptions.swift index 0f25f89d2..a2b4ac038 100644 --- a/PhoneNumberKit/UI/CountryCodePickerOptions.swift +++ b/PhoneNumberKit/UI/CountryCodePickerOptions.swift @@ -9,22 +9,19 @@ #if os(iOS) import UIKit -/** - CountryCodePickerOptions object - - Parameter backgroundColor: UIColor used for background - - Parameter separatorColor: UIColor used for the separator line between cells - - Parameter textLabelColor: UIColor for the TextLabel (Country code) - - Parameter textLabelFont: UIFont for the TextLabel (Country code) - - Parameter detailTextLabelColor: UIColor for the DetailTextLabel (Country name) - - Parameter detailTextLabelFont: UIFont for the DetailTextLabel (Country name) - - Parameter tintColor: Default TintColor used on the view - - Parameter cellBackgroundColor: UIColor for the cell background - - Parameter cellBackgroundColorSelection: UIColor for the cell selectedBackgroundView - */ +/// CountryCodePickerOptions object +/// - Parameter backgroundColor: UIColor used for background +/// - Parameter separatorColor: UIColor used for the separator line between cells +/// - Parameter textLabelColor: UIColor for the TextLabel (Country code) +/// - Parameter textLabelFont: UIFont for the TextLabel (Country code) +/// - Parameter detailTextLabelColor: UIColor for the DetailTextLabel (Country name) +/// - Parameter detailTextLabelFont: UIFont for the DetailTextLabel (Country name) +/// - Parameter tintColor: Default TintColor used on the view +/// - Parameter cellBackgroundColor: UIColor for the cell background +/// - Parameter cellBackgroundColorSelection: UIColor for the cell selectedBackgroundView public struct CountryCodePickerOptions { - public init() { } - + public init(backgroundColor: UIColor? = nil, separatorColor: UIColor? = nil, textLabelColor: UIColor? = nil, @@ -34,7 +31,6 @@ public struct CountryCodePickerOptions { tintColor: UIColor? = nil, cellBackgroundColor: UIColor? = nil, cellBackgroundColorSelection: UIColor? = nil) { - self.backgroundColor = backgroundColor self.separatorColor = separatorColor self.textLabelColor = textLabelColor @@ -49,7 +45,7 @@ public struct CountryCodePickerOptions { public var backgroundColor: UIColor? public var separatorColor: UIColor? public var textLabelColor: UIColor? - public var textLabelFont: UIFont? + public var textLabelFont: UIFont? public var detailTextLabelColor: UIColor? public var detailTextLabelFont: UIFont? public var tintColor: UIColor? diff --git a/PhoneNumberKit/UI/CountryCodePickerViewController.swift b/PhoneNumberKit/UI/CountryCodePickerViewController.swift index 501c8dca8..7a58c9f79 100644 --- a/PhoneNumberKit/UI/CountryCodePickerViewController.swift +++ b/PhoneNumberKit/UI/CountryCodePickerViewController.swift @@ -7,7 +7,6 @@ public protocol CountryCodePickerDelegate: AnyObject { } public class CountryCodePickerViewController: UITableViewController { - lazy var searchController: UISearchController = { let searchController = UISearchController(searchResultsController: nil) searchController.searchBar.placeholder = NSLocalizedString( @@ -19,7 +18,7 @@ public class CountryCodePickerViewController: UITableViewController { }() public let phoneNumberKit: PhoneNumberKit - + public let options: CountryCodePickerOptions let commonCountryCodes: [String] @@ -70,17 +69,14 @@ public class CountryCodePickerViewController: UITableViewController { lazy var cancelButton = UIBarButtonItem(barButtonSystemItem: .cancel, target: self, action: #selector(dismissAnimated)) - /** - Init with a phone number kit instance. Because a PhoneNumberKit initialization is expensive you can must pass a pre-initialized instance to avoid incurring perf penalties. - - - parameter phoneNumberKit: A PhoneNumberKit instance to be used by the text field. - - parameter commonCountryCodes: An array of country codes to display in the section below the current region section. defaults to `PhoneNumberKit.CountryCodePicker.commonCountryCodes` - */ + /// Init with a phone number kit instance. Because a PhoneNumberKit initialization is expensive you can must pass a pre-initialized instance to avoid incurring perf penalties. + /// + /// - parameter phoneNumberKit: A PhoneNumberKit instance to be used by the text field. + /// - parameter commonCountryCodes: An array of country codes to display in the section below the current region section. defaults to `PhoneNumberKit.CountryCodePicker.commonCountryCodes` public init( phoneNumberKit: PhoneNumberKit, options: CountryCodePickerOptions?, - commonCountryCodes: [String] = PhoneNumberKit.CountryCodePicker.commonCountryCodes) - { + commonCountryCodes: [String] = PhoneNumberKit.CountryCodePicker.commonCountryCodes) { self.phoneNumberKit = phoneNumberKit self.commonCountryCodes = commonCountryCodes self.options = options ?? CountryCodePickerOptions() @@ -123,18 +119,18 @@ public class CountryCodePickerViewController: UITableViewController { } } - public override func viewWillAppear(_ animated: Bool) { + override public func viewWillAppear(_ animated: Bool) { super.viewWillAppear(animated) if let nav = navigationController { shouldRestoreNavigationBarToHidden = nav.isNavigationBarHidden nav.setNavigationBarHidden(false, animated: true) } - if let nav = navigationController, nav.isBeingPresented && nav.viewControllers.count == 1 { + if let nav = navigationController, nav.isBeingPresented, nav.viewControllers.count == 1 { navigationItem.setRightBarButton(cancelButton, animated: true) } } - public override func viewWillDisappear(_ animated: Bool) { + override public func viewWillDisappear(_ animated: Bool) { super.viewWillDisappear(animated) navigationController?.setNavigationBarHidden(shouldRestoreNavigationBarToHidden, animated: true) } @@ -147,15 +143,15 @@ public class CountryCodePickerViewController: UITableViewController { isFiltering ? filteredCountries[indexPath.row] : countries[indexPath.section][indexPath.row] } - public override func numberOfSections(in tableView: UITableView) -> Int { + override public func numberOfSections(in tableView: UITableView) -> Int { isFiltering ? 1 : countries.count } - public override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { + override public func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { isFiltering ? filteredCountries.count : countries[section].count } - public override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { + override public func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { let cell = tableView.dequeueReusableCell(withIdentifier: Cell.reuseIdentifier, for: indexPath) let country = self.country(for: indexPath) @@ -192,7 +188,7 @@ public class CountryCodePickerViewController: UITableViewController { return cell } - public override func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? { + override public func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? { if isFiltering { return nil } else if section == 0, hasCurrent { @@ -205,7 +201,7 @@ public class CountryCodePickerViewController: UITableViewController { return countries[section].first?.name.first.map(String.init) } - public override func sectionIndexTitles(for tableView: UITableView) -> [String]? { + override public func sectionIndexTitles(for tableView: UITableView) -> [String]? { guard !isFiltering else { return nil } @@ -223,7 +219,7 @@ public class CountryCodePickerViewController: UITableViewController { } } - public override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { + override public func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { let country = self.country(for: indexPath) delegate?.countryCodePickerViewControllerDidPickCountry(country) tableView.deselectRow(at: indexPath, animated: true) @@ -231,7 +227,6 @@ public class CountryCodePickerViewController: UITableViewController { } extension CountryCodePickerViewController: UISearchResultsUpdating { - var isFiltering: Bool { searchController.isActive && !isSearchBarEmpty } @@ -251,11 +246,9 @@ extension CountryCodePickerViewController: UISearchResultsUpdating { } } - // MARK: Types public extension CountryCodePickerViewController { - struct Country { public var code: String public var flag: String @@ -287,13 +280,13 @@ public extension CountryCodePickerViewController { } class Cell: UITableViewCell { - static let reuseIdentifier = "Cell" override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) { super.init(style: .value2, reuseIdentifier: Self.reuseIdentifier) } + @available(*, unavailable) required init?(coder: NSCoder) { fatalError("init(coder:) has not been implemented") } diff --git a/PhoneNumberKit/UI/PhoneNumberTextField.swift b/PhoneNumberKit/UI/PhoneNumberTextField.swift index 8fdc0dd80..1fbe07ca3 100644 --- a/PhoneNumberKit/UI/PhoneNumberTextField.swift +++ b/PhoneNumberKit/UI/PhoneNumberTextField.swift @@ -18,7 +18,7 @@ open class PhoneNumberTextField: UITextField, UITextFieldDelegate { public lazy var flagButton = UIButton() /// Override setText so number will be automatically formatted when setting text by code - open override var text: String? { + override open var text: String? { set { if isPartialFormatterEnabled, let newValue = newValue { let formattedNumber = partialFormatter.formatPartial(newValue) @@ -132,7 +132,7 @@ open class PhoneNumberTextField: UITextField, UITextFieldDelegate { set { _withDefaultPickerUI = newValue } } - public var withDefaultPickerUIOptions: CountryCodePickerOptions = CountryCodePickerOptions() + public var withDefaultPickerUIOptions: CountryCodePickerOptions = .init() public var modalPresentationStyle: UIModalPresentationStyle? @@ -144,7 +144,7 @@ open class PhoneNumberTextField: UITextField, UITextFieldDelegate { } } - public private(set) lazy var partialFormatter: PartialFormatter = PartialFormatter( + public private(set) lazy var partialFormatter: PartialFormatter = .init( phoneNumberKit: phoneNumberKit, defaultRegion: defaultRegion, withPrefix: withPrefix, @@ -161,7 +161,7 @@ open class PhoneNumberTextField: UITextField, UITextFieldDelegate { private weak var _delegate: UITextFieldDelegate? - open override var delegate: UITextFieldDelegate? { + override open var delegate: UITextFieldDelegate? { get { return self._delegate } @@ -191,10 +191,8 @@ open class PhoneNumberTextField: UITextField, UITextFieldDelegate { } } - /** - Returns the current valid phone number. - - returns: PhoneNumber? - */ + /// Returns the current valid phone number. + /// - returns: PhoneNumber? public var phoneNumber: PhoneNumber? { guard let rawNumber = self.text else { return nil } do { @@ -204,75 +202,67 @@ open class PhoneNumberTextField: UITextField, UITextFieldDelegate { } } - open override func layoutSubviews() { + override open func layoutSubviews() { if self.withFlag { // update the width of the flagButton automatically, iOS <13 doesn't handle this for you let width = self.flagButton.systemLayoutSizeFitting(bounds.size).width self.flagButton.frame.size.width = width } super.layoutSubviews() } - + // MARK: - Insets + private var insets: UIEdgeInsets? private var clearButtonPadding: CGFloat? // MARK: Lifecycle - /** - Init with a phone number kit instance. Because a PhoneNumberKit initialization is expensive, - you can pass a pre-initialized instance to avoid incurring perf penalties. - - - parameter phoneNumberKit: A PhoneNumberKit instance to be used by the text field. - - - returns: UITextfield - */ + /// Init with a phone number kit instance. Because a PhoneNumberKit initialization is expensive, + /// you can pass a pre-initialized instance to avoid incurring perf penalties. + /// + /// - parameter phoneNumberKit: A PhoneNumberKit instance to be used by the text field. + /// + /// - returns: UITextfield public convenience init(withPhoneNumberKit phoneNumberKit: PhoneNumberKit) { self.init(frame: .zero, phoneNumberKit: phoneNumberKit) } - /** - Init with frame and phone number kit instance. - - - parameter frame: UITextfield frame - - parameter phoneNumberKit: A PhoneNumberKit instance to be used by the text field. - - - returns: UITextfield - */ + /// Init with frame and phone number kit instance. + /// + /// - parameter frame: UITextfield frame + /// - parameter phoneNumberKit: A PhoneNumberKit instance to be used by the text field. + /// + /// - returns: UITextfield public init(frame: CGRect, phoneNumberKit: PhoneNumberKit) { self.phoneNumberKit = phoneNumberKit super.init(frame: frame) self.setup() } - /** - Init with frame - - - parameter frame: UITextfield F - - - returns: UITextfield - */ - public override init(frame: CGRect) { + /// Init with frame + /// + /// - parameter frame: UITextfield F + /// + /// - returns: UITextfield + override public init(frame: CGRect) { self.phoneNumberKit = PhoneNumberKit() super.init(frame: frame) self.setup() } - - - /** - Initialize an instance with specific insets and clear button padding. - - This initializer creates an instance of the class with custom UIEdgeInsets and padding for the clear button. - Both of these parameters are used to customize the appearance of the text field and its clear button within the class. - - - Parameters: - - insets: The UIEdgeInsets to be applied to the text field's bounding rectangle. These insets define the padding - that is applied within the text field's bounding rectangle. A UIEdgeInsets value contains insets for - each of the four directions (top, bottom, left, right). Positive values move the content toward the center of the - text field, and negative values move the content toward the edges of the text field. - - clearButtonPadding: The padding to be applied to the clear button. This value defines the space between the clear - button and the edges of the text field. A positive value increases the distance between the clear button and the - text field's edges, and a negative value decreases this distance. - */ + + /// Initialize an instance with specific insets and clear button padding. + /// + /// This initializer creates an instance of the class with custom UIEdgeInsets and padding for the clear button. + /// Both of these parameters are used to customize the appearance of the text field and its clear button within the class. + /// + /// - Parameters: + /// - insets: The UIEdgeInsets to be applied to the text field's bounding rectangle. These insets define the padding + /// that is applied within the text field's bounding rectangle. A UIEdgeInsets value contains insets for + /// each of the four directions (top, bottom, left, right). Positive values move the content toward the center of the + /// text field, and negative values move the content toward the edges of the text field. + /// - clearButtonPadding: The padding to be applied to the clear button. This value defines the space between the clear + /// button and the edges of the text field. A positive value increases the distance between the clear button and the + /// text field's edges, and a negative value decreases this distance. public init(insets: UIEdgeInsets, clearButtonPadding: CGFloat) { self.phoneNumberKit = PhoneNumberKit() self.insets = insets @@ -281,13 +271,11 @@ open class PhoneNumberTextField: UITextField, UITextFieldDelegate { self.setup() } - /** - Init with coder - - - parameter aDecoder: decoder - - - returns: UITextfield - */ + /// Init with coder + /// + /// - parameter aDecoder: decoder + /// + /// - returns: UITextfield public required init(coder aDecoder: NSCoder) { self.phoneNumberKit = PhoneNumberKit() super.init(coder: aDecoder)! @@ -307,7 +295,7 @@ open class PhoneNumberTextField: UITextField, UITextFieldDelegate { open func updateFlag() { guard self.withFlag else { return } - + if let phoneNumber = phoneNumber, let regionCode = phoneNumber.regionID, regionCode != currentRegion, @@ -315,7 +303,7 @@ open class PhoneNumberTextField: UITextField, UITextFieldDelegate { _defaultRegion = regionCode partialFormatter.defaultRegion = regionCode } - + let flagBase = UnicodeScalar("🇦").value - UnicodeScalar("A").value let flag = self.currentRegion @@ -384,25 +372,22 @@ open class PhoneNumberTextField: UITextField, UITextFieldDelegate { /// containingViewController looks at the responder chain to find the view controller nearest to itself var containingViewController: UIViewController? { var responder: UIResponder? = self - while !(responder is UIViewController) && responder != nil { + while !(responder is UIViewController), responder != nil { responder = responder?.next } return (responder as? UIViewController) } - // MARK: Phone number formatting - /** - * To keep the cursor position, we find the character immediately after the cursor and count the number of times it repeats in the remaining string as this will remain constant in every kind of editing. - */ + /// To keep the cursor position, we find the character immediately after the cursor and count the number of times it repeats in the remaining string as this will remain constant in every kind of editing. - internal struct CursorPosition { + struct CursorPosition { let numberAfterCursor: String let repetitionCountFromEnd: Int } - internal func extractCursorPosition() -> CursorPosition? { + func extractCursorPosition() -> CursorPosition? { var repetitionCountFromEnd = 0 // Check that there is text in the UITextField guard let text = text, let selectedTextRange = selectedTextRange else { @@ -428,7 +413,7 @@ open class PhoneNumberTextField: UITextField, UITextFieldDelegate { } // Finds position of previous cursor in new formatted text - internal func selectionRangeForNumberReplacement(textField: UITextField, formattedText: String) -> NSRange? { + func selectionRangeForNumberReplacement(textField: UITextField, formattedText: String) -> NSRange? { let textAsNSString = formattedText as NSString var countFromEnd = 0 guard let cursorPosition = extractCursorPosition() else { @@ -461,9 +446,9 @@ open class PhoneNumberTextField: UITextField, UITextFieldDelegate { guard self.isPartialFormatterEnabled else { return true } - + // This allows for the case when a user autocompletes a phone number: - if range == NSRange(location: 0, length: 0) && string.isBlank { + if range == NSRange(location: 0, length: 0), string.isBlank { return true } @@ -495,8 +480,7 @@ open class PhoneNumberTextField: UITextField, UITextFieldDelegate { // we change the default region to be the one most recently typed // but only when the withFlag is true as to not confuse the user who don't see the flag - if withFlag == true - { + if withFlag == true { self._defaultRegion = self.currentRegion self.partialFormatter.defaultRegion = self.currentRegion self.updateFlag() @@ -531,7 +515,7 @@ open class PhoneNumberTextField: UITextField, UITextFieldDelegate { open func textFieldDidEndEditing(_ textField: UITextField, reason: UITextField.DidEndEditingReason) { updateTextFieldDidEndEditing(textField) if let _delegate = _delegate { - if (_delegate.responds(to: #selector(textFieldDidEndEditing(_:reason:)))) { + if _delegate.responds(to: #selector(textFieldDidEndEditing(_:reason:))) { _delegate.textFieldDidEndEditing?(textField, reason: reason) } else { _delegate.textFieldDidEndEditing?(textField) @@ -554,8 +538,8 @@ open class PhoneNumberTextField: UITextField, UITextFieldDelegate { private func updateTextFieldDidEndEditing(_ textField: UITextField) { if self.withExamplePlaceholder, self.withPrefix, let countryCode = phoneNumberKit.countryCode(for: currentRegion)?.description, - let text = textField.text, - text == internationalPrefix(for: countryCode) { + let text = textField.text, + text == internationalPrefix(for: countryCode) { textField.text = "" sendActions(for: .editingChanged) self.updateFlag() @@ -565,7 +549,6 @@ open class PhoneNumberTextField: UITextField, UITextFieldDelegate { } extension PhoneNumberTextField: CountryCodePickerDelegate { - public func countryCodePickerViewControllerDidPickCountry(_ country: CountryCodePickerViewController.Country) { text = isEditing ? "+" + country.prefix : "" _defaultRegion = country.code @@ -584,16 +567,15 @@ extension PhoneNumberTextField: CountryCodePickerDelegate { // MARK: - Insets extension PhoneNumberTextField { - - open override func textRect(forBounds bounds: CGRect) -> CGRect { + override open func textRect(forBounds bounds: CGRect) -> CGRect { if let insets = self.insets { return super.textRect(forBounds: bounds.inset(by: insets)) } else { return super.textRect(forBounds: bounds) } } - - open override func editingRect(forBounds bounds: CGRect) -> CGRect { + + override open func editingRect(forBounds bounds: CGRect) -> CGRect { if let insets = self.insets { return super.editingRect(forBounds: bounds .inset(by: insets)) @@ -601,8 +583,8 @@ extension PhoneNumberTextField { return super.editingRect(forBounds: bounds) } } - - open override func clearButtonRect(forBounds bounds: CGRect) -> CGRect { + + override open func clearButtonRect(forBounds bounds: CGRect) -> CGRect { if let insets = self.insets, let clearButtonPadding = self.clearButtonPadding { return super.clearButtonRect(forBounds: bounds.insetBy(dx: insets.left - clearButtonPadding, dy: 0)) @@ -612,11 +594,10 @@ extension PhoneNumberTextField { } } - extension String { - var isBlank: Bool { - return allSatisfy({ $0.isWhitespace }) - } + var isBlank: Bool { + return allSatisfy(\.isWhitespace) + } } #endif diff --git a/PhoneNumberKitTests/PartialFormatterTests.swift b/PhoneNumberKitTests/PartialFormatterTests.swift index 6b9e66c18..e68cbfaf5 100644 --- a/PhoneNumberKitTests/PartialFormatterTests.swift +++ b/PhoneNumberKitTests/PartialFormatterTests.swift @@ -326,64 +326,64 @@ final class PartialFormatterTests: XCTestCase { // +٩٧١٥٠٠٥٠٠٥٥٠ (+971500500550) func testAENumberWithHinduArabicNumerals() { - let partialFormatter = PartialFormatter(phoneNumberKit: phoneNumberKit, defaultRegion: "AE") - var testNumber = "+" - XCTAssertEqual(partialFormatter.formatPartial(testNumber), "+") - testNumber = "+٩" - XCTAssertEqual(partialFormatter.formatPartial(testNumber), "+9") - testNumber = "+٩٧" - XCTAssertEqual(partialFormatter.formatPartial(testNumber), "+9 7") - testNumber = "+٩٧١" - XCTAssertEqual(partialFormatter.formatPartial(testNumber), "+971") - testNumber = "+٩٧١٥" - XCTAssertEqual(partialFormatter.formatPartial(testNumber), "+971 5") - testNumber = "+٩٧١٥٠" - XCTAssertEqual(partialFormatter.formatPartial(testNumber), "+971 50") - testNumber = "+٩٧١٥٠٠" - XCTAssertEqual(partialFormatter.formatPartial(testNumber), "+971 50 0") - testNumber = "+٩٧١٥٠٠٥" - XCTAssertEqual(partialFormatter.formatPartial(testNumber), "+971 50 05") - testNumber = "+٩٧١٥٠٠٥٠" - XCTAssertEqual(partialFormatter.formatPartial(testNumber), "+971 50 050") - testNumber = "+٩٧١٥٠٠٥٠٠" - XCTAssertEqual(partialFormatter.formatPartial(testNumber), "+971 50 050 0") - testNumber = "+٩٧١٥٠٠٥٠٠٥" - XCTAssertEqual(partialFormatter.formatPartial(testNumber), "+971 50 050 05") - testNumber = "+٩٧١٥٠٠٥٠٠٥٥" - XCTAssertEqual(partialFormatter.formatPartial(testNumber), "+971 50 050 055") - testNumber = "+٩٧١٥٠٠٥٠٠٥٥٠" - XCTAssertEqual(partialFormatter.formatPartial(testNumber), "+971 50 050 0550") + let partialFormatter = PartialFormatter(phoneNumberKit: phoneNumberKit, defaultRegion: "AE") + var testNumber = "+" + XCTAssertEqual(partialFormatter.formatPartial(testNumber), "+") + testNumber = "+٩" + XCTAssertEqual(partialFormatter.formatPartial(testNumber), "+9") + testNumber = "+٩٧" + XCTAssertEqual(partialFormatter.formatPartial(testNumber), "+9 7") + testNumber = "+٩٧١" + XCTAssertEqual(partialFormatter.formatPartial(testNumber), "+971") + testNumber = "+٩٧١٥" + XCTAssertEqual(partialFormatter.formatPartial(testNumber), "+971 5") + testNumber = "+٩٧١٥٠" + XCTAssertEqual(partialFormatter.formatPartial(testNumber), "+971 50") + testNumber = "+٩٧١٥٠٠" + XCTAssertEqual(partialFormatter.formatPartial(testNumber), "+971 50 0") + testNumber = "+٩٧١٥٠٠٥" + XCTAssertEqual(partialFormatter.formatPartial(testNumber), "+971 50 05") + testNumber = "+٩٧١٥٠٠٥٠" + XCTAssertEqual(partialFormatter.formatPartial(testNumber), "+971 50 050") + testNumber = "+٩٧١٥٠٠٥٠٠" + XCTAssertEqual(partialFormatter.formatPartial(testNumber), "+971 50 050 0") + testNumber = "+٩٧١٥٠٠٥٠٠٥" + XCTAssertEqual(partialFormatter.formatPartial(testNumber), "+971 50 050 05") + testNumber = "+٩٧١٥٠٠٥٠٠٥٥" + XCTAssertEqual(partialFormatter.formatPartial(testNumber), "+971 50 050 055") + testNumber = "+٩٧١٥٠٠٥٠٠٥٥٠" + XCTAssertEqual(partialFormatter.formatPartial(testNumber), "+971 50 050 0550") } // +٩٧١5٠٠5٠٠55٠ (+971500500550) func testAENumberWithMixedHinduArabicNumerals() { - let partialFormatter = PartialFormatter(phoneNumberKit: phoneNumberKit, defaultRegion: "AE") - var testNumber = "+" - XCTAssertEqual(partialFormatter.formatPartial(testNumber), "+") - testNumber = "+٩" - XCTAssertEqual(partialFormatter.formatPartial(testNumber), "+9") - testNumber = "+٩٧" - XCTAssertEqual(partialFormatter.formatPartial(testNumber), "+9 7") - testNumber = "+٩٧١" - XCTAssertEqual(partialFormatter.formatPartial(testNumber), "+971") - testNumber = "+٩٧١5" - XCTAssertEqual(partialFormatter.formatPartial(testNumber), "+971 5") - testNumber = "+٩٧١5٠" - XCTAssertEqual(partialFormatter.formatPartial(testNumber), "+971 50") - testNumber = "+٩٧١5٠٠" - XCTAssertEqual(partialFormatter.formatPartial(testNumber), "+971 50 0") - testNumber = "+٩٧١5٠٠5" - XCTAssertEqual(partialFormatter.formatPartial(testNumber), "+971 50 05") - testNumber = "+٩٧١5٠٠5٠" - XCTAssertEqual(partialFormatter.formatPartial(testNumber), "+971 50 050") - testNumber = "+٩٧١5٠٠5٠٠" - XCTAssertEqual(partialFormatter.formatPartial(testNumber), "+971 50 050 0") - testNumber = "+٩٧١5٠٠5٠٠5" - XCTAssertEqual(partialFormatter.formatPartial(testNumber), "+971 50 050 05") - testNumber = "+٩٧١5٠٠5٠٠55" - XCTAssertEqual(partialFormatter.formatPartial(testNumber), "+971 50 050 055") - testNumber = "+٩٧١5٠٠5٠٠55٠" - XCTAssertEqual(partialFormatter.formatPartial(testNumber), "+971 50 050 0550") + let partialFormatter = PartialFormatter(phoneNumberKit: phoneNumberKit, defaultRegion: "AE") + var testNumber = "+" + XCTAssertEqual(partialFormatter.formatPartial(testNumber), "+") + testNumber = "+٩" + XCTAssertEqual(partialFormatter.formatPartial(testNumber), "+9") + testNumber = "+٩٧" + XCTAssertEqual(partialFormatter.formatPartial(testNumber), "+9 7") + testNumber = "+٩٧١" + XCTAssertEqual(partialFormatter.formatPartial(testNumber), "+971") + testNumber = "+٩٧١5" + XCTAssertEqual(partialFormatter.formatPartial(testNumber), "+971 5") + testNumber = "+٩٧١5٠" + XCTAssertEqual(partialFormatter.formatPartial(testNumber), "+971 50") + testNumber = "+٩٧١5٠٠" + XCTAssertEqual(partialFormatter.formatPartial(testNumber), "+971 50 0") + testNumber = "+٩٧١5٠٠5" + XCTAssertEqual(partialFormatter.formatPartial(testNumber), "+971 50 05") + testNumber = "+٩٧١5٠٠5٠" + XCTAssertEqual(partialFormatter.formatPartial(testNumber), "+971 50 050") + testNumber = "+٩٧١5٠٠5٠٠" + XCTAssertEqual(partialFormatter.formatPartial(testNumber), "+971 50 050 0") + testNumber = "+٩٧١5٠٠5٠٠5" + XCTAssertEqual(partialFormatter.formatPartial(testNumber), "+971 50 050 05") + testNumber = "+٩٧١5٠٠5٠٠55" + XCTAssertEqual(partialFormatter.formatPartial(testNumber), "+971 50 050 055") + testNumber = "+٩٧١5٠٠5٠٠55٠" + XCTAssertEqual(partialFormatter.formatPartial(testNumber), "+971 50 050 0550") } // +۹۷۱۵۰۰۵۰۰۵۵۰ (+971500500550) @@ -454,7 +454,7 @@ final class PartialFormatterTests: XCTestCase { let formatted = partialFormatter.formatPartial("+420777123456") XCTAssertEqual(formatted, "777 123 456") } - + // MARK: region prediction func testMinimalFrenchNumber() { @@ -508,7 +508,7 @@ final class PartialFormatterTests: XCTestCase { let testNumber = "8675309" XCTAssertEqual(partialFormatter.formatPartial(testNumber), "867-5309") } - + // *144 func testBrazilianOperatorService() { let partialFormatter = PartialFormatter(phoneNumberKit: phoneNumberKit, defaultRegion: "BR") @@ -521,7 +521,7 @@ final class PartialFormatterTests: XCTestCase { testNumber = "*144" XCTAssertEqual(partialFormatter.formatPartial(testNumber), "*144") } - + // *#06# func testImeiCodeRetrieval() { let partialFormatter = PartialFormatter(phoneNumberKit: phoneNumberKit, defaultRegion: "BR") @@ -536,7 +536,7 @@ final class PartialFormatterTests: XCTestCase { testNumber = "*#06#" XCTAssertEqual(partialFormatter.formatPartial(testNumber), "*#06#") } - + // *#*6# func testAsteriskShouldNotBeRejectedInTheMiddle() { let partialFormatter = PartialFormatter(phoneNumberKit: phoneNumberKit, defaultRegion: "BR") @@ -551,7 +551,7 @@ final class PartialFormatterTests: XCTestCase { testNumber = "*#*6#" XCTAssertEqual(partialFormatter.formatPartial(testNumber), "*#*6#") } - + // *#*6# func testPoundShouldNotBeRejectedInTheMiddle() { let partialFormatter = PartialFormatter(phoneNumberKit: phoneNumberKit, defaultRegion: "BR") @@ -566,9 +566,9 @@ final class PartialFormatterTests: XCTestCase { testNumber = "*#*6#" XCTAssertEqual(partialFormatter.formatPartial(testNumber), "*#*6#") } - + // Pauses and waits (http://allgaierconsulting.com/techtalk/2014/8/1/why-and-how-to-insert-a-pause-or-wait-key-on-your-iphone) - + // 650,9,2 func testPausedPhoneNumber() { let partialFormatter = PartialFormatter(phoneNumberKit: phoneNumberKit, defaultRegion: "US") @@ -587,7 +587,7 @@ final class PartialFormatterTests: XCTestCase { testNumber = "650,9,2" XCTAssertEqual(partialFormatter.formatPartial(testNumber), "650,9,2") } - + // 121;4 func testWaitPhoneNumber() { let partialFormatter = PartialFormatter(phoneNumberKit: phoneNumberKit, defaultRegion: "US") @@ -602,6 +602,5 @@ final class PartialFormatterTests: XCTestCase { testNumber = "121;4" XCTAssertEqual(partialFormatter.formatPartial(testNumber), "121;4") } - } #endif diff --git a/PhoneNumberKitTests/PhoneNumberKitParsingTests.swift b/PhoneNumberKitTests/PhoneNumberKitParsingTests.swift index f4dbefb53..fde0ce081 100644 --- a/PhoneNumberKitTests/PhoneNumberKitParsingTests.swift +++ b/PhoneNumberKitTests/PhoneNumberKitParsingTests.swift @@ -187,7 +187,7 @@ final class PhoneNumberKitParsingTests: XCTestCase { XCTAssertEqual(phoneNumber.type, type, "Expected type \(type) for number \(phoneNumber)") } } - } catch (let e) { + } catch let e { XCTFail("Failed to create PhoneNumber for \(exampleNumber): \(e)") } } @@ -279,7 +279,7 @@ final class PhoneNumberKitParsingTests: XCTestCase { let phoneNumberE164Format1 = self.phoneNumberKit.format(phoneNumber1, toType: .e164) XCTAssertEqual(phoneNumberE164Format1, "+971500500550") } - + func testPerformanceSimple() { let numberOfParses = 1000 let startTime = Date() @@ -294,7 +294,7 @@ final class PhoneNumberKitParsingTests: XCTestCase { print("time to parse \(numberOfParses) phone numbers, \(timeInterval) seconds") XCTAssertLessThan(timeInterval, 1) } - + func testPerformanceNonOptimizedSample() { let numberOfParses = 2000 let startTime = Date() @@ -307,7 +307,7 @@ final class PhoneNumberKitParsingTests: XCTestCase { print("time to parse \(numberOfParses) phone numbers, \(timeInterval) seconds") XCTAssertLessThan(timeInterval, 2) } - + func testPerformanceWithoutSupplyingDefaultRegion() { let numberOfParses = 2000 let startTime = Date() @@ -322,7 +322,7 @@ final class PhoneNumberKitParsingTests: XCTestCase { print("time to parse \(numberOfParses) phone numbers, \(timeInterval) seconds") XCTAssertLessThan(timeInterval, 2) } - + func testPerformanceNonOptimizedParsingUsageWithoutDefaultRegion() throws { let numberOfParses = 2000 let startTime = Date() @@ -361,7 +361,7 @@ final class PhoneNumberKitParsingTests: XCTestCase { XCTAssertTrue(phoneNumberNationalFormat1 == "050 188 7766") let phoneNumberE164Format1 = self.phoneNumberKit.format(phoneNumber1, toType: .e164) XCTAssertTrue(phoneNumberE164Format1 == "+380501887766") - + let phoneNumber2 = try phoneNumberKit.parse("050 188 7766", withRegion: "UA") XCTAssertNotNil(phoneNumber2) let phoneNumberInternationalFormat2 = self.phoneNumberKit.format(phoneNumber2, toType: .international) @@ -371,13 +371,13 @@ final class PhoneNumberKitParsingTests: XCTestCase { let phoneNumberE164Format2 = self.phoneNumberKit.format(phoneNumber2, toType: .e164) XCTAssertTrue(phoneNumberE164Format2 == "+380501887766") } - + func testExtensionWithCommaParsing() throws { let number = try phoneNumberKit.parse("+33 612-345-678,22") XCTAssertEqual(number.type, .mobile) XCTAssertEqual(number.numberExtension, "22") } - + func testExtensionWithSemiColonParsing() throws { let number = try phoneNumberKit.parse("+33 612-345-678;22") XCTAssertEqual(number.type, .mobile) @@ -389,7 +389,7 @@ final class PhoneNumberKitParsingTests: XCTestCase { let address = "+1 345 916 1234" try XCTAssertNotNil(phoneNumberKit.parse(address, withRegion: "JM")) } - + func testRegionCountryCodeConflict() { XCTAssertThrowsError(try phoneNumberKit.parse("212-2344", withRegion: "US")) { error in XCTAssertEqual(error as? PhoneNumberError, .invalidNumber) diff --git a/PhoneNumberKitTests/PhoneNumberKitTests.swift b/PhoneNumberKitTests/PhoneNumberKitTests.swift index 6f4993d72..e2272c840 100644 --- a/PhoneNumberKitTests/PhoneNumberKitTests.swift +++ b/PhoneNumberKitTests/PhoneNumberKitTests.swift @@ -30,7 +30,7 @@ final class PhoneNumberKitTests: XCTestCase { func testMetadataMainCountryFunction() { let countryName = self.phoneNumberKit.mainCountry(forCode: 1)! XCTAssertEqual(countryName, "US") - let invalidCountry = self.phoneNumberKit.mainCountry(forCode: 992322) + let invalidCountry = self.phoneNumberKit.mainCountry(forCode: 992_322) XCTAssertNil(invalidCountry) } @@ -55,7 +55,7 @@ final class PhoneNumberKitTests: XCTestCase { XCTFail() } } - + // Bool checker, GitHub issue #325 func testValidNumberBool() { XCTAssert(phoneNumberKit.isValidPhoneNumber("6297062979", withRegion: "IN")) @@ -159,7 +159,7 @@ final class PhoneNumberKitTests: XCTestCase { let phoneNumber = try phoneNumberKit.parse(testNumber) // XCTAssertEqual(phoneNumber.toInternational(), testNumber) XCTAssertEqual(phoneNumber.countryCode, 39) - XCTAssertEqual(phoneNumber.nationalNumber, 549555555) + XCTAssertEqual(phoneNumber.nationalNumber, 549_555_555) XCTAssertEqual(phoneNumber.leadingZero, true) } catch { XCTFail() @@ -173,7 +173,7 @@ final class PhoneNumberKitTests: XCTestCase { let phoneNumber = try phoneNumberKit.parse(testNumber) XCTAssertEqual(phoneNumber.countryCode, 33) XCTAssertEqual(phoneNumber.numberExtension, "84") - XCTAssertEqual(phoneNumber.nationalNumber, 689555555) + XCTAssertEqual(phoneNumber.nationalNumber, 689_555_555) XCTAssertEqual(phoneNumber.leadingZero, false) } catch { XCTFail() @@ -187,7 +187,7 @@ final class PhoneNumberKitTests: XCTestCase { let phoneNumber = try phoneNumberKit.parse(testNumber, withRegion: "US", ignoreType: false) XCTAssertEqual(phoneNumber.countryCode, 1) XCTAssertEqual(phoneNumber.numberExtension, "28") - XCTAssertEqual(phoneNumber.nationalNumber, 2129316760) + XCTAssertEqual(phoneNumber.nationalNumber, 2_129_316_760) XCTAssertEqual(phoneNumber.leadingZero, false) } catch { XCTFail() @@ -202,7 +202,7 @@ final class PhoneNumberKitTests: XCTestCase { XCTAssertEqual(self.phoneNumberKit.format(phoneNumber, toType: .e164), testNumber) XCTAssertEqual(self.phoneNumberKit.format(phoneNumber, toType: .international, withPrefix: false), "6 89 55 55 55") XCTAssertEqual(phoneNumber.countryCode, 33) - XCTAssertEqual(phoneNumber.nationalNumber, 689555555) + XCTAssertEqual(phoneNumber.nationalNumber, 689_555_555) XCTAssertEqual(phoneNumber.leadingZero, false) // XCTAssertEqual(phoneNumber.type, PhoneNumberType.mobile) } catch { @@ -217,7 +217,7 @@ final class PhoneNumberKitTests: XCTestCase { let phoneNumber = try phoneNumberKit.parse(testNumber) XCTAssertEqual(self.phoneNumberKit.format(phoneNumber, toType: .e164), "+81601555555") XCTAssertEqual(phoneNumber.countryCode, 81) - XCTAssertEqual(phoneNumber.nationalNumber, 601555555) + XCTAssertEqual(phoneNumber.nationalNumber, 601_555_555) XCTAssertEqual(phoneNumber.leadingZero, false) } catch { XCTFail() @@ -231,7 +231,7 @@ final class PhoneNumberKitTests: XCTestCase { let phoneNumber = try phoneNumberKit.parse(testNumber, withRegion: "US") XCTAssertEqual(self.phoneNumberKit.format(phoneNumber, toType: .e164), "+447739555555") XCTAssertEqual(phoneNumber.countryCode, 44) - XCTAssertEqual(phoneNumber.nationalNumber, 7739555555) + XCTAssertEqual(phoneNumber.nationalNumber, 7_739_555_555) XCTAssertEqual(phoneNumber.leadingZero, false) } catch { XCTFail() @@ -245,7 +245,7 @@ final class PhoneNumberKitTests: XCTestCase { let phoneNumber = try phoneNumberKit.parse(testNumber, withRegion: "US") XCTAssertEqual(self.phoneNumberKit.format(phoneNumber, toType: .e164), "+5511965555555") XCTAssertEqual(phoneNumber.countryCode, 55) - XCTAssertEqual(phoneNumber.nationalNumber, 11965555555) + XCTAssertEqual(phoneNumber.nationalNumber, 11_965_555_555) XCTAssertEqual(phoneNumber.leadingZero, false) } catch { XCTFail() @@ -259,7 +259,7 @@ final class PhoneNumberKitTests: XCTestCase { let phoneNumber = try phoneNumberKit.parse(testNumber, withRegion: "US") XCTAssertEqual(self.phoneNumberKit.format(phoneNumber, toType: .e164), "+12015555555") XCTAssertEqual(phoneNumber.countryCode, 1) - XCTAssertEqual(phoneNumber.nationalNumber, 2015555555) + XCTAssertEqual(phoneNumber.nationalNumber, 2_015_555_555) XCTAssertEqual(phoneNumber.leadingZero, false) } catch { XCTFail() @@ -273,20 +273,20 @@ final class PhoneNumberKitTests: XCTestCase { let phoneNumber = try phoneNumberKit.parse(testNumber, withRegion: "US") XCTAssertEqual(self.phoneNumberKit.format(phoneNumber, toType: .e164), "+15002555555") XCTAssertEqual(phoneNumber.countryCode, 1) - XCTAssertEqual(phoneNumber.nationalNumber, 5002555555) + XCTAssertEqual(phoneNumber.nationalNumber, 5_002_555_555) XCTAssertEqual(phoneNumber.leadingZero, false) } catch { XCTFail() } } - + func testValidAENumberWithHinduArabicNumerals() { let testNumber = "+٩٧١٥٠٠٥٠٠٥٥٠" do { let phoneNumber = try phoneNumberKit.parse(testNumber, withRegion: "AE") XCTAssertEqual(self.phoneNumberKit.format(phoneNumber, toType: .e164), "+971500500550") XCTAssertEqual(phoneNumber.countryCode, 971) - XCTAssertEqual(phoneNumber.nationalNumber, 500500550) + XCTAssertEqual(phoneNumber.nationalNumber, 500_500_550) XCTAssertEqual(phoneNumber.leadingZero, false) } catch { XCTFail() @@ -299,7 +299,7 @@ final class PhoneNumberKitTests: XCTestCase { let phoneNumber = try phoneNumberKit.parse(testNumber, withRegion: "AE") XCTAssertEqual(self.phoneNumberKit.format(phoneNumber, toType: .e164), "+971500500550") XCTAssertEqual(phoneNumber.countryCode, 971) - XCTAssertEqual(phoneNumber.nationalNumber, 500500550) + XCTAssertEqual(phoneNumber.nationalNumber, 500_500_550) XCTAssertEqual(phoneNumber.leadingZero, false) } catch { XCTFail() @@ -312,7 +312,7 @@ final class PhoneNumberKitTests: XCTestCase { let phoneNumber = try phoneNumberKit.parse(testNumber, withRegion: "AE") XCTAssertEqual(self.phoneNumberKit.format(phoneNumber, toType: .e164), "+971500500550") XCTAssertEqual(phoneNumber.countryCode, 971) - XCTAssertEqual(phoneNumber.nationalNumber, 500500550) + XCTAssertEqual(phoneNumber.nationalNumber, 500_500_550) XCTAssertEqual(phoneNumber.leadingZero, false) } catch { XCTFail() @@ -325,7 +325,7 @@ final class PhoneNumberKitTests: XCTestCase { let phoneNumber = try phoneNumberKit.parse(testNumber, withRegion: "AE") XCTAssertEqual(self.phoneNumberKit.format(phoneNumber, toType: .e164), "+971500500550") XCTAssertEqual(phoneNumber.countryCode, 971) - XCTAssertEqual(phoneNumber.nationalNumber, 500500550) + XCTAssertEqual(phoneNumber.nationalNumber, 500_500_550) XCTAssertEqual(phoneNumber.leadingZero, false) } catch { XCTFail() @@ -378,7 +378,7 @@ final class PhoneNumberKitTests: XCTestCase { // Test that metadata initiates correctly by checking all countries func testAllCountries() { let allCountries = self.phoneNumberKit.allCountries() - XCTAssert(allCountries.count > 0) + XCTAssert(!allCountries.isEmpty) } // Test code for country function - valid country @@ -399,7 +399,7 @@ final class PhoneNumberKitTests: XCTestCase { // Test countries for code function func testCountriesForCodeInvalid() { let phoneNumberKit = PhoneNumberKit() - XCTAssertEqual(phoneNumberKit.countries(withCode: 424242)?.count, nil) + XCTAssertEqual(phoneNumberKit.countries(withCode: 424_242)?.count, nil) } // Test region code for number function @@ -410,7 +410,7 @@ final class PhoneNumberKitTests: XCTestCase { } XCTAssertEqual(self.phoneNumberKit.getRegionCode(of: phoneNumber), "IT") } - + // In the case of multiple // countries sharing a calling code, the one // indicated with "isMainCountryForCode" in the metadata should be first. @@ -421,7 +421,7 @@ final class PhoneNumberKitTests: XCTestCase { } XCTAssertEqual(self.phoneNumberKit.getRegionCode(of: phoneNumber), "US") } - + // RU number with KZ country code func testValidRUNumberWithKZRegion() { let testNumber = "+7 916 195 55 58" @@ -429,14 +429,14 @@ final class PhoneNumberKitTests: XCTestCase { let phoneNumber = try phoneNumberKit.parse(testNumber, withRegion: "KZ") XCTAssertEqual(self.phoneNumberKit.format(phoneNumber, toType: .e164), "+79161955558") XCTAssertEqual(phoneNumber.countryCode, 7) - XCTAssertEqual(phoneNumber.nationalNumber, 9161955558) + XCTAssertEqual(phoneNumber.nationalNumber, 9_161_955_558) XCTAssertEqual(phoneNumber.leadingZero, false) XCTAssertEqual(phoneNumber.regionID, "RU") } catch { XCTFail() } } - + func testValidKZNumbersWithInternationalPrefix() { let numbers = ["+7 (777)110-85-31", "+77777056982", "+7(701)977-75-05"] numbers.forEach { XCTAssertTrue(phoneNumberKit.isValidPhoneNumber($0, withRegion: "KZ")) } @@ -457,24 +457,24 @@ final class PhoneNumberKitTests: XCTestCase { } } } - + func testValidCZNumbers() throws { let numbers = ["420734593819", "+420734593819", "734593819"] try numbers.forEach { let phoneNumber = try phoneNumberKit.parse($0, withRegion: "CZ") XCTAssertNotNil(phoneNumber) - + let formatted = phoneNumberKit.format(phoneNumber, toType: .e164) XCTAssertEqual(formatted, "+420734593819") } } - + func testValidDENumbers() throws { let numbers = ["491713369876", "+491713369876", "01713369876", "1713369876"] try numbers.forEach { let phoneNumber = try phoneNumberKit.parse($0, withRegion: "DE") XCTAssertNotNil(phoneNumber) - + let formatted = phoneNumberKit.format(phoneNumber, toType: .e164) XCTAssertEqual(formatted, "+491713369876") } diff --git a/examples/AsYouType/Sample/AppDelegate.swift b/examples/AsYouType/Sample/AppDelegate.swift index 9afc10c46..71e1620f2 100644 --- a/examples/AsYouType/Sample/AppDelegate.swift +++ b/examples/AsYouType/Sample/AppDelegate.swift @@ -8,7 +8,7 @@ import UIKit -@UIApplicationMain +@main class AppDelegate: UIResponder, UIApplicationDelegate { var window: UIWindow? diff --git a/examples/AsYouType/Sample/ViewController.swift b/examples/AsYouType/Sample/ViewController.swift index 6288b1d1d..547ff8e87 100644 --- a/examples/AsYouType/Sample/ViewController.swift +++ b/examples/AsYouType/Sample/ViewController.swift @@ -29,7 +29,7 @@ final class ViewController: UIViewController, CNContactPickerDelegate { self.withFlagSwitch.isOn = self.textField.withFlag self.withExamplePlaceholderSwitch.isOn = self.textField.withExamplePlaceholder self.withDefaultPickerUISwitch.isOn = self.textField.withDefaultPickerUI - + if #available(iOS 13.0, *) { self.view.backgroundColor = .systemBackground } diff --git a/examples/PhoneBook/Sample/AppDelegate.swift b/examples/PhoneBook/Sample/AppDelegate.swift index 9afc10c46..71e1620f2 100644 --- a/examples/PhoneBook/Sample/AppDelegate.swift +++ b/examples/PhoneBook/Sample/AppDelegate.swift @@ -8,7 +8,7 @@ import UIKit -@UIApplicationMain +@main class AppDelegate: UIResponder, UIApplicationDelegate { var window: UIWindow? diff --git a/examples/PhoneBook/Sample/ViewController.swift b/examples/PhoneBook/Sample/ViewController.swift index f5ad39cf2..9a8e481cf 100644 --- a/examples/PhoneBook/Sample/ViewController.swift +++ b/examples/PhoneBook/Sample/ViewController.swift @@ -23,7 +23,7 @@ class ViewController: UIViewController, CNContactPickerDelegate { override func viewDidLoad() { super.viewDidLoad() self.clearResults() - + if #available(iOS 13.0, *) { self.view.backgroundColor = .systemBackground }