diff --git a/README.md b/README.md index 5f05731..82102c5 100644 --- a/README.md +++ b/README.md @@ -26,6 +26,7 @@ Informed by explicit developer cues, MemberwiseInit can more often automatically * [Attributed properties are ignored by default, but includable](#attributed-properties-are-ignored-by-default-but-includable) * [Support for property wrappers](#support-for-property-wrappers) * [Automatic `@escaping` for closure types (usually)](#automatic-escaping-for-closure-types-usually) + * [Experimental: Unchecked memberwise initialization](#experimental-unchecked-memberwise-initialization) * [Experimental: Deunderscore parameter names](#experimental-deunderscore-parameter-names) * [Experimental: Defaulting optionals to nil](#experimental-defaulting-optionals-to-nil) * [Tuple destructuring in property declarations isn’t supported (yet)](#tuple-destructuring-in-property-declarations-isnt-supported-yet) @@ -45,7 +46,7 @@ To use MemberwiseInit: ```swift dependencies: [ - .package(url: "https://github.com/gohanlon/swift-memberwise-init-macro", from: "0.4.0") + .package(url: "https://github.com/gohanlon/swift-memberwise-init-macro", from: "0.5.0") ] ``` @@ -176,6 +177,9 @@ Attach to the property declarations of a struct that `@MemberwiseInit` is provid * `@MemberwiseInit` on `actor`, `class` *(experimental)*
Attachable to actor and class. +* `@_UncheckedMemberwiseInit` *(experimental)* +
Generate a memberwise initializer for all properties, regardless of access level, with reduced compile-time safety checks (compared to `@MemberwiseInit`). + ## Features and limitations ### Custom `init` parameter labels @@ -598,6 +602,43 @@ public init( } ``` +### Experimental: Unchecked memberwise initialization + +`@_UncheckedMemberwiseInit` is an experimental macro that bypasses compile-time safety checks and strict access control enforcement. It generates an initializer for all properties of a type, regardless of their declared access levels. Use it judiciously. + +Key characteristics: + +- Generates an initializer that includes all properties, regardless of their declared access levels +- Includes attributed properties by default (differs from `@MemberwiseInit`) +- Follows the same usage pattern as `@MemberwiseInit` + +Example: + +```swift +@_UncheckedMemberwiseInit(.public) +public struct APIResponse: Codable { + public let id: String + @Monitored internal var statusCode: Int + private var rawResponse: Data + + // Computed properties and methods... +} +``` + +This yields a public initializer that includes all properties, regardless of their access level or attributes. Unlike `@MemberwiseInit`, this macro doesn't require `@Init` annotations or any other explicit opt-ins. The resulting initializer is: + +```swift +public init( + id: String, + statusCode: Int, + rawResponse: Data +) { + self.id = id + self.statusCode = statusCode + self.rawResponse = rawResponse +} +``` + ### Experimental: Deunderscore parameter names > **Note** diff --git a/Tests/MemberwiseInitTests/ReadmeTests.swift b/Tests/MemberwiseInitTests/ReadmeTests.swift index 95777a3..2e43be3 100644 --- a/Tests/MemberwiseInitTests/ReadmeTests.swift +++ b/Tests/MemberwiseInitTests/ReadmeTests.swift @@ -11,6 +11,7 @@ final class ReadmeTests: XCTestCase { macros: [ "MemberwiseInit": MemberwiseInitMacro.self, "Init": InitMacro.self, + "_UncheckedMemberwiseInit": UncheckedMemberwiseInitMacro.self, ] ) { super.invokeTest() @@ -526,6 +527,41 @@ final class ReadmeTests: XCTestCase { } } + func testUncheckedMemberwiseInit() { + assertMacro { + """ + @_UncheckedMemberwiseInit(.internal) + public struct APIResponse: Codable { + public let id: String + @Monitored internal var statusCode: Int + private var rawResponse: Data + + // Computed properties and methods... + } + """ + } expansion: { + """ + public struct APIResponse: Codable { + public let id: String + @Monitored internal var statusCode: Int + private var rawResponse: Data + + internal init( + id: String, + statusCode: Int, + rawResponse: Data + ) { + self.id = id + self.statusCode = statusCode + self.rawResponse = rawResponse + } + + // Computed properties and methods... + } + """ + } + } + func testDeunderscoreParameterNames() { assertMacro { """