CombineValidations
A package of Combine operators for validating objects, such as name, email, etc.  
This includes a stripped down fork of vapor/validation, check out their documentation for more examples.
Documentation
For full API documentation you can click here.
Installation
Just add as a package dependency to your Xcode Project or to your Package.swift.
// swift-tools-version:5.1
// The swift-tools-version declares the minimum version of Swift required to build this package.
import PackageDescription
let package = Package(
    name: "MyProject",
    platforms: [
        .macOS(.v10_15),
        .iOS(.v13)
    ],
    ...
    dependencies: [
        .package(url: "https://github.com/m-housh/CombineValidations.git", from: "0.1.0"),
    ],
    targets: [
        .target(
            name: "MyProject",
            dependencies: ["CombineValidations", ...]
        ),
        ...
    ]
)
Usage
Top Level Publishers
There are two top level publishers that can be used to validate objects.
ValidatedPublisher
The VaidatedPublisher passes validated output or nil to downstream subscribers.
_ = Publishers.ValidatedPublisher("foo-bar", !.empty && .count(3...))
    .replaceNil(with: "failed")
    .sink { print($0) }
// "foo-bar"   
_ = Publishers.ValidatedPublisher("foo-bar", !.empty && .count(3...))
    .replaceNil(with: "failed")
    .sink { print($0) }
// "failed"
TryValidatedPublisher
The TryVaidatedPublisher passes validated output or BasicValidationError to downstream subscribers.
_ = Publishers.TryValidatedPublisher("foo-bar", !.empty && .count(3...))
    .replaceError(with: "failed")
    .sink { print($0) }
// "foo-bar"   
_ = Publishers.TryValidatedPublisher("foo-bar", !.empty && .count(3...))
    .replaceError(with: "failed")
    .sink { print($0) }
// "failed"
Operators
There are also three operators that can be applied to existing publishers.
Validate
The Validate operator, passes validated objects or nil to downstream subscribers.
_ = Just("foo-bar")
    .validate { !.empty && .count(3...) }
    .replaceNil(with: "failed")
    .sink { print($0) }
// foo-bar
_ = Just("")
    .validate { !.empty && .count(3...) }
    .replaceNil(with: "failed")
    .sink { print($0) }
// failed
TryValidate
The TryValidate operator sends validated objects or BasicValidatiionError to downstream subscriibers.
_ = Just("foo-bar")
    .tryValidate { !.empty && .count(3...) }
    .replaceError(with: "failed")
    .sink { print($0) }
// foo-bar
_ = Just("")
    .tryValidate { !.empty && .count(3...) }
    .replaceError(with: "failed")
    .sink { print($0) }
// failed
CompactValidate
The CompactValidate operater sends validated non-nil objects to downstream subscribers.
_ = Just("foo-bar")
    .compactValidate { !.empty && .count(3...) }
    .sink { print($0) }
// foo-bar
_ = Just("foo")
    .compactValidate { !.empty && .count(3...) }
    .sink { print($0) }
// nothing get's printed or passed downstream.
Subjects
PassthroughValidatedSubject
A PassthroughValidatedSubject never fails and only sends values that pass validation
to downstream subscribers.
let subject = PassthroughValidatedSubject<String> {
    !.empty && .count(3...)
}
let cancellable = subject.sink { print($0) }
subject.send("foo-bar")
// foo-bar
subject.send("")
// does not get sent to downstreams.
Validatable Objects
All of the above also work with any type that implements the Validatable protocol.
class MyValidatable: Codable, Reflectable, Validatable {
    let name: String?
    init(_ name: String? = nil) {
        self.name = name
    }
    static func validations() throws -> Validations<MyValidatable> {
        var validations = Validations(MyValidatable.self)
        try validations.add(\.name, !.nil && !.empty && .count(3...))
        return validations
    }
}
// Top-Level works the same for `ValidatePublisher` or `TryValidatedPublisher`
_ = Publishers.ValidatedPublisher(MyValidatable("foo-bar"))
    .replaceNil(with: MyValidatable("failed"))
    .sink { print($0.name) }
// foo-bar
// Validate
_ = Just(MyValidatable())
    .validate()
    .replaceNil(with: MyValidator("failed"))
    .sink { print($0!.name) }
// failed
// TryValidate
_ = Just(MyValidatable("foo-bar"))
    .tryValidate()
    .replaceError(with: MyValidator("failed"))
    .sink { print($0!.name) }
// foo-bar
// Subject
let subject = PassthroughValidatedSubject(MyValidatable.self)
let cancellable = subject.sink { print($0.name) }
subject.send(MyValidatable())
// Not sent
subject.send(MyValidatable("foo-bar"))
// foo-bar
          
        Reference