di

package module
v0.0.0-...-7ed3c21 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jul 24, 2026 License: Apache-2.0 Imports: 6 Imported by: 0

README

gendi - Compile-Time Dependency Injection for Go

CI codecov License

gendi is a compile-time dependency injection container generator for Go. It reads YAML configuration files and generates type-safe, efficient container code with full compile-time validation.

Features

  • Compile-time type safety - All dependencies resolved and type-checked during code generation
  • Zero runtime reflection - Generated code uses direct type assertions
  • YAML configuration - Declarative service definitions with imports and overrides
  • Service lifecycle - Shared (singleton) and non-shared (factory) services
  • Tagged injection - Collect multiple services by tag with custom sorting
  • Service decoration - Decorator pattern with priority ordering
  • Method constructors - Use service methods as constructors
  • Variadic functions - Full support for variadic constructors
  • Generic constructors - Support for Go generics with type arguments
  • Custom compiler passes - Transform configuration before generation
  • Parameter injection - Type-safe parameter references with automatic conversion
  • Circular dependency detection - Catches circular references at generation time
  • Public API generation - Expose selected services via public getter methods
  • Standard library factories - Ready-to-use factories for common stdlib types

Installation

Add gendi as a tool dependency to your project:

go get -tool github.com/gendi-org/gendi/cmd/gendi

This adds gendi to your go.mod and allows running it via go tool gendi.

Quick Start

1. Create a service configuration

gendi.yaml:

# yaml-language-server: $schema=https://raw.githubusercontent.com/gendi-org/gendi/master/gendi.schema.json

parameters:
  db_dsn: "postgres://localhost/myapp"

services:
  database:
    constructor:
      func: "github.com/myapp/db.New"
      args:
        - "%db_dsn%"  # Parameter reference
    shared: true

  user_repo:
    constructor:
      func: "github.com/myapp/repo.NewUserRepository"
      args:
        - "@database"  # Service reference
    shared: true
    public: true  # Exposed via public getter

💡 Tip: Add the schema comment at the top of your YAML files to get autocomplete and validation in editors that support YAML schemas (VS Code, IntelliJ, etc.)

2. Generate the container
go tool gendi --config=gendi.yaml --out=./di --pkg=di

Or use go:generate:

//go:generate go tool gendi --config=gendi.yaml --out=./di --pkg=di
3. Use the generated container
package main

import "github.com/myapp/di"

func main() {
    container := di.NewContainer(nil)

    userRepo, err := container.GetUserRepo()
    if err != nil {
        panic(err)
    }

    // Use userRepo...
}

Core Concepts

Parameters

Typed configuration values injected using %name% syntax. Supported types: string, int, float64, bool, time.Duration.

Services

Objects constructed and managed by the container. Services can be:

  • Shared (singleton): Created once, cached, thread-safe
  • Non-shared (factory): New instance on each access
  • Public: Exposed via public getter methods
  • Decorated: Wrapped by decorator services
Tags

Collect multiple services implementing a common interface. Tags support:

  • Custom sorting by attributes
  • Auto-configuration (automatic tagging)
  • Public getters for tagged collections
Imports

Configuration files can import and override other configurations using relative paths, glob patterns, or module imports.

📖 See Configuration Reference for complete YAML syntax and examples.

CLI Usage

go tool gendi [flags]

Flags:
  --config string      Root YAML configuration file (required)
  --out string         Output directory or file (required)
  --pkg string         Go package name (required)
  --container string   Container struct name (default: "Container")
  --build-tags string  Build tags used for type resolution and emitted as the generated file's //go:build header
  --enable-pass string
                      Enable an optional compiler pass (repeatable)
  --verbose           Enable verbose logging

Examples:

# Generate to directory
go tool gendi --config=gendi.yaml --out=./di --pkg=di

# Generate specific file
go tool gendi --config=gendi.yaml --out=./di/container_gen.go --pkg=di

# With build tags
go tool gendi --config=gendi.yaml --out=./di --pkg=di --build-tags=integration

Custom Compiler Passes

Compiler passes transform configuration before code generation, enabling project-specific conventions:

type AutoTagPass struct{}

func (p *AutoTagPass) Name() string { return "auto-tag" }

func (p *AutoTagPass) Process(cfg *di.Config) (*di.Config, error) {
    for id, svc := range cfg.Services {
        if strings.HasSuffix(id, ".handler") {
            svc.Tags = append(svc.Tags, di.ServiceTag{Name: "http.handler"})
            cfg.Services[id] = svc
        }
    }
    return cfg, nil
}

📖 See Custom Passes Guide for complete documentation and examples.

Standard Library Services

Pre-configured services for common stdlib types (HTTP clients, loggers, channels):

imports:
  - github.com/gendi-org/gendi/stdlib/gendi.yaml

services:
  my_service:
    constructor:
      func: "github.com/myapp.NewService"
      args:
        - "@stdlib.http.client"  # Pre-configured HTTP client
        - "@stdlib.logger"       # Pre-configured slog logger

📖 See stdlib/README.md for all available services and factory functions.

Examples

The flagship demo lives in a separate repo: gendi-org/gendi-example-app — a realistic HTTP task-tracker service wired end-to-end by gendi, covering services, tagged injection, decorators, stdlib and built-in passes, imports, and integration tests.

Documentation

Requirements

  • Go 1.25.4 or later
  • No runtime dependencies for generated code (except github.com/gendi-org/gendi/parameters)

License

gendi is licensed under the Apache License 2.0.

Documentation

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type Argument

type Argument struct {
	Kind     ArgumentKind
	Value    string
	Literal  Literal
	Packages []string

	// Source location (optional)
	SourceLoc *srcloc.Location
}

Argument represents a constructor argument.

type ArgumentKind

type ArgumentKind int

ArgumentKind is the parsed kind of a constructor argument.

const (
	ArgLiteral ArgumentKind = iota
	ArgServiceRef
	ArgInner
	ArgParam
	ArgTagged
	ArgSpread
	ArgGoRef
	ArgFieldAccessService
	ArgFieldAccessGo
)

type Config

type Config struct {
	Parameters map[string]Parameter
	Tags       map[string]Tag
	Services   map[string]Service
}

Config is the root configuration for the DI container. This is a resolved configuration with no import directives.

func ApplyInternalPasses

func ApplyInternalPasses(cfg *Config) (*Config, error)

ApplyInternalPasses applies mandatory internal transformation passes. These passes desugar high-level config constructs (like decorators) into simpler primitives before IR building.

func ApplyPasses

func ApplyPasses(cfg *Config, passes []Pass) (*Config, error)

ApplyPasses applies compiler passes sequentially to the config. Each pass receives the result of the previous pass.

func NewConfig

func NewConfig() *Config

func (*Config) Clone

func (cfg *Config) Clone() *Config

Clone returns a copy of the config that can be transformed by passes without affecting the receiver. Slices holding per-service state (constructor args, tags) are cloned; their elements are treated as immutable by passes, which replace entries wholesale.

func (*Config) MergeWith

func (cfg *Config) MergeWith(src *Config) *Config

MergeWith merges src into cfg and returns cfg.

type Constructor

type Constructor struct {
	Func     string
	Method   string
	Args     []Argument
	Packages []string

	// Source locations (optional)
	SourceLoc *srcloc.Location
}

Constructor defines service constructor configuration.

type DecoratorPass

type DecoratorPass struct{}

DecoratorPass transforms decorator services into plain services and aliases. This is an internal mandatory pass applied during the pipeline build after a user passes.

Transformation example:

Input:
  base: { constructor: ... }
  dec: { decorates: "base", args: ["@.inner"] }
Output:
  dec.inner: { constructor: <original base constructor> }
  dec: { args: ["@dec.inner"] }
  base: { alias: "dec" }

func (*DecoratorPass) Name

func (p *DecoratorPass) Name() string

func (*DecoratorPass) Process

func (p *DecoratorPass) Process(cfg *Config) (*Config, error)

type ExposeAllPass

type ExposeAllPass struct{}

ExposeAllPass promotes every service to public, causing the generator to emit a public getter for each one. Intended for test containers that need direct access to all services regardless of how they are declared in the YAML config.

Enable via: --enable-pass=expose-all

Avoid using in production containers — it overrides explicit `public: false` declarations and disables unreachable-service pruning (all services become reachable roots), so every imported service gets a generated getter.

func (*ExposeAllPass) Name

func (p *ExposeAllPass) Name() string

func (*ExposeAllPass) Process

func (p *ExposeAllPass) Process(cfg *Config) (*Config, error)

type Literal

type Literal struct {
	Kind  LiteralKind
	Value any // string, int64, float64, bool, or nil
}

Literal represents a typed literal value, independent of any parsing format.

func NewBoolLiteral

func NewBoolLiteral(v bool) Literal

NewBoolLiteral creates a bool literal.

func NewFloatLiteral

func NewFloatLiteral(v float64) Literal

NewFloatLiteral creates a float literal.

func NewIntLiteral

func NewIntLiteral(v int64) Literal

NewIntLiteral creates an int literal.

func NewNullLiteral

func NewNullLiteral() Literal

NewNullLiteral creates a null literal.

func NewStringLiteral

func NewStringLiteral(s string) Literal

NewStringLiteral creates a string literal.

func (Literal) Bool

func (l Literal) Bool() bool

Bool returns the bool value, or false if not a bool literal.

func (Literal) Float

func (l Literal) Float() float64

Float returns the float64 value, or 0 if not a float literal.

func (Literal) Int

func (l Literal) Int() int64

Int returns the int64 value, or 0 if not an int literal.

func (Literal) IsNull

func (l Literal) IsNull() bool

IsNull returns true if this is a null literal.

func (Literal) String

func (l Literal) String() string

String returns the string value, or empty string if not a string literal.

type LiteralKind

type LiteralKind int

LiteralKind indicates the type of a literal value.

const (
	LiteralString LiteralKind = iota
	LiteralInt
	LiteralFloat
	LiteralBool
	LiteralNull
)

type Parameter

type Parameter struct {
	Value Literal

	// Source location (optional)
	SourceLoc *srcloc.Location
}

Parameter defines a parameter default value. Its target type is contextual: it comes from each constructor argument the parameter is injected into, not from the declaration.

type Pass

type Pass interface {
	Name() string
	Process(cfg *Config) (*Config, error)
}

Pass is a compiler pass that transforms config before validation and generation. Passes mutate the config and return it for chaining.

type Service

type Service struct {
	Type               string
	Constructor        Constructor
	Shared             bool
	Public             bool
	Autoconfigure      bool
	Decorates          string
	DecorationPriority int
	Tags               []ServiceTag
	Alias              string
	Packages           []string

	// Source location (optional)
	SourceLoc *srcloc.Location
}

Service defines a service entry.

type ServiceTag

type ServiceTag struct {
	Name       string
	Attributes map[string]any

	// Source location (optional)
	SourceLoc *srcloc.Location
}

ServiceTag defines a tag assigned to a service.

type Tag

type Tag struct {
	ElementType   string
	SortBy        string
	Public        bool
	Autoconfigure bool
	Packages      []string

	// Source location (optional)
	SourceLoc *srcloc.Location
}

Tag defines a tag declaration.

Directories

Path Synopsis
cmd
gendi command
Package gomod provides utilities for locating Go modules.
Package gomod provides utilities for locating Go modules.
Package yaml provides YAML parsing for DI configuration files.
Package yaml provides YAML parsing for DI configuration files.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL