New: flat keyword initializer (2.12.0)
@Mapper now generates a third member for every attached struct/class: a plain, labeled "keyword" initializer that mirrors the canonical initializer's own labels, order, and types exactly, with each field wrapped in an independent () -> T closure — an ordinary Swift call instead of the existing Builder-DSL block:
// Builder-DSL (unchanged, still generated):
Address { Street, City, PostalCode in
Street { rawInput.line1 }
City { rawInput.city.capitalized }
PostalCode { rawInput.zip.trimmed() }
}
// New: flat keyword initializer
Address(
street: { rawInput.line1 },
city: { rawInput.city.capitalized },
postalCode: { rawInput.zip.trimmed() }
)Both initializers are always generated together; neither replaces the other. Purely additive — no breaking changes.
Fix: no .execute() needed for Rule fields in the keyword initializer (2.13.0)
The keyword initializer's per-field Rule resolution was redesigned to use a private, per-position RuleBuilder<T> typealias attached to each field's closure parameter, instead of requiring an explicit .execute() call. Each field independently resolves a plain value or a child Rule via RuleBuilder's existing buildExpression overloads.
This also avoids a recurrence of a known Swift compiler bug (swiftlang/swift#70087) where a type's hand-written == (or other operator) alongside an arbitrary-named member macro gets misreported as colliding with itself. The fix uses a fixed, statically-named list of typealiases (via named(...)), at the cost of a documented, diagnosed 32-field cap on the keyword initializer only — the Builder-DSL initializer is unaffected.
Upgrading
No source changes required — this is a drop-in upgrade. If you generate a diagnostic about exceeding 32 fields in the keyword initializer, switch that initializer's call to the Builder-DSL form instead.