Contents

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 CodableKit

Requirements

  • Swift tools 6.0
  • Xcode 16+ or a Swift 6.0-compatible Apple toolchain
  • swift-syntax 600.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"]]?.stringValue

Explicit 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 -v

Tests 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

MIT

Package Metadata

Repository: wendellxy/codablekit

Default branch: main

README: README.md