{"id":24840398,"url":"https://github.com/swiftylab/metacodable","last_synced_at":"2025-05-15T07:07:41.782Z","repository":{"id":176563605,"uuid":"655068226","full_name":"SwiftyLab/MetaCodable","owner":"SwiftyLab","description":"Supercharge Swift's Codable implementations with macros meta-programming.","archived":false,"fork":false,"pushed_at":"2025-05-04T18:23:33.000Z","size":47372,"stargazers_count":702,"open_issues_count":12,"forks_count":33,"subscribers_count":6,"default_branch":"main","last_synced_at":"2025-05-04T19:18:52.607Z","etag":null,"topics":["codable","code-generation","macro","metaprogramming","no-boilerplate","swift","swift-codable","swift-macros","swift-package-manager","swift-package-manager-plugin","swift-package-plugin","swift5-9"],"latest_commit_sha":null,"homepage":"https://swiftpackageindex.com/SwiftyLab/MetaCodable/main/documentation/metacodable","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/SwiftyLab.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"CONTRIBUTING.md","funding":".github/FUNDING.yml","license":"LICENSE","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null},"funding":{"github":["soumyamahunt"],"patreon":null,"open_collective":"soumyamahunt","ko_fi":"soumyamahunt","tidelift":null,"community_bridge":null,"liberapay":"soumyamahunt","issuehunt":null,"otechie":null,"lfx_crowdfunding":null,"custom":null}},"created_at":"2023-06-17T19:32:29.000Z","updated_at":"2025-05-04T18:23:36.000Z","dependencies_parsed_at":"2023-10-01T19:05:34.822Z","dependency_job_id":"d8230e34-8756-40b7-96b1-17e106ed25f9","html_url":"https://github.com/SwiftyLab/MetaCodable","commit_stats":null,"previous_names":["swiftylab/metacodable"],"tags_count":8,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/SwiftyLab%2FMetaCodable","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/SwiftyLab%2FMetaCodable/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/SwiftyLab%2FMetaCodable/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/SwiftyLab%2FMetaCodable/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/SwiftyLab","download_url":"https://codeload.github.com/SwiftyLab/MetaCodable/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":254292043,"owners_count":22046426,"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":["codable","code-generation","macro","metaprogramming","no-boilerplate","swift","swift-codable","swift-macros","swift-package-manager","swift-package-manager-plugin","swift-package-plugin","swift5-9"],"created_at":"2025-01-31T06:56:13.901Z","updated_at":"2025-05-15T07:07:36.773Z","avatar_url":"https://github.com/SwiftyLab.png","language":"Swift","readme":"# MetaCodable\n\n[![API Docs](http://img.shields.io/badge/Read_the-docs-2196f3.svg)](https://swiftpackageindex.com/SwiftyLab/MetaCodable/documentation/metacodable)\n[![Swift Package Manager Compatible](https://img.shields.io/github/v/tag/SwiftyLab/MetaCodable?label=SPM\u0026color=orange)](https://badge.fury.io/gh/SwiftyLab%2FMetaCodable)\n[![CocoaPods Compatible](https://img.shields.io/cocoapods/v/MetaCodable.svg?label=CocoaPods\u0026color=C90005)](https://badge.fury.io/co/MetaCodable)\n[![Swift](https://img.shields.io/badge/Swift-5.9+-orange)](https://img.shields.io/badge/Swift-5-DE5D43)\n[![Platforms](https://img.shields.io/badge/Platforms-all-sucess)](https://img.shields.io/badge/Platforms-all-sucess)\n[![CI/CD](https://github.com/SwiftyLab/MetaCodable/actions/workflows/main.yml/badge.svg)](https://github.com/SwiftyLab/MetaCodable/actions/workflows/main.yml)\n[![CodeFactor](https://www.codefactor.io/repository/github/swiftylab/metacodable/badge)](https://www.codefactor.io/repository/github/swiftylab/metacodable)\n[![codecov](https://codecov.io/gh/SwiftyLab/MetaCodable/branch/main/graph/badge.svg?token=jKxMv5oFeA)](https://codecov.io/gh/SwiftyLab/MetaCodable)\n\u003c!-- [![CodeQL](https://github.com/SwiftyLab/MetaCodable/actions/workflows/codeql-analysis.yml/badge.svg?event=schedule)](https://github.com/SwiftyLab/MetaCodable/actions/workflows/codeql-analysis.yml) --\u003e\n\nSupercharge `Swift`'s `Codable` implementations with macros.\n\n## Overview\n\n`MetaCodable` framework exposes custom macros which can be used to generate dynamic `Codable` implementations. The core of the framework is ``Codable()`` macro which generates the implementation aided by data provided with using other macros.\n\n`MetaCodable` aims to supercharge your `Codable` implementations by providing these inbox features:\n\n- Allows custom `CodingKey` value declaration per variable with ``CodedAt(_:)`` passing single argument, instead of requiring you to write all the `CodingKey` values.\n- Allows to create flattened model for nested `CodingKey` values with ``CodedAt(_:)`` and ``CodedIn(_:)``.\n- Allows to create composition of multiple `Codable` types with ``CodedAt(_:)`` passing no arguments.\n- Allows to read data from additional fallback `CodingKey`s provided with ``CodedAs(_:_:)``.\n- Allows to provide default value in case of decoding failures with ``Default(_:)``, or only in case of failures when missing value with ``Default(ifMissing:)``. Different default values can also be used for value missing and other errors respectively with ``Default(ifMissing:forErrors:)``.\n- Allows to create custom decoding/encoding strategies with ``HelperCoder`` and using them with ``CodedBy(_:)``, ``CodedBy(_:properties:)`` or others. i.e. ``LossySequenceCoder`` etc.\n- Allows specifying different case values with ``CodedAs(_:_:)`` and case value/protocol type identifier type different from `String` with ``CodedAs()``.\n- Allows specifying enum-case/protocol type identifier path with ``CodedAt(_:)`` and case content path with ``ContentAt(_:_:)``.\n- Allows decoding/encoding enums that lack distinct identifiers for each case data with ``UnTagged()``.\n- Allows to ignore specific properties/cases from decoding/encoding with ``IgnoreCoding()``, ``IgnoreDecoding()`` and ``IgnoreEncoding()``. Allows to ignore encoding based on custom conditions with ``IgnoreEncoding(if:)``.\n- Allows to use camel-case names for variables according to [Swift API Design Guidelines](https://www.swift.org/documentation/api-design-guidelines/#general-conventions), while enabling a type/case to work with different case style keys with ``CodingKeys(_:)``.\n- Allows to ignore all initialized properties of a type/case from decoding/encoding with ``IgnoreCodingInitialized()`` unless explicitly asked to decode/encode by attaching any coding attributes, i.e. ``CodedIn(_:)``, ``CodedAt(_:)``, ``CodedBy(_:)``, ``Default(_:)`` etc.\n- Allows to generate protocol decoding/encoding ``HelperCoder``s with `MetaProtocolCodable` build tool plugin from ``DynamicCodable`` types.\n\n[**See the limitations for this macro**](\u003cdoc:Limitations\u003e).\n\n## Requirements\n\n| Platform | Minimum Swift Version | Installation | Status |\n| --- | --- | --- | --- |\n| iOS 13.0+ / macOS 10.15+ / tvOS 13.0+ / watchOS 6.0+ | 5.9 | Swift Package Manager, CocoaPods | Fully Tested |\n| Linux | 5.9 | Swift Package Manager | Fully Tested |\n| Windows | 5.9.1 | Swift Package Manager | Fully Tested |\n\n## Installation\n\n\u003cdetails\u003e\n  \u003csummary\u003e\u003ch3\u003eSwift Package Manager\u003c/h3\u003e\u003c/summary\u003e\n\nThe [Swift Package Manager](https://swift.org/package-manager/) is a tool for automating the distribution of Swift code and is integrated into the `swift` compiler.\n\nOnce you have your Swift package set up, adding `MetaCodable` as a dependency is as easy as adding it to the `dependencies` value of your `Package.swift`.\n\n```swift\n.package(url: \"https://github.com/SwiftyLab/MetaCodable.git\", from: \"1.0.0\"),\n```\n\nThen you can add the `MetaCodable` module product as dependency to the `target`s of your choosing, by adding it to the `dependencies` value of your `target`s.\n\n```swift\n.product(name: \"MetaCodable\", package: \"MetaCodable\"),\n```\n\n\u003c/details\u003e\n\u003cdetails\u003e\n  \u003csummary\u003e\u003ch3\u003eCocoaPods\u003c/h3\u003e\u003c/summary\u003e\n\n[CocoaPods](https://cocoapods.org) is a dependency manager for Cocoa projects. For usage and installation instructions, visit their website. To integrate `MetaCodable` into your Xcode project using CocoaPods, specify it in your `Podfile`:\n\n```ruby\npod 'MetaCodable'\n```\n\n\u003c/details\u003e\n\n## Usage\n\n`MetaCodable` allows to get rid of boiler plate that was often needed in some typical `Codable` implementations with features like:\n\n\u003cdetails\u003e\n  \u003csummary\u003eCustom `CodingKey` value declaration per variable, instead of requiring you to write for all fields.\u003c/summary\u003e\n\n i.e. in the official [docs](https://developer.apple.com/documentation/foundation/archives_and_serialization/encoding_and_decoding_custom_types#2904057), to define custom `CodingKey` for 2 fields of `Landmark` type you had to write:\n\n```swift\nstruct Landmark: Codable {\n    var name: String\n    var foundingYear: Int\n    var location: Coordinate\n    var vantagePoints: [Coordinate]\n\n    enum CodingKeys: String, CodingKey {\n        case name = \"title\"\n        case foundingYear = \"founding_date\"\n        case location\n        case vantagePoints\n    }\n}\n```\n\nBut with `MetaCodable` all you have to write is this:\n\n```swift\n@Codable\nstruct Landmark {\n    @CodedAt(\"title\")\n    var name: String\n    @CodedAt(\"founding_date\")\n    var foundingYear: Int\n\n    var location: Coordinate\n    var vantagePoints: [Coordinate]\n}\n```\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n  \u003csummary\u003eCreate flattened model for nested `CodingKey` values.\u003c/summary\u003e\n\ni.e. in official [docs](https://developer.apple.com/documentation/foundation/archives_and_serialization/encoding_and_decoding_custom_types#2904058) to decode a JSON like this:\n\n```json\n{\n  \"latitude\": 0,\n  \"longitude\": 0,\n  \"additionalInfo\": {\n      \"elevation\": 0\n  }\n}\n```\n\nYou had to write all these boilerplate:\n\n```swift\nstruct Coordinate {\n    var latitude: Double\n    var longitude: Double\n    var elevation: Double\n\n    enum CodingKeys: String, CodingKey {\n        case latitude\n        case longitude\n        case additionalInfo\n    }\n\n    enum AdditionalInfoKeys: String, CodingKey {\n        case elevation\n    }\n}\n\nextension Coordinate: Decodable {\n    init(from decoder: Decoder) throws {\n        let values = try decoder.container(keyedBy: CodingKeys.self)\n        latitude = try values.decode(Double.self, forKey: .latitude)\n        longitude = try values.decode(Double.self, forKey: .longitude)\n\n        let additionalInfo = try values.nestedContainer(keyedBy: AdditionalInfoKeys.self, forKey: .additionalInfo)\n        elevation = try additionalInfo.decode(Double.self, forKey: .elevation)\n    }\n}\n\nextension Coordinate: Encodable {\n    func encode(to encoder: Encoder) throws {\n        var container = encoder.container(keyedBy: CodingKeys.self)\n        try container.encode(latitude, forKey: .latitude)\n        try container.encode(longitude, forKey: .longitude)\n\n        var additionalInfo = container.nestedContainer(keyedBy: AdditionalInfoKeys.self, forKey: .additionalInfo)\n        try additionalInfo.encode(elevation, forKey: .elevation)\n    }\n}\n```\n\nBut with `MetaCodable` all you have to write is this:\n\n```swift\n@Codable\nstruct Coordinate {\n    var latitude: Double\n    var longitude: Double\n\n    @CodedAt(\"additionalInfo\", \"elevation\")\n    var elevation: Double\n}\n```\n\nYou can even minimize further using `CodedIn` macro since the final `CodingKey` value is the same as field name:\n\n```swift\n@Codable\nstruct Coordinate {\n    var latitude: Double\n    var longitude: Double\n\n    @CodedIn(\"additionalInfo\")\n    var elevation: Double\n}\n```\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n  \u003csummary\u003eProvide default value in case of decoding failures.\u003c/summary\u003e\n\nInstead of throwing error in case of missing data or type mismatch, you can provide a default value that will be assigned in this case. The following definition with `MetaCodable`:\n\n```swift\n@Codable\nstruct CodableData {\n    @Default(\"some\")\n    let field: String\n}\n```\n\nwill not throw any error when empty JSON(`{}`) or JSON with type mismatch(`{ \"field\": 5 }`) is provided. The default value will be assigned in such case.\n\nAlso, memberwise initializer can be generated that uses this default value for the field.\n\n```swift\n@Codable\n@MemberInit\nstruct CodableData {\n    @Default(\"some\")\n    let field: String\n}\n```\n\nThe memberwise initializer generated will look like this:\n\n```swift\ninit(field: String = \"some\") {\n    self.field = field\n}\n```\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n  \u003csummary\u003eUse or create custom helpers to provide custom decoding/encoding.\u003c/summary\u003e\n\nLibrary provides following helpers that address common custom decoding/encoding needs:\n\n- `LossySequenceCoder` to decode only valid data while ignoring invalid data in a sequence, instead of traditional way of failing decoding entirely.\n- `ValueCoder` to decode `Bool`, `Int`, `Double`, `String` etc. basic types even if they are represented in some other type, i.e decoding `Int` from `\"1\"`, decoding boolean from `\"yes\"` etc.\n- Custom Date decoding/encoding with UNIX timestamp (`Since1970DateCoder`) or date formatters (`DateCoder`, `ISO8601DateCoder`).\n- `Base64Coder` to decode/encode data in base64 string representation.\n\nAnd more, see the full documentation for [`HelperCoders`](https://swiftpackageindex.com/SwiftyLab/MetaCodable/documentation/helpercoders) for more details.\n\nYou can even create your own by conforming to `HelperCoder`.\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n  \u003csummary\u003eRepresent data with variations in the form of external/internal/adjacent tagging or lack of any tagging, with single enum with each case as a variation or a protocol type (lack of tagging not supported) that varies with conformances across modules.\u003c/summary\u003e\n\n i.e. while `Swift` compiler only generates implementation assuming external tagged enums, only following data:\n\n```json\n[\n  {\n    \"load\": {\n      \"key\": \"MyKey\"\n    }\n  },\n  {\n    \"store\": {\n      \"key\": \"MyKey\",\n      \"value\": 42\n    }\n  }\n]\n```\n\ncan be represented by following `enum` with current compiler implementation:\n\n```swift\nenum Command {\n    case load(key: String)\n    case store(key: String, value: Int)\n}\n```\n\nwhile `MetaCodable` allows data in both of the following format to be represented by above `enum` as well:\n\n```json\n[\n  {\n    \"type\": \"load\",\n    \"key\": \"MyKey\"\n  },\n  {\n    \"type\": \"store\",\n    \"key\": \"MyKey\",\n    \"value\": 42\n  }\n]\n```\n\n```json\n[\n  {\n    \"type\": \"load\",\n    \"content\": {\n      \"key\": \"MyKey\"\n    }\n  },\n  {\n    \"type\": \"store\",\n    \"content\": {\n      \"key\": \"MyKey\",\n      \"value\": 42\n    }\n  }\n]\n```\n\n\u003c/details\u003e\n\nSee the full documentation for [`MetaCodable`](https://swiftpackageindex.com/SwiftyLab/MetaCodable/documentation/metacodable) and [`HelperCoders`](https://swiftpackageindex.com/SwiftyLab/MetaCodable/documentation/helpercoders), for API details and advanced use cases.\nAlso, [see the limitations](Sources/MetaCodable/MetaCodable.docc/Limitations.md).\n\n## Contributing\n\nIf you wish to contribute a change, suggest any improvements,\nplease review our [contribution guide](CONTRIBUTING.md),\ncheck for open [issues](https://github.com/SwiftyLab/MetaCodable/issues), if it is already being worked upon\nor open a [pull request](https://github.com/SwiftyLab/MetaCodable/pulls).\n\n## License\n\n`MetaCodable` is released under the MIT license. [See LICENSE](LICENSE) for details.\n","funding_links":["https://github.com/sponsors/soumyamahunt","https://opencollective.com/soumyamahunt","https://ko-fi.com/soumyamahunt","https://liberapay.com/soumyamahunt"],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fswiftylab%2Fmetacodable","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fswiftylab%2Fmetacodable","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fswiftylab%2Fmetacodable/lists"}