go-fxlint
A custom golangci-lint analyzer that enforces domain-driven module organization patterns in Go projects using uber/fx.
Installation
go install github.com/jonesrussell/go-fxlint/cmd/go-fxlint@latest
Features
The linter enforces the following rules:
- Module files must be named
module.go
- Module files must be in their respective domain packages (not in
internal/module/
)
- Module files cannot be directly in the
internal/
directory
- The fx.Module name should match its package name (e.g., package auth should have
fx.Module("auth", ...)
)
fx.Module
can only be used in module.go
files
- Each domain package should have its own
module.go
Usage
# Run on a package
go-fxlint ./...
# Run with custom configuration
go-fxlint -module-paths="internal/*/module.go,pkg/*/module.go" -strict-naming=true ./...
With golangci-lint
Add to your .golangci.yml
:
linters:
enable:
- fxlint
linters-settings:
fxlint:
# Optional: Configure allowed module locations
modulePaths:
- internal/*/module.go
- pkg/*/module.go
# Optional: Enforce strict module naming
strictNaming: true
Then run:
golangci-lint run
Configuration
Option |
Description |
Default |
modulePaths |
Glob patterns for allowed module file locations |
["internal/*/module.go", "pkg/*/module.go"] |
strictNaming |
Enforce that module names match their package names |
true |
Examples
Valid Module Organization
// internal/auth/module.go
package auth
import "go.uber.org/fx"
var Module = fx.Module("auth",
fx.Provide(
NewAuthenticator,
),
)
Common Violations
// BAD: Module in wrong location
// internal/module/auth.go
package auth
var Module = fx.Module("auth", ...)
// BAD: Module directly in internal
// internal/module.go
package internal
var Module = fx.Module("internal", ...)
// BAD: Wrong module name
// internal/auth/module.go
package auth
var Module = fx.Module("user", ...) // Should be "auth"
// BAD: fx.Module in non-module file
// internal/auth/service.go
package auth
func init() {
fx.Module("auth", ...) // Should be in module.go
}
Development
Prerequisites
Commands
# Build the binary
task build
# Run tests
task test
# Run linter
task lint
# Run all CI checks
task ci
# Install globally
task install
# Clean build artifacts
task clean
Integration
VSCode
Add to your .vscode/settings.json
:
{
"go.lintTool": "golangci-lint",
"go.lintFlags": [
"--fast"
]
}
GitHub Actions
name: Tests
on:
push:
branches:
- main
- master
pull_request:
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-go@v5
with:
go-version: '1.23'
- uses: arduino/setup-task@v2
with:
version: 3.x
- run: task ci
Contributing
- Fork the repository
- Create your feature branch (
git checkout -b feature/amazing-feature
)
- Commit your changes (
git commit -m 'Add some amazing feature'
)
- Push to the branch (
git push origin feature/amazing-feature
)
- Open a Pull Request
License
MIT License - see the LICENSE file for details