{"id":16886729,"url":"https://github.com/alisoftware/sourcerytemplates","last_synced_at":"2025-03-20T12:38:59.959Z","repository":{"id":41142939,"uuid":"91236772","full_name":"AliSoftware/SourceryTemplates","owner":"AliSoftware","description":"Some templates to use for Code Generation in Swift with http://github.com/krzysztofzablocki/Sourcery","archived":false,"fork":false,"pushed_at":"2019-08-09T21:30:59.000Z","size":12148,"stargazers_count":99,"open_issues_count":1,"forks_count":12,"subscribers_count":4,"default_branch":"master","last_synced_at":"2025-01-25T12:42:09.716Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"HTML","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/AliSoftware.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}},"created_at":"2017-05-14T10:45:31.000Z","updated_at":"2023-07-05T02:13:29.000Z","dependencies_parsed_at":"2022-09-09T21:21:04.447Z","dependency_job_id":null,"html_url":"https://github.com/AliSoftware/SourceryTemplates","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/AliSoftware%2FSourceryTemplates","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/AliSoftware%2FSourceryTemplates/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/AliSoftware%2FSourceryTemplates/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/AliSoftware%2FSourceryTemplates/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/AliSoftware","download_url":"https://codeload.github.com/AliSoftware/SourceryTemplates/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":244612070,"owners_count":20481320,"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":"2024-10-13T16:41:03.018Z","updated_at":"2025-03-20T12:38:59.929Z","avatar_url":"https://github.com/AliSoftware.png","language":"HTML","readme":"# SourceryTemplates\n\nThis repository contains some templates (in the `Templates/` directory) to use for Code Generation in Swift with [Sourcery](http://github.com/krzysztofzablocki/Sourcery).\n\nYou can see them in action by opening the `TemplatesDemo.xcodeproj` Xcode project: its `UnitTests` target contains some use case examples for each template, and some code using the generated code in each associated `XCTestCase`.\n\n- [Type Erasure](#type-erasure)\n- [AutoInterface](#autointerface): _Generate protocols matching an API_\n- [AutoPropertiesProtocol](#autopropertiesprotocol): _Ideal to use Protocol Composition for Dependency Injection_\n- [AutoCaseName](#autocasename): _To be able to compare enums with associated values regardless of their payloads_\n- [Other templates](#other-templates): _link to places where you can find other templates_\n\n---\n\n## Type Erasure\n\nThis template provides type erasure to any protocol you annotated accordingly.\n\n### Usage\n\n* Annotate the protocol to type-erase using `// sourcery: TypeErase = X` where `X` is the `associatedtype` to erase\n* Use the template in [`Templates/TypeErase.stencil`](https://github.com/AliSoftware/SourceryTemplates/blob/master/Templates/TypeErase.stencil) with [Sourcery](http://github.com/krzysztofzablocki/Sourcery) to generate Type-Erased code for this annotated protocol(s)\n* Add the generated `TypeErase.generated.swift` file to your Xcode project\n* Profit!\n\n### Examples\n\nYou can find some examples in the [`UnitTests/TypeErasure`](https://github.com/AliSoftware/SourceryTemplates/tree/master/UnitTests/TypeErasure) directory in this repo, like those:\n\n```swift\n// sourcery: TypeErase = PokemonType\nprotocol Pokemon {\n  associatedtype PokemonType\n  func attack(move: PokemonType)\n}\n```\n\n```swift\n// sourcery: TypeErase = Model\nprotocol Row {\n  associatedtype Model\n\n  var sizeLabelText: String { get set }\n\n  func configure(model: Model)\n}\n```\n\nYou can look at the [file generated by Sourcery](https://github.com/AliSoftware/SourceryTemplates/blob/master/UnitTests/Generated/TypeErase.generated.swift) from those examples using the provided [`Templates/TypeErase.stencil`](https://github.com/AliSoftware/SourceryTemplates/blob/master/Templates/TypeErase.stencil) template. Magic! 🎩✨\n\n### More Info\n\nThis is a first draft of the template, so please don't hesitate to improve it.\n\nI haven't tested a lot of real-world use cases yet so some corner cases are probably missing but feel free to submit a PR to fix them!\n\nThe template generates the same code structure as the one explained in [this BigNerdRanch article](https://www.bignerdranch.com/blog/breaking-down-type-erasure-in-swift/) that inspired me to come up with a working template.\n\nYou can also find more information about Type-Erasure by watching [Gwendolyn's talk at Try! Swift](https://news.realm.io/news/tryswift-gwendolyn-weston-type-erasure/) — from which I borrowed the Pokemon examples to test that template.\n\n## AutoInterface\n\nThis template allows to auto-generate a protocol matching the API of a `class`/`struct`.\n\n### Usage\n\n* Create an empty phantom protocol `protocol AutoInterface {}` somewhere in your code.\n* Make your classes or structs conform to `AutoInterface` to opt-in\n* Optionally, you can customize the name of the generated `protocol` for each type using annotations:\n  * By default, the generated protocol as the same name as the type it was generated from, but prefixed with an `I` (e.g. `protocol IWebService` for `class WebService: AutoInterface`\n  * You can use `// sourcery: AutoInterfacePrefix = …` to change that prefix\n  * You can use `// sourcery: AutoInterfaceSuffix = …` to add a suffix\n  * You can use `// sourcery: AutoInterface = …` to force an exact name (in that case the `AutoInterfacePrefix` \u0026 `AutoInterfaceSuffix` are ignored if present)\n* Use the template in [`Templates/AutoInterface.stencil`](https://github.com/AliSoftware/SourceryTemplates/blob/master/Templates/AutoInterface.stencil) with [Sourcery](http://github.com/krzysztofzablocki/Sourcery) to generate a `protocol` for each opted-in type and automatically make your type conform to that new protocol\n* Add the generated `AutoInterface.generated.swift` file to your Xcode project\n* Profit!\n\n### Examples\n\nYou can find some examples in the [`UnitTests/AutoInterface`](https://github.com/AliSoftware/SourceryTemplates/tree/master/UnitTests/AutoInterface) directory in this repo, like this:\n\n```swift\nclass UserWSClient: AutoInterface {\n  struct User {\n    let id: Int\n    let name: String\n  }\n\n  let baseURL: URL = URL(string: \"https://example.com/api\")!\n  \n  func fetchUsers() -\u003e [User] {\n    return (0..\u003c10).map { User(id: $0, name: \"User\\($0)\") }\n  }\n\n  func fetchUser(id: Int) -\u003e User? {\n    return User(id: id, name: \"User\\(id)\")\n  }\n}\n```\n\nWill generate a `protocol IUserWSClient` containing all the functions and properties of your type and make your type conform to that protocol:\n\n```swift\nprotocol IUserWSClient {\n\tvar baseURL: URL { get }\n\tfunc fetchUsers() -\u003e [WSClient.UserWSClient.User]\n\tfunc fetchUser(id: Int) -\u003e WSClient.UserWSClient.User?\n}\nextension UserWSClient: IUserWSClient {}\n```\n\nYou can look at the [file generated by Sourcery](https://github.com/AliSoftware/SourceryTemplates/blob/master/UnitTests/Generated/AutoInterface.generated.swift) from this example using the provided [`Templates/AutoInterface.stencil`](https://github.com/AliSoftware/SourceryTemplates/blob/master/Templates/AutoInterface.stencil) template. Magic! 🎩✨\n\n## AutoPropertiesProtocol\n\nThis template allows you to generate one protocol for each property of your type, each protocol exposing that single property.\n\nThis allows you to later leverage protocol composition to express exactly which properties of that type you're gonna use and want to be able to access.\n\nThis pattern is typically useful to [leverage protocol composition for Dependency Injection](http://merowing.info/2017/04/using-protocol-compositon-for-dependency-injection/), which mixes the benefits of having a single struct containing all your dependencies (instead of passing them all one by one in your constructor) and the benefits of compile-type safety + explicit list of dependencies you want without exposing too much\n\n### Usage\n\n* Declare a phantom protocol `protocol AutoPropertiesProtocol {}` somewhere in your code\n* Make the class you want to opt-it for this feature to conform to this phantom protocol\n* Optionally, you can annotate your properties with the `PropertiesProtocolPrefix` and/or `PropertiesProtocolSuffix` annotations to provide a custom prefix/suffix for the name of the generated protocols\n  * By default (if the annotation is not set / has no value), the prefix will be `Has` and there will be no suffix\n  * Reminder: if you want _all_ the properties of your type to have the same prefix/suffix, you can use `// sourcery:begin: PropertiesProtocolPrefix = …` at the beginning of your type + `// sourcery:end` at the end to apply the same annotation(s) to all the variables inside that scope.\n* Alternatively, you can also optionally annotate your properties with the `PropertiesProtocol` annotation to give an exact name for the protocol to generate for that property.\n* Finally, use the template in [`Templates/AutoPropertiesProtocol.stencil`](https://github.com/AliSoftware/SourceryTemplates/blob/master/Templates/AutoPropertiesProtocol.stencil) with [Sourcery](http://github.com/krzysztofzablocki/Sourcery) to generate all the necessary protocols\n\n### Examples\n\nYou can find some examples in the [`UnitTests/AutoPropertiesProtocol`](https://github.com/AliSoftware/SourceryTemplates/tree/master/UnitTests/AutoPropertiesProtocol) directory in this repo, like this one:\n\n```swift\n// sourcery:begin: PropertiesProtocolPrefix = I, PropertiesProtocolSuffix = Container\nclass Dependencies: AutoPropertiesProtocol {\n  let webServiceClient: WebServiceClient\n  let loginManager: LoginManager\n  let cartManager: CartManager\n\n  init(wsClient: WebServiceClient, loginManager: LoginManager, cartManager: CartManager) {\n    self.webServiceClient = wsClient\n    self.loginManager = loginManager\n    self.cartManager = cartManager\n  }\n}\n// sourcery:end\n```\n\nWith this example above, you can then use `Dependencies` as a single `struct` containing _all_ the dependencies you need to pass throughout your app workflow, but still keep type safety and explicitness by saying exactly which dependencies of that container you allow to use:\n\n```swift\nclass LoginScreen {\n  typealias Dependencies = IWebServiceClientContainer \u0026 ILoginManagerContainer\n  private let deps: Dependencies\n  init(deps: Dependencies) {\n    self.deps = deps\n  }\n\n  func login() {\n    print(self.deps.webServiceClient)\n    print(self.deps.loginManager)\n    // print(self.deps.cartManager) // Can't access this, which is a good thing :)\n  }\n}\n```\n\nYou can look at the [file generated by Sourcery](https://github.com/AliSoftware/SourceryTemplates/blob/master/UnitTests/Generated/AutoPropertiesProtocol.generated.swift) from those examples using the provided [`Templates/AutoPropertiesProtocol.stencil`](https://github.com/AliSoftware/SourceryTemplates/blob/master/Templates/AutoPropertiesProtocol.stencil) template. Magic! 🎩✨\n\n## AutoCaseName\n\nThis template allows you to generate an extension to expose the root name of cases in enums with associated values.\n\nThis especially allows you to test if an enum is of a given case using a simple `if` or `guard`, without having to do a `switch` (which would otherwise be needed if you want to use a `guard` clause, because the enum has associated value, and sure you can use `if case .loading = state`, but you cannot negate the pattern matching condition)\n\n### Usage\n\n* Declare a phantom protocol `protocol AutoCaseName {}` somewhere in your code\n* Make the enums with associated values you want to opt-it for this feature to conform to this phantom protocol\n* Finally, use the template in [`Templates/AutoCaseName.stencil`](https://github.com/AliSoftware/SourceryTemplates/blob/master/Templates/AutoCaseName.stencil) with [Sourcery](http://github.com/krzysztofzablocki/Sourcery) to generate all the necessary protocols\n\n### Examples\n\nYou can find some examples in the [`UnitTests/AutoCaseName`](https://github.com/AliSoftware/SourceryTemplates/tree/master/UnitTests/AutoCaseName) directory in this repo, like this one:\n\n```swift\nenum State: AutoCaseName {\n  case notLoaded\n  case loading(message: String, percent: Double)\n  case loaded(data: [String])\n  case error(message: String, code: Int)\n}\n```\n\nWithout the Sourcery Template, if you wanted to then check if a `State` was _not_ in state `loaded` without caring about the associated value of that state, you'd still have to use a `switch`:\n\n```swift\nlet state = State.loading(message: \"In progress…\", percent: 0.42)\nlet isLoading: Bool = {\n  switch state {\n    case .loading: return true\n    default: return false\n  }\n}()\nguard !isLoading else { return }\n```\n\nBut instead, using this Sourcery template, you can simply do:\n\n```swift\nlet state = State.loading(message: \"In progress…\", percent: 0.42)\nguard state.caseName != .loading else { return }\n```\n\nAlso, as the `caseName` property returns a `YourType.CaseName` (generated by Sourcery)… which is `Comparable`, you can also compare if two instances of your enum are the same case regardless of their payload too:\n\n```swift\nlet state1 = State.loaded(data: [\"Foo\", Bar\"])\nlet state2 = State.loaded(data: [\"Baz\"])\nlet state3 = State.error(message)\nguard state1.caseName == satte2.caseName, state1.caseName != state3.caseName else { return }\n```\n\nAs a last bonus, the generated `YourType.CaseName` is also a `enum CaseName: String` (so it's `RawRepresentable` using a `String`) which allows you to get the name of a case as a `String` using `state.caseName.rawValue` if needed.\n\nYou can look at the [file generated by Sourcery](https://github.com/AliSoftware/SourceryTemplates/blob/master/UnitTests/Generated/AutoCaseName.generated.swift) from those examples using the provided [`Templates/AutoCaseName.stencil`](https://github.com/AliSoftware/SourceryTemplates/blob/master/Templates/AutoCaseName.stencil) template. Magic! 🎩✨\n\n## Other templates\n\n* [Sourcery itself has some template examples](https://github.com/krzysztofzablocki/Sourcery/tree/master/Templates)\n* You can also find a template by **@Liquidsoul** [on his own repo](https://github.com/Liquidsoul/Sourcery-AutoJSONSerializable) to auto-generate code for JSON serialization \u0026 deserialization.\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Falisoftware%2Fsourcerytemplates","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Falisoftware%2Fsourcerytemplates","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Falisoftware%2Fsourcerytemplates/lists"}