Skip to content

Conversation

@ecito
Copy link
Contributor

@ecito ecito commented Nov 3, 2025

Description

This PR adds support for Swift's CodingKeys enum to the @Schemable macro. When a type defines a CodingKeys enum with custom string raw values, the macro will automatically use those values as property names in the generated JSON schema.

Motivation

Currently, if you want different property names in your JSON schema than your Swift property names, you need to manually add @SchemaOptions(.key("custom_name")) to each property. This is repetitive when you already have a CodingKeys enum defined for Codable conformance.

Example Usage

Before:

@Schemable
struct User: Codable {
  @SchemaOptions(.key("first_name"))
  let firstName: String
  @SchemaOptions(.key("last_name"))
  let lastName: String
  @SchemaOptions(.key("email"))
  let emailAddress: String

  enum CodingKeys: String, CodingKey {
    case firstName = "first_name"
    case lastName = "last_name"
    case emailAddress = "email"
  }
}

After:

@Schemable
struct User: Codable {
  let firstName: String
  let lastName: String
  let emailAddress: String

  enum CodingKeys: String, CodingKey {
    case firstName = "first_name"
    case lastName = "last_name"
    case emailAddress = "email"
  }
}

Both generate the same schema with properties: "first_name", "last_name", "email"

Key Features

  • Automatic mapping: Extracts key mappings from existing CodingKeys enum
  • Partial support: Properties without CodingKeys entries fall back to property names
  • Priority system: @SchemaOptions(.key) > CodingKeys > keyStrategy > property name
  • Nested types: Each type's CodingKeys is properly scoped
  • Backward compatible: No breaking changes, purely additive

Additional Examples

Partial CodingKeys:

@Schemable
struct Product {
  let name: String           // Uses "name" (no CodingKeys entry)
  let productId: Int         // Uses "product_id" (from CodingKeys)

  enum CodingKeys: String, CodingKey {
    case productId = "product_id"
  }
}

Priority Override:

@Schemable
struct Customer {
  let firstName: String      // Uses "first_name" (from CodingKeys)
  @SchemaOptions(.key("surname"))
  let lastName: String       // Uses "surname" (@SchemaOptions takes priority)

  enum CodingKeys: String, CodingKey {
    case firstName = "first_name"
    case lastName = "last_name"  // Overridden by @SchemaOptions
  }
}

Type of Change

  • Bug fix
  • New feature
  • Breaking change
  • Documentation update

Additional Notes

  • All existing tests continue to pass
  • Added comprehensive integration tests for CodingKeys support
  • Added macro expansion tests to verify generated code
  • Implementation uses SwiftSyntax AST parsing for robustness

ecito added 2 commits November 4, 2025 00:01
The @Schemable macro now respects Swift's CodingKeys enum when generating
JSON schemas. When a type defines a CodingKeys enum with custom string raw
values, those values are used as property names in the generated schema.

Key features:
- Automatic extraction of CodingKeys mapping from enum definitions
- Support for partial CodingKeys (missing entries fall back to property names)
- Proper priority order: @SchemaOptions(.key) > CodingKeys > keyStrategy > property name
- Works with both struct and class types
- Handles nested types with their own CodingKeys

Implementation:
- Added extractCodingKeys() method to parse CodingKeys enum via SwiftSyntax
- Updated schema generation to check CodingKeys mapping before other strategies
- Maintains backward compatibility (no breaking changes)
Copy link
Owner

@ajevans99 ajevans99 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Like the idea. Let's just update to macros docc page key coding section https://swiftpackageindex.com/ajevans99/swift-json-schema/main/documentation/jsonschemabuilder/macros#Key-encoding-strategies and we're good to go

@ajevans99 ajevans99 merged commit 0b69d85 into ajevans99:main Nov 4, 2025
8 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants