{"id":26120636,"url":"https://github.com/swiftrex/swiftrexmacros","last_synced_at":"2025-06-18T03:36:53.783Z","repository":{"id":203631732,"uuid":"710054272","full_name":"SwiftRex/SwiftRexMacros","owner":"SwiftRex","description":"Macros to help automating SwiftRex boilerplate","archived":false,"fork":false,"pushed_at":"2024-04-06T02:12:09.000Z","size":33,"stargazers_count":4,"open_issues_count":0,"forks_count":0,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-03-10T13:45:53.957Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Swift","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/SwiftRex.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null}},"created_at":"2023-10-25T23:28:27.000Z","updated_at":"2024-05-24T20:00:59.000Z","dependencies_parsed_at":null,"dependency_job_id":"5180c6df-5a19-4dad-987f-03a3a777c588","html_url":"https://github.com/SwiftRex/SwiftRexMacros","commit_stats":null,"previous_names":["swiftrex/swiftrexmacros"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/SwiftRex/SwiftRexMacros","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/SwiftRex%2FSwiftRexMacros","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/SwiftRex%2FSwiftRexMacros/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/SwiftRex%2FSwiftRexMacros/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/SwiftRex%2FSwiftRexMacros/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/SwiftRex","download_url":"https://codeload.github.com/SwiftRex/SwiftRexMacros/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/SwiftRex%2FSwiftRexMacros/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":260483599,"owners_count":23016084,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2025-03-10T13:43:35.677Z","updated_at":"2025-06-18T03:36:48.752Z","avatar_url":"https://github.com/SwiftRex.png","language":"Swift","funding_links":[],"categories":[],"sub_categories":[],"readme":"# SwiftRexMacros\nMacros to help automating SwiftRex boilerplate\n\n## MemberwiseInit\nA macro that produces memberwise initializers for a struct, with the option to control the visibility accessor modifier.\n\n### Examples\n```swift\n@MemberwiseInit(visibility: .fileprivate)\npublic struct BlackjackCard {\n    var suit = \"diamonds\", rank = \"3\"\n    let type: String\n    let flipped: Bool\n    let onFlip: (Bool) -\u003e Void\n}\n\n```\nproduces:\n```swift\nextension BlackjackCard {\n    fileprivate init(suit: String = \"diamonds\", rank: String = \"3\", type: String, flipped: Bool, onFlip: @escaping (Bool) -\u003e Void) {\n        self.suit = suit\n        self.rank = rank\n        self.type = type\n        self.flipped = flipped\n    }\n}\n```\n\n### Limitations\nType inference is hard. Swift compiler does an amazing job inferring types, especially in closures. However, re-implementing whatever Swift compiler\ndoes to infer the types would not be feasible here, and Swift Macros run before type-checkers, so we can't reliably know what type is when a variable\nis not explicitly telling us:\n```swift\n@MemberwiseInit\nstruct MyStruct {\n    // Bool\n    var isToday = Calendar.current.isDateInToday(Date())\n\n    // (DateComponents) -\u003e Date?\n    var myCrazyClosure = {\n        Calendar.current.date(from: $0)\n    }\n}\n```\n\nIn such situations, the variable may be omited from the init, causing a compiler error, or it may use a wrong value that we tried our best to infer.\nIf you face such situations, please explicitly annotate your variables with the proper type, and everything should work as expected.\n\n## Prism\nA macro that produces predicates and prisms for all cases of an Enum.\nPredicates will be Bool properties in the format `isCaseA` that returns `true` whenever that instance points to the `caseA` case of the enum.\nPrism is a property with the same name as the case, but for the instance of the enum. If the instance points to that case, the variable will return a tuple of all associated values of that case, or instance of Void `()` for case without associated values. However, if the instance points to another case, it will return `nil`. This is extremely useful for using KeyPaths.\n\n### Example of predicates:\n```swift\n@Prism\nenum Color {\n    case red, green, blue\n}\n```\nproduces:\n```swift\nextension Color {\n    var isRed: Bool {\n        if case .red = self { true } else { false }\n    }\n    var isGreen: Bool {\n        if case .green = self { true } else { false }\n    }\n    var isBlue: Bool {\n        if case .blue = self { true } else { false }\n    }\n}\n```\nusage:\n```swift\nlet color1 = Color.red\ncolor1.isRed // true\ncolor1.isGreen // false\ncolor1.isBlue // false\n```\n\n### Example of prism:\n```swift\n@Prism\nenum Contact {\n    case email(address: String)\n    case phone(countryCode: String, number: String)\n    case letter(street: String, house: String, postalCode: String, city: String, state: String, country: String)\n    case noContact\n}\n```\nproduces:\n```swift\nextension Contact {\n    var email: String? {\n        guard case let .email(address) = self else { return nil }\n        return address\n    }\n    var phone: (countryCode: String, number: String)? {\n        guard case let .phone(countryCode, number) = self else { return nil }\n        return (countryCode: countryCode, number: number)\n    }\n    var letter: (street: String, house: String, postalCode: String, city: String, state: String, country: String)? {\n        guard case let .letter(street, house, postalCode, city, state, country) = self else { return nil }\n        return (street: street, house: house, postalCode: postalCode, city: city, state: state, country: country)\n    }\n    var noContact: Void? {\n        guard case .noContact = self else { return nil }\n        return ()\n    }\n}\n```\n\nPlease notice that the `Void` case is important not only for consistency, but for more advanced cases of composition.\nLogically, a case with no associated values \"holds\" a Void associated value (singleton type), or not (nil) if the instance has another case.\n\nusage:\n```swift\nlet contact = Contact.phone(countryCode: \"44\", number: \"078906789\")\nlet phone = contact.phone.map { $0.countryCode + \" \" + $0.number } ?? \"\u003cNo Phone\u003e\"     // \"44 078906789\"\n\nlet resolveEmail: KeyPath\u003cContact, String?\u003e = \\Contact.email    // passing contact will resolve to `nil`,\n                                                                // but passing something with email will resolve to the addrees\n```\n\nSetter\nPrisms also produce setters. In that case, if the enum case has an associated value and you want to change the values in the tuple, that is possible as long as the instance points to the same case, otherwise it will be ignored. For example:\n```swift\nvar contact = Contact.phone(countryCode: \"44\", number: \"078906789\")\ncontact.phone = (countryCode: \"44\", number: \"99999999\")     // ✅ this change happens with success\ncontact.email = \"my@email.com\"                              // 🚫 this change is ignored, because the enum instance points to phone, not email\n```\n\nThe setter can be really useful if you have a long tree of enums and want to change the leaf. It's also useful for `WritableKeyPath` situations.\n\nExtra:\n- Use `Prism` in the enum if you want to generate code for every case\n- Use `PrismCase` in a case if you want a different visibility only for that case generated code.\n- Use only `PrismCase` without `Prism` in the enum if you want code generated only for that case.\n- Use `NoPrism` in a case if you don't want code generated for that case.\n\n## PrismCase\nA macro that produces predicates and prisms for a single case of an Enum.\n\n### Example of predicates:\n```swift\nenum Color {\n    case red, black\n    @PrismCase\n    case green, blue\n    case yellow, white\n}\n```\nproduces:\n```swift\nextension Color {\n    var isGreen: Bool {\n        if case .green = self { true } else { false }\n    }\n    var isBlue: Bool {\n        if case .blue = self { true } else { false }\n    }\n}\n```\nusage:\n```swift\nlet color1 = Color.green\ncolor1.isGreen // true\ncolor1.isBlue // false\ncolor1.isRed 🚫 // Compiler error, not generated\n```\n\n### Example of prism:\n```swift\nenum Contact {\n    case email(address: String)\n    @PrismCase\n    case phone(countryCode: String, number: String)\n    case letter(street: String, house: String, postalCode: String, city: String, state: String, country: String)\n    case noContact\n}\n```\nproduces:\n```swift\nextension Contact {\n    var phone: (countryCode: String, number: String)? {\n        guard case let .phone(countryCode, number) = self else { return nil }\n        return (countryCode: countryCode, number: number)\n    }\n}\n```\nPlease notice that the `Void` case is important not only for consistency, but for more advanced cases of composition.\nLogically, a case with no associated values \"holds\" a Void associated value (singleton type), or not (nil) if the instance has another case.\n\nusage:\n```swift\nlet contact = Contact.phone(countryCode: \"44\", number: \"078906789\")\nlet phone = contact.phone.map { $0.countryCode + \" \" + $0.number } ?? \"\u003cNo Phone\u003e\"     // \"44 078906789\"\n\nlet resolveEmail: KeyPath\u003cContact, String?\u003e = \\Contact.phone?.number    // passing contact will resolve to `\"078906789\"`,\n                                                                        // but passing something with email will resolve to nil\n```\n\n## NoPrism\nA macro that prevents the code generatio of predicates and prisms for a specific case, in an Enum marked with `Prism`\n\n### Example of predicates:\n```swift\n@Prism\nenum Color {\n    case red, green, blue\n    @NoPrism\n    case white, black\n}\n```\nproduces:\n```swift\nextension Color {\n    var isRed: Bool {\n        if case .red = self { true } else { false }\n    }\n    var isGreen: Bool {\n        if case .green = self { true } else { false }\n    }\n    var isBlue: Bool {\n        if case .blue = self { true } else { false }\n    }\n}\n```\nusage:\n```swift\nlet color1 = Color.red\ncolor1.isRed // true\ncolor1.isGreen // false\ncolor1.isBlue // false\ncolor1.isWhite 🚫 // Compiler error, not generated\n```\n\n### Example of prism:\n```swift\n@Prism\nenum Contact {\n    case email(address: String)\n    case phone(countryCode: String, number: String)\n    @NoPrism\n    case letter(street: String, house: String, postalCode: String, city: String, state: String, country: String)\n    @NoPrism\n    case noContact\n}\n```\nproduces:\n```swift\nextension Contact {\n    var email: String? {\n        guard case let .email(address) = self else { return nil }\n        return address\n    }\n    var phone: (countryCode: String, number: String)? {\n        guard case let .phone(countryCode, number) = self else { return nil }\n        return (countryCode: countryCode, number: number)\n    }\n}\n```\nPlease notice that the `Void` case is important not only for consistency, but for more advanced cases of composition.\nLogically, a case with no associated values \"holds\" a Void associated value (singleton type), or not (nil) if the instance has another case.\n\nusage:\n```swift\nlet contact = Contact.phone(countryCode: \"44\", number: \"078906789\")\nlet phone = contact.phone.map { $0.countryCode + \" \" + $0.number } ?? \"\u003cNo Phone\u003e\"     // \"44 078906789\"\n\nlet resolveEmail: KeyPath\u003cContact, String?\u003e = \\Contact.email    // passing contact will resolve to `nil`,\n                                                                // but passing something with email will resolve to the addrees\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fswiftrex%2Fswiftrexmacros","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fswiftrex%2Fswiftrexmacros","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fswiftrex%2Fswiftrexmacros/lists"}