{"id":15882640,"url":"https://github.com/sventiigi/validatedpropertykit","last_synced_at":"2025-05-16T11:06:39.285Z","repository":{"id":44454252,"uuid":"193634095","full_name":"SvenTiigi/ValidatedPropertyKit","owner":"SvenTiigi","description":"Easily validate your Properties with Property Wrappers 👮","archived":false,"fork":false,"pushed_at":"2024-01-08T06:59:50.000Z","size":417,"stargazers_count":981,"open_issues_count":2,"forks_count":46,"subscribers_count":18,"default_branch":"main","last_synced_at":"2025-05-09T17:21:27.417Z","etag":null,"topics":["ios","propertywrapper","swift","swift-package","swiftui","validated","validation"],"latest_commit_sha":null,"homepage":"https://sventiigi.github.io/ValidatedPropertyKit","language":"Swift","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/SvenTiigi.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":".github/FUNDING.yml","license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null},"funding":{"github":"SvenTiigi"}},"created_at":"2019-06-25T04:23:58.000Z","updated_at":"2025-04-24T07:47:11.000Z","dependencies_parsed_at":"2024-01-16T15:14:31.457Z","dependency_job_id":"9a59078f-6480-4b71-973a-5a15bcbe34e4","html_url":"https://github.com/SvenTiigi/ValidatedPropertyKit","commit_stats":{"total_commits":97,"total_committers":2,"mean_commits":48.5,"dds":"0.010309278350515427","last_synced_commit":"632978d0fe4e4962b3f88f0d53adc61fe1019072"},"previous_names":[],"tags_count":7,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/SvenTiigi%2FValidatedPropertyKit","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/SvenTiigi%2FValidatedPropertyKit/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/SvenTiigi%2FValidatedPropertyKit/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/SvenTiigi%2FValidatedPropertyKit/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/SvenTiigi","download_url":"https://codeload.github.com/SvenTiigi/ValidatedPropertyKit/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":254518383,"owners_count":22084374,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["ios","propertywrapper","swift","swift-package","swiftui","validated","validation"],"created_at":"2024-10-06T04:05:57.046Z","updated_at":"2025-05-16T11:06:34.266Z","avatar_url":"https://github.com/SvenTiigi.png","language":"Swift","funding_links":["https://github.com/sponsors/SvenTiigi"],"categories":[],"sub_categories":[],"readme":"\u003cbr/\u003e\n\n\u003cp align=\"center\"\u003e\n   \u003cimg width=\"30%\" src=\"Assets/logo.png\" alt=\"ValidatedPropertyKit Logo\"\u003e\n\u003c/p\u003e\n\n\u003ch1 align=\"center\"\u003e\n    ValidatedPropertyKit\n\u003c/h1\u003e\n\n\u003cp align=\"center\"\u003e\n   A Swift Package to easily validate your properties using Property Wrappers 👮\n\u003c/p\u003e\n\n\u003cp align=\"center\"\u003e\n   \u003ca href=\"https://swiftpackageindex.com/SvenTiigi/ValidatedPropertyKit\"\u003e\n    \u003cimg src=\"https://img.shields.io/endpoint?url=https%3A%2F%2Fswiftpackageindex.com%2Fapi%2Fpackages%2FSvenTiigi%2FValidatedPropertyKit%2Fbadge%3Ftype%3Dswift-versions\" alt=\"Swift Version\"\u003e\n   \u003c/a\u003e\n   \u003ca href=\"https://swiftpackageindex.com/SvenTiigi/ValidatedPropertyKit\"\u003e\n    \u003cimg src=\"https://img.shields.io/endpoint?url=https%3A%2F%2Fswiftpackageindex.com%2Fapi%2Fpackages%2FSvenTiigi%2FValidatedPropertyKit%2Fbadge%3Ftype%3Dplatforms\" alt=\"Platforms\"\u003e\n   \u003c/a\u003e\n   \u003cbr/\u003e\n   \u003ca href=\"https://github.com/SvenTiigi/ValidatedPropertyKit/actions/workflows/build_and_test.yml\"\u003e\n       \u003cimg src=\"https://github.com/SvenTiigi/ValidatedPropertyKit/actions/workflows/build_and_test.yml/badge.svg\" alt=\"Build and Test Status\"\u003e\n   \u003c/a\u003e\n   \u003ca href=\"https://sventiigi.github.io/ValidatedPropertyKit/documentation/validatedpropertykit/\"\u003e\n       \u003cimg src=\"https://img.shields.io/badge/Documentation-DocC-blue\" alt=\"Documentation\"\u003e\n   \u003c/a\u003e\n   \u003ca href=\"https://twitter.com/SvenTiigi/\"\u003e\n      \u003cimg src=\"https://img.shields.io/badge/Twitter-@SvenTiigi-blue.svg?style=flat\" alt=\"Twitter\"\u003e\n   \u003c/a\u003e\n\u003c/p\u003e\n\n```swift\nimport SwiftUI\nimport ValidatedPropertyKit\n\nstruct LoginView: View {\n\n    @Validated(!.isEmpty \u0026\u0026 .isEmail)\n    var mailAddress = String()\n\n    @Validated(.range(8...))\n    var password = String()\n\n    var body: some View {\n        List {\n            TextField(\n               \"E-Mail\",\n               text: self.$mailAddress\n            )\n            if self._mailAddress.isInvalidAfterChanges {\n                Text(verbatim: \"Please enter a valid E-Mail address.\")\n            }\n            TextField(\n               \"Password\",\n               text: self.$password\n            )\n            if self._password.isInvalidAfterChanges {\n                Text(verbatim: \"Please enter a valid password.\")\n            }\n            Button {\n               print(\"Login\", self.mailAddress, self.password)\n            } label: {\n               Text(verbatim: \"Submit\")\n            }\n            .validated(\n                self._mailAddress,\n                self._password\n            )\n        }\n    }\n\n}\n```\n\n## Features\n\n- [x] Easily validate your properties 👮\n- [x] Predefined validations 🚦\n- [x] Logical Operators to combine validations 🔗\n- [x] Customization and configuration to your needs 💪\n\n## Installation\n\n### Swift Package Manager\n\nTo integrate using Apple's [Swift Package Manager](https://swift.org/package-manager/), add the following as a dependency to your `Package.swift`:\n\n```swift\ndependencies: [\n    .package(url: \"https://github.com/SvenTiigi/ValidatedPropertyKit.git\", from: \"0.0.6\")\n]\n```\n\nOr navigate to your Xcode project then select `Swift Packages`, click the “+” icon and search for `ValidatedPropertyKit`.\n\n### Manually\n\nIf you prefer not to use any of the aforementioned dependency managers, you can integrate ValidatedPropertyKit into your project manually. Simply drag the `Sources` Folder into your Xcode project.\n\n## Validated 👮‍♂️\n\nThe `@Validated` attribute allows you to specify a validation alongside to the declaration of your property.\n\n\u003e **Note**: @Validated supports SwiftUI View updates and will basically work the same way as @State does.\n\n```swift\n@Validated(!.isEmpty)\nvar username = String()\n\n@Validated(.hasPrefix(\"https\"))\nvar avatarURL: String?\n```\n\nIf `@Validated` is applied on an optional type e.g. `String?` you can specify whether the validation should fail or succeed when the value is `nil`.\n\n```swift\n@Validated(\n   .isURL \u0026\u0026 .hasPrefix(\"https\"),\n   isNilValid: true\n)\nvar avatarURL: String?\n```\n\n\u003e By default the argument `nilValidation` is set to `.constant(false)`\n\nIn addition the `SwiftUI.View` extension `validated()` allows you to disable or enable a certain `SwiftUI.View` based on your `@Validated` properties. The `validated()` function will disable the `SwiftUI.View` if at least one of the passed in `@Validated` properties evaluates to `false`.\n\n```swift\n@Validated(!.isEmpty \u0026\u0026 .contains(\"@\"))\nvar mailAddress = String()\n\n@Validated(.range(8...))\nvar password = String()\n\nButton(\n   action: {},\n   label: { Text(\"Submit\") }\n)\n.validated(self._mailAddress \u0026\u0026 self._password)\n```\n\n\u003e By using the underscore notation you are passing the `@Validated` property wrapper to the `validated()` function\n\n## Validation 🚦\n\nEach `@Validated` attribute will be initialized with a `Validation` which can be initialized with a simple closure that must return a `Bool` value.\n\n```swift\n@Validated(.init { value in\n   value.isEmpty\n})\nvar username = String()\n```\n\nTherefore, ValidatedPropertyKit comes along with many built-in convenience functions for various types and protocols.\n\n```swift\n@Validated(!.contains(\"Android\", options: .caseInsensitive))\nvar favoriteOperatingSystem = String()\n\n@Validated(.equals(42))\nvar magicNumber = Int()\n\n@Validated(.keyPath(\\.isEnabled, .equals(true)))\nvar object = MyCustomObject()\n```\n\n\u003e Head over the [Predefined Validations](https://github.com/SvenTiigi/ValidatedPropertyKit#predefined-validations) section to learn more\n\nAdditionally, you can extend the `Validation` via conditional conformance to easily declare your own Validations.\n\n```swift\nextension Validation where Value == Int {\n\n    /// Will validate if the Integer is the meaning of life\n    static var isMeaningOfLife: Self {\n        .init { value in\n            value == 42\n        }\n    }\n\n}\n```\n\nAnd apply them to your validated property.\n\n```swift\n@Validated(.isMeaningOfLife)\nvar number = Int()\n```\n\n## isValid ✅\n\nYou can access the `isValid` state at anytime by using the underscore notation to directly access the `@Validated` property wrapper.\n\n```swift\n@Validated(!.isEmpty)\nvar username = String()\n\nusername = \"Mr.Robot\"\nprint(_username.isValid) // true\n\nusername = \"\"\nprint(_username.isValid) // false\n```\n\n## Validation Operators 🔗\n\nValidation Operators allowing you to combine multiple Validations like you would do with Bool values.\n\n```swift\n// Logical AND\n@Validated(.hasPrefix(\"https\") \u0026\u0026 .hasSuffix(\"png\"))\nvar avatarURL = String()\n\n// Logical OR\n@Validated(.hasPrefix(\"Mr.\") || .hasPrefix(\"Mrs.\"))\nvar name = String()\n\n// Logical NOT\n@Validated(!.contains(\"Android\", options: .caseInsensitive))\nvar favoriteOperatingSystem = String()\n```\n\n## Predefined Validations\n\nThe `ValidatedPropertyKit` comes with many predefined common validations which you can make use of in order to specify a `Validation` for your validated property.\n\n**KeyPath**\n\nThe `keyPath` validation will allow you to specify a validation for a given `KeyPath` of the attributed property.\n\n```swift\n@Validated(.keyPath(\\.isEnabled, .equals(true)))\nvar object = MyCustomObject()\n```\n\n**Strings**\n\nA String property can be validated in many ways like `contains`, `hasPrefix` and even `RegularExpressions`.\n\n```swift\n@Validated(.isEmail)\nvar string = String()\n\n@Validated(.contains(\"Mr.Robot\"))\nvar string = String()\n\n@Validated(.hasPrefix(\"Mr.\"))\nvar string = String()\n\n@Validated(.hasSuffix(\"OS\"))\nvar string = String()\n\n@Validated(.regularExpression(\"[0-9]+$\"))\nvar string = String()\n```\n\n**Equatable**\n\nA `Equatable` type can be validated against a specified value.\n\n```swift\n@Validated(.equals(42))\nvar number = Int()\n```\n\n**Sequence**\n\nA property of type `Sequence` can be validated via the `contains` or `startsWith` validation.\n\n```swift\n@Validated(.contains(\"Mr.Robot\", \"Elliot\"))\nvar sequence = [String]()\n\n@Validated(.startsWith(\"First Entry\"))\nvar sequence = [String]()\n```\n\n**Collection**\n\nEvery `Collection` type offers the `isEmpty` validation and the `range` validation where you can easily declare the valid capacity.\n\n```swift\n@Validated(!.isEmpty)\nvar collection = [String]()\n\n@Validated(.range(1...10))\nvar collection = [String]()\n```\n\n**Comparable**\n\nA `Comparable` type can be validated with all common comparable operators.\n\n```swift\n@Validated(.less(50))\nvar comparable = Int()\n\n@Validated(.lessOrEqual(50))\nvar comparable = Int()\n\n@Validated(.greater(50))\nvar comparable = Int()\n\n@Validated(.greaterOrEqual(50))\nvar comparable = Int()\n```\n\n## License\n\n```\nValidatedPropertyKit\nCopyright (c) 2022 Sven Tiigi sven.tiigi@gmail.com\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in\nall copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\nTHE SOFTWARE.\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsventiigi%2Fvalidatedpropertykit","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fsventiigi%2Fvalidatedpropertykit","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsventiigi%2Fvalidatedpropertykit/lists"}