Repository: gohanlon/swift-memberwise-init-macro (swift)

Issue:
Support `package` access modifier
### Description

Swift 5.9 has a new access modifier: `package` access ([SE-0386](https://github.com/apple/swift-evolution/blob/main/proposals/0386-package-access-modifier.md)).

(Thanks @davdroman, tracking #5.)

### Checklist

- [X] If possible, I've reproduced the issue using the `main` branch of this package.
- [X] This issue hasn't been addressed in an [existing GitHub issue](https://github.com/gohanlon/swift-memberwise-init-macro/issues) or [discussion](https://github.com/gohanlon/swift-memberwise-init-macro/discussions).

Pull request description:
Fixes #6.

This builds upon the work done in PR #5 by David Roman, with the following changes:

* Don't default to `optionalsDefaultNil` for `package` access level
* Add tests

Patch:
diff --git a/Sources/MemberwiseInit/MemberwiseInit.swift b/Sources/MemberwiseInit/MemberwiseInit.swift
index 18edce9..e346f6c 100644
--- a/Sources/MemberwiseInit/MemberwiseInit.swift
+++ b/Sources/MemberwiseInit/MemberwiseInit.swift
@@ -2,6 +2,7 @@ public enum AccessLevelConfig {
   case `private`
   case `fileprivate`
   case `internal`
+  case `package`
   case `public`
   case `open`
 }
diff --git a/Sources/MemberwiseInitMacros/Macros/MemberwiseInitMacro.swift b/Sources/MemberwiseInitMacros/Macros/MemberwiseInitMacro.swift
index 0161948..a3b6ae7 100644
--- a/Sources/MemberwiseInitMacros/Macros/MemberwiseInitMacro.swift
+++ b/Sources/MemberwiseInitMacros/Macros/MemberwiseInitMacro.swift
@@ -310,7 +310,7 @@ public struct MemberwiseInitMacro: MemberMacro {
     return switch initAccessLevel {
     case .private, .fileprivate, .internal:
       true
-    case .public, .open:
+    case .package, .public, .open:
       false
     }
   }
diff --git a/Sources/MemberwiseInitMacros/Macros/Support/AccesssLevelSyntax.swift b/Sources/MemberwiseInitMacros/Macros/Support/AccesssLevelSyntax.swift
index afc5dfe..f48e9d0 100644
--- a/Sources/MemberwiseInitMacros/Macros/Support/AccesssLevelSyntax.swift
+++ b/Sources/MemberwiseInitMacros/Macros/Support/AccesssLevelSyntax.swift
@@ -17,6 +17,7 @@ enum AccessLevelModifier: String, Comparable, CaseIterable, Sendable {
   case `private`
   case `fileprivate`
   case `internal`
+  case `package`
   case `public`
   case `open`
 
@@ -25,6 +26,7 @@ enum AccessLevelModifier: String, Comparable, CaseIterable, Sendable {
     case .private: return .private
     case .fileprivate: return .fileprivate
     case .internal: return .internal
+    case .package: return .package
     case .public: return .public
     case .open: return .open
     }


Test patch:
diff --git a/Tests/MemberwiseInitTests/MemberwiseInitTests.swift b/Tests/MemberwiseInitTests/MemberwiseInitTests.swift
index 49fda97..5751e38 100644
--- a/Tests/MemberwiseInitTests/MemberwiseInitTests.swift
+++ b/Tests/MemberwiseInitTests/MemberwiseInitTests.swift
@@ -885,6 +885,10 @@ final class MemberwiseInitTests: XCTestCase {
       internal struct Person {
       }
 
+      @MemberwiseInit
+      package struct Person {
+      }
+
       @MemberwiseInit
       public struct Person {
       }
@@ -915,6 +919,11 @@ final class MemberwiseInitTests: XCTestCase {
           internal init() {
           }
       }
+      package struct Person {
+
+          internal init() {
+          }
+      }
       public struct Person {
 
           internal init() {
@@ -929,9 +938,9 @@ final class MemberwiseInitTests: XCTestCase {
     }
   }
 
-  // NB: This is almost covered by the exhaustive AccessLevelTests, but `open class Person`
-  // is missing. This test touches on all the access levels (instead of a meaningful few).
-  func testDefaultInitAccessLeves() {
+  // NB: This is almost covered by the exhaustive AccessLevelTests. This test touches on all the
+  // access levels (instead of a meaningful few).
+  func testDefaultInitAccessLevels() {
     assertMacro {
       """
       @MemberwiseInit
@@ -954,6 +963,11 @@ final class MemberwiseInitTests: XCTestCase {
         fileprivate let name: String
       }
 
+      @MemberwiseInit
+      package struct Person {
+        let name: String
+      }
+
       @MemberwiseInit
       public struct Person {
         let name: String
@@ -1002,6 +1016,15 @@ final class MemberwiseInitTests: XCTestCase {
           self.name = name
         }
       }
+      package struct Person {
+        let name: String
+
+        internal init(
+          name: String
+        ) {
+          self.name = name
+        }
+      }
       public struct Person {
         let name: String
 
@@ -1053,6 +1076,29 @@ final class MemberwiseInitTests: XCTestCase {
     }
   }
 
+  func testMemberwiseInitPackage_PublicStruct_PublicProperty_PackageInit() throws {
+    assertMacro {
+      """
+      @MemberwiseInit(.package)
+      public struct Person {
+        public let firstName: String
+      }
+      """
+    } expansion: {
+      """
+      public struct Person {
+        public let firstName: String
+
+        package init(
+          firstName: String
+        ) {
+          self.firstName = firstName
+        }
+      }
+      """
+    }
+  }
+
   func testPublicStruct_PublicAndFileprivateProperty_FileprivateInit() {
     assertMacro {
       """
@@ -1854,6 +1900,29 @@ final class MemberwiseInitTests: XCTestCase {
     }
   }
 
+  func testOptionalVarProperty_PackageInitNoDefault() {
+    assertMacro {
+      """
+      @MemberwiseInit(.public)
+      public struct Person {
+        package var nickname: String?
+      }
+      """
+    } expansion: {
+      """
+      public struct Person {
+        package var nickname: String?
+
+        package init(
+          nickname: String?
+        ) {
+          self.nickname = nickname
+        }
+      }
+      """
+    }
+  }
+
   func testOptionalVarProperty_PublicInitNoDefault() {
     assertMacro {
       """