{"id":14985646,"url":"https://github.com/swinject/swinject-codegen","last_synced_at":"2025-07-18T16:03:13.802Z","repository":{"id":48909569,"uuid":"56907687","full_name":"Swinject/Swinject-CodeGen","owner":"Swinject","description":"Generate code to make the use of Swinject type-safe and reduce duplicate identifiers for Services","archived":false,"fork":false,"pushed_at":"2021-07-05T17:34:57.000Z","size":145,"stargazers_count":33,"open_issues_count":0,"forks_count":5,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-06-25T21:15:43.247Z","etag":null,"topics":["codegeneration","csv","swinject","yml"],"latest_commit_sha":null,"homepage":"","language":"Ruby","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/Swinject.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":"2016-04-23T08:00:21.000Z","updated_at":"2022-02-07T15:38:22.000Z","dependencies_parsed_at":"2022-09-13T02:10:28.109Z","dependency_job_id":null,"html_url":"https://github.com/Swinject/Swinject-CodeGen","commit_stats":null,"previous_names":["swinject/swinject-codegeneration"],"tags_count":6,"template":false,"template_full_name":null,"purl":"pkg:github/Swinject/Swinject-CodeGen","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Swinject%2FSwinject-CodeGen","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Swinject%2FSwinject-CodeGen/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Swinject%2FSwinject-CodeGen/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Swinject%2FSwinject-CodeGen/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Swinject","download_url":"https://codeload.github.com/Swinject/Swinject-CodeGen/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Swinject%2FSwinject-CodeGen/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":265791407,"owners_count":23829160,"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":["codegeneration","csv","swinject","yml"],"created_at":"2024-09-24T14:11:25.352Z","updated_at":"2025-07-18T16:03:13.769Z","avatar_url":"https://github.com/Swinject.png","language":"Ruby","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Swinject Code Generation\n\n[![Build Status](https://travis-ci.org/Swinject/Swinject-CodeGen.svg?branch=master)](https://travis-ci.org/Swinject/Swinject-CodeGen)\n\nSwinject-CodeGen provides a method to get rid of duplicate use of class values and namestrings, by generating explicit functions for registering and resolving using Swinject.\nDoing this, we also can generate typed tuples to use when resolving, thus allowing better documented and less error-prone code.\n\n## Installation\n### Cocoapods\n\nAdd\n\n```\npod 'Swinject-CodeGen'\n```\n\nto your podfile.\n\n### Carthage\n\nAdd\n\n```\ngithub \"Swinject/Swinject-CodeGeneration\"\n```\n\nto your Cartfile.\n\n## Integration\n1. Define your dependencies in a .csv or .yml file (see below and example file)\n2. Add a call to generate the code as build script phase:\n\nFor Cocoapods:\n```Shell\n$PODS_ROOT/Swinject-CodeGen/bin/swinject_codegen -i baseInput.csv -o extensions/baseContainerExtension.swift\n```\n\nFor Carthage:\n```Shell\n$SRCROOT/Carthage/Checkouts/Swinject-CodeGen/bin/swinject_codegen -i baseInput.csv -o extensions/baseContainerExtension.swift\n```\n\n3. Add the generated file (here: `extensions/baseContainerExtension.swift`) to xcode\n4. Repeat if you need to support multiple targets/have multiple input files.\n\nThe code is then generated at every build run.\n\n## The Issue\n\nWhen using Swinject, lots of duplicate definitions appear, whenever we do a\n\n```Swift\ncontainer.register(PersonType.self, name: \"initializer\") { r in\n    InjectablePerson(pet: r.resolve(AnimalType.self)!)\n}\n\nlet initializerInjection = container.resolve(PersonType.self, name:\"initializer\")!\n```\n\nthe tuple (PersonType.self, name:\"initializer\") becomes very redundant across the code.\n\nFurthermore, when using arguments, as done in\n\n```Swift\ncontainer.register(AnimalType.self) { _, name in Horse(name: name) }\nlet horse1 = container.resolve(AnimalType.self, argument: \"Spirit\") as! Horse\n```\n\nthe `argument: \"Spirit\"` part is not strictly typed when calling it.\n\nWe propose a solution to both these problems by using CodeGeneration\n\n## Input Format\nInput can be given as .csv or .yml\n\nThe call\n```\n./swinject_codegen -i example.csv -c\n```\n\ncan be used to convert example.csv into example.csv.yml (also works for .yml).\n\n### CSV\n\n#### Basic Structure\n\nOur basic csv structure is defined as follows:\n\n```CSV\nSourceClassName; TargetClassName; Identifier; Argument 1 ... 9\n```\n\nThe example above would translate to\n\n```CSV\nPersonType; InjectablePerson; initializer\n```\n\nto generate both a `registerPersonType_initializer` and a `resolvePersonType_initializer` function.\n\nSee the examples below for more examples.\n\nWe decided to use `;` as delimiter instead of `,` to allow the use of tuples as types.\n\n#### Additional Commands\nThe ruby parser allows using  `//` and `#` for comments.\nEmpty lines are ignored and can be used for grouping.\n\n`#= \u003cheader\u003e` can be used to specify additional lines, e.g. `#= import KeychainAccess`\n\n#### Dictionaries and Arrays as Parameters\nWhen using typed dictionaries or arrays as parameters, use `Array\u003cType\u003e` instead of `[Type]` and `Dictionary\u003cTypeA, TypeB\u003e` instead of `[TypeA:TypeB]`:\n\n```CSV\nPersonType; InjectablePerson; initializer; additionalNames:Array\u003cString\u003e; family:Dictionary\u003cString, String\u003e;\n```\n\n### YAML\n\nExample for a .yml definition:\n```yml\n---\nHEADERS:\n  - import ADependency\nDEFINITIONS:\n- service: PersonType\n  component: InjectablePerson\n  name: initializer\n- service: PersonType\n  component: InjectablePerson\n- service: PersonType\n  component: PersonType\n- service: AnotherPersonType\n  component: AnotherPersonType\n- service: PersonType\n  component: InjectablePerson\n  arguments:\n  - argument_name: argument_name\n    argument_type: argument_type\n- service: PersonType\n  component: InjectablePerson\n  arguments:\n  - argument_name: argument_name\n    argument_type: argument_type\n  - argument_name: argument_typewithoutspecificname\n    argument_type: argument_typeWithoutSpecificName\n  - argument_name: title\n    argument_type: String\n  - argument_name: string\n    argument_type: String\n- service: PersonType\n  component: InjectablePerson\n  name: initializer\n  arguments:\n  - argument_name: argument_name\n    argument_type: argument_type\n  - argument_name: argument_typewithoutspecificname\n    argument_type: argument_typeWithoutSpecificName\n  - argument_name: title\n    argument_type: String\n  - argument_name: string\n    argument_type: String\n```\n\n## Generation Examples\n\n\n### Example A: Same class as source and target\n\n#### Input\n```CSV\nPersonType\n```\n\n#### Output\n```Swift\n// this code is autogenerated, do not modify!\n\nimport Swinject\n\nextension Resolver {\n\n    func resolvePersonType() -\u003e PersonType {\n        return self.resolve(PersonType.self)!\n    }\n}\n\nextension Container {\n\n    @discardableResult func registerPersonType(registerClosure: @escaping (_ resolver: Resolver) -\u003e (PersonType)) -\u003e ServiceEntry\u003cPersonType\u003e {\n        return self.register(PersonType.self, factory: registerClosure)\n    }\n}\n```\n\n### Example B: Different source and target\n\n#### Input\n```CSV\nPersonType; InjectablePerson\n```\n\n#### Output\n```Swift\n// this code is autogenerated, do not modify!\n\nimport Swinject\n\nextension Resolver {\n\n    func resolveInjectablePerson() -\u003e InjectablePerson {\n        return self.resolve(PersonType.self) as! InjectablePerson\n    }\n}\n\nextension Container {\n\n    @discardableResult func registerInjectablePerson(registerClosure: @escaping (_ resolver: Resolver) -\u003e (InjectablePerson)) -\u003e ServiceEntry\u003cPersonType\u003e {\n        return self.register(PersonType.self, factory: registerClosure)\n    }\n}\n```\n\n### Example C: Different source and target class with name\n\n#### Input\n```CSV\nPersonType; InjectablePerson; initializer\n```\n\n#### Output\n```Swift\n// this code is autogenerated, do not modify!\n\nimport Swinject\n\nextension Resolver {\n\n    func resolveInjectablePerson_initializer() -\u003e InjectablePerson {\n        return self.resolve(PersonType.self, name: \"initializer\") as! InjectablePerson\n    }\n}\n\nextension Container {\n\n    @discardableResult func registerInjectablePerson_initializer(registerClosure: @escaping (_ resolver: Resolver) -\u003e (InjectablePerson)) -\u003e ServiceEntry\u003cPersonType\u003e {\n        return self.register(PersonType.self, name: \"initializer\", factory: registerClosure)\n    }\n}\n```\n\n### Example D: Different source and target with a single, explicitly named argument\n#### Input\n```CSV\nPersonType; InjectablePerson; ; argumentName:ArgumentType\n```\n\n#### Output\n```Swift\n// this code is autogenerated, do not modify!\n\nimport Swinject\n\nextension Resolver {\n\n    func resolveInjectablePerson(argumentName: ArgumentType) -\u003e InjectablePerson {\n        return self.resolve(PersonType.self, argument: argumentName) as! InjectablePerson\n    }\n}\n\nextension Container {\n\n    @discardableResult func registerInjectablePerson(registerClosure: @escaping (_ resolver: Resolver, _ argumentName: ArgumentType) -\u003e (InjectablePerson)) -\u003e ServiceEntry\u003cPersonType\u003e {\n        return self.register(PersonType.self, factory: registerClosure)\n    }\n}\n```\n\n### Example E: Different source and target with multiple arguments, both explicitly named and not\nIf no explicit name is given, the lowercase type is used as argumentname.\n\n#### Input\n```CSV\nPersonType; InjectablePerson; ; argumentName:ArgumentType; ArgumentTypeWithoutSpecificName; title:String; String\n```\n\n#### Output\n```Swift\n// this code is autogenerated, do not modify!\n\nimport Swinject\n\nextension Resolver {\n\n    func resolveInjectablePerson(argumentName: ArgumentType, argumenttypewithoutspecificname: ArgumentTypeWithoutSpecificName, title: String, string: String) -\u003e InjectablePerson {\n        return self.resolve(PersonType.self, arguments: argumentName, argumenttypewithoutspecificname, title, string) as! InjectablePerson\n    }\n}\n\nextension Container {\n\n    @discardableResult func registerInjectablePerson(registerClosure: @escaping (_ resolver: Resolver, _ argumentName: ArgumentType, _ argumenttypewithoutspecificname: ArgumentTypeWithoutSpecificName, _ title: String, _ string: String) -\u003e (InjectablePerson)) -\u003e ServiceEntry\u003cPersonType\u003e {\n        return self.register(PersonType.self, factory: registerClosure)\n    }\n}\n```\n\n### Example F:  Different source and target with name with multiple arguments, both explicitly named and not\n#### Input\n```CSV\nPersonType; InjectablePerson; initializer; argumentName:ArgumentType; ArgumentTypeWithoutSpecificName; title:String; String\n```\n\n#### Output\n```Swift\n// this code is autogenerated, do not modify!\n\nimport Swinject\n\nextension Resolver {\n\n    func resolveInjectablePerson_initializer(argumentName: ArgumentType, argumenttypewithoutspecificname: ArgumentTypeWithoutSpecificName, title: String, string: String) -\u003e InjectablePerson {\n        return self.resolve(PersonType.self, name: \"initializer\", arguments: argumentName, argumenttypewithoutspecificname, title, string) as! InjectablePerson\n    }\n}\n\nextension Container {\n\n    @discardableResult func registerInjectablePerson_initializer(registerClosure: @escaping (_ resolver: Resolver, _ argumentName: ArgumentType, _ argumenttypewithoutspecificname: ArgumentTypeWithoutSpecificName, _ title: String, _ string: String) -\u003e (InjectablePerson)) -\u003e ServiceEntry\u003cPersonType\u003e {\n        return self.register(PersonType.self, name: \"initializer\", factory: registerClosure)\n    }\n}\n```\n\n## Usage Examples\n\nUsing the examples given at the beginning, we can now instead of\n\n```Swift\ncontainer.register(PersonType.self, name: \"initializer\") { r in\n    InjectablePerson(pet: r.resolve(AnimalType.self)!)\n}\n\nlet initializerInjection = container.resolve(PersonType.self, name:\"initializer\")!\n```\n\nwrite:\n\n```Swift\ncontainer.registerPersonType_initializer { r in\n    InjectablePerson(pet: r.resolve(AnimalType.self)!)\n}\n\nlet initializerInjection = container.resolvePersonType_initializer()\n```\n\nAlso\n\n```Swift\ncontainer.register(AnimalType.self) { _, name in Horse(name: name) }\nlet horse1 = container.resolve(AnimalType.self, argument: \"Spirit\")\n```\n\nbecomes\n\n```Swift\ncontainer.registerAnimalType { (_, name:String) in\n  Horse(name: name)\n}\nlet horse1 = container.resolveAnimalType(\"Spirit\")\n```\n\n## Migration\nThe script also generates migration.sh files (when using the -m switch), which use sed to go through the code and replace simple cases (i.e. no arguments) of resolve and register.\nNo automatic migration is available for cases with arguments, yet.\nSimply call the .sh file from the root of the project and compare the results in a git-GUI.\n\n## Results\nWe currently use the code generation in two medium-sized apps across tvOS and iOS.\n\nWe found our code to become much more convenient to read and write, due to reduced duplication and autocompletion.\nWe also have a much better overview the classes available through dependency injection.\nChanging some definition immediately leads to information, where an error will occur.\nWe were able to replace all our occurrences of `.resolve(` and `.register(` using the current implementation.\n\n## Contributors\nThe original idea for combining CodeGeneration and Swinject came from [Daniel Dengler](https://github.com/ddengler), [David Kraus](https://github.com/davidkraus) and [Wolfgang Lutz](https://github.com/lutzifer).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fswinject%2Fswinject-codegen","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fswinject%2Fswinject-codegen","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fswinject%2Fswinject-codegen/lists"}