wendellxy/codablekit
> Compile-time Codable macros for resilient Swift models.
Quick Start
import CodableKit
@Codable
struct User {
@CodableKey("data.uid")
let id: Int
var name: String
var age: Int = 24
@CodableHook(.didDecode)
mutating func normalize() {
name = name.trimmingCharacters(in: .whitespacesAndNewlines)
}
}That single model gets generated CodingKeys, init(from:), and encode(to:) implementations with nested key support, default fallback behavior, and an explicit post-decode hook.
Feature Highlights
| Capability | Example | What you get | | --- | --- | --- | | Generated conformance | @Codable, @Encodable, @Decodable | Compile-time synthesis with predictable output | | Default values | var retries: Int = 3 | Missing keys can fall back without hand-written decode code | | Nested coding keys | @CodableKey("profile.info.name") | Deep key-path mapping without manual containers | | Graceful failure | @CodableKey(options: .useDefaultOnFailure) | Recover from bad payloads by falling back to defaults or nil | | Raw-string transcoding | @CodableKey(options: .safeTranscodeRawString) | Decode string-encoded JSON into strongly typed models | | Lossy collections | @CodableKey(options: .lossy) | Drop invalid array, set, or dictionary entries during decode | | Explicit hooks | @CodableHook(.didDecode) | Run validation, normalization, or derived-value logic at clear lifecycle stages | | Transformer pipelines | @CodableKey(transformer: MyTransformer()) | Compose reusable decode and encode transformations |
Targets
| Target | Purpose | | --- | --- | | CodableKit | Public facade that exports macros, hooks, transformers, lossy wrappers, and compatibility shims | | CodableKitCore | Canonical shared option definitions consumed by both runtime and macro targets | | CodableKitMacros | SwiftSyntax-based code generation, diagnostics, and compiler plugin entry points |
Installation
Add CodableKit to your Swift Package Manager dependencies:
.package(url: "https://github.com/WendellXY/CodableKit.git", from: "2.0.0")Then import it where you declare your models:
import CodableKitRequirements
- Swift tools 6.0
- Xcode 16+ or a Swift 6.0-compatible Apple toolchain
swift-syntax600.x- macOS 10.15+, iOS 13+, tvOS 13+, watchOS 6+, Mac Catalyst 13+, visionOS 1+
If you need the legacy Swift 5 line that targets swift-syntax 510.x, use from: "0.4.0" instead.
Examples
Nested keys and defaults
@Codable
struct Session {
@CodableKey("meta.version")
var version: Int = 1
@CodableKey("user.profile.name")
let name: String
}Lossy collections and raw-string payloads
@Codable
struct Feed {
@CodableKey(options: [.lossy, .safeTranscodeRawString])
var items: [Item] = []
}Dynamic JSON values
@Codable
struct Payload {
var value: JSONValue
}
let payload = try JSONDecoder().decode(
Payload.self,
from: #"{"value":{"name":"Ada","flags":[true,null]}}"#.data(using: .utf8)!
)
let name = payload.value["name"]?.stringValue
let firstFlag = payload.value["flags"]?[0]?.boolValue
let sameValue = try JSONValue(jsonString: #"{"name":"Ada","flags":[true,null]}"#)
let nestedName = sameValue[path: ["name"]]?.stringValueExplicit lifecycle hooks
@Encodable
struct AuditEvent {
var createdAt: Date
@CodableHook(.willEncode)
func validate() throws {
// validate or normalize before encoding
}
}In v2, hooks are explicit. Conventional method names alone are not invoked anymore. See MIGRATION.md for the upgrade path.
Development
swift build -v
swift test -vTests cover macro expansion, diagnostics, hooks, inheritance, lossy coding, nested keys, and transformer behavior.
Docs
- Migration Guide: breaking changes and upgrade notes for v2
- Roadmap: current priorities and planned work
- Swift Package Index: compatibility, metadata, and package discovery
- Tests: real examples for structs, classes, enums, hooks, diagnostics, and transformers
License
Package Metadata
Repository: wendellxy/codablekit
Default branch: main
README: README.md