{"id":45356083,"url":"https://github.com/miyamo2/braider","last_synced_at":"2026-03-01T16:09:06.250Z","repository":{"id":339751369,"uuid":"1142571903","full_name":"miyamo2/braider","owner":"miyamo2","description":"compile-time DI via go/analysis","archived":false,"fork":false,"pushed_at":"2026-02-21T16:48:35.000Z","size":972,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-02-21T16:53:08.325Z","etag":null,"topics":["compile-time","compile-time-meta-programming","dependency-injection","di","go","go-analysis","go-vet","golang"],"latest_commit_sha":null,"homepage":"","language":"Go","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/miyamo2.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,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":"AGENTS.md","dco":null,"cla":null}},"created_at":"2026-01-26T15:29:59.000Z","updated_at":"2026-02-21T11:34:07.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/miyamo2/braider","commit_stats":null,"previous_names":["miyamo2/braider"],"tags_count":2,"template":false,"template_full_name":null,"purl":"pkg:github/miyamo2/braider","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/miyamo2%2Fbraider","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/miyamo2%2Fbraider/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/miyamo2%2Fbraider/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/miyamo2%2Fbraider/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/miyamo2","download_url":"https://codeload.github.com/miyamo2/braider/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/miyamo2%2Fbraider/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":29879932,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-02-26T23:51:21.483Z","status":"ssl_error","status_checked_at":"2026-02-26T23:50:46.793Z","response_time":89,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.5:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"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":["compile-time","compile-time-meta-programming","dependency-injection","di","go","go-analysis","go-vet","golang"],"created_at":"2026-02-21T13:02:22.347Z","updated_at":"2026-03-01T16:09:06.244Z","avatar_url":"https://github.com/miyamo2.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"# braider — compile-time DI via go/analysis\n\n[![Go Reference](https://pkg.go.dev/badge/github.com/miyamo2/braider.svg)](https://pkg.go.dev/github.com/miyamo2/braider)\n[![GitHub go.mod Go version (subdirectory of monorepo)](https://img.shields.io/github/go-mod/go-version/miyamo2/braider?logo=go)](https://img.shields.io/github/go-mod/go-version/miyamo2/braider?logo=go)\n[![GitHub release (latest by date)](https://img.shields.io/github/v/release/miyamo2/braider)](https://img.shields.io/github/v/release/miyamo2/braider)\n![Coverage](https://github.com/miyamo2/braider/blob/main/.assets/test_cov.svg?raw=true)\n![Code to Test Ratio](https://github.com/miyamo2/braider/blob/main/.assets/ratio.svg?raw=true)\n![Test Execution Time](https://github.com/miyamo2/braider/blob/main/.assets/time.svg?raw=true)\n[![Go Report Card](https://goreportcard.com/badge/github.com/miyamo2/braider)](https://goreportcard.com/report/github.com/miyamo2/braider)\n[![GitHub License](https://img.shields.io/github/license/miyamo2/braider?\u0026color=blue)](https://img.shields.io/github/license/miyamo2/braider?\u0026color=blue)\n\nbraider is a `go/analysis` analyzer that resolves dependency injection (DI) bindings and generates constructors and bootstrap wiring using `analysis.SuggestedFix`. It integrates with the standard Go toolchain, produces plain Go code with no runtime container, and is inspired by google/wire.\n\n## Overview\n\n- Compile-time DI validation with actionable diagnostics\n- Constructor generation for structs annotated with `annotation.Injectable[T]`\n- Provider registration via `annotation.Provide[T](fn)`\n- Variable registration via `annotation.Variable[T](value)` for pre-existing variables\n- Interface-typed dependencies via `inject.Typed[I]`, `provide.Typed[I]`, and `variable.Typed[I]`\n- Named dependencies via `inject.Named[N]`, `provide.Named[N]`, and `variable.Named[N]`\n- Custom constructors via `inject.WithoutConstructor`\n- Field-level DI control via `braider` struct tags (`braider:\"name\"` / `braider:\"-\"`)\n- App options: `app.Default` (anonymous struct) and `app.Container[T]` (user-defined container)\n- Bootstrap wiring generated from a dependency graph in topological order\n- Works with `braider -fix` for one-shot application of suggested fixes\n\n## Installation\n\nRequires go 1.25+.\n\n### CLI\n\n```bash\ngo install github.com/miyamo2/braider/cmd/braider@latest\n```\n\nOr, add it as a [tool dependency](https://go.dev/doc/modules/managing-dependencies#tools)\n\n```bash\ngo get -tool github.com/miyamo2/braider/cmd/braider@latest\n```\n\nOr, install via [Homebrew](https://brew.sh/)\n\n```bash\nbrew install miyamo2/tap/braider\n```\n\n### Module\n\nAnnotation types and option packages used in your code are provided by this module.\n\n```bash\ngo get github.com/miyamo2/braider\n```\n\n## Usage\n\n1. Add annotations in your code.\n2. (Optional) Run the analyzer to check for configuration issues\n\n```bash\nbraider ./...\n```\n\n3. Apply generated constructors and bootstrap wiring\n\n```bash\nbraider -fix ./...\n```\n\n### Annotations\n\n- `annotation.Injectable[inject.Default]` — marks structs that need constructor generation and will be exposed from the bootstrap dependency struct.\n- `annotation.Provide[provide.Default](fn)` — registers provider functions exposed as fields in the bootstrap dependency struct.\n- `annotation.Variable[variable.Default](value)` — registers a pre-existing variable or package-qualified identifier (e.g., `os.Stdout`) as a DI dependency without generating a constructor.\n- `annotation.App[app.Default](main)` — marks the entry point where bootstrap code is generated. Use `app.Default` for an anonymous struct or `app.Container[T]` for a user-defined container type.\n\n### Options\n\n`Injectable[T]`, `Provide[T]`, and `Variable[T]` accept option interfaces to customize registration:\n\n| Option | Injectable | Provide | Variable | Description |\n|--------|-----------|---------|----------|-------------|\n| `Default` | `inject.Default` | `provide.Default` | `variable.Default` | Default registration. |\n| `Typed[I]` | `inject.Typed[I]` | `provide.Typed[I]` | `variable.Typed[I]` | Register as interface type `I` instead of the concrete type. |\n| `Named[N]` | `inject.Named[N]` | `provide.Named[N]` | `variable.Named[N]` | Register with name `N.Name()`. `N` must implement `namer.Namer` and return a string literal. |\n| `WithoutConstructor` | `inject.WithoutConstructor` | N/A | N/A | Skip constructor generation. You must provide a manual `New\u003cType\u003e` function. |\n\n`App[T]` accepts option interfaces to customize bootstrap output:\n\n| Option | Description |\n|--------|-------------|\n| `app.Default` | Generate an anonymous struct with all dependencies as fields (default behavior). |\n| `app.Container[T]` | Generate a bootstrap function that returns the user-defined container type `T`. Container fields are matched by type; use `braider:\"name\"` tags for named dependencies and `braider:\"-\"` to exclude fields. |\n\n### Struct Tags\n\n`Injectable[T]` struct fields can use `braider` struct tags for field-level DI control:\n\n| Tag | Description |\n|-----|-------------|\n| `braider:\"\u003cname\u003e\"` | Resolve this field using the named dependency matching `\u003cname\u003e`. |\n| `braider:\"-\"` | Exclude this field from dependency injection entirely. |\n\nFields without a `braider` tag are resolved by type as usual.\n\n**Named dependency injection** — use `braider:\"\u003cname\u003e\"` to wire a specific named provider/injector/variable to a field:\n\n```go\ntype PrimaryRepoName struct{}\n\nfunc (PrimaryRepoName) Name() string { return \"primaryRepo\" }\n\nvar _ = annotation.Provide[provide.Named[PrimaryRepoName]](NewUserRepository)\n\nfunc NewUserRepository() *UserRepository { return \u0026UserRepository{} }\n\ntype AppService struct {\n    annotation.Injectable[inject.Default]\n    repo *UserRepository `braider:\"primaryRepo\"`\n}\n```\n\n**Field exclusion** — use `braider:\"-\"` to keep a field out of DI:\n\n```go\ntype AppService struct {\n    annotation.Injectable[inject.Default]\n    logger   Logger\n    debugger Debugger `braider:\"-\"`\n}\n```\n\nThe generated constructor will only accept `logger` as a parameter; `debugger` is ignored.\n\nStruct tags can be combined freely — some fields tagged with names, some excluded, and others resolved by type:\n\n```go\ntype AppService struct {\n    annotation.Injectable[inject.Default]\n    repo     *UserRepository `braider:\"primaryRepo\"`\n    logger   Logger\n    debugger Debugger        `braider:\"-\"`\n}\n```\n\n**Mixed options** are supported by embedding multiple option interfaces in a single anonymous interface:\n\n```go\ntype MixedService struct {\n    annotation.Injectable[interface {\n        inject.Typed[Repository]\n        inject.Named[ServiceName]\n    }]\n}\n```\n\n**Custom Namer types** must return a hardcoded string literal from `Name()`:\n\n```go\ntype PrimaryDBName struct{}\n\nfunc (PrimaryDBName) Name() string { return \"primaryDB\" }\n```\n\n### Variable\n\n`annotation.Variable[T](value)` registers a pre-existing variable or package-qualified identifier as a DI dependency. Unlike `Injectable` and `Provide`, no constructor is generated or invoked — the value is assigned directly in the bootstrap code.\n\nSupported argument expressions: identifiers (`myVar`) and package-qualified selectors (`os.Stdout`). Literals, function calls, and composite literals are not supported.\n\n```go\nimport (\n    \"os\"\n\n    \"github.com/miyamo2/braider/pkg/annotation\"\n    \"github.com/miyamo2/braider/pkg/annotation/variable\"\n)\n\n// Register os.Stdout as a *os.File dependency.\nvar _ = annotation.Variable[variable.Default](os.Stdout)\n```\n\nIn the generated bootstrap code, this becomes a direct assignment: `stdout := os.Stdout`.\n\n### App Options\n\n`annotation.App[T](main)` is generic — the type parameter `T` controls the shape of the bootstrap output.\n\n**`app.Default`** — generates an anonymous struct with all dependencies as fields:\n\n```go\nvar _ = annotation.App[app.Default](main)\n```\n\n**`app.Container[T]`** — generates a bootstrap function that returns a user-defined container type `T`:\n\n```go\nvar _ = annotation.App[app.Container[struct {\n    Svc *Service\n}]](main)\n```\n\nContainer fields are matched against registered dependencies by type. Use `braider:\"name\"` tags to match named dependencies. Note that `braider:\"-\"` is not permitted on container fields (it is a validation error):\n\n```go\nvar _ = annotation.App[app.Container[struct {\n    Primary *Database `braider:\"primaryDB\"`\n    Replica *Database `braider:\"replicaDB\"`\n}]](main)\n```\n\nThe container type can also be a named struct from another package:\n\n```go\nvar _ = annotation.App[app.Container[container.AppContainer]](main)\n```\n\n## Example\n\n```go\npackage main\n\nimport (\n    \"time\"\n\n    \"github.com/miyamo2/braider/pkg/annotation\"\n    \"github.com/miyamo2/braider/pkg/annotation/app\"\n    \"github.com/miyamo2/braider/pkg/annotation/inject\"\n    \"github.com/miyamo2/braider/pkg/annotation/provide\"\n)\n\ntype Clock interface {\n    Now() time.Time\n}\n\ntype realClock struct{}\n\nfunc (realClock) Now() time.Time { return time.Now() }\n\nvar _ = annotation.Provide[provide.Typed[Clock]](NewClock)\n\nfunc NewClock() *realClock { return \u0026realClock{} }\n\ntype Service struct {\n    annotation.Injectable[inject.Default]\n    Clock Clock\n}\n\nvar _ = annotation.App[app.Default](main)\n\nfunc main() {}\n```\n\n**Following `braider -fix ./...`, the generated bootstrap code will look like this**\n\n```go\npackage main\n\nimport (\n    \"time\"\n\n    \"github.com/miyamo2/braider/pkg/annotation\"\n    \"github.com/miyamo2/braider/pkg/annotation/app\"\n    \"github.com/miyamo2/braider/pkg/annotation/inject\"\n    \"github.com/miyamo2/braider/pkg/annotation/provide\"\n)\n\ntype Clock interface {\n    Now() time.Time\n}\n\ntype realClock struct{}\n\nfunc (r realClock) Now() time.Time {\n\treturn time.Now()\n}\n\nvar _ = annotation.Provide[provide.Typed[Clock]](NewClock)\n\nfunc NewClock() *realClock { return \u0026realClock{} }\n\ntype Service struct {\n    annotation.Injectable[inject.Default]\n    Clock Clock\n}\n\n// NewService is a constructor for Service.\n//\n// Generated by braider. DO NOT EDIT.\nfunc NewService(c Clock) Service {\n    return Service{Clock: c}\n}\n\nvar _ = annotation.App[app.Default](main)\n\nfunc main() {\n    _ = dependencies\n}\n\n// braider:hash:blurblurblur\nvar dependencies = func() struct {\n    Service Service\n} {\n    clock := NewClock()\n    service := NewService(clock)\n    return struct {\n        Service Service\n    }{\n        Service: service,\n    }\n}\n```\n\n### Examples\n\n- [Typed inject](examples/typed-inject) -- register a struct as an interface type with `inject.Typed[I]`\n- [Named inject](examples/named-inject) -- register multiple instances with different names via `inject.Named[N]`\n- [Without constructor](examples/without-constructor) -- skip constructor generation with `inject.WithoutConstructor`\n- [Mixed options](examples/mixed-options) -- combine `Typed[I]` and `Named[N]` in a single annotation\n- [Provide typed](examples/provide-typed) -- register a provider function as an interface type with `provide.Typed[I]`\n- [Variable](examples/variable) -- register a pre-existing variable as a DI dependency with `annotation.Variable[T]`\n- [Struct tag named](examples/struct-tag-named) -- inject a named dependency into a specific field with `braider:\"\u003cname\u003e\"`\n- [Struct tag exclude](examples/struct-tag-exclude) -- exclude a field from DI with `braider:\"-\"`\n- [Container (anonymous)](examples/container-basic) -- use `app.Container[T]` with an anonymous struct as the bootstrap output\n- [Container (named type)](examples/container-named) -- use `app.Container[T]` with a named container type from another package\n\n## Contributing\n\nIssues and pull requests are welcome. Please keep changes focused and add tests where applicable (`go test ./...`).\n\n## License\n\nMIT. See [LICENSE](LICENSE).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmiyamo2%2Fbraider","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmiyamo2%2Fbraider","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmiyamo2%2Fbraider/lists"}