diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml new file mode 100644 index 0000000..9f8f1df --- /dev/null +++ b/.github/FUNDING.yml @@ -0,0 +1,12 @@ +# These are supported funding model platforms + +github: reddavis +patreon: # Replace with a single Patreon username +open_collective: # Replace with a single Open Collective username +ko_fi: # Replace with a single Ko-fi username +tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel +community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry +liberapay: # Replace with a single Liberapay username +issuehunt: # Replace with a single IssueHunt username +otechie: # Replace with a single Otechie username +custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2'] diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..ec7327c --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,19 @@ +name: CI + +on: + push: + branches: [ main ] + pull_request: + branches: [ main ] + +jobs: + ios-latest: + name: Unit Test - iOS 15.2, Xcode 13.2 + runs-on: macOS-11 + env: + DEVELOPER_DIR: /Applications/Xcode_13.2.app/Contents/Developer + steps: + - uses: actions/checkout@v2 + - name: Run Tests + run: Scripts/test -d "OS=15.2,name=iPhone 13 Pro" + \ No newline at end of file diff --git a/.github/workflows/swiftlint.yml b/.github/workflows/swiftlint.yml new file mode 100644 index 0000000..32d318b --- /dev/null +++ b/.github/workflows/swiftlint.yml @@ -0,0 +1,20 @@ +name: SwiftLint + +on: + pull_request: + paths: + - '.github/workflows/swiftlint.yml' + - '.swiftlint.yml' + - '**/*.swift' + +jobs: + SwiftLint: + runs-on: ubuntu-latest + steps: + - name: Swiftlint + uses: norio-nomura/action-swiftlint@3.2.1 + with: + args: --strict + env: + WORKING_DIRECTORY: Validate + DIFF_BASE: ${{ github.base_ref }} \ No newline at end of file diff --git a/.swiftlint.yml b/.swiftlint.yml new file mode 100644 index 0000000..67342e6 --- /dev/null +++ b/.swiftlint.yml @@ -0,0 +1,34 @@ +only_rules: + - closure_spacing + - colon + - empty_count + - fatal_error_message + - force_cast + - force_try + - force_unwrapping + - implicitly_unwrapped_optional + - legacy_cggeometry_functions + - legacy_constant + - legacy_constructor + - legacy_nsgeometry_functions + - operator_usage_whitespace + - redundant_string_enum_value + - return_arrow_whitespace + - trailing_newline + - type_name + - unused_optional_binding + - vertical_whitespace + - void_return + - custom_rules + +custom_rules: + no_direct_standard_out_logs: + name: "Writing log messages directly to standard out is disallowed" + regex: "(\\bprint|\\bdebugPrint|\\bdump|Swift\\.print|Swift\\.debugPrint|Swift\\.dump)\\s*\\(" + match_kinds: + - identifier + message: "Don't commit `print(…)`, `debugPrint(…)`, or `dump(…)` as they write to standard out in release. Either log to a dedicated logging system or silence this warning in debug-only scenarios explicitly using `// swiftlint:disable:next no_direct_standard_out_logs`" + severity: error + +vertical_whitespace: + max_empty_lines: 4 diff --git a/README.md b/README.md index a017428..35ad4c2 100644 --- a/README.md +++ b/README.md @@ -23,10 +23,6 @@ dependencies: [ ] ``` -## Note - -Worth noting Validate is still in very early days and API's are expected to change. Saying that, [SEMVER](https://semver.org) will be kept. - ## Documentation [API Reference](https://swift-validate.netlify.app) @@ -38,8 +34,7 @@ import SwiftUI import Validate -struct ContentView: View -{ +struct ContentView: View { @Validate(.presence()) var name: String = "" var body: some View { @@ -82,8 +77,7 @@ You're not just limited to using the built in validations but can build your own This is how the built in presence validation is built: ```swift -public extension Validation -{ +public extension Validation { /// Validate an optional value is present. /// /// If the value is nil, it is considered invalid. @@ -92,11 +86,9 @@ public extension Validation /// - Returns: A Validation instance. static func presence( message: String? = nil - ) -> Validation> - { + ) -> Validation> { .init { value in - if value == nil - { + if value == nil { throw ValidationError.build(message: message) } } diff --git a/Validate.xcodeproj/project.pbxproj b/Validate.xcodeproj/project.pbxproj index cf0ec9b..a3e6756 100644 --- a/Validate.xcodeproj/project.pbxproj +++ b/Validate.xcodeproj/project.pbxproj @@ -32,13 +32,6 @@ /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ - A4AD9E002714873F007890AD /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = A4AD9DEB2714873F007890AD /* Project object */; - proxyType = 1; - remoteGlobalIDString = A4AD9DF32714873F007890AD; - remoteInfo = Validate; - }; A4AD9E3F27186975007890AD /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = A4AD9DEB2714873F007890AD /* Project object */; @@ -273,7 +266,6 @@ buildRules = ( ); dependencies = ( - A4AD9E012714873F007890AD /* PBXTargetDependency */, ); name = ValidateTests; productName = ValidateTests; @@ -407,11 +399,6 @@ /* End PBXSourcesBuildPhase section */ /* Begin PBXTargetDependency section */ - A4AD9E012714873F007890AD /* PBXTargetDependency */ = { - isa = PBXTargetDependency; - target = A4AD9DF32714873F007890AD /* Validate */; - targetProxy = A4AD9E002714873F007890AD /* PBXContainerItemProxy */; - }; A4AD9E4027186975007890AD /* PBXTargetDependency */ = { isa = PBXTargetDependency; target = A4AD9DF32714873F007890AD /* Validate */; @@ -545,10 +532,10 @@ A4AD9E092714873F007890AD /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { - CODE_SIGN_STYLE = Automatic; + CODE_SIGN_STYLE = Manual; CURRENT_PROJECT_VERSION = 1; DEFINES_MODULE = YES; - DEVELOPMENT_TEAM = CF43K35J9C; + DEVELOPMENT_TEAM = ""; DYLIB_COMPATIBILITY_VERSION = 1; DYLIB_CURRENT_VERSION = 1; DYLIB_INSTALL_NAME_BASE = "@rpath"; @@ -563,7 +550,11 @@ MARKETING_VERSION = 1.0; PRODUCT_BUNDLE_IDENTIFIER = com.reddavis.Validate; PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; + PROVISIONING_PROFILE_SPECIFIER = ""; + "PROVISIONING_PROFILE_SPECIFIER[sdk=macosx*]" = ""; + SDKROOT = ""; SKIP_INSTALL = YES; + SUPPORTED_PLATFORMS = "iphonesimulator iphoneos watchsimulator watchos macosx appletvsimulator appletvos"; SWIFT_EMIT_LOC_STRINGS = YES; SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = "1,2"; @@ -573,10 +564,10 @@ A4AD9E0A2714873F007890AD /* Release */ = { isa = XCBuildConfiguration; buildSettings = { - CODE_SIGN_STYLE = Automatic; + CODE_SIGN_STYLE = Manual; CURRENT_PROJECT_VERSION = 1; DEFINES_MODULE = YES; - DEVELOPMENT_TEAM = CF43K35J9C; + DEVELOPMENT_TEAM = ""; DYLIB_COMPATIBILITY_VERSION = 1; DYLIB_CURRENT_VERSION = 1; DYLIB_INSTALL_NAME_BASE = "@rpath"; @@ -591,7 +582,11 @@ MARKETING_VERSION = 1.0; PRODUCT_BUNDLE_IDENTIFIER = com.reddavis.Validate; PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; + PROVISIONING_PROFILE_SPECIFIER = ""; + "PROVISIONING_PROFILE_SPECIFIER[sdk=macosx*]" = ""; + SDKROOT = ""; SKIP_INSTALL = YES; + SUPPORTED_PLATFORMS = "iphonesimulator iphoneos watchsimulator watchos macosx appletvsimulator appletvos"; SWIFT_EMIT_LOC_STRINGS = YES; SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = "1,2"; @@ -601,10 +596,12 @@ A4AD9E0C2714873F007890AD /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { + ALLOW_TARGET_PLATFORM_SPECIALIZATION = YES; ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; + CODE_SIGN_IDENTITY = "-"; CODE_SIGN_STYLE = Automatic; CURRENT_PROJECT_VERSION = 1; - DEVELOPMENT_TEAM = CF43K35J9C; + DEVELOPMENT_TEAM = ""; GENERATE_INFOPLIST_FILE = YES; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", @@ -614,6 +611,11 @@ MARKETING_VERSION = 1.0; PRODUCT_BUNDLE_IDENTIFIER = com.reddavis.ValidateTests; PRODUCT_NAME = "$(TARGET_NAME)"; + PROVISIONING_PROFILE_SPECIFIER = ""; + "PROVISIONING_PROFILE_SPECIFIER[sdk=macosx*]" = ""; + SDKROOT = ""; + SUPPORTED_PLATFORMS = "watchsimulator watchos macosx iphonesimulator iphoneos appletvsimulator appletvos"; + SUPPORTS_MACCATALYST = NO; SWIFT_EMIT_LOC_STRINGS = NO; SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = "1,2"; @@ -623,10 +625,12 @@ A4AD9E0D2714873F007890AD /* Release */ = { isa = XCBuildConfiguration; buildSettings = { + ALLOW_TARGET_PLATFORM_SPECIALIZATION = YES; ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; + CODE_SIGN_IDENTITY = "-"; CODE_SIGN_STYLE = Automatic; CURRENT_PROJECT_VERSION = 1; - DEVELOPMENT_TEAM = CF43K35J9C; + DEVELOPMENT_TEAM = ""; GENERATE_INFOPLIST_FILE = YES; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", @@ -636,6 +640,11 @@ MARKETING_VERSION = 1.0; PRODUCT_BUNDLE_IDENTIFIER = com.reddavis.ValidateTests; PRODUCT_NAME = "$(TARGET_NAME)"; + PROVISIONING_PROFILE_SPECIFIER = ""; + "PROVISIONING_PROFILE_SPECIFIER[sdk=macosx*]" = ""; + SDKROOT = ""; + SUPPORTED_PLATFORMS = "watchsimulator watchos macosx iphonesimulator iphoneos appletvsimulator appletvos"; + SUPPORTS_MACCATALYST = NO; SWIFT_EMIT_LOC_STRINGS = NO; SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = "1,2"; diff --git a/Validate.xcodeproj/xcshareddata/xcschemes/Validate.xcscheme b/Validate.xcodeproj/xcshareddata/xcschemes/Validate.xcscheme new file mode 100644 index 0000000..ff9bc11 --- /dev/null +++ b/Validate.xcodeproj/xcshareddata/xcschemes/Validate.xcscheme @@ -0,0 +1,78 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Validate/Source/Extensions/NSRegularExpression+Extension.swift b/Validate/Source/Extensions/NSRegularExpression+Extension.swift index 09911df..2717371 100644 --- a/Validate/Source/Extensions/NSRegularExpression+Extension.swift +++ b/Validate/Source/Extensions/NSRegularExpression+Extension.swift @@ -1,26 +1,20 @@ import Foundation -extension NSRegularExpression -{ +extension NSRegularExpression { // MARK: Initialization - convenience init(_ pattern: String, options: NSRegularExpression.Options) - { - do - { + convenience init(_ pattern: String, options: NSRegularExpression.Options) { + do { try self.init(pattern: pattern, options: options) - } - catch - { + } catch { preconditionFailure("Invalid regex pattern: \(pattern)") } } // MARK: Matches - func matches(_ value: String) -> Bool - { + func matches(_ value: String) -> Bool { let range = NSRange(location: 0, length: value.utf16.count) return self.firstMatch(in: value, options: [], range: range) != nil } diff --git a/Validate/Source/Extensions/Sequence+Extension.swift b/Validate/Source/Extensions/Sequence+Extension.swift index cbc80c8..dcb8c02 100644 --- a/Validate/Source/Extensions/Sequence+Extension.swift +++ b/Validate/Source/Extensions/Sequence+Extension.swift @@ -1,9 +1,8 @@ import Foundation -public extension Sequence where Element: Error -{ - var localizedDescriptions: [String] { +extension Sequence where Element: Error { + public var localizedDescriptions: [String] { self.map { $0.localizedDescription } } } diff --git a/Validate/Source/Validate.swift b/Validate/Source/Validate.swift index 4af0ddc..941d71e 100644 --- a/Validate/Source/Validate.swift +++ b/Validate/Source/Validate.swift @@ -16,8 +16,7 @@ import SwiftUI /// If the included validations don't quite do what is required, new validations /// can be built with the `Validation` struct. @propertyWrapper -public struct Validate: DynamicProperty -{ +public struct Validate: DynamicProperty { /// The wrapped value public var wrappedValue: Value { get { self.validator.value } @@ -53,8 +52,7 @@ public struct Validate: DynamicProperty public init( wrappedValue: Value, _ validations: Validation... - ) - { + ) { self.init(wrappedValue: wrappedValue, validations: validations) } @@ -65,16 +63,14 @@ public struct Validate: DynamicProperty public init( wrappedValue: Value, _ validations: Validation... - ) where Value == Optional - { + ) where Value == Optional { self.init(wrappedValue: wrappedValue, validations: validations) } init( wrappedValue: Value, validations: [Validation] - ) - { + ) { self._validator = ObservedObject( wrappedValue: Validator( value: wrappedValue, @@ -83,3 +79,11 @@ public struct Validate: DynamicProperty ) } } + +// MARK: Equatable + +extension Validate: Equatable where Value: Equatable { + public static func ==(lhs: Validate, rhs: Validate) -> Bool { + lhs.wrappedValue == rhs.wrappedValue + } +} diff --git a/Validate/Source/Validation.swift b/Validate/Source/Validation.swift index 006acb3..1d325b7 100644 --- a/Validate/Source/Validation.swift +++ b/Validate/Source/Validation.swift @@ -2,8 +2,7 @@ import Foundation /// A struct for encapsulating validations. -public struct Validation -{ +public struct Validation { public typealias Validate = (_ value: Value) throws -> Void public let validate: Validate @@ -11,8 +10,7 @@ public struct Validation /// Initialize a new `Validation` instance. /// - Parameter validate: A `Validation.Validate` closure. - public init(_ validate: @escaping Validate) - { + public init(_ validate: @escaping Validate) { self.validate = validate } } diff --git a/Validate/Source/ValidationError.swift b/Validate/Source/ValidationError.swift index d2e53d3..8a6fe47 100644 --- a/Validate/Source/ValidationError.swift +++ b/Validate/Source/ValidationError.swift @@ -2,8 +2,7 @@ import Foundation /// Describes a validation error. -public struct ValidationError: LocalizedError -{ +public struct ValidationError: LocalizedError { /// A localized message describing what error occurred. public var errorDescription: String? { self.description } @@ -14,8 +13,7 @@ public struct ValidationError: LocalizedError /// Initialize a new `ValidationError` instance. /// - Parameter description: The description of the error. - public init(description: String) - { + public init(description: String) { self.description = description } } diff --git a/Validate/Source/Validations/Count.swift b/Validate/Source/Validations/Count.swift index a218ca1..3336c64 100644 --- a/Validate/Source/Validations/Count.swift +++ b/Validate/Source/Validations/Count.swift @@ -3,8 +3,7 @@ import Foundation // MARK: Greater than -public extension Validation -{ +public extension Validation { typealias CountGreaterThanErrorMessageBuilder = (_ minimum: Int) -> String /// Validate a collection's count is greater than a minimum amount. @@ -15,11 +14,9 @@ public extension Validation static func count( greaterThan minimum: Int, message: CountGreaterThanErrorMessageBuilder? = nil - ) -> Validation - { + ) -> Validation { .init { value in - guard value.count > minimum else - { + guard value.count > minimum else { throw ValidationError.buildGreaterThan( minimum: minimum, message: message @@ -38,12 +35,10 @@ public extension Validation static func count( greaterThan minimum: Int, message: CountGreaterThanErrorMessageBuilder? = nil - ) -> Validation> - { + ) -> Validation> { .init { value in guard let value = value, - value.count > minimum else - { + value.count > minimum else { throw ValidationError.buildGreaterThan( minimum: minimum, message: message @@ -56,10 +51,8 @@ public extension Validation // MARK: Greater than error -extension ValidationError -{ - private static func greaterThan(minimum: Int) -> ValidationError - { +extension ValidationError { + private static func greaterThan(minimum: Int) -> ValidationError { .init(description: "Should be greater than \(minimum)") } @@ -68,10 +61,8 @@ extension ValidationError fileprivate static func buildGreaterThan( minimum: Int, message: Validation.CountGreaterThanErrorMessageBuilder? - ) -> ValidationError - { - guard let message = message else - { + ) -> ValidationError { + guard let message = message else { return ValidationError.greaterThan(minimum: minimum) } @@ -83,8 +74,7 @@ extension ValidationError // MARK: Less than -public extension Validation -{ +public extension Validation { typealias CountLessThanErrorMessageBuilder = (_ maximum: Int) -> String /// Validate a collection's count is less than a maximum amount. @@ -95,11 +85,9 @@ public extension Validation static func count( lessThan maximum: Int, message: CountLessThanErrorMessageBuilder? = nil - ) -> Validation - { + ) -> Validation { .init { value in - guard value.count < maximum else - { + guard value.count < maximum else { throw ValidationError.buildLessThan( maximum: maximum, message: message @@ -118,12 +106,10 @@ public extension Validation static func count( lessThan maximum: Int, message: CountLessThanErrorMessageBuilder? = nil - ) -> Validation> - { + ) -> Validation> { .init { value in guard let value = value, - value.count < maximum else - { + value.count < maximum else { throw ValidationError.buildLessThan( maximum: maximum, message: message @@ -136,10 +122,8 @@ public extension Validation // MARK: Less than error -extension ValidationError -{ - private static func lessThan(maximum: Int) -> ValidationError - { +extension ValidationError { + private static func lessThan(maximum: Int) -> ValidationError { .init(description: "Should be less than \(maximum)") } @@ -148,10 +132,8 @@ extension ValidationError fileprivate static func buildLessThan( maximum: Int, message: Validation.CountLessThanErrorMessageBuilder? - ) -> ValidationError - { - guard let message = message else - { + ) -> ValidationError { + guard let message = message else { return ValidationError.lessThan(maximum: maximum) } @@ -163,8 +145,7 @@ extension ValidationError // MARK: Equal to -public extension Validation -{ +public extension Validation { typealias CountEqualToErrorMessageBuilder = (_ value: Int) -> String /// Validate a collection's count is equal to an amount. @@ -175,11 +156,9 @@ public extension Validation static func count( equalTo count: Int, message: CountEqualToErrorMessageBuilder? = nil - ) -> Validation - { + ) -> Validation { .init { value in - guard value.count == count else - { + guard value.count == count else { throw ValidationError.buildEqualTo( value: count, message: message @@ -198,12 +177,11 @@ public extension Validation static func count( equalTo count: Int, message: CountEqualToErrorMessageBuilder? = nil - ) -> Validation> - { + ) -> Validation> { .init { value in - guard let value = value, - value.count == count else - { + guard + let value = value, + value.count == count else { throw ValidationError.buildEqualTo( value: count, message: message @@ -216,10 +194,8 @@ public extension Validation // MARK: Equal to error -extension ValidationError -{ - private static func equalTo(value: Int) -> ValidationError - { +extension ValidationError { + private static func equalTo(value: Int) -> ValidationError { .init(description: "Should be equal to \(value)") } @@ -228,10 +204,8 @@ extension ValidationError fileprivate static func buildEqualTo( value: Int, message: Validation.CountEqualToErrorMessageBuilder? - ) -> ValidationError - { - guard let message = message else - { + ) -> ValidationError { + guard let message = message else { return ValidationError.equalTo(value: value) } @@ -242,8 +216,7 @@ extension ValidationError // MARK: In -public extension Validation -{ +public extension Validation { typealias CountRangeErrorMessageBuilder = (_ range: ClosedRange) -> String /// Validate a collection's count is in a range. @@ -254,11 +227,9 @@ public extension Validation static func count( in range: ClosedRange, message: CountRangeErrorMessageBuilder? = nil - ) -> Validation - { + ) -> Validation { .init { value in - guard range.contains(value.count) else - { + guard range.contains(value.count) else { throw ValidationError.buildRange( range: range, message: message @@ -277,12 +248,10 @@ public extension Validation static func count( in range: ClosedRange, message: CountRangeErrorMessageBuilder? = nil - ) -> Validation> - { + ) -> Validation> { .init { value in guard let value = value, - range.contains(value.count) else - { + range.contains(value.count) else { throw ValidationError.buildRange( range: range, message: message @@ -296,10 +265,8 @@ public extension Validation // MARK: Error -extension ValidationError -{ - private static func range(range: ClosedRange) -> ValidationError - { +extension ValidationError { + private static func range(range: ClosedRange) -> ValidationError { .init(description: "Should be between \(range.lowerBound) and \(range.upperBound)") } @@ -308,10 +275,8 @@ extension ValidationError fileprivate static func buildRange( range: ClosedRange, message: Validation.CountRangeErrorMessageBuilder? - ) -> ValidationError - { - guard let message = message else - { + ) -> ValidationError { + guard let message = message else { return ValidationError.range(range: range) } diff --git a/Validate/Source/Validations/Format.swift b/Validate/Source/Validations/Format.swift index 81e50d1..50c7098 100644 --- a/Validate/Source/Validations/Format.swift +++ b/Validate/Source/Validations/Format.swift @@ -1,8 +1,7 @@ import Foundation -public extension Validation -{ +public extension Validation { /// Validate a string matches a regular expression. /// - Parameters: /// - pattern: The regular expression pattern. @@ -14,8 +13,7 @@ public extension Validation _ pattern: String, options: NSRegularExpression.Options = [], message: String? = nil - ) -> Validation - { + ) -> Validation { .init { value in let regex = NSRegularExpression(pattern, options: options) guard !regex.matches(value) else { return } @@ -35,11 +33,9 @@ public extension Validation _ pattern: String, options: NSRegularExpression.Options = [], message: String? = nil - ) -> Validation> - { + ) -> Validation> { .init { value in - guard let value = value else - { + guard let value = value else { throw ValidationError.build(message: message) } @@ -55,19 +51,15 @@ public extension Validation // MARK: Error -extension ValidationError -{ - private static func format() -> ValidationError - { +extension ValidationError { + private static func format() -> ValidationError { .init(description: "Is incorrectly formatted") } // MARK: Builder - fileprivate static func build(message: String?) -> ValidationError - { - guard let message = message else - { + fileprivate static func build(message: String?) -> ValidationError { + guard let message = message else { return ValidationError.format() } diff --git a/Validate/Source/Validations/Presence.swift b/Validate/Source/Validations/Presence.swift index 6765297..9a4a6c2 100644 --- a/Validate/Source/Validations/Presence.swift +++ b/Validate/Source/Validations/Presence.swift @@ -1,8 +1,7 @@ import Foundation -public extension Validation -{ +public extension Validation { /// Validate an optional value is present. /// /// If the value is nil, it is considered invalid. @@ -11,11 +10,9 @@ public extension Validation /// - Returns: A Validation instance. static func presence( message: String? = nil - ) -> Validation> - { + ) -> Validation> { .init { value in - if value == nil - { + if value == nil { throw ValidationError.build(message: message) } } @@ -34,16 +31,13 @@ public extension Validation static func presence( allowEmpty: Bool = false, message: String? = nil - ) -> Validation> - { + ) -> Validation> { .init { value in - guard let value = value else - { + guard let value = value else { throw ValidationError.build(message: message) } - if value.isEmpty && !allowEmpty - { + if value.isEmpty && !allowEmpty { throw ValidationError.build(message: message) } } @@ -58,11 +52,9 @@ public extension Validation /// - Returns: A Validation instance. static func presence( message: String? = nil - ) -> Validation - { + ) -> Validation { .init { value in - if value.isEmpty - { + if value.isEmpty { throw ValidationError.build(message: message) } } @@ -73,19 +65,15 @@ public extension Validation // MARK: Error -extension ValidationError -{ - private static func presence() -> ValidationError - { +extension ValidationError { + private static func presence() -> ValidationError { .init(description: "Can't be blank") } // MARK: Builder - fileprivate static func build(message: String?) -> ValidationError - { - guard let message = message else - { + fileprivate static func build(message: String?) -> ValidationError { + guard let message = message else { return ValidationError.presence() } diff --git a/Validate/Source/Validator.swift b/Validate/Source/Validator.swift index 6f5258b..100c2c1 100644 --- a/Validate/Source/Validator.swift +++ b/Validate/Source/Validator.swift @@ -1,8 +1,7 @@ import SwiftUI -final class Validator: ObservableObject -{ +final class Validator: ObservableObject { var value: Value { didSet { self.validate() @@ -18,8 +17,7 @@ final class Validator: ObservableObject // MARK: Initialization - init(value: Value, validations: [Validation]) - { + init(value: Value, validations: [Validation]) { self.value = value self.validations = validations self.validate() @@ -27,16 +25,12 @@ final class Validator: ObservableObject // Validate - private func validate() - { + private func validate() { self.errors = self.validations.compactMap { validation in - do - { + do { try validation.validate(self.value) return nil - } - catch - { + } catch { return error } } diff --git a/scripts/test b/scripts/test new file mode 100755 index 0000000..116e92d --- /dev/null +++ b/scripts/test @@ -0,0 +1,23 @@ +#!/bin/sh +## HT to Nuke! - https://github.com/kean/Nuke + +set -eo pipefail + +scheme="Validate" + +while getopts "s:d:" opt; do + case $opt in + s) scheme=${OPTARG};; + d) destination=$OPTARG;; + esac +done +shift $((OPTIND -1)) + +echo "scheme = ${scheme}" +echo "destinations = ${destination}" + +xcodebuild -version +xcodebuild build-for-testing -scheme "$scheme" -destination "$destination" + +echo "\nRunning tests for destination: $destination" +xcodebuild test-without-building -scheme "$scheme" -destination "$destination"