Skip to content

Commit ab61565

Browse files
authored
feat: added common strategies applicable to all properties (#129)
1 parent cc973b0 commit ab61565

36 files changed

+1130
-55
lines changed

Examples/App/Sources/ContentView.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1-
import SwiftUI
2-
import MetaCodable
31
import HelperCoders
2+
import MetaCodable
3+
import SwiftUI
44

55
public struct ContentView: View {
66
public init() {}

Package.swift

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
// swift-tools-version: 6.0
2+
// swift-format-ignore-file
23

4+
import CompilerPluginSupport
35
import Foundation
46
import PackageDescription
5-
import CompilerPluginSupport
67

78
let package = Package(
89
name: "MetaCodable",

Package@swift-5.swift

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
// swift-tools-version: 5.9
2+
// swift-format-ignore-file
23

4+
import CompilerPluginSupport
35
import Foundation
46
import PackageDescription
5-
import CompilerPluginSupport
67

78
let package = Package(
89
name: "MetaCodable",

README.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ Supercharge `Swift`'s `Codable` implementations with macros.
1414

1515
## Overview
1616

17-
`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.
17+
`MetaCodable` framework exposes custom macros which can be used to generate dynamic `Codable` implementations. The core of the framework is ``Codable(commonStrategies:)`` macro which generates the implementation aided by data provided with using other macros.
1818

1919
`MetaCodable` aims to supercharge your `Codable` implementations by providing these inbox features:
2020

@@ -24,6 +24,7 @@ Supercharge `Swift`'s `Codable` implementations with macros.
2424
- Allows to read data from additional fallback `CodingKey`s provided with ``CodedAs(_:_:)``.
2525
- 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:)``.
2626
- Allows to create custom decoding/encoding strategies with ``HelperCoder`` and using them with ``CodedBy(_:)``, ``CodedBy(_:properties:)`` or others. i.e. ``LossySequenceCoder`` etc.
27+
- Allows applying common strategies like `ValueCoder` to all properties of a type through the ``Codable(commonStrategies:)`` parameter, reducing the need for repetitive property annotations.
2728
- Allows specifying different case values with ``CodedAs(_:_:)`` and case value/protocol type identifier type different from `String` with ``CodedAs()``.
2829
- Allows specifying enum-case/protocol type identifier path with ``CodedAt(_:)`` and case content path with ``ContentAt(_:_:)``.
2930
- Allows decoding/encoding enums that lack distinct identifiers for each case data with ``UnTagged()``.

Sources/HelperCoders/HelperCoders.docc/HelperCoders.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,3 +75,7 @@ Level up `MetaCodable`'s generated implementations with helpers assisting common
7575
### Sequence
7676

7777
- ``SequenceCoder``
78+
79+
### Strategies
80+
81+
- ``HelperCoderStrategy``
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
import MetaCodable
2+
3+
/// An enumeration of supported helper coder strategies for use with the `@Codable` macro's `commonStrategies` parameter.
4+
///
5+
/// Use cases such as `.valueCoder()` allow you to specify that all properties should use a particular value coding strategy
6+
/// (e.g., `ValueCoder`) for encoding and decoding, without annotating each property individually.
7+
public enum HelperCoderStrategy {
8+
/// Applies the `ValueCoder` strategy to all properties, optionally specifying additional types.
9+
case valueCoder(_ additionalTypes: [any ValueCodingStrategy.Type] = [])
10+
// Future cases can be added here
11+
}
12+
13+
public extension CodableCommonStrategy {
14+
/// Returns a `CodableCommonStrategy` representing the use of a helper coder strategy for all properties.
15+
///
16+
/// - Parameter helperCoderStrategy: The helper coder strategy to apply (e.g., `.valueCoder()`).
17+
/// - Returns: A `CodableCommonStrategy` value for use in the `commonStrategies` parameter of `@Codable`.
18+
static func codedBy(_ helperCoderStrategy: HelperCoderStrategy) -> Self {
19+
return .init()
20+
}
21+
}

Sources/MetaCodable/Codable/Codable.swift

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,10 @@
4646
/// * If attached declaration already conforms to `Codable` this macro expansion
4747
/// is skipped.
4848
///
49+
/// - Parameters:
50+
/// - commonStrategies: An array of CodableCommonStrategy values specifying
51+
/// type conversion strategies to be automatically applied to all properties of the type.
52+
///
4953
/// - Important: The attached declaration must be of a `struct`, `class`, `enum`
5054
/// or `actor` type. [See the limitations for this macro](<doc:Limitations>).
5155
@attached(
@@ -58,17 +62,17 @@
5862
names: named(CodingKeys), named(init(from:)), named(encode(to:))
5963
)
6064
@available(swift 5.9)
61-
public macro Codable() =
65+
public macro Codable(commonStrategies: [CodableCommonStrategy] = []) =
6266
#externalMacro(module: "MacroPlugin", type: "Codable")
6367

6468
/// Indicates whether super class conforms to `Codable` or not.
6569
///
66-
/// By default, ``Codable()`` assumes class inherits `Decodable`
70+
/// By default, ``Codable(commonStrategies:)`` assumes class inherits `Decodable`
6771
/// or `Encodable` conformance if it doesn't receive protocol needs
6872
/// to be conformed from the compiler. Using this macro, it can be explicitly
6973
/// indicated that the class doesn't inherit conformance in such cases.
7074
///
71-
/// Following code indicates ``Codable()`` that `Item` class doesn't
75+
/// Following code indicates ``Codable(commonStrategies:)`` that `Item` class doesn't
7276
/// inherit conformance:
7377
/// ```swift
7478
/// @Codable
@@ -87,7 +91,7 @@ public macro Codable() =
8791
/// - encodable: Whether super class conforms to `Encodable`.
8892
///
8993
/// - Note: This macro on its own only validates if attached declaration
90-
/// is a class declaration. ``Codable()`` macro uses this macro
94+
/// is a class declaration. ``Codable(commonStrategies:)`` macro uses this macro
9195
/// when generating final implementations.
9296
@attached(peer)
9397
@available(swift 5.9)
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
// CodableCommonStrategy.swift
2+
// Defines the CodableCommonStrategy struct for commonStrategies parameter in @Codable macro.
3+
4+
/// A marker type used to represent a common type conversion strategy for the `@Codable` macro.
5+
///
6+
/// `CodableCommonStrategy` is used as the element type for the `commonStrategies` parameter in the
7+
/// `@Codable` macro. It allows users to specify strategies (such as value coding) that should be
8+
/// automatically applied to all properties of a type, so that users do not have to annotate each property
9+
/// individually. The macro system interprets these strategies and injects the appropriate coding logic
10+
/// during macro expansion.
11+
///
12+
/// Example usage:
13+
/// ```swift
14+
/// @Codable(commonStrategies: [.codedBy(.valueCoder())])
15+
/// struct MyModel {
16+
/// let int: Int
17+
/// let string: String
18+
/// }
19+
/// ```
20+
public struct CodableCommonStrategy {
21+
// Only allow MetaCodable to construct
22+
package init() {}
23+
}

Sources/MetaCodable/Codable/CodingKeys.swift

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@
2525
/// let description: String
2626
/// }
2727
/// ```
28-
/// The ``Codable()`` macro generated code will transform field names
28+
/// The ``Codable(commonStrategies:)`` macro generated code will transform field names
2929
/// to snake-case in the `Codable` implementation.
3030
///
3131
/// Similarly, for enums associated value label can be kept camel-cased while
@@ -88,10 +88,10 @@
8888
/// ``CodedAt(_:)`` will remain unchanged.
8989
///
9090
/// - Note: This macro on its own only validates if attached declaration
91-
/// is a variable declaration. ``Codable()`` macro uses this macro
91+
/// is a variable declaration. ``Codable(commonStrategies:)`` macro uses this macro
9292
/// when generating final implementations.
9393
///
94-
/// - Important: This attribute must be used combined with ``Codable()``.
94+
/// - Important: This attribute must be used combined with ``Codable(commonStrategies:)``.
9595
///
9696
/// [Swift API Design Guidelines]:
9797
/// https://www.swift.org/documentation/api-design-guidelines/#general-conventions

Sources/MetaCodable/Codable/IgnoreCodingInitialized.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -57,10 +57,10 @@
5757
/// while `notIgnored` is decoded and encoded.
5858
///
5959
/// - Note: This macro on its own only validates if attached declaration
60-
/// is a variable declaration. ``Codable()`` macro uses this macro
60+
/// is a variable declaration. ``Codable(commonStrategies:)`` macro uses this macro
6161
/// when generating final implementations.
6262
///
63-
/// - Important: This attribute must be used combined with ``Codable()``.
63+
/// - Important: This attribute must be used combined with ``Codable(commonStrategies:)``.
6464
@attached(peer)
6565
@available(swift 5.9)
6666
public macro IgnoreCodingInitialized() =

0 commit comments

Comments
 (0)