diff --git a/.circleci/config.yml b/.circleci/config.yml new file mode 100644 index 0000000..3f2ffdb --- /dev/null +++ b/.circleci/config.yml @@ -0,0 +1,39 @@ +version: 2 + +jobs: + build: + macos: + xcode: "9.4.0" + + steps: + - checkout + + - run: + name: Mac Info + command: system_profiler SPSoftwareDataType + + - run: + name: Simulator Info + command: instruments -s devices + + - run: + name: Check out dependencies + command: swift package update + + - run: + name: Run iOS tests + command: make test-ios + environment: + SNAPSHOT_ARTIFACTS: $CIRCLE_ARTIFACTS + + - run: + name: Run macOS tests + command: make test-macos + environment: + SNAPSHOT_ARTIFACTS: $CIRCLE_ARTIFACTS + + - run: + name: Run Swift tests + command: make test-swift + environment: + SNAPSHOT_ARTIFACTS: $CIRCLE_ARTIFACTS diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..47f8ac6 --- /dev/null +++ b/.gitignore @@ -0,0 +1,69 @@ +# Xcode +# +# gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore + +## Build generated +build/ +DerivedData/ + +## Various settings +*.pbxuser +!default.pbxuser +*.mode1v3 +!default.mode1v3 +*.mode2v3 +!default.mode2v3 +*.perspectivev3 +!default.perspectivev3 +xcuserdata/ + +## Other +*.moved-aside +*.xccheckout +*.xcscmblueprint + +## Obj-C/Swift specific +*.hmap +*.ipa +*.dSYM.zip +*.dSYM + +## Playgrounds +timeline.xctimeline +playground.xcworkspace + +# Swift Package Manager +# +# Add this line if you want to avoid checking in source code from Swift Package Manager dependencies. +# Packages/ +# Package.pins +.build/ + +# CocoaPods +# +# We recommend against adding the Pods directory to your .gitignore. However +# you should judge for yourself, the pros and cons are mentioned at: +# https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control +# +# Pods/ + +# Carthage +# +# Add this line if you want to avoid checking in source code from Carthage dependencies. +# Carthage/Checkouts + +Carthage/Build + +# fastlane +# +# It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the +# screenshots whenever they are needed. +# For more information about the recommended setup visit: +# https://docs.fastlane.tools/best-practices/source-control/#source-control + +fastlane/report.xml +fastlane/Preview.html +fastlane/screenshots +fastlane/test_output + +.DS_Store diff --git a/.sourcery-templates/LinuxMain.stencil b/.sourcery-templates/LinuxMain.stencil new file mode 100644 index 0000000..9701fc5 --- /dev/null +++ b/.sourcery-templates/LinuxMain.stencil @@ -0,0 +1,16 @@ +import XCTest + +{{ argument.testimports }} +{% for type in types.classes|based:"XCTestCase" %} +{% if not type.annotations.disableTests %}extension {{ type.name }} { + static var allTests: [(String, ({{ type.name }}) -> () throws -> Void)] = [ + {% for method in type.methods %}{% if method.parameters.count == 0 and method.shortName|hasPrefix:"test" %} ("{{ method.shortName }}", {{ method.shortName }}){% if not forloop.last %},{% endif %} + {% endif %}{% endfor %}] +} +{% endif %}{% endfor %} + +// swiftlint:disable trailing_comma +XCTMain([ +{% for type in types.classes|based:"XCTestCase" %}{% if not type.annotations.disableTests %} testCase({{ type.name }}.allTests), +{% endif %}{% endfor %}]) +// swiftlint:enable trailing_comma diff --git a/.swift-version b/.swift-version new file mode 100644 index 0000000..7d5c902 --- /dev/null +++ b/.swift-version @@ -0,0 +1 @@ +4.1 diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000..b2b93f7 --- /dev/null +++ b/.travis.yml @@ -0,0 +1,12 @@ +os: + - linux +env: +language: generic +sudo: required +dist: trusty +install: + - if [ $TRAVIS_OS_NAME = linux ]; then + eval "$(curl -sL https://swiftenv.fuller.li/install.sh)"; + fi +script: + - swift test diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md new file mode 100644 index 0000000..24ce6a2 --- /dev/null +++ b/CODE_OF_CONDUCT.md @@ -0,0 +1,46 @@ +# Contributor Covenant Code of Conduct + +## Our Pledge + +In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, religion, or sexual identity and orientation. + +## Our Standards + +Examples of behavior that contributes to creating a positive environment include: + +* Using welcoming and inclusive language +* Being respectful of differing viewpoints and experiences +* Gracefully accepting constructive criticism +* Focusing on what is best for the community +* Showing empathy towards other community members + +Examples of unacceptable behavior by participants include: + +* The use of sexualized language or imagery and unwelcome sexual attention or advances +* Trolling, insulting/derogatory comments, and personal or political attacks +* Public or private harassment +* Publishing others' private information, such as a physical or electronic address, without explicit permission +* Other conduct which could reasonably be considered inappropriate in a professional setting + +## Our Responsibilities + +Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior. + +Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful. + +## Scope + +This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers. + +## Enforcement + +Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at mbw234@gmail.com. The project team will review and investigate all complaints, and will respond in a way that it deems appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately. + +Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership. + +## Attribution + +This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at [http://contributor-covenant.org/version/1/4][version] + +[homepage]: http://contributor-covenant.org +[version]: http://contributor-covenant.org/version/1/4/ diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..78c6272 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,9 @@ +FROM swift:4.0 + +WORKDIR /package + +COPY . ./ + +RUN swift package resolve +RUN swift package clean +CMD swift test --parallel diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..01d7d4a --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2018 Point-Free, Inc. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..b7d8580 --- /dev/null +++ b/Makefile @@ -0,0 +1,36 @@ +imports = \ + @testable import ValidatedTests; + +xcodeproj: + swift package generate-xcodeproj --xcconfig-overrides=Validated.xcconfig + +linux-main: + sourcery \ + --sources ./Tests/ \ + --templates ./.sourcery-templates/ \ + --output ./Tests/ \ + --args testimports='$(imports)' \ + && mv ./Tests/LinuxMain.generated.swift ./Tests/LinuxMain.swift + +test-linux: linux-main + docker build --tag tagged-testing . \ + && docker run --rm tagged-testing + +test-macos: + set -o pipefail && \ + xcodebuild test \ + -scheme Validated-Package \ + -destination platform="macOS" \ + | xcpretty + +test-ios: + set -o pipefail && \ + xcodebuild test \ + -scheme Validated-Package \ + -destination platform="iOS Simulator,name=iPhone 8,OS=11.4" \ + | xcpretty + +test-swift: + swift test + +test-all: test-linux test-mac test-ios diff --git a/Package.resolved b/Package.resolved new file mode 100644 index 0000000..42746ab --- /dev/null +++ b/Package.resolved @@ -0,0 +1,16 @@ +{ + "object": { + "pins": [ + { + "package": "NonEmpty", + "repositoryURL": "https://github.com/pointfreeco/swift-nonempty.git", + "state": { + "branch": null, + "revision": "57e42477177bee239d97a7fdcbc5264da47f2344", + "version": "0.1.0" + } + } + ] + }, + "version": 1 +} diff --git a/Package.swift b/Package.swift new file mode 100644 index 0000000..429f5c6 --- /dev/null +++ b/Package.swift @@ -0,0 +1,22 @@ +// swift-tools-version:4.0 +import PackageDescription + +let package = Package( + name: "Validated", + products: [ + .library( + name: "Validated", + targets: ["Validated"]), + ], + dependencies: [ + .package(url: "https://github.com/pointfreeco/swift-nonempty.git", from: "0.1.0"), + ], + targets: [ + .target( + name: "Validated", + dependencies: ["NonEmpty"]), + .testTarget( + name: "ValidatedTests", + dependencies: ["Validated"]), + ] +) diff --git a/PointFree-Validated.podspec b/PointFree-Validated.podspec new file mode 100644 index 0000000..cbe9c05 --- /dev/null +++ b/PointFree-Validated.podspec @@ -0,0 +1,37 @@ +version = "0.1.0" + +Pod::Spec.new do |s| + s.name = "PointFree-Validated" + s.version = version + s.summary = "A result type that accumulates multiple errors." + + s.description = <<-DESC + Swift error handling short-circuits on the first failure. Because of this, it's not the greatest option for handling things like form data, where multiple inputs may result in multiple errors. + + Validated is a Result-like type that can accumulate multiple errors. + DESC + + s.homepage = "https://github.com/pointfreeco/swift-validated" + + s.license = "MIT" + + s.authors = { + "Stephen Celis" => "stephen@stephencelis.com", + "Brandon Williams" => "mbw234@gmail.com" + } + s.social_media_url = "https://twitter.com/pointfreeco" + + s.source = { + :git => "https://github.com/pointfreeco/swift-validated.git", + :tag => version + } + + s.ios.deployment_target = "8.0" + s.osx.deployment_target = "10.9" + s.tvos.deployment_target = "9.0" + s.watchos.deployment_target = "2.0" + + s.source_files = "Sources", "Sources/**/*.swift" + + s.dependency "NonEmpty" +end diff --git a/README.md b/README.md new file mode 100644 index 0000000..4058b28 --- /dev/null +++ b/README.md @@ -0,0 +1,212 @@ +# 🛂 Validated + +[![Swift 4.1](https://img.shields.io/badge/swift-4.1-ED523F.svg?style=flat)](https://swift.org/download/) +[![iOS/macOS CI](https://img.shields.io/circleci/project/github/pointfreeco/swift-validated/master.svg?label=ios/macos)](https://circleci.com/gh/pointfreeco/swift-validated) +[![Linux CI](https://img.shields.io/travis/pointfreeco/swift-validated/master.svg?label=linux)](https://travis-ci.org/pointfreeco/swift-validated) +[![@pointfreeco](https://img.shields.io/badge/contact-@pointfreeco-5AA9E7.svg?style=flat)](https://twitter.com/pointfreeco) + +A result type that accumulates multiple errors. + +## Table of Contents + + - [Motivation](#motivation) + - [The problem](#the-problem) + - [Handling multiple errors with Validated](#handling-multiple-errors-with-validated) + - [Installation](#installation) + - [Interested in learning more?](#interested-in-learning-more) + - [License](#license) + +## Motivation + +### The problem + +Swift error handling short-circuits on the first failure. Because of this, it's not the greatest option for handling things like form data, where multiple inputs may result in multiple errors. + +``` swift +struct User { + let id: Int + let email: String + let name: String +} + +func validate(id: Int) -> Int throws { + guard id > 0 else { + throw Invalid.error("id must be greater than zero") + } + return id +} + +func validate(email: String) -> String throws { + guard email.contains("@") else { + throw Invalid.error("email must be valid") + } + return email +} + +func validate(name: String) -> String throws { + guard !name.isEmpty else { + throw Invalid.error("name can't be blank") + } + return name +} + +func validateUser(id: Int, email: String, name: String) throws -> User { + return User( + id: try validate(id: id), + email: try validate(id: email), + name: try validate(id: name) + ) +} +``` + +Here we've combined a few throwing functions into a single throwing function that may return a `User`. + +``` swift +let user = try validateUser(id: 1, email: "blob@pointfree.co", name: "Blob") +// User(id: 1, email: "blob@pointfree.co", name: "Blob") +``` + +If the `id`, `email`, or `name` are invalid, an error is thrown. + +``` swift +let user = try validateUser(id: 1, email: "blob@pointfree.co", name: "") +// throws Invalid.error("name can't be blank") +``` + +Unfortunately, if several or all of these inputs are invalid, the first error wins. + +``` swift +let user = try validateUser(id: -1, email: "blobpointfree.co", name: "") +// throws Invalid.error("id must be greater than zero") +``` + +### Handling multiple errors with Validated + +`Validated` is a [`Result`](https://github.com/antitypical/Result)-like type that can accumulate multiple errors. Instead of using `throw`ing functions, we can define functions that work with `Validated`. + +``` swift +func validate(id: Int) -> Validated { + return id > 0 + ? .valid(id) + : .error("id must be greater than zero") +} + +func validate(email: String) -> Validated { + return email.contains("@") + ? .valid(email) + : .error("email must be valid") +} + +func validate(name: String) -> Validated { + return !name.isEmpty + ? .valid(name) + : .error("name can't be blank") +} +``` + +To accumulate errors, we use a function that we may already be familiar with: `zip`. + +``` swift +let validInputs = zip( + validate(id: 1), + validate(email: "blob@pointfree.co"), + validate(name: "Blob") +) +// Validated<(Int, String, String), String> +``` + +The `zip` function on `Validated` works much the same way it works on sequences, but rather than zipping a pair of sequences into a sequence pairs, it zips up a group of single `Validated` values into single `Validated` value of a group. + +From here, we can use another function that we may already be familiar with, `map`, which takes a transform function and produces a new `Validated` value with its valid case transformed. + +``` swift +let validUser = validInputs.map(User.init) +// valid(User(id: 1, email: "blob@pointfree.co", name: "Blob")) +``` + +For ergonomics, a `zip(with:)` function is provided that takes both a transform and `Validated` inputs at once. + +``` swift +zip(with: User.init)( + validate(id: 1), + validate(email: "blob@pointfree.co"), + validate(name: "Blob") +) +// valid(User(id: 1, email: "blob@pointfree.co", name: "Blob")) +``` + +Valid inputs yield a user wrapped in the `valid` case. + +Meanwhile, an invalid input yields an error in the `invalid` case. + +``` swift +zip(with: User.init)( + validate(id: 1), + validate(email: "blob@pointfree.co"), + validate(name: "") +) +// invalid(["name can't be blank"]) +``` + +More importantly, multiple invalid inputs yield an `invalid` case with multiple errors. + +``` swift +zip(with: User.init)( + validate(id: -1), + validate(email: "blob@pointfree.co"), + validate(name: "") +) +// invalid([ +// "id must be greater than zero", +// "email must be valid", +// "name can't be blank" +// ]) +``` + +Invalid errors are held in a [non-empty array](https://github.com/pointfreeco/swift-nonempty.git) to provide a compile-time guarantee that you will never encounter an empty `invalid` case. + +## Installation + +### Carthage + +If you use [Carthage](https://github.com/Carthage/Carthage), you can add the following dependency to your `Cartfile`: + +``` ruby +github "pointfreeco/swift-validated" ~> 0.1 +``` + +### CocoaPods + +If your project uses [CocoaPods](https://cocoapods.org), just add the following to your `Podfile`: + +``` ruby +pod 'PointFree-Validated', '~> 0.1' +``` + +### SwiftPM + +If you want to use Validated in a project that uses [SwiftPM](https://swift.org/package-manager/), it's as simple as adding a `dependencies` clause to your `Package.swift`: + +``` swift +dependencies: [ + .package(url: "https://github.com/pointfreeco/swift-validated.git", from: "0.1.0") +] +``` + +### Xcode Sub-project + +Submodule, clone, or download Validated, and drag `Validated.xcodeproj` into your project. + +## Interested in learning more? + +These concepts (and more) are explored thoroughly in [Point-Free](https://www.pointfree.co), a video series exploring functional programming and Swift hosted by [Brandon Williams](https://github.com/mbrandonw) and [Stephen Celis](https://github.com/stephencelis). + +Validated was explored in [The Many Faces of Zip: Part 2](https://www.pointfree.co/episodes/ep24-the-many-faces-of-zip-part-2): + + + video poster image + + +## License + +All modules are released under the MIT license. See [LICENSE](LICENSE) for details. diff --git a/Sources/Validated/Validated.swift b/Sources/Validated/Validated.swift new file mode 100644 index 0000000..1626eba --- /dev/null +++ b/Sources/Validated/Validated.swift @@ -0,0 +1,132 @@ +@_exported import NonEmpty + +/// A result type that accumulates multiple errors. +public enum Validated { + + /// Wraps a value that has passed validation. + case valid(Value) + + /// Collects a non-empty array of errors due to validation failure. + case invalid(NonEmptyArray) + + /// Fail with a validation error. + /// + /// - Parameter error: A single validation error. + /// - Returns: The error, wrapped in a validated value. + public static func error(_ error: Error) -> Validated { + return .invalid(NonEmptyArray(error)) + } + + /// Returns true for valid values. + public var isValid: Bool { + switch self { + case .valid: + return true + case .invalid: + return false + } + } + + /// Returns a valid value (or `nil`, when invalid). + public var value: Value? { + switch self { + case let .valid(value): + return value + case .invalid: + return nil + } + } + + /// Returns a non-empty array of errors (or `nil`, when valid). + public var errors: NonEmptyArray? { + switch self { + case .valid: + return nil + case let .invalid(errors): + return errors + } + } + + /// Case analysis to produce the same type. "Folds" a validated value into some other value. + /// + /// - Parameters: + /// - ifValid: A function that transforms a valid value into some other value. + /// - ifInvalid: A function that transforms a non-empty array of errors into some other value. + /// - Returns: The result of the transformation. + public func validate( + ifValid: (Value) -> ValueOfResult, + ifInvalid: (NonEmptyArray) -> ValueOfResult + ) + -> ValueOfResult { + switch self { + case let .valid(value): + return ifValid(value) + case let .invalid(errors): + return ifInvalid(errors) + } + } + + /// Transforms a valid value into some other valid value. + /// + /// - Parameter transform: A transform function for valid values. + /// - Returns: A new validated value. + public func map(_ transform: (Value) -> ValueOfResult) -> Validated { + switch self { + case let .valid(value): + return .valid(transform(value)) + case let .invalid(errors): + return .invalid(errors) + } + } +} + +extension Validated: Equatable where Value: Equatable, Error: Equatable { + public static func == (lhs: Validated, rhs: Validated) -> Bool { + switch (lhs, rhs) { + case let (.valid(value1), .valid(value2)): + return value1 == value2 + case let (.invalid(errors1), .invalid(errors2)): + return errors1 == errors2 + case (.valid, .invalid), (.invalid, .valid): + return false + } + } +} + +/// Zips multiple validated values together, accumulating errors if both sides are invalid. +/// +/// - Parameters: +/// - validated1: A validated value (or errors). +/// - validated2: A second, validated value (or errors). +/// - Returns: A validated tuple of the first and second value (or the accumulation of any errors). +public func zip( + _ validated1: Validated, + _ validated2: Validated + ) + -> Validated<(Value1, Value2), Error> { + + switch (validated1, validated2) { + case let (.valid(value1), .valid(value2)): + return .valid((value1, value2)) + case let (.valid, .invalid(errors)): + return .invalid(errors) + case let (.invalid(errors), .valid): + return .invalid(errors) + case let (.invalid(errors1), .invalid(errors2)): + return .invalid(errors1 + errors2) + } +} + +/// Lifts a function that takes two values and returns a result into a function that takes two validated +/// values and returns a validated result. +/// +/// - Parameter transform: A tranform function that takes two values and returns a result. +/// - Returns: A function that takes two validated values and returns a validated result. +public func zip( + with transform: @escaping (Value1, Value2) -> ValueOfResult + ) + -> (Validated, Validated) + -> Validated { + + return { zip($0, $1).map(transform) } +} diff --git a/Sources/Validated/Zips.swift b/Sources/Validated/Zips.swift new file mode 100644 index 0000000..b5e6c2d --- /dev/null +++ b/Sources/Validated/Zips.swift @@ -0,0 +1,247 @@ +public func zip( + _ a: Validated, + _ b: Validated, + _ c: Validated + ) + -> Validated<(A, B, C), Error> { + + return zip(zip(a, b), c) + .map { ($0.0, $0.1, $1) } +} + +public func zip( + with f: @escaping (A, B, C) -> D + ) + -> ( + Validated, + Validated, + Validated + ) + -> Validated { + + return { zip($0, $1, $2).map(f) } +} + +public func zip( + _ a: Validated, + _ b: Validated, + _ c: Validated, + _ d: Validated + ) + -> Validated<(A, B, C, D), Error> { + + return zip(zip(a, b), c, d) + .map { ($0.0, $0.1, $1, $2) } +} + +public func zip( + with f: @escaping (A, B, C, D) -> E + ) + -> ( + Validated, + Validated, + Validated, + Validated + ) + -> Validated { + + return { zip($0, $1, $2, $3).map(f) } +} + +public func zip( + _ a: Validated, + _ b: Validated, + _ c: Validated, + _ d: Validated, + _ e: Validated + ) + -> Validated<(A, B, C, D, E), Error> { + + return zip(zip(a, b), c, d, e) + .map { ($0.0, $0.1, $1, $2, $3) } +} + +public func zip( + with f: @escaping (A, B, C, D, E) -> F + ) + -> ( + Validated, + Validated, + Validated, + Validated, + Validated + ) + -> Validated { + + return { zip($0, $1, $2, $3, $4).map(f) } +} + +public func zip( + _ a: Validated, + _ b: Validated, + _ c: Validated, + _ d: Validated, + _ e: Validated, + _ f: Validated + ) + -> Validated<(A, B, C, D, E, F), Error> { + + return zip(zip(a, b), c, d, e, f) + .map { ($0.0, $0.1, $1, $2, $3, $4) } +} + +public func zip( + with f: @escaping (A, B, C, D, E, F) -> G + ) + -> ( + Validated, + Validated, + Validated, + Validated, + Validated, + Validated + ) + -> Validated { + + return { zip($0, $1, $2, $3, $4, $5).map(f) } +} + +public func zip( + _ a: Validated, + _ b: Validated, + _ c: Validated, + _ d: Validated, + _ e: Validated, + _ f: Validated, + _ g: Validated + ) + -> Validated<(A, B, C, D, E, F, G), Error> { + + return zip(zip(a, b), c, d, e, f, g) + .map { ($0.0, $0.1, $1, $2, $3, $4, $5) } +} + +public func zip( + with f: @escaping (A, B, C, D, E, F, G) -> H + ) + -> ( + Validated, + Validated, + Validated, + Validated, + Validated, + Validated, + Validated + ) + -> Validated { + + return { zip($0, $1, $2, $3, $4, $5, $6).map(f) } +} + +public func zip( + _ a: Validated, + _ b: Validated, + _ c: Validated, + _ d: Validated, + _ e: Validated, + _ f: Validated, + _ g: Validated, + _ h: Validated + ) + -> Validated<(A, B, C, D, E, F, G, H), Error> { + + return zip(zip(a, b), c, d, e, f, g, h) + .map { ($0.0, $0.1, $1, $2, $3, $4, $5, $6) } +} + +public func zip( + with f: @escaping (A, B, C, D, E, F, G, H) -> I + ) + -> ( + Validated, + Validated, + Validated, + Validated, + Validated, + Validated, + Validated, + Validated + ) + -> Validated { + + return { zip($0, $1, $2, $3, $4, $5, $6, $7).map(f) } +} + +public func zip( + _ a: Validated, + _ b: Validated, + _ c: Validated, + _ d: Validated, + _ e: Validated, + _ f: Validated, + _ g: Validated, + _ h: Validated, + _ i: Validated + ) + -> Validated<(A, B, C, D, E, F, G, H, I), Error> { + + return zip(zip(a, b), c, d, e, f, g, h, i) + .map { ($0.0, $0.1, $1, $2, $3, $4, $5, $6, $7) } +} + +public func zip( + with f: @escaping (A, B, C, D, E, F, G, H, I) -> J + ) + -> ( + Validated, + Validated, + Validated, + Validated, + Validated, + Validated, + Validated, + Validated, + Validated + ) + -> Validated { + + return { zip($0, $1, $2, $3, $4, $5, $6, $7, $8).map(f) } +} + +public func zip( + _ a: Validated, + _ b: Validated, + _ c: Validated, + _ d: Validated, + _ e: Validated, + _ f: Validated, + _ g: Validated, + _ h: Validated, + _ i: Validated, + _ j: Validated + ) + -> Validated<(A, B, C, D, E, F, G, H, I, J), Error> { + + return zip(zip(a, b), c, d, e, f, g, h, i, j) + .map { ($0.0, $0.1, $1, $2, $3, $4, $5, $6, $7, $8) } +} + +public func zip( + with f: @escaping (A, B, C, D, E, F, G, H, I, J) -> K + ) + -> ( + Validated, + Validated, + Validated, + Validated, + Validated, + Validated, + Validated, + Validated, + Validated, + Validated + ) + -> Validated { + + return { zip($0, $1, $2, $3, $4, $5, $6, $7, $8, $9).map(f) } +} diff --git a/Tests/LinuxMain.swift b/Tests/LinuxMain.swift new file mode 100644 index 0000000..b0fefa7 --- /dev/null +++ b/Tests/LinuxMain.swift @@ -0,0 +1,18 @@ +// Generated using Sourcery 0.11.0 — https://github.com/krzysztofzablocki/Sourcery +// DO NOT EDIT + +import XCTest + +@testable import ValidatedTests; +extension ValidatedTests { + static var allTests: [(String, (ValidatedTests) -> () throws -> Void)] = [ + ("testZipWith", testZipWith), + ("testHigherOrderZips", testHigherOrderZips) + ] +} + +// swiftlint:disable trailing_comma +XCTMain([ + testCase(ValidatedTests.allTests), +]) +// swiftlint:enable trailing_comma diff --git a/Tests/ValidatedTests/ValidatedTests.swift b/Tests/ValidatedTests/ValidatedTests.swift new file mode 100644 index 0000000..3cde9c4 --- /dev/null +++ b/Tests/ValidatedTests/ValidatedTests.swift @@ -0,0 +1,113 @@ +import XCTest +import Validated + +func validate(id: Int) -> Validated { + return id > 0 + ? .valid(id) + : .error("id must be greater than zero") +} + +func validate(name: String) -> Validated { + return !name.isEmpty + ? .valid(name) + : .error("name can't be blank") +} + +struct User: Equatable { + let id: Int + let name: String +} + +final class ValidatedTests: XCTestCase { + func testZipWith() { + let validUser = zip(with: User.init)( + validate(id: 1), + validate(name: "Blob") + ) + XCTAssertTrue(validUser.isValid) + XCTAssertEqual(User(id: 1, name: "Blob"), validUser.value) + XCTAssertNil(validUser.errors) + let validMessage = validUser.validate( + ifValid: { "\($0.name) is valid!" }, + ifInvalid: { $0.joined(separator: ", ") } + ) + XCTAssertEqual("Blob is valid!", validMessage) + + let invalidUser = zip(with: User.init)( + validate(id: -1), + validate(name: "") + ) + XCTAssertFalse(invalidUser.isValid) + XCTAssertNil(invalidUser.value) + XCTAssertEqual( + NonEmptyArray( + "id must be greater than zero", + "name can't be blank" + ), + invalidUser.errors + ) + let invalidMessage = invalidUser.validate( + ifValid: { "\($0.name) is valid!" }, + ifInvalid: { $0.joined(separator: ", ") } + ) + XCTAssertEqual("id must be greater than zero, name can't be blank", invalidMessage) + + let partiallyInvalidUser1 = zip(with: User.init)( + validate(id: 1), + validate(name: "") + ) + XCTAssertEqual( + NonEmptyArray( + "name can't be blank" + ), + partiallyInvalidUser1.errors + ) + let partiallyInvalidUser2 = zip(with: User.init)( + validate(id: -1), + validate(name: "Blob") + ) + XCTAssertEqual( + NonEmptyArray( + "id must be greater than zero" + ), + partiallyInvalidUser2.errors + ) + + XCTAssertNotEqual(validUser, invalidUser) + XCTAssertNotEqual(invalidUser, validUser) + XCTAssertNotEqual(partiallyInvalidUser1, partiallyInvalidUser2) + } + + func testHigherOrderZips() { + struct A: Equatable { + let a1: Int + let a2: Int + let a3: Int + let a4: Int + let a5: Int + let a6: Int + let a7: Int + let a8: Int + let a9: Int + let a10: Int + } + + let validA = zip(with: A.init)( + validate(id: 1), + validate(id: 2), + validate(id: 3), + validate(id: 4), + validate(id: 5), + validate(id: 6), + validate(id: 7), + validate(id: 8), + validate(id: 9), + validate(id: 10) + ) + + XCTAssertEqual( + .valid(A(a1: 1, a2: 2, a3: 3, a4: 4, a5: 5, a6: 6, a7: 7, a8: 8, a9: 9, a10: 10)), + validA + ) + } +} diff --git a/Validated.playground/Contents.swift b/Validated.playground/Contents.swift new file mode 100644 index 0000000..058f94f --- /dev/null +++ b/Validated.playground/Contents.swift @@ -0,0 +1,41 @@ +import Validated + +struct User { + let id: Int + let email: String + let name: String +} + +func validate(id: Int) -> Validated { + return id > 0 + ? .valid(id) + : .error("id must be greater than zero") +} + +func validate(email: String) -> Validated { + return email.contains("@") + ? .valid(email) + : .error("email must be valid") +} + +func validate(name: String) -> Validated { + return !name.isEmpty + ? .valid(name) + : .error("name can't be blank") +} + +let validUser = zip(with: User.init)( + validate(id: 1), + validate(email: "blob@pointfree.co"), + validate(name: "Blob") +) +validUser.isValid +validUser.value + +let invalidUser = zip(with: User.init)( + validate(id: -1), + validate(email: "blobpointfree.co"), + validate(name: "") +) +invalidUser.isValid +invalidUser.errors diff --git a/Validated.playground/contents.xcplayground b/Validated.playground/contents.xcplayground new file mode 100644 index 0000000..b478c1d --- /dev/null +++ b/Validated.playground/contents.xcplayground @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/Validated.xcconfig b/Validated.xcconfig new file mode 100644 index 0000000..df240e3 --- /dev/null +++ b/Validated.xcconfig @@ -0,0 +1,5 @@ +IPHONEOS_DEPLOYMENT_TARGET=8.0 +OTHER_SWIFT_FLAGS=$(inherited) -Xfrontend -warn-long-expression-type-checking=80 +MACOSX_DEPLOYMENT_TARGET=10.9 +TVOS_DEPLOYMENT_TARGET=9.0 +WATCHOS_DEPLOYMENT_TARGET=2.0 diff --git a/Validated.xcodeproj/NonEmpty_Info.plist b/Validated.xcodeproj/NonEmpty_Info.plist new file mode 100644 index 0000000..57ada9f --- /dev/null +++ b/Validated.xcodeproj/NonEmpty_Info.plist @@ -0,0 +1,25 @@ + + + + CFBundleDevelopmentRegion + en + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + FMWK + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + $(CURRENT_PROJECT_VERSION) + NSPrincipalClass + + + diff --git a/Validated.xcodeproj/ValidatedTests_Info.plist b/Validated.xcodeproj/ValidatedTests_Info.plist new file mode 100644 index 0000000..7c23420 --- /dev/null +++ b/Validated.xcodeproj/ValidatedTests_Info.plist @@ -0,0 +1,25 @@ + + + + CFBundleDevelopmentRegion + en + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + BNDL + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + $(CURRENT_PROJECT_VERSION) + NSPrincipalClass + + + diff --git a/Validated.xcodeproj/Validated_Info.plist b/Validated.xcodeproj/Validated_Info.plist new file mode 100644 index 0000000..57ada9f --- /dev/null +++ b/Validated.xcodeproj/Validated_Info.plist @@ -0,0 +1,25 @@ + + + + CFBundleDevelopmentRegion + en + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + FMWK + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + $(CURRENT_PROJECT_VERSION) + NSPrincipalClass + + + diff --git a/Validated.xcodeproj/project.pbxproj b/Validated.xcodeproj/project.pbxproj new file mode 100644 index 0000000..a5f9a34 --- /dev/null +++ b/Validated.xcodeproj/project.pbxproj @@ -0,0 +1,744 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + objects = { + +/* Begin PBXAggregateTarget section */ + "Validated::ValidatedPackageTests::ProductTarget" /* ValidatedPackageTests */ = { + isa = PBXAggregateTarget; + buildConfigurationList = OBJ_84 /* Build configuration list for PBXAggregateTarget "ValidatedPackageTests" */; + buildPhases = ( + ); + dependencies = ( + OBJ_87 /* PBXTargetDependency */, + ); + name = ValidatedPackageTests; + productName = ValidatedPackageTests; + }; +/* End PBXAggregateTarget section */ + +/* Begin PBXBuildFile section */ + OBJ_45 /* NonEmpty+Array.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_20 /* NonEmpty+Array.swift */; }; + OBJ_46 /* NonEmpty+BidirectionalCollection.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_21 /* NonEmpty+BidirectionalCollection.swift */; }; + OBJ_47 /* NonEmpty+Codable.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_22 /* NonEmpty+Codable.swift */; }; + OBJ_48 /* NonEmpty+Collection.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_23 /* NonEmpty+Collection.swift */; }; + OBJ_49 /* NonEmpty+Comparable.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_24 /* NonEmpty+Comparable.swift */; }; + OBJ_50 /* NonEmpty+Dictionary.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_25 /* NonEmpty+Dictionary.swift */; }; + OBJ_51 /* NonEmpty+Equatable.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_26 /* NonEmpty+Equatable.swift */; }; + OBJ_52 /* NonEmpty+Hashable.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_27 /* NonEmpty+Hashable.swift */; }; + OBJ_53 /* NonEmpty+MutableCollection.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_28 /* NonEmpty+MutableCollection.swift */; }; + OBJ_54 /* NonEmpty+Random.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_29 /* NonEmpty+Random.swift */; }; + OBJ_55 /* NonEmpty+RandomAccessCollection.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_30 /* NonEmpty+RandomAccessCollection.swift */; }; + OBJ_56 /* NonEmpty+RangeReplaceableCollection.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_31 /* NonEmpty+RangeReplaceableCollection.swift */; }; + OBJ_57 /* NonEmpty+SetAlgebra.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_32 /* NonEmpty+SetAlgebra.swift */; }; + OBJ_58 /* NonEmpty+String.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_33 /* NonEmpty+String.swift */; }; + OBJ_59 /* NonEmpty.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_34 /* NonEmpty.swift */; }; + OBJ_66 /* Package.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_35 /* Package.swift */; }; + OBJ_72 /* Validated.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_11 /* Validated.swift */; }; + OBJ_73 /* Zips.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_12 /* Zips.swift */; }; + OBJ_75 /* NonEmpty.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = "NonEmpty::NonEmpty::Product" /* NonEmpty.framework */; }; + OBJ_82 /* Package.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_6 /* Package.swift */; }; + OBJ_93 /* ValidatedTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_15 /* ValidatedTests.swift */; }; + OBJ_95 /* Validated.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = "Validated::Validated::Product" /* Validated.framework */; }; + OBJ_96 /* NonEmpty.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = "NonEmpty::NonEmpty::Product" /* NonEmpty.framework */; }; +/* End PBXBuildFile section */ + +/* Begin PBXContainerItemProxy section */ + DCF8236B21267200000A7F94 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = OBJ_1 /* Project object */; + proxyType = 1; + remoteGlobalIDString = "NonEmpty::NonEmpty"; + remoteInfo = NonEmpty; + }; + DCF8236C21267200000A7F94 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = OBJ_1 /* Project object */; + proxyType = 1; + remoteGlobalIDString = "Validated::Validated"; + remoteInfo = Validated; + }; + DCF8236D21267200000A7F94 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = OBJ_1 /* Project object */; + proxyType = 1; + remoteGlobalIDString = "NonEmpty::NonEmpty"; + remoteInfo = NonEmpty; + }; + DCF8236E21267201000A7F94 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = OBJ_1 /* Project object */; + proxyType = 1; + remoteGlobalIDString = "Validated::ValidatedTests"; + remoteInfo = ValidatedTests; + }; +/* End PBXContainerItemProxy section */ + +/* Begin PBXFileReference section */ + "NonEmpty::NonEmpty::Product" /* NonEmpty.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = NonEmpty.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + OBJ_11 /* Validated.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Validated.swift; sourceTree = ""; }; + OBJ_12 /* Zips.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Zips.swift; sourceTree = ""; }; + OBJ_15 /* ValidatedTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ValidatedTests.swift; sourceTree = ""; }; + OBJ_16 /* Validated.xcworkspace */ = {isa = PBXFileReference; lastKnownFileType = wrapper.workspace; path = Validated.xcworkspace; sourceTree = SOURCE_ROOT; }; + OBJ_20 /* NonEmpty+Array.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "NonEmpty+Array.swift"; sourceTree = ""; }; + OBJ_21 /* NonEmpty+BidirectionalCollection.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "NonEmpty+BidirectionalCollection.swift"; sourceTree = ""; }; + OBJ_22 /* NonEmpty+Codable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "NonEmpty+Codable.swift"; sourceTree = ""; }; + OBJ_23 /* NonEmpty+Collection.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "NonEmpty+Collection.swift"; sourceTree = ""; }; + OBJ_24 /* NonEmpty+Comparable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "NonEmpty+Comparable.swift"; sourceTree = ""; }; + OBJ_25 /* NonEmpty+Dictionary.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "NonEmpty+Dictionary.swift"; sourceTree = ""; }; + OBJ_26 /* NonEmpty+Equatable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "NonEmpty+Equatable.swift"; sourceTree = ""; }; + OBJ_27 /* NonEmpty+Hashable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "NonEmpty+Hashable.swift"; sourceTree = ""; }; + OBJ_28 /* NonEmpty+MutableCollection.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "NonEmpty+MutableCollection.swift"; sourceTree = ""; }; + OBJ_29 /* NonEmpty+Random.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "NonEmpty+Random.swift"; sourceTree = ""; }; + OBJ_30 /* NonEmpty+RandomAccessCollection.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "NonEmpty+RandomAccessCollection.swift"; sourceTree = ""; }; + OBJ_31 /* NonEmpty+RangeReplaceableCollection.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "NonEmpty+RangeReplaceableCollection.swift"; sourceTree = ""; }; + OBJ_32 /* NonEmpty+SetAlgebra.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "NonEmpty+SetAlgebra.swift"; sourceTree = ""; }; + OBJ_33 /* NonEmpty+String.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "NonEmpty+String.swift"; sourceTree = ""; }; + OBJ_34 /* NonEmpty.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NonEmpty.swift; sourceTree = ""; }; + OBJ_35 /* Package.swift */ = {isa = PBXFileReference; explicitFileType = sourcecode.swift; name = Package.swift; path = "/Users/stephen/Developer/pointfreeco/swift-validated/.build/checkouts/swift-nonempty.git-996229071149320975/Package.swift"; sourceTree = ""; }; + OBJ_6 /* Package.swift */ = {isa = PBXFileReference; explicitFileType = sourcecode.swift; path = Package.swift; sourceTree = ""; }; + OBJ_8 /* Validated.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Validated.xcconfig; sourceTree = ""; }; + "Validated::Validated::Product" /* Validated.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = Validated.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + "Validated::ValidatedTests::Product" /* ValidatedTests.xctest */ = {isa = PBXFileReference; lastKnownFileType = file; path = ValidatedTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + OBJ_60 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 0; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + OBJ_74 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 0; + files = ( + OBJ_75 /* NonEmpty.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + OBJ_94 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 0; + files = ( + OBJ_95 /* Validated.framework in Frameworks */, + OBJ_96 /* NonEmpty.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + OBJ_10 /* Validated */ = { + isa = PBXGroup; + children = ( + OBJ_11 /* Validated.swift */, + OBJ_12 /* Zips.swift */, + ); + name = Validated; + path = Sources/Validated; + sourceTree = SOURCE_ROOT; + }; + OBJ_13 /* Tests */ = { + isa = PBXGroup; + children = ( + OBJ_14 /* ValidatedTests */, + ); + name = Tests; + sourceTree = SOURCE_ROOT; + }; + OBJ_14 /* ValidatedTests */ = { + isa = PBXGroup; + children = ( + OBJ_15 /* ValidatedTests.swift */, + ); + name = ValidatedTests; + path = Tests/ValidatedTests; + sourceTree = SOURCE_ROOT; + }; + OBJ_17 /* Dependencies */ = { + isa = PBXGroup; + children = ( + OBJ_18 /* NonEmpty 0.1.0 */, + ); + name = Dependencies; + sourceTree = ""; + }; + OBJ_18 /* NonEmpty 0.1.0 */ = { + isa = PBXGroup; + children = ( + OBJ_19 /* NonEmpty */, + OBJ_35 /* Package.swift */, + ); + name = "NonEmpty 0.1.0"; + sourceTree = SOURCE_ROOT; + }; + OBJ_19 /* NonEmpty */ = { + isa = PBXGroup; + children = ( + OBJ_20 /* NonEmpty+Array.swift */, + OBJ_21 /* NonEmpty+BidirectionalCollection.swift */, + OBJ_22 /* NonEmpty+Codable.swift */, + OBJ_23 /* NonEmpty+Collection.swift */, + OBJ_24 /* NonEmpty+Comparable.swift */, + OBJ_25 /* NonEmpty+Dictionary.swift */, + OBJ_26 /* NonEmpty+Equatable.swift */, + OBJ_27 /* NonEmpty+Hashable.swift */, + OBJ_28 /* NonEmpty+MutableCollection.swift */, + OBJ_29 /* NonEmpty+Random.swift */, + OBJ_30 /* NonEmpty+RandomAccessCollection.swift */, + OBJ_31 /* NonEmpty+RangeReplaceableCollection.swift */, + OBJ_32 /* NonEmpty+SetAlgebra.swift */, + OBJ_33 /* NonEmpty+String.swift */, + OBJ_34 /* NonEmpty.swift */, + ); + name = NonEmpty; + path = ".build/checkouts/swift-nonempty.git-996229071149320975/Sources/NonEmpty"; + sourceTree = SOURCE_ROOT; + }; + OBJ_36 /* Products */ = { + isa = PBXGroup; + children = ( + "Validated::ValidatedTests::Product" /* ValidatedTests.xctest */, + "Validated::Validated::Product" /* Validated.framework */, + "NonEmpty::NonEmpty::Product" /* NonEmpty.framework */, + ); + name = Products; + sourceTree = BUILT_PRODUCTS_DIR; + }; + OBJ_5 /* */ = { + isa = PBXGroup; + children = ( + OBJ_6 /* Package.swift */, + OBJ_7 /* Configs */, + OBJ_9 /* Sources */, + OBJ_13 /* Tests */, + OBJ_16 /* Validated.xcworkspace */, + OBJ_17 /* Dependencies */, + OBJ_36 /* Products */, + ); + name = ""; + sourceTree = ""; + }; + OBJ_7 /* Configs */ = { + isa = PBXGroup; + children = ( + OBJ_8 /* Validated.xcconfig */, + ); + name = Configs; + sourceTree = ""; + }; + OBJ_9 /* Sources */ = { + isa = PBXGroup; + children = ( + OBJ_10 /* Validated */, + ); + name = Sources; + sourceTree = SOURCE_ROOT; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + "NonEmpty::NonEmpty" /* NonEmpty */ = { + isa = PBXNativeTarget; + buildConfigurationList = OBJ_41 /* Build configuration list for PBXNativeTarget "NonEmpty" */; + buildPhases = ( + OBJ_44 /* Sources */, + OBJ_60 /* Frameworks */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = NonEmpty; + productName = NonEmpty; + productReference = "NonEmpty::NonEmpty::Product" /* NonEmpty.framework */; + productType = "com.apple.product-type.framework"; + }; + "NonEmpty::SwiftPMPackageDescription" /* NonEmptyPackageDescription */ = { + isa = PBXNativeTarget; + buildConfigurationList = OBJ_62 /* Build configuration list for PBXNativeTarget "NonEmptyPackageDescription" */; + buildPhases = ( + OBJ_65 /* Sources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = NonEmptyPackageDescription; + productName = NonEmptyPackageDescription; + productType = "com.apple.product-type.framework"; + }; + "Validated::SwiftPMPackageDescription" /* ValidatedPackageDescription */ = { + isa = PBXNativeTarget; + buildConfigurationList = OBJ_78 /* Build configuration list for PBXNativeTarget "ValidatedPackageDescription" */; + buildPhases = ( + OBJ_81 /* Sources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = ValidatedPackageDescription; + productName = ValidatedPackageDescription; + productType = "com.apple.product-type.framework"; + }; + "Validated::Validated" /* Validated */ = { + isa = PBXNativeTarget; + buildConfigurationList = OBJ_68 /* Build configuration list for PBXNativeTarget "Validated" */; + buildPhases = ( + OBJ_71 /* Sources */, + OBJ_74 /* Frameworks */, + ); + buildRules = ( + ); + dependencies = ( + OBJ_76 /* PBXTargetDependency */, + ); + name = Validated; + productName = Validated; + productReference = "Validated::Validated::Product" /* Validated.framework */; + productType = "com.apple.product-type.framework"; + }; + "Validated::ValidatedTests" /* ValidatedTests */ = { + isa = PBXNativeTarget; + buildConfigurationList = OBJ_89 /* Build configuration list for PBXNativeTarget "ValidatedTests" */; + buildPhases = ( + OBJ_92 /* Sources */, + OBJ_94 /* Frameworks */, + ); + buildRules = ( + ); + dependencies = ( + OBJ_97 /* PBXTargetDependency */, + OBJ_98 /* PBXTargetDependency */, + ); + name = ValidatedTests; + productName = ValidatedTests; + productReference = "Validated::ValidatedTests::Product" /* ValidatedTests.xctest */; + productType = "com.apple.product-type.bundle.unit-test"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + OBJ_1 /* Project object */ = { + isa = PBXProject; + attributes = { + LastUpgradeCheck = 9999; + }; + buildConfigurationList = OBJ_2 /* Build configuration list for PBXProject "Validated" */; + compatibilityVersion = "Xcode 3.2"; + developmentRegion = English; + hasScannedForEncodings = 0; + knownRegions = ( + en, + ); + mainGroup = OBJ_5 /* */; + productRefGroup = OBJ_36 /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + "NonEmpty::NonEmpty" /* NonEmpty */, + "NonEmpty::SwiftPMPackageDescription" /* NonEmptyPackageDescription */, + "Validated::Validated" /* Validated */, + "Validated::SwiftPMPackageDescription" /* ValidatedPackageDescription */, + "Validated::ValidatedPackageTests::ProductTarget" /* ValidatedPackageTests */, + "Validated::ValidatedTests" /* ValidatedTests */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXSourcesBuildPhase section */ + OBJ_44 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 0; + files = ( + OBJ_45 /* NonEmpty+Array.swift in Sources */, + OBJ_46 /* NonEmpty+BidirectionalCollection.swift in Sources */, + OBJ_47 /* NonEmpty+Codable.swift in Sources */, + OBJ_48 /* NonEmpty+Collection.swift in Sources */, + OBJ_49 /* NonEmpty+Comparable.swift in Sources */, + OBJ_50 /* NonEmpty+Dictionary.swift in Sources */, + OBJ_51 /* NonEmpty+Equatable.swift in Sources */, + OBJ_52 /* NonEmpty+Hashable.swift in Sources */, + OBJ_53 /* NonEmpty+MutableCollection.swift in Sources */, + OBJ_54 /* NonEmpty+Random.swift in Sources */, + OBJ_55 /* NonEmpty+RandomAccessCollection.swift in Sources */, + OBJ_56 /* NonEmpty+RangeReplaceableCollection.swift in Sources */, + OBJ_57 /* NonEmpty+SetAlgebra.swift in Sources */, + OBJ_58 /* NonEmpty+String.swift in Sources */, + OBJ_59 /* NonEmpty.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + OBJ_65 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 0; + files = ( + OBJ_66 /* Package.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + OBJ_71 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 0; + files = ( + OBJ_72 /* Validated.swift in Sources */, + OBJ_73 /* Zips.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + OBJ_81 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 0; + files = ( + OBJ_82 /* Package.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + OBJ_92 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 0; + files = ( + OBJ_93 /* ValidatedTests.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXTargetDependency section */ + OBJ_76 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = "NonEmpty::NonEmpty" /* NonEmpty */; + targetProxy = DCF8236B21267200000A7F94 /* PBXContainerItemProxy */; + }; + OBJ_87 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = "Validated::ValidatedTests" /* ValidatedTests */; + targetProxy = DCF8236E21267201000A7F94 /* PBXContainerItemProxy */; + }; + OBJ_97 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = "Validated::Validated" /* Validated */; + targetProxy = DCF8236C21267200000A7F94 /* PBXContainerItemProxy */; + }; + OBJ_98 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = "NonEmpty::NonEmpty" /* NonEmpty */; + targetProxy = DCF8236D21267200000A7F94 /* PBXContainerItemProxy */; + }; +/* End PBXTargetDependency section */ + +/* Begin XCBuildConfiguration section */ + OBJ_3 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + CLANG_ENABLE_OBJC_ARC = YES; + COMBINE_HIDPI_IMAGES = YES; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = dwarf; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + ENABLE_NS_ASSERTIONS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + MACOSX_DEPLOYMENT_TARGET = 10.10; + ONLY_ACTIVE_ARCH = YES; + OTHER_SWIFT_FLAGS = "-DXcode"; + PRODUCT_NAME = "$(TARGET_NAME)"; + SDKROOT = macosx; + SUPPORTED_PLATFORMS = "macosx iphoneos iphonesimulator appletvos appletvsimulator watchos watchsimulator"; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = "SWIFT_PACKAGE DEBUG"; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + USE_HEADERMAP = NO; + }; + name = Debug; + }; + OBJ_4 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + CLANG_ENABLE_OBJC_ARC = YES; + COMBINE_HIDPI_IMAGES = YES; + COPY_PHASE_STRIP = YES; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + GCC_OPTIMIZATION_LEVEL = s; + MACOSX_DEPLOYMENT_TARGET = 10.10; + OTHER_SWIFT_FLAGS = "-DXcode"; + PRODUCT_NAME = "$(TARGET_NAME)"; + SDKROOT = macosx; + SUPPORTED_PLATFORMS = "macosx iphoneos iphonesimulator appletvos appletvsimulator watchos watchsimulator"; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = SWIFT_PACKAGE; + SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; + USE_HEADERMAP = NO; + }; + name = Release; + }; + OBJ_42 /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = OBJ_8 /* Validated.xcconfig */; + buildSettings = { + ENABLE_TESTABILITY = YES; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PLATFORM_DIR)/Developer/Library/Frameworks", + ); + HEADER_SEARCH_PATHS = "$(inherited)"; + INFOPLIST_FILE = Validated.xcodeproj/NonEmpty_Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) $(TOOLCHAIN_DIR)/usr/lib/swift/macosx"; + OTHER_CFLAGS = "$(inherited)"; + OTHER_LDFLAGS = "$(inherited)"; + OTHER_SWIFT_FLAGS = "$(inherited)"; + PRODUCT_BUNDLE_IDENTIFIER = NonEmpty; + PRODUCT_MODULE_NAME = "$(TARGET_NAME:c99extidentifier)"; + PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; + SKIP_INSTALL = YES; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = "$(inherited)"; + SWIFT_VERSION = 4.0; + TARGET_NAME = NonEmpty; + }; + name = Debug; + }; + OBJ_43 /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = OBJ_8 /* Validated.xcconfig */; + buildSettings = { + ENABLE_TESTABILITY = YES; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PLATFORM_DIR)/Developer/Library/Frameworks", + ); + HEADER_SEARCH_PATHS = "$(inherited)"; + INFOPLIST_FILE = Validated.xcodeproj/NonEmpty_Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) $(TOOLCHAIN_DIR)/usr/lib/swift/macosx"; + OTHER_CFLAGS = "$(inherited)"; + OTHER_LDFLAGS = "$(inherited)"; + OTHER_SWIFT_FLAGS = "$(inherited)"; + PRODUCT_BUNDLE_IDENTIFIER = NonEmpty; + PRODUCT_MODULE_NAME = "$(TARGET_NAME:c99extidentifier)"; + PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; + SKIP_INSTALL = YES; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = "$(inherited)"; + SWIFT_VERSION = 4.0; + TARGET_NAME = NonEmpty; + }; + name = Release; + }; + OBJ_63 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + LD = /usr/bin/true; + OTHER_SWIFT_FLAGS = "-swift-version 4 -I $(TOOLCHAIN_DIR)/usr/lib/swift/pm/4 -target x86_64-apple-macosx10.10 -sdk /Applications/Xcode-beta.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.14.sdk"; + SWIFT_VERSION = 4.0; + }; + name = Debug; + }; + OBJ_64 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + LD = /usr/bin/true; + OTHER_SWIFT_FLAGS = "-swift-version 4 -I $(TOOLCHAIN_DIR)/usr/lib/swift/pm/4 -target x86_64-apple-macosx10.10 -sdk /Applications/Xcode-beta.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.14.sdk"; + SWIFT_VERSION = 4.0; + }; + name = Release; + }; + OBJ_69 /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = OBJ_8 /* Validated.xcconfig */; + buildSettings = { + ENABLE_TESTABILITY = YES; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PLATFORM_DIR)/Developer/Library/Frameworks", + ); + HEADER_SEARCH_PATHS = "$(inherited)"; + INFOPLIST_FILE = Validated.xcodeproj/Validated_Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) $(TOOLCHAIN_DIR)/usr/lib/swift/macosx"; + OTHER_CFLAGS = "$(inherited)"; + OTHER_LDFLAGS = "$(inherited)"; + OTHER_SWIFT_FLAGS = "$(inherited)"; + PRODUCT_BUNDLE_IDENTIFIER = Validated; + PRODUCT_MODULE_NAME = "$(TARGET_NAME:c99extidentifier)"; + PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; + SKIP_INSTALL = YES; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = "$(inherited)"; + SWIFT_VERSION = 4.0; + TARGET_NAME = Validated; + }; + name = Debug; + }; + OBJ_70 /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = OBJ_8 /* Validated.xcconfig */; + buildSettings = { + ENABLE_TESTABILITY = YES; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PLATFORM_DIR)/Developer/Library/Frameworks", + ); + HEADER_SEARCH_PATHS = "$(inherited)"; + INFOPLIST_FILE = Validated.xcodeproj/Validated_Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) $(TOOLCHAIN_DIR)/usr/lib/swift/macosx"; + OTHER_CFLAGS = "$(inherited)"; + OTHER_LDFLAGS = "$(inherited)"; + OTHER_SWIFT_FLAGS = "$(inherited)"; + PRODUCT_BUNDLE_IDENTIFIER = Validated; + PRODUCT_MODULE_NAME = "$(TARGET_NAME:c99extidentifier)"; + PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; + SKIP_INSTALL = YES; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = "$(inherited)"; + SWIFT_VERSION = 4.0; + TARGET_NAME = Validated; + }; + name = Release; + }; + OBJ_79 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + LD = /usr/bin/true; + OTHER_SWIFT_FLAGS = "-swift-version 4 -I $(TOOLCHAIN_DIR)/usr/lib/swift/pm/4 -target x86_64-apple-macosx10.10 -sdk /Applications/Xcode-beta.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.14.sdk"; + SWIFT_VERSION = 4.0; + }; + name = Debug; + }; + OBJ_80 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + LD = /usr/bin/true; + OTHER_SWIFT_FLAGS = "-swift-version 4 -I $(TOOLCHAIN_DIR)/usr/lib/swift/pm/4 -target x86_64-apple-macosx10.10 -sdk /Applications/Xcode-beta.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.14.sdk"; + SWIFT_VERSION = 4.0; + }; + name = Release; + }; + OBJ_85 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + }; + name = Debug; + }; + OBJ_86 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + }; + name = Release; + }; + OBJ_90 /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = OBJ_8 /* Validated.xcconfig */; + buildSettings = { + CLANG_ENABLE_MODULES = YES; + EMBEDDED_CONTENT_CONTAINS_SWIFT = YES; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PLATFORM_DIR)/Developer/Library/Frameworks", + ); + HEADER_SEARCH_PATHS = "$(inherited)"; + INFOPLIST_FILE = Validated.xcodeproj/ValidatedTests_Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @loader_path/../Frameworks @loader_path/Frameworks"; + OTHER_CFLAGS = "$(inherited)"; + OTHER_LDFLAGS = "$(inherited)"; + OTHER_SWIFT_FLAGS = "$(inherited)"; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = "$(inherited)"; + SWIFT_VERSION = 4.0; + TARGET_NAME = ValidatedTests; + }; + name = Debug; + }; + OBJ_91 /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = OBJ_8 /* Validated.xcconfig */; + buildSettings = { + CLANG_ENABLE_MODULES = YES; + EMBEDDED_CONTENT_CONTAINS_SWIFT = YES; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PLATFORM_DIR)/Developer/Library/Frameworks", + ); + HEADER_SEARCH_PATHS = "$(inherited)"; + INFOPLIST_FILE = Validated.xcodeproj/ValidatedTests_Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @loader_path/../Frameworks @loader_path/Frameworks"; + OTHER_CFLAGS = "$(inherited)"; + OTHER_LDFLAGS = "$(inherited)"; + OTHER_SWIFT_FLAGS = "$(inherited)"; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = "$(inherited)"; + SWIFT_VERSION = 4.0; + TARGET_NAME = ValidatedTests; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + OBJ_2 /* Build configuration list for PBXProject "Validated" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + OBJ_3 /* Debug */, + OBJ_4 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + OBJ_41 /* Build configuration list for PBXNativeTarget "NonEmpty" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + OBJ_42 /* Debug */, + OBJ_43 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + OBJ_62 /* Build configuration list for PBXNativeTarget "NonEmptyPackageDescription" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + OBJ_63 /* Debug */, + OBJ_64 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + OBJ_68 /* Build configuration list for PBXNativeTarget "Validated" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + OBJ_69 /* Debug */, + OBJ_70 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + OBJ_78 /* Build configuration list for PBXNativeTarget "ValidatedPackageDescription" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + OBJ_79 /* Debug */, + OBJ_80 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + OBJ_84 /* Build configuration list for PBXAggregateTarget "ValidatedPackageTests" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + OBJ_85 /* Debug */, + OBJ_86 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + OBJ_89 /* Build configuration list for PBXNativeTarget "ValidatedTests" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + OBJ_90 /* Debug */, + OBJ_91 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = OBJ_1 /* Project object */; +} diff --git a/Validated.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/Validated.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000..fe1aa71 --- /dev/null +++ b/Validated.xcodeproj/project.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + \ No newline at end of file diff --git a/Validated.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings b/Validated.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings new file mode 100644 index 0000000..a72dc2b --- /dev/null +++ b/Validated.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings @@ -0,0 +1,8 @@ + + + + + IDEWorkspaceSharedSettings_AutocreateContextsIfNeeded + + + \ No newline at end of file diff --git a/Validated.xcodeproj/xcshareddata/xcschemes/Validated-Package.xcscheme b/Validated.xcodeproj/xcshareddata/xcschemes/Validated-Package.xcscheme new file mode 100644 index 0000000..94dbf5c --- /dev/null +++ b/Validated.xcodeproj/xcshareddata/xcschemes/Validated-Package.xcscheme @@ -0,0 +1,82 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Validated.xcodeproj/xcshareddata/xcschemes/xcschememanagement.plist b/Validated.xcodeproj/xcshareddata/xcschemes/xcschememanagement.plist new file mode 100644 index 0000000..cbc1067 --- /dev/null +++ b/Validated.xcodeproj/xcshareddata/xcschemes/xcschememanagement.plist @@ -0,0 +1,12 @@ + + + + SchemeUserState + + Validated-Package.xcscheme + + + SuppressBuildableAutocreation + + + diff --git a/Validated.xcworkspace/contents.xcworkspacedata b/Validated.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000..40ea772 --- /dev/null +++ b/Validated.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,16 @@ + + + + + + + + + + + diff --git a/Validated.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/Validated.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 0000000..18d9810 --- /dev/null +++ b/Validated.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + +